febac1c
# ./pullrev.sh 1332643 1345599
f04e663
f04e663
https://bugzilla.redhat.com//show_bug.cgi?id=809599
f04e663
f04e663
http://svn.apache.org/viewvc?view=revision&revision=1332643
f04e663
febac1c
http://svn.apache.org/viewvc?view=revision&revision=1345599
febac1c
a3c2292
--- httpd-2.4.4/modules/ssl/mod_ssl.c.r1332643+
a3c2292
+++ httpd-2.4.4/modules/ssl/mod_ssl.c
a3c2292
@@ -272,6 +272,18 @@ static const command_rec ssl_config_cmds
f04e663
     AP_END_CMD
f04e663
 };
f04e663
 
f04e663
+/* Implement 'modssl_run_npn_advertise_protos_hook'. */
f04e663
+APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(
f04e663
+    modssl, AP, int, npn_advertise_protos_hook,
f04e663
+    (conn_rec *connection, apr_array_header_t *protos),
f04e663
+    (connection, protos), OK, DECLINED);
f04e663
+
f04e663
+/* Implement 'modssl_run_npn_proto_negotiated_hook'. */
f04e663
+APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(
f04e663
+    modssl, AP, int, npn_proto_negotiated_hook,
f04e663
+    (conn_rec *connection, const char *proto_name, apr_size_t proto_name_len),
f04e663
+    (connection, proto_name, proto_name_len), OK, DECLINED);
f04e663
+
f04e663
 /*
f04e663
  *  the various processing hooks
f04e663
  */
a3c2292
--- httpd-2.4.4/modules/ssl/mod_ssl.h.r1332643+
a3c2292
+++ httpd-2.4.4/modules/ssl/mod_ssl.h
7e10e90
@@ -63,5 +63,26 @@ APR_DECLARE_OPTIONAL_FN(int, ssl_proxy_e
f04e663
 
f04e663
 APR_DECLARE_OPTIONAL_FN(int, ssl_engine_disable, (conn_rec *));
f04e663
 
f04e663
+/** The npn_advertise_protos optional hook allows other modules to add entries
f04e663
+ * to the list of protocol names advertised by the server during the Next
f04e663
+ * Protocol Negotiation (NPN) portion of the SSL handshake.  The hook callee is
f04e663
+ * given the connection and an APR array; it should push one or more char*'s
f04e663
+ * pointing to null-terminated strings (such as "http/1.1" or "spdy/2") onto
f04e663
+ * the array and return OK, or do nothing and return DECLINED. */
f04e663
+APR_DECLARE_EXTERNAL_HOOK(modssl, AP, int, npn_advertise_protos_hook,
f04e663
+                          (conn_rec *connection, apr_array_header_t *protos));
f04e663
+
f04e663
+/** The npn_proto_negotiated optional hook allows other modules to discover the
f04e663
+ * name of the protocol that was chosen during the Next Protocol Negotiation
f04e663
+ * (NPN) portion of the SSL handshake.  Note that this may be the empty string
f04e663
+ * (in which case modules should probably assume HTTP), or it may be a protocol
f04e663
+ * that was never even advertised by the server.  The hook callee is given the
f04e663
+ * connection, a non-null-terminated string containing the protocol name, and
f04e663
+ * the length of the string; it should do something appropriate (i.e. insert or
f04e663
+ * remove filters) and return OK, or do nothing and return DECLINED. */
f04e663
+APR_DECLARE_EXTERNAL_HOOK(modssl, AP, int, npn_proto_negotiated_hook,
f04e663
+                          (conn_rec *connection, const char *proto_name,
f04e663
+                           apr_size_t proto_name_len));
f04e663
+
f04e663
 #endif /* __MOD_SSL_H__ */
f04e663
 /** @} */
a3c2292
--- httpd-2.4.4/modules/ssl/ssl_engine_init.c.r1332643+
a3c2292
+++ httpd-2.4.4/modules/ssl/ssl_engine_init.c
a3c2292
@@ -725,6 +725,11 @@ static void ssl_init_ctx_callbacks(serve
f04e663
 #endif
f04e663
 
f04e663
     SSL_CTX_set_info_callback(ctx, ssl_callback_Info);
f04e663
+
f04e663
+#ifdef HAVE_TLS_NPN
f04e663
+    SSL_CTX_set_next_protos_advertised_cb(
f04e663
+        ctx, ssl_callback_AdvertiseNextProtos, NULL);
f04e663
+#endif
f04e663
 }
f04e663
 
f04e663
 static void ssl_init_ctx_verify(server_rec *s,
a3c2292
--- httpd-2.4.4/modules/ssl/ssl_engine_io.c.r1332643+
a3c2292
+++ httpd-2.4.4/modules/ssl/ssl_engine_io.c
f04e663
@@ -28,6 +28,7 @@
f04e663
                                   core keeps dumping.''
f04e663
                                             -- Unknown    */
f04e663
 #include "ssl_private.h"
f04e663
+#include "mod_ssl.h"
f04e663
 #include "apr_date.h"
f04e663
 
f04e663
 /*  _________________________________________________________________
7e10e90
@@ -297,6 +298,7 @@ typedef struct {
f04e663
     apr_pool_t *pool;
f04e663
     char buffer[AP_IOBUFSIZE];
f04e663
     ssl_filter_ctx_t *filter_ctx;
f04e663
+    int npn_finished;  /* 1 if NPN has finished, 0 otherwise */
f04e663
 } bio_filter_in_ctx_t;
f04e663
 
f04e663
 /*
a3c2292
@@ -1385,6 +1387,26 @@ static apr_status_t ssl_io_filter_input(
f04e663
         APR_BRIGADE_INSERT_TAIL(bb, bucket);
f04e663
     }
f04e663
 
f04e663
+#ifdef HAVE_TLS_NPN
f04e663
+    /* By this point, Next Protocol Negotiation (NPN) should be completed (if
f04e663
+     * our version of OpenSSL supports it).  If we haven't already, find out
f04e663
+     * which protocol was decided upon and inform other modules by calling
f04e663
+     * npn_proto_negotiated_hook. */
f04e663
+    if (!inctx->npn_finished) {
f04e663
+        const unsigned char *next_proto = NULL;
f04e663
+        unsigned next_proto_len = 0;
f04e663
+
f04e663
+        SSL_get0_next_proto_negotiated(
f04e663
+            inctx->ssl, &next_proto, &next_proto_len);
f04e663
+        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, f->c,
febac1c
+                      APLOGNO(02306) "SSL NPN negotiated protocol: '%*s'",
febac1c
+                      next_proto_len, (const char*)next_proto);
f04e663
+        modssl_run_npn_proto_negotiated_hook(
f04e663
+            f->c, (const char*)next_proto, next_proto_len);
f04e663
+        inctx->npn_finished = 1;
f04e663
+    }
f04e663
+#endif
f04e663
+
f04e663
     return APR_SUCCESS;
f04e663
 }
f04e663
 
a3c2292
@@ -1866,6 +1888,7 @@ static void ssl_io_input_add_filter(ssl_
f04e663
     inctx->block = APR_BLOCK_READ;
f04e663
     inctx->pool = c->pool;
f04e663
     inctx->filter_ctx = filter_ctx;
f04e663
+    inctx->npn_finished = 0;
f04e663
 }
f04e663
 
f04e663
 /* The request_rec pointer is passed in here only to ensure that the
a3c2292
--- httpd-2.4.4/modules/ssl/ssl_engine_kernel.c.r1332643+
a3c2292
+++ httpd-2.4.4/modules/ssl/ssl_engine_kernel.c
f04e663
@@ -29,6 +29,7 @@
f04e663
                                   time I was too famous.''
f04e663
                                             -- Unknown                */
f04e663
 #include "ssl_private.h"
f04e663
+#include "mod_ssl.h"
f04e663
 #include "util_md5.h"
f04e663
 
f04e663
 static void ssl_configure_env(request_rec *r, SSLConnRec *sslconn);
a3c2292
@@ -2161,6 +2162,90 @@ int ssl_callback_SessionTicket(SSL *ssl,
7e10e90
 }
a3c2292
 #endif /* HAVE_TLS_SESSION_TICKETS */
a3c2292
 
f04e663
+#ifdef HAVE_TLS_NPN
f04e663
+/*
f04e663
+ * This callback function is executed when SSL needs to decide what protocols
f04e663
+ * to advertise during Next Protocol Negotiation (NPN).  It must produce a
f04e663
+ * string in wire format -- a sequence of length-prefixed strings -- indicating
f04e663
+ * the advertised protocols.  Refer to SSL_CTX_set_next_protos_advertised_cb
f04e663
+ * in OpenSSL for reference.
f04e663
+ */
f04e663
+int ssl_callback_AdvertiseNextProtos(SSL *ssl, const unsigned char **data_out,
f04e663
+                                     unsigned int *size_out, void *arg)
f04e663
+{
f04e663
+    conn_rec *c = (conn_rec*)SSL_get_app_data(ssl);
f04e663
+    apr_array_header_t *protos;
f04e663
+    int num_protos;
f04e663
+    unsigned int size;
f04e663
+    int i;
f04e663
+    unsigned char *data;
f04e663
+    unsigned char *start;
f04e663
+
f04e663
+    *data_out = NULL;
f04e663
+    *size_out = 0;
f04e663
+
f04e663
+    /* If the connection object is not available, then there's nothing for us
f04e663
+     * to do. */
f04e663
+    if (c == NULL) {
f04e663
+        return SSL_TLSEXT_ERR_OK;
f04e663
+    }
f04e663
+
f04e663
+    /* Invoke our npn_advertise_protos hook, giving other modules a chance to
f04e663
+     * add alternate protocol names to advertise. */
f04e663
+    protos = apr_array_make(c->pool, 0, sizeof(char*));
f04e663
+    modssl_run_npn_advertise_protos_hook(c, protos);
f04e663
+    num_protos = protos->nelts;
f04e663
+
f04e663
+    /* We now have a list of null-terminated strings; we need to concatenate
f04e663
+     * them together into a single string, where each protocol name is prefixed
f04e663
+     * by its length.  First, calculate how long that string will be. */
f04e663
+    size = 0;
f04e663
+    for (i = 0; i < num_protos; ++i) {
f04e663
+        const char *string = APR_ARRAY_IDX(protos, i, const char*);
f04e663
+        unsigned int length = strlen(string);
f04e663
+        /* If the protocol name is too long (the length must fit in one byte),
f04e663
+         * then log an error and skip it. */
f04e663
+        if (length > 255) {
febac1c
+            ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(02307)
f04e663
+                          "SSL NPN protocol name too long (length=%u): %s",
f04e663
+                          length, string);
f04e663
+            continue;
f04e663
+        }
f04e663
+        /* Leave room for the length prefix (one byte) plus the protocol name
f04e663
+         * itself. */
f04e663
+        size += 1 + length;
f04e663
+    }
f04e663
+
f04e663
+    /* If there is nothing to advertise (either because no modules added
f04e663
+     * anything to the protos array, or because all strings added to the array
f04e663
+     * were skipped), then we're done. */
f04e663
+    if (size == 0) {
f04e663
+        return SSL_TLSEXT_ERR_OK;
f04e663
+    }
f04e663
+
f04e663
+    /* Now we can build the string.  Copy each protocol name string into the
f04e663
+     * larger string, prefixed by its length. */
f04e663
+    data = apr_palloc(c->pool, size * sizeof(unsigned char));
f04e663
+    start = data;
f04e663
+    for (i = 0; i < num_protos; ++i) {
f04e663
+        const char *string = APR_ARRAY_IDX(protos, i, const char*);
f04e663
+        apr_size_t length = strlen(string);
febac1c
+        if (length > 255)
febac1c
+            continue;
f04e663
+        *start = (unsigned char)length;
f04e663
+        ++start;
f04e663
+        memcpy(start, string, length * sizeof(unsigned char));
f04e663
+        start += length;
f04e663
+    }
f04e663
+
f04e663
+    /* Success. */
f04e663
+    *data_out = data;
f04e663
+    *size_out = size;
f04e663
+    return SSL_TLSEXT_ERR_OK;
f04e663
+}
a3c2292
+
a3c2292
+#endif /* HAVE_TLS_NPN */
a3c2292
+
a3c2292
 #ifndef OPENSSL_NO_SRP
a3c2292
 
a3c2292
 int ssl_callback_SRPServerParams(SSL *ssl, int *ad, void *arg)
a3c2292
--- httpd-2.4.4/modules/ssl/ssl_private.h.r1332643+
a3c2292
+++ httpd-2.4.4/modules/ssl/ssl_private.h
7e10e90
@@ -139,6 +139,11 @@
7e10e90
 #define HAVE_FIPS
7e10e90
 #endif
7e10e90
 
7e10e90
+#if OPENSSL_VERSION_NUMBER >= 0x10001000L && !defined(OPENSSL_NO_NEXTPROTONEG) \
7e10e90
+    && !defined(OPENSSL_NO_TLSEXT)
7e10e90
+#define HAVE_TLS_NPN
7e10e90
+#endif
7e10e90
+
7e10e90
 #if (OPENSSL_VERSION_NUMBER >= 0x10000000)
7e10e90
 #define MODSSL_SSL_CIPHER_CONST const
7e10e90
 #define MODSSL_SSL_METHOD_CONST const
a3c2292
@@ -840,6 +845,7 @@ int          ssl_callback_ServerNameIndi
7e10e90
 int         ssl_callback_SessionTicket(SSL *, unsigned char *, unsigned char *,
7e10e90
                                        EVP_CIPHER_CTX *, HMAC_CTX *, int);
7e10e90
 #endif
7e10e90
+int ssl_callback_AdvertiseNextProtos(SSL *ssl, const unsigned char **data, unsigned int *len, void *arg);
7e10e90
 
7e10e90
 /**  Session Cache Support  */
7e10e90
 void         ssl_scache_init(server_rec *, apr_pool_t *);