Gentoo Archives: gentoo-commits

From: "Mike Frysinger (vapier)" <vapier@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] gentoo-x86 commit in www-servers/apache/files: apache-2.4.12-alpn.patch
Date: Mon, 01 Jun 2015 06:08:41
Message-Id: 20150601060835.A9DD3A1C@oystercatcher.gentoo.org
1 vapier 15/06/01 06:08:35
2
3 Added: apache-2.4.12-alpn.patch
4 Log:
5 Add ALPN support via USE=alpn #471512.
6
7 (Portage version: 2.2.20/cvs/Linux x86_64, signed Manifest commit with key D2E96200)
8
9 Revision Changes Path
10 1.1 www-servers/apache/files/apache-2.4.12-alpn.patch
11
12 file : http://sources.gentoo.org/viewvc.cgi/gentoo-x86/www-servers/apache/files/apache-2.4.12-alpn.patch?rev=1.1&view=markup
13 plain: http://sources.gentoo.org/viewvc.cgi/gentoo-x86/www-servers/apache/files/apache-2.4.12-alpn.patch?rev=1.1&content-type=text/plain
14
15 Index: apache-2.4.12-alpn.patch
16 ===================================================================
17 https://bugs.gentoo.org/471512
18
19 upstream apache has merged alpn into trunk:
20 https://issues.apache.org/bugzilla/show_bug.cgi?id=52210
21 note: the bug is closed INVALID due to the npn discussion; go to the bottom to
22 see alpn merged into it trunk. unfortunately, it wasn't merged into the 2.4
23 branch.
24
25 the mod_h2 project has backported it to the 2.4 branch:
26 https://github.com/icing/mod_h2/tree/master/sandbox/httpd/patches
27 commit 73e4d0e9c813b58581a32a6948780fa948094cc1
28
29 --- modules/ssl/mod_ssl.c
30 +++ modules/ssl/mod_ssl.c
31 @@ -273,6 +273,12 @@
32 "OpenSSL configuration command")
33 #endif
34
35 +#ifdef HAVE_TLS_ALPN
36 + SSL_CMD_SRV(ALPNPreference, ITERATE,
37 + "Preference in Application-Layer Protocol Negotiation (ALPN), "
38 + "protocols are chosen in the specified order")
39 +#endif
40 +
41 /* Deprecated directives. */
42 AP_INIT_RAW_ARGS("SSLLog", ap_set_deprecated, NULL, OR_ALL,
43 "SSLLog directive is no longer supported - use ErrorLog."),
44 @@ -423,12 +448,44 @@
45 return 1;
46 }
47
48 +static int modssl_register_alpn(conn_rec *c,
49 + ssl_alpn_propose_protos advertisefn,
50 + ssl_alpn_proto_negotiated negotiatedfn)
51 +{
52 +#ifdef HAVE_TLS_ALPN
53 + SSLConnRec *sslconn = myConnConfig(c);
54 +
55 + if (!sslconn) {
56 + return DECLINED;
57 + }
58 +
59 + if (!sslconn->alpn_proposefns) {
60 + sslconn->alpn_proposefns =
61 + apr_array_make(c->pool, 5, sizeof(ssl_alpn_propose_protos));
62 + sslconn->alpn_negofns =
63 + apr_array_make(c->pool, 5, sizeof(ssl_alpn_proto_negotiated));
64 + }
65 +
66 + if (advertisefn)
67 + APR_ARRAY_PUSH(sslconn->alpn_proposefns, ssl_alpn_propose_protos) =
68 + advertisefn;
69 + if (negotiatedfn)
70 + APR_ARRAY_PUSH(sslconn->alpn_negofns, ssl_alpn_proto_negotiated) =
71 + negotiatedfn;
72 +
73 + return OK;
74 +#else
75 + return DECLINED;
76 +#endif
77 +}
78 +
79 int ssl_init_ssl_connection(conn_rec *c, request_rec *r)
80 {
81 SSLSrvConfigRec *sc;
82 SSL *ssl;
83 SSLConnRec *sslconn = myConnConfig(c);
84 char *vhost_md5;
85 + int rc;
86 modssl_ctx_t *mctx;
87 server_rec *server;
88
89 @@ -585,6 +647,7 @@
90
91 APR_REGISTER_OPTIONAL_FN(ssl_proxy_enable);
92 APR_REGISTER_OPTIONAL_FN(ssl_engine_disable);
93 + APR_REGISTER_OPTIONAL_FN(modssl_register_alpn);
94
95 ap_register_auth_provider(p, AUTHZ_PROVIDER_GROUP, "ssl",
96 AUTHZ_PROVIDER_VERSION,
97 --- modules/ssl/mod_ssl.h
98 +++ modules/ssl/mod_ssl.h
99 @@ -63,5 +93,46 @@
100
101 APR_DECLARE_OPTIONAL_FN(int, ssl_engine_disable, (conn_rec *));
102
103 +/** The alpn_propose_proto callback allows other modules to propose
104 + * the name of the protocol that will be chosen during the
105 + * Application-Layer Protocol Negotiation (ALPN) portion of the SSL handshake.
106 + * The callback is given the connection and a list of NULL-terminated
107 + * protocol strings as supported by the client. If this client_protos is
108 + * non-empty, it must pick its preferred protocol from that list. Otherwise
109 + * it should add its supported protocols in order of precedence.
110 + * The callback should not yet modify the connection or install any filters
111 + * as its proposal(s) may be overridden by another callback or server
112 + * configuration.
113 + * It should return OK or, to prevent further processing of (other modules')
114 + * callbacks, return DONE.
115 + */
116 +typedef int (*ssl_alpn_propose_protos)(conn_rec *connection,
117 + apr_array_header_t *client_protos,
118 + apr_array_header_t *proposed_protos);
119 +
120 +/** The alpn_proto_negotiated callback allows other modules to discover
121 + * the name of the protocol that was chosen during the Application-Layer
122 + * Protocol Negotiation (ALPN) portion of the SSL handshake.
123 + * The callback is given the connection, a
124 + * non-NUL-terminated string containing the protocol name, and the
125 + * length of the string; it should do something appropriate
126 + * (i.e. insert or remove filters) and return OK. To prevent further
127 + * processing of (other modules') callbacks, return DONE. */
128 +typedef int (*ssl_alpn_proto_negotiated)(conn_rec *connection,
129 + const char *proto_name,
130 + apr_size_t proto_name_len);
131 +
132 +/* An optional function which can be used to register a pair of callbacks
133 + * for ALPN handling.
134 + * This optional function should be invoked from a pre_connection hook
135 + * which runs *after* mod_ssl.c's pre_connection hook. The function returns
136 + * OK if the callbacks are registered, or DECLINED otherwise (for example if
137 + * mod_ssl does not support ALPN).
138 + */
139 +APR_DECLARE_OPTIONAL_FN(int, modssl_register_alpn,
140 + (conn_rec *conn,
141 + ssl_alpn_propose_protos proposefn,
142 + ssl_alpn_proto_negotiated negotiatedfn));
143 +
144 #endif /* __MOD_SSL_H__ */
145 /** @} */
146 --- modules/ssl/ssl_engine_config.c
147 +++ modules/ssl/ssl_engine_config.c
148 @@ -159,6 +160,9 @@
149 SSL_CONF_CTX_set_flags(mctx->ssl_ctx_config, SSL_CONF_FLAG_CERTIFICATE);
150 mctx->ssl_ctx_param = apr_array_make(p, 5, sizeof(ssl_ctx_param_t));
151 #endif
152 +#ifdef HAVE_TLS_ALPN
153 + mctx->ssl_alpn_pref = apr_array_make(p, 5, sizeof(const char *));
154 +#endif
155 }
156
157 static void modssl_ctx_init_proxy(SSLSrvConfigRec *sc,
158 @@ -301,6 +307,9 @@
159 #ifdef HAVE_SSL_CONF_CMD
160 cfgMergeArray(ssl_ctx_param);
161 #endif
162 +#ifdef HAVE_TLS_ALPN
163 + cfgMergeArray(ssl_alpn_pref);
164 +#endif
165 }
166
167 static void modssl_ctx_cfg_merge_proxy(apr_pool_t *p,
168 @@ -1875,6 +1868,16 @@
169 }
170 #endif
171
172 +#ifdef HAVE_TLS_ALPN
173 +const char *ssl_cmd_SSLALPNPreference(cmd_parms *cmd, void *dcfg,
174 + const char *protocol)
175 +{
176 + SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
177 + APR_ARRAY_PUSH(sc->server->ssl_alpn_pref, const char *) = protocol;
178 + return NULL;
179 +}
180 +#endif
181 +
182 #ifdef HAVE_SRP
183
184 const char *ssl_cmd_SSLSRPVerifierFile(cmd_parms *cmd, void *dcfg,
185 --- modules/ssl/ssl_engine_init.c
186 +++ modules/ssl/ssl_engine_init.c
187 @@ -623,6 +646,11 @@
188 SSL_CTX_set_tmp_dh_callback(ctx, ssl_callback_TmpDH);
189
190 SSL_CTX_set_info_callback(ctx, ssl_callback_Info);
191 +
192 +#ifdef HAVE_TLS_ALPN
193 + SSL_CTX_set_alpn_select_cb(
194 + ctx, ssl_callback_alpn_select, NULL);
195 +#endif
196 }
197
198 static apr_status_t ssl_init_ctx_verify(server_rec *s,
199 --- modules/ssl/ssl_engine_io.c
200 +++ modules/ssl/ssl_engine_io.c
201 @@ -28,6 +28,7 @@
202 core keeps dumping.''
203 -- Unknown */
204 #include "ssl_private.h"
205 +#include "mod_ssl.h"
206 #include "apr_date.h"
207
208 /* _________________________________________________________________
209 @@ -297,6 +315,9 @@
210 apr_pool_t *pool;
211 char buffer[AP_IOBUFSIZE];
212 ssl_filter_ctx_t *filter_ctx;
213 +#ifdef HAVE_TLS_ALPN
214 + int alpn_finished; /* 1 if ALPN has finished, 0 otherwise */
215 +#endif
216 } bio_filter_in_ctx_t;
217
218 /*
219 @@ -1412,6 +1485,37 @@
220 APR_BRIGADE_INSERT_TAIL(bb, bucket);
221 }
222
223 +#ifdef HAVE_TLS_ALPN
224 + /* By this point, Application-Layer Protocol Negotiation (ALPN) should be
225 + * completed (if our version of OpenSSL supports it). If we haven't already,
226 + * find out which protocol was decided upon and inform other modules
227 + * by calling alpn_proto_negotiated_hook.
228 + */
229 + if (!inctx->alpn_finished) {
230 + SSLConnRec *sslconn = myConnConfig(f->c);
231 + const unsigned char *next_proto = NULL;
232 + unsigned next_proto_len = 0;
233 + int n;
234 +
235 + if (sslconn->alpn_negofns) {
236 + SSL_get0_alpn_selected(inctx->ssl, &next_proto, &next_proto_len);
237 + ap_log_cerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, f->c,
238 + APLOGNO(02836) "SSL negotiated protocol: '%s'",
239 + (next_proto && next_proto_len)?
240 + apr_pstrmemdup(f->c->pool, (const char *)next_proto,
241 + next_proto_len) : "(null)");
242 + for (n = 0; n < sslconn->alpn_negofns->nelts; n++) {
243 + ssl_alpn_proto_negotiated fn =
244 + APR_ARRAY_IDX(sslconn->alpn_negofns, n, ssl_alpn_proto_negotiated);
245 +
246 + if (fn(f->c, (const char *)next_proto, next_proto_len) == DONE)
247 + break;
248 + }
249 + }
250 + inctx->alpn_finished = 1;
251 + }
252 +#endif
253 +
254 return APR_SUCCESS;
255 }
256
257 @@ -1893,6 +1996,9 @@
258 inctx->block = APR_BLOCK_READ;
259 inctx->pool = c->pool;
260 inctx->filter_ctx = filter_ctx;
261 +#ifdef HAVE_TLS_ALPN
262 + inctx->alpn_finished = 0;
263 +#endif
264 }
265
266 /* The request_rec pointer is passed in here only to ensure that the
267 --- modules/ssl/ssl_engine_kernel.c
268 +++ modules/ssl/ssl_engine_kernel.c
269 @@ -29,6 +29,7 @@
270 time I was too famous.''
271 -- Unknown */
272 #include "ssl_private.h"
273 +#include "mod_ssl.h"
274 #include "util_md5.h"
275
276 static void ssl_configure_env(request_rec *r, SSLConnRec *sslconn);
277 @@ -2137,6 +2162,153 @@
278 }
279 #endif /* HAVE_TLS_SESSION_TICKETS */
280
281 +#ifdef HAVE_TLS_ALPN
282 +static int ssl_array_index(apr_array_header_t *array,
283 + const char *s)
284 +{
285 + int i;
286 + for (i = 0; i < array->nelts; i++) {
287 + const char *p = APR_ARRAY_IDX(array, i, const char*);
288 + if (!strcmp(p, s)) {
289 + return i;
290 + }
291 + }
292 + return -1;
293 +}
294 +
295 +/*
296 + * Compare two ALPN protocol proposal. Result is similar to strcmp():
297 + * 0 gives same precedence, >0 means proto1 is prefered.
298 + */
299 +static int ssl_cmp_alpn_protos(modssl_ctx_t *ctx,
300 + const char *proto1,
301 + const char *proto2)
302 +{
303 + /* TODO: we should have a mod_ssl configuration parameter. */
304 + if (ctx && ctx->ssl_alpn_pref) {
305 + int index1 = ssl_array_index(ctx->ssl_alpn_pref, proto1);
306 + int index2 = ssl_array_index(ctx->ssl_alpn_pref, proto2);
307 + if (index2 > index1) {
308 + return (index1 >= 0)? 1 : -1;
309 + }
310 + else if (index1 > index2) {
311 + return (index2 >= 0)? -1 : 1;
312 + }
313 + }
314 + /* both have the same index (mabye -1 or no pref configured) and we compare
315 + * the names so that spdy3 gets precedence over spdy2. That makes
316 + * the outcome at least deterministic. */
317 + return strcmp((const char *)proto1, (const char *)proto2);
318 +}
319 +
320 +/*
321 + * This callback function is executed when the TLS Application Layer
322 + * Protocol Negotiate Extension (ALPN, RFC 7301) is triggered by the client
323 + * hello, giving a list of desired protocol names (in descending preference)
324 + * to the server.
325 + * The callback has to select a protocol name or return an error if none of
326 + * the clients preferences is supported.
327 + * The selected protocol does not have to be on the client list, according
328 + * to RFC 7301, so no checks are performed.
329 + * The client protocol list is serialized as length byte followed by ascii
330 + * characters (not null-terminated), followed by the next protocol name.
331 + */
332 +int ssl_callback_alpn_select(SSL *ssl,
333 + const unsigned char **out, unsigned char *outlen,
334 + const unsigned char *in, unsigned int inlen, void *arg)
335 +{
336 + conn_rec *c = (conn_rec*)SSL_get_app_data(ssl);
337 + SSLConnRec *sslconn = myConnConfig(c);
338 + server_rec *s = mySrvFromConn(c);
339 + SSLSrvConfigRec *sc = mySrvConfig(s);
340 + modssl_ctx_t *mctx = myCtxConfig(sslconn, sc);
341 + const char *alpn_http1 = "http/1.1";
342 + apr_array_header_t *client_protos;
343 + apr_array_header_t *proposed_protos;
344 + int i;
345 + size_t len;
346 +
347 + /* If the connection object is not available,
348 + * then there's nothing for us to do. */
349 + if (c == NULL) {
350 + return SSL_TLSEXT_ERR_OK;
351 + }
352 +
353 + if (inlen == 0) {
354 + // someone tries to trick us?
355 + ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(02837)
356 + "ALPN client protocol list empty");
357 + return SSL_TLSEXT_ERR_ALERT_FATAL;
358 + }
359 +
360 + client_protos = apr_array_make(c->pool, 0, sizeof(char *));
361 + for (i = 0; i < inlen; /**/) {
362 + unsigned int plen = in[i++];
363 + if (plen + i > inlen) {
364 + // someone tries to trick us?
365 + ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(02838)
366 + "ALPN protocol identier too long");
367 + return SSL_TLSEXT_ERR_ALERT_FATAL;
368 + }
369 + APR_ARRAY_PUSH(client_protos, char*) =
370 + apr_pstrndup(c->pool, (const char *)in+i, plen);
371 + i += plen;
372 + }
373 +
374 + proposed_protos = apr_array_make(c->pool, client_protos->nelts+1,
375 + sizeof(char *));
376 +
377 + if (sslconn->alpn_proposefns != NULL) {
378 + /* Invoke our alpn_propos_proto hooks, giving other modules a chance to
379 + * propose protocol names for selection. We might have several such
380 + * hooks installed and if two make a proposal, we need to give
381 + * preference to one.
382 + */
383 + for (i = 0; i < sslconn->alpn_proposefns->nelts; i++) {
384 + ssl_alpn_propose_protos fn =
385 + APR_ARRAY_IDX(sslconn->alpn_proposefns, i,
386 + ssl_alpn_propose_protos);
387 +
388 + if (fn(c, client_protos, proposed_protos) == DONE)
389 + break;
390 + }
391 + }
392 +
393 + if (proposed_protos->nelts <= 0) {
394 + /* Regardless of installed hooks, the http/1.1 protocol is always
395 + * supported by us. Choose it if none other matches. */
396 + if (ssl_array_index(client_protos, alpn_http1) < 0) {
397 + ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(02839)
398 + "none of the client ALPN protocols are supported");
399 + return SSL_TLSEXT_ERR_ALERT_FATAL;
400 + }
401 + *out = (const unsigned char*)alpn_http1;
402 + *outlen = (unsigned char)strlen(alpn_http1);
403 + return SSL_TLSEXT_ERR_OK;
404 + }
405 +
406 + /* Now select the most preferred protocol from the proposals. */
407 + *out = APR_ARRAY_IDX(proposed_protos, 0, const unsigned char *);
408 + for (i = 1; i < proposed_protos->nelts; ++i) {
409 + const char *proto = APR_ARRAY_IDX(proposed_protos, i, const char*);
410 + /* Do we prefer it over existing candidate? */
411 + if (ssl_cmp_alpn_protos(mctx, (const char *)*out, proto) < 0) {
412 + *out = (const unsigned char*)proto;
413 + }
414 + }
415 +
416 + len = strlen((const char*)*out);
417 + if (len > 255) {
418 + ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(02840)
419 + "ALPN negotiated protocol name too long");
420 + return SSL_TLSEXT_ERR_ALERT_FATAL;
421 + }
422 + *outlen = (unsigned char)len;
423 +
424 + return SSL_TLSEXT_ERR_OK;
425 +}
426 +#endif
427 +
428 #ifdef HAVE_SRP
429
430 int ssl_callback_SRPServerParams(SSL *ssl, int *ad, void *arg)
431 --- modules/ssl/ssl_private.h
432 +++ modules/ssl/ssl_private.h
433 @@ -182,6 +182,11 @@
434 #include <openssl/srp.h>
435 #endif
436
437 +/* ALPN Protocol Negotiation */
438 +#if defined(TLSEXT_TYPE_application_layer_protocol_negotiation)
439 +#define HAVE_TLS_ALPN
440 +#endif
441 +
442 #endif /* !defined(OPENSSL_NO_TLSEXT) && defined(SSL_set_tlsext_host_name) */
443
444 /* mod_ssl headers */
445 @@ -443,6 +438,12 @@
446 * connection */
447 } reneg_state;
448
449 +#ifdef HAVE_TLS_ALPN
450 + /* Poor man's inter-module optional hooks for ALPN. */
451 + apr_array_header_t *alpn_proposefns; /* list of ssl_alpn_propose_protos callbacks */
452 + apr_array_header_t *alpn_negofns; /* list of ssl_alpn_proto_negotiated callbacks. */
453 +#endif
454 +
455 server_rec *server;
456 } SSLConnRec;
457
458 @@ -633,6 +633,10 @@
459 SSL_CONF_CTX *ssl_ctx_config; /* Configuration context */
460 apr_array_header_t *ssl_ctx_param; /* parameters to pass to SSL_CTX */
461 #endif
462 +
463 +#ifdef HAVE_TLS_ALPN
464 + apr_array_header_t *ssl_alpn_pref; /* protocol names in order of preference */
465 +#endif
466 } modssl_ctx_t;
467
468 struct SSLSrvConfigRec {
469 @@ -763,6 +763,10 @@
470 const char *ssl_cmd_SSLOpenSSLConfCmd(cmd_parms *cmd, void *dcfg, const char *arg1, const char *arg2);
471 #endif
472
473 +#ifdef HAVE_TLS_ALPN
474 +const char *ssl_cmd_SSLALPNPreference(cmd_parms *cmd, void *dcfg, const char *protocol);
475 +#endif
476 +
477 #ifdef HAVE_SRP
478 const char *ssl_cmd_SSLSRPVerifierFile(cmd_parms *cmd, void *dcfg, const char *arg);
479 const char *ssl_cmd_SSLSRPUnknownUserSeed(cmd_parms *cmd, void *dcfg, const char *arg);
480 @@ -815,6 +815,12 @@
481 EVP_CIPHER_CTX *, HMAC_CTX *, int);
482 #endif
483
484 +#ifdef HAVE_TLS_ALPN
485 +int ssl_callback_alpn_select(SSL *ssl, const unsigned char **out,
486 + unsigned char *outlen, const unsigned char *in,
487 + unsigned int inlen, void *arg);
488 +#endif
489 +
490 /** Session Cache Support */
491 apr_status_t ssl_scache_init(server_rec *, apr_pool_t *);
492 void ssl_scache_status_register(apr_pool_t *p);