diff options
author | dartraiden <wowemuh@gmail.com> | 2024-11-06 20:55:13 +0300 |
---|---|---|
committer | dartraiden <wowemuh@gmail.com> | 2024-11-06 21:41:16 +0300 |
commit | 5d2ecfef56e49a8e4bfad25a582ff1597987f717 (patch) | |
tree | cdb31e45b051830ecf50c74a84b8d2ac5aa6cfd9 /libs/libcurl/src/vtls | |
parent | 995e85e9e63553576fc285d937d4abbad369e7e4 (diff) |
libcurl: update to 8.11.0
Diffstat (limited to 'libs/libcurl/src/vtls')
-rw-r--r-- | libs/libcurl/src/vtls/bearssl.c | 55 | ||||
-rw-r--r-- | libs/libcurl/src/vtls/cipher_suite.c | 4 | ||||
-rw-r--r-- | libs/libcurl/src/vtls/gtls.c | 522 | ||||
-rw-r--r-- | libs/libcurl/src/vtls/gtls.h | 9 | ||||
-rw-r--r-- | libs/libcurl/src/vtls/keylog.c | 12 | ||||
-rw-r--r-- | libs/libcurl/src/vtls/mbedtls.c | 222 | ||||
-rw-r--r-- | libs/libcurl/src/vtls/openssl.c | 247 | ||||
-rw-r--r-- | libs/libcurl/src/vtls/rustls.c | 30 | ||||
-rw-r--r-- | libs/libcurl/src/vtls/schannel.c | 201 | ||||
-rw-r--r-- | libs/libcurl/src/vtls/schannel_int.h | 13 | ||||
-rw-r--r-- | libs/libcurl/src/vtls/schannel_verify.c | 314 | ||||
-rw-r--r-- | libs/libcurl/src/vtls/sectransp.c | 64 | ||||
-rw-r--r-- | libs/libcurl/src/vtls/vtls.c | 242 | ||||
-rw-r--r-- | libs/libcurl/src/vtls/vtls.h | 13 | ||||
-rw-r--r-- | libs/libcurl/src/vtls/vtls_int.h | 47 | ||||
-rw-r--r-- | libs/libcurl/src/vtls/wolfssl.c | 469 | ||||
-rw-r--r-- | libs/libcurl/src/vtls/wolfssl.h | 22 | ||||
-rw-r--r-- | libs/libcurl/src/vtls/x509asn1.c | 6 |
18 files changed, 1552 insertions, 940 deletions
diff --git a/libs/libcurl/src/vtls/bearssl.c b/libs/libcurl/src/vtls/bearssl.c index f262639540..f4d0cc43b3 100644 --- a/libs/libcurl/src/vtls/bearssl.c +++ b/libs/libcurl/src/vtls/bearssl.c @@ -609,11 +609,15 @@ static CURLcode bearssl_connect_step1(struct Curl_cfilter *cf, br_ssl_engine_set_x509(&backend->ctx.eng, &backend->x509.vtable);
if(ssl_config->primary.cache_session) {
- void *session;
+ void *sdata;
+ size_t slen;
+ const br_ssl_session_parameters *session;
CURL_TRC_CF(data, cf, "connect_step1, check session cache");
Curl_ssl_sessionid_lock(data);
- if(!Curl_ssl_getsessionid(cf, data, &connssl->peer, &session, NULL)) {
+ if(!Curl_ssl_getsessionid(cf, data, &connssl->peer, &sdata, &slen, NULL) &&
+ slen == sizeof(*session)) {
+ session = sdata;
br_ssl_engine_set_session_parameters(&backend->ctx.eng, session);
session_set = 1;
infof(data, "BearSSL: reusing session ID");
@@ -653,10 +657,10 @@ static CURLcode bearssl_connect_step1(struct Curl_cfilter *cf, /* give application a chance to interfere with SSL set up. */
if(data->set.ssl.fsslctx) {
- Curl_set_in_callback(data, true);
+ Curl_set_in_callback(data, TRUE);
ret = (*data->set.ssl.fsslctx)(data, &backend->ctx,
data->set.ssl.fsslctxp);
- Curl_set_in_callback(data, false);
+ Curl_set_in_callback(data, FALSE);
if(ret) {
failf(data, "BearSSL: error signaled by ssl ctx callback");
return ret;
@@ -761,7 +765,6 @@ static CURLcode bearssl_connect_step2(struct Curl_cfilter *cf, (struct bearssl_ssl_backend_data *)connssl->backend;
br_ssl_session_parameters session;
char cipher_str[64];
- char ver_str[16];
CURLcode ret;
DEBUGASSERT(backend);
@@ -772,6 +775,7 @@ static CURLcode bearssl_connect_step2(struct Curl_cfilter *cf, return CURLE_OK;
if(ret == CURLE_OK) {
unsigned int tver;
+ int subver = 0;
if(br_ssl_engine_current_state(&backend->ctx.eng) == BR_SSL_CLOSED) {
failf(data, "SSL: connection closed during handshake");
@@ -780,19 +784,22 @@ static CURLcode bearssl_connect_step2(struct Curl_cfilter *cf, connssl->connecting_state = ssl_connect_3;
/* Informational message */
tver = br_ssl_engine_get_version(&backend->ctx.eng);
- if(tver == BR_TLS12)
- strcpy(ver_str, "TLSv1.2");
- else if(tver == BR_TLS11)
- strcpy(ver_str, "TLSv1.1");
- else if(tver == BR_TLS10)
- strcpy(ver_str, "TLSv1.0");
- else {
- msnprintf(ver_str, sizeof(ver_str), "TLS 0x%04x", tver);
+ switch(tver) {
+ case BR_TLS12:
+ subver = 2; /* 1.2 */
+ break;
+ case BR_TLS11:
+ subver = 1; /* 1.1 */
+ break;
+ case BR_TLS10: /* 1.0 */
+ default: /* unknown, leave it at zero */
+ break;
}
br_ssl_engine_get_session_parameters(&backend->ctx.eng, &session);
Curl_cipher_suite_get_str(session.cipher_suite, cipher_str,
- sizeof(cipher_str), true);
- infof(data, "BearSSL: %s connection using %s", ver_str, cipher_str);
+ sizeof(cipher_str), TRUE);
+ infof(data, "BearSSL: TLS v1.%d connection using %s", subver,
+ cipher_str);
}
return ret;
}
@@ -820,8 +827,8 @@ static CURLcode bearssl_connect_step3(struct Curl_cfilter *cf, const char *proto;
proto = br_ssl_engine_get_selected_protocol(&backend->ctx.eng);
- Curl_alpn_set_negotiated(cf, data, (const unsigned char *)proto,
- proto? strlen(proto) : 0);
+ Curl_alpn_set_negotiated(cf, data, connssl, (const unsigned char *)proto,
+ proto ? strlen(proto) : 0);
}
if(ssl_config->primary.cache_session) {
@@ -832,7 +839,8 @@ static CURLcode bearssl_connect_step3(struct Curl_cfilter *cf, return CURLE_OUT_OF_MEMORY;
br_ssl_engine_get_session_parameters(&backend->ctx.eng, session);
Curl_ssl_sessionid_lock(data);
- ret = Curl_ssl_set_sessionid(cf, data, &connssl->peer, session, 0,
+ ret = Curl_ssl_set_sessionid(cf, data, &connssl->peer, NULL,
+ session, sizeof(*session),
bearssl_session_free);
Curl_ssl_sessionid_unlock(data);
if(ret)
@@ -941,15 +949,14 @@ static CURLcode bearssl_connect_common(struct Curl_cfilter *cf, /* if ssl is expecting something, check if it is available. */
if(connssl->io_need) {
-
- curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND)?
- sockfd:CURL_SOCKET_BAD;
- curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV)?
- sockfd:CURL_SOCKET_BAD;
+ curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND) ?
+ sockfd : CURL_SOCKET_BAD;
+ curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV) ?
+ 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);
+ nonblocking ? 0 : timeout_ms);
CURL_TRC_CF(data, cf, "connect_common, check socket -> %d", what);
if(what < 0) {
/* fatal error */
diff --git a/libs/libcurl/src/vtls/cipher_suite.c b/libs/libcurl/src/vtls/cipher_suite.c index be5dbf5cbe..ca7c5ba46d 100644 --- a/libs/libcurl/src/vtls/cipher_suite.c +++ b/libs/libcurl/src/vtls/cipher_suite.c @@ -844,10 +844,10 @@ static bool cs_is_separator(char c) case ':':
case ',':
case ';':
- return true;
+ return TRUE;
default:;
}
- return false;
+ return FALSE;
}
uint16_t Curl_cipher_suite_walk_str(const char **str, const char **end)
diff --git a/libs/libcurl/src/vtls/gtls.c b/libs/libcurl/src/vtls/gtls.c index 2d03712801..398af77bf3 100644 --- a/libs/libcurl/src/vtls/gtls.c +++ b/libs/libcurl/src/vtls/gtls.c @@ -50,6 +50,7 @@ #include "vauth/vauth.h"
#include "parsedate.h"
#include "connect.h" /* for the connect timeout */
+#include "progress.h"
#include "select.h"
#include "strcase.h"
#include "warnless.h"
@@ -108,7 +109,7 @@ static ssize_t gtls_push(void *s, const void *buf, size_t blen) backend->gtls.io_result = result;
if(nwritten < 0) {
gnutls_transport_set_errno(backend->gtls.session,
- (CURLE_AGAIN == result)? EAGAIN : EINVAL);
+ (CURLE_AGAIN == result) ? EAGAIN : EINVAL);
nwritten = -1;
}
return nwritten;
@@ -140,7 +141,7 @@ static ssize_t gtls_pull(void *s, void *buf, size_t blen) backend->gtls.io_result = result;
if(nread < 0) {
gnutls_transport_set_errno(backend->gtls.session,
- (CURLE_AGAIN == result)? EAGAIN : EINVAL);
+ (CURLE_AGAIN == result) ? EAGAIN : EINVAL);
nread = -1;
}
else if(nread == 0)
@@ -159,7 +160,7 @@ static int gtls_init(void) {
int ret = 1;
if(!gtls_inited) {
- ret = gnutls_global_init()?0:1;
+ ret = gnutls_global_init() ? 0 : 1;
#ifdef GTLSDEBUG
gnutls_global_set_log_function(tls_log_func);
gnutls_global_set_log_level(2);
@@ -193,7 +194,7 @@ static void showtime(struct Curl_easy *data, sizeof(str),
" %s: %s, %02d %s %4d %02d:%02d:%02d GMT",
text,
- Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
+ Curl_wkday[tm->tm_wday ? tm->tm_wday-1 : 6],
tm->tm_mday,
Curl_month[tm->tm_mon],
tm->tm_year + 1900,
@@ -269,14 +270,14 @@ static CURLcode handshake(struct Curl_cfilter *cf, /* if ssl is expecting something, check if it is available. */
if(connssl->io_need) {
int what;
- curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND)?
- sockfd:CURL_SOCKET_BAD;
- curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV)?
- sockfd:CURL_SOCKET_BAD;
+ curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND) ?
+ sockfd : CURL_SOCKET_BAD;
+ curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV) ?
+ sockfd : CURL_SOCKET_BAD;
what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
- nonblocking?0:
- timeout_ms?timeout_ms:1000);
+ nonblocking ? 0 :
+ timeout_ms ? timeout_ms : 1000);
if(what < 0) {
/* fatal error */
failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
@@ -284,7 +285,7 @@ static CURLcode handshake(struct Curl_cfilter *cf, }
else if(0 == what) {
if(nonblocking)
- return CURLE_OK;
+ return CURLE_AGAIN;
else if(timeout_ms) {
/* timeout */
failf(data, "SSL connection timeout at %ld", (long)timeout_ms);
@@ -308,8 +309,8 @@ static CURLcode handshake(struct Curl_cfilter *cf, if((rc == GNUTLS_E_AGAIN) || (rc == GNUTLS_E_INTERRUPTED)) {
connssl->io_need =
- gnutls_record_get_direction(session)?
- CURL_SSL_IO_NEED_SEND:CURL_SSL_IO_NEED_RECV;
+ gnutls_record_get_direction(session) ?
+ CURL_SSL_IO_NEED_SEND : CURL_SSL_IO_NEED_RECV;
continue;
}
else if((rc < 0) && !gnutls_error_is_fatal(rc)) {
@@ -509,7 +510,7 @@ static CURLcode gtls_populate_creds(struct Curl_cfilter *cf, int rc;
if(config->verifypeer) {
- bool imported_native_ca = false;
+ bool imported_native_ca = FALSE;
if(ssl_config->native_ca_store) {
rc = gnutls_certificate_set_x509_system_trust(creds);
@@ -519,7 +520,7 @@ static CURLcode gtls_populate_creds(struct Curl_cfilter *cf, else {
infof(data, "found %d certificates in native ca store", rc);
if(rc > 0)
- imported_native_ca = true;
+ imported_native_ca = TRUE;
}
}
@@ -590,7 +591,7 @@ static bool gtls_shared_creds_expired(const struct Curl_easy *data, timediff_t timeout_ms = cfg->ca_cache_timeout * (timediff_t)1000;
if(timeout_ms < 0)
- return false;
+ return FALSE;
return elapsed_ms >= timeout_ms;
}
@@ -719,45 +720,57 @@ static void gtls_sessionid_free(void *sessionid, size_t idsize) free(sessionid);
}
-static CURLcode gtls_update_session_id(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- gnutls_session_t session)
+CURLcode Curl_gtls_update_session_id(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ gnutls_session_t session,
+ struct ssl_peer *peer,
+ const char *alpn)
{
struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
- struct ssl_connect_data *connssl = cf->ctx;
+ void *connect_sessionid;
+ size_t connect_idsize = 0;
CURLcode result = CURLE_OK;
- if(ssl_config->primary.cache_session) {
- /* we always unconditionally get the session id here, as even if we
- already got it from the cache and asked to use it in the connection, it
- might've been rejected and then a new one is in use now and we need to
- detect that. */
- void *connect_sessionid;
- size_t connect_idsize = 0;
-
- /* get the session ID data size */
- gnutls_session_get_data(session, NULL, &connect_idsize);
- connect_sessionid = malloc(connect_idsize); /* get a buffer for it */
- if(!connect_sessionid) {
- return CURLE_OUT_OF_MEMORY;
- }
- else {
- /* extract session ID to the allocated buffer */
- gnutls_session_get_data(session, connect_sessionid, &connect_idsize);
-
- CURL_TRC_CF(data, cf, "get session id (len=%zu) and store in cache",
- connect_idsize);
- Curl_ssl_sessionid_lock(data);
- /* store this session id, takes ownership */
- result = Curl_ssl_set_sessionid(cf, data, &connssl->peer,
- connect_sessionid, connect_idsize,
- gtls_sessionid_free);
- Curl_ssl_sessionid_unlock(data);
- }
- }
+ if(!ssl_config->primary.cache_session)
+ return CURLE_OK;
+
+ /* we always unconditionally get the session id here, as even if we
+ already got it from the cache and asked to use it in the connection, it
+ might've been rejected and then a new one is in use now and we need to
+ detect that. */
+
+ /* get the session ID data size */
+ gnutls_session_get_data(session, NULL, &connect_idsize);
+ if(!connect_idsize) /* gnutls does this for some version combinations */
+ return CURLE_OK;
+
+ connect_sessionid = malloc(connect_idsize); /* get a buffer for it */
+ if(!connect_sessionid)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* extract session ID to the allocated buffer */
+ gnutls_session_get_data(session, connect_sessionid, &connect_idsize);
+
+ CURL_TRC_CF(data, cf, "get session id (len=%zu, alpn=%s) and store in cache",
+ connect_idsize, alpn ? alpn : "-");
+ Curl_ssl_sessionid_lock(data);
+ /* store this session id, takes ownership */
+ result = Curl_ssl_set_sessionid(cf, data, peer, alpn,
+ connect_sessionid, connect_idsize,
+ gtls_sessionid_free);
+ Curl_ssl_sessionid_unlock(data);
return result;
}
+static CURLcode cf_gtls_update_session_id(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ gnutls_session_t session)
+{
+ struct ssl_connect_data *connssl = cf->ctx;
+ return Curl_gtls_update_session_id(cf, data, session, &connssl->peer,
+ connssl->alpn_negotiated);
+}
+
static int gtls_handshake_cb(gnutls_session_t session, unsigned int htype,
unsigned when, unsigned int incoming,
const gnutls_datum_t *msg)
@@ -770,10 +783,10 @@ static int gtls_handshake_cb(gnutls_session_t session, unsigned int htype, struct Curl_easy *data = CF_DATA_CURRENT(cf);
if(data) {
CURL_TRC_CF(data, cf, "handshake: %s message type %d",
- incoming? "incoming" : "outgoing", htype);
+ incoming ? "incoming" : "outgoing", htype);
switch(htype) {
case GNUTLS_HANDSHAKE_NEW_SESSION_TICKET: {
- gtls_update_session_id(cf, data, session);
+ cf_gtls_update_session_id(cf, data, session);
break;
}
default:
@@ -845,9 +858,13 @@ static CURLcode gtls_client_init(struct Curl_cfilter *cf, init_flags |= GNUTLS_FORCE_CLIENT_CERT;
#endif
-#if defined(GNUTLS_NO_TICKETS)
- /* Disable TLS session tickets */
- init_flags |= GNUTLS_NO_TICKETS;
+#if defined(GNUTLS_NO_TICKETS_TLS12)
+ init_flags |= GNUTLS_NO_TICKETS_TLS12;
+#elif defined(GNUTLS_NO_TICKETS)
+ /* Disable TLS session tickets for non 1.3 connections */
+ if((config->version != CURL_SSLVERSION_TLSv1_3) &&
+ (config->version != CURL_SSLVERSION_DEFAULT))
+ init_flags |= GNUTLS_NO_TICKETS;
#endif
#if defined(GNUTLS_NO_STATUS_REQUEST)
@@ -936,7 +953,19 @@ static CURLcode gtls_client_init(struct Curl_cfilter *cf, if(result)
return result;
}
- if(ssl_config->key_passwd) {
+ if(ssl_config->cert_type && strcasecompare(ssl_config->cert_type, "P12")) {
+ rc = gnutls_certificate_set_x509_simple_pkcs12_file(
+ gtls->shared_creds->creds, config->clientcert, GNUTLS_X509_FMT_DER,
+ ssl_config->key_passwd ? ssl_config->key_passwd : "");
+ if(rc != GNUTLS_E_SUCCESS) {
+ failf(data,
+ "error reading X.509 potentially-encrypted key or certificate "
+ "file: %s",
+ gnutls_strerror(rc));
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ }
+ else if(ssl_config->key_passwd) {
const unsigned int supported_key_encryption_algorithms =
GNUTLS_PKCS_USE_PKCS12_3DES | GNUTLS_PKCS_USE_PKCS12_ARCFOUR |
GNUTLS_PKCS_USE_PKCS12_RC2_40 | GNUTLS_PKCS_USE_PBES2_3DES |
@@ -1022,11 +1051,15 @@ CURLcode Curl_gtls_ctx_init(struct gtls_ctx *gctx, struct Curl_easy *data,
struct ssl_peer *peer,
const unsigned char *alpn, size_t alpn_len,
+ struct ssl_connect_data *connssl,
Curl_gtls_ctx_setup_cb *cb_setup,
void *cb_user_data,
void *ssl_user_data)
{
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);
+ gnutls_datum_t gtls_alpns[5];
+ size_t gtls_alpns_count = 0;
CURLcode result;
DEBUGASSERT(gctx);
@@ -1049,52 +1082,91 @@ CURLcode Curl_gtls_ctx_init(struct gtls_ctx *gctx, gnutls_session_set_keylog_function(gctx->session, keylog_callback);
}
- /* convert the ALPN string from our arguments to a list of strings
- * that gnutls wants and will convert internally back to this very
- * string for sending to the server. nice. */
- if(alpn && alpn_len) {
- gnutls_datum_t alpns[5];
- size_t i, alen = alpn_len;
- unsigned char *s = (unsigned char *)alpn;
- unsigned char slen;
- for(i = 0; (i < ARRAYSIZE(alpns)) && alen; ++i) {
- slen = s[0];
- if(slen >= alen)
- return CURLE_FAILED_INIT;
- alpns[i].data = s + 1;
- alpns[i].size = slen;
- s += slen + 1;
- alen -= (size_t)slen + 1;
- }
- if(alen) /* not all alpn chars used, wrong format or too many */
- return CURLE_FAILED_INIT;
- if(i && gnutls_alpn_set_protocols(gctx->session,
- alpns, (unsigned int)i,
- GNUTLS_ALPN_MANDATORY)) {
- failf(data, "failed setting ALPN");
- return CURLE_SSL_CONNECT_ERROR;
- }
- }
-
/* This might be a reconnect, so we check for a session ID in the cache
to speed up things */
if(conn_config->cache_session) {
void *ssl_sessionid;
size_t ssl_idsize;
-
+ char *session_alpn;
Curl_ssl_sessionid_lock(data);
- if(!Curl_ssl_getsessionid(cf, data, peer, &ssl_sessionid, &ssl_idsize)) {
+ if(!Curl_ssl_getsessionid(cf, data, peer,
+ &ssl_sessionid, &ssl_idsize, &session_alpn)) {
/* we got a session id, use it! */
int rc;
rc = gnutls_session_set_data(gctx->session, ssl_sessionid, ssl_idsize);
if(rc < 0)
infof(data, "SSL failed to set session ID");
- else
- infof(data, "SSL reusing session ID (size=%zu)", ssl_idsize);
+ else {
+ infof(data, "SSL reusing session ID (size=%zu, alpn=%s)",
+ ssl_idsize, session_alpn ? session_alpn : "-");
+#ifdef DEBUGBUILD
+ if((ssl_config->earlydata || !!getenv("CURL_USE_EARLYDATA")) &&
+#else
+ if(ssl_config->earlydata &&
+#endif
+ !cf->conn->connect_only && connssl &&
+ (gnutls_protocol_get_version(gctx->session) == GNUTLS_TLS1_3) &&
+ Curl_alpn_contains_proto(connssl->alpn, session_alpn)) {
+ connssl->earlydata_max =
+ gnutls_record_get_max_early_data_size(gctx->session);
+ if((!connssl->earlydata_max ||
+ connssl->earlydata_max == 0xFFFFFFFFUL)) {
+ /* Seems to be GnuTLS way to signal no EarlyData in session */
+ CURL_TRC_CF(data, cf, "TLS session does not allow earlydata");
+ }
+ else {
+ CURL_TRC_CF(data, cf, "TLS session allows %zu earlydata bytes, "
+ "reusing ALPN '%s'",
+ connssl->earlydata_max, session_alpn);
+ connssl->earlydata_state = ssl_earlydata_use;
+ connssl->state = ssl_connection_deferred;
+ result = Curl_alpn_set_negotiated(cf, data, connssl,
+ (const unsigned char *)session_alpn,
+ session_alpn ? strlen(session_alpn) : 0);
+ if(result)
+ return result;
+ /* We only try the ALPN protocol the session used before,
+ * otherwise we might send early data for the wrong protocol */
+ gtls_alpns[0].data = (unsigned char *)session_alpn;
+ gtls_alpns[0].size = (unsigned)strlen(session_alpn);
+ gtls_alpns_count = 1;
+ }
+ }
+ }
}
Curl_ssl_sessionid_unlock(data);
}
+
+ /* convert the ALPN string from our arguments to a list of strings that
+ * gnutls wants and will convert internally back to this string for sending
+ * to the server. nice. */
+ if(!gtls_alpns_count && alpn && alpn_len) {
+ size_t i, alen = alpn_len;
+ unsigned char *s = (unsigned char *)alpn;
+ unsigned char slen;
+ for(i = 0; (i < ARRAYSIZE(gtls_alpns)) && alen; ++i) {
+ slen = s[0];
+ if(slen >= alen)
+ return CURLE_FAILED_INIT;
+ gtls_alpns[i].data = s + 1;
+ gtls_alpns[i].size = slen;
+ s += slen + 1;
+ alen -= (size_t)slen + 1;
+ }
+ if(alen) /* not all alpn chars used, wrong format or too many */
+ return CURLE_FAILED_INIT;
+ gtls_alpns_count = i;
+ }
+
+ if(gtls_alpns_count &&
+ gnutls_alpn_set_protocols(gctx->session,
+ gtls_alpns, (unsigned int)gtls_alpns_count,
+ GNUTLS_ALPN_MANDATORY)) {
+ failf(data, "failed setting ALPN");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
return CURLE_OK;
}
@@ -1125,10 +1197,15 @@ gtls_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) }
result = Curl_gtls_ctx_init(&backend->gtls, cf, data, &connssl->peer,
- proto.data, proto.len, NULL, NULL, cf);
+ proto.data, proto.len, connssl, NULL, NULL, cf);
if(result)
return result;
+ if(connssl->alpn && (connssl->state != ssl_connection_deferred)) {
+ Curl_alpn_to_proto_str(&proto, connssl->alpn);
+ infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data);
+ }
+
gnutls_handshake_set_hook_function(backend->gtls.session,
GNUTLS_HANDSHAKE_ANY, GNUTLS_HOOK_POST,
gtls_handshake_cb);
@@ -1313,7 +1390,7 @@ Curl_gtls_verifyserver(struct Curl_easy *data, cause = "attached OCSP status response is invalid";
failf(data, "server verification failed: %s. (CAfile: %s "
"CRLfile: %s)", cause,
- config->CAfile ? config->CAfile: "none",
+ config->CAfile ? config->CAfile : "none",
ssl_config->primary.CRLfile ?
ssl_config->primary.CRLfile : "none");
return CURLE_PEER_FAILED_VERIFICATION;
@@ -1440,12 +1517,12 @@ Curl_gtls_verifyserver(struct Curl_easy *data, unload_file(issuerp);
if(rc <= 0) {
failf(data, "server certificate issuer check failed (IssuerCert: %s)",
- config->issuercert?config->issuercert:"none");
+ config->issuercert ? config->issuercert : "none");
gnutls_x509_crt_deinit(x509_cert);
return CURLE_SSL_ISSUER_ERROR;
}
infof(data, " server certificate issuer check OK (Issuer Cert: %s)",
- config->issuercert?config->issuercert:"none");
+ config->issuercert ? config->issuercert : "none");
}
size = sizeof(certname);
@@ -1650,8 +1727,8 @@ static CURLcode gtls_verifyserver(struct Curl_cfilter *cf, 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);
#ifndef CURL_DISABLE_PROXY
- const char *pinned_key = Curl_ssl_cf_is_proxy(cf)?
- data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]:
+ const char *pinned_key = Curl_ssl_cf_is_proxy(cf) ?
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
data->set.str[STRING_SSL_PINNEDPUBLICKEY];
#else
const char *pinned_key = data->set.str[STRING_SSL_PINNEDPUBLICKEY];
@@ -1663,22 +1740,75 @@ static CURLcode gtls_verifyserver(struct Curl_cfilter *cf, if(result)
goto out;
- if(connssl->alpn) {
- gnutls_datum_t proto;
- int rc;
-
- rc = gnutls_alpn_get_selected_protocol(session, &proto);
- if(rc == 0)
- Curl_alpn_set_negotiated(cf, data, proto.data, proto.size);
- else
- Curl_alpn_set_negotiated(cf, data, NULL, 0);
- }
-
/* Only on TLSv1.2 or lower do we have the session id now. For
* TLSv1.3 we get it via a SESSION_TICKET message that arrives later. */
if(gnutls_protocol_get_version(session) < GNUTLS_TLS1_3)
- result = gtls_update_session_id(cf, data, session);
+ result = cf_gtls_update_session_id(cf, data, session);
+
+out:
+ return result;
+}
+
+static CURLcode gtls_set_earlydata(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ const void *buf, size_t blen)
+{
+ struct ssl_connect_data *connssl = cf->ctx;
+ ssize_t nwritten = 0;
+ CURLcode result = CURLE_OK;
+
+ DEBUGASSERT(connssl->earlydata_state == ssl_earlydata_use);
+ DEBUGASSERT(Curl_bufq_is_empty(&connssl->earlydata));
+ if(blen) {
+ if(blen > connssl->earlydata_max)
+ blen = connssl->earlydata_max;
+ nwritten = Curl_bufq_write(&connssl->earlydata, buf, blen, &result);
+ CURL_TRC_CF(data, cf, "gtls_set_earlydata(len=%zu) -> %zd",
+ blen, nwritten);
+ if(nwritten < 0)
+ return result;
+ }
+ connssl->earlydata_state = ssl_earlydata_sending;
+ connssl->earlydata_skip = Curl_bufq_len(&connssl->earlydata);
+ return CURLE_OK;
+}
+
+static CURLcode gtls_send_earlydata(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
+{
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct gtls_ssl_backend_data *backend =
+ (struct gtls_ssl_backend_data *)connssl->backend;
+ CURLcode result = CURLE_OK;
+ const unsigned char *buf;
+ size_t blen;
+ ssize_t n;
+ DEBUGASSERT(connssl->earlydata_state == ssl_earlydata_sending);
+ backend->gtls.io_result = CURLE_OK;
+ while(Curl_bufq_peek(&connssl->earlydata, &buf, &blen)) {
+ n = gnutls_record_send_early_data(backend->gtls.session, buf, blen);
+ CURL_TRC_CF(data, cf, "gtls_send_earlydata(len=%zu) -> %zd",
+ blen, n);
+ if(n < 0) {
+ if(n == GNUTLS_E_AGAIN)
+ result = CURLE_AGAIN;
+ else
+ result = backend->gtls.io_result ?
+ backend->gtls.io_result : CURLE_SEND_ERROR;
+ goto out;
+ }
+ else if(!n) {
+ /* gnutls is buggy, it *SHOULD* return the amount of bytes it took in.
+ * Instead it returns 0 if everything was written. */
+ n = (ssize_t)blen;
+ }
+
+ Curl_bufq_skip(&connssl->earlydata, (size_t)n);
+ }
+ /* sent everything there was */
+ infof(data, "SSL sending %" FMT_OFF_T " bytes of early data",
+ connssl->earlydata_skip);
out:
return result;
}
@@ -1696,46 +1826,89 @@ static CURLcode gtls_connect_common(struct Curl_cfilter *cf,
struct Curl_easy *data,
bool nonblocking,
- bool *done)
-{
+ bool *done) {
struct ssl_connect_data *connssl = cf->ctx;
- CURLcode rc;
+ struct gtls_ssl_backend_data *backend =
+ (struct gtls_ssl_backend_data *)connssl->backend;
CURLcode result = CURLE_OK;
+ DEBUGASSERT(backend);
+
/* Initiate the connection, if not already done */
- if(ssl_connect_1 == connssl->connecting_state) {
- rc = gtls_connect_step1(cf, data);
- if(rc) {
- result = rc;
+ if(connssl->connecting_state == ssl_connect_1) {
+ result = gtls_connect_step1(cf, data);
+ if(result)
goto out;
- }
+ connssl->connecting_state = ssl_connect_2;
}
- rc = handshake(cf, data, TRUE, nonblocking);
- if(rc) {
- /* handshake() sets its own error message with failf() */
- result = rc;
- goto out;
+ if(connssl->connecting_state == ssl_connect_2) {
+ if(connssl->earlydata_state == ssl_earlydata_use) {
+ goto out;
+ }
+ else if(connssl->earlydata_state == ssl_earlydata_sending) {
+ result = gtls_send_earlydata(cf, data);
+ if(result)
+ goto out;
+ connssl->earlydata_state = ssl_earlydata_sent;
+ if(!Curl_ssl_cf_is_proxy(cf))
+ Curl_pgrsEarlyData(data, (curl_off_t)connssl->earlydata_skip);
+ }
+ DEBUGASSERT((connssl->earlydata_state == ssl_earlydata_none) ||
+ (connssl->earlydata_state == ssl_earlydata_sent));
+
+ result = handshake(cf, data, TRUE, nonblocking);
+ if(result)
+ goto out;
+ connssl->connecting_state = ssl_connect_3;
}
/* Finish connecting once the handshake is done */
- if(ssl_connect_1 == connssl->connecting_state) {
- struct gtls_ssl_backend_data *backend =
- (struct gtls_ssl_backend_data *)connssl->backend;
- gnutls_session_t session;
- DEBUGASSERT(backend);
- session = backend->gtls.session;
- rc = gtls_verifyserver(cf, data, session);
- if(rc) {
- result = rc;
+ if(connssl->connecting_state == ssl_connect_3) {
+ gnutls_datum_t proto;
+ int rc;
+ result = gtls_verifyserver(cf, data, backend->gtls.session);
+ if(result)
goto out;
- }
+
connssl->state = ssl_connection_complete;
+ connssl->connecting_state = ssl_connect_1;
+
+ rc = gnutls_alpn_get_selected_protocol(backend->gtls.session, &proto);
+ if(rc) { /* No ALPN from server */
+ proto.data = NULL;
+ proto.size = 0;
+ }
+
+ result = Curl_alpn_set_negotiated(cf, data, connssl,
+ proto.data, proto.size);
+ if(result)
+ goto out;
+
+ if(connssl->earlydata_state == ssl_earlydata_sent) {
+ if(gnutls_session_get_flags(backend->gtls.session) &
+ GNUTLS_SFLAGS_EARLY_DATA) {
+ connssl->earlydata_state = ssl_earlydata_accepted;
+ infof(data, "Server accepted %zu bytes of TLS early data.",
+ connssl->earlydata_skip);
+ }
+ else {
+ connssl->earlydata_state = ssl_earlydata_rejected;
+ if(!Curl_ssl_cf_is_proxy(cf))
+ Curl_pgrsEarlyData(data, -(curl_off_t)connssl->earlydata_skip);
+ infof(data, "Server rejected TLS early data.");
+ connssl->earlydata_skip = 0;
+ }
+ }
}
out:
- *done = ssl_connect_1 == connssl->connecting_state;
-
+ if(result == CURLE_AGAIN) {
+ *done = FALSE;
+ return CURLE_OK;
+ }
+ *done = ((connssl->connecting_state == ssl_connect_1) ||
+ (connssl->state == ssl_connection_deferred));
return result;
}
@@ -1743,6 +1916,12 @@ static CURLcode gtls_connect_nonblocking(struct Curl_cfilter *cf, struct Curl_easy *data,
bool *done)
{
+ struct ssl_connect_data *connssl = cf->ctx;
+ if(connssl->state == ssl_connection_deferred) {
+ /* We refuse to be pushed, we are waiting for someone to send/recv. */
+ *done = TRUE;
+ return CURLE_OK;
+ }
return gtls_connect_common(cf, data, TRUE, done);
}
@@ -1761,6 +1940,26 @@ static CURLcode gtls_connect(struct Curl_cfilter *cf, return CURLE_OK;
}
+static CURLcode gtls_connect_deferred(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ const void *buf,
+ size_t blen,
+ bool *done)
+{
+ struct ssl_connect_data *connssl = cf->ctx;
+ CURLcode result = CURLE_OK;
+
+ DEBUGASSERT(connssl->state == ssl_connection_deferred);
+ *done = FALSE;
+ if(connssl->earlydata_state == ssl_earlydata_use) {
+ result = gtls_set_earlydata(cf, data, buf, blen);
+ if(result)
+ return result;
+ }
+
+ return gtls_connect_common(cf, data, TRUE, done);
+}
+
static bool gtls_data_pending(struct Curl_cfilter *cf,
const struct Curl_easy *data)
{
@@ -1788,8 +1987,38 @@ static ssize_t gtls_send(struct Curl_cfilter *cf, ssize_t rc;
size_t nwritten, total_written = 0;
- (void)data;
DEBUGASSERT(backend);
+
+ if(connssl->state == ssl_connection_deferred) {
+ bool done = FALSE;
+ *curlcode = gtls_connect_deferred(cf, data, buf, blen, &done);
+ if(*curlcode) {
+ rc = -1;
+ goto out;
+ }
+ else if(!done) {
+ *curlcode = CURLE_AGAIN;
+ rc = -1;
+ goto out;
+ }
+ DEBUGASSERT(connssl->state == ssl_connection_complete);
+ }
+
+ if(connssl->earlydata_skip) {
+ if(connssl->earlydata_skip >= blen) {
+ connssl->earlydata_skip -= blen;
+ *curlcode = CURLE_OK;
+ rc = (ssize_t)blen;
+ goto out;
+ }
+ else {
+ total_written += connssl->earlydata_skip;
+ buf = ((const char *)buf) + connssl->earlydata_skip;
+ blen -= connssl->earlydata_skip;
+ connssl->earlydata_skip = 0;
+ }
+ }
+
while(blen) {
backend->gtls.io_result = CURLE_OK;
rc = gnutls_record_send(backend->gtls.session, buf, blen);
@@ -1800,9 +2029,9 @@ static ssize_t gtls_send(struct Curl_cfilter *cf, rc = (ssize_t)total_written;
goto out;
}
- *curlcode = (rc == GNUTLS_E_AGAIN)?
+ *curlcode = (rc == GNUTLS_E_AGAIN) ?
CURLE_AGAIN :
- (backend->gtls.io_result? backend->gtls.io_result : CURLE_SEND_ERROR);
+ (backend->gtls.io_result ? backend->gtls.io_result : CURLE_SEND_ERROR);
rc = -1;
goto out;
@@ -1836,7 +2065,9 @@ static CURLcode gtls_shutdown(struct Curl_cfilter *cf, size_t i;
DEBUGASSERT(backend);
- if(!backend->gtls.session || cf->shutdown) {
+ /* If we have no handshaked connection or already shut down */
+ if(!backend->gtls.session || cf->shutdown ||
+ connssl->state != ssl_connection_complete) {
*done = TRUE;
goto out;
}
@@ -1851,7 +2082,7 @@ static CURLcode gtls_shutdown(struct Curl_cfilter *cf, int ret = gnutls_bye(backend->gtls.session, GNUTLS_SHUT_RDWR);
if((ret == GNUTLS_E_AGAIN) || (ret == GNUTLS_E_INTERRUPTED)) {
CURL_TRC_CF(data, cf, "SSL shutdown, gnutls_bye EAGAIN");
- connssl->io_need = gnutls_record_get_direction(backend->gtls.session)?
+ connssl->io_need = gnutls_record_get_direction(backend->gtls.session) ?
CURL_SSL_IO_NEED_SEND : CURL_SSL_IO_NEED_RECV;
backend->gtls.sent_shutdown = FALSE;
result = CURLE_OK;
@@ -1881,7 +2112,7 @@ static CURLcode gtls_shutdown(struct Curl_cfilter *cf, *done = TRUE;
}
else if((nread == GNUTLS_E_AGAIN) || (nread == GNUTLS_E_INTERRUPTED)) {
- connssl->io_need = gnutls_record_get_direction(backend->gtls.session)?
+ connssl->io_need = gnutls_record_get_direction(backend->gtls.session) ?
CURL_SSL_IO_NEED_SEND : CURL_SSL_IO_NEED_RECV;
}
else {
@@ -1934,7 +2165,21 @@ static ssize_t gtls_recv(struct Curl_cfilter *cf, (void)data;
DEBUGASSERT(backend);
- backend->gtls.io_result = CURLE_OK;
+ if(connssl->state == ssl_connection_deferred) {
+ bool done = FALSE;
+ *curlcode = gtls_connect_deferred(cf, data, NULL, 0, &done);
+ if(*curlcode) {
+ ret = -1;
+ goto out;
+ }
+ else if(!done) {
+ *curlcode = CURLE_AGAIN;
+ ret = -1;
+ goto out;
+ }
+ DEBUGASSERT(connssl->state == ssl_connection_complete);
+ }
+
ret = gnutls_record_recv(backend->gtls.session, buf, buffersize);
if((ret == GNUTLS_E_AGAIN) || (ret == GNUTLS_E_INTERRUPTED)) {
*curlcode = CURLE_AGAIN;
@@ -1957,10 +2202,9 @@ static ssize_t gtls_recv(struct Curl_cfilter *cf, if(ret < 0) {
failf(data, "GnuTLS recv error (%d): %s",
-
(int)ret, gnutls_strerror((int)ret));
- *curlcode = backend->gtls.io_result?
- backend->gtls.io_result : CURLE_RECV_ERROR;
+ *curlcode = backend->gtls.io_result ?
+ backend->gtls.io_result : CURLE_RECV_ERROR;
ret = -1;
goto out;
}
@@ -1981,7 +2225,7 @@ static CURLcode gtls_random(struct Curl_easy *data, int rc;
(void)data;
rc = gnutls_rnd(GNUTLS_RND_RANDOM, entropy, length);
- return rc?CURLE_FAILED_INIT:CURLE_OK;
+ return rc ? CURLE_FAILED_INIT : CURLE_OK;
}
static CURLcode gtls_sha256sum(const unsigned char *tmp, /* input */
diff --git a/libs/libcurl/src/vtls/gtls.h b/libs/libcurl/src/vtls/gtls.h index 2ba237a315..4f3c089bc6 100644 --- a/libs/libcurl/src/vtls/gtls.h +++ b/libs/libcurl/src/vtls/gtls.h @@ -45,6 +45,7 @@ struct Curl_cfilter; struct ssl_primary_config;
struct ssl_config_data;
struct ssl_peer;
+struct ssl_connect_data;
struct gtls_shared_creds {
gnutls_certificate_credentials_t creds;
@@ -78,6 +79,7 @@ CURLcode Curl_gtls_ctx_init(struct gtls_ctx *gctx, struct Curl_easy *data,
struct ssl_peer *peer,
const unsigned char *alpn, size_t alpn_len,
+ struct ssl_connect_data *connssl,
Curl_gtls_ctx_setup_cb *cb_setup,
void *cb_user_data,
void *ssl_user_data);
@@ -93,6 +95,13 @@ CURLcode Curl_gtls_verifyserver(struct Curl_easy *data, struct ssl_peer *peer,
const char *pinned_key);
+/* Extract TLS session and place in cache, if configured. */
+CURLcode Curl_gtls_update_session_id(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ gnutls_session_t session,
+ struct ssl_peer *peer,
+ const char *alpn);
+
extern const struct Curl_ssl Curl_ssl_gnutls;
#endif /* USE_GNUTLS */
diff --git a/libs/libcurl/src/vtls/keylog.c b/libs/libcurl/src/vtls/keylog.c index 9cdfc02213..e403114934 100644 --- a/libs/libcurl/src/vtls/keylog.c +++ b/libs/libcurl/src/vtls/keylog.c @@ -99,13 +99,13 @@ Curl_tls_keylog_write_line(const char *line) char buf[256];
if(!keylog_file_fp || !line) {
- return false;
+ return FALSE;
}
linelen = strlen(line);
if(linelen == 0 || linelen > sizeof(buf) - 2) {
/* Empty line or too big to fit in a LF and NUL. */
- return false;
+ return FALSE;
}
memcpy(buf, line, linelen);
@@ -117,7 +117,7 @@ Curl_tls_keylog_write_line(const char *line) /* Using fputs here instead of fprintf since libcurl's fprintf replacement
may not be thread-safe. */
fputs(buf, keylog_file_fp);
- return true;
+ return TRUE;
}
bool
@@ -131,13 +131,13 @@ Curl_tls_keylog_write(const char *label, 2 * SECRET_MAXLEN + 1 + 1];
if(!keylog_file_fp) {
- return false;
+ return FALSE;
}
pos = strlen(label);
if(pos > KEYLOG_LABEL_MAXLEN || !secretlen || secretlen > SECRET_MAXLEN) {
/* Should never happen - sanity check anyway. */
- return false;
+ return FALSE;
}
memcpy(line, label, pos);
@@ -161,7 +161,7 @@ Curl_tls_keylog_write(const char *label, /* Using fputs here instead of fprintf since libcurl's fprintf replacement
may not be thread-safe. */
fputs(line, keylog_file_fp);
- return true;
+ return TRUE;
}
#endif /* TLS or QUIC backend */
diff --git a/libs/libcurl/src/vtls/mbedtls.c b/libs/libcurl/src/vtls/mbedtls.c index 14fedf8b23..20226b74bd 100644 --- a/libs/libcurl/src/vtls/mbedtls.c +++ b/libs/libcurl/src/vtls/mbedtls.c @@ -36,13 +36,6 @@ /* Define this to enable lots of debugging for mbedTLS */
/* #define MBEDTLS_DEBUG */
-#ifdef __GNUC__
-#pragma GCC diagnostic push
-/* mbedTLS (as of v3.5.1) has a duplicate function declaration
- in its public headers. Disable the warning that detects it. */
-#pragma GCC diagnostic ignored "-Wredundant-decls"
-#endif
-
#include <mbedtls/version.h>
#if MBEDTLS_VERSION_NUMBER >= 0x02040000
#include <mbedtls/net_sockets.h>
@@ -63,10 +56,6 @@ # endif
#endif
-#ifdef __GNUC__
-#pragma GCC diagnostic pop
-#endif
-
#include "cipher_suite.h"
#include "strcase.h"
#include "urldata.h"
@@ -129,6 +118,10 @@ struct mbed_ssl_backend_data { #define TLS13_SUPPORT
#endif
+#if defined(TLS13_SUPPORT) && defined(MBEDTLS_SSL_SESSION_TICKETS)
+#define HAS_SESSION_TICKETS
+#endif
+
#if defined(THREADING_SUPPORT)
static mbedtls_entropy_context ts_entropy;
@@ -302,7 +295,8 @@ mbed_set_ssl_version_min_max(struct Curl_easy *data, break;
#endif
default:
- failf(data, "mbedTLS: unsupported minimum TLS version value");
+ failf(data, "mbedTLS: unsupported minimum TLS version value: %x",
+ conn_config->version);
return CURLE_SSL_CONNECT_ERROR;
}
@@ -351,6 +345,7 @@ mbed_set_ssl_version_min_max(struct Curl_easy *data, cipher suite present in other SSL implementations. Provide
provisional support for specifying the cipher suite here. */
#ifdef MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8
+#if MBEDTLS_VERSION_NUMBER >= 0x03020000
static int
mbed_cipher_suite_get_str(uint16_t id, char *buf, size_t buf_size,
bool prefer_rfc)
@@ -361,6 +356,7 @@ mbed_cipher_suite_get_str(uint16_t id, char *buf, size_t buf_size, return Curl_cipher_suite_get_str(id, buf, buf_size, prefer_rfc);
return 0;
}
+#endif
static uint16_t
mbed_cipher_suite_walk_str(const char **str, const char **end)
@@ -552,7 +548,7 @@ static int mbed_verify_cb(void *ptr, mbedtls_x509_crt *crt, mbedtls_x509_crt_verify_info(buf, sizeof(buf), "", *flags);
failf(data, "mbedTLS: %s", buf);
#else
- failf(data, "mbedTLS: cerificate verification error 0x%08x", *flags);
+ failf(data, "mbedTLS: certificate verification error 0x%08x", *flags);
#endif
}
@@ -638,7 +634,7 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) ret = mbedtls_x509_crt_parse(&backend->cacert, newblob,
ca_info_blob->len + 1);
free(newblob);
- if(ret<0) {
+ if(ret < 0) {
mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
failf(data, "Error importing ca cert blob - mbedTLS: (-0x%04X) %s",
-ret, errorbuf);
@@ -650,7 +646,7 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) #ifdef MBEDTLS_FS_IO
ret = mbedtls_x509_crt_parse_file(&backend->cacert, ssl_cafile);
- if(ret<0) {
+ if(ret < 0) {
mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
failf(data, "Error reading ca cert file %s - mbedTLS: (-0x%04X) %s",
ssl_cafile, -ret, errorbuf);
@@ -666,7 +662,7 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) #ifdef MBEDTLS_FS_IO
ret = mbedtls_x509_crt_parse_path(&backend->cacert, ssl_capath);
- if(ret<0) {
+ if(ret < 0) {
mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
failf(data, "Error reading ca cert path %s - mbedTLS: (-0x%04X) %s",
ssl_capath, -ret, errorbuf);
@@ -816,6 +812,12 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) return CURLE_SSL_CONNECT_ERROR;
}
+#ifdef MBEDTLS_SSL_TLS1_3_SIGNAL_NEW_SESSION_TICKETS_ENABLED
+ /* New in mbedTLS 3.6.1, need to enable, default is now disabled */
+ mbedtls_ssl_conf_tls13_enable_signal_new_session_tickets(&backend->config,
+ MBEDTLS_SSL_TLS1_3_SIGNAL_NEW_SESSION_TICKETS_ENABLED);
+#endif
+
/* Always let mbedTLS verify certificates, if verifypeer or verifyhost are
* disabled we clear the corresponding error flags in the verify callback
* function. That is also where we log verification errors. */
@@ -883,17 +885,27 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) /* Check if there is a cached ID we can/should use here! */
if(ssl_config->primary.cache_session) {
- void *old_session = NULL;
+ void *sdata = NULL;
+ size_t slen = 0;
Curl_ssl_sessionid_lock(data);
- if(!Curl_ssl_getsessionid(cf, data, &connssl->peer, &old_session, NULL)) {
- ret = mbedtls_ssl_set_session(&backend->ssl, old_session);
+ if(!Curl_ssl_getsessionid(cf, data, &connssl->peer,
+ &sdata, &slen, NULL) && slen) {
+ mbedtls_ssl_session session;
+
+ mbedtls_ssl_session_init(&session);
+ ret = mbedtls_ssl_session_load(&session, sdata, slen);
if(ret) {
- Curl_ssl_sessionid_unlock(data);
- failf(data, "mbedtls_ssl_set_session returned -0x%x", -ret);
- return CURLE_SSL_CONNECT_ERROR;
+ failf(data, "error loading cached session: -0x%x", -ret);
}
- infof(data, "mbedTLS reusing session");
+ else {
+ ret = mbedtls_ssl_set_session(&backend->ssl, &session);
+ if(ret)
+ failf(data, "error setting session: -0x%x", -ret);
+ else
+ infof(data, "SSL reusing session ID");
+ }
+ mbedtls_ssl_session_free(&session);
}
Curl_ssl_sessionid_unlock(data);
}
@@ -911,7 +923,7 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) &backend->clicert, &backend->pk);
}
- if(mbedtls_ssl_set_hostname(&backend->ssl, connssl->peer.sni?
+ if(mbedtls_ssl_set_hostname(&backend->ssl, connssl->peer.sni ?
connssl->peer.sni : connssl->peer.hostname)) {
/* mbedtls_ssl_set_hostname() sets the name to use in CN/SAN checks and
the name to set in the SNI extension. So even if curl connects to a
@@ -975,8 +987,8 @@ mbed_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) struct mbed_ssl_backend_data *backend =
(struct mbed_ssl_backend_data *)connssl->backend;
#ifndef CURL_DISABLE_PROXY
- const char * const pinnedpubkey = Curl_ssl_cf_is_proxy(cf)?
- data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]:
+ const char * const pinnedpubkey = Curl_ssl_cf_is_proxy(cf) ?
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
data->set.str[STRING_SSL_PINNEDPUBLICKEY];
#else
const char * const pinnedpubkey = data->set.str[STRING_SSL_PINNEDPUBLICKEY];
@@ -1016,7 +1028,7 @@ mbed_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) uint16_t cipher_id;
cipher_id = (uint16_t)
mbedtls_ssl_get_ciphersuite_id_from_ssl(&backend->ssl);
- mbed_cipher_suite_get_str(cipher_id, cipher_str, sizeof(cipher_str), true);
+ mbed_cipher_suite_get_str(cipher_id, cipher_str, sizeof(cipher_str), TRUE);
infof(data, "mbedTLS: %s Handshake complete, cipher is %s",
mbedtls_ssl_get_version(&backend->ssl), cipher_str);
}
@@ -1059,7 +1071,7 @@ mbed_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) /* Make a copy of our const peercert because mbedtls_pk_write_pubkey_der
needs a non-const key, for now.
- https://github.com/ARMmbed/mbedtls/issues/396 */
+ https://github.com/Mbed-TLS/mbedtls/issues/396 */
#if MBEDTLS_VERSION_NUMBER == 0x03000000
if(mbedtls_x509_crt_parse_der(p,
peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(p),
@@ -1102,8 +1114,8 @@ pinnedpubkey_error: if(connssl->alpn) {
const char *proto = mbedtls_ssl_get_alpn_protocol(&backend->ssl);
- Curl_alpn_set_negotiated(cf, data, (const unsigned char *)proto,
- proto? strlen(proto) : 0);
+ Curl_alpn_set_negotiated(cf, data, connssl, (const unsigned char *)proto,
+ proto ? strlen(proto) : 0);
}
#endif
@@ -1113,57 +1125,62 @@ pinnedpubkey_error: return CURLE_OK;
}
-static void mbedtls_session_free(void *sessionid, size_t idsize)
+static void mbedtls_session_free(void *session, size_t slen)
{
- (void)idsize;
- mbedtls_ssl_session_free(sessionid);
- free(sessionid);
+ (void)slen;
+ free(session);
}
static CURLcode
-mbed_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
+mbed_new_session(struct Curl_cfilter *cf, struct Curl_easy *data)
{
- CURLcode retcode = CURLE_OK;
struct ssl_connect_data *connssl = cf->ctx;
struct mbed_ssl_backend_data *backend =
(struct mbed_ssl_backend_data *)connssl->backend;
struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+ CURLcode result = CURLE_OK;
- DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
DEBUGASSERT(backend);
-
if(ssl_config->primary.cache_session) {
int ret;
- mbedtls_ssl_session *our_ssl_sessionid;
-
- our_ssl_sessionid = malloc(sizeof(mbedtls_ssl_session));
- if(!our_ssl_sessionid)
- return CURLE_OUT_OF_MEMORY;
-
- mbedtls_ssl_session_init(our_ssl_sessionid);
+ mbedtls_ssl_session session;
+ unsigned char *sdata = NULL;
+ size_t slen = 0;
- ret = mbedtls_ssl_get_session(&backend->ssl, our_ssl_sessionid);
+ mbedtls_ssl_session_init(&session);
+ ret = mbedtls_ssl_get_session(&backend->ssl, &session);
if(ret) {
if(ret != MBEDTLS_ERR_SSL_ALLOC_FAILED)
- mbedtls_ssl_session_free(our_ssl_sessionid);
- free(our_ssl_sessionid);
+ mbedtls_ssl_session_free(&session);
failf(data, "mbedtls_ssl_get_session returned -0x%x", -ret);
return CURLE_SSL_CONNECT_ERROR;
}
- /* If there is already a matching session in the cache, delete it */
- Curl_ssl_sessionid_lock(data);
- retcode = Curl_ssl_set_sessionid(cf, data, &connssl->peer,
- our_ssl_sessionid, 0,
- mbedtls_session_free);
- Curl_ssl_sessionid_unlock(data);
- if(retcode)
- return retcode;
+ mbedtls_ssl_session_save(&session, NULL, 0, &slen);
+ if(!slen) {
+ failf(data, "failed to serialize session: length is 0");
+ }
+ else {
+ sdata = malloc(slen);
+ if(sdata) {
+ ret = mbedtls_ssl_session_save(&session, sdata, slen, &slen);
+ if(ret) {
+ failf(data, "failed to serialize session: -0x%x", -ret);
+ }
+ else {
+ Curl_ssl_sessionid_lock(data);
+ result = Curl_ssl_set_sessionid(cf, data, &connssl->peer, NULL,
+ sdata, slen, mbedtls_session_free);
+ Curl_ssl_sessionid_unlock(data);
+ if(!result)
+ sdata = NULL;
+ }
+ }
+ }
+ mbedtls_ssl_session_free(&session);
+ free(sdata);
}
-
- connssl->connecting_state = ssl_connect_done;
-
- return CURLE_OK;
+ return result;
}
static ssize_t mbed_send(struct Curl_cfilter *cf, struct Curl_easy *data,
@@ -1186,7 +1203,7 @@ static ssize_t mbed_send(struct Curl_cfilter *cf, struct Curl_easy *data, #ifdef TLS13_SUPPORT
|| (ret == MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET)
#endif
- )? CURLE_AGAIN : CURLE_SEND_ERROR;
+ ) ? CURLE_AGAIN : CURLE_SEND_ERROR;
ret = -1;
}
@@ -1322,7 +1339,6 @@ static ssize_t mbed_recv(struct Curl_cfilter *cf, struct Curl_easy *data, struct mbed_ssl_backend_data *backend =
(struct mbed_ssl_backend_data *)connssl->backend;
int ret = -1;
- ssize_t len = -1;
(void)data;
DEBUGASSERT(backend);
@@ -1332,24 +1348,31 @@ static ssize_t mbed_recv(struct Curl_cfilter *cf, struct Curl_easy *data, if(ret <= 0) {
CURL_TRC_CF(data, cf, "mbedtls_ssl_read(len=%zu) -> -0x%04X",
buffersize, -ret);
- if(ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY)
- return 0;
- *curlcode = ((ret == MBEDTLS_ERR_SSL_WANT_READ)
-#ifdef TLS13_SUPPORT
- || (ret == MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET)
+ switch(ret) {
+#ifdef HAS_SESSION_TICKETS
+ case MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET:
+ mbed_new_session(cf, data);
+ FALLTHROUGH();
#endif
- ) ? CURLE_AGAIN : CURLE_RECV_ERROR;
- if(*curlcode != CURLE_AGAIN) {
+ case MBEDTLS_ERR_SSL_WANT_READ:
+ *curlcode = CURLE_AGAIN;
+ ret = -1;
+ break;
+ case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY:
+ *curlcode = CURLE_OK;
+ ret = 0;
+ break;
+ default: {
char errorbuf[128];
mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
failf(data, "ssl_read returned: (-0x%04X) %s", -ret, errorbuf);
+ *curlcode = CURLE_RECV_ERROR;
+ ret = -1;
+ break;
+ }
}
- return -1;
}
-
- len = ret;
-
- return len;
+ return (ssize_t)ret;
}
static size_t mbedtls_version(char *buffer, size_t size)
@@ -1357,42 +1380,31 @@ static size_t mbedtls_version(char *buffer, size_t size) #ifdef MBEDTLS_VERSION_C
/* if mbedtls_version_get_number() is available it is better */
unsigned int version = mbedtls_version_get_number();
- return msnprintf(buffer, size, "mbedTLS/%u.%u.%u", version>>24,
- (version>>16)&0xff, (version>>8)&0xff);
+ return msnprintf(buffer, size, "mbedTLS/%u.%u.%u", version >> 24,
+ (version >> 16) & 0xff, (version >> 8) & 0xff);
#else
return msnprintf(buffer, size, "mbedTLS/%s", MBEDTLS_VERSION_STRING);
#endif
}
+/* 'data' might be NULL */
static CURLcode mbedtls_random(struct Curl_easy *data,
unsigned char *entropy, size_t length)
{
#if defined(MBEDTLS_CTR_DRBG_C)
- int ret = -1;
- char errorbuf[128];
+ int ret;
mbedtls_entropy_context ctr_entropy;
mbedtls_ctr_drbg_context ctr_drbg;
mbedtls_entropy_init(&ctr_entropy);
mbedtls_ctr_drbg_init(&ctr_drbg);
+ (void)data;
ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func,
&ctr_entropy, NULL, 0);
- if(ret) {
- mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
- failf(data, "mbedtls_ctr_drbg_seed returned (-0x%04X) %s",
- -ret, errorbuf);
- }
- else {
+ if(!ret)
ret = mbedtls_ctr_drbg_random(&ctr_drbg, entropy, length);
- if(ret) {
- mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
- failf(data, "mbedtls_ctr_drbg_random returned (-0x%04X) %s",
- -ret, errorbuf);
- }
- }
-
mbedtls_ctr_drbg_free(&ctr_drbg);
mbedtls_entropy_free(&ctr_entropy);
@@ -1452,11 +1464,10 @@ mbed_connect_common(struct Curl_cfilter *cf, struct Curl_easy *data, /* if ssl is expecting something, check if it is available. */
if(connssl->io_need) {
-
- curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND)?
- sockfd:CURL_SOCKET_BAD;
- curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV)?
- sockfd:CURL_SOCKET_BAD;
+ curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND) ?
+ sockfd : CURL_SOCKET_BAD;
+ curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV) ?
+ sockfd : CURL_SOCKET_BAD;
what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
nonblocking ? 0 : timeout_ms);
@@ -1495,9 +1506,22 @@ mbed_connect_common(struct Curl_cfilter *cf, struct Curl_easy *data, } /* repeat step2 until all transactions are done. */
if(ssl_connect_3 == connssl->connecting_state) {
- retcode = mbed_connect_step3(cf, data);
- if(retcode)
- return retcode;
+ /* For tls1.3 we get notified about new sessions */
+#if MBEDTLS_VERSION_NUMBER >= 0x03020000
+ struct ssl_connect_data *ctx = cf->ctx;
+ struct mbed_ssl_backend_data *backend =
+ (struct mbed_ssl_backend_data *)ctx->backend;
+
+ if(mbedtls_ssl_get_version_number(&backend->ssl) <=
+ MBEDTLS_SSL_VERSION_TLS1_2) {
+#else
+ { /* no TLSv1.3 supported here */
+#endif
+ retcode = mbed_new_session(cf, data);
+ if(retcode)
+ return retcode;
+ }
+ connssl->connecting_state = ssl_connect_done;
}
if(ssl_connect_done == connssl->connecting_state) {
diff --git a/libs/libcurl/src/vtls/openssl.c b/libs/libcurl/src/vtls/openssl.c index 4aea58d87c..86931089b1 100644 --- a/libs/libcurl/src/vtls/openssl.c +++ b/libs/libcurl/src/vtls/openssl.c @@ -247,7 +247,7 @@ #elif defined(OPENSSL_IS_AWSLC)
#define OSSL_PACKAGE "AWS-LC"
#else
-# if defined(USE_NGTCP2) && defined(USE_NGHTTP3)
+# if (defined(USE_NGTCP2) && defined(USE_NGHTTP3)) || defined(USE_MSH3)
# define OSSL_PACKAGE "quictls"
# else
# define OSSL_PACKAGE "OpenSSL"
@@ -916,7 +916,7 @@ ossl_log_tls12_secret(const SSL *ssl, bool *keylog_done) if(master_key_length <= 0)
return;
- *keylog_done = true;
+ *keylog_done = TRUE;
Curl_tls_keylog_write("CLIENT_RANDOM", client_random,
master_key, master_key_length);
}
@@ -1015,7 +1015,7 @@ static int passwd_callback(char *buf, int num, int encrypting, */
static bool rand_enough(void)
{
- return (0 != RAND_status()) ? TRUE : FALSE;
+ return (0 != RAND_status());
}
static CURLcode ossl_seed(struct Curl_easy *data)
@@ -1558,7 +1558,8 @@ fail: SSL_CTX_use_PrivateKey_file(ctx, key_file, file_type);
if(cert_use_result != 1) {
failf(data, "unable to set private key file: '%s' type %s",
- key_file?key_file:"(memory blob)", key_type?key_type:"PEM");
+ key_file ? key_file : "(memory blob)",
+ key_type ? key_type : "PEM");
return 0;
}
break;
@@ -1680,29 +1681,23 @@ fail: }
/* returns non-zero on failure */
-static int x509_name_oneline(X509_NAME *a, char *buf, size_t size)
+static CURLcode x509_name_oneline(X509_NAME *a, struct dynbuf *d)
{
BIO *bio_out = BIO_new(BIO_s_mem());
BUF_MEM *biomem;
int rc;
-
- if(!bio_out)
- return 1; /* alloc failed! */
-
- rc = X509_NAME_print_ex(bio_out, a, 0, XN_FLAG_SEP_SPLUS_SPC);
- BIO_get_mem_ptr(bio_out, &biomem);
-
- if((size_t)biomem->length < size)
- size = biomem->length;
- else
- size--; /* do not overwrite the buffer end */
-
- memcpy(buf, biomem->data, size);
- buf[size] = 0;
-
- BIO_free(bio_out);
-
- return !rc;
+ CURLcode result = CURLE_OUT_OF_MEMORY;
+
+ if(bio_out) {
+ Curl_dyn_reset(d);
+ rc = X509_NAME_print_ex(bio_out, a, 0, XN_FLAG_SEP_SPLUS_SPC);
+ if(rc != -1) {
+ BIO_get_mem_ptr(bio_out, &biomem);
+ result = Curl_dyn_addn(d, biomem->data, biomem->length);
+ BIO_free(bio_out);
+ }
+ }
+ return result;
}
/**
@@ -1940,8 +1935,9 @@ static CURLcode ossl_shutdown(struct Curl_cfilter *cf, /* SSL should now have started the shutdown from our side. Since it
* was not complete, we are lacking the close notify from the server. */
- if(send_shutdown) {
+ if(send_shutdown && !(SSL_get_shutdown(octx->ssl) & SSL_SENT_SHUTDOWN)) {
ERR_clear_error();
+ CURL_TRC_CF(data, cf, "send SSL close notify");
if(SSL_shutdown(octx->ssl) == 1) {
CURL_TRC_CF(data, cf, "SSL shutdown finished");
*done = TRUE;
@@ -1966,7 +1962,10 @@ static CURLcode ossl_shutdown(struct Curl_cfilter *cf, err = SSL_get_error(octx->ssl, nread);
switch(err) {
case SSL_ERROR_ZERO_RETURN: /* no more data */
- CURL_TRC_CF(data, cf, "SSL shutdown not received, but closed");
+ if(SSL_shutdown(octx->ssl) == 1)
+ CURL_TRC_CF(data, cf, "SSL shutdown finished");
+ else
+ CURL_TRC_CF(data, cf, "SSL shutdown not received, but closed");
*done = TRUE;
break;
case SSL_ERROR_NONE: /* just did not get anything */
@@ -2234,8 +2233,9 @@ static CURLcode ossl_verifyhost(struct Curl_easy *data, /* we have to look to the last occurrence of a commonName in the
distinguished one to get the most significant one. */
int i = -1;
- unsigned char *peer_CN = NULL;
- int peerlen = 0;
+ unsigned char *cn = NULL;
+ int cnlen = 0;
+ bool free_cn = FALSE;
/* The following is done because of a bug in 0.9.6b */
X509_NAME *name = X509_get_subject_name(server_cert);
@@ -2259,21 +2259,17 @@ static CURLcode ossl_verifyhost(struct Curl_easy *data, conditional in the future when OpenSSL has been fixed. */
if(tmp) {
if(ASN1_STRING_type(tmp) == V_ASN1_UTF8STRING) {
- peerlen = ASN1_STRING_length(tmp);
- if(peerlen >= 0) {
- peer_CN = OPENSSL_malloc(peerlen + 1);
- if(peer_CN) {
- memcpy(peer_CN, ASN1_STRING_get0_data(tmp), peerlen);
- peer_CN[peerlen] = '\0';
- }
- else
- result = CURLE_OUT_OF_MEMORY;
- }
+ cnlen = ASN1_STRING_length(tmp);
+ cn = (unsigned char *) ASN1_STRING_get0_data(tmp);
+ }
+ else { /* not a UTF8 name */
+ cnlen = ASN1_STRING_to_UTF8(&cn, tmp);
+ free_cn = TRUE;
}
- else /* not a UTF8 name */
- peerlen = ASN1_STRING_to_UTF8(&peer_CN, tmp);
- if(peer_CN && (curlx_uztosi(strlen((char *)peer_CN)) != peerlen)) {
+ if((cnlen <= 0) || !cn)
+ result = CURLE_OUT_OF_MEMORY;
+ else if((size_t)cnlen != strlen((char *)cn)) {
/* there was a terminating zero before the end of string, this
cannot match and we return failure! */
failf(data, "SSL: illegal cert name field");
@@ -2285,22 +2281,22 @@ static CURLcode ossl_verifyhost(struct Curl_easy *data, if(result)
/* error already detected, pass through */
;
- else if(!peer_CN) {
+ else if(!cn) {
failf(data,
"SSL: unable to obtain common name from peer certificate");
result = CURLE_PEER_FAILED_VERIFICATION;
}
- else if(!Curl_cert_hostcheck((const char *)peer_CN,
- peerlen, peer->hostname, hostlen)) {
+ else if(!Curl_cert_hostcheck((const char *)cn, cnlen,
+ peer->hostname, hostlen)) {
failf(data, "SSL: certificate subject name '%s' does not match "
- "target hostname '%s'", peer_CN, peer->dispname);
+ "target hostname '%s'", cn, peer->dispname);
result = CURLE_PEER_FAILED_VERIFICATION;
}
else {
- infof(data, " common name: %s (matched)", peer_CN);
+ infof(data, " common name: %s (matched)", cn);
}
- if(peer_CN)
- OPENSSL_free(peer_CN);
+ if(free_cn)
+ OPENSSL_free(cn);
}
return result;
@@ -2685,11 +2681,9 @@ static void ossl_trace(int direction, int ssl_ver, int content_type, txt_len = msnprintf(ssl_buf, sizeof(ssl_buf),
"%s (%s), %s, %s (%d):\n",
- verstr, direction?"OUT":"IN",
+ verstr, direction ? "OUT" : "IN",
tls_rt_name, msg_name, msg_type);
- if(0 <= txt_len && (unsigned)txt_len < sizeof(ssl_buf)) {
- Curl_debug(data, CURLINFO_TEXT, ssl_buf, (size_t)txt_len);
- }
+ Curl_debug(data, CURLINFO_TEXT, ssl_buf, (size_t)txt_len);
}
Curl_debug(data, (direction == 1) ? CURLINFO_SSL_DATA_OUT :
@@ -2922,8 +2916,8 @@ CURLcode Curl_ossl_add_session(struct Curl_cfilter *cf, }
Curl_ssl_sessionid_lock(data);
- result = Curl_ssl_set_sessionid(cf, data, peer, der_session_buf,
- der_session_size, ossl_session_free);
+ result = Curl_ssl_set_sessionid(cf, data, peer, NULL, der_session_buf,
+ der_session_size, ossl_session_free);
Curl_ssl_sessionid_unlock(data);
}
@@ -2941,8 +2935,8 @@ static int ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid) struct ssl_connect_data *connssl;
cf = (struct Curl_cfilter*) SSL_get_app_data(ssl);
- connssl = cf? cf->ctx : NULL;
- data = connssl? CF_DATA_CURRENT(cf) : NULL;
+ connssl = cf ? cf->ctx : NULL;
+ data = connssl ? CF_DATA_CURRENT(cf) : NULL;
Curl_ossl_add_session(cf, data, &connssl->peer, ssl_sessionid);
return 0;
}
@@ -3012,7 +3006,7 @@ static CURLcode import_windows_cert_store(struct Curl_easy *data, CURLcode result = CURLE_OK;
HCERTSTORE hStore;
- *imported = false;
+ *imported = FALSE;
hStore = CertOpenSystemStoreA(0, name);
if(hStore) {
@@ -3034,20 +3028,19 @@ static CURLcode import_windows_cert_store(struct Curl_easy *data, BYTE key_usage[2];
DWORD req_size;
const unsigned char *encoded_cert;
-#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
- char cert_name[256];
-#endif
-
pContext = CertEnumCertificatesInStore(hStore, pContext);
if(!pContext)
break;
#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
- if(!CertGetNameStringA(pContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0,
- NULL, cert_name, sizeof(cert_name))) {
- strcpy(cert_name, "Unknown");
+ else {
+ char cert_name[256];
+ if(!CertGetNameStringA(pContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0,
+ NULL, cert_name, sizeof(cert_name)))
+ infof(data, "SSL: unknown cert name");
+ else
+ infof(data, "SSL: Checking cert \"%s\"", cert_name);
}
- infof(data, "SSL: Checking cert \"%s\"", cert_name);
#endif
encoded_cert = (const unsigned char *)pContext->pbCertEncoded;
if(!encoded_cert)
@@ -3100,12 +3093,12 @@ static CURLcode import_windows_cert_store(struct Curl_easy *data, }
else {
DWORD i;
- bool found = false;
+ bool found = FALSE;
for(i = 0; i < enhkey_usage->cUsageIdentifier; ++i) {
if(!strcmp("1.3.6.1.5.5.7.3.1" /* OID server auth */,
enhkey_usage->rgpszUsageIdentifier[i])) {
- found = true;
+ found = TRUE;
break;
}
}
@@ -3129,9 +3122,9 @@ static CURLcode import_windows_cert_store(struct Curl_easy *data, not OpenSSL. */
if(X509_STORE_add_cert(store, x509) == 1) {
#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
- infof(data, "SSL: Imported cert \"%s\"", cert_name);
+ infof(data, "SSL: Imported cert");
#endif
- *imported = true;
+ *imported = TRUE;
}
X509_free(x509);
}
@@ -3163,11 +3156,11 @@ static CURLcode populate_x509_store(struct Curl_cfilter *cf, const char * const ssl_capath = conn_config->CApath;
const char * const ssl_crlfile = ssl_config->primary.CRLfile;
const bool verifypeer = conn_config->verifypeer;
- bool imported_native_ca = false;
- bool imported_ca_info_blob = false;
+ bool imported_native_ca = FALSE;
+ bool imported_ca_info_blob = FALSE;
CURL_TRC_CF(data, cf, "populate_x509_store, path=%s, blob=%d",
- ssl_cafile? ssl_cafile : "none", !!ca_info_blob);
+ ssl_cafile ? ssl_cafile : "none", !!ca_info_blob);
if(!store)
return CURLE_OUT_OF_MEMORY;
@@ -3185,14 +3178,14 @@ static CURLcode populate_x509_store(struct Curl_cfilter *cf, };
size_t i;
for(i = 0; i < ARRAYSIZE(storeNames); ++i) {
- bool imported = false;
+ bool imported = FALSE;
result = import_windows_cert_store(data, storeNames[i], store,
&imported);
if(result)
return result;
if(imported) {
infof(data, "successfully imported Windows %s store", storeNames[i]);
- imported_native_ca = true;
+ imported_native_ca = TRUE;
}
else
infof(data, "error importing Windows %s store, continuing anyway",
@@ -3207,7 +3200,7 @@ static CURLcode populate_x509_store(struct Curl_cfilter *cf, return result;
}
else {
- imported_ca_info_blob = true;
+ imported_ca_info_blob = TRUE;
infof(data, "successfully imported CA certificate blob");
}
}
@@ -3371,9 +3364,9 @@ static X509_STORE *get_cached_x509_store(struct Curl_cfilter *cf, X509_STORE *store = NULL;
DEBUGASSERT(multi);
- share = multi? Curl_hash_pick(&multi->proto_hash,
- (void *)MPROTO_OSSL_X509_KEY,
- sizeof(MPROTO_OSSL_X509_KEY)-1) : NULL;
+ share = multi ? Curl_hash_pick(&multi->proto_hash,
+ (void *)MPROTO_OSSL_X509_KEY,
+ sizeof(MPROTO_OSSL_X509_KEY)-1) : NULL;
if(share && share->store &&
!cached_x509_store_expired(data, share) &&
!cached_x509_store_different(cf, share)) {
@@ -3804,10 +3797,10 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx, return result;
octx->x509_store_setup = TRUE;
}
- Curl_set_in_callback(data, true);
+ Curl_set_in_callback(data, TRUE);
result = (*data->set.ssl.fsslctx)(data, octx->ssl_ctx,
data->set.ssl.fsslctxp);
- Curl_set_in_callback(data, false);
+ Curl_set_in_callback(data, FALSE);
if(result) {
failf(data, "error signaled by ssl ctx callback");
return result;
@@ -3979,10 +3972,10 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx, #endif
octx->reused_session = FALSE;
- if(ssl_config->primary.cache_session && transport == TRNSPRT_TCP) {
+ if(ssl_config->primary.cache_session) {
Curl_ssl_sessionid_lock(data);
if(!Curl_ssl_getsessionid(cf, data, peer, (void **)&der_sessionid,
- &der_sessionid_size)) {
+ &der_sessionid_size, NULL)) {
/* we got a session id, use it! */
ssl_session = d2i_SSL_SESSION(NULL, &der_sessionid,
(long)der_sessionid_size);
@@ -4001,8 +3994,8 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx, octx->reused_session = TRUE;
}
else {
- Curl_ssl_sessionid_unlock(data);
- return CURLE_SSL_CONNECT_ERROR;
+ Curl_ssl_sessionid_unlock(data);
+ return CURLE_SSL_CONNECT_ERROR;
}
}
Curl_ssl_sessionid_unlock(data);
@@ -4231,10 +4224,10 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf, "SSL certificate problem: %s",
X509_verify_cert_error_string(lerr));
}
- else
- /* strcpy() is fine here as long as the string fits within
- error_buffer */
- strcpy(error_buffer, "SSL certificate verification failed");
+ else {
+ failf(data, "%s", "SSL certificate verification failed");
+ return result;
+ }
}
#if defined(SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED)
/* SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED is only available on
@@ -4244,7 +4237,8 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf, /* If client certificate is required, communicate the
error to client */
result = CURLE_SSL_CLIENTCERT;
- ossl_strerror(errdetail, error_buffer, sizeof(error_buffer));
+ failf(data, "TLS cert problem: %s",
+ ossl_strerror(errdetail, error_buffer, sizeof(error_buffer)));
}
#endif
#ifdef USE_ECH
@@ -4259,12 +4253,14 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf, ossl_trace_ech_retry_configs(data, octx->ssl, reason);
result = CURLE_ECH_REQUIRED;
- ossl_strerror(errdetail, error_buffer, sizeof(error_buffer));
+ failf(data, "ECH required: %s",
+ ossl_strerror(errdetail, error_buffer, sizeof(error_buffer)));
}
#endif
else {
result = CURLE_SSL_CONNECT_ERROR;
- ossl_strerror(errdetail, error_buffer, sizeof(error_buffer));
+ failf(data, "TLS connect error: %s",
+ ossl_strerror(errdetail, error_buffer, sizeof(error_buffer)));
}
/* detail is already set to the SSL error above */
@@ -4285,9 +4281,6 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf, return result;
}
- /* Could be a CERT problem */
- failf(data, "%s", error_buffer);
-
return result;
}
}
@@ -4312,7 +4305,7 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf, infof(data, "SSL connection using %s / %s / %s / %s",
SSL_get_version(octx->ssl),
SSL_get_cipher(octx->ssl),
- negotiated_group_name? negotiated_group_name : "[blank]",
+ negotiated_group_name ? negotiated_group_name : "[blank]",
OBJ_nid2sn(psigtype_nid));
#ifdef USE_ECH
@@ -4356,9 +4349,9 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf, infof(data, "ECH: unexpected status %d",rv);
}
infof(data, "ECH: result: status is %s, inner is %s, outer is %s",
- (status?status:"NULL"),
- (inner?inner:"NULL"),
- (outer?outer:"NULL"));
+ (status ? status : "NULL"),
+ (inner ? inner : "NULL"),
+ (outer ? outer : "NULL"));
OPENSSL_free(inner);
OPENSSL_free(outer);
if(rv == SSL_ECH_STATUS_GREASE_ECH) {
@@ -4386,7 +4379,7 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf, unsigned int len;
SSL_get0_alpn_selected(octx->ssl, &neg_protocol, &len);
- return Curl_alpn_set_negotiated(cf, data, neg_protocol, len);
+ return Curl_alpn_set_negotiated(cf, data, connssl, neg_protocol, len);
}
#endif
@@ -4521,6 +4514,8 @@ static void infof_certstack(struct Curl_easy *data, const SSL *ssl) #define infof_certstack(data, ssl)
#endif
+#define MAX_CERT_NAME_LENGTH 2048
+
CURLcode Curl_oss_check_peer_cert(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct ossl_ctx *octx,
@@ -4530,18 +4525,19 @@ CURLcode Curl_oss_check_peer_cert(struct Curl_cfilter *cf, struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
CURLcode result = CURLE_OK;
- int rc;
long lerr;
X509 *issuer;
BIO *fp = NULL;
char error_buffer[256]="";
- char buffer[2048];
const char *ptr;
BIO *mem = BIO_new(BIO_s_mem());
bool strict = (conn_config->verifypeer || conn_config->verifyhost);
+ struct dynbuf dname;
DEBUGASSERT(octx);
+ Curl_dyn_init(&dname, MAX_CERT_NAME_LENGTH);
+
if(!mem) {
failf(data,
"BIO_new return NULL, " OSSL_PACKAGE
@@ -4566,11 +4562,11 @@ CURLcode Curl_oss_check_peer_cert(struct Curl_cfilter *cf, }
infof(data, "%s certificate:",
- Curl_ssl_cf_is_proxy(cf)? "Proxy" : "Server");
+ Curl_ssl_cf_is_proxy(cf) ? "Proxy" : "Server");
- rc = x509_name_oneline(X509_get_subject_name(octx->server_cert),
- buffer, sizeof(buffer));
- infof(data, " subject: %s", rc?"[NONE]":buffer);
+ result = x509_name_oneline(X509_get_subject_name(octx->server_cert),
+ &dname);
+ infof(data, " subject: %s", result ? "[NONE]" : Curl_dyn_ptr(&dname));
#ifndef CURL_DISABLE_VERBOSE_STRINGS
{
@@ -4594,19 +4590,21 @@ CURLcode Curl_oss_check_peer_cert(struct Curl_cfilter *cf, if(result) {
X509_free(octx->server_cert);
octx->server_cert = NULL;
+ Curl_dyn_free(&dname);
return result;
}
}
- rc = x509_name_oneline(X509_get_issuer_name(octx->server_cert),
- buffer, sizeof(buffer));
- if(rc) {
+ result = x509_name_oneline(X509_get_issuer_name(octx->server_cert),
+ &dname);
+ if(result) {
if(strict)
failf(data, "SSL: could not get X509-issuer name");
result = CURLE_PEER_FAILED_VERIFICATION;
}
else {
- infof(data, " issuer: %s", buffer);
+ infof(data, " issuer: %s", Curl_dyn_ptr(&dname));
+ Curl_dyn_free(&dname);
/* We could do all sorts of certificate verification stuff here before
deallocating the certificate. */
@@ -4699,7 +4697,6 @@ CURLcode Curl_oss_check_peer_cert(struct Curl_cfilter *cf, else
infof(data, " SSL certificate verify ok.");
}
-
infof_certstack(data, octx->ssl);
#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
@@ -4715,7 +4712,7 @@ CURLcode Curl_oss_check_peer_cert(struct Curl_cfilter *cf, bool incache;
Curl_ssl_sessionid_lock(data);
incache = !(Curl_ssl_getsessionid(cf, data, peer,
- &old_ssl_sessionid, NULL));
+ &old_ssl_sessionid, NULL, NULL));
if(incache) {
infof(data, "Remove session ID again from cache");
Curl_ssl_delsessionid(data, old_ssl_sessionid);
@@ -4735,8 +4732,8 @@ CURLcode Curl_oss_check_peer_cert(struct Curl_cfilter *cf, result = CURLE_OK;
#ifndef CURL_DISABLE_PROXY
- ptr = Curl_ssl_cf_is_proxy(cf)?
- data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]:
+ ptr = Curl_ssl_cf_is_proxy(cf) ?
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
data->set.str[STRING_SSL_PINNEDPUBLICKEY];
#else
ptr = data->set.str[STRING_SSL_PINNEDPUBLICKEY];
@@ -4822,11 +4819,10 @@ static CURLcode ossl_connect_common(struct Curl_cfilter *cf, /* if ssl is expecting something, check if it is available. */
if(!nonblocking && connssl->io_need) {
-
- curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND)?
- sockfd:CURL_SOCKET_BAD;
- curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV)?
- sockfd:CURL_SOCKET_BAD;
+ curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND) ?
+ sockfd : CURL_SOCKET_BAD;
+ curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV) ?
+ sockfd : CURL_SOCKET_BAD;
what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
timeout_ms);
@@ -5136,9 +5132,8 @@ static CURLcode ossl_get_channel_binding(struct Curl_easy *data, int sockindex, } while(cf->next);
if(!octx) {
- failf(data,
- "Failed to find SSL backend for endpoint");
- return CURLE_SSL_ENGINE_INITFAILED;
+ failf(data, "Failed to find the SSL filter");
+ return CURLE_BAD_FUNCTION_ARGUMENT;
}
cert = SSL_get1_peer_certificate(octx->ssl);
@@ -5209,9 +5204,9 @@ static size_t ossl_version(char *buffer, size_t size) #else
return msnprintf(buffer, size, "%s/%lx.%lx.%lx",
OSSL_PACKAGE,
- (LIBRESSL_VERSION_NUMBER>>28)&0xf,
- (LIBRESSL_VERSION_NUMBER>>20)&0xff,
- (LIBRESSL_VERSION_NUMBER>>12)&0xff);
+ (LIBRESSL_VERSION_NUMBER >> 28) & 0xf,
+ (LIBRESSL_VERSION_NUMBER >> 20) & 0xff,
+ (LIBRESSL_VERSION_NUMBER >> 12) & 0xff);
#endif
#elif defined(OPENSSL_IS_BORINGSSL)
#ifdef CURL_BORINGSSL_VERSION
@@ -5262,9 +5257,9 @@ static size_t ossl_version(char *buffer, size_t size) #endif
,
OSSL_PACKAGE,
- (ssleay_value>>28)&0xf,
- (ssleay_value>>20)&0xff,
- (ssleay_value>>12)&0xff,
+ (ssleay_value >> 28) & 0xf,
+ (ssleay_value >> 20) & 0xff,
+ (ssleay_value >> 12) & 0xff,
sub);
#endif /* OPENSSL_IS_BORINGSSL */
}
diff --git a/libs/libcurl/src/vtls/rustls.c b/libs/libcurl/src/vtls/rustls.c index 18284eeffd..b10328d4aa 100644 --- a/libs/libcurl/src/vtls/rustls.c +++ b/libs/libcurl/src/vtls/rustls.c @@ -37,6 +37,7 @@ #include "sendf.h"
#include "vtls.h"
#include "vtls_int.h"
+#include "rustls.h"
#include "select.h"
#include "strerror.h"
#include "multiif.h"
@@ -570,7 +571,7 @@ cr_init_backend(struct Curl_cfilter *cf, struct Curl_easy *data, break;
default:
failf(data, "rustls: unsupported minimum TLS version value");
- return CURLE_SSL_ENGINE_INITFAILED;
+ return CURLE_BAD_FUNCTION_ARGUMENT;
}
switch(conn_config->version_max) {
@@ -588,7 +589,7 @@ cr_init_backend(struct Curl_cfilter *cf, struct Curl_easy *data, case CURL_SSLVERSION_MAX_TLSv1_0:
default:
failf(data, "rustls: unsupported maximum TLS version value");
- return CURLE_SSL_ENGINE_INITFAILED;
+ return CURLE_BAD_FUNCTION_ARGUMENT;
}
cipher_suites = malloc(sizeof(cipher_suites) * (cipher_suites_len));
@@ -610,7 +611,7 @@ cr_init_backend(struct Curl_cfilter *cf, struct Curl_easy *data, if(result != RUSTLS_RESULT_OK) {
failf(data,
"rustls: failed to create crypto provider builder from default");
- return CURLE_SSL_ENGINE_INITFAILED;
+ return CURLE_SSL_CIPHER;
}
result =
@@ -622,7 +623,7 @@ cr_init_backend(struct Curl_cfilter *cf, struct Curl_easy *data, failf(data,
"rustls: failed to set ciphersuites for crypto provider builder");
rustls_crypto_provider_builder_free(custom_provider_builder);
- return CURLE_SSL_ENGINE_INITFAILED;
+ return CURLE_SSL_CIPHER;
}
result = rustls_crypto_provider_builder_build(
@@ -630,7 +631,7 @@ cr_init_backend(struct Curl_cfilter *cf, struct Curl_easy *data, if(result != RUSTLS_RESULT_OK) {
failf(data, "rustls: failed to build custom crypto provider");
rustls_crypto_provider_builder_free(custom_provider_builder);
- return CURLE_SSL_ENGINE_INITFAILED;
+ return CURLE_SSL_CIPHER;
}
result = rustls_client_config_builder_new_custom(custom_provider,
@@ -640,7 +641,7 @@ cr_init_backend(struct Curl_cfilter *cf, struct Curl_easy *data, free(cipher_suites);
if(result != RUSTLS_RESULT_OK) {
failf(data, "rustls: failed to create client config");
- return CURLE_SSL_ENGINE_INITFAILED;
+ return CURLE_SSL_CIPHER;
}
}
@@ -747,7 +748,7 @@ cr_init_backend(struct Curl_cfilter *cf, struct Curl_easy *data, if(result != RUSTLS_RESULT_OK) {
failf(data, "rustls: failed to build client config");
rustls_client_config_free(backend->config);
- return CURLE_SSL_ENGINE_INITFAILED;
+ return CURLE_SSL_CONNECT_ERROR;
}
DEBUGASSERT(rconn == NULL);
@@ -768,11 +769,12 @@ static void cr_set_negotiated_alpn(struct Curl_cfilter *cf, struct Curl_easy *data,
const struct rustls_connection *rconn)
{
+ struct ssl_connect_data *const connssl = cf->ctx;
const uint8_t *protocol = NULL;
size_t len = 0;
rustls_connection_get_alpn_protocol(rconn, &protocol, &len);
- Curl_alpn_set_negotiated(cf, data, protocol, len);
+ Curl_alpn_set_negotiated(cf, data, connssl, protocol, len);
}
/* Given an established network connection, do a TLS handshake.
@@ -852,7 +854,7 @@ cr_connect_common(struct Curl_cfilter *cf, ver = "TLSv1.3";
if(proto == RUSTLS_TLS_VERSION_TLSV1_2)
ver = "TLSv1.2";
- Curl_cipher_suite_get_str(cipher, buf, sizeof(buf), true);
+ Curl_cipher_suite_get_str(cipher, buf, sizeof(buf), TRUE);
infof(data, "rustls: handshake complete, %s, cipher: %s",
ver, buf);
}
@@ -866,8 +868,8 @@ cr_connect_common(struct Curl_cfilter *cf, wants_write = rustls_connection_wants_write(rconn) ||
backend->plain_out_buffered;
DEBUGASSERT(wants_read || wants_write);
- writefd = wants_write?sockfd:CURL_SOCKET_BAD;
- readfd = wants_read?sockfd:CURL_SOCKET_BAD;
+ writefd = wants_write ? sockfd : CURL_SOCKET_BAD;
+ readfd = wants_read ? sockfd : CURL_SOCKET_BAD;
/* check allowed time left */
timeout_ms = Curl_timeleft(data, NULL, TRUE);
@@ -878,7 +880,7 @@ cr_connect_common(struct Curl_cfilter *cf, return CURLE_OPERATION_TIMEDOUT;
}
- socket_check_timeout = blocking?timeout_ms:0;
+ socket_check_timeout = blocking ? timeout_ms : 0;
what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
socket_check_timeout);
@@ -894,7 +896,7 @@ cr_connect_common(struct Curl_cfilter *cf, }
if(0 == what) {
CURL_TRC_CF(data, cf, "Curl_socket_check: %s would block",
- wants_read&&wants_write ? "writing and reading" :
+ wants_read && wants_write ? "writing and reading" :
wants_write ? "writing" : "reading");
if(wants_write)
connssl->io_need |= CURL_SSL_IO_NEED_SEND;
@@ -935,7 +937,7 @@ cr_connect_common(struct Curl_cfilter *cf, /* We should never fall through the loop. We should return either because
the handshake is done or because we cannot read/write without blocking. */
- DEBUGASSERT(false);
+ DEBUGASSERT(FALSE);
}
static CURLcode
diff --git a/libs/libcurl/src/vtls/schannel.c b/libs/libcurl/src/vtls/schannel.c index d785ea2c60..85d018d322 100644 --- a/libs/libcurl/src/vtls/schannel.c +++ b/libs/libcurl/src/vtls/schannel.c @@ -59,6 +59,17 @@ #include "curl_memory.h"
#include "memdebug.h"
+/* Some verbose debug messages are wrapped by SCH_DEV() instead of DEBUGF()
+ * and only shown if CURL_SCHANNEL_DEV_DEBUG was defined at build time. These
+ * messages are extra verbose and intended for curl developers debugging
+ * Schannel recv decryption.
+ */
+#ifdef CURL_SCHANNEL_DEV_DEBUG
+#define SCH_DEV(x) x
+#else
+#define SCH_DEV(x) do { } while(0)
+#endif
+
/* ALPN requires version 8.1 of the Windows SDK, which was
shipped with Visual Studio 2013, aka _MSC_VER 1800:
@@ -1090,14 +1101,14 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) curlx_verify_windows_version(6, 3, 0, PLATFORM_WINNT,
VERSION_GREATER_THAN_EQUAL);
#else
- backend->use_alpn = false;
+ backend->use_alpn = FALSE;
#endif
#ifdef _WIN32_WCE
#ifdef HAS_MANUAL_VERIFY_API
/* certificate validation on CE does not seem to work right; we will
* do it following a more manual process. */
- backend->use_manual_cred_validation = true;
+ backend->use_manual_cred_validation = TRUE;
#else
#error "compiler too old to support Windows CE requisite manual cert verify"
#endif
@@ -1106,7 +1117,7 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) if(conn_config->CAfile || conn_config->ca_info_blob) {
if(curlx_verify_windows_version(6, 1, 0, PLATFORM_WINNT,
VERSION_GREATER_THAN_EQUAL)) {
- backend->use_manual_cred_validation = true;
+ backend->use_manual_cred_validation = TRUE;
}
else {
failf(data, "schannel: this version of Windows is too old to support "
@@ -1115,7 +1126,7 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) }
}
else
- backend->use_manual_cred_validation = false;
+ backend->use_manual_cred_validation = FALSE;
#else
if(conn_config->CAfile || conn_config->ca_info_blob) {
failf(data, "schannel: CA cert support not built in");
@@ -1130,7 +1141,7 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) if(ssl_config->primary.cache_session) {
Curl_ssl_sessionid_lock(data);
if(!Curl_ssl_getsessionid(cf, data, &connssl->peer,
- (void **)&old_cred, NULL)) {
+ (void **)&old_cred, NULL, NULL)) {
backend->cred = old_cred;
DEBUGF(infof(data, "schannel: reusing existing credential handle"));
@@ -1153,7 +1164,7 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) /* A hostname associated with the credential is needed by
InitializeSecurityContext for SNI and other reasons. */
- snihost = connssl->peer.sni? connssl->peer.sni : connssl->peer.hostname;
+ snihost = connssl->peer.sni ? connssl->peer.sni : connssl->peer.hostname;
backend->cred->sni_hostname = curlx_convert_UTF8_to_tchar(snihost);
if(!backend->cred->sni_hostname)
return CURLE_OUT_OF_MEMORY;
@@ -1300,10 +1311,10 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) "sent %zd bytes", written));
backend->recv_unrecoverable_err = CURLE_OK;
- backend->recv_sspi_close_notify = false;
- backend->recv_connection_closed = false;
- backend->recv_renegotiating = false;
- backend->encdata_is_incomplete = false;
+ backend->recv_sspi_close_notify = FALSE;
+ backend->recv_connection_closed = FALSE;
+ backend->recv_renegotiating = FALSE;
+ backend->encdata_is_incomplete = FALSE;
/* continue to second handshake step */
connssl->connecting_state = ssl_connect_2;
@@ -1332,7 +1343,7 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) DEBUGASSERT(backend);
- doread = (connssl->io_need & CURL_SSL_IO_NEED_SEND)? FALSE : TRUE;
+ doread = (connssl->io_need & CURL_SSL_IO_NEED_SEND) ? FALSE : TRUE;
connssl->io_need = CURL_SSL_IO_NEED_NONE;
DEBUGF(infof(data,
@@ -1355,7 +1366,7 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) /* buffer to store previously received and encrypted data */
if(!backend->encdata_buffer) {
- backend->encdata_is_incomplete = false;
+ backend->encdata_is_incomplete = FALSE;
backend->encdata_offset = 0;
backend->encdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
backend->encdata_buffer = malloc(backend->encdata_length);
@@ -1407,13 +1418,13 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) /* increase encrypted data buffer offset */
backend->encdata_offset += nread;
- backend->encdata_is_incomplete = false;
- DEBUGF(infof(data, "schannel: encrypted data got %zd", nread));
+ backend->encdata_is_incomplete = FALSE;
+ SCH_DEV(infof(data, "schannel: encrypted data got %zd", nread));
}
- DEBUGF(infof(data,
- "schannel: encrypted data buffer: offset %zu length %zu",
- backend->encdata_offset, backend->encdata_length));
+ SCH_DEV(infof(data,
+ "schannel: encrypted data buffer: offset %zu length %zu",
+ backend->encdata_offset, backend->encdata_length));
/* setup input buffers */
InitSecBuffer(&inbuf[0], SECBUFFER_TOKEN, malloc(backend->encdata_offset),
@@ -1447,7 +1458,7 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) /* check if the handshake was incomplete */
if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
- backend->encdata_is_incomplete = true;
+ backend->encdata_is_incomplete = TRUE;
connssl->io_need = CURL_SSL_IO_NEED_RECV;
DEBUGF(infof(data,
"schannel: received incomplete message, need more data"));
@@ -1527,8 +1538,8 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) /* check if there was additional remaining encrypted data */
if(inbuf[1].BufferType == SECBUFFER_EXTRA && inbuf[1].cbBuffer > 0) {
- DEBUGF(infof(data, "schannel: encrypted data length: %lu",
- inbuf[1].cbBuffer));
+ SCH_DEV(infof(data, "schannel: encrypted data length: %lu",
+ inbuf[1].cbBuffer));
/*
There are two cases where we could be getting extra data here:
1) If we are renegotiating a connection and the handshake is already
@@ -1571,8 +1582,8 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) }
#ifndef CURL_DISABLE_PROXY
- pubkey_ptr = Curl_ssl_cf_is_proxy(cf)?
- data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]:
+ pubkey_ptr = Curl_ssl_cf_is_proxy(cf) ?
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
data->set.str[STRING_SSL_PINNEDPUBLICKEY];
#else
pubkey_ptr = data->set.str[STRING_SSL_PINNEDPUBLICKEY];
@@ -1617,9 +1628,9 @@ traverse_cert_store(const CERT_CONTEXT *context, Read_crt_func func, void *arg)
{
const CERT_CONTEXT *current_context = NULL;
- bool should_continue = true;
- bool first = true;
- bool reverse_order = false;
+ bool should_continue = TRUE;
+ bool first = TRUE;
+ bool reverse_order = FALSE;
while(should_continue &&
(current_context = CertEnumCertificatesInStore(
context->hCertStore,
@@ -1630,9 +1641,9 @@ traverse_cert_store(const CERT_CONTEXT *context, Read_crt_func func, 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;
+ reverse_order = TRUE;
should_continue = func(current_context, reverse_order, arg);
- first = false;
+ first = FALSE;
}
if(current_context)
@@ -1646,7 +1657,7 @@ cert_counter_callback(const CERT_CONTEXT *ccert_context, bool reverse_order, (void)reverse_order; /* unused */
if(valid_cert_encoding(ccert_context))
(*(int *)certs_count)++;
- return true;
+ return TRUE;
}
struct Adder_args
@@ -1752,7 +1763,7 @@ schannel_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data) SecApplicationProtocolNegotiationStatus_Success) {
unsigned char prev_alpn = cf->conn->alpn;
- Curl_alpn_set_negotiated(cf, data, alpn_result.ProtocolId,
+ Curl_alpn_set_negotiated(cf, data, connssl, alpn_result.ProtocolId,
alpn_result.ProtocolIdSize);
if(backend->recv_renegotiating) {
if(prev_alpn != cf->conn->alpn &&
@@ -1766,7 +1777,7 @@ schannel_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data) }
else {
if(!backend->recv_renegotiating)
- Curl_alpn_set_negotiated(cf, data, NULL, 0);
+ Curl_alpn_set_negotiated(cf, data, connssl, NULL, 0);
}
}
#endif
@@ -1776,7 +1787,8 @@ schannel_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data) Curl_ssl_sessionid_lock(data);
/* Up ref count since call takes ownership */
backend->cred->refcount++;
- result = Curl_ssl_set_sessionid(cf, data, &connssl->peer, backend->cred,
+ result = Curl_ssl_set_sessionid(cf, data, &connssl->peer, NULL,
+ backend->cred,
sizeof(struct Curl_schannel_cred),
schannel_session_free);
Curl_ssl_sessionid_unlock(data);
@@ -1863,10 +1875,10 @@ schannel_connect_common(struct Curl_cfilter *cf, /* if ssl is expecting something, check if it is available. */
if(connssl->io_need) {
- curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND)?
- sockfd : CURL_SOCKET_BAD;
- curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV)?
- sockfd : CURL_SOCKET_BAD;
+ curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND) ?
+ sockfd : CURL_SOCKET_BAD;
+ curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV) ?
+ sockfd : CURL_SOCKET_BAD;
what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
nonblocking ? 0 : timeout_ms);
@@ -2109,17 +2121,23 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data, * cleanup. The pattern for return error is set *err, optional infof, goto
* cleanup.
*
+ * Some verbose debug messages are wrapped by SCH_DEV() instead of DEBUGF()
+ * and only shown if CURL_SCHANNEL_DEV_DEBUG was defined at build time. These
+ * messages are extra verbose and intended for curl developers debugging
+ * Schannel recv decryption.
+ *
* Our priority is to always return as much decrypted data to the caller as
* possible, even if an error occurs. The state of the decrypted buffer must
* always be valid. Transfer of decrypted data to the caller's buffer is
* handled in the cleanup.
*/
- DEBUGF(infof(data, "schannel: client wants to read %zu bytes", len));
+ SCH_DEV(infof(data, "schannel: client wants to read %zu bytes", len));
*err = CURLE_OK;
if(len && len <= backend->decdata_offset) {
- infof(data, "schannel: enough decrypted data is already available");
+ SCH_DEV(infof(data,
+ "schannel: enough decrypted data is already available"));
goto cleanup;
}
else if(backend->recv_unrecoverable_err) {
@@ -2157,13 +2175,13 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data, backend->encdata_buffer = reallocated_buffer;
backend->encdata_length = reallocated_length;
size = backend->encdata_length - backend->encdata_offset;
- DEBUGF(infof(data, "schannel: encdata_buffer resized %zu",
- backend->encdata_length));
+ SCH_DEV(infof(data, "schannel: encdata_buffer resized %zu",
+ backend->encdata_length));
}
- DEBUGF(infof(data,
- "schannel: encrypted data buffer: offset %zu length %zu",
- backend->encdata_offset, backend->encdata_length));
+ SCH_DEV(infof(data,
+ "schannel: encrypted data buffer: offset %zu length %zu",
+ backend->encdata_offset, backend->encdata_length));
/* read encrypted data from socket */
nread = Curl_conn_cf_recv(cf->next, data,
@@ -2173,27 +2191,25 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data, if(*err) {
nread = -1;
if(*err == CURLE_AGAIN)
- DEBUGF(infof(data,
- "schannel: recv returned CURLE_AGAIN"));
+ SCH_DEV(infof(data, "schannel: recv returned CURLE_AGAIN"));
else if(*err == CURLE_RECV_ERROR)
infof(data, "schannel: recv returned CURLE_RECV_ERROR");
else
infof(data, "schannel: recv returned error %d", *err);
}
else if(nread == 0) {
- backend->recv_connection_closed = true;
+ backend->recv_connection_closed = TRUE;
DEBUGF(infof(data, "schannel: server closed the connection"));
}
else if(nread > 0) {
backend->encdata_offset += (size_t)nread;
- backend->encdata_is_incomplete = false;
- DEBUGF(infof(data, "schannel: encrypted data got %zd", nread));
+ backend->encdata_is_incomplete = FALSE;
+ SCH_DEV(infof(data, "schannel: encrypted data got %zd", nread));
}
}
- DEBUGF(infof(data,
- "schannel: encrypted data buffer: offset %zu length %zu",
- backend->encdata_offset, backend->encdata_length));
+ SCH_DEV(infof(data, "schannel: encrypted data buffer: offset %zu length %zu",
+ backend->encdata_offset, backend->encdata_length));
/* decrypt loop */
while(backend->encdata_offset > 0 && sspi_status == SEC_E_OK &&
@@ -2221,8 +2237,8 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data, /* check for successfully decrypted data, even before actual
renegotiation or shutdown of the connection context */
if(inbuf[1].BufferType == SECBUFFER_DATA) {
- DEBUGF(infof(data, "schannel: decrypted data length: %lu",
- inbuf[1].cbBuffer));
+ SCH_DEV(infof(data, "schannel: decrypted data length: %lu",
+ inbuf[1].cbBuffer));
/* increase buffer in order to fit the received amount of data */
size = inbuf[1].cbBuffer > CURL_SCHANNEL_BUFFER_FREE_SIZE ?
@@ -2254,16 +2270,16 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data, backend->decdata_offset += size;
}
- DEBUGF(infof(data, "schannel: decrypted data added: %zu", size));
- DEBUGF(infof(data,
- "schannel: decrypted cached: offset %zu length %zu",
- backend->decdata_offset, backend->decdata_length));
+ SCH_DEV(infof(data, "schannel: decrypted data added: %zu", size));
+ SCH_DEV(infof(data,
+ "schannel: decrypted cached: offset %zu length %zu",
+ backend->decdata_offset, backend->decdata_length));
}
/* check for remaining encrypted data */
if(inbuf[3].BufferType == SECBUFFER_EXTRA && inbuf[3].cbBuffer > 0) {
- DEBUGF(infof(data, "schannel: encrypted data length: %lu",
- inbuf[3].cbBuffer));
+ SCH_DEV(infof(data, "schannel: encrypted data length: %lu",
+ inbuf[3].cbBuffer));
/* check if the remaining data is less than the total amount
* and therefore begins after the already processed data
@@ -2277,9 +2293,9 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data, backend->encdata_offset = inbuf[3].cbBuffer;
}
- DEBUGF(infof(data,
- "schannel: encrypted cached: offset %zu length %zu",
- backend->encdata_offset, backend->encdata_length));
+ SCH_DEV(infof(data,
+ "schannel: encrypted cached: offset %zu length %zu",
+ backend->encdata_offset, backend->encdata_length));
}
else {
/* reset encrypted buffer offset, because there is no data remaining */
@@ -2299,9 +2315,9 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data, connssl->state = ssl_connection_negotiating;
connssl->connecting_state = ssl_connect_2;
connssl->io_need = CURL_SSL_IO_NEED_SEND;
- backend->recv_renegotiating = true;
+ backend->recv_renegotiating = TRUE;
*err = schannel_connect_common(cf, data, FALSE, &done);
- backend->recv_renegotiating = false;
+ backend->recv_renegotiating = FALSE;
if(*err) {
infof(data, "schannel: renegotiation failed");
goto cleanup;
@@ -2315,25 +2331,30 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data, else if(sspi_status == SEC_I_CONTEXT_EXPIRED) {
/* In Windows 2000 SEC_I_CONTEXT_EXPIRED (close_notify) is not
returned so we have to work around that in cleanup. */
- backend->recv_sspi_close_notify = true;
+ backend->recv_sspi_close_notify = TRUE;
if(!backend->recv_connection_closed)
- backend->recv_connection_closed = true;
+ backend->recv_connection_closed = TRUE;
+ /* We received the close notify just fine, any error we got
+ * from the lower filters afterwards (e.g. the socket), is not
+ * an error on the TLS data stream. That one ended here. */
+ if(*err == CURLE_RECV_ERROR)
+ *err = CURLE_OK;
infof(data,
"schannel: server close notification received (close_notify)");
goto cleanup;
}
}
else if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
- backend->encdata_is_incomplete = true;
+ backend->encdata_is_incomplete = TRUE;
if(!*err)
*err = CURLE_AGAIN;
- infof(data, "schannel: failed to decrypt data, need more data");
+ SCH_DEV(infof(data, "schannel: failed to decrypt data, need more data"));
goto cleanup;
}
else {
#ifndef CURL_DISABLE_VERBOSE_STRINGS
char buffer[STRERROR_LEN];
- infof(data, "schannel: failed to read data from server: %s",
+ failf(data, "schannel: failed to read data from server: %s",
Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
#endif
*err = CURLE_RECV_ERROR;
@@ -2341,17 +2362,15 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data, }
}
- DEBUGF(infof(data,
- "schannel: encrypted data buffer: offset %zu length %zu",
- backend->encdata_offset, backend->encdata_length));
+ SCH_DEV(infof(data, "schannel: encrypted data buffer: offset %zu length %zu",
+ backend->encdata_offset, backend->encdata_length));
- DEBUGF(infof(data,
- "schannel: decrypted data buffer: offset %zu length %zu",
- backend->decdata_offset, backend->decdata_length));
+ SCH_DEV(infof(data, "schannel: decrypted data buffer: offset %zu length %zu",
+ backend->decdata_offset, backend->decdata_length));
cleanup:
/* Warning- there is no guarantee the encdata state is valid at this point */
- DEBUGF(infof(data, "schannel: schannel_recv cleanup"));
+ SCH_DEV(infof(data, "schannel: schannel_recv cleanup"));
/* Error if the connection has closed without a close_notify.
@@ -2370,10 +2389,10 @@ cleanup: VERSION_EQUAL);
if(isWin2k && sspi_status == SEC_E_OK)
- backend->recv_sspi_close_notify = true;
+ backend->recv_sspi_close_notify = TRUE;
else {
*err = CURLE_RECV_ERROR;
- infof(data, "schannel: server closed abruptly (missing close_notify)");
+ failf(data, "schannel: server closed abruptly (missing close_notify)");
}
}
@@ -2387,10 +2406,10 @@ cleanup: memmove(backend->decdata_buffer, backend->decdata_buffer + size,
backend->decdata_offset - size);
backend->decdata_offset -= size;
- DEBUGF(infof(data, "schannel: decrypted data returned %zu", size));
- DEBUGF(infof(data,
- "schannel: decrypted data buffer: offset %zu length %zu",
- backend->decdata_offset, backend->decdata_length));
+ SCH_DEV(infof(data, "schannel: decrypted data returned %zu", size));
+ SCH_DEV(infof(data,
+ "schannel: decrypted data buffer: offset %zu length %zu",
+ backend->decdata_offset, backend->decdata_length));
*err = CURLE_OK;
return (ssize_t)size;
}
@@ -2536,7 +2555,7 @@ static CURLcode schannel_shutdown(struct Curl_cfilter *cf, if(!result) {
if(written < (ssize_t)outbuf.cbBuffer) {
/* TODO: handle partial sends */
- infof(data, "schannel: failed to send close msg: %s"
+ failf(data, "schannel: failed to send close msg: %s"
" (bytes written: %zd)", curl_easy_strerror(result), written);
result = CURLE_SEND_ERROR;
goto out;
@@ -2551,7 +2570,7 @@ static CURLcode schannel_shutdown(struct Curl_cfilter *cf, }
else {
if(!backend->recv_connection_closed) {
- infof(data, "schannel: error sending close msg: %d", result);
+ failf(data, "schannel: error sending close msg: %d", result);
result = CURLE_SEND_ERROR;
goto out;
}
@@ -2622,7 +2641,7 @@ static void schannel_close(struct Curl_cfilter *cf, struct Curl_easy *data) Curl_safefree(backend->encdata_buffer);
backend->encdata_length = 0;
backend->encdata_offset = 0;
- backend->encdata_is_incomplete = false;
+ backend->encdata_is_incomplete = FALSE;
}
/* free internal buffer for received decrypted data */
@@ -2732,7 +2751,7 @@ static void schannel_checksum(const unsigned char *input, DWORD provType,
const unsigned int algId)
{
-#ifdef CURL_WINDOWS_APP
+#ifdef CURL_WINDOWS_UWP
(void)input;
(void)inputlen;
(void)provType;
@@ -2896,7 +2915,7 @@ bool Curl_schannel_set_cached_cert_store(struct Curl_cfilter *cf, DEBUGASSERT(multi);
if(!multi) {
- return false;
+ return FALSE;
}
share = Curl_hash_pick(&multi->proto_hash,
@@ -2905,14 +2924,14 @@ bool Curl_schannel_set_cached_cert_store(struct Curl_cfilter *cf, if(!share) {
share = calloc(1, sizeof(*share));
if(!share) {
- return false;
+ return FALSE;
}
if(!Curl_hash_add2(&multi->proto_hash,
(void *)MPROTO_SCHANNEL_CERT_SHARE_KEY,
sizeof(MPROTO_SCHANNEL_CERT_SHARE_KEY)-1,
share, schannel_cert_share_free)) {
free(share);
- return false;
+ return FALSE;
}
}
@@ -2927,7 +2946,7 @@ bool Curl_schannel_set_cached_cert_store(struct Curl_cfilter *cf, if(conn_config->CAfile) {
CAfile = strdup(conn_config->CAfile);
if(!CAfile) {
- return false;
+ return FALSE;
}
}
}
@@ -2942,7 +2961,7 @@ bool Curl_schannel_set_cached_cert_store(struct Curl_cfilter *cf, share->cert_store = cert_store;
share->CAinfo_blob_size = CAinfo_blob_size;
share->CAfile = CAfile;
- return true;
+ return TRUE;
}
const struct Curl_ssl Curl_ssl_schannel = {
@@ -2952,7 +2971,7 @@ const struct Curl_ssl Curl_ssl_schannel = { #ifdef HAS_MANUAL_VERIFY_API
SSLSUPP_CAINFO_BLOB |
#endif
-#ifndef CURL_WINDOWS_APP
+#ifndef CURL_WINDOWS_UWP
SSLSUPP_PINNEDPUBKEY |
#endif
SSLSUPP_TLS13_CIPHERSUITES |
diff --git a/libs/libcurl/src/vtls/schannel_int.h b/libs/libcurl/src/vtls/schannel_int.h index c914ccfc6e..52d6fd5214 100644 --- a/libs/libcurl/src/vtls/schannel_int.h +++ b/libs/libcurl/src/vtls/schannel_int.h @@ -31,7 +31,7 @@ #include "vtls.h"
#if (defined(__MINGW32__) || defined(CERT_CHAIN_REVOCATION_CHECK_CHAIN)) \
- && !defined(CURL_WINDOWS_APP)
+ && !defined(CURL_WINDOWS_UWP)
#define HAS_MANUAL_VERIFY_API
#endif
@@ -176,6 +176,17 @@ struct schannel_cert_share { struct curltime time; /* when the cached store was created */
};
+/*
+* size of the structure: 20 bytes.
+*/
+struct num_ip_data {
+ DWORD size; /* 04 bytes */
+ union {
+ struct in_addr ia; /* 04 bytes */
+ struct in6_addr ia6; /* 16 bytes */
+ } bData;
+};
+
HCERTSTORE Curl_schannel_get_cached_cert_store(struct Curl_cfilter *cf,
const struct Curl_easy *data);
diff --git a/libs/libcurl/src/vtls/schannel_verify.c b/libs/libcurl/src/vtls/schannel_verify.c index afc19baba0..ee960ed2c5 100644 --- a/libs/libcurl/src/vtls/schannel_verify.c +++ b/libs/libcurl/src/vtls/schannel_verify.c @@ -39,6 +39,7 @@ #include "schannel.h"
#include "schannel_int.h"
+#include "inet_pton.h"
#include "vtls.h"
#include "vtls_int.h"
#include "sendf.h"
@@ -54,7 +55,6 @@ #define BACKEND ((struct schannel_ssl_backend_data *)connssl->backend)
-
#ifdef HAS_MANUAL_VERIFY_API
#define MAX_CAFILE_SIZE 1048576 /* 1 MiB */
@@ -116,7 +116,7 @@ static CURLcode add_certs_data_to_store(HCERTSTORE trust_store, const char *current_ca_file_ptr = ca_buffer;
const char *ca_buffer_limit = ca_buffer + ca_buffer_size;
- while(more_certs && (current_ca_file_ptr<ca_buffer_limit)) {
+ while(more_certs && (current_ca_file_ptr < ca_buffer_limit)) {
const char *begin_cert_ptr = c_memmem(current_ca_file_ptr,
ca_buffer_limit-current_ca_file_ptr,
BEGIN_CERT,
@@ -343,29 +343,26 @@ cleanup: static DWORD cert_get_name_string(struct Curl_easy *data,
CERT_CONTEXT *cert_context,
LPTSTR host_names,
- DWORD length)
+ DWORD length,
+ PCERT_ALT_NAME_INFO alt_name_info,
+ BOOL Win8_compat)
{
DWORD actual_length = 0;
-#if defined(CURL_WINDOWS_APP)
+#if defined(CURL_WINDOWS_UWP)
(void)data;
(void)cert_context;
(void)host_names;
(void)length;
+ (void)alt_name_info;
+ (void)Win8_compat;
#else
BOOL compute_content = FALSE;
- CERT_INFO *cert_info = NULL;
- CERT_EXTENSION *extension = NULL;
- CRYPT_DECODE_PARA decode_para = {0, 0, 0};
- CERT_ALT_NAME_INFO *alt_name_info = NULL;
- DWORD alt_name_info_size = 0;
- BOOL ret_val = FALSE;
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)) {
+ if(Win8_compat) {
/* CertGetNameString will provide the 8-bit character string without
* any decoding */
DWORD name_flags =
@@ -378,6 +375,9 @@ static DWORD cert_get_name_string(struct Curl_easy *data, length);
return actual_length;
}
+#else
+ (void)cert_context;
+ (void)Win8_compat;
#endif
compute_content = host_names != NULL && length != 0;
@@ -388,43 +388,6 @@ static DWORD cert_get_name_string(struct Curl_easy *data, *host_names = '\0';
}
- if(!cert_context) {
- failf(data, "schannel: Null certificate context.");
- return actual_length;
- }
-
- cert_info = cert_context->pCertInfo;
- if(!cert_info) {
- failf(data, "schannel: Null certificate info.");
- return actual_length;
- }
-
- extension = CertFindExtension(szOID_SUBJECT_ALT_NAME2,
- cert_info->cExtension,
- cert_info->rgExtension);
- if(!extension) {
- failf(data, "schannel: CertFindExtension() returned no extension.");
- return actual_length;
- }
-
- decode_para.cbSize = sizeof(CRYPT_DECODE_PARA);
-
- ret_val =
- CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
- szOID_SUBJECT_ALT_NAME2,
- extension->Value.pbData,
- extension->Value.cbData,
- CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG,
- &decode_para,
- &alt_name_info,
- &alt_name_info_size);
- if(!ret_val) {
- failf(data,
- "schannel: CryptDecodeObjectEx() returned no alternate name "
- "information.");
- return actual_length;
- }
-
current_pos = host_names;
/* Iterate over the alternate names and populate host_names. */
@@ -467,6 +430,88 @@ static DWORD cert_get_name_string(struct Curl_easy *data, return actual_length;
}
+/*
+* Returns TRUE if the hostname is a numeric IPv4/IPv6 Address,
+* and populates the buffer with IPv4/IPv6 info.
+*/
+
+static bool get_num_host_info(struct num_ip_data *ip_blob,
+ LPCSTR hostname)
+{
+ struct in_addr ia;
+ struct in6_addr ia6;
+ bool result = FALSE;
+
+ int res = Curl_inet_pton(AF_INET, hostname, &ia);
+ if(res) {
+ ip_blob->size = sizeof(struct in_addr);
+ memcpy(&ip_blob->bData.ia, &ia, sizeof(struct in_addr));
+ result = TRUE;
+ }
+ else {
+ res = Curl_inet_pton(AF_INET6, hostname, &ia6);
+ if(res) {
+ ip_blob->size = sizeof(struct in6_addr);
+ memcpy(&ip_blob->bData.ia6, &ia6, sizeof(struct in6_addr));
+ result = TRUE;
+ }
+ }
+ return result;
+}
+
+static bool get_alt_name_info(struct Curl_easy *data,
+ PCCERT_CONTEXT ctx,
+ PCERT_ALT_NAME_INFO *alt_name_info,
+ LPDWORD alt_name_info_size)
+{
+ bool result = FALSE;
+#if defined(CURL_WINDOWS_UWP)
+ (void)data;
+ (void)ctx;
+ (void)alt_name_info;
+ (void)alt_name_info_size;
+#else
+ PCERT_INFO cert_info = NULL;
+ PCERT_EXTENSION extension = NULL;
+ CRYPT_DECODE_PARA decode_para = { sizeof(CRYPT_DECODE_PARA), NULL, NULL };
+
+ if(!ctx) {
+ failf(data, "schannel: Null certificate context.");
+ return result;
+ }
+
+ cert_info = ctx->pCertInfo;
+ if(!cert_info) {
+ failf(data, "schannel: Null certificate info.");
+ return result;
+ }
+
+ extension = CertFindExtension(szOID_SUBJECT_ALT_NAME2,
+ cert_info->cExtension,
+ cert_info->rgExtension);
+ if(!extension) {
+ failf(data, "schannel: CertFindExtension() returned no extension.");
+ return result;
+ }
+
+ if(!CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
+ szOID_SUBJECT_ALT_NAME2,
+ extension->Value.pbData,
+ extension->Value.cbData,
+ CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG,
+ &decode_para,
+ alt_name_info,
+ alt_name_info_size)) {
+ failf(data,
+ "schannel: CryptDecodeObjectEx() returned no alternate name "
+ "information.");
+ return result;
+ }
+ result = TRUE;
+#endif
+ return result;
+}
+
/* Verify the server's hostname */
CURLcode Curl_verify_host(struct Curl_cfilter *cf,
struct Curl_easy *data)
@@ -481,6 +526,12 @@ CURLcode Curl_verify_host(struct Curl_cfilter *cf, size_t hostlen = strlen(conn_hostname);
DWORD len = 0;
DWORD actual_len = 0;
+ PCERT_ALT_NAME_INFO alt_name_info = NULL;
+ DWORD alt_name_info_size = 0;
+ struct num_ip_data ip_blob = { 0 };
+ bool Win8_compat;
+ struct num_ip_data *p = &ip_blob;
+ DWORD i;
sspi_status =
Curl_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
@@ -491,97 +542,123 @@ CURLcode Curl_verify_host(struct Curl_cfilter *cf, 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) {
- failf(data,
- "schannel: CertGetNameString() returned no "
- "certificate name information");
- result = CURLE_PEER_FAILED_VERIFICATION;
- goto cleanup;
+ Win8_compat = curlx_verify_windows_version(6, 2, 0, PLATFORM_WINNT,
+ VERSION_GREATER_THAN_EQUAL);
+ if(get_num_host_info(p, conn_hostname) || !Win8_compat) {
+ if(!get_alt_name_info(data, pCertContextServer,
+ &alt_name_info, &alt_name_info_size)) {
+ goto cleanup;
+ }
}
- /* CertGetNameString guarantees that the returned name will not contain
- * embedded null bytes. This appears to be undocumented behavior.
- */
- cert_hostname_buff = (LPTSTR)malloc(len * sizeof(TCHAR));
- if(!cert_hostname_buff) {
- result = CURLE_OUT_OF_MEMORY;
- goto cleanup;
+ if(p->size) {
+ for(i = 0; i < alt_name_info->cAltEntry; ++i) {
+ PCERT_ALT_NAME_ENTRY entry = &alt_name_info->rgAltEntry[i];
+ if(entry->dwAltNameChoice == CERT_ALT_NAME_IP_ADDRESS) {
+ if(entry->IPAddress.cbData == p->size) {
+ if(!memcmp(entry->IPAddress.pbData, &p->bData,
+ entry->IPAddress.cbData)) {
+ result = CURLE_OK;
+ infof(data,
+ "schannel: connection hostname (%s) matched cert's IP address!",
+ conn_hostname);
+ break;
+ }
+ }
+ }
+ }
}
- actual_len = cert_get_name_string(
- data, pCertContextServer, (LPTSTR)cert_hostname_buff, len);
- /* Sanity check */
- if(actual_len != len) {
- failf(data,
- "schannel: CertGetNameString() returned certificate "
- "name information of unexpected size");
- result = CURLE_PEER_FAILED_VERIFICATION;
- goto cleanup;
- }
+ else {
+ /* Determine the size of the string needed for the cert hostname */
+ len = cert_get_name_string(data, pCertContextServer,
+ NULL, 0, alt_name_info, Win8_compat);
+ if(len == 0) {
+ failf(data,
+ "schannel: CertGetNameString() returned no "
+ "certificate name information");
+ goto cleanup;
+ }
- /* 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 &&
- cert_hostname_buff[cert_hostname_buff_index] != TEXT('\0') &&
- result == CURLE_PEER_FAILED_VERIFICATION) {
+ /* CertGetNameString guarantees that the returned name will not contain
+ * embedded null bytes. This appears to be undocumented behavior.
+ */
+ cert_hostname_buff = (LPTSTR)malloc(len * sizeof(TCHAR));
+ if(!cert_hostname_buff) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto cleanup;
+ }
+ actual_len = cert_get_name_string(data, pCertContextServer,
+ (LPTSTR)cert_hostname_buff, len, alt_name_info, Win8_compat);
- char *cert_hostname;
+ /* Sanity check */
+ if(actual_len != len) {
+ failf(data,
+ "schannel: CertGetNameString() returned certificate "
+ "name information of unexpected size");
+ goto cleanup;
+ }
- /* Comparing the cert name and the connection hostname encoded as UTF-8
- * is acceptable since both values are assumed to use ASCII
- * (or some equivalent) encoding
+ /* 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.
*/
- cert_hostname = curlx_convert_tchar_to_UTF8(
+ while(cert_hostname_buff_index < len &&
+ cert_hostname_buff[cert_hostname_buff_index] != TEXT('\0') &&
+ result == CURLE_PEER_FAILED_VERIFICATION) {
+
+ char *cert_hostname;
+
+ /* Comparing the cert name and the connection hostname encoded as UTF-8
+ * is acceptable since both values are assumed to use ASCII
+ * (or some equivalent) encoding
+ */
+ cert_hostname = curlx_convert_tchar_to_UTF8(
&cert_hostname_buff[cert_hostname_buff_index]);
- if(!cert_hostname) {
- result = CURLE_OUT_OF_MEMORY;
- }
- else {
- if(Curl_cert_hostcheck(cert_hostname, strlen(cert_hostname),
- conn_hostname, hostlen)) {
- infof(data,
- "schannel: connection hostname (%s) validated "
- "against certificate name (%s)",
- conn_hostname, cert_hostname);
- result = CURLE_OK;
+ if(!cert_hostname) {
+ result = CURLE_OUT_OF_MEMORY;
}
else {
- size_t cert_hostname_len;
+ if(Curl_cert_hostcheck(cert_hostname, strlen(cert_hostname),
+ conn_hostname, hostlen)) {
+ infof(data,
+ "schannel: connection hostname (%s) validated "
+ "against certificate name (%s)",
+ conn_hostname, cert_hostname);
+ result = CURLE_OK;
+ }
+ else {
+ size_t cert_hostname_len;
- infof(data,
- "schannel: connection hostname (%s) did not match "
- "against certificate name (%s)",
- conn_hostname, cert_hostname);
+ infof(data,
+ "schannel: connection hostname (%s) did not match "
+ "against certificate name (%s)",
+ conn_hostname, cert_hostname);
- cert_hostname_len =
- _tcslen(&cert_hostname_buff[cert_hostname_buff_index]);
+ cert_hostname_len =
+ _tcslen(&cert_hostname_buff[cert_hostname_buff_index]);
- /* Move on to next cert name */
- cert_hostname_buff_index += cert_hostname_len + 1;
+ /* Move on to next cert name */
+ cert_hostname_buff_index += cert_hostname_len + 1;
- result = CURLE_PEER_FAILED_VERIFICATION;
+ result = CURLE_PEER_FAILED_VERIFICATION;
+ }
+ curlx_unicodefree(cert_hostname);
}
- curlx_unicodefree(cert_hostname);
}
- }
- if(result == CURLE_PEER_FAILED_VERIFICATION) {
- failf(data,
- "schannel: CertGetNameString() failed to match "
- "connection hostname (%s) against server certificate names",
- conn_hostname);
+ if(result == CURLE_PEER_FAILED_VERIFICATION) {
+ failf(data,
+ "schannel: CertGetNameString() failed to match "
+ "connection hostname (%s) against server certificate names",
+ conn_hostname);
+ }
+ else if(result != CURLE_OK)
+ failf(data, "schannel: server certificate name verification failed");
}
- else if(result != CURLE_OK)
- failf(data, "schannel: server certificate name verification failed");
cleanup:
Curl_safefree(cert_hostname_buff);
@@ -592,7 +669,6 @@ cleanup: return result;
}
-
#ifdef HAS_MANUAL_VERIFY_API
/* Verify the server's certificate and hostname */
CURLcode Curl_verify_certificate(struct Curl_cfilter *cf,
diff --git a/libs/libcurl/src/vtls/sectransp.c b/libs/libcurl/src/vtls/sectransp.c index 8ca7d4e507..bf1d44dbdf 100644 --- a/libs/libcurl/src/vtls/sectransp.c +++ b/libs/libcurl/src/vtls/sectransp.c @@ -24,7 +24,7 @@ ***************************************************************************/
/*
- * Source file for all iOS and macOS SecureTransport-specific code for the
+ * Source file for all iOS and macOS Secure Transport-specific code for the
* TLS/SSL layer. No code but vtls.c should ever call or use these functions.
*/
@@ -197,7 +197,7 @@ static const uint16_t default_ciphers[] = { TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, /* 0xCCA8 */
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, /* 0xCCA9 */
- /* TLSv1.3 is not supported by sectransp, but there is also other
+ /* TLSv1.3 is not supported by Secure Transport, but there is also other
* code referencing TLSv1.3, like: kTLSProtocol13 ? */
TLS_AES_128_GCM_SHA256, /* 0x1301 */
TLS_AES_256_GCM_SHA384, /* 0x1302 */
@@ -278,7 +278,7 @@ static OSStatus sectransp_bio_cf_in_read(SSLConnectionRef connection, case CURLE_OK:
case CURLE_AGAIN:
rtn = errSSLWouldBlock;
- backend->ssl_direction = false;
+ backend->ssl_direction = FALSE;
break;
default:
rtn = ioErr;
@@ -317,7 +317,7 @@ static OSStatus sectransp_bio_cf_out_write(SSLConnectionRef connection, if(nwritten <= 0) {
if(result == CURLE_AGAIN) {
rtn = errSSLWouldBlock;
- backend->ssl_direction = true;
+ backend->ssl_direction = TRUE;
}
else {
rtn = ioErr;
@@ -512,7 +512,7 @@ static OSStatus CopyIdentityWithLabel(char *label, * label matching below worked correctly */
keys[2] = kSecMatchLimit;
/* identity searches need a SecPolicyRef in order to work */
- values[3] = SecPolicyCreateSSL(false, NULL);
+ values[3] = SecPolicyCreateSSL(FALSE, NULL);
keys[3] = kSecMatchPolicy;
/* match the name of the certificate (does not work in macOS 10.12.1) */
values[4] = label_cf;
@@ -532,7 +532,7 @@ static OSStatus CopyIdentityWithLabel(char *label, keys_list_count = CFArrayGetCount(keys_list);
*out_cert_and_key = NULL;
status = 1;
- for(i = 0; i<keys_list_count; i++) {
+ for(i = 0; i < keys_list_count; i++) {
OSStatus err = noErr;
SecCertificateRef cert = NULL;
SecIdentityRef identity =
@@ -609,7 +609,7 @@ static OSStatus CopyIdentityFromPKCS12File(const char *cPath, pkcs_url =
CFURLCreateFromFileSystemRepresentation(NULL,
(const UInt8 *)cPath,
- (CFIndex)strlen(cPath), false);
+ (CFIndex)strlen(cPath), FALSE);
resource_imported =
CFURLCreateDataAndPropertiesFromResource(NULL,
pkcs_url, &pkcs_data,
@@ -711,11 +711,11 @@ CF_INLINE bool is_file(const char *filename) struct_stat st;
if(!filename)
- return false;
+ return FALSE;
if(stat(filename, &st) == 0)
return S_ISREG(st.st_mode);
- return false;
+ return FALSE;
}
static CURLcode
@@ -796,8 +796,8 @@ legacy: }
/* only TLS 1.0 is supported, disable SSL 3.0 and SSL 2.0 */
- SSLSetProtocolVersionEnabled(backend->ssl_ctx, kSSLProtocolAll, false);
- SSLSetProtocolVersionEnabled(backend->ssl_ctx, kTLSProtocol1, true);
+ SSLSetProtocolVersionEnabled(backend->ssl_ctx, kSSLProtocolAll, FALSE);
+ SSLSetProtocolVersionEnabled(backend->ssl_ctx, kTLSProtocol1, TRUE);
return CURLE_OK;
#endif
@@ -1069,7 +1069,7 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf, #if CURL_SUPPORT_MAC_10_8
if(backend->ssl_ctx)
(void)SSLDisposeContext(backend->ssl_ctx);
- err = SSLNewContext(false, &(backend->ssl_ctx));
+ err = SSLNewContext(FALSE, &(backend->ssl_ctx));
if(err != noErr) {
failf(data, "SSL: could not create a context: OSStatus %d", err);
return CURLE_OUT_OF_MEMORY;
@@ -1079,7 +1079,7 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf, #else
if(backend->ssl_ctx)
(void)SSLDisposeContext(backend->ssl_ctx);
- err = SSLNewContext(false, &(backend->ssl_ctx));
+ err = SSLNewContext(FALSE, &(backend->ssl_ctx));
if(err != noErr) {
failf(data, "SSL: could not create a context: OSStatus %d", err);
return CURLE_OUT_OF_MEMORY;
@@ -1227,8 +1227,7 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf, Mountain Lion.
So we need to call SSLSetEnableCertVerify() on those older cats in order
to disable certificate validation if the user turned that off.
- (SecureTransport will always validate the certificate chain by
- default.)
+ (Secure Transport always validates the certificate chain by default.)
Note:
Darwin 11.x.x is Lion (10.7)
Darwin 12.x.x is Mountain Lion (10.8)
@@ -1254,7 +1253,7 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf, else {
#if CURL_SUPPORT_MAC_10_8
err = SSLSetEnableCertVerify(backend->ssl_ctx,
- conn_config->verifypeer?true:false);
+ conn_config->verifypeer ? true : FALSE);
if(err != noErr) {
failf(data, "SSL: SSLSetEnableCertVerify() failed: OSStatus %d", err);
return CURLE_SSL_CONNECT_ERROR;
@@ -1263,7 +1262,7 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf, }
#else
err = SSLSetEnableCertVerify(backend->ssl_ctx,
- conn_config->verifypeer?true:false);
+ conn_config->verifypeer ? true : FALSE);
if(err != noErr) {
failf(data, "SSL: SSLSetEnableCertVerify() failed: OSStatus %d", err);
return CURLE_SSL_CONNECT_ERROR;
@@ -1285,8 +1284,8 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf, * Both hostname check and SNI require SSLSetPeerDomainName().
* Also: the verifyhost setting influences SNI usage */
if(conn_config->verifyhost) {
- char *server = connssl->peer.sni?
- connssl->peer.sni : connssl->peer.hostname;
+ char *server = connssl->peer.sni ?
+ connssl->peer.sni : connssl->peer.hostname;
err = SSLSetPeerDomainName(backend->ssl_ctx, server, strlen(server));
if(err != noErr) {
@@ -1335,7 +1334,8 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf, Curl_ssl_sessionid_lock(data);
if(!Curl_ssl_getsessionid(cf, data, &connssl->peer,
- (void **)&ssl_sessionid, &ssl_sessionid_len)) {
+ (void **)&ssl_sessionid, &ssl_sessionid_len,
+ NULL)) {
/* we got a session id, use it! */
err = SSLSetPeerID(backend->ssl_ctx, ssl_sessionid, ssl_sessionid_len);
Curl_ssl_sessionid_unlock(data);
@@ -1363,8 +1363,8 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf, return CURLE_SSL_CONNECT_ERROR;
}
- result = Curl_ssl_set_sessionid(cf, data, &connssl->peer, ssl_sessionid,
- ssl_sessionid_len,
+ result = Curl_ssl_set_sessionid(cf, data, &connssl->peer, NULL,
+ ssl_sessionid, ssl_sessionid_len,
sectransp_session_free);
Curl_ssl_sessionid_unlock(data);
if(result)
@@ -1605,7 +1605,7 @@ static CURLcode verify_cert_buf(struct Curl_cfilter *cf, failf(data, "SecTrustSetAnchorCertificates() returned error %d", ret);
goto out;
}
- ret = SecTrustSetAnchorCertificatesOnly(trust, true);
+ ret = SecTrustSetAnchorCertificatesOnly(trust, TRUE);
if(ret != noErr) {
failf(data, "SecTrustSetAnchorCertificatesOnly() returned error %d", ret);
goto out;
@@ -2054,7 +2054,7 @@ check_handshake: (void)SSLGetNegotiatedProtocolVersion(backend->ssl_ctx, &protocol);
sectransp_cipher_suite_get_str((uint16_t) cipher, cipher_str,
- sizeof(cipher_str), true);
+ sizeof(cipher_str), TRUE);
switch(protocol) {
case kSSLProtocol2:
infof(data, "SSL 2.0 connection using %s", cipher_str);
@@ -2169,7 +2169,7 @@ static CURLcode collect_server_cert(struct Curl_cfilter *cf, #ifndef CURL_DISABLE_VERBOSE_STRINGS
const bool show_verbose_server_cert = data->set.verbose;
#else
- const bool show_verbose_server_cert = false;
+ const bool show_verbose_server_cert = FALSE;
#endif
struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
CURLcode result = ssl_config->certinfo ?
@@ -2328,10 +2328,10 @@ sectransp_connect_common(struct Curl_cfilter *cf, struct Curl_easy *data, /* if ssl is expecting something, check if it is available. */
if(connssl->io_need) {
- curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND)?
- sockfd:CURL_SOCKET_BAD;
- curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV)?
- sockfd:CURL_SOCKET_BAD;
+ curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND) ?
+ sockfd : CURL_SOCKET_BAD;
+ curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV) ?
+ sockfd : CURL_SOCKET_BAD;
what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
nonblocking ? 0 : timeout_ms);
@@ -2463,7 +2463,7 @@ static CURLcode sectransp_shutdown(struct Curl_cfilter *cf, }
else {
/* We would like to read the close notify from the server using
- * secure transport, however SSLRead() no longer works after we
+ * Secure Transport, however SSLRead() no longer works after we
* sent the notify from our side. So, we just read from the
* underlying filter and hope it will end. */
nread = Curl_conn_cf_recv(cf->next, data, buf, sizeof(buf), &result);
@@ -2544,10 +2544,10 @@ static bool sectransp_data_pending(struct Curl_cfilter *cf, err = SSLGetBufferedReadSize(backend->ssl_ctx, &buffer);
if(err == noErr)
return buffer > 0UL;
- return false;
+ return FALSE;
}
else
- return false;
+ return FALSE;
}
static CURLcode sectransp_random(struct Curl_easy *data UNUSED_PARAM,
diff --git a/libs/libcurl/src/vtls/vtls.c b/libs/libcurl/src/vtls/vtls.c index 2a0d232024..0a90bf46fd 100644 --- a/libs/libcurl/src/vtls/vtls.c +++ b/libs/libcurl/src/vtls/vtls.c @@ -55,6 +55,16 @@ #include "vtls.h" /* generic SSL protos etc */
#include "vtls_int.h"
+
+#include "openssl.h" /* OpenSSL versions */
+#include "gtls.h" /* GnuTLS versions */
+#include "wolfssl.h" /* wolfSSL versions */
+#include "schannel.h" /* Schannel SSPI version */
+#include "sectransp.h" /* Secure Transport (Darwin) version */
+#include "mbedtls.h" /* mbedTLS versions */
+#include "bearssl.h" /* BearSSL versions */
+#include "rustls.h" /* Rustls versions */
+
#include "slist.h"
#include "sendf.h"
#include "strcase.h"
@@ -259,7 +269,7 @@ static bool clone_ssl_primary_config(struct ssl_primary_config *source, return TRUE;
}
-static void Curl_free_primary_ssl_config(struct ssl_primary_config *sslc)
+static void free_primary_ssl_config(struct ssl_primary_config *sslc)
{
Curl_safefree(sslc->CApath);
Curl_safefree(sslc->CAfile);
@@ -359,9 +369,9 @@ CURLcode Curl_ssl_conn_config_init(struct Curl_easy *data, void Curl_ssl_conn_config_cleanup(struct connectdata *conn)
{
- Curl_free_primary_ssl_config(&conn->ssl_config);
+ free_primary_ssl_config(&conn->ssl_config);
#ifndef CURL_DISABLE_PROXY
- Curl_free_primary_ssl_config(&conn->proxy_ssl_config);
+ free_primary_ssl_config(&conn->proxy_ssl_config);
#endif
}
@@ -371,8 +381,8 @@ void Curl_ssl_conn_config_update(struct Curl_easy *data, bool for_proxy) if(data->conn) {
struct ssl_primary_config *src, *dest;
#ifndef CURL_DISABLE_PROXY
- src = for_proxy? &data->set.proxy_ssl.primary : &data->set.ssl.primary;
- dest = for_proxy? &data->conn->proxy_ssl_config : &data->conn->ssl_config;
+ src = for_proxy ? &data->set.proxy_ssl.primary : &data->set.ssl.primary;
+ dest = for_proxy ? &data->conn->proxy_ssl_config : &data->conn->ssl_config;
#else
(void)for_proxy;
src = &data->set.ssl.primary;
@@ -454,6 +464,7 @@ static struct ssl_connect_data *cf_ctx_new(struct Curl_easy *data, return NULL;
ctx->alpn = alpn;
+ Curl_bufq_init2(&ctx->earlydata, CURL_SSL_EARLY_MAX, 1, BUFQ_OPT_NO_SPARES);
ctx->backend = calloc(1, Curl_ssl->sizeof_ssl_backend_data);
if(!ctx->backend) {
free(ctx);
@@ -465,6 +476,8 @@ static struct ssl_connect_data *cf_ctx_new(struct Curl_easy *data, static void cf_ctx_free(struct ssl_connect_data *ctx)
{
if(ctx) {
+ Curl_safefree(ctx->alpn_negotiated);
+ Curl_bufq_free(&ctx->earlydata);
free(ctx->backend);
free(ctx);
}
@@ -527,7 +540,8 @@ bool Curl_ssl_getsessionid(struct Curl_cfilter *cf, struct Curl_easy *data,
const struct ssl_peer *peer,
void **ssl_sessionid,
- size_t *idsize) /* set 0 if unknown */
+ size_t *idsize, /* set 0 if unknown */
+ char **palpn)
{
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);
@@ -537,6 +551,8 @@ bool Curl_ssl_getsessionid(struct Curl_cfilter *cf, bool no_match = TRUE;
*ssl_sessionid = NULL;
+ if(palpn)
+ *palpn = NULL;
if(!ssl_config)
return TRUE;
@@ -575,13 +591,15 @@ bool Curl_ssl_getsessionid(struct Curl_cfilter *cf, *ssl_sessionid = check->sessionid;
if(idsize)
*idsize = check->idsize;
+ if(palpn)
+ *palpn = check->alpn;
no_match = FALSE;
break;
}
}
CURL_TRC_CF(data, cf, "%s cached session ID for %s://%s:%d",
- no_match? "No": "Found",
+ no_match ? "No" : "Found",
cf->conn->handler->scheme, peer->hostname, peer->port);
return no_match;
}
@@ -601,10 +619,11 @@ void Curl_ssl_kill_session(struct Curl_ssl_session *session) session->sessionid_free = NULL;
session->age = 0; /* fresh */
- Curl_free_primary_ssl_config(&session->ssl_config);
+ free_primary_ssl_config(&session->ssl_config);
Curl_safefree(session->name);
Curl_safefree(session->conn_to_host);
+ Curl_safefree(session->alpn);
}
}
@@ -628,6 +647,7 @@ void Curl_ssl_delsessionid(struct Curl_easy *data, void *ssl_sessionid) CURLcode Curl_ssl_set_sessionid(struct Curl_cfilter *cf,
struct Curl_easy *data,
const struct ssl_peer *peer,
+ const char *alpn,
void *ssl_sessionid,
size_t idsize,
Curl_ssl_sessionid_dtor *sessionid_free_cb)
@@ -639,6 +659,7 @@ CURLcode Curl_ssl_set_sessionid(struct Curl_cfilter *cf, long oldest_age;
char *clone_host = NULL;
char *clone_conn_to_host = NULL;
+ char *clone_alpn = NULL;
int conn_to_port;
long *general_age;
void *old_sessionid;
@@ -653,7 +674,7 @@ CURLcode Curl_ssl_set_sessionid(struct Curl_cfilter *cf, return CURLE_OK;
}
- if(!Curl_ssl_getsessionid(cf, data, peer, &old_sessionid, &old_size)) {
+ if(!Curl_ssl_getsessionid(cf, data, peer, &old_sessionid, &old_size, NULL)) {
if((old_size == idsize) &&
((old_sessionid == ssl_sessionid) ||
(idsize && !memcmp(old_sessionid, ssl_sessionid, idsize)))) {
@@ -679,6 +700,10 @@ CURLcode Curl_ssl_set_sessionid(struct Curl_cfilter *cf, goto out;
}
+ clone_alpn = alpn ? strdup(alpn) : NULL;
+ if(alpn && !clone_alpn)
+ goto out;
+
if(cf->conn->bits.conn_to_port)
conn_to_port = cf->conn->conn_to_port;
else
@@ -711,7 +736,7 @@ CURLcode Curl_ssl_set_sessionid(struct Curl_cfilter *cf, /* now init the session struct wisely */
if(!clone_ssl_primary_config(conn_config, &store->ssl_config)) {
- Curl_free_primary_ssl_config(&store->ssl_config);
+ free_primary_ssl_config(&store->ssl_config);
store->sessionid = NULL; /* let caller free sessionid */
goto out;
}
@@ -727,6 +752,8 @@ CURLcode Curl_ssl_set_sessionid(struct Curl_cfilter *cf, store->conn_to_host = clone_conn_to_host; /* clone connect to hostname */
clone_conn_to_host = NULL;
store->conn_to_port = conn_to_port; /* connect to port number */
+ store->alpn = clone_alpn;
+ clone_alpn = NULL;
/* port number */
store->remote_port = peer->port;
store->scheme = cf->conn->handler->scheme;
@@ -737,6 +764,7 @@ CURLcode Curl_ssl_set_sessionid(struct Curl_cfilter *cf, out:
free(clone_host);
free(clone_conn_to_host);
+ free(clone_alpn);
if(result) {
failf(data, "Failed to add Session ID to cache for %s://%s:%d [%s]",
store->scheme, store->name, store->remote_port,
@@ -857,7 +885,7 @@ void Curl_ssl_free_certinfo(struct Curl_easy *data) if(ci->num_of_certs) {
/* free all individual lists used */
int i;
- for(i = 0; i<ci->num_of_certs; i++) {
+ for(i = 0; i < ci->num_of_certs; i++) {
curl_slist_free_all(ci->certinfo[i]);
ci->certinfo[i] = NULL;
}
@@ -941,14 +969,17 @@ CURLcode Curl_ssl_random(struct Curl_easy *data, static CURLcode pubkey_pem_to_der(const char *pem,
unsigned char **der, size_t *der_len)
{
- char *stripped_pem, *begin_pos, *end_pos;
- size_t pem_count, stripped_pem_count = 0, pem_len;
+ char *begin_pos, *end_pos;
+ size_t pem_count, pem_len;
CURLcode result;
+ struct dynbuf pbuf;
/* if no pem, exit. */
if(!pem)
return CURLE_BAD_CONTENT_ENCODING;
+ Curl_dyn_init(&pbuf, MAX_PINNED_PUBKEY_SIZE);
+
begin_pos = strstr(pem, "-----BEGIN PUBLIC KEY-----");
if(!begin_pos)
return CURLE_BAD_CONTENT_ENCODING;
@@ -968,26 +999,23 @@ static CURLcode pubkey_pem_to_der(const char *pem, pem_len = end_pos - pem;
- stripped_pem = malloc(pem_len - pem_count + 1);
- if(!stripped_pem)
- return CURLE_OUT_OF_MEMORY;
-
/*
* Here we loop through the pem array one character at a time between the
* correct indices, and place each character that is not '\n' or '\r'
* into the stripped_pem array, which should represent the raw base64 string
*/
while(pem_count < pem_len) {
- if('\n' != pem[pem_count] && '\r' != pem[pem_count])
- stripped_pem[stripped_pem_count++] = pem[pem_count];
+ if('\n' != pem[pem_count] && '\r' != pem[pem_count]) {
+ result = Curl_dyn_addn(&pbuf, &pem[pem_count], 1);
+ if(result)
+ return result;
+ }
++pem_count;
}
- /* Place the null terminator in the correct place */
- stripped_pem[stripped_pem_count] = '\0';
- result = Curl_base64_decode(stripped_pem, der, der_len);
+ result = Curl_base64_decode(Curl_dyn_ptr(&pbuf), der, der_len);
- Curl_safefree(stripped_pem);
+ Curl_dyn_free(&pbuf);
return result;
}
@@ -1000,8 +1028,6 @@ CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data, const char *pinnedpubkey,
const unsigned char *pubkey, size_t pubkeylen)
{
- FILE *fp;
- unsigned char *buf = NULL, *pem_ptr = NULL;
CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
#ifdef CURL_DISABLE_VERBOSE_STRINGS
(void)data;
@@ -1014,7 +1040,7 @@ CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data, return result;
/* only do this if pinnedpubkey starts with "sha256//", length 8 */
- if(strncmp(pinnedpubkey, "sha256//", 8) == 0) {
+ if(!strncmp(pinnedpubkey, "sha256//", 8)) {
CURLcode encode;
size_t encodedlen = 0;
char *encoded = NULL, *pinkeycopy, *begin_pos, *end_pos;
@@ -1078,26 +1104,28 @@ CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data, } while(end_pos && begin_pos);
Curl_safefree(encoded);
Curl_safefree(pinkeycopy);
- return result;
}
-
- fp = fopen(pinnedpubkey, "rb");
- if(!fp)
- return result;
-
- do {
+ else {
long filesize;
size_t size, pem_len;
CURLcode pem_read;
+ struct dynbuf buf;
+ char unsigned *pem_ptr = NULL;
+ size_t left;
+ FILE *fp = fopen(pinnedpubkey, "rb");
+ if(!fp)
+ return result;
+
+ Curl_dyn_init(&buf, MAX_PINNED_PUBKEY_SIZE);
/* Determine the file's size */
if(fseek(fp, 0, SEEK_END))
- break;
+ goto end;
filesize = ftell(fp);
if(fseek(fp, 0, SEEK_SET))
- break;
+ goto end;
if(filesize < 0 || filesize > MAX_PINNED_PUBKEY_SIZE)
- break;
+ goto end;
/*
* if the size of our certificate is bigger than the file
@@ -1105,36 +1133,37 @@ CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data, */
size = curlx_sotouz((curl_off_t) filesize);
if(pubkeylen > size)
- break;
+ goto end;
/*
- * Allocate buffer for the pinned key
- * With 1 additional byte for null terminator in case of PEM key
+ * Read the file into the dynbuf
*/
- buf = malloc(size + 1);
- if(!buf)
- break;
-
- /* Returns number of elements read, which should be 1 */
- if((int) fread(buf, size, 1, fp) != 1)
- break;
+ left = size;
+ do {
+ char buffer[1024];
+ size_t want = left > sizeof(buffer) ? sizeof(buffer) : left;
+ if(want != fread(buffer, 1, want, fp))
+ goto end;
+ if(Curl_dyn_addn(&buf, buffer, want))
+ goto end;
+ left -= want;
+ } while(left);
/* If the sizes are the same, it cannot be base64 encoded, must be der */
if(pubkeylen == size) {
- if(!memcmp(pubkey, buf, pubkeylen))
+ if(!memcmp(pubkey, Curl_dyn_ptr(&buf), pubkeylen))
result = CURLE_OK;
- break;
+ goto end;
}
/*
* Otherwise we will assume it is PEM and try to decode it
* after placing null terminator
*/
- buf[size] = '\0';
- pem_read = pubkey_pem_to_der((const char *)buf, &pem_ptr, &pem_len);
+ pem_read = pubkey_pem_to_der(Curl_dyn_ptr(&buf), &pem_ptr, &pem_len);
/* if it was not read successfully, exit */
if(pem_read)
- break;
+ goto end;
/*
* if the size of our certificate does not match the size of
@@ -1142,11 +1171,11 @@ CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data, */
if(pubkeylen == pem_len && !memcmp(pubkey, pem_ptr, pubkeylen))
result = CURLE_OK;
- } while(0);
-
- Curl_safefree(buf);
- Curl_safefree(pem_ptr);
- fclose(fp);
+end:
+ Curl_dyn_free(&buf);
+ Curl_safefree(pem_ptr);
+ fclose(fp);
+ }
return result;
}
@@ -1715,7 +1744,9 @@ static CURLcode ssl_cf_connect(struct Curl_cfilter *cf, if(!result && *done) {
cf->connected = TRUE;
connssl->handshake_done = Curl_now();
- DEBUGASSERT(connssl->state == ssl_connection_complete);
+ /* Connection can be deferred when sending early data */
+ DEBUGASSERT(connssl->state == ssl_connection_complete ||
+ connssl->state == ssl_connection_deferred);
}
out:
CURL_TRC_CF(data, cf, "cf_connect() -> %d, done=%d", result, *done);
@@ -1743,13 +1774,16 @@ static ssize_t ssl_cf_send(struct Curl_cfilter *cf, bool eos, CURLcode *err)
{
struct cf_call_data save;
- ssize_t nwritten;
+ ssize_t nwritten = 0;
- (void)eos; /* unused */
- CF_DATA_SAVE(save, cf, data);
+ (void)eos;
+ /* OpenSSL and maybe other TLS libs do not like 0-length writes. Skip. */
*err = CURLE_OK;
- nwritten = Curl_ssl->send_plain(cf, data, buf, len, err);
- CF_DATA_RESTORE(cf, save);
+ if(len > 0) {
+ CF_DATA_SAVE(save, cf, data);
+ nwritten = Curl_ssl->send_plain(cf, data, buf, len, err);
+ CF_DATA_RESTORE(cf, save);
+ }
return nwritten;
}
@@ -1851,7 +1885,7 @@ static CURLcode ssl_cf_query(struct Curl_cfilter *cf, default:
break;
}
- return cf->next?
+ return cf->next ?
cf->next->cft->query(cf->next, data, query, pres1, pres2) :
CURLE_UNKNOWN_OPTION;
}
@@ -1881,7 +1915,7 @@ static bool cf_ssl_is_alive(struct Curl_cfilter *cf, struct Curl_easy *data, return FALSE;
}
/* ssl backend does not know */
- return cf->next?
+ return cf->next ?
cf->next->cft->is_alive(cf->next, data, input_pending) :
FALSE; /* pessimistic in absence of data */
}
@@ -1950,7 +1984,7 @@ static CURLcode cf_ssl_create(struct Curl_cfilter **pcf, out:
if(result)
cf_ctx_free(ctx);
- *pcf = result? NULL : cf;
+ *pcf = result ? NULL : cf;
return result;
}
@@ -2008,7 +2042,7 @@ static CURLcode cf_ssl_proxy_create(struct Curl_cfilter **pcf, out:
if(result)
cf_ctx_free(ctx);
- *pcf = result? NULL : cf;
+ *pcf = result ? NULL : cf;
return result;
}
@@ -2029,7 +2063,7 @@ CURLcode Curl_cf_ssl_proxy_insert_after(struct Curl_cfilter *cf_at, bool Curl_ssl_supports(struct Curl_easy *data, unsigned int ssl_option)
{
(void)data;
- return (Curl_ssl->supports & ssl_option)? TRUE : FALSE;
+ return (Curl_ssl->supports & ssl_option);
}
static struct Curl_cfilter *get_ssl_filter(struct Curl_cfilter *cf)
@@ -2124,7 +2158,7 @@ CURLcode Curl_ssl_cfilter_remove(struct Curl_easy *data, struct Curl_cfilter *cf, *head;
CURLcode result = CURLE_OK;
- head = data->conn? data->conn->cfilter[sockindex] : NULL;
+ head = data->conn ? data->conn->cfilter[sockindex] : NULL;
for(cf = head; cf; cf = cf->next) {
if(cf->cft == &Curl_cft_ssl) {
bool done;
@@ -2154,7 +2188,7 @@ Curl_ssl_cf_get_config(struct Curl_cfilter *cf, struct Curl_easy *data) (void)cf;
return &data->set.ssl;
#else
- return Curl_ssl_cf_is_proxy(cf)? &data->set.proxy_ssl : &data->set.ssl;
+ return Curl_ssl_cf_is_proxy(cf) ? &data->set.proxy_ssl : &data->set.ssl;
#endif
}
@@ -2164,7 +2198,7 @@ Curl_ssl_cf_get_primary_config(struct Curl_cfilter *cf) #ifdef CURL_DISABLE_PROXY
return &cf->conn->ssl_config;
#else
- return Curl_ssl_cf_is_proxy(cf)?
+ return Curl_ssl_cf_is_proxy(cf) ?
&cf->conn->proxy_ssl_config : &cf->conn->ssl_config;
#endif
}
@@ -2215,20 +2249,73 @@ CURLcode Curl_alpn_to_proto_str(struct alpn_proto_buf *buf, return CURLE_OK;
}
+bool Curl_alpn_contains_proto(const struct alpn_spec *spec,
+ const char *proto)
+{
+ size_t i, plen = proto ? strlen(proto) : 0;
+ for(i = 0; spec && plen && i < spec->count; ++i) {
+ size_t slen = strlen(spec->entries[i]);
+ if((slen == plen) && !memcmp(proto, spec->entries[i], plen))
+ return TRUE;
+ }
+ return FALSE;
+}
+
CURLcode Curl_alpn_set_negotiated(struct Curl_cfilter *cf,
struct Curl_easy *data,
+ struct ssl_connect_data *connssl,
const unsigned char *proto,
size_t proto_len)
{
+ CURLcode result = CURLE_OK;
unsigned char *palpn =
#ifndef CURL_DISABLE_PROXY
- (cf->conn->bits.tunnel_proxy && Curl_ssl_cf_is_proxy(cf))?
+ (cf->conn->bits.tunnel_proxy && Curl_ssl_cf_is_proxy(cf)) ?
&cf->conn->proxy_alpn : &cf->conn->alpn
#else
&cf->conn->alpn
#endif
;
+ if(connssl->alpn_negotiated) {
+ /* When we ask for a specific ALPN protocol, we need the confirmation
+ * of it by the server, as we have installed protocol handler and
+ * connection filter chain for exactly this protocol. */
+ if(!proto_len) {
+ failf(data, "ALPN: asked for '%s' from previous session, "
+ "but server did not confirm it. Refusing to continue.",
+ connssl->alpn_negotiated);
+ result = CURLE_SSL_CONNECT_ERROR;
+ goto out;
+ }
+ else if((strlen(connssl->alpn_negotiated) != proto_len) ||
+ memcmp(connssl->alpn_negotiated, proto, proto_len)) {
+ failf(data, "ALPN: asked for '%s' from previous session, but server "
+ "selected '%.*s'. Refusing to continue.",
+ connssl->alpn_negotiated, (int)proto_len, proto);
+ result = CURLE_SSL_CONNECT_ERROR;
+ goto out;
+ }
+ /* ALPN is exactly what we asked for, done. */
+ infof(data, "ALPN: server confirmed to use '%s'",
+ connssl->alpn_negotiated);
+ goto out;
+ }
+
+ if(proto && proto_len) {
+ if(memchr(proto, '\0', proto_len)) {
+ failf(data, "ALPN: server selected protocol contains NUL. "
+ "Refusing to continue.");
+ result = CURLE_SSL_CONNECT_ERROR;
+ goto out;
+ }
+ connssl->alpn_negotiated = malloc(proto_len + 1);
+ if(!connssl->alpn_negotiated)
+ return CURLE_OUT_OF_MEMORY;
+ memcpy(connssl->alpn_negotiated, proto, proto_len);
+ connssl->alpn_negotiated[proto_len] = 0;
+ }
+
if(proto && proto_len) {
if(proto_len == ALPN_HTTP_1_1_LENGTH &&
!memcmp(ALPN_HTTP_1_1, proto, ALPN_HTTP_1_1_LENGTH)) {
@@ -2254,15 +2341,22 @@ CURLcode Curl_alpn_set_negotiated(struct Curl_cfilter *cf, /* return CURLE_NOT_BUILT_IN; */
goto out;
}
- infof(data, VTLS_INFOF_ALPN_ACCEPTED_LEN_1STR, (int)proto_len, proto);
+
+ if(connssl->state == ssl_connection_deferred)
+ infof(data, VTLS_INFOF_ALPN_DEFERRED, (int)proto_len, proto);
+ else
+ infof(data, VTLS_INFOF_ALPN_ACCEPTED, (int)proto_len, proto);
}
else {
*palpn = CURL_HTTP_VERSION_NONE;
- infof(data, VTLS_INFOF_NO_ALPN);
+ if(connssl->state == ssl_connection_deferred)
+ infof(data, VTLS_INFOF_NO_ALPN_DEFERRED);
+ else
+ infof(data, VTLS_INFOF_NO_ALPN);
}
out:
- return CURLE_OK;
+ return result;
}
#endif /* USE_SSL */
diff --git a/libs/libcurl/src/vtls/vtls.h b/libs/libcurl/src/vtls/vtls.h index c716b2c6f8..171a5d8e55 100644 --- a/libs/libcurl/src/vtls/vtls.h +++ b/libs/libcurl/src/vtls/vtls.h @@ -43,15 +43,18 @@ struct Curl_ssl_session; #define ALPN_ACCEPTED "ALPN: server accepted "
-#define VTLS_INFOF_NO_ALPN \
+#define VTLS_INFOF_NO_ALPN \
"ALPN: server did not agree on a protocol. Uses default."
-#define VTLS_INFOF_ALPN_OFFER_1STR \
+#define VTLS_INFOF_ALPN_OFFER_1STR \
"ALPN: curl offers %s"
-#define VTLS_INFOF_ALPN_ACCEPTED_1STR \
- ALPN_ACCEPTED "%s"
-#define VTLS_INFOF_ALPN_ACCEPTED_LEN_1STR \
+#define VTLS_INFOF_ALPN_ACCEPTED \
ALPN_ACCEPTED "%.*s"
+#define VTLS_INFOF_NO_ALPN_DEFERRED \
+ "ALPN: deferred handshake for early data without specific protocol."
+#define VTLS_INFOF_ALPN_DEFERRED \
+ "ALPN: deferred handshake for early data using '%.*s'."
+
/* Curl_multi SSL backend-specific data; declared differently by each SSL
backend */
struct Curl_cfilter;
diff --git a/libs/libcurl/src/vtls/vtls_int.h b/libs/libcurl/src/vtls/vtls_int.h index 6cd2867dee..250273ef9d 100644 --- a/libs/libcurl/src/vtls/vtls_int.h +++ b/libs/libcurl/src/vtls/vtls_int.h @@ -29,6 +29,8 @@ #ifdef USE_SSL
+struct ssl_connect_data;
+
/* see https://www.iana.org/assignments/tls-extensiontype-values/ */
#define ALPN_HTTP_1_1_LENGTH 8
#define ALPN_HTTP_1_1 "http/1.1"
@@ -61,9 +63,13 @@ CURLcode Curl_alpn_to_proto_str(struct alpn_proto_buf *buf, CURLcode Curl_alpn_set_negotiated(struct Curl_cfilter *cf,
struct Curl_easy *data,
+ struct ssl_connect_data *connssl,
const unsigned char *proto,
size_t proto_len);
+bool Curl_alpn_contains_proto(const struct alpn_spec *spec,
+ const char *proto);
+
/* enum for the nonblocking SSL connection state machine */
typedef enum {
ssl_connect_1,
@@ -74,14 +80,27 @@ typedef enum { typedef enum {
ssl_connection_none,
+ ssl_connection_deferred,
ssl_connection_negotiating,
ssl_connection_complete
} ssl_connection_state;
+typedef enum {
+ ssl_earlydata_none,
+ ssl_earlydata_use,
+ ssl_earlydata_sending,
+ ssl_earlydata_sent,
+ ssl_earlydata_accepted,
+ ssl_earlydata_rejected
+} ssl_earlydata_state;
+
#define CURL_SSL_IO_NEED_NONE (0)
#define CURL_SSL_IO_NEED_RECV (1<<0)
#define CURL_SSL_IO_NEED_SEND (1<<1)
+/* Max earlydata payload we want to send */
+#define CURL_SSL_EARLY_MAX (64*1024)
+
/* Information in each SSL cfilter context: cf->ctx */
struct ssl_connect_data {
struct ssl_peer peer;
@@ -89,8 +108,14 @@ struct ssl_connect_data { void *backend; /* vtls backend specific props */
struct cf_call_data call_data; /* data handle used in current call */
struct curltime handshake_done; /* time when handshake finished */
+ char *alpn_negotiated; /* negotiated ALPN value or NULL */
+ struct bufq earlydata; /* earlydata to be send to peer */
+ size_t earlydata_max; /* max earlydata allowed by peer */
+ size_t earlydata_skip; /* sending bytes to skip when earlydata
+ * is accepted by peer */
ssl_connection_state state;
ssl_connect_state connecting_state;
+ ssl_earlydata_state earlydata_state;
int io_need; /* TLS signals special SEND/RECV needs */
BIT(use_alpn); /* if ALPN shall be used in handshake */
BIT(peer_closed); /* peer has closed connection */
@@ -193,15 +218,23 @@ bool Curl_ssl_cf_is_proxy(struct Curl_cfilter *cf); * Caller must make sure that the ownership of returned sessionid object
* is properly taken (e.g. its refcount is incremented
* under sessionid mutex).
+ * @param cf the connection filter wanting to use it
+ * @param data the transfer involved
+ * @param peer the peer the filter wants to talk to
+ * @param sessionid on return the TLS session
+ * @param idsize on return the size of the TLS session data
+ * @param palpn on return the ALPN string used by the session,
+ * set to NULL when not interested
*/
bool Curl_ssl_getsessionid(struct Curl_cfilter *cf,
struct Curl_easy *data,
const struct ssl_peer *peer,
void **ssl_sessionid,
- size_t *idsize); /* set 0 if unknown */
+ size_t *idsize, /* set 0 if unknown */
+ char **palpn);
/* Set a TLS session ID for `peer`. Replaces an existing session ID if
- * not already the very same.
+ * not already the same.
* Sessionid mutex must be locked (see Curl_ssl_sessionid_lock).
* Call takes ownership of `ssl_sessionid`, using `sessionid_free_cb`
* to deallocate it. Is called in all outcomes, either right away or
@@ -212,19 +245,11 @@ bool Curl_ssl_getsessionid(struct Curl_cfilter *cf, CURLcode Curl_ssl_set_sessionid(struct Curl_cfilter *cf,
struct Curl_easy *data,
const struct ssl_peer *peer,
+ const char *alpn,
void *sessionid,
size_t sessionid_size,
Curl_ssl_sessionid_dtor *sessionid_free_cb);
-#include "openssl.h" /* OpenSSL versions */
-#include "gtls.h" /* GnuTLS versions */
-#include "wolfssl.h" /* wolfSSL versions */
-#include "schannel.h" /* Schannel SSPI version */
-#include "sectransp.h" /* SecureTransport (Darwin) version */
-#include "mbedtls.h" /* mbedTLS versions */
-#include "bearssl.h" /* BearSSL versions */
-#include "rustls.h" /* Rustls versions */
-
#endif /* USE_SSL */
#endif /* HEADER_CURL_VTLS_INT_H */
diff --git a/libs/libcurl/src/vtls/wolfssl.c b/libs/libcurl/src/vtls/wolfssl.c index 458219ef61..9a05f82946 100644 --- a/libs/libcurl/src/vtls/wolfssl.c +++ b/libs/libcurl/src/vtls/wolfssl.c @@ -97,9 +97,25 @@ #endif
#endif
-#if defined(HAVE_WOLFSSL_FULL_BIO) && HAVE_WOLFSSL_FULL_BIO
+#ifdef HAVE_WOLFSSL_BIO
#define USE_BIO_CHAIN
-#else
+#ifdef HAVE_WOLFSSL_FULL_BIO
+#define USE_FULL_BIO
+#else /* HAVE_WOLFSSL_FULL_BIO */
+#undef USE_FULL_BIO
+#endif
+/* wolfSSL 5.7.4 and older do not have these symbols, but only the
+ * OpenSSL ones. */
+#ifndef WOLFSSL_BIO_CTRL_GET_CLOSE
+#define WOLFSSL_BIO_CTRL_GET_CLOSE BIO_CTRL_GET_CLOSE
+#define WOLFSSL_BIO_CTRL_SET_CLOSE BIO_CTRL_SET_CLOSE
+#define WOLFSSL_BIO_CTRL_FLUSH BIO_CTRL_FLUSH
+#define WOLFSSL_BIO_CTRL_DUP BIO_CTRL_DUP
+#define wolfSSL_BIO_set_retry_write BIO_set_retry_write
+#define wolfSSL_BIO_set_retry_read BIO_set_retry_read
+#endif /* !WOLFSSL_BIO_CTRL_GET_CLOSE */
+
+#else /* HAVE_WOLFSSL_BIO */
#undef USE_BIO_CHAIN
#endif
@@ -163,7 +179,7 @@ wolfssl_tls13_secret_callback(SSL *ssl, int id, const unsigned char *secret, #endif /* defined(HAVE_SECRET_CALLBACK) && defined(WOLFSSL_TLS13) */
static void
-wolfssl_log_tls12_secret(SSL *ssl)
+wolfssl_log_tls12_secret(WOLFSSL *ssl)
{
unsigned char *ms, *sr, *cr;
unsigned int msLen, srLen, crLen, i, x = 0;
@@ -187,7 +203,7 @@ wolfssl_log_tls12_secret(SSL *ssl) #endif
if(wolfSSL_get_keys(ssl, &ms, &msLen, &sr, &srLen, &cr, &crLen) !=
- SSL_SUCCESS) {
+ WOLFSSL_SUCCESS) {
return;
}
@@ -208,11 +224,11 @@ wolfssl_log_tls12_secret(SSL *ssl) static int wolfssl_do_file_type(const char *type)
{
if(!type || !type[0])
- return SSL_FILETYPE_PEM;
+ return WOLFSSL_FILETYPE_PEM;
if(strcasecompare(type, "PEM"))
- return SSL_FILETYPE_PEM;
+ return WOLFSSL_FILETYPE_PEM;
if(strcasecompare(type, "DER"))
- return SSL_FILETYPE_ASN1;
+ return WOLFSSL_FILETYPE_ASN1;
return -1;
}
@@ -237,7 +253,9 @@ static const struct group_name_map gnm[] = { static int wolfssl_bio_cf_create(WOLFSSL_BIO *bio)
{
+#ifdef USE_FULL_BIO
wolfSSL_BIO_set_shutdown(bio, 1);
+#endif
wolfSSL_BIO_set_data(bio, NULL);
return 1;
}
@@ -251,28 +269,35 @@ static int wolfssl_bio_cf_destroy(WOLFSSL_BIO *bio) static long wolfssl_bio_cf_ctrl(WOLFSSL_BIO *bio, int cmd, long num, void *ptr)
{
- struct Curl_cfilter *cf = BIO_get_data(bio);
+ struct Curl_cfilter *cf = wolfSSL_BIO_get_data(bio);
long ret = 1;
(void)cf;
(void)ptr;
+ (void)num;
switch(cmd) {
- case BIO_CTRL_GET_CLOSE:
+ case WOLFSSL_BIO_CTRL_GET_CLOSE:
+#ifdef USE_FULL_BIO
ret = (long)wolfSSL_BIO_get_shutdown(bio);
+#else
+ ret = 0;
+#endif
break;
- case BIO_CTRL_SET_CLOSE:
+ case WOLFSSL_BIO_CTRL_SET_CLOSE:
+#ifdef USE_FULL_BIO
wolfSSL_BIO_set_shutdown(bio, (int)num);
+#endif
break;
- case BIO_CTRL_FLUSH:
+ case WOLFSSL_BIO_CTRL_FLUSH:
/* we do no delayed writes, but if we ever would, this
* needs to trigger it. */
ret = 1;
break;
- case BIO_CTRL_DUP:
+ case WOLFSSL_BIO_CTRL_DUP:
ret = 1;
break;
-#ifdef BIO_CTRL_EOF
- case BIO_CTRL_EOF:
+#ifdef WOLFSSL_BIO_CTRL_EOF
+ case WOLFSSL_BIO_CTRL_EOF:
/* EOF has been reached on input? */
return (!cf->next || !cf->next->connected);
#endif
@@ -309,9 +334,11 @@ static int wolfssl_bio_cf_out_write(WOLFSSL_BIO *bio, backend->io_result = result;
CURL_TRC_CF(data, cf, "bio_write(len=%d) -> %zd, %d",
blen, nwritten, result);
+#ifdef USE_FULL_BIO
wolfSSL_BIO_clear_retry_flags(bio);
+#endif
if(nwritten < 0 && CURLE_AGAIN == result) {
- BIO_set_retry_write(bio);
+ wolfSSL_BIO_set_retry_write(bio);
if(backend->shutting_down && !backend->io_send_blocked_len)
backend->io_send_blocked_len = blen;
}
@@ -338,9 +365,11 @@ static int wolfssl_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;
CURL_TRC_CF(data, cf, "bio_read(len=%d) -> %zd, %d", blen, nread, result);
+#ifdef USE_FULL_BIO
wolfSSL_BIO_clear_retry_flags(bio);
+#endif
if(nread < 0 && CURLE_AGAIN == result)
- BIO_set_retry_read(bio);
+ wolfSSL_BIO_set_retry_read(bio);
else if(nread == 0)
connssl->peer_closed = TRUE;
return (int)nread;
@@ -350,7 +379,8 @@ static WOLFSSL_BIO_METHOD *wolfssl_bio_cf_method = NULL; static void wolfssl_bio_cf_init_methods(void)
{
- wolfssl_bio_cf_method = wolfSSL_BIO_meth_new(BIO_TYPE_MEM, "wolfSSL CF BIO");
+ wolfssl_bio_cf_method = wolfSSL_BIO_meth_new(WOLFSSL_BIO_MEMORY,
+ "wolfSSL CF BIO");
wolfSSL_BIO_meth_set_write(wolfssl_bio_cf_method, &wolfssl_bio_cf_out_write);
wolfSSL_BIO_meth_set_read(wolfssl_bio_cf_method, &wolfssl_bio_cf_in_read);
wolfSSL_BIO_meth_set_ctrl(wolfssl_bio_cf_method, &wolfssl_bio_cf_ctrl);
@@ -370,9 +400,114 @@ static void wolfssl_bio_cf_free_methods(void) #endif /* !USE_BIO_CHAIN */
+static void wolfssl_session_free(void *sdata, size_t slen)
+{
+ (void)slen;
+ free(sdata);
+}
+
+CURLcode wssl_cache_session(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct ssl_peer *peer,
+ WOLFSSL_SESSION *session)
+{
+ CURLcode result = CURLE_OK;
+ unsigned char *sdata = NULL;
+ unsigned int slen;
+
+ if(!session)
+ goto out;
+
+ slen = wolfSSL_i2d_SSL_SESSION(session, NULL);
+ if(slen <= 0) {
+ CURL_TRC_CF(data, cf, "fail to assess session length: %u", slen);
+ result = CURLE_FAILED_INIT;
+ goto out;
+ }
+ sdata = calloc(1, slen);
+ if(!sdata) {
+ failf(data, "unable to allocate session buffer of %u bytes", slen);
+ result = CURLE_OUT_OF_MEMORY;
+ goto out;
+ }
+ slen = wolfSSL_i2d_SSL_SESSION(session, &sdata);
+ if(slen <= 0) {
+ CURL_TRC_CF(data, cf, "fail to serialize session: %u", slen);
+ result = CURLE_FAILED_INIT;
+ goto out;
+ }
+
+ Curl_ssl_sessionid_lock(data);
+ result = Curl_ssl_set_sessionid(cf, data, peer, NULL,
+ sdata, slen, wolfssl_session_free);
+ Curl_ssl_sessionid_unlock(data);
+ if(result)
+ failf(data, "failed to add new ssl session to cache (%d)", result);
+ else {
+ CURL_TRC_CF(data, cf, "added new session to cache");
+ sdata = NULL;
+ }
+
+out:
+ free(sdata);
+ return 0;
+}
+
+static int wssl_vtls_new_session_cb(WOLFSSL *ssl, WOLFSSL_SESSION *session)
+{
+ struct Curl_cfilter *cf;
+
+ cf = (struct Curl_cfilter*)wolfSSL_get_app_data(ssl);
+ DEBUGASSERT(cf != NULL);
+ if(cf && session) {
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct Curl_easy *data = CF_DATA_CURRENT(cf);
+ DEBUGASSERT(connssl);
+ DEBUGASSERT(data);
+ if(connssl && data) {
+ (void)wssl_cache_session(cf, data, &connssl->peer, session);
+ }
+ }
+ return 0;
+}
+
+CURLcode wssl_setup_session(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct wolfssl_ctx *wss,
+ struct ssl_peer *peer)
+{
+ void *psdata;
+ const unsigned char *sdata = NULL;
+ size_t slen = 0;
+ CURLcode result = CURLE_OK;
+
+ Curl_ssl_sessionid_lock(data);
+ if(!Curl_ssl_getsessionid(cf, data, peer, &psdata, &slen, NULL)) {
+ WOLFSSL_SESSION *session;
+ sdata = psdata;
+ session = wolfSSL_d2i_SSL_SESSION(NULL, &sdata, (long)slen);
+ if(session) {
+ int ret = wolfSSL_set_session(wss->handle, session);
+ if(ret != WOLFSSL_SUCCESS) {
+ Curl_ssl_delsessionid(data, psdata);
+ infof(data, "previous session not accepted (%d), "
+ "removing from cache", ret);
+ }
+ else
+ infof(data, "SSL reusing session ID");
+ wolfSSL_SESSION_free(session);
+ }
+ else {
+ failf(data, "could not decode previous session");
+ }
+ }
+ Curl_ssl_sessionid_unlock(data);
+ return result;
+}
+
static CURLcode populate_x509_store(struct Curl_cfilter *cf,
struct Curl_easy *data,
- X509_STORE *store,
+ WOLFSSL_X509_STORE *store,
struct wolfssl_ctx *wssl)
{
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
@@ -382,7 +517,7 @@ static CURLcode populate_x509_store(struct Curl_cfilter *cf, (ca_info_blob ? NULL : conn_config->CAfile);
const char * const ssl_capath = conn_config->CApath;
struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
- bool imported_native_ca = false;
+ bool imported_native_ca = FALSE;
#if !defined(NO_FILESYSTEM) && defined(WOLFSSL_SYS_CA_CERTS)
/* load native CA certificates */
@@ -391,7 +526,7 @@ static CURLcode populate_x509_store(struct Curl_cfilter *cf, infof(data, "error importing native CA store, continuing anyway");
}
else {
- imported_native_ca = true;
+ imported_native_ca = TRUE;
infof(data, "successfully imported native CA store");
wssl->x509_store_setup = TRUE;
}
@@ -402,7 +537,8 @@ static CURLcode populate_x509_store(struct Curl_cfilter *cf, if(ca_info_blob) {
if(wolfSSL_CTX_load_verify_buffer(wssl->ctx, ca_info_blob->data,
(long)ca_info_blob->len,
- SSL_FILETYPE_PEM) != SSL_SUCCESS) {
+ WOLFSSL_FILETYPE_PEM) !=
+ WOLFSSL_SUCCESS) {
if(imported_native_ca) {
infof(data, "error importing CA certificate blob, continuing anyway");
}
@@ -421,7 +557,7 @@ static CURLcode populate_x509_store(struct Curl_cfilter *cf, /* load trusted cacert from file if not blob */
CURL_TRC_CF(data, cf, "populate_x509_store, path=%s, blob=%d",
- ssl_cafile? ssl_cafile : "none", !!ca_info_blob);
+ ssl_cafile ? ssl_cafile : "none", !!ca_info_blob);
if(!store)
return CURLE_OUT_OF_MEMORY;
@@ -431,7 +567,7 @@ static CURLcode populate_x509_store(struct Curl_cfilter *cf, ssl_cafile,
ssl_capath,
WOLFSSL_LOAD_FLAG_IGNORE_ERR);
- if(SSL_SUCCESS != rc) {
+ if(WOLFSSL_SUCCESS != rc) {
if(conn_config->verifypeer) {
/* Fail if we insist on successfully verifying the server. */
failf(data, "error setting certificate verify locations:"
@@ -493,7 +629,7 @@ cached_x509_store_expired(const struct Curl_easy *data, timediff_t timeout_ms = cfg->ca_cache_timeout * (timediff_t)1000;
if(timeout_ms < 0)
- return false;
+ return FALSE;
return elapsed_ms >= timeout_ms;
}
@@ -509,17 +645,17 @@ cached_x509_store_different(struct Curl_cfilter *cf, return strcmp(mb->CAfile, conn_config->CAfile);
}
-static X509_STORE *get_cached_x509_store(struct Curl_cfilter *cf,
- const struct Curl_easy *data)
+static WOLFSSL_X509_STORE *get_cached_x509_store(struct Curl_cfilter *cf,
+ const struct Curl_easy *data)
{
struct Curl_multi *multi = data->multi;
struct wssl_x509_share *share;
WOLFSSL_X509_STORE *store = NULL;
DEBUGASSERT(multi);
- share = multi? Curl_hash_pick(&multi->proto_hash,
- (void *)MPROTO_WSSL_X509_KEY,
- sizeof(MPROTO_WSSL_X509_KEY)-1) : NULL;
+ share = multi ? Curl_hash_pick(&multi->proto_hash,
+ (void *)MPROTO_WSSL_X509_KEY,
+ sizeof(MPROTO_WSSL_X509_KEY)-1) : NULL;
if(share && share->store &&
!cached_x509_store_expired(data, share) &&
!cached_x509_store_different(cf, share)) {
@@ -531,7 +667,7 @@ static X509_STORE *get_cached_x509_store(struct Curl_cfilter *cf, static void set_cached_x509_store(struct Curl_cfilter *cf,
const struct Curl_easy *data,
- X509_STORE *store)
+ WOLFSSL_X509_STORE *store)
{
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
struct Curl_multi *multi = data->multi;
@@ -563,13 +699,13 @@ static void set_cached_x509_store(struct Curl_cfilter *cf, if(conn_config->CAfile) {
CAfile = strdup(conn_config->CAfile);
if(!CAfile) {
- X509_STORE_free(store);
+ wolfSSL_X509_STORE_free(store);
return;
}
}
if(share->store) {
- X509_STORE_free(share->store);
+ wolfSSL_X509_STORE_free(share->store);
free(share->CAfile);
}
@@ -609,7 +745,7 @@ CURLcode Curl_wssl_setup_x509_store(struct Curl_cfilter *cf, else if(cache_criteria_met) {
/* wolfSSL's initial store in CTX is not shareable by default.
* Make a new one, suitable for adding to the cache. See #14278 */
- X509_STORE *store = wolfSSL_X509_STORE_new();
+ WOLFSSL_X509_STORE *store = wolfSSL_X509_STORE_new();
if(!store) {
failf(data, "SSL: could not create a X509 store");
return CURLE_OUT_OF_MEMORY;
@@ -623,7 +759,7 @@ CURLcode Curl_wssl_setup_x509_store(struct Curl_cfilter *cf, }
else {
/* We never share the CTX's store, use it. */
- X509_STORE *store = wolfSSL_CTX_get_cert_store(wssl->ctx);
+ WOLFSSL_X509_STORE *store = wolfSSL_CTX_get_cert_store(wssl->ctx);
result = populate_x509_store(cf, data, store, wssl);
}
@@ -631,36 +767,35 @@ CURLcode Curl_wssl_setup_x509_store(struct Curl_cfilter *cf, }
#ifdef WOLFSSL_TLS13
-static size_t
-wssl_get_default_ciphers(bool tls13, char *buf, size_t size)
+static CURLcode
+wssl_add_default_ciphers(bool tls13, struct dynbuf *buf)
{
- size_t len = 0;
- char *term = buf;
int i;
char *str;
- size_t n;
for(i = 0; (str = wolfSSL_get_cipher_list(i)); i++) {
+ size_t n;
if((strncmp(str, "TLS13", 5) == 0) != tls13)
continue;
- n = strlen(str);
- if(buf && len + n + 1 <= size) {
- memcpy(buf + len, str, n);
- term = buf + len + n;
- *term = ':';
+ /* if there already is data in the string, add colon separator */
+ if(Curl_dyn_len(buf)) {
+ CURLcode result = Curl_dyn_addn(buf, ":", 1);
+ if(result)
+ return result;
}
- len += n + 1;
- }
- if(buf)
- *term = '\0';
+ n = strlen(str);
+ if(Curl_dyn_addn(buf, str, n))
+ return CURLE_OUT_OF_MEMORY;
+ }
- return len > 0 ? len - 1 : 0;
+ return CURLE_OK;
}
#endif
-#if LIBWOLFSSL_VERSION_HEX < 0x04002000 /* 4.2.0 (2019) */
+/* 4.2.0 (2019) */
+#if LIBWOLFSSL_VERSION_HEX < 0x04002000 || !defined(OPENSSL_EXTRA)
static int
wssl_legacy_CTX_set_min_proto_version(WOLFSSL_CTX* ctx, int version)
{
@@ -707,7 +842,7 @@ static CURLcode wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
{
int res;
- char *ciphers, *curves;
+ char *curves;
struct ssl_connect_data *connssl = cf->ctx;
struct wolfssl_ctx *backend =
(struct wolfssl_ctx *)connssl->backend;
@@ -798,50 +933,50 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) }
#ifndef WOLFSSL_TLS13
- ciphers = conn_config->cipher_list;
- if(ciphers) {
- if(!SSL_CTX_set_cipher_list(backend->ctx, ciphers)) {
- failf(data, "failed setting cipher list: %s", ciphers);
- return CURLE_SSL_CIPHER;
+ {
+ char *ciphers = conn_config->cipher_list;
+ if(ciphers) {
+ if(!SSL_CTX_set_cipher_list(backend->ctx, ciphers)) {
+ failf(data, "failed setting cipher list: %s", ciphers);
+ return CURLE_SSL_CIPHER;
+ }
+ infof(data, "Cipher selection: %s", ciphers);
}
- infof(data, "Cipher selection: %s", ciphers);
}
#else
+#define MAX_CIPHER_LEN 4096
if(conn_config->cipher_list || conn_config->cipher_list13) {
const char *ciphers12 = conn_config->cipher_list;
const char *ciphers13 = conn_config->cipher_list13;
-
- /* Set ciphers to a combination of ciphers_list and ciphers_list13.
- * If cipher_list is not set use the default TLSv1.2 (1.1, 1.0) ciphers.
- * If cipher_list13 is not set use the default TLSv1.3 ciphers. */
- size_t len13 = ciphers13 ? strlen(ciphers13)
- : wssl_get_default_ciphers(true, NULL, 0);
- size_t len12 = ciphers12 ? strlen(ciphers12)
- : wssl_get_default_ciphers(false, NULL, 0);
-
- ciphers = malloc(len13 + 1 + len12 + 1);
- if(!ciphers)
- return CURLE_OUT_OF_MEMORY;
+ struct dynbuf c;
+ CURLcode result;
+ Curl_dyn_init(&c, MAX_CIPHER_LEN);
if(ciphers13)
- memcpy(ciphers, ciphers13, len13);
+ result = Curl_dyn_add(&c, ciphers13);
else
- wssl_get_default_ciphers(true, ciphers, len13 + 1);
- ciphers[len13] = ':';
+ result = wssl_add_default_ciphers(TRUE, &c);
- if(ciphers12)
- memcpy(ciphers + len13 + 1, ciphers12, len12);
- else
- wssl_get_default_ciphers(false, ciphers + len13 + 1, len12 + 1);
- ciphers[len13 + 1 + len12] = '\0';
+ if(!result) {
+ if(ciphers12) {
+ if(Curl_dyn_len(&c))
+ result = Curl_dyn_addn(&c, ":", 1);
+ if(!result)
+ result = Curl_dyn_add(&c, ciphers12);
+ }
+ else
+ result = wssl_add_default_ciphers(FALSE, &c);
+ }
+ if(result)
+ return result;
- if(!SSL_CTX_set_cipher_list(backend->ctx, ciphers)) {
- failf(data, "failed setting cipher list: %s", ciphers);
- free(ciphers);
+ if(!wolfSSL_CTX_set_cipher_list(backend->ctx, Curl_dyn_ptr(&c))) {
+ failf(data, "failed setting cipher list: %s", Curl_dyn_ptr(&c));
+ Curl_dyn_free(&c);
return CURLE_SSL_CIPHER;
}
- infof(data, "Cipher selection: %s", ciphers);
- free(ciphers);
+ infof(data, "Cipher selection: %s", Curl_dyn_ptr(&c));
+ Curl_dyn_free(&c);
}
#endif
@@ -859,7 +994,7 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) if(pqkem == 0)
#endif
{
- if(!SSL_CTX_set1_curves_list(backend->ctx, curves)) {
+ if(!wolfSSL_CTX_set1_curves_list(backend->ctx, curves)) {
failf(data, "failed setting curves list: '%s'", curves);
return CURLE_SSL_CIPHER;
}
@@ -960,8 +1095,8 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) * anyway. In the latter case the result of the verification is checked with
* SSL_get_verify_result() below. */
wolfSSL_CTX_set_verify(backend->ctx,
- conn_config->verifypeer?SSL_VERIFY_PEER:
- SSL_VERIFY_NONE, NULL);
+ conn_config->verifypeer ? WOLFSSL_VERIFY_PEER :
+ WOLFSSL_VERIFY_NONE, NULL);
#ifdef HAVE_SNI
if(connssl->peer.sni) {
@@ -1028,7 +1163,7 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) if(result ||
wolfSSL_UseALPN(backend->handle,
(char *)proto.data, (unsigned int)proto.len,
- WOLFSSL_ALPN_CONTINUE_ON_MISMATCH) != SSL_SUCCESS) {
+ WOLFSSL_ALPN_CONTINUE_ON_MISMATCH) != WOLFSSL_SUCCESS) {
failf(data, "SSL: failed setting ALPN protocols");
return CURLE_SSL_CONNECT_ERROR;
}
@@ -1056,20 +1191,11 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) /* Check if there is a cached ID we can/should use here! */
if(ssl_config->primary.cache_session) {
- void *ssl_sessionid = NULL;
-
- Curl_ssl_sessionid_lock(data);
- if(!Curl_ssl_getsessionid(cf, data, &connssl->peer,
- &ssl_sessionid, NULL)) {
- /* we got a session id, use it! */
- if(!SSL_set_session(backend->handle, ssl_sessionid)) {
- Curl_ssl_delsessionid(data, ssl_sessionid);
- infof(data, "cannot use session ID, going on without");
- }
- else
- infof(data, "SSL reusing session ID");
- }
- Curl_ssl_sessionid_unlock(data);
+ /* Set session from cache if there is one */
+ (void)wssl_setup_session(cf, data, backend, &connssl->peer);
+ /* Register to get notified when a new session is received */
+ wolfSSL_set_app_data(backend->handle, cf);
+ wolfSSL_CTX_sess_set_new_cb(backend->ctx, wssl_vtls_new_session_cb);
}
#ifdef USE_ECH
@@ -1152,7 +1278,7 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) {
WOLFSSL_BIO *bio;
- bio = BIO_new(wolfssl_bio_cf_method);
+ bio = wolfSSL_BIO_new(wolfssl_bio_cf_method);
if(!bio)
return CURLE_OUT_OF_MEMORY;
@@ -1200,8 +1326,8 @@ wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) (struct wolfssl_ctx *)connssl->backend;
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
#ifndef CURL_DISABLE_PROXY
- const char * const pinnedpubkey = Curl_ssl_cf_is_proxy(cf)?
- data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]:
+ const char * const pinnedpubkey = Curl_ssl_cf_is_proxy(cf) ?
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
data->set.str[STRING_SSL_PINNEDPUBLICKEY];
#else
const char * const pinnedpubkey = data->set.str[STRING_SSL_PINNEDPUBLICKEY];
@@ -1213,9 +1339,9 @@ wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) /* Enable RFC2818 checks */
if(conn_config->verifyhost) {
- char *snihost = connssl->peer.sni?
- connssl->peer.sni : connssl->peer.hostname;
- if(wolfSSL_check_domain_name(backend->handle, snihost) == SSL_FAILURE)
+ char *snihost = connssl->peer.sni ?
+ connssl->peer.sni : connssl->peer.hostname;
+ if(wolfSSL_check_domain_name(backend->handle, snihost) == WOLFSSL_FAILURE)
return CURLE_SSL_CONNECT_ERROR;
}
@@ -1244,7 +1370,7 @@ wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) * Note that OpenSSL SSL_want_read() is always true here. If wolfSSL ever
* changes, the worst case is that no key is logged on error.
*/
- if(ret == SSL_SUCCESS ||
+ if(ret == WOLFSSL_SUCCESS ||
(!wolfSSL_want_read(backend->handle) &&
!wolfSSL_want_write(backend->handle))) {
wolfssl_log_tls12_secret(backend->handle);
@@ -1258,11 +1384,11 @@ wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) if(ret != 1) {
int detail = wolfSSL_get_error(backend->handle, ret);
- if(SSL_ERROR_WANT_READ == detail) {
+ if(WOLFSSL_ERROR_WANT_READ == detail) {
connssl->io_need = CURL_SSL_IO_NEED_RECV;
return CURLE_OK;
}
- else if(SSL_ERROR_WANT_WRITE == detail) {
+ else if(WOLFSSL_ERROR_WANT_WRITE == detail) {
connssl->io_need = CURL_SSL_IO_NEED_SEND;
return CURLE_OK;
}
@@ -1354,7 +1480,7 @@ wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) if(pinnedpubkey) {
#ifdef KEEP_PEER_CERT
- X509 *x509;
+ WOLFSSL_X509 *x509;
const char *x509_der;
int x509_der_len;
struct Curl_X509certificate x509_parsed;
@@ -1406,12 +1532,12 @@ wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) rc = wolfSSL_ALPN_GetProtocol(backend->handle, &protocol, &protocol_len);
- if(rc == SSL_SUCCESS) {
- Curl_alpn_set_negotiated(cf, data, (const unsigned char *)protocol,
- protocol_len);
+ if(rc == WOLFSSL_SUCCESS) {
+ Curl_alpn_set_negotiated(cf, data, connssl,
+ (const unsigned char *)protocol, protocol_len);
}
- else if(rc == SSL_ALPN_NOT_FOUND)
- Curl_alpn_set_negotiated(cf, data, NULL, 0);
+ else if(rc == WOLFSSL_ALPN_NOT_FOUND)
+ Curl_alpn_set_negotiated(cf, data, connssl, NULL, 0);
else {
failf(data, "ALPN, failure getting protocol, error %d", rc);
return CURLE_SSL_CONNECT_ERROR;
@@ -1431,50 +1557,6 @@ wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) return CURLE_OK;
}
-
-static void wolfssl_session_free(void *sessionid, size_t idsize)
-{
- (void)idsize;
- wolfSSL_SESSION_free(sessionid);
-}
-
-
-static CURLcode
-wolfssl_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
-{
- CURLcode result = CURLE_OK;
- struct ssl_connect_data *connssl = cf->ctx;
- struct wolfssl_ctx *backend =
- (struct wolfssl_ctx *)connssl->backend;
- const struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
-
- DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
- DEBUGASSERT(backend);
-
- if(ssl_config->primary.cache_session) {
- /* 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);
- /* call takes ownership of `our_ssl_sessionid` */
- result = Curl_ssl_set_sessionid(cf, data, &connssl->peer,
- our_ssl_sessionid, 0,
- wolfssl_session_free);
- Curl_ssl_sessionid_unlock(data);
- if(result) {
- failf(data, "failed to store ssl session");
- return result;
- }
- }
- }
-
- connssl->connecting_state = ssl_connect_done;
-
- return result;
-}
-
-
static ssize_t wolfssl_send(struct Curl_cfilter *cf,
struct Curl_easy *data,
const void *mem,
@@ -1496,8 +1578,8 @@ static ssize_t wolfssl_send(struct Curl_cfilter *cf, int err = wolfSSL_get_error(backend->handle, rc);
switch(err) {
- case SSL_ERROR_WANT_READ:
- case SSL_ERROR_WANT_WRITE:
+ case WOLFSSL_ERROR_WANT_READ:
+ case WOLFSSL_ERROR_WANT_WRITE:
/* there is data pending, re-invoke SSL_write() */
CURL_TRC_CF(data, cf, "wolfssl_send(len=%zu) -> AGAIN", len);
*curlcode = CURLE_AGAIN;
@@ -1546,14 +1628,14 @@ static CURLcode wolfssl_shutdown(struct Curl_cfilter *cf, wctx->shutting_down = TRUE;
connssl->io_need = CURL_SSL_IO_NEED_NONE;
*done = FALSE;
- if(!(wolfSSL_get_shutdown(wctx->handle) & SSL_SENT_SHUTDOWN)) {
+ if(!(wolfSSL_get_shutdown(wctx->handle) & WOLFSSL_SENT_SHUTDOWN)) {
/* We have not started the shutdown from our side yet. Check
* if the server already sent us one. */
- ERR_clear_error();
+ wolfSSL_ERR_clear_error();
nread = wolfSSL_read(wctx->handle, buf, (int)sizeof(buf));
err = wolfSSL_get_error(wctx->handle, nread);
CURL_TRC_CF(data, cf, "wolfSSL_read, nread=%d, err=%d", nread, err);
- if(!nread && err == SSL_ERROR_ZERO_RETURN) {
+ if(!nread && err == WOLFSSL_ERROR_ZERO_RETURN) {
bool input_pending;
/* Yes, it did. */
if(!send_shutdown) {
@@ -1576,13 +1658,13 @@ static CURLcode wolfssl_shutdown(struct Curl_cfilter *cf, /* SSL should now have started the shutdown from our side. Since it
* was not complete, we are lacking the close notify from the server. */
if(send_shutdown) {
- ERR_clear_error();
+ wolfSSL_ERR_clear_error();
if(wolfSSL_shutdown(wctx->handle) == 1) {
CURL_TRC_CF(data, cf, "SSL shutdown finished");
*done = TRUE;
goto out;
}
- if(SSL_ERROR_WANT_WRITE == wolfSSL_get_error(wctx->handle, nread)) {
+ if(WOLFSSL_ERROR_WANT_WRITE == wolfSSL_get_error(wctx->handle, nread)) {
CURL_TRC_CF(data, cf, "SSL shutdown still wants to send");
connssl->io_need = CURL_SSL_IO_NEED_SEND;
goto out;
@@ -1592,25 +1674,25 @@ static CURLcode wolfssl_shutdown(struct Curl_cfilter *cf, }
for(i = 0; i < 10; ++i) {
- ERR_clear_error();
+ wolfSSL_ERR_clear_error();
nread = wolfSSL_read(wctx->handle, buf, (int)sizeof(buf));
if(nread <= 0)
break;
}
err = wolfSSL_get_error(wctx->handle, nread);
switch(err) {
- case SSL_ERROR_ZERO_RETURN: /* no more data */
+ case WOLFSSL_ERROR_ZERO_RETURN: /* no more data */
CURL_TRC_CF(data, cf, "SSL shutdown received");
*done = TRUE;
break;
- case SSL_ERROR_NONE: /* just did not get anything */
- case SSL_ERROR_WANT_READ:
+ case WOLFSSL_ERROR_NONE: /* just did not get anything */
+ case WOLFSSL_ERROR_WANT_READ:
/* SSL has send its notify and now wants to read the reply
* from the server. We are not really interested in that. */
CURL_TRC_CF(data, cf, "SSL shutdown sent, want receive");
connssl->io_need = CURL_SSL_IO_NEED_RECV;
break;
- case SSL_ERROR_WANT_WRITE:
+ case WOLFSSL_ERROR_WANT_WRITE:
CURL_TRC_CF(data, cf, "SSL shutdown send blocked");
connssl->io_need = CURL_SSL_IO_NEED_SEND;
break;
@@ -1671,13 +1753,18 @@ static ssize_t wolfssl_recv(struct Curl_cfilter *cf, int err = wolfSSL_get_error(backend->handle, nread);
switch(err) {
- case SSL_ERROR_ZERO_RETURN: /* no more data */
+ case WOLFSSL_ERROR_ZERO_RETURN: /* no more data */
CURL_TRC_CF(data, cf, "wolfssl_recv(len=%zu) -> CLOSED", blen);
*curlcode = CURLE_OK;
return 0;
- case SSL_ERROR_NONE:
- case SSL_ERROR_WANT_READ:
- case SSL_ERROR_WANT_WRITE:
+ case WOLFSSL_ERROR_NONE:
+ case WOLFSSL_ERROR_WANT_READ:
+ case WOLFSSL_ERROR_WANT_WRITE:
+ if(!backend->io_result && connssl->peer_closed) {
+ CURL_TRC_CF(data, cf, "wolfssl_recv(len=%zu) -> CLOSED", blen);
+ *curlcode = CURLE_OK;
+ return 0;
+ }
/* there is data pending, re-invoke wolfSSL_read() */
CURL_TRC_CF(data, cf, "wolfssl_recv(len=%zu) -> AGAIN", blen);
*curlcode = CURLE_AGAIN;
@@ -1688,7 +1775,12 @@ static ssize_t wolfssl_recv(struct Curl_cfilter *cf, *curlcode = CURLE_AGAIN;
return -1;
}
- {
+ else if(!backend->io_result && connssl->peer_closed) {
+ CURL_TRC_CF(data, cf, "wolfssl_recv(len=%zu) -> CLOSED", blen);
+ *curlcode = CURLE_OK;
+ return 0;
+ }
+ else {
char error_buffer[256];
failf(data, "SSL read: %s, errno %d",
wolfssl_strerror((unsigned long)err, error_buffer,
@@ -1721,7 +1813,7 @@ static int wolfssl_init(void) #ifdef OPENSSL_EXTRA
Curl_tls_keylog_open();
#endif
- ret = (wolfSSL_Init() == SSL_SUCCESS);
+ ret = (wolfSSL_Init() == WOLFSSL_SUCCESS);
wolfssl_bio_cf_init_methods();
return ret;
}
@@ -1748,7 +1840,7 @@ static bool wolfssl_data_pending(struct Curl_cfilter *cf, backend = (struct wolfssl_ctx *)ctx->backend;
if(backend->handle) /* SSL is in use */
- return (0 != wolfSSL_pending(backend->handle)) ? TRUE : FALSE;
+ return wolfSSL_pending(backend->handle);
else
return FALSE;
}
@@ -1762,7 +1854,6 @@ wolfssl_connect_common(struct Curl_cfilter *cf, CURLcode result;
struct ssl_connect_data *connssl = cf->ctx;
curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data);
- int what;
/* check if the connection has already been established */
if(ssl_connection_complete == connssl->state) {
@@ -1798,14 +1889,12 @@ wolfssl_connect_common(struct Curl_cfilter *cf, /* if ssl is expecting something, check if it is available. */
if(connssl->io_need) {
-
- curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND)?
- sockfd:CURL_SOCKET_BAD;
- curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV)?
- sockfd:CURL_SOCKET_BAD;
-
- what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
- nonblocking?0:timeout_ms);
+ curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND) ?
+ sockfd : CURL_SOCKET_BAD;
+ curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV) ?
+ sockfd : CURL_SOCKET_BAD;
+ int what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
+ nonblocking ? 0 : timeout_ms);
if(what < 0) {
/* fatal error */
failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
@@ -1838,9 +1927,9 @@ wolfssl_connect_common(struct Curl_cfilter *cf, } /* repeat step2 until all transactions are done. */
if(ssl_connect_3 == connssl->connecting_state) {
- result = wolfssl_connect_step3(cf, data);
- if(result)
- return result;
+ /* In other backends, this is where we verify the certificate, but
+ * wolfSSL already does that as part of the handshake. */
+ connssl->connecting_state = ssl_connect_done;
}
if(ssl_connect_done == connssl->connecting_state) {
diff --git a/libs/libcurl/src/vtls/wolfssl.h b/libs/libcurl/src/vtls/wolfssl.h index 0e0ffb6e70..0a4d253a58 100644 --- a/libs/libcurl/src/vtls/wolfssl.h +++ b/libs/libcurl/src/vtls/wolfssl.h @@ -26,13 +26,16 @@ #include "curl_setup.h"
#ifdef USE_WOLFSSL
-#include <wolfssl/version.h>
-#include <wolfssl/options.h>
-#include <wolfssl/ssl.h>
-#include <wolfssl/error-ssl.h>
#include "urldata.h"
+struct WOLFSSL;
+typedef struct WOLFSSL WOLFSSL;
+struct WOLFSSL_CTX;
+typedef struct WOLFSSL_CTX WOLFSSL_CTX;
+struct WOLFSSL_SESSION;
+typedef struct WOLFSSL_SESSION WOLFSSL_SESSION;
+
extern const struct Curl_ssl Curl_ssl_wolfssl;
struct wolfssl_ctx {
@@ -48,5 +51,16 @@ CURLcode Curl_wssl_setup_x509_store(struct Curl_cfilter *cf, struct Curl_easy *data,
struct wolfssl_ctx *wssl);
+CURLcode wssl_setup_session(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct wolfssl_ctx *wss,
+ struct ssl_peer *peer);
+
+CURLcode wssl_cache_session(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct ssl_peer *peer,
+ WOLFSSL_SESSION *session);
+
+
#endif /* USE_WOLFSSL */
#endif /* HEADER_CURL_WOLFSSL_H */
diff --git a/libs/libcurl/src/vtls/x509asn1.c b/libs/libcurl/src/vtls/x509asn1.c index e92449fb2e..6e1fbfab49 100644 --- a/libs/libcurl/src/vtls/x509asn1.c +++ b/libs/libcurl/src/vtls/x509asn1.c @@ -270,7 +270,7 @@ static CURLcode bool2str(struct dynbuf *store, {
if(end - beg != 1)
return CURLE_BAD_FUNCTION_ARGUMENT;
- return Curl_dyn_add(store, *beg? "TRUE": "FALSE");
+ return Curl_dyn_add(store, *beg ? "TRUE": "FALSE");
}
/*
@@ -323,7 +323,7 @@ static CURLcode int2str(struct dynbuf *store, do
val = (val << 8) | *(const unsigned char *) beg++;
while(beg < end);
- return Curl_dyn_addf(store, "%s%x", val >= 10? "0x": "", val);
+ return Curl_dyn_addf(store, "%s%x", val >= 10 ? "0x" : "", val);
}
/*
@@ -551,7 +551,7 @@ static CURLcode GTime2str(struct dynbuf *store, "%.4s-%.2s-%.2s %.2s:%.2s:%c%c%s%.*s%s%.*s",
beg, beg + 4, beg + 6,
beg + 8, beg + 10, sec1, sec2,
- fracl? ".": "", (int)fracl, fracp,
+ fracl ? ".": "", (int)fracl, fracp,
sep, (int)tzl, tzp);
}
|