diff options
Diffstat (limited to 'www-servers/apache/files/apache-2.4.12-alpn.patch')
-rw-r--r-- | www-servers/apache/files/apache-2.4.12-alpn.patch | 476 |
1 files changed, 476 insertions, 0 deletions
diff --git a/www-servers/apache/files/apache-2.4.12-alpn.patch b/www-servers/apache/files/apache-2.4.12-alpn.patch new file mode 100644 index 000000000000..25bb6e1b5145 --- /dev/null +++ b/www-servers/apache/files/apache-2.4.12-alpn.patch @@ -0,0 +1,476 @@ +https://bugs.gentoo.org/471512 + +upstream apache has merged alpn into trunk: +https://issues.apache.org/bugzilla/show_bug.cgi?id=52210 +note: the bug is closed INVALID due to the npn discussion; go to the bottom to +see alpn merged into it trunk. unfortunately, it wasn't merged into the 2.4 +branch. + +the mod_h2 project has backported it to the 2.4 branch: +https://github.com/icing/mod_h2/tree/master/sandbox/httpd/patches +commit 73e4d0e9c813b58581a32a6948780fa948094cc1 + +--- modules/ssl/mod_ssl.c ++++ modules/ssl/mod_ssl.c +@@ -273,6 +273,12 @@ + "OpenSSL configuration command") + #endif + ++#ifdef HAVE_TLS_ALPN ++ SSL_CMD_SRV(ALPNPreference, ITERATE, ++ "Preference in Application-Layer Protocol Negotiation (ALPN), " ++ "protocols are chosen in the specified order") ++#endif ++ + /* Deprecated directives. */ + AP_INIT_RAW_ARGS("SSLLog", ap_set_deprecated, NULL, OR_ALL, + "SSLLog directive is no longer supported - use ErrorLog."), +@@ -423,12 +448,44 @@ + return 1; + } + ++static int modssl_register_alpn(conn_rec *c, ++ ssl_alpn_propose_protos advertisefn, ++ ssl_alpn_proto_negotiated negotiatedfn) ++{ ++#ifdef HAVE_TLS_ALPN ++ SSLConnRec *sslconn = myConnConfig(c); ++ ++ if (!sslconn) { ++ return DECLINED; ++ } ++ ++ if (!sslconn->alpn_proposefns) { ++ sslconn->alpn_proposefns = ++ apr_array_make(c->pool, 5, sizeof(ssl_alpn_propose_protos)); ++ sslconn->alpn_negofns = ++ apr_array_make(c->pool, 5, sizeof(ssl_alpn_proto_negotiated)); ++ } ++ ++ if (advertisefn) ++ APR_ARRAY_PUSH(sslconn->alpn_proposefns, ssl_alpn_propose_protos) = ++ advertisefn; ++ if (negotiatedfn) ++ APR_ARRAY_PUSH(sslconn->alpn_negofns, ssl_alpn_proto_negotiated) = ++ negotiatedfn; ++ ++ return OK; ++#else ++ return DECLINED; ++#endif ++} ++ + int ssl_init_ssl_connection(conn_rec *c, request_rec *r) + { + SSLSrvConfigRec *sc; + SSL *ssl; + SSLConnRec *sslconn = myConnConfig(c); + char *vhost_md5; ++ int rc; + modssl_ctx_t *mctx; + server_rec *server; + +@@ -585,6 +647,7 @@ + + APR_REGISTER_OPTIONAL_FN(ssl_proxy_enable); + APR_REGISTER_OPTIONAL_FN(ssl_engine_disable); ++ APR_REGISTER_OPTIONAL_FN(modssl_register_alpn); + + ap_register_auth_provider(p, AUTHZ_PROVIDER_GROUP, "ssl", + AUTHZ_PROVIDER_VERSION, +--- modules/ssl/mod_ssl.h ++++ modules/ssl/mod_ssl.h +@@ -63,5 +93,46 @@ + + APR_DECLARE_OPTIONAL_FN(int, ssl_engine_disable, (conn_rec *)); + ++/** The alpn_propose_proto callback allows other modules to propose ++ * the name of the protocol that will be chosen during the ++ * Application-Layer Protocol Negotiation (ALPN) portion of the SSL handshake. ++ * The callback is given the connection and a list of NULL-terminated ++ * protocol strings as supported by the client. If this client_protos is ++ * non-empty, it must pick its preferred protocol from that list. Otherwise ++ * it should add its supported protocols in order of precedence. ++ * The callback should not yet modify the connection or install any filters ++ * as its proposal(s) may be overridden by another callback or server ++ * configuration. ++ * It should return OK or, to prevent further processing of (other modules') ++ * callbacks, return DONE. ++ */ ++typedef int (*ssl_alpn_propose_protos)(conn_rec *connection, ++ apr_array_header_t *client_protos, ++ apr_array_header_t *proposed_protos); ++ ++/** The alpn_proto_negotiated callback allows other modules to discover ++ * the name of the protocol that was chosen during the Application-Layer ++ * Protocol Negotiation (ALPN) portion of the SSL handshake. ++ * The callback is given the connection, a ++ * non-NUL-terminated string containing the protocol name, and the ++ * length of the string; it should do something appropriate ++ * (i.e. insert or remove filters) and return OK. To prevent further ++ * processing of (other modules') callbacks, return DONE. */ ++typedef int (*ssl_alpn_proto_negotiated)(conn_rec *connection, ++ const char *proto_name, ++ apr_size_t proto_name_len); ++ ++/* An optional function which can be used to register a pair of callbacks ++ * for ALPN handling. ++ * This optional function should be invoked from a pre_connection hook ++ * which runs *after* mod_ssl.c's pre_connection hook. The function returns ++ * OK if the callbacks are registered, or DECLINED otherwise (for example if ++ * mod_ssl does not support ALPN). ++ */ ++APR_DECLARE_OPTIONAL_FN(int, modssl_register_alpn, ++ (conn_rec *conn, ++ ssl_alpn_propose_protos proposefn, ++ ssl_alpn_proto_negotiated negotiatedfn)); ++ + #endif /* __MOD_SSL_H__ */ + /** @} */ +--- modules/ssl/ssl_engine_config.c ++++ modules/ssl/ssl_engine_config.c +@@ -159,6 +160,9 @@ + SSL_CONF_CTX_set_flags(mctx->ssl_ctx_config, SSL_CONF_FLAG_CERTIFICATE); + mctx->ssl_ctx_param = apr_array_make(p, 5, sizeof(ssl_ctx_param_t)); + #endif ++#ifdef HAVE_TLS_ALPN ++ mctx->ssl_alpn_pref = apr_array_make(p, 5, sizeof(const char *)); ++#endif + } + + static void modssl_ctx_init_proxy(SSLSrvConfigRec *sc, +@@ -301,6 +307,9 @@ + #ifdef HAVE_SSL_CONF_CMD + cfgMergeArray(ssl_ctx_param); + #endif ++#ifdef HAVE_TLS_ALPN ++ cfgMergeArray(ssl_alpn_pref); ++#endif + } + + static void modssl_ctx_cfg_merge_proxy(apr_pool_t *p, +@@ -1875,6 +1868,16 @@ + } + #endif + ++#ifdef HAVE_TLS_ALPN ++const char *ssl_cmd_SSLALPNPreference(cmd_parms *cmd, void *dcfg, ++ const char *protocol) ++{ ++ SSLSrvConfigRec *sc = mySrvConfig(cmd->server); ++ APR_ARRAY_PUSH(sc->server->ssl_alpn_pref, const char *) = protocol; ++ return NULL; ++} ++#endif ++ + #ifdef HAVE_SRP + + const char *ssl_cmd_SSLSRPVerifierFile(cmd_parms *cmd, void *dcfg, +--- modules/ssl/ssl_engine_init.c ++++ modules/ssl/ssl_engine_init.c +@@ -623,6 +646,11 @@ + SSL_CTX_set_tmp_dh_callback(ctx, ssl_callback_TmpDH); + + SSL_CTX_set_info_callback(ctx, ssl_callback_Info); ++ ++#ifdef HAVE_TLS_ALPN ++ SSL_CTX_set_alpn_select_cb( ++ ctx, ssl_callback_alpn_select, NULL); ++#endif + } + + static apr_status_t ssl_init_ctx_verify(server_rec *s, +--- modules/ssl/ssl_engine_io.c ++++ modules/ssl/ssl_engine_io.c +@@ -28,6 +28,7 @@ + core keeps dumping.'' + -- Unknown */ + #include "ssl_private.h" ++#include "mod_ssl.h" + #include "apr_date.h" + + /* _________________________________________________________________ +@@ -297,6 +315,9 @@ + apr_pool_t *pool; + char buffer[AP_IOBUFSIZE]; + ssl_filter_ctx_t *filter_ctx; ++#ifdef HAVE_TLS_ALPN ++ int alpn_finished; /* 1 if ALPN has finished, 0 otherwise */ ++#endif + } bio_filter_in_ctx_t; + + /* +@@ -1412,6 +1485,37 @@ + APR_BRIGADE_INSERT_TAIL(bb, bucket); + } + ++#ifdef HAVE_TLS_ALPN ++ /* By this point, Application-Layer Protocol Negotiation (ALPN) should be ++ * completed (if our version of OpenSSL supports it). If we haven't already, ++ * find out which protocol was decided upon and inform other modules ++ * by calling alpn_proto_negotiated_hook. ++ */ ++ if (!inctx->alpn_finished) { ++ SSLConnRec *sslconn = myConnConfig(f->c); ++ const unsigned char *next_proto = NULL; ++ unsigned next_proto_len = 0; ++ int n; ++ ++ if (sslconn->alpn_negofns) { ++ SSL_get0_alpn_selected(inctx->ssl, &next_proto, &next_proto_len); ++ ap_log_cerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, f->c, ++ APLOGNO(02836) "SSL negotiated protocol: '%s'", ++ (next_proto && next_proto_len)? ++ apr_pstrmemdup(f->c->pool, (const char *)next_proto, ++ next_proto_len) : "(null)"); ++ for (n = 0; n < sslconn->alpn_negofns->nelts; n++) { ++ ssl_alpn_proto_negotiated fn = ++ APR_ARRAY_IDX(sslconn->alpn_negofns, n, ssl_alpn_proto_negotiated); ++ ++ if (fn(f->c, (const char *)next_proto, next_proto_len) == DONE) ++ break; ++ } ++ } ++ inctx->alpn_finished = 1; ++ } ++#endif ++ + return APR_SUCCESS; + } + +@@ -1893,6 +1996,9 @@ + inctx->block = APR_BLOCK_READ; + inctx->pool = c->pool; + inctx->filter_ctx = filter_ctx; ++#ifdef HAVE_TLS_ALPN ++ inctx->alpn_finished = 0; ++#endif + } + + /* The request_rec pointer is passed in here only to ensure that the +--- modules/ssl/ssl_engine_kernel.c ++++ modules/ssl/ssl_engine_kernel.c +@@ -29,6 +29,7 @@ + time I was too famous.'' + -- Unknown */ + #include "ssl_private.h" ++#include "mod_ssl.h" + #include "util_md5.h" + + static void ssl_configure_env(request_rec *r, SSLConnRec *sslconn); +@@ -2137,6 +2162,153 @@ + } + #endif /* HAVE_TLS_SESSION_TICKETS */ + ++#ifdef HAVE_TLS_ALPN ++static int ssl_array_index(apr_array_header_t *array, ++ const char *s) ++{ ++ int i; ++ for (i = 0; i < array->nelts; i++) { ++ const char *p = APR_ARRAY_IDX(array, i, const char*); ++ if (!strcmp(p, s)) { ++ return i; ++ } ++ } ++ return -1; ++} ++ ++/* ++ * Compare two ALPN protocol proposal. Result is similar to strcmp(): ++ * 0 gives same precedence, >0 means proto1 is prefered. ++ */ ++static int ssl_cmp_alpn_protos(modssl_ctx_t *ctx, ++ const char *proto1, ++ const char *proto2) ++{ ++ /* TODO: we should have a mod_ssl configuration parameter. */ ++ if (ctx && ctx->ssl_alpn_pref) { ++ int index1 = ssl_array_index(ctx->ssl_alpn_pref, proto1); ++ int index2 = ssl_array_index(ctx->ssl_alpn_pref, proto2); ++ if (index2 > index1) { ++ return (index1 >= 0)? 1 : -1; ++ } ++ else if (index1 > index2) { ++ return (index2 >= 0)? -1 : 1; ++ } ++ } ++ /* both have the same index (mabye -1 or no pref configured) and we compare ++ * the names so that spdy3 gets precedence over spdy2. That makes ++ * the outcome at least deterministic. */ ++ return strcmp((const char *)proto1, (const char *)proto2); ++} ++ ++/* ++ * This callback function is executed when the TLS Application Layer ++ * Protocol Negotiate Extension (ALPN, RFC 7301) is triggered by the client ++ * hello, giving a list of desired protocol names (in descending preference) ++ * to the server. ++ * The callback has to select a protocol name or return an error if none of ++ * the clients preferences is supported. ++ * The selected protocol does not have to be on the client list, according ++ * to RFC 7301, so no checks are performed. ++ * The client protocol list is serialized as length byte followed by ascii ++ * characters (not null-terminated), followed by the next protocol name. ++ */ ++int ssl_callback_alpn_select(SSL *ssl, ++ const unsigned char **out, unsigned char *outlen, ++ const unsigned char *in, unsigned int inlen, void *arg) ++{ ++ conn_rec *c = (conn_rec*)SSL_get_app_data(ssl); ++ SSLConnRec *sslconn = myConnConfig(c); ++ server_rec *s = mySrvFromConn(c); ++ SSLSrvConfigRec *sc = mySrvConfig(s); ++ modssl_ctx_t *mctx = myCtxConfig(sslconn, sc); ++ const char *alpn_http1 = "http/1.1"; ++ apr_array_header_t *client_protos; ++ apr_array_header_t *proposed_protos; ++ int i; ++ size_t len; ++ ++ /* If the connection object is not available, ++ * then there's nothing for us to do. */ ++ if (c == NULL) { ++ return SSL_TLSEXT_ERR_OK; ++ } ++ ++ if (inlen == 0) { ++ // someone tries to trick us? ++ ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(02837) ++ "ALPN client protocol list empty"); ++ return SSL_TLSEXT_ERR_ALERT_FATAL; ++ } ++ ++ client_protos = apr_array_make(c->pool, 0, sizeof(char *)); ++ for (i = 0; i < inlen; /**/) { ++ unsigned int plen = in[i++]; ++ if (plen + i > inlen) { ++ // someone tries to trick us? ++ ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(02838) ++ "ALPN protocol identier too long"); ++ return SSL_TLSEXT_ERR_ALERT_FATAL; ++ } ++ APR_ARRAY_PUSH(client_protos, char*) = ++ apr_pstrndup(c->pool, (const char *)in+i, plen); ++ i += plen; ++ } ++ ++ proposed_protos = apr_array_make(c->pool, client_protos->nelts+1, ++ sizeof(char *)); ++ ++ if (sslconn->alpn_proposefns != NULL) { ++ /* Invoke our alpn_propos_proto hooks, giving other modules a chance to ++ * propose protocol names for selection. We might have several such ++ * hooks installed and if two make a proposal, we need to give ++ * preference to one. ++ */ ++ for (i = 0; i < sslconn->alpn_proposefns->nelts; i++) { ++ ssl_alpn_propose_protos fn = ++ APR_ARRAY_IDX(sslconn->alpn_proposefns, i, ++ ssl_alpn_propose_protos); ++ ++ if (fn(c, client_protos, proposed_protos) == DONE) ++ break; ++ } ++ } ++ ++ if (proposed_protos->nelts <= 0) { ++ /* Regardless of installed hooks, the http/1.1 protocol is always ++ * supported by us. Choose it if none other matches. */ ++ if (ssl_array_index(client_protos, alpn_http1) < 0) { ++ ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(02839) ++ "none of the client ALPN protocols are supported"); ++ return SSL_TLSEXT_ERR_ALERT_FATAL; ++ } ++ *out = (const unsigned char*)alpn_http1; ++ *outlen = (unsigned char)strlen(alpn_http1); ++ return SSL_TLSEXT_ERR_OK; ++ } ++ ++ /* Now select the most preferred protocol from the proposals. */ ++ *out = APR_ARRAY_IDX(proposed_protos, 0, const unsigned char *); ++ for (i = 1; i < proposed_protos->nelts; ++i) { ++ const char *proto = APR_ARRAY_IDX(proposed_protos, i, const char*); ++ /* Do we prefer it over existing candidate? */ ++ if (ssl_cmp_alpn_protos(mctx, (const char *)*out, proto) < 0) { ++ *out = (const unsigned char*)proto; ++ } ++ } ++ ++ len = strlen((const char*)*out); ++ if (len > 255) { ++ ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(02840) ++ "ALPN negotiated protocol name too long"); ++ return SSL_TLSEXT_ERR_ALERT_FATAL; ++ } ++ *outlen = (unsigned char)len; ++ ++ return SSL_TLSEXT_ERR_OK; ++} ++#endif ++ + #ifdef HAVE_SRP + + int ssl_callback_SRPServerParams(SSL *ssl, int *ad, void *arg) +--- modules/ssl/ssl_private.h ++++ modules/ssl/ssl_private.h +@@ -182,6 +182,11 @@ + #include <openssl/srp.h> + #endif + ++/* ALPN Protocol Negotiation */ ++#if defined(TLSEXT_TYPE_application_layer_protocol_negotiation) ++#define HAVE_TLS_ALPN ++#endif ++ + #endif /* !defined(OPENSSL_NO_TLSEXT) && defined(SSL_set_tlsext_host_name) */ + + /* mod_ssl headers */ +@@ -443,6 +438,12 @@ + * connection */ + } reneg_state; + ++#ifdef HAVE_TLS_ALPN ++ /* Poor man's inter-module optional hooks for ALPN. */ ++ apr_array_header_t *alpn_proposefns; /* list of ssl_alpn_propose_protos callbacks */ ++ apr_array_header_t *alpn_negofns; /* list of ssl_alpn_proto_negotiated callbacks. */ ++#endif ++ + server_rec *server; + } SSLConnRec; + +@@ -633,6 +633,10 @@ + SSL_CONF_CTX *ssl_ctx_config; /* Configuration context */ + apr_array_header_t *ssl_ctx_param; /* parameters to pass to SSL_CTX */ + #endif ++ ++#ifdef HAVE_TLS_ALPN ++ apr_array_header_t *ssl_alpn_pref; /* protocol names in order of preference */ ++#endif + } modssl_ctx_t; + + struct SSLSrvConfigRec { +@@ -763,6 +763,10 @@ + const char *ssl_cmd_SSLOpenSSLConfCmd(cmd_parms *cmd, void *dcfg, const char *arg1, const char *arg2); + #endif + ++#ifdef HAVE_TLS_ALPN ++const char *ssl_cmd_SSLALPNPreference(cmd_parms *cmd, void *dcfg, const char *protocol); ++#endif ++ + #ifdef HAVE_SRP + const char *ssl_cmd_SSLSRPVerifierFile(cmd_parms *cmd, void *dcfg, const char *arg); + const char *ssl_cmd_SSLSRPUnknownUserSeed(cmd_parms *cmd, void *dcfg, const char *arg); +@@ -815,6 +815,12 @@ + EVP_CIPHER_CTX *, HMAC_CTX *, int); + #endif + ++#ifdef HAVE_TLS_ALPN ++int ssl_callback_alpn_select(SSL *ssl, const unsigned char **out, ++ unsigned char *outlen, const unsigned char *in, ++ unsigned int inlen, void *arg); ++#endif ++ + /** Session Cache Support */ + apr_status_t ssl_scache_init(server_rec *, apr_pool_t *); + void ssl_scache_status_register(apr_pool_t *p); |