diff options
author | Fabian Frank <fabian@pagefault.de> | 2014-02-02 18:33:28 -0800 |
---|---|---|
committer | Daniel Stenberg <daniel@haxx.se> | 2014-02-03 23:46:06 +0100 |
commit | 8b6654224ba5f7ab358f4ebdb8270c3d92fd61df (patch) | |
tree | 466033a325b0533090a28fec65001e89a4f1e9b3 | |
parent | c35d05aa62cbeed14629769293e3c30ec59fc728 (diff) |
openssl: add ALPN support
Add ALPN support when using OpenSSL. This will offer ALPN and NPN to the
server, who can respond with either one or none of the two. OpenSSL >=
1.0.2 is required, which means as of today obtaining a snapshot from
ftp://ftp.openssl.org/snapshot/.
See:
http://tools.ietf.org/html/draft-ietf-tls-applayerprotoneg-04
https://github.com/openssl/openssl/blob/ba168244a14bbd056e502d7daa04cae4aabe9d0d/ssl/ssl_lib.c#L1787
-rw-r--r-- | configure.ac | 4 | ||||
-rw-r--r-- | lib/vtls/openssl.c | 66 |
2 files changed, 68 insertions, 2 deletions
diff --git a/configure.ac b/configure.ac index 2bc86083f..dd309345d 100644 --- a/configure.ac +++ b/configure.ac @@ -1595,7 +1595,9 @@ if test "$curl_ssl_msg" = "$init_ssl_msg" && test X"$OPT_SSL" != Xno; then CRYPTO_cleanup_all_ex_data \ SSL_get_shutdown \ SSLv2_client_method \ - SSL_CTX_set_next_proto_select_cb ) + SSL_CTX_set_next_proto_select_cb \ + SSL_CTX_set_alpn_protos \ + SSL_CTX_set_alpn_select_cb ) dnl Make an attempt to detect if this is actually yassl's headers and dnl OpenSSL emulation layer. We still leave everything else believing diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index 264dcf7c6..063945922 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -1401,11 +1401,27 @@ static void ssl_tls_trace(int direction, int ssl_ver, int content_type, #ifdef USE_NGHTTP2 +#undef HAS_ALPN +#if defined(HAVE_SSL_CTX_SET_ALPN_PROTOS) && \ + defined(HAVE_SSL_CTX_SET_ALPN_SELECT_CB) +# define HAS_ALPN 1 +#endif + #if !defined(HAVE_SSL_CTX_SET_NEXT_PROTO_SELECT_CB) || \ defined(OPENSSL_NO_NEXTPROTONEG) -#error http2 builds require OpenSSL with NPN support +# if !defined(HAS_ALPN) +# error http2 builds require OpenSSL with NPN or ALPN support +# endif +#endif + + +/* see http://tools.ietf.org/html/draft-ietf-tls-applayerprotoneg-04 */ +#ifdef HAS_ALPN +#define ALPN_HTTP_1_1_LENGTH 8 +#define ALPN_HTTP_1_1 "http/1.0" #endif + /* * 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. @@ -1457,6 +1473,9 @@ ossl_connect_step1(struct connectdata *conn, struct in_addr addr; #endif #endif +#ifdef HAS_ALPN + unsigned char protocols[128]; +#endif DEBUGASSERT(ssl_connect_1 == connssl->connecting_state); @@ -1656,6 +1675,25 @@ ossl_connect_step1(struct connectdata *conn, #ifdef USE_NGHTTP2 SSL_CTX_set_next_proto_select_cb(connssl->ctx, select_next_proto_cb, conn); + +#ifdef HAS_ALPN + protocols[0] = NGHTTP2_PROTO_VERSION_ID_LEN; + memcpy(&protocols[1], NGHTTP2_PROTO_VERSION_ID, + NGHTTP2_PROTO_VERSION_ID_LEN); + + 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); + + infof(data, "ALPN, offering %s, %s\n", NGHTTP2_PROTO_VERSION_ID, + ALPN_HTTP_1_1); +#endif #endif if(data->set.str[STRING_CERT] || data->set.str[STRING_CERT_TYPE]) { @@ -1829,6 +1867,10 @@ ossl_connect_step2(struct connectdata *conn, int sockindex) struct SessionHandle *data = conn->data; int err; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; +#ifdef HAS_ALPN + char* neg_protocol; + int len = 0; +#endif DEBUGASSERT(ssl_connect_2 == connssl->connecting_state || ssl_connect_2_reading == connssl->connecting_state @@ -1925,6 +1967,28 @@ ossl_connect_step2(struct connectdata *conn, int sockindex) infof (data, "SSL connection using %s\n", SSL_get_cipher(connssl->handle)); +#ifdef HAS_ALPN + /* Sets data and len to negotiated protocol, len is 0 if no protocol was + * negotiated + */ + SSL_get0_alpn_selected(connssl->handle, &neg_protocol, &len); + if(len != 0) { + infof(data, "ALPN, server accepted to use %.*s\n", len, neg_protocol); + + if(len == NGHTTP2_PROTO_VERSION_ID_LEN && + memcmp(NGHTTP2_PROTO_VERSION_ID, neg_protocol, len) == 0) { + conn->negnpn = NPN_HTTP2_DRAFT09; + } + else if(len == ALPN_HTTP_1_1_LENGTH && memcmp(ALPN_HTTP_1_1, + neg_protocol, ALPN_HTTP_1_1_LENGTH) == 0) { + conn->negnpn = NPN_HTTP1_1; + } + } + else { + infof(data, "ALPN, server did not agree to a protocol\n"); + } +#endif + return CURLE_OK; } } |