From 27e117f45a756620bec2de4eac6644443be10b19 Mon Sep 17 00:00:00 2001 From: Arne Goedeke <el@laramies.com> Date: Sat, 7 Apr 2012 02:28:51 +0200 Subject: [PATCH] SSL: added next protocol negotiation extension --- lib/modules/SSL.pmod/Constants.pmod | 2 ++ lib/modules/SSL.pmod/context.pike | 9 +++++++++ lib/modules/SSL.pmod/handshake.pike | 29 ++++++++++++++++++++++++++--- lib/modules/SSL.pmod/sslfile.pike | 6 ++++++ 4 files changed, 43 insertions(+), 3 deletions(-) diff --git a/lib/modules/SSL.pmod/Constants.pmod b/lib/modules/SSL.pmod/Constants.pmod index b444c2821f..83883dba88 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 dbfb010345..cf8b6476c5 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 e8594dd948..15ffe8078b 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 496039604d..03757fd122 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 -- GitLab