From a43b22e05b726e7e080eda63f287f728392b7064 Mon Sep 17 00:00:00 2001 From: Jay Satiro Date: Mon, 28 Mar 2016 18:18:09 -0400 Subject: [PATCH] wolfssl: Add ALPN support --- configure.ac | 3 +- docs/HTTP2.md | 4 +- lib/vtls/cyassl.c | 104 +++++++++++++++++++++++++++++++++++-- projects/wolfssl_options.h | 3 ++ 4 files changed, 107 insertions(+), 7 deletions(-) diff --git a/configure.ac b/configure.ac index b208d4d11..b3ad5816f 100644 --- a/configure.ac +++ b/configure.ac @@ -2206,7 +2206,8 @@ if test "$curl_ssl_msg" = "$init_ssl_msg"; then dnl Recent WolfSSL versions build without SSLv3 by default dnl WolfSSL needs configure --enable-opensslextra to have *get_peer* AC_CHECK_FUNCS(wolfSSLv3_client_method \ - wolfSSL_get_peer_certificate) + wolfSSL_get_peer_certificate \ + wolfSSL_UseALPN) else dnl Cyassl needs configure --enable-opensslextra to have *get_peer* AC_CHECK_FUNCS(CyaSSL_get_peer_certificate) diff --git a/docs/HTTP2.md b/docs/HTTP2.md index 6f7ece431..331bcb0ae 100644 --- a/docs/HTTP2.md +++ b/docs/HTTP2.md @@ -7,7 +7,8 @@ HTTP/2 with curl Build prerequisites ------------------- - nghttp2 - - OpenSSL, NSS, GnutTLS, PolarSSL or SChannel with a new enough version + - OpenSSL, NSS, GnutTLS, PolarSSL, wolfSSL or SChannel with a new enough + version. [nghttp2](https://nghttp2.org/) ------------------------------- @@ -59,6 +60,7 @@ provide the necessary TLS features. Right now we support: - GnuTLS: ALPN - PolarSSL: ALPN - SChannel: ALPN + - wolfSSL: ALPN Multiplexing ------------ diff --git a/lib/vtls/cyassl.c b/lib/vtls/cyassl.c index f6b57af68..7fa853678 100644 --- a/lib/vtls/cyassl.c +++ b/lib/vtls/cyassl.c @@ -77,6 +77,41 @@ and that's a problem since options.h hasn't been included yet. */ #define CYASSL_MAX_ERROR_SZ 80 #endif +/* To determine what functions are available we rely on one or both of: + - the user's options.h generated by CyaSSL/wolfSSL + - the symbols detected by curl's configure + Since they are markedly different from one another, and one or the other may + not be available, we do some checking below to bring things in sync. */ + +/* HAVE_ALPN is wolfSSL's build time symbol for enabling ALPN in options.h. */ +#ifndef HAVE_ALPN +#ifdef HAVE_WOLFSSL_USEALPN +#define HAVE_ALPN +#endif +#endif + +/* WOLFSSL_ALLOW_SSLV3 is wolfSSL's build time symbol for enabling SSLv3 in + options.h, but is only seen in >= 3.6.6 since that's when they started + disabling SSLv3 by default. */ +#ifndef WOLFSSL_ALLOW_SSLV3 +#if (LIBCYASSL_VERSION_HEX < 0x03006006) || \ + defined(HAVE_WOLFSSLV3_CLIENT_METHOD) +#define WOLFSSL_ALLOW_SSLV3 +#endif +#endif + +/* KEEP_PEER_CERT is a product of the presence of build time symbol + OPENSSL_EXTRA without NO_CERTS, depending on the version. KEEP_PEER_CERT is + in wolfSSL's settings.h, and the latter two are build time symbols in + options.h. */ +#ifndef KEEP_PEER_CERT +#if defined(HAVE_CYASSL_GET_PEER_CERTIFICATE) || \ + defined(HAVE_WOLFSSL_GET_PEER_CERTIFICATE) || \ + (defined(OPENSSL_EXTRA) && !defined(NO_CERTS)) +#define KEEP_PEER_CERT +#endif +#endif + static Curl_recv cyassl_recv; static Curl_send cyassl_send; @@ -143,9 +178,7 @@ cyassl_connect_step1(struct connectdata *conn, use_sni(TRUE); break; case CURL_SSLVERSION_SSLv3: - /* before WolfSSL SSLv3 was enabled by default, and starting in WolfSSL - we check for its presence since it is built without it by default */ -#if !defined(WOLFSSL_VERSION) || defined(HAVE_WOLFSSLV3_CLIENT_METHOD) +#ifdef WOLFSSL_ALLOW_SSLV3 req_method = SSLv3_client_method(); use_sni(FALSE); #else @@ -309,6 +342,33 @@ cyassl_connect_step1(struct connectdata *conn, return CURLE_OUT_OF_MEMORY; } +#ifdef HAVE_ALPN + if(data->set.ssl_enable_alpn) { + char protocols[128]; + *protocols = '\0'; + + /* wolfSSL's ALPN protocol name list format is a comma separated string of + protocols in descending order of preference, eg: "h2,http/1.1" */ + +#ifdef USE_NGHTTP2 + if(data->set.httpversion >= CURL_HTTP_VERSION_2) { + strcpy(protocols + strlen(protocols), NGHTTP2_PROTO_VERSION_ID ","); + infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID); + } +#endif + + strcpy(protocols + strlen(protocols), ALPN_HTTP_1_1); + infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1); + + if(wolfSSL_UseALPN(conssl->handle, protocols, + (unsigned)strlen(protocols), + WOLFSSL_ALPN_CONTINUE_ON_MISMATCH) != SSL_SUCCESS) { + failf(data, "SSL: failed setting ALPN protocols"); + return CURLE_SSL_CONNECT_ERROR; + } + } +#endif /* HAVE_ALPN */ + /* Check if there's a cached ID we can/should use here! */ if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL)) { /* we got a session id, use it! */ @@ -413,8 +473,7 @@ cyassl_connect_step2(struct connectdata *conn, } if(data->set.str[STRING_SSL_PINNEDPUBLICKEY]) { -#if defined(HAVE_WOLFSSL_GET_PEER_CERTIFICATE) || \ - defined(HAVE_CYASSL_GET_PEER_CERTIFICATE) +#ifdef KEEP_PEER_CERT X509 *x509; const char *x509_der; int x509_der_len; @@ -457,6 +516,41 @@ cyassl_connect_step2(struct connectdata *conn, #endif } +#ifdef HAVE_ALPN + if(data->set.ssl_enable_alpn) { + int rc; + char *protocol = NULL; + unsigned short protocol_len = 0; + + rc = wolfSSL_ALPN_GetProtocol(conssl->handle, &protocol, &protocol_len); + + if(rc == SSL_SUCCESS) { + infof(data, "ALPN, server accepted to use %.*s\n", protocol_len, + protocol); + + if(protocol_len == ALPN_HTTP_1_1_LENGTH && + !memcmp(protocol, ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH)) + conn->negnpn = CURL_HTTP_VERSION_1_1; +#ifdef USE_NGHTTP2 + else if(data->set.httpversion >= CURL_HTTP_VERSION_2 && + protocol_len == NGHTTP2_PROTO_VERSION_ID_LEN && + !memcmp(protocol, NGHTTP2_PROTO_VERSION_ID, + NGHTTP2_PROTO_VERSION_ID_LEN)) + conn->negnpn = CURL_HTTP_VERSION_2; +#endif + else + infof(data, "ALPN, unrecognized protocol %.*s\n", protocol_len, + protocol); + } + else if(rc == SSL_ALPN_NOT_FOUND) + infof(data, "ALPN, server did not agree to a protocol\n"); + else { + failf(data, "ALPN, failure getting protocol, error %d", rc); + return CURLE_SSL_CONNECT_ERROR; + } + } +#endif /* HAVE_ALPN */ + conssl->connecting_state = ssl_connect_3; infof(data, "SSL connected\n"); diff --git a/projects/wolfssl_options.h b/projects/wolfssl_options.h index 61cc22593..40c34e5d7 100644 --- a/projects/wolfssl_options.h +++ b/projects/wolfssl_options.h @@ -19,6 +19,7 @@ These configure flags were used in MinGW to generate the options in this file: --enable-sessioncerts --enable-certgen --enable-testcert +--enable-alpn C_EXTRA_FLAGS="-DFP_MAX_BITS=16384 -DTFM_TIMING_RESISTANT" Two generated options HAVE_THREAD_LS and _POSIX_THREADS were removed since they @@ -129,6 +130,8 @@ extern "C" { #undef USE_FAST_MATH #define USE_FAST_MATH +#undef HAVE_ALPN +#define HAVE_ALPN #ifdef __cplusplus }