diff --git a/lib/modules/SSL.pmod/Constants.pmod b/lib/modules/SSL.pmod/Constants.pmod index b444c2821fcf82fa22526becbd163981f12792c8..83883dba88720cdf37f063bc8e0b3499771c2787 100644 --- a/lib/modules/SSL.pmod/Constants.pmod +++ b/lib/modules/SSL.pmod/Constants.pmod @@ -459,6 +459,7 @@ constant HANDSHAKE_finished = 20; constant HANDSHAKE_cerificate_url = 21; constant HANDSHAKE_certificate_status = 22; constant HANDSHAKE_supplemental_data = 23; +constant HANDSHAKE_next_protocol = 67; // draft-agl-tls-nextprotoneg constant AUTHLEVEL_none = 1; constant AUTHLEVEL_ask = 2; @@ -486,3 +487,4 @@ constant EXTENSION_client_authz = 7; // RFC 5878. constant EXTENSION_server_authz = 8; // RFC 5878. constant EXTENSION_signature_algorithms = 13; // RFC 5246. constant EXTENSION_renegotiation_info = 0xff01; // RFC 5746. +constant EXTENSION_next_protocol_negotiation = 13172; // draft-agl-tls-nextprotoneg diff --git a/lib/modules/SSL.pmod/context.pike b/lib/modules/SSL.pmod/context.pike index dbfb01034547e10b66d868d27f8dc634d2a74d4d..cf8b6476c5fa4f6ae8992fb3a1e0cc41a6354143 100644 --- a/lib/modules/SSL.pmod/context.pike +++ b/lib/modules/SSL.pmod/context.pike @@ -137,6 +137,15 @@ array(int) preferred_auth_methods = //! Cipher suites we want to support, in order of preference, best first. array(int) preferred_suites; +//! List of advertised protocols using using TLS next protocol negotiation. +array(string) advertised_protocols; + +//! Protocols to advertise during handshake using the next protocol +//! negotiation extension. Currently only used together with spdy. +void advertise_protocols(string ... protos) { + advertised_protocols = protos; +} + //! Filter cipher suites from @[preferred_suites] that don't have //! a key with an effective length of at least @[min_keylength] bits. void filter_weak_suites(int min_keylength) diff --git a/lib/modules/SSL.pmod/handshake.pike b/lib/modules/SSL.pmod/handshake.pike index e8594dd948a7d050e8eecfb975443869d4359bae..15ffe8078b561e51a23db5fde4f9c1ce804d48d9 100644 --- a/lib/modules/SSL.pmod/handshake.pike +++ b/lib/modules/SSL.pmod/handshake.pike @@ -86,6 +86,9 @@ constant Session = SSL.session; constant Packet = SSL.packet; constant Alert = SSL.alert; +int has_next_protocol_negotiation; + +string next_protocol; #ifdef SSL3_PROFILING int timestamp; @@ -133,9 +136,9 @@ Packet server_hello_packet() struct->put_uint(session->cipher_suite, 2); struct->put_uint(session->compression_algorithm, 1); - if (secure_renegotiation) { - ADT.struct extensions = ADT.struct(); + ADT.struct extensions = ADT.struct(); + if (secure_renegotiation) { // RFC 5746 3.7: // The server MUST include a "renegotiation_info" extension // containing the saved client_verify_data and server_verify_data in @@ -145,9 +148,20 @@ Packet server_hello_packet() extension->put_var_string(client_verify_data + server_verify_data, 1); extensions->put_var_string(extension->pop_data(), 2); - struct->put_var_string(extensions->pop_data(), 2); } + if (has_next_protocol_negotiation && context->advertised_protocols) { + extensions->put_uint(EXTENSION_next_protocol_negotiation, 2); + ADT.struct extension = ADT.struct(); + foreach (context->advertised_protocols;; string proto) { + extension->put_var_string(proto, 1); + } + extensions->put_var_string(extension->pop_data(), 2); + } + + if (!extensions->is_empty()) + struct->put_var_string(extensions->pop_data(), 2); + string data = struct->pop_data(); #ifdef SSL3_DEBUG werror("SSL.handshake: Server hello: %O\n", data); @@ -872,6 +886,9 @@ int(-1..1) handle_handshake(int type, string data, string raw) secure_renegotiation = 1; missing_secure_renegotiation = 0; break; + case EXTENSION_next_protocol_negotiation: + has_next_protocol_negotiation = 1; + break; default: break; } @@ -1071,6 +1088,12 @@ int(-1..1) handle_handshake(int type, string data, string raw) "SSL.session->handle_handshake: unexpected message\n", backtrace())); return -1; + case HANDSHAKE_next_protocol: + { + next_protocol = input->get_var_string(1); + handshake_messages += raw; + return 1; + } case HANDSHAKE_finished: { string my_digest; diff --git a/lib/modules/SSL.pmod/sslfile.pike b/lib/modules/SSL.pmod/sslfile.pike index 496039604d848d1b05f7008bcf17a6ff657cfd43..03757fd12203a4ff492e450ec6c9486557d339b5 100644 --- a/lib/modules/SSL.pmod/sslfile.pike +++ b/lib/modules/SSL.pmod/sslfile.pike @@ -2264,6 +2264,12 @@ protected int ssl_close_callback (int called_from_real_backend) return -1; } +//! The next protocol chosen by the client during next protocol +//! negotiation. +string `->next_protocol() { + return conn->next_protocol; +} + #else // constant(SSL.Cipher.CipherAlgorithm) constant this_program_does_not_exist = 1; #endif