summaryrefslogtreecommitdiff
path: root/libs/libcurl/src/vtls
diff options
context:
space:
mode:
authordartraiden <wowemuh@gmail.com>2024-05-24 23:43:03 +0300
committerdartraiden <wowemuh@gmail.com>2024-05-24 23:43:03 +0300
commitff76fe6c8f1e3b34c5571437612a038077f29860 (patch)
tree0ae912a13465fa5658253185d4eeab21d6ecdfde /libs/libcurl/src/vtls
parent174bf88b63eaf4b49c00894a3f14fbf9194cae02 (diff)
libcurl: update to 8.8.0
Diffstat (limited to 'libs/libcurl/src/vtls')
-rw-r--r--libs/libcurl/src/vtls/bearssl.c298
-rw-r--r--libs/libcurl/src/vtls/cipher_suite.c716
-rw-r--r--libs/libcurl/src/vtls/cipher_suite.h46
-rw-r--r--libs/libcurl/src/vtls/gtls.c477
-rw-r--r--libs/libcurl/src/vtls/gtls.h40
-rw-r--r--libs/libcurl/src/vtls/keylog.c1
-rw-r--r--libs/libcurl/src/vtls/mbedtls.c237
-rw-r--r--libs/libcurl/src/vtls/openssl.c907
-rw-r--r--libs/libcurl/src/vtls/openssl.h51
-rw-r--r--libs/libcurl/src/vtls/rustls.c238
-rw-r--r--libs/libcurl/src/vtls/schannel.c82
-rw-r--r--libs/libcurl/src/vtls/schannel_int.h10
-rw-r--r--libs/libcurl/src/vtls/sectransp.c47
-rw-r--r--libs/libcurl/src/vtls/vtls.c106
-rw-r--r--libs/libcurl/src/vtls/vtls.h4
-rw-r--r--libs/libcurl/src/vtls/vtls_int.h9
-rw-r--r--libs/libcurl/src/vtls/wolfssl.c174
-rw-r--r--libs/libcurl/src/vtls/x509asn1.c3
18 files changed, 2494 insertions, 952 deletions
diff --git a/libs/libcurl/src/vtls/bearssl.c b/libs/libcurl/src/vtls/bearssl.c
index 9ccfd8f473..f5f6ad3756 100644
--- a/libs/libcurl/src/vtls/bearssl.c
+++ b/libs/libcurl/src/vtls/bearssl.c
@@ -28,6 +28,7 @@
#include <bearssl.h>
#include "bearssl.h"
+#include "cipher_suite.h"
#include "urldata.h"
#include "sendf.h"
#include "inet_pton.h"
@@ -37,7 +38,6 @@
#include "select.h"
#include "multiif.h"
#include "curl_printf.h"
-#include "strcase.h"
/* The last #include files should be: */
#include "curl_memory.h"
@@ -120,9 +120,9 @@ static CURLcode load_cafile(struct cafile_source *source,
br_x509_pkey *pkey;
FILE *fp = 0;
unsigned char buf[BUFSIZ];
- const unsigned char *p;
+ const unsigned char *p = NULL;
const char *name;
- size_t n, i, pushed;
+ size_t n = 0, i, pushed;
DEBUGASSERT(source->type == CAFILE_SOURCE_PATH
|| source->type == CAFILE_SOURCE_BLOB);
@@ -360,219 +360,121 @@ static const br_x509_class x509_vtable = {
x509_get_pkey
};
-struct st_cipher {
- const char *name; /* Cipher suite IANA name. It starts with "TLS_" prefix */
- const char *alias_name; /* Alias name is the same as OpenSSL cipher name */
- uint16_t num; /* BearSSL cipher suite */
-};
-
-/* Macro to initialize st_cipher data structure */
-#define CIPHER_DEF(num, alias) { #num, alias, BR_##num }
-
-static const struct st_cipher ciphertable[] = {
+static const uint16_t ciphertable[] = {
/* RFC 2246 TLS 1.0 */
- CIPHER_DEF(TLS_RSA_WITH_3DES_EDE_CBC_SHA, /* 0x000A */
- "DES-CBC3-SHA"),
+ BR_TLS_RSA_WITH_3DES_EDE_CBC_SHA, /* 0x000A */
/* RFC 3268 TLS 1.0 AES */
- CIPHER_DEF(TLS_RSA_WITH_AES_128_CBC_SHA, /* 0x002F */
- "AES128-SHA"),
- CIPHER_DEF(TLS_RSA_WITH_AES_256_CBC_SHA, /* 0x0035 */
- "AES256-SHA"),
+ BR_TLS_RSA_WITH_AES_128_CBC_SHA, /* 0x002F */
+ BR_TLS_RSA_WITH_AES_256_CBC_SHA, /* 0x0035 */
/* RFC 5246 TLS 1.2 */
- CIPHER_DEF(TLS_RSA_WITH_AES_128_CBC_SHA256, /* 0x003C */
- "AES128-SHA256"),
- CIPHER_DEF(TLS_RSA_WITH_AES_256_CBC_SHA256, /* 0x003D */
- "AES256-SHA256"),
+ BR_TLS_RSA_WITH_AES_128_CBC_SHA256, /* 0x003C */
+ BR_TLS_RSA_WITH_AES_256_CBC_SHA256, /* 0x003D */
/* RFC 5288 TLS 1.2 AES GCM */
- CIPHER_DEF(TLS_RSA_WITH_AES_128_GCM_SHA256, /* 0x009C */
- "AES128-GCM-SHA256"),
- CIPHER_DEF(TLS_RSA_WITH_AES_256_GCM_SHA384, /* 0x009D */
- "AES256-GCM-SHA384"),
+ BR_TLS_RSA_WITH_AES_128_GCM_SHA256, /* 0x009C */
+ BR_TLS_RSA_WITH_AES_256_GCM_SHA384, /* 0x009D */
/* RFC 4492 TLS 1.0 ECC */
- CIPHER_DEF(TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, /* 0xC003 */
- "ECDH-ECDSA-DES-CBC3-SHA"),
- CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, /* 0xC004 */
- "ECDH-ECDSA-AES128-SHA"),
- CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, /* 0xC005 */
- "ECDH-ECDSA-AES256-SHA"),
- CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, /* 0xC008 */
- "ECDHE-ECDSA-DES-CBC3-SHA"),
- CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, /* 0xC009 */
- "ECDHE-ECDSA-AES128-SHA"),
- CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, /* 0xC00A */
- "ECDHE-ECDSA-AES256-SHA"),
- CIPHER_DEF(TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, /* 0xC00D */
- "ECDH-RSA-DES-CBC3-SHA"),
- CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, /* 0xC00E */
- "ECDH-RSA-AES128-SHA"),
- CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, /* 0xC00F */
- "ECDH-RSA-AES256-SHA"),
- CIPHER_DEF(TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, /* 0xC012 */
- "ECDHE-RSA-DES-CBC3-SHA"),
- CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, /* 0xC013 */
- "ECDHE-RSA-AES128-SHA"),
- CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, /* 0xC014 */
- "ECDHE-RSA-AES256-SHA"),
+ BR_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, /* 0xC003 */
+ BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, /* 0xC004 */
+ BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, /* 0xC005 */
+ BR_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, /* 0xC008 */
+ BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, /* 0xC009 */
+ BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, /* 0xC00A */
+ BR_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, /* 0xC00D */
+ BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, /* 0xC00E */
+ BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, /* 0xC00F */
+ BR_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, /* 0xC012 */
+ BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, /* 0xC013 */
+ BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, /* 0xC014 */
/* RFC 5289 TLS 1.2 ECC HMAC SHA256/384 */
- CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, /* 0xC023 */
- "ECDHE-ECDSA-AES128-SHA256"),
- CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, /* 0xC024 */
- "ECDHE-ECDSA-AES256-SHA384"),
- CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, /* 0xC025 */
- "ECDH-ECDSA-AES128-SHA256"),
- CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, /* 0xC026 */
- "ECDH-ECDSA-AES256-SHA384"),
- CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, /* 0xC027 */
- "ECDHE-RSA-AES128-SHA256"),
- CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, /* 0xC028 */
- "ECDHE-RSA-AES256-SHA384"),
- CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, /* 0xC029 */
- "ECDH-RSA-AES128-SHA256"),
- CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, /* 0xC02A */
- "ECDH-RSA-AES256-SHA384"),
+ BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, /* 0xC023 */
+ BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, /* 0xC024 */
+ BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, /* 0xC025 */
+ BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, /* 0xC026 */
+ BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, /* 0xC027 */
+ BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, /* 0xC028 */
+ BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, /* 0xC029 */
+ BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, /* 0xC02A */
/* RFC 5289 TLS 1.2 GCM */
- CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, /* 0xC02B */
- "ECDHE-ECDSA-AES128-GCM-SHA256"),
- CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, /* 0xC02C */
- "ECDHE-ECDSA-AES256-GCM-SHA384"),
- CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, /* 0xC02D */
- "ECDH-ECDSA-AES128-GCM-SHA256"),
- CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, /* 0xC02E */
- "ECDH-ECDSA-AES256-GCM-SHA384"),
- CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, /* 0xC02F */
- "ECDHE-RSA-AES128-GCM-SHA256"),
- CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, /* 0xC030 */
- "ECDHE-RSA-AES256-GCM-SHA384"),
- CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, /* 0xC031 */
- "ECDH-RSA-AES128-GCM-SHA256"),
- CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384, /* 0xC032 */
- "ECDH-RSA-AES256-GCM-SHA384"),
-#ifdef BR_TLS_RSA_WITH_AES_128_CCM
+ BR_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, /* 0xC02B */
+ BR_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, /* 0xC02C */
+ BR_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, /* 0xC02D */
+ BR_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, /* 0xC02E */
+ BR_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, /* 0xC02F */
+ BR_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, /* 0xC030 */
+ BR_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, /* 0xC031 */
+ BR_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384, /* 0xC032 */
+#ifdef BR_TLS_RSA_WITH_AES_128_CCM
/* RFC 6655 TLS 1.2 CCM
Supported since BearSSL 0.6 */
- CIPHER_DEF(TLS_RSA_WITH_AES_128_CCM, /* 0xC09C */
- "AES128-CCM"),
- CIPHER_DEF(TLS_RSA_WITH_AES_256_CCM, /* 0xC09D */
- "AES256-CCM"),
- CIPHER_DEF(TLS_RSA_WITH_AES_128_CCM_8, /* 0xC0A0 */
- "AES128-CCM8"),
- CIPHER_DEF(TLS_RSA_WITH_AES_256_CCM_8, /* 0xC0A1 */
- "AES256-CCM8"),
+ BR_TLS_RSA_WITH_AES_128_CCM, /* 0xC09C */
+ BR_TLS_RSA_WITH_AES_256_CCM, /* 0xC09D */
+ BR_TLS_RSA_WITH_AES_128_CCM_8, /* 0xC0A0 */
+ BR_TLS_RSA_WITH_AES_256_CCM_8, /* 0xC0A1 */
/* RFC 7251 TLS 1.2 ECC CCM
Supported since BearSSL 0.6 */
- CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_128_CCM, /* 0xC0AC */
- "ECDHE-ECDSA-AES128-CCM"),
- CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_256_CCM, /* 0xC0AD */
- "ECDHE-ECDSA-AES256-CCM"),
- CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, /* 0xC0AE */
- "ECDHE-ECDSA-AES128-CCM8"),
- CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8, /* 0xC0AF */
- "ECDHE-ECDSA-AES256-CCM8"),
+ BR_TLS_ECDHE_ECDSA_WITH_AES_128_CCM, /* 0xC0AC */
+ BR_TLS_ECDHE_ECDSA_WITH_AES_256_CCM, /* 0xC0AD */
+ BR_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, /* 0xC0AE */
+ BR_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8, /* 0xC0AF */
#endif
/* RFC 7905 TLS 1.2 ChaCha20-Poly1305
Supported since BearSSL 0.2 */
- CIPHER_DEF(TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, /* 0xCCA8 */
- "ECDHE-RSA-CHACHA20-POLY1305"),
- CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, /* 0xCCA9 */
- "ECDHE-ECDSA-CHACHA20-POLY1305"),
+ BR_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, /* 0xCCA8 */
+ BR_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, /* 0xCCA9 */
};
#define NUM_OF_CIPHERS (sizeof(ciphertable) / sizeof(ciphertable[0]))
-#define CIPHER_NAME_BUF_LEN 64
-
-static bool is_separator(char c)
-{
- /* Return whether character is a cipher list separator. */
- switch(c) {
- case ' ':
- case '\t':
- case ':':
- case ',':
- case ';':
- return true;
- }
- return false;
-}
static CURLcode bearssl_set_selected_ciphers(struct Curl_easy *data,
br_ssl_engine_context *ssl_eng,
const char *ciphers)
{
- uint16_t selected_ciphers[NUM_OF_CIPHERS];
- size_t selected_count = 0;
- const char *cipher_start = ciphers;
- const char *cipher_end;
- size_t i, j;
-
- if(!cipher_start)
- return CURLE_SSL_CIPHER;
-
- while(true) {
- const char *cipher;
- size_t clen;
-
- /* Extract the next cipher name from the ciphers string */
- while(is_separator(*cipher_start))
- ++cipher_start;
- if(!*cipher_start)
- break;
- cipher_end = cipher_start;
- while(*cipher_end && !is_separator(*cipher_end))
- ++cipher_end;
-
- clen = cipher_end - cipher_start;
- cipher = cipher_start;
-
- cipher_start = cipher_end;
-
- /* Lookup the cipher name in the table of available ciphers. If the cipher
- name starts with "TLS_" we do the lookup by IANA name. Otherwise, we try
- to match cipher name by an (OpenSSL) alias. */
- if(strncasecompare(cipher, "TLS_", 4)) {
- for(i = 0; i < NUM_OF_CIPHERS &&
- (strlen(ciphertable[i].name) == clen) &&
- !strncasecompare(cipher, ciphertable[i].name, clen); ++i);
+ uint16_t selected[NUM_OF_CIPHERS];
+ size_t count = 0, i;
+ const char *ptr, *end;
+
+ for(ptr = ciphers; ptr[0] != '\0' && count < NUM_OF_CIPHERS; ptr = end) {
+ uint16_t id = Curl_cipher_suite_walk_str(&ptr, &end);
+
+ /* Check if cipher is supported */
+ if(id) {
+ for(i = 0; i < NUM_OF_CIPHERS && ciphertable[i] != id; i++);
+ if(i == NUM_OF_CIPHERS)
+ id = 0;
}
- else {
- for(i = 0; i < NUM_OF_CIPHERS &&
- (strlen(ciphertable[i].alias_name) == clen) &&
- !strncasecompare(cipher, ciphertable[i].alias_name, clen); ++i);
- }
- if(i == NUM_OF_CIPHERS) {
- infof(data, "BearSSL: unknown cipher in list: %.*s",
- (int)clen, cipher);
+ if(!id) {
+ if(ptr[0] != '\0')
+ infof(data, "BearSSL: unknown cipher in list: \"%.*s\"",
+ (int) (end - ptr), ptr);
continue;
}
/* No duplicates allowed */
- for(j = 0; j < selected_count &&
- selected_ciphers[j] != ciphertable[i].num; j++);
- if(j < selected_count) {
- infof(data, "BearSSL: duplicate cipher in list: %.*s",
- (int)clen, cipher);
+ for(i = 0; i < count && selected[i] != id; i++);
+ if(i < count) {
+ infof(data, "BearSSL: duplicate cipher in list: \"%.*s\"",
+ (int) (end - ptr), ptr);
continue;
}
- DEBUGASSERT(selected_count < NUM_OF_CIPHERS);
- selected_ciphers[selected_count] = ciphertable[i].num;
- ++selected_count;
+ selected[count++] = id;
}
- if(selected_count == 0) {
+ if(count == 0) {
failf(data, "BearSSL: no supported cipher in list");
return CURLE_SSL_CIPHER;
}
- br_ssl_engine_set_suites(ssl_eng, selected_ciphers, selected_count);
+ br_ssl_engine_set_suites(ssl_eng, selected, count);
return CURLE_OK;
}
@@ -686,7 +588,7 @@ static CURLcode bearssl_connect_step1(struct Curl_cfilter *cf,
CURL_TRC_CF(data, cf, "connect_step1, check session cache");
Curl_ssl_sessionid_lock(data);
- if(!Curl_ssl_getsessionid(cf, data, &session, NULL)) {
+ if(!Curl_ssl_getsessionid(cf, data, &connssl->peer, &session, NULL)) {
br_ssl_engine_set_session_parameters(&backend->ctx.eng, session);
session_set = 1;
infof(data, "BearSSL: reusing session ID");
@@ -830,7 +732,7 @@ static CURLcode bearssl_run_until(struct Curl_cfilter *cf,
CURL_TRC_CF(data, cf, "ssl_recv(len=%zu) -> %zd, %d", len, ret, result);
if(ret == 0) {
failf(data, "SSL: EOF without close notify");
- return CURLE_READ_ERROR;
+ return CURLE_RECV_ERROR;
}
if(ret <= 0) {
return result;
@@ -846,6 +748,9 @@ static CURLcode bearssl_connect_step2(struct Curl_cfilter *cf,
struct ssl_connect_data *connssl = cf->ctx;
struct bearssl_ssl_backend_data *backend =
(struct bearssl_ssl_backend_data *)connssl->backend;
+ br_ssl_session_parameters session;
+ char cipher_str[64];
+ char ver_str[16];
CURLcode ret;
DEBUGASSERT(backend);
@@ -856,6 +761,7 @@ static CURLcode bearssl_connect_step2(struct Curl_cfilter *cf,
return CURLE_OK;
if(ret == CURLE_OK) {
unsigned int tver;
+
if(br_ssl_engine_current_state(&backend->ctx.eng) == BR_SSL_CLOSED) {
failf(data, "SSL: connection closed during handshake");
return CURLE_SSL_CONNECT_ERROR;
@@ -863,16 +769,29 @@ 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 == 0x0303)
- infof(data, "SSL connection using TLSv1.2");
- else if(tver == 0x0304)
- infof(data, "SSL connection using TLSv1.3");
- else
- infof(data, "SSL connection using TLS 0x%x", tver);
+ 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);
+ }
+ 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);
}
return ret;
}
+static void bearssl_session_free(void *sessionid, size_t idsize)
+{
+ (void)idsize;
+ free(sessionid);
+}
+
static CURLcode bearssl_connect_step3(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
@@ -896,7 +815,6 @@ static CURLcode bearssl_connect_step3(struct Curl_cfilter *cf,
if(ssl_config->primary.sessionid) {
bool incache;
- bool added = FALSE;
void *oldsession;
br_ssl_session_parameters *session;
@@ -905,16 +823,16 @@ 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);
- incache = !(Curl_ssl_getsessionid(cf, data, &oldsession, NULL));
+ incache = !(Curl_ssl_getsessionid(cf, data, &connssl->peer,
+ &oldsession, NULL));
if(incache)
Curl_ssl_delsessionid(data, oldsession);
- ret = Curl_ssl_addsessionid(cf, data, session, 0, &added);
+
+ ret = Curl_ssl_addsessionid(cf, data, &connssl->peer, session, 0,
+ bearssl_session_free);
Curl_ssl_sessionid_unlock(data);
- if(!added)
- free(session);
- if(ret) {
- return CURLE_OUT_OF_MEMORY;
- }
+ if(ret)
+ return ret;
}
connssl->connecting_state = ssl_connect_done;
@@ -1173,11 +1091,6 @@ static void bearssl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
}
}
-static void bearssl_session_free(void *ptr)
-{
- free(ptr);
-}
-
static CURLcode bearssl_sha256sum(const unsigned char *input,
size_t inputlen,
unsigned char *sha256sum,
@@ -1210,7 +1123,6 @@ const struct Curl_ssl Curl_ssl_bearssl = {
bearssl_get_internals, /* get_internals */
bearssl_close, /* close_one */
Curl_none_close_all, /* close_all */
- bearssl_session_free, /* session_free */
Curl_none_set_engine, /* set_engine */
Curl_none_set_engine_default, /* set_engine_default */
Curl_none_engines_list, /* engines_list */
diff --git a/libs/libcurl/src/vtls/cipher_suite.c b/libs/libcurl/src/vtls/cipher_suite.c
new file mode 100644
index 0000000000..723b94d13f
--- /dev/null
+++ b/libs/libcurl/src/vtls/cipher_suite.c
@@ -0,0 +1,716 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Jan Venekamp, <jan@venekamp.net>
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+#if defined(USE_MBEDTLS) || defined(USE_BEARSSL)
+#include "cipher_suite.h"
+#include "curl_printf.h"
+#include "strcase.h"
+#include <string.h>
+
+/*
+ * To support the CURLOPT_SSL_CIPHER_LIST option on SSL backends
+ * that do not support it natively, but do support setting a list of
+ * IANA ids, we need a list of all supported cipher suite names
+ * (openssl and IANA) to be able to look up the IANA ids.
+ *
+ * To keep the binary size of this list down we compress each entry
+ * down to 2 + 6 bytes using the C preprocessor.
+ */
+
+/*
+ * mbedTLS NOTE: mbedTLS has mbedtls_ssl_get_ciphersuite_id() to
+ * convert a string representation to an IANA id, we do not use that
+ * because it does not support "standard" openssl cipher suite
+ * names, nor IANA names.
+ */
+
+/* NOTE: also see tests/unit/unit3205.c */
+
+/* Text for cipher suite parts (max 64 entries),
+ keep indexes below in sync with this! */
+static const char *cs_txt =
+ "\0"
+ "TLS" "\0"
+ "WITH" "\0"
+ "128" "\0"
+ "256" "\0"
+ "3DES" "\0"
+ "8" "\0"
+ "AES" "\0"
+ "AES128" "\0"
+ "AES256" "\0"
+ "CBC" "\0"
+ "CBC3" "\0"
+ "CCM" "\0"
+ "CCM8" "\0"
+ "CHACHA20" "\0"
+ "DES" "\0"
+ "DHE" "\0"
+ "ECDH" "\0"
+ "ECDHE" "\0"
+ "ECDSA" "\0"
+ "EDE" "\0"
+ "GCM" "\0"
+ "MD5" "\0"
+ "NULL" "\0"
+ "POLY1305" "\0"
+ "PSK" "\0"
+ "RSA" "\0"
+ "SHA" "\0"
+ "SHA256" "\0"
+ "SHA384" "\0"
+#if defined(USE_MBEDTLS)
+ "ARIA" "\0"
+ "ARIA128" "\0"
+ "ARIA256" "\0"
+ "CAMELLIA" "\0"
+ "CAMELLIA128" "\0"
+ "CAMELLIA256" "\0"
+#endif
+;
+/* Indexes of above cs_txt */
+enum {
+ CS_TXT_IDX_,
+ CS_TXT_IDX_TLS,
+ CS_TXT_IDX_WITH,
+ CS_TXT_IDX_128,
+ CS_TXT_IDX_256,
+ CS_TXT_IDX_3DES,
+ CS_TXT_IDX_8,
+ CS_TXT_IDX_AES,
+ CS_TXT_IDX_AES128,
+ CS_TXT_IDX_AES256,
+ CS_TXT_IDX_CBC,
+ CS_TXT_IDX_CBC3,
+ CS_TXT_IDX_CCM,
+ CS_TXT_IDX_CCM8,
+ CS_TXT_IDX_CHACHA20,
+ CS_TXT_IDX_DES,
+ CS_TXT_IDX_DHE,
+ CS_TXT_IDX_ECDH,
+ CS_TXT_IDX_ECDHE,
+ CS_TXT_IDX_ECDSA,
+ CS_TXT_IDX_EDE,
+ CS_TXT_IDX_GCM,
+ CS_TXT_IDX_MD5,
+ CS_TXT_IDX_NULL,
+ CS_TXT_IDX_POLY1305,
+ CS_TXT_IDX_PSK,
+ CS_TXT_IDX_RSA,
+ CS_TXT_IDX_SHA,
+ CS_TXT_IDX_SHA256,
+ CS_TXT_IDX_SHA384,
+#if defined(USE_MBEDTLS)
+ CS_TXT_IDX_ARIA,
+ CS_TXT_IDX_ARIA128,
+ CS_TXT_IDX_ARIA256,
+ CS_TXT_IDX_CAMELLIA,
+ CS_TXT_IDX_CAMELLIA128,
+ CS_TXT_IDX_CAMELLIA256,
+#endif
+ CS_TXT_LEN,
+};
+
+#define CS_ZIP_IDX(a, b, c, d, e, f, g, h) \
+{ \
+ (uint8_t) ((a) << 2 | ((b) & 0x3F) >> 4), \
+ (uint8_t) ((b) << 4 | ((c) & 0x3F) >> 2), \
+ (uint8_t) ((c) << 6 | ((d) & 0x3F)), \
+ (uint8_t) ((e) << 2 | ((f) & 0x3F) >> 4), \
+ (uint8_t) ((f) << 4 | ((g) & 0x3F) >> 2), \
+ (uint8_t) ((g) << 6 | ((h) & 0x3F)) \
+}
+#define CS_ENTRY(id, a, b, c, d, e, f, g, h) \
+{ \
+ id, \
+ CS_ZIP_IDX( \
+ CS_TXT_IDX_ ## a, CS_TXT_IDX_ ## b, \
+ CS_TXT_IDX_ ## c, CS_TXT_IDX_ ## d, \
+ CS_TXT_IDX_ ## e, CS_TXT_IDX_ ## f, \
+ CS_TXT_IDX_ ## g, CS_TXT_IDX_ ## h \
+ ) \
+}
+
+struct cs_entry {
+ uint16_t id;
+ uint8_t zip[6];
+};
+
+/* !checksrc! disable COMMANOSPACE all */
+static const struct cs_entry cs_list [] = {
+ CS_ENTRY(0x002F, TLS,RSA,WITH,AES,128,CBC,SHA,),
+ CS_ENTRY(0x002F, AES128,SHA,,,,,,),
+ CS_ENTRY(0x0035, TLS,RSA,WITH,AES,256,CBC,SHA,),
+ CS_ENTRY(0x0035, AES256,SHA,,,,,,),
+ CS_ENTRY(0x003C, TLS,RSA,WITH,AES,128,CBC,SHA256,),
+ CS_ENTRY(0x003C, AES128,SHA256,,,,,,),
+ CS_ENTRY(0x003D, TLS,RSA,WITH,AES,256,CBC,SHA256,),
+ CS_ENTRY(0x003D, AES256,SHA256,,,,,,),
+ CS_ENTRY(0x009C, TLS,RSA,WITH,AES,128,GCM,SHA256,),
+ CS_ENTRY(0x009C, AES128,GCM,SHA256,,,,,),
+ CS_ENTRY(0x009D, TLS,RSA,WITH,AES,256,GCM,SHA384,),
+ CS_ENTRY(0x009D, AES256,GCM,SHA384,,,,,),
+ CS_ENTRY(0xC004, TLS,ECDH,ECDSA,WITH,AES,128,CBC,SHA),
+ CS_ENTRY(0xC004, ECDH,ECDSA,AES128,SHA,,,,),
+ CS_ENTRY(0xC005, TLS,ECDH,ECDSA,WITH,AES,256,CBC,SHA),
+ CS_ENTRY(0xC005, ECDH,ECDSA,AES256,SHA,,,,),
+ CS_ENTRY(0xC009, TLS,ECDHE,ECDSA,WITH,AES,128,CBC,SHA),
+ CS_ENTRY(0xC009, ECDHE,ECDSA,AES128,SHA,,,,),
+ CS_ENTRY(0xC00A, TLS,ECDHE,ECDSA,WITH,AES,256,CBC,SHA),
+ CS_ENTRY(0xC00A, ECDHE,ECDSA,AES256,SHA,,,,),
+ CS_ENTRY(0xC00E, TLS,ECDH,RSA,WITH,AES,128,CBC,SHA),
+ CS_ENTRY(0xC00E, ECDH,RSA,AES128,SHA,,,,),
+ CS_ENTRY(0xC00F, TLS,ECDH,RSA,WITH,AES,256,CBC,SHA),
+ CS_ENTRY(0xC00F, ECDH,RSA,AES256,SHA,,,,),
+ CS_ENTRY(0xC013, TLS,ECDHE,RSA,WITH,AES,128,CBC,SHA),
+ CS_ENTRY(0xC013, ECDHE,RSA,AES128,SHA,,,,),
+ CS_ENTRY(0xC014, TLS,ECDHE,RSA,WITH,AES,256,CBC,SHA),
+ CS_ENTRY(0xC014, ECDHE,RSA,AES256,SHA,,,,),
+ CS_ENTRY(0xC023, TLS,ECDHE,ECDSA,WITH,AES,128,CBC,SHA256),
+ CS_ENTRY(0xC023, ECDHE,ECDSA,AES128,SHA256,,,,),
+ CS_ENTRY(0xC024, TLS,ECDHE,ECDSA,WITH,AES,256,CBC,SHA384),
+ CS_ENTRY(0xC024, ECDHE,ECDSA,AES256,SHA384,,,,),
+ CS_ENTRY(0xC025, TLS,ECDH,ECDSA,WITH,AES,128,CBC,SHA256),
+ CS_ENTRY(0xC025, ECDH,ECDSA,AES128,SHA256,,,,),
+ CS_ENTRY(0xC026, TLS,ECDH,ECDSA,WITH,AES,256,CBC,SHA384),
+ CS_ENTRY(0xC026, ECDH,ECDSA,AES256,SHA384,,,,),
+ CS_ENTRY(0xC027, TLS,ECDHE,RSA,WITH,AES,128,CBC,SHA256),
+ CS_ENTRY(0xC027, ECDHE,RSA,AES128,SHA256,,,,),
+ CS_ENTRY(0xC028, TLS,ECDHE,RSA,WITH,AES,256,CBC,SHA384),
+ CS_ENTRY(0xC028, ECDHE,RSA,AES256,SHA384,,,,),
+ CS_ENTRY(0xC029, TLS,ECDH,RSA,WITH,AES,128,CBC,SHA256),
+ CS_ENTRY(0xC029, ECDH,RSA,AES128,SHA256,,,,),
+ CS_ENTRY(0xC02A, TLS,ECDH,RSA,WITH,AES,256,CBC,SHA384),
+ CS_ENTRY(0xC02A, ECDH,RSA,AES256,SHA384,,,,),
+ CS_ENTRY(0xC02B, TLS,ECDHE,ECDSA,WITH,AES,128,GCM,SHA256),
+ CS_ENTRY(0xC02B, ECDHE,ECDSA,AES128,GCM,SHA256,,,),
+ CS_ENTRY(0xC02C, TLS,ECDHE,ECDSA,WITH,AES,256,GCM,SHA384),
+ CS_ENTRY(0xC02C, ECDHE,ECDSA,AES256,GCM,SHA384,,,),
+ CS_ENTRY(0xC02D, TLS,ECDH,ECDSA,WITH,AES,128,GCM,SHA256),
+ CS_ENTRY(0xC02D, ECDH,ECDSA,AES128,GCM,SHA256,,,),
+ CS_ENTRY(0xC02E, TLS,ECDH,ECDSA,WITH,AES,256,GCM,SHA384),
+ CS_ENTRY(0xC02E, ECDH,ECDSA,AES256,GCM,SHA384,,,),
+ CS_ENTRY(0xC02F, TLS,ECDHE,RSA,WITH,AES,128,GCM,SHA256),
+ CS_ENTRY(0xC02F, ECDHE,RSA,AES128,GCM,SHA256,,,),
+ CS_ENTRY(0xC030, TLS,ECDHE,RSA,WITH,AES,256,GCM,SHA384),
+ CS_ENTRY(0xC030, ECDHE,RSA,AES256,GCM,SHA384,,,),
+ CS_ENTRY(0xC031, TLS,ECDH,RSA,WITH,AES,128,GCM,SHA256),
+ CS_ENTRY(0xC031, ECDH,RSA,AES128,GCM,SHA256,,,),
+ CS_ENTRY(0xC032, TLS,ECDH,RSA,WITH,AES,256,GCM,SHA384),
+ CS_ENTRY(0xC032, ECDH,RSA,AES256,GCM,SHA384,,,),
+ CS_ENTRY(0xCCA8, TLS,ECDHE,RSA,WITH,CHACHA20,POLY1305,SHA256,),
+ CS_ENTRY(0xCCA8, ECDHE,RSA,CHACHA20,POLY1305,,,,),
+ CS_ENTRY(0xCCA9, TLS,ECDHE,ECDSA,WITH,CHACHA20,POLY1305,SHA256,),
+ CS_ENTRY(0xCCA9, ECDHE,ECDSA,CHACHA20,POLY1305,,,,),
+#if defined(USE_MBEDTLS)
+ CS_ENTRY(0x0001, TLS,RSA,WITH,NULL,MD5,,,),
+ CS_ENTRY(0x0001, NULL,MD5,,,,,,),
+ CS_ENTRY(0x0002, TLS,RSA,WITH,NULL,SHA,,,),
+ CS_ENTRY(0x0002, NULL,SHA,,,,,,),
+ CS_ENTRY(0x002C, TLS,PSK,WITH,NULL,SHA,,,),
+ CS_ENTRY(0x002C, PSK,NULL,SHA,,,,,),
+ CS_ENTRY(0x002D, TLS,DHE,PSK,WITH,NULL,SHA,,),
+ CS_ENTRY(0x002D, DHE,PSK,NULL,SHA,,,,),
+ CS_ENTRY(0x002E, TLS,RSA,PSK,WITH,NULL,SHA,,),
+ CS_ENTRY(0x002E, RSA,PSK,NULL,SHA,,,,),
+ CS_ENTRY(0x0033, TLS,DHE,RSA,WITH,AES,128,CBC,SHA),
+ CS_ENTRY(0x0033, DHE,RSA,AES128,SHA,,,,),
+ CS_ENTRY(0x0039, TLS,DHE,RSA,WITH,AES,256,CBC,SHA),
+ CS_ENTRY(0x0039, DHE,RSA,AES256,SHA,,,,),
+ CS_ENTRY(0x003B, TLS,RSA,WITH,NULL,SHA256,,,),
+ CS_ENTRY(0x003B, NULL,SHA256,,,,,,),
+ CS_ENTRY(0x0067, TLS,DHE,RSA,WITH,AES,128,CBC,SHA256),
+ CS_ENTRY(0x0067, DHE,RSA,AES128,SHA256,,,,),
+ CS_ENTRY(0x006B, TLS,DHE,RSA,WITH,AES,256,CBC,SHA256),
+ CS_ENTRY(0x006B, DHE,RSA,AES256,SHA256,,,,),
+ CS_ENTRY(0x008C, TLS,PSK,WITH,AES,128,CBC,SHA,),
+ CS_ENTRY(0x008C, PSK,AES128,CBC,SHA,,,,),
+ CS_ENTRY(0x008D, TLS,PSK,WITH,AES,256,CBC,SHA,),
+ CS_ENTRY(0x008D, PSK,AES256,CBC,SHA,,,,),
+ CS_ENTRY(0x0090, TLS,DHE,PSK,WITH,AES,128,CBC,SHA),
+ CS_ENTRY(0x0090, DHE,PSK,AES128,CBC,SHA,,,),
+ CS_ENTRY(0x0091, TLS,DHE,PSK,WITH,AES,256,CBC,SHA),
+ CS_ENTRY(0x0091, DHE,PSK,AES256,CBC,SHA,,,),
+ CS_ENTRY(0x0094, TLS,RSA,PSK,WITH,AES,128,CBC,SHA),
+ CS_ENTRY(0x0094, RSA,PSK,AES128,CBC,SHA,,,),
+ CS_ENTRY(0x0095, TLS,RSA,PSK,WITH,AES,256,CBC,SHA),
+ CS_ENTRY(0x0095, RSA,PSK,AES256,CBC,SHA,,,),
+ CS_ENTRY(0x009E, TLS,DHE,RSA,WITH,AES,128,GCM,SHA256),
+ CS_ENTRY(0x009E, DHE,RSA,AES128,GCM,SHA256,,,),
+ CS_ENTRY(0x009F, TLS,DHE,RSA,WITH,AES,256,GCM,SHA384),
+ CS_ENTRY(0x009F, DHE,RSA,AES256,GCM,SHA384,,,),
+ CS_ENTRY(0x00A8, TLS,PSK,WITH,AES,128,GCM,SHA256,),
+ CS_ENTRY(0x00A8, PSK,AES128,GCM,SHA256,,,,),
+ CS_ENTRY(0x00A9, TLS,PSK,WITH,AES,256,GCM,SHA384,),
+ CS_ENTRY(0x00A9, PSK,AES256,GCM,SHA384,,,,),
+ CS_ENTRY(0x00AA, TLS,DHE,PSK,WITH,AES,128,GCM,SHA256),
+ CS_ENTRY(0x00AA, DHE,PSK,AES128,GCM,SHA256,,,),
+ CS_ENTRY(0x00AB, TLS,DHE,PSK,WITH,AES,256,GCM,SHA384),
+ CS_ENTRY(0x00AB, DHE,PSK,AES256,GCM,SHA384,,,),
+ CS_ENTRY(0x00AC, TLS,RSA,PSK,WITH,AES,128,GCM,SHA256),
+ CS_ENTRY(0x00AC, RSA,PSK,AES128,GCM,SHA256,,,),
+ CS_ENTRY(0x00AD, TLS,RSA,PSK,WITH,AES,256,GCM,SHA384),
+ CS_ENTRY(0x00AD, RSA,PSK,AES256,GCM,SHA384,,,),
+ CS_ENTRY(0x00AE, TLS,PSK,WITH,AES,128,CBC,SHA256,),
+ CS_ENTRY(0x00AE, PSK,AES128,CBC,SHA256,,,,),
+ CS_ENTRY(0x00AF, TLS,PSK,WITH,AES,256,CBC,SHA384,),
+ CS_ENTRY(0x00AF, PSK,AES256,CBC,SHA384,,,,),
+ CS_ENTRY(0x00B0, TLS,PSK,WITH,NULL,SHA256,,,),
+ CS_ENTRY(0x00B0, PSK,NULL,SHA256,,,,,),
+ CS_ENTRY(0x00B1, TLS,PSK,WITH,NULL,SHA384,,,),
+ CS_ENTRY(0x00B1, PSK,NULL,SHA384,,,,,),
+ CS_ENTRY(0x00B2, TLS,DHE,PSK,WITH,AES,128,CBC,SHA256),
+ CS_ENTRY(0x00B2, DHE,PSK,AES128,CBC,SHA256,,,),
+ CS_ENTRY(0x00B3, TLS,DHE,PSK,WITH,AES,256,CBC,SHA384),
+ CS_ENTRY(0x00B3, DHE,PSK,AES256,CBC,SHA384,,,),
+ CS_ENTRY(0x00B4, TLS,DHE,PSK,WITH,NULL,SHA256,,),
+ CS_ENTRY(0x00B4, DHE,PSK,NULL,SHA256,,,,),
+ CS_ENTRY(0x00B5, TLS,DHE,PSK,WITH,NULL,SHA384,,),
+ CS_ENTRY(0x00B5, DHE,PSK,NULL,SHA384,,,,),
+ CS_ENTRY(0x00B6, TLS,RSA,PSK,WITH,AES,128,CBC,SHA256),
+ CS_ENTRY(0x00B6, RSA,PSK,AES128,CBC,SHA256,,,),
+ CS_ENTRY(0x00B7, TLS,RSA,PSK,WITH,AES,256,CBC,SHA384),
+ CS_ENTRY(0x00B7, RSA,PSK,AES256,CBC,SHA384,,,),
+ CS_ENTRY(0x00B8, TLS,RSA,PSK,WITH,NULL,SHA256,,),
+ CS_ENTRY(0x00B8, RSA,PSK,NULL,SHA256,,,,),
+ CS_ENTRY(0x00B9, TLS,RSA,PSK,WITH,NULL,SHA384,,),
+ CS_ENTRY(0x00B9, RSA,PSK,NULL,SHA384,,,,),
+ CS_ENTRY(0x1301, TLS,AES,128,GCM,SHA256,,,),
+ CS_ENTRY(0x1302, TLS,AES,256,GCM,SHA384,,,),
+ CS_ENTRY(0x1303, TLS,CHACHA20,POLY1305,SHA256,,,,),
+ CS_ENTRY(0x1304, TLS,AES,128,CCM,SHA256,,,),
+ CS_ENTRY(0x1305, TLS,AES,128,CCM,8,SHA256,,),
+ CS_ENTRY(0xC001, TLS,ECDH,ECDSA,WITH,NULL,SHA,,),
+ CS_ENTRY(0xC001, ECDH,ECDSA,NULL,SHA,,,,),
+ CS_ENTRY(0xC006, TLS,ECDHE,ECDSA,WITH,NULL,SHA,,),
+ CS_ENTRY(0xC006, ECDHE,ECDSA,NULL,SHA,,,,),
+ CS_ENTRY(0xC00B, TLS,ECDH,RSA,WITH,NULL,SHA,,),
+ CS_ENTRY(0xC00B, ECDH,RSA,NULL,SHA,,,,),
+ CS_ENTRY(0xC010, TLS,ECDHE,RSA,WITH,NULL,SHA,,),
+ CS_ENTRY(0xC010, ECDHE,RSA,NULL,SHA,,,,),
+ CS_ENTRY(0xC035, TLS,ECDHE,PSK,WITH,AES,128,CBC,SHA),
+ CS_ENTRY(0xC035, ECDHE,PSK,AES128,CBC,SHA,,,),
+ CS_ENTRY(0xC036, TLS,ECDHE,PSK,WITH,AES,256,CBC,SHA),
+ CS_ENTRY(0xC036, ECDHE,PSK,AES256,CBC,SHA,,,),
+ CS_ENTRY(0xCCAB, TLS,PSK,WITH,CHACHA20,POLY1305,SHA256,,),
+ CS_ENTRY(0xCCAB, PSK,CHACHA20,POLY1305,,,,,),
+#endif
+#if defined(USE_BEARSSL)
+ CS_ENTRY(0x000A, TLS,RSA,WITH,3DES,EDE,CBC,SHA,),
+ CS_ENTRY(0x000A, DES,CBC3,SHA,,,,,),
+ CS_ENTRY(0xC003, TLS,ECDH,ECDSA,WITH,3DES,EDE,CBC,SHA),
+ CS_ENTRY(0xC003, ECDH,ECDSA,DES,CBC3,SHA,,,),
+ CS_ENTRY(0xC008, TLS,ECDHE,ECDSA,WITH,3DES,EDE,CBC,SHA),
+ CS_ENTRY(0xC008, ECDHE,ECDSA,DES,CBC3,SHA,,,),
+ CS_ENTRY(0xC00D, TLS,ECDH,RSA,WITH,3DES,EDE,CBC,SHA),
+ CS_ENTRY(0xC00D, ECDH,RSA,DES,CBC3,SHA,,,),
+ CS_ENTRY(0xC012, TLS,ECDHE,RSA,WITH,3DES,EDE,CBC,SHA),
+ CS_ENTRY(0xC012, ECDHE,RSA,DES,CBC3,SHA,,,),
+#endif
+ CS_ENTRY(0xC09C, TLS,RSA,WITH,AES,128,CCM,,),
+ CS_ENTRY(0xC09C, AES128,CCM,,,,,,),
+ CS_ENTRY(0xC09D, TLS,RSA,WITH,AES,256,CCM,,),
+ CS_ENTRY(0xC09D, AES256,CCM,,,,,,),
+ CS_ENTRY(0xC0A0, TLS,RSA,WITH,AES,128,CCM,8,),
+ CS_ENTRY(0xC0A0, AES128,CCM8,,,,,,),
+ CS_ENTRY(0xC0A1, TLS,RSA,WITH,AES,256,CCM,8,),
+ CS_ENTRY(0xC0A1, AES256,CCM8,,,,,,),
+ CS_ENTRY(0xC0AC, TLS,ECDHE,ECDSA,WITH,AES,128,CCM,),
+ CS_ENTRY(0xC0AC, ECDHE,ECDSA,AES128,CCM,,,,),
+ CS_ENTRY(0xC0AD, TLS,ECDHE,ECDSA,WITH,AES,256,CCM,),
+ CS_ENTRY(0xC0AD, ECDHE,ECDSA,AES256,CCM,,,,),
+ CS_ENTRY(0xC0AE, TLS,ECDHE,ECDSA,WITH,AES,128,CCM,8),
+ CS_ENTRY(0xC0AE, ECDHE,ECDSA,AES128,CCM8,,,,),
+ CS_ENTRY(0xC0AF, TLS,ECDHE,ECDSA,WITH,AES,256,CCM,8),
+ CS_ENTRY(0xC0AF, ECDHE,ECDSA,AES256,CCM8,,,,),
+#if defined(USE_MBEDTLS)
+ /* entries marked ns are "non-standard", they are not in openssl */
+ CS_ENTRY(0x0041, TLS,RSA,WITH,CAMELLIA,128,CBC,SHA,),
+ CS_ENTRY(0x0041, CAMELLIA128,SHA,,,,,,),
+ CS_ENTRY(0x0045, TLS,DHE,RSA,WITH,CAMELLIA,128,CBC,SHA),
+ CS_ENTRY(0x0045, DHE,RSA,CAMELLIA128,SHA,,,,),
+ CS_ENTRY(0x0084, TLS,RSA,WITH,CAMELLIA,256,CBC,SHA,),
+ CS_ENTRY(0x0084, CAMELLIA256,SHA,,,,,,),
+ CS_ENTRY(0x0088, TLS,DHE,RSA,WITH,CAMELLIA,256,CBC,SHA),
+ CS_ENTRY(0x0088, DHE,RSA,CAMELLIA256,SHA,,,,),
+ CS_ENTRY(0x00BA, TLS,RSA,WITH,CAMELLIA,128,CBC,SHA256,),
+ CS_ENTRY(0x00BA, CAMELLIA128,SHA256,,,,,,),
+ CS_ENTRY(0x00BE, TLS,DHE,RSA,WITH,CAMELLIA,128,CBC,SHA256),
+ CS_ENTRY(0x00BE, DHE,RSA,CAMELLIA128,SHA256,,,,),
+ CS_ENTRY(0x00C0, TLS,RSA,WITH,CAMELLIA,256,CBC,SHA256,),
+ CS_ENTRY(0x00C0, CAMELLIA256,SHA256,,,,,,),
+ CS_ENTRY(0x00C4, TLS,DHE,RSA,WITH,CAMELLIA,256,CBC,SHA256),
+ CS_ENTRY(0x00C4, DHE,RSA,CAMELLIA256,SHA256,,,,),
+ CS_ENTRY(0xC037, TLS,ECDHE,PSK,WITH,AES,128,CBC,SHA256),
+ CS_ENTRY(0xC037, ECDHE,PSK,AES128,CBC,SHA256,,,),
+ CS_ENTRY(0xC038, TLS,ECDHE,PSK,WITH,AES,256,CBC,SHA384),
+ CS_ENTRY(0xC038, ECDHE,PSK,AES256,CBC,SHA384,,,),
+ CS_ENTRY(0xC039, TLS,ECDHE,PSK,WITH,NULL,SHA,,),
+ CS_ENTRY(0xC039, ECDHE,PSK,NULL,SHA,,,,),
+ CS_ENTRY(0xC03A, TLS,ECDHE,PSK,WITH,NULL,SHA256,,),
+ CS_ENTRY(0xC03A, ECDHE,PSK,NULL,SHA256,,,,),
+ CS_ENTRY(0xC03B, TLS,ECDHE,PSK,WITH,NULL,SHA384,,),
+ CS_ENTRY(0xC03B, ECDHE,PSK,NULL,SHA384,,,,),
+ CS_ENTRY(0xC03C, TLS,RSA,WITH,ARIA,128,CBC,SHA256,),
+ CS_ENTRY(0xC03C, ARIA128,SHA256,,,,,,), /* ns */
+ CS_ENTRY(0xC03D, TLS,RSA,WITH,ARIA,256,CBC,SHA384,),
+ CS_ENTRY(0xC03D, ARIA256,SHA384,,,,,,), /* ns */
+ CS_ENTRY(0xC044, TLS,DHE,RSA,WITH,ARIA,128,CBC,SHA256),
+ CS_ENTRY(0xC044, DHE,RSA,ARIA128,SHA256,,,,), /* ns */
+ CS_ENTRY(0xC045, TLS,DHE,RSA,WITH,ARIA,256,CBC,SHA384),
+ CS_ENTRY(0xC045, DHE,RSA,ARIA256,SHA384,,,,), /* ns */
+ CS_ENTRY(0xC048, TLS,ECDHE,ECDSA,WITH,ARIA,128,CBC,SHA256),
+ CS_ENTRY(0xC048, ECDHE,ECDSA,ARIA128,SHA256,,,,), /* ns */
+ CS_ENTRY(0xC049, TLS,ECDHE,ECDSA,WITH,ARIA,256,CBC,SHA384),
+ CS_ENTRY(0xC049, ECDHE,ECDSA,ARIA256,SHA384,,,,), /* ns */
+ CS_ENTRY(0xC04A, TLS,ECDH,ECDSA,WITH,ARIA,128,CBC,SHA256),
+ CS_ENTRY(0xC04A, ECDH,ECDSA,ARIA128,SHA256,,,,), /* ns */
+ CS_ENTRY(0xC04B, TLS,ECDH,ECDSA,WITH,ARIA,256,CBC,SHA384),
+ CS_ENTRY(0xC04B, ECDH,ECDSA,ARIA256,SHA384,,,,), /* ns */
+ CS_ENTRY(0xC04C, TLS,ECDHE,RSA,WITH,ARIA,128,CBC,SHA256),
+ CS_ENTRY(0xC04C, ECDHE,ARIA128,SHA256,,,,,), /* ns */
+ CS_ENTRY(0xC04D, TLS,ECDHE,RSA,WITH,ARIA,256,CBC,SHA384),
+ CS_ENTRY(0xC04D, ECDHE,ARIA256,SHA384,,,,,), /* ns */
+ CS_ENTRY(0xC04E, TLS,ECDH,RSA,WITH,ARIA,128,CBC,SHA256),
+ CS_ENTRY(0xC04E, ECDH,ARIA128,SHA256,,,,,), /* ns */
+ CS_ENTRY(0xC04F, TLS,ECDH,RSA,WITH,ARIA,256,CBC,SHA384),
+ CS_ENTRY(0xC04F, ECDH,ARIA256,SHA384,,,,,), /* ns */
+ CS_ENTRY(0xC050, TLS,RSA,WITH,ARIA,128,GCM,SHA256,),
+ CS_ENTRY(0xC050, ARIA128,GCM,SHA256,,,,,),
+ CS_ENTRY(0xC051, TLS,RSA,WITH,ARIA,256,GCM,SHA384,),
+ CS_ENTRY(0xC051, ARIA256,GCM,SHA384,,,,,),
+ CS_ENTRY(0xC052, TLS,DHE,RSA,WITH,ARIA,128,GCM,SHA256),
+ CS_ENTRY(0xC052, DHE,RSA,ARIA128,GCM,SHA256,,,),
+ CS_ENTRY(0xC053, TLS,DHE,RSA,WITH,ARIA,256,GCM,SHA384),
+ CS_ENTRY(0xC053, DHE,RSA,ARIA256,GCM,SHA384,,,),
+ CS_ENTRY(0xC05C, TLS,ECDHE,ECDSA,WITH,ARIA,128,GCM,SHA256),
+ CS_ENTRY(0xC05C, ECDHE,ECDSA,ARIA128,GCM,SHA256,,,),
+ CS_ENTRY(0xC05D, TLS,ECDHE,ECDSA,WITH,ARIA,256,GCM,SHA384),
+ CS_ENTRY(0xC05D, ECDHE,ECDSA,ARIA256,GCM,SHA384,,,),
+ CS_ENTRY(0xC05E, TLS,ECDH,ECDSA,WITH,ARIA,128,GCM,SHA256),
+ CS_ENTRY(0xC05E, ECDH,ECDSA,ARIA128,GCM,SHA256,,,), /* ns */
+ CS_ENTRY(0xC05F, TLS,ECDH,ECDSA,WITH,ARIA,256,GCM,SHA384),
+ CS_ENTRY(0xC05F, ECDH,ECDSA,ARIA256,GCM,SHA384,,,), /* ns */
+ CS_ENTRY(0xC060, TLS,ECDHE,RSA,WITH,ARIA,128,GCM,SHA256),
+ CS_ENTRY(0xC060, ECDHE,ARIA128,GCM,SHA256,,,,),
+ CS_ENTRY(0xC061, TLS,ECDHE,RSA,WITH,ARIA,256,GCM,SHA384),
+ CS_ENTRY(0xC061, ECDHE,ARIA256,GCM,SHA384,,,,),
+ CS_ENTRY(0xC062, TLS,ECDH,RSA,WITH,ARIA,128,GCM,SHA256),
+ CS_ENTRY(0xC062, ECDH,ARIA128,GCM,SHA256,,,,), /* ns */
+ CS_ENTRY(0xC063, TLS,ECDH,RSA,WITH,ARIA,256,GCM,SHA384),
+ CS_ENTRY(0xC063, ECDH,ARIA256,GCM,SHA384,,,,), /* ns */
+ CS_ENTRY(0xC064, TLS,PSK,WITH,ARIA,128,CBC,SHA256,),
+ CS_ENTRY(0xC064, PSK,ARIA128,SHA256,,,,,), /* ns */
+ CS_ENTRY(0xC065, TLS,PSK,WITH,ARIA,256,CBC,SHA384,),
+ CS_ENTRY(0xC065, PSK,ARIA256,SHA384,,,,,), /* ns */
+ CS_ENTRY(0xC066, TLS,DHE,PSK,WITH,ARIA,128,CBC,SHA256),
+ CS_ENTRY(0xC066, DHE,PSK,ARIA128,SHA256,,,,), /* ns */
+ CS_ENTRY(0xC067, TLS,DHE,PSK,WITH,ARIA,256,CBC,SHA384),
+ CS_ENTRY(0xC067, DHE,PSK,ARIA256,SHA384,,,,), /* ns */
+ CS_ENTRY(0xC068, TLS,RSA,PSK,WITH,ARIA,128,CBC,SHA256),
+ CS_ENTRY(0xC068, RSA,PSK,ARIA128,SHA256,,,,), /* ns */
+ CS_ENTRY(0xC069, TLS,RSA,PSK,WITH,ARIA,256,CBC,SHA384),
+ CS_ENTRY(0xC069, RSA,PSK,ARIA256,SHA384,,,,), /* ns */
+ CS_ENTRY(0xC06A, TLS,PSK,WITH,ARIA,128,GCM,SHA256,),
+ CS_ENTRY(0xC06A, PSK,ARIA128,GCM,SHA256,,,,),
+ CS_ENTRY(0xC06B, TLS,PSK,WITH,ARIA,256,GCM,SHA384,),
+ CS_ENTRY(0xC06B, PSK,ARIA256,GCM,SHA384,,,,),
+ CS_ENTRY(0xC06C, TLS,DHE,PSK,WITH,ARIA,128,GCM,SHA256),
+ CS_ENTRY(0xC06C, DHE,PSK,ARIA128,GCM,SHA256,,,),
+ CS_ENTRY(0xC06D, TLS,DHE,PSK,WITH,ARIA,256,GCM,SHA384),
+ CS_ENTRY(0xC06D, DHE,PSK,ARIA256,GCM,SHA384,,,),
+ CS_ENTRY(0xC06E, TLS,RSA,PSK,WITH,ARIA,128,GCM,SHA256),
+ CS_ENTRY(0xC06E, RSA,PSK,ARIA128,GCM,SHA256,,,),
+ CS_ENTRY(0xC06F, TLS,RSA,PSK,WITH,ARIA,256,GCM,SHA384),
+ CS_ENTRY(0xC06F, RSA,PSK,ARIA256,GCM,SHA384,,,),
+ CS_ENTRY(0xC070, TLS,ECDHE,PSK,WITH,ARIA,128,CBC,SHA256),
+ CS_ENTRY(0xC070, ECDHE,PSK,ARIA128,SHA256,,,,), /* ns */
+ CS_ENTRY(0xC071, TLS,ECDHE,PSK,WITH,ARIA,256,CBC,SHA384),
+ CS_ENTRY(0xC071, ECDHE,PSK,ARIA256,SHA384,,,,), /* ns */
+ CS_ENTRY(0xC072, TLS,ECDHE,ECDSA,WITH,CAMELLIA,128,CBC,SHA256),
+ CS_ENTRY(0xC072, ECDHE,ECDSA,CAMELLIA128,SHA256,,,,),
+ CS_ENTRY(0xC073, TLS,ECDHE,ECDSA,WITH,CAMELLIA,256,CBC,SHA384),
+ CS_ENTRY(0xC073, ECDHE,ECDSA,CAMELLIA256,SHA384,,,,),
+ CS_ENTRY(0xC074, TLS,ECDH,ECDSA,WITH,CAMELLIA,128,CBC,SHA256),
+ CS_ENTRY(0xC074, ECDH,ECDSA,CAMELLIA128,SHA256,,,,), /* ns */
+ CS_ENTRY(0xC075, TLS,ECDH,ECDSA,WITH,CAMELLIA,256,CBC,SHA384),
+ CS_ENTRY(0xC075, ECDH,ECDSA,CAMELLIA256,SHA384,,,,), /* ns */
+ CS_ENTRY(0xC076, TLS,ECDHE,RSA,WITH,CAMELLIA,128,CBC,SHA256),
+ CS_ENTRY(0xC076, ECDHE,RSA,CAMELLIA128,SHA256,,,,),
+ CS_ENTRY(0xC077, TLS,ECDHE,RSA,WITH,CAMELLIA,256,CBC,SHA384),
+ CS_ENTRY(0xC077, ECDHE,RSA,CAMELLIA256,SHA384,,,,),
+ CS_ENTRY(0xC078, TLS,ECDH,RSA,WITH,CAMELLIA,128,CBC,SHA256),
+ CS_ENTRY(0xC078, ECDH,CAMELLIA128,SHA256,,,,,), /* ns */
+ CS_ENTRY(0xC079, TLS,ECDH,RSA,WITH,CAMELLIA,256,CBC,SHA384),
+ CS_ENTRY(0xC079, ECDH,CAMELLIA256,SHA384,,,,,), /* ns */
+ CS_ENTRY(0xC07A, TLS,RSA,WITH,CAMELLIA,128,GCM,SHA256,),
+ CS_ENTRY(0xC07A, CAMELLIA128,GCM,SHA256,,,,,), /* ns */
+ CS_ENTRY(0xC07B, TLS,RSA,WITH,CAMELLIA,256,GCM,SHA384,),
+ CS_ENTRY(0xC07B, CAMELLIA256,GCM,SHA384,,,,,), /* ns */
+ CS_ENTRY(0xC07C, TLS,DHE,RSA,WITH,CAMELLIA,128,GCM,SHA256),
+ CS_ENTRY(0xC07C, DHE,RSA,CAMELLIA128,GCM,SHA256,,,), /* ns */
+ CS_ENTRY(0xC07D, TLS,DHE,RSA,WITH,CAMELLIA,256,GCM,SHA384),
+ CS_ENTRY(0xC07D, DHE,RSA,CAMELLIA256,GCM,SHA384,,,), /* ns */
+ CS_ENTRY(0xC086, TLS,ECDHE,ECDSA,WITH,CAMELLIA,128,GCM,SHA256),
+ CS_ENTRY(0xC086, ECDHE,ECDSA,CAMELLIA128,GCM,SHA256,,,), /* ns */
+ CS_ENTRY(0xC087, TLS,ECDHE,ECDSA,WITH,CAMELLIA,256,GCM,SHA384),
+ CS_ENTRY(0xC087, ECDHE,ECDSA,CAMELLIA256,GCM,SHA384,,,), /* ns */
+ CS_ENTRY(0xC088, TLS,ECDH,ECDSA,WITH,CAMELLIA,128,GCM,SHA256),
+ CS_ENTRY(0xC088, ECDH,ECDSA,CAMELLIA128,GCM,SHA256,,,), /* ns */
+ CS_ENTRY(0xC089, TLS,ECDH,ECDSA,WITH,CAMELLIA,256,GCM,SHA384),
+ CS_ENTRY(0xC089, ECDH,ECDSA,CAMELLIA256,GCM,SHA384,,,), /* ns */
+ CS_ENTRY(0xC08A, TLS,ECDHE,RSA,WITH,CAMELLIA,128,GCM,SHA256),
+ CS_ENTRY(0xC08A, ECDHE,CAMELLIA128,GCM,SHA256,,,,), /* ns */
+ CS_ENTRY(0xC08B, TLS,ECDHE,RSA,WITH,CAMELLIA,256,GCM,SHA384),
+ CS_ENTRY(0xC08B, ECDHE,CAMELLIA256,GCM,SHA384,,,,), /* ns */
+ CS_ENTRY(0xC08C, TLS,ECDH,RSA,WITH,CAMELLIA,128,GCM,SHA256),
+ CS_ENTRY(0xC08C, ECDH,CAMELLIA128,GCM,SHA256,,,,), /* ns */
+ CS_ENTRY(0xC08D, TLS,ECDH,RSA,WITH,CAMELLIA,256,GCM,SHA384),
+ CS_ENTRY(0xC08D, ECDH,CAMELLIA256,GCM,SHA384,,,,), /* ns */
+ CS_ENTRY(0xC08E, TLS,PSK,WITH,CAMELLIA,128,GCM,SHA256,),
+ CS_ENTRY(0xC08E, PSK,CAMELLIA128,GCM,SHA256,,,,), /* ns */
+ CS_ENTRY(0xC08F, TLS,PSK,WITH,CAMELLIA,256,GCM,SHA384,),
+ CS_ENTRY(0xC08F, PSK,CAMELLIA256,GCM,SHA384,,,,), /* ns */
+ CS_ENTRY(0xC090, TLS,DHE,PSK,WITH,CAMELLIA,128,GCM,SHA256),
+ CS_ENTRY(0xC090, DHE,PSK,CAMELLIA128,GCM,SHA256,,,), /* ns */
+ CS_ENTRY(0xC091, TLS,DHE,PSK,WITH,CAMELLIA,256,GCM,SHA384),
+ CS_ENTRY(0xC091, DHE,PSK,CAMELLIA256,GCM,SHA384,,,), /* ns */
+ CS_ENTRY(0xC092, TLS,RSA,PSK,WITH,CAMELLIA,128,GCM,SHA256),
+ CS_ENTRY(0xC092, RSA,PSK,CAMELLIA128,GCM,SHA256,,,), /* ns */
+ CS_ENTRY(0xC093, TLS,RSA,PSK,WITH,CAMELLIA,256,GCM,SHA384),
+ CS_ENTRY(0xC093, RSA,PSK,CAMELLIA256,GCM,SHA384,,,), /* ns */
+ CS_ENTRY(0xC094, TLS,PSK,WITH,CAMELLIA,128,CBC,SHA256,),
+ CS_ENTRY(0xC094, PSK,CAMELLIA128,SHA256,,,,,),
+ CS_ENTRY(0xC095, TLS,PSK,WITH,CAMELLIA,256,CBC,SHA384,),
+ CS_ENTRY(0xC095, PSK,CAMELLIA256,SHA384,,,,,),
+ CS_ENTRY(0xC096, TLS,DHE,PSK,WITH,CAMELLIA,128,CBC,SHA256),
+ CS_ENTRY(0xC096, DHE,PSK,CAMELLIA128,SHA256,,,,),
+ CS_ENTRY(0xC097, TLS,DHE,PSK,WITH,CAMELLIA,256,CBC,SHA384),
+ CS_ENTRY(0xC097, DHE,PSK,CAMELLIA256,SHA384,,,,),
+ CS_ENTRY(0xC098, TLS,RSA,PSK,WITH,CAMELLIA,128,CBC,SHA256),
+ CS_ENTRY(0xC098, RSA,PSK,CAMELLIA128,SHA256,,,,),
+ CS_ENTRY(0xC099, TLS,RSA,PSK,WITH,CAMELLIA,256,CBC,SHA384),
+ CS_ENTRY(0xC099, RSA,PSK,CAMELLIA256,SHA384,,,,),
+ CS_ENTRY(0xC09A, TLS,ECDHE,PSK,WITH,CAMELLIA,128,CBC,SHA256),
+ CS_ENTRY(0xC09A, ECDHE,PSK,CAMELLIA128,SHA256,,,,),
+ CS_ENTRY(0xC09B, TLS,ECDHE,PSK,WITH,CAMELLIA,256,CBC,SHA384),
+ CS_ENTRY(0xC09B, ECDHE,PSK,CAMELLIA256,SHA384,,,,),
+ CS_ENTRY(0xC09E, TLS,DHE,RSA,WITH,AES,128,CCM,),
+ CS_ENTRY(0xC09E, DHE,RSA,AES128,CCM,,,,),
+ CS_ENTRY(0xC09F, TLS,DHE,RSA,WITH,AES,256,CCM,),
+ CS_ENTRY(0xC09F, DHE,RSA,AES256,CCM,,,,),
+ CS_ENTRY(0xC0A2, TLS,DHE,RSA,WITH,AES,128,CCM,8),
+ CS_ENTRY(0xC0A2, DHE,RSA,AES128,CCM8,,,,),
+ CS_ENTRY(0xC0A3, TLS,DHE,RSA,WITH,AES,256,CCM,8),
+ CS_ENTRY(0xC0A3, DHE,RSA,AES256,CCM8,,,,),
+ CS_ENTRY(0xC0A4, TLS,PSK,WITH,AES,128,CCM,,),
+ CS_ENTRY(0xC0A4, PSK,AES128,CCM,,,,,),
+ CS_ENTRY(0xC0A5, TLS,PSK,WITH,AES,256,CCM,,),
+ CS_ENTRY(0xC0A5, PSK,AES256,CCM,,,,,),
+ CS_ENTRY(0xC0A6, TLS,DHE,PSK,WITH,AES,128,CCM,),
+ CS_ENTRY(0xC0A6, DHE,PSK,AES128,CCM,,,,),
+ CS_ENTRY(0xC0A7, TLS,DHE,PSK,WITH,AES,256,CCM,),
+ CS_ENTRY(0xC0A7, DHE,PSK,AES256,CCM,,,,),
+ CS_ENTRY(0xC0A8, TLS,PSK,WITH,AES,128,CCM,8,),
+ CS_ENTRY(0xC0A8, PSK,AES128,CCM8,,,,,),
+ CS_ENTRY(0xC0A9, TLS,PSK,WITH,AES,256,CCM,8,),
+ CS_ENTRY(0xC0A9, PSK,AES256,CCM8,,,,,),
+ CS_ENTRY(0xC0AA, TLS,PSK,DHE,WITH,AES,128,CCM,8),
+ CS_ENTRY(0xC0AA, DHE,PSK,AES128,CCM8,,,,),
+ CS_ENTRY(0xC0AB, TLS,PSK,DHE,WITH,AES,256,CCM,8),
+ CS_ENTRY(0xC0AB, DHE,PSK,AES256,CCM8,,,,),
+ CS_ENTRY(0xCCAA, TLS,DHE,RSA,WITH,CHACHA20,POLY1305,SHA256,),
+ CS_ENTRY(0xCCAA, DHE,RSA,CHACHA20,POLY1305,,,,),
+ CS_ENTRY(0xCCAC, TLS,ECDHE,PSK,WITH,CHACHA20,POLY1305,SHA256,),
+ CS_ENTRY(0xCCAC, ECDHE,PSK,CHACHA20,POLY1305,,,,),
+ CS_ENTRY(0xCCAD, TLS,DHE,PSK,WITH,CHACHA20,POLY1305,SHA256,),
+ CS_ENTRY(0xCCAD, DHE,PSK,CHACHA20,POLY1305,,,,),
+ CS_ENTRY(0xCCAE, TLS,RSA,PSK,WITH,CHACHA20,POLY1305,SHA256,),
+ CS_ENTRY(0xCCAE, RSA,PSK,CHACHA20,POLY1305,,,,),
+#endif
+};
+#define CS_LIST_LEN (sizeof(cs_list) / sizeof(cs_list[0]))
+
+static int cs_str_to_zip(const char *cs_str, size_t cs_len,
+ uint8_t zip[6])
+{
+ uint8_t indexes[8] = {0};
+ const char *entry, *cur;
+ const char *nxt = cs_str;
+ const char *end = cs_str + cs_len;
+ char separator = '-';
+ int idx, i = 0;
+ size_t len;
+
+ /* split the cipher string by '-' or '_' */
+ if(strncasecompare(cs_str, "TLS", 3))
+ separator = '_';
+
+ do {
+ if(i == 8)
+ return -1;
+
+ /* determine the length of the part */
+ cur = nxt;
+ for(; nxt < end && *nxt != '\0' && *nxt != separator; nxt++);
+ len = nxt - cur;
+
+ /* lookup index for the part (skip empty string at 0) */
+ for(idx = 1, entry = cs_txt + 1; idx < CS_TXT_LEN; idx++) {
+ size_t elen = strlen(entry);
+ if(elen == len && strncasecompare(entry, cur, len))
+ break;
+ entry += elen + 1;
+ }
+ if(idx == CS_TXT_LEN)
+ return -1;
+
+ indexes[i++] = (uint8_t) idx;
+ } while(nxt < end && *(nxt++) != '\0');
+
+ /* zip the 8 indexes into 48 bits */
+ zip[0] = (uint8_t) (indexes[0] << 2 | (indexes[1] & 0x3F) >> 4);
+ zip[1] = (uint8_t) (indexes[1] << 4 | (indexes[2] & 0x3F) >> 2);
+ zip[2] = (uint8_t) (indexes[2] << 6 | (indexes[3] & 0x3F));
+ zip[3] = (uint8_t) (indexes[4] << 2 | (indexes[5] & 0x3F) >> 4);
+ zip[4] = (uint8_t) (indexes[5] << 4 | (indexes[6] & 0x3F) >> 2);
+ zip[5] = (uint8_t) (indexes[6] << 6 | (indexes[7] & 0x3F));
+
+ return 0;
+}
+
+static int cs_zip_to_str(const uint8_t zip[6],
+ char *buf, size_t buf_size)
+{
+ uint8_t indexes[8] = {0};
+ const char *entry;
+ char separator = '-';
+ int idx, i, r;
+ size_t len = 0;
+
+ /* unzip the 8 indexes */
+ indexes[0] = zip[0] >> 2;
+ indexes[1] = ((zip[0] << 4) & 0x3F) | zip[1] >> 4;
+ indexes[2] = ((zip[1] << 2) & 0x3F) | zip[2] >> 6;
+ indexes[3] = ((zip[2] << 0) & 0x3F);
+ indexes[4] = zip[3] >> 2;
+ indexes[5] = ((zip[3] << 4) & 0x3F) | zip[4] >> 4;
+ indexes[6] = ((zip[4] << 2) & 0x3F) | zip[5] >> 6;
+ indexes[7] = ((zip[5] << 0) & 0x3F);
+
+ if(indexes[0] == CS_TXT_IDX_TLS)
+ separator = '_';
+
+ for(i = 0; i < 8 && indexes[i] != 0 && len < buf_size; i++) {
+ if(indexes[i] >= CS_TXT_LEN)
+ return -1;
+
+ /* lookup the part string for the index (skip empty string at 0) */
+ for(idx = 1, entry = cs_txt + 1; idx < indexes[i]; idx++) {
+ size_t elen = strlen(entry);
+ entry += elen + 1;
+ }
+
+ /* append the part string to the buffer */
+ if(i > 0)
+ r = msnprintf(&buf[len], buf_size - len, "%c%s", separator, entry);
+ else
+ r = msnprintf(&buf[len], buf_size - len, "%s", entry);
+
+ if(r < 0)
+ return -1;
+ len += r;
+ }
+
+ return 0;
+}
+
+uint16_t Curl_cipher_suite_lookup_id(const char *cs_str, size_t cs_len)
+{
+ size_t i;
+ uint8_t zip[6];
+
+ if(cs_len > 0 && cs_str_to_zip(cs_str, cs_len, zip) == 0) {
+ for(i = 0; i < CS_LIST_LEN; i++) {
+ if(memcmp(cs_list[i].zip, zip, sizeof(zip)) == 0)
+ return cs_list[i].id;
+ }
+ }
+
+ return 0;
+}
+
+static bool cs_is_separator(char c)
+{
+ switch(c) {
+ case ' ':
+ case '\t':
+ case ':':
+ case ',':
+ case ';':
+ return true;
+ default:;
+ }
+ return false;
+}
+
+uint16_t Curl_cipher_suite_walk_str(const char **str, const char **end)
+{
+ /* move string pointer to first non-separator or end of string */
+ for(; cs_is_separator(*str[0]); (*str)++);
+
+ /* move end pointer to next separator or end of string */
+ for(*end = *str; *end[0] != '\0' && !cs_is_separator(*end[0]); (*end)++);
+
+ return Curl_cipher_suite_lookup_id(*str, *end - *str);
+}
+
+int Curl_cipher_suite_get_str(uint16_t id, char *buf, size_t buf_size,
+ bool prefer_rfc)
+{
+ size_t i, j = CS_LIST_LEN;
+ int r = -1;
+
+ for(i = 0; i < CS_LIST_LEN; i++) {
+ if(cs_list[i].id != id)
+ continue;
+ if((cs_list[i].zip[0] >> 2 != CS_TXT_IDX_TLS) == !prefer_rfc) {
+ j = i;
+ break;
+ }
+ if(j == CS_LIST_LEN)
+ j = i;
+ }
+
+ if(j < CS_LIST_LEN)
+ r = cs_zip_to_str(cs_list[j].zip, buf, buf_size);
+
+ if(r < 0)
+ msnprintf(buf, buf_size, "TLS_UNKNOWN_0x%04x", id);
+
+ return r;
+}
+
+#endif /* defined(USE_MBEDTLS) || defined(USE_BEARSSL) */
diff --git a/libs/libcurl/src/vtls/cipher_suite.h b/libs/libcurl/src/vtls/cipher_suite.h
new file mode 100644
index 0000000000..712325e9f3
--- /dev/null
+++ b/libs/libcurl/src/vtls/cipher_suite.h
@@ -0,0 +1,46 @@
+#ifndef HEADER_CURL_CIPHER_SUITE_H
+#define HEADER_CURL_CIPHER_SUITE_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Jan Venekamp, <jan@venekamp.net>
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if defined(USE_MBEDTLS) || defined(USE_BEARSSL)
+#include <stdint.h>
+
+/* Lookup IANA id for cipher suite string, returns 0 if not recognized */
+uint16_t Curl_cipher_suite_lookup_id(const char *cs_str, size_t cs_len);
+
+/* Walk over cipher suite string, update str and end pointers to next
+ cipher suite in string, returns IANA id of that suite if recognized */
+uint16_t Curl_cipher_suite_walk_str(const char **str, const char **end);
+
+/* Copy openssl or RFC name for cipher suite in supplied buffer.
+ Caller is responsible to supply sufficiently large buffer (size
+ of 64 should suffice), excess bytes are silently truncated. */
+int Curl_cipher_suite_get_str(uint16_t id, char *buf, size_t buf_size,
+ bool prefer_rfc);
+
+#endif /* defined(USE_MBEDTLS) || defined(USE_BEARSSL) */
+#endif /* HEADER_CURL_CIPHER_SUITE_H */
diff --git a/libs/libcurl/src/vtls/gtls.c b/libs/libcurl/src/vtls/gtls.c
index 1184ceb5c6..ef7f6059a3 100644
--- a/libs/libcurl/src/vtls/gtls.c
+++ b/libs/libcurl/src/vtls/gtls.c
@@ -43,6 +43,7 @@
#include "urldata.h"
#include "sendf.h"
#include "inet_pton.h"
+#include "keylog.h"
#include "gtls.h"
#include "vtls.h"
#include "vtls_int.h"
@@ -59,6 +60,16 @@
/* The last #include file should be: */
#include "memdebug.h"
+#ifndef ARRAYSIZE
+#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
+#endif
+
+#define QUIC_PRIORITY \
+ "NORMAL:-VERS-ALL:+VERS-TLS1.3:-CIPHER-ALL:+AES-128-GCM:+AES-256-GCM:" \
+ "+CHACHA20-POLY1305:+AES-128-CCM:-GROUP-ALL:+GROUP-SECP256R1:" \
+ "+GROUP-X25519:+GROUP-SECP384R1:+GROUP-SECP521R1:" \
+ "%DISABLE_TLS13_COMPAT_MODE"
+
/* Enable GnuTLS debugging by defining GTLSDEBUG */
/*#define GTLSDEBUG */
@@ -77,22 +88,25 @@ static bool gtls_inited = FALSE;
# include <gnutls/ocsp.h>
struct gtls_ssl_backend_data {
- struct gtls_instance gtls;
+ struct gtls_ctx gtls;
};
static ssize_t gtls_push(void *s, const void *buf, size_t blen)
{
struct Curl_cfilter *cf = s;
struct ssl_connect_data *connssl = cf->ctx;
+ struct gtls_ssl_backend_data *backend =
+ (struct gtls_ssl_backend_data *)connssl->backend;
struct Curl_easy *data = CF_DATA_CURRENT(cf);
ssize_t nwritten;
CURLcode result;
DEBUGASSERT(data);
nwritten = Curl_conn_cf_send(cf->next, data, buf, blen, &result);
+ CURL_TRC_CF(data, cf, "gtls_push(len=%zu) -> %zd, err=%d",
+ blen, nwritten, result);
+ backend->gtls.io_result = result;
if(nwritten < 0) {
- struct gtls_ssl_backend_data *backend =
- (struct gtls_ssl_backend_data *)connssl->backend;
gnutls_transport_set_errno(backend->gtls.session,
(CURLE_AGAIN == result)? EAGAIN : EINVAL);
nwritten = -1;
@@ -104,15 +118,27 @@ static ssize_t gtls_pull(void *s, void *buf, size_t blen)
{
struct Curl_cfilter *cf = s;
struct ssl_connect_data *connssl = cf->ctx;
+ struct gtls_ssl_backend_data *backend =
+ (struct gtls_ssl_backend_data *)connssl->backend;
struct Curl_easy *data = CF_DATA_CURRENT(cf);
ssize_t nread;
CURLcode result;
DEBUGASSERT(data);
+ if(!backend->gtls.trust_setup) {
+ result = Curl_gtls_client_trust_setup(cf, data, &backend->gtls);
+ if(result) {
+ gnutls_transport_set_errno(backend->gtls.session, EINVAL);
+ backend->gtls.io_result = result;
+ return -1;
+ }
+ }
+
nread = Curl_conn_cf_recv(cf->next, data, buf, blen, &result);
+ CURL_TRC_CF(data, cf, "glts_pull(len=%zu) -> %zd, err=%d",
+ blen, nread, result);
+ backend->gtls.io_result = result;
if(nread < 0) {
- struct gtls_ssl_backend_data *backend =
- (struct gtls_ssl_backend_data *)connssl->backend;
gnutls_transport_set_errno(backend->gtls.session,
(CURLE_AGAIN == result)? EAGAIN : EINVAL);
nread = -1;
@@ -268,8 +294,17 @@ static CURLcode handshake(struct Curl_cfilter *cf,
/* socket is readable or writable */
}
+ backend->gtls.io_result = CURLE_OK;
rc = gnutls_handshake(session);
+ if(!backend->gtls.trust_setup) {
+ /* After having send off the ClientHello, we prepare the trust
+ * store to verify the coming certificate from the server */
+ CURLcode result = Curl_gtls_client_trust_setup(cf, data, &backend->gtls);
+ if(result)
+ return result;
+ }
+
if((rc == GNUTLS_E_AGAIN) || (rc == GNUTLS_E_INTERRUPTED)) {
connssl->connecting_state =
gnutls_record_get_direction(session)?
@@ -290,6 +325,9 @@ static CURLcode handshake(struct Curl_cfilter *cf,
infof(data, "gnutls_handshake() warning: %s", strerr);
continue;
}
+ else if((rc < 0) && backend->gtls.io_result) {
+ return backend->gtls.io_result;
+ }
else if(rc < 0) {
const char *strerr = NULL;
@@ -330,6 +368,7 @@ static gnutls_x509_crt_fmt_t do_file_type(const char *type)
static CURLcode
set_ssl_version_min_max(struct Curl_easy *data,
+ struct ssl_peer *peer,
struct ssl_primary_config *conn_config,
const char **prioritylist,
const char *tls13support)
@@ -337,6 +376,16 @@ set_ssl_version_min_max(struct Curl_easy *data,
long ssl_version = conn_config->version;
long ssl_version_max = conn_config->version_max;
+ if(peer->transport == TRNSPRT_QUIC) {
+ if((ssl_version != CURL_SSLVERSION_DEFAULT) &&
+ (ssl_version < CURL_SSLVERSION_TLSv1_3)) {
+ failf(data, "QUIC needs at least TLS version 1.3");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ *prioritylist = QUIC_PRIORITY;
+ return CURLE_OK;
+ }
+
if((ssl_version == CURL_SSLVERSION_DEFAULT) ||
(ssl_version == CURL_SSLVERSION_TLSv1))
ssl_version = CURL_SSLVERSION_TLSv1_0;
@@ -401,62 +450,15 @@ set_ssl_version_min_max(struct Curl_easy *data,
return CURLE_SSL_CONNECT_ERROR;
}
-CURLcode gtls_client_init(struct Curl_easy *data,
- struct ssl_primary_config *config,
- struct ssl_config_data *ssl_config,
- struct ssl_peer *peer,
- struct gtls_instance *gtls,
- long *pverifyresult)
+CURLcode Curl_gtls_client_trust_setup(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct gtls_ctx *gtls)
{
- unsigned int init_flags;
+ struct ssl_primary_config *config = Curl_ssl_cf_get_primary_config(cf);
+ struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
int rc;
- bool sni = TRUE; /* default is SNI enabled */
- const char *prioritylist;
- const char *err = NULL;
- const char *tls13support;
- CURLcode result;
-
- if(!gtls_inited)
- gtls_init();
-
- *pverifyresult = 0;
-
- if(config->version == CURL_SSLVERSION_SSLv2) {
- failf(data, "GnuTLS does not support SSLv2");
- return CURLE_SSL_CONNECT_ERROR;
- }
- else if(config->version == CURL_SSLVERSION_SSLv3)
- sni = FALSE; /* SSLv3 has no SNI */
-
- /* allocate a cred struct */
- rc = gnutls_certificate_allocate_credentials(&gtls->cred);
- if(rc != GNUTLS_E_SUCCESS) {
- failf(data, "gnutls_cert_all_cred() failed: %s", gnutls_strerror(rc));
- return CURLE_SSL_CONNECT_ERROR;
- }
-
-#ifdef USE_GNUTLS_SRP
- if(config->username && Curl_auth_allowed_to_host(data)) {
- infof(data, "Using TLS-SRP username: %s", config->username);
-
- rc = gnutls_srp_allocate_client_credentials(&gtls->srp_client_cred);
- if(rc != GNUTLS_E_SUCCESS) {
- failf(data, "gnutls_srp_allocate_client_cred() failed: %s",
- gnutls_strerror(rc));
- return CURLE_OUT_OF_MEMORY;
- }
-
- rc = gnutls_srp_set_client_credentials(gtls->srp_client_cred,
- config->username,
- config->password);
- if(rc != GNUTLS_E_SUCCESS) {
- failf(data, "gnutls_srp_set_client_cred() failed: %s",
- gnutls_strerror(rc));
- return CURLE_BAD_FUNCTION_ARGUMENT;
- }
- }
-#endif
+ CURL_TRC_CF(data, cf, "setup trust anchors and CRLs");
if(config->verifypeer) {
bool imported_native_ca = false;
@@ -485,7 +487,7 @@ CURLcode gtls_client_init(struct Curl_easy *data,
config->CAfile, gnutls_strerror(rc),
(imported_native_ca ? ", continuing anyway" : ""));
if(!imported_native_ca) {
- *pverifyresult = rc;
+ ssl_config->certverifyresult = rc;
return CURLE_SSL_CACERT_BADFILE;
}
}
@@ -503,7 +505,7 @@ CURLcode gtls_client_init(struct Curl_easy *data,
config->CApath, gnutls_strerror(rc),
(imported_native_ca ? ", continuing anyway" : ""));
if(!imported_native_ca) {
- *pverifyresult = rc;
+ ssl_config->certverifyresult = rc;
return CURLE_SSL_CACERT_BADFILE;
}
}
@@ -526,6 +528,148 @@ CURLcode gtls_client_init(struct Curl_easy *data,
infof(data, "found %d CRL in %s", rc, config->CRLfile);
}
+ gtls->trust_setup = TRUE;
+ return CURLE_OK;
+}
+
+static void gtls_sessionid_free(void *sessionid, size_t idsize)
+{
+ (void)idsize;
+ free(sessionid);
+}
+
+static CURLcode gtls_update_session_id(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ gnutls_session_t session)
+{
+ struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+ struct ssl_connect_data *connssl = cf->ctx;
+ CURLcode result = CURLE_OK;
+
+ if(ssl_config->primary.sessionid) {
+ /* 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 {
+ bool incache;
+ void *ssl_sessionid;
+
+ /* extract session ID to the allocated buffer */
+ gnutls_session_get_data(session, connect_sessionid, &connect_idsize);
+
+ DEBUGF(infof(data, "get session id (len=%zu) and store in cache",
+ connect_idsize));
+ Curl_ssl_sessionid_lock(data);
+ incache = !(Curl_ssl_getsessionid(cf, data, &connssl->peer,
+ &ssl_sessionid, NULL));
+ if(incache) {
+ /* there was one before in the cache, so instead of risking that the
+ previous one was rejected, we just kill that and store the new */
+ Curl_ssl_delsessionid(data, ssl_sessionid);
+ }
+
+ /* store this session id, takes ownership */
+ result = Curl_ssl_addsessionid(cf, data, &connssl->peer,
+ connect_sessionid, connect_idsize,
+ gtls_sessionid_free);
+ Curl_ssl_sessionid_unlock(data);
+ }
+ }
+ return result;
+}
+
+static int gtls_handshake_cb(gnutls_session_t session, unsigned int htype,
+ unsigned when, unsigned int incoming,
+ const gnutls_datum_t *msg)
+{
+ struct Curl_cfilter *cf = gnutls_session_get_ptr(session);
+
+ (void)msg;
+ (void)incoming;
+ if(when) { /* after message has been processed */
+ struct Curl_easy *data = CF_DATA_CURRENT(cf);
+ if(data) {
+ DEBUGF(infof(data, "handshake: %s message type %d",
+ incoming? "incoming" : "outgoing", htype));
+ switch(htype) {
+ case GNUTLS_HANDSHAKE_NEW_SESSION_TICKET: {
+ gtls_update_session_id(cf, data, session);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ }
+ return 0;
+}
+
+static CURLcode gtls_client_init(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct ssl_peer *peer,
+ struct gtls_ctx *gtls)
+{
+ struct ssl_primary_config *config = Curl_ssl_cf_get_primary_config(cf);
+ struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+ unsigned int init_flags;
+ int rc;
+ bool sni = TRUE; /* default is SNI enabled */
+ const char *prioritylist;
+ const char *err = NULL;
+ const char *tls13support;
+ CURLcode result;
+
+ if(!gtls_inited)
+ gtls_init();
+
+ if(config->version == CURL_SSLVERSION_SSLv2) {
+ failf(data, "GnuTLS does not support SSLv2");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ else if(config->version == CURL_SSLVERSION_SSLv3)
+ sni = FALSE; /* SSLv3 has no SNI */
+
+ /* allocate a cred struct */
+ rc = gnutls_certificate_allocate_credentials(&gtls->cred);
+ if(rc != GNUTLS_E_SUCCESS) {
+ failf(data, "gnutls_cert_all_cred() failed: %s", gnutls_strerror(rc));
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+#ifdef USE_GNUTLS_SRP
+ if(config->username && Curl_auth_allowed_to_host(data)) {
+ infof(data, "Using TLS-SRP username: %s", config->username);
+
+ rc = gnutls_srp_allocate_client_credentials(&gtls->srp_client_cred);
+ if(rc != GNUTLS_E_SUCCESS) {
+ failf(data, "gnutls_srp_allocate_client_cred() failed: %s",
+ gnutls_strerror(rc));
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ rc = gnutls_srp_set_client_credentials(gtls->srp_client_cred,
+ config->username,
+ config->password);
+ if(rc != GNUTLS_E_SUCCESS) {
+ failf(data, "gnutls_srp_set_client_cred() failed: %s",
+ gnutls_strerror(rc));
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ }
+ }
+#endif
+
+ ssl_config->certverifyresult = 0;
+
/* Initialize TLS session as a client */
init_flags = GNUTLS_CLIENT;
@@ -578,7 +722,8 @@ CURLcode gtls_client_init(struct Curl_easy *data,
}
/* At this point we know we have a supported TLS version, so set it */
- result = set_ssl_version_min_max(data, config, &prioritylist, tls13support);
+ result = set_ssl_version_min_max(data, peer,
+ config, &prioritylist, tls13support);
if(result)
return result;
@@ -611,6 +756,11 @@ CURLcode gtls_client_init(struct Curl_easy *data,
}
if(config->clientcert) {
+ if(!gtls->trust_setup) {
+ result = Curl_gtls_client_trust_setup(cf, data, gtls);
+ if(result)
+ return result;
+ }
if(ssl_config->key_passwd) {
const unsigned int supported_key_encryption_algorithms =
GNUTLS_PKCS_USE_PKCS12_3DES | GNUTLS_PKCS_USE_PKCS12_ARCFOUR |
@@ -677,46 +827,78 @@ CURLcode gtls_client_init(struct Curl_easy *data,
return CURLE_OK;
}
-static CURLcode
-gtls_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
+static int keylog_callback(gnutls_session_t session, const char *label,
+ const gnutls_datum_t *secret)
+{
+ gnutls_datum_t crandom;
+ gnutls_datum_t srandom;
+
+ gnutls_session_get_random(session, &crandom, &srandom);
+ if(crandom.size != 32) {
+ return -1;
+ }
+
+ Curl_tls_keylog_write(label, crandom.data, secret->data, secret->size);
+ return 0;
+}
+
+CURLcode Curl_gtls_ctx_init(struct gtls_ctx *gctx,
+ struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct ssl_peer *peer,
+ const unsigned char *alpn, size_t alpn_len,
+ Curl_gtls_ctx_setup_cb *cb_setup,
+ void *cb_user_data,
+ void *ssl_user_data)
{
- struct ssl_connect_data *connssl = cf->ctx;
- struct gtls_ssl_backend_data *backend =
- (struct gtls_ssl_backend_data *)connssl->backend;
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
- struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
- long * const pverifyresult = &ssl_config->certverifyresult;
CURLcode result;
- DEBUGASSERT(backend);
-
- if(connssl->state == ssl_connection_complete)
- /* to make us tolerant against being called more than once for the
- same connection */
- return CURLE_OK;
+ DEBUGASSERT(gctx);
- result = gtls_client_init(data, conn_config, ssl_config,
- &connssl->peer,
- &backend->gtls, pverifyresult);
+ result = gtls_client_init(cf, data, peer, gctx);
if(result)
return result;
- if(connssl->alpn) {
- struct alpn_proto_buf proto;
- gnutls_datum_t alpn[ALPN_ENTRIES_MAX];
- size_t i;
+ gnutls_session_set_ptr(gctx->session, ssl_user_data);
+
+ if(cb_setup) {
+ result = cb_setup(cf, data, cb_user_data);
+ if(result)
+ return result;
+ }
+
+ /* Open the file if a TLS or QUIC backend has not done this before. */
+ Curl_tls_keylog_open();
+ if(Curl_tls_keylog_enabled()) {
+ gnutls_session_set_keylog_function(gctx->session, keylog_callback);
+ }
- for(i = 0; i < connssl->alpn->count; ++i) {
- alpn[i].data = (unsigned char *)connssl->alpn->entries[i];
- alpn[i].size = (unsigned)strlen(connssl->alpn->entries[i]);
+ /* 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(gnutls_alpn_set_protocols(backend->gtls.session, alpn,
- (unsigned)connssl->alpn->count, 0)) {
+ 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;
}
- Curl_alpn_to_proto_str(&proto, connssl->alpn);
- infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data);
}
/* This might be a reconnect, so we check for a session ID in the cache
@@ -726,16 +908,55 @@ gtls_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
size_t ssl_idsize;
Curl_ssl_sessionid_lock(data);
- if(!Curl_ssl_getsessionid(cf, data, &ssl_sessionid, &ssl_idsize)) {
+ if(!Curl_ssl_getsessionid(cf, data, peer, &ssl_sessionid, &ssl_idsize)) {
/* we got a session id, use it! */
- gnutls_session_set_data(backend->gtls.session,
- ssl_sessionid, ssl_idsize);
+ int rc;
- /* Informational message */
- infof(data, "SSL reusing session ID");
+ 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);
}
Curl_ssl_sessionid_unlock(data);
}
+ return CURLE_OK;
+}
+
+static CURLcode
+gtls_connect_step1(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;
+ struct alpn_proto_buf proto;
+ CURLcode result;
+
+ DEBUGASSERT(backend);
+ DEBUGASSERT(ssl_connect_1 == connssl->connecting_state);
+
+ if(connssl->state == ssl_connection_complete)
+ /* to make us tolerant against being called more than once for the
+ same connection */
+ return CURLE_OK;
+
+ memset(&proto, 0, sizeof(proto));
+ if(connssl->alpn) {
+ result = Curl_alpn_to_proto_buf(&proto, connssl->alpn);
+ if(result) {
+ failf(data, "Error determining ALPN");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ }
+
+ result = Curl_gtls_ctx_init(&backend->gtls, cf, data, &connssl->peer,
+ proto.data, proto.len, NULL, NULL, cf);
+ if(result)
+ return result;
+
+ gnutls_handshake_set_hook_function(backend->gtls.session,
+ GNUTLS_HANDSHAKE_ANY, GNUTLS_HOOK_POST,
+ gtls_handshake_cb);
/* register callback functions and handle to send and receive data. */
gnutls_transport_set_ptr(backend->gtls.session, cf);
@@ -1071,7 +1292,7 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
/* Before 3.3.6, gnutls_x509_crt_check_hostname() didn't check IP
addresses. */
if(!rc) {
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
#define use_addr in6_addr
#else
#define use_addr in_addr
@@ -1081,7 +1302,7 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
if(Curl_inet_pton(AF_INET, peer->hostname, addrbuf) > 0)
addrlen = 4;
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
else if(Curl_inet_pton(AF_INET6, peer->hostname, addrbuf) > 0)
addrlen = 16;
#endif
@@ -1245,9 +1466,13 @@ static CURLcode gtls_verifyserver(struct Curl_cfilter *cf,
struct ssl_connect_data *connssl = cf->ctx;
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+#ifndef CURL_DISABLE_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];
+#endif
CURLcode result;
result = Curl_gtls_verifyserver(data, session, conn_config, ssl_config,
@@ -1266,47 +1491,10 @@ static CURLcode gtls_verifyserver(struct Curl_cfilter *cf,
Curl_alpn_set_negotiated(cf, data, NULL, 0);
}
- if(ssl_config->primary.sessionid) {
- /* 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) {
- bool incache;
- bool added = FALSE;
- void *ssl_sessionid;
-
- /* extract session ID to the allocated buffer */
- gnutls_session_get_data(session, connect_sessionid, &connect_idsize);
-
- Curl_ssl_sessionid_lock(data);
- incache = !(Curl_ssl_getsessionid(cf, data, &ssl_sessionid, NULL));
- if(incache) {
- /* there was one before in the cache, so instead of risking that the
- previous one was rejected, we just kill that and store the new */
- Curl_ssl_delsessionid(data, ssl_sessionid);
- }
-
- /* store this session id */
- result = Curl_ssl_addsessionid(cf, data, connect_sessionid,
- connect_idsize, &added);
- Curl_ssl_sessionid_unlock(data);
- if(!added)
- free(connect_sessionid);
- if(result) {
- result = CURLE_OUT_OF_MEMORY;
- }
- }
- else
- result = CURLE_OUT_OF_MEMORY;
- }
+ /* 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);
out:
return result;
@@ -1418,12 +1606,13 @@ static ssize_t gtls_send(struct Curl_cfilter *cf,
(void)data;
DEBUGASSERT(backend);
+ backend->gtls.io_result = CURLE_OK;
rc = gnutls_record_send(backend->gtls.session, mem, len);
if(rc < 0) {
- *curlcode = (rc == GNUTLS_E_AGAIN)
- ? CURLE_AGAIN
- : CURLE_SEND_ERROR;
+ *curlcode = (rc == GNUTLS_E_AGAIN)?
+ CURLE_AGAIN :
+ (backend->gtls.io_result? backend->gtls.io_result : CURLE_SEND_ERROR);
rc = -1;
}
@@ -1559,6 +1748,7 @@ static ssize_t gtls_recv(struct Curl_cfilter *cf,
(void)data;
DEBUGASSERT(backend);
+ backend->gtls.io_result = CURLE_OK;
ret = gnutls_record_recv(backend->gtls.session, buf, buffersize);
if((ret == GNUTLS_E_AGAIN) || (ret == GNUTLS_E_INTERRUPTED)) {
*curlcode = CURLE_AGAIN;
@@ -1583,7 +1773,8 @@ static ssize_t gtls_recv(struct Curl_cfilter *cf,
failf(data, "GnuTLS recv error (%d): %s",
(int)ret, gnutls_strerror((int)ret));
- *curlcode = CURLE_RECV_ERROR;
+ *curlcode = backend->gtls.io_result?
+ backend->gtls.io_result : CURLE_RECV_ERROR;
ret = -1;
goto out;
}
@@ -1592,11 +1783,6 @@ out:
return ret;
}
-static void gtls_session_free(void *ptr)
-{
- free(ptr);
-}
-
static size_t gtls_version(char *buffer, size_t size)
{
return msnprintf(buffer, size, "GnuTLS/%s", gnutls_check_version(NULL));
@@ -1663,7 +1849,6 @@ const struct Curl_ssl Curl_ssl_gnutls = {
gtls_get_internals, /* get_internals */
gtls_close, /* close_one */
Curl_none_close_all, /* close_all */
- gtls_session_free, /* session_free */
Curl_none_set_engine, /* set_engine */
Curl_none_set_engine_default, /* set_engine_default */
Curl_none_engines_list, /* engines_list */
diff --git a/libs/libcurl/src/vtls/gtls.h b/libs/libcurl/src/vtls/gtls.h
index 998957e689..534b320287 100644
--- a/libs/libcurl/src/vtls/gtls.h
+++ b/libs/libcurl/src/vtls/gtls.h
@@ -45,29 +45,39 @@ struct ssl_primary_config;
struct ssl_config_data;
struct ssl_peer;
-struct gtls_instance {
+struct gtls_ctx {
gnutls_session_t session;
gnutls_certificate_credentials_t cred;
#ifdef USE_GNUTLS_SRP
gnutls_srp_client_credentials_t srp_client_cred;
#endif
+ CURLcode io_result; /* result of last IO cfilter operation */
+ BIT(trust_setup); /* x509 anchors + CRLs have been set up */
};
-CURLcode
-gtls_client_init(struct Curl_easy *data,
- struct ssl_primary_config *config,
- struct ssl_config_data *ssl_config,
- struct ssl_peer *peer,
- struct gtls_instance *gtls,
- long *pverifyresult);
+typedef CURLcode Curl_gtls_ctx_setup_cb(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ void *user_data);
-CURLcode
-Curl_gtls_verifyserver(struct Curl_easy *data,
- gnutls_session_t session,
- struct ssl_primary_config *config,
- struct ssl_config_data *ssl_config,
- struct ssl_peer *peer,
- const char *pinned_key);
+CURLcode Curl_gtls_ctx_init(struct gtls_ctx *gctx,
+ struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct ssl_peer *peer,
+ const unsigned char *alpn, size_t alpn_len,
+ Curl_gtls_ctx_setup_cb *cb_setup,
+ void *cb_user_data,
+ void *ssl_user_data);
+
+CURLcode Curl_gtls_client_trust_setup(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct gtls_ctx *gtls);
+
+CURLcode Curl_gtls_verifyserver(struct Curl_easy *data,
+ gnutls_session_t session,
+ struct ssl_primary_config *config,
+ struct ssl_config_data *ssl_config,
+ struct ssl_peer *peer,
+ const char *pinned_key);
extern const struct Curl_ssl Curl_ssl_gnutls;
diff --git a/libs/libcurl/src/vtls/keylog.c b/libs/libcurl/src/vtls/keylog.c
index 4a1f8ce74b..9cdfc02213 100644
--- a/libs/libcurl/src/vtls/keylog.c
+++ b/libs/libcurl/src/vtls/keylog.c
@@ -24,6 +24,7 @@
#include "curl_setup.h"
#if defined(USE_OPENSSL) || \
+ defined(USE_GNUTLS) || \
defined(USE_WOLFSSL) || \
(defined(USE_NGTCP2) && defined(USE_NGHTTP3)) || \
defined(USE_QUICHE)
diff --git a/libs/libcurl/src/vtls/mbedtls.c b/libs/libcurl/src/vtls/mbedtls.c
index 22a6a8cba2..d4820c4c50 100644
--- a/libs/libcurl/src/vtls/mbedtls.c
+++ b/libs/libcurl/src/vtls/mbedtls.c
@@ -67,6 +67,8 @@
#pragma GCC diagnostic pop
#endif
+#include "cipher_suite.h"
+#include "strcase.h"
#include "urldata.h"
#include "sendf.h"
#include "inet_pton.h"
@@ -107,6 +109,7 @@ struct mbed_ssl_backend_data {
#ifdef HAS_ALPN
const char *protocols[3];
#endif
+ int *ciphersuites;
};
/* apply threading? */
@@ -119,6 +122,10 @@ struct mbed_ssl_backend_data {
#define mbedtls_strerror(a,b,c) b[0] = 0
#endif
+#if defined(MBEDTLS_SSL_PROTO_TLS1_3) && MBEDTLS_VERSION_NUMBER >= 0x03060000
+#define TLS13_SUPPORT
+#endif
+
#if defined(THREADING_SUPPORT)
static mbedtls_entropy_context ts_entropy;
@@ -163,15 +170,18 @@ static int entropy_func_mutex(void *data, unsigned char *output, size_t len)
static void mbed_debug(void *context, int level, const char *f_name,
int line_nb, const char *line)
{
- struct Curl_easy *data = NULL;
-
- if(!context)
- return;
-
- data = (struct Curl_easy *)context;
-
- infof(data, "%s", line);
+ struct Curl_easy *data = (struct Curl_easy *)context;
(void) level;
+ (void) line_nb;
+ (void) f_name;
+
+ if(data) {
+ size_t len = strlen(line);
+ if(len && (line[len - 1] == '\n'))
+ /* discount any trailing newline */
+ len--;
+ infof(data, "%.*s", (int)len, line);
+ }
}
#endif
@@ -256,7 +266,12 @@ static CURLcode mbedtls_version_from_curl(
*mbedver = MBEDTLS_SSL_VERSION_TLS1_2;
return CURLE_OK;
case CURL_SSLVERSION_TLSv1_3:
+#ifdef TLS13_SUPPORT
+ *mbedver = MBEDTLS_SSL_VERSION_TLS1_3;
+ return CURLE_OK;
+#else
break;
+#endif
}
return CURLE_SSL_CONNECT_ERROR;
@@ -303,7 +318,11 @@ set_ssl_version_min_max(struct Curl_cfilter *cf, struct Curl_easy *data)
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
#if MBEDTLS_VERSION_NUMBER >= 0x03020000
mbedtls_ssl_protocol_version mbedtls_ver_min = MBEDTLS_SSL_VERSION_TLS1_2;
+#ifdef TLS13_SUPPORT
+ mbedtls_ssl_protocol_version mbedtls_ver_max = MBEDTLS_SSL_VERSION_TLS1_3;
+#else
mbedtls_ssl_protocol_version mbedtls_ver_max = MBEDTLS_SSL_VERSION_TLS1_2;
+#endif
#elif MBEDTLS_VERSION_NUMBER >= 0x03000000
int mbedtls_ver_min = MBEDTLS_SSL_MINOR_VERSION_3;
int mbedtls_ver_max = MBEDTLS_SSL_MINOR_VERSION_3;
@@ -327,7 +346,11 @@ set_ssl_version_min_max(struct Curl_cfilter *cf, struct Curl_easy *data)
switch(ssl_version_max) {
case CURL_SSLVERSION_MAX_NONE:
case CURL_SSLVERSION_MAX_DEFAULT:
+#ifdef TLS13_SUPPORT
+ ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_3;
+#else
ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
+#endif
break;
}
@@ -352,9 +375,113 @@ set_ssl_version_min_max(struct Curl_cfilter *cf, struct Curl_easy *data)
mbedtls_ver_max);
#endif
+#ifdef TLS13_SUPPORT
+ if(mbedtls_ver_min == MBEDTLS_SSL_VERSION_TLS1_3) {
+ mbedtls_ssl_conf_authmode(&backend->config, MBEDTLS_SSL_VERIFY_REQUIRED);
+ }
+ else {
+ mbedtls_ssl_conf_authmode(&backend->config, MBEDTLS_SSL_VERIFY_OPTIONAL);
+ }
+#else
+ mbedtls_ssl_conf_authmode(&backend->config, MBEDTLS_SSL_VERIFY_OPTIONAL);
+#endif
+
return result;
}
+/* TLS_ECJPAKE_WITH_AES_128_CCM_8 (0xC0FF) is marked experimental
+ in mbedTLS. The number is not reserved by IANA nor is the
+ 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
+static int
+mbed_cipher_suite_get_str(uint16_t id, char *buf, size_t buf_size,
+ bool prefer_rfc)
+{
+ if(id == MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8)
+ msnprintf(buf, buf_size, "%s", "TLS_ECJPAKE_WITH_AES_128_CCM_8");
+ else
+ return Curl_cipher_suite_get_str(id, buf, buf_size, prefer_rfc);
+ return 0;
+}
+
+static uint16_t
+mbed_cipher_suite_walk_str(const char **str, const char **end)
+{
+ uint16_t id = Curl_cipher_suite_walk_str(str, end);
+ size_t len = *end - *str;
+
+ if(!id) {
+ if(strncasecompare("TLS_ECJPAKE_WITH_AES_128_CCM_8", *str, len))
+ id = MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8;
+ }
+ return id;
+}
+#else
+#define mbed_cipher_suite_get_str Curl_cipher_suite_get_str
+#define mbed_cipher_suite_walk_str Curl_cipher_suite_walk_str
+#endif
+
+static CURLcode
+mbed_set_selected_ciphers(struct Curl_easy *data,
+ struct mbed_ssl_backend_data *backend,
+ const char *ciphers)
+{
+ const int *supported;
+ int *selected;
+ size_t supported_len, count = 0, i;
+ const char *ptr, *end;
+
+ supported = mbedtls_ssl_list_ciphersuites();
+ for(i = 0; supported[i] != 0; i++);
+ supported_len = i;
+
+ selected = malloc(sizeof(int) * (supported_len + 1));
+ if(!selected)
+ return CURLE_OUT_OF_MEMORY;
+
+ for(ptr = ciphers; ptr[0] != '\0' && count < supported_len; ptr = end) {
+ uint16_t id = mbed_cipher_suite_walk_str(&ptr, &end);
+
+ /* Check if cipher is supported */
+ if(id) {
+ for(i = 0; i < supported_len && supported[i] != id; i++);
+ if(i == supported_len)
+ id = 0;
+ }
+ if(!id) {
+ if(ptr[0] != '\0')
+ infof(data, "mbedTLS: unknown cipher in list: \"%.*s\"",
+ (int) (end - ptr), ptr);
+ continue;
+ }
+
+ /* No duplicates allowed (so selected cannot overflow) */
+ for(i = 0; i < count && selected[i] != id; i++);
+ if(i < count) {
+ infof(data, "mbedTLS: duplicate cipher in list: \"%.*s\"",
+ (int) (end - ptr), ptr);
+ continue;
+ }
+
+ selected[count++] = id;
+ }
+
+ selected[count] = 0;
+
+ if(count == 0) {
+ free(selected);
+ failf(data, "mbedTLS: no supported cipher in list");
+ return CURLE_SSL_CIPHER;
+ }
+
+ /* mbedtls_ssl_conf_ciphersuites(): The ciphersuites array is not copied.
+ It must remain valid for the lifetime of the SSL configuration */
+ backend->ciphersuites = selected;
+ mbedtls_ssl_conf_ciphersuites(&backend->config, backend->ciphersuites);
+ return CURLE_OK;
+}
+
static CURLcode
mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
{
@@ -384,6 +511,16 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
return CURLE_NOT_BUILT_IN;
}
+#ifdef TLS13_SUPPORT
+ ret = psa_crypto_init();
+ if(ret != PSA_SUCCESS) {
+ mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
+ failf(data, "mbedTLS psa_crypto_init returned (-0x%04X) %s",
+ -ret, errorbuf);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+#endif /* TLS13_SUPPORT */
+
#ifdef THREADING_SUPPORT
mbedtls_ctr_drbg_init(&backend->ctr_drbg);
@@ -589,7 +726,7 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
}
#endif
- infof(data, "mbedTLS: Connecting to %s:%d", hostname, connssl->port);
+ infof(data, "mbedTLS: Connecting to %s:%d", hostname, connssl->peer.port);
mbedtls_ssl_config_init(&backend->config);
ret = mbedtls_ssl_config_defaults(&backend->config,
@@ -602,10 +739,6 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
}
mbedtls_ssl_init(&backend->ssl);
- if(mbedtls_ssl_setup(&backend->ssl, &backend->config)) {
- failf(data, "mbedTLS: ssl_init failed");
- return CURLE_SSL_CONNECT_ERROR;
- }
/* new profile with RSA min key len = 1024 ... */
mbedtls_ssl_conf_cert_profile(&backend->config,
@@ -635,17 +768,34 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
return CURLE_SSL_CONNECT_ERROR;
}
- mbedtls_ssl_conf_authmode(&backend->config, MBEDTLS_SSL_VERIFY_OPTIONAL);
-
mbedtls_ssl_conf_rng(&backend->config, mbedtls_ctr_drbg_random,
&backend->ctr_drbg);
+
+ ret = mbedtls_ssl_setup(&backend->ssl, &backend->config);
+ if(ret) {
+ mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
+ failf(data, "ssl_setup failed - mbedTLS: (-0x%04X) %s",
+ -ret, errorbuf);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
mbedtls_ssl_set_bio(&backend->ssl, cf,
mbedtls_bio_cf_write,
mbedtls_bio_cf_read,
NULL /* rev_timeout() */);
- mbedtls_ssl_conf_ciphersuites(&backend->config,
- mbedtls_ssl_list_ciphersuites());
+ if(conn_config->cipher_list) {
+ ret = mbed_set_selected_ciphers(data, backend, conn_config->cipher_list);
+ if(ret) {
+ failf(data, "mbedTLS: failed to set cipher suites");
+ return ret;
+ }
+ }
+ else {
+ mbedtls_ssl_conf_ciphersuites(&backend->config,
+ mbedtls_ssl_list_ciphersuites());
+ }
+
#if defined(MBEDTLS_SSL_RENEGOTIATION)
mbedtls_ssl_conf_renegotiation(&backend->config,
@@ -662,7 +812,7 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
void *old_session = NULL;
Curl_ssl_sessionid_lock(data);
- if(!Curl_ssl_getsessionid(cf, data, &old_session, NULL)) {
+ if(!Curl_ssl_getsessionid(cf, data, &connssl->peer, &old_session, NULL)) {
ret = mbedtls_ssl_set_session(&backend->ssl, old_session);
if(ret) {
Curl_ssl_sessionid_unlock(data);
@@ -752,9 +902,15 @@ mbed_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
(struct mbed_ssl_backend_data *)connssl->backend;
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
const mbedtls_x509_crt *peercert;
+ char cipher_str[64];
+ uint16_t cipher_id;
+#ifndef CURL_DISABLE_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];
+#endif
DEBUGASSERT(backend);
@@ -776,8 +932,10 @@ mbed_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
return CURLE_SSL_CONNECT_ERROR;
}
- infof(data, "mbedTLS: Handshake complete, cipher is %s",
- mbedtls_ssl_get_ciphersuite(&backend->ssl));
+ 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);
+ infof(data, "mbedTLS: Handshake complete, cipher is %s", cipher_str);
ret = mbedtls_ssl_get_verify_result(&backend->ssl);
@@ -911,6 +1069,13 @@ pinnedpubkey_error:
return CURLE_OK;
}
+static void mbedtls_session_free(void *sessionid, size_t idsize)
+{
+ (void)idsize;
+ mbedtls_ssl_session_free(sessionid);
+ free(sessionid);
+}
+
static CURLcode
mbed_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
{
@@ -927,7 +1092,6 @@ mbed_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
int ret;
mbedtls_ssl_session *our_ssl_sessionid;
void *old_ssl_sessionid = NULL;
- bool added = FALSE;
our_ssl_sessionid = malloc(sizeof(mbedtls_ssl_session));
if(!our_ssl_sessionid)
@@ -946,20 +1110,16 @@ mbed_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
/* If there's already a matching session in the cache, delete it */
Curl_ssl_sessionid_lock(data);
- if(!Curl_ssl_getsessionid(cf, data, &old_ssl_sessionid, NULL))
+ if(!Curl_ssl_getsessionid(cf, data, &connssl->peer,
+ &old_ssl_sessionid, NULL))
Curl_ssl_delsessionid(data, old_ssl_sessionid);
- retcode = Curl_ssl_addsessionid(cf, data, our_ssl_sessionid,
- 0, &added);
+ retcode = Curl_ssl_addsessionid(cf, data, &connssl->peer,
+ our_ssl_sessionid, 0,
+ mbedtls_session_free);
Curl_ssl_sessionid_unlock(data);
- if(!added) {
- mbedtls_ssl_session_free(our_ssl_sessionid);
- free(our_ssl_sessionid);
- }
- if(retcode) {
- failf(data, "failed to store ssl session");
+ if(retcode)
return retcode;
- }
}
connssl->connecting_state = ssl_connect_done;
@@ -1014,6 +1174,7 @@ static void mbedtls_close(struct Curl_cfilter *cf, struct Curl_easy *data)
#ifdef MBEDTLS_X509_CRL_PARSE_C
mbedtls_x509_crl_free(&backend->crl);
#endif
+ Curl_safefree(backend->ciphersuites);
mbedtls_ssl_config_free(&backend->config);
mbedtls_ssl_free(&backend->ssl);
mbedtls_ctr_drbg_free(&backend->ctr_drbg);
@@ -1042,8 +1203,11 @@ static ssize_t mbed_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
if(ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY)
return 0;
- *curlcode = (ret == MBEDTLS_ERR_SSL_WANT_READ) ?
- CURLE_AGAIN : CURLE_RECV_ERROR;
+ *curlcode = ((ret == MBEDTLS_ERR_SSL_WANT_READ)
+#ifdef TLS13_SUPPORT
+ || (ret == MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET)
+#endif
+ ) ? CURLE_AGAIN : CURLE_RECV_ERROR;
return -1;
}
@@ -1052,12 +1216,6 @@ static ssize_t mbed_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
return len;
}
-static void mbedtls_session_free(void *ptr)
-{
- mbedtls_ssl_session_free(ptr);
- free(ptr);
-}
-
static size_t mbedtls_version(char *buffer, size_t size)
{
#ifdef MBEDTLS_VERSION_C
@@ -1336,7 +1494,6 @@ const struct Curl_ssl Curl_ssl_mbedtls = {
mbedtls_get_internals, /* get_internals */
mbedtls_close, /* close_one */
mbedtls_close_all, /* close_all */
- mbedtls_session_free, /* session_free */
Curl_none_set_engine, /* set_engine */
Curl_none_set_engine_default, /* set_engine_default */
Curl_none_engines_list, /* engines_list */
diff --git a/libs/libcurl/src/vtls/openssl.c b/libs/libcurl/src/vtls/openssl.c
index b22ec269ac..f53cb69471 100644
--- a/libs/libcurl/src/vtls/openssl.c
+++ b/libs/libcurl/src/vtls/openssl.c
@@ -82,6 +82,17 @@
#include <openssl/tls1.h>
#include <openssl/evp.h>
+#ifdef USE_ECH
+# ifndef OPENSSL_IS_BORINGSSL
+# include <openssl/ech.h>
+# endif
+# include "curl_base64.h"
+# define ECH_ENABLED(__data__) \
+ (__data__->set.tls_ech && \
+ !(__data__->set.tls_ech & CURLECH_DISABLE)\
+ )
+#endif /* USE_ECH */
+
#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_OCSP)
#include <openssl/ocsp.h>
#endif
@@ -193,12 +204,10 @@
* Whether SSL_CTX_set_keylog_callback is available.
* OpenSSL: supported since 1.1.1 https://github.com/openssl/openssl/pull/2287
* BoringSSL: supported since d28f59c27bac (committed 2015-11-19)
- * LibreSSL: supported since 3.5.0 (released 2022-02-24)
+ * LibreSSL: not supported. 3.5.0+ has a stub function that does nothing.
*/
#if (OPENSSL_VERSION_NUMBER >= 0x10101000L && \
!defined(LIBRESSL_VERSION_NUMBER)) || \
- (defined(LIBRESSL_VERSION_NUMBER) && \
- LIBRESSL_VERSION_NUMBER >= 0x3050000fL) || \
defined(OPENSSL_IS_BORINGSSL)
#define HAVE_KEYLOG_CALLBACK
#endif
@@ -298,20 +307,6 @@ typedef unsigned long sslerr_t;
#define USE_PRE_1_1_API (OPENSSL_VERSION_NUMBER < 0x10100000L)
#endif /* !LIBRESSL_VERSION_NUMBER */
-struct ossl_ssl_backend_data {
- /* these ones requires specific SSL-types */
- SSL_CTX* ctx;
- SSL* handle;
- X509* server_cert;
- BIO_METHOD *bio_method;
- CURLcode io_result; /* result of last BIO cfilter operation */
-#ifndef HAVE_KEYLOG_CALLBACK
- /* Set to true once a valid keylog entry has been created to avoid dupes. */
- bool keylog_done;
-#endif
- bool x509_store_setup; /* x509 store has been set up */
-};
-
#if defined(HAVE_SSL_X509_STORE_SHARE)
struct multi_ssl_backend_data {
char *CAfile; /* CAfile path used to generate X509 store */
@@ -726,8 +721,7 @@ static int ossl_bio_cf_out_write(BIO *bio, const char *buf, int blen)
{
struct Curl_cfilter *cf = BIO_get_data(bio);
struct ssl_connect_data *connssl = cf->ctx;
- struct ossl_ssl_backend_data *backend =
- (struct ossl_ssl_backend_data *)connssl->backend;
+ struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
struct Curl_easy *data = CF_DATA_CURRENT(cf);
ssize_t nwritten;
CURLcode result = CURLE_SEND_ERROR;
@@ -737,7 +731,7 @@ static int ossl_bio_cf_out_write(BIO *bio, const char *buf, int blen)
CURL_TRC_CF(data, cf, "ossl_bio_cf_out_write(len=%d) -> %d, err=%d",
blen, (int)nwritten, result);
BIO_clear_retry_flags(bio);
- backend->io_result = result;
+ octx->io_result = result;
if(nwritten < 0) {
if(CURLE_AGAIN == result)
BIO_set_retry_write(bio);
@@ -749,8 +743,7 @@ static int ossl_bio_cf_in_read(BIO *bio, char *buf, int blen)
{
struct Curl_cfilter *cf = BIO_get_data(bio);
struct ssl_connect_data *connssl = cf->ctx;
- struct ossl_ssl_backend_data *backend =
- (struct ossl_ssl_backend_data *)connssl->backend;
+ struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
struct Curl_easy *data = CF_DATA_CURRENT(cf);
ssize_t nread;
CURLcode result = CURLE_RECV_ERROR;
@@ -764,7 +757,7 @@ static int ossl_bio_cf_in_read(BIO *bio, char *buf, int blen)
CURL_TRC_CF(data, cf, "ossl_bio_cf_in_read(len=%d) -> %d, err=%d",
blen, (int)nread, result);
BIO_clear_retry_flags(bio);
- backend->io_result = result;
+ octx->io_result = result;
if(nread < 0) {
if(CURLE_AGAIN == result)
BIO_set_retry_read(bio);
@@ -775,13 +768,13 @@ static int ossl_bio_cf_in_read(BIO *bio, char *buf, int blen)
/* Before returning server replies to the SSL instance, we need
* to have setup the x509 store or verification will fail. */
- if(!backend->x509_store_setup) {
- result = Curl_ssl_setup_x509_store(cf, data, backend->ctx);
+ if(!octx->x509_store_setup) {
+ result = Curl_ssl_setup_x509_store(cf, data, octx->ssl_ctx);
if(result) {
- backend->io_result = result;
+ octx->io_result = result;
return -1;
}
- backend->x509_store_setup = TRUE;
+ octx->x509_store_setup = TRUE;
}
return (int)nread;
@@ -1883,13 +1876,12 @@ static struct curl_slist *ossl_engines_list(struct Curl_easy *data)
static void ossl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
struct ssl_connect_data *connssl = cf->ctx;
- struct ossl_ssl_backend_data *backend =
- (struct ossl_ssl_backend_data *)connssl->backend;
+ struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
(void)data;
- DEBUGASSERT(backend);
+ DEBUGASSERT(octx);
- if(backend->handle) {
+ if(octx->ssl) {
/* Send the TLS shutdown if we are still connected *and* if
* the peer did not already close the connection. */
if(cf->next && cf->next->connected && !connssl->peer_closed) {
@@ -1900,8 +1892,8 @@ static void ossl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
/* Maybe the server has already sent a close notify alert.
Read it to avoid an RST on the TCP connection. */
ERR_clear_error();
- nread = SSL_read(backend->handle, buf, (int)sizeof(buf));
- err = SSL_get_error(backend->handle, nread);
+ nread = SSL_read(octx->ssl, buf, (int)sizeof(buf));
+ err = SSL_get_error(octx->ssl, nread);
if(!nread && err == SSL_ERROR_ZERO_RETURN) {
CURLcode result;
ssize_t n;
@@ -1924,12 +1916,12 @@ static void ossl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
CURL_TRC_CF(data, cf, "not from sending TLS shutdown on "
"connection closed by peer");
}
- else if(SSL_shutdown(backend->handle) == 1) {
+ else if(SSL_shutdown(octx->ssl) == 1) {
CURL_TRC_CF(data, cf, "SSL shutdown finished");
}
else {
- nread = SSL_read(backend->handle, buf, (int)sizeof(buf));
- err = SSL_get_error(backend->handle, nread);
+ nread = SSL_read(octx->ssl, buf, (int)sizeof(buf));
+ err = SSL_get_error(octx->ssl, nread);
switch(err) {
case SSL_ERROR_NONE: /* this is not an error */
case SSL_ERROR_ZERO_RETURN: /* no more data */
@@ -1955,20 +1947,20 @@ static void ossl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
}
ERR_clear_error();
- SSL_set_connect_state(backend->handle);
+ SSL_set_connect_state(octx->ssl);
}
- SSL_free(backend->handle);
- backend->handle = NULL;
+ SSL_free(octx->ssl);
+ octx->ssl = NULL;
}
- if(backend->ctx) {
- SSL_CTX_free(backend->ctx);
- backend->ctx = NULL;
- backend->x509_store_setup = FALSE;
+ if(octx->ssl_ctx) {
+ SSL_CTX_free(octx->ssl_ctx);
+ octx->ssl_ctx = NULL;
+ octx->x509_store_setup = FALSE;
}
- if(backend->bio_method) {
- ossl_bio_cf_method_free(backend->bio_method);
- backend->bio_method = NULL;
+ if(octx->bio_method) {
+ ossl_bio_cf_method_free(octx->bio_method);
+ octx->bio_method = NULL;
}
}
@@ -1988,11 +1980,10 @@ static int ossl_shutdown(struct Curl_cfilter *cf,
int buffsize;
int err;
bool done = FALSE;
- struct ossl_ssl_backend_data *backend =
- (struct ossl_ssl_backend_data *)connssl->backend;
+ struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
int loop = 10;
- DEBUGASSERT(backend);
+ DEBUGASSERT(octx);
#ifndef CURL_DISABLE_FTP
/* This has only been tested on the proftpd server, and the mod_tls code
@@ -2001,10 +1992,10 @@ static int ossl_shutdown(struct Curl_cfilter *cf,
we do not send one. Let's hope other servers do the same... */
if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE)
- (void)SSL_shutdown(backend->handle);
+ (void)SSL_shutdown(octx->ssl);
#endif
- if(backend->handle) {
+ if(octx->ssl) {
buffsize = (int)sizeof(buf);
while(!done && loop--) {
int what = SOCKET_READABLE(Curl_conn_cf_get_socket(cf, data),
@@ -2014,8 +2005,8 @@ static int ossl_shutdown(struct Curl_cfilter *cf,
/* Something to read, let's do it and hope that it is the close
notify alert from the server */
- nread = SSL_read(backend->handle, buf, buffsize);
- err = SSL_get_error(backend->handle, nread);
+ nread = SSL_read(octx->ssl, buf, buffsize);
+ err = SSL_get_error(octx->ssl, nread);
switch(err) {
case SSL_ERROR_NONE: /* this is not an error */
@@ -2060,7 +2051,7 @@ static int ossl_shutdown(struct Curl_cfilter *cf,
if(data->set.verbose) {
#ifdef HAVE_SSL_GET_SHUTDOWN
- switch(SSL_get_shutdown(backend->handle)) {
+ switch(SSL_get_shutdown(octx->ssl)) {
case SSL_SENT_SHUTDOWN:
infof(data, "SSL_get_shutdown() returned SSL_SENT_SHUTDOWN");
break;
@@ -2075,16 +2066,17 @@ static int ossl_shutdown(struct Curl_cfilter *cf,
#endif
}
- SSL_free(backend->handle);
- backend->handle = NULL;
+ SSL_free(octx->ssl);
+ octx->ssl = NULL;
}
return retval;
}
-static void ossl_session_free(void *ptr)
+static void ossl_session_free(void *sessionid, size_t idsize)
{
/* free the ID */
- SSL_SESSION_free(ptr);
+ (void)idsize;
+ SSL_SESSION_free(sessionid);
}
/*
@@ -2165,14 +2157,14 @@ CURLcode Curl_ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
int target; /* target type, GEN_DNS or GEN_IPADD */
size_t addrlen = 0;
STACK_OF(GENERAL_NAME) *altnames;
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
struct in6_addr addr;
#else
struct in_addr addr;
#endif
CURLcode result = CURLE_OK;
bool dNSName = FALSE; /* if a dNSName field exists in the cert */
- bool iPAddress = FALSE; /* if a iPAddress field exists in the cert */
+ bool iPAddress = FALSE; /* if an iPAddress field exists in the cert */
size_t hostlen;
(void)conn;
@@ -2184,7 +2176,7 @@ CURLcode Curl_ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
target = GEN_IPADD;
addrlen = sizeof(struct in_addr);
break;
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
case CURL_SSL_PEER_IPV6:
if(!Curl_inet_pton(AF_INET6, peer->hostname, &addr))
return CURLE_PEER_FAILED_VERIFICATION;
@@ -2381,8 +2373,7 @@ static CURLcode verifystatus(struct Curl_cfilter *cf,
OCSP_BASICRESP *br = NULL;
X509_STORE *st = NULL;
STACK_OF(X509) *ch = NULL;
- struct ossl_ssl_backend_data *backend =
- (struct ossl_ssl_backend_data *)connssl->backend;
+ struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
X509 *cert;
OCSP_CERTID *id = NULL;
int cert_status, crl_reason;
@@ -2390,9 +2381,9 @@ static CURLcode verifystatus(struct Curl_cfilter *cf,
int ret;
long len;
- DEBUGASSERT(backend);
+ DEBUGASSERT(octx);
- len = SSL_get_tlsext_status_ocsp_resp(backend->handle, &status);
+ len = SSL_get_tlsext_status_ocsp_resp(octx->ssl, &status);
if(!status) {
failf(data, "No OCSP response received");
@@ -2422,13 +2413,13 @@ static CURLcode verifystatus(struct Curl_cfilter *cf,
goto end;
}
- ch = SSL_get_peer_cert_chain(backend->handle);
+ ch = SSL_get_peer_cert_chain(octx->ssl);
if(!ch) {
failf(data, "Could not get peer certificate chain");
result = CURLE_SSL_INVALIDCERTSTATUS;
goto end;
}
- st = SSL_CTX_get_cert_store(backend->ctx);
+ st = SSL_CTX_get_cert_store(octx->ssl_ctx);
#if ((OPENSSL_VERSION_NUMBER <= 0x1000201fL) /* Fixed after 1.0.2a */ || \
(defined(LIBRESSL_VERSION_NUMBER) && \
@@ -2465,7 +2456,7 @@ static CURLcode verifystatus(struct Curl_cfilter *cf,
}
/* Compute the certificate's ID */
- cert = SSL_get1_peer_certificate(backend->handle);
+ cert = SSL_get1_peer_certificate(octx->ssl);
if(!cert) {
failf(data, "Error getting peer certificate");
result = CURLE_SSL_INVALIDCERTSTATUS;
@@ -2880,10 +2871,9 @@ ossl_set_ssl_version_min_max_legacy(ctx_option_t *ctx_options,
#ifdef TLS1_3_VERSION
{
struct ssl_connect_data *connssl = cf->ctx;
- struct ossl_ssl_backend_data *backend =
- (struct ossl_ssl_backend_data *)connssl->backend;
- DEBUGASSERT(backend);
- SSL_CTX_set_max_proto_version(backend->ctx, TLS1_3_VERSION);
+ struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
+ DEBUGASSERT(octx);
+ SSL_CTX_set_max_proto_version(octx->ssl_ctx, TLS1_3_VERSION);
*ctx_options |= SSL_OP_NO_TLSv1_2;
}
#else
@@ -2941,61 +2931,64 @@ ossl_set_ssl_version_min_max_legacy(ctx_option_t *ctx_options,
}
#endif
-/* The "new session" callback must return zero if the session can be removed
- * or non-zero if the session has been put into the session cache.
- */
-static int ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid)
+CURLcode Curl_ossl_add_session(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ const struct ssl_peer *peer,
+ SSL_SESSION *session)
{
- int res = 0;
- struct Curl_easy *data;
- struct Curl_cfilter *cf;
const struct ssl_config_data *config;
- struct ssl_connect_data *connssl;
bool isproxy;
+ bool added = FALSE;
- cf = (struct Curl_cfilter*) SSL_get_app_data(ssl);
- connssl = cf? cf->ctx : NULL;
- data = connssl? CF_DATA_CURRENT(cf) : NULL;
- /* The sockindex has been stored as a pointer to an array element */
if(!cf || !data)
- return 0;
+ goto out;
isproxy = Curl_ssl_cf_is_proxy(cf);
config = Curl_ssl_cf_get_config(cf, data);
if(config->primary.sessionid) {
bool incache;
- bool added = FALSE;
- void *old_ssl_sessionid = NULL;
+ void *old_session = NULL;
Curl_ssl_sessionid_lock(data);
if(isproxy)
incache = FALSE;
else
- incache = !(Curl_ssl_getsessionid(cf, data, &old_ssl_sessionid, NULL));
- if(incache) {
- if(old_ssl_sessionid != ssl_sessionid) {
- infof(data, "old SSL session ID is stale, removing");
- Curl_ssl_delsessionid(data, old_ssl_sessionid);
- incache = FALSE;
- }
+ incache = !(Curl_ssl_getsessionid(cf, data, peer,
+ &old_session, NULL));
+ if(incache && (old_session != session)) {
+ infof(data, "old SSL session ID is stale, removing");
+ Curl_ssl_delsessionid(data, old_session);
+ incache = FALSE;
}
if(!incache) {
- if(!Curl_ssl_addsessionid(cf, data, ssl_sessionid,
- 0 /* unknown size */, &added)) {
- if(added) {
- /* the session has been put into the session cache */
- res = 1;
- }
- }
- else
- failf(data, "failed to store ssl session");
+ added = TRUE;
+ Curl_ssl_addsessionid(cf, data, peer, session, 0, ossl_session_free);
}
Curl_ssl_sessionid_unlock(data);
}
- return res;
+out:
+ if(!added)
+ ossl_session_free(session, 0);
+ return CURLE_OK;
+}
+
+/* The "new session" callback must return zero if the session can be removed
+ * or non-zero if the session has been put into the session cache.
+ */
+static int ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid)
+{
+ struct Curl_cfilter *cf;
+ struct Curl_easy *data;
+ 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;
+ Curl_ossl_add_session(cf, data, &connssl->peer, ssl_sessionid);
+ return 1;
}
static CURLcode load_cacert_from_memory(X509_STORE *store,
@@ -3390,7 +3383,7 @@ static bool cached_x509_store_different(
static X509_STORE *get_cached_x509_store(struct Curl_cfilter *cf,
const struct Curl_easy *data)
{
- struct Curl_multi *multi = data->multi_easy ? data->multi_easy : data->multi;
+ struct Curl_multi *multi = data->multi;
X509_STORE *store = NULL;
DEBUGASSERT(multi);
@@ -3410,7 +3403,7 @@ static void set_cached_x509_store(struct Curl_cfilter *cf,
X509_STORE *store)
{
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
- struct Curl_multi *multi = data->multi_easy ? data->multi_easy : data->multi;
+ struct Curl_multi *multi = data->multi;
struct multi_ssl_backend_data *mbackend;
DEBUGASSERT(multi);
@@ -3493,29 +3486,33 @@ CURLcode Curl_ssl_setup_x509_store(struct Curl_cfilter *cf,
}
#endif /* HAVE_SSL_X509_STORE_SHARE */
-static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,
- struct Curl_easy *data)
+CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx,
+ struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct ssl_peer *peer,
+ int transport, /* TCP or QUIC */
+ const unsigned char *alpn, size_t alpn_len,
+ Curl_ossl_ctx_setup_cb *cb_setup,
+ void *cb_user_data,
+ Curl_ossl_new_session_cb *cb_new_session,
+ void *ssl_user_data)
{
CURLcode result = CURLE_OK;
- char *ciphers;
+ const char *ciphers;
SSL_METHOD_QUAL SSL_METHOD *req_method = NULL;
- struct ssl_connect_data *connssl = cf->ctx;
ctx_option_t ctx_options = 0;
void *ssl_sessionid = NULL;
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);
- BIO *bio;
const long int ssl_version = conn_config->version;
char * const ssl_cert = ssl_config->primary.clientcert;
const struct curl_blob *ssl_cert_blob = ssl_config->primary.cert_blob;
const char * const ssl_cert_type = ssl_config->cert_type;
const bool verifypeer = conn_config->verifypeer;
char error_buffer[256];
- struct ossl_ssl_backend_data *backend =
- (struct ossl_ssl_backend_data *)connssl->backend;
-
- DEBUGASSERT(ssl_connect_1 == connssl->connecting_state);
- DEBUGASSERT(backend);
+#ifdef USE_ECH
+ struct ssl_connect_data *connssl = cf->ctx;
+#endif
/* Make funny stuff to get random input */
result = ossl_seed(data);
@@ -3524,56 +3521,74 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,
ssl_config->certverifyresult = !X509_V_OK;
- /* check to see if we've been told to use an explicit SSL/TLS version */
-
- switch(ssl_version) {
- case CURL_SSLVERSION_DEFAULT:
- case CURL_SSLVERSION_TLSv1:
- case CURL_SSLVERSION_TLSv1_0:
- case CURL_SSLVERSION_TLSv1_1:
- case CURL_SSLVERSION_TLSv1_2:
- case CURL_SSLVERSION_TLSv1_3:
- /* it will be handled later with the context options */
-#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
- req_method = TLS_client_method();
+ switch(transport) {
+ case TRNSPRT_TCP:
+ /* check to see if we've been told to use an explicit SSL/TLS version */
+ switch(ssl_version) {
+ case CURL_SSLVERSION_DEFAULT:
+ case CURL_SSLVERSION_TLSv1:
+ case CURL_SSLVERSION_TLSv1_0:
+ case CURL_SSLVERSION_TLSv1_1:
+ case CURL_SSLVERSION_TLSv1_2:
+ case CURL_SSLVERSION_TLSv1_3:
+ /* it will be handled later with the context options */
+ #if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
+ req_method = TLS_client_method();
+ #else
+ req_method = SSLv23_client_method();
+ #endif
+ break;
+ case CURL_SSLVERSION_SSLv2:
+ failf(data, "No SSLv2 support");
+ return CURLE_NOT_BUILT_IN;
+ case CURL_SSLVERSION_SSLv3:
+ failf(data, "No SSLv3 support");
+ return CURLE_NOT_BUILT_IN;
+ default:
+ failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ break;
+ case TRNSPRT_QUIC:
+ if((ssl_version != CURL_SSLVERSION_DEFAULT) &&
+ (ssl_version < CURL_SSLVERSION_TLSv1_3)) {
+ failf(data, "QUIC needs at least TLS version 1.3");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+#ifdef USE_OPENSSL_QUIC
+ req_method = OSSL_QUIC_client_method();
+#elif (OPENSSL_VERSION_NUMBER >= 0x10100000L)
+ req_method = TLS_method();
#else
req_method = SSLv23_client_method();
#endif
break;
- case CURL_SSLVERSION_SSLv2:
- failf(data, "No SSLv2 support");
- return CURLE_NOT_BUILT_IN;
- case CURL_SSLVERSION_SSLv3:
- failf(data, "No SSLv3 support");
- return CURLE_NOT_BUILT_IN;
default:
- failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
+ failf(data, "unsupported transport %d in SSL init", transport);
return CURLE_SSL_CONNECT_ERROR;
}
- if(backend->ctx) {
- /* This happens when an error was encountered before in this
- * step and we are called to do it again. Get rid of any leftover
- * from the previous call. */
- ossl_close(cf, data);
- }
- backend->ctx = SSL_CTX_new(req_method);
- if(!backend->ctx) {
+ DEBUGASSERT(!octx->ssl_ctx);
+ octx->ssl_ctx = SSL_CTX_new(req_method);
+
+ if(!octx->ssl_ctx) {
failf(data, "SSL: couldn't create a context: %s",
ossl_strerror(ERR_peek_error(), error_buffer, sizeof(error_buffer)));
return CURLE_OUT_OF_MEMORY;
}
-#ifdef SSL_MODE_RELEASE_BUFFERS
- SSL_CTX_set_mode(backend->ctx, SSL_MODE_RELEASE_BUFFERS);
-#endif
+ if(cb_setup) {
+ result = cb_setup(cf, data, cb_user_data);
+ if(result)
+ return result;
+ }
#ifdef SSL_CTRL_SET_MSG_CALLBACK
if(data->set.fdebug && data->set.verbose) {
/* the SSL trace callback is only used for verbose logging */
- SSL_CTX_set_msg_callback(backend->ctx, ossl_trace);
- SSL_CTX_set_msg_callback_arg(backend->ctx, cf);
+ SSL_CTX_set_msg_callback(octx->ssl_ctx, ossl_trace);
+ SSL_CTX_set_msg_callback_arg(octx->ssl_ctx, cf);
}
#endif
@@ -3653,7 +3668,7 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,
ctx_options |= SSL_OP_NO_SSLv3;
#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) /* 1.1.0 */
- result = ossl_set_ssl_version_min_max(cf, backend->ctx);
+ result = ossl_set_ssl_version_min_max(cf, octx->ssl_ctx);
#else
result = ossl_set_ssl_version_min_max_legacy(&ctx_options, cf, data);
#endif
@@ -3666,26 +3681,20 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,
return CURLE_SSL_CONNECT_ERROR;
}
- SSL_CTX_set_options(backend->ctx, ctx_options);
+ SSL_CTX_set_options(octx->ssl_ctx, ctx_options);
#ifdef HAS_ALPN
- if(connssl->alpn) {
- struct alpn_proto_buf proto;
-
- result = Curl_alpn_to_proto_buf(&proto, connssl->alpn);
- if(result ||
- SSL_CTX_set_alpn_protos(backend->ctx, proto.data, proto.len)) {
+ if(alpn && alpn_len) {
+ if(SSL_CTX_set_alpn_protos(octx->ssl_ctx, alpn, (int)alpn_len)) {
failf(data, "Error setting ALPN");
return CURLE_SSL_CONNECT_ERROR;
}
- Curl_alpn_to_proto_str(&proto, connssl->alpn);
- infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data);
}
#endif
if(ssl_cert || ssl_cert_blob || ssl_cert_type) {
if(!result &&
- !cert_stuff(data, backend->ctx,
+ !cert_stuff(data, octx->ssl_ctx,
ssl_cert, ssl_cert_blob, ssl_cert_type,
ssl_config->key, ssl_config->key_blob,
ssl_config->key_type, ssl_config->key_passwd))
@@ -3696,10 +3705,10 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,
}
ciphers = conn_config->cipher_list;
- if(!ciphers)
- ciphers = (char *)DEFAULT_CIPHER_SELECTION;
+ if(!ciphers && (peer->transport != TRNSPRT_QUIC))
+ ciphers = DEFAULT_CIPHER_SELECTION;
if(ciphers) {
- if(!SSL_CTX_set_cipher_list(backend->ctx, ciphers)) {
+ if(!SSL_CTX_set_cipher_list(octx->ssl_ctx, ciphers)) {
failf(data, "failed setting cipher list: %s", ciphers);
return CURLE_SSL_CIPHER;
}
@@ -3708,9 +3717,9 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,
#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES
{
- char *ciphers13 = conn_config->cipher_list13;
+ const char *ciphers13 = conn_config->cipher_list13;
if(ciphers13) {
- if(!SSL_CTX_set_ciphersuites(backend->ctx, ciphers13)) {
+ if(!SSL_CTX_set_ciphersuites(octx->ssl_ctx, ciphers13)) {
failf(data, "failed setting TLS 1.3 cipher suite: %s", ciphers13);
return CURLE_SSL_CIPHER;
}
@@ -3721,14 +3730,14 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,
#ifdef HAVE_SSL_CTX_SET_POST_HANDSHAKE_AUTH
/* OpenSSL 1.1.1 requires clients to opt-in for PHA */
- SSL_CTX_set_post_handshake_auth(backend->ctx, 1);
+ SSL_CTX_set_post_handshake_auth(octx->ssl_ctx, 1);
#endif
#ifdef HAVE_SSL_CTX_SET_EC_CURVES
{
- char *curves = conn_config->curves;
+ const char *curves = conn_config->curves;
if(curves) {
- if(!SSL_CTX_set1_curves_list(backend->ctx, curves)) {
+ if(!SSL_CTX_set1_curves_list(octx->ssl_ctx, curves)) {
failf(data, "failed setting curves list: '%s'", curves);
return CURLE_SSL_CIPHER;
}
@@ -3742,18 +3751,18 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,
char * const ssl_password = ssl_config->primary.password;
infof(data, "Using TLS-SRP username: %s", ssl_username);
- if(!SSL_CTX_set_srp_username(backend->ctx, ssl_username)) {
+ if(!SSL_CTX_set_srp_username(octx->ssl_ctx, ssl_username)) {
failf(data, "Unable to set SRP user name");
return CURLE_BAD_FUNCTION_ARGUMENT;
}
- if(!SSL_CTX_set_srp_password(backend->ctx, ssl_password)) {
+ if(!SSL_CTX_set_srp_password(octx->ssl_ctx, ssl_password)) {
failf(data, "failed setting SRP password");
return CURLE_BAD_FUNCTION_ARGUMENT;
}
if(!conn_config->cipher_list) {
infof(data, "Setting cipher list SRP");
- if(!SSL_CTX_set_cipher_list(backend->ctx, "SRP")) {
+ if(!SSL_CTX_set_cipher_list(octx->ssl_ctx, "SRP")) {
failf(data, "failed setting SRP cipher list");
return CURLE_SSL_CIPHER;
}
@@ -3765,38 +3774,40 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,
* fail to connect if the verification fails, or if it should continue
* anyway. In the latter case the result of the verification is checked with
* SSL_get_verify_result() below. */
- SSL_CTX_set_verify(backend->ctx,
+ SSL_CTX_set_verify(octx->ssl_ctx,
verifypeer ? SSL_VERIFY_PEER : SSL_VERIFY_NONE, NULL);
/* Enable logging of secrets to the file specified in env SSLKEYLOGFILE. */
#ifdef HAVE_KEYLOG_CALLBACK
if(Curl_tls_keylog_enabled()) {
- SSL_CTX_set_keylog_callback(backend->ctx, ossl_keylog_callback);
+ SSL_CTX_set_keylog_callback(octx->ssl_ctx, ossl_keylog_callback);
}
#endif
- /* Enable the session cache because it's a prerequisite for the "new session"
- * callback. Use the "external storage" mode to prevent OpenSSL from creating
- * an internal session cache.
- */
- SSL_CTX_set_session_cache_mode(backend->ctx,
- SSL_SESS_CACHE_CLIENT |
- SSL_SESS_CACHE_NO_INTERNAL);
- SSL_CTX_sess_set_new_cb(backend->ctx, ossl_new_session_cb);
+ if(cb_new_session) {
+ /* Enable the session cache because it's a prerequisite for the
+ * "new session" callback. Use the "external storage" mode to prevent
+ * OpenSSL from creating an internal session cache.
+ */
+ SSL_CTX_set_session_cache_mode(octx->ssl_ctx,
+ SSL_SESS_CACHE_CLIENT |
+ SSL_SESS_CACHE_NO_INTERNAL);
+ SSL_CTX_sess_set_new_cb(octx->ssl_ctx, cb_new_session);
+ }
/* give application a chance to interfere with SSL set up. */
if(data->set.ssl.fsslctx) {
/* When a user callback is installed to modify the SSL_CTX,
* we need to do the full initialization before calling it.
* See: #11800 */
- if(!backend->x509_store_setup) {
- result = Curl_ssl_setup_x509_store(cf, data, backend->ctx);
+ if(!octx->x509_store_setup) {
+ result = Curl_ssl_setup_x509_store(cf, data, octx->ssl_ctx);
if(result)
return result;
- backend->x509_store_setup = TRUE;
+ octx->x509_store_setup = TRUE;
}
Curl_set_in_callback(data, true);
- result = (*data->set.ssl.fsslctx)(data, backend->ctx,
+ result = (*data->set.ssl.fsslctx)(data, octx->ssl_ctx,
data->set.ssl.fsslctxp);
Curl_set_in_callback(data, false);
if(result) {
@@ -3806,47 +3817,174 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,
}
/* Let's make an SSL structure */
- if(backend->handle)
- SSL_free(backend->handle);
- backend->handle = SSL_new(backend->ctx);
- if(!backend->handle) {
+ if(octx->ssl)
+ SSL_free(octx->ssl);
+ octx->ssl = SSL_new(octx->ssl_ctx);
+ if(!octx->ssl) {
failf(data, "SSL: couldn't create a context (handle)");
return CURLE_OUT_OF_MEMORY;
}
- SSL_set_app_data(backend->handle, cf);
+ SSL_set_app_data(octx->ssl, ssl_user_data);
#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
!defined(OPENSSL_NO_OCSP)
if(conn_config->verifystatus)
- SSL_set_tlsext_status_type(backend->handle, TLSEXT_STATUSTYPE_ocsp);
+ SSL_set_tlsext_status_type(octx->ssl, TLSEXT_STATUSTYPE_ocsp);
#endif
#if (defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)) && \
defined(ALLOW_RENEG)
- SSL_set_renegotiate_mode(backend->handle, ssl_renegotiate_freely);
+ SSL_set_renegotiate_mode(octx->ssl, ssl_renegotiate_freely);
#endif
- SSL_set_connect_state(backend->handle);
+ SSL_set_connect_state(octx->ssl);
- backend->server_cert = 0x0;
+ octx->server_cert = 0x0;
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
- if(connssl->peer.sni) {
- if(!SSL_set_tlsext_host_name(backend->handle, connssl->peer.sni)) {
+ if(peer->sni) {
+ if(!SSL_set_tlsext_host_name(octx->ssl, peer->sni)) {
failf(data, "Failed set SNI");
return CURLE_SSL_CONNECT_ERROR;
}
}
-#endif
- SSL_set_app_data(backend->handle, cf);
+#ifdef USE_ECH
+ if(ECH_ENABLED(data)) {
+ unsigned char *ech_config = NULL;
+ size_t ech_config_len = 0;
+ char *outername = data->set.str[STRING_ECH_PUBLIC];
+ int trying_ech_now = 0;
+
+ if(data->set.tls_ech & CURLECH_GREASE) {
+ infof(data, "ECH: will GREASE ClientHello");
+# ifdef OPENSSL_IS_BORINGSSL
+ SSL_set_enable_ech_grease(octx->ssl, 1);
+# else
+ SSL_set_options(octx->ssl, SSL_OP_ECH_GREASE);
+# endif
+ }
+ else if(data->set.tls_ech & CURLECH_CLA_CFG) {
+# ifdef OPENSSL_IS_BORINGSSL
+ /* have to do base64 decode here for boring */
+ const char *b64 = data->set.str[STRING_ECH_CONFIG];
+
+ if(!b64) {
+ infof(data, "ECH: ECHConfig from command line empty");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ ech_config_len = 2 * strlen(b64);
+ result = Curl_base64_decode(b64, &ech_config, &ech_config_len);
+ if(result || !ech_config) {
+ infof(data, "ECH: can't base64 decode ECHConfig from command line");
+ if(data->set.tls_ech & CURLECH_HARD)
+ return result;
+ }
+ if(SSL_set1_ech_config_list(octx->ssl, ech_config,
+ ech_config_len) != 1) {
+ infof(data, "ECH: SSL_ECH_set1_echconfig failed");
+ if(data->set.tls_ech & CURLECH_HARD) {
+ free(ech_config);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ }
+ free(ech_config);
+ trying_ech_now = 1;
+# else
+ ech_config = (unsigned char *) data->set.str[STRING_ECH_CONFIG];
+ if(!ech_config) {
+ infof(data, "ECH: ECHConfig from command line empty");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ ech_config_len = strlen(data->set.str[STRING_ECH_CONFIG]);
+ if(SSL_ech_set1_echconfig(octx->ssl, ech_config, ech_config_len) != 1) {
+ infof(data, "ECH: SSL_ECH_set1_echconfig failed");
+ if(data->set.tls_ech & CURLECH_HARD)
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ else
+ trying_ech_now = 1;
+# endif
+ infof(data, "ECH: ECHConfig from command line");
+ }
+ else {
+ struct Curl_dns_entry *dns = NULL;
+
+ dns = Curl_fetch_addr(data, connssl->peer.hostname, connssl->peer.port);
+ if(!dns) {
+ infof(data, "ECH: requested but no DNS info available");
+ if(data->set.tls_ech & CURLECH_HARD)
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ else {
+ struct Curl_https_rrinfo *rinfo = NULL;
+
+ rinfo = dns->hinfo;
+ if(rinfo && rinfo->echconfiglist) {
+ unsigned char *ecl = rinfo->echconfiglist;
+ size_t elen = rinfo->echconfiglist_len;
+
+ infof(data, "ECH: ECHConfig from DoH HTTPS RR");
+# ifndef OPENSSL_IS_BORINGSSL
+ if(SSL_ech_set1_echconfig(octx->ssl, ecl, elen) != 1) {
+ infof(data, "ECH: SSL_ECH_set1_echconfig failed");
+ if(data->set.tls_ech & CURLECH_HARD)
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+# else
+ if(SSL_set1_ech_config_list(octx->ssl, ecl, elen) != 1) {
+ infof(data, "ECH: SSL_set1_ech_config_list failed (boring)");
+ if(data->set.tls_ech & CURLECH_HARD)
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+# endif
+ else {
+ trying_ech_now = 1;
+ infof(data, "ECH: imported ECHConfigList of length %ld", elen);
+ }
+ }
+ else {
+ infof(data, "ECH: requested but no ECHConfig available");
+ if(data->set.tls_ech & CURLECH_HARD)
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ Curl_resolv_unlock(data, dns);
+ }
+ }
+# ifdef OPENSSL_IS_BORINGSSL
+ if(trying_ech_now && outername) {
+ infof(data, "ECH: setting public_name not supported with boringssl");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+# else
+ if(trying_ech_now && outername) {
+ infof(data, "ECH: inner: '%s', outer: '%s'",
+ connssl->peer.hostname, outername);
+ result = SSL_ech_set_server_names(octx->ssl,
+ connssl->peer.hostname, outername,
+ 0 /* do send outer */);
+ if(result != 1) {
+ infof(data, "ECH: rv failed to set server name(s) %d [ERROR]", result);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ }
+# endif /* not BORING */
+ if(trying_ech_now
+ && SSL_set_min_proto_version(octx->ssl, TLS1_3_VERSION) != 1) {
+ infof(data, "ECH: Can't force TLSv1.3 [ERROR]");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ }
+#endif /* USE_ECH */
- connssl->reused_session = FALSE;
- if(ssl_config->primary.sessionid) {
+#endif
+
+ octx->reused_session = FALSE;
+ if(ssl_config->primary.sessionid && transport == TRNSPRT_TCP) {
Curl_ssl_sessionid_lock(data);
- if(!Curl_ssl_getsessionid(cf, data, &ssl_sessionid, NULL)) {
+ if(!Curl_ssl_getsessionid(cf, data, peer, &ssl_sessionid, NULL)) {
/* we got a session id, use it! */
- if(!SSL_set_session(backend->handle, ssl_sessionid)) {
+ if(!SSL_set_session(octx->ssl, ssl_sessionid)) {
Curl_ssl_sessionid_unlock(data);
failf(data, "SSL: SSL_set_session failed: %s",
ossl_strerror(ERR_get_error(), error_buffer,
@@ -3855,15 +3993,46 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,
}
/* Informational message */
infof(data, "SSL reusing session ID");
- connssl->reused_session = TRUE;
+ octx->reused_session = TRUE;
}
Curl_ssl_sessionid_unlock(data);
}
- backend->bio_method = ossl_bio_cf_method_create();
- if(!backend->bio_method)
+ return CURLE_OK;
+}
+
+static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
+{
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
+ struct alpn_proto_buf proto;
+ BIO *bio;
+ CURLcode result;
+
+ DEBUGASSERT(ssl_connect_1 == connssl->connecting_state);
+ DEBUGASSERT(octx);
+ memset(&proto, 0, sizeof(proto));
+#ifdef HAS_ALPN
+ if(connssl->alpn) {
+ result = Curl_alpn_to_proto_buf(&proto, connssl->alpn);
+ if(result) {
+ failf(data, "Error determining ALPN");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ }
+#endif
+
+ result = Curl_ossl_ctx_init(octx, cf, data, &connssl->peer, TRNSPRT_TCP,
+ proto.data, proto.len, NULL, NULL,
+ ossl_new_session_cb, cf);
+ if(result)
+ return result;
+
+ octx->bio_method = ossl_bio_cf_method_create();
+ if(!octx->bio_method)
return CURLE_OUT_OF_MEMORY;
- bio = BIO_new(backend->bio_method);
+ bio = BIO_new(octx->bio_method);
if(!bio)
return CURLE_OUT_OF_MEMORY;
@@ -3875,40 +4044,109 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,
* We check on the function in configure, since libressl and friends
* each have their own versions to add support for this. */
BIO_up_ref(bio);
- SSL_set0_rbio(backend->handle, bio);
- SSL_set0_wbio(backend->handle, bio);
+ SSL_set0_rbio(octx->ssl, bio);
+ SSL_set0_wbio(octx->ssl, bio);
#else
- SSL_set_bio(backend->handle, bio, bio);
+ SSL_set_bio(octx->ssl, bio, bio);
#endif
- connssl->connecting_state = ssl_connect_2;
+#ifdef HAS_ALPN
+ if(connssl->alpn) {
+ Curl_alpn_to_proto_str(&proto, connssl->alpn);
+ infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data);
+ }
+#endif
+ connssl->connecting_state = ssl_connect_2;
return CURLE_OK;
}
+#ifdef USE_ECH
+/* If we have retry configs, then trace those out */
+static void ossl_trace_ech_retry_configs(struct Curl_easy *data, SSL* ssl,
+ int reason)
+{
+ CURLcode result = CURLE_OK;
+ size_t rcl = 0;
+ int rv = 1;
+# ifndef OPENSSL_IS_BORINGSSL
+ char *inner = NULL;
+ unsigned char *rcs = NULL;
+ char *outer = NULL;
+# else
+ const char *inner = NULL;
+ const uint8_t *rcs = NULL;
+ const char *outer = NULL;
+ size_t out_name_len = 0;
+ int servername_type = 0;
+# endif
+
+ /* nothing to trace if not doing ECH */
+ if(!ECH_ENABLED(data))
+ return;
+# ifndef OPENSSL_IS_BORINGSSL
+ rv = SSL_ech_get_retry_config(ssl, &rcs, &rcl);
+# else
+ SSL_get0_ech_retry_configs(ssl, &rcs, &rcl);
+ rv = (int)rcl;
+# endif
+
+ if(rv && rcs) {
+# define HEXSTR_MAX 800
+ char *b64str = NULL;
+ size_t blen = 0;
+
+ result = Curl_base64_encode((const char *)rcs, rcl,
+ &b64str, &blen);
+ if(!result && b64str)
+ infof(data, "ECH: retry_configs %s", b64str);
+ free(b64str);
+# ifndef OPENSSL_IS_BORINGSSL
+ rv = SSL_ech_get_status(ssl, &inner, &outer);
+ infof(data, "ECH: retry_configs for %s from %s, %d %d",
+ inner ? inner : "NULL", outer ? outer : "NULL", reason, rv);
+#else
+ rv = SSL_ech_accepted(ssl);
+ servername_type = SSL_get_servername_type(ssl);
+ inner = SSL_get_servername(ssl, servername_type);
+ SSL_get0_ech_name_override(ssl, &outer, &out_name_len);
+ /* TODO: get the inner from boring */
+ infof(data, "ECH: retry_configs for %s from %s, %d %d",
+ inner ? inner : "NULL", outer ? outer : "NULL", reason, rv);
+#endif
+ }
+ else
+ infof(data, "ECH: no retry_configs (rv = %d)", rv);
+# ifndef OPENSSL_IS_BORINGSSL
+ OPENSSL_free((void *)rcs);
+# endif
+ return;
+}
+
+#endif
+
static CURLcode ossl_connect_step2(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
int err;
struct ssl_connect_data *connssl = cf->ctx;
- struct ossl_ssl_backend_data *backend =
- (struct ossl_ssl_backend_data *)connssl->backend;
+ struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
DEBUGASSERT(ssl_connect_2 == connssl->connecting_state
|| ssl_connect_2_reading == connssl->connecting_state
|| ssl_connect_2_writing == connssl->connecting_state);
- DEBUGASSERT(backend);
+ DEBUGASSERT(octx);
ERR_clear_error();
- err = SSL_connect(backend->handle);
+ err = SSL_connect(octx->ssl);
- if(!backend->x509_store_setup) {
+ if(!octx->x509_store_setup) {
/* After having send off the ClientHello, we prepare the x509
* store to verify the coming certificate from the server */
- CURLcode result = Curl_ssl_setup_x509_store(cf, data, backend->ctx);
+ CURLcode result = Curl_ssl_setup_x509_store(cf, data, octx->ssl_ctx);
if(result)
return result;
- backend->x509_store_setup = TRUE;
+ octx->x509_store_setup = TRUE;
}
#ifndef HAVE_KEYLOG_CALLBACK
@@ -3916,7 +4154,9 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf,
/* If key logging is enabled, wait for the handshake to complete and then
* proceed with logging secrets (for TLS 1.2 or older).
*/
- ossl_log_tls12_secret(backend->handle, &backend->keylog_done);
+ bool done = FALSE;
+ ossl_log_tls12_secret(octx->ssl, &done);
+ octx->keylog_done = done;
}
#endif
@@ -3924,7 +4164,7 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf,
0 is "not successful but was shut down controlled"
<0 is "handshake was not successful, because a fatal error occurred" */
if(1 != err) {
- int detail = SSL_get_error(backend->handle, err);
+ int detail = SSL_get_error(octx->ssl, err);
if(SSL_ERROR_WANT_READ == detail) {
connssl->connecting_state = ssl_connect_2_reading;
@@ -3946,7 +4186,7 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf,
return CURLE_OK;
}
#endif
- if(backend->io_result == CURLE_AGAIN) {
+ if(octx->io_result == CURLE_AGAIN) {
return CURLE_OK;
}
else {
@@ -3974,7 +4214,7 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf,
(reason == SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED))) {
result = CURLE_PEER_FAILED_VERIFICATION;
- lerr = SSL_get_verify_result(backend->handle);
+ lerr = SSL_get_verify_result(octx->ssl);
if(lerr != X509_V_OK) {
ssl_config->certverifyresult = lerr;
msnprintf(error_buffer, sizeof(error_buffer),
@@ -3997,6 +4237,21 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf,
ossl_strerror(errdetail, error_buffer, sizeof(error_buffer));
}
#endif
+#ifdef USE_ECH
+ else if((lib == ERR_LIB_SSL) &&
+# ifndef OPENSSL_IS_BORINGSSL
+ (reason == SSL_R_ECH_REQUIRED)) {
+# else
+ (reason == SSL_R_ECH_REJECTED)) {
+# endif
+
+ /* trace retry_configs if we got some */
+ ossl_trace_ech_retry_configs(data, octx->ssl, reason);
+
+ result = CURLE_ECH_REQUIRED;
+ ossl_strerror(errdetail, error_buffer, sizeof(error_buffer));
+ }
+#endif
else {
result = CURLE_SSL_CONNECT_ERROR;
ossl_strerror(errdetail, error_buffer, sizeof(error_buffer));
@@ -4016,7 +4271,7 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf,
Curl_strerror(sockerr, extramsg, sizeof(extramsg));
failf(data, OSSL_PACKAGE " SSL_connect: %s in connection to %s:%d ",
extramsg[0] ? extramsg : SSL_ERROR_to_str(detail),
- connssl->peer.hostname, connssl->port);
+ connssl->peer.hostname, connssl->peer.port);
return result;
}
@@ -4034,22 +4289,84 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf,
connssl->connecting_state = ssl_connect_3;
#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
- SSL_get_peer_signature_type_nid(backend->handle, &psigtype_nid);
+ SSL_get_peer_signature_type_nid(octx->ssl, &psigtype_nid);
#if (OPENSSL_VERSION_NUMBER >= 0x30200000L)
- negotiated_group_name = SSL_get0_group_name(backend->handle);
+ negotiated_group_name = SSL_get0_group_name(octx->ssl);
#else
negotiated_group_name =
- OBJ_nid2sn(SSL_get_negotiated_group(backend->handle) & 0x0000FFFF);
+ OBJ_nid2sn(SSL_get_negotiated_group(octx->ssl) & 0x0000FFFF);
#endif
#endif
/* Informational message */
infof(data, "SSL connection using %s / %s / %s / %s",
- SSL_get_version(backend->handle),
- SSL_get_cipher(backend->handle),
+ SSL_get_version(octx->ssl),
+ SSL_get_cipher(octx->ssl),
negotiated_group_name? negotiated_group_name : "[blank]",
OBJ_nid2sn(psigtype_nid));
+#ifdef USE_ECH
+# ifndef OPENSSL_IS_BORINGSSL
+ if(ECH_ENABLED(data)) {
+ char *inner = NULL, *outer = NULL;
+ const char *status = NULL;
+ int rv;
+
+ rv = SSL_ech_get_status(octx->ssl, &inner, &outer);
+ switch(rv) {
+ case SSL_ECH_STATUS_SUCCESS:
+ status = "succeeded";
+ break;
+ case SSL_ECH_STATUS_GREASE_ECH:
+ status = "sent GREASE, got retry-configs";
+ break;
+ case SSL_ECH_STATUS_GREASE:
+ status = "sent GREASE";
+ break;
+ case SSL_ECH_STATUS_NOT_TRIED:
+ status = "not attempted";
+ break;
+ case SSL_ECH_STATUS_NOT_CONFIGURED:
+ status = "not configured";
+ break;
+ case SSL_ECH_STATUS_BACKEND:
+ status = "backend (unexpected)";
+ break;
+ case SSL_ECH_STATUS_FAILED:
+ status = "failed";
+ break;
+ case SSL_ECH_STATUS_BAD_CALL:
+ status = "bad call (unexpected)";
+ break;
+ case SSL_ECH_STATUS_BAD_NAME:
+ status = "bad name (unexpected)";
+ break;
+ default:
+ status = "unexpected status";
+ 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"));
+ OPENSSL_free(inner);
+ OPENSSL_free(outer);
+ if(rv == SSL_ECH_STATUS_GREASE_ECH) {
+ /* trace retry_configs if we got some */
+ ossl_trace_ech_retry_configs(data, octx->ssl, 0);
+ }
+ if(rv != SSL_ECH_STATUS_SUCCESS
+ && data->set.tls_ech & CURLECH_HARD) {
+ infof(data, "ECH: ech-hard failed");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ }
+ else {
+ infof(data, "ECH: result: status is not attempted");
+ }
+# endif /* BORING */
+#endif /* USE_ECH */
+
#ifdef HAS_ALPN
/* Sets data and len to negotiated protocol, len is 0 if no protocol was
* negotiated
@@ -4057,7 +4374,7 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf,
if(connssl->alpn) {
const unsigned char *neg_protocol;
unsigned int len;
- SSL_get0_alpn_selected(backend->handle, &neg_protocol, &len);
+ SSL_get0_alpn_selected(octx->ssl, &neg_protocol, &len);
return Curl_alpn_set_negotiated(cf, data, neg_protocol, len);
}
@@ -4194,20 +4511,12 @@ static void infof_certstack(struct Curl_easy *data, const SSL *ssl)
#define infof_certstack(data, ssl)
#endif
-/*
- * Get the server cert, verify it and show it, etc., only call failf() if the
- * 'strict' argument is TRUE as otherwise all this is for informational
- * purposes only!
- *
- * We check certificates to authenticate the server; otherwise we risk
- * man-in-the-middle attack.
- */
-static CURLcode servercert(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- bool strict)
+CURLcode Curl_oss_check_peer_cert(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct ossl_ctx *octx,
+ struct ssl_peer *peer)
{
struct connectdata *conn = cf->conn;
- struct ssl_connect_data *connssl = cf->ctx;
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;
@@ -4219,10 +4528,9 @@ static CURLcode servercert(struct Curl_cfilter *cf,
char buffer[2048];
const char *ptr;
BIO *mem = BIO_new(BIO_s_mem());
- struct ossl_ssl_backend_data *backend =
- (struct ossl_ssl_backend_data *)connssl->backend;
+ bool strict = (conn_config->verifypeer || conn_config->verifyhost);
- DEBUGASSERT(backend);
+ DEBUGASSERT(octx);
if(!mem) {
failf(data,
@@ -4235,10 +4543,10 @@ static CURLcode servercert(struct Curl_cfilter *cf,
if(data->set.ssl.certinfo)
/* asked to gather certificate info */
- (void)Curl_ossl_certchain(data, backend->handle);
+ (void)Curl_ossl_certchain(data, octx->ssl);
- backend->server_cert = SSL_get1_peer_certificate(backend->handle);
- if(!backend->server_cert) {
+ octx->server_cert = SSL_get1_peer_certificate(octx->ssl);
+ if(!octx->server_cert) {
BIO_free(mem);
if(!strict)
return CURLE_OK;
@@ -4250,19 +4558,19 @@ static CURLcode servercert(struct Curl_cfilter *cf,
infof(data, "%s certificate:",
Curl_ssl_cf_is_proxy(cf)? "Proxy" : "Server");
- rc = x509_name_oneline(X509_get_subject_name(backend->server_cert),
+ rc = x509_name_oneline(X509_get_subject_name(octx->server_cert),
buffer, sizeof(buffer));
infof(data, " subject: %s", rc?"[NONE]":buffer);
#ifndef CURL_DISABLE_VERBOSE_STRINGS
{
long len;
- ASN1_TIME_print(mem, X509_get0_notBefore(backend->server_cert));
+ ASN1_TIME_print(mem, X509_get0_notBefore(octx->server_cert));
len = BIO_get_mem_data(mem, (char **) &ptr);
infof(data, " start date: %.*s", (int)len, ptr);
(void)BIO_reset(mem);
- ASN1_TIME_print(mem, X509_get0_notAfter(backend->server_cert));
+ ASN1_TIME_print(mem, X509_get0_notAfter(octx->server_cert));
len = BIO_get_mem_data(mem, (char **) &ptr);
infof(data, " expire date: %.*s", (int)len, ptr);
(void)BIO_reset(mem);
@@ -4272,16 +4580,15 @@ static CURLcode servercert(struct Curl_cfilter *cf,
BIO_free(mem);
if(conn_config->verifyhost) {
- result = Curl_ossl_verifyhost(data, conn, &connssl->peer,
- backend->server_cert);
+ result = Curl_ossl_verifyhost(data, conn, peer, octx->server_cert);
if(result) {
- X509_free(backend->server_cert);
- backend->server_cert = NULL;
+ X509_free(octx->server_cert);
+ octx->server_cert = NULL;
return result;
}
}
- rc = x509_name_oneline(X509_get_issuer_name(backend->server_cert),
+ rc = x509_name_oneline(X509_get_issuer_name(octx->server_cert),
buffer, sizeof(buffer));
if(rc) {
if(strict)
@@ -4305,8 +4612,8 @@ static CURLcode servercert(struct Curl_cfilter *cf,
" error %s",
ossl_strerror(ERR_get_error(), error_buffer,
sizeof(error_buffer)) );
- X509_free(backend->server_cert);
- backend->server_cert = NULL;
+ X509_free(octx->server_cert);
+ octx->server_cert = NULL;
return CURLE_OUT_OF_MEMORY;
}
}
@@ -4318,8 +4625,8 @@ static CURLcode servercert(struct Curl_cfilter *cf,
" error %s",
ossl_strerror(ERR_get_error(), error_buffer,
sizeof(error_buffer)) );
- X509_free(backend->server_cert);
- backend->server_cert = NULL;
+ X509_free(octx->server_cert);
+ octx->server_cert = NULL;
return CURLE_OUT_OF_MEMORY;
}
@@ -4328,8 +4635,8 @@ static CURLcode servercert(struct Curl_cfilter *cf,
failf(data, "SSL: Unable to open issuer cert (%s)",
conn_config->issuercert);
BIO_free(fp);
- X509_free(backend->server_cert);
- backend->server_cert = NULL;
+ X509_free(octx->server_cert);
+ octx->server_cert = NULL;
return CURLE_SSL_ISSUER_ERROR;
}
}
@@ -4341,19 +4648,19 @@ static CURLcode servercert(struct Curl_cfilter *cf,
conn_config->issuercert);
BIO_free(fp);
X509_free(issuer);
- X509_free(backend->server_cert);
- backend->server_cert = NULL;
+ X509_free(octx->server_cert);
+ octx->server_cert = NULL;
return CURLE_SSL_ISSUER_ERROR;
}
- if(X509_check_issued(issuer, backend->server_cert) != X509_V_OK) {
+ if(X509_check_issued(issuer, octx->server_cert) != X509_V_OK) {
if(strict)
failf(data, "SSL: Certificate issuer check failed (%s)",
conn_config->issuercert);
BIO_free(fp);
X509_free(issuer);
- X509_free(backend->server_cert);
- backend->server_cert = NULL;
+ X509_free(octx->server_cert);
+ octx->server_cert = NULL;
return CURLE_SSL_ISSUER_ERROR;
}
@@ -4363,7 +4670,7 @@ static CURLcode servercert(struct Curl_cfilter *cf,
X509_free(issuer);
}
- lerr = SSL_get_verify_result(backend->handle);
+ lerr = SSL_get_verify_result(octx->ssl);
ssl_config->certverifyresult = lerr;
if(lerr != X509_V_OK) {
if(conn_config->verifypeer) {
@@ -4383,11 +4690,11 @@ static CURLcode servercert(struct Curl_cfilter *cf,
infof(data, " SSL certificate verify ok.");
}
- infof_certstack(data, backend->handle);
+ infof_certstack(data, octx->ssl);
#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
!defined(OPENSSL_NO_OCSP)
- if(conn_config->verifystatus && !connssl->reused_session) {
+ if(conn_config->verifystatus && !octx->reused_session) {
/* don't do this after Session ID reuse */
result = verifystatus(cf, data);
if(result) {
@@ -4397,7 +4704,8 @@ static CURLcode servercert(struct Curl_cfilter *cf,
void *old_ssl_sessionid = NULL;
bool incache;
Curl_ssl_sessionid_lock(data);
- incache = !(Curl_ssl_getsessionid(cf, data, &old_ssl_sessionid, NULL));
+ incache = !(Curl_ssl_getsessionid(cf, data, peer,
+ &old_ssl_sessionid, NULL));
if(incache) {
infof(data, "Remove session ID again from cache");
Curl_ssl_delsessionid(data, old_ssl_sessionid);
@@ -4405,8 +4713,8 @@ static CURLcode servercert(struct Curl_cfilter *cf,
Curl_ssl_sessionid_unlock(data);
}
- X509_free(backend->server_cert);
- backend->server_cert = NULL;
+ X509_free(octx->server_cert);
+ octx->server_cert = NULL;
return result;
}
}
@@ -4416,18 +4724,21 @@ static CURLcode servercert(struct Curl_cfilter *cf,
/* when not strict, we don't bother about the verify cert problems */
result = CURLE_OK;
+#ifndef CURL_DISABLE_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];
+#endif
if(!result && ptr) {
- result = ossl_pkp_pin_peer_pubkey(data, backend->server_cert, ptr);
+ result = ossl_pkp_pin_peer_pubkey(data, octx->server_cert, ptr);
if(result)
failf(data, "SSL: public key does not match pinned public key");
}
- X509_free(backend->server_cert);
- backend->server_cert = NULL;
- connssl->connecting_state = ssl_connect_done;
+ X509_free(octx->server_cert);
+ octx->server_cert = NULL;
return result;
}
@@ -4437,7 +4748,7 @@ static CURLcode ossl_connect_step3(struct Curl_cfilter *cf,
{
CURLcode result = CURLE_OK;
struct ssl_connect_data *connssl = cf->ctx;
- struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+ struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
@@ -4448,9 +4759,7 @@ static CURLcode ossl_connect_step3(struct Curl_cfilter *cf,
* operations.
*/
- result = servercert(cf, data, conn_config->verifypeer ||
- conn_config->verifyhost);
-
+ result = Curl_oss_check_peer_cert(cf, data, octx, &connssl->peer);
if(!result)
connssl->connecting_state = ssl_connect_done;
@@ -4590,12 +4899,11 @@ static bool ossl_data_pending(struct Curl_cfilter *cf,
const struct Curl_easy *data)
{
struct ssl_connect_data *connssl = cf->ctx;
- struct ossl_ssl_backend_data *backend =
- (struct ossl_ssl_backend_data *)connssl->backend;
+ struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
(void)data;
- DEBUGASSERT(connssl && backend);
- if(backend->handle && SSL_pending(backend->handle))
+ DEBUGASSERT(connssl && octx);
+ if(octx->ssl && SSL_pending(octx->ssl))
return TRUE;
return FALSE;
}
@@ -4614,19 +4922,18 @@ static ssize_t ossl_send(struct Curl_cfilter *cf,
int memlen;
int rc;
struct ssl_connect_data *connssl = cf->ctx;
- struct ossl_ssl_backend_data *backend =
- (struct ossl_ssl_backend_data *)connssl->backend;
+ struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
(void)data;
- DEBUGASSERT(backend);
+ DEBUGASSERT(octx);
ERR_clear_error();
memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len;
- rc = SSL_write(backend->handle, mem, memlen);
+ rc = SSL_write(octx->ssl, mem, memlen);
if(rc <= 0) {
- err = SSL_get_error(backend->handle, rc);
+ err = SSL_get_error(octx->ssl, rc);
switch(err) {
case SSL_ERROR_WANT_READ:
@@ -4641,7 +4948,7 @@ static ssize_t ossl_send(struct Curl_cfilter *cf,
{
int sockerr = SOCKERRNO;
- if(backend->io_result == CURLE_AGAIN) {
+ if(octx->io_result == CURLE_AGAIN) {
*curlcode = CURLE_AGAIN;
rc = -1;
goto out;
@@ -4698,20 +5005,19 @@ static ssize_t ossl_recv(struct Curl_cfilter *cf,
int buffsize;
struct connectdata *conn = cf->conn;
struct ssl_connect_data *connssl = cf->ctx;
- struct ossl_ssl_backend_data *backend =
- (struct ossl_ssl_backend_data *)connssl->backend;
+ struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
(void)data;
- DEBUGASSERT(backend);
+ DEBUGASSERT(octx);
ERR_clear_error();
buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize;
- nread = (ssize_t)SSL_read(backend->handle, buf, buffsize);
+ nread = (ssize_t)SSL_read(octx->ssl, buf, buffsize);
if(nread <= 0) {
/* failed SSL_read */
- int err = SSL_get_error(backend->handle, (int)nread);
+ int err = SSL_get_error(octx->ssl, (int)nread);
switch(err) {
case SSL_ERROR_NONE: /* this is not an error */
@@ -4733,7 +5039,7 @@ static ssize_t ossl_recv(struct Curl_cfilter *cf,
/* openssl/ssl.h for SSL_ERROR_SYSCALL says "look at error stack/return
value/errno" */
/* https://www.openssl.org/docs/crypto/ERR_get_error.html */
- if(backend->io_result == CURLE_AGAIN) {
+ if(octx->io_result == CURLE_AGAIN) {
*curlcode = CURLE_AGAIN;
nread = -1;
goto out;
@@ -4924,11 +5230,10 @@ static void *ossl_get_internals(struct ssl_connect_data *connssl,
CURLINFO info)
{
/* Legacy: CURLINFO_TLS_SESSION must return an SSL_CTX pointer. */
- struct ossl_ssl_backend_data *backend =
- (struct ossl_ssl_backend_data *)connssl->backend;
- DEBUGASSERT(backend);
+ struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
+ DEBUGASSERT(octx);
return info == CURLINFO_TLS_SESSION ?
- (void *)backend->ctx : (void *)backend->handle;
+ (void *)octx->ssl_ctx : (void *)octx->ssl;
}
static void ossl_free_multi_ssl_backend_data(
@@ -4956,9 +5261,12 @@ const struct Curl_ssl Curl_ssl_openssl = {
#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES
SSLSUPP_TLS13_CIPHERSUITES |
#endif
+#ifdef USE_ECH
+ SSLSUPP_ECH |
+#endif
SSLSUPP_HTTPS_PROXY,
- sizeof(struct ossl_ssl_backend_data),
+ sizeof(struct ossl_ctx),
ossl_init, /* init */
ossl_cleanup, /* cleanup */
@@ -4974,7 +5282,6 @@ const struct Curl_ssl Curl_ssl_openssl = {
ossl_get_internals, /* get_internals */
ossl_close, /* close_one */
ossl_close_all, /* close_all */
- ossl_session_free, /* session_free */
ossl_set_engine, /* set_engine */
ossl_set_engine_default, /* set_engine_default */
ossl_engines_list, /* engines_list */
diff --git a/libs/libcurl/src/vtls/openssl.h b/libs/libcurl/src/vtls/openssl.h
index df36a831b1..f46fbf3722 100644
--- a/libs/libcurl/src/vtls/openssl.h
+++ b/libs/libcurl/src/vtls/openssl.h
@@ -36,6 +36,39 @@
#include "urldata.h"
+/* Struct to hold a Curl OpenSSL instance */
+struct ossl_ctx {
+ /* these ones requires specific SSL-types */
+ SSL_CTX* ssl_ctx;
+ SSL* ssl;
+ X509* server_cert;
+ BIO_METHOD *bio_method;
+ CURLcode io_result; /* result of last BIO cfilter operation */
+#ifndef HAVE_KEYLOG_CALLBACK
+ /* Set to true once a valid keylog entry has been created to avoid dupes. */
+ BIT(keylog_done);
+#endif
+ BIT(x509_store_setup); /* x509 store has been set up */
+ BIT(reused_session); /* session-ID was reused for this */
+};
+
+typedef CURLcode Curl_ossl_ctx_setup_cb(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ void *user_data);
+
+typedef int Curl_ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid);
+
+CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx,
+ struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct ssl_peer *peer,
+ int transport, /* TCP or QUIC */
+ const unsigned char *alpn, size_t alpn_len,
+ Curl_ossl_ctx_setup_cb *cb_setup,
+ void *cb_user_data,
+ Curl_ossl_new_session_cb *cb_new_session,
+ void *ssl_user_data);
+
#if (OPENSSL_VERSION_NUMBER < 0x30000000L)
#define SSL_get1_peer_certificate SSL_get_peer_certificate
#endif
@@ -66,5 +99,23 @@ CURLcode Curl_ossl_ctx_configure(struct Curl_cfilter *cf,
struct Curl_easy *data,
SSL_CTX *ssl_ctx);
+/*
+ * Add a new session to the cache. Takes ownership of the session.
+ */
+CURLcode Curl_ossl_add_session(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ const struct ssl_peer *peer,
+ SSL_SESSION *ssl_sessionid);
+
+/*
+ * Get the server cert, verify it and show it, etc., only call failf() if
+ * ssl config verifypeer or -host is set. Otherwise all this is for
+ * informational purposes only!
+ */
+CURLcode Curl_oss_check_peer_cert(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct ossl_ctx *octx,
+ struct ssl_peer *peer);
+
#endif /* USE_OPENSSL */
#endif /* HEADER_CURL_SSLUSE_H */
diff --git a/libs/libcurl/src/vtls/rustls.c b/libs/libcurl/src/vtls/rustls.c
index 0688df13ef..0e65c37f37 100644
--- a/libs/libcurl/src/vtls/rustls.c
+++ b/libs/libcurl/src/vtls/rustls.c
@@ -46,7 +46,8 @@ struct rustls_ssl_backend_data
{
const struct rustls_client_config *config;
struct rustls_connection *conn;
- bool data_pending;
+ size_t plain_out_buffered;
+ BIT(data_in_pending);
};
/* For a given rustls_result error code, return the best-matching CURLcode. */
@@ -61,7 +62,7 @@ static CURLcode map_error(rustls_result r)
case RUSTLS_RESULT_NULL_PARAMETER:
return CURLE_BAD_FUNCTION_ARGUMENT;
default:
- return CURLE_READ_ERROR;
+ return CURLE_RECV_ERROR;
}
}
@@ -74,7 +75,7 @@ cr_data_pending(struct Curl_cfilter *cf, const struct Curl_easy *data)
(void)data;
DEBUGASSERT(ctx && ctx->backend);
backend = (struct rustls_ssl_backend_data *)ctx->backend;
- return backend->data_pending;
+ return backend->data_in_pending;
}
struct io_ctx {
@@ -101,6 +102,8 @@ read_cb(void *userdata, uint8_t *buf, uintptr_t len, uintptr_t *out_n)
else if(nread == 0)
connssl->peer_closed = TRUE;
*out_n = (int)nread;
+ CURL_TRC_CF(io_ctx->data, io_ctx->cf, "cf->next recv(len=%zu) -> %zd, %d",
+ len, nread, result);
return ret;
}
@@ -120,10 +123,8 @@ write_cb(void *userdata, const uint8_t *buf, uintptr_t len, uintptr_t *out_n)
ret = EINVAL;
}
*out_n = (int)nwritten;
- /*
- CURL_TRC_CFX(io_ctx->data, io_ctx->cf, "cf->next send(len=%zu) -> %zd, %d",
- len, nwritten, result));
- */
+ CURL_TRC_CF(io_ctx->data, io_ctx->cf, "cf->next send(len=%zu) -> %zd, %d",
+ len, nwritten, result);
return ret;
}
@@ -150,7 +151,7 @@ static ssize_t tls_recv_more(struct Curl_cfilter *cf,
char buffer[STRERROR_LEN];
failf(data, "reading from socket: %s",
Curl_strerror(io_error, buffer, sizeof(buffer)));
- *err = CURLE_READ_ERROR;
+ *err = CURLE_RECV_ERROR;
return -1;
}
@@ -165,7 +166,7 @@ static ssize_t tls_recv_more(struct Curl_cfilter *cf,
return -1;
}
- backend->data_pending = TRUE;
+ backend->data_in_pending = TRUE;
*err = CURLE_OK;
return (ssize_t)tls_bytes_read;
}
@@ -200,7 +201,7 @@ cr_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
rconn = backend->conn;
while(plain_bytes_copied < plainlen) {
- if(!backend->data_pending) {
+ if(!backend->data_in_pending) {
if(tls_recv_more(cf, data, err) < 0) {
if(*err != CURLE_AGAIN) {
nread = -1;
@@ -215,12 +216,12 @@ cr_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
plainlen - plain_bytes_copied,
&n);
if(rresult == RUSTLS_RESULT_PLAINTEXT_EMPTY) {
- backend->data_pending = FALSE;
+ backend->data_in_pending = FALSE;
}
else if(rresult == RUSTLS_RESULT_UNEXPECTED_EOF) {
failf(data, "rustls: peer closed TCP connection "
"without first closing TLS connection");
- *err = CURLE_READ_ERROR;
+ *err = CURLE_RECV_ERROR;
nread = -1;
goto out;
}
@@ -230,7 +231,7 @@ cr_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
size_t errorlen;
rustls_error(rresult, errorbuf, sizeof(errorbuf), &errorlen);
failf(data, "rustls_connection_read: %.*s", (int)errorlen, errorbuf);
- *err = CURLE_READ_ERROR;
+ *err = CURLE_RECV_ERROR;
nread = -1;
goto out;
}
@@ -265,6 +266,42 @@ out:
return nread;
}
+static CURLcode cr_flush_out(struct Curl_cfilter *cf, struct Curl_easy *data,
+ struct rustls_connection *rconn)
+{
+ struct io_ctx io_ctx;
+ rustls_io_result io_error;
+ size_t tlswritten = 0;
+ size_t tlswritten_total = 0;
+ CURLcode result = CURLE_OK;
+
+ io_ctx.cf = cf;
+ io_ctx.data = data;
+
+ while(rustls_connection_wants_write(rconn)) {
+ io_error = rustls_connection_write_tls(rconn, write_cb, &io_ctx,
+ &tlswritten);
+ if(io_error == EAGAIN || io_error == EWOULDBLOCK) {
+ CURL_TRC_CF(data, cf, "cf_send: EAGAIN after %zu bytes",
+ tlswritten_total);
+ return CURLE_AGAIN;
+ }
+ else if(io_error) {
+ char buffer[STRERROR_LEN];
+ failf(data, "writing to socket: %s",
+ Curl_strerror(io_error, buffer, sizeof(buffer)));
+ return CURLE_SEND_ERROR;
+ }
+ if(tlswritten == 0) {
+ failf(data, "EOF in swrite");
+ return CURLE_SEND_ERROR;
+ }
+ CURL_TRC_CF(data, cf, "cf_send: wrote %zu TLS bytes", tlswritten);
+ tlswritten_total += tlswritten;
+ }
+ return result;
+}
+
/*
* On each call:
* - Copy `plainlen` bytes into rustls' plaintext input buffer (if > 0).
@@ -283,26 +320,43 @@ cr_send(struct Curl_cfilter *cf, struct Curl_easy *data,
struct rustls_ssl_backend_data *const backend =
(struct rustls_ssl_backend_data *)connssl->backend;
struct rustls_connection *rconn = NULL;
- struct io_ctx io_ctx;
size_t plainwritten = 0;
- size_t tlswritten = 0;
- size_t tlswritten_total = 0;
rustls_result rresult;
- rustls_io_result io_error;
char errorbuf[256];
size_t errorlen;
+ const unsigned char *buf = plainbuf;
+ size_t blen = plainlen;
+ ssize_t nwritten = 0;
DEBUGASSERT(backend);
rconn = backend->conn;
+ DEBUGASSERT(rconn);
+
+ CURL_TRC_CF(data, cf, "cf_send(len=%zu)", plainlen);
+
+ /* If a previous send blocked, we already added its plain bytes
+ * to rustsls and must not do that again. Flush the TLS bytes and,
+ * if successful, deduct the previous plain bytes from the current
+ * send. */
+ if(backend->plain_out_buffered) {
+ *err = cr_flush_out(cf, data, rconn);
+ CURL_TRC_CF(data, cf, "cf_send: flushing %zu previously added bytes -> %d",
+ backend->plain_out_buffered, *err);
+ if(*err)
+ return -1;
+ if(blen > backend->plain_out_buffered) {
+ blen -= backend->plain_out_buffered;
+ buf += backend->plain_out_buffered;
+ }
+ else
+ blen = 0;
+ nwritten += (ssize_t)backend->plain_out_buffered;
+ backend->plain_out_buffered = 0;
+ }
- CURL_TRC_CF(data, cf, "cf_send: %zu plain bytes", plainlen);
-
- io_ctx.cf = cf;
- io_ctx.data = data;
-
- if(plainlen > 0) {
- rresult = rustls_connection_write(rconn, plainbuf, plainlen,
- &plainwritten);
+ if(blen > 0) {
+ CURL_TRC_CF(data, cf, "cf_send: adding %zu plain bytes to rustls", blen);
+ rresult = rustls_connection_write(rconn, buf, blen, &plainwritten);
if(rresult != RUSTLS_RESULT_OK) {
rustls_error(rresult, errorbuf, sizeof(errorbuf), &errorlen);
failf(data, "rustls_connection_write: %.*s", (int)errorlen, errorbuf);
@@ -316,32 +370,27 @@ cr_send(struct Curl_cfilter *cf, struct Curl_easy *data,
}
}
- while(rustls_connection_wants_write(rconn)) {
- io_error = rustls_connection_write_tls(rconn, write_cb, &io_ctx,
- &tlswritten);
- if(io_error == EAGAIN || io_error == EWOULDBLOCK) {
- CURL_TRC_CF(data, cf, "cf_send: EAGAIN after %zu bytes",
- tlswritten_total);
- *err = CURLE_AGAIN;
- return -1;
- }
- else if(io_error) {
- char buffer[STRERROR_LEN];
- failf(data, "writing to socket: %s",
- Curl_strerror(io_error, buffer, sizeof(buffer)));
- *err = CURLE_WRITE_ERROR;
- return -1;
- }
- if(tlswritten == 0) {
- failf(data, "EOF in swrite");
- *err = CURLE_WRITE_ERROR;
- return -1;
+ *err = cr_flush_out(cf, data, rconn);
+ if(*err) {
+ if(CURLE_AGAIN == *err) {
+ /* The TLS bytes may have been partially written, but we fail the
+ * complete send() and remember how much we already added to rustls. */
+ CURL_TRC_CF(data, cf, "cf_send: EAGAIN, remember we added %zu plain"
+ " bytes already to rustls", blen);
+ backend->plain_out_buffered = plainwritten;
+ if(nwritten) {
+ *err = CURLE_OK;
+ return (ssize_t)nwritten;
+ }
}
- CURL_TRC_CF(data, cf, "cf_send: wrote %zu TLS bytes", tlswritten);
- tlswritten_total += tlswritten;
+ return -1;
}
+ else
+ nwritten += (ssize_t)plainwritten;
- return plainwritten;
+ CURL_TRC_CF(data, cf, "cf_send(len=%zu) -> %d, %zd",
+ plainlen, *err, nwritten);
+ return nwritten;
}
/* A server certificate verify callback for rustls that always returns
@@ -357,12 +406,12 @@ static bool
cr_hostname_is_ip(const char *hostname)
{
struct in_addr in;
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
struct in6_addr in6;
if(Curl_inet_pton(AF_INET6, hostname, &in6) > 0) {
return true;
}
-#endif /* ENABLE_IPV6 */
+#endif /* USE_IPV6 */
if(Curl_inet_pton(AF_INET, hostname, &in) > 0) {
return true;
}
@@ -479,18 +528,14 @@ cr_init_backend(struct Curl_cfilter *cf, struct Curl_easy *data,
backend->config = rustls_client_config_builder_build(config_builder);
DEBUGASSERT(rconn == NULL);
- {
- /* rustls claims to manage ip address hostnames as well here. So,
- * if we have an SNI, we use it, otherwise we pass the hostname */
- char *server = connssl->peer.sni?
- connssl->peer.sni : connssl->peer.hostname;
- result = rustls_client_connection_new(backend->config, server, &rconn);
- }
+ result = rustls_client_connection_new(backend->config,
+ connssl->peer.hostname, &rconn);
if(result != RUSTLS_RESULT_OK) {
rustls_error(result, errorbuf, sizeof(errorbuf), &errorlen);
failf(data, "rustls_client_connection_new: %.*s", (int)errorlen, errorbuf);
return CURLE_COULDNT_CONNECT;
}
+ DEBUGASSERT(rconn);
rustls_connection_set_userdata(rconn, backend);
backend->conn = rconn;
return CURLE_OK;
@@ -539,9 +584,12 @@ cr_connect_common(struct Curl_cfilter *cf,
DEBUGASSERT(backend);
- if(ssl_connection_none == connssl->state) {
+ CURL_TRC_CF(data, cf, "cr_connect_common, state=%d", connssl->state);
+ *done = FALSE;
+ if(!backend->conn) {
result = cr_init_backend(cf, data,
(struct rustls_ssl_backend_data *)connssl->backend);
+ CURL_TRC_CF(data, cf, "cr_connect_common, init backend -> %d", result);
if(result != CURLE_OK) {
return result;
}
@@ -558,21 +606,34 @@ cr_connect_common(struct Curl_cfilter *cf,
*/
if(!rustls_connection_is_handshaking(rconn)) {
infof(data, "Done handshaking");
- /* Done with the handshake. Set up callbacks to send/receive data. */
- connssl->state = ssl_connection_complete;
-
+ /* rustls claims it is no longer handshaking *before* it has
+ * send its FINISHED message off. We attempt to let it write
+ * one more time. Oh my.
+ */
cr_set_negotiated_alpn(cf, data, rconn);
-
+ cr_send(cf, data, NULL, 0, &tmperr);
+ if(tmperr == CURLE_AGAIN) {
+ connssl->connecting_state = ssl_connect_2_writing;
+ return CURLE_OK;
+ }
+ else if(tmperr != CURLE_OK) {
+ return tmperr;
+ }
+ /* REALLY Done with the handshake. */
+ connssl->state = ssl_connection_complete;
*done = TRUE;
return CURLE_OK;
}
wants_read = rustls_connection_wants_read(rconn);
- wants_write = rustls_connection_wants_write(rconn);
+ 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;
+ connssl->connecting_state = wants_write?
+ ssl_connect_2_writing : ssl_connect_2_reading;
/* check allowed time left */
timeout_ms = Curl_timeleft(data, NULL, TRUE);
@@ -584,8 +645,8 @@ cr_connect_common(struct Curl_cfilter *cf,
socket_check_timeout = blocking?timeout_ms:0;
- what = Curl_socket_check(
- readfd, CURL_SOCKET_BAD, writefd, socket_check_timeout);
+ what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
+ socket_check_timeout);
if(what < 0) {
/* fatal error */
failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
@@ -597,19 +658,18 @@ cr_connect_common(struct Curl_cfilter *cf,
return CURLE_OPERATION_TIMEDOUT;
}
if(0 == what) {
- infof(data, "Curl_socket_check: %s would block",
+ CURL_TRC_CF(data, cf, "Curl_socket_check: %s would block",
wants_read&&wants_write ? "writing and reading" :
wants_write ? "writing" : "reading");
- *done = FALSE;
return CURLE_OK;
}
/* socket is readable or writable */
if(wants_write) {
- infof(data, "rustls_connection wants us to write_tls.");
+ CURL_TRC_CF(data, cf, "rustls_connection wants us to write_tls.");
cr_send(cf, data, NULL, 0, &tmperr);
if(tmperr == CURLE_AGAIN) {
- infof(data, "writing would block");
+ CURL_TRC_CF(data, cf, "writing would block");
/* fall through */
}
else if(tmperr != CURLE_OK) {
@@ -618,14 +678,13 @@ cr_connect_common(struct Curl_cfilter *cf,
}
if(wants_read) {
- infof(data, "rustls_connection wants us to read_tls.");
-
+ CURL_TRC_CF(data, cf, "rustls_connection wants us to read_tls.");
if(tls_recv_more(cf, data, &tmperr) < 0) {
if(tmperr == CURLE_AGAIN) {
- infof(data, "reading would block");
+ CURL_TRC_CF(data, cf, "reading would block");
/* fall through */
}
- else if(tmperr == CURLE_READ_ERROR) {
+ else if(tmperr == CURLE_RECV_ERROR) {
return CURLE_SSL_CONNECT_ERROR;
}
else {
@@ -648,37 +707,12 @@ cr_connect_nonblocking(struct Curl_cfilter *cf,
}
static CURLcode
-cr_connect_blocking(struct Curl_cfilter *cf UNUSED_PARAM,
- struct Curl_easy *data UNUSED_PARAM)
+cr_connect_blocking(struct Curl_cfilter *cf, struct Curl_easy *data)
{
bool done; /* unused */
return cr_connect_common(cf, data, true, &done);
}
-static void cr_adjust_pollset(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- struct easy_pollset *ps)
-{
- if(!cf->connected) {
- curl_socket_t sock = Curl_conn_cf_get_socket(cf->next, data);
- struct ssl_connect_data *const connssl = cf->ctx;
- struct rustls_ssl_backend_data *const backend =
- (struct rustls_ssl_backend_data *)connssl->backend;
- struct rustls_connection *rconn = NULL;
-
- (void)data;
- DEBUGASSERT(backend);
- rconn = backend->conn;
-
- if(rustls_connection_wants_write(rconn)) {
- Curl_pollset_add_out(data, ps, sock);
- }
- if(rustls_connection_wants_read(rconn)) {
- Curl_pollset_add_in(data, ps, sock);
- }
- }
-}
-
static void *
cr_get_internals(struct ssl_connect_data *connssl,
CURLINFO info UNUSED_PARAM)
@@ -699,8 +733,8 @@ cr_close(struct Curl_cfilter *cf, struct Curl_easy *data)
ssize_t n = 0;
DEBUGASSERT(backend);
-
if(backend->conn && !connssl->peer_closed) {
+ CURL_TRC_CF(data, cf, "closing connection, send notify");
rustls_connection_send_close_notify(backend->conn);
n = cr_send(cf, data, NULL, 0, &tmperr);
if(n < 0) {
@@ -725,7 +759,6 @@ static size_t cr_version(char *buffer, size_t size)
const struct Curl_ssl Curl_ssl_rustls = {
{ CURLSSLBACKEND_RUSTLS, "rustls" },
SSLSUPP_CAINFO_BLOB | /* supports */
- SSLSUPP_TLS13_CIPHERSUITES |
SSLSUPP_HTTPS_PROXY,
sizeof(struct rustls_ssl_backend_data),
@@ -739,11 +772,10 @@ const struct Curl_ssl Curl_ssl_rustls = {
Curl_none_cert_status_request, /* cert_status_request */
cr_connect_blocking, /* connect */
cr_connect_nonblocking, /* connect_nonblocking */
- cr_adjust_pollset, /* adjust_pollset */
+ Curl_ssl_adjust_pollset, /* adjust_pollset */
cr_get_internals, /* get_internals */
cr_close, /* close_one */
Curl_none_close_all, /* close_all */
- Curl_none_session_free, /* session_free */
Curl_none_set_engine, /* set_engine */
Curl_none_set_engine_default, /* set_engine_default */
Curl_none_engines_list, /* engines_list */
diff --git a/libs/libcurl/src/vtls/schannel.c b/libs/libcurl/src/vtls/schannel.c
index d63d321bf3..d172b567c4 100644
--- a/libs/libcurl/src/vtls/schannel.c
+++ b/libs/libcurl/src/vtls/schannel.c
@@ -1071,7 +1071,7 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
DEBUGASSERT(backend);
DEBUGF(infof(data,
"schannel: SSL/TLS connection with %s port %d (step 1/3)",
- connssl->peer.hostname, connssl->port));
+ connssl->peer.hostname, connssl->peer.port));
if(curlx_verify_windows_version(5, 1, 0, PLATFORM_WINNT,
VERSION_LESS_THAN_EQUAL)) {
@@ -1129,7 +1129,8 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
/* check for an existing reusable credential handle */
if(ssl_config->primary.sessionid) {
Curl_ssl_sessionid_lock(data);
- if(!Curl_ssl_getsessionid(cf, data, (void **)&old_cred, NULL)) {
+ if(!Curl_ssl_getsessionid(cf, data, &connssl->peer,
+ (void **)&old_cred, NULL)) {
backend->cred = old_cred;
DEBUGF(infof(data, "schannel: reusing existing credential handle"));
@@ -1335,7 +1336,7 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
DEBUGF(infof(data,
"schannel: SSL/TLS connection with %s port %d (step 2/3)",
- connssl->peer.hostname, connssl->port));
+ connssl->peer.hostname, connssl->peer.port));
if(!backend->cred || !backend->ctxt)
return CURLE_SSL_CONNECT_ERROR;
@@ -1569,9 +1570,13 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
DEBUGF(infof(data, "schannel: SSL/TLS handshake complete"));
}
+#ifndef CURL_DISABLE_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];
+#endif
if(pubkey_ptr) {
result = schannel_pkp_pin_peer_pubkey(cf, data, pubkey_ptr);
if(result) {
@@ -1670,6 +1675,28 @@ add_cert_to_certinfo(const CERT_CONTEXT *ccert_context, bool reverse_order,
return args->result == CURLE_OK;
}
+static void schannel_session_free(void *sessionid, size_t idsize)
+{
+ /* this is expected to be called under sessionid lock */
+ struct Curl_schannel_cred *cred = sessionid;
+
+ (void)idsize;
+ if(cred) {
+ cred->refcount--;
+ if(cred->refcount == 0) {
+ s_pSecFn->FreeCredentialsHandle(&cred->cred_handle);
+ curlx_unicodefree(cred->sni_hostname);
+#ifdef HAS_CLIENT_CERT_PATH
+ if(cred->client_cert_store) {
+ CertCloseStore(cred->client_cert_store, 0);
+ cred->client_cert_store = NULL;
+ }
+#endif
+ Curl_safefree(cred);
+ }
+ }
+}
+
static CURLcode
schannel_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
{
@@ -1689,7 +1716,7 @@ schannel_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
DEBUGF(infof(data,
"schannel: SSL/TLS connection with %s port %d (step 3/3)",
- connssl->peer.hostname, connssl->port));
+ connssl->peer.hostname, connssl->peer.port));
if(!backend->cred)
return CURLE_SSL_CONNECT_ERROR;
@@ -1747,11 +1774,11 @@ schannel_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
/* save the current session data for possible reuse */
if(ssl_config->primary.sessionid) {
bool incache;
- bool added = FALSE;
struct Curl_schannel_cred *old_cred = NULL;
Curl_ssl_sessionid_lock(data);
- incache = !(Curl_ssl_getsessionid(cf, data, (void **)&old_cred, NULL));
+ incache = !(Curl_ssl_getsessionid(cf, data, &connssl->peer,
+ (void **)&old_cred, NULL));
if(incache) {
if(old_cred != backend->cred) {
DEBUGF(infof(data,
@@ -1762,20 +1789,15 @@ schannel_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
}
}
if(!incache) {
- result = Curl_ssl_addsessionid(cf, data, backend->cred,
+ /* Up ref count since call takes ownership */
+ backend->cred->refcount++;
+ result = Curl_ssl_addsessionid(cf, data, &connssl->peer, backend->cred,
sizeof(struct Curl_schannel_cred),
- &added);
+ schannel_session_free);
if(result) {
Curl_ssl_sessionid_unlock(data);
- failf(data, "schannel: failed to store credential handle");
return result;
}
- else if(added) {
- /* this cred session is now also referenced by sessionid cache */
- backend->cred->refcount++;
- DEBUGF(infof(data,
- "schannel: stored credential handle in session cache"));
- }
}
Curl_ssl_sessionid_unlock(data);
}
@@ -2450,27 +2472,6 @@ static bool schannel_data_pending(struct Curl_cfilter *cf,
return FALSE;
}
-static void schannel_session_free(void *ptr)
-{
- /* this is expected to be called under sessionid lock */
- struct Curl_schannel_cred *cred = ptr;
-
- if(cred) {
- cred->refcount--;
- if(cred->refcount == 0) {
- s_pSecFn->FreeCredentialsHandle(&cred->cred_handle);
- curlx_unicodefree(cred->sni_hostname);
-#ifdef HAS_CLIENT_CERT_PATH
- if(cred->client_cert_store) {
- CertCloseStore(cred->client_cert_store, 0);
- cred->client_cert_store = NULL;
- }
-#endif
- Curl_safefree(cred);
- }
- }
-}
-
/* shut down the SSL connection and clean up related memory.
this function can be called multiple times on the same connection including
if the SSL connection failed (eg connection made but failed handshake). */
@@ -2489,7 +2490,7 @@ static int schannel_shutdown(struct Curl_cfilter *cf,
if(backend->ctxt) {
infof(data, "schannel: shutting down SSL/TLS connection with %s port %d",
- connssl->peer.hostname, connssl->port);
+ connssl->peer.hostname, connssl->peer.port);
}
if(backend->cred && backend->ctxt) {
@@ -2554,7 +2555,7 @@ static int schannel_shutdown(struct Curl_cfilter *cf,
/* free SSPI Schannel API credential handle */
if(backend->cred) {
Curl_ssl_sessionid_lock(data);
- schannel_session_free(backend->cred);
+ schannel_session_free(backend->cred, 0);
Curl_ssl_sessionid_unlock(data);
backend->cred = NULL;
}
@@ -2749,7 +2750,7 @@ HCERTSTORE Curl_schannel_get_cached_cert_store(struct Curl_cfilter *cf,
const struct Curl_easy *data)
{
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
- struct Curl_multi *multi = data->multi_easy ? data->multi_easy : data->multi;
+ struct Curl_multi *multi = data->multi;
const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
struct schannel_multi_ssl_backend_data *mbackend;
const struct ssl_general_config *cfg = &data->set.general_ssl;
@@ -2818,7 +2819,7 @@ bool Curl_schannel_set_cached_cert_store(struct Curl_cfilter *cf,
HCERTSTORE cert_store)
{
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
- struct Curl_multi *multi = data->multi_easy ? data->multi_easy : data->multi;
+ struct Curl_multi *multi = data->multi;
const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
struct schannel_multi_ssl_backend_data *mbackend;
unsigned char *CAinfo_blob_digest = NULL;
@@ -2917,7 +2918,6 @@ const struct Curl_ssl Curl_ssl_schannel = {
schannel_get_internals, /* get_internals */
schannel_close, /* close_one */
Curl_none_close_all, /* close_all */
- schannel_session_free, /* session_free */
Curl_none_set_engine, /* set_engine */
Curl_none_set_engine_default, /* set_engine_default */
Curl_none_engines_list, /* engines_list */
diff --git a/libs/libcurl/src/vtls/schannel_int.h b/libs/libcurl/src/vtls/schannel_int.h
index c460be63aa..92fbc073b0 100644
--- a/libs/libcurl/src/vtls/schannel_int.h
+++ b/libs/libcurl/src/vtls/schannel_int.h
@@ -53,6 +53,16 @@
#define CERT_ALT_NAME_IP_ADDRESS 8
#endif
+#if defined(_MSC_VER) && (_MSC_VER <= 1600)
+/* Workaround for warning:
+ 'type cast' : conversion from 'int' to 'LPCSTR' of greater size */
+#undef CERT_STORE_PROV_MEMORY
+#undef CERT_STORE_PROV_SYSTEM_A
+#undef CERT_STORE_PROV_SYSTEM_W
+#define CERT_STORE_PROV_MEMORY ((LPCSTR)(size_t)2)
+#define CERT_STORE_PROV_SYSTEM_A ((LPCSTR)(size_t)9)
+#define CERT_STORE_PROV_SYSTEM_W ((LPCSTR)(size_t)10)
+#endif
#ifndef SCH_CREDENTIALS_VERSION
diff --git a/libs/libcurl/src/vtls/sectransp.c b/libs/libcurl/src/vtls/sectransp.c
index f62c034e55..6482fb9168 100644
--- a/libs/libcurl/src/vtls/sectransp.c
+++ b/libs/libcurl/src/vtls/sectransp.c
@@ -1453,7 +1453,7 @@ static bool is_cipher_suite_strong(SSLCipherSuite suite_num)
return true;
}
-static bool is_separator(char c)
+static bool sectransp_is_separator(char c)
{
/* Return whether character is a cipher list separator. */
switch(c) {
@@ -1547,7 +1547,7 @@ static CURLcode sectransp_set_selected_ciphers(struct Curl_easy *data,
if(!ciphers)
return CURLE_OK;
- while(is_separator(*ciphers)) /* Skip initial separators. */
+ while(sectransp_is_separator(*ciphers)) /* Skip initial separators. */
ciphers++;
if(!*ciphers)
return CURLE_OK;
@@ -1561,14 +1561,14 @@ static CURLcode sectransp_set_selected_ciphers(struct Curl_easy *data,
size_t i;
/* Skip separators */
- while(is_separator(*cipher_start))
+ while(sectransp_is_separator(*cipher_start))
cipher_start++;
if(*cipher_start == '\0') {
break;
}
/* Find last position of a cipher in the ciphers string */
cipher_end = cipher_start;
- while(*cipher_end != '\0' && !is_separator(*cipher_end)) {
+ while(*cipher_end != '\0' && !sectransp_is_separator(*cipher_end)) {
++cipher_end;
}
@@ -1636,6 +1636,18 @@ static CURLcode sectransp_set_selected_ciphers(struct Curl_easy *data,
return CURLE_OK;
}
+static void sectransp_session_free(void *sessionid, size_t idsize)
+{
+ /* ST, as of iOS 5 and Mountain Lion, has no public method of deleting a
+ cached session ID inside the Security framework. There is a private
+ function that does this, but I don't want to have to explain to you why I
+ got your application rejected from the App Store due to the use of a
+ private API, so the best we can do is free up our own char array that we
+ created way back in sectransp_connect_step1... */
+ (void)idsize;
+ Curl_safefree(sessionid);
+}
+
static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
@@ -2047,8 +2059,8 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
size_t ssl_sessionid_len;
Curl_ssl_sessionid_lock(data);
- if(!Curl_ssl_getsessionid(cf, data, (void **)&ssl_sessionid,
- &ssl_sessionid_len)) {
+ if(!Curl_ssl_getsessionid(cf, data, &connssl->peer,
+ (void **)&ssl_sessionid, &ssl_sessionid_len)) {
/* we got a session id, use it! */
err = SSLSetPeerID(backend->ssl_ctx, ssl_sessionid, ssl_sessionid_len);
Curl_ssl_sessionid_unlock(data);
@@ -2067,7 +2079,7 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
aprintf("%s:%d:%d:%s:%d",
ssl_cafile ? ssl_cafile : "(blob memory)",
verifypeer, conn_config->verifyhost, connssl->peer.hostname,
- connssl->port);
+ connssl->peer.port);
ssl_sessionid_len = strlen(ssl_sessionid);
err = SSLSetPeerID(backend->ssl_ctx, ssl_sessionid, ssl_sessionid_len);
@@ -2077,13 +2089,12 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
return CURLE_SSL_CONNECT_ERROR;
}
- result = Curl_ssl_addsessionid(cf, data, ssl_sessionid,
- ssl_sessionid_len, NULL);
+ result = Curl_ssl_addsessionid(cf, data, &connssl->peer, ssl_sessionid,
+ ssl_sessionid_len,
+ sectransp_session_free);
Curl_ssl_sessionid_unlock(data);
- if(result) {
- failf(data, "failed to store ssl session");
+ if(result)
return result;
- }
}
}
@@ -3225,17 +3236,6 @@ static int sectransp_shutdown(struct Curl_cfilter *cf,
return rc;
}
-static void sectransp_session_free(void *ptr)
-{
- /* ST, as of iOS 5 and Mountain Lion, has no public method of deleting a
- cached session ID inside the Security framework. There is a private
- function that does this, but I don't want to have to explain to you why I
- got your application rejected from the App Store due to the use of a
- private API, so the best we can do is free up our own char array that we
- created way back in sectransp_connect_step1... */
- Curl_safefree(ptr);
-}
-
static size_t sectransp_version(char *buffer, size_t size)
{
return msnprintf(buffer, size, "SecureTransport");
@@ -3469,7 +3469,6 @@ const struct Curl_ssl Curl_ssl_sectransp = {
sectransp_get_internals, /* get_internals */
sectransp_close, /* close_one */
Curl_none_close_all, /* close_all */
- sectransp_session_free, /* session_free */
Curl_none_set_engine, /* set_engine */
Curl_none_set_engine_default, /* set_engine_default */
Curl_none_engines_list, /* engines_list */
diff --git a/libs/libcurl/src/vtls/vtls.c b/libs/libcurl/src/vtls/vtls.c
index e4fcb0dd83..f4633a5f1c 100644
--- a/libs/libcurl/src/vtls/vtls.c
+++ b/libs/libcurl/src/vtls/vtls.c
@@ -534,10 +534,10 @@ void Curl_ssl_sessionid_unlock(struct Curl_easy *data)
*/
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 */
{
- struct ssl_connect_data *connssl = cf->ctx;
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
struct Curl_ssl_session *check;
@@ -567,14 +567,15 @@ bool Curl_ssl_getsessionid(struct Curl_cfilter *cf,
if(!check->sessionid)
/* not session ID means blank entry */
continue;
- if(strcasecompare(connssl->peer.hostname, check->name) &&
+ if(strcasecompare(peer->hostname, check->name) &&
((!cf->conn->bits.conn_to_host && !check->conn_to_host) ||
(cf->conn->bits.conn_to_host && check->conn_to_host &&
strcasecompare(cf->conn->conn_to_host.name, check->conn_to_host))) &&
((!cf->conn->bits.conn_to_port && check->conn_to_port == -1) ||
(cf->conn->bits.conn_to_port && check->conn_to_port != -1 &&
cf->conn->conn_to_port == check->conn_to_port)) &&
- (connssl->port == check->remote_port) &&
+ (peer->port == check->remote_port) &&
+ (peer->transport == check->transport) &&
strcasecompare(cf->conn->handler->scheme, check->scheme) &&
match_ssl_primary_config(data, conn_config, &check->ssl_config)) {
/* yes, we have a session ID! */
@@ -591,8 +592,7 @@ bool Curl_ssl_getsessionid(struct Curl_cfilter *cf,
DEBUGF(infof(data, "%s Session ID in cache for %s %s://%s:%d",
no_match? "Didn't find": "Found",
Curl_ssl_cf_is_proxy(cf) ? "proxy" : "host",
- cf->conn->handler->scheme, connssl->peer.hostname,
- connssl->port));
+ cf->conn->handler->scheme, peer->hostname, peer->port));
return no_match;
}
@@ -605,9 +605,10 @@ void Curl_ssl_kill_session(struct Curl_ssl_session *session)
/* defensive check */
/* free the ID the SSL-layer specific way */
- Curl_ssl->session_free(session->sessionid);
+ session->sessionid_free(session->sessionid, session->idsize);
session->sessionid = NULL;
+ session->sessionid_free = NULL;
session->age = 0; /* fresh */
Curl_free_primary_ssl_config(&session->ssl_config);
@@ -642,45 +643,44 @@ void Curl_ssl_delsessionid(struct Curl_easy *data, void *ssl_sessionid)
*/
CURLcode Curl_ssl_addsessionid(struct Curl_cfilter *cf,
struct Curl_easy *data,
+ const struct ssl_peer *peer,
void *ssl_sessionid,
size_t idsize,
- bool *added)
+ Curl_ssl_sessionid_dtor *sessionid_free_cb)
{
- struct ssl_connect_data *connssl = cf->ctx;
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);
size_t i;
struct Curl_ssl_session *store;
long oldest_age;
- char *clone_host;
- char *clone_conn_to_host;
+ char *clone_host = NULL;
+ char *clone_conn_to_host = NULL;
int conn_to_port;
long *general_age;
+ CURLcode result = CURLE_OUT_OF_MEMORY;
- if(added)
- *added = FALSE;
+ DEBUGASSERT(ssl_sessionid);
+ DEBUGASSERT(sessionid_free_cb);
- if(!data->state.session)
+ if(!data->state.session) {
+ sessionid_free_cb(ssl_sessionid, idsize);
return CURLE_OK;
+ }
store = &data->state.session[0];
oldest_age = data->state.session[0].age; /* zero if unused */
- (void)ssl_config;
DEBUGASSERT(ssl_config->primary.sessionid);
+ (void)ssl_config;
- clone_host = strdup(connssl->peer.hostname);
+ clone_host = strdup(peer->hostname);
if(!clone_host)
- return CURLE_OUT_OF_MEMORY; /* bail out */
+ goto out;
if(cf->conn->bits.conn_to_host) {
clone_conn_to_host = strdup(cf->conn->conn_to_host.name);
- if(!clone_conn_to_host) {
- free(clone_host);
- return CURLE_OUT_OF_MEMORY; /* bail out */
- }
+ if(!clone_conn_to_host)
+ goto out;
}
- else
- clone_conn_to_host = NULL;
if(cf->conn->bits.conn_to_port)
conn_to_port = cf->conn->conn_to_port;
@@ -713,33 +713,43 @@ CURLcode Curl_ssl_addsessionid(struct Curl_cfilter *cf,
store = &data->state.session[i]; /* use this slot */
/* now init the session struct wisely */
+ if(!clone_ssl_primary_config(conn_config, &store->ssl_config)) {
+ Curl_free_primary_ssl_config(&store->ssl_config);
+ store->sessionid = NULL; /* let caller free sessionid */
+ goto out;
+ }
store->sessionid = ssl_sessionid;
store->idsize = idsize;
+ store->sessionid_free = sessionid_free_cb;
store->age = *general_age; /* set current age */
/* free it if there's one already present */
free(store->name);
free(store->conn_to_host);
store->name = clone_host; /* clone host name */
+ clone_host = NULL;
store->conn_to_host = clone_conn_to_host; /* clone connect to host name */
+ clone_conn_to_host = NULL;
store->conn_to_port = conn_to_port; /* connect to port number */
/* port number */
- store->remote_port = connssl->port;
+ store->remote_port = peer->port;
store->scheme = cf->conn->handler->scheme;
+ store->transport = peer->transport;
- if(!clone_ssl_primary_config(conn_config, &store->ssl_config)) {
- Curl_free_primary_ssl_config(&store->ssl_config);
- store->sessionid = NULL; /* let caller free sessionid */
- free(clone_host);
- free(clone_conn_to_host);
- return CURLE_OUT_OF_MEMORY;
- }
-
- if(added)
- *added = TRUE;
+ result = CURLE_OK;
- DEBUGF(infof(data, "Added Session ID to cache for %s://%s:%d [%s]",
- store->scheme, store->name, store->remote_port,
- Curl_ssl_cf_is_proxy(cf) ? "PROXY" : "server"));
+out:
+ free(clone_host);
+ free(clone_conn_to_host);
+ if(result) {
+ failf(data, "Failed to add Session ID to cache for %s://%s:%d [%s]",
+ store->scheme, store->name, store->remote_port,
+ Curl_ssl_cf_is_proxy(cf) ? "PROXY" : "server");
+ sessionid_free_cb(ssl_sessionid, idsize);
+ return result;
+ }
+ CURL_TRC_CF(data, cf, "Added Session ID to cache for %s://%s:%d [%s]",
+ store->scheme, store->name, store->remote_port,
+ Curl_ssl_cf_is_proxy(cf) ? "PROXY" : "server");
return CURLE_OK;
}
@@ -1322,7 +1332,6 @@ static const struct Curl_ssl Curl_ssl_multi = {
multissl_get_internals, /* get_internals */
multissl_close, /* close_one */
Curl_none_close_all, /* close_all */
- Curl_none_session_free, /* session_free */
Curl_none_set_engine, /* set_engine */
Curl_none_set_engine_default, /* set_engine_default */
Curl_none_engines_list, /* engines_list */
@@ -1533,14 +1542,14 @@ static void cf_close(struct Curl_cfilter *cf, struct Curl_easy *data)
static ssl_peer_type get_peer_type(const char *hostname)
{
if(hostname && hostname[0]) {
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
struct in6_addr addr;
#else
struct in_addr addr;
#endif
if(Curl_inet_pton(AF_INET, hostname, &addr))
return CURL_SSL_PEER_IPV4;
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
else if(Curl_inet_pton(AF_INET6, hostname, &addr)) {
return CURL_SSL_PEER_IPV6;
}
@@ -1549,9 +1558,9 @@ static ssl_peer_type get_peer_type(const char *hostname)
return CURL_SSL_PEER_DNS;
}
-CURLcode Curl_ssl_peer_init(struct ssl_peer *peer, struct Curl_cfilter *cf)
+CURLcode Curl_ssl_peer_init(struct ssl_peer *peer, struct Curl_cfilter *cf,
+ int transport)
{
- struct ssl_connect_data *connssl = cf->ctx;
const char *ehostname, *edispname;
int eport;
@@ -1594,7 +1603,6 @@ CURLcode Curl_ssl_peer_init(struct ssl_peer *peer, struct Curl_cfilter *cf)
}
}
- peer->sni = NULL;
peer->type = get_peer_type(peer->hostname);
if(peer->type == CURL_SSL_PEER_DNS && peer->hostname[0]) {
/* not an IP address, normalize according to RCC 6066 ch. 3,
@@ -1614,7 +1622,8 @@ CURLcode Curl_ssl_peer_init(struct ssl_peer *peer, struct Curl_cfilter *cf)
}
}
- connssl->port = eport;
+ peer->port = eport;
+ peer->transport = transport;
return CURLE_OK;
}
@@ -1667,7 +1676,7 @@ static CURLcode ssl_cf_connect(struct Curl_cfilter *cf,
goto out;
*done = FALSE;
- result = Curl_ssl_peer_init(&connssl->peer, cf);
+ result = Curl_ssl_peer_init(&connssl->peer, cf, TRNSPRT_TCP);
if(result)
goto out;
@@ -1857,7 +1866,7 @@ struct Curl_cftype Curl_cft_ssl = {
struct Curl_cftype Curl_cft_ssl_proxy = {
"SSL-PROXY",
- CF_TYPE_SSL,
+ CF_TYPE_SSL|CF_TYPE_PROXY,
CURL_LOG_LVL_NONE,
ssl_cf_destroy,
ssl_cf_connect,
@@ -2033,12 +2042,7 @@ CURLcode Curl_ssl_cfilter_remove(struct Curl_easy *data,
bool Curl_ssl_cf_is_proxy(struct Curl_cfilter *cf)
{
-#ifndef CURL_DISABLE_PROXY
- return (cf->cft == &Curl_cft_ssl_proxy);
-#else
- (void)cf;
- return FALSE;
-#endif
+ return (cf->cft->flags & CF_TYPE_SSL) && (cf->cft->flags & CF_TYPE_PROXY);
}
struct ssl_config_data *
diff --git a/libs/libcurl/src/vtls/vtls.h b/libs/libcurl/src/vtls/vtls.h
index 0bfefd0502..4eedc707e4 100644
--- a/libs/libcurl/src/vtls/vtls.h
+++ b/libs/libcurl/src/vtls/vtls.h
@@ -37,6 +37,7 @@ struct Curl_ssl_session;
#define SSLSUPP_HTTPS_PROXY (1<<4) /* supports access via HTTPS proxies */
#define SSLSUPP_TLS13_CIPHERSUITES (1<<5) /* supports TLS 1.3 ciphersuites */
#define SSLSUPP_CAINFO_BLOB (1<<6)
+#define SSLSUPP_ECH (1<<7)
#define ALPN_ACCEPTED "ALPN: server accepted "
@@ -107,7 +108,8 @@ void Curl_ssl_conn_config_update(struct Curl_easy *data, bool for_proxy);
/**
* Init SSL peer information for filter. Can be called repeatedly.
*/
-CURLcode Curl_ssl_peer_init(struct ssl_peer *peer, struct Curl_cfilter *cf);
+CURLcode Curl_ssl_peer_init(struct ssl_peer *peer,
+ struct Curl_cfilter *cf, int transport);
/**
* Free all allocated data and reset peer information.
*/
diff --git a/libs/libcurl/src/vtls/vtls_int.h b/libs/libcurl/src/vtls/vtls_int.h
index 563a5d11a9..d9f73f720d 100644
--- a/libs/libcurl/src/vtls/vtls_int.h
+++ b/libs/libcurl/src/vtls/vtls_int.h
@@ -73,9 +73,7 @@ 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 */
- int port; /* remote port at origin */
BIT(use_alpn); /* if ALPN shall be used in handshake */
- BIT(reused_session); /* session-ID was reused for this */
BIT(peer_closed); /* peer has closed connection */
};
@@ -125,7 +123,6 @@ struct Curl_ssl {
void *(*get_internals)(struct ssl_connect_data *connssl, CURLINFO info);
void (*close)(struct Curl_cfilter *cf, struct Curl_easy *data);
void (*close_all)(struct Curl_easy *data);
- void (*session_free)(void *ptr);
CURLcode (*set_engine)(struct Curl_easy *data, const char *engine);
CURLcode (*set_engine_default)(struct Curl_easy *data);
@@ -181,18 +178,22 @@ bool Curl_ssl_cf_is_proxy(struct Curl_cfilter *cf);
*/
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 */
/* add a new session ID
* Sessionid mutex must be locked (see Curl_ssl_sessionid_lock).
* Caller must ensure that it has properly shared ownership of this sessionid
* object with cache (e.g. incrementing refcount on success)
+ * Call takes ownership of `ssl_sessionid`, using `sessionid_free_cb`
+ * to destroy it in case of failure or later removal.
*/
CURLcode Curl_ssl_addsessionid(struct Curl_cfilter *cf,
struct Curl_easy *data,
+ const struct ssl_peer *peer,
void *ssl_sessionid,
size_t idsize,
- bool *added);
+ Curl_ssl_sessionid_dtor *sessionid_free_cb);
#include "openssl.h" /* OpenSSL versions */
#include "gtls.h" /* GnuTLS versions */
diff --git a/libs/libcurl/src/vtls/wolfssl.c b/libs/libcurl/src/vtls/wolfssl.c
index fe845c5752..53e7f0e895 100644
--- a/libs/libcurl/src/vtls/wolfssl.c
+++ b/libs/libcurl/src/vtls/wolfssl.c
@@ -74,6 +74,14 @@
#include "curl_memory.h"
#include "memdebug.h"
+#ifdef USE_ECH
+# include "curl_base64.h"
+# define ECH_ENABLED(__data__) \
+ (__data__->set.tls_ech && \
+ !(__data__->set.tls_ech & CURLECH_DISABLE)\
+ )
+#endif /* USE_ECH */
+
/* KEEP_PEER_CERT is a product of the presence of build time symbol
OPENSSL_EXTRA without NO_CERTS, depending on the version. KEEP_PEER_CERT is
in wolfSSL's settings.h, and the latter two are build time symbols in
@@ -409,11 +417,11 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
#if defined(WOLFSSL_ALLOW_TLSV10) && !defined(NO_OLD_TLS)
req_method = TLSv1_client_method();
use_sni(TRUE);
+ break;
#else
failf(data, "wolfSSL does not support TLS 1.0");
return CURLE_NOT_BUILT_IN;
#endif
- break;
case CURL_SSLVERSION_TLSv1_1:
#ifndef NO_OLD_TLS
req_method = TLSv1_1_client_method();
@@ -481,6 +489,7 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
return CURLE_SSL_CONNECT_ERROR;
}
#endif
+ FALLTHROUGH();
default:
break;
}
@@ -711,7 +720,8 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
void *ssl_sessionid = NULL;
Curl_ssl_sessionid_lock(data);
- if(!Curl_ssl_getsessionid(cf, data, &ssl_sessionid, NULL)) {
+ 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);
@@ -723,6 +733,82 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
Curl_ssl_sessionid_unlock(data);
}
+#ifdef USE_ECH
+ if(ECH_ENABLED(data)) {
+ int trying_ech_now = 0;
+
+ if(data->set.str[STRING_ECH_PUBLIC]) {
+ infof(data, "ECH: outername not (yet) supported with WolfSSL");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ if(data->set.tls_ech == CURLECH_GREASE) {
+ infof(data, "ECH: GREASE'd ECH not yet supported for wolfSSL");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ if(data->set.tls_ech & CURLECH_CLA_CFG
+ && data->set.str[STRING_ECH_CONFIG]) {
+ char *b64val = data->set.str[STRING_ECH_CONFIG];
+ word32 b64len = 0;
+
+ b64len = (word32) strlen(b64val);
+ if(b64len
+ && wolfSSL_SetEchConfigsBase64(backend->handle, b64val, b64len)
+ != WOLFSSL_SUCCESS) {
+ if(data->set.tls_ech & CURLECH_HARD)
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ else {
+ trying_ech_now = 1;
+ infof(data, "ECH: ECHConfig from command line");
+ }
+ }
+ else {
+ struct Curl_dns_entry *dns = NULL;
+
+ dns = Curl_fetch_addr(data, connssl->peer.hostname, connssl->peer.port);
+ if(!dns) {
+ infof(data, "ECH: requested but no DNS info available");
+ if(data->set.tls_ech & CURLECH_HARD)
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ else {
+ struct Curl_https_rrinfo *rinfo = NULL;
+
+ rinfo = dns->hinfo;
+ if(rinfo && rinfo->echconfiglist) {
+ unsigned char *ecl = rinfo->echconfiglist;
+ size_t elen = rinfo->echconfiglist_len;
+
+ infof(data, "ECH: ECHConfig from DoH HTTPS RR");
+ if(wolfSSL_SetEchConfigs(backend->handle, ecl, (word32) elen) !=
+ WOLFSSL_SUCCESS) {
+ infof(data, "ECH: wolfSSL_SetEchConfigs failed");
+ if(data->set.tls_ech & CURLECH_HARD)
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ else {
+ trying_ech_now = 1;
+ infof(data, "ECH: imported ECHConfigList of length %ld", elen);
+ }
+ }
+ else {
+ infof(data, "ECH: requested but no ECHConfig available");
+ if(data->set.tls_ech & CURLECH_HARD)
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ Curl_resolv_unlock(data, dns);
+ }
+ }
+
+ if(trying_ech_now
+ && SSL_set_min_proto_version(backend->handle, TLS1_3_VERSION) != 1) {
+ infof(data, "ECH: Can't force TLSv1.3 [ERROR]");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ }
+#endif /* USE_ECH */
+
#ifdef USE_BIO_CHAIN
{
WOLFSSL_BIO *bio;
@@ -756,9 +842,13 @@ wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
struct wolfssl_ssl_backend_data *backend =
(struct wolfssl_ssl_backend_data *)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]:
data->set.str[STRING_SSL_PINNEDPUBLICKEY];
+#else
+ const char * const pinnedpubkey = data->set.str[STRING_SSL_PINNEDPUBLICKEY];
+#endif
DEBUGASSERT(backend);
@@ -853,6 +943,31 @@ wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
}
}
#endif
+#ifdef USE_ECH
+ else if(-1 == detail) {
+ /* try access a retry_config ECHConfigList for tracing */
+ byte echConfigs[1000];
+ word32 echConfigsLen = 1000;
+ int rv = 0;
+
+ /* this currently doesn't produce the retry_configs */
+ rv = wolfSSL_GetEchConfigs(backend->handle, echConfigs,
+ &echConfigsLen);
+ if(rv != WOLFSSL_SUCCESS) {
+ infof(data, "Failed to get ECHConfigs");
+ }
+ else {
+ char *b64str = NULL;
+ size_t blen = 0;
+
+ rv = Curl_base64_encode((const char *)echConfigs, echConfigsLen,
+ &b64str, &blen);
+ if(!rv && b64str)
+ infof(data, "ECH: (not yet) retry_configs %s", b64str);
+ free(b64str);
+ }
+ }
+#endif
else if(backend->io_result == CURLE_AGAIN) {
return CURLE_OK;
}
@@ -898,6 +1013,7 @@ wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
pinnedpubkey,
(const unsigned char *)pubkey->header,
(size_t)(pubkey->end - pubkey->header));
+ wolfSSL_FreeX509(x509);
if(result) {
failf(data, "SSL: public key does not match pinned public key");
return result;
@@ -942,6 +1058,13 @@ wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
}
+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)
{
@@ -955,40 +1078,27 @@ wolfssl_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
DEBUGASSERT(backend);
if(ssl_config->primary.sessionid) {
- bool incache;
- bool added = FALSE;
- void *old_ssl_sessionid = NULL;
/* wolfSSL_get1_session allocates memory that has to be freed. */
WOLFSSL_SESSION *our_ssl_sessionid = wolfSSL_get1_session(backend->handle);
if(our_ssl_sessionid) {
+ void *old_ssl_sessionid = NULL;
+ bool incache;
Curl_ssl_sessionid_lock(data);
- incache = !(Curl_ssl_getsessionid(cf, data, &old_ssl_sessionid, NULL));
+ incache = !(Curl_ssl_getsessionid(cf, data, &connssl->peer,
+ &old_ssl_sessionid, NULL));
if(incache) {
- if(old_ssl_sessionid != our_ssl_sessionid) {
- infof(data, "old SSL session ID is stale, removing");
- Curl_ssl_delsessionid(data, old_ssl_sessionid);
- incache = FALSE;
- }
+ Curl_ssl_delsessionid(data, old_ssl_sessionid);
}
- if(!incache) {
- result = Curl_ssl_addsessionid(cf, data, our_ssl_sessionid, 0, NULL);
- if(result) {
- Curl_ssl_sessionid_unlock(data);
- wolfSSL_SESSION_free(our_ssl_sessionid);
- failf(data, "failed to store ssl session");
- return result;
- }
- else {
- added = TRUE;
- }
- }
+ /* call takes ownership of `our_ssl_sessionid` */
+ result = Curl_ssl_addsessionid(cf, data, &connssl->peer,
+ our_ssl_sessionid, 0,
+ wolfssl_session_free);
Curl_ssl_sessionid_unlock(data);
-
- if(!added) {
- /* If the session info wasn't added to the cache, free our copy. */
- wolfSSL_SESSION_free(our_ssl_sessionid);
+ if(result) {
+ failf(data, "failed to store ssl session");
+ return result;
}
}
}
@@ -1122,12 +1232,6 @@ static ssize_t wolfssl_recv(struct Curl_cfilter *cf,
}
-static void wolfssl_session_free(void *ptr)
-{
- wolfSSL_SESSION_free(ptr);
-}
-
-
static size_t wolfssl_version(char *buffer, size_t size)
{
#if LIBWOLFSSL_VERSION_HEX >= 0x03006000
@@ -1386,6 +1490,9 @@ const struct Curl_ssl Curl_ssl_wolfssl = {
#endif
SSLSUPP_CA_PATH |
SSLSUPP_CAINFO_BLOB |
+#ifdef USE_ECH
+ SSLSUPP_ECH |
+#endif
SSLSUPP_SSL_CTX,
sizeof(struct wolfssl_ssl_backend_data),
@@ -1404,7 +1511,6 @@ const struct Curl_ssl Curl_ssl_wolfssl = {
wolfssl_get_internals, /* get_internals */
wolfssl_close, /* close_one */
Curl_none_close_all, /* close_all */
- wolfssl_session_free, /* session_free */
Curl_none_set_engine, /* set_engine */
Curl_none_set_engine_default, /* set_engine_default */
Curl_none_engines_list, /* engines_list */
diff --git a/libs/libcurl/src/vtls/x509asn1.c b/libs/libcurl/src/vtls/x509asn1.c
index 50a5fb5e9f..0887b34049 100644
--- a/libs/libcurl/src/vtls/x509asn1.c
+++ b/libs/libcurl/src/vtls/x509asn1.c
@@ -160,6 +160,7 @@ static const struct Curl_OID OIDtable[] = {
{ "2.16.840.1.101.3.4.2.1", "sha256" },
{ "2.16.840.1.101.3.4.2.2", "sha384" },
{ "2.16.840.1.101.3.4.2.3", "sha512" },
+ { "1.2.840.113549.1.9.2", "unstructuredName" },
{ (const char *) NULL, (const char *) NULL }
};
@@ -467,6 +468,8 @@ static CURLcode OID2str(struct dynbuf *store,
const struct Curl_OID *op = searchOID(Curl_dyn_ptr(&buf));
if(op)
result = Curl_dyn_add(store, op->textoid);
+ else
+ result = CURLE_BAD_FUNCTION_ARGUMENT;
Curl_dyn_free(&buf);
}
}