summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
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.patch476
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);