diff options
author | Curl Upstream <curl-library@lists.haxx.se> | 2022-01-04 23:35:58 (GMT) |
---|---|---|
committer | Brad King <brad.king@kitware.com> | 2022-01-07 16:41:33 (GMT) |
commit | a1f6ec647cfab8d613897562f8ee5f81a8f6b68d (patch) | |
tree | 23868e745531ca352f4ae8df37dc242b8ed6f80e /lib/vtls | |
parent | a4ad12d8435cdd4ab7301d21215c40348c04c8ed (diff) | |
download | CMake-a1f6ec647cfab8d613897562f8ee5f81a8f6b68d.zip CMake-a1f6ec647cfab8d613897562f8ee5f81a8f6b68d.tar.gz CMake-a1f6ec647cfab8d613897562f8ee5f81a8f6b68d.tar.bz2 |
curl 2022-01-05 (801bd513)
Code extracted from:
https://github.com/curl/curl.git
at commit 801bd5138ce31aa0d906fa4e2eabfc599d74e793 (curl-7_81_0).
Diffstat (limited to 'lib/vtls')
-rw-r--r-- | lib/vtls/bearssl.c | 6 | ||||
-rw-r--r-- | lib/vtls/gtls.c | 79 | ||||
-rw-r--r-- | lib/vtls/gtls.h | 8 | ||||
-rw-r--r-- | lib/vtls/mbedtls.c | 60 | ||||
-rw-r--r-- | lib/vtls/mesalink.c | 93 | ||||
-rw-r--r-- | lib/vtls/nss.c | 107 | ||||
-rw-r--r-- | lib/vtls/openssl.c | 290 | ||||
-rw-r--r-- | lib/vtls/openssl.h | 8 | ||||
-rw-r--r-- | lib/vtls/rustls.c | 61 | ||||
-rw-r--r-- | lib/vtls/schannel.c | 447 | ||||
-rw-r--r-- | lib/vtls/schannel_verify.c | 5 | ||||
-rw-r--r-- | lib/vtls/sectransp.c | 32 | ||||
-rw-r--r-- | lib/vtls/vtls.c | 10 | ||||
-rw-r--r-- | lib/vtls/vtls.h | 3 | ||||
-rw-r--r-- | lib/vtls/wolfssl.c | 75 |
15 files changed, 741 insertions, 543 deletions
diff --git a/lib/vtls/bearssl.c b/lib/vtls/bearssl.c index e87649e..9b772d0 100644 --- a/lib/vtls/bearssl.c +++ b/lib/vtls/bearssl.c @@ -608,6 +608,7 @@ static CURLcode bearssl_connect_step3(struct Curl_easy *data, if(SSL_SET_OPTION(primary.sessionid)) { bool incache; + bool added = FALSE; void *oldsession; br_ssl_session_parameters *session; @@ -623,10 +624,11 @@ static CURLcode bearssl_connect_step3(struct Curl_easy *data, Curl_ssl_delsessionid(data, oldsession); ret = Curl_ssl_addsessionid(data, conn, SSL_IS_PROXY() ? TRUE : FALSE, - session, 0, sockindex); + session, 0, sockindex, &added); Curl_ssl_sessionid_unlock(data); - if(ret) { + if(!added) free(session); + if(ret) { return CURLE_OUT_OF_MEMORY; } } diff --git a/lib/vtls/gtls.c b/lib/vtls/gtls.c index 1b145d8..18864aa 100644 --- a/lib/vtls/gtls.c +++ b/lib/vtls/gtls.c @@ -404,6 +404,7 @@ gtls_connect_step1(struct Curl_easy *data, const char * const hostname = SSL_HOST_NAME(); long * const certverifyresult = &SSL_SET_OPTION_LVALUE(certverifyresult); const char *tls13support; + CURLcode result; if(connssl->state == ssl_connection_complete) /* to make us tolerant against being called more than once for the @@ -496,6 +497,7 @@ gtls_connect_step1(struct Curl_easy *data, /* use system ca certificate store as fallback */ if(SSL_CONN_CONFIG(verifypeer) && !(SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(CApath))) { + /* this ignores errors on purpose */ gnutls_certificate_set_x509_system_trust(backend->cred); } #endif @@ -557,31 +559,25 @@ gtls_connect_step1(struct Curl_easy *data, /* Ensure +SRP comes at the *end* of all relevant strings so that it can be * removed if a run-time error indicates that SRP is not supported by this * GnuTLS version */ - switch(SSL_CONN_CONFIG(version)) { - case CURL_SSLVERSION_TLSv1_3: - if(!tls13support) { - failf(data, "This GnuTLS installation does not support TLS 1.3"); - return CURLE_SSL_CONNECT_ERROR; - } - /* FALLTHROUGH */ - case CURL_SSLVERSION_DEFAULT: - case CURL_SSLVERSION_TLSv1: - case CURL_SSLVERSION_TLSv1_0: - case CURL_SSLVERSION_TLSv1_1: - case CURL_SSLVERSION_TLSv1_2: { - CURLcode result = set_ssl_version_min_max(data, &prioritylist, - tls13support); - if(result) - return result; - break; - } - case CURL_SSLVERSION_SSLv2: - case CURL_SSLVERSION_SSLv3: - default: - failf(data, "GnuTLS does not support SSLv2 or SSLv3"); + + if(SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv2 || + SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv3) { + failf(data, "GnuTLS does not support SSLv2 or SSLv3"); + return CURLE_SSL_CONNECT_ERROR; + } + + if(SSL_CONN_CONFIG(version) == CURL_SSLVERSION_TLSv1_3) { + if(!tls13support) { + failf(data, "This GnuTLS installation does not support TLS 1.3"); return CURLE_SSL_CONNECT_ERROR; + } } + /* At this point we know we have a supported TLS version, so set it */ + result = set_ssl_version_min_max(data, &prioritylist, tls13support); + if(result) + return result; + #ifdef HAVE_GNUTLS_SRP /* Only add SRP to the cipher list if SRP is requested. Otherwise * GnuTLS will disable TLS 1.3 support. */ @@ -636,7 +632,10 @@ gtls_connect_step1(struct Curl_easy *data, cur++; infof(data, "ALPN, offering %s", ALPN_HTTP_1_1); - gnutls_alpn_set_protocols(session, protocols, cur, 0); + if(gnutls_alpn_set_protocols(session, protocols, cur, 0)) { + failf(data, "failed setting ALPN"); + return CURLE_SSL_CONNECT_ERROR; + } } if(SSL_SET_OPTION(primary.clientcert)) { @@ -762,10 +761,10 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data, CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH; /* if a path wasn't specified, don't pin */ - if(NULL == pinnedpubkey) + if(!pinnedpubkey) return CURLE_OK; - if(NULL == cert) + if(!cert) return result; do { @@ -783,7 +782,7 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data, break; /* failed */ buff1 = malloc(len1); - if(NULL == buff1) + if(!buff1) break; /* failed */ len2 = len1; @@ -798,7 +797,7 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data, result = Curl_pin_peer_pubkey(data, pinnedpubkey, buff1, len1); } while(0); - if(NULL != key) + if(key) gnutls_pubkey_deinit(key); Curl_safefree(buff1); @@ -809,10 +808,11 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data, static Curl_recv gtls_recv; static Curl_send gtls_send; -static CURLcode -gtls_connect_step3(struct Curl_easy *data, - struct connectdata *conn, - int sockindex) +CURLcode +Curl_gtls_verifyserver(struct Curl_easy *data, + struct connectdata *conn, + gnutls_session_t session, + int sockindex) { unsigned int cert_list_size; const gnutls_datum_t *chainp; @@ -824,9 +824,6 @@ gtls_connect_step3(struct Curl_easy *data, size_t size; time_t certclock; const char *ptr; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - struct ssl_backend_data *backend = connssl->backend; - gnutls_session_t session = backend->session; int rc; gnutls_datum_t proto; CURLcode result = CURLE_OK; @@ -1270,8 +1267,6 @@ gtls_connect_step3(struct Curl_easy *data, } conn->ssl[sockindex].state = ssl_connection_complete; - conn->recv[sockindex] = gtls_recv; - conn->send[sockindex] = gtls_send; if(SSL_SET_OPTION(primary.sessionid)) { /* we always unconditionally get the session id here, as even if we @@ -1287,6 +1282,7 @@ gtls_connect_step3(struct Curl_easy *data, if(connect_sessionid) { bool incache; + bool added = FALSE; void *ssl_sessionid; /* extract session ID to the allocated buffer */ @@ -1306,10 +1302,11 @@ gtls_connect_step3(struct Curl_easy *data, result = Curl_ssl_addsessionid(data, conn, SSL_IS_PROXY() ? TRUE : FALSE, connect_sessionid, connect_idsize, - sockindex); + sockindex, &added); Curl_ssl_sessionid_unlock(data); - if(result) { + if(!added) free(connect_sessionid); + if(result) { result = CURLE_OUT_OF_MEMORY; } } @@ -1354,9 +1351,13 @@ gtls_connect_common(struct Curl_easy *data, /* Finish connecting once the handshake is done */ if(ssl_connect_1 == connssl->connecting_state) { - rc = gtls_connect_step3(data, conn, sockindex); + struct ssl_backend_data *backend = connssl->backend; + gnutls_session_t session = backend->session; + rc = Curl_gtls_verifyserver(data, conn, session, sockindex); if(rc) return rc; + conn->recv[sockindex] = gtls_recv; + conn->send[sockindex] = gtls_send; } *done = ssl_connect_1 == connssl->connecting_state; diff --git a/lib/vtls/gtls.h b/lib/vtls/gtls.h index 1a146a3..642d5f0 100644 --- a/lib/vtls/gtls.h +++ b/lib/vtls/gtls.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2021, 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 @@ -27,7 +27,11 @@ #ifdef USE_GNUTLS #include "urldata.h" - +#include <gnutls/gnutls.h> +CURLcode +Curl_gtls_verifyserver(struct Curl_easy *data, struct connectdata *conn, + gnutls_session_t session, + int sockindex); extern const struct Curl_ssl Curl_ssl_gnutls; #endif /* USE_GNUTLS */ diff --git a/lib/vtls/mbedtls.c b/lib/vtls/mbedtls.c index 780d13e..1d209b2 100644 --- a/lib/vtls/mbedtls.c +++ b/lib/vtls/mbedtls.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2012 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2012 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. * Copyright (C) 2010 - 2011, Hoi-Ho Chan, <hoiho.chan@gmail.com> * * This software is licensed as described in the file COPYING, which @@ -270,7 +270,10 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn, { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; struct ssl_backend_data *backend = connssl->backend; - const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile); + const struct curl_blob *ca_info_blob = SSL_CONN_CONFIG(ca_info_blob); + const char * const ssl_cafile = + /* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */ + (ca_info_blob ? NULL : SSL_CONN_CONFIG(CAfile)); const bool verifypeer = SSL_CONN_CONFIG(verifypeer); const char * const ssl_capath = SSL_CONN_CONFIG(CApath); char * const ssl_cert = SSL_SET_OPTION(primary.clientcert); @@ -316,16 +319,34 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn, /* Load the trusted CA */ mbedtls_x509_crt_init(&backend->cacert); - if(ssl_cafile) { + if(ca_info_blob && verifypeer) { + /* Unfortunately, mbedtls_x509_crt_parse() requires the data to be null + terminated even when provided the exact length, forcing us to waste + extra memory here. */ + unsigned char *newblob = malloc(ca_info_blob->len + 1); + if(!newblob) + return CURLE_OUT_OF_MEMORY; + memcpy(newblob, ca_info_blob->data, ca_info_blob->len); + newblob[ca_info_blob->len] = 0; /* null terminate */ + ret = mbedtls_x509_crt_parse(&backend->cacert, newblob, + ca_info_blob->len + 1); + free(newblob); + if(ret<0) { + mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); + failf(data, "Error importing ca cert blob - mbedTLS: (-0x%04X) %s", + -ret, errorbuf); + return ret; + } + } + + if(ssl_cafile && verifypeer) { ret = mbedtls_x509_crt_parse_file(&backend->cacert, ssl_cafile); if(ret<0) { mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); failf(data, "Error reading ca cert file %s - mbedTLS: (-0x%04X) %s", ssl_cafile, -ret, errorbuf); - - if(verifypeer) - return CURLE_SSL_CACERT_BADFILE; + return CURLE_SSL_CACERT_BADFILE; } } @@ -358,10 +379,17 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn, } if(ssl_cert_blob) { - const unsigned char *blob_data = - (const unsigned char *)ssl_cert_blob->data; - ret = mbedtls_x509_crt_parse(&backend->clicert, blob_data, + /* Unfortunately, mbedtls_x509_crt_parse() requires the data to be null + terminated even when provided the exact length, forcing us to waste + extra memory here. */ + unsigned char *newblob = malloc(ssl_cert_blob->len + 1); + if(!newblob) + return CURLE_OUT_OF_MEMORY; + memcpy(newblob, ssl_cert_blob->data, ssl_cert_blob->len); + newblob[ssl_cert_blob->len] = 0; /* null terminate */ + ret = mbedtls_x509_crt_parse(&backend->clicert, newblob, ssl_cert_blob->len); + free(newblob); if(ret) { mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); @@ -671,7 +699,7 @@ mbed_connect_step2(struct Curl_easy *data, struct connectdata *conn, mbedtls_x509_crt *p = NULL; unsigned char *pubkey = NULL; -#if MBEDTLS_VERSION_NUMBER >= 0x03000000 +#if MBEDTLS_VERSION_NUMBER == 0x03000000 if(!peercert || !peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(p) || !peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(len)) { #else @@ -698,7 +726,7 @@ mbed_connect_step2(struct Curl_easy *data, struct connectdata *conn, /* Make a copy of our const peercert because mbedtls_pk_write_pubkey_der needs a non-const key, for now. https://github.com/ARMmbed/mbedtls/issues/396 */ -#if MBEDTLS_VERSION_NUMBER >= 0x03000000 +#if MBEDTLS_VERSION_NUMBER == 0x03000000 if(mbedtls_x509_crt_parse_der(p, peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(p), peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(len))) { @@ -710,7 +738,7 @@ mbed_connect_step2(struct Curl_easy *data, struct connectdata *conn, goto pinnedpubkey_error; } -#if MBEDTLS_VERSION_NUMBER >= 0x03000000 +#if MBEDTLS_VERSION_NUMBER == 0x03000000 size = mbedtls_pk_write_pubkey_der(&p->MBEDTLS_PRIVATE(pk), pubkey, PUB_DER_MAX_BYTES); #else @@ -784,6 +812,7 @@ mbed_connect_step3(struct Curl_easy *data, struct connectdata *conn, mbedtls_ssl_session *our_ssl_sessionid; void *old_ssl_sessionid = NULL; bool isproxy = SSL_IS_PROXY() ? TRUE : FALSE; + bool added = FALSE; our_ssl_sessionid = malloc(sizeof(mbedtls_ssl_session)); if(!our_ssl_sessionid) @@ -807,11 +836,13 @@ mbed_connect_step3(struct Curl_easy *data, struct connectdata *conn, Curl_ssl_delsessionid(data, old_ssl_sessionid); retcode = Curl_ssl_addsessionid(data, conn, isproxy, our_ssl_sessionid, - 0, sockindex); + 0, sockindex, &added); Curl_ssl_sessionid_unlock(data); - if(retcode) { + if(!added) { mbedtls_ssl_session_free(our_ssl_sessionid); free(our_ssl_sessionid); + } + if(retcode) { failf(data, "failed to store ssl session"); return retcode; } @@ -1151,6 +1182,7 @@ const struct Curl_ssl Curl_ssl_mbedtls = { { CURLSSLBACKEND_MBEDTLS, "mbedtls" }, /* info */ SSLSUPP_CA_PATH | + SSLSUPP_CAINFO_BLOB | SSLSUPP_PINNEDPUBKEY | SSLSUPP_SSL_CTX, diff --git a/lib/vtls/mesalink.c b/lib/vtls/mesalink.c index 3db9184..35a9165 100644 --- a/lib/vtls/mesalink.c +++ b/lib/vtls/mesalink.c @@ -68,8 +68,6 @@ struct ssl_backend_data SSL *handle; }; -#define BACKEND connssl->backend - static Curl_recv mesalink_recv; static Curl_send mesalink_send; @@ -100,9 +98,9 @@ mesalink_connect_step1(struct Curl_easy *data, #endif const char * const hostname = SSL_HOST_NAME(); size_t hostname_len = strlen(hostname); - SSL_METHOD *req_method = NULL; curl_socket_t sockfd = conn->sock[sockindex]; + struct ssl_backend_data *backend = connssl->backend; if(connssl->state == ssl_connection_complete) return CURLE_OK; @@ -139,22 +137,22 @@ mesalink_connect_step1(struct Curl_easy *data, return CURLE_OUT_OF_MEMORY; } - if(BACKEND->ctx) - SSL_CTX_free(BACKEND->ctx); - BACKEND->ctx = SSL_CTX_new(req_method); + if(backend->ctx) + SSL_CTX_free(backend->ctx); + backend->ctx = SSL_CTX_new(req_method); - if(!BACKEND->ctx) { + if(!backend->ctx) { failf(data, "SSL: couldn't create a context!"); return CURLE_OUT_OF_MEMORY; } SSL_CTX_set_verify( - BACKEND->ctx, SSL_CONN_CONFIG(verifypeer) ? + backend->ctx, SSL_CONN_CONFIG(verifypeer) ? SSL_VERIFY_PEER : SSL_VERIFY_NONE, NULL); if(SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(CApath)) { - if(!SSL_CTX_load_verify_locations(BACKEND->ctx, SSL_CONN_CONFIG(CAfile), - SSL_CONN_CONFIG(CApath))) { + if(!SSL_CTX_load_verify_locations(backend->ctx, SSL_CONN_CONFIG(CAfile), + SSL_CONN_CONFIG(CApath))) { if(SSL_CONN_CONFIG(verifypeer)) { failf(data, "error setting certificate verify locations: " @@ -181,7 +179,7 @@ mesalink_connect_step1(struct Curl_easy *data, if(SSL_SET_OPTION(primary.clientcert) && SSL_SET_OPTION(key)) { int file_type = do_file_type(SSL_SET_OPTION(cert_type)); - if(SSL_CTX_use_certificate_chain_file(BACKEND->ctx, + if(SSL_CTX_use_certificate_chain_file(backend->ctx, SSL_SET_OPTION(primary.clientcert), file_type) != 1) { failf(data, "unable to use client certificate (no key or wrong pass" @@ -190,8 +188,8 @@ mesalink_connect_step1(struct Curl_easy *data, } file_type = do_file_type(SSL_SET_OPTION(key_type)); - if(SSL_CTX_use_PrivateKey_file(BACKEND->ctx, SSL_SET_OPTION(key), - file_type) != 1) { + if(SSL_CTX_use_PrivateKey_file(backend->ctx, SSL_SET_OPTION(key), + file_type) != 1) { failf(data, "unable to set private key"); return CURLE_SSL_CONNECT_ERROR; } @@ -204,7 +202,7 @@ mesalink_connect_step1(struct Curl_easy *data, ciphers = SSL_CONN_CONFIG(cipher_list); if(ciphers) { #ifdef MESALINK_HAVE_CIPHER - if(!SSL_CTX_set_cipher_list(BACKEND->ctx, ciphers)) { + if(!SSL_CTX_set_cipher_list(backend->ctx, ciphers)) { failf(data, "failed setting cipher list: %s", ciphers); return CURLE_SSL_CIPHER; } @@ -212,10 +210,10 @@ mesalink_connect_step1(struct Curl_easy *data, infof(data, "Cipher selection: %s", ciphers); } - if(BACKEND->handle) - SSL_free(BACKEND->handle); - BACKEND->handle = SSL_new(BACKEND->ctx); - if(!BACKEND->handle) { + if(backend->handle) + SSL_free(backend->handle); + backend->handle = SSL_new(backend->ctx); + if(!backend->handle) { failf(data, "SSL: couldn't create a context (handle)!"); return CURLE_OUT_OF_MEMORY; } @@ -227,7 +225,7 @@ mesalink_connect_step1(struct Curl_easy *data, #endif ) { /* hostname is not a valid IP address */ - if(SSL_set_tlsext_host_name(BACKEND->handle, hostname) != SSL_SUCCESS) { + if(SSL_set_tlsext_host_name(backend->handle, hostname) != SSL_SUCCESS) { failf(data, "WARNING: failed to configure server name indication (SNI) " "TLS extension\n"); @@ -244,7 +242,7 @@ mesalink_connect_step1(struct Curl_easy *data, || strncmp(hostname, "[::1]", 5) == 0 #endif ) { - SSL_set_tlsext_host_name(BACKEND->handle, "localhost"); + SSL_set_tlsext_host_name(backend->handle, "localhost"); } else #endif @@ -264,12 +262,12 @@ mesalink_connect_step1(struct Curl_easy *data, SSL_IS_PROXY() ? TRUE : FALSE, &ssl_sessionid, NULL, sockindex)) { /* we got a session id, use it! */ - if(!SSL_set_session(BACKEND->handle, ssl_sessionid)) { + if(!SSL_set_session(backend->handle, ssl_sessionid)) { Curl_ssl_sessionid_unlock(data); failf( data, "SSL: SSL_set_session failed: %s", - ERR_error_string(SSL_get_error(BACKEND->handle, 0), error_buffer)); + ERR_error_string(SSL_get_error(backend->handle, 0), error_buffer)); return CURLE_SSL_CONNECT_ERROR; } /* Informational message */ @@ -279,7 +277,7 @@ mesalink_connect_step1(struct Curl_easy *data, } #endif /* MESALINK_HAVE_SESSION */ - if(SSL_set_fd(BACKEND->handle, (int)sockfd) != SSL_SUCCESS) { + if(SSL_set_fd(backend->handle, (int)sockfd) != SSL_SUCCESS) { failf(data, "SSL: SSL_set_fd failed"); return CURLE_SSL_CONNECT_ERROR; } @@ -294,13 +292,14 @@ mesalink_connect_step2(struct Curl_easy *data, { int ret = -1; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; conn->recv[sockindex] = mesalink_recv; conn->send[sockindex] = mesalink_send; - ret = SSL_connect(BACKEND->handle); + ret = SSL_connect(backend->handle); if(ret != SSL_SUCCESS) { - int detail = SSL_get_error(BACKEND->handle, ret); + int detail = SSL_get_error(backend->handle, ret); if(SSL_ERROR_WANT_CONNECT == detail || SSL_ERROR_WANT_READ == detail) { connssl->connecting_state = ssl_connect_2_reading; @@ -327,8 +326,8 @@ mesalink_connect_step2(struct Curl_easy *data, connssl->connecting_state = ssl_connect_3; infof(data, "SSL connection using %s / %s", - SSL_get_version(BACKEND->handle), - SSL_get_cipher_name(BACKEND->handle)); + SSL_get_version(backend->handle), + SSL_get_cipher_name(backend->handle)); return CURLE_OK; } @@ -347,8 +346,9 @@ mesalink_connect_step3(struct connectdata *conn, int sockindex) SSL_SESSION *our_ssl_sessionid; void *old_ssl_sessionid = NULL; bool isproxy = SSL_IS_PROXY() ? TRUE : FALSE; + struct ssl_backend_data *backend = connssl->backend; - our_ssl_sessionid = SSL_get_session(BACKEND->handle); + our_ssl_sessionid = SSL_get_session(backend->handle); Curl_ssl_sessionid_lock(data); incache = @@ -365,7 +365,7 @@ mesalink_connect_step3(struct connectdata *conn, int sockindex) if(!incache) { result = Curl_ssl_addsessionid(data, conn, isproxy, our_ssl_sessionid, 0, - sockindex); + sockindex, NULL); if(result) { Curl_ssl_sessionid_unlock(data); failf(data, "failed to store ssl session"); @@ -387,12 +387,13 @@ mesalink_send(struct Curl_easy *data, int sockindex, const void *mem, { struct connectdata *conn = data->conn; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; char error_buffer[MESALINK_MAX_ERROR_SZ]; int memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len; - int rc = SSL_write(BACKEND->handle, mem, memlen); + int rc = SSL_write(backend->handle, mem, memlen); if(rc < 0) { - int err = SSL_get_error(BACKEND->handle, rc); + int err = SSL_get_error(backend->handle, rc); switch(err) { case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: @@ -415,17 +416,18 @@ static void mesalink_close(struct Curl_easy *data, struct connectdata *conn, int sockindex) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; (void) data; - if(BACKEND->handle) { - (void)SSL_shutdown(BACKEND->handle); - SSL_free(BACKEND->handle); - BACKEND->handle = NULL; + if(backend->handle) { + (void)SSL_shutdown(backend->handle); + SSL_free(backend->handle); + backend->handle = NULL; } - if(BACKEND->ctx) { - SSL_CTX_free(BACKEND->ctx); - BACKEND->ctx = NULL; + if(backend->ctx) { + SSL_CTX_free(backend->ctx); + backend->ctx = NULL; } } @@ -435,12 +437,13 @@ mesalink_recv(struct Curl_easy *data, int num, char *buf, size_t buffersize, { struct connectdata *conn = data->conn; struct ssl_connect_data *connssl = &conn->ssl[num]; + struct ssl_backend_data *backend = connssl->backend; char error_buffer[MESALINK_MAX_ERROR_SZ]; int buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize; - int nread = SSL_read(BACKEND->handle, buf, buffsize); + int nread = SSL_read(backend->handle, buf, buffsize); if(nread <= 0) { - int err = SSL_get_error(BACKEND->handle, nread); + int err = SSL_get_error(backend->handle, nread); switch(err) { case SSL_ERROR_ZERO_RETURN: /* no more data */ @@ -485,12 +488,13 @@ mesalink_shutdown(struct Curl_easy *data, { int retval = 0; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; (void) data; - if(BACKEND->handle) { - SSL_free(BACKEND->handle); - BACKEND->handle = NULL; + if(backend->handle) { + SSL_free(backend->handle); + backend->handle = NULL; } return retval; } @@ -636,8 +640,9 @@ static void * mesalink_get_internals(struct ssl_connect_data *connssl, CURLINFO info UNUSED_PARAM) { + struct ssl_backend_data *backend = connssl->backend; (void)info; - return BACKEND->handle; + return backend->handle; } const struct Curl_ssl Curl_ssl_mesalink = { diff --git a/lib/vtls/nss.c b/lib/vtls/nss.c index cf65789..2b44f05 100644 --- a/lib/vtls/nss.c +++ b/lib/vtls/nss.c @@ -304,13 +304,14 @@ static char *nss_sslver_to_name(PRUint16 nssver) } } -static SECStatus set_ciphers(struct Curl_easy *data, PRFileDesc * model, - char *cipher_list) +/* the longest cipher name this supports */ +#define MAX_CIPHER_LENGTH 128 + +static SECStatus set_ciphers(struct Curl_easy *data, PRFileDesc *model, + const char *cipher_list) { unsigned int i; - PRBool cipher_state[NUM_OF_CIPHERS]; - PRBool found; - char *cipher; + const char *cipher; /* use accessors to avoid dynamic linking issues after an update of NSS */ const PRUint16 num_implemented_ciphers = SSL_GetNumImplementedCiphers(); @@ -326,51 +327,52 @@ static SECStatus set_ciphers(struct Curl_easy *data, PRFileDesc * model, SSL_CipherPrefSet(model, implemented_ciphers[i], PR_FALSE); } - /* Set every entry in our list to false */ - for(i = 0; i < NUM_OF_CIPHERS; i++) { - cipher_state[i] = PR_FALSE; - } - cipher = cipher_list; - while(cipher_list && (cipher_list[0])) { + while(cipher && cipher[0]) { + const char *end; + char name[MAX_CIPHER_LENGTH + 1]; + size_t len; + bool found = FALSE; while((*cipher) && (ISSPACE(*cipher))) ++cipher; - cipher_list = strpbrk(cipher, ":, "); - if(cipher_list) { - *cipher_list++ = '\0'; - } - - found = PR_FALSE; - - for(i = 0; i<NUM_OF_CIPHERS; i++) { - if(strcasecompare(cipher, cipherlist[i].name)) { - cipher_state[i] = PR_TRUE; - found = PR_TRUE; - break; - } - } + end = strpbrk(cipher, ":, "); + if(end) + len = end - cipher; + else + len = strlen(cipher); - if(found == PR_FALSE) { - failf(data, "Unknown cipher in list: %s", cipher); + if(len > MAX_CIPHER_LENGTH) { + failf(data, "Bad cipher list"); return SECFailure; } - - if(cipher_list) { - cipher = cipher_list; + else if(len) { + memcpy(name, cipher, len); + name[len] = 0; + + for(i = 0; i<NUM_OF_CIPHERS; i++) { + if(strcasecompare(name, cipherlist[i].name)) { + /* Enable the selected cipher */ + if(SSL_CipherPrefSet(model, cipherlist[i].num, PR_TRUE) != + SECSuccess) { + failf(data, "cipher-suite not supported by NSS: %s", name); + return SECFailure; + } + found = TRUE; + break; + } + } } - } - - /* Finally actually enable the selected ciphers */ - for(i = 0; i<NUM_OF_CIPHERS; i++) { - if(!cipher_state[i]) - continue; - if(SSL_CipherPrefSet(model, cipherlist[i].num, PR_TRUE) != SECSuccess) { - failf(data, "cipher-suite not supported by NSS: %s", cipherlist[i].name); + if(!found && len) { + failf(data, "Unknown cipher: %s", name); return SECFailure; } + if(end) + cipher = ++end; + else + break; } return SECSuccess; @@ -782,7 +784,7 @@ static char *nss_get_password(PK11SlotInfo *slot, PRBool retry, void *arg) { (void)slot; /* unused */ - if(retry || NULL == arg) + if(retry || !arg) return NULL; else return (char *)PORT_Strdup((char *)arg); @@ -955,7 +957,7 @@ static void display_cert_info(struct Curl_easy *data, subject = CERT_NameToAscii(&cert->subject); issuer = CERT_NameToAscii(&cert->issuer); common_name = CERT_GetCommonName(&cert->subject); - infof(data, "subject: %s\n", subject); + infof(data, "subject: %s", subject); CERT_GetCertTimes(cert, ¬Before, ¬After); PR_ExplodeTime(notBefore, PR_GMTParameters, &printableTime); @@ -1168,7 +1170,7 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock, struct SECKEYPrivateKeyStr *key; PK11SlotInfo *slot = nss_find_slot_by_name(pem_slotname); - if(NULL == slot) { + if(!slot) { failf(data, "NSS: PK11 slot not found: %s", pem_slotname); return SECFailure; } @@ -1182,7 +1184,7 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock, cert = PK11_FindCertFromDERCertItem(slot, &cert_der, proto_win); SECITEM_FreeItem(&cert_der, PR_FALSE); - if(NULL == cert) { + if(!cert) { failf(data, "NSS: client certificate from file not found"); PK11_FreeSlot(slot); return SECFailure; @@ -1190,7 +1192,7 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock, key = PK11_FindPrivateKeyFromCert(slot, cert, NULL); PK11_FreeSlot(slot); - if(NULL == key) { + if(!key) { failf(data, "NSS: private key from file not found"); CERT_DestroyCertificate(cert); return SECFailure; @@ -1207,9 +1209,9 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock, /* use the default NSS hook */ if(SECSuccess != NSS_GetClientAuthData((void *)nickname, sock, caNames, pRetCert, pRetKey) - || NULL == *pRetCert) { + || !*pRetCert) { - if(NULL == nickname) + if(!nickname) failf(data, "NSS: client certificate not found (nickname not " "specified)"); else @@ -1220,7 +1222,7 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock, /* get certificate nickname if any */ nickname = (*pRetCert)->nickname; - if(NULL == nickname) + if(!nickname) nickname = "[unknown]"; if(!strncmp(nickname, pem_slotname, sizeof(pem_slotname) - 1U)) { @@ -1229,7 +1231,7 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock, return SECFailure; } - if(NULL == *pRetKey) { + if(!*pRetKey) { failf(data, "NSS: private key not found for certificate: %s", nickname); return SECFailure; } @@ -1344,7 +1346,7 @@ static CURLcode nss_init_core(struct Curl_easy *data, const char *cert_dir) PRErrorCode err; const char *err_name; - if(nss_context != NULL) + if(nss_context) return CURLE_OK; memset((void *) &initparams, '\0', sizeof(initparams)); @@ -1360,7 +1362,7 @@ static CURLcode nss_init_core(struct Curl_easy *data, const char *cert_dir) NSS_INIT_READONLY | NSS_INIT_PK11RELOAD); free(certpath); - if(nss_context != NULL) + if(nss_context) return CURLE_OK; err = PR_GetError(); @@ -1372,7 +1374,7 @@ static CURLcode nss_init_core(struct Curl_easy *data, const char *cert_dir) nss_context = NSS_InitContext("", "", "", "", &initparams, NSS_INIT_READONLY | NSS_INIT_NOCERTDB | NSS_INIT_NOMODDB | NSS_INIT_FORCEOPEN | NSS_INIT_NOROOTINIT | NSS_INIT_OPTIMIZESPACE | NSS_INIT_PK11RELOAD); - if(nss_context != NULL) + if(nss_context) return CURLE_OK; err = PR_GetError(); @@ -2250,10 +2252,11 @@ static CURLcode nss_connect_common(struct Curl_easy *data, case CURLE_OK: break; case CURLE_AGAIN: + /* CURLE_AGAIN in non-blocking mode is not an error */ if(!blocking) - /* CURLE_AGAIN in non-blocking mode is not an error */ return CURLE_OK; - /* FALLTHROUGH */ + else + return result; default: return result; } diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index 87f4b02..f836c63 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -171,6 +171,21 @@ #define OPENSSL_load_builtin_modules(x) #endif +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) +#define HAVE_EVP_PKEY_GET_PARAMS 1 +#else +#define SSL_get1_peer_certificate SSL_get_peer_certificate +#endif + +#ifdef HAVE_EVP_PKEY_GET_PARAMS +#include <openssl/core_names.h> +#define DECLARE_PKEY_PARAM_BIGNUM(name) BIGNUM *name = NULL +#define FREE_PKEY_PARAM_BIGNUM(name) BN_clear_free(name) +#else +#define DECLARE_PKEY_PARAM_BIGNUM(name) const BIGNUM *name +#define FREE_PKEY_PARAM_BIGNUM(name) +#endif + /* * Whether SSL_CTX_set_keylog_callback is available. * OpenSSL: supported since 1.1.1 https://github.com/openssl/openssl/pull/2287 @@ -227,6 +242,17 @@ #endif #endif +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) +#define HAVE_RANDOM_INIT_BY_DEFAULT 1 +#endif + +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && \ + !(defined(LIBRESSL_VERSION_NUMBER) && \ + LIBRESSL_VERSION_NUMBER < 0x2070100fL) && \ + !defined(OPENSSL_IS_BORINGSSL) +#define HAVE_OPENSSL_VERSION +#endif + struct ssl_backend_data { struct Curl_easy *logger; /* transfer handle to pass trace logs to, only using sockindex 0 */ @@ -435,18 +461,21 @@ static bool rand_enough(void) static CURLcode ossl_seed(struct Curl_easy *data) { - char fname[256]; - /* This might get called before it has been added to a multi handle */ if(data->multi && data->multi->ssl_seeded) return CURLE_OK; if(rand_enough()) { - /* OpenSSL 1.1.0+ will return here */ + /* OpenSSL 1.1.0+ should return here */ if(data->multi) data->multi->ssl_seeded = TRUE; return CURLE_OK; } +#ifdef HAVE_RANDOM_INIT_BY_DEFAULT + /* with OpenSSL 1.1.0+, a failed RAND_status is a showstopper */ + failf(data, "Insufficient randomness"); + return CURLE_SSL_CONNECT_ERROR; +#else #ifndef RANDOM_FILE /* if RANDOM_FILE isn't defined, we only perform this if an option tells @@ -507,19 +536,23 @@ static CURLcode ossl_seed(struct Curl_easy *data) RAND_add(randb, (int)len, (double)len/2); } while(!rand_enough()); - /* generates a default path for the random seed file */ - fname[0] = 0; /* blank it first */ - RAND_file_name(fname, sizeof(fname)); - if(fname[0]) { - /* we got a file name to try */ - RAND_load_file(fname, RAND_LOAD_LENGTH); - if(rand_enough()) - return CURLE_OK; + { + /* generates a default path for the random seed file */ + char fname[256]; + fname[0] = 0; /* blank it first */ + RAND_file_name(fname, sizeof(fname)); + if(fname[0]) { + /* we got a file name to try */ + RAND_load_file(fname, RAND_LOAD_LENGTH); + if(rand_enough()) + return CURLE_OK; + } } infof(data, "libcurl is now using a weak random seed!"); return (rand_enough() ? CURLE_OK : - CURLE_SSL_CONNECT_ERROR /* confusing error code */); + CURLE_SSL_CONNECT_ERROR /* confusing error code */); +#endif } #ifndef SSL_FILETYPE_ENGINE @@ -1088,7 +1121,8 @@ int cert_stuff(struct Curl_easy *data, EVP_PKEY_free(pktmp); } -#if !defined(OPENSSL_NO_RSA) && !defined(OPENSSL_IS_BORINGSSL) +#if !defined(OPENSSL_NO_RSA) && !defined(OPENSSL_IS_BORINGSSL) && \ + !defined(OPENSSL_NO_DEPRECATED_3_0) { /* If RSA is used, don't check the private key if its flags indicate * it doesn't support it. */ @@ -1401,6 +1435,12 @@ static void ossl_closeone(struct Curl_easy *data, if(backend->handle) { char buf[32]; set_logger(conn, data); + /* + * The conn->sock[0] socket is passed to openssl with SSL_set_fd(). Make + * sure the socket is not closed before calling OpenSSL functions that + * will use it. + */ + DEBUGASSERT(conn->sock[FIRSTSOCKET] != CURL_SOCKET_BAD); /* Maybe the server has already sent a close notify alert. Read it to avoid an RST on the TCP connection. */ @@ -1639,9 +1679,10 @@ static bool subj_alt_hostcheck(struct Curl_easy *data, hostname. In this case, the iPAddress subjectAltName must be present in the certificate and must exactly match the IP in the URI. + This function is now used from ngtcp2 (QUIC) as well. */ -static CURLcode verifyhost(struct Curl_easy *data, struct connectdata *conn, - X509 *server_cert) +CURLcode Curl_ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn, + X509 *server_cert) { bool matched = FALSE; int target = GEN_DNS; /* target type, GEN_DNS or GEN_IPADD */ @@ -1926,7 +1967,7 @@ static CURLcode verifystatus(struct Curl_easy *data, } /* Compute the certificate's ID */ - cert = SSL_get_peer_certificate(backend->handle); + cert = SSL_get1_peer_certificate(backend->handle); if(!cert) { failf(data, "Error getting peer certificate"); result = CURLE_SSL_INVALIDCERTSTATUS; @@ -2493,6 +2534,7 @@ static int ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid) if(SSL_SET_OPTION(primary.sessionid)) { bool incache; + bool added = FALSE; void *old_ssl_sessionid = NULL; Curl_ssl_sessionid_lock(data); @@ -2511,9 +2553,11 @@ static int ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid) if(!incache) { if(!Curl_ssl_addsessionid(data, conn, isproxy, ssl_sessionid, - 0 /* unknown size */, sockindex)) { - /* the session has been put into the session cache */ - res = 1; + 0 /* unknown size */, sockindex, &added)) { + if(added) { + /* the session has been put into the session cache */ + res = 1; + } } else failf(data, "failed to store ssl session"); @@ -2936,7 +2980,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data, NULL, cert_name, sizeof(cert_name))) { strcpy(cert_name, "Unknown"); } - infof(data, "SSL: Checking cert %s\"\n", cert_name); + infof(data, "SSL: Checking cert \"%s\"", cert_name); #endif encoded_cert = (const unsigned char *)pContext->pbCertEncoded; @@ -3052,60 +3096,36 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data, } } + if(verifypeer && !imported_native_ca && (ssl_cafile || ssl_capath)) { #if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3) /* OpenSSL 3.0.0 has deprecated SSL_CTX_load_verify_locations */ - { - if(ssl_cafile) { - if(!SSL_CTX_load_verify_file(backend->ctx, ssl_cafile)) { - if(verifypeer && !imported_native_ca) { - /* Fail if we insist on successfully verifying the server. */ - failf(data, "error setting certificate file: %s", ssl_cafile); - return CURLE_SSL_CACERT_BADFILE; - } - /* Continue with warning if certificate verification isn't required. */ - infof(data, "error setting certificate file, continuing anyway"); - } - infof(data, " CAfile: %s", ssl_cafile); + if(ssl_cafile && + !SSL_CTX_load_verify_file(backend->ctx, ssl_cafile)) { + /* Fail if we insist on successfully verifying the server. */ + failf(data, "error setting certificate file: %s", ssl_cafile); + return CURLE_SSL_CACERT_BADFILE; } - if(ssl_capath) { - if(!SSL_CTX_load_verify_dir(backend->ctx, ssl_capath)) { - if(verifypeer && !imported_native_ca) { - /* Fail if we insist on successfully verifying the server. */ - failf(data, "error setting certificate path: %s", ssl_capath); - return CURLE_SSL_CACERT_BADFILE; - } - /* Continue with warning if certificate verification isn't required. */ - infof(data, "error setting certificate path, continuing anyway"); - } - infof(data, " CApath: %s", ssl_capath); + if(ssl_capath && + !SSL_CTX_load_verify_dir(backend->ctx, ssl_capath)) { + /* Fail if we insist on successfully verifying the server. */ + failf(data, "error setting certificate path: %s", ssl_capath); + return CURLE_SSL_CACERT_BADFILE; } - } #else - if(ssl_cafile || ssl_capath) { - /* tell SSL where to find CA certificates that are used to verify - the server's certificate. */ + /* tell OpenSSL where to find CA certificates that are used to verify the + server's certificate. */ if(!SSL_CTX_load_verify_locations(backend->ctx, ssl_cafile, ssl_capath)) { - if(verifypeer && !imported_native_ca) { - /* Fail if we insist on successfully verifying the server. */ - failf(data, "error setting certificate verify locations:" - " CAfile: %s CApath: %s", - ssl_cafile ? ssl_cafile : "none", - ssl_capath ? ssl_capath : "none"); - return CURLE_SSL_CACERT_BADFILE; - } - /* Just continue with a warning if no strict certificate verification - is required. */ - infof(data, "error setting certificate verify locations," - " continuing anyway:"); - } - else { - /* Everything is fine. */ - infof(data, "successfully set certificate verify locations:"); + /* Fail if we insist on successfully verifying the server. */ + failf(data, "error setting certificate verify locations:" + " CAfile: %s CApath: %s", + ssl_cafile ? ssl_cafile : "none", + ssl_capath ? ssl_capath : "none"); + return CURLE_SSL_CACERT_BADFILE; } +#endif infof(data, " CAfile: %s", ssl_cafile ? ssl_cafile : "none"); infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none"); } -#endif #ifdef CURL_CA_FALLBACK if(verifypeer && @@ -3476,10 +3496,7 @@ static void pubkey_show(struct Curl_easy *data, int num, const char *type, const char *name, -#ifdef HAVE_OPAQUE_RSA_DSA_DH - const -#endif - BIGNUM *bn) + const BIGNUM *bn) { char *ptr; char namebuf[32]; @@ -3544,12 +3561,6 @@ typedef size_t numcert_t; typedef int numcert_t; #endif -#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3) -#define OSSL3_CONST const -#else -#define OSSL3_CONST -#endif - static CURLcode get_cert_chain(struct Curl_easy *data, struct ssl_connect_data *connssl) { @@ -3573,6 +3584,9 @@ static CURLcode get_cert_chain(struct Curl_easy *data, } mem = BIO_new(BIO_s_mem()); + if(!mem) { + return CURLE_OUT_OF_MEMORY; + } for(i = 0; i < (int)numcerts; i++) { ASN1_INTEGER *num; @@ -3657,92 +3671,115 @@ static CURLcode get_cert_chain(struct Curl_easy *data, switch(pktype) { case EVP_PKEY_RSA: { - OSSL3_CONST RSA *rsa; +#ifndef HAVE_EVP_PKEY_GET_PARAMS + RSA *rsa; #ifdef HAVE_OPAQUE_EVP_PKEY rsa = EVP_PKEY_get0_RSA(pubkey); #else rsa = pubkey->pkey.rsa; -#endif +#endif /* HAVE_OPAQUE_EVP_PKEY */ +#endif /* !HAVE_EVP_PKEY_GET_PARAMS */ -#ifdef HAVE_OPAQUE_RSA_DSA_DH { - const BIGNUM *n; - const BIGNUM *e; - +#ifdef HAVE_OPAQUE_RSA_DSA_DH + DECLARE_PKEY_PARAM_BIGNUM(n); + DECLARE_PKEY_PARAM_BIGNUM(e); +#ifdef HAVE_EVP_PKEY_GET_PARAMS + EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_RSA_N, &n); + EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_RSA_E, &e); +#else RSA_get0_key(rsa, &n, &e, NULL); +#endif /* HAVE_EVP_PKEY_GET_PARAMS */ BIO_printf(mem, "%d", BN_num_bits(n)); +#else + BIO_printf(mem, "%d", BN_num_bits(rsa->n)); +#endif /* HAVE_OPAQUE_RSA_DSA_DH */ push_certinfo("RSA Public Key", i); print_pubkey_BN(rsa, n, i); print_pubkey_BN(rsa, e, i); + FREE_PKEY_PARAM_BIGNUM(n); + FREE_PKEY_PARAM_BIGNUM(e); } -#else - BIO_printf(mem, "%d", BN_num_bits(rsa->n)); - push_certinfo("RSA Public Key", i); - print_pubkey_BN(rsa, n, i); - print_pubkey_BN(rsa, e, i); -#endif break; } case EVP_PKEY_DSA: { #ifndef OPENSSL_NO_DSA - OSSL3_CONST DSA *dsa; +#ifndef HAVE_EVP_PKEY_GET_PARAMS + DSA *dsa; #ifdef HAVE_OPAQUE_EVP_PKEY dsa = EVP_PKEY_get0_DSA(pubkey); #else dsa = pubkey->pkey.dsa; -#endif -#ifdef HAVE_OPAQUE_RSA_DSA_DH +#endif /* HAVE_OPAQUE_EVP_PKEY */ +#endif /* !HAVE_EVP_PKEY_GET_PARAMS */ { - const BIGNUM *p; - const BIGNUM *q; - const BIGNUM *g; - const BIGNUM *pub_key; - +#ifdef HAVE_OPAQUE_RSA_DSA_DH + DECLARE_PKEY_PARAM_BIGNUM(p); + DECLARE_PKEY_PARAM_BIGNUM(q); + DECLARE_PKEY_PARAM_BIGNUM(g); + DECLARE_PKEY_PARAM_BIGNUM(pub_key); +#ifdef HAVE_EVP_PKEY_GET_PARAMS + EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_FFC_P, &p); + EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_FFC_Q, &q); + EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_FFC_G, &g); + EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_PUB_KEY, &pub_key); +#else DSA_get0_pqg(dsa, &p, &q, &g); DSA_get0_key(dsa, &pub_key, NULL); - +#endif /* HAVE_EVP_PKEY_GET_PARAMS */ +#endif /* HAVE_OPAQUE_RSA_DSA_DH */ print_pubkey_BN(dsa, p, i); print_pubkey_BN(dsa, q, i); print_pubkey_BN(dsa, g, i); print_pubkey_BN(dsa, pub_key, i); + FREE_PKEY_PARAM_BIGNUM(p); + FREE_PKEY_PARAM_BIGNUM(q); + FREE_PKEY_PARAM_BIGNUM(g); + FREE_PKEY_PARAM_BIGNUM(pub_key); } -#else - print_pubkey_BN(dsa, p, i); - print_pubkey_BN(dsa, q, i); - print_pubkey_BN(dsa, g, i); - print_pubkey_BN(dsa, pub_key, i); -#endif #endif /* !OPENSSL_NO_DSA */ break; } case EVP_PKEY_DH: { - OSSL3_CONST DH *dh; +#ifndef HAVE_EVP_PKEY_GET_PARAMS + DH *dh; #ifdef HAVE_OPAQUE_EVP_PKEY dh = EVP_PKEY_get0_DH(pubkey); #else dh = pubkey->pkey.dh; -#endif -#ifdef HAVE_OPAQUE_RSA_DSA_DH +#endif /* HAVE_OPAQUE_EVP_PKEY */ +#endif /* !HAVE_EVP_PKEY_GET_PARAMS */ { - const BIGNUM *p; - const BIGNUM *q; - const BIGNUM *g; - const BIGNUM *pub_key; +#ifdef HAVE_OPAQUE_RSA_DSA_DH + DECLARE_PKEY_PARAM_BIGNUM(p); + DECLARE_PKEY_PARAM_BIGNUM(q); + DECLARE_PKEY_PARAM_BIGNUM(g); + DECLARE_PKEY_PARAM_BIGNUM(pub_key); +#ifdef HAVE_EVP_PKEY_GET_PARAMS + EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_FFC_P, &p); + EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_FFC_Q, &q); + EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_FFC_G, &g); + EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_PUB_KEY, &pub_key); +#else DH_get0_pqg(dh, &p, &q, &g); DH_get0_key(dh, &pub_key, NULL); +#endif /* HAVE_EVP_PKEY_GET_PARAMS */ print_pubkey_BN(dh, p, i); print_pubkey_BN(dh, q, i); print_pubkey_BN(dh, g, i); +#else + print_pubkey_BN(dh, p, i); + print_pubkey_BN(dh, g, i); +#endif /* HAVE_OPAQUE_RSA_DSA_DH */ print_pubkey_BN(dh, pub_key, i); + FREE_PKEY_PARAM_BIGNUM(p); + FREE_PKEY_PARAM_BIGNUM(q); + FREE_PKEY_PARAM_BIGNUM(g); + FREE_PKEY_PARAM_BIGNUM(pub_key); } -#else - print_pubkey_BN(dh, p, i); - print_pubkey_BN(dh, g, i); - print_pubkey_BN(dh, pub_key, i); -#endif break; } } @@ -3846,11 +3883,20 @@ static CURLcode servercert(struct Curl_easy *data, BIO *mem = BIO_new(BIO_s_mem()); struct ssl_backend_data *backend = connssl->backend; + if(!mem) { + failf(data, + "BIO_new return NULL, " OSSL_PACKAGE + " error %s", + ossl_strerror(ERR_get_error(), error_buffer, + sizeof(error_buffer)) ); + return CURLE_OUT_OF_MEMORY; + } + if(data->set.ssl.certinfo) /* we've been asked to gather certificate info! */ (void)get_cert_chain(data, connssl); - backend->server_cert = SSL_get_peer_certificate(backend->handle); + backend->server_cert = SSL_get1_peer_certificate(backend->handle); if(!backend->server_cert) { BIO_free(mem); if(!strict) @@ -3884,7 +3930,7 @@ static CURLcode servercert(struct Curl_easy *data, BIO_free(mem); if(SSL_CONN_CONFIG(verifyhost)) { - result = verifyhost(data, conn, backend->server_cert); + result = Curl_ossl_verifyhost(data, conn, backend->server_cert); if(result) { X509_free(backend->server_cert); backend->server_cert = NULL; @@ -4364,13 +4410,7 @@ static ssize_t ossl_recv(struct Curl_easy *data, /* transfer */ static size_t ossl_version(char *buffer, size_t size) { #ifdef LIBRESSL_VERSION_NUMBER -#if LIBRESSL_VERSION_NUMBER < 0x2070100fL - return msnprintf(buffer, size, "%s/%lx.%lx.%lx", - OSSL_PACKAGE, - (LIBRESSL_VERSION_NUMBER>>28)&0xf, - (LIBRESSL_VERSION_NUMBER>>20)&0xff, - (LIBRESSL_VERSION_NUMBER>>12)&0xff); -#else /* OpenSSL_version() first appeared in LibreSSL 2.7.1 */ +#ifdef HAVE_OPENSSL_VERSION char *p; int count; const char *ver = OpenSSL_version(OPENSSL_VERSION); @@ -4384,6 +4424,12 @@ static size_t ossl_version(char *buffer, size_t size) *p = '_'; } return count; +#else + return msnprintf(buffer, size, "%s/%lx.%lx.%lx", + OSSL_PACKAGE, + (LIBRESSL_VERSION_NUMBER>>28)&0xf, + (LIBRESSL_VERSION_NUMBER>>20)&0xff, + (LIBRESSL_VERSION_NUMBER>>12)&0xff); #endif #elif defined(OPENSSL_IS_BORINGSSL) return msnprintf(buffer, size, OSSL_PACKAGE); diff --git a/lib/vtls/openssl.h b/lib/vtls/openssl.h index 2f6e1b2..2805845 100644 --- a/lib/vtls/openssl.h +++ b/lib/vtls/openssl.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2021, 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 @@ -26,11 +26,15 @@ #ifdef USE_OPENSSL /* - * This header should only be needed to get included by vtls.c and openssl.c + * This header should only be needed to get included by vtls.c, openssl.c + * and ngtcp2.c */ +#include <openssl/x509v3.h> #include "urldata.h" +CURLcode Curl_ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn, + X509 *server_cert); extern const struct Curl_ssl Curl_ssl_openssl; #endif /* USE_OPENSSL */ diff --git a/lib/vtls/rustls.c b/lib/vtls/rustls.c index 2ac97ce..6dbb1ef 100644 --- a/lib/vtls/rustls.c +++ b/lib/vtls/rustls.c @@ -27,7 +27,7 @@ #include "curl_printf.h" #include <errno.h> -#include <crustls.h> +#include <rustls.h> #include "inet_pton.h" #include "urldata.h" @@ -138,11 +138,6 @@ cr_recv(struct Curl_easy *data, int sockindex, *err = CURLE_READ_ERROR; return -1; } - else if(tls_bytes_read == 0) { - failf(data, "connection closed without TLS close_notify alert"); - *err = CURLE_READ_ERROR; - return -1; - } infof(data, "cr_recv read %ld bytes from the network", tls_bytes_read); @@ -161,22 +156,21 @@ cr_recv(struct Curl_easy *data, int sockindex, (uint8_t *)plainbuf + plain_bytes_copied, plainlen - plain_bytes_copied, &n); - if(rresult == RUSTLS_RESULT_ALERT_CLOSE_NOTIFY) { - *err = CURLE_OK; - return 0; + if(rresult == RUSTLS_RESULT_PLAINTEXT_EMPTY) { + infof(data, "cr_recv got PLAINTEXT_EMPTY. will try again later."); + backend->data_pending = FALSE; + break; } else if(rresult != RUSTLS_RESULT_OK) { - failf(data, "error in rustls_connection_read"); + /* n always equals 0 in this case, don't need to check it */ + failf(data, "error in rustls_connection_read: %d", rresult); *err = CURLE_READ_ERROR; return -1; } else if(n == 0) { - /* rustls returns 0 from connection_read to mean "all currently - available data has been read." If we bring in more ciphertext with - read_tls, more plaintext will become available. So don't tell curl - this is an EOF. Instead, say "come back later." */ - infof(data, "cr_recv got 0 bytes of plaintext"); - backend->data_pending = FALSE; + /* n == 0 indicates clean EOF, but we may have read some other + plaintext bytes before we reached this. Break out of the loop + so we can figure out whether to return success or EOF. */ break; } else { @@ -185,15 +179,23 @@ cr_recv(struct Curl_easy *data, int sockindex, } } - /* If we wrote out 0 plaintext bytes, it might just mean we haven't yet - read a full TLS record. Return CURLE_AGAIN so curl doesn't treat this - as EOF. */ - if(plain_bytes_copied == 0) { + if(plain_bytes_copied) { + *err = CURLE_OK; + return plain_bytes_copied; + } + + /* If we wrote out 0 plaintext bytes, that means either we hit a clean EOF, + OR we got a RUSTLS_RESULT_PLAINTEXT_EMPTY. + If the latter, return CURLE_AGAIN so curl doesn't treat this as EOF. */ + if(!backend->data_pending) { *err = CURLE_AGAIN; return -1; } - return plain_bytes_copied; + /* Zero bytes read, and no RUSTLS_RESULT_PLAINTEXT_EMPTY, means the TCP + connection was cleanly closed (with a close_notify alert). */ + *err = CURLE_OK; + return 0; } /* @@ -309,10 +311,10 @@ cr_init_backend(struct Curl_easy *data, struct connectdata *conn, config_builder = rustls_client_config_builder_new(); #ifdef USE_HTTP2 infof(data, "offering ALPN for HTTP/1.1 and HTTP/2"); - rustls_client_config_builder_set_protocols(config_builder, alpn, 2); + rustls_client_config_builder_set_alpn_protocols(config_builder, alpn, 2); #else infof(data, "offering ALPN for HTTP/1.1 only"); - rustls_client_config_builder_set_protocols(config_builder, alpn, 1); + rustls_client_config_builder_set_alpn_protocols(config_builder, alpn, 1); #endif if(!verifypeer) { rustls_client_config_builder_dangerous_set_certificate_verifier( @@ -358,7 +360,7 @@ cr_set_negotiated_alpn(struct Curl_easy *data, struct connectdata *conn, size_t len = 0; rustls_connection_get_alpn_protocol(rconn, &protocol, &len); - if(NULL == protocol) { + if(!protocol) { infof(data, "ALPN, server did not agree to a protocol"); return; } @@ -414,9 +416,6 @@ cr_connect_nonblocking(struct Curl_easy *data, struct connectdata *conn, /* * Connection has been established according to rustls. Set send/recv * handlers, and update the state machine. - * This check has to come last because is_handshaking starts out false, - * then becomes true when we first write data, then becomes false again - * once the handshake is done. */ if(!rustls_connection_is_handshaking(rconn)) { infof(data, "Done handshaking"); @@ -543,6 +542,12 @@ cr_close(struct Curl_easy *data, struct connectdata *conn, } } +static size_t cr_version(char *buffer, size_t size) +{ + struct rustls_str ver = rustls_version(); + return msnprintf(buffer, size, "%.*s", (int)ver.len, ver.data); +} + const struct Curl_ssl Curl_ssl_rustls = { { CURLSSLBACKEND_RUSTLS, "rustls" }, SSLSUPP_TLS13_CIPHERSUITES, /* supports */ @@ -550,7 +555,7 @@ const struct Curl_ssl Curl_ssl_rustls = { Curl_none_init, /* init */ Curl_none_cleanup, /* cleanup */ - rustls_version, /* version */ + cr_version, /* version */ Curl_none_check_cxn, /* check_cxn */ Curl_none_shutdown, /* shutdown */ cr_data_pending, /* data_pending */ diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c index 722a937..0a8e606 100644 --- a/lib/vtls/schannel.c +++ b/lib/vtls/schannel.c @@ -147,8 +147,6 @@ #define ALG_CLASS_DHASH ALG_CLASS_HASH #endif -#define BACKEND connssl->backend - static Curl_recv schannel_recv; static Curl_send schannel_send; @@ -423,6 +421,7 @@ schannel_acquire_credential_handle(struct Curl_easy *data, PCCERT_CONTEXT client_certs[1] = { NULL }; SECURITY_STATUS sspi_status = SEC_E_OK; CURLcode result; + struct ssl_backend_data *backend = connssl->backend; /* setup Schannel API options */ memset(&schannel_cred, 0, sizeof(schannel_cred)); @@ -430,7 +429,7 @@ schannel_acquire_credential_handle(struct Curl_easy *data, if(conn->ssl_config.verifypeer) { #ifdef HAS_MANUAL_VERIFY_API - if(BACKEND->use_manual_cred_validation) + if(backend->use_manual_cred_validation) schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION; else #endif @@ -503,7 +502,7 @@ schannel_acquire_credential_handle(struct Curl_easy *data, if(SSL_CONN_CONFIG(cipher_list)) { result = set_ssl_ciphers(&schannel_cred, SSL_CONN_CONFIG(cipher_list), - BACKEND->algIds); + backend->algIds); if(CURLE_OK != result) { failf(data, "Unable to set ciphers to passed via SSL_CONN_CONFIG"); return result; @@ -600,7 +599,7 @@ schannel_acquire_credential_handle(struct Curl_easy *data, datablob.pbData = (BYTE*)certdata; datablob.cbData = (DWORD)certsize; - if(data->set.ssl.key_passwd != NULL) + if(data->set.ssl.key_passwd) pwd_len = strlen(data->set.ssl.key_passwd); pszPassword = (WCHAR*)malloc(sizeof(WCHAR)*(pwd_len + 1)); if(pszPassword) { @@ -704,9 +703,9 @@ schannel_acquire_credential_handle(struct Curl_easy *data, #endif /* allocate memory for the re-usable credential handle */ - BACKEND->cred = (struct Curl_schannel_cred *) + backend->cred = (struct Curl_schannel_cred *) calloc(1, sizeof(struct Curl_schannel_cred)); - if(!BACKEND->cred) { + if(!backend->cred) { failf(data, "schannel: unable to allocate memory"); if(client_certs[0]) @@ -714,16 +713,14 @@ schannel_acquire_credential_handle(struct Curl_easy *data, return CURLE_OUT_OF_MEMORY; } - BACKEND->cred->refcount = 1; + backend->cred->refcount = 1; - /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa374716.aspx - */ sspi_status = s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR *)UNISP_NAME, SECPKG_CRED_OUTBOUND, NULL, &schannel_cred, NULL, NULL, - &BACKEND->cred->cred_handle, - &BACKEND->cred->time_stamp); + &backend->cred->cred_handle, + &backend->cred->time_stamp); if(client_certs[0]) CertFreeCertificateContext(client_certs[0]); @@ -732,7 +729,7 @@ schannel_acquire_credential_handle(struct Curl_easy *data, char buffer[STRERROR_LEN]; failf(data, "schannel: AcquireCredentialsHandle failed: %s", Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer))); - Curl_safefree(BACKEND->cred); + Curl_safefree(backend->cred); switch(sspi_status) { case SEC_E_INSUFFICIENT_MEMORY: return CURLE_OUT_OF_MEMORY; @@ -771,12 +768,13 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn, TCHAR *host_name; CURLcode result; char * const hostname = SSL_HOST_NAME(); + struct ssl_backend_data *backend = connssl->backend; DEBUGF(infof(data, "schannel: SSL/TLS connection with %s port %hu (step 1/3)", hostname, conn->remote_port)); - if(curlx_verify_windows_version(5, 1, PLATFORM_WINNT, + if(curlx_verify_windows_version(5, 1, 0, PLATFORM_WINNT, VERSION_LESS_THAN_EQUAL)) { /* Schannel in Windows XP (OS version 5.1) uses legacy handshakes and algorithms that may not be supported by all servers. */ @@ -787,29 +785,29 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn, #ifdef HAS_ALPN /* ALPN is only supported on Windows 8.1 / Server 2012 R2 and above. Also it doesn't seem to be supported for Wine, see curl bug #983. */ - BACKEND->use_alpn = conn->bits.tls_enable_alpn && + backend->use_alpn = conn->bits.tls_enable_alpn && !GetProcAddress(GetModuleHandle(TEXT("ntdll")), "wine_get_version") && - curlx_verify_windows_version(6, 3, PLATFORM_WINNT, + curlx_verify_windows_version(6, 3, 0, PLATFORM_WINNT, VERSION_GREATER_THAN_EQUAL); #else - BACKEND->use_alpn = false; + backend->use_alpn = false; #endif #ifdef _WIN32_WCE #ifdef HAS_MANUAL_VERIFY_API /* certificate validation on CE doesn't seem to work right; we'll * do it following a more manual process. */ - BACKEND->use_manual_cred_validation = true; + backend->use_manual_cred_validation = true; #else #error "compiler too old to support requisite manual cert verify for Win CE" #endif #else #ifdef HAS_MANUAL_VERIFY_API if(SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(ca_info_blob)) { - if(curlx_verify_windows_version(6, 1, PLATFORM_WINNT, + if(curlx_verify_windows_version(6, 1, 0, PLATFORM_WINNT, VERSION_GREATER_THAN_EQUAL)) { - BACKEND->use_manual_cred_validation = true; + backend->use_manual_cred_validation = true; } else { failf(data, "schannel: this version of Windows is too old to support " @@ -818,7 +816,7 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn, } } else - BACKEND->use_manual_cred_validation = false; + backend->use_manual_cred_validation = false; #else if(SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(ca_info_blob)) { failf(data, "schannel: CA cert support not built in"); @@ -827,7 +825,7 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn, #endif #endif - BACKEND->cred = NULL; + backend->cred = NULL; /* check for an existing re-usable credential handle */ if(SSL_SET_OPTION(primary.sessionid)) { @@ -835,19 +833,19 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn, if(!Curl_ssl_getsessionid(data, conn, SSL_IS_PROXY() ? TRUE : FALSE, (void **)&old_cred, NULL, sockindex)) { - BACKEND->cred = old_cred; + backend->cred = old_cred; DEBUGF(infof(data, "schannel: re-using existing credential handle")); /* increment the reference counter of the credential/session handle */ - BACKEND->cred->refcount++; + backend->cred->refcount++; DEBUGF(infof(data, "schannel: incremented credential handle refcount = %d", - BACKEND->cred->refcount)); + backend->cred->refcount)); } Curl_ssl_sessionid_unlock(data); } - if(!BACKEND->cred) { + if(!backend->cred) { result = schannel_acquire_credential_handle(data, conn, sockindex); if(result != CURLE_OK) { return result; @@ -864,7 +862,7 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn, } #ifdef HAS_ALPN - if(BACKEND->use_alpn) { + if(backend->use_alpn) { int cur = 0; int list_start_index = 0; unsigned int *extension_len = NULL; @@ -922,18 +920,18 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn, InitSecBufferDesc(&outbuf_desc, &outbuf, 1); /* security request flags */ - BACKEND->req_flags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT | + backend->req_flags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT | ISC_REQ_CONFIDENTIALITY | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM; if(!SSL_SET_OPTION(auto_client_cert)) { - BACKEND->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS; + backend->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS; } /* allocate memory for the security context handle */ - BACKEND->ctxt = (struct Curl_schannel_ctxt *) + backend->ctxt = (struct Curl_schannel_ctxt *) calloc(1, sizeof(struct Curl_schannel_ctxt)); - if(!BACKEND->ctxt) { + if(!backend->ctxt) { failf(data, "schannel: unable to allocate memory"); return CURLE_OUT_OF_MEMORY; } @@ -950,16 +948,16 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn, us problems with inbuf regardless. https://github.com/curl/curl/issues/983 */ sspi_status = s_pSecFn->InitializeSecurityContext( - &BACKEND->cred->cred_handle, NULL, host_name, BACKEND->req_flags, 0, 0, - (BACKEND->use_alpn ? &inbuf_desc : NULL), - 0, &BACKEND->ctxt->ctxt_handle, - &outbuf_desc, &BACKEND->ret_flags, &BACKEND->ctxt->time_stamp); + &backend->cred->cred_handle, NULL, host_name, backend->req_flags, 0, 0, + (backend->use_alpn ? &inbuf_desc : NULL), + 0, &backend->ctxt->ctxt_handle, + &outbuf_desc, &backend->ret_flags, &backend->ctxt->time_stamp); curlx_unicodefree(host_name); if(sspi_status != SEC_I_CONTINUE_NEEDED) { char buffer[STRERROR_LEN]; - Curl_safefree(BACKEND->ctxt); + Curl_safefree(backend->ctxt); switch(sspi_status) { case SEC_E_INSUFFICIENT_MEMORY: failf(data, "schannel: initial InitializeSecurityContext failed: %s", @@ -1003,10 +1001,10 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn, DEBUGF(infof(data, "schannel: sent initial handshake data: " "sent %zd bytes", written)); - BACKEND->recv_unrecoverable_err = CURLE_OK; - BACKEND->recv_sspi_close_notify = false; - BACKEND->recv_connection_closed = false; - BACKEND->encdata_is_incomplete = false; + backend->recv_unrecoverable_err = CURLE_OK; + backend->recv_sspi_close_notify = false; + backend->recv_connection_closed = false; + backend->encdata_is_incomplete = false; /* continue to second handshake step */ connssl->connecting_state = ssl_connect_2; @@ -1031,6 +1029,7 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn, bool doread; char * const hostname = SSL_HOST_NAME(); const char *pubkey_ptr; + struct ssl_backend_data *backend = connssl->backend; doread = (connssl->connecting_state != ssl_connect_2_writing) ? TRUE : FALSE; @@ -1038,39 +1037,39 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn, "schannel: SSL/TLS connection with %s port %hu (step 2/3)", hostname, conn->remote_port)); - if(!BACKEND->cred || !BACKEND->ctxt) + if(!backend->cred || !backend->ctxt) return CURLE_SSL_CONNECT_ERROR; /* buffer to store previously received and decrypted data */ - if(!BACKEND->decdata_buffer) { - BACKEND->decdata_offset = 0; - BACKEND->decdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE; - BACKEND->decdata_buffer = malloc(BACKEND->decdata_length); - if(!BACKEND->decdata_buffer) { + if(!backend->decdata_buffer) { + backend->decdata_offset = 0; + backend->decdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE; + backend->decdata_buffer = malloc(backend->decdata_length); + if(!backend->decdata_buffer) { failf(data, "schannel: unable to allocate memory"); return CURLE_OUT_OF_MEMORY; } } /* buffer to store previously received and encrypted data */ - if(!BACKEND->encdata_buffer) { - BACKEND->encdata_is_incomplete = false; - BACKEND->encdata_offset = 0; - BACKEND->encdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE; - BACKEND->encdata_buffer = malloc(BACKEND->encdata_length); - if(!BACKEND->encdata_buffer) { + if(!backend->encdata_buffer) { + backend->encdata_is_incomplete = false; + backend->encdata_offset = 0; + backend->encdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE; + backend->encdata_buffer = malloc(backend->encdata_length); + if(!backend->encdata_buffer) { failf(data, "schannel: unable to allocate memory"); return CURLE_OUT_OF_MEMORY; } } /* if we need a bigger buffer to read a full message, increase buffer now */ - if(BACKEND->encdata_length - BACKEND->encdata_offset < + if(backend->encdata_length - backend->encdata_offset < CURL_SCHANNEL_BUFFER_FREE_SIZE) { /* increase internal encrypted data buffer */ - size_t reallocated_length = BACKEND->encdata_offset + + size_t reallocated_length = backend->encdata_offset + CURL_SCHANNEL_BUFFER_FREE_SIZE; - reallocated_buffer = realloc(BACKEND->encdata_buffer, + reallocated_buffer = realloc(backend->encdata_buffer, reallocated_length); if(!reallocated_buffer) { @@ -1078,8 +1077,8 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn, return CURLE_OUT_OF_MEMORY; } else { - BACKEND->encdata_buffer = reallocated_buffer; - BACKEND->encdata_length = reallocated_length; + backend->encdata_buffer = reallocated_buffer; + backend->encdata_length = reallocated_length; } } @@ -1088,10 +1087,10 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn, if(doread) { /* read encrypted handshake data from socket */ result = Curl_read_plain(conn->sock[sockindex], - (char *) (BACKEND->encdata_buffer + - BACKEND->encdata_offset), - BACKEND->encdata_length - - BACKEND->encdata_offset, + (char *) (backend->encdata_buffer + + backend->encdata_offset), + backend->encdata_length - + backend->encdata_offset, &nread); if(result == CURLE_AGAIN) { if(connssl->connecting_state != ssl_connect_2_writing) @@ -1107,18 +1106,18 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn, } /* increase encrypted data buffer offset */ - BACKEND->encdata_offset += nread; - BACKEND->encdata_is_incomplete = false; + backend->encdata_offset += nread; + backend->encdata_is_incomplete = false; DEBUGF(infof(data, "schannel: encrypted data got %zd", nread)); } DEBUGF(infof(data, "schannel: encrypted data buffer: offset %zu length %zu", - BACKEND->encdata_offset, BACKEND->encdata_length)); + backend->encdata_offset, backend->encdata_length)); /* setup input buffers */ - InitSecBuffer(&inbuf[0], SECBUFFER_TOKEN, malloc(BACKEND->encdata_offset), - curlx_uztoul(BACKEND->encdata_offset)); + InitSecBuffer(&inbuf[0], SECBUFFER_TOKEN, malloc(backend->encdata_offset), + curlx_uztoul(backend->encdata_offset)); InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0); InitSecBufferDesc(&inbuf_desc, inbuf, 2); @@ -1134,19 +1133,17 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn, } /* copy received handshake data into input buffer */ - memcpy(inbuf[0].pvBuffer, BACKEND->encdata_buffer, - BACKEND->encdata_offset); + memcpy(inbuf[0].pvBuffer, backend->encdata_buffer, + backend->encdata_offset); host_name = curlx_convert_UTF8_to_tchar(hostname); if(!host_name) return CURLE_OUT_OF_MEMORY; - /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx - */ sspi_status = s_pSecFn->InitializeSecurityContext( - &BACKEND->cred->cred_handle, &BACKEND->ctxt->ctxt_handle, - host_name, BACKEND->req_flags, 0, 0, &inbuf_desc, 0, NULL, - &outbuf_desc, &BACKEND->ret_flags, &BACKEND->ctxt->time_stamp); + &backend->cred->cred_handle, &backend->ctxt->ctxt_handle, + host_name, backend->req_flags, 0, 0, &inbuf_desc, 0, NULL, + &outbuf_desc, &backend->ret_flags, &backend->ctxt->time_stamp); curlx_unicodefree(host_name); @@ -1155,7 +1152,7 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn, /* check if the handshake was incomplete */ if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) { - BACKEND->encdata_is_incomplete = true; + backend->encdata_is_incomplete = true; connssl->connecting_state = ssl_connect_2_reading; DEBUGF(infof(data, "schannel: received incomplete message, need more data")); @@ -1166,8 +1163,8 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn, the handshake without one. This will allow connections to servers which request a client certificate but do not require it. */ if(sspi_status == SEC_I_INCOMPLETE_CREDENTIALS && - !(BACKEND->req_flags & ISC_REQ_USE_SUPPLIED_CREDS)) { - BACKEND->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS; + !(backend->req_flags & ISC_REQ_USE_SUPPLIED_CREDS)) { + backend->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS; connssl->connecting_state = ssl_connect_2_writing; DEBUGF(infof(data, "schannel: a client certificate has been requested")); @@ -1195,7 +1192,7 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn, } /* free obsolete buffer */ - if(outbuf[i].pvBuffer != NULL) { + if(outbuf[i].pvBuffer) { s_pSecFn->FreeContextBuffer(outbuf[i].pvBuffer); } } @@ -1249,11 +1246,11 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn, */ /* check if the remaining data is less than the total amount and therefore begins after the already processed data */ - if(BACKEND->encdata_offset > inbuf[1].cbBuffer) { - memmove(BACKEND->encdata_buffer, - (BACKEND->encdata_buffer + BACKEND->encdata_offset) - + if(backend->encdata_offset > inbuf[1].cbBuffer) { + memmove(backend->encdata_buffer, + (backend->encdata_buffer + backend->encdata_offset) - inbuf[1].cbBuffer, inbuf[1].cbBuffer); - BACKEND->encdata_offset = inbuf[1].cbBuffer; + backend->encdata_offset = inbuf[1].cbBuffer; if(sspi_status == SEC_I_CONTINUE_NEEDED) { doread = FALSE; continue; @@ -1261,7 +1258,7 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn, } } else { - BACKEND->encdata_offset = 0; + backend->encdata_offset = 0; } break; } @@ -1288,7 +1285,7 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn, } #ifdef HAS_MANUAL_VERIFY_API - if(conn->ssl_config.verifypeer && BACKEND->use_manual_cred_validation) { + if(conn->ssl_config.verifypeer && backend->use_manual_cred_validation) { return Curl_verify_certificate(data, conn, sockindex); } #endif @@ -1370,6 +1367,7 @@ schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn, #ifdef HAS_ALPN SecPkgContext_ApplicationProtocol alpn_result; #endif + struct ssl_backend_data *backend = connssl->backend; DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); @@ -1377,28 +1375,28 @@ schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn, "schannel: SSL/TLS connection with %s port %hu (step 3/3)", hostname, conn->remote_port)); - if(!BACKEND->cred) + if(!backend->cred) return CURLE_SSL_CONNECT_ERROR; /* check if the required context attributes are met */ - if(BACKEND->ret_flags != BACKEND->req_flags) { - if(!(BACKEND->ret_flags & ISC_RET_SEQUENCE_DETECT)) + if(backend->ret_flags != backend->req_flags) { + if(!(backend->ret_flags & ISC_RET_SEQUENCE_DETECT)) failf(data, "schannel: failed to setup sequence detection"); - if(!(BACKEND->ret_flags & ISC_RET_REPLAY_DETECT)) + if(!(backend->ret_flags & ISC_RET_REPLAY_DETECT)) failf(data, "schannel: failed to setup replay detection"); - if(!(BACKEND->ret_flags & ISC_RET_CONFIDENTIALITY)) + if(!(backend->ret_flags & ISC_RET_CONFIDENTIALITY)) failf(data, "schannel: failed to setup confidentiality"); - if(!(BACKEND->ret_flags & ISC_RET_ALLOCATED_MEMORY)) + if(!(backend->ret_flags & ISC_RET_ALLOCATED_MEMORY)) failf(data, "schannel: failed to setup memory allocation"); - if(!(BACKEND->ret_flags & ISC_RET_STREAM)) + if(!(backend->ret_flags & ISC_RET_STREAM)) failf(data, "schannel: failed to setup stream orientation"); return CURLE_SSL_CONNECT_ERROR; } #ifdef HAS_ALPN - if(BACKEND->use_alpn) { + if(backend->use_alpn) { sspi_status = - s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle, + s_pSecFn->QueryContextAttributes(&backend->ctxt->ctxt_handle, SECPKG_ATTR_APPLICATION_PROTOCOL, &alpn_result); @@ -1436,13 +1434,14 @@ schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn, /* save the current session data for possible re-use */ if(SSL_SET_OPTION(primary.sessionid)) { bool incache; + bool added = FALSE; struct Curl_schannel_cred *old_cred = NULL; Curl_ssl_sessionid_lock(data); incache = !(Curl_ssl_getsessionid(data, conn, isproxy, (void **)&old_cred, NULL, sockindex)); if(incache) { - if(old_cred != BACKEND->cred) { + if(old_cred != backend->cred) { DEBUGF(infof(data, "schannel: old credential handle is stale, removing")); /* we're not taking old_cred ownership here, no refcount++ is needed */ @@ -1451,17 +1450,17 @@ schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn, } } if(!incache) { - result = Curl_ssl_addsessionid(data, conn, isproxy, BACKEND->cred, + result = Curl_ssl_addsessionid(data, conn, isproxy, backend->cred, sizeof(struct Curl_schannel_cred), - sockindex); + sockindex, &added); if(result) { Curl_ssl_sessionid_unlock(data); failf(data, "schannel: failed to store credential handle"); return result; } - else { + else if(added) { /* this cred session is now also referenced by sessionid cache */ - BACKEND->cred->refcount++; + backend->cred->refcount++; DEBUGF(infof(data, "schannel: stored credential handle in session cache")); } @@ -1472,7 +1471,7 @@ schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn, if(data->set.ssl.certinfo) { int certs_count = 0; sspi_status = - s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle, + s_pSecFn->QueryContextAttributes(&backend->ctxt->ctxt_handle, SECPKG_ATTR_REMOTE_CERT_CONTEXT, &ccert_context); @@ -1609,7 +1608,10 @@ schannel_connect_common(struct Curl_easy *data, struct connectdata *conn, * binding to pass the IIS extended protection checks. * Available on Windows 7 or later. */ - conn->sslContext = &BACKEND->ctxt->ctxt_handle; + { + struct ssl_backend_data *backend = connssl->backend; + conn->sslContext = &backend->ctxt->ctxt_handle; + } #endif *done = TRUE; @@ -1636,13 +1638,14 @@ schannel_send(struct Curl_easy *data, int sockindex, SecBufferDesc outbuf_desc; SECURITY_STATUS sspi_status = SEC_E_OK; CURLcode result; + struct ssl_backend_data *backend = connssl->backend; /* check if the maximum stream sizes were queried */ - if(BACKEND->stream_sizes.cbMaximumMessage == 0) { + if(backend->stream_sizes.cbMaximumMessage == 0) { sspi_status = s_pSecFn->QueryContextAttributes( - &BACKEND->ctxt->ctxt_handle, + &backend->ctxt->ctxt_handle, SECPKG_ATTR_STREAM_SIZES, - &BACKEND->stream_sizes); + &backend->stream_sizes); if(sspi_status != SEC_E_OK) { *err = CURLE_SEND_ERROR; return -1; @@ -1650,13 +1653,13 @@ schannel_send(struct Curl_easy *data, int sockindex, } /* check if the buffer is longer than the maximum message length */ - if(len > BACKEND->stream_sizes.cbMaximumMessage) { - len = BACKEND->stream_sizes.cbMaximumMessage; + if(len > backend->stream_sizes.cbMaximumMessage) { + len = backend->stream_sizes.cbMaximumMessage; } /* calculate the complete message length and allocate a buffer for it */ - data_len = BACKEND->stream_sizes.cbHeader + len + - BACKEND->stream_sizes.cbTrailer; + data_len = backend->stream_sizes.cbHeader + len + + backend->stream_sizes.cbTrailer; ptr = (unsigned char *) malloc(data_len); if(!ptr) { *err = CURLE_OUT_OF_MEMORY; @@ -1665,12 +1668,12 @@ schannel_send(struct Curl_easy *data, int sockindex, /* setup output buffers (header, data, trailer, empty) */ InitSecBuffer(&outbuf[0], SECBUFFER_STREAM_HEADER, - ptr, BACKEND->stream_sizes.cbHeader); + ptr, backend->stream_sizes.cbHeader); InitSecBuffer(&outbuf[1], SECBUFFER_DATA, - ptr + BACKEND->stream_sizes.cbHeader, curlx_uztoul(len)); + ptr + backend->stream_sizes.cbHeader, curlx_uztoul(len)); InitSecBuffer(&outbuf[2], SECBUFFER_STREAM_TRAILER, - ptr + BACKEND->stream_sizes.cbHeader + len, - BACKEND->stream_sizes.cbTrailer); + ptr + backend->stream_sizes.cbHeader + len, + backend->stream_sizes.cbTrailer); InitSecBuffer(&outbuf[3], SECBUFFER_EMPTY, NULL, 0); InitSecBufferDesc(&outbuf_desc, outbuf, 4); @@ -1678,7 +1681,7 @@ schannel_send(struct Curl_easy *data, int sockindex, memcpy(outbuf[1].pvBuffer, buf, len); /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375390.aspx */ - sspi_status = s_pSecFn->EncryptMessage(&BACKEND->ctxt->ctxt_handle, 0, + sspi_status = s_pSecFn->EncryptMessage(&backend->ctxt->ctxt_handle, 0, &outbuf_desc, 0); /* check if the message was encrypted */ @@ -1783,9 +1786,10 @@ schannel_recv(struct Curl_easy *data, int sockindex, /* we want the length of the encrypted buffer to be at least large enough that it can hold all the bytes requested and some TLS record overhead. */ size_t min_encdata_length = len + CURL_SCHANNEL_BUFFER_FREE_SIZE; + struct ssl_backend_data *backend = connssl->backend; /**************************************************************************** - * Don't return or set BACKEND->recv_unrecoverable_err unless in the cleanup. + * Don't return or set backend->recv_unrecoverable_err unless in the cleanup. * The pattern for return error is set *err, optional infof, goto cleanup. * * Our priority is to always return as much decrypted data to the caller as @@ -1797,16 +1801,16 @@ schannel_recv(struct Curl_easy *data, int sockindex, DEBUGF(infof(data, "schannel: client wants to read %zu bytes", len)); *err = CURLE_OK; - if(len && len <= BACKEND->decdata_offset) { + if(len && len <= backend->decdata_offset) { infof(data, "schannel: enough decrypted data is already available"); goto cleanup; } - else if(BACKEND->recv_unrecoverable_err) { - *err = BACKEND->recv_unrecoverable_err; + else if(backend->recv_unrecoverable_err) { + *err = backend->recv_unrecoverable_err; infof(data, "schannel: an unrecoverable error occurred in a prior call"); goto cleanup; } - else if(BACKEND->recv_sspi_close_notify) { + else if(backend->recv_sspi_close_notify) { /* once a server has indicated shutdown there is no more encrypted data */ infof(data, "schannel: server indicated shutdown in a prior call"); goto cleanup; @@ -1816,17 +1820,17 @@ schannel_recv(struct Curl_easy *data, int sockindex, immediately because there may be data to decrypt (in the case we want to decrypt all encrypted cached data) so handle !len later in cleanup. */ - else if(len && !BACKEND->recv_connection_closed) { + else if(len && !backend->recv_connection_closed) { /* increase enc buffer in order to fit the requested amount of data */ - size = BACKEND->encdata_length - BACKEND->encdata_offset; + size = backend->encdata_length - backend->encdata_offset; if(size < CURL_SCHANNEL_BUFFER_FREE_SIZE || - BACKEND->encdata_length < min_encdata_length) { - reallocated_length = BACKEND->encdata_offset + + backend->encdata_length < min_encdata_length) { + reallocated_length = backend->encdata_offset + CURL_SCHANNEL_BUFFER_FREE_SIZE; if(reallocated_length < min_encdata_length) { reallocated_length = min_encdata_length; } - reallocated_buffer = realloc(BACKEND->encdata_buffer, + reallocated_buffer = realloc(backend->encdata_buffer, reallocated_length); if(!reallocated_buffer) { *err = CURLE_OUT_OF_MEMORY; @@ -1834,21 +1838,21 @@ schannel_recv(struct Curl_easy *data, int sockindex, goto cleanup; } - BACKEND->encdata_buffer = reallocated_buffer; - BACKEND->encdata_length = reallocated_length; - size = BACKEND->encdata_length - BACKEND->encdata_offset; + backend->encdata_buffer = reallocated_buffer; + backend->encdata_length = reallocated_length; + size = backend->encdata_length - backend->encdata_offset; DEBUGF(infof(data, "schannel: encdata_buffer resized %zu", - BACKEND->encdata_length)); + backend->encdata_length)); } DEBUGF(infof(data, "schannel: encrypted data buffer: offset %zu length %zu", - BACKEND->encdata_offset, BACKEND->encdata_length)); + backend->encdata_offset, backend->encdata_length)); /* read encrypted data from socket */ *err = Curl_read_plain(conn->sock[sockindex], - (char *)(BACKEND->encdata_buffer + - BACKEND->encdata_offset), + (char *)(backend->encdata_buffer + + backend->encdata_offset), size, &nread); if(*err) { nread = -1; @@ -1861,27 +1865,27 @@ schannel_recv(struct Curl_easy *data, int sockindex, infof(data, "schannel: Curl_read_plain returned error %d", *err); } else if(nread == 0) { - BACKEND->recv_connection_closed = true; + backend->recv_connection_closed = true; DEBUGF(infof(data, "schannel: server closed the connection")); } else if(nread > 0) { - BACKEND->encdata_offset += (size_t)nread; - BACKEND->encdata_is_incomplete = false; + backend->encdata_offset += (size_t)nread; + backend->encdata_is_incomplete = false; DEBUGF(infof(data, "schannel: encrypted data got %zd", nread)); } } DEBUGF(infof(data, "schannel: encrypted data buffer: offset %zu length %zu", - BACKEND->encdata_offset, BACKEND->encdata_length)); + backend->encdata_offset, backend->encdata_length)); /* decrypt loop */ - while(BACKEND->encdata_offset > 0 && sspi_status == SEC_E_OK && - (!len || BACKEND->decdata_offset < len || - BACKEND->recv_connection_closed)) { + while(backend->encdata_offset > 0 && sspi_status == SEC_E_OK && + (!len || backend->decdata_offset < len || + backend->recv_connection_closed)) { /* prepare data buffer for DecryptMessage call */ - InitSecBuffer(&inbuf[0], SECBUFFER_DATA, BACKEND->encdata_buffer, - curlx_uztoul(BACKEND->encdata_offset)); + InitSecBuffer(&inbuf[0], SECBUFFER_DATA, backend->encdata_buffer, + curlx_uztoul(backend->encdata_offset)); /* we need 3 more empty input buffers for possible output */ InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0); @@ -1891,7 +1895,7 @@ schannel_recv(struct Curl_easy *data, int sockindex, /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375348.aspx */ - sspi_status = s_pSecFn->DecryptMessage(&BACKEND->ctxt->ctxt_handle, + sspi_status = s_pSecFn->DecryptMessage(&backend->ctxt->ctxt_handle, &inbuf_desc, 0, NULL); /* check if everything went fine (server may want to renegotiate @@ -1907,37 +1911,37 @@ schannel_recv(struct Curl_easy *data, int sockindex, /* increase buffer in order to fit the received amount of data */ size = inbuf[1].cbBuffer > CURL_SCHANNEL_BUFFER_FREE_SIZE ? inbuf[1].cbBuffer : CURL_SCHANNEL_BUFFER_FREE_SIZE; - if(BACKEND->decdata_length - BACKEND->decdata_offset < size || - BACKEND->decdata_length < len) { + if(backend->decdata_length - backend->decdata_offset < size || + backend->decdata_length < len) { /* increase internal decrypted data buffer */ - reallocated_length = BACKEND->decdata_offset + size; + reallocated_length = backend->decdata_offset + size; /* make sure that the requested amount of data fits */ if(reallocated_length < len) { reallocated_length = len; } - reallocated_buffer = realloc(BACKEND->decdata_buffer, + reallocated_buffer = realloc(backend->decdata_buffer, reallocated_length); if(!reallocated_buffer) { *err = CURLE_OUT_OF_MEMORY; failf(data, "schannel: unable to re-allocate memory"); goto cleanup; } - BACKEND->decdata_buffer = reallocated_buffer; - BACKEND->decdata_length = reallocated_length; + backend->decdata_buffer = reallocated_buffer; + backend->decdata_length = reallocated_length; } /* copy decrypted data to internal buffer */ size = inbuf[1].cbBuffer; if(size) { - memcpy(BACKEND->decdata_buffer + BACKEND->decdata_offset, + memcpy(backend->decdata_buffer + backend->decdata_offset, inbuf[1].pvBuffer, size); - BACKEND->decdata_offset += size; + backend->decdata_offset += size; } DEBUGF(infof(data, "schannel: decrypted data added: %zu", size)); DEBUGF(infof(data, "schannel: decrypted cached: offset %zu length %zu", - BACKEND->decdata_offset, BACKEND->decdata_length)); + backend->decdata_offset, backend->decdata_length)); } /* check for remaining encrypted data */ @@ -1948,34 +1952,34 @@ schannel_recv(struct Curl_easy *data, int sockindex, /* check if the remaining data is less than the total amount * and therefore begins after the already processed data */ - if(BACKEND->encdata_offset > inbuf[3].cbBuffer) { + if(backend->encdata_offset > inbuf[3].cbBuffer) { /* move remaining encrypted data forward to the beginning of buffer */ - memmove(BACKEND->encdata_buffer, - (BACKEND->encdata_buffer + BACKEND->encdata_offset) - + memmove(backend->encdata_buffer, + (backend->encdata_buffer + backend->encdata_offset) - inbuf[3].cbBuffer, inbuf[3].cbBuffer); - BACKEND->encdata_offset = inbuf[3].cbBuffer; + backend->encdata_offset = inbuf[3].cbBuffer; } DEBUGF(infof(data, "schannel: encrypted cached: offset %zu length %zu", - BACKEND->encdata_offset, BACKEND->encdata_length)); + backend->encdata_offset, backend->encdata_length)); } else { /* reset encrypted buffer offset, because there is no data remaining */ - BACKEND->encdata_offset = 0; + backend->encdata_offset = 0; } /* check if server wants to renegotiate the connection context */ if(sspi_status == SEC_I_RENEGOTIATE) { infof(data, "schannel: remote party requests renegotiation"); if(*err && *err != CURLE_AGAIN) { - infof(data, "schannel: can't renogotiate, an error is pending"); + infof(data, "schannel: can't renegotiate, an error is pending"); goto cleanup; } - if(BACKEND->encdata_offset) { + if(backend->encdata_offset) { *err = CURLE_RECV_ERROR; - infof(data, "schannel: can't renogotiate, " + infof(data, "schannel: can't renegotiate, " "encrypted data available"); goto cleanup; } @@ -1997,16 +2001,16 @@ schannel_recv(struct Curl_easy *data, int sockindex, else if(sspi_status == SEC_I_CONTEXT_EXPIRED) { /* In Windows 2000 SEC_I_CONTEXT_EXPIRED (close_notify) is not returned so we have to work around that in cleanup. */ - BACKEND->recv_sspi_close_notify = true; - if(!BACKEND->recv_connection_closed) { - BACKEND->recv_connection_closed = true; + backend->recv_sspi_close_notify = true; + if(!backend->recv_connection_closed) { + backend->recv_connection_closed = true; infof(data, "schannel: server closed the connection"); } goto cleanup; } } else if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) { - BACKEND->encdata_is_incomplete = true; + backend->encdata_is_incomplete = true; if(!*err) *err = CURLE_AGAIN; infof(data, "schannel: failed to decrypt data, need more data"); @@ -2025,11 +2029,11 @@ schannel_recv(struct Curl_easy *data, int sockindex, DEBUGF(infof(data, "schannel: encrypted data buffer: offset %zu length %zu", - BACKEND->encdata_offset, BACKEND->encdata_length)); + backend->encdata_offset, backend->encdata_length)); DEBUGF(infof(data, "schannel: decrypted data buffer: offset %zu length %zu", - BACKEND->decdata_offset, BACKEND->decdata_length)); + backend->decdata_offset, backend->decdata_length)); cleanup: /* Warning- there is no guarantee the encdata state is valid at this point */ @@ -2046,13 +2050,13 @@ schannel_recv(struct Curl_easy *data, int sockindex, assume it was graceful (close_notify) since there doesn't seem to be a way to tell. */ - if(len && !BACKEND->decdata_offset && BACKEND->recv_connection_closed && - !BACKEND->recv_sspi_close_notify) { - bool isWin2k = curlx_verify_windows_version(5, 0, PLATFORM_WINNT, + if(len && !backend->decdata_offset && backend->recv_connection_closed && + !backend->recv_sspi_close_notify) { + bool isWin2k = curlx_verify_windows_version(5, 0, 0, PLATFORM_WINNT, VERSION_EQUAL); if(isWin2k && sspi_status == SEC_E_OK) - BACKEND->recv_sspi_close_notify = true; + backend->recv_sspi_close_notify = true; else { *err = CURLE_RECV_ERROR; infof(data, "schannel: server closed abruptly (missing close_notify)"); @@ -2061,23 +2065,23 @@ schannel_recv(struct Curl_easy *data, int sockindex, /* Any error other than CURLE_AGAIN is an unrecoverable error. */ if(*err && *err != CURLE_AGAIN) - BACKEND->recv_unrecoverable_err = *err; + backend->recv_unrecoverable_err = *err; - size = len < BACKEND->decdata_offset ? len : BACKEND->decdata_offset; + size = len < backend->decdata_offset ? len : backend->decdata_offset; if(size) { - memcpy(buf, BACKEND->decdata_buffer, size); - memmove(BACKEND->decdata_buffer, BACKEND->decdata_buffer + size, - BACKEND->decdata_offset - size); - BACKEND->decdata_offset -= size; + memcpy(buf, backend->decdata_buffer, size); + memmove(backend->decdata_buffer, backend->decdata_buffer + size, + backend->decdata_offset - size); + backend->decdata_offset -= size; DEBUGF(infof(data, "schannel: decrypted data returned %zu", size)); DEBUGF(infof(data, "schannel: decrypted data buffer: offset %zu length %zu", - BACKEND->decdata_offset, BACKEND->decdata_length)); + backend->decdata_offset, backend->decdata_length)); *err = CURLE_OK; return (ssize_t)size; } - if(!*err && !BACKEND->recv_connection_closed) + if(!*err && !backend->recv_connection_closed) *err = CURLE_AGAIN; /* It's debatable what to return when !len. We could return whatever error @@ -2116,34 +2120,32 @@ static bool schannel_data_pending(const struct connectdata *conn, int sockindex) { const struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; if(connssl->use) /* SSL/TLS is in use */ - return (BACKEND->decdata_offset > 0 || - (BACKEND->encdata_offset > 0 && !BACKEND->encdata_is_incomplete)); + return (backend->decdata_offset > 0 || + (backend->encdata_offset > 0 && !backend->encdata_is_incomplete)); else return FALSE; } -static void schannel_close(struct Curl_easy *data, struct connectdata *conn, - int sockindex) -{ - if(conn->ssl[sockindex].use) - /* if the SSL/TLS channel hasn't been shut down yet, do that now. */ - Curl_ssl_shutdown(data, conn, sockindex); -} - static void schannel_session_free(void *ptr) { /* this is expected to be called under sessionid lock */ struct Curl_schannel_cred *cred = ptr; - cred->refcount--; - if(cred->refcount == 0) { - s_pSecFn->FreeCredentialsHandle(&cred->cred_handle); - Curl_safefree(cred); + if(cred) { + cred->refcount--; + if(cred->refcount == 0) { + s_pSecFn->FreeCredentialsHandle(&cred->cred_handle); + Curl_safefree(cred); + } } } +/* shut down the SSL connection and clean up related memory. + this function can be called multiple times on the same connection including + if the SSL connection failed (eg connection made but failed handshake). */ static int schannel_shutdown(struct Curl_easy *data, struct connectdata *conn, int sockindex) { @@ -2152,13 +2154,16 @@ static int schannel_shutdown(struct Curl_easy *data, struct connectdata *conn, */ struct ssl_connect_data *connssl = &conn->ssl[sockindex]; char * const hostname = SSL_HOST_NAME(); + struct ssl_backend_data *backend = connssl->backend; DEBUGASSERT(data); - infof(data, "schannel: shutting down SSL/TLS connection with %s port %hu", - hostname, conn->remote_port); + if(connssl->use) { + infof(data, "schannel: shutting down SSL/TLS connection with %s port %hu", + hostname, conn->remote_port); + } - if(BACKEND->cred && BACKEND->ctxt) { + if(connssl->use && backend->cred && backend->ctxt) { SecBufferDesc BuffDesc; SecBuffer Buffer; SECURITY_STATUS sspi_status; @@ -2171,7 +2176,7 @@ static int schannel_shutdown(struct Curl_easy *data, struct connectdata *conn, InitSecBuffer(&Buffer, SECBUFFER_TOKEN, &dwshut, sizeof(dwshut)); InitSecBufferDesc(&BuffDesc, &Buffer, 1); - sspi_status = s_pSecFn->ApplyControlToken(&BACKEND->ctxt->ctxt_handle, + sspi_status = s_pSecFn->ApplyControlToken(&backend->ctxt->ctxt_handle, &BuffDesc); if(sspi_status != SEC_E_OK) { @@ -2189,18 +2194,18 @@ static int schannel_shutdown(struct Curl_easy *data, struct connectdata *conn, InitSecBufferDesc(&outbuf_desc, &outbuf, 1); sspi_status = s_pSecFn->InitializeSecurityContext( - &BACKEND->cred->cred_handle, - &BACKEND->ctxt->ctxt_handle, + &backend->cred->cred_handle, + &backend->ctxt->ctxt_handle, host_name, - BACKEND->req_flags, + backend->req_flags, 0, 0, NULL, 0, - &BACKEND->ctxt->ctxt_handle, + &backend->ctxt->ctxt_handle, &outbuf_desc, - &BACKEND->ret_flags, - &BACKEND->ctxt->time_stamp); + &backend->ret_flags, + &backend->ctxt->time_stamp); curlx_unicodefree(host_name); @@ -2219,38 +2224,48 @@ static int schannel_shutdown(struct Curl_easy *data, struct connectdata *conn, } /* free SSPI Schannel API security context handle */ - if(BACKEND->ctxt) { + if(backend->ctxt) { DEBUGF(infof(data, "schannel: clear security context handle")); - s_pSecFn->DeleteSecurityContext(&BACKEND->ctxt->ctxt_handle); - Curl_safefree(BACKEND->ctxt); + s_pSecFn->DeleteSecurityContext(&backend->ctxt->ctxt_handle); + Curl_safefree(backend->ctxt); } /* free SSPI Schannel API credential handle */ - if(BACKEND->cred) { + if(backend->cred) { Curl_ssl_sessionid_lock(data); - schannel_session_free(BACKEND->cred); + schannel_session_free(backend->cred); Curl_ssl_sessionid_unlock(data); - BACKEND->cred = NULL; + backend->cred = NULL; } /* free internal buffer for received encrypted data */ - if(BACKEND->encdata_buffer != NULL) { - Curl_safefree(BACKEND->encdata_buffer); - BACKEND->encdata_length = 0; - BACKEND->encdata_offset = 0; - BACKEND->encdata_is_incomplete = false; + if(backend->encdata_buffer) { + Curl_safefree(backend->encdata_buffer); + backend->encdata_length = 0; + backend->encdata_offset = 0; + backend->encdata_is_incomplete = false; } /* free internal buffer for received decrypted data */ - if(BACKEND->decdata_buffer != NULL) { - Curl_safefree(BACKEND->decdata_buffer); - BACKEND->decdata_length = 0; - BACKEND->decdata_offset = 0; + if(backend->decdata_buffer) { + Curl_safefree(backend->decdata_buffer); + backend->decdata_length = 0; + backend->decdata_offset = 0; } return CURLE_OK; } +static void schannel_close(struct Curl_easy *data, struct connectdata *conn, + int sockindex) +{ + if(conn->ssl[sockindex].use) + /* Curl_ssl_shutdown resets the socket state and calls schannel_shutdown */ + Curl_ssl_shutdown(data, conn, sockindex); + else + schannel_shutdown(data, conn, sockindex); +} + static int schannel_init(void) { return (Curl_sspi_global_init() == CURLE_OK ? 1 : 0); @@ -2293,6 +2308,7 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data, const char *pinnedpubkey) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; CERT_CONTEXT *pCertContextServer = NULL; /* Result is returned to caller */ @@ -2310,7 +2326,7 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data, struct Curl_asn1Element *pubkey; sspi_status = - s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle, + s_pSecFn->QueryContextAttributes(&backend->ctxt->ctxt_handle, SECPKG_ATTR_REMOTE_CERT_CONTEXT, &pCertContextServer); @@ -2416,8 +2432,9 @@ static CURLcode schannel_sha256sum(const unsigned char *input, static void *schannel_get_internals(struct ssl_connect_data *connssl, CURLINFO info UNUSED_PARAM) { + struct ssl_backend_data *backend = connssl->backend; (void)info; - return &BACKEND->ctxt->ctxt_handle; + return &backend->ctxt->ctxt_handle; } const struct Curl_ssl Curl_ssl_schannel = { diff --git a/lib/vtls/schannel_verify.c b/lib/vtls/schannel_verify.c index 1b283d0..4966cd4 100644 --- a/lib/vtls/schannel_verify.c +++ b/lib/vtls/schannel_verify.c @@ -355,7 +355,7 @@ static DWORD cert_get_name_string(struct Curl_easy *data, DWORD i; /* CERT_NAME_SEARCH_ALL_NAMES_FLAG is available from Windows 8 onwards. */ - if(curlx_verify_windows_version(6, 2, PLATFORM_WINNT, + if(curlx_verify_windows_version(6, 2, 0, PLATFORM_WINNT, VERSION_GREATER_THAN_EQUAL)) { #ifdef CERT_NAME_SEARCH_ALL_NAMES_FLAG /* CertGetNameString will provide the 8-bit character string without @@ -597,7 +597,8 @@ CURLcode Curl_verify_certificate(struct Curl_easy *data, * trusted certificates. This is only supported on Windows 7+. */ - if(curlx_verify_windows_version(6, 1, PLATFORM_WINNT, VERSION_LESS_THAN)) { + if(curlx_verify_windows_version(6, 1, 0, PLATFORM_WINNT, + VERSION_LESS_THAN)) { failf(data, "schannel: this version of Windows is too old to support " "certificate verification via CA bundle file."); result = CURLE_SSL_CACERT_BADFILE; diff --git a/lib/vtls/sectransp.c b/lib/vtls/sectransp.c index 1e6ed5f..f7a20b2 100644 --- a/lib/vtls/sectransp.c +++ b/lib/vtls/sectransp.c @@ -997,14 +997,14 @@ CF_INLINE CFStringRef getsubject(SecCertificateRef cert) #else #if CURL_BUILD_MAC_10_7 /* Lion & later: Get the long description if we can. */ - if(SecCertificateCopyLongDescription != NULL) + if(SecCertificateCopyLongDescription) server_cert_summary = SecCertificateCopyLongDescription(NULL, cert, NULL); else #endif /* CURL_BUILD_MAC_10_7 */ #if CURL_BUILD_MAC_10_6 /* Snow Leopard: Get the certificate summary. */ - if(SecCertificateCopySubjectSummary != NULL) + if(SecCertificateCopySubjectSummary) server_cert_summary = SecCertificateCopySubjectSummary(cert); else #endif /* CURL_BUILD_MAC_10_6 */ @@ -1118,7 +1118,7 @@ static OSStatus CopyIdentityWithLabel(char *label, /* SecItemCopyMatching() was introduced in iOS and Snow Leopard. kSecClassIdentity was introduced in Lion. If both exist, let's use them to find the certificate. */ - if(SecItemCopyMatching != NULL && kSecClassIdentity != NULL) { + if(SecItemCopyMatching && kSecClassIdentity) { CFTypeRef keys[5]; CFTypeRef values[5]; CFDictionaryRef query_dict; @@ -1248,7 +1248,7 @@ static OSStatus CopyIdentityFromPKCS12File(const char *cPath, CFDictionaryRef options = CFDictionaryCreate(NULL, cKeys, cValues, password ? 1L : 0L, NULL, NULL); - if(options != NULL) { + if(options) { status = SecPKCS12Import(pkcs_data, options, &items); CFRelease(options); } @@ -1406,7 +1406,7 @@ set_ssl_version_min_max(struct Curl_easy *data, struct connectdata *conn, } #if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS - if(SSLSetProtocolVersionMax != NULL) { + if(SSLSetProtocolVersionMax) { SSLProtocol darwin_ver_min = kTLSProtocol1; SSLProtocol darwin_ver_max = kTLSProtocol1; CURLcode result = sectransp_version_from_curl(&darwin_ver_min, @@ -1608,7 +1608,7 @@ static CURLcode sectransp_set_selected_ciphers(struct Curl_easy *data, if(tls_name) { table_cipher_name = ciphertable[i].name; } - else if(ciphertable[i].alias_name != NULL) { + else if(ciphertable[i].alias_name) { table_cipher_name = ciphertable[i].alias_name; } else { @@ -1688,7 +1688,7 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data, #endif /* CURL_BUILD_MAC */ #if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS - if(SSLCreateContext != NULL) { /* use the newer API if available */ + if(SSLCreateContext) { /* use the newer API if available */ if(backend->ssl_ctx) CFRelease(backend->ssl_ctx); backend->ssl_ctx = SSLCreateContext(NULL, kSSLClientSide, kSSLStreamType); @@ -1722,7 +1722,7 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data, /* check to see if we've been told to use an explicit SSL/TLS version */ #if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS - if(SSLSetProtocolVersionMax != NULL) { + if(SSLSetProtocolVersionMax) { switch(conn->ssl_config.version) { case CURL_SSLVERSION_TLSv1: (void)SSLSetProtocolVersionMin(backend->ssl_ctx, kTLSProtocol1); @@ -1980,9 +1980,9 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data, Darwin 15.x.x is El Capitan (10.11) */ #if CURL_BUILD_MAC - if(SSLSetSessionOption != NULL && darwinver_maj >= 13) { + if(SSLSetSessionOption && darwinver_maj >= 13) { #else - if(SSLSetSessionOption != NULL) { + if(SSLSetSessionOption) { #endif /* CURL_BUILD_MAC */ bool break_on_auth = !conn->ssl_config.verifypeer || ssl_cafile || ssl_cablob; @@ -2065,7 +2065,7 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data, #if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 /* We want to enable 1/n-1 when using a CBC cipher unless the user specifically doesn't want us doing that: */ - if(SSLSetSessionOption != NULL) { + if(SSLSetSessionOption) { SSLSetSessionOption(backend->ssl_ctx, kSSLSessionOptionSendOneByteRecord, !SSL_SET_OPTION(enable_beast)); SSLSetSessionOption(backend->ssl_ctx, kSSLSessionOptionFalseStart, @@ -2109,7 +2109,7 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data, } result = Curl_ssl_addsessionid(data, conn, isproxy, ssl_sessionid, - ssl_sessionid_len, sockindex); + ssl_sessionid_len, sockindex, NULL); Curl_ssl_sessionid_unlock(data); if(result) { failf(data, "failed to store ssl session"); @@ -2521,7 +2521,7 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data, } while(0); Curl_safefree(realpubkey); - if(publicKeyBits != NULL) + if(publicKeyBits) CFRelease(publicKeyBits); return result; @@ -2947,7 +2947,7 @@ collect_server_cert(struct Curl_easy *data, private API and doesn't work as expected. So we have to look for a different symbol to make sure this code is only executed under Lion or later. */ - if(SecTrustEvaluateAsync != NULL) { + if(SecTrustEvaluateAsync) { #pragma unused(server_certs) err = SSLCopyPeerTrust(backend->ssl_ctx, &trust); /* For some reason, SSLCopyPeerTrust() can return noErr and yet return @@ -3165,7 +3165,7 @@ static void sectransp_close(struct Curl_easy *data, struct connectdata *conn, if(backend->ssl_ctx) { (void)SSLClose(backend->ssl_ctx); #if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS - if(SSLCreateContext != NULL) + if(SSLCreateContext) CFRelease(backend->ssl_ctx); #if CURL_SUPPORT_MAC_10_8 else @@ -3329,7 +3329,7 @@ static CURLcode sectransp_sha256sum(const unsigned char *tmp, /* input */ static bool sectransp_false_start(void) { #if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 - if(SSLSetSessionOption != NULL) + if(SSLSetSessionOption) return TRUE; #endif return FALSE; diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c index e5bbe1f..6007bbb 100644 --- a/lib/vtls/vtls.c +++ b/lib/vtls/vtls.c @@ -516,7 +516,8 @@ CURLcode Curl_ssl_addsessionid(struct Curl_easy *data, const bool isProxy, void *ssl_sessionid, size_t idsize, - int sockindex) + int sockindex, + bool *added) { size_t i; struct Curl_ssl_session *store; @@ -536,6 +537,10 @@ CURLcode Curl_ssl_addsessionid(struct Curl_easy *data, const char *hostname = conn->host.name; #endif (void)sockindex; + + if(added) + *added = FALSE; + if(!data->state.session) return CURLE_OK; @@ -609,6 +614,9 @@ CURLcode Curl_ssl_addsessionid(struct Curl_easy *data, return CURLE_OUT_OF_MEMORY; } + if(added) + *added = TRUE; + DEBUGF(infof(data, "Added Session ID to cache for %s://%s:%d [%s]", store->scheme, store->name, store->remote_port, isProxy ? "PROXY" : "server")); diff --git a/lib/vtls/vtls.h b/lib/vtls/vtls.h index beaa83d..c7bbba0 100644 --- a/lib/vtls/vtls.h +++ b/lib/vtls/vtls.h @@ -261,7 +261,8 @@ CURLcode Curl_ssl_addsessionid(struct Curl_easy *data, const bool isProxy, void *ssl_sessionid, size_t idsize, - int sockindex); + int sockindex, + bool *added); /* Kill a single session ID entry in the cache * Sessionid mutex must be locked (see Curl_ssl_sessionid_lock). * This will call engine-specific curlssl_session_free function, which must diff --git a/lib/vtls/wolfssl.c b/lib/vtls/wolfssl.c index 16fbb89..8c5b915 100644 --- a/lib/vtls/wolfssl.c +++ b/lib/vtls/wolfssl.c @@ -202,6 +202,43 @@ static int do_file_type(const char *type) return -1; } +#ifdef HAVE_LIBOQS +struct group_name_map { + const word16 group; + const char *name; +}; + +static const struct group_name_map gnm[] = { + { WOLFSSL_KYBER_LEVEL1, "KYBER_LEVEL1" }, + { WOLFSSL_KYBER_LEVEL3, "KYBER_LEVEL3" }, + { WOLFSSL_KYBER_LEVEL5, "KYBER_LEVEL5" }, + { WOLFSSL_NTRU_HPS_LEVEL1, "NTRU_HPS_LEVEL1" }, + { WOLFSSL_NTRU_HPS_LEVEL3, "NTRU_HPS_LEVEL3" }, + { WOLFSSL_NTRU_HPS_LEVEL5, "NTRU_HPS_LEVEL5" }, + { WOLFSSL_NTRU_HRSS_LEVEL3, "NTRU_HRSS_LEVEL3" }, + { WOLFSSL_SABER_LEVEL1, "SABER_LEVEL1" }, + { WOLFSSL_SABER_LEVEL3, "SABER_LEVEL3" }, + { WOLFSSL_SABER_LEVEL5, "SABER_LEVEL5" }, + { WOLFSSL_KYBER_90S_LEVEL1, "KYBER_90S_LEVEL1" }, + { WOLFSSL_KYBER_90S_LEVEL3, "KYBER_90S_LEVEL3" }, + { WOLFSSL_KYBER_90S_LEVEL5, "KYBER_90S_LEVEL5" }, + { WOLFSSL_P256_NTRU_HPS_LEVEL1, "P256_NTRU_HPS_LEVEL1" }, + { WOLFSSL_P384_NTRU_HPS_LEVEL3, "P384_NTRU_HPS_LEVEL3" }, + { WOLFSSL_P521_NTRU_HPS_LEVEL5, "P521_NTRU_HPS_LEVEL5" }, + { WOLFSSL_P384_NTRU_HRSS_LEVEL3, "P384_NTRU_HRSS_LEVEL3" }, + { WOLFSSL_P256_SABER_LEVEL1, "P256_SABER_LEVEL1" }, + { WOLFSSL_P384_SABER_LEVEL3, "P384_SABER_LEVEL3" }, + { WOLFSSL_P521_SABER_LEVEL5, "P521_SABER_LEVEL5" }, + { WOLFSSL_P256_KYBER_LEVEL1, "P256_KYBER_LEVEL1" }, + { WOLFSSL_P384_KYBER_LEVEL3, "P384_KYBER_LEVEL3" }, + { WOLFSSL_P521_KYBER_LEVEL5, "P521_KYBER_LEVEL5" }, + { WOLFSSL_P256_KYBER_90S_LEVEL1, "P256_KYBER_90S_LEVEL1" }, + { WOLFSSL_P384_KYBER_90S_LEVEL3, "P384_KYBER_90S_LEVEL3" }, + { WOLFSSL_P521_KYBER_90S_LEVEL5, "P521_KYBER_90S_LEVEL5" }, + { 0, NULL } +}; +#endif + /* * This function loads all the client/CA certificates and CRLs. Setup the TLS * layer and do all necessary magic. @@ -210,11 +247,15 @@ static CURLcode wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn, int sockindex) { - char *ciphers; + char *ciphers, *curves; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; struct ssl_backend_data *backend = connssl->backend; SSL_METHOD* req_method = NULL; curl_socket_t sockfd = conn->sock[sockindex]; +#ifdef HAVE_LIBOQS + word16 oqsAlg = 0; + size_t idx = 0; +#endif #ifdef HAVE_SNI bool sni = FALSE; #define use_sni(x) sni = (x) @@ -327,6 +368,26 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn, infof(data, "Cipher selection: %s", ciphers); } + curves = SSL_CONN_CONFIG(curves); + if(curves) { + +#ifdef HAVE_LIBOQS + for(idx = 0; gnm[idx].name != NULL; idx++) { + if(strncmp(curves, gnm[idx].name, strlen(gnm[idx].name)) == 0) { + oqsAlg = gnm[idx].group; + break; + } + } + + if(oqsAlg == 0) +#endif + { + if(!SSL_CTX_set1_curves_list(backend->ctx, curves)) { + failf(data, "failed setting curves list: '%s'", curves); + return CURLE_SSL_CIPHER; + } + } + } #ifndef NO_FILESYSTEM /* load trusted cacert */ if(SSL_CONN_CONFIG(CAfile)) { @@ -439,6 +500,14 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn, return CURLE_OUT_OF_MEMORY; } +#ifdef HAVE_LIBOQS + if(oqsAlg) { + if(wolfSSL_UseKeyShare(backend->handle, oqsAlg) != WOLFSSL_SUCCESS) { + failf(data, "unable to use oqs KEM"); + } + } +#endif + #ifdef HAVE_ALPN if(conn->bits.tls_enable_alpn) { char protocols[128]; @@ -495,7 +564,7 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn, /* we got a session id, use it! */ if(!SSL_set_session(backend->handle, ssl_sessionid)) { Curl_ssl_delsessionid(data, ssl_sessionid); - infof(data, "Can't use session ID, going on without\n"); + infof(data, "Can't use session ID, going on without"); } else infof(data, "SSL re-using session ID"); @@ -749,7 +818,7 @@ wolfssl_connect_step3(struct Curl_easy *data, struct connectdata *conn, if(!incache) { result = Curl_ssl_addsessionid(data, conn, isproxy, our_ssl_sessionid, - 0, sockindex); + 0, sockindex, NULL); if(result) { Curl_ssl_sessionid_unlock(data); failf(data, "failed to store ssl session"); |