summaryrefslogtreecommitdiffstats
path: root/lib/vtls
diff options
context:
space:
mode:
Diffstat (limited to 'lib/vtls')
-rw-r--r--lib/vtls/bearssl.c89
-rw-r--r--lib/vtls/gskit.c1329
-rw-r--r--lib/vtls/gskit.h40
-rw-r--r--lib/vtls/gtls.c2
-rw-r--r--lib/vtls/hostcheck.c5
-rw-r--r--lib/vtls/mbedtls.c10
-rw-r--r--lib/vtls/nss.c2551
-rw-r--r--lib/vtls/nssg.h41
-rw-r--r--lib/vtls/openssl.c80
-rw-r--r--lib/vtls/rustls.c18
-rw-r--r--lib/vtls/schannel.c74
-rw-r--r--lib/vtls/schannel.h3
-rw-r--r--lib/vtls/schannel_int.h52
-rw-r--r--lib/vtls/schannel_verify.c49
-rw-r--r--lib/vtls/sectransp.c64
-rw-r--r--lib/vtls/vtls.c59
-rw-r--r--lib/vtls/vtls.h2
-rw-r--r--lib/vtls/vtls_int.h2
-rw-r--r--lib/vtls/wolfssl.c176
-rw-r--r--lib/vtls/x509asn1.c21
-rw-r--r--lib/vtls/x509asn1.h7
21 files changed, 444 insertions, 4230 deletions
diff --git a/lib/vtls/bearssl.c b/lib/vtls/bearssl.c
index 6ed453b..934149c 100644
--- a/lib/vtls/bearssl.c
+++ b/lib/vtls/bearssl.c
@@ -587,6 +587,7 @@ static CURLcode bearssl_connect_step1(struct Curl_cfilter *cf,
const bool verifyhost = conn_config->verifyhost;
CURLcode ret;
unsigned version_min, version_max;
+ int session_set = 0;
#ifdef ENABLE_IPV6
struct in6_addr addr;
#else
@@ -594,6 +595,7 @@ static CURLcode bearssl_connect_step1(struct Curl_cfilter *cf,
#endif
DEBUGASSERT(backend);
+ CURL_TRC_CF(data, cf, "connect_step1");
switch(conn_config->version) {
case CURL_SSLVERSION_SSLv2:
@@ -624,38 +626,34 @@ static CURLcode bearssl_connect_step1(struct Curl_cfilter *cf,
return CURLE_SSL_CONNECT_ERROR;
}
- if(ca_info_blob) {
- struct cafile_source source;
- source.type = CAFILE_SOURCE_BLOB;
- source.data = ca_info_blob->data;
- source.len = ca_info_blob->len;
+ if(verifypeer) {
+ if(ca_info_blob) {
+ struct cafile_source source;
+ source.type = CAFILE_SOURCE_BLOB;
+ source.data = ca_info_blob->data;
+ source.len = ca_info_blob->len;
- ret = load_cafile(&source, &backend->anchors, &backend->anchors_len);
- if(ret != CURLE_OK) {
- if(verifypeer) {
+ CURL_TRC_CF(data, cf, "connect_step1, load ca_info_blob");
+ ret = load_cafile(&source, &backend->anchors, &backend->anchors_len);
+ if(ret != CURLE_OK) {
failf(data, "error importing CA certificate blob");
return ret;
}
- /* Only warn if no certificate verification is required. */
- infof(data, "error importing CA certificate blob, continuing anyway");
}
- }
- if(ssl_cafile) {
- struct cafile_source source;
- source.type = CAFILE_SOURCE_PATH;
- source.data = ssl_cafile;
- source.len = 0;
+ if(ssl_cafile) {
+ struct cafile_source source;
+ source.type = CAFILE_SOURCE_PATH;
+ source.data = ssl_cafile;
+ source.len = 0;
- ret = load_cafile(&source, &backend->anchors, &backend->anchors_len);
- if(ret != CURLE_OK) {
- if(verifypeer) {
+ CURL_TRC_CF(data, cf, "connect_step1, load cafile");
+ ret = load_cafile(&source, &backend->anchors, &backend->anchors_len);
+ if(ret != CURLE_OK) {
failf(data, "error setting certificate verify locations."
" CAfile: %s", ssl_cafile);
return ret;
}
- infof(data, "error setting certificate verify locations,"
- " continuing anyway:");
}
}
@@ -669,6 +667,7 @@ static CURLcode bearssl_connect_step1(struct Curl_cfilter *cf,
if(conn_config->cipher_list) {
/* Override the ciphers as specified. For the default cipher list see the
BearSSL source code of br_ssl_client_init_full() */
+ CURL_TRC_CF(data, cf, "connect_step1, set ciphers");
ret = bearssl_set_selected_ciphers(data, &backend->ctx.eng,
conn_config->cipher_list);
if(ret)
@@ -684,10 +683,12 @@ static CURLcode bearssl_connect_step1(struct Curl_cfilter *cf,
if(ssl_config->primary.sessionid) {
void *session;
+ CURL_TRC_CF(data, cf, "connect_step1, check session cache");
Curl_ssl_sessionid_lock(data);
if(!Curl_ssl_getsessionid(cf, data, &session, NULL)) {
br_ssl_engine_set_session_parameters(&backend->ctx.eng, session);
- infof(data, "BearSSL: re-using session ID");
+ session_set = 1;
+ infof(data, "BearSSL: reusing session ID");
}
Curl_ssl_sessionid_unlock(data);
}
@@ -724,6 +725,7 @@ static CURLcode bearssl_connect_step1(struct Curl_cfilter *cf,
return CURLE_SSL_CONNECT_ERROR;
}
hostname = snihost;
+ CURL_TRC_CF(data, cf, "connect_step1, SNI set");
}
/* give application a chance to interfere with SSL set up. */
@@ -738,7 +740,7 @@ static CURLcode bearssl_connect_step1(struct Curl_cfilter *cf,
}
}
- if(!br_ssl_client_reset(&backend->ctx, hostname, 1))
+ if(!br_ssl_client_reset(&backend->ctx, hostname, session_set))
return CURLE_FAILED_INIT;
backend->active = TRUE;
@@ -747,6 +749,28 @@ static CURLcode bearssl_connect_step1(struct Curl_cfilter *cf,
return CURLE_OK;
}
+static int bearssl_get_select_socks(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ curl_socket_t *socks)
+{
+ struct ssl_connect_data *connssl = cf->ctx;
+ curl_socket_t sock = Curl_conn_cf_get_socket(cf->next, data);
+
+ if(sock == CURL_SOCKET_BAD)
+ return GETSOCK_BLANK;
+ else {
+ struct bearssl_ssl_backend_data *backend =
+ (struct bearssl_ssl_backend_data *)connssl->backend;
+ unsigned state = br_ssl_engine_current_state(&backend->ctx.eng);
+ if(state & BR_SSL_SENDREC) {
+ socks[0] = sock;
+ return GETSOCK_WRITESOCK(0);
+ }
+ }
+ socks[0] = sock;
+ return GETSOCK_READSOCK(0);
+}
+
static CURLcode bearssl_run_until(struct Curl_cfilter *cf,
struct Curl_easy *data,
unsigned target)
@@ -798,6 +822,7 @@ static CURLcode bearssl_run_until(struct Curl_cfilter *cf,
if(state & BR_SSL_SENDREC) {
buf = br_ssl_engine_sendrec_buf(&backend->ctx.eng, &len);
ret = Curl_conn_cf_send(cf->next, data, (char *)buf, len, &result);
+ CURL_TRC_CF(data, cf, "ssl_send(len=%zu) -> %zd, %d", len, ret, result);
if(ret <= 0) {
return result;
}
@@ -806,6 +831,7 @@ static CURLcode bearssl_run_until(struct Curl_cfilter *cf,
else if(state & BR_SSL_RECVREC) {
buf = br_ssl_engine_recvrec_buf(&backend->ctx.eng, &len);
ret = Curl_conn_cf_recv(cf->next, data, (char *)buf, len, &result);
+ CURL_TRC_CF(data, cf, "ssl_recv(len=%zu) -> %zd, %d", len, ret, result);
if(ret == 0) {
failf(data, "SSL: EOF without close notify");
return CURLE_READ_ERROR;
@@ -827,16 +853,26 @@ static CURLcode bearssl_connect_step2(struct Curl_cfilter *cf,
CURLcode ret;
DEBUGASSERT(backend);
+ CURL_TRC_CF(data, cf, "connect_step2");
ret = bearssl_run_until(cf, data, BR_SSL_SENDAPP | BR_SSL_RECVAPP);
if(ret == CURLE_AGAIN)
return CURLE_OK;
if(ret == CURLE_OK) {
+ unsigned int tver;
if(br_ssl_engine_current_state(&backend->ctx.eng) == BR_SSL_CLOSED) {
failf(data, "SSL: connection closed during handshake");
return CURLE_SSL_CONNECT_ERROR;
}
connssl->connecting_state = ssl_connect_3;
+ /* Informational message */
+ tver = br_ssl_engine_get_version(&backend->ctx.eng);
+ if(tver == 0x0303)
+ infof(data, "SSL connection using TLSv1.2");
+ else if(tver == 0x0304)
+ infof(data, "SSL connection using TLSv1.3");
+ else
+ infof(data, "SSL connection using TLS 0x%x", tver);
}
return ret;
}
@@ -852,6 +888,7 @@ static CURLcode bearssl_connect_step3(struct Curl_cfilter *cf,
DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
DEBUGASSERT(backend);
+ CURL_TRC_CF(data, cf, "connect_step3");
if(connssl->alpn) {
const char *proto;
@@ -960,8 +997,10 @@ static CURLcode bearssl_connect_common(struct Curl_cfilter *cf,
timediff_t timeout_ms;
int what;
+ CURL_TRC_CF(data, cf, "connect_common(blocking=%d)", !nonblocking);
/* check if the connection has already been established */
if(ssl_connection_complete == connssl->state) {
+ CURL_TRC_CF(data, cf, "connect_common, connected");
*done = TRUE;
return CURLE_OK;
}
@@ -993,8 +1032,10 @@ static CURLcode bearssl_connect_common(struct Curl_cfilter *cf,
curl_socket_t readfd = ssl_connect_2_reading ==
connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
+ CURL_TRC_CF(data, cf, "connect_common, check socket");
what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
nonblocking?0:timeout_ms);
+ CURL_TRC_CF(data, cf, "connect_common, check socket -> %d", what);
if(what < 0) {
/* fatal error */
failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
@@ -1169,7 +1210,7 @@ const struct Curl_ssl Curl_ssl_bearssl = {
Curl_none_cert_status_request, /* cert_status_request */
bearssl_connect, /* connect */
bearssl_connect_nonblocking, /* connect_nonblocking */
- Curl_ssl_get_select_socks, /* getsock */
+ bearssl_get_select_socks, /* getsock */
bearssl_get_internals, /* get_internals */
bearssl_close, /* close_one */
Curl_none_close_all, /* close_all */
diff --git a/lib/vtls/gskit.c b/lib/vtls/gskit.c
deleted file mode 100644
index c128293..0000000
--- a/lib/vtls/gskit.c
+++ /dev/null
@@ -1,1329 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at https://curl.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * SPDX-License-Identifier: curl
- *
- ***************************************************************************/
-
-#include "curl_setup.h"
-
-#ifdef USE_GSKIT
-
-#include <gskssl.h>
-#include <qsoasync.h>
-#undef HAVE_SOCKETPAIR /* because the native one isn't good enough */
-#include "socketpair.h"
-#include "strerror.h"
-
-/* Some symbols are undefined/unsupported on OS400 versions < V7R1. */
-#ifndef GSK_SSL_EXTN_SERVERNAME_REQUEST
-#define GSK_SSL_EXTN_SERVERNAME_REQUEST 230
-#endif
-
-#ifndef GSK_TLSV10_CIPHER_SPECS
-#define GSK_TLSV10_CIPHER_SPECS 236
-#endif
-
-#ifndef GSK_TLSV11_CIPHER_SPECS
-#define GSK_TLSV11_CIPHER_SPECS 237
-#endif
-
-#ifndef GSK_TLSV12_CIPHER_SPECS
-#define GSK_TLSV12_CIPHER_SPECS 238
-#endif
-
-#ifndef GSK_PROTOCOL_TLSV11
-#define GSK_PROTOCOL_TLSV11 437
-#endif
-
-#ifndef GSK_PROTOCOL_TLSV12
-#define GSK_PROTOCOL_TLSV12 438
-#endif
-
-#ifndef GSK_FALSE
-#define GSK_FALSE 0
-#endif
-
-#ifndef GSK_TRUE
-#define GSK_TRUE 1
-#endif
-
-
-#include <limits.h>
-
-#include <curl/curl.h>
-#include "urldata.h"
-#include "sendf.h"
-#include "gskit.h"
-#include "vtls.h"
-#include "vtls_int.h"
-#include "connect.h" /* for the connect timeout */
-#include "select.h"
-#include "strcase.h"
-#include "timediff.h"
-#include "x509asn1.h"
-#include "curl_printf.h"
-
-#include "curl_memory.h"
-/* The last #include file should be: */
-#include "memdebug.h"
-
-
-/* Directions. */
-#define SOS_READ 0x01
-#define SOS_WRITE 0x02
-
-/* SSL version flags. */
-#define CURL_GSKPROTO_SSLV2 0
-#define CURL_GSKPROTO_SSLV2_MASK (1 << CURL_GSKPROTO_SSLV2)
-#define CURL_GSKPROTO_SSLV3 1
-#define CURL_GSKPROTO_SSLV3_MASK (1 << CURL_GSKPROTO_SSLV3)
-#define CURL_GSKPROTO_TLSV10 2
-#define CURL_GSKPROTO_TLSV10_MASK (1 << CURL_GSKPROTO_TLSV10)
-#define CURL_GSKPROTO_TLSV11 3
-#define CURL_GSKPROTO_TLSV11_MASK (1 << CURL_GSKPROTO_TLSV11)
-#define CURL_GSKPROTO_TLSV12 4
-#define CURL_GSKPROTO_TLSV12_MASK (1 << CURL_GSKPROTO_TLSV12)
-#define CURL_GSKPROTO_LAST 5
-
-struct gskit_ssl_backend_data {
- gsk_handle handle;
- int iocport;
- int localfd;
- int remotefd;
-};
-
-#define BACKEND ((struct gskit_ssl_backend_data *)connssl->backend)
-
-/* Supported ciphers. */
-struct gskit_cipher {
- const char *name; /* Cipher name. */
- const char *gsktoken; /* Corresponding token for GSKit String. */
- unsigned int versions; /* SSL version flags. */
-};
-
-static const struct gskit_cipher ciphertable[] = {
- { "null-md5", "01",
- CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK |
- CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK },
- { "null-sha", "02",
- CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK |
- CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK },
- { "exp-rc4-md5", "03",
- CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK },
- { "rc4-md5", "04",
- CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK |
- CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK },
- { "rc4-sha", "05",
- CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK |
- CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK },
- { "exp-rc2-cbc-md5", "06",
- CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK },
- { "exp-des-cbc-sha", "09",
- CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK |
- CURL_GSKPROTO_TLSV11_MASK },
- { "des-cbc3-sha", "0A",
- CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK |
- CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK },
- { "aes128-sha", "2F",
- CURL_GSKPROTO_TLSV10_MASK | CURL_GSKPROTO_TLSV11_MASK |
- CURL_GSKPROTO_TLSV12_MASK },
- { "aes256-sha", "35",
- CURL_GSKPROTO_TLSV10_MASK | CURL_GSKPROTO_TLSV11_MASK |
- CURL_GSKPROTO_TLSV12_MASK },
- { "null-sha256", "3B", CURL_GSKPROTO_TLSV12_MASK },
- { "aes128-sha256", "3C", CURL_GSKPROTO_TLSV12_MASK },
- { "aes256-sha256", "3D", CURL_GSKPROTO_TLSV12_MASK },
- { "aes128-gcm-sha256",
- "9C", CURL_GSKPROTO_TLSV12_MASK },
- { "aes256-gcm-sha384",
- "9D", CURL_GSKPROTO_TLSV12_MASK },
- { "rc4-md5", "1", CURL_GSKPROTO_SSLV2_MASK },
- { "exp-rc4-md5", "2", CURL_GSKPROTO_SSLV2_MASK },
- { "rc2-md5", "3", CURL_GSKPROTO_SSLV2_MASK },
- { "exp-rc2-md5", "4", CURL_GSKPROTO_SSLV2_MASK },
- { "des-cbc-md5", "6", CURL_GSKPROTO_SSLV2_MASK },
- { "des-cbc3-md5", "7", CURL_GSKPROTO_SSLV2_MASK },
- { (const char *) NULL, (const char *) NULL, 0 }
-};
-
-
-static bool is_separator(char c)
-{
- /* Return whether character is a cipher list separator. */
- switch(c) {
- case ' ':
- case '\t':
- case ':':
- case ',':
- case ';':
- return true;
- }
- return false;
-}
-
-
-static CURLcode gskit_status(struct Curl_easy *data, int rc,
- const char *procname, CURLcode defcode)
-{
- char buffer[STRERROR_LEN];
- /* Process GSKit status and map it to a CURLcode. */
- switch(rc) {
- case GSK_OK:
- case GSK_OS400_ASYNCHRONOUS_SOC_INIT:
- return CURLE_OK;
- case GSK_KEYRING_OPEN_ERROR:
- case GSK_OS400_ERROR_NO_ACCESS:
- return CURLE_SSL_CACERT_BADFILE;
- case GSK_INSUFFICIENT_STORAGE:
- return CURLE_OUT_OF_MEMORY;
- case GSK_ERROR_BAD_V2_CIPHER:
- case GSK_ERROR_BAD_V3_CIPHER:
- case GSK_ERROR_NO_CIPHERS:
- return CURLE_SSL_CIPHER;
- case GSK_OS400_ERROR_NOT_TRUSTED_ROOT:
- case GSK_ERROR_CERT_VALIDATION:
- return CURLE_PEER_FAILED_VERIFICATION;
- case GSK_OS400_ERROR_TIMED_OUT:
- return CURLE_OPERATION_TIMEDOUT;
- case GSK_WOULD_BLOCK:
- return CURLE_AGAIN;
- case GSK_OS400_ERROR_NOT_REGISTERED:
- break;
- case GSK_ERROR_IO:
- switch(errno) {
- case ENOMEM:
- return CURLE_OUT_OF_MEMORY;
- default:
- failf(data, "%s I/O error: %s", procname,
- Curl_strerror(errno, buffer, sizeof(buffer)));
- break;
- }
- break;
- default:
- failf(data, "%s: %s", procname, gsk_strerror(rc));
- break;
- }
- return defcode;
-}
-
-
-static CURLcode set_enum(struct Curl_easy *data, gsk_handle h,
- GSK_ENUM_ID id, GSK_ENUM_VALUE value, bool unsupported_ok)
-{
- char buffer[STRERROR_LEN];
- int rc = gsk_attribute_set_enum(h, id, value);
-
- switch(rc) {
- case GSK_OK:
- return CURLE_OK;
- case GSK_ERROR_IO:
- failf(data, "gsk_attribute_set_enum() I/O error: %s",
- Curl_strerror(errno, buffer, sizeof(buffer)));
- break;
- case GSK_ATTRIBUTE_INVALID_ID:
- if(unsupported_ok)
- return CURLE_UNSUPPORTED_PROTOCOL;
- default:
- failf(data, "gsk_attribute_set_enum(): %s", gsk_strerror(rc));
- break;
- }
- return CURLE_SSL_CONNECT_ERROR;
-}
-
-
-static CURLcode set_buffer(struct Curl_easy *data, gsk_handle h,
- GSK_BUF_ID id, const char *buf, bool unsupported_ok)
-{
- char buffer[STRERROR_LEN];
- int rc = gsk_attribute_set_buffer(h, id, buf, 0);
-
- switch(rc) {
- case GSK_OK:
- return CURLE_OK;
- case GSK_ERROR_IO:
- failf(data, "gsk_attribute_set_buffer() I/O error: %s",
- Curl_strerror(errno, buffer, sizeof(buffer)));
- break;
- case GSK_ATTRIBUTE_INVALID_ID:
- if(unsupported_ok)
- return CURLE_UNSUPPORTED_PROTOCOL;
- default:
- failf(data, "gsk_attribute_set_buffer(): %s", gsk_strerror(rc));
- break;
- }
- return CURLE_SSL_CONNECT_ERROR;
-}
-
-
-static CURLcode set_numeric(struct Curl_easy *data,
- gsk_handle h, GSK_NUM_ID id, int value)
-{
- char buffer[STRERROR_LEN];
- int rc = gsk_attribute_set_numeric_value(h, id, value);
-
- switch(rc) {
- case GSK_OK:
- return CURLE_OK;
- case GSK_ERROR_IO:
- failf(data, "gsk_attribute_set_numeric_value() I/O error: %s",
- Curl_strerror(errno, buffer, sizeof(buffer)));
- break;
- default:
- failf(data, "gsk_attribute_set_numeric_value(): %s", gsk_strerror(rc));
- break;
- }
- return CURLE_SSL_CONNECT_ERROR;
-}
-
-
-static CURLcode set_ciphers(struct Curl_cfilter *cf, struct Curl_easy *data,
- gsk_handle h, unsigned int *protoflags)
-{
- struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
- struct connectdata *conn = data->conn;
- const char *cipherlist = conn_config->cipher_list;
- const char *clp;
- const struct gskit_cipher *ctp;
- int i;
- int l;
- bool unsupported;
- CURLcode result;
- struct {
- char *buf;
- char *ptr;
- } ciphers[CURL_GSKPROTO_LAST];
-
- /* Compile cipher list into GSKit-compatible cipher lists. */
-
- if(!cipherlist)
- return CURLE_OK;
- while(is_separator(*cipherlist)) /* Skip initial separators. */
- cipherlist++;
- if(!*cipherlist)
- return CURLE_OK;
-
- /* We allocate GSKit buffers of the same size as the input string: since
- GSKit tokens are always shorter than their cipher names, allocated buffers
- will always be large enough to accommodate the result. */
- l = strlen(cipherlist) + 1;
- memset(ciphers, 0, sizeof(ciphers));
- for(i = 0; i < CURL_GSKPROTO_LAST; i++) {
- ciphers[i].buf = malloc(l);
- if(!ciphers[i].buf) {
- while(i--)
- free(ciphers[i].buf);
- return CURLE_OUT_OF_MEMORY;
- }
- ciphers[i].ptr = ciphers[i].buf;
- *ciphers[i].ptr = '\0';
- }
-
- /* Process each cipher in input string. */
- unsupported = FALSE;
- result = CURLE_OK;
- for(;;) {
- for(clp = cipherlist; *cipherlist && !is_separator(*cipherlist);)
- cipherlist++;
- l = cipherlist - clp;
- if(!l)
- break;
- /* Search the cipher in our table. */
- for(ctp = ciphertable; ctp->name; ctp++)
- if(strncasecompare(ctp->name, clp, l) && !ctp->name[l])
- break;
- if(!ctp->name) {
- failf(data, "Unknown cipher %.*s", l, clp);
- result = CURLE_SSL_CIPHER;
- }
- else {
- unsupported |= !(ctp->versions & (CURL_GSKPROTO_SSLV2_MASK |
- CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK));
- for(i = 0; i < CURL_GSKPROTO_LAST; i++) {
- if(ctp->versions & (1 << i)) {
- strcpy(ciphers[i].ptr, ctp->gsktoken);
- ciphers[i].ptr += strlen(ctp->gsktoken);
- }
- }
- }
-
- /* Advance to next cipher name or end of string. */
- while(is_separator(*cipherlist))
- cipherlist++;
- }
-
- /* Disable protocols with empty cipher lists. */
- for(i = 0; i < CURL_GSKPROTO_LAST; i++) {
- if(!(*protoflags & (1 << i)) || !ciphers[i].buf[0]) {
- *protoflags &= ~(1 << i);
- ciphers[i].buf[0] = '\0';
- }
- }
-
- /* Try to set-up TLSv1.1 and TLSv2.1 ciphers. */
- if(*protoflags & CURL_GSKPROTO_TLSV11_MASK) {
- result = set_buffer(data, h, GSK_TLSV11_CIPHER_SPECS,
- ciphers[CURL_GSKPROTO_TLSV11].buf, TRUE);
- if(result == CURLE_UNSUPPORTED_PROTOCOL) {
- result = CURLE_OK;
- if(unsupported) {
- failf(data, "TLSv1.1-only ciphers are not yet supported");
- result = CURLE_SSL_CIPHER;
- }
- }
- }
- if(!result && (*protoflags & CURL_GSKPROTO_TLSV12_MASK)) {
- result = set_buffer(data, h, GSK_TLSV12_CIPHER_SPECS,
- ciphers[CURL_GSKPROTO_TLSV12].buf, TRUE);
- if(result == CURLE_UNSUPPORTED_PROTOCOL) {
- result = CURLE_OK;
- if(unsupported) {
- failf(data, "TLSv1.2-only ciphers are not yet supported");
- result = CURLE_SSL_CIPHER;
- }
- }
- }
-
- /* Try to set-up TLSv1.0 ciphers. If not successful, concatenate them to
- the SSLv3 ciphers. OS/400 prior to version 7.1 will understand it. */
- if(!result && (*protoflags & CURL_GSKPROTO_TLSV10_MASK)) {
- result = set_buffer(data, h, GSK_TLSV10_CIPHER_SPECS,
- ciphers[CURL_GSKPROTO_TLSV10].buf, TRUE);
- if(result == CURLE_UNSUPPORTED_PROTOCOL) {
- result = CURLE_OK;
- strcpy(ciphers[CURL_GSKPROTO_SSLV3].ptr,
- ciphers[CURL_GSKPROTO_TLSV10].ptr);
- }
- }
-
- /* Set-up other ciphers. */
- if(!result && (*protoflags & CURL_GSKPROTO_SSLV3_MASK))
- result = set_buffer(data, h, GSK_V3_CIPHER_SPECS,
- ciphers[CURL_GSKPROTO_SSLV3].buf, FALSE);
- if(!result && (*protoflags & CURL_GSKPROTO_SSLV2_MASK))
- result = set_buffer(data, h, GSK_V2_CIPHER_SPECS,
- ciphers[CURL_GSKPROTO_SSLV2].buf, FALSE);
-
- /* Clean-up. */
- for(i = 0; i < CURL_GSKPROTO_LAST; i++)
- free(ciphers[i].buf);
-
- return result;
-}
-
-
-static int gskit_init(void)
-{
- /* No initialization needed. */
- return 1;
-}
-
-
-static void gskit_cleanup(void)
-{
- /* Nothing to do. */
-}
-
-
-static CURLcode init_environment(struct Curl_easy *data,
- gsk_handle *envir, const char *appid,
- const char *file, const char *label,
- const char *password)
-{
- int rc;
- CURLcode result;
- gsk_handle h;
-
- /* Creates the GSKit environment. */
-
- rc = gsk_environment_open(&h);
- switch(rc) {
- case GSK_OK:
- break;
- case GSK_INSUFFICIENT_STORAGE:
- return CURLE_OUT_OF_MEMORY;
- default:
- failf(data, "gsk_environment_open(): %s", gsk_strerror(rc));
- return CURLE_SSL_CONNECT_ERROR;
- }
-
- result = set_enum(data, h, GSK_SESSION_TYPE, GSK_CLIENT_SESSION, FALSE);
- if(!result && appid)
- result = set_buffer(data, h, GSK_OS400_APPLICATION_ID, appid, FALSE);
- if(!result && file)
- result = set_buffer(data, h, GSK_KEYRING_FILE, file, FALSE);
- if(!result && label)
- result = set_buffer(data, h, GSK_KEYRING_LABEL, label, FALSE);
- if(!result && password)
- result = set_buffer(data, h, GSK_KEYRING_PW, password, FALSE);
-
- if(!result) {
- /* Locate CAs, Client certificate and key according to our settings.
- Note: this call may be blocking for some tenths of seconds. */
- result = gskit_status(data, gsk_environment_init(h),
- "gsk_environment_init()", CURLE_SSL_CERTPROBLEM);
- if(!result) {
- *envir = h;
- return result;
- }
- }
- /* Error: rollback. */
- gsk_environment_close(&h);
- return result;
-}
-
-
-static void cancel_async_handshake(struct Curl_cfilter *cf,
- struct Curl_easy *data)
-{
- struct ssl_connect_data *connssl = cf->ctx;
- Qso_OverlappedIO_t cstat;
-
- (void)data;
- DEBUGASSERT(BACKEND);
-
- if(QsoCancelOperation(Curl_conn_cf_get_socket(cf, data), 0) > 0)
- QsoWaitForIOCompletion(BACKEND->iocport, &cstat, (struct timeval *) NULL);
-}
-
-
-static void close_async_handshake(struct ssl_connect_data *connssl)
-{
- DEBUGASSERT(BACKEND);
- QsoDestroyIOCompletionPort(BACKEND->iocport);
- BACKEND->iocport = -1;
-}
-
-static int pipe_ssloverssl(struct Curl_cfilter *cf, struct Curl_easy *data,
- int directions)
-{
- struct ssl_connect_data *connssl = cf->ctx;
- struct Curl_cfilter *cf_ssl_next = Curl_ssl_cf_get_ssl(cf->next);
- struct ssl_connect_data *connssl_next = cf_ssl_next?
- cf_ssl_next->ctx : NULL;
- struct gskit_ssl_backend_data *backend_next;
- struct pollfd fds[2];
- int n;
- int m;
- int i;
- int ret = 0;
- char buf[CURL_MAX_WRITE_SIZE];
-
- DEBUGASSERT(BACKEND);
-
- if(!connssl_next)
- return 0; /* No SSL over SSL: OK. */
-
- DEBUGASSERT(connssl_next->backend);
- backend_next = (struct gskit_ssl_backend_data *)connssl_next->backend;
-
- n = 1;
- fds[0].fd = BACKEND->remotefd;
- fds[1].fd = Curl_conn_cf_get_socket(cf, data);
-
- if(directions & SOS_READ) {
- fds[0].events |= POLLOUT;
- }
- if(directions & SOS_WRITE) {
- n = 2;
- fds[0].events |= POLLIN;
- fds[1].events |= POLLOUT;
- }
- i = Curl_poll(fds, n, 0);
- if(i < 0)
- return -1; /* Select error. */
-
- if(fds[0].revents & POLLOUT) {
- /* Try getting data from HTTPS proxy and pipe it upstream. */
- n = 0;
- i = gsk_secure_soc_read(backend_next->handle, buf, sizeof(buf), &n);
- switch(i) {
- case GSK_OK:
- if(n) {
- i = write(BACKEND->remotefd, buf, n);
- if(i < 0)
- return -1;
- ret = 1;
- }
- break;
- case GSK_OS400_ERROR_TIMED_OUT:
- case GSK_WOULD_BLOCK:
- break;
- default:
- return -1;
- }
- }
-
- if((fds[0].revents & POLLIN) && (fds[1].revents & POLLOUT)) {
- /* Pipe data to HTTPS proxy. */
- n = read(BACKEND->remotefd, buf, sizeof(buf));
- if(n < 0)
- return -1;
- if(n) {
- i = gsk_secure_soc_write(backend_next->handle, buf, n, &m);
- if(i != GSK_OK || n != m)
- return -1;
- ret = 1;
- }
- }
-
- return ret; /* OK */
-}
-
-
-static void close_one(struct Curl_cfilter *cf, struct Curl_easy *data)
-{
- struct ssl_connect_data *connssl = cf->ctx;
-
- DEBUGASSERT(BACKEND);
- if(BACKEND->handle) {
- gskit_status(data, gsk_secure_soc_close(&BACKEND->handle),
- "gsk_secure_soc_close()", 0);
- /* Last chance to drain output. */
- while(pipe_ssloverssl(cf, data, SOS_WRITE) > 0)
- ;
- BACKEND->handle = (gsk_handle) NULL;
- if(BACKEND->localfd >= 0) {
- close(BACKEND->localfd);
- BACKEND->localfd = -1;
- }
- if(BACKEND->remotefd >= 0) {
- close(BACKEND->remotefd);
- BACKEND->remotefd = -1;
- }
- }
- if(BACKEND->iocport >= 0)
- close_async_handshake(connssl);
-}
-
-
-static ssize_t gskit_send(struct Curl_cfilter *cf, struct Curl_easy *data,
- const void *mem, size_t len, CURLcode *curlcode)
-{
- struct connectdata *conn = cf->conn;
- struct ssl_connect_data *connssl = cf->ctx;
- CURLcode cc = CURLE_SEND_ERROR;
- int written;
-
- DEBUGASSERT(BACKEND);
-
- if(pipe_ssloverssl(cf, data, SOS_WRITE) >= 0) {
- cc = gskit_status(data,
- gsk_secure_soc_write(BACKEND->handle,
- (char *) mem, (int) len, &written),
- "gsk_secure_soc_write()", CURLE_SEND_ERROR);
- if(cc == CURLE_OK)
- if(pipe_ssloverssl(cf, data, SOS_WRITE) < 0)
- cc = CURLE_SEND_ERROR;
- }
- if(cc != CURLE_OK) {
- *curlcode = cc;
- written = -1;
- }
- return (ssize_t) written; /* number of bytes */
-}
-
-
-static ssize_t gskit_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
- char *buf, size_t buffersize, CURLcode *curlcode)
-{
- struct connectdata *conn = cf->conn;
- struct ssl_connect_data *connssl = cf->ctx;
- int nread;
- CURLcode cc = CURLE_RECV_ERROR;
-
- (void)data;
- DEBUGASSERT(BACKEND);
-
- if(pipe_ssloverssl(cf, data, SOS_READ) >= 0) {
- int buffsize = buffersize > (size_t) INT_MAX? INT_MAX: (int) buffersize;
- cc = gskit_status(data, gsk_secure_soc_read(BACKEND->handle,
- buf, buffsize, &nread),
- "gsk_secure_soc_read()", CURLE_RECV_ERROR);
- }
- switch(cc) {
- case CURLE_OK:
- break;
- case CURLE_OPERATION_TIMEDOUT:
- cc = CURLE_AGAIN;
- default:
- *curlcode = cc;
- nread = -1;
- break;
- }
- return (ssize_t) nread;
-}
-
-static CURLcode
-set_ssl_version_min_max(unsigned int *protoflags,
- struct Curl_cfilter *cf,
- struct Curl_easy *data)
-{
- struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
- struct connectdata *conn = data->conn;
- long ssl_version = conn_config->version;
- long ssl_version_max = conn_config->version_max;
- long i = ssl_version;
- switch(ssl_version_max) {
- case CURL_SSLVERSION_MAX_NONE:
- case CURL_SSLVERSION_MAX_DEFAULT:
- ssl_version_max = CURL_SSLVERSION_TLSv1_2;
- break;
- }
- for(; i <= (ssl_version_max >> 16); ++i) {
- switch(i) {
- case CURL_SSLVERSION_TLSv1_0:
- *protoflags |= CURL_GSKPROTO_TLSV10_MASK;
- break;
- case CURL_SSLVERSION_TLSv1_1:
- *protoflags |= CURL_GSKPROTO_TLSV11_MASK;
- break;
- case CURL_SSLVERSION_TLSv1_2:
- *protoflags |= CURL_GSKPROTO_TLSV11_MASK;
- break;
- case CURL_SSLVERSION_TLSv1_3:
- failf(data, "GSKit: TLS 1.3 is not yet supported");
- return CURLE_SSL_CONNECT_ERROR;
- }
- }
-
- return CURLE_OK;
-}
-
-static CURLcode gskit_connect_step1(struct Curl_cfilter *cf,
- struct Curl_easy *data)
-{
- struct ssl_connect_data *connssl = cf->ctx;
- struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
- struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
- struct Curl_cfilter *cf_ssl_next = Curl_ssl_cf_get_ssl(cf->next);
- struct ssl_connect_data *connssl_next = cf_ssl_next?
- cf_ssl_next->ctx : NULL;
- gsk_handle envir;
- CURLcode result;
- const char * const keyringfile = conn_config->CAfile;
- const char * const keyringpwd = ssl_config->key_passwd;
- const char * const keyringlabel = ssl_config->primary.clientcert;
- const long int ssl_version = conn_config->version;
- const bool verifypeer = conn_config->verifypeer;
- const char *hostname = connssl->hostname;
- const char *sni;
- unsigned int protoflags = 0;
- Qso_OverlappedIO_t commarea;
- int sockpair[2];
- static const int sobufsize = CURL_MAX_WRITE_SIZE;
-
- /* Create SSL environment, start (preferably asynchronous) handshake. */
- DEBUGASSERT(BACKEND);
-
- BACKEND->handle = (gsk_handle) NULL;
- BACKEND->iocport = -1;
- BACKEND->localfd = -1;
- BACKEND->remotefd = -1;
-
- /* GSKit supports two ways of specifying an SSL context: either by
- * application identifier (that should have been defined at the system
- * level) or by keyring file, password and certificate label.
- * Local certificate name (CURLOPT_SSLCERT) is used to hold either the
- * application identifier of the certificate label.
- * Key password (CURLOPT_KEYPASSWD) holds the keyring password.
- * It is not possible to have different keyrings for the CAs and the
- * local certificate. We thus use the CA file (CURLOPT_CAINFO) to identify
- * the keyring file.
- * If no key password is given and the keyring is the system keyring,
- * application identifier mode is tried first, as recommended in IBM doc.
- */
-
- envir = (gsk_handle) NULL;
-
- if(keyringlabel && *keyringlabel && !keyringpwd &&
- !strcmp(keyringfile, CURL_CA_BUNDLE)) {
- /* Try application identifier mode. */
- init_environment(data, &envir, keyringlabel, (const char *) NULL,
- (const char *) NULL, (const char *) NULL);
- }
-
- if(!envir) {
- /* Use keyring mode. */
- result = init_environment(data, &envir, (const char *) NULL,
- keyringfile, keyringlabel, keyringpwd);
- if(result)
- return result;
- }
-
- /* Create secure session. */
- result = gskit_status(data, gsk_secure_soc_open(envir, &BACKEND->handle),
- "gsk_secure_soc_open()", CURLE_SSL_CONNECT_ERROR);
- gsk_environment_close(&envir);
- if(result)
- return result;
-
- /* Establish a pipelining socket pair for SSL over SSL. */
- if(connssl_next) {
- if(Curl_socketpair(0, 0, 0, sockpair))
- return CURLE_SSL_CONNECT_ERROR;
- BACKEND->localfd = sockpair[0];
- BACKEND->remotefd = sockpair[1];
- setsockopt(BACKEND->localfd, SOL_SOCKET, SO_RCVBUF,
- (void *) &sobufsize, sizeof(sobufsize));
- setsockopt(BACKEND->remotefd, SOL_SOCKET, SO_RCVBUF,
- (void *) &sobufsize, sizeof(sobufsize));
- setsockopt(BACKEND->localfd, SOL_SOCKET, SO_SNDBUF,
- (void *) &sobufsize, sizeof(sobufsize));
- setsockopt(BACKEND->remotefd, SOL_SOCKET, SO_SNDBUF,
- (void *) &sobufsize, sizeof(sobufsize));
- curlx_nonblock(BACKEND->localfd, TRUE);
- curlx_nonblock(BACKEND->remotefd, TRUE);
- }
-
- /* Determine which SSL/TLS version should be enabled. */
- sni = hostname;
- switch(ssl_version) {
- case CURL_SSLVERSION_SSLv2:
- protoflags = CURL_GSKPROTO_SSLV2_MASK;
- sni = NULL;
- break;
- case CURL_SSLVERSION_SSLv3:
- protoflags = CURL_GSKPROTO_SSLV3_MASK;
- sni = NULL;
- break;
- case CURL_SSLVERSION_DEFAULT:
- case CURL_SSLVERSION_TLSv1:
- protoflags = CURL_GSKPROTO_TLSV10_MASK |
- CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK;
- break;
- case CURL_SSLVERSION_TLSv1_0:
- case CURL_SSLVERSION_TLSv1_1:
- case CURL_SSLVERSION_TLSv1_2:
- case CURL_SSLVERSION_TLSv1_3:
- result = set_ssl_version_min_max(&protoflags, cf, data);
- if(result != CURLE_OK)
- return result;
- break;
- default:
- failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
- return CURLE_SSL_CONNECT_ERROR;
- }
-
- /* Process SNI. Ignore if not supported (on OS400 < V7R1). */
- if(sni) {
- char *snihost = Curl_ssl_snihost(data, sni, NULL);
- if(!snihost) {
- failf(data, "Failed to set SNI");
- return CURLE_SSL_CONNECT_ERROR;
- }
- result = set_buffer(data, BACKEND->handle,
- GSK_SSL_EXTN_SERVERNAME_REQUEST, snihost, TRUE);
- if(result == CURLE_UNSUPPORTED_PROTOCOL)
- result = CURLE_OK;
- }
-
- /* Set session parameters. */
- if(!result) {
- /* Compute the handshake timeout. Since GSKit granularity is 1 second,
- we round up the required value. */
- timediff_t timeout = Curl_timeleft(data, NULL, TRUE);
- if(timeout < 0)
- result = CURLE_OPERATION_TIMEDOUT;
- else
- result = set_numeric(data, BACKEND->handle, GSK_HANDSHAKE_TIMEOUT,
- (timeout + 999) / 1000);
- }
- if(!result)
- result = set_numeric(data, BACKEND->handle, GSK_OS400_READ_TIMEOUT, 1);
- if(!result)
- result = set_numeric(data, BACKEND->handle, GSK_FD, BACKEND->localfd >= 0?
- BACKEND->localfd: Curl_conn_cf_get_socket(cf, data));
- if(!result)
- result = set_ciphers(cf, data, BACKEND->handle, &protoflags);
- if(!protoflags) {
- failf(data, "No SSL protocol/cipher combination enabled");
- result = CURLE_SSL_CIPHER;
- }
- if(!result)
- result = set_enum(data, BACKEND->handle, GSK_PROTOCOL_SSLV2,
- (protoflags & CURL_GSKPROTO_SSLV2_MASK)?
- GSK_PROTOCOL_SSLV2_ON: GSK_PROTOCOL_SSLV2_OFF, FALSE);
- if(!result)
- result = set_enum(data, BACKEND->handle, GSK_PROTOCOL_SSLV3,
- (protoflags & CURL_GSKPROTO_SSLV3_MASK)?
- GSK_PROTOCOL_SSLV3_ON: GSK_PROTOCOL_SSLV3_OFF, FALSE);
- if(!result)
- result = set_enum(data, BACKEND->handle, GSK_PROTOCOL_TLSV1,
- (protoflags & CURL_GSKPROTO_TLSV10_MASK)?
- GSK_PROTOCOL_TLSV1_ON: GSK_PROTOCOL_TLSV1_OFF, FALSE);
- if(!result) {
- result = set_enum(data, BACKEND->handle, GSK_PROTOCOL_TLSV11,
- (protoflags & CURL_GSKPROTO_TLSV11_MASK)?
- GSK_TRUE: GSK_FALSE, TRUE);
- if(result == CURLE_UNSUPPORTED_PROTOCOL) {
- result = CURLE_OK;
- if(protoflags == CURL_GSKPROTO_TLSV11_MASK) {
- failf(data, "TLS 1.1 not yet supported");
- result = CURLE_SSL_CIPHER;
- }
- }
- }
- if(!result) {
- result = set_enum(data, BACKEND->handle, GSK_PROTOCOL_TLSV12,
- (protoflags & CURL_GSKPROTO_TLSV12_MASK)?
- GSK_TRUE: GSK_FALSE, TRUE);
- if(result == CURLE_UNSUPPORTED_PROTOCOL) {
- result = CURLE_OK;
- if(protoflags == CURL_GSKPROTO_TLSV12_MASK) {
- failf(data, "TLS 1.2 not yet supported");
- result = CURLE_SSL_CIPHER;
- }
- }
- }
- if(!result)
- result = set_enum(data, BACKEND->handle, GSK_SERVER_AUTH_TYPE,
- verifypeer? GSK_SERVER_AUTH_FULL:
- GSK_SERVER_AUTH_PASSTHRU, FALSE);
-
- if(!result) {
- /* Start handshake. Try asynchronous first. */
- memset(&commarea, 0, sizeof(commarea));
- BACKEND->iocport = QsoCreateIOCompletionPort();
- if(BACKEND->iocport != -1) {
- result = gskit_status(data,
- gsk_secure_soc_startInit(BACKEND->handle,
- BACKEND->iocport,
- &commarea),
- "gsk_secure_soc_startInit()",
- CURLE_SSL_CONNECT_ERROR);
- if(!result) {
- connssl->connecting_state = ssl_connect_2;
- return CURLE_OK;
- }
- else
- close_async_handshake(connssl);
- }
- else if(errno != ENOBUFS)
- result = gskit_status(data, GSK_ERROR_IO,
- "QsoCreateIOCompletionPort()", 0);
- else if(connssl_next) {
- /* Cannot pipeline while handshaking synchronously. */
- result = CURLE_SSL_CONNECT_ERROR;
- }
- else {
- /* No more completion port available. Use synchronous IO. */
- result = gskit_status(data, gsk_secure_soc_init(BACKEND->handle),
- "gsk_secure_soc_init()", CURLE_SSL_CONNECT_ERROR);
- if(!result) {
- connssl->connecting_state = ssl_connect_3;
- return CURLE_OK;
- }
- }
- }
-
- /* Error: rollback. */
- close_one(cf, data);
- return result;
-}
-
-
-static CURLcode gskit_connect_step2(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- bool nonblocking)
-{
- struct ssl_connect_data *connssl = cf->ctx;
- Qso_OverlappedIO_t cstat;
- struct timeval stmv;
- CURLcode result;
-
- /* Poll or wait for end of SSL asynchronous handshake. */
- DEBUGASSERT(BACKEND);
-
- for(;;) {
- timediff_t timeout_ms = nonblocking? 0: Curl_timeleft(data, NULL, TRUE);
- stmv.tv_sec = 0;
- stmv.tv_usec = 0;
- if(timeout_ms < 0)
- timeout_ms = 0;
- switch(QsoWaitForIOCompletion(BACKEND->iocport, &cstat,
- curlx_mstotv(&stmv, timeout_ms))) {
- case 1: /* Operation complete. */
- break;
- case -1: /* An error occurred: handshake still in progress. */
- if(errno == EINTR) {
- if(nonblocking)
- return CURLE_OK;
- continue; /* Retry. */
- }
- if(errno != ETIME) {
- char buffer[STRERROR_LEN];
- failf(data, "QsoWaitForIOCompletion() I/O error: %s",
- Curl_strerror(errno, buffer, sizeof(buffer)));
- cancel_async_handshake(cf, data);
- close_async_handshake(connssl);
- return CURLE_SSL_CONNECT_ERROR;
- }
- /* FALL INTO... */
- case 0: /* Handshake in progress, timeout occurred. */
- if(nonblocking)
- return CURLE_OK;
- cancel_async_handshake(cf, data);
- close_async_handshake(connssl);
- return CURLE_OPERATION_TIMEDOUT;
- }
- break;
- }
- result = gskit_status(data, cstat.returnValue, "SSL handshake",
- CURLE_SSL_CONNECT_ERROR);
- if(!result)
- connssl->connecting_state = ssl_connect_3;
- close_async_handshake(connssl);
- return result;
-}
-
-
-static CURLcode gskit_connect_step3(struct Curl_cfilter *cf,
- struct Curl_easy *data)
-{
- struct ssl_connect_data *connssl = cf->ctx;
- const gsk_cert_data_elem *cdev;
- int cdec;
- const gsk_cert_data_elem *p;
- const char *cert = (const char *) NULL;
- const char *certend = (const char *) NULL;
- const char *ptr;
- CURLcode result;
-
- /* SSL handshake done: gather certificate info and verify host. */
- DEBUGASSERT(BACKEND);
-
- if(gskit_status(data, gsk_attribute_get_cert_info(BACKEND->handle,
- GSK_PARTNER_CERT_INFO,
- &cdev, &cdec),
- "gsk_attribute_get_cert_info()", CURLE_SSL_CONNECT_ERROR) ==
- CURLE_OK) {
- int i;
-
- infof(data, "Server certificate:");
- p = cdev;
- for(i = 0; i++ < cdec; p++)
- switch(p->cert_data_id) {
- case CERT_BODY_DER:
- cert = p->cert_data_p;
- certend = cert + cdev->cert_data_l;
- break;
- case CERT_DN_PRINTABLE:
- infof(data, "\t subject: %.*s", p->cert_data_l, p->cert_data_p);
- break;
- case CERT_ISSUER_DN_PRINTABLE:
- infof(data, "\t issuer: %.*s", p->cert_data_l, p->cert_data_p);
- break;
- case CERT_VALID_FROM:
- infof(data, "\t start date: %.*s", p->cert_data_l, p->cert_data_p);
- break;
- case CERT_VALID_TO:
- infof(data, "\t expire date: %.*s", p->cert_data_l, p->cert_data_p);
- break;
- }
- }
-
- /* Verify host. */
- result = Curl_verifyhost(cf, data, cert, certend);
- if(result)
- return result;
-
- /* The only place GSKit can get the whole CA chain is a validation
- callback where no user data pointer is available. Therefore it's not
- possible to copy this chain into our structures for CAINFO.
- However the server certificate may be available, thus we can return
- info about it. */
- if(data->set.ssl.certinfo) {
- result = Curl_ssl_init_certinfo(data, 1);
- if(result)
- return result;
-
- if(cert) {
- result = Curl_extract_certinfo(data, 0, cert, certend);
- if(result)
- return result;
- }
- }
-
- /* Check pinned public key. */
- ptr = Curl_ssl_cf_is_proxy(cf)?
- data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]:
- data->set.str[STRING_SSL_PINNEDPUBLICKEY];
- if(!result && ptr) {
- struct Curl_X509certificate x509;
- struct Curl_asn1Element *p;
-
- memset(&x509, 0, sizeof(x509));
- if(Curl_parseX509(&x509, cert, certend))
- return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
- p = &x509.subjectPublicKeyInfo;
- result = Curl_pin_peer_pubkey(data, ptr, p->header, p->end - p->header);
- if(result) {
- failf(data, "SSL: public key does not match pinned public key");
- return result;
- }
- }
-
- connssl->connecting_state = ssl_connect_done;
- return CURLE_OK;
-}
-
-
-static CURLcode gskit_connect_common(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- bool nonblocking, bool *done)
-{
- struct ssl_connect_data *connssl = cf->ctx;
- timediff_t timeout_ms;
- CURLcode result = CURLE_OK;
-
- *done = connssl->state == ssl_connection_complete;
- if(*done)
- return CURLE_OK;
-
- /* Step 1: create session, start handshake. */
- if(connssl->connecting_state == ssl_connect_1) {
- /* check allowed time left */
- timeout_ms = Curl_timeleft(data, NULL, TRUE);
-
- if(timeout_ms < 0) {
- /* no need to continue if time already is up */
- failf(data, "SSL connection timeout");
- result = CURLE_OPERATION_TIMEDOUT;
- }
- else
- result = gskit_connect_step1(cf, data);
- }
-
- /* Handle handshake pipelining. */
- if(!result)
- if(pipe_ssloverssl(cf, data, SOS_READ | SOS_WRITE) < 0)
- result = CURLE_SSL_CONNECT_ERROR;
-
- /* Step 2: check if handshake is over. */
- if(!result && connssl->connecting_state == ssl_connect_2) {
- /* check allowed time left */
- timeout_ms = Curl_timeleft(data, NULL, TRUE);
-
- if(timeout_ms < 0) {
- /* no need to continue if time already is up */
- failf(data, "SSL connection timeout");
- result = CURLE_OPERATION_TIMEDOUT;
- }
- else
- result = gskit_connect_step2(cf, data, nonblocking);
- }
-
- /* Handle handshake pipelining. */
- if(!result)
- if(pipe_ssloverssl(cf, data, SOS_READ | SOS_WRITE) < 0)
- result = CURLE_SSL_CONNECT_ERROR;
-
- /* Step 3: gather certificate info, verify host. */
- if(!result && connssl->connecting_state == ssl_connect_3)
- result = gskit_connect_step3(cf, data);
-
- if(result)
- close_one(cf, data);
- else if(connssl->connecting_state == ssl_connect_done) {
- connssl->state = ssl_connection_complete;
- connssl->connecting_state = ssl_connect_1;
- *done = TRUE;
- }
-
- return result;
-}
-
-
-static CURLcode gskit_connect_nonblocking(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- bool *done)
-{
- struct ssl_connect_data *connssl = cf->ctx;
- CURLcode result;
-
- result = gskit_connect_common(cf, data, TRUE, done);
- if(*done || result)
- connssl->connecting_state = ssl_connect_1;
- return result;
-}
-
-
-static CURLcode gskit_connect(struct Curl_cfilter *cf,
- struct Curl_easy *data)
-{
- struct ssl_connect_data *connssl = cf->ctx;
- CURLcode result;
- bool done;
-
- connssl->connecting_state = ssl_connect_1;
- result = gskit_connect_common(cf, data, FALSE, &done);
- if(result)
- return result;
-
- DEBUGASSERT(done);
-
- return CURLE_OK;
-}
-
-
-static void gskit_close(struct Curl_cfilter *cf, struct Curl_easy *data)
-{
- close_one(cf, data);
-}
-
-
-static int gskit_shutdown(struct Curl_cfilter *cf,
- struct Curl_easy *data)
-{
- struct ssl_connect_data *connssl = cf->ctx;
- int what;
- int rc;
- char buf[120];
- int loop = 10; /* don't get stuck */
-
- DEBUGASSERT(BACKEND);
-
- if(!BACKEND->handle)
- return 0;
-
-#ifndef CURL_DISABLE_FTP
- if(data->set.ftp_ccc != CURLFTPSSL_CCC_ACTIVE)
- return 0;
-#endif
-
- close_one(cf, data);
- rc = 0;
- what = SOCKET_READABLE(Curl_conn_cf_get_socket(cf, data),
- SSL_SHUTDOWN_TIMEOUT);
-
- while(loop--) {
- ssize_t nread;
-
- if(what < 0) {
- /* anything that gets here is fatally bad */
- failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
- rc = -1;
- break;
- }
-
- if(!what) { /* timeout */
- failf(data, "SSL shutdown timeout");
- break;
- }
-
- /* Something to read, let's do it and hope that it is the close
- notify alert from the server. No way to gsk_secure_soc_read() now, so
- use read(). */
-
- nread = read(Curl_conn_cf_get_socket(cf, data), buf, sizeof(buf));
-
- if(nread < 0) {
- char buffer[STRERROR_LEN];
- failf(data, "read: %s", Curl_strerror(errno, buffer, sizeof(buffer)));
- rc = -1;
- }
-
- if(nread <= 0)
- break;
-
- what = SOCKET_READABLE(Curl_conn_cf_get_socket(cf, data), 0);
- }
-
- return rc;
-}
-
-
-static size_t gskit_version(char *buffer, size_t size)
-{
- return msnprintf(buffer, size, "GSKit");
-}
-
-
-static int gskit_check_cxn(struct Curl_cfilter *cf,
- struct Curl_easy *data)
-{
- struct ssl_connect_data *connssl = cf->ctx;
- int err;
- int errlen;
-
- (void)data;
- /* The only thing that can be tested here is at the socket level. */
- DEBUGASSERT(BACKEND);
-
- if(!BACKEND->handle)
- return 0; /* connection has been closed */
-
- err = 0;
- errlen = sizeof(err);
-
- if(getsockopt(Curl_conn_cf_get_socket(cf, data), SOL_SOCKET, SO_ERROR,
- (unsigned char *) &err, &errlen) ||
- errlen != sizeof(err) || err)
- return 0; /* connection has been closed */
-
- return -1; /* connection status unknown */
-}
-
-static void *gskit_get_internals(struct ssl_connect_data *connssl,
- CURLINFO info UNUSED_PARAM)
-{
- (void)info;
- DEBUGASSERT(BACKEND);
- return BACKEND->handle;
-}
-
-const struct Curl_ssl Curl_ssl_gskit = {
- { CURLSSLBACKEND_GSKIT, "gskit" }, /* info */
-
- SSLSUPP_CERTINFO |
- SSLSUPP_PINNEDPUBKEY,
-
- sizeof(struct gskit_ssl_backend_data),
-
- gskit_init, /* init */
- gskit_cleanup, /* cleanup */
- gskit_version, /* version */
- gskit_check_cxn, /* check_cxn */
- gskit_shutdown, /* shutdown */
- Curl_none_data_pending, /* data_pending */
- Curl_none_random, /* random */
- Curl_none_cert_status_request, /* cert_status_request */
- gskit_connect, /* connect */
- gskit_connect_nonblocking, /* connect_nonblocking */
- Curl_ssl_get_select_socks, /* getsock */
- gskit_get_internals, /* get_internals */
- gskit_close, /* close_one */
- Curl_none_close_all, /* close_all */
- /* No session handling for GSKit */
- Curl_none_session_free, /* session_free */
- Curl_none_set_engine, /* set_engine */
- Curl_none_set_engine_default, /* set_engine_default */
- Curl_none_engines_list, /* engines_list */
- Curl_none_false_start, /* false_start */
- NULL, /* sha256sum */
- NULL, /* associate_connection */
- NULL, /* disassociate_connection */
- NULL, /* free_multi_ssl_backend_data */
- gskit_recv, /* recv decrypted data */
- gskit_send, /* send data to encrypt */
-};
-
-#endif /* USE_GSKIT */
diff --git a/lib/vtls/gskit.h b/lib/vtls/gskit.h
deleted file mode 100644
index c71e6a0..0000000
--- a/lib/vtls/gskit.h
+++ /dev/null
@@ -1,40 +0,0 @@
-#ifndef HEADER_CURL_GSKIT_H
-#define HEADER_CURL_GSKIT_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at https://curl.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * SPDX-License-Identifier: curl
- *
- ***************************************************************************/
-#include "curl_setup.h"
-
-/*
- * This header should only be needed to get included by vtls.c and gskit.c
- */
-
-#include "urldata.h"
-
-#ifdef USE_GSKIT
-
-extern const struct Curl_ssl Curl_ssl_gskit;
-
-#endif /* USE_GSKIT */
-
-#endif /* HEADER_CURL_GSKIT_H */
diff --git a/lib/vtls/gtls.c b/lib/vtls/gtls.c
index f6f1e10..e483469 100644
--- a/lib/vtls/gtls.c
+++ b/lib/vtls/gtls.c
@@ -735,7 +735,7 @@ gtls_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
ssl_sessionid, ssl_idsize);
/* Informational message */
- infof(data, "SSL re-using session ID");
+ infof(data, "SSL reusing session ID");
}
Curl_ssl_sessionid_unlock(data);
}
diff --git a/lib/vtls/hostcheck.c b/lib/vtls/hostcheck.c
index d061c63..2726dca 100644
--- a/lib/vtls/hostcheck.c
+++ b/lib/vtls/hostcheck.c
@@ -24,8 +24,7 @@
#include "curl_setup.h"
-#if defined(USE_OPENSSL) \
- || defined(USE_GSKIT) \
+#if defined(USE_OPENSSL) \
|| defined(USE_SCHANNEL)
/* these backends use functions from this file */
@@ -133,4 +132,4 @@ bool Curl_cert_hostcheck(const char *match, size_t matchlen,
return FALSE;
}
-#endif /* OPENSSL, GSKIT or schannel+wince */
+#endif /* OPENSSL or SCHANNEL */
diff --git a/lib/vtls/mbedtls.c b/lib/vtls/mbedtls.c
index 8d0fa39..f45636e 100644
--- a/lib/vtls/mbedtls.c
+++ b/lib/vtls/mbedtls.c
@@ -165,8 +165,8 @@ static int bio_cf_write(void *bio, const unsigned char *buf, size_t blen)
DEBUGASSERT(data);
nwritten = Curl_conn_cf_send(cf->next, data, (char *)buf, blen, &result);
- DEBUGF(LOG_CF(data, cf, "bio_cf_out_write(len=%zu) -> %zd, err=%d",
- blen, nwritten, result));
+ CURL_TRC_CF(data, cf, "bio_cf_out_write(len=%zu) -> %zd, err=%d",
+ blen, nwritten, result);
if(nwritten < 0 && CURLE_AGAIN == result) {
nwritten = MBEDTLS_ERR_SSL_WANT_WRITE;
}
@@ -186,8 +186,8 @@ static int bio_cf_read(void *bio, unsigned char *buf, size_t blen)
return 0;
nread = Curl_conn_cf_recv(cf->next, data, (char *)buf, blen, &result);
- DEBUGF(LOG_CF(data, cf, "bio_cf_in_read(len=%zu) -> %zd, err=%d",
- blen, nread, result));
+ CURL_TRC_CF(data, cf, "bio_cf_in_read(len=%zu) -> %zd, err=%d",
+ blen, nread, result);
if(nread < 0 && CURLE_AGAIN == result) {
nread = MBEDTLS_ERR_SSL_WANT_READ;
}
@@ -619,7 +619,7 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
failf(data, "mbedtls_ssl_set_session returned -0x%x", -ret);
return CURLE_SSL_CONNECT_ERROR;
}
- infof(data, "mbedTLS re-using session");
+ infof(data, "mbedTLS reusing session");
}
Curl_ssl_sessionid_unlock(data);
}
diff --git a/lib/vtls/nss.c b/lib/vtls/nss.c
deleted file mode 100644
index 322f507..0000000
--- a/lib/vtls/nss.c
+++ /dev/null
@@ -1,2551 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at https://curl.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * SPDX-License-Identifier: curl
- *
- ***************************************************************************/
-
-/*
- * Source file for all NSS-specific code for the TLS/SSL layer. No code
- * but vtls.c should ever call or use these functions.
- */
-
-#include "curl_setup.h"
-
-#ifdef USE_NSS
-
-#include "urldata.h"
-#include "sendf.h"
-#include "formdata.h" /* for the boundary function */
-#include "url.h" /* for the ssl config check function */
-#include "connect.h"
-#include "strcase.h"
-#include "select.h"
-#include "vtls.h"
-#include "vtls_int.h"
-#include "llist.h"
-#include "multiif.h"
-#include "curl_printf.h"
-#include "nssg.h"
-#include <nspr.h>
-#include <nss.h>
-#include <ssl.h>
-#include <sslerr.h>
-#include <secerr.h>
-#include <secmod.h>
-#include <sslproto.h>
-#include <prtypes.h>
-#include <pk11pub.h>
-#include <prio.h>
-#include <secitem.h>
-#include <secport.h>
-#include <certdb.h>
-#include <base64.h>
-#include <cert.h>
-#include <prerror.h>
-#include <keyhi.h> /* for SECKEY_DestroyPublicKey() */
-#include <private/pprio.h> /* for PR_ImportTCPSocket */
-
-#define NSSVERNUM ((NSS_VMAJOR<<16)|(NSS_VMINOR<<8)|NSS_VPATCH)
-
-#if NSSVERNUM >= 0x030f00 /* 3.15.0 */
-#include <ocsp.h>
-#endif
-
-#include "warnless.h"
-#include "x509asn1.h"
-
-/* The last #include files should be: */
-#include "curl_memory.h"
-#include "memdebug.h"
-
-#define SSL_DIR "/etc/pki/nssdb"
-
-/* enough to fit the string "PEM Token #[0|1]" */
-#define SLOTSIZE 13
-
-struct nss_ssl_backend_data {
- PRFileDesc *handle;
- char *client_nickname;
- struct Curl_easy *data;
- struct Curl_llist obj_list;
- PK11GenericObject *obj_clicert;
-};
-
-static PRLock *nss_initlock = NULL;
-static PRLock *nss_crllock = NULL;
-static PRLock *nss_findslot_lock = NULL;
-static PRLock *nss_trustload_lock = NULL;
-static struct Curl_llist nss_crl_list;
-static NSSInitContext *nss_context = NULL;
-static volatile int initialized = 0;
-
-/* type used to wrap pointers as list nodes */
-struct ptr_list_wrap {
- void *ptr;
- struct Curl_llist_element node;
-};
-
-struct cipher_s {
- const char *name;
- int num;
-};
-
-#define PK11_SETATTRS(_attr, _idx, _type, _val, _len) do { \
- CK_ATTRIBUTE *ptr = (_attr) + ((_idx)++); \
- ptr->type = (_type); \
- ptr->pValue = (_val); \
- ptr->ulValueLen = (_len); \
-} while(0)
-
-#define CERT_NewTempCertificate __CERT_NewTempCertificate
-
-#define NUM_OF_CIPHERS sizeof(cipherlist)/sizeof(cipherlist[0])
-static const struct cipher_s cipherlist[] = {
- /* SSL2 cipher suites */
- {"rc4", SSL_EN_RC4_128_WITH_MD5},
- {"rc4-md5", SSL_EN_RC4_128_WITH_MD5},
- {"rc4export", SSL_EN_RC4_128_EXPORT40_WITH_MD5},
- {"rc2", SSL_EN_RC2_128_CBC_WITH_MD5},
- {"rc2export", SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5},
- {"des", SSL_EN_DES_64_CBC_WITH_MD5},
- {"desede3", SSL_EN_DES_192_EDE3_CBC_WITH_MD5},
- /* SSL3/TLS cipher suites */
- {"rsa_rc4_128_md5", SSL_RSA_WITH_RC4_128_MD5},
- {"rsa_rc4_128_sha", SSL_RSA_WITH_RC4_128_SHA},
- {"rsa_3des_sha", SSL_RSA_WITH_3DES_EDE_CBC_SHA},
- {"rsa_des_sha", SSL_RSA_WITH_DES_CBC_SHA},
- {"rsa_rc4_40_md5", SSL_RSA_EXPORT_WITH_RC4_40_MD5},
- {"rsa_rc2_40_md5", SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5},
- {"rsa_null_md5", SSL_RSA_WITH_NULL_MD5},
- {"rsa_null_sha", SSL_RSA_WITH_NULL_SHA},
- {"fips_3des_sha", SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA},
- {"fips_des_sha", SSL_RSA_FIPS_WITH_DES_CBC_SHA},
- {"fortezza", SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA},
- {"fortezza_rc4_128_sha", SSL_FORTEZZA_DMS_WITH_RC4_128_SHA},
- {"fortezza_null", SSL_FORTEZZA_DMS_WITH_NULL_SHA},
- {"dhe_rsa_3des_sha", SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA},
- {"dhe_dss_3des_sha", SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA},
- {"dhe_rsa_des_sha", SSL_DHE_RSA_WITH_DES_CBC_SHA},
- {"dhe_dss_des_sha", SSL_DHE_DSS_WITH_DES_CBC_SHA},
- /* TLS 1.0: Exportable 56-bit Cipher Suites. */
- {"rsa_des_56_sha", TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA},
- {"rsa_rc4_56_sha", TLS_RSA_EXPORT1024_WITH_RC4_56_SHA},
- /* Ephemeral DH with RC4 bulk encryption */
- {"dhe_dss_rc4_128_sha", TLS_DHE_DSS_WITH_RC4_128_SHA},
- /* AES ciphers. */
- {"dhe_dss_aes_128_cbc_sha", TLS_DHE_DSS_WITH_AES_128_CBC_SHA},
- {"dhe_dss_aes_256_cbc_sha", TLS_DHE_DSS_WITH_AES_256_CBC_SHA},
- {"dhe_rsa_aes_128_cbc_sha", TLS_DHE_RSA_WITH_AES_128_CBC_SHA},
- {"dhe_rsa_aes_256_cbc_sha", TLS_DHE_RSA_WITH_AES_256_CBC_SHA},
- {"rsa_aes_128_sha", TLS_RSA_WITH_AES_128_CBC_SHA},
- {"rsa_aes_256_sha", TLS_RSA_WITH_AES_256_CBC_SHA},
- /* ECC ciphers. */
- {"ecdh_ecdsa_null_sha", TLS_ECDH_ECDSA_WITH_NULL_SHA},
- {"ecdh_ecdsa_rc4_128_sha", TLS_ECDH_ECDSA_WITH_RC4_128_SHA},
- {"ecdh_ecdsa_3des_sha", TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA},
- {"ecdh_ecdsa_aes_128_sha", TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA},
- {"ecdh_ecdsa_aes_256_sha", TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA},
- {"ecdhe_ecdsa_null_sha", TLS_ECDHE_ECDSA_WITH_NULL_SHA},
- {"ecdhe_ecdsa_rc4_128_sha", TLS_ECDHE_ECDSA_WITH_RC4_128_SHA},
- {"ecdhe_ecdsa_3des_sha", TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA},
- {"ecdhe_ecdsa_aes_128_sha", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA},
- {"ecdhe_ecdsa_aes_256_sha", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA},
- {"ecdh_rsa_null_sha", TLS_ECDH_RSA_WITH_NULL_SHA},
- {"ecdh_rsa_128_sha", TLS_ECDH_RSA_WITH_RC4_128_SHA},
- {"ecdh_rsa_3des_sha", TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA},
- {"ecdh_rsa_aes_128_sha", TLS_ECDH_RSA_WITH_AES_128_CBC_SHA},
- {"ecdh_rsa_aes_256_sha", TLS_ECDH_RSA_WITH_AES_256_CBC_SHA},
- {"ecdhe_rsa_null", TLS_ECDHE_RSA_WITH_NULL_SHA},
- {"ecdhe_rsa_rc4_128_sha", TLS_ECDHE_RSA_WITH_RC4_128_SHA},
- {"ecdhe_rsa_3des_sha", TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA},
- {"ecdhe_rsa_aes_128_sha", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
- {"ecdhe_rsa_aes_256_sha", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA},
- {"ecdh_anon_null_sha", TLS_ECDH_anon_WITH_NULL_SHA},
- {"ecdh_anon_rc4_128sha", TLS_ECDH_anon_WITH_RC4_128_SHA},
- {"ecdh_anon_3des_sha", TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA},
- {"ecdh_anon_aes_128_sha", TLS_ECDH_anon_WITH_AES_128_CBC_SHA},
- {"ecdh_anon_aes_256_sha", TLS_ECDH_anon_WITH_AES_256_CBC_SHA},
-#ifdef TLS_RSA_WITH_NULL_SHA256
- /* new HMAC-SHA256 cipher suites specified in RFC */
- {"rsa_null_sha_256", TLS_RSA_WITH_NULL_SHA256},
- {"rsa_aes_128_cbc_sha_256", TLS_RSA_WITH_AES_128_CBC_SHA256},
- {"rsa_aes_256_cbc_sha_256", TLS_RSA_WITH_AES_256_CBC_SHA256},
- {"dhe_rsa_aes_128_cbc_sha_256", TLS_DHE_RSA_WITH_AES_128_CBC_SHA256},
- {"dhe_rsa_aes_256_cbc_sha_256", TLS_DHE_RSA_WITH_AES_256_CBC_SHA256},
- {"ecdhe_ecdsa_aes_128_cbc_sha_256", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256},
- {"ecdhe_rsa_aes_128_cbc_sha_256", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256},
-#endif
-#ifdef TLS_RSA_WITH_AES_128_GCM_SHA256
- /* AES GCM cipher suites in RFC 5288 and RFC 5289 */
- {"rsa_aes_128_gcm_sha_256", TLS_RSA_WITH_AES_128_GCM_SHA256},
- {"dhe_rsa_aes_128_gcm_sha_256", TLS_DHE_RSA_WITH_AES_128_GCM_SHA256},
- {"dhe_dss_aes_128_gcm_sha_256", TLS_DHE_DSS_WITH_AES_128_GCM_SHA256},
- {"ecdhe_ecdsa_aes_128_gcm_sha_256", TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
- {"ecdh_ecdsa_aes_128_gcm_sha_256", TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256},
- {"ecdhe_rsa_aes_128_gcm_sha_256", TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
- {"ecdh_rsa_aes_128_gcm_sha_256", TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256},
-#endif
-#ifdef TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
- /* cipher suites using SHA384 */
- {"rsa_aes_256_gcm_sha_384", TLS_RSA_WITH_AES_256_GCM_SHA384},
- {"dhe_rsa_aes_256_gcm_sha_384", TLS_DHE_RSA_WITH_AES_256_GCM_SHA384},
- {"dhe_dss_aes_256_gcm_sha_384", TLS_DHE_DSS_WITH_AES_256_GCM_SHA384},
- {"ecdhe_ecdsa_aes_256_sha_384", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384},
- {"ecdhe_rsa_aes_256_sha_384", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384},
- {"ecdhe_ecdsa_aes_256_gcm_sha_384", TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384},
- {"ecdhe_rsa_aes_256_gcm_sha_384", TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384},
-#endif
-#ifdef TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256
- /* chacha20-poly1305 cipher suites */
- {"ecdhe_rsa_chacha20_poly1305_sha_256",
- TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256},
- {"ecdhe_ecdsa_chacha20_poly1305_sha_256",
- TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256},
- {"dhe_rsa_chacha20_poly1305_sha_256",
- TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256},
-#endif
-#ifdef TLS_AES_256_GCM_SHA384
- {"aes_128_gcm_sha_256", TLS_AES_128_GCM_SHA256},
- {"aes_256_gcm_sha_384", TLS_AES_256_GCM_SHA384},
- {"chacha20_poly1305_sha_256", TLS_CHACHA20_POLY1305_SHA256},
-#endif
-#ifdef TLS_DHE_DSS_WITH_AES_128_CBC_SHA256
- /* AES CBC cipher suites in RFC 5246. Introduced in NSS release 3.20 */
- {"dhe_dss_aes_128_sha_256", TLS_DHE_DSS_WITH_AES_128_CBC_SHA256},
- {"dhe_dss_aes_256_sha_256", TLS_DHE_DSS_WITH_AES_256_CBC_SHA256},
-#endif
-#ifdef TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA
- /* Camellia cipher suites in RFC 4132/5932.
- Introduced in NSS release 3.12 */
- {"dhe_rsa_camellia_128_sha", TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA},
- {"dhe_dss_camellia_128_sha", TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA},
- {"dhe_rsa_camellia_256_sha", TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA},
- {"dhe_dss_camellia_256_sha", TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA},
- {"rsa_camellia_128_sha", TLS_RSA_WITH_CAMELLIA_128_CBC_SHA},
- {"rsa_camellia_256_sha", TLS_RSA_WITH_CAMELLIA_256_CBC_SHA},
-#endif
-#ifdef TLS_RSA_WITH_SEED_CBC_SHA
- /* SEED cipher suite in RFC 4162. Introduced in NSS release 3.12.3 */
- {"rsa_seed_sha", TLS_RSA_WITH_SEED_CBC_SHA},
-#endif
-};
-
-#if defined(WIN32)
-static const char *pem_library = "nsspem.dll";
-static const char *trust_library = "nssckbi.dll";
-#elif defined(__APPLE__)
-static const char *pem_library = "libnsspem.dylib";
-static const char *trust_library = "libnssckbi.dylib";
-#else
-static const char *pem_library = "libnsspem.so";
-static const char *trust_library = "libnssckbi.so";
-#endif
-
-static SECMODModule *pem_module = NULL;
-static SECMODModule *trust_module = NULL;
-
-/* NSPR I/O layer we use to detect blocking direction during SSL handshake */
-static PRDescIdentity nspr_io_identity = PR_INVALID_IO_LAYER;
-static PRIOMethods nspr_io_methods;
-
-static const char *nss_error_to_name(PRErrorCode code)
-{
- const char *name = PR_ErrorToName(code);
- if(name)
- return name;
-
- return "unknown error";
-}
-
-static void nss_print_error_message(struct Curl_easy *data, PRUint32 err)
-{
- failf(data, "%s", PR_ErrorToString(err, PR_LANGUAGE_I_DEFAULT));
-}
-
-static char *nss_sslver_to_name(PRUint16 nssver)
-{
- switch(nssver) {
- case SSL_LIBRARY_VERSION_2:
- return strdup("SSLv2");
- case SSL_LIBRARY_VERSION_3_0:
- return strdup("SSLv3");
- case SSL_LIBRARY_VERSION_TLS_1_0:
- return strdup("TLSv1.0");
-#ifdef SSL_LIBRARY_VERSION_TLS_1_1
- case SSL_LIBRARY_VERSION_TLS_1_1:
- return strdup("TLSv1.1");
-#endif
-#ifdef SSL_LIBRARY_VERSION_TLS_1_2
- case SSL_LIBRARY_VERSION_TLS_1_2:
- return strdup("TLSv1.2");
-#endif
-#ifdef SSL_LIBRARY_VERSION_TLS_1_3
- case SSL_LIBRARY_VERSION_TLS_1_3:
- return strdup("TLSv1.3");
-#endif
- default:
- return curl_maprintf("0x%04x", nssver);
- }
-}
-
-/* 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;
- const char *cipher;
-
- /* use accessors to avoid dynamic linking issues after an update of NSS */
- const PRUint16 num_implemented_ciphers = SSL_GetNumImplementedCiphers();
- const PRUint16 *implemented_ciphers = SSL_GetImplementedCiphers();
- if(!implemented_ciphers)
- return SECFailure;
-
- /* First disable all ciphers. This uses a different max value in case
- * NSS adds more ciphers later we don't want them available by
- * accident
- */
- for(i = 0; i < num_implemented_ciphers; i++) {
- SSL_CipherPrefSet(model, implemented_ciphers[i], PR_FALSE);
- }
-
- cipher = cipher_list;
-
- while(cipher && cipher[0]) {
- const char *end;
- char name[MAX_CIPHER_LENGTH + 1];
- size_t len;
- bool found = FALSE;
- while((*cipher) && (ISBLANK(*cipher)))
- ++cipher;
-
- end = strpbrk(cipher, ":, ");
- if(end)
- len = end - cipher;
- else
- len = strlen(cipher);
-
- if(len > MAX_CIPHER_LENGTH) {
- failf(data, "Bad cipher list");
- return SECFailure;
- }
- 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;
- }
- }
- }
-
- if(!found && len) {
- failf(data, "Unknown cipher: %s", name);
- return SECFailure;
- }
- if(end)
- cipher = ++end;
- else
- break;
- }
-
- return SECSuccess;
-}
-
-/*
- * Return true if at least one cipher-suite is enabled. Used to determine
- * if we need to call NSS_SetDomesticPolicy() to enable the default ciphers.
- */
-static bool any_cipher_enabled(void)
-{
- unsigned int i;
-
- for(i = 0; i<NUM_OF_CIPHERS; i++) {
- PRInt32 policy = 0;
- SSL_CipherPolicyGet(cipherlist[i].num, &policy);
- if(policy)
- return TRUE;
- }
-
- return FALSE;
-}
-
-/*
- * Determine whether the nickname passed in is a filename that needs to
- * be loaded as a PEM or a regular NSS nickname.
- *
- * returns 1 for a file
- * returns 0 for not a file (NSS nickname)
- */
-static int is_file(const char *filename)
-{
- struct_stat st;
-
- if(!filename)
- return 0;
-
- if(stat(filename, &st) == 0)
- if(S_ISREG(st.st_mode) || S_ISFIFO(st.st_mode) || S_ISCHR(st.st_mode))
- return 1;
-
- return 0;
-}
-
-/* Check if the given string is filename or nickname of a certificate. If the
- * given string is recognized as filename, return NULL. If the given string is
- * recognized as nickname, return a duplicated string. The returned string
- * should be later deallocated using free(). If the OOM failure occurs, we
- * return NULL, too.
- */
-static char *dup_nickname(struct Curl_easy *data, const char *str)
-{
- const char *n;
-
- if(!is_file(str))
- /* no such file exists, use the string as nickname */
- return strdup(str);
-
- /* search the first slash; we require at least one slash in a file name */
- n = strchr(str, '/');
- if(!n) {
- infof(data, "WARNING: certificate file name \"%s\" handled as nickname; "
- "please use \"./%s\" to force file name", str, str);
- return strdup(str);
- }
-
- /* we'll use the PEM reader to read the certificate from file */
- return NULL;
-}
-
-/* Lock/unlock wrapper for PK11_FindSlotByName() to work around race condition
- * in nssSlot_IsTokenPresent() causing spurious SEC_ERROR_NO_TOKEN. For more
- * details, go to <https://bugzilla.mozilla.org/1297397>.
- */
-static PK11SlotInfo* nss_find_slot_by_name(const char *slot_name)
-{
- PK11SlotInfo *slot;
- PR_Lock(nss_findslot_lock);
- slot = PK11_FindSlotByName(slot_name);
- PR_Unlock(nss_findslot_lock);
- return slot;
-}
-
-/* wrap 'ptr' as list node and tail-insert into 'list' */
-static CURLcode insert_wrapped_ptr(struct Curl_llist *list, void *ptr)
-{
- struct ptr_list_wrap *wrap = malloc(sizeof(*wrap));
- if(!wrap)
- return CURLE_OUT_OF_MEMORY;
-
- wrap->ptr = ptr;
- Curl_llist_insert_next(list, list->tail, wrap, &wrap->node);
- return CURLE_OK;
-}
-
-/* Call PK11_CreateGenericObject() with the given obj_class and filename. If
- * the call succeeds, append the object handle to the list of objects so that
- * the object can be destroyed in nss_close(). */
-static CURLcode nss_create_object(struct ssl_connect_data *connssl,
- CK_OBJECT_CLASS obj_class,
- const char *filename, bool cacert)
-{
- PK11SlotInfo *slot;
- PK11GenericObject *obj;
- CK_BBOOL cktrue = CK_TRUE;
- CK_BBOOL ckfalse = CK_FALSE;
- CK_ATTRIBUTE attrs[/* max count of attributes */ 4];
- int attr_cnt = 0;
- CURLcode result = (cacert)
- ? CURLE_SSL_CACERT_BADFILE
- : CURLE_SSL_CERTPROBLEM;
-
- const int slot_id = (cacert) ? 0 : 1;
- char *slot_name = aprintf("PEM Token #%d", slot_id);
- struct nss_ssl_backend_data *backend =
- (struct nss_ssl_backend_data *)connssl->backend;
-
- DEBUGASSERT(backend);
-
- if(!slot_name)
- return CURLE_OUT_OF_MEMORY;
-
- slot = nss_find_slot_by_name(slot_name);
- free(slot_name);
- if(!slot)
- return result;
-
- PK11_SETATTRS(attrs, attr_cnt, CKA_CLASS, &obj_class, sizeof(obj_class));
- PK11_SETATTRS(attrs, attr_cnt, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL));
- PK11_SETATTRS(attrs, attr_cnt, CKA_LABEL, (unsigned char *)filename,
- (CK_ULONG)strlen(filename) + 1);
-
- if(CKO_CERTIFICATE == obj_class) {
- CK_BBOOL *pval = (cacert) ? (&cktrue) : (&ckfalse);
- PK11_SETATTRS(attrs, attr_cnt, CKA_TRUST, pval, sizeof(*pval));
- }
-
- /* PK11_CreateManagedGenericObject() was introduced in NSS 3.34 because
- * PK11_DestroyGenericObject() does not release resources allocated by
- * PK11_CreateGenericObject() early enough. */
- obj =
-#ifdef HAVE_PK11_CREATEMANAGEDGENERICOBJECT
- PK11_CreateManagedGenericObject
-#else
- PK11_CreateGenericObject
-#endif
- (slot, attrs, attr_cnt, PR_FALSE);
-
- PK11_FreeSlot(slot);
- if(!obj)
- return result;
-
- if(insert_wrapped_ptr(&backend->obj_list, obj) != CURLE_OK) {
- PK11_DestroyGenericObject(obj);
- return CURLE_OUT_OF_MEMORY;
- }
-
- if(!cacert && CKO_CERTIFICATE == obj_class)
- /* store reference to a client certificate */
- backend->obj_clicert = obj;
-
- return CURLE_OK;
-}
-
-/* Destroy the NSS object whose handle is given by ptr. This function is
- * a callback of Curl_llist_alloc() used by Curl_llist_destroy() to destroy
- * NSS objects in nss_close() */
-static void nss_destroy_object(void *user, void *ptr)
-{
- struct ptr_list_wrap *wrap = (struct ptr_list_wrap *) ptr;
- PK11GenericObject *obj = (PK11GenericObject *) wrap->ptr;
- (void) user;
- PK11_DestroyGenericObject(obj);
- free(wrap);
-}
-
-/* same as nss_destroy_object() but for CRL items */
-static void nss_destroy_crl_item(void *user, void *ptr)
-{
- struct ptr_list_wrap *wrap = (struct ptr_list_wrap *) ptr;
- SECItem *crl_der = (SECItem *) wrap->ptr;
- (void) user;
- SECITEM_FreeItem(crl_der, PR_TRUE);
- free(wrap);
-}
-
-static CURLcode nss_load_cert(struct ssl_connect_data *ssl,
- const char *filename, PRBool cacert)
-{
- CURLcode result = (cacert)
- ? CURLE_SSL_CACERT_BADFILE
- : CURLE_SSL_CERTPROBLEM;
-
- /* libnsspem.so leaks memory if the requested file does not exist. For more
- * details, go to <https://bugzilla.redhat.com/734760>. */
- if(is_file(filename))
- result = nss_create_object(ssl, CKO_CERTIFICATE, filename, cacert);
-
- if(!result && !cacert) {
- /* we have successfully loaded a client certificate */
- char *nickname = NULL;
- char *n = strrchr(filename, '/');
- if(n)
- n++;
-
- /* The following undocumented magic helps to avoid a SIGSEGV on call
- * of PK11_ReadRawAttribute() from SelectClientCert() when using an
- * immature version of libnsspem.so. For more details, go to
- * <https://bugzilla.redhat.com/733685>. */
- nickname = aprintf("PEM Token #1:%s", n);
- if(nickname) {
- CERTCertificate *cert = PK11_FindCertFromNickname(nickname, NULL);
- if(cert)
- CERT_DestroyCertificate(cert);
-
- free(nickname);
- }
- }
-
- return result;
-}
-
-/* add given CRL to cache if it is not already there */
-static CURLcode nss_cache_crl(SECItem *crl_der)
-{
- CERTCertDBHandle *db = CERT_GetDefaultCertDB();
- CERTSignedCrl *crl = SEC_FindCrlByDERCert(db, crl_der, 0);
- if(crl) {
- /* CRL already cached */
- SEC_DestroyCrl(crl);
- SECITEM_FreeItem(crl_der, PR_TRUE);
- return CURLE_OK;
- }
-
- /* acquire lock before call of CERT_CacheCRL() and accessing nss_crl_list */
- PR_Lock(nss_crllock);
-
- if(SECSuccess != CERT_CacheCRL(db, crl_der)) {
- /* unable to cache CRL */
- SECITEM_FreeItem(crl_der, PR_TRUE);
- PR_Unlock(nss_crllock);
- return CURLE_SSL_CRL_BADFILE;
- }
-
- /* store the CRL item so that we can free it in nss_cleanup() */
- if(insert_wrapped_ptr(&nss_crl_list, crl_der) != CURLE_OK) {
- if(SECSuccess == CERT_UncacheCRL(db, crl_der))
- SECITEM_FreeItem(crl_der, PR_TRUE);
- PR_Unlock(nss_crllock);
- return CURLE_OUT_OF_MEMORY;
- }
-
- /* we need to clear session cache, so that the CRL could take effect */
- SSL_ClearSessionCache();
- PR_Unlock(nss_crllock);
- return CURLE_OK;
-}
-
-static CURLcode nss_load_crl(const char *crlfilename)
-{
- PRFileDesc *infile;
- PRFileInfo info;
- SECItem filedata = { 0, NULL, 0 };
- SECItem *crl_der = NULL;
- char *body;
-
- infile = PR_Open(crlfilename, PR_RDONLY, 0);
- if(!infile)
- return CURLE_SSL_CRL_BADFILE;
-
- if(PR_SUCCESS != PR_GetOpenFileInfo(infile, &info))
- goto fail;
-
- if(!SECITEM_AllocItem(NULL, &filedata, info.size + /* zero ended */ 1))
- goto fail;
-
- if(info.size != PR_Read(infile, filedata.data, info.size))
- goto fail;
-
- crl_der = SECITEM_AllocItem(NULL, NULL, 0U);
- if(!crl_der)
- goto fail;
-
- /* place a trailing zero right after the visible data */
- body = (char *)filedata.data;
- body[--filedata.len] = '\0';
-
- body = strstr(body, "-----BEGIN");
- if(body) {
- /* assume ASCII */
- char *trailer;
- char *begin = PORT_Strchr(body, '\n');
- if(!begin)
- begin = PORT_Strchr(body, '\r');
- if(!begin)
- goto fail;
-
- trailer = strstr(++begin, "-----END");
- if(!trailer)
- goto fail;
-
- /* retrieve DER from ASCII */
- *trailer = '\0';
- if(ATOB_ConvertAsciiToItem(crl_der, begin))
- goto fail;
-
- SECITEM_FreeItem(&filedata, PR_FALSE);
- }
- else
- /* assume DER */
- *crl_der = filedata;
-
- PR_Close(infile);
- return nss_cache_crl(crl_der);
-
-fail:
- PR_Close(infile);
- SECITEM_FreeItem(crl_der, PR_TRUE);
- SECITEM_FreeItem(&filedata, PR_FALSE);
- return CURLE_SSL_CRL_BADFILE;
-}
-
-static CURLcode nss_load_key(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- char *key_file)
-{
- struct ssl_connect_data *connssl = cf->ctx;
- struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
- PK11SlotInfo *slot, *tmp;
- SECStatus status;
- CURLcode result;
-
- (void)data;
- result = nss_create_object(connssl, CKO_PRIVATE_KEY, key_file, FALSE);
- if(result) {
- PR_SetError(SEC_ERROR_BAD_KEY, 0);
- return result;
- }
-
- slot = nss_find_slot_by_name("PEM Token #1");
- if(!slot)
- return CURLE_SSL_CERTPROBLEM;
-
- /* This will force the token to be seen as re-inserted */
- tmp = SECMOD_WaitForAnyTokenEvent(pem_module, 0, 0);
- if(tmp)
- PK11_FreeSlot(tmp);
- if(!PK11_IsPresent(slot)) {
- PK11_FreeSlot(slot);
- return CURLE_SSL_CERTPROBLEM;
- }
-
- status = PK11_Authenticate(slot, PR_TRUE, ssl_config->key_passwd);
- PK11_FreeSlot(slot);
-
- return (SECSuccess == status) ? CURLE_OK : CURLE_SSL_CERTPROBLEM;
-}
-
-static int display_error(struct Curl_easy *data, PRInt32 err,
- const char *filename)
-{
- switch(err) {
- case SEC_ERROR_BAD_PASSWORD:
- failf(data, "Unable to load client key: Incorrect password");
- return 1;
- case SEC_ERROR_UNKNOWN_CERT:
- failf(data, "Unable to load certificate %s", filename);
- return 1;
- default:
- break;
- }
- return 0; /* The caller will print a generic error */
-}
-
-static CURLcode cert_stuff(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- char *cert_file, char *key_file)
-{
- struct ssl_connect_data *connssl = cf->ctx;
- CURLcode result;
-
- if(cert_file) {
- result = nss_load_cert(connssl, cert_file, PR_FALSE);
- if(result) {
- const PRErrorCode err = PR_GetError();
- if(!display_error(data, err, cert_file)) {
- const char *err_name = nss_error_to_name(err);
- failf(data, "unable to load client cert: %d (%s)", err, err_name);
- }
-
- return result;
- }
- }
-
- if(key_file || (is_file(cert_file))) {
- if(key_file)
- result = nss_load_key(cf, data, key_file);
- else
- /* In case the cert file also has the key */
- result = nss_load_key(cf, data, cert_file);
- if(result) {
- const PRErrorCode err = PR_GetError();
- if(!display_error(data, err, key_file)) {
- const char *err_name = nss_error_to_name(err);
- failf(data, "unable to load client key: %d (%s)", err, err_name);
- }
-
- return result;
- }
- }
-
- return CURLE_OK;
-}
-
-static char *nss_get_password(PK11SlotInfo *slot, PRBool retry, void *arg)
-{
- (void)slot; /* unused */
-
- if(retry || !arg)
- return NULL;
- else
- return (char *)PORT_Strdup((char *)arg);
-}
-
-/* bypass the default SSL_AuthCertificate() hook in case we do not want to
- * verify peer */
-static SECStatus nss_auth_cert_hook(void *arg, PRFileDesc *fd, PRBool checksig,
- PRBool isServer)
-{
- struct Curl_cfilter *cf = (struct Curl_cfilter *)arg;
- struct ssl_connect_data *connssl = cf->ctx;
- struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
- struct nss_ssl_backend_data *backend =
- (struct nss_ssl_backend_data *)connssl->backend;
- struct Curl_easy *data = backend->data;
-
- DEBUGASSERT(data);
-#ifdef SSL_ENABLE_OCSP_STAPLING
- if(conn_config->verifystatus) {
- SECStatus cacheResult;
-
- const SECItemArray *csa = SSL_PeerStapledOCSPResponses(fd);
- if(!csa) {
- failf(data, "Invalid OCSP response");
- return SECFailure;
- }
-
- if(csa->len == 0) {
- failf(data, "No OCSP response received");
- return SECFailure;
- }
-
- cacheResult = CERT_CacheOCSPResponseFromSideChannel(
- CERT_GetDefaultCertDB(), SSL_PeerCertificate(fd),
- PR_Now(), &csa->items[0], arg
- );
-
- if(cacheResult != SECSuccess) {
- failf(data, "Invalid OCSP response");
- return cacheResult;
- }
- }
-#endif
-
- if(!conn_config->verifypeer) {
- infof(data, "skipping SSL peer certificate verification");
- return SECSuccess;
- }
-
- return SSL_AuthCertificate(CERT_GetDefaultCertDB(), fd, checksig, isServer);
-}
-
-/**
- * Inform the application that the handshake is complete.
- */
-static void HandshakeCallback(PRFileDesc *sock, void *arg)
-{
- struct Curl_cfilter *cf = (struct Curl_cfilter *)arg;
- struct ssl_connect_data *connssl = cf->ctx;
- struct nss_ssl_backend_data *backend =
- (struct nss_ssl_backend_data *)connssl->backend;
- struct Curl_easy *data = backend->data;
- unsigned int buflenmax = 50;
- unsigned char buf[50];
- unsigned int buflen;
- SSLNextProtoState state;
-
- DEBUGASSERT(data);
- if(!connssl->alpn) {
- return;
- }
-
- if(SSL_GetNextProto(sock, &state, buf, &buflen, buflenmax) == SECSuccess) {
-
- switch(state) {
-#if NSSVERNUM >= 0x031a00 /* 3.26.0 */
- /* used by NSS internally to implement 0-RTT */
- case SSL_NEXT_PROTO_EARLY_VALUE:
- /* fall through! */
-#endif
- case SSL_NEXT_PROTO_NO_SUPPORT:
- case SSL_NEXT_PROTO_NO_OVERLAP:
- Curl_alpn_set_negotiated(cf, data, NULL, 0);
- return;
-#ifdef SSL_ENABLE_ALPN
- case SSL_NEXT_PROTO_SELECTED:
- Curl_alpn_set_negotiated(cf, data, buf, buflen);
- break;
-#endif
- default:
- /* ignore SSL_NEXT_PROTO_NEGOTIATED */
- break;
- }
-
- }
-}
-
-#if NSSVERNUM >= 0x030f04 /* 3.15.4 */
-static SECStatus CanFalseStartCallback(PRFileDesc *sock, void *client_data,
- PRBool *canFalseStart)
-{
- struct Curl_easy *data = (struct Curl_easy *)client_data;
-
- SSLChannelInfo channelInfo;
- SSLCipherSuiteInfo cipherInfo;
-
- SECStatus rv;
- PRBool negotiatedExtension;
-
- *canFalseStart = PR_FALSE;
-
- if(SSL_GetChannelInfo(sock, &channelInfo, sizeof(channelInfo)) != SECSuccess)
- return SECFailure;
-
- if(SSL_GetCipherSuiteInfo(channelInfo.cipherSuite, &cipherInfo,
- sizeof(cipherInfo)) != SECSuccess)
- return SECFailure;
-
- /* Prevent version downgrade attacks from TLS 1.2, and avoid False Start for
- * TLS 1.3 and later. See https://bugzilla.mozilla.org/show_bug.cgi?id=861310
- */
- if(channelInfo.protocolVersion != SSL_LIBRARY_VERSION_TLS_1_2)
- goto end;
-
- /* Only allow ECDHE key exchange algorithm.
- * See https://bugzilla.mozilla.org/show_bug.cgi?id=952863 */
- if(cipherInfo.keaType != ssl_kea_ecdh)
- goto end;
-
- /* Prevent downgrade attacks on the symmetric cipher. We do not allow CBC
- * mode due to BEAST, POODLE, and other attacks on the MAC-then-Encrypt
- * design. See https://bugzilla.mozilla.org/show_bug.cgi?id=1109766 */
- if(cipherInfo.symCipher != ssl_calg_aes_gcm)
- goto end;
-
- /* Enforce ALPN to do False Start, as an indicator of server
- compatibility. */
- rv = SSL_HandshakeNegotiatedExtension(sock, ssl_app_layer_protocol_xtn,
- &negotiatedExtension);
- if(rv != SECSuccess || !negotiatedExtension) {
- rv = SSL_HandshakeNegotiatedExtension(sock, ssl_next_proto_nego_xtn,
- &negotiatedExtension);
- }
-
- if(rv != SECSuccess || !negotiatedExtension)
- goto end;
-
- *canFalseStart = PR_TRUE;
-
- infof(data, "Trying TLS False Start");
-
-end:
- return SECSuccess;
-}
-#endif
-
-static void display_cert_info(struct Curl_easy *data,
- CERTCertificate *cert)
-{
- char *subject, *issuer, *common_name;
- PRExplodedTime printableTime;
- char timeString[256];
- PRTime notBefore, notAfter;
-
- subject = CERT_NameToAscii(&cert->subject);
- issuer = CERT_NameToAscii(&cert->issuer);
- common_name = CERT_GetCommonName(&cert->subject);
- infof(data, "subject: %s", subject);
-
- CERT_GetCertTimes(cert, &notBefore, &notAfter);
- PR_ExplodeTime(notBefore, PR_GMTParameters, &printableTime);
- PR_FormatTime(timeString, 256, "%b %d %H:%M:%S %Y GMT", &printableTime);
- infof(data, " start date: %s", timeString);
- PR_ExplodeTime(notAfter, PR_GMTParameters, &printableTime);
- PR_FormatTime(timeString, 256, "%b %d %H:%M:%S %Y GMT", &printableTime);
- infof(data, " expire date: %s", timeString);
- infof(data, " common name: %s", common_name);
- infof(data, " issuer: %s", issuer);
-
- PR_Free(subject);
- PR_Free(issuer);
- PR_Free(common_name);
-}
-
-/* A number of certs that will never occur in a real server handshake */
-#define TOO_MANY_CERTS 300
-
-static CURLcode display_conn_info(struct Curl_easy *data, PRFileDesc *sock)
-{
- CURLcode result = CURLE_OK;
- SSLChannelInfo channel;
- SSLCipherSuiteInfo suite;
- CERTCertificate *cert;
- CERTCertificate *cert2;
- CERTCertificate *cert3;
- PRTime now;
-
- if(SSL_GetChannelInfo(sock, &channel, sizeof(channel)) ==
- SECSuccess && channel.length == sizeof(channel) &&
- channel.cipherSuite) {
- if(SSL_GetCipherSuiteInfo(channel.cipherSuite,
- &suite, sizeof(suite)) == SECSuccess) {
- infof(data, "SSL connection using %s", suite.cipherSuiteName);
- }
- }
-
- cert = SSL_PeerCertificate(sock);
- if(cert) {
- infof(data, "Server certificate:");
-
- if(!data->set.ssl.certinfo) {
- display_cert_info(data, cert);
- CERT_DestroyCertificate(cert);
- }
- else {
- /* Count certificates in chain. */
- int i = 1;
- now = PR_Now();
- if(!cert->isRoot) {
- cert2 = CERT_FindCertIssuer(cert, now, certUsageSSLCA);
- while(cert2) {
- i++;
- if(i >= TOO_MANY_CERTS) {
- CERT_DestroyCertificate(cert2);
- failf(data, "certificate loop");
- return CURLE_SSL_CERTPROBLEM;
- }
- if(cert2->isRoot) {
- CERT_DestroyCertificate(cert2);
- break;
- }
- cert3 = CERT_FindCertIssuer(cert2, now, certUsageSSLCA);
- CERT_DestroyCertificate(cert2);
- cert2 = cert3;
- }
- }
-
- result = Curl_ssl_init_certinfo(data, i);
- if(!result) {
- for(i = 0; cert; cert = cert2) {
- result = Curl_extract_certinfo(data, i++, (char *)cert->derCert.data,
- (char *)cert->derCert.data +
- cert->derCert.len);
- if(result)
- break;
-
- if(cert->isRoot) {
- CERT_DestroyCertificate(cert);
- break;
- }
-
- cert2 = CERT_FindCertIssuer(cert, now, certUsageSSLCA);
- CERT_DestroyCertificate(cert);
- }
- }
- }
- }
-
- return result;
-}
-
-static SECStatus BadCertHandler(void *arg, PRFileDesc *sock)
-{
- struct Curl_cfilter *cf = (struct Curl_cfilter *)arg;
- struct ssl_connect_data *connssl = cf->ctx;
- struct nss_ssl_backend_data *backend =
- (struct nss_ssl_backend_data *)connssl->backend;
- struct Curl_easy *data = backend->data;
- struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
- struct ssl_config_data *ssl_config;
- PRErrorCode err = PR_GetError();
- CERTCertificate *cert;
-
- DEBUGASSERT(data);
- ssl_config = Curl_ssl_cf_get_config(cf, data);
- /* remember the cert verification result */
- ssl_config->certverifyresult = err;
-
- if(err == SSL_ERROR_BAD_CERT_DOMAIN && !conn_config->verifyhost)
- /* we are asked not to verify the host name */
- return SECSuccess;
-
- /* print only info about the cert, the error is printed off the callback */
- cert = SSL_PeerCertificate(sock);
- if(cert) {
- infof(data, "Server certificate:");
- display_cert_info(data, cert);
- CERT_DestroyCertificate(cert);
- }
-
- return SECFailure;
-}
-
-/**
- *
- * Check that the Peer certificate's issuer certificate matches the one found
- * by issuer_nickname. This is not exactly the way OpenSSL and GNU TLS do the
- * issuer check, so we provide comments that mimic the OpenSSL
- * X509_check_issued function (in x509v3/v3_purp.c)
- */
-static SECStatus check_issuer_cert(PRFileDesc *sock,
- char *issuer_nickname)
-{
- CERTCertificate *cert, *cert_issuer, *issuer;
- SECStatus res = SECSuccess;
- void *proto_win = NULL;
-
- cert = SSL_PeerCertificate(sock);
- cert_issuer = CERT_FindCertIssuer(cert, PR_Now(), certUsageObjectSigner);
-
- proto_win = SSL_RevealPinArg(sock);
- issuer = PK11_FindCertFromNickname(issuer_nickname, proto_win);
-
- if((!cert_issuer) || (!issuer))
- res = SECFailure;
- else if(SECITEM_CompareItem(&cert_issuer->derCert,
- &issuer->derCert) != SECEqual)
- res = SECFailure;
-
- CERT_DestroyCertificate(cert);
- CERT_DestroyCertificate(issuer);
- CERT_DestroyCertificate(cert_issuer);
- return res;
-}
-
-static CURLcode cmp_peer_pubkey(struct ssl_connect_data *connssl,
- const char *pinnedpubkey)
-{
- CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
- struct nss_ssl_backend_data *backend =
- (struct nss_ssl_backend_data *)connssl->backend;
- struct Curl_easy *data = NULL;
- CERTCertificate *cert;
-
- DEBUGASSERT(backend);
- data = backend->data;
-
- if(!pinnedpubkey)
- /* no pinned public key specified */
- return CURLE_OK;
-
- /* get peer certificate */
- cert = SSL_PeerCertificate(backend->handle);
- if(cert) {
- /* extract public key from peer certificate */
- SECKEYPublicKey *pubkey = CERT_ExtractPublicKey(cert);
- if(pubkey) {
- /* encode the public key as DER */
- SECItem *cert_der = PK11_DEREncodePublicKey(pubkey);
- if(cert_der) {
- /* compare the public key with the pinned public key */
- result = Curl_pin_peer_pubkey(data, pinnedpubkey, cert_der->data,
- cert_der->len);
- SECITEM_FreeItem(cert_der, PR_TRUE);
- }
- SECKEY_DestroyPublicKey(pubkey);
- }
- CERT_DestroyCertificate(cert);
- }
-
- /* report the resulting status */
- switch(result) {
- case CURLE_OK:
- infof(data, "pinned public key verified successfully");
- break;
- case CURLE_SSL_PINNEDPUBKEYNOTMATCH:
- failf(data, "failed to verify pinned public key");
- break;
- default:
- /* OOM, etc. */
- break;
- }
-
- return result;
-}
-
-/**
- *
- * Callback to pick the SSL client certificate.
- */
-static SECStatus SelectClientCert(void *arg, PRFileDesc *sock,
- struct CERTDistNamesStr *caNames,
- struct CERTCertificateStr **pRetCert,
- struct SECKEYPrivateKeyStr **pRetKey)
-{
- struct ssl_connect_data *connssl = (struct ssl_connect_data *)arg;
- struct nss_ssl_backend_data *backend =
- (struct nss_ssl_backend_data *)connssl->backend;
- struct Curl_easy *data = NULL;
- const char *nickname = NULL;
- static const char pem_slotname[] = "PEM Token #1";
-
- DEBUGASSERT(backend);
-
- data = backend->data;
- nickname = backend->client_nickname;
-
- if(backend->obj_clicert) {
- /* use the cert/key provided by PEM reader */
- SECItem cert_der = { 0, NULL, 0 };
- void *proto_win = SSL_RevealPinArg(sock);
- struct CERTCertificateStr *cert;
- struct SECKEYPrivateKeyStr *key;
-
- PK11SlotInfo *slot = nss_find_slot_by_name(pem_slotname);
- if(!slot) {
- failf(data, "NSS: PK11 slot not found: %s", pem_slotname);
- return SECFailure;
- }
-
- if(PK11_ReadRawAttribute(PK11_TypeGeneric, backend->obj_clicert, CKA_VALUE,
- &cert_der) != SECSuccess) {
- failf(data, "NSS: CKA_VALUE not found in PK11 generic object");
- PK11_FreeSlot(slot);
- return SECFailure;
- }
-
- cert = PK11_FindCertFromDERCertItem(slot, &cert_der, proto_win);
- SECITEM_FreeItem(&cert_der, PR_FALSE);
- if(!cert) {
- failf(data, "NSS: client certificate from file not found");
- PK11_FreeSlot(slot);
- return SECFailure;
- }
-
- key = PK11_FindPrivateKeyFromCert(slot, cert, NULL);
- PK11_FreeSlot(slot);
- if(!key) {
- failf(data, "NSS: private key from file not found");
- CERT_DestroyCertificate(cert);
- return SECFailure;
- }
-
- infof(data, "NSS: client certificate from file");
- display_cert_info(data, cert);
-
- *pRetCert = cert;
- *pRetKey = key;
- return SECSuccess;
- }
-
- /* use the default NSS hook */
- if(SECSuccess != NSS_GetClientAuthData((void *)nickname, sock, caNames,
- pRetCert, pRetKey)
- || !*pRetCert) {
-
- if(!nickname)
- failf(data, "NSS: client certificate not found (nickname not "
- "specified)");
- else
- failf(data, "NSS: client certificate not found: %s", nickname);
-
- return SECFailure;
- }
-
- /* get certificate nickname if any */
- nickname = (*pRetCert)->nickname;
- if(!nickname)
- nickname = "[unknown]";
-
- if(!strncmp(nickname, pem_slotname, sizeof(pem_slotname) - 1U)) {
- failf(data, "NSS: refusing previously loaded certificate from file: %s",
- nickname);
- return SECFailure;
- }
-
- if(!*pRetKey) {
- failf(data, "NSS: private key not found for certificate: %s", nickname);
- return SECFailure;
- }
-
- infof(data, "NSS: using client certificate: %s", nickname);
- display_cert_info(data, *pRetCert);
- return SECSuccess;
-}
-
-/* update blocking direction in case of PR_WOULD_BLOCK_ERROR */
-static void nss_update_connecting_state(ssl_connect_state state, void *secret)
-{
- struct ssl_connect_data *connssl = (struct ssl_connect_data *)secret;
- if(PR_GetError() != PR_WOULD_BLOCK_ERROR)
- /* an unrelated error is passing by */
- return;
-
- switch(connssl->connecting_state) {
- case ssl_connect_2:
- case ssl_connect_2_reading:
- case ssl_connect_2_writing:
- break;
- default:
- /* we are not called from an SSL handshake */
- return;
- }
-
- /* update the state accordingly */
- connssl->connecting_state = state;
-}
-
-/* recv() wrapper we use to detect blocking direction during SSL handshake */
-static PRInt32 nspr_io_recv(PRFileDesc *fd, void *buf, PRInt32 amount,
- PRIntn flags, PRIntervalTime timeout)
-{
- const PRRecvFN recv_fn = fd->lower->methods->recv;
- const PRInt32 rv = recv_fn(fd->lower, buf, amount, flags, timeout);
- if(rv < 0)
- /* check for PR_WOULD_BLOCK_ERROR and update blocking direction */
- nss_update_connecting_state(ssl_connect_2_reading, fd->secret);
- return rv;
-}
-
-/* send() wrapper we use to detect blocking direction during SSL handshake */
-static PRInt32 nspr_io_send(PRFileDesc *fd, const void *buf, PRInt32 amount,
- PRIntn flags, PRIntervalTime timeout)
-{
- const PRSendFN send_fn = fd->lower->methods->send;
- const PRInt32 rv = send_fn(fd->lower, buf, amount, flags, timeout);
- if(rv < 0)
- /* check for PR_WOULD_BLOCK_ERROR and update blocking direction */
- nss_update_connecting_state(ssl_connect_2_writing, fd->secret);
- return rv;
-}
-
-/* close() wrapper to avoid assertion failure due to fd->secret != NULL */
-static PRStatus nspr_io_close(PRFileDesc *fd)
-{
- const PRCloseFN close_fn = PR_GetDefaultIOMethods()->close;
- fd->secret = NULL;
- return close_fn(fd);
-}
-
-/* load a PKCS #11 module */
-static CURLcode nss_load_module(SECMODModule **pmod, const char *library,
- const char *name)
-{
- char *config_string;
- SECMODModule *module = *pmod;
- if(module)
- /* already loaded */
- return CURLE_OK;
-
- config_string = aprintf("library=%s name=%s", library, name);
- if(!config_string)
- return CURLE_OUT_OF_MEMORY;
-
- module = SECMOD_LoadUserModule(config_string, NULL, PR_FALSE);
- free(config_string);
-
- if(module && module->loaded) {
- /* loaded successfully */
- *pmod = module;
- return CURLE_OK;
- }
-
- if(module)
- SECMOD_DestroyModule(module);
- return CURLE_FAILED_INIT;
-}
-
-/* unload a PKCS #11 module */
-static void nss_unload_module(SECMODModule **pmod)
-{
- SECMODModule *module = *pmod;
- if(!module)
- /* not loaded */
- return;
-
- if(SECMOD_UnloadUserModule(module) != SECSuccess)
- /* unload failed */
- return;
-
- SECMOD_DestroyModule(module);
- *pmod = NULL;
-}
-
-/* data might be NULL */
-static CURLcode nss_init_core(struct Curl_easy *data, const char *cert_dir)
-{
- NSSInitParameters initparams;
- PRErrorCode err;
- const char *err_name;
-
- if(nss_context)
- return CURLE_OK;
-
- memset((void *) &initparams, '\0', sizeof(initparams));
- initparams.length = sizeof(initparams);
-
- if(cert_dir) {
- char *certpath = aprintf("sql:%s", cert_dir);
- if(!certpath)
- return CURLE_OUT_OF_MEMORY;
-
- infof(data, "Initializing NSS with certpath: %s", certpath);
- nss_context = NSS_InitContext(certpath, "", "", "", &initparams,
- NSS_INIT_READONLY | NSS_INIT_PK11RELOAD);
- free(certpath);
-
- if(nss_context)
- return CURLE_OK;
-
- err = PR_GetError();
- err_name = nss_error_to_name(err);
- infof(data, "Unable to initialize NSS database: %d (%s)", err, err_name);
- }
-
- infof(data, "Initializing NSS with certpath: none");
- 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)
- return CURLE_OK;
-
- err = PR_GetError();
- err_name = nss_error_to_name(err);
- failf(data, "Unable to initialize NSS: %d (%s)", err, err_name);
- return CURLE_SSL_CACERT_BADFILE;
-}
-
-/* data might be NULL */
-static CURLcode nss_setup(struct Curl_easy *data)
-{
- char *cert_dir;
- struct_stat st;
- CURLcode result;
-
- if(initialized)
- return CURLE_OK;
-
- /* list of all CRL items we need to destroy in nss_cleanup() */
- Curl_llist_init(&nss_crl_list, nss_destroy_crl_item);
-
- /* First we check if $SSL_DIR points to a valid dir */
- cert_dir = getenv("SSL_DIR");
- if(cert_dir) {
- if((stat(cert_dir, &st) != 0) ||
- (!S_ISDIR(st.st_mode))) {
- cert_dir = NULL;
- }
- }
-
- /* Now we check if the default location is a valid dir */
- if(!cert_dir) {
- if((stat(SSL_DIR, &st) == 0) &&
- (S_ISDIR(st.st_mode))) {
- cert_dir = (char *)SSL_DIR;
- }
- }
-
- if(nspr_io_identity == PR_INVALID_IO_LAYER) {
- /* allocate an identity for our own NSPR I/O layer */
- nspr_io_identity = PR_GetUniqueIdentity("libcurl");
- if(nspr_io_identity == PR_INVALID_IO_LAYER)
- return CURLE_OUT_OF_MEMORY;
-
- /* the default methods just call down to the lower I/O layer */
- memcpy(&nspr_io_methods, PR_GetDefaultIOMethods(),
- sizeof(nspr_io_methods));
-
- /* override certain methods in the table by our wrappers */
- nspr_io_methods.recv = nspr_io_recv;
- nspr_io_methods.send = nspr_io_send;
- nspr_io_methods.close = nspr_io_close;
- }
-
- result = nss_init_core(data, cert_dir);
- if(result)
- return result;
-
- if(!any_cipher_enabled())
- NSS_SetDomesticPolicy();
-
- initialized = 1;
-
- return CURLE_OK;
-}
-
-/**
- * Global SSL init
- *
- * @retval 0 error initializing SSL
- * @retval 1 SSL initialized successfully
- */
-static int nss_init(void)
-{
- /* curl_global_init() is not thread-safe so this test is ok */
- if(!nss_initlock) {
- PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
- nss_initlock = PR_NewLock();
- nss_crllock = PR_NewLock();
- nss_findslot_lock = PR_NewLock();
- nss_trustload_lock = PR_NewLock();
- }
-
- /* We will actually initialize NSS later */
-
- return 1;
-}
-
-/* data might be NULL */
-CURLcode Curl_nss_force_init(struct Curl_easy *data)
-{
- CURLcode result;
- if(!nss_initlock) {
- if(data)
- failf(data, "unable to initialize NSS, curl_global_init() should have "
- "been called with CURL_GLOBAL_SSL or CURL_GLOBAL_ALL");
- return CURLE_FAILED_INIT;
- }
-
- PR_Lock(nss_initlock);
- result = nss_setup(data);
- PR_Unlock(nss_initlock);
-
- return result;
-}
-
-/* Global cleanup */
-static void nss_cleanup(void)
-{
- /* This function isn't required to be threadsafe and this is only done
- * as a safety feature.
- */
- PR_Lock(nss_initlock);
- if(initialized) {
- /* Free references to client certificates held in the SSL session cache.
- * Omitting this hampers destruction of the security module owning
- * the certificates. */
- SSL_ClearSessionCache();
-
- nss_unload_module(&pem_module);
- nss_unload_module(&trust_module);
- NSS_ShutdownContext(nss_context);
- nss_context = NULL;
- }
-
- /* destroy all CRL items */
- Curl_llist_destroy(&nss_crl_list, NULL);
-
- PR_Unlock(nss_initlock);
-
- PR_DestroyLock(nss_initlock);
- PR_DestroyLock(nss_crllock);
- PR_DestroyLock(nss_findslot_lock);
- PR_DestroyLock(nss_trustload_lock);
- nss_initlock = NULL;
-
- initialized = 0;
-}
-
-static void close_one(struct ssl_connect_data *connssl)
-{
- /* before the cleanup, check whether we are using a client certificate */
- struct nss_ssl_backend_data *backend =
- (struct nss_ssl_backend_data *)connssl->backend;
- bool client_cert = true;
-
- DEBUGASSERT(backend);
-
- client_cert = (backend->client_nickname != NULL)
- || (backend->obj_clicert != NULL);
-
- if(backend->handle) {
- char buf[32];
- /* Maybe the server has already sent a close notify alert.
- Read it to avoid an RST on the TCP connection. */
- (void)PR_Recv(backend->handle, buf, (int)sizeof(buf), 0,
- PR_INTERVAL_NO_WAIT);
- }
-
- free(backend->client_nickname);
- backend->client_nickname = NULL;
-
- /* destroy all NSS objects in order to avoid failure of NSS shutdown */
- Curl_llist_destroy(&backend->obj_list, NULL);
- backend->obj_clicert = NULL;
-
- if(backend->handle) {
- if(client_cert)
- /* A server might require different authentication based on the
- * particular path being requested by the client. To support this
- * scenario, we must ensure that a connection will never reuse the
- * authentication data from a previous connection. */
- SSL_InvalidateSession(backend->handle);
-
- PR_Close(backend->handle);
- backend->handle = NULL;
- }
-}
-
-/*
- * This function is called when an SSL connection is closed.
- */
-static void nss_close(struct Curl_cfilter *cf, struct Curl_easy *data)
-{
- struct ssl_connect_data *connssl = cf->ctx;
- struct nss_ssl_backend_data *backend =
- (struct nss_ssl_backend_data *)connssl->backend;
- (void)data;
- DEBUGASSERT(backend);
-
- if(backend->handle) {
- /* NSS closes the socket we previously handed to it, so we must mark it
- as closed to avoid double close */
- fake_sclose(cf->conn->sock[cf->sockindex]);
- cf->conn->sock[cf->sockindex] = CURL_SOCKET_BAD;
- }
-
- close_one(connssl);
-}
-
-/* return true if NSS can provide error code (and possibly msg) for the
- error */
-static bool is_nss_error(CURLcode err)
-{
- switch(err) {
- case CURLE_PEER_FAILED_VERIFICATION:
- case CURLE_SSL_CERTPROBLEM:
- case CURLE_SSL_CONNECT_ERROR:
- case CURLE_SSL_ISSUER_ERROR:
- return true;
-
- default:
- return false;
- }
-}
-
-/* return true if the given error code is related to a client certificate */
-static bool is_cc_error(PRInt32 err)
-{
- switch(err) {
- case SSL_ERROR_BAD_CERT_ALERT:
- case SSL_ERROR_EXPIRED_CERT_ALERT:
- case SSL_ERROR_REVOKED_CERT_ALERT:
- return true;
-
- default:
- return false;
- }
-}
-
-static CURLcode nss_load_ca_certificates(struct Curl_cfilter *cf,
- struct Curl_easy *data)
-{
- struct ssl_connect_data *connssl = cf->ctx;
- struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
- const char *cafile = conn_config->CAfile;
- const char *capath = conn_config->CApath;
- bool use_trust_module;
- CURLcode result = CURLE_OK;
-
- /* treat empty string as unset */
- if(cafile && !cafile[0])
- cafile = NULL;
- if(capath && !capath[0])
- capath = NULL;
-
- infof(data, " CAfile: %s", cafile ? cafile : "none");
- infof(data, " CApath: %s", capath ? capath : "none");
-
- /* load libnssckbi.so if no other trust roots were specified */
- use_trust_module = !cafile && !capath;
-
- PR_Lock(nss_trustload_lock);
- if(use_trust_module && !trust_module) {
- /* libnssckbi.so needed but not yet loaded --> load it! */
- result = nss_load_module(&trust_module, trust_library, "trust");
- infof(data, "%s %s", (result) ? "failed to load" : "loaded",
- trust_library);
- if(result == CURLE_FAILED_INIT)
- /* If libnssckbi.so is not available (or fails to load), one can still
- use CA certificates stored in NSS database. Ignore the failure. */
- result = CURLE_OK;
- }
- else if(!use_trust_module && trust_module) {
- /* libnssckbi.so not needed but already loaded --> unload it! */
- infof(data, "unloading %s", trust_library);
- nss_unload_module(&trust_module);
- }
- PR_Unlock(nss_trustload_lock);
-
- if(cafile)
- result = nss_load_cert(connssl, cafile, PR_TRUE);
-
- if(result)
- return result;
-
- if(capath) {
- struct_stat st;
- if(stat(capath, &st) == -1)
- return CURLE_SSL_CACERT_BADFILE;
-
- if(S_ISDIR(st.st_mode)) {
- PRDirEntry *entry;
- PRDir *dir = PR_OpenDir(capath);
- if(!dir)
- return CURLE_SSL_CACERT_BADFILE;
-
- while((entry =
- PR_ReadDir(dir, (PRDirFlags)(PR_SKIP_BOTH | PR_SKIP_HIDDEN)))) {
- char *fullpath = aprintf("%s/%s", capath, entry->name);
- if(!fullpath) {
- PR_CloseDir(dir);
- return CURLE_OUT_OF_MEMORY;
- }
-
- if(CURLE_OK != nss_load_cert(connssl, fullpath, PR_TRUE))
- /* This is purposefully tolerant of errors so non-PEM files can
- * be in the same directory */
- infof(data, "failed to load '%s' from CURLOPT_CAPATH", fullpath);
-
- free(fullpath);
- }
-
- PR_CloseDir(dir);
- }
- else
- infof(data, "WARNING: CURLOPT_CAPATH not a directory (%s)", capath);
- }
-
- return CURLE_OK;
-}
-
-static CURLcode nss_sslver_from_curl(PRUint16 *nssver, long version)
-{
- switch(version) {
- case CURL_SSLVERSION_SSLv2:
- *nssver = SSL_LIBRARY_VERSION_2;
- return CURLE_OK;
-
- case CURL_SSLVERSION_SSLv3:
- return CURLE_NOT_BUILT_IN;
-
- case CURL_SSLVERSION_TLSv1_0:
- *nssver = SSL_LIBRARY_VERSION_TLS_1_0;
- return CURLE_OK;
-
- case CURL_SSLVERSION_TLSv1_1:
-#ifdef SSL_LIBRARY_VERSION_TLS_1_1
- *nssver = SSL_LIBRARY_VERSION_TLS_1_1;
- return CURLE_OK;
-#else
- return CURLE_SSL_CONNECT_ERROR;
-#endif
-
- case CURL_SSLVERSION_TLSv1_2:
-#ifdef SSL_LIBRARY_VERSION_TLS_1_2
- *nssver = SSL_LIBRARY_VERSION_TLS_1_2;
- return CURLE_OK;
-#else
- return CURLE_SSL_CONNECT_ERROR;
-#endif
-
- case CURL_SSLVERSION_TLSv1_3:
-#ifdef SSL_LIBRARY_VERSION_TLS_1_3
- *nssver = SSL_LIBRARY_VERSION_TLS_1_3;
- return CURLE_OK;
-#else
- return CURLE_SSL_CONNECT_ERROR;
-#endif
-
- default:
- return CURLE_SSL_CONNECT_ERROR;
- }
-}
-
-static CURLcode nss_init_sslver(SSLVersionRange *sslver,
- struct Curl_cfilter *cf,
- struct Curl_easy *data)
-{
- struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
- CURLcode result;
- const long min = conn_config->version;
- const long max = conn_config->version_max;
- SSLVersionRange vrange;
-
- switch(min) {
- case CURL_SSLVERSION_TLSv1:
- case CURL_SSLVERSION_DEFAULT:
- /* Bump our minimum TLS version if NSS has stricter requirements. */
- if(SSL_VersionRangeGetDefault(ssl_variant_stream, &vrange) != SECSuccess)
- return CURLE_SSL_CONNECT_ERROR;
- if(sslver->min < vrange.min)
- sslver->min = vrange.min;
- break;
- default:
- result = nss_sslver_from_curl(&sslver->min, min);
- if(result) {
- failf(data, "unsupported min version passed via CURLOPT_SSLVERSION");
- return result;
- }
- }
-
- switch(max) {
- case CURL_SSLVERSION_MAX_NONE:
- case CURL_SSLVERSION_MAX_DEFAULT:
- break;
- default:
- result = nss_sslver_from_curl(&sslver->max, max >> 16);
- if(result) {
- failf(data, "unsupported max version passed via CURLOPT_SSLVERSION");
- return result;
- }
- }
-
- return CURLE_OK;
-}
-
-static CURLcode nss_fail_connect(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- CURLcode curlerr)
-{
- struct ssl_connect_data *connssl = cf->ctx;
- struct nss_ssl_backend_data *backend =
- (struct nss_ssl_backend_data *)connssl->backend;
-
- DEBUGASSERT(backend);
-
- if(is_nss_error(curlerr)) {
- /* read NSPR error code */
- PRErrorCode err = PR_GetError();
- if(is_cc_error(err))
- curlerr = CURLE_SSL_CERTPROBLEM;
-
- /* print the error number and error string */
- infof(data, "NSS error %d (%s)", err, nss_error_to_name(err));
-
- /* print a human-readable message describing the error if available */
- nss_print_error_message(data, err);
- }
-
- /* cleanup on connection failure */
- Curl_llist_destroy(&backend->obj_list, NULL);
-
- return curlerr;
-}
-
-/* Switch the SSL socket into blocking or non-blocking mode. */
-static CURLcode nss_set_blocking(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- bool blocking)
-{
- struct ssl_connect_data *connssl = cf->ctx;
- PRSocketOptionData sock_opt;
- struct nss_ssl_backend_data *backend =
- (struct nss_ssl_backend_data *)connssl->backend;
-
- DEBUGASSERT(backend);
-
- sock_opt.option = PR_SockOpt_Nonblocking;
- sock_opt.value.non_blocking = !blocking;
-
- if(PR_SetSocketOption(backend->handle, &sock_opt) != PR_SUCCESS)
- return nss_fail_connect(cf, data, CURLE_SSL_CONNECT_ERROR);
-
- return CURLE_OK;
-}
-
-static CURLcode nss_setup_connect(struct Curl_cfilter *cf,
- struct Curl_easy *data)
-{
- PRFileDesc *model = NULL;
- PRFileDesc *nspr_io = NULL;
- PRFileDesc *nspr_io_stub = NULL;
- PRBool ssl_no_cache;
- PRBool ssl_cbc_random_iv;
- curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data);
- struct ssl_connect_data *connssl = cf->ctx;
- struct nss_ssl_backend_data *backend =
- (struct nss_ssl_backend_data *)connssl->backend;
- struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
- struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
- struct Curl_cfilter *cf_ssl_next = Curl_ssl_cf_get_ssl(cf->next);
- struct ssl_connect_data *connssl_next = cf_ssl_next?
- cf_ssl_next->ctx : NULL;
- CURLcode result;
- bool second_layer = FALSE;
- SSLVersionRange sslver_supported;
- SSLVersionRange sslver = {
- SSL_LIBRARY_VERSION_TLS_1_0, /* min */
-#ifdef SSL_LIBRARY_VERSION_TLS_1_3
- SSL_LIBRARY_VERSION_TLS_1_3 /* max */
-#elif defined SSL_LIBRARY_VERSION_TLS_1_2
- SSL_LIBRARY_VERSION_TLS_1_2
-#elif defined SSL_LIBRARY_VERSION_TLS_1_1
- SSL_LIBRARY_VERSION_TLS_1_1
-#else
- SSL_LIBRARY_VERSION_TLS_1_0
-#endif
- };
- const char *hostname = connssl->hostname;
- char *snihost;
-
- snihost = Curl_ssl_snihost(data, hostname, NULL);
- if(!snihost) {
- failf(data, "Failed to set SNI");
- return CURLE_SSL_CONNECT_ERROR;
- }
-
- DEBUGASSERT(backend);
-
- backend->data = data;
-
- /* list of all NSS objects we need to destroy in nss_do_close() */
- Curl_llist_init(&backend->obj_list, nss_destroy_object);
-
- PR_Lock(nss_initlock);
- result = nss_setup(data);
- if(result) {
- PR_Unlock(nss_initlock);
- goto error;
- }
-
- PK11_SetPasswordFunc(nss_get_password);
-
- result = nss_load_module(&pem_module, pem_library, "PEM");
- PR_Unlock(nss_initlock);
- if(result == CURLE_FAILED_INIT)
- infof(data, "WARNING: failed to load NSS PEM library %s. Using "
- "OpenSSL PEM certificates will not work.", pem_library);
- else if(result)
- goto error;
-
- result = CURLE_SSL_CONNECT_ERROR;
-
- model = PR_NewTCPSocket();
- if(!model)
- goto error;
- model = SSL_ImportFD(NULL, model);
-
- if(SSL_OptionSet(model, SSL_SECURITY, PR_TRUE) != SECSuccess)
- goto error;
- if(SSL_OptionSet(model, SSL_HANDSHAKE_AS_SERVER, PR_FALSE) != SECSuccess)
- goto error;
- if(SSL_OptionSet(model, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE) != SECSuccess)
- goto error;
-
- /* do not use SSL cache if disabled or we are not going to verify peer */
- ssl_no_cache = (ssl_config->primary.sessionid
- && conn_config->verifypeer) ? PR_FALSE : PR_TRUE;
- if(SSL_OptionSet(model, SSL_NO_CACHE, ssl_no_cache) != SECSuccess)
- goto error;
-
- /* enable/disable the requested SSL version(s) */
- if(nss_init_sslver(&sslver, cf, data) != CURLE_OK)
- goto error;
- if(SSL_VersionRangeGetSupported(ssl_variant_stream,
- &sslver_supported) != SECSuccess)
- goto error;
- if(sslver_supported.max < sslver.max && sslver_supported.max >= sslver.min) {
- char *sslver_req_str, *sslver_supp_str;
- sslver_req_str = nss_sslver_to_name(sslver.max);
- sslver_supp_str = nss_sslver_to_name(sslver_supported.max);
- if(sslver_req_str && sslver_supp_str)
- infof(data, "Falling back from %s to max supported SSL version (%s)",
- sslver_req_str, sslver_supp_str);
- free(sslver_req_str);
- free(sslver_supp_str);
- sslver.max = sslver_supported.max;
- }
- if(SSL_VersionRangeSet(model, &sslver) != SECSuccess)
- goto error;
-
- ssl_cbc_random_iv = !ssl_config->enable_beast;
-#ifdef SSL_CBC_RANDOM_IV
- /* unless the user explicitly asks to allow the protocol vulnerability, we
- use the work-around */
- if(SSL_OptionSet(model, SSL_CBC_RANDOM_IV, ssl_cbc_random_iv) != SECSuccess)
- infof(data, "WARNING: failed to set SSL_CBC_RANDOM_IV = %d",
- ssl_cbc_random_iv);
-#else
- if(ssl_cbc_random_iv)
- infof(data, "WARNING: support for SSL_CBC_RANDOM_IV not compiled in");
-#endif
-
- if(conn_config->cipher_list) {
- if(set_ciphers(data, model, conn_config->cipher_list) != SECSuccess) {
- result = CURLE_SSL_CIPHER;
- goto error;
- }
- }
-
- if(!conn_config->verifypeer && conn_config->verifyhost)
- infof(data, "WARNING: ignoring value of ssl.verifyhost");
-
- /* bypass the default SSL_AuthCertificate() hook in case we do not want to
- * verify peer */
- if(SSL_AuthCertificateHook(model, nss_auth_cert_hook, cf) != SECSuccess)
- goto error;
-
- /* not checked yet */
- ssl_config->certverifyresult = 0;
-
- if(SSL_BadCertHook(model, BadCertHandler, cf) != SECSuccess)
- goto error;
-
- if(SSL_HandshakeCallback(model, HandshakeCallback, cf) != SECSuccess)
- goto error;
-
- {
- const CURLcode rv = nss_load_ca_certificates(cf, data);
- if((rv == CURLE_SSL_CACERT_BADFILE) && !conn_config->verifypeer)
- /* not a fatal error because we are not going to verify the peer */
- infof(data, "WARNING: CA certificates failed to load");
- else if(rv) {
- result = rv;
- goto error;
- }
- }
-
- if(ssl_config->primary.CRLfile) {
- const CURLcode rv = nss_load_crl(ssl_config->primary.CRLfile);
- if(rv) {
- result = rv;
- goto error;
- }
- infof(data, " CRLfile: %s", ssl_config->primary.CRLfile);
- }
-
- if(ssl_config->primary.clientcert) {
- char *nickname = dup_nickname(data, ssl_config->primary.clientcert);
- if(nickname) {
- /* we are not going to use libnsspem.so to read the client cert */
- backend->obj_clicert = NULL;
- }
- else {
- CURLcode rv = cert_stuff(cf, data,
- ssl_config->primary.clientcert,
- ssl_config->key);
- if(rv) {
- /* failf() is already done in cert_stuff() */
- result = rv;
- goto error;
- }
- }
-
- /* store the nickname for SelectClientCert() called during handshake */
- backend->client_nickname = nickname;
- }
- else
- backend->client_nickname = NULL;
-
- if(SSL_GetClientAuthDataHook(model, SelectClientCert,
- (void *)connssl) != SECSuccess) {
- result = CURLE_SSL_CERTPROBLEM;
- goto error;
- }
-
- /* Is there an SSL filter "in front" of us or are we writing directly
- * to the socket? */
- if(connssl_next) {
- struct nss_ssl_backend_data *backend_next =
- (struct nss_ssl_backend_data *)connssl_next->backend;
- /* The filter should be connected by now, with full handshake */
- DEBUGASSERT(backend_next->handle);
- DEBUGASSERT(ssl_connection_complete == connssl_next->state);
- /* We tell our NSS instance to use do IO with the 'next' NSS
- * instance. This NSS instance will take ownership of the next
- * one, including its destruction. We therefore need to `disown`
- * the next filter's handle, once import succeeds. */
- nspr_io = backend->handle;
- second_layer = TRUE;
- }
- else {
- /* wrap OS file descriptor by NSPR's file descriptor abstraction */
- nspr_io = PR_ImportTCPSocket(sockfd);
- if(!nspr_io)
- goto error;
- }
-
- /* create our own NSPR I/O layer */
- nspr_io_stub = PR_CreateIOLayerStub(nspr_io_identity, &nspr_io_methods);
- if(!nspr_io_stub) {
- if(!second_layer)
- PR_Close(nspr_io);
- goto error;
- }
-
- /* make the per-connection data accessible from NSPR I/O callbacks */
- nspr_io_stub->secret = (void *)connssl;
-
- /* push our new layer to the NSPR I/O stack */
- if(PR_PushIOLayer(nspr_io, PR_TOP_IO_LAYER, nspr_io_stub) != PR_SUCCESS) {
- if(!second_layer)
- PR_Close(nspr_io);
- PR_Close(nspr_io_stub);
- goto error;
- }
-
- /* import our model socket onto the current I/O stack */
- backend->handle = SSL_ImportFD(model, nspr_io);
- if(!backend->handle) {
- if(!second_layer)
- PR_Close(nspr_io);
- goto error;
- }
-
- PR_Close(model); /* We don't need this any more */
- model = NULL;
- if(connssl_next) { /* steal the NSS handle we just imported successfully */
- struct nss_ssl_backend_data *backend_next =
- (struct nss_ssl_backend_data *)connssl_next->backend;
- backend_next->handle = NULL;
- }
-
- /* This is the password associated with the cert that we're using */
- if(ssl_config->key_passwd) {
- SSL_SetPKCS11PinArg(backend->handle, ssl_config->key_passwd);
- }
-
-#ifdef SSL_ENABLE_OCSP_STAPLING
- if(conn_config->verifystatus) {
- if(SSL_OptionSet(backend->handle, SSL_ENABLE_OCSP_STAPLING, PR_TRUE)
- != SECSuccess)
- goto error;
- }
-#endif
-
-#ifdef SSL_ENABLE_ALPN
- if(SSL_OptionSet(backend->handle, SSL_ENABLE_ALPN,
- connssl->alpn ? PR_TRUE : PR_FALSE)
- != SECSuccess)
- goto error;
-#endif
-
-#if NSSVERNUM >= 0x030f04 /* 3.15.4 */
- if(data->set.ssl.falsestart) {
- if(SSL_OptionSet(backend->handle, SSL_ENABLE_FALSE_START, PR_TRUE)
- != SECSuccess)
- goto error;
-
- if(SSL_SetCanFalseStartCallback(backend->handle, CanFalseStartCallback,
- data) != SECSuccess)
- goto error;
- }
-#endif
-
-#if defined(SSL_ENABLE_ALPN)
- if(connssl->alpn) {
- struct alpn_proto_buf proto;
-
- result = Curl_alpn_to_proto_buf(&proto, connssl->alpn);
- if(result || SSL_SetNextProtoNego(backend->handle, proto.data, proto.len)
- != SECSuccess) {
- failf(data, "Error setting ALPN");
- goto error;
- }
- Curl_alpn_to_proto_str(&proto, connssl->alpn);
- infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data);
- }
-#endif
-
-
- /* Force handshake on next I/O */
- if(SSL_ResetHandshake(backend->handle, /* asServer */ PR_FALSE)
- != SECSuccess)
- goto error;
-
- /* propagate hostname to the TLS layer */
- if(SSL_SetURL(backend->handle, snihost) != SECSuccess)
- goto error;
-
- /* prevent NSS from re-using the session for a different hostname */
- if(SSL_SetSockPeerID(backend->handle, snihost) != SECSuccess)
- goto error;
-
- return CURLE_OK;
-
-error:
- if(model)
- PR_Close(model);
-
- return nss_fail_connect(cf, data, result);
-}
-
-static CURLcode nss_do_connect(struct Curl_cfilter *cf,
- struct Curl_easy *data)
-{
- struct ssl_connect_data *connssl = cf->ctx;
- struct nss_ssl_backend_data *backend =
- (struct nss_ssl_backend_data *)connssl->backend;
- struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
- struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
- CURLcode result = CURLE_SSL_CONNECT_ERROR;
- PRUint32 timeout;
-
- /* check timeout situation */
- const timediff_t time_left = Curl_timeleft(data, NULL, TRUE);
- if(time_left < 0) {
- failf(data, "timed out before SSL handshake");
- result = CURLE_OPERATION_TIMEDOUT;
- goto error;
- }
-
- DEBUGASSERT(backend);
-
- /* Force the handshake now */
- timeout = PR_MillisecondsToInterval((PRUint32) time_left);
- if(SSL_ForceHandshakeWithTimeout(backend->handle, timeout) != SECSuccess) {
- if(PR_GetError() == PR_WOULD_BLOCK_ERROR)
- /* blocking direction is updated by nss_update_connecting_state() */
- return CURLE_AGAIN;
- else if(ssl_config->certverifyresult == SSL_ERROR_BAD_CERT_DOMAIN)
- result = CURLE_PEER_FAILED_VERIFICATION;
- else if(ssl_config->certverifyresult)
- result = CURLE_PEER_FAILED_VERIFICATION;
- goto error;
- }
-
- result = display_conn_info(data, backend->handle);
- if(result)
- goto error;
-
- if(conn_config->issuercert) {
- SECStatus ret = SECFailure;
- char *nickname = dup_nickname(data, conn_config->issuercert);
- if(nickname) {
- /* we support only nicknames in case of issuercert for now */
- ret = check_issuer_cert(backend->handle, nickname);
- free(nickname);
- }
-
- if(SECFailure == ret) {
- infof(data, "SSL certificate issuer check failed");
- result = CURLE_SSL_ISSUER_ERROR;
- goto error;
- }
- else {
- infof(data, "SSL certificate issuer check ok");
- }
- }
-
- result = cmp_peer_pubkey(connssl, Curl_ssl_cf_is_proxy(cf)?
- data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]:
- data->set.str[STRING_SSL_PINNEDPUBLICKEY]);
- if(result)
- /* status already printed */
- goto error;
-
- return CURLE_OK;
-
-error:
- return nss_fail_connect(cf, data, result);
-}
-
-static CURLcode nss_connect_common(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- bool *done)
-{
- struct ssl_connect_data *connssl = cf->ctx;
- const bool blocking = (done == NULL);
- CURLcode result;
-
- if(connssl->state == ssl_connection_complete) {
- if(!blocking)
- *done = TRUE;
- return CURLE_OK;
- }
-
- if(connssl->connecting_state == ssl_connect_1) {
- result = nss_setup_connect(cf, data);
- if(result)
- /* we do not expect CURLE_AGAIN from nss_setup_connect() */
- return result;
-
- connssl->connecting_state = ssl_connect_2;
- }
-
- /* enable/disable blocking mode before handshake */
- result = nss_set_blocking(cf, data, blocking);
- if(result)
- return result;
-
- result = nss_do_connect(cf, data);
- switch(result) {
- case CURLE_OK:
- break;
- case CURLE_AGAIN:
- /* CURLE_AGAIN in non-blocking mode is not an error */
- if(!blocking)
- return CURLE_OK;
- else
- return result;
- default:
- return result;
- }
-
- if(blocking) {
- /* in blocking mode, set NSS non-blocking mode _after_ SSL handshake */
- result = nss_set_blocking(cf, data, /* blocking */ FALSE);
- if(result)
- return result;
- }
- else
- /* signal completed SSL handshake */
- *done = TRUE;
-
- connssl->state = ssl_connection_complete;
-
- /* ssl_connect_done is never used outside, go back to the initial state */
- connssl->connecting_state = ssl_connect_1;
-
- return CURLE_OK;
-}
-
-static CURLcode nss_connect(struct Curl_cfilter *cf,
- struct Curl_easy *data)
-{
- return nss_connect_common(cf, data, /* blocking */ NULL);
-}
-
-static CURLcode nss_connect_nonblocking(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- bool *done)
-{
- return nss_connect_common(cf, data, done);
-}
-
-static ssize_t nss_send(struct Curl_cfilter *cf,
- struct Curl_easy *data, /* transfer */
- const void *mem, /* send this data */
- size_t len, /* amount to write */
- CURLcode *curlcode)
-{
- struct ssl_connect_data *connssl = cf->ctx;
- struct nss_ssl_backend_data *backend =
- (struct nss_ssl_backend_data *)connssl->backend;
- ssize_t rc;
-
- (void)data;
- DEBUGASSERT(backend);
-
- /* The SelectClientCert() hook uses this for infof() and failf() but the
- handle stored in nss_setup_connect() could have already been freed. */
- backend->data = data;
-
- rc = PR_Send(backend->handle, mem, (int)len, 0, PR_INTERVAL_NO_WAIT);
- if(rc < 0) {
- PRInt32 err = PR_GetError();
- if(err == PR_WOULD_BLOCK_ERROR)
- *curlcode = CURLE_AGAIN;
- else {
- /* print the error number and error string */
- const char *err_name = nss_error_to_name(err);
- infof(data, "SSL write: error %d (%s)", err, err_name);
-
- /* print a human-readable message describing the error if available */
- nss_print_error_message(data, err);
-
- *curlcode = (is_cc_error(err))
- ? CURLE_SSL_CERTPROBLEM
- : CURLE_SEND_ERROR;
- }
-
- return -1;
- }
-
- return rc; /* number of bytes */
-}
-
-static bool
-nss_data_pending(struct Curl_cfilter *cf, const struct Curl_easy *data)
-{
- struct ssl_connect_data *connssl = cf->ctx;
- struct nss_ssl_backend_data *backend =
- (struct nss_ssl_backend_data *)connssl->backend;
- PRFileDesc *fd = backend->handle->lower;
- char buf;
-
- (void) data;
-
- /* Returns true in case of error to force reading. */
- return PR_Recv(fd, (void *) &buf, 1, PR_MSG_PEEK, PR_INTERVAL_NO_WAIT) != 0;
-}
-
-static ssize_t nss_recv(struct Curl_cfilter *cf,
- struct Curl_easy *data, /* transfer */
- char *buf, /* store read data here */
- size_t buffersize, /* max amount to read */
- CURLcode *curlcode)
-{
- struct ssl_connect_data *connssl = cf->ctx;
- struct nss_ssl_backend_data *backend =
- (struct nss_ssl_backend_data *)connssl->backend;
- ssize_t nread;
-
- (void)data;
- DEBUGASSERT(backend);
-
- /* The SelectClientCert() hook uses this for infof() and failf() but the
- handle stored in nss_setup_connect() could have already been freed. */
- backend->data = data;
-
- nread = PR_Recv(backend->handle, buf, (int)buffersize, 0,
- PR_INTERVAL_NO_WAIT);
- if(nread < 0) {
- /* failed SSL read */
- PRInt32 err = PR_GetError();
-
- if(err == PR_WOULD_BLOCK_ERROR)
- *curlcode = CURLE_AGAIN;
- else {
- /* print the error number and error string */
- const char *err_name = nss_error_to_name(err);
- infof(data, "SSL read: errno %d (%s)", err, err_name);
-
- /* print a human-readable message describing the error if available */
- nss_print_error_message(data, err);
-
- *curlcode = (is_cc_error(err))
- ? CURLE_SSL_CERTPROBLEM
- : CURLE_RECV_ERROR;
- }
-
- return -1;
- }
-
- return nread;
-}
-
-static size_t nss_version(char *buffer, size_t size)
-{
- return msnprintf(buffer, size, "NSS/%s", NSS_GetVersion());
-}
-
-/* data might be NULL */
-static int Curl_nss_seed(struct Curl_easy *data)
-{
- /* make sure that NSS is initialized */
- return !!Curl_nss_force_init(data);
-}
-
-/* data might be NULL */
-static CURLcode nss_random(struct Curl_easy *data,
- unsigned char *entropy,
- size_t length)
-{
- Curl_nss_seed(data); /* Initiate the seed if not already done */
-
- if(SECSuccess != PK11_GenerateRandom(entropy, curlx_uztosi(length)))
- /* signal a failure */
- return CURLE_FAILED_INIT;
-
- return CURLE_OK;
-}
-
-static CURLcode nss_sha256sum(const unsigned char *tmp, /* input */
- size_t tmplen,
- unsigned char *sha256sum, /* output */
- size_t sha256len)
-{
- PK11Context *SHA256pw = PK11_CreateDigestContext(SEC_OID_SHA256);
- unsigned int SHA256out;
-
- if(!SHA256pw)
- return CURLE_NOT_BUILT_IN;
-
- PK11_DigestOp(SHA256pw, tmp, curlx_uztoui(tmplen));
- PK11_DigestFinal(SHA256pw, sha256sum, &SHA256out, curlx_uztoui(sha256len));
- PK11_DestroyContext(SHA256pw, PR_TRUE);
-
- return CURLE_OK;
-}
-
-static bool nss_cert_status_request(void)
-{
-#ifdef SSL_ENABLE_OCSP_STAPLING
- return TRUE;
-#else
- return FALSE;
-#endif
-}
-
-static bool nss_false_start(void)
-{
-#if NSSVERNUM >= 0x030f04 /* 3.15.4 */
- return TRUE;
-#else
- return FALSE;
-#endif
-}
-
-static void *nss_get_internals(struct ssl_connect_data *connssl,
- CURLINFO info UNUSED_PARAM)
-{
- struct nss_ssl_backend_data *backend =
- (struct nss_ssl_backend_data *)connssl->backend;
- (void)info;
- DEBUGASSERT(backend);
- return backend->handle;
-}
-
-static bool nss_attach_data(struct Curl_cfilter *cf,
- struct Curl_easy *data)
-{
- struct ssl_connect_data *connssl = cf->ctx;
- struct nss_ssl_backend_data *backend =
- (struct nss_ssl_backend_data *)connssl->backend;
-
- if(!backend->data)
- backend->data = data;
- return TRUE;
-}
-
-static void nss_detach_data(struct Curl_cfilter *cf,
- struct Curl_easy *data)
-{
- struct ssl_connect_data *connssl = cf->ctx;
- struct nss_ssl_backend_data *backend =
- (struct nss_ssl_backend_data *)connssl->backend;
-
- if(backend->data == data)
- backend->data = NULL;
-}
-
-const struct Curl_ssl Curl_ssl_nss = {
- { CURLSSLBACKEND_NSS, "nss" }, /* info */
-
- SSLSUPP_CA_PATH |
- SSLSUPP_CERTINFO |
- SSLSUPP_PINNEDPUBKEY |
- SSLSUPP_HTTPS_PROXY,
-
- sizeof(struct nss_ssl_backend_data),
-
- nss_init, /* init */
- nss_cleanup, /* cleanup */
- nss_version, /* version */
- Curl_none_check_cxn, /* check_cxn */
- /* NSS has no shutdown function provided and thus always fail */
- Curl_none_shutdown, /* shutdown */
- nss_data_pending, /* data_pending */
- nss_random, /* random */
- nss_cert_status_request, /* cert_status_request */
- nss_connect, /* connect */
- nss_connect_nonblocking, /* connect_nonblocking */
- Curl_ssl_get_select_socks, /* getsock */
- nss_get_internals, /* get_internals */
- nss_close, /* close_one */
- Curl_none_close_all, /* close_all */
- /* NSS has its own session ID cache */
- Curl_none_session_free, /* session_free */
- Curl_none_set_engine, /* set_engine */
- Curl_none_set_engine_default, /* set_engine_default */
- Curl_none_engines_list, /* engines_list */
- nss_false_start, /* false_start */
- nss_sha256sum, /* sha256sum */
- nss_attach_data, /* associate_connection */
- nss_detach_data, /* disassociate_connection */
- NULL, /* free_multi_ssl_backend_data */
- nss_recv, /* recv decrypted data */
- nss_send, /* send data to encrypt */
-};
-
-#endif /* USE_NSS */
diff --git a/lib/vtls/nssg.h b/lib/vtls/nssg.h
deleted file mode 100644
index ad7eef5..0000000
--- a/lib/vtls/nssg.h
+++ /dev/null
@@ -1,41 +0,0 @@
-#ifndef HEADER_CURL_NSSG_H
-#define HEADER_CURL_NSSG_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at https://curl.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * SPDX-License-Identifier: curl
- *
- ***************************************************************************/
-#include "curl_setup.h"
-
-#ifdef USE_NSS
-/*
- * This header should only be needed to get included by vtls.c and nss.c
- */
-
-#include "urldata.h"
-
-/* initialize NSS library if not already */
-CURLcode Curl_nss_force_init(struct Curl_easy *data);
-
-extern const struct Curl_ssl Curl_ssl_nss;
-
-#endif /* USE_NSS */
-#endif /* HEADER_CURL_NSSG_H */
diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c
index ae33147..a12e712 100644
--- a/lib/vtls/openssl.c
+++ b/lib/vtls/openssl.c
@@ -190,11 +190,12 @@
* Whether SSL_CTX_set_keylog_callback is available.
* OpenSSL: supported since 1.1.1 https://github.com/openssl/openssl/pull/2287
* BoringSSL: supported since d28f59c27bac (committed 2015-11-19)
- * LibreSSL: unsupported in at least 2.7.2 (explicitly check for it since it
- * lies and pretends to be OpenSSL 2.0.0).
+ * LibreSSL: supported since 3.5.0 (released 2022-02-24)
*/
#if (OPENSSL_VERSION_NUMBER >= 0x10101000L && \
!defined(LIBRESSL_VERSION_NUMBER)) || \
+ (defined(LIBRESSL_VERSION_NUMBER) && \
+ LIBRESSL_VERSION_NUMBER >= 0x3050000fL) || \
defined(OPENSSL_IS_BORINGSSL)
#define HAVE_KEYLOG_CALLBACK
#endif
@@ -202,11 +203,13 @@
/* Whether SSL_CTX_set_ciphersuites is available.
* OpenSSL: supported since 1.1.1 (commit a53b5be6a05)
* BoringSSL: no
- * LibreSSL: no
+ * LibreSSL: supported since 3.4.1 (released 2021-10-14)
*/
-#if ((OPENSSL_VERSION_NUMBER >= 0x10101000L) && \
- !defined(LIBRESSL_VERSION_NUMBER) && \
- !defined(OPENSSL_IS_BORINGSSL))
+#if ((OPENSSL_VERSION_NUMBER >= 0x10101000L && \
+ !defined(LIBRESSL_VERSION_NUMBER)) || \
+ (defined(LIBRESSL_VERSION_NUMBER) && \
+ LIBRESSL_VERSION_NUMBER >= 0x3040100fL)) && \
+ !defined(OPENSSL_IS_BORINGSSL)
#define HAVE_SSL_CTX_SET_CIPHERSUITES
#if !defined(OPENSSL_IS_AWSLC)
#define HAVE_SSL_CTX_SET_POST_HANDSHAKE_AUTH
@@ -266,7 +269,7 @@
#define HAVE_OPENSSL_VERSION
#endif
-#ifdef OPENSSL_IS_BORINGSSL
+#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)
typedef uint32_t sslerr_t;
#else
typedef unsigned long sslerr_t;
@@ -722,8 +725,8 @@ static int bio_cf_out_write(BIO *bio, const char *buf, int blen)
DEBUGASSERT(data);
nwritten = Curl_conn_cf_send(cf->next, data, buf, blen, &result);
- DEBUGF(LOG_CF(data, cf, "bio_cf_out_write(len=%d) -> %d, err=%d",
- blen, (int)nwritten, result));
+ CURL_TRC_CF(data, cf, "bio_cf_out_write(len=%d) -> %d, err=%d",
+ blen, (int)nwritten, result);
BIO_clear_retry_flags(bio);
backend->io_result = result;
if(nwritten < 0) {
@@ -749,8 +752,8 @@ static int bio_cf_in_read(BIO *bio, char *buf, int blen)
return 0;
nread = Curl_conn_cf_recv(cf->next, data, buf, blen, &result);
- DEBUGF(LOG_CF(data, cf, "bio_cf_in_read(len=%d) -> %d, err=%d",
- blen, (int)nread, result));
+ CURL_TRC_CF(data, cf, "bio_cf_in_read(len=%d) -> %d, err=%d",
+ blen, (int)nread, result);
BIO_clear_retry_flags(bio);
backend->io_result = result;
if(nread < 0) {
@@ -996,20 +999,6 @@ static CURLcode ossl_seed(struct Curl_easy *data)
return CURLE_OK;
#endif
-#if defined(HAVE_RAND_EGD) && defined(EGD_SOCKET)
- /* available in OpenSSL 0.9.5 and later */
- /* EGD_SOCKET is set at configure time or not at all */
- {
- /* If there's an option and a define, the option overrides the
- define */
- int ret = RAND_egd(EGD_SOCKET);
- if(-1 != ret) {
- if(rand_enough())
- return CURLE_OK;
- }
- }
-#endif
-
/* fallback to a custom seeding of the PRNG using a hash based on a current
time */
do {
@@ -1705,7 +1694,7 @@ static int x509_name_oneline(X509_NAME *a, char *buf, size_t size)
static int ossl_init(void)
{
#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && \
- !defined(LIBRESSL_VERSION_NUMBER)
+ (!defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER >= 0x2070000fL)
const uint64_t flags =
#ifdef OPENSSL_INIT_ENGINE_ALL_BUILTIN
/* not present in BoringSSL */
@@ -1895,6 +1884,9 @@ static void ossl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
(void)SSL_read(backend->handle, buf, (int)sizeof(buf));
(void)SSL_shutdown(backend->handle);
+
+ ERR_clear_error();
+
SSL_set_connect_state(backend->handle);
}
@@ -2320,7 +2312,11 @@ static CURLcode verifystatus(struct Curl_cfilter *cf,
{
struct ssl_connect_data *connssl = cf->ctx;
int i, ocsp_status;
+#if defined(OPENSSL_IS_AWSLC)
+ const uint8_t *status;
+#else
unsigned char *status;
+#endif
const unsigned char *p;
CURLcode result = CURLE_OK;
OCSP_RESPONSE *rsp = NULL;
@@ -2418,7 +2414,7 @@ static CURLcode verifystatus(struct Curl_cfilter *cf,
goto end;
}
- for(i = 0; i < sk_X509_num(ch); i++) {
+ for(i = 0; i < (int)sk_X509_num(ch); i++) {
X509 *issuer = sk_X509_value(ch, i);
if(X509_check_issued(issuer, cert) == X509_V_OK) {
id = OCSP_cert_to_id(EVP_sha1(), cert, issuer);
@@ -3716,6 +3712,15 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,
/* give application a chance to interfere with SSL set up. */
if(data->set.ssl.fsslctx) {
+ /* When a user callback is installed to modify the SSL_CTX,
+ * we need to do the full initialization before calling it.
+ * See: #11800 */
+ if(!backend->x509_store_setup) {
+ result = Curl_ssl_setup_x509_store(cf, data, backend->ctx);
+ if(result)
+ return result;
+ backend->x509_store_setup = TRUE;
+ }
Curl_set_in_callback(data, true);
result = (*data->set.ssl.fsslctx)(data, backend->ctx,
data->set.ssl.fsslctxp);
@@ -3779,7 +3784,7 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,
return CURLE_SSL_CONNECT_ERROR;
}
/* Informational message */
- infof(data, "SSL re-using session ID");
+ infof(data, "SSL reusing session ID");
}
Curl_ssl_sessionid_unlock(data);
}
@@ -3864,7 +3869,13 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf,
return CURLE_OK;
}
#endif
- else if(backend->io_result == CURLE_AGAIN) {
+#ifdef SSL_ERROR_WANT_RETRY_VERIFY
+ if(SSL_ERROR_WANT_RETRY_VERIFY == detail) {
+ connssl->connecting_state = ssl_connect_2;
+ return CURLE_OK;
+ }
+#endif
+ if(backend->io_result == CURLE_AGAIN) {
return CURLE_OK;
}
else {
@@ -3904,11 +3915,7 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf,
error_buffer */
strcpy(error_buffer, "SSL certificate verification failed");
}
-#if (OPENSSL_VERSION_NUMBER >= 0x10101000L && \
- !defined(LIBRESSL_VERSION_NUMBER) && \
- !defined(OPENSSL_IS_BORINGSSL) && \
- !defined(OPENSSL_IS_AWSLC))
-
+#if defined(SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED)
/* SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED is only available on
OpenSSL version above v1.1.1, not LibreSSL, BoringSSL, or AWS-LC */
else if((lib == ERR_LIB_SSL) &&
@@ -4734,7 +4741,10 @@ static CURLcode ossl_sha256sum(const unsigned char *tmp, /* input */
mdctx = EVP_MD_CTX_create();
if(!mdctx)
return CURLE_OUT_OF_MEMORY;
- EVP_DigestInit(mdctx, EVP_sha256());
+ if(!EVP_DigestInit(mdctx, EVP_sha256())) {
+ EVP_MD_CTX_destroy(mdctx);
+ return CURLE_FAILED_INIT;
+ }
EVP_DigestUpdate(mdctx, tmp, tmplen);
EVP_DigestFinal_ex(mdctx, sha256sum, &len);
EVP_MD_CTX_destroy(mdctx);
diff --git a/lib/vtls/rustls.c b/lib/vtls/rustls.c
index 76d3e24..a3e9d96 100644
--- a/lib/vtls/rustls.c
+++ b/lib/vtls/rustls.c
@@ -104,10 +104,6 @@ read_cb(void *userdata, uint8_t *buf, uintptr_t len, uintptr_t *out_n)
ret = EINVAL;
}
*out_n = (int)nread;
- /*
- DEBUGF(LOG_CF(io_ctx->data, io_ctx->cf, "cf->next recv(len=%zu) -> %zd, %d",
- len, nread, result));
- */
return ret;
}
@@ -128,7 +124,7 @@ write_cb(void *userdata, const uint8_t *buf, uintptr_t len, uintptr_t *out_n)
}
*out_n = (int)nwritten;
/*
- DEBUGF(LOG_CF(io_ctx->data, io_ctx->cf, "cf->next send(len=%zu) -> %zd, %d",
+ CURL_TRC_CFX(io_ctx->data, io_ctx->cf, "cf->next send(len=%zu) -> %zd, %d",
len, nwritten, result));
*/
return ret;
@@ -267,8 +263,8 @@ cr_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
}
out:
- DEBUGF(LOG_CF(data, cf, "cf_recv(len=%zu) -> %zd, %d",
- plainlen, nread, *err));
+ CURL_TRC_CF(data, cf, "cf_recv(len=%zu) -> %zd, %d",
+ plainlen, nread, *err);
return nread;
}
@@ -302,7 +298,7 @@ cr_send(struct Curl_cfilter *cf, struct Curl_easy *data,
DEBUGASSERT(backend);
rconn = backend->conn;
- DEBUGF(LOG_CF(data, cf, "cf_send: %ld plain bytes", plainlen));
+ CURL_TRC_CF(data, cf, "cf_send: %ld plain bytes", plainlen);
io_ctx.cf = cf;
io_ctx.data = data;
@@ -327,8 +323,8 @@ cr_send(struct Curl_cfilter *cf, struct Curl_easy *data,
io_error = rustls_connection_write_tls(rconn, write_cb, &io_ctx,
&tlswritten);
if(io_error == EAGAIN || io_error == EWOULDBLOCK) {
- DEBUGF(LOG_CF(data, cf, "cf_send: EAGAIN after %zu bytes",
- tlswritten_total));
+ CURL_TRC_CF(data, cf, "cf_send: EAGAIN after %zu bytes",
+ tlswritten_total);
*err = CURLE_AGAIN;
return -1;
}
@@ -344,7 +340,7 @@ cr_send(struct Curl_cfilter *cf, struct Curl_easy *data,
*err = CURLE_WRITE_ERROR;
return -1;
}
- DEBUGF(LOG_CF(data, cf, "cf_send: wrote %zu TLS bytes", tlswritten));
+ CURL_TRC_CF(data, cf, "cf_send: wrote %zu TLS bytes", tlswritten);
tlswritten_total += tlswritten;
}
diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c
index 5dcf5ba..f6a5d44 100644
--- a/lib/vtls/schannel.c
+++ b/lib/vtls/schannel.c
@@ -793,8 +793,11 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf,
backend->cred->client_cert_store = client_cert_store;
#endif
- /* Windows 10, 1809 (a.k.a. Windows 10 build 17763) */
- if(curlx_verify_windows_version(10, 0, 17763, PLATFORM_WINNT,
+ /* We support TLS 1.3 starting in Windows 10 version 1809 (OS build 17763) as
+ long as the user did not set a legacy algorithm list
+ (CURLOPT_SSL_CIPHER_LIST). */
+ if(!conn_config->cipher_list &&
+ curlx_verify_windows_version(10, 0, 17763, PLATFORM_WINNT,
VERSION_GREATER_THAN_EQUAL)) {
char *ciphers13 = 0;
@@ -807,9 +810,9 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf,
SCH_CREDENTIALS credentials = { 0 };
TLS_PARAMETERS tls_parameters = { 0 };
- CRYPTO_SETTINGS crypto_settings[4] = { 0 };
- UNICODE_STRING blocked_ccm_modes[1] = { 0 };
- UNICODE_STRING blocked_gcm_modes[1] = { 0 };
+ CRYPTO_SETTINGS crypto_settings[4] = { { 0 } };
+ UNICODE_STRING blocked_ccm_modes[1] = { { 0 } };
+ UNICODE_STRING blocked_gcm_modes[1] = { { 0 } };
int crypto_settings_idx = 0;
@@ -844,7 +847,7 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf,
/* reject too-long cipher names */
if(n > (LONGEST_ALG_ID - 1)) {
- failf(data, "Cipher name too long, not checked.");
+ failf(data, "schannel: Cipher name too long, not checked");
return CURLE_SSL_CIPHER;
}
@@ -872,7 +875,7 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf,
disable_aes_ccm_sha256 = FALSE;
}
else {
- failf(data, "Passed in an unknown TLS 1.3 cipher.");
+ failf(data, "schannel: Unknown TLS 1.3 cipher: %s", tmp);
return CURLE_SSL_CIPHER;
}
@@ -887,7 +890,7 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf,
if(disable_aes_gcm_sha384 && disable_aes_gcm_sha256
&& disable_chacha_poly && disable_aes_ccm_8_sha256
&& disable_aes_ccm_sha256) {
- failf(data, "All available TLS 1.3 ciphers were disabled.");
+ failf(data, "schannel: All available TLS 1.3 ciphers were disabled");
return CURLE_SSL_CIPHER;
}
@@ -1010,7 +1013,9 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf,
&backend->cred->time_stamp);
}
else {
- /* Pre-Windows 10 1809 */
+ /* Pre-Windows 10 1809 or the user set a legacy algorithm list. Although MS
+ doesn't document it, currently Schannel will not negotiate TLS 1.3 when
+ SCHANNEL_CRED is used. */
ALG_ID algIds[NUM_CIPHERS];
char *ciphers = conn_config->cipher_list;
SCHANNEL_CRED schannel_cred = { 0 };
@@ -1019,9 +1024,20 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf,
schannel_cred.grbitEnabledProtocols = enabled_protocols;
if(ciphers) {
+ if((enabled_protocols & SP_PROT_TLS1_3_CLIENT)) {
+ infof(data, "schannel: WARNING: This version of Schannel may "
+ "negotiate a less-secure TLS version than TLS 1.3 because the "
+ "user set an algorithm cipher list.");
+ }
+ if(conn_config->cipher_list13) {
+ failf(data, "schannel: This version of Schannel does not support "
+ "setting an algorithm cipher list and TLS 1.3 cipher list at "
+ "the same time");
+ return CURLE_SSL_CIPHER;
+ }
result = set_ssl_ciphers(&schannel_cred, ciphers, algIds);
if(CURLE_OK != result) {
- failf(data, "Unable to set ciphers to from connection ssl config");
+ failf(data, "schannel: Failed setting algorithm cipher list");
return result;
}
}
@@ -1158,7 +1174,7 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
Curl_ssl_sessionid_lock(data);
if(!Curl_ssl_getsessionid(cf, data, (void **)&old_cred, NULL)) {
backend->cred = old_cred;
- DEBUGF(infof(data, "schannel: re-using existing credential handle"));
+ DEBUGF(infof(data, "schannel: reusing existing credential handle"));
/* increment the reference counter of the credential/session handle */
backend->cred->refcount++;
@@ -1618,10 +1634,16 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
#ifdef HAS_MANUAL_VERIFY_API
if(conn_config->verifypeer && backend->use_manual_cred_validation) {
+ /* Certificate verification also verifies the hostname if verifyhost */
return Curl_verify_certificate(cf, data);
}
#endif
+ /* Verify the hostname manually when certificate verification is disabled,
+ because in that case Schannel won't verify it. */
+ if(!conn_config->verifypeer && conn_config->verifyhost)
+ return Curl_verify_host(cf, data);
+
return CURLE_OK;
}
@@ -1634,7 +1656,8 @@ valid_cert_encoding(const CERT_CONTEXT *cert_context)
(cert_context->cbCertEncoded > 0);
}
-typedef bool(*Read_crt_func)(const CERT_CONTEXT *ccert_context, void *arg);
+typedef bool(*Read_crt_func)(const CERT_CONTEXT *ccert_context,
+ bool reverse_order, void *arg);
static void
traverse_cert_store(const CERT_CONTEXT *context, Read_crt_func func,
@@ -1642,19 +1665,32 @@ traverse_cert_store(const CERT_CONTEXT *context, Read_crt_func func,
{
const CERT_CONTEXT *current_context = NULL;
bool should_continue = true;
+ bool first = true;
+ bool reverse_order = false;
while(should_continue &&
(current_context = CertEnumCertificatesInStore(
context->hCertStore,
- current_context)) != NULL)
- should_continue = func(current_context, arg);
+ current_context)) != NULL) {
+ /* Windows 11 22H2 OS Build 22621.674 or higher enumerates certificates in
+ leaf-to-root order while all previous versions of Windows enumerate
+ certificates in root-to-leaf order. Determine the order of enumeration
+ by comparing SECPKG_ATTR_REMOTE_CERT_CONTEXT's pbCertContext with the
+ first certificate's pbCertContext. */
+ if(first && context->pbCertEncoded != current_context->pbCertEncoded)
+ reverse_order = true;
+ should_continue = func(current_context, reverse_order, arg);
+ first = false;
+ }
if(current_context)
CertFreeCertificateContext(current_context);
}
static bool
-cert_counter_callback(const CERT_CONTEXT *ccert_context, void *certs_count)
+cert_counter_callback(const CERT_CONTEXT *ccert_context, bool reverse_order,
+ void *certs_count)
{
+ (void)reverse_order; /* unused */
if(valid_cert_encoding(ccert_context))
(*(int *)certs_count)++;
return true;
@@ -1669,14 +1705,16 @@ struct Adder_args
};
static bool
-add_cert_to_certinfo(const CERT_CONTEXT *ccert_context, void *raw_arg)
+add_cert_to_certinfo(const CERT_CONTEXT *ccert_context, bool reverse_order,
+ void *raw_arg)
{
struct Adder_args *args = (struct Adder_args*)raw_arg;
args->result = CURLE_OK;
if(valid_cert_encoding(ccert_context)) {
const char *beg = (const char *) ccert_context->pbCertEncoded;
const char *end = beg + ccert_context->cbCertEncoded;
- int insert_index = (args->certs_count - 1) - args->idx;
+ int insert_index = reverse_order ? (args->certs_count - 1) - args->idx :
+ args->idx;
args->result = Curl_extract_certinfo(args->data, insert_index,
beg, end);
args->idx++;
@@ -1758,7 +1796,7 @@ schannel_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
}
#endif
- /* save the current session data for possible re-use */
+ /* save the current session data for possible reuse */
if(ssl_config->primary.sessionid) {
bool incache;
bool added = FALSE;
diff --git a/lib/vtls/schannel.h b/lib/vtls/schannel.h
index b8cb494..be23567 100644
--- a/lib/vtls/schannel.h
+++ b/lib/vtls/schannel.h
@@ -76,6 +76,9 @@
extern const struct Curl_ssl Curl_ssl_schannel;
+CURLcode Curl_verify_host(struct Curl_cfilter *cf,
+ struct Curl_easy *data);
+
CURLcode Curl_verify_certificate(struct Curl_cfilter *cf,
struct Curl_easy *data);
diff --git a/lib/vtls/schannel_int.h b/lib/vtls/schannel_int.h
index d8b6cce..edb20bc 100644
--- a/lib/vtls/schannel_int.h
+++ b/lib/vtls/schannel_int.h
@@ -43,6 +43,58 @@
#define HAS_CLIENT_CERT_PATH
#endif
+#ifndef CRYPT_DECODE_NOCOPY_FLAG
+#define CRYPT_DECODE_NOCOPY_FLAG 0x1
+#endif
+
+#ifndef CRYPT_DECODE_ALLOC_FLAG
+#define CRYPT_DECODE_ALLOC_FLAG 0x8000
+#endif
+
+#ifndef CERT_ALT_NAME_DNS_NAME
+#define CERT_ALT_NAME_DNS_NAME 3
+#endif
+
+#ifndef CERT_ALT_NAME_IP_ADDRESS
+#define CERT_ALT_NAME_IP_ADDRESS 8
+#endif
+
+
+#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
+/* Original mingw is missing CERT structs or they're disabled.
+ Refer to w32api-5.0.2-mingw32-dev\include\wincrypt.h. */
+
+/* !checksrc! disable TYPEDEFSTRUCT 4 */
+typedef struct _CERT_OTHER_NAME {
+ LPSTR pszObjId;
+ CRYPT_OBJID_BLOB Value;
+} CERT_OTHER_NAME, *PCERT_OTHER_NAME;
+
+typedef struct _CERT_ALT_NAME_ENTRY {
+ DWORD dwAltNameChoice;
+ union {
+ PCERT_OTHER_NAME pOtherName;
+ LPWSTR pwszRfc822Name;
+ LPWSTR pwszDNSName;
+ CERT_NAME_BLOB DirectoryName;
+ LPWSTR pwszURL;
+ CRYPT_DATA_BLOB IPAddress;
+ LPSTR pszRegisteredID;
+ };
+} CERT_ALT_NAME_ENTRY, *PCERT_ALT_NAME_ENTRY;
+
+typedef struct _CERT_ALT_NAME_INFO {
+ DWORD cAltEntry;
+ PCERT_ALT_NAME_ENTRY rgAltEntry;
+} CERT_ALT_NAME_INFO, *PCERT_ALT_NAME_INFO;
+
+typedef struct _CRYPT_DECODE_PARA {
+ DWORD cbSize;
+ PFN_CRYPT_ALLOC pfnAlloc;
+ PFN_CRYPT_FREE pfnFree;
+} CRYPT_DECODE_PARA, *PCRYPT_DECODE_PARA;
+#endif
+
#ifndef SCH_CREDENTIALS_VERSION
#define SCH_CREDENTIALS_VERSION 0x00000005
diff --git a/lib/vtls/schannel_verify.c b/lib/vtls/schannel_verify.c
index c582ee4..a5d5c98 100644
--- a/lib/vtls/schannel_verify.c
+++ b/lib/vtls/schannel_verify.c
@@ -39,8 +39,6 @@
#include "schannel.h"
#include "schannel_int.h"
-#ifdef HAS_MANUAL_VERIFY_API
-
#include "vtls.h"
#include "vtls_int.h"
#include "sendf.h"
@@ -56,6 +54,9 @@
#define BACKEND ((struct schannel_ssl_backend_data *)connssl->backend)
+
+#ifdef HAS_MANUAL_VERIFY_API
+
#define MAX_CAFILE_SIZE 1048576 /* 1 MiB */
#define BEGIN_CERT "-----BEGIN CERTIFICATE-----"
#define END_CERT "\n-----END CERTIFICATE-----"
@@ -330,6 +331,8 @@ cleanup:
return result;
}
+#endif /* HAS_MANUAL_VERIFY_API */
+
/*
* Returns the number of characters necessary to populate all the host_names.
* If host_names is not NULL, populate it with all the host names. Each string
@@ -353,10 +356,10 @@ static DWORD cert_get_name_string(struct Curl_easy *data,
LPTSTR current_pos = NULL;
DWORD i;
+#ifdef CERT_NAME_SEARCH_ALL_NAMES_FLAG
/* CERT_NAME_SEARCH_ALL_NAMES_FLAG is available from Windows 8 onwards. */
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
* any decoding */
DWORD name_flags =
@@ -368,8 +371,8 @@ static DWORD cert_get_name_string(struct Curl_easy *data,
host_names,
length);
return actual_length;
-#endif
}
+#endif
compute_content = host_names != NULL && length != 0;
@@ -457,17 +460,34 @@ static DWORD cert_get_name_string(struct Curl_easy *data,
return actual_length;
}
-static CURLcode verify_host(struct Curl_easy *data,
- CERT_CONTEXT *pCertContextServer,
- const char *conn_hostname)
+/* Verify the server's hostname */
+CURLcode Curl_verify_host(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
+ struct ssl_connect_data *connssl = cf->ctx;
+ SECURITY_STATUS sspi_status;
CURLcode result = CURLE_PEER_FAILED_VERIFICATION;
+ CERT_CONTEXT *pCertContextServer = NULL;
TCHAR *cert_hostname_buff = NULL;
size_t cert_hostname_buff_index = 0;
+ const char *conn_hostname = connssl->hostname;
size_t hostlen = strlen(conn_hostname);
DWORD len = 0;
DWORD actual_len = 0;
+ sspi_status =
+ s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
+ SECPKG_ATTR_REMOTE_CERT_CONTEXT,
+ &pCertContextServer);
+
+ if((sspi_status != SEC_E_OK) || !pCertContextServer) {
+ char buffer[STRERROR_LEN];
+ failf(data, "schannel: Failed to read remote certificate context: %s",
+ Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
+ result = CURLE_PEER_FAILED_VERIFICATION;
+ goto cleanup;
+ }
+
/* Determine the size of the string needed for the cert hostname */
len = cert_get_name_string(data, pCertContextServer, NULL, 0);
if(len == 0) {
@@ -498,10 +518,9 @@ static CURLcode verify_host(struct Curl_easy *data,
goto cleanup;
}
- /* If HAVE_CERT_NAME_SEARCH_ALL_NAMES is available, the output
- * will contain all DNS names, where each name is null-terminated
- * and the last DNS name is double null-terminated. Due to this
- * encoding, use the length of the buffer to iterate over all names.
+ /* cert_hostname_buff contains all DNS names, where each name is
+ * null-terminated and the last DNS name is double null-terminated. Due to
+ * this encoding, use the length of the buffer to iterate over all names.
*/
result = CURLE_PEER_FAILED_VERIFICATION;
while(cert_hostname_buff_index < len &&
@@ -560,9 +579,15 @@ static CURLcode verify_host(struct Curl_easy *data,
cleanup:
Curl_safefree(cert_hostname_buff);
+ if(pCertContextServer)
+ CertFreeCertificateContext(pCertContextServer);
+
return result;
}
+
+#ifdef HAS_MANUAL_VERIFY_API
+/* Verify the server's certificate and hostname */
CURLcode Curl_verify_certificate(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
@@ -721,7 +746,7 @@ CURLcode Curl_verify_certificate(struct Curl_cfilter *cf,
if(result == CURLE_OK) {
if(conn_config->verifyhost) {
- result = verify_host(data, pCertContextServer, connssl->hostname);
+ result = Curl_verify_host(cf, data);
}
}
diff --git a/lib/vtls/sectransp.c b/lib/vtls/sectransp.c
index 32bb3a5..e6a114a 100644
--- a/lib/vtls/sectransp.c
+++ b/lib/vtls/sectransp.c
@@ -845,8 +845,8 @@ static OSStatus bio_cf_in_read(SSLConnectionRef connection,
DEBUGASSERT(data);
nread = Curl_conn_cf_recv(cf->next, data, buf, *dataLength, &result);
- DEBUGF(LOG_CF(data, cf, "bio_read(len=%zu) -> %zd, result=%d",
- *dataLength, nread, result));
+ CURL_TRC_CF(data, cf, "bio_read(len=%zu) -> %zd, result=%d",
+ *dataLength, nread, result);
if(nread < 0) {
switch(result) {
case CURLE_OK:
@@ -885,8 +885,8 @@ static OSStatus bio_cf_out_write(SSLConnectionRef connection,
DEBUGASSERT(data);
nwritten = Curl_conn_cf_send(cf->next, data, buf, *dataLength, &result);
- DEBUGF(LOG_CF(data, cf, "bio_send(len=%zu) -> %zd, result=%d",
- *dataLength, nwritten, result));
+ CURL_TRC_CF(data, cf, "bio_send(len=%zu) -> %zd, result=%d",
+ *dataLength, nwritten, result);
if(nwritten <= 0) {
if(result == CURLE_AGAIN) {
rtn = errSSLWouldBlock;
@@ -1086,7 +1086,6 @@ static OSStatus CopyIdentityWithLabel(char *label,
CFArrayRef keys_list;
CFIndex keys_list_count;
CFIndex i;
- CFStringRef common_name;
/* SecItemCopyMatching() was introduced in iOS and Snow Leopard.
kSecClassIdentity was introduced in Lion. If both exist, let's use them
@@ -1134,6 +1133,7 @@ static OSStatus CopyIdentityWithLabel(char *label,
(SecIdentityRef) CFArrayGetValueAtIndex(keys_list, i);
err = SecIdentityCopyCertificate(identity, &cert);
if(err == noErr) {
+ CFStringRef common_name = NULL;
OSStatus copy_status = noErr;
#if CURL_BUILD_IOS
common_name = SecCertificateCopySubjectSummary(cert);
@@ -1149,7 +1149,8 @@ static OSStatus CopyIdentityWithLabel(char *label,
status = noErr;
break;
}
- CFRelease(common_name);
+ if(common_name)
+ CFRelease(common_name);
}
CFRelease(cert);
}
@@ -1293,7 +1294,7 @@ static OSStatus CopyIdentityFromPKCS12File(const char *cPath,
/* This code was borrowed from nss.c, with some modifications:
* Determine whether the nickname passed in is a filename that needs to
- * be loaded as a PEM or a regular NSS nickname.
+ * be loaded as a PEM or a nickname.
*
* returns 1 for a file
* returns 0 for not a file
@@ -1611,7 +1612,7 @@ static CURLcode sectransp_set_selected_ciphers(struct Curl_easy *data,
The message is a bit cryptic and longer than necessary but can be
understood by humans. */
failf(data, "SSL: cipher string \"%s\" contains unsupported cipher name"
- " starting position %d and ending position %d",
+ " starting position %zd and ending position %zd",
ciphers,
cipher_start - ciphers,
cipher_end - ciphers);
@@ -1662,7 +1663,7 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
DEBUGASSERT(backend);
- DEBUGF(LOG_CF(data, cf, "connect_step1"));
+ CURL_TRC_CF(data, cf, "connect_step1");
GetDarwinVersionNumber(&darwinver_maj, &darwinver_min);
#endif /* CURL_BUILD_MAC */
@@ -2069,7 +2070,7 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
return CURLE_SSL_CONNECT_ERROR;
}
/* Informational message */
- infof(data, "SSL re-using session ID");
+ infof(data, "SSL reusing session ID");
}
/* If there isn't one, then let's make one up! This has to be done prior
to starting the handshake. */
@@ -2293,7 +2294,7 @@ static CURLcode verify_cert_buf(struct Curl_cfilter *cf,
/* This is not a PEM file, probably a certificate in DER format. */
rc = append_cert_to_array(data, certbuf, buflen, array);
if(rc != CURLE_OK) {
- DEBUGF(LOG_CF(data, cf, "append_cert for CA failed"));
+ CURL_TRC_CF(data, cf, "append_cert for CA failed");
result = rc;
goto out;
}
@@ -2307,7 +2308,7 @@ static CURLcode verify_cert_buf(struct Curl_cfilter *cf,
rc = append_cert_to_array(data, der, derlen, array);
free(der);
if(rc != CURLE_OK) {
- DEBUGF(LOG_CF(data, cf, "append_cert for CA failed"));
+ CURL_TRC_CF(data, cf, "append_cert for CA failed");
result = rc;
goto out;
}
@@ -2323,7 +2324,7 @@ static CURLcode verify_cert_buf(struct Curl_cfilter *cf,
goto out;
}
- DEBUGF(LOG_CF(data, cf, "setting %d trust anchors", n));
+ CURL_TRC_CF(data, cf, "setting %d trust anchors", n);
ret = SecTrustSetAnchorCertificates(trust, array);
if(ret != noErr) {
failf(data, "SecTrustSetAnchorCertificates() returned error %d", ret);
@@ -2345,11 +2346,11 @@ static CURLcode verify_cert_buf(struct Curl_cfilter *cf,
switch(trust_eval) {
case kSecTrustResultUnspecified:
/* what does this really mean? */
- DEBUGF(LOG_CF(data, cf, "trust result: Unspecified"));
+ CURL_TRC_CF(data, cf, "trust result: Unspecified");
result = CURLE_OK;
goto out;
case kSecTrustResultProceed:
- DEBUGF(LOG_CF(data, cf, "trust result: Proceed"));
+ CURL_TRC_CF(data, cf, "trust result: Proceed");
result = CURLE_OK;
goto out;
@@ -2382,7 +2383,7 @@ static CURLcode verify_cert(struct Curl_cfilter *cf,
size_t buflen;
if(ca_info_blob) {
- DEBUGF(LOG_CF(data, cf, "verify_peer, CA from config blob"));
+ CURL_TRC_CF(data, cf, "verify_peer, CA from config blob");
certbuf = (unsigned char *)malloc(ca_info_blob->len + 1);
if(!certbuf) {
return CURLE_OUT_OF_MEMORY;
@@ -2392,7 +2393,7 @@ static CURLcode verify_cert(struct Curl_cfilter *cf,
certbuf[ca_info_blob->len]='\0';
}
else if(cafile) {
- DEBUGF(LOG_CF(data, cf, "verify_peer, CA from file '%s'", cafile));
+ CURL_TRC_CF(data, cf, "verify_peer, CA from file '%s'", cafile);
if(read_cert(cafile, &certbuf, &buflen) < 0) {
failf(data, "SSL: failed to read or invalid CA certificate");
return CURLE_SSL_CACERT_BADFILE;
@@ -2432,7 +2433,6 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
SecTrustRef trust;
OSStatus ret;
SecKeyRef keyRef;
- OSStatus success;
ret = SSLCopyPeerTrust(ctx, &trust);
if(ret != noErr || !trust)
@@ -2452,11 +2452,14 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
#elif SECTRANSP_PINNEDPUBKEY_V2
- success = SecItemExport(keyRef, kSecFormatOpenSSL, 0, NULL,
- &publicKeyBits);
- CFRelease(keyRef);
- if(success != errSecSuccess || !publicKeyBits)
- break;
+ {
+ OSStatus success;
+ success = SecItemExport(keyRef, kSecFormatOpenSSL, 0, NULL,
+ &publicKeyBits);
+ CFRelease(keyRef);
+ if(success != errSecSuccess || !publicKeyBits)
+ break;
+ }
#endif /* SECTRANSP_PINNEDPUBKEY_V2 */
@@ -2484,7 +2487,7 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
spkiHeaderLength = 23;
break;
default:
- infof(data, "SSL: unhandled public key length: %d", pubkeylen);
+ infof(data, "SSL: unhandled public key length: %zu", pubkeylen);
#elif SECTRANSP_PINNEDPUBKEY_V2
default:
/* ecDSA secp256r1 pubkeylen == 91 header already included?
@@ -2533,7 +2536,7 @@ static CURLcode sectransp_connect_step2(struct Curl_cfilter *cf,
|| ssl_connect_2_reading == connssl->connecting_state
|| ssl_connect_2_writing == connssl->connecting_state);
DEBUGASSERT(backend);
- DEBUGF(LOG_CF(data, cf, "connect_step2"));
+ CURL_TRC_CF(data, cf, "connect_step2");
/* Here goes nothing: */
check_handshake:
@@ -3000,7 +3003,7 @@ static CURLcode sectransp_connect_step3(struct Curl_cfilter *cf,
struct ssl_connect_data *connssl = cf->ctx;
CURLcode result;
- DEBUGF(LOG_CF(data, cf, "connect_step3"));
+ CURL_TRC_CF(data, cf, "connect_step3");
/* There is no step 3!
* Well, okay, let's collect server certificates, and if verbose mode is on,
* let's print the details of the server certificates. */
@@ -3109,7 +3112,7 @@ sectransp_connect_common(struct Curl_cfilter *cf, struct Curl_easy *data,
}
if(ssl_connect_done == connssl->connecting_state) {
- DEBUGF(LOG_CF(data, cf, "connected"));
+ CURL_TRC_CF(data, cf, "connected");
connssl->state = ssl_connection_complete;
*done = TRUE;
}
@@ -3156,7 +3159,7 @@ static void sectransp_close(struct Curl_cfilter *cf, struct Curl_easy *data)
DEBUGASSERT(backend);
if(backend->ssl_ctx) {
- DEBUGF(LOG_CF(data, cf, "close"));
+ CURL_TRC_CF(data, cf, "close");
(void)SSLClose(backend->ssl_ctx);
#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
if(SSLCreateContext)
@@ -3202,7 +3205,7 @@ static int sectransp_shutdown(struct Curl_cfilter *cf,
what = SOCKET_READABLE(Curl_conn_cf_get_socket(cf, data),
SSL_SHUTDOWN_TIMEOUT);
- DEBUGF(LOG_CF(data, cf, "shutdown"));
+ CURL_TRC_CF(data, cf, "shutdown");
while(loop--) {
if(what < 0) {
/* anything that gets here is fatally bad */
@@ -3264,7 +3267,7 @@ static bool sectransp_data_pending(struct Curl_cfilter *cf,
DEBUGASSERT(backend);
if(backend->ssl_ctx) { /* SSL is in use */
- DEBUGF(LOG_CF((struct Curl_easy *)data, cf, "data_pending"));
+ CURL_TRC_CF((struct Curl_easy *)data, cf, "data_pending");
err = SSLGetBufferedReadSize(backend->ssl_ctx, &buffer);
if(err == noErr)
return buffer > 0UL;
@@ -3299,6 +3302,7 @@ static CURLcode sectransp_sha256sum(const unsigned char *tmp, /* input */
unsigned char *sha256sum, /* output */
size_t sha256len)
{
+ (void)sha256len;
assert(sha256len >= CURL_SHA256_DIGEST_LENGTH);
(void)CC_SHA256(tmp, (CC_LONG)tmplen, sha256sum);
return CURLE_OK;
diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c
index 510bcfe..38a20e8 100644
--- a/lib/vtls/vtls.c
+++ b/lib/vtls/vtls.c
@@ -417,7 +417,7 @@ bool Curl_ssl_getsessionid(struct Curl_cfilter *cf,
DEBUGASSERT(ssl_config->primary.sessionid);
if(!ssl_config->primary.sessionid || !data->state.session)
- /* session ID re-use is disabled or the session cache has not been
+ /* session ID reuse is disabled or the session cache has not been
setup */
return TRUE;
@@ -635,19 +635,16 @@ int Curl_ssl_get_select_socks(struct Curl_cfilter *cf, struct Curl_easy *data,
struct ssl_connect_data *connssl = cf->ctx;
curl_socket_t sock = Curl_conn_cf_get_socket(cf->next, data);
- if(sock != CURL_SOCKET_BAD) {
- if(connssl->connecting_state == ssl_connect_2_writing) {
- /* write mode */
- socks[0] = sock;
- return GETSOCK_WRITESOCK(0);
- }
- if(connssl->connecting_state == ssl_connect_2_reading) {
- /* read mode */
- socks[0] = sock;
- return GETSOCK_READSOCK(0);
- }
+ if(sock == CURL_SOCKET_BAD)
+ return GETSOCK_BLANK;
+
+ if(connssl->connecting_state == ssl_connect_2_writing) {
+ /* we are only interested in writing */
+ socks[0] = sock;
+ return GETSOCK_WRITESOCK(0);
}
- return GETSOCK_BLANK;
+ socks[0] = sock;
+ return GETSOCK_READSOCK(0);
}
/* Selects an SSL crypto engine
@@ -883,6 +880,9 @@ CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data,
FILE *fp;
unsigned char *buf = NULL, *pem_ptr = NULL;
CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
+#ifdef CURL_DISABLE_VERBOSE_STRINGS
+ (void)data;
+#endif
/* if a path wasn't specified, don't pin */
if(!pinnedpubkey)
@@ -1240,12 +1240,8 @@ const struct Curl_ssl *Curl_ssl =
&Curl_ssl_sectransp;
#elif defined(USE_GNUTLS)
&Curl_ssl_gnutls;
-#elif defined(USE_GSKIT)
- &Curl_ssl_gskit;
#elif defined(USE_MBEDTLS)
&Curl_ssl_mbedtls;
-#elif defined(USE_NSS)
- &Curl_ssl_nss;
#elif defined(USE_RUSTLS)
&Curl_ssl_rustls;
#elif defined(USE_OPENSSL)
@@ -1268,15 +1264,9 @@ static const struct Curl_ssl *available_backends[] = {
#if defined(USE_GNUTLS)
&Curl_ssl_gnutls,
#endif
-#if defined(USE_GSKIT)
- &Curl_ssl_gskit,
-#endif
#if defined(USE_MBEDTLS)
&Curl_ssl_mbedtls,
#endif
-#if defined(USE_NSS)
- &Curl_ssl_nss,
-#endif
#if defined(USE_OPENSSL)
&Curl_ssl_openssl,
#endif
@@ -1522,6 +1512,7 @@ static CURLcode ssl_cf_connect(struct Curl_cfilter *cf,
}
CF_DATA_SAVE(save, cf, data);
+ CURL_TRC_CF(data, cf, "cf_connect()");
(void)connssl;
DEBUGASSERT(data->conn);
DEBUGASSERT(data->conn == cf->conn);
@@ -1551,6 +1542,7 @@ static CURLcode ssl_cf_connect(struct Curl_cfilter *cf,
DEBUGASSERT(connssl->state == ssl_connection_complete);
}
out:
+ CURL_TRC_CF(data, cf, "cf_connect() -> %d, done=%d", result, *done);
CF_DATA_RESTORE(cf, save);
return result;
}
@@ -1601,7 +1593,7 @@ static ssize_t ssl_cf_recv(struct Curl_cfilter *cf,
/* eof */
*err = CURLE_OK;
}
- DEBUGF(LOG_CF(data, cf, "cf_recv(len=%zu) -> %zd, %d", len, nread, *err));
+ CURL_TRC_CF(data, cf, "cf_recv(len=%zu) -> %zd, %d", len, nread, *err);
CF_DATA_RESTORE(cf, save);
return nread;
}
@@ -1611,12 +1603,17 @@ static int ssl_cf_get_select_socks(struct Curl_cfilter *cf,
curl_socket_t *socks)
{
struct cf_call_data save;
- int result;
+ int fds = GETSOCK_BLANK;
- CF_DATA_SAVE(save, cf, data);
- result = Curl_ssl->get_select_socks(cf, data, socks);
- CF_DATA_RESTORE(cf, save);
- return result;
+ if(!cf->next->connected) {
+ fds = cf->next->cft->get_select_socks(cf->next, data, socks);
+ }
+ else if(!cf->connected) {
+ CF_DATA_SAVE(save, cf, data);
+ fds = Curl_ssl->get_select_socks(cf, data, socks);
+ CF_DATA_RESTORE(cf, save);
+ }
+ return fds;
}
static CURLcode ssl_cf_cntrl(struct Curl_cfilter *cf,
@@ -1702,7 +1699,7 @@ static bool cf_ssl_is_alive(struct Curl_cfilter *cf, struct Curl_easy *data,
struct Curl_cftype Curl_cft_ssl = {
"SSL",
CF_TYPE_SSL,
- CURL_LOG_DEFAULT,
+ CURL_LOG_LVL_NONE,
ssl_cf_destroy,
ssl_cf_connect,
ssl_cf_close,
@@ -1720,7 +1717,7 @@ struct Curl_cftype Curl_cft_ssl = {
struct Curl_cftype Curl_cft_ssl_proxy = {
"SSL-PROXY",
CF_TYPE_SSL,
- CURL_LOG_DEFAULT,
+ CURL_LOG_LVL_NONE,
ssl_cf_destroy,
ssl_cf_connect,
ssl_cf_close,
diff --git a/lib/vtls/vtls.h b/lib/vtls/vtls.h
index 3516247..8ad1cf6 100644
--- a/lib/vtls/vtls.h
+++ b/lib/vtls/vtls.h
@@ -43,7 +43,7 @@ struct Curl_ssl_session;
#define VTLS_INFOF_NO_ALPN \
"ALPN: server did not agree on a protocol. Uses default."
#define VTLS_INFOF_ALPN_OFFER_1STR \
- "ALPN: offers %s"
+ "ALPN: curl offers %s"
#define VTLS_INFOF_ALPN_ACCEPTED_1STR \
ALPN_ACCEPTED "%s"
#define VTLS_INFOF_ALPN_ACCEPTED_LEN_1STR \
diff --git a/lib/vtls/vtls_int.h b/lib/vtls/vtls_int.h
index fe0115c..a6e4544 100644
--- a/lib/vtls/vtls_int.h
+++ b/lib/vtls/vtls_int.h
@@ -217,8 +217,6 @@ CURLcode Curl_ssl_addsessionid(struct Curl_cfilter *cf,
#include "openssl.h" /* OpenSSL versions */
#include "gtls.h" /* GnuTLS versions */
-#include "nssg.h" /* NSS versions */
-#include "gskit.h" /* Global Secure ToolKit versions */
#include "wolfssl.h" /* wolfSSL versions */
#include "schannel.h" /* Schannel SSPI version */
#include "sectransp.h" /* SecureTransport (Darwin) version */
diff --git a/lib/vtls/wolfssl.c b/lib/vtls/wolfssl.c
index 6cfc201..5f15720 100644
--- a/lib/vtls/wolfssl.c
+++ b/lib/vtls/wolfssl.c
@@ -92,9 +92,9 @@
#endif
struct wolfssl_ssl_backend_data {
- SSL_CTX* ctx;
- SSL* handle;
- CURLcode io_result; /* result of last BIO cfilter operation */
+ WOLFSSL_CTX *ctx;
+ WOLFSSL *handle;
+ CURLcode io_result; /* result of last BIO cfilter operation */
};
#ifdef OPENSSL_EXTRA
@@ -180,7 +180,8 @@ wolfssl_log_tls12_secret(SSL *ssl)
}
#endif
- if(SSL_get_keys(ssl, &ms, &msLen, &sr, &srLen, &cr, &crLen) != SSL_SUCCESS) {
+ if(wolfSSL_get_keys(ssl, &ms, &msLen, &sr, &srLen, &cr, &crLen) !=
+ SSL_SUCCESS) {
return;
}
@@ -290,11 +291,11 @@ static int bio_cf_out_write(WOLFSSL_BIO *bio, const char *buf, int blen)
DEBUGASSERT(data);
nwritten = Curl_conn_cf_send(cf->next, data, buf, blen, &result);
backend->io_result = result;
- DEBUGF(LOG_CF(data, cf, "bio_write(len=%d) -> %zd, %d",
- blen, nwritten, result));
+ CURL_TRC_CF(data, cf, "bio_write(len=%d) -> %zd, %d",
+ blen, nwritten, result);
wolfSSL_BIO_clear_retry_flags(bio);
if(nwritten < 0 && CURLE_AGAIN == result)
- BIO_set_retry_read(bio);
+ BIO_set_retry_write(bio);
return (int)nwritten;
}
@@ -315,8 +316,7 @@ static int bio_cf_in_read(WOLFSSL_BIO *bio, char *buf, int blen)
nread = Curl_conn_cf_recv(cf->next, data, buf, blen, &result);
backend->io_result = result;
- DEBUGF(LOG_CF(data, cf, "bio_read(len=%d) -> %zd, %d",
- blen, nread, result));
+ CURL_TRC_CF(data, cf, "bio_read(len=%d) -> %zd, %d", blen, nread, result);
wolfSSL_BIO_clear_retry_flags(bio);
if(nread < 0 && CURLE_AGAIN == result)
BIO_set_retry_read(bio);
@@ -327,17 +327,17 @@ static WOLFSSL_BIO_METHOD *bio_cf_method = NULL;
static void bio_cf_init_methods(void)
{
- bio_cf_method = wolfSSL_BIO_meth_new(BIO_TYPE_MEM, "wolfSSL CF BIO");
- wolfSSL_BIO_meth_set_write(bio_cf_method, &bio_cf_out_write);
- wolfSSL_BIO_meth_set_read(bio_cf_method, &bio_cf_in_read);
- wolfSSL_BIO_meth_set_ctrl(bio_cf_method, &bio_cf_ctrl);
- wolfSSL_BIO_meth_set_create(bio_cf_method, &bio_cf_create);
- wolfSSL_BIO_meth_set_destroy(bio_cf_method, &bio_cf_destroy);
+ bio_cf_method = wolfSSL_BIO_meth_new(BIO_TYPE_MEM, "wolfSSL CF BIO");
+ wolfSSL_BIO_meth_set_write(bio_cf_method, &bio_cf_out_write);
+ wolfSSL_BIO_meth_set_read(bio_cf_method, &bio_cf_in_read);
+ wolfSSL_BIO_meth_set_ctrl(bio_cf_method, &bio_cf_ctrl);
+ wolfSSL_BIO_meth_set_create(bio_cf_method, &bio_cf_create);
+ wolfSSL_BIO_meth_set_destroy(bio_cf_method, &bio_cf_destroy);
}
static void bio_cf_free_methods(void)
{
- wolfSSL_BIO_meth_free(bio_cf_method);
+ wolfSSL_BIO_meth_free(bio_cf_method);
}
#else /* USE_BIO_CHAIN */
@@ -361,7 +361,7 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
const struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
- SSL_METHOD* req_method = NULL;
+ WOLFSSL_METHOD* req_method = NULL;
#ifdef HAVE_LIBOQS
word16 oqsAlg = 0;
size_t idx = 0;
@@ -372,6 +372,7 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
#else
#define use_sni(x) Curl_nop_stmt
#endif
+ bool imported_native_ca = false;
bool imported_ca_info_blob = false;
DEBUGASSERT(backend);
@@ -445,8 +446,8 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
}
if(backend->ctx)
- SSL_CTX_free(backend->ctx);
- backend->ctx = SSL_CTX_new(req_method);
+ wolfSSL_CTX_free(backend->ctx);
+ backend->ctx = wolfSSL_CTX_new(req_method);
if(!backend->ctx) {
failf(data, "SSL: couldn't create a context");
@@ -507,13 +508,31 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
}
}
+#ifndef NO_FILESYSTEM
+ /* load native CA certificates */
+ if(ssl_config->native_ca_store) {
+ if(wolfSSL_CTX_load_system_CA_certs(backend->ctx) != WOLFSSL_SUCCESS) {
+ infof(data, "error importing native CA store, continuing anyway");
+ }
+ else {
+ imported_native_ca = true;
+ infof(data, "successfully imported native CA store");
+ }
+ }
+#endif /* !NO_FILESYSTEM */
+
+ /* load certificate blob */
if(ca_info_blob) {
- if(wolfSSL_CTX_load_verify_buffer(
- backend->ctx, ca_info_blob->data, ca_info_blob->len,
- SSL_FILETYPE_PEM
- ) != SSL_SUCCESS) {
- failf(data, "error importing CA certificate blob");
- return CURLE_SSL_CACERT_BADFILE;
+ if(wolfSSL_CTX_load_verify_buffer(backend->ctx, ca_info_blob->data,
+ ca_info_blob->len,
+ SSL_FILETYPE_PEM) != SSL_SUCCESS) {
+ if(imported_native_ca) {
+ infof(data, "error importing CA certificate blob, continuing anyway");
+ }
+ else {
+ failf(data, "error importing CA certificate blob");
+ return CURLE_SSL_CACERT_BADFILE;
+ }
}
else {
imported_ca_info_blob = true;
@@ -524,10 +543,11 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
#ifndef NO_FILESYSTEM
/* load trusted cacert */
if(conn_config->CAfile) {
- if(1 != SSL_CTX_load_verify_locations(backend->ctx,
- conn_config->CAfile,
- conn_config->CApath)) {
- if(conn_config->verifypeer && !imported_ca_info_blob) {
+ if(1 != wolfSSL_CTX_load_verify_locations(backend->ctx,
+ conn_config->CAfile,
+ conn_config->CApath)) {
+ if(conn_config->verifypeer && !imported_ca_info_blob &&
+ !imported_native_ca) {
/* Fail if we insist on successfully verifying the server. */
failf(data, "error setting certificate verify locations:"
" CAfile: %s CApath: %s",
@@ -558,17 +578,17 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
if(ssl_config->primary.clientcert && ssl_config->key) {
int file_type = do_file_type(ssl_config->cert_type);
- if(SSL_CTX_use_certificate_file(backend->ctx,
- ssl_config->primary.clientcert,
- file_type) != 1) {
+ if(wolfSSL_CTX_use_certificate_file(backend->ctx,
+ ssl_config->primary.clientcert,
+ file_type) != 1) {
failf(data, "unable to use client certificate (no key or wrong pass"
" phrase?)");
return CURLE_SSL_CONNECT_ERROR;
}
file_type = do_file_type(ssl_config->key_type);
- if(SSL_CTX_use_PrivateKey_file(backend->ctx, ssl_config->key,
- file_type) != 1) {
+ if(wolfSSL_CTX_use_PrivateKey_file(backend->ctx, ssl_config->key,
+ file_type) != 1) {
failf(data, "unable to set private key");
return CURLE_SSL_CONNECT_ERROR;
}
@@ -579,10 +599,9 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
* fail to connect if the verification fails, or if it should continue
* anyway. In the latter case the result of the verification is checked with
* SSL_get_verify_result() below. */
- SSL_CTX_set_verify(backend->ctx,
- conn_config->verifypeer?SSL_VERIFY_PEER:
- SSL_VERIFY_NONE,
- NULL);
+ wolfSSL_CTX_set_verify(backend->ctx,
+ conn_config->verifypeer?SSL_VERIFY_PEER:
+ SSL_VERIFY_NONE, NULL);
#ifdef HAVE_SNI
if(sni) {
@@ -631,8 +650,8 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
/* Let's make an SSL structure */
if(backend->handle)
- SSL_free(backend->handle);
- backend->handle = SSL_new(backend->ctx);
+ wolfSSL_free(backend->handle);
+ backend->handle = wolfSSL_new(backend->ctx);
if(!backend->handle) {
failf(data, "SSL: couldn't create a handle");
return CURLE_OUT_OF_MEMORY;
@@ -692,7 +711,7 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
infof(data, "Can't use session ID, going on without");
}
else
- infof(data, "SSL re-using session ID");
+ infof(data, "SSL reusing session ID");
}
Curl_ssl_sessionid_unlock(data);
}
@@ -710,7 +729,8 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
}
#else /* USE_BIO_CHAIN */
/* pass the raw socket into the SSL layer */
- if(!SSL_set_fd(backend->handle, (int)Curl_conn_cf_get_socket(cf, data))) {
+ if(!wolfSSL_set_fd(backend->handle,
+ (int)Curl_conn_cf_get_socket(cf, data))) {
failf(data, "SSL: SSL_set_fd failed");
return CURLE_SSL_CONNECT_ERROR;
}
@@ -735,7 +755,7 @@ wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
DEBUGASSERT(backend);
- ERR_clear_error();
+ wolfSSL_ERR_clear_error();
/* Enable RFC2818 checks */
if(conn_config->verifyhost) {
@@ -745,7 +765,7 @@ wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
return CURLE_SSL_CONNECT_ERROR;
}
- ret = SSL_connect(backend->handle);
+ ret = wolfSSL_connect(backend->handle);
#ifdef OPENSSL_EXTRA
if(Curl_tls_keylog_enabled()) {
@@ -773,7 +793,7 @@ wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
if(ret != 1) {
char error_buffer[WOLFSSL_MAX_ERROR_SZ];
- int detail = SSL_get_error(backend->handle, ret);
+ int detail = wolfSSL_get_error(backend->handle, ret);
if(SSL_ERROR_WANT_READ == detail) {
connssl->connecting_state = ssl_connect_2_reading;
@@ -831,7 +851,7 @@ wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
}
else {
failf(data, "SSL_connect failed with error %d: %s", detail,
- ERR_error_string(detail, error_buffer));
+ wolfSSL_ERR_error_string(detail, error_buffer));
return CURLE_SSL_CONNECT_ERROR;
}
}
@@ -845,7 +865,7 @@ wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
struct Curl_asn1Element *pubkey;
CURLcode result;
- x509 = SSL_get_peer_certificate(backend->handle);
+ x509 = wolfSSL_get_peer_certificate(backend->handle);
if(!x509) {
failf(data, "SSL: failed retrieving server certificate");
return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
@@ -931,8 +951,8 @@ wolfssl_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
bool incache;
bool added = FALSE;
void *old_ssl_sessionid = NULL;
- /* SSL_get1_session allocates memory that has to be freed. */
- SSL_SESSION *our_ssl_sessionid = SSL_get1_session(backend->handle);
+ /* wolfSSL_get1_session allocates memory that has to be freed. */
+ WOLFSSL_SESSION *our_ssl_sessionid = wolfSSL_get1_session(backend->handle);
if(our_ssl_sessionid) {
Curl_ssl_sessionid_lock(data);
@@ -949,7 +969,7 @@ wolfssl_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
result = Curl_ssl_addsessionid(cf, data, our_ssl_sessionid, 0, NULL);
if(result) {
Curl_ssl_sessionid_unlock(data);
- SSL_SESSION_free(our_ssl_sessionid);
+ wolfSSL_SESSION_free(our_ssl_sessionid);
failf(data, "failed to store ssl session");
return result;
}
@@ -961,7 +981,7 @@ wolfssl_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
if(!added) {
/* If the session info wasn't added to the cache, free our copy. */
- SSL_SESSION_free(our_ssl_sessionid);
+ wolfSSL_SESSION_free(our_ssl_sessionid);
}
}
}
@@ -987,35 +1007,34 @@ static ssize_t wolfssl_send(struct Curl_cfilter *cf,
DEBUGASSERT(backend);
- ERR_clear_error();
+ wolfSSL_ERR_clear_error();
- rc = SSL_write(backend->handle, mem, memlen);
+ rc = wolfSSL_write(backend->handle, mem, memlen);
if(rc <= 0) {
- int err = SSL_get_error(backend->handle, rc);
+ int err = wolfSSL_get_error(backend->handle, rc);
switch(err) {
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
/* there's data pending, re-invoke SSL_write() */
- DEBUGF(LOG_CF(data, cf, "wolfssl_send(len=%zu) -> AGAIN", len));
+ CURL_TRC_CF(data, cf, "wolfssl_send(len=%zu) -> AGAIN", len);
*curlcode = CURLE_AGAIN;
return -1;
default:
if(backend->io_result == CURLE_AGAIN) {
- DEBUGF(LOG_CF(data, cf, "wolfssl_send(len=%zu) -> AGAIN", len));
+ CURL_TRC_CF(data, cf, "wolfssl_send(len=%zu) -> AGAIN", len);
*curlcode = CURLE_AGAIN;
return -1;
}
- DEBUGF(LOG_CF(data, cf, "wolfssl_send(len=%zu) -> %d, %d",
- len, rc, err));
+ CURL_TRC_CF(data, cf, "wolfssl_send(len=%zu) -> %d, %d", len, rc, err);
failf(data, "SSL write: %s, errno %d",
- ERR_error_string(err, error_buffer),
+ wolfSSL_ERR_error_string(err, error_buffer),
SOCKERRNO);
*curlcode = CURLE_SEND_ERROR;
return -1;
}
}
- DEBUGF(LOG_CF(data, cf, "wolfssl_send(len=%zu) -> %d", len, rc));
+ CURL_TRC_CF(data, cf, "wolfssl_send(len=%zu) -> %d", len, rc);
return rc;
}
@@ -1033,13 +1052,13 @@ static void wolfssl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
char buf[32];
/* Maybe the server has already sent a close notify alert.
Read it to avoid an RST on the TCP connection. */
- (void)SSL_read(backend->handle, buf, (int)sizeof(buf));
- (void)SSL_shutdown(backend->handle);
- SSL_free(backend->handle);
+ (void)wolfSSL_read(backend->handle, buf, (int)sizeof(buf));
+ (void)wolfSSL_shutdown(backend->handle);
+ wolfSSL_free(backend->handle);
backend->handle = NULL;
}
if(backend->ctx) {
- SSL_CTX_free(backend->ctx);
+ wolfSSL_CTX_free(backend->ctx);
backend->ctx = NULL;
}
}
@@ -1058,17 +1077,17 @@ static ssize_t wolfssl_recv(struct Curl_cfilter *cf,
DEBUGASSERT(backend);
- ERR_clear_error();
+ wolfSSL_ERR_clear_error();
*curlcode = CURLE_OK;
- nread = SSL_read(backend->handle, buf, buffsize);
+ nread = wolfSSL_read(backend->handle, buf, buffsize);
if(nread <= 0) {
- int err = SSL_get_error(backend->handle, nread);
+ int err = wolfSSL_get_error(backend->handle, nread);
switch(err) {
case SSL_ERROR_ZERO_RETURN: /* no more data */
- DEBUGF(LOG_CF(data, cf, "wolfssl_recv(len=%zu) -> CLOSED", blen));
+ CURL_TRC_CF(data, cf, "wolfssl_recv(len=%zu) -> CLOSED", blen);
*curlcode = CURLE_OK;
return 0;
case SSL_ERROR_NONE:
@@ -1076,30 +1095,30 @@ static ssize_t wolfssl_recv(struct Curl_cfilter *cf,
case SSL_ERROR_WANT_READ:
/* FALLTHROUGH */
case SSL_ERROR_WANT_WRITE:
- /* there's data pending, re-invoke SSL_read() */
- DEBUGF(LOG_CF(data, cf, "wolfssl_recv(len=%zu) -> AGAIN", blen));
+ /* there's data pending, re-invoke wolfSSL_read() */
+ CURL_TRC_CF(data, cf, "wolfssl_recv(len=%zu) -> AGAIN", blen);
*curlcode = CURLE_AGAIN;
return -1;
default:
if(backend->io_result == CURLE_AGAIN) {
- DEBUGF(LOG_CF(data, cf, "wolfssl_recv(len=%zu) -> AGAIN", blen));
+ CURL_TRC_CF(data, cf, "wolfssl_recv(len=%zu) -> AGAIN", blen);
*curlcode = CURLE_AGAIN;
return -1;
}
failf(data, "SSL read: %s, errno %d",
- ERR_error_string(err, error_buffer), SOCKERRNO);
+ wolfSSL_ERR_error_string(err, error_buffer), SOCKERRNO);
*curlcode = CURLE_RECV_ERROR;
return -1;
}
}
- DEBUGF(LOG_CF(data, cf, "wolfssl_recv(len=%zu) -> %d", blen, nread));
+ CURL_TRC_CF(data, cf, "wolfssl_recv(len=%zu) -> %d", blen, nread);
return nread;
}
static void wolfssl_session_free(void *ptr)
{
- SSL_SESSION_free(ptr);
+ wolfSSL_SESSION_free(ptr);
}
@@ -1147,7 +1166,7 @@ static bool wolfssl_data_pending(struct Curl_cfilter *cf,
backend = (struct wolfssl_ssl_backend_data *)ctx->backend;
if(backend->handle) /* SSL is in use */
- return (0 != SSL_pending(backend->handle)) ? TRUE : FALSE;
+ return (0 != wolfSSL_pending(backend->handle)) ? TRUE : FALSE;
else
return FALSE;
}
@@ -1169,8 +1188,8 @@ static int wolfssl_shutdown(struct Curl_cfilter *cf,
backend = (struct wolfssl_ssl_backend_data *)ctx->backend;
if(backend->handle) {
- ERR_clear_error();
- SSL_free(backend->handle);
+ wolfSSL_ERR_clear_error();
+ wolfSSL_free(backend->handle);
backend->handle = NULL;
}
return retval;
@@ -1333,7 +1352,8 @@ static CURLcode wolfssl_sha256sum(const unsigned char *tmp, /* input */
{
wc_Sha256 SHA256pw;
(void)unused;
- wc_InitSha256(&SHA256pw);
+ if(wc_InitSha256(&SHA256pw))
+ return CURLE_FAILED_INIT;
wc_Sha256Update(&SHA256pw, tmp, (word32)tmplen);
wc_Sha256Final(&SHA256pw, sha256sum);
return CURLE_OK;
diff --git a/lib/vtls/x509asn1.c b/lib/vtls/x509asn1.c
index acf8bdb..c3fd3a3 100644
--- a/lib/vtls/x509asn1.c
+++ b/lib/vtls/x509asn1.c
@@ -24,24 +24,18 @@
#include "curl_setup.h"
-#if defined(USE_GSKIT) || defined(USE_NSS) || defined(USE_GNUTLS) || \
- defined(USE_WOLFSSL) || defined(USE_SCHANNEL) || defined(USE_SECTRANSP)
+#if defined(USE_GNUTLS) || defined(USE_WOLFSSL) || \
+ defined(USE_SCHANNEL) || defined(USE_SECTRANSP)
-#if defined(USE_GSKIT) || defined(USE_WOLFSSL) || defined(USE_SCHANNEL)
+#if defined(USE_WOLFSSL) || defined(USE_SCHANNEL)
#define WANT_PARSEX509 /* uses Curl_parseX509() */
#endif
-#if defined(USE_GSKIT) || defined(USE_NSS) || defined(USE_GNUTLS) || \
- defined(USE_SCHANNEL) || defined(USE_SECTRANSP)
+#if defined(USE_GNUTLS) || defined(USE_SCHANNEL) || defined(USE_SECTRANSP)
#define WANT_EXTRACT_CERTINFO /* uses Curl_extract_certinfo() */
#define WANT_PARSEX509 /* ... uses Curl_parseX509() */
#endif
-#if defined(USE_GSKIT)
-#define WANT_VERIFYHOST /* uses Curl_verifyhost () */
-#define WANT_PARSEX509 /* ... uses Curl_parseX509() */
-#endif
-
#include <curl/curl.h>
#include "urldata.h"
#include "strcase.h"
@@ -973,7 +967,7 @@ static int do_pubkey(struct Curl_easy *data, int certnum,
infof(data, " ECC Public Key (%lu bits)", len);
if(data->set.ssl.certinfo) {
char q[sizeof(len) * 8 / 3 + 1];
- (void)msnprintf(q, sizeof(q), "%lu", len);
+ (void)msnprintf(q, sizeof(q), "%zu", len);
if(ssl_push_certinfo(data, certnum, "ECC Public Key", q))
return 1;
}
@@ -1007,7 +1001,7 @@ static int do_pubkey(struct Curl_easy *data, int certnum,
infof(data, " RSA Public Key (%lu bits)", len);
if(data->set.ssl.certinfo) {
char r[sizeof(len) * 8 / 3 + 1];
- msnprintf(r, sizeof(r), "%lu", len);
+ msnprintf(r, sizeof(r), "%zu", len);
if(ssl_push_certinfo(data, certnum, "RSA Public Key", r))
return 1;
}
@@ -1261,8 +1255,7 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data,
#endif /* WANT_EXTRACT_CERTINFO */
-#endif /* USE_GSKIT or USE_NSS or USE_GNUTLS or USE_WOLFSSL or USE_SCHANNEL
- * or USE_SECTRANSP */
+#endif /* USE_GNUTLS or USE_WOLFSSL or USE_SCHANNEL or USE_SECTRANSP */
#ifdef WANT_VERIFYHOST
diff --git a/lib/vtls/x509asn1.h b/lib/vtls/x509asn1.h
index 5496de4..23a67b8 100644
--- a/lib/vtls/x509asn1.h
+++ b/lib/vtls/x509asn1.h
@@ -27,8 +27,8 @@
#include "curl_setup.h"
-#if defined(USE_GSKIT) || defined(USE_NSS) || defined(USE_GNUTLS) || \
- defined(USE_WOLFSSL) || defined(USE_SCHANNEL) || defined(USE_SECTRANSP)
+#if defined(USE_GNUTLS) || defined(USE_WOLFSSL) || \
+ defined(USE_SCHANNEL) || defined(USE_SECTRANSP)
#include "cfilters.h"
#include "urldata.h"
@@ -76,6 +76,5 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data, int certnum,
const char *beg, const char *end);
CURLcode Curl_verifyhost(struct Curl_cfilter *cf, struct Curl_easy *data,
const char *beg, const char *end);
-#endif /* USE_GSKIT or USE_NSS or USE_GNUTLS or USE_WOLFSSL or USE_SCHANNEL
- * or USE_SECTRANSP */
+#endif /* USE_GNUTLS or USE_WOLFSSL or USE_SCHANNEL or USE_SECTRANSP */
#endif /* HEADER_CURL_X509ASN1_H */