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