Hello, I rebased my previous patch set against master. It's mostly unchanged, except for the last patch that needed updating.
Cheers
From b874ecb5653d2d16a99460849900f3a276e7a0de Mon Sep 17 00:00:00 2001 From: Alessandro Ghedini <[email protected]> Date: Mon, 16 Feb 2015 16:47:56 +0100 Subject: [PATCH 1/5] openssl: make it possible to enable ALPN/NPN without HTTP2 --- lib/vtls/openssl.c | 106 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 61 insertions(+), 45 deletions(-) diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index 731ecc5..9544e34 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -1591,8 +1591,6 @@ static void ssl_tls_trace(int direction, int ssl_ver, int content_type, # define use_sni(x) Curl_nop_stmt #endif -#ifdef USE_NGHTTP2 - /* Check for OpenSSL 1.0.2 which has ALPN support. */ #undef HAS_ALPN #if OPENSSL_VERSION_NUMBER >= 0x10002000L \ @@ -1614,6 +1612,23 @@ static void ssl_tls_trace(int direction, int ssl_ver, int content_type, * in is a list of lenght prefixed strings. this function has to select * the protocol we want to use from the list and write its string into out. */ + +static int +select_next_protocol(unsigned char **out, unsigned char *outlen, + const unsigned char *in, unsigned int inlen, + const char *key, unsigned int keylen) +{ + unsigned int i; + for(i = 0; i + keylen <= inlen; i += in[i] + 1) { + if(memcmp(&in[i + 1], key, keylen) == 0) { + *out = (unsigned char *) &in[i + 1]; + *outlen = in[i]; + return 0; + } + } + return -1; +} + static int select_next_proto_cb(SSL *ssl, unsigned char **out, unsigned char *outlen, @@ -1621,33 +1636,36 @@ select_next_proto_cb(SSL *ssl, void *arg) { struct connectdata *conn = (struct connectdata*) arg; - int retval = nghttp2_select_next_protocol(out, outlen, in, inlen); (void)ssl; - if(retval == 1) { +#ifdef USE_NGHTTP2 + if(conn->data->set.httpversion == CURL_HTTP_VERSION_2_0 && + !select_next_protocol(out, outlen, in, inlen, NGHTTP2_PROTO_VERSION_ID, + NGHTTP2_PROTO_VERSION_ID_LEN)) { infof(conn->data, "NPN, negotiated HTTP2 (%s)\n", NGHTTP2_PROTO_VERSION_ID); conn->negnpn = NPN_HTTP2; + return SSL_TLSEXT_ERR_OK; } - else if(retval == 0) { +#endif + + if(!select_next_protocol(out, outlen, in, inlen, ALPN_HTTP_1_1, + ALPN_HTTP_1_1_LENGTH)) { infof(conn->data, "NPN, negotiated HTTP1.1\n"); conn->negnpn = NPN_HTTP1_1; - } - else { - infof(conn->data, "NPN, no overlap, use HTTP1.1\n", - NGHTTP2_PROTO_VERSION_ID); - *out = (unsigned char*)"http/1.1"; - *outlen = sizeof("http/1.1") - 1; - conn->negnpn = NPN_HTTP1_1; + return SSL_TLSEXT_ERR_OK; } + infof(conn->data, "NPN, no overlap, use HTTP1.1\n"); + *out = ALPN_HTTP_1_1; + *outlen = ALPN_HTTP_1_1_LENGTH; + conn->negnpn = NPN_HTTP1_1; + return SSL_TLSEXT_ERR_OK; } #endif /* HAS_NPN */ -#endif /* USE_NGHTTP2 */ - static const char * get_ssl_version_txt(SSL *ssl) { @@ -1690,9 +1708,6 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) struct in_addr addr; #endif #endif -#ifdef HAS_ALPN - unsigned char protocols[128]; -#endif DEBUGASSERT(ssl_connect_1 == connssl->connecting_state); @@ -1888,36 +1903,36 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) SSL_CTX_set_options(connssl->ctx, ctx_options); -#ifdef USE_NGHTTP2 - if(data->set.httpversion == CURL_HTTP_VERSION_2_0) { #ifdef HAS_NPN - if(data->set.ssl_enable_npn) { - SSL_CTX_set_next_proto_select_cb(connssl->ctx, select_next_proto_cb, - conn); - } + if(data->set.ssl_enable_npn) + SSL_CTX_set_next_proto_select_cb(connssl->ctx, select_next_proto_cb, conn); #endif #ifdef HAS_ALPN - if(data->set.ssl_enable_alpn) { - protocols[0] = NGHTTP2_PROTO_VERSION_ID_LEN; - memcpy(&protocols[1], NGHTTP2_PROTO_VERSION_ID, - NGHTTP2_PROTO_VERSION_ID_LEN); + if(data->set.ssl_enable_alpn) { + int cur = 0; + unsigned char protocols[128]; - protocols[NGHTTP2_PROTO_VERSION_ID_LEN+1] = ALPN_HTTP_1_1_LENGTH; - memcpy(&protocols[NGHTTP2_PROTO_VERSION_ID_LEN+2], ALPN_HTTP_1_1, - ALPN_HTTP_1_1_LENGTH); - - /* expects length prefixed preference ordered list of protocols in wire - * format - */ - SSL_CTX_set_alpn_protos(connssl->ctx, protocols, - NGHTTP2_PROTO_VERSION_ID_LEN + ALPN_HTTP_1_1_LENGTH + 2); +#ifdef USE_NGHTTP2 + if(data->set.httpversion == CURL_HTTP_VERSION_2_0) { + protocols[cur++] = NGHTTP2_PROTO_VERSION_ID_LEN; - infof(data, "ALPN, offering %s, %s\n", NGHTTP2_PROTO_VERSION_ID, - ALPN_HTTP_1_1); - connssl->asked_for_h2 = TRUE; + memcpy(&protocols[cur], NGHTTP2_PROTO_VERSION_ID, + NGHTTP2_PROTO_VERSION_ID_LEN); + cur += NGHTTP2_PROTO_VERSION_ID_LEN; + infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID); } #endif + + protocols[cur++] = ALPN_HTTP_1_1_LENGTH; + memcpy(&protocols[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH); + cur += ALPN_HTTP_1_1_LENGTH; + infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1); + + /* expects length prefixed preference ordered list of protocols in wire + * format + */ + SSL_CTX_set_alpn_protos(connssl->ctx, protocols, cur); } #endif @@ -2207,18 +2222,19 @@ static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex) if(len != 0) { infof(data, "ALPN, server accepted to use %.*s\n", len, neg_protocol); +#ifdef USE_NGHTTP2 if(len == NGHTTP2_PROTO_VERSION_ID_LEN && - memcmp(NGHTTP2_PROTO_VERSION_ID, neg_protocol, len) == 0) { + !memcmp(NGHTTP2_PROTO_VERSION_ID, neg_protocol, len)) { conn->negnpn = NPN_HTTP2; } - else if(len == - ALPN_HTTP_1_1_LENGTH && memcmp(ALPN_HTTP_1_1, - neg_protocol, - ALPN_HTTP_1_1_LENGTH) == 0) { + else +#endif + if(len == ALPN_HTTP_1_1_LENGTH && + !memcmp(ALPN_HTTP_1_1, neg_protocol, ALPN_HTTP_1_1_LENGTH)) { conn->negnpn = NPN_HTTP1_1; } } - else if(connssl->asked_for_h2) + else infof(data, "ALPN, server did not agree to a protocol\n"); } #endif -- 2.1.4
From f1a868777e285a73c4c54fe6f431f5fc36eef700 Mon Sep 17 00:00:00 2001 From: Alessandro Ghedini <[email protected]> Date: Thu, 19 Feb 2015 16:22:07 +0100 Subject: [PATCH 2/5] gtls: make it possible to enable ALPN/NPN without HTTP2 --- lib/vtls/gtls.c | 56 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/lib/vtls/gtls.c b/lib/vtls/gtls.c index be14dcf..232e573 100644 --- a/lib/vtls/gtls.c +++ b/lib/vtls/gtls.c @@ -90,11 +90,8 @@ static bool gtls_inited = FALSE; # define GNUTLS_MAPS_WINSOCK_ERRORS 1 # endif -# ifdef USE_NGHTTP2 -# undef HAS_ALPN -# if (GNUTLS_VERSION_NUMBER >= 0x030200) -# define HAS_ALPN -# endif +# if (GNUTLS_VERSION_NUMBER >= 0x030200) +# define HAS_ALPN # endif # if (GNUTLS_VERSION_NUMBER >= 0x03020d) @@ -398,10 +395,6 @@ gtls_connect_step1(struct connectdata *conn, const char* prioritylist; const char *err = NULL; #endif -#ifdef HAS_ALPN - int protocols_size = 2; - gnutls_datum_t protocols[2]; -#endif if(conn->ssl[sockindex].state == ssl_connection_complete) /* to make us tolerant against being called more than once for the @@ -615,20 +608,25 @@ gtls_connect_step1(struct connectdata *conn, #endif #ifdef HAS_ALPN - if(data->set.httpversion == CURL_HTTP_VERSION_2_0) { - if(data->set.ssl_enable_alpn) { - protocols[0].data = NGHTTP2_PROTO_VERSION_ID; - protocols[0].size = NGHTTP2_PROTO_VERSION_ID_LEN; - protocols[1].data = ALPN_HTTP_1_1; - protocols[1].size = ALPN_HTTP_1_1_LENGTH; - gnutls_alpn_set_protocols(session, protocols, protocols_size, 0); - infof(data, "ALPN, offering %s, %s\n", NGHTTP2_PROTO_VERSION_ID, - ALPN_HTTP_1_1); - conn->ssl[sockindex].asked_for_h2 = TRUE; - } - else { - infof(data, "SSL, can't negotiate HTTP/2.0 without ALPN\n"); + if(data->set.ssl_enable_alpn) { + int cur = 0; + gnutls_datum_t protocols[2]; + +#ifdef USE_NGHTTP2 + if(data->set.httpversion == CURL_HTTP_VERSION_2_0) { + protocols[cur].data = NGHTTP2_PROTO_VERSION_ID; + protocols[cur].size = NGHTTP2_PROTO_VERSION_ID_LEN; + cur++; + infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID); } +#endif + + protocols[cur].data = ALPN_HTTP_1_1; + protocols[cur].size = ALPN_HTTP_1_1_LENGTH; + cur++; + infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1); + + gnutls_alpn_set_protocols(session, protocols, cur, 0); } #endif @@ -1071,19 +1069,21 @@ gtls_connect_step3(struct connectdata *conn, infof(data, "ALPN, server accepted to use %.*s\n", proto.size, proto.data); +#ifdef USE_NGHTTP2 if(proto.size == NGHTTP2_PROTO_VERSION_ID_LEN && - memcmp(NGHTTP2_PROTO_VERSION_ID, proto.data, - NGHTTP2_PROTO_VERSION_ID_LEN) == 0) { + !memcmp(NGHTTP2_PROTO_VERSION_ID, proto.data, + NGHTTP2_PROTO_VERSION_ID_LEN)) { conn->negnpn = NPN_HTTP2; } - else if(proto.size == ALPN_HTTP_1_1_LENGTH && memcmp(ALPN_HTTP_1_1, - proto.data, ALPN_HTTP_1_1_LENGTH) == 0) { + else +#endif + if(proto.size == ALPN_HTTP_1_1_LENGTH && + !memcmp(ALPN_HTTP_1_1, proto.data, ALPN_HTTP_1_1_LENGTH)) { conn->negnpn = NPN_HTTP1_1; } } - else if(conn->ssl[sockindex].asked_for_h2) { + else infof(data, "ALPN, server did not agree to a protocol\n"); - } } #endif -- 2.1.4
From 945b1b15c89de2694b3dd3ab297f6c32b1cf36a4 Mon Sep 17 00:00:00 2001 From: Alessandro Ghedini <[email protected]> Date: Mon, 16 Feb 2015 16:41:57 +0100 Subject: [PATCH 3/5] nss: make it possible to enable ALPN/NPN without HTTP2 --- lib/vtls/nss.c | 76 ++++++++++++++++++++++++---------------------------------- 1 file changed, 31 insertions(+), 45 deletions(-) diff --git a/lib/vtls/nss.c b/lib/vtls/nss.c index 24ffa59..86bdb54 100644 --- a/lib/vtls/nss.c +++ b/lib/vtls/nss.c @@ -683,14 +683,15 @@ static SECStatus nss_auth_cert_hook(void *arg, PRFileDesc *fd, PRBool checksig, */ static void HandshakeCallback(PRFileDesc *sock, void *arg) { -#ifdef USE_NGHTTP2 struct connectdata *conn = (struct connectdata*) arg; unsigned int buflenmax = 50; unsigned char buf[50]; unsigned int buflen; SSLNextProtoState state; +#ifdef USE_NGHTTP2 struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET]; +#endif if(!conn->data->set.ssl_enable_npn && !conn->data->set.ssl_enable_alpn) { return; @@ -701,8 +702,7 @@ static void HandshakeCallback(PRFileDesc *sock, void *arg) switch(state) { case SSL_NEXT_PROTO_NO_SUPPORT: case SSL_NEXT_PROTO_NO_OVERLAP: - if(connssl->asked_for_h2) - infof(conn->data, "TLS, neither ALPN nor NPN succeeded\n"); + infof(conn->data, "ALPN/NPN, server did not agree to a protocol\n"); return; #ifdef SSL_ENABLE_ALPN case SSL_NEXT_PROTO_SELECTED: @@ -714,19 +714,18 @@ static void HandshakeCallback(PRFileDesc *sock, void *arg) break; } +#ifdef USE_NGHTTP2 if(buflen == NGHTTP2_PROTO_VERSION_ID_LEN && !memcmp(NGHTTP2_PROTO_VERSION_ID, buf, NGHTTP2_PROTO_VERSION_ID_LEN)) { conn->negnpn = NPN_HTTP2; } - else if(buflen == ALPN_HTTP_1_1_LENGTH && - !memcmp(ALPN_HTTP_1_1, buf, ALPN_HTTP_1_1_LENGTH)) { + else +#endif + if(buflen == ALPN_HTTP_1_1_LENGTH && + !memcmp(ALPN_HTTP_1_1, buf, ALPN_HTTP_1_1_LENGTH)) { conn->negnpn = NPN_HTTP1_1; } } -#else - (void)sock; - (void)arg; -#endif } static void display_cert_info(struct SessionHandle *data, @@ -1456,16 +1455,6 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) SSL_LIBRARY_VERSION_TLS_1_0 /* max */ }; -#ifdef USE_NGHTTP2 -#if defined(SSL_ENABLE_NPN) || defined(SSL_ENABLE_ALPN) - unsigned int alpn_protos_len = NGHTTP2_PROTO_VERSION_ID_LEN + - ALPN_HTTP_1_1_LENGTH + 2; - unsigned char alpn_protos[NGHTTP2_PROTO_VERSION_ID_LEN + ALPN_HTTP_1_1_LENGTH - + 2]; - int cur = 0; -#endif -#endif - connssl->data = data; /* list of all NSS objects we need to destroy in Curl_nss_close() */ @@ -1653,43 +1642,40 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) } #endif -#ifdef USE_NGHTTP2 - if(data->set.httpversion == CURL_HTTP_VERSION_2_0) { #ifdef SSL_ENABLE_NPN - if(data->set.ssl_enable_npn) { - if(SSL_OptionSet(connssl->handle, SSL_ENABLE_NPN, PR_TRUE) != SECSuccess) - goto error; - } + if(data->set.ssl_enable_npn) { + if(SSL_OptionSet(connssl->handle, SSL_ENABLE_NPN, PR_TRUE) != SECSuccess) + goto error; + } #endif #ifdef SSL_ENABLE_ALPN - if(data->set.ssl_enable_alpn) { - if(SSL_OptionSet(connssl->handle, SSL_ENABLE_ALPN, PR_TRUE) - != SECSuccess) - goto error; - } + if(data->set.ssl_enable_alpn) { + if(SSL_OptionSet(connssl->handle, SSL_ENABLE_ALPN, PR_TRUE) + != SECSuccess) + goto error; + } #endif #if defined(SSL_ENABLE_NPN) || defined(SSL_ENABLE_ALPN) - if(data->set.ssl_enable_npn || data->set.ssl_enable_alpn) { - alpn_protos[cur] = NGHTTP2_PROTO_VERSION_ID_LEN; - cur++; - memcpy(&alpn_protos[cur], NGHTTP2_PROTO_VERSION_ID, + if(data->set.ssl_enable_npn || data->set.ssl_enable_alpn) { + int cur = 0; + unsigned char protocols[128]; + +#ifdef USE_NGHTTP2 + if(data->set.httpversion == CURL_HTTP_VERSION_2_0) { + protocols[cur++] = NGHTTP2_PROTO_VERSION_ID_LEN; + memcpy(&protocols[cur], NGHTTP2_PROTO_VERSION_ID, NGHTTP2_PROTO_VERSION_ID_LEN); cur += NGHTTP2_PROTO_VERSION_ID_LEN; - alpn_protos[cur] = ALPN_HTTP_1_1_LENGTH; - cur++; - memcpy(&alpn_protos[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH); - - if(SSL_SetNextProtoNego(connssl->handle, alpn_protos, alpn_protos_len) - != SECSuccess) - goto error; - connssl->asked_for_h2 = TRUE; - } - else { - infof(data, "SSL, can't negotiate HTTP/2.0 with neither NPN nor ALPN\n"); } #endif + protocols[cur++] = ALPN_HTTP_1_1_LENGTH; + memcpy(&protocols[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH); + cur += ALPN_HTTP_1_1_LENGTH; + + if(SSL_SetNextProtoNego(connssl->handle, protocols, cur) != SECSuccess) + goto error; } #endif -- 2.1.4
From 3749477ec53da933e43be03c78f843231ffe7511 Mon Sep 17 00:00:00 2001 From: Alessandro Ghedini <[email protected]> Date: Thu, 19 Feb 2015 19:41:48 +0100 Subject: [PATCH 4/5] polarssl: make it possible to enable ALPN/NPN without HTTP2 --- lib/vtls/polarssl.c | 46 ++++++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/lib/vtls/polarssl.c b/lib/vtls/polarssl.c index 2d46aae..b7f2f6c 100644 --- a/lib/vtls/polarssl.c +++ b/lib/vtls/polarssl.c @@ -118,11 +118,8 @@ static void polarssl_debug(void *context, int level, const char *line) #endif /* ALPN for http2? */ -#ifdef USE_NGHTTP2 -# undef HAS_ALPN -# ifdef POLARSSL_SSL_ALPN -# define HAS_ALPN -# endif +#ifdef POLARSSL_SSL_ALPN +# define HAS_ALPN #endif static Curl_recv polarssl_recv; @@ -357,16 +354,23 @@ polarssl_connect_step1(struct connectdata *conn, } #ifdef HAS_ALPN - if(data->set.httpversion == CURL_HTTP_VERSION_2_0) { - if(data->set.ssl_enable_alpn) { - static const char* protocols[] = { - NGHTTP2_PROTO_VERSION_ID, ALPN_HTTP_1_1, NULL - }; - ssl_set_alpn_protocols(&connssl->ssl, protocols); - infof(data, "ALPN, offering %s, %s\n", protocols[0], - protocols[1]); - connssl->asked_for_h2 = TRUE; + if(data->set.ssl_enable_alpn) { + static const char* protocols[3]; + int cur = 0; + +#ifdef USE_NGHTTP2 + if(data->set.httpversion == CURL_HTTP_VERSION_2_0) { + protocols[cur++] = NGHTTP2_PROTO_VERSION_ID; + infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID); } +#endif + + protocols[cur++] = ALPN_HTTP_1_1; + infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1); + + protocols[cur] = NULL; + + ssl_set_alpn_protocols(&connssl->ssl, protocols); } #endif @@ -388,10 +392,6 @@ polarssl_connect_step2(struct connectdata *conn, struct ssl_connect_data* connssl = &conn->ssl[sockindex]; char buffer[1024]; -#ifdef HAS_ALPN - const char* next_protocol; -#endif - char errorbuf[128]; errorbuf[0] = 0; @@ -461,22 +461,24 @@ polarssl_connect_step2(struct connectdata *conn, #ifdef HAS_ALPN if(data->set.ssl_enable_alpn) { - next_protocol = ssl_get_alpn_protocol(&connssl->ssl); + const char *next_protocol = ssl_get_alpn_protocol(&connssl->ssl); if(next_protocol != NULL) { infof(data, "ALPN, server accepted to use %s\n", next_protocol); +#ifdef USE_NGHTTP2 if(!strncmp(next_protocol, NGHTTP2_PROTO_VERSION_ID, NGHTTP2_PROTO_VERSION_ID_LEN)) { conn->negnpn = NPN_HTTP2; } - else if(!strncmp(next_protocol, ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH)) { + else +#endif + if(!strncmp(next_protocol, ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH)) { conn->negnpn = NPN_HTTP1_1; } } - else if(connssl->asked_for_h2) { + else infof(data, "ALPN, server did not agree to a protocol\n"); - } } #endif -- 2.1.4
From 251d4b308b404901237a53523d35029c485c4cb6 Mon Sep 17 00:00:00 2001 From: Alessandro Ghedini <[email protected]> Date: Wed, 25 Feb 2015 11:33:12 +0100 Subject: [PATCH 5/5] urldata: remove unused asked_for_h2 field --- lib/urldata.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/urldata.h b/lib/urldata.h index f444c0f..37081c1 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -262,9 +262,6 @@ struct ssl_connect_data { current state of the connection. */ bool use; ssl_connection_state state; -#ifdef USE_NGHTTP2 - bool asked_for_h2; -#endif #ifdef USE_OPENSSL /* these ones requires specific SSL-types */ SSL_CTX* ctx; -- 2.1.4
signature.asc
Description: Digital signature
------------------------------------------------------------------- List admin: http://cool.haxx.se/list/listinfo/curl-library Etiquette: http://curl.haxx.se/mail/etiquette.html
