diff options
Diffstat (limited to 'Utilities/cmcurl/lib/vtls/cyassl.c')
-rw-r--r-- | Utilities/cmcurl/lib/vtls/cyassl.c | 203 |
1 files changed, 166 insertions, 37 deletions
diff --git a/Utilities/cmcurl/lib/vtls/cyassl.c b/Utilities/cmcurl/lib/vtls/cyassl.c index 3ded7f1..7994b3e 100644 --- a/Utilities/cmcurl/lib/vtls/cyassl.c +++ b/Utilities/cmcurl/lib/vtls/cyassl.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -33,7 +33,7 @@ #define WOLFSSL_OPTIONS_IGNORE_SYS /* CyaSSL's version.h, which should contain only the version, should come before all other CyaSSL includes and be immediately followed by build config -aka options.h. http://curl.haxx.se/mail/lib-2015-04/0069.html */ +aka options.h. https://curl.haxx.se/mail/lib-2015-04/0069.html */ #include <cyassl/version.h> #if defined(HAVE_CYASSL_OPTIONS_H) && (LIBCYASSL_VERSION_HEX > 0x03004008) #if defined(CYASSL_API) || defined(WOLFSSL_API) @@ -51,7 +51,6 @@ and that's a problem since options.h hasn't been included yet. */ #include "urldata.h" #include "sendf.h" #include "inet_pton.h" -#include "cyassl.h" #include "vtls.h" #include "parsedate.h" #include "connect.h" /* for the connect timeout */ @@ -69,6 +68,8 @@ and that's a problem since options.h hasn't been included yet. */ #include <cyassl/ctaocrypt/random.h> #include <cyassl/ctaocrypt/sha256.h> +#include "cyassl.h" + /* The last #include files should be: */ #include "curl_memory.h" #include "memdebug.h" @@ -77,6 +78,38 @@ 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 + +/* HAVE_SUPPORTED_CURVES is wolfSSL's build time symbol for enabling the ECC + supported curve extension in options.h. Note ECC is enabled separately. */ +#ifndef HAVE_SUPPORTED_CURVES +#if defined(HAVE_CYASSL_CTX_USESUPPORTEDCURVE) || \ + defined(HAVE_WOLFSSL_CTX_USESUPPORTEDCURVE) +#define HAVE_SUPPORTED_CURVES +#endif +#endif + static Curl_recv cyassl_recv; static Curl_send cyassl_send; @@ -101,10 +134,9 @@ cyassl_connect_step1(struct connectdata *conn, int sockindex) { char error_buffer[CYASSL_MAX_ERROR_SZ]; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ssl_connect_data* conssl = &conn->ssl[sockindex]; SSL_METHOD* req_method = NULL; - void* ssl_sessionid = NULL; curl_socket_t sockfd = conn->sock[sockindex]; #ifdef HAVE_SNI bool sni = FALSE; @@ -143,8 +175,13 @@ cyassl_connect_step1(struct connectdata *conn, use_sni(TRUE); break; case CURL_SSLVERSION_SSLv3: +#ifdef WOLFSSL_ALLOW_SSLV3 req_method = SSLv3_client_method(); use_sni(FALSE); +#else + failf(data, "No support for SSLv3"); + return CURLE_NOT_BUILT_IN; +#endif break; case CURL_SSLVERSION_SSLv2: failf(data, "CyaSSL does not support SSLv2"); @@ -273,6 +310,16 @@ cyassl_connect_step1(struct connectdata *conn, } #endif +#ifdef HAVE_SUPPORTED_CURVES + /* CyaSSL/wolfSSL does not send the supported ECC curves ext automatically: + https://github.com/wolfSSL/wolfssl/issues/366 + The supported curves below are those also supported by OpenSSL 1.0.2 and + in the same order. */ + CyaSSL_CTX_UseSupportedCurve(conssl->ctx, 0x17); /* secp256r1 */ + CyaSSL_CTX_UseSupportedCurve(conssl->ctx, 0x19); /* secp521r1 */ + CyaSSL_CTX_UseSupportedCurve(conssl->ctx, 0x18); /* secp384r1 */ +#endif + /* give application a chance to interfere with SSL set up. */ if(data->set.ssl.fsslctx) { CURLcode result = CURLE_OK; @@ -302,16 +349,51 @@ cyassl_connect_step1(struct connectdata *conn, return CURLE_OUT_OF_MEMORY; } - /* 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! */ - if(!SSL_set_session(conssl->handle, ssl_sessionid)) { - failf(data, "SSL: SSL_set_session failed: %s", - ERR_error_string(SSL_get_error(conssl->handle, 0), error_buffer)); +#ifdef HAVE_ALPN + if(conn->bits.tls_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; } - /* Informational message */ - infof (data, "SSL re-using session ID\n"); + } +#endif /* HAVE_ALPN */ + + /* Check if there's a cached ID we can/should use here! */ + if(conn->ssl_config.sessionid) { + void *ssl_sessionid = NULL; + + Curl_ssl_sessionid_lock(conn); + if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL)) { + /* we got a session id, use it! */ + if(!SSL_set_session(conssl->handle, ssl_sessionid)) { + Curl_ssl_sessionid_unlock(conn); + failf(data, "SSL: SSL_set_session failed: %s", + ERR_error_string(SSL_get_error(conssl->handle, 0), + error_buffer)); + return CURLE_SSL_CONNECT_ERROR; + } + /* Informational message */ + infof (data, "SSL re-using session ID\n"); + } + Curl_ssl_sessionid_unlock(conn); } /* pass the raw socket into the SSL layer */ @@ -330,7 +412,7 @@ cyassl_connect_step2(struct connectdata *conn, int sockindex) { int ret = -1; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ssl_connect_data* conssl = &conn->ssl[sockindex]; conn->recv[sockindex] = cyassl_recv; @@ -406,6 +488,7 @@ cyassl_connect_step2(struct connectdata *conn, } if(data->set.str[STRING_SSL_PINNEDPUBLICKEY]) { +#ifdef KEEP_PEER_CERT X509 *x509; const char *x509_der; int x509_der_len; @@ -434,14 +517,54 @@ cyassl_connect_step2(struct connectdata *conn, return CURLE_SSL_PINNEDPUBKEYNOTMATCH; } - result = Curl_pin_peer_pubkey(data->set.str[STRING_SSL_PINNEDPUBLICKEY], + result = Curl_pin_peer_pubkey(data, + data->set.str[STRING_SSL_PINNEDPUBLICKEY], (const unsigned char *)pubkey->header, (size_t)(pubkey->end - pubkey->header)); if(result) { failf(data, "SSL: public key does not match pinned public key!"); return result; } +#else + failf(data, "Library lacks pinning support built-in"); + return CURLE_NOT_BUILT_IN; +#endif + } + +#ifdef HAVE_ALPN + if(conn->bits.tls_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"); @@ -455,32 +578,38 @@ cyassl_connect_step3(struct connectdata *conn, int sockindex) { CURLcode result = CURLE_OK; - void *old_ssl_sessionid=NULL; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - bool incache; - SSL_SESSION *our_ssl_sessionid; DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); - our_ssl_sessionid = SSL_get_session(connssl->handle); + if(conn->ssl_config.sessionid) { + bool incache; + SSL_SESSION *our_ssl_sessionid; + void *old_ssl_sessionid = NULL; + + our_ssl_sessionid = SSL_get_session(connssl->handle); - incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL)); - if(incache) { - if(old_ssl_sessionid != our_ssl_sessionid) { - infof(data, "old SSL session ID is stale, removing\n"); - Curl_ssl_delsessionid(conn, old_ssl_sessionid); - incache = FALSE; + Curl_ssl_sessionid_lock(conn); + incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL)); + if(incache) { + if(old_ssl_sessionid != our_ssl_sessionid) { + infof(data, "old SSL session ID is stale, removing\n"); + Curl_ssl_delsessionid(conn, old_ssl_sessionid); + incache = FALSE; + } } - } - if(!incache) { - result = Curl_ssl_addsessionid(conn, our_ssl_sessionid, - 0 /* unknown size */); - if(result) { - failf(data, "failed to store ssl session"); - return result; + if(!incache) { + result = Curl_ssl_addsessionid(conn, our_ssl_sessionid, + 0 /* unknown size */); + if(result) { + Curl_ssl_sessionid_unlock(conn); + failf(data, "failed to store ssl session"); + return result; + } } + Curl_ssl_sessionid_unlock(conn); } connssl->connecting_state = ssl_connect_done; @@ -625,7 +754,7 @@ cyassl_connect_common(struct connectdata *conn, bool *done) { CURLcode result; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; curl_socket_t sockfd = conn->sock[sockindex]; long timeout_ms; @@ -756,7 +885,7 @@ Curl_cyassl_connect(struct connectdata *conn, return CURLE_OK; } -int Curl_cyassl_random(struct SessionHandle *data, +int Curl_cyassl_random(struct Curl_easy *data, unsigned char *entropy, size_t length) { @@ -779,7 +908,7 @@ void Curl_cyassl_sha256sum(const unsigned char *tmp, /* input */ Sha256 SHA256pw; (void)unused; InitSha256(&SHA256pw); - Sha256Update(&SHA256pw, tmp, tmplen); + Sha256Update(&SHA256pw, tmp, (word32)tmplen); Sha256Final(&SHA256pw, sha256sum); } |