summaryrefslogtreecommitdiff
path: root/libs/libcurl/src/vtls
diff options
context:
space:
mode:
authordartraiden <wowemuh@gmail.com>2024-07-25 00:50:30 +0300
committerdartraiden <wowemuh@gmail.com>2024-07-25 02:38:23 +0300
commit67a42fc97c64c83e02f6f0d68e5a4a22c71138d3 (patch)
tree21eb2d53a9cd7e645a58662dee11588f56057eee /libs/libcurl/src/vtls
parent0a365886f2d06750a707037d894e1492988eb53c (diff)
libcurl: update to 8.9.0
Diffstat (limited to 'libs/libcurl/src/vtls')
-rw-r--r--libs/libcurl/src/vtls/bearssl.c90
-rw-r--r--libs/libcurl/src/vtls/cipher_suite.c182
-rw-r--r--libs/libcurl/src/vtls/cipher_suite.h5
-rw-r--r--libs/libcurl/src/vtls/gtls.c498
-rw-r--r--libs/libcurl/src/vtls/gtls.h18
-rw-r--r--libs/libcurl/src/vtls/hostcheck.c2
-rw-r--r--libs/libcurl/src/vtls/hostcheck.h2
-rw-r--r--libs/libcurl/src/vtls/mbedtls.c325
-rw-r--r--libs/libcurl/src/vtls/openssl.c681
-rw-r--r--libs/libcurl/src/vtls/openssl.h5
-rw-r--r--libs/libcurl/src/vtls/rustls.c123
-rw-r--r--libs/libcurl/src/vtls/schannel.c336
-rw-r--r--libs/libcurl/src/vtls/schannel_int.h11
-rw-r--r--libs/libcurl/src/vtls/schannel_verify.c19
-rw-r--r--libs/libcurl/src/vtls/sectransp.c1421
-rw-r--r--libs/libcurl/src/vtls/vtls.c222
-rw-r--r--libs/libcurl/src/vtls/vtls.h10
-rw-r--r--libs/libcurl/src/vtls/vtls_int.h58
-rw-r--r--libs/libcurl/src/vtls/wolfssl.c648
-rw-r--r--libs/libcurl/src/vtls/wolfssl.h17
-rw-r--r--libs/libcurl/src/vtls/x509asn1.c34
-rw-r--r--libs/libcurl/src/vtls/x509asn1.h3
22 files changed, 2585 insertions, 2125 deletions
diff --git a/libs/libcurl/src/vtls/bearssl.c b/libs/libcurl/src/vtls/bearssl.c
index f5f6ad3756..fdbb4f648a 100644
--- a/libs/libcurl/src/vtls/bearssl.c
+++ b/libs/libcurl/src/vtls/bearssl.c
@@ -63,6 +63,7 @@ struct bearssl_ssl_backend_data {
bool active;
/* size of pending write, yet to be flushed */
size_t pending_write;
+ BIT(sent_shutdown);
};
struct cafile_parser {
@@ -327,7 +328,7 @@ static unsigned x509_end_chain(const br_x509_class **ctx)
struct x509_context *x509 = (struct x509_context *)ctx;
if(!x509->verifypeer) {
- return br_x509_decoder_last_error(&x509->decoder);
+ return (unsigned)br_x509_decoder_last_error(&x509->decoder);
}
return x509->minimal.vtable->end_chain(&x509->minimal.vtable);
@@ -583,7 +584,7 @@ static CURLcode bearssl_connect_step1(struct Curl_cfilter *cf,
backend->x509.verifyhost = verifyhost;
br_ssl_engine_set_x509(&backend->ctx.eng, &backend->x509.vtable);
- if(ssl_config->primary.sessionid) {
+ if(ssl_config->primary.cache_session) {
void *session;
CURL_TRC_CF(data, cf, "connect_step1, check session cache");
@@ -722,6 +723,8 @@ static CURLcode bearssl_run_until(struct Curl_cfilter *cf,
ret = Curl_conn_cf_send(cf->next, data, (char *)buf, len, &result);
CURL_TRC_CF(data, cf, "ssl_send(len=%zu) -> %zd, %d", len, ret, result);
if(ret <= 0) {
+ if(result == CURLE_AGAIN)
+ connssl->io_need |= CURL_SSL_IO_NEED_SEND;
return result;
}
br_ssl_engine_sendrec_ack(&backend->ctx.eng, ret);
@@ -735,6 +738,8 @@ static CURLcode bearssl_run_until(struct Curl_cfilter *cf,
return CURLE_RECV_ERROR;
}
if(ret <= 0) {
+ if(result == CURLE_AGAIN)
+ connssl->io_need |= CURL_SSL_IO_NEED_RECV;
return result;
}
br_ssl_engine_recvrec_ack(&backend->ctx.eng, ret);
@@ -813,9 +818,7 @@ static CURLcode bearssl_connect_step3(struct Curl_cfilter *cf,
proto? strlen(proto) : 0);
}
- if(ssl_config->primary.sessionid) {
- bool incache;
- void *oldsession;
+ if(ssl_config->primary.cache_session) {
br_ssl_session_parameters *session;
session = malloc(sizeof(*session));
@@ -823,13 +826,8 @@ static CURLcode bearssl_connect_step3(struct Curl_cfilter *cf,
return CURLE_OUT_OF_MEMORY;
br_ssl_engine_get_session_parameters(&backend->ctx.eng, session);
Curl_ssl_sessionid_lock(data);
- incache = !(Curl_ssl_getsessionid(cf, data, &connssl->peer,
- &oldsession, NULL));
- if(incache)
- Curl_ssl_delsessionid(data, oldsession);
-
- ret = Curl_ssl_addsessionid(cf, data, &connssl->peer, session, 0,
- bearssl_session_free);
+ ret = Curl_ssl_set_sessionid(cf, data, &connssl->peer, session, 0,
+ bearssl_session_free);
Curl_ssl_sessionid_unlock(data);
if(ret)
return ret;
@@ -925,9 +923,7 @@ static CURLcode bearssl_connect_common(struct Curl_cfilter *cf,
return ret;
}
- while(ssl_connect_2 == connssl->connecting_state ||
- ssl_connect_2_reading == connssl->connecting_state ||
- ssl_connect_2_writing == connssl->connecting_state) {
+ while(ssl_connect_2 == connssl->connecting_state) {
/* check allowed time left */
timeout_ms = Curl_timeleft(data, NULL, TRUE);
@@ -937,14 +933,13 @@ static CURLcode bearssl_connect_common(struct Curl_cfilter *cf,
return CURLE_OPERATION_TIMEDOUT;
}
- /* if ssl is expecting something, check if it's available. */
- if(ssl_connect_2_reading == connssl->connecting_state ||
- ssl_connect_2_writing == connssl->connecting_state) {
+ /* if ssl is expecting something, check if it is available. */
+ if(connssl->io_need) {
- curl_socket_t writefd = ssl_connect_2_writing ==
- connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
- curl_socket_t readfd = ssl_connect_2_reading ==
- connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
+ curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND)?
+ sockfd:CURL_SOCKET_BAD;
+ curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV)?
+ sockfd:CURL_SOCKET_BAD;
CURL_TRC_CF(data, cf, "connect_common, check socket");
what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
@@ -975,11 +970,9 @@ static CURLcode bearssl_connect_common(struct Curl_cfilter *cf,
* before step2 has completed while ensuring that a client using select()
* or epoll() will always have a valid fdset to wait on.
*/
+ connssl->io_need = CURL_SSL_IO_NEED_NONE;
ret = bearssl_connect_step2(cf, data);
- if(ret || (nonblocking &&
- (ssl_connect_2 == connssl->connecting_state ||
- ssl_connect_2_reading == connssl->connecting_state ||
- ssl_connect_2_writing == connssl->connecting_state)))
+ if(ret || (nonblocking && (ssl_connect_2 == connssl->connecting_state)))
return ret;
}
@@ -1070,20 +1063,52 @@ static void *bearssl_get_internals(struct ssl_connect_data *connssl,
return &backend->ctx;
}
-static void bearssl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
+static CURLcode bearssl_shutdown(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool send_shutdown, bool *done)
{
struct ssl_connect_data *connssl = cf->ctx;
struct bearssl_ssl_backend_data *backend =
(struct bearssl_ssl_backend_data *)connssl->backend;
- size_t i;
+ CURLcode result;
DEBUGASSERT(backend);
+ if(!backend->active || cf->shutdown) {
+ *done = TRUE;
+ return CURLE_OK;
+ }
- if(backend->active) {
- backend->active = FALSE;
+ *done = FALSE;
+ if(!backend->sent_shutdown) {
+ (void)send_shutdown; /* unknown how to suppress our close notify */
br_ssl_engine_close(&backend->ctx.eng);
- (void)bearssl_run_until(cf, data, BR_SSL_CLOSED);
+ backend->sent_shutdown = TRUE;
+ }
+
+ result = bearssl_run_until(cf, data, BR_SSL_CLOSED);
+ if(result == CURLE_OK) {
+ *done = TRUE;
}
+ else if(result == CURLE_AGAIN)
+ result = CURLE_OK;
+ else
+ CURL_TRC_CF(data, cf, "shutdown error: %d", result);
+
+ cf->shutdown = (result || *done);
+ return result;
+}
+
+static void bearssl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct bearssl_ssl_backend_data *backend =
+ (struct bearssl_ssl_backend_data *)connssl->backend;
+ size_t i;
+
+ (void)data;
+ DEBUGASSERT(backend);
+
+ backend->active = FALSE;
if(backend->anchors) {
for(i = 0; i < backend->anchors_len; ++i)
free(backend->anchors[i].dn.data);
@@ -1113,7 +1138,7 @@ const struct Curl_ssl Curl_ssl_bearssl = {
Curl_none_cleanup, /* cleanup */
bearssl_version, /* version */
Curl_none_check_cxn, /* check_cxn */
- Curl_none_shutdown, /* shutdown */
+ bearssl_shutdown, /* shutdown */
bearssl_data_pending, /* data_pending */
bearssl_random, /* random */
Curl_none_cert_status_request, /* cert_status_request */
@@ -1130,7 +1155,6 @@ const struct Curl_ssl Curl_ssl_bearssl = {
bearssl_sha256sum, /* sha256sum */
NULL, /* associate_connection */
NULL, /* disassociate_connection */
- NULL, /* free_multi_ssl_backend_data */
bearssl_recv, /* recv decrypted data */
bearssl_send, /* send data to encrypt */
};
diff --git a/libs/libcurl/src/vtls/cipher_suite.c b/libs/libcurl/src/vtls/cipher_suite.c
index 723b94d13f..76a0d424ff 100644
--- a/libs/libcurl/src/vtls/cipher_suite.c
+++ b/libs/libcurl/src/vtls/cipher_suite.c
@@ -23,7 +23,7 @@
***************************************************************************/
#include "curl_setup.h"
-#if defined(USE_MBEDTLS) || defined(USE_BEARSSL)
+#if defined(USE_SECTRANSP) || defined(USE_MBEDTLS) || defined(USE_BEARSSL)
#include "cipher_suite.h"
#include "curl_printf.h"
#include "strcase.h"
@@ -33,7 +33,7 @@
* 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.
+ * (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.
@@ -42,7 +42,7 @@
/*
* 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
+ * because it does not support "standard" OpenSSL cipher suite
* names, nor IANA names.
*/
@@ -89,6 +89,21 @@ static const char *cs_txt =
"CAMELLIA128" "\0"
"CAMELLIA256" "\0"
#endif
+#if defined(USE_SECTRANSP)
+ "40" "\0"
+ "ADH" "\0"
+ "AECDH" "\0"
+ "anon" "\0"
+ "DES40" "\0"
+ "DH" "\0"
+ "DSS" "\0"
+ "EDH" "\0"
+ "EXP" "\0"
+ "EXPORT" "\0"
+ "IDEA" "\0"
+ "RC2" "\0"
+ "RC4" "\0"
+#endif
;
/* Indexes of above cs_txt */
enum {
@@ -130,6 +145,21 @@ enum {
CS_TXT_IDX_CAMELLIA128,
CS_TXT_IDX_CAMELLIA256,
#endif
+#if defined(USE_SECTRANSP)
+ CS_TXT_IDX_40,
+ CS_TXT_IDX_ADH,
+ CS_TXT_IDX_AECDH,
+ CS_TXT_IDX_anon,
+ CS_TXT_IDX_DES40,
+ CS_TXT_IDX_DH,
+ CS_TXT_IDX_DSS,
+ CS_TXT_IDX_EDH,
+ CS_TXT_IDX_EXP,
+ CS_TXT_IDX_EXPORT,
+ CS_TXT_IDX_IDEA,
+ CS_TXT_IDX_RC2,
+ CS_TXT_IDX_RC4,
+#endif
CS_TXT_LEN,
};
@@ -224,7 +254,7 @@ static const struct cs_entry cs_list [] = {
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)
+#if defined(USE_SECTRANSP) || defined(USE_MBEDTLS)
CS_ENTRY(0x0001, TLS,RSA,WITH,NULL,MD5,,,),
CS_ENTRY(0x0001, NULL,MD5,,,,,,),
CS_ENTRY(0x0002, TLS,RSA,WITH,NULL,SHA,,,),
@@ -317,7 +347,7 @@ static const struct cs_entry cs_list [] = {
CS_ENTRY(0xCCAB, TLS,PSK,WITH,CHACHA20,POLY1305,SHA256,,),
CS_ENTRY(0xCCAB, PSK,CHACHA20,POLY1305,,,,,),
#endif
-#if defined(USE_BEARSSL)
+#if defined(USE_SECTRANSP) || 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),
@@ -329,6 +359,7 @@ static const struct cs_entry cs_list [] = {
CS_ENTRY(0xC012, TLS,ECDHE,RSA,WITH,3DES,EDE,CBC,SHA),
CS_ENTRY(0xC012, ECDHE,RSA,DES,CBC3,SHA,,,),
#endif
+#if defined(USE_MBEDTLS) || defined(USE_BEARSSL)
CS_ENTRY(0xC09C, TLS,RSA,WITH,AES,128,CCM,,),
CS_ENTRY(0xC09C, AES128,CCM,,,,,,),
CS_ENTRY(0xC09D, TLS,RSA,WITH,AES,256,CCM,,),
@@ -345,8 +376,144 @@ static const struct cs_entry cs_list [] = {
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,,,,),
+#endif
+#if defined(USE_SECTRANSP)
+ /* entries marked bc are backward compatible aliases for old OpenSSL names */
+ CS_ENTRY(0x0003, TLS,RSA,EXPORT,WITH,RC4,40,MD5,),
+ CS_ENTRY(0x0003, EXP,RC4,MD5,,,,,),
+ CS_ENTRY(0x0004, TLS,RSA,WITH,RC4,128,MD5,,),
+ CS_ENTRY(0x0004, RC4,MD5,,,,,,),
+ CS_ENTRY(0x0005, TLS,RSA,WITH,RC4,128,SHA,,),
+ CS_ENTRY(0x0005, RC4,SHA,,,,,,),
+ CS_ENTRY(0x0006, TLS,RSA,EXPORT,WITH,RC2,CBC,40,MD5),
+ CS_ENTRY(0x0006, EXP,RC2,CBC,MD5,,,,),
+ CS_ENTRY(0x0007, TLS,RSA,WITH,IDEA,CBC,SHA,,),
+ CS_ENTRY(0x0007, IDEA,CBC,SHA,,,,,),
+ CS_ENTRY(0x0008, TLS,RSA,EXPORT,WITH,DES40,CBC,SHA,),
+ CS_ENTRY(0x0008, EXP,DES,CBC,SHA,,,,),
+ CS_ENTRY(0x0009, TLS,RSA,WITH,DES,CBC,SHA,,),
+ CS_ENTRY(0x0009, DES,CBC,SHA,,,,,),
+ CS_ENTRY(0x000B, TLS,DH,DSS,EXPORT,WITH,DES40,CBC,SHA),
+ CS_ENTRY(0x000B, EXP,DH,DSS,DES,CBC,SHA,,),
+ CS_ENTRY(0x000C, TLS,DH,DSS,WITH,DES,CBC,SHA,),
+ CS_ENTRY(0x000C, DH,DSS,DES,CBC,SHA,,,),
+ CS_ENTRY(0x000D, TLS,DH,DSS,WITH,3DES,EDE,CBC,SHA),
+ CS_ENTRY(0x000D, DH,DSS,DES,CBC3,SHA,,,),
+ CS_ENTRY(0x000E, TLS,DH,RSA,EXPORT,WITH,DES40,CBC,SHA),
+ CS_ENTRY(0x000E, EXP,DH,RSA,DES,CBC,SHA,,),
+ CS_ENTRY(0x000F, TLS,DH,RSA,WITH,DES,CBC,SHA,),
+ CS_ENTRY(0x000F, DH,RSA,DES,CBC,SHA,,,),
+ CS_ENTRY(0x0010, TLS,DH,RSA,WITH,3DES,EDE,CBC,SHA),
+ CS_ENTRY(0x0010, DH,RSA,DES,CBC3,SHA,,,),
+ CS_ENTRY(0x0011, TLS,DHE,DSS,EXPORT,WITH,DES40,CBC,SHA),
+ CS_ENTRY(0x0011, EXP,DHE,DSS,DES,CBC,SHA,,),
+ CS_ENTRY(0x0011, EXP,EDH,DSS,DES,CBC,SHA,,), /* bc */
+ CS_ENTRY(0x0012, TLS,DHE,DSS,WITH,DES,CBC,SHA,),
+ CS_ENTRY(0x0012, DHE,DSS,DES,CBC,SHA,,,),
+ CS_ENTRY(0x0012, EDH,DSS,DES,CBC,SHA,,,), /* bc */
+ CS_ENTRY(0x0013, TLS,DHE,DSS,WITH,3DES,EDE,CBC,SHA),
+ CS_ENTRY(0x0013, DHE,DSS,DES,CBC3,SHA,,,),
+ CS_ENTRY(0x0013, EDH,DSS,DES,CBC3,SHA,,,), /* bc */
+ CS_ENTRY(0x0014, TLS,DHE,RSA,EXPORT,WITH,DES40,CBC,SHA),
+ CS_ENTRY(0x0014, EXP,DHE,RSA,DES,CBC,SHA,,),
+ CS_ENTRY(0x0014, EXP,EDH,RSA,DES,CBC,SHA,,), /* bc */
+ CS_ENTRY(0x0015, TLS,DHE,RSA,WITH,DES,CBC,SHA,),
+ CS_ENTRY(0x0015, DHE,RSA,DES,CBC,SHA,,,),
+ CS_ENTRY(0x0015, EDH,RSA,DES,CBC,SHA,,,), /* bc */
+ CS_ENTRY(0x0016, TLS,DHE,RSA,WITH,3DES,EDE,CBC,SHA),
+ CS_ENTRY(0x0016, DHE,RSA,DES,CBC3,SHA,,,),
+ CS_ENTRY(0x0016, EDH,RSA,DES,CBC3,SHA,,,), /* bc */
+ CS_ENTRY(0x0017, TLS,DH,anon,EXPORT,WITH,RC4,40,MD5),
+ CS_ENTRY(0x0017, EXP,ADH,RC4,MD5,,,,),
+ CS_ENTRY(0x0018, TLS,DH,anon,WITH,RC4,128,MD5,),
+ CS_ENTRY(0x0018, ADH,RC4,MD5,,,,,),
+ CS_ENTRY(0x0019, TLS,DH,anon,EXPORT,WITH,DES40,CBC,SHA),
+ CS_ENTRY(0x0019, EXP,ADH,DES,CBC,SHA,,,),
+ CS_ENTRY(0x001A, TLS,DH,anon,WITH,DES,CBC,SHA,),
+ CS_ENTRY(0x001A, ADH,DES,CBC,SHA,,,,),
+ CS_ENTRY(0x001B, TLS,DH,anon,WITH,3DES,EDE,CBC,SHA),
+ CS_ENTRY(0x001B, ADH,DES,CBC3,SHA,,,,),
+ CS_ENTRY(0x0030, TLS,DH,DSS,WITH,AES,128,CBC,SHA),
+ CS_ENTRY(0x0030, DH,DSS,AES128,SHA,,,,),
+ CS_ENTRY(0x0031, TLS,DH,RSA,WITH,AES,128,CBC,SHA),
+ CS_ENTRY(0x0031, DH,RSA,AES128,SHA,,,,),
+ CS_ENTRY(0x0032, TLS,DHE,DSS,WITH,AES,128,CBC,SHA),
+ CS_ENTRY(0x0032, DHE,DSS,AES128,SHA,,,,),
+ CS_ENTRY(0x0034, TLS,DH,anon,WITH,AES,128,CBC,SHA),
+ CS_ENTRY(0x0034, ADH,AES128,SHA,,,,,),
+ CS_ENTRY(0x0036, TLS,DH,DSS,WITH,AES,256,CBC,SHA),
+ CS_ENTRY(0x0036, DH,DSS,AES256,SHA,,,,),
+ CS_ENTRY(0x0037, TLS,DH,RSA,WITH,AES,256,CBC,SHA),
+ CS_ENTRY(0x0037, DH,RSA,AES256,SHA,,,,),
+ CS_ENTRY(0x0038, TLS,DHE,DSS,WITH,AES,256,CBC,SHA),
+ CS_ENTRY(0x0038, DHE,DSS,AES256,SHA,,,,),
+ CS_ENTRY(0x003A, TLS,DH,anon,WITH,AES,256,CBC,SHA),
+ CS_ENTRY(0x003A, ADH,AES256,SHA,,,,,),
+ CS_ENTRY(0x003E, TLS,DH,DSS,WITH,AES,128,CBC,SHA256),
+ CS_ENTRY(0x003E, DH,DSS,AES128,SHA256,,,,),
+ CS_ENTRY(0x003F, TLS,DH,RSA,WITH,AES,128,CBC,SHA256),
+ CS_ENTRY(0x003F, DH,RSA,AES128,SHA256,,,,),
+ CS_ENTRY(0x0040, TLS,DHE,DSS,WITH,AES,128,CBC,SHA256),
+ CS_ENTRY(0x0040, DHE,DSS,AES128,SHA256,,,,),
+ CS_ENTRY(0x0068, TLS,DH,DSS,WITH,AES,256,CBC,SHA256),
+ CS_ENTRY(0x0068, DH,DSS,AES256,SHA256,,,,),
+ CS_ENTRY(0x0069, TLS,DH,RSA,WITH,AES,256,CBC,SHA256),
+ CS_ENTRY(0x0069, DH,RSA,AES256,SHA256,,,,),
+ CS_ENTRY(0x006A, TLS,DHE,DSS,WITH,AES,256,CBC,SHA256),
+ CS_ENTRY(0x006A, DHE,DSS,AES256,SHA256,,,,),
+ CS_ENTRY(0x006C, TLS,DH,anon,WITH,AES,128,CBC,SHA256),
+ CS_ENTRY(0x006C, ADH,AES128,SHA256,,,,,),
+ CS_ENTRY(0x006D, TLS,DH,anon,WITH,AES,256,CBC,SHA256),
+ CS_ENTRY(0x006D, ADH,AES256,SHA256,,,,,),
+ CS_ENTRY(0x008A, TLS,PSK,WITH,RC4,128,SHA,,),
+ CS_ENTRY(0x008A, PSK,RC4,SHA,,,,,),
+ CS_ENTRY(0x008B, TLS,PSK,WITH,3DES,EDE,CBC,SHA,),
+ CS_ENTRY(0x008B, PSK,3DES,EDE,CBC,SHA,,,),
+ CS_ENTRY(0x008E, TLS,DHE,PSK,WITH,RC4,128,SHA,),
+ CS_ENTRY(0x008E, DHE,PSK,RC4,SHA,,,,),
+ CS_ENTRY(0x008F, TLS,DHE,PSK,WITH,3DES,EDE,CBC,SHA),
+ CS_ENTRY(0x008F, DHE,PSK,3DES,EDE,CBC,SHA,,),
+ CS_ENTRY(0x0092, TLS,RSA,PSK,WITH,RC4,128,SHA,),
+ CS_ENTRY(0x0092, RSA,PSK,RC4,SHA,,,,),
+ CS_ENTRY(0x0093, TLS,RSA,PSK,WITH,3DES,EDE,CBC,SHA),
+ CS_ENTRY(0x0093, RSA,PSK,3DES,EDE,CBC,SHA,,),
+ CS_ENTRY(0x00A0, TLS,DH,RSA,WITH,AES,128,GCM,SHA256),
+ CS_ENTRY(0x00A0, DH,RSA,AES128,GCM,SHA256,,,),
+ CS_ENTRY(0x00A1, TLS,DH,RSA,WITH,AES,256,GCM,SHA384),
+ CS_ENTRY(0x00A1, DH,RSA,AES256,GCM,SHA384,,,),
+ CS_ENTRY(0x00A2, TLS,DHE,DSS,WITH,AES,128,GCM,SHA256),
+ CS_ENTRY(0x00A2, DHE,DSS,AES128,GCM,SHA256,,,),
+ CS_ENTRY(0x00A3, TLS,DHE,DSS,WITH,AES,256,GCM,SHA384),
+ CS_ENTRY(0x00A3, DHE,DSS,AES256,GCM,SHA384,,,),
+ CS_ENTRY(0x00A4, TLS,DH,DSS,WITH,AES,128,GCM,SHA256),
+ CS_ENTRY(0x00A4, DH,DSS,AES128,GCM,SHA256,,,),
+ CS_ENTRY(0x00A5, TLS,DH,DSS,WITH,AES,256,GCM,SHA384),
+ CS_ENTRY(0x00A5, DH,DSS,AES256,GCM,SHA384,,,),
+ CS_ENTRY(0x00A6, TLS,DH,anon,WITH,AES,128,GCM,SHA256),
+ CS_ENTRY(0x00A6, ADH,AES128,GCM,SHA256,,,,),
+ CS_ENTRY(0x00A7, TLS,DH,anon,WITH,AES,256,GCM,SHA384),
+ CS_ENTRY(0x00A7, ADH,AES256,GCM,SHA384,,,,),
+ CS_ENTRY(0xC002, TLS,ECDH,ECDSA,WITH,RC4,128,SHA,),
+ CS_ENTRY(0xC002, ECDH,ECDSA,RC4,SHA,,,,),
+ CS_ENTRY(0xC007, TLS,ECDHE,ECDSA,WITH,RC4,128,SHA,),
+ CS_ENTRY(0xC007, ECDHE,ECDSA,RC4,SHA,,,,),
+ CS_ENTRY(0xC00C, TLS,ECDH,RSA,WITH,RC4,128,SHA,),
+ CS_ENTRY(0xC00C, ECDH,RSA,RC4,SHA,,,,),
+ CS_ENTRY(0xC011, TLS,ECDHE,RSA,WITH,RC4,128,SHA,),
+ CS_ENTRY(0xC011, ECDHE,RSA,RC4,SHA,,,,),
+ CS_ENTRY(0xC015, TLS,ECDH,anon,WITH,NULL,SHA,,),
+ CS_ENTRY(0xC015, AECDH,NULL,SHA,,,,,),
+ CS_ENTRY(0xC016, TLS,ECDH,anon,WITH,RC4,128,SHA,),
+ CS_ENTRY(0xC016, AECDH,RC4,SHA,,,,,),
+ CS_ENTRY(0xC017, TLS,ECDH,anon,WITH,3DES,EDE,CBC,SHA),
+ CS_ENTRY(0xC017, AECDH,DES,CBC3,SHA,,,,),
+ CS_ENTRY(0xC018, TLS,ECDH,anon,WITH,AES,128,CBC,SHA),
+ CS_ENTRY(0xC018, AECDH,AES128,SHA,,,,,),
+ CS_ENTRY(0xC019, TLS,ECDH,anon,WITH,AES,256,CBC,SHA),
+ CS_ENTRY(0xC019, AECDH,AES256,SHA,,,,,),
+#endif
#if defined(USE_MBEDTLS)
- /* entries marked ns are "non-standard", they are not in openssl */
+ /* 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),
@@ -713,4 +880,5 @@ int Curl_cipher_suite_get_str(uint16_t id, char *buf, size_t buf_size,
return r;
}
-#endif /* defined(USE_MBEDTLS) || defined(USE_BEARSSL) */
+#endif /* defined(USE_SECTRANSP) || defined(USE_MBEDTLS) || \
+ defined(USE_BEARSSL) */
diff --git a/libs/libcurl/src/vtls/cipher_suite.h b/libs/libcurl/src/vtls/cipher_suite.h
index 712325e9f3..4f66070d43 100644
--- a/libs/libcurl/src/vtls/cipher_suite.h
+++ b/libs/libcurl/src/vtls/cipher_suite.h
@@ -26,7 +26,7 @@
#include "curl_setup.h"
-#if defined(USE_MBEDTLS) || defined(USE_BEARSSL)
+#if defined(USE_SECTRANSP) || defined(USE_MBEDTLS) || defined(USE_BEARSSL)
#include <stdint.h>
/* Lookup IANA id for cipher suite string, returns 0 if not recognized */
@@ -42,5 +42,6 @@ uint16_t Curl_cipher_suite_walk_str(const char **str, const char **end);
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 /* defined(USE_SECTRANSP) || 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 ef7f6059a3..aa838b22a7 100644
--- a/libs/libcurl/src/vtls/gtls.c
+++ b/libs/libcurl/src/vtls/gtls.c
@@ -26,7 +26,7 @@
* Source file for all GnuTLS-specific code for the TLS/SSL layer. No code
* but vtls.c should ever call or use these functions.
*
- * Note: don't use the GnuTLS' *_t variable type names in this source code,
+ * Note: do not use the GnuTLS' *_t variable type names in this source code,
* since they were not present in 1.0.X.
*/
@@ -125,7 +125,7 @@ static ssize_t gtls_pull(void *s, void *buf, size_t blen)
CURLcode result;
DEBUGASSERT(data);
- if(!backend->gtls.trust_setup) {
+ if(!backend->gtls.shared_creds->trust_setup) {
result = Curl_gtls_client_trust_setup(cf, data, &backend->gtls);
if(result) {
gnutls_transport_set_errno(backend->gtls.session, EINVAL);
@@ -251,6 +251,7 @@ static CURLcode handshake(struct Curl_cfilter *cf,
DEBUGASSERT(backend);
session = backend->gtls.session;
+ connssl->connecting_state = ssl_connect_2;
for(;;) {
timediff_t timeout_ms;
@@ -265,14 +266,13 @@ static CURLcode handshake(struct Curl_cfilter *cf,
return CURLE_OPERATION_TIMEDOUT;
}
- /* if ssl is expecting something, check if it's available. */
- if(connssl->connecting_state == ssl_connect_2_reading
- || connssl->connecting_state == ssl_connect_2_writing) {
+ /* if ssl is expecting something, check if it is available. */
+ if(connssl->io_need) {
int what;
- curl_socket_t writefd = ssl_connect_2_writing ==
- connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
- curl_socket_t readfd = ssl_connect_2_reading ==
- connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
+ curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND)?
+ sockfd:CURL_SOCKET_BAD;
+ curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV)?
+ sockfd:CURL_SOCKET_BAD;
what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
nonblocking?0:
@@ -294,10 +294,11 @@ static CURLcode handshake(struct Curl_cfilter *cf,
/* socket is readable or writable */
}
+ connssl->io_need = CURL_SSL_IO_NEED_NONE;
backend->gtls.io_result = CURLE_OK;
rc = gnutls_handshake(session);
- if(!backend->gtls.trust_setup) {
+ if(!backend->gtls.shared_creds->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);
@@ -306,16 +307,16 @@ static CURLcode handshake(struct Curl_cfilter *cf,
}
if((rc == GNUTLS_E_AGAIN) || (rc == GNUTLS_E_INTERRUPTED)) {
- connssl->connecting_state =
+ connssl->io_need =
gnutls_record_get_direction(session)?
- ssl_connect_2_writing:ssl_connect_2_reading;
+ CURL_SSL_IO_NEED_SEND:CURL_SSL_IO_NEED_RECV;
continue;
}
else if((rc < 0) && !gnutls_error_is_fatal(rc)) {
const char *strerr = NULL;
if(rc == GNUTLS_E_WARNING_ALERT_RECEIVED) {
- int alert = gnutls_alert_get(session);
+ gnutls_alert_description_t alert = gnutls_alert_get(session);
strerr = gnutls_alert_get_name(alert);
}
@@ -332,7 +333,7 @@ static CURLcode handshake(struct Curl_cfilter *cf,
const char *strerr = NULL;
if(rc == GNUTLS_E_FATAL_ALERT_RECEIVED) {
- int alert = gnutls_alert_get(session);
+ gnutls_alert_description_t alert = gnutls_alert_get(session);
strerr = gnutls_alert_get_name(alert);
}
@@ -376,9 +377,15 @@ set_ssl_version_min_max(struct Curl_easy *data,
long ssl_version = conn_config->version;
long ssl_version_max = conn_config->version_max;
+ if((ssl_version == CURL_SSLVERSION_DEFAULT) ||
+ (ssl_version == CURL_SSLVERSION_TLSv1))
+ ssl_version = CURL_SSLVERSION_TLSv1_0;
+ if(ssl_version_max == CURL_SSLVERSION_MAX_NONE)
+ ssl_version_max = CURL_SSLVERSION_MAX_DEFAULT;
+
if(peer->transport == TRNSPRT_QUIC) {
- if((ssl_version != CURL_SSLVERSION_DEFAULT) &&
- (ssl_version < CURL_SSLVERSION_TLSv1_3)) {
+ if((ssl_version_max != CURL_SSLVERSION_MAX_DEFAULT) &&
+ (ssl_version_max < CURL_SSLVERSION_MAX_TLSv1_3)) {
failf(data, "QUIC needs at least TLS version 1.3");
return CURLE_SSL_CONNECT_ERROR;
}
@@ -386,13 +393,8 @@ set_ssl_version_min_max(struct Curl_easy *data,
return CURLE_OK;
}
- if((ssl_version == CURL_SSLVERSION_DEFAULT) ||
- (ssl_version == CURL_SSLVERSION_TLSv1))
- ssl_version = CURL_SSLVERSION_TLSv1_0;
- if(ssl_version_max == CURL_SSLVERSION_MAX_NONE)
- ssl_version_max = CURL_SSLVERSION_MAX_DEFAULT;
if(!tls13support) {
- /* If the running GnuTLS doesn't support TLS 1.3, we must not specify a
+ /* If the running GnuTLS does not support TLS 1.3, we must not specify a
prioritylist involving that since it will make GnuTLS return an en
error back at us */
if((ssl_version_max == CURL_SSLVERSION_MAX_TLSv1_3) ||
@@ -450,20 +452,67 @@ set_ssl_version_min_max(struct Curl_easy *data,
return CURLE_SSL_CONNECT_ERROR;
}
-CURLcode Curl_gtls_client_trust_setup(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- struct gtls_ctx *gtls)
+CURLcode Curl_gtls_shared_creds_create(struct Curl_easy *data,
+ struct gtls_shared_creds **pcreds)
+{
+ struct gtls_shared_creds *shared;
+ int rc;
+
+ *pcreds = NULL;
+ shared = calloc(1, sizeof(*shared));
+ if(!shared)
+ return CURLE_OUT_OF_MEMORY;
+
+ rc = gnutls_certificate_allocate_credentials(&shared->creds);
+ if(rc != GNUTLS_E_SUCCESS) {
+ failf(data, "gnutls_cert_all_cred() failed: %s", gnutls_strerror(rc));
+ free(shared);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ shared->refcount = 1;
+ shared->time = Curl_now();
+ *pcreds = shared;
+ return CURLE_OK;
+}
+
+CURLcode Curl_gtls_shared_creds_up_ref(struct gtls_shared_creds *creds)
+{
+ DEBUGASSERT(creds);
+ if(creds->refcount < SIZE_T_MAX) {
+ ++creds->refcount;
+ return CURLE_OK;
+ }
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+}
+
+void Curl_gtls_shared_creds_free(struct gtls_shared_creds **pcreds)
+{
+ struct gtls_shared_creds *shared = *pcreds;
+ *pcreds = NULL;
+ if(shared) {
+ --shared->refcount;
+ if(!shared->refcount) {
+ gnutls_certificate_free_credentials(shared->creds);
+ free(shared->CAfile);
+ free(shared);
+ }
+ }
+}
+
+static CURLcode gtls_populate_creds(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ gnutls_certificate_credentials_t creds)
{
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;
- CURL_TRC_CF(data, cf, "setup trust anchors and CRLs");
if(config->verifypeer) {
bool imported_native_ca = false;
if(ssl_config->native_ca_store) {
- rc = gnutls_certificate_set_x509_system_trust(gtls->cred);
+ rc = gnutls_certificate_set_x509_system_trust(creds);
if(rc < 0)
infof(data, "error reading native ca store (%s), continuing anyway",
gnutls_strerror(rc));
@@ -476,10 +525,10 @@ CURLcode Curl_gtls_client_trust_setup(struct Curl_cfilter *cf,
if(config->CAfile) {
/* set the trusted CA cert bundle file */
- gnutls_certificate_set_verify_flags(gtls->cred,
+ gnutls_certificate_set_verify_flags(creds,
GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);
- rc = gnutls_certificate_set_x509_trust_file(gtls->cred,
+ rc = gnutls_certificate_set_x509_trust_file(creds,
config->CAfile,
GNUTLS_X509_FMT_PEM);
if(rc < 0) {
@@ -497,8 +546,7 @@ CURLcode Curl_gtls_client_trust_setup(struct Curl_cfilter *cf,
if(config->CApath) {
/* set the trusted CA cert directory */
- rc = gnutls_certificate_set_x509_trust_dir(gtls->cred,
- config->CApath,
+ rc = gnutls_certificate_set_x509_trust_dir(creds, config->CApath,
GNUTLS_X509_FMT_PEM);
if(rc < 0) {
infof(data, "error reading ca cert file %s (%s)%s",
@@ -516,8 +564,7 @@ CURLcode Curl_gtls_client_trust_setup(struct Curl_cfilter *cf,
if(config->CRLfile) {
/* set the CRL list file */
- rc = gnutls_certificate_set_x509_crl_file(gtls->cred,
- config->CRLfile,
+ rc = gnutls_certificate_set_x509_crl_file(creds, config->CRLfile,
GNUTLS_X509_FMT_PEM);
if(rc < 0) {
failf(data, "error reading crl file %s (%s)",
@@ -528,7 +575,141 @@ CURLcode Curl_gtls_client_trust_setup(struct Curl_cfilter *cf,
infof(data, "found %d CRL in %s", rc, config->CRLfile);
}
- gtls->trust_setup = TRUE;
+ return CURLE_OK;
+}
+
+/* key to use at `multi->proto_hash` */
+#define MPROTO_GTLS_X509_KEY "tls:gtls:x509:share"
+
+static bool gtls_shared_creds_expired(const struct Curl_easy *data,
+ const struct gtls_shared_creds *sc)
+{
+ const struct ssl_general_config *cfg = &data->set.general_ssl;
+ struct curltime now = Curl_now();
+ timediff_t elapsed_ms = Curl_timediff(now, sc->time);
+ timediff_t timeout_ms = cfg->ca_cache_timeout * (timediff_t)1000;
+
+ if(timeout_ms < 0)
+ return false;
+
+ return elapsed_ms >= timeout_ms;
+}
+
+static bool gtls_shared_creds_different(struct Curl_cfilter *cf,
+ const struct gtls_shared_creds *sc)
+{
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+ if(!sc->CAfile || !conn_config->CAfile)
+ return sc->CAfile != conn_config->CAfile;
+
+ return strcmp(sc->CAfile, conn_config->CAfile);
+}
+
+static struct gtls_shared_creds*
+gtls_get_cached_creds(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+ struct gtls_shared_creds *shared_creds;
+
+ if(data->multi) {
+ shared_creds = Curl_hash_pick(&data->multi->proto_hash,
+ (void *)MPROTO_GTLS_X509_KEY,
+ sizeof(MPROTO_GTLS_X509_KEY)-1);
+ if(shared_creds && shared_creds->creds &&
+ !gtls_shared_creds_expired(data, shared_creds) &&
+ !gtls_shared_creds_different(cf, shared_creds)) {
+ return shared_creds;
+ }
+ }
+ return NULL;
+}
+
+static void gtls_shared_creds_hash_free(void *key, size_t key_len, void *p)
+{
+ struct gtls_shared_creds *sc = p;
+ DEBUGASSERT(key_len == (sizeof(MPROTO_GTLS_X509_KEY)-1));
+ DEBUGASSERT(!memcmp(MPROTO_GTLS_X509_KEY, key, key_len));
+ (void)key;
+ (void)key_len;
+ Curl_gtls_shared_creds_free(&sc); /* down reference */
+}
+
+static void gtls_set_cached_creds(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct gtls_shared_creds *sc)
+{
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+
+ DEBUGASSERT(sc);
+ DEBUGASSERT(sc->creds);
+ DEBUGASSERT(!sc->CAfile);
+ DEBUGASSERT(sc->refcount == 1);
+ if(!data->multi)
+ return;
+
+ if(conn_config->CAfile) {
+ sc->CAfile = strdup(conn_config->CAfile);
+ if(!sc->CAfile)
+ return;
+ }
+
+ if(Curl_gtls_shared_creds_up_ref(sc))
+ return;
+
+ if(!Curl_hash_add2(&data->multi->proto_hash,
+ (void *)MPROTO_GTLS_X509_KEY,
+ sizeof(MPROTO_GTLS_X509_KEY)-1,
+ sc, gtls_shared_creds_hash_free)) {
+ Curl_gtls_shared_creds_free(&sc); /* down reference again */
+ return;
+ }
+}
+
+CURLcode Curl_gtls_client_trust_setup(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct gtls_ctx *gtls)
+{
+ 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 gtls_shared_creds *cached_creds = NULL;
+ bool cache_criteria_met;
+ CURLcode result;
+ int rc;
+
+
+ /* Consider the X509 store cacheable if it comes exclusively from a CAfile,
+ or no source is provided and we are falling back to OpenSSL's built-in
+ default. */
+ cache_criteria_met = (data->set.general_ssl.ca_cache_timeout != 0) &&
+ conn_config->verifypeer &&
+ !conn_config->CApath &&
+ !conn_config->ca_info_blob &&
+ !ssl_config->primary.CRLfile &&
+ !ssl_config->native_ca_store &&
+ !conn_config->clientcert; /* GnuTLS adds client cert to its credentials! */
+
+ if(cache_criteria_met)
+ cached_creds = gtls_get_cached_creds(cf, data);
+
+ if(cached_creds && !Curl_gtls_shared_creds_up_ref(cached_creds)) {
+ CURL_TRC_CF(data, cf, "using shared trust anchors and CRLs");
+ Curl_gtls_shared_creds_free(&gtls->shared_creds);
+ gtls->shared_creds = cached_creds;
+ rc = gnutls_credentials_set(gtls->session, GNUTLS_CRD_CERTIFICATE,
+ gtls->shared_creds->creds);
+ if(rc != GNUTLS_E_SUCCESS) {
+ failf(data, "gnutls_credentials_set() failed: %s", gnutls_strerror(rc));
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ }
+ else {
+ CURL_TRC_CF(data, cf, "loading trust anchors and CRLs");
+ result = gtls_populate_creds(cf, data, gtls->shared_creds->creds);
+ if(result)
+ return result;
+ gtls->shared_creds->trust_setup = TRUE;
+ if(cache_criteria_met)
+ gtls_set_cached_creds(cf, data, gtls->shared_creds);
+ }
return CURLE_OK;
}
@@ -546,7 +727,7 @@ static CURLcode gtls_update_session_id(struct Curl_cfilter *cf,
struct ssl_connect_data *connssl = cf->ctx;
CURLcode result = CURLE_OK;
- if(ssl_config->primary.sessionid) {
+ if(ssl_config->primary.cache_session) {
/* we always unconditionally get the session id here, as even if we
already got it from the cache and asked to use it in the connection, it
might've been rejected and then a new one is in use now and we need to
@@ -561,27 +742,16 @@ static CURLcode gtls_update_session_id(struct Curl_cfilter *cf,
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_TRC_CF(data, cf, "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);
+ result = Curl_ssl_set_sessionid(cf, data, &connssl->peer,
+ connect_sessionid, connect_idsize,
+ gtls_sessionid_free);
Curl_ssl_sessionid_unlock(data);
}
}
@@ -599,8 +769,8 @@ static int gtls_handshake_cb(gnutls_session_t session, unsigned int htype,
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));
+ CURL_TRC_CF(data, cf, "handshake: %s message type %d",
+ incoming? "incoming" : "outgoing", htype);
switch(htype) {
case GNUTLS_HANDSHAKE_NEW_SESSION_TICKET: {
gtls_update_session_id(cf, data, session);
@@ -639,12 +809,10 @@ static CURLcode gtls_client_init(struct Curl_cfilter *cf,
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;
- }
+ /* allocate a shared creds struct */
+ result = Curl_gtls_shared_creds_create(data, &gtls->shared_creds);
+ if(result)
+ return result;
#ifdef USE_GNUTLS_SRP
if(config->username && Curl_auth_allowed_to_host(data)) {
@@ -705,7 +873,7 @@ static CURLcode gtls_client_init(struct Curl_cfilter *cf,
tls13support = gnutls_check_version("3.6.5");
/* Ensure +SRP comes at the *end* of all relevant strings so that it can be
- * removed if a run-time error indicates that SRP is not supported by this
+ * removed if a runtime error indicates that SRP is not supported by this
* GnuTLS version */
if(config->version == CURL_SSLVERSION_SSLv2 ||
@@ -756,7 +924,7 @@ static CURLcode gtls_client_init(struct Curl_cfilter *cf,
}
if(config->clientcert) {
- if(!gtls->trust_setup) {
+ if(!gtls->shared_creds->trust_setup) {
result = Curl_gtls_client_trust_setup(cf, data, gtls);
if(result)
return result;
@@ -768,7 +936,7 @@ static CURLcode gtls_client_init(struct Curl_cfilter *cf,
GNUTLS_PKCS_USE_PBES2_AES_128 | GNUTLS_PKCS_USE_PBES2_AES_192 |
GNUTLS_PKCS_USE_PBES2_AES_256;
rc = gnutls_certificate_set_x509_key_file2(
- gtls->cred,
+ gtls->shared_creds->creds,
config->clientcert,
ssl_config->key ? ssl_config->key : config->clientcert,
do_file_type(ssl_config->cert_type),
@@ -783,7 +951,7 @@ static CURLcode gtls_client_init(struct Curl_cfilter *cf,
}
else {
if(gnutls_certificate_set_x509_key_file(
- gtls->cred,
+ gtls->shared_creds->creds,
config->clientcert,
ssl_config->key ? ssl_config->key : config->clientcert,
do_file_type(ssl_config->cert_type) ) !=
@@ -808,7 +976,7 @@ static CURLcode gtls_client_init(struct Curl_cfilter *cf,
#endif
{
rc = gnutls_credentials_set(gtls->session, GNUTLS_CRD_CERTIFICATE,
- gtls->cred);
+ gtls->shared_creds->creds);
if(rc != GNUTLS_E_SUCCESS) {
failf(data, "gnutls_credentials_set() failed: %s", gnutls_strerror(rc));
return CURLE_SSL_CONNECT_ERROR;
@@ -903,7 +1071,7 @@ CURLcode Curl_gtls_ctx_init(struct gtls_ctx *gctx,
/* This might be a reconnect, so we check for a session ID in the cache
to speed up things */
- if(conn_config->sessionid) {
+ if(conn_config->cache_session) {
void *ssl_sessionid;
size_t ssl_idsize;
@@ -979,7 +1147,7 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
/* Result is returned to caller */
CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
- /* if a path wasn't specified, don't pin */
+ /* if a path was not specified, do not pin */
if(!pinnedpubkey)
return CURLE_OK;
@@ -1045,7 +1213,7 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
CURLcode result = CURLE_OK;
#ifndef CURL_DISABLE_VERBOSE_STRINGS
const char *ptr;
- unsigned int algo;
+ int algo;
unsigned int bits;
gnutls_protocol_t version = gnutls_protocol_get_version(session);
#endif
@@ -1087,13 +1255,13 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
}
#endif
}
- infof(data, " common name: WARNING couldn't obtain");
+ infof(data, " common name: WARNING could not obtain");
}
if(data->set.ssl.certinfo && chainp) {
unsigned int i;
- result = Curl_ssl_init_certinfo(data, cert_list_size);
+ result = Curl_ssl_init_certinfo(data, (int)cert_list_size);
if(result)
return result;
@@ -1101,7 +1269,7 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
const char *beg = (const char *) chainp[i].data;
const char *end = beg + chainp[i].size;
- result = Curl_extract_certinfo(data, i, beg, end);
+ result = Curl_extract_certinfo(data, (int)i, beg, end);
if(result)
return result;
}
@@ -1258,7 +1426,7 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
gnutls_x509_crt_init(&x509_issuer);
issuerp = load_file(config->issuercert);
gnutls_x509_crt_import(x509_issuer, &issuerp, GNUTLS_X509_FMT_PEM);
- rc = gnutls_x509_crt_check_issuer(x509_cert, x509_issuer);
+ rc = (int)gnutls_x509_crt_check_issuer(x509_cert, x509_issuer);
gnutls_x509_crt_deinit(x509_issuer);
unload_file(issuerp);
if(rc <= 0) {
@@ -1287,9 +1455,15 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
in RFC2818 (HTTPS), which takes into account wildcards, and the subject
alternative name PKIX extension. Returns non zero on success, and zero on
failure. */
- rc = gnutls_x509_crt_check_hostname(x509_cert, peer->hostname);
+
+ /* This function does not handle trailing dots, so if we have an SNI name
+ use that and fallback to the hostname only if there is no SNI (like for
+ IP addresses) */
+ rc = (int)gnutls_x509_crt_check_hostname(x509_cert,
+ peer->sni ? peer->sni :
+ peer->hostname);
#if GNUTLS_VERSION_NUMBER < 0x030306
- /* Before 3.3.6, gnutls_x509_crt_check_hostname() didn't check IP
+ /* Before 3.3.6, gnutls_x509_crt_check_hostname() did not check IP
addresses. */
if(!rc) {
#ifdef USE_IPV6
@@ -1315,7 +1489,7 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
size_t certaddrlen = sizeof(certaddr);
int ret = gnutls_x509_crt_get_subject_alt_name(x509_cert, i, certaddr,
&certaddrlen, NULL);
- /* If this happens, it wasn't an IP address. */
+ /* If this happens, it was not an IP address. */
if(ret == GNUTLS_E_SHORT_MEMORY_BUFFER)
continue;
if(ret < 0)
@@ -1333,7 +1507,7 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
if(!rc) {
if(config->verifyhost) {
failf(data, "SSL: certificate subject name (%s) does not match "
- "target host name '%s'", certname, peer->dispname);
+ "target hostname '%s'", certname, peer->dispname);
gnutls_x509_crt_deinit(x509_cert);
return CURLE_PEER_FAILED_VERIFICATION;
}
@@ -1422,7 +1596,7 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
/* public key algorithm's parameters */
algo = gnutls_x509_crt_get_pk_algorithm(x509_cert, &bits);
infof(data, " certificate public key: %s",
- gnutls_pk_algorithm_get_name(algo));
+ gnutls_pk_algorithm_get_name((gnutls_pk_algorithm_t)algo));
/* version of the X.509 certificate. */
infof(data, " certificate version: #%d",
@@ -1506,8 +1680,8 @@ out:
*/
/* We use connssl->connecting_state to keep track of the connection status;
there are three states: 'ssl_connect_1' (not started yet or complete),
- 'ssl_connect_2_reading' (waiting for data from server), and
- 'ssl_connect_2_writing' (waiting to be able to write).
+ 'ssl_connect_2' (doing handshake with the server), and
+ 'ssl_connect_3' (verifying and getting stats).
*/
static CURLcode
gtls_connect_common(struct Curl_cfilter *cf,
@@ -1516,7 +1690,7 @@ gtls_connect_common(struct Curl_cfilter *cf,
bool *done)
{
struct ssl_connect_data *connssl = cf->ctx;
- int rc;
+ CURLcode rc;
CURLcode result = CURLE_OK;
/* Initiate the connection, if not already done */
@@ -1620,118 +1794,104 @@ static ssize_t gtls_send(struct Curl_cfilter *cf,
return rc;
}
-static void gtls_close(struct Curl_cfilter *cf,
- struct Curl_easy *data)
+/*
+ * This function is called to shut down the SSL layer but keep the
+ * socket open (CCC - Clear Command Channel)
+ */
+static CURLcode gtls_shutdown(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool send_shutdown, bool *done)
{
struct ssl_connect_data *connssl = cf->ctx;
struct gtls_ssl_backend_data *backend =
(struct gtls_ssl_backend_data *)connssl->backend;
+ char buf[1024];
+ CURLcode result = CURLE_OK;
+ ssize_t nread;
+ size_t i;
- (void) data;
DEBUGASSERT(backend);
+ if(!backend->gtls.session || cf->shutdown) {
+ *done = TRUE;
+ goto out;
+ }
- if(backend->gtls.session) {
- char buf[32];
- /* Maybe the server has already sent a close notify alert.
- Read it to avoid an RST on the TCP connection. */
- (void)gnutls_record_recv(backend->gtls.session, buf, sizeof(buf));
- gnutls_bye(backend->gtls.session, GNUTLS_SHUT_WR);
- gnutls_deinit(backend->gtls.session);
- backend->gtls.session = NULL;
+ connssl->io_need = CURL_SSL_IO_NEED_NONE;
+ *done = FALSE;
+
+ if(!backend->gtls.sent_shutdown) {
+ /* do this only once */
+ backend->gtls.sent_shutdown = TRUE;
+ if(send_shutdown) {
+ int ret = gnutls_bye(backend->gtls.session, GNUTLS_SHUT_RDWR);
+ if((ret == GNUTLS_E_AGAIN) || (ret == GNUTLS_E_INTERRUPTED)) {
+ CURL_TRC_CF(data, cf, "SSL shutdown, gnutls_bye EAGAIN");
+ connssl->io_need = gnutls_record_get_direction(backend->gtls.session)?
+ CURL_SSL_IO_NEED_SEND : CURL_SSL_IO_NEED_RECV;
+ result = CURLE_OK;
+ goto out;
+ }
+ if(ret != GNUTLS_E_SUCCESS) {
+ CURL_TRC_CF(data, cf, "SSL shutdown, gnutls_bye error: '%s'(%d)",
+ gnutls_strerror((int)ret), (int)ret);
+ result = CURLE_RECV_ERROR;
+ goto out;
+ }
+ }
}
- if(backend->gtls.cred) {
- gnutls_certificate_free_credentials(backend->gtls.cred);
- backend->gtls.cred = NULL;
+
+ /* SSL should now have started the shutdown from our side. Since it
+ * was not complete, we are lacking the close notify from the server. */
+ for(i = 0; i < 10; ++i) {
+ nread = gnutls_record_recv(backend->gtls.session, buf, sizeof(buf));
+ if(nread <= 0)
+ break;
}
-#ifdef USE_GNUTLS_SRP
- if(backend->gtls.srp_client_cred) {
- gnutls_srp_free_client_credentials(backend->gtls.srp_client_cred);
- backend->gtls.srp_client_cred = NULL;
+ if(nread > 0) {
+ /* still data coming in? */
}
-#endif
+ else if(nread == 0) {
+ /* We got the close notify alert and are done. */
+ *done = TRUE;
+ }
+ else if((nread == GNUTLS_E_AGAIN) || (nread == GNUTLS_E_INTERRUPTED)) {
+ connssl->io_need = gnutls_record_get_direction(backend->gtls.session)?
+ CURL_SSL_IO_NEED_SEND : CURL_SSL_IO_NEED_RECV;
+ }
+ else {
+ CURL_TRC_CF(data, cf, "SSL shutdown, error: '%s'(%d)",
+ gnutls_strerror((int)nread), (int)nread);
+ result = CURLE_RECV_ERROR;
+ }
+
+out:
+ cf->shutdown = (result || *done);
+ return result;
}
-/*
- * This function is called to shut down the SSL layer but keep the
- * socket open (CCC - Clear Command Channel)
- */
-static int gtls_shutdown(struct Curl_cfilter *cf,
- struct Curl_easy *data)
+static void gtls_close(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;
- int retval = 0;
+ (void) data;
DEBUGASSERT(backend);
-
-#ifndef CURL_DISABLE_FTP
- /* This has only been tested on the proftpd server, and the mod_tls code
- sends a close notify alert without waiting for a close notify alert in
- response. Thus we wait for a close notify alert from the server, but
- we do not send one. Let's hope other servers do the same... */
-
- if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE)
- gnutls_bye(backend->gtls.session, GNUTLS_SHUT_WR);
-#endif
-
+ CURL_TRC_CF(data, cf, "close");
if(backend->gtls.session) {
- ssize_t result;
- bool done = FALSE;
- char buf[120];
-
- while(!done && !connssl->peer_closed) {
- int what = SOCKET_READABLE(Curl_conn_cf_get_socket(cf, data),
- SSL_SHUTDOWN_TIMEOUT);
- if(what > 0) {
- /* Something to read, let's do it and hope that it is the close
- notify alert from the server */
- result = gnutls_record_recv(backend->gtls.session,
- buf, sizeof(buf));
- switch(result) {
- case 0:
- /* This is the expected response. There was no data but only
- the close notify alert */
- done = TRUE;
- break;
- case GNUTLS_E_AGAIN:
- case GNUTLS_E_INTERRUPTED:
- infof(data, "GNUTLS_E_AGAIN || GNUTLS_E_INTERRUPTED");
- break;
- default:
- retval = -1;
- done = TRUE;
- break;
- }
- }
- else if(0 == what) {
- /* timeout */
- failf(data, "SSL shutdown timeout");
- done = TRUE;
- }
- else {
- /* anything that gets here is fatally bad */
- failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
- retval = -1;
- done = TRUE;
- }
- }
gnutls_deinit(backend->gtls.session);
+ backend->gtls.session = NULL;
+ }
+ if(backend->gtls.shared_creds) {
+ Curl_gtls_shared_creds_free(&backend->gtls.shared_creds);
}
- gnutls_certificate_free_credentials(backend->gtls.cred);
-
#ifdef USE_GNUTLS_SRP
- {
- struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
- if(ssl_config->primary.username)
- gnutls_srp_free_client_credentials(backend->gtls.srp_client_cred);
+ if(backend->gtls.srp_client_cred) {
+ gnutls_srp_free_client_credentials(backend->gtls.srp_client_cred);
+ backend->gtls.srp_client_cred = NULL;
}
#endif
-
- backend->gtls.cred = NULL;
- backend->gtls.session = NULL;
-
- return retval;
}
static ssize_t gtls_recv(struct Curl_cfilter *cf,
@@ -1831,7 +1991,8 @@ const struct Curl_ssl Curl_ssl_gnutls = {
SSLSUPP_CA_PATH |
SSLSUPP_CERTINFO |
SSLSUPP_PINNEDPUBKEY |
- SSLSUPP_HTTPS_PROXY,
+ SSLSUPP_HTTPS_PROXY |
+ SSLSUPP_CA_CACHE,
sizeof(struct gtls_ssl_backend_data),
@@ -1856,7 +2017,6 @@ const struct Curl_ssl Curl_ssl_gnutls = {
gtls_sha256sum, /* sha256sum */
NULL, /* associate_connection */
NULL, /* disassociate_connection */
- NULL, /* free_multi_ssl_backend_data */
gtls_recv, /* recv decrypted data */
gtls_send, /* send data to encrypt */
};
diff --git a/libs/libcurl/src/vtls/gtls.h b/libs/libcurl/src/vtls/gtls.h
index 534b320287..2ba237a315 100644
--- a/libs/libcurl/src/vtls/gtls.h
+++ b/libs/libcurl/src/vtls/gtls.h
@@ -30,6 +30,7 @@
#ifdef USE_GNUTLS
#include <gnutls/gnutls.h>
+#include "timeval.h"
#ifdef HAVE_GNUTLS_SRP
/* the function exists */
@@ -45,14 +46,27 @@ struct ssl_primary_config;
struct ssl_config_data;
struct ssl_peer;
+struct gtls_shared_creds {
+ gnutls_certificate_credentials_t creds;
+ char *CAfile; /* CAfile path used to generate X509 store */
+ struct curltime time; /* when the shared creds was created */
+ size_t refcount;
+ BIT(trust_setup); /* x509 anchors + CRLs have been set up */
+};
+
+CURLcode Curl_gtls_shared_creds_create(struct Curl_easy *data,
+ struct gtls_shared_creds **pcreds);
+CURLcode Curl_gtls_shared_creds_up_ref(struct gtls_shared_creds *creds);
+void Curl_gtls_shared_creds_free(struct gtls_shared_creds **pcreds);
+
struct gtls_ctx {
gnutls_session_t session;
- gnutls_certificate_credentials_t cred;
+ struct gtls_shared_creds *shared_creds;
#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 */
+ BIT(sent_shutdown);
};
typedef CURLcode Curl_gtls_ctx_setup_cb(struct Curl_cfilter *cf,
diff --git a/libs/libcurl/src/vtls/hostcheck.c b/libs/libcurl/src/vtls/hostcheck.c
index 3078ab8061..79ed869e87 100644
--- a/libs/libcurl/src/vtls/hostcheck.c
+++ b/libs/libcurl/src/vtls/hostcheck.c
@@ -62,7 +62,7 @@ static bool pmatch(const char *hostname, size_t hostlen,
* We use the matching rule described in RFC6125, section 6.4.3.
* https://datatracker.ietf.org/doc/html/rfc6125#section-6.4.3
*
- * In addition: ignore trailing dots in the host names and wildcards, so that
+ * In addition: ignore trailing dots in the hostnames and wildcards, so that
* the names are used normalized. This is what the browsers do.
*
* Do not allow wildcard matching on IP numbers. There are apparently
diff --git a/libs/libcurl/src/vtls/hostcheck.h b/libs/libcurl/src/vtls/hostcheck.h
index ce3e81fd42..bc4d40fbe8 100644
--- a/libs/libcurl/src/vtls/hostcheck.h
+++ b/libs/libcurl/src/vtls/hostcheck.h
@@ -26,7 +26,7 @@
#include <curl/curl.h>
-/* returns TRUE if there's a match */
+/* returns TRUE if there is a match */
bool Curl_cert_hostcheck(const char *match_pattern, size_t matchlen,
const char *hostname, size_t hostlen);
diff --git a/libs/libcurl/src/vtls/mbedtls.c b/libs/libcurl/src/vtls/mbedtls.c
index d4820c4c50..a6286f82d6 100644
--- a/libs/libcurl/src/vtls/mbedtls.c
+++ b/libs/libcurl/src/vtls/mbedtls.c
@@ -75,6 +75,7 @@
#include "mbedtls.h"
#include "vtls.h"
#include "vtls_int.h"
+#include "x509asn1.h"
#include "parsedate.h"
#include "connect.h" /* for the connect timeout */
#include "select.h"
@@ -110,6 +111,8 @@ struct mbed_ssl_backend_data {
const char *protocols[3];
#endif
int *ciphersuites;
+ BIT(initialized); /* mbedtls_ssl_context is initialized */
+ BIT(sent_shutdown);
};
/* apply threading? */
@@ -482,6 +485,20 @@ mbed_set_selected_ciphers(struct Curl_easy *data,
return CURLE_OK;
}
+#ifdef TLS13_SUPPORT
+static int mbed_no_verify(void *udata, mbedtls_x509_crt *crt,
+ int depth, uint32_t *flags)
+{
+ (void)udata;
+ (void)crt;
+ (void)depth;
+ /* we clear any faults the mbedtls' own verification found.
+ * See <https://github.com/Mbed-TLS/mbedtls/issues/9210> */
+ *flags = 0;
+ return 0;
+}
+#endif
+
static CURLcode
mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
{
@@ -504,6 +521,7 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
char errorbuf[128];
DEBUGASSERT(backend);
+ DEBUGASSERT(!backend->initialized);
if((conn_config->version == CURL_SSLVERSION_SSLv2) ||
(conn_config->version == CURL_SSLVERSION_SSLv3)) {
@@ -636,7 +654,7 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
if(ret) {
mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
- failf(data, "Error reading private key %s - mbedTLS: (-0x%04X) %s",
+ failf(data, "Error reading client cert data %s - mbedTLS: (-0x%04X) %s",
ssl_config->key, -ret, errorbuf);
return CURLE_SSL_CERTPROBLEM;
}
@@ -737,8 +755,19 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
failf(data, "mbedTLS: ssl_config failed");
return CURLE_SSL_CONNECT_ERROR;
}
+#ifdef TLS13_SUPPORT
+ if(!verifypeer) {
+ /* Default verify behaviour changed in mbedtls v3.6.0 with TLS v1.3.
+ * On 1.3 connections, the handshake fails by default without trust
+ * anchors. We override this questionable change by installing our
+ * own verify callback that clears all errors. */
+ mbedtls_ssl_conf_verify(&backend->config, mbed_no_verify, cf);
+ }
+#endif
+
mbedtls_ssl_init(&backend->ssl);
+ backend->initialized = TRUE;
/* new profile with RSA min key len = 1024 ... */
mbedtls_ssl_conf_cert_profile(&backend->config,
@@ -785,10 +814,11 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
NULL /* rev_timeout() */);
if(conn_config->cipher_list) {
- ret = mbed_set_selected_ciphers(data, backend, conn_config->cipher_list);
- if(ret) {
+ CURLcode result = mbed_set_selected_ciphers(data, backend,
+ conn_config->cipher_list);
+ if(result != CURLE_OK) {
failf(data, "mbedTLS: failed to set cipher suites");
- return ret;
+ return result;
}
}
else {
@@ -807,8 +837,8 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
MBEDTLS_SSL_SESSION_TICKETS_DISABLED);
#endif
- /* Check if there's a cached ID we can/should use here! */
- if(ssl_config->primary.sessionid) {
+ /* Check if there is a cached ID we can/should use here! */
+ if(ssl_config->primary.cache_session) {
void *old_session = NULL;
Curl_ssl_sessionid_lock(data);
@@ -854,7 +884,7 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
for(i = 0; i < connssl->alpn->count; ++i) {
backend->protocols[i] = connssl->alpn->entries[i];
}
- /* this function doesn't clone the protocols array, which is why we need
+ /* this function does not clone the protocols array, which is why we need
to keep it around */
if(mbedtls_ssl_conf_alpn_protocols(&backend->config,
&backend->protocols[0])) {
@@ -880,11 +910,11 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
/* give application a chance to interfere with mbedTLS set up. */
if(data->set.ssl.fsslctx) {
- ret = (*data->set.ssl.fsslctx)(data, &backend->config,
- data->set.ssl.fsslctxp);
- if(ret) {
+ CURLcode result = (*data->set.ssl.fsslctx)(data, &backend->config,
+ data->set.ssl.fsslctxp);
+ if(result != CURLE_OK) {
failf(data, "error signaled by ssl ctx callback");
- return ret;
+ return result;
}
}
@@ -893,6 +923,60 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
return CURLE_OK;
}
+static int count_server_cert(const mbedtls_x509_crt *peercert)
+{
+ int count = 1;
+
+ DEBUGASSERT(peercert);
+
+ while(peercert->next) {
+ ++count;
+ peercert = peercert->next;
+ }
+ return count;
+}
+
+static CURLcode collect_server_cert_single(struct Curl_easy *data,
+ const mbedtls_x509_crt *server_cert,
+ int idx)
+{
+ const char *beg, *end;
+
+ DEBUGASSERT(server_cert);
+
+ beg = (const char *)server_cert->raw.p;
+ end = beg + server_cert->raw.len;
+ return Curl_extract_certinfo(data, idx, beg, end);
+}
+
+static CURLcode collect_server_cert(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ const struct mbedtls_x509_crt *peercert)
+{
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+ const bool show_verbose_server_cert = data->set.verbose;
+#else
+ const bool show_verbose_server_cert = false;
+#endif
+ struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+ CURLcode result = CURLE_PEER_FAILED_VERIFICATION;
+ int i, count;
+
+ if(!show_verbose_server_cert && !ssl_config->certinfo)
+ return CURLE_OK;
+
+ if(!peercert)
+ return result;
+
+ count = count_server_cert(peercert);
+ result = Curl_ssl_init_certinfo(data, count);
+ for(i = 0 ; !result && peercert ; i++) {
+ result = collect_server_cert_single(data, peercert, i);
+ peercert = peercert->next;
+ }
+ return result;
+}
+
static CURLcode
mbed_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
{
@@ -902,8 +986,6 @@ 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]:
@@ -917,26 +999,41 @@ mbed_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
ret = mbedtls_ssl_handshake(&backend->ssl);
if(ret == MBEDTLS_ERR_SSL_WANT_READ) {
- connssl->connecting_state = ssl_connect_2_reading;
+ connssl->io_need = CURL_SSL_IO_NEED_RECV;
return CURLE_OK;
}
else if(ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
- connssl->connecting_state = ssl_connect_2_writing;
+ connssl->io_need = CURL_SSL_IO_NEED_SEND;
return CURLE_OK;
}
+ else if(ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED) {
+ failf(data, "peer certificate could not be verified");
+ return CURLE_PEER_FAILED_VERIFICATION;
+ }
else if(ret) {
char errorbuf[128];
+#if MBEDTLS_VERSION_NUMBER >= 0x03020000
+ CURL_TRC_CF(data, cf, "TLS version %04X",
+ mbedtls_ssl_get_version_number(&backend->ssl));
+#endif
mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
- failf(data, "ssl_handshake returned - mbedTLS: (-0x%04X) %s",
+ failf(data, "ssl_handshake returned: (-0x%04X) %s",
-ret, errorbuf);
return CURLE_SSL_CONNECT_ERROR;
}
- 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);
-
+#if MBEDTLS_VERSION_NUMBER >= 0x03020000
+ {
+ char cipher_str[64];
+ uint16_t cipher_id;
+ cipher_id = (uint16_t)
+ mbedtls_ssl_get_ciphersuite_id_from_ssl(&backend->ssl);
+ mbed_cipher_suite_get_str(cipher_id, cipher_str, sizeof(cipher_str), true);
+ infof(data, "mbedTLS: Handshake complete, cipher is %s", cipher_str);
+ }
+#else
+ infof(data, "mbedTLS: Handshake complete");
+#endif
ret = mbedtls_ssl_get_verify_result(&backend->ssl);
if(!conn_config->verifyhost)
@@ -964,6 +1061,12 @@ mbed_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
peercert = mbedtls_ssl_get_peer_cert(&backend->ssl);
+ if(peercert) {
+ const CURLcode result = collect_server_cert(cf, data, peercert);
+ if(result)
+ return result;
+ }
+
if(peercert && data->set.verbose) {
#ifndef MBEDTLS_X509_REMOVE_INFO
const size_t bufsize = 16384;
@@ -1088,10 +1191,9 @@ mbed_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
DEBUGASSERT(backend);
- if(ssl_config->primary.sessionid) {
+ if(ssl_config->primary.cache_session) {
int ret;
mbedtls_ssl_session *our_ssl_sessionid;
- void *old_ssl_sessionid = NULL;
our_ssl_sessionid = malloc(sizeof(mbedtls_ssl_session));
if(!our_ssl_sessionid)
@@ -1108,15 +1210,11 @@ mbed_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
return CURLE_SSL_CONNECT_ERROR;
}
- /* If there's already a matching session in the cache, delete it */
+ /* If there is already a matching session in the cache, delete it */
Curl_ssl_sessionid_lock(data);
- 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, &connssl->peer,
- our_ssl_sessionid, 0,
- mbedtls_session_free);
+ retcode = Curl_ssl_set_sessionid(cf, data, &connssl->peer,
+ our_ssl_sessionid, 0,
+ mbedtls_session_free);
Curl_ssl_sessionid_unlock(data);
if(retcode)
return retcode;
@@ -1141,8 +1239,13 @@ static ssize_t mbed_send(struct Curl_cfilter *cf, struct Curl_easy *data,
ret = mbedtls_ssl_write(&backend->ssl, (unsigned char *)mem, len);
if(ret < 0) {
- *curlcode = (ret == MBEDTLS_ERR_SSL_WANT_WRITE) ?
- CURLE_AGAIN : CURLE_SEND_ERROR;
+ CURL_TRC_CF(data, cf, "mbedtls_ssl_write(len=%zu) -> -0x%04X",
+ len, -ret);
+ *curlcode = ((ret == MBEDTLS_ERR_SSL_WANT_WRITE)
+#ifdef TLS13_SUPPORT
+ || (ret == MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET)
+#endif
+ )? CURLE_AGAIN : CURLE_SEND_ERROR;
ret = -1;
}
@@ -1154,33 +1257,120 @@ static void mbedtls_close_all(struct Curl_easy *data)
(void)data;
}
-static void mbedtls_close(struct Curl_cfilter *cf, struct Curl_easy *data)
+static CURLcode mbedtls_shutdown(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool send_shutdown, bool *done)
{
struct ssl_connect_data *connssl = cf->ctx;
struct mbed_ssl_backend_data *backend =
(struct mbed_ssl_backend_data *)connssl->backend;
- char buf[32];
+ unsigned char buf[1024];
+ CURLcode result = CURLE_OK;
+ int ret;
+ size_t i;
- (void)data;
DEBUGASSERT(backend);
- /* Maybe the server has already sent a close notify alert.
- Read it to avoid an RST on the TCP connection. */
- (void)mbedtls_ssl_read(&backend->ssl, (unsigned char *)buf, sizeof(buf));
+ if(!backend->initialized || cf->shutdown) {
+ *done = TRUE;
+ return CURLE_OK;
+ }
+
+ connssl->io_need = CURL_SSL_IO_NEED_NONE;
+ *done = FALSE;
+
+ if(!backend->sent_shutdown) {
+ /* do this only once */
+ backend->sent_shutdown = TRUE;
+ if(send_shutdown) {
+ ret = mbedtls_ssl_close_notify(&backend->ssl);
+ switch(ret) {
+ case 0: /* we sent it, receive from the server */
+ break;
+ case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY: /* server also closed */
+ *done = TRUE;
+ goto out;
+ case MBEDTLS_ERR_SSL_WANT_READ:
+ connssl->io_need = CURL_SSL_IO_NEED_RECV;
+ goto out;
+ case MBEDTLS_ERR_SSL_WANT_WRITE:
+ connssl->io_need = CURL_SSL_IO_NEED_SEND;
+ goto out;
+ default:
+ CURL_TRC_CF(data, cf, "mbedtls_shutdown error -0x%04X", -ret);
+ result = CURLE_RECV_ERROR;
+ goto out;
+ }
+ }
+ }
+
+ /* SSL should now have started the shutdown from our side. Since it
+ * was not complete, we are lacking the close notify from the server. */
+ for(i = 0; i < 10; ++i) {
+ ret = mbedtls_ssl_read(&backend->ssl, buf, sizeof(buf));
+ /* This seems to be a bug in mbedTLS TLSv1.3 where it reports
+ * WANT_READ, but has not encountered an EAGAIN. */
+ if(ret == MBEDTLS_ERR_SSL_WANT_READ)
+ ret = mbedtls_ssl_read(&backend->ssl, buf, sizeof(buf));
+#ifdef TLS13_SUPPORT
+ if(ret == MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET)
+ continue;
+#endif
+ if(ret <= 0)
+ break;
+ }
- mbedtls_pk_free(&backend->pk);
- mbedtls_x509_crt_free(&backend->clicert);
- mbedtls_x509_crt_free(&backend->cacert);
+ if(ret > 0) {
+ /* still data coming in? */
+ CURL_TRC_CF(data, cf, "mbedtls_shutdown, still getting data");
+ }
+ else if(ret == 0 || (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY)) {
+ /* We got the close notify alert and are done. */
+ CURL_TRC_CF(data, cf, "mbedtls_shutdown done");
+ *done = TRUE;
+ }
+ else if(ret == MBEDTLS_ERR_SSL_WANT_READ) {
+ CURL_TRC_CF(data, cf, "mbedtls_shutdown, need RECV");
+ connssl->io_need = CURL_SSL_IO_NEED_RECV;
+ }
+ else if(ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
+ CURL_TRC_CF(data, cf, "mbedtls_shutdown, need SEND");
+ connssl->io_need = CURL_SSL_IO_NEED_SEND;
+ }
+ else {
+ CURL_TRC_CF(data, cf, "mbedtls_shutdown error -0x%04X", -ret);
+ result = CURLE_RECV_ERROR;
+ }
+
+out:
+ cf->shutdown = (result || *done);
+ return result;
+}
+
+static void mbedtls_close(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct mbed_ssl_backend_data *backend =
+ (struct mbed_ssl_backend_data *)connssl->backend;
+
+ (void)data;
+ DEBUGASSERT(backend);
+ if(backend->initialized) {
+ mbedtls_pk_free(&backend->pk);
+ mbedtls_x509_crt_free(&backend->clicert);
+ mbedtls_x509_crt_free(&backend->cacert);
#ifdef MBEDTLS_X509_CRL_PARSE_C
- mbedtls_x509_crl_free(&backend->crl);
+ 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);
+ Curl_safefree(backend->ciphersuites);
+ mbedtls_ssl_config_free(&backend->config);
+ mbedtls_ssl_free(&backend->ssl);
+ mbedtls_ctr_drbg_free(&backend->ctr_drbg);
#ifndef THREADING_SUPPORT
- mbedtls_entropy_free(&backend->entropy);
+ mbedtls_entropy_free(&backend->entropy);
#endif /* THREADING_SUPPORT */
+ backend->initialized = FALSE;
+ }
}
static ssize_t mbed_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
@@ -1198,16 +1388,21 @@ static ssize_t mbed_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
ret = mbedtls_ssl_read(&backend->ssl, (unsigned char *)buf,
buffersize);
-
if(ret <= 0) {
+ CURL_TRC_CF(data, cf, "mbedtls_ssl_read(len=%zu) -> -0x%04X",
+ buffersize, -ret);
if(ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY)
return 0;
-
*curlcode = ((ret == MBEDTLS_ERR_SSL_WANT_READ)
#ifdef TLS13_SUPPORT
|| (ret == MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET)
#endif
) ? CURLE_AGAIN : CURLE_RECV_ERROR;
+ if(*curlcode != CURLE_AGAIN) {
+ char errorbuf[128];
+ mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
+ failf(data, "ssl_read returned: (-0x%04X) %s", -ret, errorbuf);
+ }
return -1;
}
@@ -1290,7 +1485,7 @@ mbed_connect_common(struct Curl_cfilter *cf, struct Curl_easy *data,
}
if(ssl_connect_1 == connssl->connecting_state) {
- /* Find out how much more time we're allowed */
+ /* Find out how much more time we are allowed */
timeout_ms = Curl_timeleft(data, NULL, TRUE);
if(timeout_ms < 0) {
@@ -1303,9 +1498,7 @@ mbed_connect_common(struct Curl_cfilter *cf, struct Curl_easy *data,
return retcode;
}
- while(ssl_connect_2 == connssl->connecting_state ||
- ssl_connect_2_reading == connssl->connecting_state ||
- ssl_connect_2_writing == connssl->connecting_state) {
+ while(ssl_connect_2 == connssl->connecting_state) {
/* check allowed time left */
timeout_ms = Curl_timeleft(data, NULL, TRUE);
@@ -1316,14 +1509,13 @@ mbed_connect_common(struct Curl_cfilter *cf, struct Curl_easy *data,
return CURLE_OPERATION_TIMEDOUT;
}
- /* if ssl is expecting something, check if it's available. */
- if(connssl->connecting_state == ssl_connect_2_reading
- || connssl->connecting_state == ssl_connect_2_writing) {
+ /* if ssl is expecting something, check if it is available. */
+ if(connssl->io_need) {
- curl_socket_t writefd = ssl_connect_2_writing ==
- connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
- curl_socket_t readfd = ssl_connect_2_reading ==
- connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
+ curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND)?
+ sockfd:CURL_SOCKET_BAD;
+ curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV)?
+ sockfd:CURL_SOCKET_BAD;
what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
nonblocking ? 0 : timeout_ms);
@@ -1353,11 +1545,10 @@ mbed_connect_common(struct Curl_cfilter *cf, struct Curl_easy *data,
* ensuring that a client using select() or epoll() will always
* have a valid fdset to wait on.
*/
+ connssl->io_need = CURL_SSL_IO_NEED_NONE;
retcode = mbed_connect_step2(cf, data);
- if(retcode || (nonblocking &&
- (ssl_connect_2 == connssl->connecting_state ||
- ssl_connect_2_reading == connssl->connecting_state ||
- ssl_connect_2_writing == connssl->connecting_state)))
+ if(retcode ||
+ (nonblocking && (ssl_connect_2 == connssl->connecting_state)))
return retcode;
} /* repeat step2 until all transactions are done. */
@@ -1474,6 +1665,7 @@ const struct Curl_ssl Curl_ssl_mbedtls = {
SSLSUPP_CA_PATH |
SSLSUPP_CAINFO_BLOB |
+ SSLSUPP_CERTINFO |
SSLSUPP_PINNEDPUBKEY |
SSLSUPP_SSL_CTX |
SSLSUPP_HTTPS_PROXY,
@@ -1484,7 +1676,7 @@ const struct Curl_ssl Curl_ssl_mbedtls = {
mbedtls_cleanup, /* cleanup */
mbedtls_version, /* version */
Curl_none_check_cxn, /* check_cxn */
- Curl_none_shutdown, /* shutdown */
+ mbedtls_shutdown, /* shutdown */
mbedtls_data_pending, /* data_pending */
mbedtls_random, /* random */
Curl_none_cert_status_request, /* cert_status_request */
@@ -1501,7 +1693,6 @@ const struct Curl_ssl Curl_ssl_mbedtls = {
mbedtls_sha256sum, /* sha256sum */
NULL, /* associate_connection */
NULL, /* disassociate_connection */
- NULL, /* free_multi_ssl_backend_data */
mbed_recv, /* recv decrypted data */
mbed_send, /* send data to encrypt */
};
diff --git a/libs/libcurl/src/vtls/openssl.c b/libs/libcurl/src/vtls/openssl.c
index f53cb69471..7cc15350a4 100644
--- a/libs/libcurl/src/vtls/openssl.c
+++ b/libs/libcurl/src/vtls/openssl.c
@@ -254,13 +254,20 @@
#endif
#endif
+#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)
+typedef size_t numcert_t;
+#else
+typedef int numcert_t;
+#endif
+#define ossl_valsize_t numcert_t
+
#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
/* up2date versions of OpenSSL maintain reasonably secure defaults without
* breaking compatibility, so it is better not to override the defaults in curl
*/
#define DEFAULT_CIPHER_SELECTION NULL
#else
-/* ... but it is not the case with old versions of OpenSSL */
+/* not the case with old versions of OpenSSL */
#define DEFAULT_CIPHER_SELECTION \
"ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH"
#endif
@@ -307,14 +314,6 @@ typedef unsigned long sslerr_t;
#define USE_PRE_1_1_API (OPENSSL_VERSION_NUMBER < 0x10100000L)
#endif /* !LIBRESSL_VERSION_NUMBER */
-#if defined(HAVE_SSL_X509_STORE_SHARE)
-struct multi_ssl_backend_data {
- char *CAfile; /* CAfile path used to generate X509 store */
- X509_STORE *store; /* cached X509 store or NULL if none */
- struct curltime time; /* when the cached store was created */
-};
-#endif /* HAVE_SSL_X509_STORE_SHARE */
-
#define push_certinfo(_label, _num) \
do { \
long info_len = BIO_get_mem_data(mem, &ptr); \
@@ -381,7 +380,7 @@ static void X509V3_ext(struct Curl_easy *data,
for(i = 0; i < (int)sk_X509_EXTENSION_num(exts); i++) {
ASN1_OBJECT *obj;
- X509_EXTENSION *ext = sk_X509_EXTENSION_value(exts, i);
+ X509_EXTENSION *ext = sk_X509_EXTENSION_value(exts, (ossl_valsize_t)i);
BUF_MEM *biomem;
char namebuf[128];
BIO *bio_out = BIO_new(BIO_s_mem());
@@ -403,12 +402,6 @@ static void X509V3_ext(struct Curl_easy *data,
}
}
-#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)
-typedef size_t numcert_t;
-#else
-typedef int numcert_t;
-#endif
-
CURLcode Curl_ossl_certchain(struct Curl_easy *data, SSL *ssl)
{
CURLcode result;
@@ -438,7 +431,7 @@ CURLcode Curl_ossl_certchain(struct Curl_easy *data, SSL *ssl)
for(i = 0; i < (int)numcerts; i++) {
ASN1_INTEGER *num;
- X509 *x = sk_X509_value(sk, i);
+ X509 *x = sk_X509_value(sk, (ossl_valsize_t)i);
EVP_PKEY *pubkey = NULL;
int j;
char *ptr;
@@ -727,7 +720,10 @@ static int ossl_bio_cf_out_write(BIO *bio, const char *buf, int blen)
CURLcode result = CURLE_SEND_ERROR;
DEBUGASSERT(data);
- nwritten = Curl_conn_cf_send(cf->next, data, buf, blen, &result);
+ if(blen < 0)
+ return 0;
+
+ nwritten = Curl_conn_cf_send(cf->next, data, buf, (size_t)blen, &result);
CURL_TRC_CF(data, cf, "ossl_bio_cf_out_write(len=%d) -> %d, err=%d",
blen, (int)nwritten, result);
BIO_clear_retry_flags(bio);
@@ -752,8 +748,10 @@ static int ossl_bio_cf_in_read(BIO *bio, char *buf, int blen)
/* OpenSSL catches this case, so should we. */
if(!buf)
return 0;
+ if(blen < 0)
+ return 0;
- nread = Curl_conn_cf_recv(cf->next, data, buf, blen, &result);
+ nread = Curl_conn_cf_recv(cf->next, data, buf, (size_t)blen, &result);
CURL_TRC_CF(data, cf, "ossl_bio_cf_in_read(len=%d) -> %d, err=%d",
blen, (int)nread, result);
BIO_clear_retry_flags(bio);
@@ -844,7 +842,7 @@ static void ossl_keylog_callback(const SSL *ssl, const char *line)
#else
/*
* ossl_log_tls12_secret is called by libcurl to make the CLIENT_RANDOMs if the
- * OpenSSL being used doesn't have native support for doing that.
+ * OpenSSL being used does not have native support for doing that.
*/
static void
ossl_log_tls12_secret(const SSL *ssl, bool *keylog_done)
@@ -860,7 +858,7 @@ ossl_log_tls12_secret(const SSL *ssl, bool *keylog_done)
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \
!(defined(LIBRESSL_VERSION_NUMBER) && \
LIBRESSL_VERSION_NUMBER < 0x20700000L)
- /* ssl->s3 is not checked in openssl 1.1.0-pre6, but let's assume that
+ /* ssl->s3 is not checked in OpenSSL 1.1.0-pre6, but let's assume that
* we have a valid SSL context if we have a non-NULL session. */
SSL_get_client_random(ssl, client_random, SSL3_RANDOM_SIZE);
master_key_length = (int)
@@ -963,7 +961,7 @@ static int passwd_callback(char *buf, int num, int encrypting,
{
DEBUGASSERT(0 == encrypting);
- if(!encrypting) {
+ if(!encrypting && num >= 0) {
int klen = curlx_uztosi(strlen((char *)global_passwd));
if(num > klen) {
memcpy(buf, global_passwd, klen + 1);
@@ -1014,13 +1012,12 @@ static CURLcode ossl_seed(struct Curl_easy *data)
for(i = 0, i_max = len / sizeof(struct curltime); i < i_max; ++i) {
struct curltime tv = Curl_now();
Curl_wait_ms(1);
- tv.tv_sec *= i + 1;
- tv.tv_usec *= (unsigned int)i + 2;
- tv.tv_sec ^= ((Curl_now().tv_sec + Curl_now().tv_usec) *
- (i + 3)) << 8;
- tv.tv_usec ^= (unsigned int) ((Curl_now().tv_sec +
- Curl_now().tv_usec) *
- (i + 4)) << 16;
+ tv.tv_sec *= (time_t)i + 1;
+ tv.tv_usec *= (int)i + 2;
+ tv.tv_sec ^= ((Curl_now().tv_sec + (time_t)Curl_now().tv_usec) *
+ (time_t)(i + 3)) << 8;
+ tv.tv_usec ^= (int) ((Curl_now().tv_sec + (time_t)Curl_now().tv_usec) *
+ (time_t)(i + 4)) << 16;
memcpy(&randb[i * sizeof(struct curltime)], &tv,
sizeof(struct curltime));
}
@@ -1033,7 +1030,7 @@ static CURLcode ossl_seed(struct Curl_easy *data)
fname[0] = 0; /* blank it first */
RAND_file_name(fname, sizeof(fname));
if(fname[0]) {
- /* we got a file name to try */
+ /* we got a filename to try */
RAND_load_file(fname, RAND_LOAD_LENGTH);
if(rand_enough())
return CURLE_OK;
@@ -1369,7 +1366,7 @@ int cert_stuff(struct Curl_easy *data,
}
if(!params.cert) {
- failf(data, "ssl engine didn't initialized the certificate "
+ failf(data, "ssl engine did not initialized the certificate "
"properly.");
return 0;
}
@@ -1380,10 +1377,10 @@ int cert_stuff(struct Curl_easy *data,
sizeof(error_buffer)));
return 0;
}
- X509_free(params.cert); /* we don't need the handle any more... */
+ X509_free(params.cert); /* we do not need the handle any more... */
}
else {
- failf(data, "crypto engine not set, can't load certificate");
+ failf(data, "crypto engine not set, cannot load certificate");
return 0;
}
}
@@ -1479,7 +1476,7 @@ int cert_stuff(struct Curl_easy *data,
* Note that sk_X509_pop() is used below to make sure the cert is
* removed from the stack properly before getting passed to
* SSL_CTX_add_extra_chain_cert(), which takes ownership. Previously
- * we used sk_X509_value() instead, but then we'd clean it in the
+ * we used sk_X509_value() instead, but then we would clean it in the
* subsequent sk_X509_pop_free() call.
*/
X509 *x = sk_X509_pop(ca);
@@ -1572,10 +1569,10 @@ fail:
EVP_PKEY_free(priv_key);
return 0;
}
- EVP_PKEY_free(priv_key); /* we don't need the handle any more... */
+ EVP_PKEY_free(priv_key); /* we do not need the handle any more... */
}
else {
- failf(data, "crypto engine not set, can't load private key");
+ failf(data, "crypto engine not set, cannot load private key");
return 0;
}
}
@@ -1614,8 +1611,8 @@ fail:
#if !defined(OPENSSL_NO_RSA) && !defined(OPENSSL_IS_BORINGSSL) && \
!defined(OPENSSL_NO_DEPRECATED_3_0)
{
- /* If RSA is used, don't check the private key if its flags indicate
- * it doesn't support it. */
+ /* If RSA is used, do not check the private key if its flags indicate
+ * it does not support it. */
EVP_PKEY *priv_key = SSL_get_privatekey(ssl);
int pktype;
#ifdef HAVE_OPAQUE_EVP_PKEY
@@ -1681,7 +1678,7 @@ static int x509_name_oneline(X509_NAME *a, char *buf, size_t size)
if((size_t)biomem->length < size)
size = biomem->length;
else
- size--; /* don't overwrite the buffer end */
+ size--; /* do not overwrite the buffer end */
memcpy(buf, biomem->data, size);
buf[size] = 0;
@@ -1873,203 +1870,133 @@ static struct curl_slist *ossl_engines_list(struct Curl_easy *data)
return list;
}
-static void ossl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
+static CURLcode ossl_shutdown(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool send_shutdown, bool *done)
{
struct ssl_connect_data *connssl = cf->ctx;
struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
+ CURLcode result = CURLE_OK;
+ char buf[1024];
+ int nread, err;
+ unsigned long sslerr;
+ size_t i;
- (void)data;
DEBUGASSERT(octx);
+ if(!octx->ssl || cf->shutdown) {
+ *done = TRUE;
+ goto out;
+ }
- 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) {
- char buf[1024];
- int nread, err;
- long sslerr;
-
- /* Maybe the server has already sent a close notify alert.
- Read it to avoid an RST on the TCP connection. */
- ERR_clear_error();
+ connssl->io_need = CURL_SSL_IO_NEED_NONE;
+ *done = FALSE;
+ if(!(SSL_get_shutdown(octx->ssl) & SSL_SENT_SHUTDOWN)) {
+ /* We have not started the shutdown from our side yet. Check
+ * if the server already sent us one. */
+ ERR_clear_error();
+ for(i = 0; i < 10; ++i) {
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;
- size_t blen = sizeof(buf);
- CURL_TRC_CF(data, cf, "peer has shutdown TLS");
- /* SSL_read() will not longer touch the socket, let's receive
- * directly from the next filter to see if the underlying
- * connection has also been closed. */
- n = Curl_conn_cf_recv(cf->next, data, buf, blen, &result);
- if(!n) {
- connssl->peer_closed = TRUE;
- CURL_TRC_CF(data, cf, "peer closed connection");
- }
- }
- ERR_clear_error();
- if(connssl->peer_closed) {
- /* As the peer closed, we do not expect it to read anything more we
- * may send. It may be harmful, leading to TCP RST and delaying
- * a lingering close. Just leave. */
- CURL_TRC_CF(data, cf, "not from sending TLS shutdown on "
- "connection closed by peer");
- }
- else if(SSL_shutdown(octx->ssl) == 1) {
- CURL_TRC_CF(data, cf, "SSL shutdown finished");
+ CURL_TRC_CF(data, cf, "SSL shutdown not sent, read -> %d", nread);
+ if(nread <= 0)
+ break;
+ }
+ err = SSL_get_error(octx->ssl, nread);
+ if(!nread && err == SSL_ERROR_ZERO_RETURN) {
+ bool input_pending;
+ /* Yes, it did. */
+ if(!send_shutdown) {
+ CURL_TRC_CF(data, cf, "SSL shutdown received, not sending");
+ *done = TRUE;
+ goto out;
}
- else {
- 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 */
- CURL_TRC_CF(data, cf, "SSL shutdown, EOF from server");
- break;
- case SSL_ERROR_WANT_READ:
- /* SSL has send its notify and now wants to read the reply
- * from the server. We are not really interested in that. */
- CURL_TRC_CF(data, cf, "SSL shutdown sent");
- break;
- case SSL_ERROR_WANT_WRITE:
- CURL_TRC_CF(data, cf, "SSL shutdown send blocked");
- break;
- default:
- sslerr = ERR_get_error();
- CURL_TRC_CF(data, cf, "SSL shutdown, error: '%s', errno %d",
- (sslerr ?
- ossl_strerror(sslerr, buf, sizeof(buf)) :
- SSL_ERROR_to_str(err)),
- SOCKERRNO);
- break;
- }
+ else if(!cf->next->cft->is_alive(cf->next, data, &input_pending)) {
+ /* Server closed the connection after its closy notify. It
+ * seems not interested to see our close notify, so do not
+ * send it. We are done. */
+ connssl->peer_closed = TRUE;
+ CURL_TRC_CF(data, cf, "peer closed connection");
+ *done = TRUE;
+ goto out;
}
-
- ERR_clear_error();
- SSL_set_connect_state(octx->ssl);
}
+ if(send_shutdown && SSL_shutdown(octx->ssl) == 1) {
+ CURL_TRC_CF(data, cf, "SSL shutdown finished");
+ *done = TRUE;
+ goto out;
+ }
+ }
- SSL_free(octx->ssl);
- octx->ssl = NULL;
+ /* SSL should now have started the shutdown from our side. Since it
+ * was not complete, we are lacking the close notify from the server. */
+ for(i = 0; i < 10; ++i) {
+ ERR_clear_error();
+ nread = SSL_read(octx->ssl, buf, (int)sizeof(buf));
+ CURL_TRC_CF(data, cf, "SSL shutdown read -> %d", nread);
+ if(nread <= 0)
+ break;
}
- if(octx->ssl_ctx) {
- SSL_CTX_free(octx->ssl_ctx);
- octx->ssl_ctx = NULL;
- octx->x509_store_setup = FALSE;
+ if(SSL_get_shutdown(octx->ssl) & SSL_RECEIVED_SHUTDOWN) {
+ CURL_TRC_CF(data, cf, "SSL shutdown received, finished");
+ *done = TRUE;
+ goto out;
}
- if(octx->bio_method) {
- ossl_bio_cf_method_free(octx->bio_method);
- octx->bio_method = NULL;
+ err = SSL_get_error(octx->ssl, nread);
+ switch(err) {
+ case SSL_ERROR_ZERO_RETURN: /* no more data */
+ CURL_TRC_CF(data, cf, "SSL shutdown not received, but closed");
+ *done = TRUE;
+ break;
+ case SSL_ERROR_NONE: /* just did not get anything */
+ case SSL_ERROR_WANT_READ:
+ /* SSL has send its notify and now wants to read the reply
+ * from the server. We are not really interested in that. */
+ CURL_TRC_CF(data, cf, "SSL shutdown sent, want receive");
+ connssl->io_need = CURL_SSL_IO_NEED_RECV;
+ break;
+ case SSL_ERROR_WANT_WRITE:
+ CURL_TRC_CF(data, cf, "SSL shutdown send blocked");
+ connssl->io_need = CURL_SSL_IO_NEED_SEND;
+ break;
+ default:
+ /* Server seems to have closed the connection without sending us
+ * a close notify. */
+ sslerr = ERR_get_error();
+ CURL_TRC_CF(data, cf, "SSL shutdown, ignore recv error: '%s', errno %d",
+ (sslerr ?
+ ossl_strerror(sslerr, buf, sizeof(buf)) :
+ SSL_ERROR_to_str(err)),
+ SOCKERRNO);
+ *done = TRUE;
+ result = CURLE_OK;
+ break;
}
+
+out:
+ cf->shutdown = (result || *done);
+ return result;
}
-/*
- * This function is called to shut down the SSL layer but keep the
- * socket open (CCC - Clear Command Channel)
- */
-static int ossl_shutdown(struct Curl_cfilter *cf,
- struct Curl_easy *data)
+static void ossl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
- int retval = 0;
struct ssl_connect_data *connssl = cf->ctx;
- char buf[256]; /* We will use this for the OpenSSL error buffer, so it has
- to be at least 256 bytes long. */
- unsigned long sslerror;
- int nread;
- int buffsize;
- int err;
- bool done = FALSE;
struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
- int loop = 10;
+ (void)data;
DEBUGASSERT(octx);
-#ifndef CURL_DISABLE_FTP
- /* This has only been tested on the proftpd server, and the mod_tls code
- sends a close notify alert without waiting for a close notify alert in
- response. Thus we wait for a close notify alert from the server, but
- we do not send one. Let's hope other servers do the same... */
-
- if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE)
- (void)SSL_shutdown(octx->ssl);
-#endif
-
if(octx->ssl) {
- buffsize = (int)sizeof(buf);
- while(!done && loop--) {
- int what = SOCKET_READABLE(Curl_conn_cf_get_socket(cf, data),
- SSL_SHUTDOWN_TIMEOUT);
- if(what > 0) {
- ERR_clear_error();
-
- /* Something to read, let's do it and hope that it is the close
- notify alert from the server */
- 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 */
- case SSL_ERROR_ZERO_RETURN: /* no more data */
- /* This is the expected response. There was no data but only
- the close notify alert */
- done = TRUE;
- break;
- case SSL_ERROR_WANT_READ:
- /* there's data pending, re-invoke SSL_read() */
- infof(data, "SSL_ERROR_WANT_READ");
- break;
- case SSL_ERROR_WANT_WRITE:
- /* SSL wants a write. Really odd. Let's bail out. */
- infof(data, "SSL_ERROR_WANT_WRITE");
- done = TRUE;
- break;
- default:
- /* openssl/ssl.h says "look at error stack/return value/errno" */
- sslerror = ERR_get_error();
- failf(data, OSSL_PACKAGE " SSL_read on shutdown: %s, errno %d",
- (sslerror ?
- ossl_strerror(sslerror, buf, sizeof(buf)) :
- SSL_ERROR_to_str(err)),
- SOCKERRNO);
- done = TRUE;
- break;
- }
- }
- else if(0 == what) {
- /* timeout */
- failf(data, "SSL shutdown timeout");
- done = TRUE;
- }
- else {
- /* anything that gets here is fatally bad */
- failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
- retval = -1;
- done = TRUE;
- }
- } /* while()-loop for the select() */
-
- if(data->set.verbose) {
-#ifdef HAVE_SSL_GET_SHUTDOWN
- switch(SSL_get_shutdown(octx->ssl)) {
- case SSL_SENT_SHUTDOWN:
- infof(data, "SSL_get_shutdown() returned SSL_SENT_SHUTDOWN");
- break;
- case SSL_RECEIVED_SHUTDOWN:
- infof(data, "SSL_get_shutdown() returned SSL_RECEIVED_SHUTDOWN");
- break;
- case SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN:
- infof(data, "SSL_get_shutdown() returned SSL_SENT_SHUTDOWN|"
- "SSL_RECEIVED__SHUTDOWN");
- break;
- }
-#endif
- }
-
SSL_free(octx->ssl);
octx->ssl = NULL;
}
- return retval;
+ if(octx->ssl_ctx) {
+ SSL_CTX_free(octx->ssl_ctx);
+ octx->ssl_ctx = NULL;
+ octx->x509_store_setup = FALSE;
+ }
+ if(octx->bio_method) {
+ ossl_bio_cf_method_free(octx->bio_method);
+ octx->bio_method = NULL;
+ }
}
static void ossl_session_free(void *sessionid, size_t idsize)
@@ -2107,7 +2034,7 @@ static void ossl_close_all(struct Curl_easy *data)
/* ====================================================== */
/*
- * Match subjectAltName against the host name.
+ * Match subjectAltName against the hostname.
*/
static bool subj_alt_hostcheck(struct Curl_easy *data,
const char *match_pattern,
@@ -2137,7 +2064,7 @@ static bool subj_alt_hostcheck(struct Curl_easy *data,
Certification Authorities are encouraged to use the dNSName instead.
Matching is performed using the matching rules specified by
- [RFC2459]. If more than one identity of a given type is present in
+ [RFC2459]. If more than one identity of a given type is present in
the certificate (e.g., more than one dNSName name, a match in any one
of the set is considered acceptable.) Names may contain the wildcard
character * which is considered to match any single domain name
@@ -2208,7 +2135,7 @@ CURLcode Curl_ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
bool ipmatched = FALSE;
/* get amount of alternatives, RFC2459 claims there MUST be at least
- one, but we don't depend on it... */
+ one, but we do not depend on it... */
numalts = sk_GENERAL_NAME_num(altnames);
/* loop through all alternatives - until a dnsmatch */
@@ -2229,7 +2156,7 @@ CURLcode Curl_ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
switch(target) {
case GEN_DNS: /* name/pattern comparison */
- /* The OpenSSL man page explicitly says: "In general it cannot be
+ /* The OpenSSL manpage explicitly says: "In general it cannot be
assumed that the data returned by ASN1_STRING_data() is null
terminated or does not contain embedded nulls." But also that
"The actual format of the data will depend on the actual string
@@ -2239,7 +2166,7 @@ CURLcode Curl_ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
is always null-terminated.
*/
if((altlen == strlen(altptr)) &&
- /* if this isn't true, there was an embedded zero in the name
+ /* if this is not true, there was an embedded zero in the name
string and we cannot match it. */
subj_alt_hostcheck(data, altptr, altlen,
peer->hostname, hostlen,
@@ -2271,7 +2198,7 @@ CURLcode Curl_ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
/* an alternative name matched */
;
else if(dNSName || iPAddress) {
- const char *tname = (peer->type == CURL_SSL_PEER_DNS) ? "host name" :
+ const char *tname = (peer->type == CURL_SSL_PEER_DNS) ? "hostname" :
(peer->type == CURL_SSL_PEER_IPV4) ?
"ipv4 address" : "ipv6 address";
infof(data, " subjectAltName does not match %s %s", tname, peer->dispname);
@@ -2342,7 +2269,7 @@ CURLcode Curl_ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
else if(!Curl_cert_hostcheck((const char *)peer_CN,
peerlen, peer->hostname, hostlen)) {
failf(data, "SSL: certificate subject name '%s' does not match "
- "target host name '%s'", peer_CN, peer->dispname);
+ "target hostname '%s'", peer_CN, peer->dispname);
result = CURLE_PEER_FAILED_VERIFICATION;
}
else {
@@ -2358,9 +2285,9 @@ CURLcode Curl_ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
!defined(OPENSSL_NO_OCSP)
static CURLcode verifystatus(struct Curl_cfilter *cf,
- struct Curl_easy *data)
+ struct Curl_easy *data,
+ struct ossl_ctx *octx)
{
- struct ssl_connect_data *connssl = cf->ctx;
int i, ocsp_status;
#if defined(OPENSSL_IS_AWSLC)
const uint8_t *status;
@@ -2373,7 +2300,6 @@ static CURLcode verifystatus(struct Curl_cfilter *cf,
OCSP_BASICRESP *br = NULL;
X509_STORE *st = NULL;
STACK_OF(X509) *ch = NULL;
- struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
X509 *cert;
OCSP_CERTID *id = NULL;
int cert_status, crl_reason;
@@ -2381,9 +2307,10 @@ static CURLcode verifystatus(struct Curl_cfilter *cf,
int ret;
long len;
+ (void)cf;
DEBUGASSERT(octx);
- len = SSL_get_tlsext_status_ocsp_resp(octx->ssl, &status);
+ len = (long)SSL_get_tlsext_status_ocsp_resp(octx->ssl, &status);
if(!status) {
failf(data, "No OCSP response received");
@@ -2425,8 +2352,8 @@ static CURLcode verifystatus(struct Curl_cfilter *cf,
(defined(LIBRESSL_VERSION_NUMBER) && \
LIBRESSL_VERSION_NUMBER <= 0x2040200fL))
/* The authorized responder cert in the OCSP response MUST be signed by the
- peer cert's issuer (see RFC6960 section 4.2.2.2). If that's a root cert,
- no problem, but if it's an intermediate cert OpenSSL has a bug where it
+ peer cert's issuer (see RFC6960 section 4.2.2.2). If that is a root cert,
+ no problem, but if it is an intermediate cert OpenSSL has a bug where it
expects this issuer to be present in the chain embedded in the OCSP
response. So we add it if necessary. */
@@ -2464,7 +2391,7 @@ static CURLcode verifystatus(struct Curl_cfilter *cf,
}
for(i = 0; i < (int)sk_X509_num(ch); i++) {
- X509 *issuer = sk_X509_value(ch, i);
+ X509 *issuer = sk_X509_value(ch, (ossl_valsize_t)i);
if(X509_check_issued(issuer, cert) == X509_V_OK) {
id = OCSP_cert_to_id(EVP_sha1(), cert, issuer);
break;
@@ -2525,7 +2452,7 @@ end:
#endif /* USE_OPENSSL */
-/* The SSL_CTRL_SET_MSG_CALLBACK doesn't exist in ancient OpenSSL versions
+/* The SSL_CTRL_SET_MSG_CALLBACK does not exist in ancient OpenSSL versions
and thus this cannot be done there. */
#ifdef SSL_CTRL_SET_MSG_CALLBACK
@@ -2710,7 +2637,7 @@ static void ossl_trace(int direction, int ssl_ver, int content_type,
ssl_ver >>= 8; /* check the upper 8 bits only below */
- /* SSLv2 doesn't seem to have TLS record-type headers, so OpenSSL
+ /* SSLv2 does not seem to have TLS record-type headers, so OpenSSL
* always pass-up content-type as 0. But the interesting message-type
* is at 'buf[0]'.
*/
@@ -2797,7 +2724,7 @@ ossl_set_ssl_version_min_max(struct Curl_cfilter *cf, SSL_CTX *ctx)
}
/* CURL_SSLVERSION_DEFAULT means that no option was selected.
- We don't want to pass 0 to SSL_CTX_set_min_proto_version as
+ We do not want to pass 0 to SSL_CTX_set_min_proto_version as
it would enable all versions down to the lowest supported by
the library.
So we skip this, and stay with the library default
@@ -2809,7 +2736,7 @@ ossl_set_ssl_version_min_max(struct Curl_cfilter *cf, SSL_CTX *ctx)
}
/* ... then, TLS max version */
- curl_ssl_version_max = conn_config->version_max;
+ curl_ssl_version_max = (long)conn_config->version_max;
/* convert curl max SSL version option to OpenSSL constant */
switch(curl_ssl_version_max) {
@@ -2850,6 +2777,9 @@ ossl_set_ssl_version_min_max(struct Curl_cfilter *cf, SSL_CTX *ctx)
typedef uint32_t ctx_option_t;
#elif OPENSSL_VERSION_NUMBER >= 0x30000000L
typedef uint64_t ctx_option_t;
+#elif OPENSSL_VERSION_NUMBER >= 0x10100000L && \
+ !defined(LIBRESSL_VERSION_NUMBER)
+typedef unsigned long ctx_option_t;
#else
typedef long ctx_option_t;
#endif
@@ -2857,14 +2787,14 @@ typedef long ctx_option_t;
#if (OPENSSL_VERSION_NUMBER < 0x10100000L) /* 1.1.0 */
static CURLcode
ossl_set_ssl_version_min_max_legacy(ctx_option_t *ctx_options,
- struct Curl_cfilter *cf,
- struct Curl_easy *data)
+ struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
long ssl_version = conn_config->version;
long ssl_version_max = conn_config->version_max;
- (void) data; /* In case it's unused. */
+ (void) data; /* In case it is unused. */
switch(ssl_version) {
case CURL_SSLVERSION_TLSv1_3:
@@ -2937,42 +2867,25 @@ CURLcode Curl_ossl_add_session(struct Curl_cfilter *cf,
SSL_SESSION *session)
{
const struct ssl_config_data *config;
- bool isproxy;
- bool added = FALSE;
+ CURLcode result = CURLE_OK;
if(!cf || !data)
goto out;
- isproxy = Curl_ssl_cf_is_proxy(cf);
-
config = Curl_ssl_cf_get_config(cf, data);
- if(config->primary.sessionid) {
- bool incache;
- void *old_session = NULL;
+ if(config->primary.cache_session) {
Curl_ssl_sessionid_lock(data);
- if(isproxy)
- incache = FALSE;
- else
- 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) {
- added = TRUE;
- Curl_ssl_addsessionid(cf, data, peer, session, 0, ossl_session_free);
- }
+ result = Curl_ssl_set_sessionid(cf, data, peer, session, 0,
+ ossl_session_free);
+ session = NULL; /* call has taken ownership */
Curl_ssl_sessionid_unlock(data);
}
out:
- if(!added)
+ if(session)
ossl_session_free(session, 0);
- return CURLE_OK;
+ return result;
}
/* The "new session" callback must return zero if the session can be removed
@@ -3017,7 +2930,7 @@ static CURLcode load_cacert_from_memory(X509_STORE *store,
/* add each entry from PEM file to x509_store */
for(i = 0; i < (int)sk_X509_INFO_num(inf); ++i) {
- itmp = sk_X509_INFO_value(inf, i);
+ itmp = sk_X509_INFO_value(inf, (ossl_valsize_t)i);
if(itmp->x509) {
if(X509_STORE_add_cert(store, itmp->x509)) {
++count;
@@ -3043,7 +2956,7 @@ static CURLcode load_cacert_from_memory(X509_STORE *store,
sk_X509_INFO_pop_free(inf, X509_INFO_free);
BIO_free(cbio);
- /* if we didn't end up importing anything, treat that as an error */
+ /* if we did not end up importing anything, treat that as an error */
return (count > 0) ? CURLE_OK : CURLE_SSL_CACERT_BADFILE;
}
@@ -3164,7 +3077,7 @@ static CURLcode import_windows_cert_store(struct Curl_easy *data,
else
continue;
- x509 = d2i_X509(NULL, &encoded_cert, pContext->cbCertEncoded);
+ x509 = d2i_X509(NULL, &encoded_cert, (long)pContext->cbCertEncoded);
if(!x509)
continue;
@@ -3302,8 +3215,8 @@ static CURLcode populate_x509_store(struct Curl_cfilter *cf,
#ifdef CURL_CA_FALLBACK
if(!ssl_cafile && !ssl_capath &&
!imported_native_ca && !imported_ca_info_blob) {
- /* verifying the peer without any CA certificates won't
- work so use openssl's built-in default as fallback */
+ /* verifying the peer without any CA certificates will not
+ work so use OpenSSL's built-in default as fallback */
X509_STORE_set_default_paths(store);
}
#endif
@@ -3328,7 +3241,7 @@ static CURLcode populate_x509_store(struct Curl_cfilter *cf,
if(verifypeer) {
/* Try building a chain using issuers in the trusted store first to avoid
- problems with server-sent legacy intermediates. Newer versions of
+ problems with server-sent legacy intermediates. Newer versions of
OpenSSL do alternate chain checking by default but we do not know how to
determine that in a reliable manner.
https://rt.openssl.org/Ticket/Display.html?id=3621&user=guest&pass=guest
@@ -3355,23 +3268,49 @@ static CURLcode populate_x509_store(struct Curl_cfilter *cf,
}
#if defined(HAVE_SSL_X509_STORE_SHARE)
-static bool cached_x509_store_expired(const struct Curl_easy *data,
- const struct multi_ssl_backend_data *mb)
+
+/* key to use at `multi->proto_hash` */
+#define MPROTO_OSSL_X509_KEY "tls:ossl:x509:share"
+
+struct ossl_x509_share {
+ char *CAfile; /* CAfile path used to generate X509 store */
+ X509_STORE *store; /* cached X509 store or NULL if none */
+ struct curltime time; /* when the cached store was created */
+};
+
+static void oss_x509_share_free(void *key, size_t key_len, void *p)
{
- const struct ssl_general_config *cfg = &data->set.general_ssl;
- struct curltime now = Curl_now();
- timediff_t elapsed_ms = Curl_timediff(now, mb->time);
- timediff_t timeout_ms = cfg->ca_cache_timeout * (timediff_t)1000;
+ struct ossl_x509_share *share = p;
+ DEBUGASSERT(key_len == (sizeof(MPROTO_OSSL_X509_KEY)-1));
+ DEBUGASSERT(!memcmp(MPROTO_OSSL_X509_KEY, key, key_len));
+ (void)key;
+ (void)key_len;
+ if(share->store) {
+ X509_STORE_free(share->store);
+ }
+ free(share->CAfile);
+ free(share);
+}
- if(timeout_ms < 0)
- return false;
+static bool
+cached_x509_store_expired(const struct Curl_easy *data,
+ const struct ossl_x509_share *mb)
+{
+ const struct ssl_general_config *cfg = &data->set.general_ssl;
+ if(cfg->ca_cache_timeout < 0)
+ return FALSE;
+ else {
+ struct curltime now = Curl_now();
+ timediff_t elapsed_ms = Curl_timediff(now, mb->time);
+ timediff_t timeout_ms = cfg->ca_cache_timeout * (timediff_t)1000;
- return elapsed_ms >= timeout_ms;
+ return elapsed_ms >= timeout_ms;
+ }
}
-static bool cached_x509_store_different(
- struct Curl_cfilter *cf,
- const struct multi_ssl_backend_data *mb)
+static bool
+cached_x509_store_different(struct Curl_cfilter *cf,
+ const struct ossl_x509_share *mb)
{
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
if(!mb->CAfile || !conn_config->CAfile)
@@ -3384,15 +3323,17 @@ static X509_STORE *get_cached_x509_store(struct Curl_cfilter *cf,
const struct Curl_easy *data)
{
struct Curl_multi *multi = data->multi;
+ struct ossl_x509_share *share;
X509_STORE *store = NULL;
DEBUGASSERT(multi);
- if(multi &&
- multi->ssl_backend_data &&
- multi->ssl_backend_data->store &&
- !cached_x509_store_expired(data, multi->ssl_backend_data) &&
- !cached_x509_store_different(cf, multi->ssl_backend_data)) {
- store = multi->ssl_backend_data->store;
+ share = multi? Curl_hash_pick(&multi->proto_hash,
+ (void *)MPROTO_OSSL_X509_KEY,
+ sizeof(MPROTO_OSSL_X509_KEY)-1) : NULL;
+ if(share && share->store &&
+ !cached_x509_store_expired(data, share) &&
+ !cached_x509_store_different(cf, share)) {
+ store = share->store;
}
return store;
@@ -3404,20 +3345,28 @@ static void set_cached_x509_store(struct Curl_cfilter *cf,
{
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
struct Curl_multi *multi = data->multi;
- struct multi_ssl_backend_data *mbackend;
+ struct ossl_x509_share *share;
DEBUGASSERT(multi);
if(!multi)
return;
+ share = Curl_hash_pick(&multi->proto_hash,
+ (void *)MPROTO_OSSL_X509_KEY,
+ sizeof(MPROTO_OSSL_X509_KEY)-1);
- if(!multi->ssl_backend_data) {
- multi->ssl_backend_data = calloc(1, sizeof(struct multi_ssl_backend_data));
- if(!multi->ssl_backend_data)
+ if(!share) {
+ share = calloc(1, sizeof(*share));
+ if(!share)
return;
+ if(!Curl_hash_add2(&multi->proto_hash,
+ (void *)MPROTO_OSSL_X509_KEY,
+ sizeof(MPROTO_OSSL_X509_KEY)-1,
+ share, oss_x509_share_free)) {
+ free(share);
+ return;
+ }
}
- mbackend = multi->ssl_backend_data;
-
if(X509_STORE_up_ref(store)) {
char *CAfile = NULL;
@@ -3429,14 +3378,14 @@ static void set_cached_x509_store(struct Curl_cfilter *cf,
}
}
- if(mbackend->store) {
- X509_STORE_free(mbackend->store);
- free(mbackend->CAfile);
+ if(share->store) {
+ X509_STORE_free(share->store);
+ free(share->CAfile);
}
- mbackend->time = Curl_now();
- mbackend->store = store;
- mbackend->CAfile = CAfile;
+ share->time = Curl_now();
+ share->store = store;
+ share->CAfile = CAfile;
}
}
@@ -3451,7 +3400,7 @@ CURLcode Curl_ssl_setup_x509_store(struct Curl_cfilter *cf,
bool cache_criteria_met;
/* Consider the X509 store cacheable if it comes exclusively from a CAfile,
- or no source is provided and we are falling back to openssl's built-in
+ or no source is provided and we are falling back to OpenSSL's built-in
default. */
cache_criteria_met = (data->set.general_ssl.ca_cache_timeout != 0) &&
conn_config->verifypeer &&
@@ -3504,15 +3453,12 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx,
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);
- const long int ssl_version = conn_config->version;
+ const long int ssl_version_min = 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];
-#ifdef USE_ECH
- struct ssl_connect_data *connssl = cf->ctx;
-#endif
/* Make funny stuff to get random input */
result = ossl_seed(data);
@@ -3523,8 +3469,8 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx,
switch(transport) {
case TRNSPRT_TCP:
- /* check to see if we've been told to use an explicit SSL/TLS version */
- switch(ssl_version) {
+ /* check to see if we have been told to use an explicit SSL/TLS version */
+ switch(ssl_version_min) {
case CURL_SSLVERSION_DEFAULT:
case CURL_SSLVERSION_TLSv1:
case CURL_SSLVERSION_TLSv1_0:
@@ -3550,11 +3496,12 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx,
}
break;
case TRNSPRT_QUIC:
- if((ssl_version != CURL_SSLVERSION_DEFAULT) &&
- (ssl_version < CURL_SSLVERSION_TLSv1_3)) {
+ if(conn_config->version_max &&
+ (conn_config->version_max != CURL_SSLVERSION_MAX_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)
@@ -3573,7 +3520,7 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx,
octx->ssl_ctx = SSL_CTX_new(req_method);
if(!octx->ssl_ctx) {
- failf(data, "SSL: couldn't create a context: %s",
+ failf(data, "SSL: could not create a context: %s",
ossl_strerror(ERR_peek_error(), error_buffer, sizeof(error_buffer)));
return CURLE_OUT_OF_MEMORY;
}
@@ -3594,12 +3541,12 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx,
/* OpenSSL contains code to work around lots of bugs and flaws in various
SSL-implementations. SSL_CTX_set_options() is used to enabled those
- work-arounds. The man page for this option states that SSL_OP_ALL enables
+ work-arounds. The manpage for this option states that SSL_OP_ALL enables
all the work-arounds and that "It is usually safe to use SSL_OP_ALL to
enable the bug workaround options if compatibility with somewhat broken
implementations is desired."
- The "-no_ticket" option was introduced in OpenSSL 0.9.8j. It's a flag to
+ The "-no_ticket" option was introduced in OpenSSL 0.9.8j. it is a flag to
disable "rfc4507bis session ticket support". rfc4507bis was later turned
into the proper RFC5077: https://datatracker.ietf.org/doc/html/rfc5077
@@ -3640,17 +3587,17 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx,
#ifdef SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG
/* mitigate CVE-2010-4180 */
- ctx_options &= ~SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG;
+ ctx_options &= ~(ctx_option_t)SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG;
#endif
#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
/* unless the user explicitly asks to allow the protocol vulnerability we
use the work-around */
if(!ssl_config->enable_beast)
- ctx_options &= ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
+ ctx_options &= ~(ctx_option_t)SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
#endif
- switch(ssl_version) {
+ switch(ssl_version_min) {
case CURL_SSLVERSION_SSLv2:
case CURL_SSLVERSION_SSLv3:
return CURLE_NOT_BUILT_IN;
@@ -3752,7 +3699,7 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx,
infof(data, "Using TLS-SRP username: %s", ssl_username);
if(!SSL_CTX_set_srp_username(octx->ssl_ctx, ssl_username)) {
- failf(data, "Unable to set SRP user name");
+ failf(data, "Unable to set SRP username");
return CURLE_BAD_FUNCTION_ARGUMENT;
}
if(!SSL_CTX_set_srp_password(octx->ssl_ctx, ssl_password)) {
@@ -3785,7 +3732,7 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx,
#endif
if(cb_new_session) {
- /* Enable the session cache because it's a prerequisite for the
+ /* Enable the session cache because it is a prerequisite for the
* "new session" callback. Use the "external storage" mode to prevent
* OpenSSL from creating an internal session cache.
*/
@@ -3821,7 +3768,7 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx,
SSL_free(octx->ssl);
octx->ssl = SSL_new(octx->ssl_ctx);
if(!octx->ssl) {
- failf(data, "SSL: couldn't create a context (handle)");
+ failf(data, "SSL: could not create a context (handle)");
return CURLE_OUT_OF_MEMORY;
}
@@ -3876,7 +3823,7 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx,
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");
+ infof(data, "ECH: cannot base64 decode ECHConfig from command line");
if(data->set.tls_ech & CURLECH_HARD)
return result;
}
@@ -3910,7 +3857,8 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx,
else {
struct Curl_dns_entry *dns = NULL;
- dns = Curl_fetch_addr(data, connssl->peer.hostname, connssl->peer.port);
+ if(peer->hostname)
+ dns = Curl_fetch_addr(data, peer->hostname, peer->port);
if(!dns) {
infof(data, "ECH: requested but no DNS info available");
if(data->set.tls_ech & CURLECH_HARD)
@@ -3940,7 +3888,7 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx,
# endif
else {
trying_ech_now = 1;
- infof(data, "ECH: imported ECHConfigList of length %ld", elen);
+ infof(data, "ECH: imported ECHConfigList of length %zu", elen);
}
}
else {
@@ -3953,15 +3901,15 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx,
}
# ifdef OPENSSL_IS_BORINGSSL
if(trying_ech_now && outername) {
- infof(data, "ECH: setting public_name not supported with boringssl");
+ 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);
+ peer->hostname ? peer->hostname : "NULL", outername);
result = SSL_ech_set_server_names(octx->ssl,
- connssl->peer.hostname, outername,
+ peer->hostname, outername,
0 /* do send outer */);
if(result != 1) {
infof(data, "ECH: rv failed to set server name(s) %d [ERROR]", result);
@@ -3971,7 +3919,7 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx,
# 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]");
+ infof(data, "ECH: cannot force TLSv1.3 [ERROR]");
return CURLE_SSL_CONNECT_ERROR;
}
}
@@ -3980,7 +3928,7 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx,
#endif
octx->reused_session = FALSE;
- if(ssl_config->primary.sessionid && transport == TRNSPRT_TCP) {
+ if(ssl_config->primary.cache_session && transport == TRNSPRT_TCP) {
Curl_ssl_sessionid_lock(data);
if(!Curl_ssl_getsessionid(cf, data, peer, &ssl_sessionid, NULL)) {
/* we got a session id, use it! */
@@ -4041,7 +3989,7 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,
/* with OpenSSL v1.1.1 we get an alternative to SSL_set_bio() that works
* without backward compat quirks. Every call takes one reference, so we
* up it and pass. SSL* then owns it and will free.
- * We check on the function in configure, since libressl and friends
+ * 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(octx->ssl, bio);
@@ -4131,11 +4079,10 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf,
struct ssl_connect_data *connssl = cf->ctx;
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(ssl_connect_2 == connssl->connecting_state);
DEBUGASSERT(octx);
+ connssl->io_need = CURL_SSL_IO_NEED_NONE;
ERR_clear_error();
err = SSL_connect(octx->ssl);
@@ -4150,14 +4097,11 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf,
}
#ifndef HAVE_KEYLOG_CALLBACK
- if(Curl_tls_keylog_enabled()) {
- /* If key logging is enabled, wait for the handshake to complete and then
- * proceed with logging secrets (for TLS 1.2 or older).
- */
- bool done = FALSE;
- ossl_log_tls12_secret(octx->ssl, &done);
- octx->keylog_done = done;
- }
+ /* If key logging is enabled, wait for the handshake to complete and then
+ * proceed with logging secrets (for TLS 1.2 or older).
+ */
+ if(Curl_tls_keylog_enabled() && !octx->keylog_done)
+ ossl_log_tls12_secret(octx->ssl, &octx->keylog_done);
#endif
/* 1 is fine
@@ -4167,11 +4111,11 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf,
int detail = SSL_get_error(octx->ssl, err);
if(SSL_ERROR_WANT_READ == detail) {
- connssl->connecting_state = ssl_connect_2_reading;
+ connssl->io_need = CURL_SSL_IO_NEED_RECV;
return CURLE_OK;
}
if(SSL_ERROR_WANT_WRITE == detail) {
- connssl->connecting_state = ssl_connect_2_writing;
+ connssl->io_need = CURL_SSL_IO_NEED_SEND;
return CURLE_OK;
}
#ifdef SSL_ERROR_WANT_ASYNC
@@ -4198,7 +4142,7 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf,
int lib;
int reason;
- /* the connection failed, we're not waiting for anything else. */
+ /* the connection failed, we are not waiting for anything else. */
connssl->connecting_state = ssl_connect_2;
/* Get the earliest error code from the thread's error queue and remove
@@ -4259,7 +4203,7 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf,
/* detail is already set to the SSL error above */
- /* If we e.g. use SSLv2 request-method and the server doesn't like us
+ /* If we e.g. use SSLv2 request-method and the server does not like us
* (RST connection, etc.), OpenSSL gives no explanation whatsoever and
* the SO_ERROR is also lost.
*/
@@ -4285,7 +4229,7 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf,
int psigtype_nid = NID_undef;
const char *negotiated_group_name = NULL;
- /* we connected fine, we're not waiting for anything else. */
+ /* we connected fine, we are not waiting for anything else. */
connssl->connecting_state = ssl_connect_3;
#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
@@ -4398,7 +4342,7 @@ static CURLcode ossl_pkp_pin_peer_pubkey(struct Curl_easy *data, X509* cert,
/* Result is returned to caller */
CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
- /* if a path wasn't specified, don't pin */
+ /* if a path was not specified, do not pin */
if(!pinnedpubkey)
return CURLE_OK;
@@ -4424,7 +4368,7 @@ static CURLcode ossl_pkp_pin_peer_pubkey(struct Curl_easy *data, X509* cert,
/*
* These checks are verifying we got back the same values as when we
- * sized the buffer. It's pretty weak since they should always be the
+ * sized the buffer. it is pretty weak since they should always be the
* same. But it gives us something to test.
*/
if((len1 != len2) || !temp || ((temp - buff1) != len1))
@@ -4551,7 +4495,7 @@ CURLcode Curl_oss_check_peer_cert(struct Curl_cfilter *cf,
if(!strict)
return CURLE_OK;
- failf(data, "SSL: couldn't get peer certificate");
+ failf(data, "SSL: could not get peer certificate");
return CURLE_PEER_FAILED_VERIFICATION;
}
@@ -4592,7 +4536,7 @@ CURLcode Curl_oss_check_peer_cert(struct Curl_cfilter *cf,
buffer, sizeof(buffer));
if(rc) {
if(strict)
- failf(data, "SSL: couldn't get X509-issuer name");
+ failf(data, "SSL: could not get X509-issuer name");
result = CURLE_PEER_FAILED_VERIFICATION;
}
else {
@@ -4695,8 +4639,8 @@ CURLcode Curl_oss_check_peer_cert(struct Curl_cfilter *cf,
#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
!defined(OPENSSL_NO_OCSP)
if(conn_config->verifystatus && !octx->reused_session) {
- /* don't do this after Session ID reuse */
- result = verifystatus(cf, data);
+ /* do not do this after Session ID reuse */
+ result = verifystatus(cf, data, octx);
if(result) {
/* when verifystatus failed, remove the session id from the cache again
if present */
@@ -4721,7 +4665,7 @@ CURLcode Curl_oss_check_peer_cert(struct Curl_cfilter *cf,
#endif
if(!strict)
- /* when not strict, we don't bother about the verify cert problems */
+ /* when not strict, we do not bother about the verify cert problems */
result = CURLE_OK;
#ifndef CURL_DISABLE_PROXY
@@ -4754,7 +4698,7 @@ static CURLcode ossl_connect_step3(struct Curl_cfilter *cf,
/*
* We check certificates to authenticate the server; otherwise we risk
- * man-in-the-middle attack; NEVERTHELESS, if we're told explicitly not to
+ * man-in-the-middle attack; NEVERTHELESS, if we are told explicitly not to
* verify the peer, ignore faults and failures from the server cert
* operations.
*/
@@ -4783,7 +4727,7 @@ static CURLcode ossl_connect_common(struct Curl_cfilter *cf,
}
if(ssl_connect_1 == connssl->connecting_state) {
- /* Find out how much more time we're allowed */
+ /* Find out how much more time we are allowed */
const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
if(timeout_ms < 0) {
@@ -4797,9 +4741,7 @@ static CURLcode ossl_connect_common(struct Curl_cfilter *cf,
goto out;
}
- while(ssl_connect_2 == connssl->connecting_state ||
- ssl_connect_2_reading == connssl->connecting_state ||
- ssl_connect_2_writing == connssl->connecting_state) {
+ while(ssl_connect_2 == connssl->connecting_state) {
/* check allowed time left */
const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
@@ -4811,15 +4753,13 @@ static CURLcode ossl_connect_common(struct Curl_cfilter *cf,
goto out;
}
- /* if ssl is expecting something, check if it's available. */
- if(!nonblocking &&
- (connssl->connecting_state == ssl_connect_2_reading ||
- connssl->connecting_state == ssl_connect_2_writing)) {
+ /* if ssl is expecting something, check if it is available. */
+ if(!nonblocking && connssl->io_need) {
- curl_socket_t writefd = ssl_connect_2_writing ==
- connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
- curl_socket_t readfd = ssl_connect_2_reading ==
- connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
+ curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND)?
+ sockfd:CURL_SOCKET_BAD;
+ curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV)?
+ sockfd:CURL_SOCKET_BAD;
what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
timeout_ms);
@@ -4845,10 +4785,7 @@ static CURLcode ossl_connect_common(struct Curl_cfilter *cf,
* or epoll() will always have a valid fdset to wait on.
*/
result = ossl_connect_step2(cf, data);
- if(result || (nonblocking &&
- (ssl_connect_2 == connssl->connecting_state ||
- ssl_connect_2_reading == connssl->connecting_state ||
- ssl_connect_2_writing == connssl->connecting_state)))
+ if(result || (nonblocking && (ssl_connect_2 == connssl->connecting_state)))
goto out;
} /* repeat step2 until all transactions are done. */
@@ -5031,7 +4968,7 @@ static ssize_t ossl_recv(struct Curl_cfilter *cf,
break;
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
- /* there's data pending, re-invoke SSL_read() */
+ /* there is data pending, re-invoke SSL_read() */
*curlcode = CURLE_AGAIN;
nread = -1;
goto out;
@@ -5065,7 +5002,7 @@ static ssize_t ossl_recv(struct Curl_cfilter *cf,
/* For debug builds be a little stricter and error on any
SSL_ERROR_SYSCALL. For example a server may have closed the connection
abruptly without a close_notify alert. For compatibility with older
- peers we don't do this by default. #4624
+ peers we do not do this by default. #4624
We can use this to gauge how many users may be affected, and
if it goes ok eventually transition to allow in dev and release with
@@ -5099,7 +5036,7 @@ static size_t ossl_version(char *buffer, size_t size)
#ifdef LIBRESSL_VERSION_NUMBER
#ifdef HAVE_OPENSSL_VERSION
char *p;
- int count;
+ size_t count;
const char *ver = OpenSSL_version(OPENSSL_VERSION);
const char expected[] = OSSL_PACKAGE " "; /* ie "LibreSSL " */
if(strncasecompare(ver, expected, sizeof(expected) - 1)) {
@@ -5181,14 +5118,14 @@ static CURLcode ossl_random(struct Curl_easy *data,
int rc;
if(data) {
if(ossl_seed(data)) /* Initiate the seed if not already done */
- return CURLE_FAILED_INIT; /* couldn't seed for some reason */
+ return CURLE_FAILED_INIT; /* could not seed for some reason */
}
else {
if(!rand_enough())
return CURLE_FAILED_INIT;
}
/* RAND_bytes() returns 1 on success, 0 otherwise. */
- rc = RAND_bytes(entropy, curlx_uztosi(length));
+ rc = RAND_bytes(entropy, (ossl_valsize_t)curlx_uztosi(length));
return (rc == 1 ? CURLE_OK : CURLE_FAILED_INIT);
}
@@ -5236,20 +5173,6 @@ static void *ossl_get_internals(struct ssl_connect_data *connssl,
(void *)octx->ssl_ctx : (void *)octx->ssl;
}
-static void ossl_free_multi_ssl_backend_data(
- struct multi_ssl_backend_data *mbackend)
-{
-#if defined(HAVE_SSL_X509_STORE_SHARE)
- if(mbackend->store) {
- X509_STORE_free(mbackend->store);
- }
- free(mbackend->CAfile);
- free(mbackend);
-#else /* HAVE_SSL_X509_STORE_SHARE */
- (void)mbackend;
-#endif /* HAVE_SSL_X509_STORE_SHARE */
-}
-
const struct Curl_ssl Curl_ssl_openssl = {
{ CURLSSLBACKEND_OPENSSL, "openssl" }, /* info */
@@ -5264,6 +5187,7 @@ const struct Curl_ssl Curl_ssl_openssl = {
#ifdef USE_ECH
SSLSUPP_ECH |
#endif
+ SSLSUPP_CA_CACHE |
SSLSUPP_HTTPS_PROXY,
sizeof(struct ossl_ctx),
@@ -5293,7 +5217,6 @@ const struct Curl_ssl Curl_ssl_openssl = {
#endif
NULL, /* use of data in this connection */
NULL, /* remote of data from this connection */
- ossl_free_multi_ssl_backend_data, /* free_multi_ssl_backend_data */
ossl_recv, /* recv decrypted data */
ossl_send, /* send data to encrypt */
};
diff --git a/libs/libcurl/src/vtls/openssl.h b/libs/libcurl/src/vtls/openssl.h
index f46fbf3722..46e75efbf1 100644
--- a/libs/libcurl/src/vtls/openssl.h
+++ b/libs/libcurl/src/vtls/openssl.h
@@ -45,8 +45,9 @@ struct ossl_ctx {
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);
+ /* Set to true once a valid keylog entry has been created to avoid dupes.
+ This is a bool and not a bitfield because it is passed by address. */
+ bool keylog_done;
#endif
BIT(x509_store_setup); /* x509 store has been set up */
BIT(reused_session); /* session-ID was reused for this */
diff --git a/libs/libcurl/src/vtls/rustls.c b/libs/libcurl/src/vtls/rustls.c
index 0e65c37f37..70592e6f76 100644
--- a/libs/libcurl/src/vtls/rustls.c
+++ b/libs/libcurl/src/vtls/rustls.c
@@ -48,6 +48,7 @@ struct rustls_ssl_backend_data
struct rustls_connection *conn;
size_t plain_out_buffered;
BIT(data_in_pending);
+ BIT(sent_shutdown);
};
/* For a given rustls_result error code, return the best-matching CURLcode. */
@@ -101,7 +102,7 @@ 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;
+ *out_n = (uintptr_t)nread;
CURL_TRC_CF(io_ctx->data, io_ctx->cf, "cf->next recv(len=%zu) -> %zd, %d",
len, nread, result);
return ret;
@@ -122,7 +123,7 @@ write_cb(void *userdata, const uint8_t *buf, uintptr_t len, uintptr_t *out_n)
else
ret = EINVAL;
}
- *out_n = (int)nwritten;
+ *out_n = (uintptr_t)nwritten;
CURL_TRC_CF(io_ctx->data, io_ctx->cf, "cf->next send(len=%zu) -> %zd, %d",
len, nwritten, result);
return ret;
@@ -178,10 +179,10 @@ static ssize_t tls_recv_more(struct Curl_cfilter *cf,
* - Read out as many plaintext bytes from rustls as possible, until hitting
* error, EOF, or EAGAIN/EWOULDBLOCK, or plainbuf/plainlen is filled up.
*
- * It's okay to call this function with plainbuf == NULL and plainlen == 0.
- * In that case, it will copy bytes from the socket into rustls' TLS input
- * buffer, and process packets, but won't consume bytes from rustls' plaintext
- * output buffer.
+ * it is okay to call this function with plainbuf == NULL and plainlen == 0. In
+ * that case, it will copy bytes from the socket into rustls' TLS input
+ * buffer, and process packets, but will not consume bytes from rustls'
+ * plaintext output buffer.
*/
static ssize_t
cr_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
@@ -226,7 +227,7 @@ cr_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
goto out;
}
else if(rresult != RUSTLS_RESULT_OK) {
- /* n always equals 0 in this case, don't need to check it */
+ /* n always equals 0 in this case, do not need to check it */
char errorbuf[255];
size_t errorlen;
rustls_error(rresult, errorbuf, sizeof(errorbuf), &errorlen);
@@ -308,8 +309,8 @@ static CURLcode cr_flush_out(struct Curl_cfilter *cf, struct Curl_easy *data,
* - Fully drain rustls' plaintext output buffer into the socket until
* we get either an error or EAGAIN/EWOULDBLOCK.
*
- * It's okay to call this function with plainbuf == NULL and plainlen == 0.
- * In that case, it won't read anything into rustls' plaintext input buffer.
+ * it is okay to call this function with plainbuf == NULL and plainlen == 0.
+ * In that case, it will not read anything into rustls' plaintext input buffer.
* It will only drain rustls' plaintext output buffer into the socket.
*/
static ssize_t
@@ -438,7 +439,7 @@ cr_init_backend(struct Curl_cfilter *cf, struct Curl_easy *data,
const char *hostname = connssl->peer.hostname;
char errorbuf[256];
size_t errorlen;
- int result;
+ rustls_result result;
DEBUGASSERT(backend);
rconn = backend->conn;
@@ -461,7 +462,7 @@ cr_init_backend(struct Curl_cfilter *cf, struct Curl_easy *data,
if(!verifypeer) {
rustls_client_config_builder_dangerous_set_certificate_verifier(
config_builder, cr_verify_none);
- /* rustls doesn't support IP addresses (as of 0.19.0), and will reject
+ /* rustls does not support IP addresses (as of 0.19.0), and will reject
* connections created with an IP address, even when certificate
* verification is turned off. Set a placeholder hostname and disable
* SNI. */
@@ -474,7 +475,7 @@ cr_init_backend(struct Curl_cfilter *cf, struct Curl_easy *data,
roots_builder = rustls_root_cert_store_builder_new();
if(ca_info_blob) {
- /* Enable strict parsing only if verification isn't disabled. */
+ /* Enable strict parsing only if verification is not disabled. */
result = rustls_root_cert_store_builder_add_pem(roots_builder,
ca_info_blob->data,
ca_info_blob->len,
@@ -488,7 +489,7 @@ cr_init_backend(struct Curl_cfilter *cf, struct Curl_easy *data,
}
}
else if(ssl_cafile) {
- /* Enable strict parsing only if verification isn't disabled. */
+ /* Enable strict parsing only if verification is not disabled. */
result = rustls_root_cert_store_builder_load_roots_from_file(
roots_builder, ssl_cafile, verifypeer);
if(result != RUSTLS_RESULT_OK) {
@@ -604,6 +605,7 @@ cr_connect_common(struct Curl_cfilter *cf,
* Connection has been established according to rustls. Set send/recv
* handlers, and update the state machine.
*/
+ connssl->io_need = CURL_SSL_IO_NEED_NONE;
if(!rustls_connection_is_handshaking(rconn)) {
infof(data, "Done handshaking");
/* rustls claims it is no longer handshaking *before* it has
@@ -613,7 +615,7 @@ cr_connect_common(struct Curl_cfilter *cf,
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;
+ connssl->io_need = CURL_SSL_IO_NEED_SEND;
return CURLE_OK;
}
else if(tmperr != CURLE_OK) {
@@ -625,6 +627,7 @@ cr_connect_common(struct Curl_cfilter *cf,
return CURLE_OK;
}
+ connssl->connecting_state = ssl_connect_2;
wants_read = rustls_connection_wants_read(rconn);
wants_write = rustls_connection_wants_write(rconn) ||
backend->plain_out_buffered;
@@ -632,8 +635,6 @@ cr_connect_common(struct Curl_cfilter *cf,
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);
@@ -661,6 +662,10 @@ cr_connect_common(struct Curl_cfilter *cf,
CURL_TRC_CF(data, cf, "Curl_socket_check: %s would block",
wants_read&&wants_write ? "writing and reading" :
wants_write ? "writing" : "reading");
+ if(wants_write)
+ connssl->io_need |= CURL_SSL_IO_NEED_SEND;
+ if(wants_read)
+ connssl->io_need |= CURL_SSL_IO_NEED_RECV;
return CURLE_OK;
}
/* socket is readable or writable */
@@ -695,7 +700,7 @@ cr_connect_common(struct Curl_cfilter *cf,
}
/* We should never fall through the loop. We should return either because
- the handshake is done or because we can't read/write without blocking. */
+ the handshake is done or because we cannot read/write without blocking. */
DEBUGASSERT(false);
}
@@ -723,24 +728,85 @@ cr_get_internals(struct ssl_connect_data *connssl,
return &backend->conn;
}
-static void
-cr_close(struct Curl_cfilter *cf, struct Curl_easy *data)
+static CURLcode
+cr_shutdown(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool send_shutdown, bool *done)
{
struct ssl_connect_data *connssl = cf->ctx;
struct rustls_ssl_backend_data *backend =
(struct rustls_ssl_backend_data *)connssl->backend;
- CURLcode tmperr = CURLE_OK;
- ssize_t n = 0;
+ CURLcode result = CURLE_OK;
+ ssize_t nwritten, nread;
+ char buf[1024];
+ size_t i;
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) {
- failf(data, "rustls: error sending close_notify: %d", tmperr);
+ if(!backend->conn || cf->shutdown) {
+ *done = TRUE;
+ goto out;
+ }
+
+ connssl->io_need = CURL_SSL_IO_NEED_NONE;
+ *done = FALSE;
+
+ if(!backend->sent_shutdown) {
+ /* do this only once */
+ backend->sent_shutdown = TRUE;
+ if(send_shutdown) {
+ rustls_connection_send_close_notify(backend->conn);
}
+ }
+
+ nwritten = cr_send(cf, data, NULL, 0, &result);
+ if(nwritten < 0) {
+ if(result == CURLE_AGAIN) {
+ connssl->io_need = CURL_SSL_IO_NEED_SEND;
+ result = CURLE_OK;
+ goto out;
+ }
+ DEBUGASSERT(result);
+ CURL_TRC_CF(data, cf, "shutdown send failed: %d", result);
+ goto out;
+ }
+
+ for(i = 0; i < 10; ++i) {
+ nread = cr_recv(cf, data, buf, (int)sizeof(buf), &result);
+ if(nread <= 0)
+ break;
+ }
+ if(nread > 0) {
+ /* still data coming in? */
+ }
+ else if(nread == 0) {
+ /* We got the close notify alert and are done. */
+ *done = TRUE;
+ }
+ else if(result == CURLE_AGAIN) {
+ connssl->io_need = CURL_SSL_IO_NEED_RECV;
+ result = CURLE_OK;
+ }
+ else {
+ DEBUGASSERT(result);
+ CURL_TRC_CF(data, cf, "shutdown, error: %d", result);
+ }
+
+out:
+ cf->shutdown = (result || *done);
+ return result;
+}
+
+static void
+cr_close(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct rustls_ssl_backend_data *backend =
+ (struct rustls_ssl_backend_data *)connssl->backend;
+
+ (void)data;
+ DEBUGASSERT(backend);
+ if(backend->conn) {
rustls_connection_free(backend->conn);
backend->conn = NULL;
}
@@ -766,7 +832,7 @@ const struct Curl_ssl Curl_ssl_rustls = {
Curl_none_cleanup, /* cleanup */
cr_version, /* version */
Curl_none_check_cxn, /* check_cxn */
- Curl_none_shutdown, /* shutdown */
+ cr_shutdown, /* shutdown */
cr_data_pending, /* data_pending */
Curl_none_random, /* random */
Curl_none_cert_status_request, /* cert_status_request */
@@ -783,7 +849,6 @@ const struct Curl_ssl Curl_ssl_rustls = {
NULL, /* sha256sum */
NULL, /* associate_connection */
NULL, /* disassociate_connection */
- NULL, /* free_multi_ssl_backend_data */
cr_recv, /* recv decrypted data */
cr_send, /* send data to encrypt */
};
diff --git a/libs/libcurl/src/vtls/schannel.c b/libs/libcurl/src/vtls/schannel.c
index d172b567c4..6fef076099 100644
--- a/libs/libcurl/src/vtls/schannel.c
+++ b/libs/libcurl/src/vtls/schannel.c
@@ -34,7 +34,7 @@
#ifdef USE_SCHANNEL
#ifndef USE_WINDOWS_SSPI
-# error "Can't compile SCHANNEL support without SSPI."
+# error "cannot compile SCHANNEL support without SSPI."
#endif
#include "schannel.h"
@@ -171,7 +171,7 @@ schannel_set_ssl_version_min_max(DWORD *enabled_protocols,
{
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
long ssl_version = conn_config->version;
- long ssl_version_max = conn_config->version_max;
+ long ssl_version_max = (long)conn_config->version_max;
long i = ssl_version;
switch(ssl_version_max) {
@@ -364,7 +364,7 @@ set_ssl_ciphers(SCHANNEL_CRED *schannel_cred, char *ciphers,
if(!alg)
alg = get_alg_id_by_name(startCur);
if(alg)
- algIds[algCount++] = alg;
+ algIds[algCount++] = (ALG_ID)alg;
else if(!strncmp(startCur, "USE_STRONG_CRYPTO",
sizeof("USE_STRONG_CRYPTO") - 1) ||
!strncmp(startCur, "SCH_USE_STRONG_CRYPTO",
@@ -377,7 +377,7 @@ set_ssl_ciphers(SCHANNEL_CRED *schannel_cred, char *ciphers,
startCur++;
}
schannel_cred->palgSupportedAlgs = algIds;
- schannel_cred->cSupportedAlgs = algCount;
+ schannel_cred->cSupportedAlgs = (DWORD)algCount;
return CURLE_OK;
}
@@ -513,7 +513,7 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf,
}
if(!ssl_config->auto_client_cert) {
- flags &= ~SCH_CRED_USE_DEFAULT_CREDS;
+ flags &= ~(DWORD)SCH_CRED_USE_DEFAULT_CREDS;
flags |= SCH_CRED_NO_DEFAULT_CREDS;
infof(data, "schannel: disabled automatic use of client certificate");
}
@@ -950,7 +950,7 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf,
tls_parameters.pDisabledCrypto = crypto_settings;
/* The number of blocked suites */
- tls_parameters.cDisabledCrypto = crypto_settings_idx;
+ tls_parameters.cDisabledCrypto = (DWORD)crypto_settings_idx;
credentials.pTlsParameters = &tls_parameters;
credentials.cTlsParameters = 1;
@@ -976,7 +976,7 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf,
}
else {
/* Pre-Windows 10 1809 or the user set a legacy algorithm list. Although MS
- doesn't document it, currently Schannel will not negotiate TLS 1.3 when
+ does not document it, currently Schannel will not negotiate TLS 1.3 when
SCHANNEL_CRED is used. */
ALG_ID algIds[NUM_CIPHERS];
char *ciphers = conn_config->cipher_list;
@@ -1083,7 +1083,7 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
#ifdef HAS_ALPN
/* ALPN is only supported on Windows 8.1 / Server 2012 R2 and above.
- Also it doesn't seem to be supported for Wine, see curl bug #983. */
+ Also it does not seem to be supported for Wine, see curl bug #983. */
backend->use_alpn = connssl->alpn &&
!GetProcAddress(GetModuleHandle(TEXT("ntdll")),
"wine_get_version") &&
@@ -1095,7 +1095,7 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
#ifdef _WIN32_WCE
#ifdef HAS_MANUAL_VERIFY_API
- /* certificate validation on CE doesn't seem to work right; we'll
+ /* certificate validation on CE does not seem to work right; we will
* do it following a more manual process. */
backend->use_manual_cred_validation = true;
#else
@@ -1127,7 +1127,7 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
backend->cred = NULL;
/* check for an existing reusable credential handle */
- if(ssl_config->primary.sessionid) {
+ if(ssl_config->primary.cache_session) {
Curl_ssl_sessionid_lock(data);
if(!Curl_ssl_getsessionid(cf, data, &connssl->peer,
(void **)&old_cred, NULL)) {
@@ -1241,7 +1241,7 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
/* Schannel InitializeSecurityContext:
https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx
- At the moment we don't pass inbuf unless we're using ALPN since we only
+ At the moment we do not pass inbuf unless we are using ALPN since we only
use it for that, and Wine (for which we currently disable ALPN) is giving
us problems with inbuf regardless. https://github.com/curl/curl/issues/983
*/
@@ -1332,7 +1332,8 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
DEBUGASSERT(backend);
- doread = (connssl->connecting_state != ssl_connect_2_writing) ? TRUE : FALSE;
+ doread = (connssl->io_need & CURL_SSL_IO_NEED_SEND)? FALSE : TRUE;
+ connssl->io_need = CURL_SSL_IO_NEED_NONE;
DEBUGF(infof(data,
"schannel: SSL/TLS connection with %s port %d (step 2/3)",
@@ -1393,8 +1394,7 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
backend->encdata_offset,
&result);
if(result == CURLE_AGAIN) {
- if(connssl->connecting_state != ssl_connect_2_writing)
- connssl->connecting_state = ssl_connect_2_reading;
+ connssl->io_need = CURL_SSL_IO_NEED_RECV;
DEBUGF(infof(data, "schannel: failed to receive handshake, "
"need more data"));
return CURLE_OK;
@@ -1448,7 +1448,7 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
/* check if the handshake was incomplete */
if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
backend->encdata_is_incomplete = true;
- connssl->connecting_state = ssl_connect_2_reading;
+ connssl->io_need = CURL_SSL_IO_NEED_RECV;
DEBUGF(infof(data,
"schannel: received incomplete message, need more data"));
return CURLE_OK;
@@ -1460,7 +1460,7 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
if(sspi_status == SEC_I_INCOMPLETE_CREDENTIALS &&
!(backend->req_flags & ISC_REQ_USE_SUPPLIED_CREDS)) {
backend->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS;
- connssl->connecting_state = ssl_connect_2_writing;
+ connssl->io_need = CURL_SSL_IO_NEED_SEND;
DEBUGF(infof(data,
"schannel: a client certificate has been requested"));
return CURLE_OK;
@@ -1531,7 +1531,7 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
inbuf[1].cbBuffer));
/*
There are two cases where we could be getting extra data here:
- 1) If we're renegotiating a connection and the handshake is already
+ 1) If we are renegotiating a connection and the handshake is already
complete (from the server perspective), it can encrypted app data
(not handshake data) in an extra buffer at this point.
2) (sspi_status == SEC_I_CONTINUE_NEEDED) We are negotiating a
@@ -1560,7 +1560,7 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
/* check if the handshake needs to be continued */
if(sspi_status == SEC_I_CONTINUE_NEEDED) {
- connssl->connecting_state = ssl_connect_2_reading;
+ connssl->io_need = CURL_SSL_IO_NEED_RECV;
return CURLE_OK;
}
@@ -1593,7 +1593,7 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
#endif
/* Verify the hostname manually when certificate verification is disabled,
- because in that case Schannel won't verify it. */
+ because in that case Schannel will not verify it. */
if(!conn_config->verifypeer && conn_config->verifyhost)
return Curl_verify_host(cf, data);
@@ -1772,34 +1772,16 @@ schannel_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
#endif
/* save the current session data for possible reuse */
- if(ssl_config->primary.sessionid) {
- bool incache;
- struct Curl_schannel_cred *old_cred = NULL;
-
+ if(ssl_config->primary.cache_session) {
Curl_ssl_sessionid_lock(data);
- incache = !(Curl_ssl_getsessionid(cf, data, &connssl->peer,
- (void **)&old_cred, NULL));
- if(incache) {
- if(old_cred != backend->cred) {
- DEBUGF(infof(data,
- "schannel: old credential handle is stale, removing"));
- /* we're not taking old_cred ownership here, no refcount++ is needed */
- Curl_ssl_delsessionid(data, (void *)old_cred);
- incache = FALSE;
- }
- }
- if(!incache) {
- /* 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),
- schannel_session_free);
- if(result) {
- Curl_ssl_sessionid_unlock(data);
- return result;
- }
- }
+ /* Up ref count since call takes ownership */
+ backend->cred->refcount++;
+ result = Curl_ssl_set_sessionid(cf, data, &connssl->peer, backend->cred,
+ sizeof(struct Curl_schannel_cred),
+ schannel_session_free);
Curl_ssl_sessionid_unlock(data);
+ if(result)
+ return result;
}
if(data->set.ssl.certinfo) {
@@ -1853,7 +1835,7 @@ schannel_connect_common(struct Curl_cfilter *cf,
}
if(ssl_connect_1 == connssl->connecting_state) {
- /* check out how much more time we're allowed */
+ /* check out how much more time we are allowed */
timeout_ms = Curl_timeleft(data, NULL, TRUE);
if(timeout_ms < 0) {
@@ -1867,11 +1849,9 @@ schannel_connect_common(struct Curl_cfilter *cf,
return result;
}
- while(ssl_connect_2 == connssl->connecting_state ||
- ssl_connect_2_reading == connssl->connecting_state ||
- ssl_connect_2_writing == connssl->connecting_state) {
+ while(ssl_connect_2 == connssl->connecting_state) {
- /* check out how much more time we're allowed */
+ /* check out how much more time we are allowed */
timeout_ms = Curl_timeleft(data, NULL, TRUE);
if(timeout_ms < 0) {
@@ -1880,14 +1860,13 @@ schannel_connect_common(struct Curl_cfilter *cf,
return CURLE_OPERATION_TIMEDOUT;
}
- /* if ssl is expecting something, check if it's available. */
- if(connssl->connecting_state == ssl_connect_2_reading
- || connssl->connecting_state == ssl_connect_2_writing) {
+ /* if ssl is expecting something, check if it is available. */
+ if(connssl->io_need) {
- curl_socket_t writefd = ssl_connect_2_writing ==
- connssl->connecting_state ? sockfd : CURL_SOCKET_BAD;
- curl_socket_t readfd = ssl_connect_2_reading ==
- connssl->connecting_state ? sockfd : CURL_SOCKET_BAD;
+ curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND)?
+ sockfd : CURL_SOCKET_BAD;
+ curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV)?
+ sockfd : CURL_SOCKET_BAD;
what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
nonblocking ? 0 : timeout_ms);
@@ -1918,10 +1897,7 @@ schannel_connect_common(struct Curl_cfilter *cf,
* have a valid fdset to wait on.
*/
result = schannel_connect_step2(cf, data);
- if(result || (nonblocking &&
- (ssl_connect_2 == connssl->connecting_state ||
- ssl_connect_2_reading == connssl->connecting_state ||
- ssl_connect_2_writing == connssl->connecting_state)))
+ if(result || (nonblocking && (ssl_connect_2 == connssl->connecting_state)))
return result;
} /* repeat step2 until all transactions are done. */
@@ -2029,10 +2005,10 @@ schannel_send(struct Curl_cfilter *cf, struct Curl_easy *data,
len = outbuf[0].cbBuffer + outbuf[1].cbBuffer + outbuf[2].cbBuffer;
/*
- It's important to send the full message which includes the header,
- encrypted payload, and trailer. Until the client receives all the
+ it is important to send the full message which includes the header,
+ encrypted payload, and trailer. Until the client receives all the
data a coherent message has not been delivered and the client
- can't read any of it.
+ cannot read any of it.
If we wanted to buffer the unwritten encrypted bytes, we would
tell the client that all data it has requested to be sent has been
@@ -2129,8 +2105,9 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
DEBUGASSERT(backend);
/****************************************************************************
- * Don't return or set backend->recv_unrecoverable_err unless in the cleanup.
- * The pattern for return error is set *err, optional infof, goto cleanup.
+ * Do not return or set backend->recv_unrecoverable_err unless in the
+ * cleanup. The pattern for return error is set *err, optional infof, goto
+ * cleanup.
*
* Our priority is to always return as much decrypted data to the caller as
* possible, even if an error occurs. The state of the decrypted buffer must
@@ -2155,7 +2132,7 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
infof(data, "schannel: server indicated shutdown in a prior call");
goto cleanup;
}
- /* It's debatable what to return when !len. Regardless we can't return
+ /* it is debatable what to return when !len. Regardless we cannot return
immediately because there may be data to decrypt (in the case we want to
decrypt all encrypted cached data) so handle !len later in cleanup.
*/
@@ -2313,14 +2290,15 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
if(sspi_status == SEC_I_RENEGOTIATE) {
infof(data, "schannel: remote party requests renegotiation");
if(*err && *err != CURLE_AGAIN) {
- infof(data, "schannel: can't renegotiate, an error is pending");
+ infof(data, "schannel: cannot renegotiate, an error is pending");
goto cleanup;
}
/* begin renegotiation */
infof(data, "schannel: renegotiating SSL/TLS connection");
connssl->state = ssl_connection_negotiating;
- connssl->connecting_state = ssl_connect_2_writing;
+ connssl->connecting_state = ssl_connect_2;
+ connssl->io_need = CURL_SSL_IO_NEED_SEND;
backend->recv_renegotiating = true;
*err = schannel_connect_common(cf, data, FALSE, &done);
backend->recv_renegotiating = false;
@@ -2377,13 +2355,13 @@ cleanup:
/* Error if the connection has closed without a close_notify.
- The behavior here is a matter of debate. We don't want to be vulnerable
- to a truncation attack however there's some browser precedent for
+ The behavior here is a matter of debate. We do not want to be vulnerable
+ to a truncation attack however there is some browser precedent for
ignoring the close_notify for compatibility reasons.
Additionally, Windows 2000 (v5.0) is a special case since it seems it
- doesn't return close_notify. In that case if the connection was closed we
- assume it was graceful (close_notify) since there doesn't seem to be a
+ does not return close_notify. In that case if the connection was closed we
+ assume it was graceful (close_notify) since there does not seem to be a
way to tell.
*/
if(len && !backend->decdata_offset && backend->recv_connection_closed &&
@@ -2420,7 +2398,7 @@ cleanup:
if(!*err && !backend->recv_connection_closed)
*err = CURLE_AGAIN;
- /* It's debatable what to return when !len. We could return whatever error
+ /* it is debatable what to return when !len. We could return whatever error
we got from decryption but instead we override here so the return is
consistent.
*/
@@ -2475,8 +2453,9 @@ static bool schannel_data_pending(struct Curl_cfilter *cf,
/* shut down the SSL connection and clean up related memory.
this function can be called multiple times on the same connection including
if the SSL connection failed (eg connection made but failed handshake). */
-static int schannel_shutdown(struct Curl_cfilter *cf,
- struct Curl_easy *data)
+static CURLcode schannel_shutdown(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool send_shutdown, bool *done)
{
/* See https://msdn.microsoft.com/en-us/library/windows/desktop/aa380138.aspx
* Shutting Down an Schannel Connection
@@ -2484,22 +2463,36 @@ static int schannel_shutdown(struct Curl_cfilter *cf,
struct ssl_connect_data *connssl = cf->ctx;
struct schannel_ssl_backend_data *backend =
(struct schannel_ssl_backend_data *)connssl->backend;
+ CURLcode result = CURLE_OK;
+
+ if(cf->shutdown) {
+ *done = TRUE;
+ return CURLE_OK;
+ }
DEBUGASSERT(data);
DEBUGASSERT(backend);
+ /* Not supported in schannel */
+ (void)send_shutdown;
+
+ *done = FALSE;
if(backend->ctxt) {
infof(data, "schannel: shutting down SSL/TLS connection with %s port %d",
connssl->peer.hostname, connssl->peer.port);
}
- if(backend->cred && backend->ctxt) {
+ if(!backend->ctxt || cf->shutdown) {
+ *done = TRUE;
+ goto out;
+ }
+
+ if(backend->cred && backend->ctxt && !backend->sent_shutdown) {
SecBufferDesc BuffDesc;
SecBuffer Buffer;
SECURITY_STATUS sspi_status;
SecBuffer outbuf;
SecBufferDesc outbuf_desc;
- CURLcode result;
DWORD dwshut = SCHANNEL_SHUTDOWN;
InitSecBuffer(&Buffer, SECBUFFER_TOKEN, &dwshut, sizeof(dwshut));
@@ -2512,6 +2505,8 @@ static int schannel_shutdown(struct Curl_cfilter *cf,
char buffer[STRERROR_LEN];
failf(data, "schannel: ApplyControlToken failure: %s",
Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
+ result = CURLE_SEND_ERROR;
+ goto out;
}
/* setup output buffer */
@@ -2538,13 +2533,75 @@ static int schannel_shutdown(struct Curl_cfilter *cf,
outbuf.pvBuffer, outbuf.cbBuffer,
&result);
s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
- if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) {
- infof(data, "schannel: failed to send close msg: %s"
- " (bytes written: %zd)", curl_easy_strerror(result), written);
+ if(!result) {
+ if(written < (ssize_t)outbuf.cbBuffer) {
+ /* TODO: handle partial sends */
+ infof(data, "schannel: failed to send close msg: %s"
+ " (bytes written: %zd)", curl_easy_strerror(result), written);
+ result = CURLE_SEND_ERROR;
+ goto out;
+ }
+ backend->sent_shutdown = TRUE;
+ *done = TRUE;
+ }
+ else if(result == CURLE_AGAIN) {
+ connssl->io_need = CURL_SSL_IO_NEED_SEND;
+ result = CURLE_OK;
+ goto out;
+ }
+ else {
+ if(!backend->recv_connection_closed) {
+ infof(data, "schannel: error sending close msg: %d", result);
+ result = CURLE_SEND_ERROR;
+ goto out;
+ }
+ /* Looks like server already closed the connection.
+ * An error to send our close notify is not a failure. */
+ *done = TRUE;
+ result = CURLE_OK;
}
}
}
+ /* If the connection seems open and we have not seen the close notify
+ * from the server yet, try to receive it. */
+ if(backend->cred && backend->ctxt &&
+ !backend->recv_sspi_close_notify && !backend->recv_connection_closed) {
+ char buffer[1024];
+ ssize_t nread;
+
+ nread = schannel_recv(cf, data, buffer, sizeof(buffer), &result);
+ if(nread > 0) {
+ /* still data coming in? */
+ }
+ else if(nread == 0) {
+ /* We got the close notify alert and are done. */
+ backend->recv_connection_closed = TRUE;
+ *done = TRUE;
+ }
+ else if(nread < 0 && result == CURLE_AGAIN) {
+ connssl->io_need = CURL_SSL_IO_NEED_RECV;
+ }
+ else {
+ CURL_TRC_CF(data, cf, "SSL shutdown, error %d", result);
+ result = CURLE_RECV_ERROR;
+ }
+ }
+
+out:
+ cf->shutdown = (result || *done);
+ return result;
+}
+
+static void schannel_close(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct schannel_ssl_backend_data *backend =
+ (struct schannel_ssl_backend_data *)connssl->backend;
+
+ DEBUGASSERT(data);
+ DEBUGASSERT(backend);
+
/* free SSPI Schannel API security context handle */
if(backend->ctxt) {
DEBUGF(infof(data, "schannel: clear security context handle"));
@@ -2574,13 +2631,6 @@ static int schannel_shutdown(struct Curl_cfilter *cf,
backend->decdata_length = 0;
backend->decdata_offset = 0;
}
-
- return CURLE_OK;
-}
-
-static void schannel_close(struct Curl_cfilter *cf, struct Curl_easy *data)
-{
- schannel_shutdown(cf, data);
}
static int schannel_init(void)
@@ -2595,9 +2645,7 @@ static void schannel_cleanup(void)
static size_t schannel_version(char *buffer, size_t size)
{
- size = msnprintf(buffer, size, "Schannel");
-
- return size;
+ return msnprintf(buffer, size, "Schannel");
}
static CURLcode schannel_random(struct Curl_easy *data UNUSED_PARAM,
@@ -2622,7 +2670,7 @@ static CURLcode schannel_pkp_pin_peer_pubkey(struct Curl_cfilter *cf,
DEBUGASSERT(backend);
- /* if a path wasn't specified, don't pin */
+ /* if a path was not specified, do not pin */
if(!pinnedpubkey)
return CURLE_OK;
@@ -2684,6 +2732,13 @@ static void schannel_checksum(const unsigned char *input,
DWORD provType,
const unsigned int algId)
{
+#ifdef CURL_WINDOWS_APP
+ (void)input;
+ (void)inputlen;
+ (void)provType;
+ (void)algId;
+ memset(checksum, 0, checksumlen);
+#else
HCRYPTPROV hProv = 0;
HCRYPTHASH hHash = 0;
DWORD cbHashSize = 0;
@@ -2724,6 +2779,7 @@ static void schannel_checksum(const unsigned char *input,
if(hProv)
CryptReleaseContext(hProv, 0);
+#endif
}
static CURLcode schannel_sha256sum(const unsigned char *input,
@@ -2752,7 +2808,7 @@ HCERTSTORE Curl_schannel_get_cached_cert_store(struct Curl_cfilter *cf,
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
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;
+ struct schannel_cert_share *share;
const struct ssl_general_config *cfg = &data->set.general_ssl;
timediff_t timeout_ms;
timediff_t elapsed_ms;
@@ -2761,12 +2817,14 @@ HCERTSTORE Curl_schannel_get_cached_cert_store(struct Curl_cfilter *cf,
DEBUGASSERT(multi);
- if(!multi || !multi->ssl_backend_data) {
+ if(!multi) {
return NULL;
}
- mbackend = (struct schannel_multi_ssl_backend_data *)multi->ssl_backend_data;
- if(!mbackend->cert_store) {
+ share = Curl_hash_pick(&multi->proto_hash,
+ (void *)MPROTO_SCHANNEL_CERT_SHARE_KEY,
+ sizeof(MPROTO_SCHANNEL_CERT_SHARE_KEY)-1);
+ if(!share || !share->cert_store) {
return NULL;
}
@@ -2781,37 +2839,52 @@ HCERTSTORE Curl_schannel_get_cached_cert_store(struct Curl_cfilter *cf,
timeout_ms = cfg->ca_cache_timeout * (timediff_t)1000;
if(timeout_ms >= 0) {
now = Curl_now();
- elapsed_ms = Curl_timediff(now, mbackend->time);
+ elapsed_ms = Curl_timediff(now, share->time);
if(elapsed_ms >= timeout_ms) {
return NULL;
}
}
if(ca_info_blob) {
- if(!mbackend->CAinfo_blob_digest) {
+ if(!share->CAinfo_blob_digest) {
return NULL;
}
- if(mbackend->CAinfo_blob_size != ca_info_blob->len) {
+ if(share->CAinfo_blob_size != ca_info_blob->len) {
return NULL;
}
schannel_sha256sum((const unsigned char *)ca_info_blob->data,
ca_info_blob->len,
info_blob_digest,
CURL_SHA256_DIGEST_LENGTH);
- if(memcmp(mbackend->CAinfo_blob_digest,
+ if(memcmp(share->CAinfo_blob_digest,
info_blob_digest,
CURL_SHA256_DIGEST_LENGTH)) {
return NULL;
}
}
else {
- if(!conn_config->CAfile || !mbackend->CAfile ||
- strcmp(mbackend->CAfile, conn_config->CAfile)) {
+ if(!conn_config->CAfile || !share->CAfile ||
+ strcmp(share->CAfile, conn_config->CAfile)) {
return NULL;
}
}
- return mbackend->cert_store;
+ return share->cert_store;
+}
+
+static void schannel_cert_share_free(void *key, size_t key_len, void *p)
+{
+ struct schannel_cert_share *share = p;
+ DEBUGASSERT(key_len == (sizeof(MPROTO_SCHANNEL_CERT_SHARE_KEY)-1));
+ DEBUGASSERT(!memcmp(MPROTO_SCHANNEL_CERT_SHARE_KEY, key, key_len));
+ (void)key;
+ (void)key_len;
+ if(share->cert_store) {
+ CertCloseStore(share->cert_store, 0);
+ }
+ free(share->CAinfo_blob_digest);
+ free(share->CAfile);
+ free(share);
}
bool Curl_schannel_set_cached_cert_store(struct Curl_cfilter *cf,
@@ -2821,7 +2894,7 @@ bool Curl_schannel_set_cached_cert_store(struct Curl_cfilter *cf,
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
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;
+ struct schannel_cert_share *share;
unsigned char *CAinfo_blob_digest = NULL;
size_t CAinfo_blob_size = 0;
char *CAfile = NULL;
@@ -2832,17 +2905,23 @@ bool Curl_schannel_set_cached_cert_store(struct Curl_cfilter *cf,
return false;
}
- if(!multi->ssl_backend_data) {
- multi->ssl_backend_data =
- calloc(1, sizeof(struct schannel_multi_ssl_backend_data));
- if(!multi->ssl_backend_data) {
+ share = Curl_hash_pick(&multi->proto_hash,
+ (void *)MPROTO_SCHANNEL_CERT_SHARE_KEY,
+ sizeof(MPROTO_SCHANNEL_CERT_SHARE_KEY)-1);
+ if(!share) {
+ share = calloc(1, sizeof(*share));
+ if(!share) {
+ return false;
+ }
+ if(!Curl_hash_add2(&multi->proto_hash,
+ (void *)MPROTO_SCHANNEL_CERT_SHARE_KEY,
+ sizeof(MPROTO_SCHANNEL_CERT_SHARE_KEY)-1,
+ share, schannel_cert_share_free)) {
+ free(share);
return false;
}
}
- mbackend = (struct schannel_multi_ssl_backend_data *)multi->ssl_backend_data;
-
-
if(ca_info_blob) {
CAinfo_blob_digest = malloc(CURL_SHA256_DIGEST_LENGTH);
if(!CAinfo_blob_digest) {
@@ -2864,33 +2943,20 @@ bool Curl_schannel_set_cached_cert_store(struct Curl_cfilter *cf,
}
/* free old cache data */
- if(mbackend->cert_store) {
- CertCloseStore(mbackend->cert_store, 0);
+ if(share->cert_store) {
+ CertCloseStore(share->cert_store, 0);
}
- free(mbackend->CAinfo_blob_digest);
- free(mbackend->CAfile);
+ free(share->CAinfo_blob_digest);
+ free(share->CAfile);
- mbackend->time = Curl_now();
- mbackend->cert_store = cert_store;
- mbackend->CAinfo_blob_digest = CAinfo_blob_digest;
- mbackend->CAinfo_blob_size = CAinfo_blob_size;
- mbackend->CAfile = CAfile;
+ share->time = Curl_now();
+ share->cert_store = cert_store;
+ share->CAinfo_blob_digest = CAinfo_blob_digest;
+ share->CAinfo_blob_size = CAinfo_blob_size;
+ share->CAfile = CAfile;
return true;
}
-static void schannel_free_multi_ssl_backend_data(
- struct multi_ssl_backend_data *msbd)
-{
- struct schannel_multi_ssl_backend_data *mbackend =
- (struct schannel_multi_ssl_backend_data*)msbd;
- if(mbackend->cert_store) {
- CertCloseStore(mbackend->cert_store, 0);
- }
- free(mbackend->CAinfo_blob_digest);
- free(mbackend->CAfile);
- free(mbackend);
-}
-
const struct Curl_ssl Curl_ssl_schannel = {
{ CURLSSLBACKEND_SCHANNEL, "schannel" }, /* info */
@@ -2898,8 +2964,11 @@ const struct Curl_ssl Curl_ssl_schannel = {
#ifdef HAS_MANUAL_VERIFY_API
SSLSUPP_CAINFO_BLOB |
#endif
+#ifndef CURL_WINDOWS_APP
SSLSUPP_PINNEDPUBKEY |
+#endif
SSLSUPP_TLS13_CIPHERSUITES |
+ SSLSUPP_CA_CACHE |
SSLSUPP_HTTPS_PROXY,
sizeof(struct schannel_ssl_backend_data),
@@ -2925,7 +2994,6 @@ const struct Curl_ssl Curl_ssl_schannel = {
schannel_sha256sum, /* sha256sum */
NULL, /* associate_connection */
NULL, /* disassociate_connection */
- schannel_free_multi_ssl_backend_data, /* free_multi_ssl_backend_data */
schannel_recv, /* recv decrypted data */
schannel_send, /* send data to encrypt */
};
diff --git a/libs/libcurl/src/vtls/schannel_int.h b/libs/libcurl/src/vtls/schannel_int.h
index 92fbc073b0..77105f81ab 100644
--- a/libs/libcurl/src/vtls/schannel_int.h
+++ b/libs/libcurl/src/vtls/schannel_int.h
@@ -28,7 +28,8 @@
#ifdef USE_SCHANNEL
-#if defined(__MINGW32__) || defined(CERT_CHAIN_REVOCATION_CHECK_CHAIN)
+#if (defined(__MINGW32__) || defined(CERT_CHAIN_REVOCATION_CHECK_CHAIN)) \
+ && !defined(CURL_WINDOWS_APP)
#define HAS_MANUAL_VERIFY_API
#endif
@@ -144,7 +145,7 @@ struct schannel_ssl_backend_data {
size_t encdata_offset, decdata_offset;
unsigned char *encdata_buffer, *decdata_buffer;
/* encdata_is_incomplete: if encdata contains only a partial record that
- can't be decrypted without another recv() (that is, status is
+ cannot be decrypted without another recv() (that is, status is
SEC_E_INCOMPLETE_MESSAGE) then set this true. after an recv() adds
more bytes into encdata then set this back to false. */
bool encdata_is_incomplete;
@@ -157,9 +158,13 @@ struct schannel_ssl_backend_data {
#ifdef HAS_MANUAL_VERIFY_API
bool use_manual_cred_validation; /* true if manual cred validation is used */
#endif
+ BIT(sent_shutdown);
};
-struct schannel_multi_ssl_backend_data {
+/* key to use at `multi->proto_hash` */
+#define MPROTO_SCHANNEL_CERT_SHARE_KEY "tls:schannel:cert:share"
+
+struct schannel_cert_share {
unsigned char *CAinfo_blob_digest; /* CA info blob digest */
size_t CAinfo_blob_size; /* CA info blob size */
char *CAfile; /* CAfile path used to generate
diff --git a/libs/libcurl/src/vtls/schannel_verify.c b/libs/libcurl/src/vtls/schannel_verify.c
index 743f3b059e..00b3b4d7d3 100644
--- a/libs/libcurl/src/vtls/schannel_verify.c
+++ b/libs/libcurl/src/vtls/schannel_verify.c
@@ -33,7 +33,7 @@
#ifdef USE_SCHANNEL
#ifndef USE_WINDOWS_SSPI
-# error "Can't compile SCHANNEL support without SSPI."
+# error "cannot compile SCHANNEL support without SSPI."
#endif
#include "schannel.h"
@@ -82,7 +82,7 @@ static int is_cr_or_lf(char c)
}
/* Search the substring needle,needlelen into string haystack,haystacklen
- * Strings don't need to be terminated by a '\0'.
+ * Strings do not need to be terminated by a '\0'.
* Similar of OSX/Linux memmem (not available on Visual Studio).
* Return position of beginning of first occurrence or NULL if not found
*/
@@ -335,7 +335,7 @@ cleanup:
/*
* Returns the number of characters necessary to populate all the host_names.
- * If host_names is not NULL, populate it with all the host names. Each string
+ * If host_names is not NULL, populate it with all the hostnames. Each string
* in the host_names is null-terminated and the last string is double
* null-terminated. If no DNS names are found, a single null-terminated empty
* string is returned.
@@ -346,6 +346,12 @@ static DWORD cert_get_name_string(struct Curl_easy *data,
DWORD length)
{
DWORD actual_length = 0;
+#if defined(CURL_WINDOWS_APP)
+ (void)data;
+ (void)cert_context;
+ (void)host_names;
+ (void)length;
+#else
BOOL compute_content = FALSE;
CERT_INFO *cert_info = NULL;
CERT_EXTENSION *extension = NULL;
@@ -441,14 +447,14 @@ static DWORD cert_get_name_string(struct Curl_easy *data,
}
/* Sanity check to prevent buffer overrun. */
if((actual_length + current_length) > length) {
- failf(data, "schannel: Not enough memory to list all host names.");
+ failf(data, "schannel: Not enough memory to list all hostnames.");
break;
}
dns_w = entry->pwszDNSName;
- /* pwszDNSName is in ia5 string format and hence doesn't contain any
+ /* pwszDNSName is in ia5 string format and hence does not contain any
* non-ascii characters. */
while(*dns_w != '\0') {
- *current_pos++ = (char)(*dns_w++);
+ *current_pos++ = (TCHAR)(*dns_w++);
}
*current_pos++ = '\0';
actual_length += (DWORD)current_length;
@@ -457,6 +463,7 @@ static DWORD cert_get_name_string(struct Curl_easy *data,
/* Last string has double null-terminator. */
*current_pos = '\0';
}
+#endif
return actual_length;
}
diff --git a/libs/libcurl/src/vtls/sectransp.c b/libs/libcurl/src/vtls/sectransp.c
index 6482fb9168..c79e18b95e 100644
--- a/libs/libcurl/src/vtls/sectransp.c
+++ b/libs/libcurl/src/vtls/sectransp.c
@@ -30,6 +30,8 @@
#include "curl_setup.h"
+#ifdef USE_SECTRANSP
+
#include "urldata.h" /* for the Curl_easy definition */
#include "curl_base64.h"
#include "strtok.h"
@@ -37,19 +39,16 @@
#include "strcase.h"
#include "x509asn1.h"
#include "strerror.h"
-
-#ifdef USE_SECTRANSP
+#include "cipher_suite.h"
#ifdef __clang__
#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wtautological-pointer-compare"
+#pragma clang diagnostic ignored "-Wunreachable-code"
#endif /* __clang__ */
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Waddress"
-#pragma GCC diagnostic ignored "-Wundef"
-#pragma GCC diagnostic ignored "-Wunreachable-code"
#endif
#include <limits.h>
@@ -72,7 +71,7 @@
#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
#if MAC_OS_X_VERSION_MAX_ALLOWED < 1050
-#error "The Secure Transport back-end requires Leopard or later."
+#error "The Secure Transport backend requires Leopard or later."
#endif /* MAC_OS_X_VERSION_MAX_ALLOWED < 1050 */
#define CURL_BUILD_IOS 0
@@ -122,7 +121,7 @@
#define CURL_SUPPORT_MAC_10_9 0
#else
-#error "The Secure Transport back-end requires iOS or macOS."
+#error "The Secure Transport backend requires iOS or macOS."
#endif /* (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) */
#if CURL_BUILD_MAC
@@ -144,7 +143,8 @@
#include "memdebug.h"
-/* From MacTypes.h (which we can't include because it isn't present in iOS: */
+/* From MacTypes.h (which we cannot include because it is not present in
+ iOS: */
#define ioErr -36
#define paramErr -50
@@ -152,636 +152,60 @@ struct st_ssl_backend_data {
SSLContextRef ssl_ctx;
bool ssl_direction; /* true if writing, false if reading */
size_t ssl_write_buffered_length;
+ BIT(sent_shutdown);
};
-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 */
- SSLCipherSuite num; /* Cipher suite code/number defined in IANA registry */
- bool weak; /* Flag to mark cipher as weak based on previous implementation
- of Secure Transport back-end by CURL */
-};
-
-/* Macro to initialize st_cipher data structure: stringify id to name, cipher
- number/id, 'weak' suite flag
- */
-#define CIPHER_DEF(num, alias, weak) \
- { #num, alias, num, weak }
-
-/*
- Macro to initialize st_cipher data structure with name, code (IANA cipher
- number/id value), and 'weak' suite flag. The first 28 cipher suite numbers
- have the same IANA code for both SSL and TLS standards: numbers 0x0000 to
- 0x001B. They have different names though. The first 4 letters of the cipher
- suite name are the protocol name: "SSL_" or "TLS_", rest of the IANA name is
- the same for both SSL and TLS cipher suite name.
- The second part of the problem is that macOS/iOS SDKs don't define all TLS
- codes but only 12 of them. The SDK defines all SSL codes though, i.e. SSL_NUM
- constant is always defined for those 28 ciphers while TLS_NUM is defined only
- for 12 of the first 28 ciphers. Those 12 TLS cipher codes match to
- corresponding SSL enum value and represent the same cipher suite. Therefore
- we'll use the SSL enum value for those cipher suites because it is defined
- for all 28 of them.
- We make internal data consistent and based on TLS names, i.e. all st_cipher
- item names start with the "TLS_" prefix.
- Summarizing all the above, those 28 first ciphers are presented in our table
- with both TLS and SSL names. Their cipher numbers are assigned based on the
- SDK enum value for the SSL cipher, which matches to IANA TLS number.
+/* Create the list of default ciphers to use by making an intersection of the
+ * ciphers supported by Secure Transport and the list below, using the order
+ * of the former.
+ * This list is based on TLS recommendations by Mozilla, balancing between
+ * security and wide compatibility: "Most ciphers that are not clearly broken
+ * and dangerous to use are supported"
*/
-#define CIPHER_DEF_SSLTLS(num_wo_prefix, alias, weak) \
- { "TLS_" #num_wo_prefix, alias, SSL_##num_wo_prefix, weak }
-
-/*
- Cipher suites were marked as weak based on the following:
- RC4 encryption - rfc7465, the document contains a list of deprecated ciphers.
- Marked in the code below as weak.
- RC2 encryption - many mentions, was found vulnerable to a relatively easy
- attack https://link.springer.com/chapter/10.1007%2F3-540-69710-1_14
- Marked in the code below as weak.
- DES and IDEA encryption - rfc5469, has a list of deprecated ciphers.
- Marked in the code below as weak.
- Anonymous Diffie-Hellman authentication and anonymous elliptic curve
- Diffie-Hellman - vulnerable to a man-in-the-middle attack. Deprecated by
- RFC 4346 aka TLS 1.1 (section A.5, page 60)
- Null bulk encryption suites - not encrypted communication
- Export ciphers, i.e. ciphers with restrictions to be used outside the US for
- software exported to some countries, they were excluded from TLS 1.1
- version. More precisely, they were noted as ciphers which MUST NOT be
- negotiated in RFC 4346 aka TLS 1.1 (section A.5, pages 60 and 61).
- All of those filters were considered weak because they contain a weak
- algorithm like DES, RC2 or RC4, and already considered weak by other
- criteria.
- 3DES - NIST deprecated it and is going to retire it by 2023
- https://csrc.nist.gov/News/2017/Update-to-Current-Use-and-Deprecation-of-TDEA
- OpenSSL https://www.openssl.org/blog/blog/2016/08/24/sweet32/ also
- deprecated those ciphers. Some other libraries also consider it
- vulnerable or at least not strong enough.
-
- CBC ciphers are vulnerable with SSL3.0 and TLS1.0:
- https://www.cisco.com/c/en/us/support/docs/security/email-security-appliance
- /118518-technote-esa-00.html
- We don't take care of this issue because it is resolved by later TLS
- versions and for us, it requires more complicated checks, we need to
- check a protocol version also. Vulnerability doesn't look very critical
- and we do not filter out those cipher suites.
- */
-
-#define CIPHER_WEAK_NOT_ENCRYPTED TRUE
-#define CIPHER_WEAK_RC_ENCRYPTION TRUE
-#define CIPHER_WEAK_DES_ENCRYPTION TRUE
-#define CIPHER_WEAK_IDEA_ENCRYPTION TRUE
-#define CIPHER_WEAK_ANON_AUTH TRUE
-#define CIPHER_WEAK_3DES_ENCRYPTION TRUE
-#define CIPHER_STRONG_ENOUGH FALSE
-
-/* Please do not change the order of the first ciphers available for SSL.
- Do not insert and do not delete any of them. Code below
- depends on their order and continuity.
- If you add a new cipher, please maintain order by number, i.e.
- insert in between existing items to appropriate place based on
- cipher suite IANA number
-*/
-static const struct st_cipher ciphertable[] = {
- /* SSL version 3.0 and initial TLS 1.0 cipher suites.
- Defined since SDK 10.2.8 */
- CIPHER_DEF_SSLTLS(NULL_WITH_NULL_NULL, /* 0x0000 */
- NULL,
- CIPHER_WEAK_NOT_ENCRYPTED),
- CIPHER_DEF_SSLTLS(RSA_WITH_NULL_MD5, /* 0x0001 */
- "NULL-MD5",
- CIPHER_WEAK_NOT_ENCRYPTED),
- CIPHER_DEF_SSLTLS(RSA_WITH_NULL_SHA, /* 0x0002 */
- "NULL-SHA",
- CIPHER_WEAK_NOT_ENCRYPTED),
- CIPHER_DEF_SSLTLS(RSA_EXPORT_WITH_RC4_40_MD5, /* 0x0003 */
- "EXP-RC4-MD5",
- CIPHER_WEAK_RC_ENCRYPTION),
- CIPHER_DEF_SSLTLS(RSA_WITH_RC4_128_MD5, /* 0x0004 */
- "RC4-MD5",
- CIPHER_WEAK_RC_ENCRYPTION),
- CIPHER_DEF_SSLTLS(RSA_WITH_RC4_128_SHA, /* 0x0005 */
- "RC4-SHA",
- CIPHER_WEAK_RC_ENCRYPTION),
- CIPHER_DEF_SSLTLS(RSA_EXPORT_WITH_RC2_CBC_40_MD5, /* 0x0006 */
- "EXP-RC2-CBC-MD5",
- CIPHER_WEAK_RC_ENCRYPTION),
- CIPHER_DEF_SSLTLS(RSA_WITH_IDEA_CBC_SHA, /* 0x0007 */
- "IDEA-CBC-SHA",
- CIPHER_WEAK_IDEA_ENCRYPTION),
- CIPHER_DEF_SSLTLS(RSA_EXPORT_WITH_DES40_CBC_SHA, /* 0x0008 */
- "EXP-DES-CBC-SHA",
- CIPHER_WEAK_DES_ENCRYPTION),
- CIPHER_DEF_SSLTLS(RSA_WITH_DES_CBC_SHA, /* 0x0009 */
- "DES-CBC-SHA",
- CIPHER_WEAK_DES_ENCRYPTION),
- CIPHER_DEF_SSLTLS(RSA_WITH_3DES_EDE_CBC_SHA, /* 0x000A */
- "DES-CBC3-SHA",
- CIPHER_WEAK_3DES_ENCRYPTION),
- CIPHER_DEF_SSLTLS(DH_DSS_EXPORT_WITH_DES40_CBC_SHA, /* 0x000B */
- "EXP-DH-DSS-DES-CBC-SHA",
- CIPHER_WEAK_DES_ENCRYPTION),
- CIPHER_DEF_SSLTLS(DH_DSS_WITH_DES_CBC_SHA, /* 0x000C */
- "DH-DSS-DES-CBC-SHA",
- CIPHER_WEAK_DES_ENCRYPTION),
- CIPHER_DEF_SSLTLS(DH_DSS_WITH_3DES_EDE_CBC_SHA, /* 0x000D */
- "DH-DSS-DES-CBC3-SHA",
- CIPHER_WEAK_3DES_ENCRYPTION),
- CIPHER_DEF_SSLTLS(DH_RSA_EXPORT_WITH_DES40_CBC_SHA, /* 0x000E */
- "EXP-DH-RSA-DES-CBC-SHA",
- CIPHER_WEAK_DES_ENCRYPTION),
- CIPHER_DEF_SSLTLS(DH_RSA_WITH_DES_CBC_SHA, /* 0x000F */
- "DH-RSA-DES-CBC-SHA",
- CIPHER_WEAK_DES_ENCRYPTION),
- CIPHER_DEF_SSLTLS(DH_RSA_WITH_3DES_EDE_CBC_SHA, /* 0x0010 */
- "DH-RSA-DES-CBC3-SHA",
- CIPHER_WEAK_3DES_ENCRYPTION),
- CIPHER_DEF_SSLTLS(DHE_DSS_EXPORT_WITH_DES40_CBC_SHA, /* 0x0011 */
- "EXP-EDH-DSS-DES-CBC-SHA",
- CIPHER_WEAK_DES_ENCRYPTION),
- CIPHER_DEF_SSLTLS(DHE_DSS_WITH_DES_CBC_SHA, /* 0x0012 */
- "EDH-DSS-CBC-SHA",
- CIPHER_WEAK_DES_ENCRYPTION),
- CIPHER_DEF_SSLTLS(DHE_DSS_WITH_3DES_EDE_CBC_SHA, /* 0x0013 */
- "DHE-DSS-DES-CBC3-SHA",
- CIPHER_WEAK_3DES_ENCRYPTION),
- CIPHER_DEF_SSLTLS(DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, /* 0x0014 */
- "EXP-EDH-RSA-DES-CBC-SHA",
- CIPHER_WEAK_DES_ENCRYPTION),
- CIPHER_DEF_SSLTLS(DHE_RSA_WITH_DES_CBC_SHA, /* 0x0015 */
- "EDH-RSA-DES-CBC-SHA",
- CIPHER_WEAK_DES_ENCRYPTION),
- CIPHER_DEF_SSLTLS(DHE_RSA_WITH_3DES_EDE_CBC_SHA, /* 0x0016 */
- "DHE-RSA-DES-CBC3-SHA",
- CIPHER_WEAK_3DES_ENCRYPTION),
- CIPHER_DEF_SSLTLS(DH_anon_EXPORT_WITH_RC4_40_MD5, /* 0x0017 */
- "EXP-ADH-RC4-MD5",
- CIPHER_WEAK_ANON_AUTH),
- CIPHER_DEF_SSLTLS(DH_anon_WITH_RC4_128_MD5, /* 0x0018 */
- "ADH-RC4-MD5",
- CIPHER_WEAK_ANON_AUTH),
- CIPHER_DEF_SSLTLS(DH_anon_EXPORT_WITH_DES40_CBC_SHA, /* 0x0019 */
- "EXP-ADH-DES-CBC-SHA",
- CIPHER_WEAK_ANON_AUTH),
- CIPHER_DEF_SSLTLS(DH_anon_WITH_DES_CBC_SHA, /* 0x001A */
- "ADH-DES-CBC-SHA",
- CIPHER_WEAK_ANON_AUTH),
- CIPHER_DEF_SSLTLS(DH_anon_WITH_3DES_EDE_CBC_SHA, /* 0x001B */
- "ADH-DES-CBC3-SHA",
- CIPHER_WEAK_3DES_ENCRYPTION),
- CIPHER_DEF(SSL_FORTEZZA_DMS_WITH_NULL_SHA, /* 0x001C */
- NULL,
- CIPHER_WEAK_NOT_ENCRYPTED),
- CIPHER_DEF(SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA, /* 0x001D */
- NULL,
- CIPHER_STRONG_ENOUGH),
-
-#if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7
- /* RFC 4785 - Pre-Shared Key (PSK) Ciphersuites with NULL Encryption */
- CIPHER_DEF(TLS_PSK_WITH_NULL_SHA, /* 0x002C */
- "PSK-NULL-SHA",
- CIPHER_WEAK_NOT_ENCRYPTED),
- CIPHER_DEF(TLS_DHE_PSK_WITH_NULL_SHA, /* 0x002D */
- "DHE-PSK-NULL-SHA",
- CIPHER_WEAK_NOT_ENCRYPTED),
- CIPHER_DEF(TLS_RSA_PSK_WITH_NULL_SHA, /* 0x002E */
- "RSA-PSK-NULL-SHA",
- CIPHER_WEAK_NOT_ENCRYPTED),
-#endif /* CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 */
-
- /* TLS addenda using AES, per RFC 3268. Defined since SDK 10.4u */
- CIPHER_DEF(TLS_RSA_WITH_AES_128_CBC_SHA, /* 0x002F */
- "AES128-SHA",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_DH_DSS_WITH_AES_128_CBC_SHA, /* 0x0030 */
- "DH-DSS-AES128-SHA",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_DH_RSA_WITH_AES_128_CBC_SHA, /* 0x0031 */
- "DH-RSA-AES128-SHA",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_DHE_DSS_WITH_AES_128_CBC_SHA, /* 0x0032 */
- "DHE-DSS-AES128-SHA",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_DHE_RSA_WITH_AES_128_CBC_SHA, /* 0x0033 */
- "DHE-RSA-AES128-SHA",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_DH_anon_WITH_AES_128_CBC_SHA, /* 0x0034 */
- "ADH-AES128-SHA",
- CIPHER_WEAK_ANON_AUTH),
- CIPHER_DEF(TLS_RSA_WITH_AES_256_CBC_SHA, /* 0x0035 */
- "AES256-SHA",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_DH_DSS_WITH_AES_256_CBC_SHA, /* 0x0036 */
- "DH-DSS-AES256-SHA",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_DH_RSA_WITH_AES_256_CBC_SHA, /* 0x0037 */
- "DH-RSA-AES256-SHA",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_DHE_DSS_WITH_AES_256_CBC_SHA, /* 0x0038 */
- "DHE-DSS-AES256-SHA",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_DHE_RSA_WITH_AES_256_CBC_SHA, /* 0x0039 */
- "DHE-RSA-AES256-SHA",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_DH_anon_WITH_AES_256_CBC_SHA, /* 0x003A */
- "ADH-AES256-SHA",
- CIPHER_WEAK_ANON_AUTH),
-
-#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
- /* TLS 1.2 addenda, RFC 5246 */
- /* Server provided RSA certificate for key exchange. */
- CIPHER_DEF(TLS_RSA_WITH_NULL_SHA256, /* 0x003B */
- "NULL-SHA256",
- CIPHER_WEAK_NOT_ENCRYPTED),
- CIPHER_DEF(TLS_RSA_WITH_AES_128_CBC_SHA256, /* 0x003C */
- "AES128-SHA256",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_RSA_WITH_AES_256_CBC_SHA256, /* 0x003D */
- "AES256-SHA256",
- CIPHER_STRONG_ENOUGH),
- /* Server-authenticated (and optionally client-authenticated)
- Diffie-Hellman. */
- CIPHER_DEF(TLS_DH_DSS_WITH_AES_128_CBC_SHA256, /* 0x003E */
- "DH-DSS-AES128-SHA256",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_DH_RSA_WITH_AES_128_CBC_SHA256, /* 0x003F */
- "DH-RSA-AES128-SHA256",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, /* 0x0040 */
- "DHE-DSS-AES128-SHA256",
- CIPHER_STRONG_ENOUGH),
-
- /* TLS 1.2 addenda, RFC 5246 */
- CIPHER_DEF(TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, /* 0x0067 */
- "DHE-RSA-AES128-SHA256",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_DH_DSS_WITH_AES_256_CBC_SHA256, /* 0x0068 */
- "DH-DSS-AES256-SHA256",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_DH_RSA_WITH_AES_256_CBC_SHA256, /* 0x0069 */
- "DH-RSA-AES256-SHA256",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, /* 0x006A */
- "DHE-DSS-AES256-SHA256",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, /* 0x006B */
- "DHE-RSA-AES256-SHA256",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_DH_anon_WITH_AES_128_CBC_SHA256, /* 0x006C */
- "ADH-AES128-SHA256",
- CIPHER_WEAK_ANON_AUTH),
- CIPHER_DEF(TLS_DH_anon_WITH_AES_256_CBC_SHA256, /* 0x006D */
- "ADH-AES256-SHA256",
- CIPHER_WEAK_ANON_AUTH),
-#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
-
-#if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7
- /* Addendum from RFC 4279, TLS PSK */
- CIPHER_DEF(TLS_PSK_WITH_RC4_128_SHA, /* 0x008A */
- "PSK-RC4-SHA",
- CIPHER_WEAK_RC_ENCRYPTION),
- CIPHER_DEF(TLS_PSK_WITH_3DES_EDE_CBC_SHA, /* 0x008B */
- "PSK-3DES-EDE-CBC-SHA",
- CIPHER_WEAK_3DES_ENCRYPTION),
- CIPHER_DEF(TLS_PSK_WITH_AES_128_CBC_SHA, /* 0x008C */
- "PSK-AES128-CBC-SHA",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_PSK_WITH_AES_256_CBC_SHA, /* 0x008D */
- "PSK-AES256-CBC-SHA",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_DHE_PSK_WITH_RC4_128_SHA, /* 0x008E */
- "DHE-PSK-RC4-SHA",
- CIPHER_WEAK_RC_ENCRYPTION),
- CIPHER_DEF(TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA, /* 0x008F */
- "DHE-PSK-3DES-EDE-CBC-SHA",
- CIPHER_WEAK_3DES_ENCRYPTION),
- CIPHER_DEF(TLS_DHE_PSK_WITH_AES_128_CBC_SHA, /* 0x0090 */
- "DHE-PSK-AES128-CBC-SHA",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_DHE_PSK_WITH_AES_256_CBC_SHA, /* 0x0091 */
- "DHE-PSK-AES256-CBC-SHA",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_RSA_PSK_WITH_RC4_128_SHA, /* 0x0092 */
- "RSA-PSK-RC4-SHA",
- CIPHER_WEAK_RC_ENCRYPTION),
- CIPHER_DEF(TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA, /* 0x0093 */
- "RSA-PSK-3DES-EDE-CBC-SHA",
- CIPHER_WEAK_3DES_ENCRYPTION),
- CIPHER_DEF(TLS_RSA_PSK_WITH_AES_128_CBC_SHA, /* 0x0094 */
- "RSA-PSK-AES128-CBC-SHA",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_RSA_PSK_WITH_AES_256_CBC_SHA, /* 0x0095 */
- "RSA-PSK-AES256-CBC-SHA",
- CIPHER_STRONG_ENOUGH),
-#endif /* CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 */
-
-#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
- /* Addenda from rfc 5288 AES Galois Counter Mode (GCM) Cipher Suites
- for TLS. */
- CIPHER_DEF(TLS_RSA_WITH_AES_128_GCM_SHA256, /* 0x009C */
- "AES128-GCM-SHA256",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_RSA_WITH_AES_256_GCM_SHA384, /* 0x009D */
- "AES256-GCM-SHA384",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, /* 0x009E */
- "DHE-RSA-AES128-GCM-SHA256",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, /* 0x009F */
- "DHE-RSA-AES256-GCM-SHA384",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_DH_RSA_WITH_AES_128_GCM_SHA256, /* 0x00A0 */
- "DH-RSA-AES128-GCM-SHA256",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_DH_RSA_WITH_AES_256_GCM_SHA384, /* 0x00A1 */
- "DH-RSA-AES256-GCM-SHA384",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, /* 0x00A2 */
- "DHE-DSS-AES128-GCM-SHA256",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_DHE_DSS_WITH_AES_256_GCM_SHA384, /* 0x00A3 */
- "DHE-DSS-AES256-GCM-SHA384",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_DH_DSS_WITH_AES_128_GCM_SHA256, /* 0x00A4 */
- "DH-DSS-AES128-GCM-SHA256",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_DH_DSS_WITH_AES_256_GCM_SHA384, /* 0x00A5 */
- "DH-DSS-AES256-GCM-SHA384",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_DH_anon_WITH_AES_128_GCM_SHA256, /* 0x00A6 */
- "ADH-AES128-GCM-SHA256",
- CIPHER_WEAK_ANON_AUTH),
- CIPHER_DEF(TLS_DH_anon_WITH_AES_256_GCM_SHA384, /* 0x00A7 */
- "ADH-AES256-GCM-SHA384",
- CIPHER_WEAK_ANON_AUTH),
-#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
-
-#if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7
- /* RFC 5487 - PSK with SHA-256/384 and AES GCM */
- CIPHER_DEF(TLS_PSK_WITH_AES_128_GCM_SHA256, /* 0x00A8 */
- "PSK-AES128-GCM-SHA256",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_PSK_WITH_AES_256_GCM_SHA384, /* 0x00A9 */
- "PSK-AES256-GCM-SHA384",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_DHE_PSK_WITH_AES_128_GCM_SHA256, /* 0x00AA */
- "DHE-PSK-AES128-GCM-SHA256",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_DHE_PSK_WITH_AES_256_GCM_SHA384, /* 0x00AB */
- "DHE-PSK-AES256-GCM-SHA384",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_RSA_PSK_WITH_AES_128_GCM_SHA256, /* 0x00AC */
- "RSA-PSK-AES128-GCM-SHA256",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_RSA_PSK_WITH_AES_256_GCM_SHA384, /* 0x00AD */
- "RSA-PSK-AES256-GCM-SHA384",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_PSK_WITH_AES_128_CBC_SHA256, /* 0x00AE */
- "PSK-AES128-CBC-SHA256",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_PSK_WITH_AES_256_CBC_SHA384, /* 0x00AF */
- "PSK-AES256-CBC-SHA384",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_PSK_WITH_NULL_SHA256, /* 0x00B0 */
- "PSK-NULL-SHA256",
- CIPHER_WEAK_NOT_ENCRYPTED),
- CIPHER_DEF(TLS_PSK_WITH_NULL_SHA384, /* 0x00B1 */
- "PSK-NULL-SHA384",
- CIPHER_WEAK_NOT_ENCRYPTED),
- CIPHER_DEF(TLS_DHE_PSK_WITH_AES_128_CBC_SHA256, /* 0x00B2 */
- "DHE-PSK-AES128-CBC-SHA256",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_DHE_PSK_WITH_AES_256_CBC_SHA384, /* 0x00B3 */
- "DHE-PSK-AES256-CBC-SHA384",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_DHE_PSK_WITH_NULL_SHA256, /* 0x00B4 */
- "DHE-PSK-NULL-SHA256",
- CIPHER_WEAK_NOT_ENCRYPTED),
- CIPHER_DEF(TLS_DHE_PSK_WITH_NULL_SHA384, /* 0x00B5 */
- "DHE-PSK-NULL-SHA384",
- CIPHER_WEAK_NOT_ENCRYPTED),
- CIPHER_DEF(TLS_RSA_PSK_WITH_AES_128_CBC_SHA256, /* 0x00B6 */
- "RSA-PSK-AES128-CBC-SHA256",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_RSA_PSK_WITH_AES_256_CBC_SHA384, /* 0x00B7 */
- "RSA-PSK-AES256-CBC-SHA384",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_RSA_PSK_WITH_NULL_SHA256, /* 0x00B8 */
- "RSA-PSK-NULL-SHA256",
- CIPHER_WEAK_NOT_ENCRYPTED),
- CIPHER_DEF(TLS_RSA_PSK_WITH_NULL_SHA384, /* 0x00B9 */
- "RSA-PSK-NULL-SHA384",
- CIPHER_WEAK_NOT_ENCRYPTED),
-#endif /* CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 */
-
- /* RFC 5746 - Secure Renegotiation. This is not a real suite,
- it is a response to initiate negotiation again */
- CIPHER_DEF(TLS_EMPTY_RENEGOTIATION_INFO_SCSV, /* 0x00FF */
- NULL,
- CIPHER_STRONG_ENOUGH),
-
-#if CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11
- /* TLS 1.3 standard cipher suites for ChaCha20+Poly1305.
- Note: TLS 1.3 ciphersuites do not specify the key exchange
- algorithm -- they only specify the symmetric ciphers.
- Cipher alias name matches to OpenSSL cipher name, and for
- TLS 1.3 ciphers */
- CIPHER_DEF(TLS_AES_128_GCM_SHA256, /* 0x1301 */
- NULL, /* The OpenSSL cipher name matches to the IANA name */
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_AES_256_GCM_SHA384, /* 0x1302 */
- NULL, /* The OpenSSL cipher name matches to the IANA name */
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_CHACHA20_POLY1305_SHA256, /* 0x1303 */
- NULL, /* The OpenSSL cipher name matches to the IANA name */
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_AES_128_CCM_SHA256, /* 0x1304 */
- NULL, /* The OpenSSL cipher name matches to the IANA name */
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_AES_128_CCM_8_SHA256, /* 0x1305 */
- NULL, /* The OpenSSL cipher name matches to the IANA name */
- CIPHER_STRONG_ENOUGH),
-#endif /* CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11 */
+static const uint16_t default_ciphers[] = {
+ TLS_RSA_WITH_3DES_EDE_CBC_SHA, /* 0x000A */
+ TLS_RSA_WITH_AES_128_CBC_SHA, /* 0x002F */
+ TLS_RSA_WITH_AES_256_CBC_SHA, /* 0x0035 */
#if CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS
- /* ECDSA addenda, RFC 4492 */
- CIPHER_DEF(TLS_ECDH_ECDSA_WITH_NULL_SHA, /* 0xC001 */
- "ECDH-ECDSA-NULL-SHA",
- CIPHER_WEAK_NOT_ENCRYPTED),
- CIPHER_DEF(TLS_ECDH_ECDSA_WITH_RC4_128_SHA, /* 0xC002 */
- "ECDH-ECDSA-RC4-SHA",
- CIPHER_WEAK_RC_ENCRYPTION),
- CIPHER_DEF(TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, /* 0xC003 */
- "ECDH-ECDSA-DES-CBC3-SHA",
- CIPHER_WEAK_3DES_ENCRYPTION),
- CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, /* 0xC004 */
- "ECDH-ECDSA-AES128-SHA",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, /* 0xC005 */
- "ECDH-ECDSA-AES256-SHA",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_NULL_SHA, /* 0xC006 */
- "ECDHE-ECDSA-NULL-SHA",
- CIPHER_WEAK_NOT_ENCRYPTED),
- CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, /* 0xC007 */
- "ECDHE-ECDSA-RC4-SHA",
- CIPHER_WEAK_RC_ENCRYPTION),
- CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, /* 0xC008 */
- "ECDHE-ECDSA-DES-CBC3-SHA",
- CIPHER_WEAK_3DES_ENCRYPTION),
- CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, /* 0xC009 */
- "ECDHE-ECDSA-AES128-SHA",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, /* 0xC00A */
- "ECDHE-ECDSA-AES256-SHA",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_ECDH_RSA_WITH_NULL_SHA, /* 0xC00B */
- "ECDH-RSA-NULL-SHA",
- CIPHER_WEAK_NOT_ENCRYPTED),
- CIPHER_DEF(TLS_ECDH_RSA_WITH_RC4_128_SHA, /* 0xC00C */
- "ECDH-RSA-RC4-SHA",
- CIPHER_WEAK_RC_ENCRYPTION),
- CIPHER_DEF(TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, /* 0xC00D */
- "ECDH-RSA-DES-CBC3-SHA",
- CIPHER_WEAK_3DES_ENCRYPTION),
- CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, /* 0xC00E */
- "ECDH-RSA-AES128-SHA",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, /* 0xC00F */
- "ECDH-RSA-AES256-SHA",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_ECDHE_RSA_WITH_NULL_SHA, /* 0xC010 */
- "ECDHE-RSA-NULL-SHA",
- CIPHER_WEAK_NOT_ENCRYPTED),
- CIPHER_DEF(TLS_ECDHE_RSA_WITH_RC4_128_SHA, /* 0xC011 */
- "ECDHE-RSA-RC4-SHA",
- CIPHER_WEAK_RC_ENCRYPTION),
- CIPHER_DEF(TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, /* 0xC012 */
- "ECDHE-RSA-DES-CBC3-SHA",
- CIPHER_WEAK_3DES_ENCRYPTION),
- CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, /* 0xC013 */
- "ECDHE-RSA-AES128-SHA",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, /* 0xC014 */
- "ECDHE-RSA-AES256-SHA",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_ECDH_anon_WITH_NULL_SHA, /* 0xC015 */
- "AECDH-NULL-SHA",
- CIPHER_WEAK_ANON_AUTH),
- CIPHER_DEF(TLS_ECDH_anon_WITH_RC4_128_SHA, /* 0xC016 */
- "AECDH-RC4-SHA",
- CIPHER_WEAK_ANON_AUTH),
- CIPHER_DEF(TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA, /* 0xC017 */
- "AECDH-DES-CBC3-SHA",
- CIPHER_WEAK_3DES_ENCRYPTION),
- CIPHER_DEF(TLS_ECDH_anon_WITH_AES_128_CBC_SHA, /* 0xC018 */
- "AECDH-AES128-SHA",
- CIPHER_WEAK_ANON_AUTH),
- CIPHER_DEF(TLS_ECDH_anon_WITH_AES_256_CBC_SHA, /* 0xC019 */
- "AECDH-AES256-SHA",
- CIPHER_WEAK_ANON_AUTH),
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, /* 0xC009 */
+ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, /* 0xC00A */
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, /* 0xC013 */
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, /* 0xC014 */
#endif /* CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS */
#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
- /* Addenda from rfc 5289 Elliptic Curve Cipher Suites with
- HMAC SHA-256/384. */
- CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, /* 0xC023 */
- "ECDHE-ECDSA-AES128-SHA256",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, /* 0xC024 */
- "ECDHE-ECDSA-AES256-SHA384",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, /* 0xC025 */
- "ECDH-ECDSA-AES128-SHA256",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, /* 0xC026 */
- "ECDH-ECDSA-AES256-SHA384",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, /* 0xC027 */
- "ECDHE-RSA-AES128-SHA256",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, /* 0xC028 */
- "ECDHE-RSA-AES256-SHA384",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, /* 0xC029 */
- "ECDH-RSA-AES128-SHA256",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, /* 0xC02A */
- "ECDH-RSA-AES256-SHA384",
- CIPHER_STRONG_ENOUGH),
- /* Addenda from rfc 5289 Elliptic Curve Cipher Suites with
- SHA-256/384 and AES Galois Counter Mode (GCM) */
- CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, /* 0xC02B */
- "ECDHE-ECDSA-AES128-GCM-SHA256",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, /* 0xC02C */
- "ECDHE-ECDSA-AES256-GCM-SHA384",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, /* 0xC02D */
- "ECDH-ECDSA-AES128-GCM-SHA256",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, /* 0xC02E */
- "ECDH-ECDSA-AES256-GCM-SHA384",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, /* 0xC02F */
- "ECDHE-RSA-AES128-GCM-SHA256",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, /* 0xC030 */
- "ECDHE-RSA-AES256-GCM-SHA384",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, /* 0xC031 */
- "ECDH-RSA-AES128-GCM-SHA256",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384, /* 0xC032 */
- "ECDH-RSA-AES256-GCM-SHA384",
- CIPHER_STRONG_ENOUGH),
+ TLS_RSA_WITH_AES_128_CBC_SHA256, /* 0x003C */
+ TLS_RSA_WITH_AES_256_CBC_SHA256, /* 0x003D */
+ TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, /* 0x0067 */
+ TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, /* 0x006B */
+ TLS_RSA_WITH_AES_128_GCM_SHA256, /* 0x009C */
+ TLS_RSA_WITH_AES_256_GCM_SHA384, /* 0x009D */
+ TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, /* 0x009E */
+ TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, /* 0x009F */
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, /* 0xC023 */
+ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, /* 0xC024 */
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, /* 0xC027 */
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, /* 0xC028 */
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, /* 0xC02B */
+ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, /* 0xC02C */
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, /* 0xC02F */
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, /* 0xC030 */
#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
-#if CURL_BUILD_MAC_10_15 || CURL_BUILD_IOS_13
- /* ECDHE_PSK Cipher Suites for Transport Layer Security (TLS), RFC 5489 */
- CIPHER_DEF(TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA, /* 0xC035 */
- "ECDHE-PSK-AES128-CBC-SHA",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA, /* 0xC036 */
- "ECDHE-PSK-AES256-CBC-SHA",
- CIPHER_STRONG_ENOUGH),
-#endif /* CURL_BUILD_MAC_10_15 || CURL_BUILD_IOS_13 */
-
#if CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11
- /* Addenda from rfc 7905 ChaCha20-Poly1305 Cipher Suites for
- Transport Layer Security (TLS). */
- CIPHER_DEF(TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, /* 0xCCA8 */
- "ECDHE-RSA-CHACHA20-POLY1305",
- CIPHER_STRONG_ENOUGH),
- CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, /* 0xCCA9 */
- "ECDHE-ECDSA-CHACHA20-POLY1305",
- CIPHER_STRONG_ENOUGH),
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, /* 0xCCA8 */
+ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, /* 0xCCA9 */
+
+ /* TLSv1.3 is not supported by sectransp, but there is also other
+ * code referencing TLSv1.3, like: kTLSProtocol13 ? */
+ TLS_AES_128_GCM_SHA256, /* 0x1301 */
+ TLS_AES_256_GCM_SHA384, /* 0x1302 */
+ TLS_CHACHA20_POLY1305_SHA256, /* 0x1303 */
#endif /* CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11 */
-
-#if CURL_BUILD_MAC_10_15 || CURL_BUILD_IOS_13
- /* ChaCha20-Poly1305 Cipher Suites for Transport Layer Security (TLS),
- RFC 7905 */
- CIPHER_DEF(TLS_PSK_WITH_CHACHA20_POLY1305_SHA256, /* 0xCCAB */
- "PSK-CHACHA20-POLY1305",
- CIPHER_STRONG_ENOUGH),
-#endif /* CURL_BUILD_MAC_10_15 || CURL_BUILD_IOS_13 */
-
- /* Tags for SSL 2 cipher kinds which are not specified for SSL 3.
- Defined since SDK 10.2.8 */
- CIPHER_DEF(SSL_RSA_WITH_RC2_CBC_MD5, /* 0xFF80 */
- NULL,
- CIPHER_WEAK_RC_ENCRYPTION),
- CIPHER_DEF(SSL_RSA_WITH_IDEA_CBC_MD5, /* 0xFF81 */
- NULL,
- CIPHER_WEAK_IDEA_ENCRYPTION),
- CIPHER_DEF(SSL_RSA_WITH_DES_CBC_MD5, /* 0xFF82 */
- NULL,
- CIPHER_WEAK_DES_ENCRYPTION),
- CIPHER_DEF(SSL_RSA_WITH_3DES_EDE_CBC_MD5, /* 0xFF83 */
- NULL,
- CIPHER_WEAK_3DES_ENCRYPTION),
};
-#define NUM_OF_CIPHERS sizeof(ciphertable)/sizeof(ciphertable[0])
+#define DEFAULT_CIPHERS_LEN sizeof(default_ciphers)/sizeof(default_ciphers[0])
/* pinned public key support tests */
@@ -816,7 +240,7 @@ static const unsigned char rsa2048SpkiHeader[] = {
0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05,
0x00, 0x03, 0x82, 0x01, 0x0f, 0x00};
#ifdef SECTRANSP_PINNEDPUBKEY_V1
-/* the *new* version doesn't return DER encoded ecdsa certs like the old... */
+/* the *new* version does not return DER encoded ecdsa certs like the old... */
static const unsigned char ecDsaSecp256r1SpkiHeader[] = {
0x30, 0x59, 0x30, 0x13, 0x06, 0x07,
0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02,
@@ -906,25 +330,6 @@ static OSStatus sectransp_bio_cf_out_write(SSLConnectionRef connection,
return rtn;
}
-CF_INLINE const char *TLSCipherNameForNumber(SSLCipherSuite cipher)
-{
- /* The first ciphers in the ciphertable are continuous. Here we do small
- optimization and instead of loop directly get SSL name by cipher number.
- */
- size_t i;
- if(cipher <= SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA) {
- return ciphertable[cipher].name;
- }
- /* Iterate through the rest of the ciphers */
- for(i = SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA + 1; i < NUM_OF_CIPHERS;
- ++i) {
- if(ciphertable[i].num == cipher) {
- return ciphertable[i].name;
- }
- }
- return ciphertable[SSL_NULL_WITH_NULL_NULL].name;
-}
-
#if CURL_BUILD_MAC
CF_INLINE void GetDarwinVersionNumber(int *major, int *minor)
{
@@ -957,27 +362,27 @@ CF_INLINE void GetDarwinVersionNumber(int *major, int *minor)
#endif /* CURL_BUILD_MAC */
/* Apple provides a myriad of ways of getting information about a certificate
- into a string. Some aren't available under iOS or newer cats. So here's
- a unified function for getting a string describing the certificate that
- ought to work in all cats starting with Leopard. */
+ into a string. Some are not available under iOS or newer cats. Here's a
+ unified function for getting a string describing the certificate that ought
+ to work in all cats starting with Leopard. */
CF_INLINE CFStringRef getsubject(SecCertificateRef cert)
{
CFStringRef server_cert_summary = CFSTR("(null)");
#if CURL_BUILD_IOS
- /* iOS: There's only one way to do this. */
+ /* iOS: There is only one way to do this. */
server_cert_summary = SecCertificateCopySubjectSummary(cert);
#else
#if CURL_BUILD_MAC_10_7
/* Lion & later: Get the long description if we can. */
- if(SecCertificateCopyLongDescription)
+ if(&SecCertificateCopyLongDescription)
server_cert_summary =
SecCertificateCopyLongDescription(NULL, cert, NULL);
else
#endif /* CURL_BUILD_MAC_10_7 */
#if CURL_BUILD_MAC_10_6
/* Snow Leopard: Get the certificate summary. */
- if(SecCertificateCopySubjectSummary)
+ if(&SecCertificateCopySubjectSummary)
server_cert_summary = SecCertificateCopySubjectSummary(cert);
else
#endif /* CURL_BUILD_MAC_10_6 */
@@ -1015,7 +420,7 @@ static CURLcode CopyCertSubject(struct Curl_easy *data,
size_t cbuf_size = ((size_t)CFStringGetLength(c) * 4) + 1;
cbuf = calloc(1, cbuf_size);
if(cbuf) {
- if(!CFStringGetCString(c, cbuf, cbuf_size,
+ if(!CFStringGetCString(c, cbuf, (CFIndex)cbuf_size,
kCFStringEncodingUTF8)) {
failf(data, "SSL: invalid CA certificate subject");
result = CURLE_PEER_FAILED_VERIFICATION;
@@ -1025,7 +430,7 @@ static CURLcode CopyCertSubject(struct Curl_easy *data,
*certp = cbuf;
}
else {
- failf(data, "SSL: couldn't allocate %zu bytes of memory", cbuf_size);
+ failf(data, "SSL: could not allocate %zu bytes of memory", cbuf_size);
result = CURLE_OUT_OF_MEMORY;
}
}
@@ -1037,7 +442,7 @@ static CURLcode CopyCertSubject(struct Curl_easy *data,
#if CURL_SUPPORT_MAC_10_6
/* The SecKeychainSearch API was deprecated in Lion, and using it will raise
- deprecation warnings, so let's not compile this unless it's necessary: */
+ deprecation warnings, so let's not compile this unless it is necessary: */
static OSStatus CopyIdentityWithLabelOldSchool(char *label,
SecIdentityRef *out_c_a_k)
{
@@ -1090,7 +495,7 @@ static OSStatus CopyIdentityWithLabel(char *label,
/* SecItemCopyMatching() was introduced in iOS and Snow Leopard.
kSecClassIdentity was introduced in Lion. If both exist, let's use them
to find the certificate. */
- if(SecItemCopyMatching && kSecClassIdentity) {
+ if(&SecItemCopyMatching && kSecClassIdentity) {
CFTypeRef keys[5];
CFTypeRef values[5];
CFDictionaryRef query_dict;
@@ -1108,7 +513,7 @@ static OSStatus CopyIdentityWithLabel(char *label,
/* identity searches need a SecPolicyRef in order to work */
values[3] = SecPolicyCreateSSL(false, NULL);
keys[3] = kSecMatchPolicy;
- /* match the name of the certificate (doesn't work in macOS 10.12.1) */
+ /* match the name of the certificate (does not work in macOS 10.12.1) */
values[4] = label_cf;
keys[4] = kSecAttrLabel;
query_dict = CFDictionaryCreate(NULL, (const void **)keys,
@@ -1120,7 +525,7 @@ static OSStatus CopyIdentityWithLabel(char *label,
/* Do we have a match? */
status = SecItemCopyMatching(query_dict, (CFTypeRef *) &keys_list);
- /* Because kSecAttrLabel matching doesn't work with kSecClassIdentity,
+ /* Because kSecAttrLabel matching does not work with kSecClassIdentity,
* we need to find the correct identity ourselves */
if(status == noErr) {
keys_list_count = CFArrayGetCount(keys_list);
@@ -1194,7 +599,8 @@ static OSStatus CopyIdentityFromPKCS12File(const char *cPath,
if(blob) {
pkcs_data = CFDataCreate(kCFAllocatorDefault,
- (const unsigned char *)blob->data, blob->len);
+ (const unsigned char *)blob->data,
+ (CFIndex)blob->len);
status = (pkcs_data != NULL) ? errSecSuccess : errSecAllocate;
resource_imported = (pkcs_data != NULL);
}
@@ -1202,7 +608,7 @@ static OSStatus CopyIdentityFromPKCS12File(const char *cPath,
pkcs_url =
CFURLCreateFromFileSystemRepresentation(NULL,
(const UInt8 *)cPath,
- strlen(cPath), false);
+ (CFIndex)strlen(cPath), false);
resource_imported =
CFURLCreateDataAndPropertiesFromResource(NULL,
pkcs_url, &pkcs_data,
@@ -1231,7 +637,7 @@ static OSStatus CopyIdentityFromPKCS12File(const char *cPath,
/* On macOS SecPKCS12Import will always add the client certificate to
* the Keychain.
*
- * As this doesn't match iOS, and apps may not want to see their client
+ * As this does not match iOS, and apps may not want to see their client
* certificate saved in the user's keychain, we use SecItemImport
* with a NULL keychain to avoid importing it.
*
@@ -1327,13 +733,14 @@ static CURLcode sectransp_version_from_curl(SSLProtocol *darwinver,
return CURLE_OK;
case CURL_SSLVERSION_TLSv1_3:
/* TLS 1.3 support first appeared in iOS 11 and macOS 10.13 */
-#if (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && HAVE_BUILTIN_AVAILABLE == 1
+#if (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && \
+ defined(HAVE_BUILTIN_AVAILABLE)
if(__builtin_available(macOS 10.13, iOS 11.0, *)) {
*darwinver = kTLSProtocol13;
return CURLE_OK;
}
#endif /* (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) &&
- HAVE_BUILTIN_AVAILABLE == 1 */
+ defined(HAVE_BUILTIN_AVAILABLE) */
break;
}
return CURLE_SSL_CONNECT_ERROR;
@@ -1356,7 +763,8 @@ static CURLcode set_ssl_version_min_max(struct Curl_cfilter *cf,
/* macOS 10.5-10.7 supported TLS 1.0 only.
macOS 10.8 and later, and iOS 5 and later, added TLS 1.1 and 1.2.
macOS 10.13 and later, and iOS 11 and later, added TLS 1.3. */
-#if (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && HAVE_BUILTIN_AVAILABLE == 1
+#if (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && \
+ defined(HAVE_BUILTIN_AVAILABLE)
if(__builtin_available(macOS 10.13, iOS 11.0, *)) {
max_supported_version_by_os = CURL_SSLVERSION_MAX_TLSv1_3;
}
@@ -1366,7 +774,7 @@ static CURLcode set_ssl_version_min_max(struct Curl_cfilter *cf,
#else
max_supported_version_by_os = CURL_SSLVERSION_MAX_TLSv1_2;
#endif /* (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) &&
- HAVE_BUILTIN_AVAILABLE == 1 */
+ defined(HAVE_BUILTIN_AVAILABLE) */
switch(ssl_version) {
case CURL_SSLVERSION_DEFAULT:
@@ -1383,7 +791,7 @@ static CURLcode set_ssl_version_min_max(struct Curl_cfilter *cf,
}
#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
- if(SSLSetProtocolVersionMax) {
+ if(&SSLSetProtocolVersionMax) {
SSLProtocol darwin_ver_min = kTLSProtocol1;
SSLProtocol darwin_ver_max = kTLSProtocol1;
CURLcode result = sectransp_version_from_curl(&darwin_ver_min,
@@ -1439,208 +847,223 @@ static CURLcode set_ssl_version_min_max(struct Curl_cfilter *cf,
return CURLE_SSL_CONNECT_ERROR;
}
-static bool is_cipher_suite_strong(SSLCipherSuite suite_num)
+static int sectransp_cipher_suite_get_str(uint16_t id, char *buf,
+ size_t buf_size, bool prefer_rfc)
{
- size_t i;
- for(i = 0; i < NUM_OF_CIPHERS; ++i) {
- if(ciphertable[i].num == suite_num) {
- return !ciphertable[i].weak;
- }
- }
- /* If the cipher is not in our list, assume it is a new one
- and therefore strong. Previous implementation was the same,
- if cipher suite is not in the list, it was considered strong enough */
- return true;
+ /* are these fortezza suites even supported ? */
+ if(id == SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA)
+ msnprintf(buf, buf_size, "%s", "SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA");
+ else if(id == SSL_FORTEZZA_DMS_WITH_NULL_SHA)
+ msnprintf(buf, buf_size, "%s", "SSL_FORTEZZA_DMS_WITH_NULL_SHA");
+ /* can TLS_EMPTY_RENEGOTIATION_INFO_SCSV even be set ? */
+ else if(id == TLS_EMPTY_RENEGOTIATION_INFO_SCSV)
+ msnprintf(buf, buf_size, "%s", "TLS_EMPTY_RENEGOTIATION_INFO_SCSV");
+ /* do we still need to support these SSL2-only ciphers ? */
+ else if(id == SSL_RSA_WITH_RC2_CBC_MD5)
+ msnprintf(buf, buf_size, "%s", "SSL_RSA_WITH_RC2_CBC_MD5");
+ else if(id == SSL_RSA_WITH_IDEA_CBC_MD5)
+ msnprintf(buf, buf_size, "%s", "SSL_RSA_WITH_IDEA_CBC_MD5");
+ else if(id == SSL_RSA_WITH_DES_CBC_MD5)
+ msnprintf(buf, buf_size, "%s", "SSL_RSA_WITH_DES_CBC_MD5");
+ else if(id == SSL_RSA_WITH_3DES_EDE_CBC_MD5)
+ msnprintf(buf, buf_size, "%s", "SSL_RSA_WITH_3DES_EDE_CBC_MD5");
+ else
+ return Curl_cipher_suite_get_str(id, buf, buf_size, prefer_rfc);
+ return 0;
}
-static bool sectransp_is_separator(char c)
+static uint16_t sectransp_cipher_suite_walk_str(const char **str,
+ const char **end)
{
- /* Return whether character is a cipher list separator. */
- switch(c) {
- case ' ':
- case '\t':
- case ':':
- case ',':
- case ';':
- return true;
- }
- return false;
+ uint16_t id = Curl_cipher_suite_walk_str(str, end);
+ size_t len = *end - *str;
+
+ if(!id) {
+ /* are these fortezza suites even supported ? */
+ if(strncasecompare("SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA", *str, len))
+ id = SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA;
+ else if(strncasecompare("SSL_FORTEZZA_DMS_WITH_NULL_SHA", *str, len))
+ id = SSL_FORTEZZA_DMS_WITH_NULL_SHA;
+ /* can TLS_EMPTY_RENEGOTIATION_INFO_SCSV even be set ? */
+ else if(strncasecompare("TLS_EMPTY_RENEGOTIATION_INFO_SCSV", *str, len))
+ id = TLS_EMPTY_RENEGOTIATION_INFO_SCSV;
+ /* do we still need to support these SSL2-only ciphers ? */
+ else if(strncasecompare("SSL_RSA_WITH_RC2_CBC_MD5", *str, len))
+ id = SSL_RSA_WITH_RC2_CBC_MD5;
+ else if(strncasecompare("SSL_RSA_WITH_IDEA_CBC_MD5", *str, len))
+ id = SSL_RSA_WITH_IDEA_CBC_MD5;
+ else if(strncasecompare("SSL_RSA_WITH_DES_CBC_MD5", *str, len))
+ id = SSL_RSA_WITH_DES_CBC_MD5;
+ else if(strncasecompare("SSL_RSA_WITH_3DES_EDE_CBC_MD5", *str, len))
+ id = SSL_RSA_WITH_3DES_EDE_CBC_MD5;
+ }
+ return id;
}
-static CURLcode sectransp_set_default_ciphers(struct Curl_easy *data,
- SSLContextRef ssl_ctx)
+/* allocated memory must be freed */
+static SSLCipherSuite * sectransp_get_supported_ciphers(SSLContextRef ssl_ctx,
+ size_t *len)
{
- size_t all_ciphers_count = 0UL, allowed_ciphers_count = 0UL, i;
- SSLCipherSuite *all_ciphers = NULL, *allowed_ciphers = NULL;
+ SSLCipherSuite *ciphers = NULL;
OSStatus err = noErr;
+ *len = 0;
-#if CURL_BUILD_MAC
- int darwinver_maj = 0, darwinver_min = 0;
+ err = SSLGetNumberSupportedCiphers(ssl_ctx, len);
+ if(err != noErr)
+ goto failed;
- GetDarwinVersionNumber(&darwinver_maj, &darwinver_min);
-#endif /* CURL_BUILD_MAC */
+ ciphers = malloc(*len * sizeof(SSLCipherSuite));
+ if(!ciphers)
+ goto failed;
+
+ err = SSLGetSupportedCiphers(ssl_ctx, ciphers, len);
+ if(err != noErr)
+ goto failed;
- /* Disable cipher suites that ST supports but are not safe. These ciphers
- are unlikely to be used in any case since ST gives other ciphers a much
- higher priority, but it's probably better that we not connect at all than
- to give the user a false sense of security if the server only supports
- insecure ciphers. (Note: We don't care about SSLv2-only ciphers.) */
- err = SSLGetNumberSupportedCiphers(ssl_ctx, &all_ciphers_count);
- if(err != noErr) {
- failf(data, "SSL: SSLGetNumberSupportedCiphers() failed: OSStatus %d",
- err);
- return CURLE_SSL_CIPHER;
- }
- all_ciphers = malloc(all_ciphers_count*sizeof(SSLCipherSuite));
- if(!all_ciphers) {
- failf(data, "SSL: Failed to allocate memory for all ciphers");
- return CURLE_OUT_OF_MEMORY;
- }
- allowed_ciphers = malloc(all_ciphers_count*sizeof(SSLCipherSuite));
- if(!allowed_ciphers) {
- Curl_safefree(all_ciphers);
- failf(data, "SSL: Failed to allocate memory for allowed ciphers");
- return CURLE_OUT_OF_MEMORY;
- }
- err = SSLGetSupportedCiphers(ssl_ctx, all_ciphers,
- &all_ciphers_count);
- if(err != noErr) {
- Curl_safefree(all_ciphers);
- Curl_safefree(allowed_ciphers);
- return CURLE_SSL_CIPHER;
- }
- for(i = 0UL ; i < all_ciphers_count ; i++) {
#if CURL_BUILD_MAC
- /* There's a known bug in early versions of Mountain Lion where ST's ECC
- ciphers (cipher suite 0xC001 through 0xC032) simply do not work.
- Work around the problem here by disabling those ciphers if we are
- running in an affected version of OS X. */
- if(darwinver_maj == 12 && darwinver_min <= 3 &&
- all_ciphers[i] >= 0xC001 && all_ciphers[i] <= 0xC032) {
- continue;
+ {
+ int maj = 0, min = 0;
+ GetDarwinVersionNumber(&maj, &min);
+ /* There is a known bug in early versions of Mountain Lion where ST's ECC
+ ciphers (cipher suite 0xC001 through 0xC032) simply do not work.
+ Work around the problem here by disabling those ciphers if we are
+ running in an affected version of OS X. */
+ if(maj == 12 && min <= 3) {
+ size_t i = 0, j = 0;
+ for(; i < *len; i++) {
+ if(ciphers[i] >= 0xC001 && ciphers[i] <= 0xC032)
+ continue;
+ ciphers[j++] = ciphers[i];
+ }
+ *len = j;
}
-#endif /* CURL_BUILD_MAC */
- if(is_cipher_suite_strong(all_ciphers[i])) {
- allowed_ciphers[allowed_ciphers_count++] = all_ciphers[i];
+ }
+#endif
+
+ return ciphers;
+failed:
+ *len = 0;
+ Curl_safefree(ciphers);
+ return NULL;
+}
+
+static CURLcode sectransp_set_default_ciphers(struct Curl_easy *data,
+ SSLContextRef ssl_ctx)
+{
+ CURLcode ret = CURLE_SSL_CIPHER;
+ size_t count = 0, i, j;
+ OSStatus err;
+ size_t supported_len;
+ SSLCipherSuite *ciphers = NULL;
+
+ ciphers = sectransp_get_supported_ciphers(ssl_ctx, &supported_len);
+ if(!ciphers) {
+ failf(data, "SSL: Failed to get supported ciphers");
+ goto failed;
+ }
+
+ /* Intersect the ciphers supported by Secure Transport with the default
+ * ciphers, using the order of the former. */
+ for(i = 0; i < supported_len; i++) {
+ for(j = 0; j < DEFAULT_CIPHERS_LEN; j++) {
+ if(default_ciphers[j] == ciphers[i]) {
+ ciphers[count++] = ciphers[i];
+ break;
+ }
}
}
- err = SSLSetEnabledCiphers(ssl_ctx, allowed_ciphers,
- allowed_ciphers_count);
- Curl_safefree(all_ciphers);
- Curl_safefree(allowed_ciphers);
+
+ if(count == 0) {
+ failf(data, "SSL: no supported default ciphers");
+ goto failed;
+ }
+
+ err = SSLSetEnabledCiphers(ssl_ctx, ciphers, count);
if(err != noErr) {
failf(data, "SSL: SSLSetEnabledCiphers() failed: OSStatus %d", err);
- return CURLE_SSL_CIPHER;
+ goto failed;
}
- return CURLE_OK;
+
+ ret = CURLE_OK;
+failed:
+ Curl_safefree(ciphers);
+ return ret;
}
static CURLcode sectransp_set_selected_ciphers(struct Curl_easy *data,
SSLContextRef ssl_ctx,
const char *ciphers)
{
- size_t ciphers_count = 0;
- const char *cipher_start = ciphers;
- OSStatus err = noErr;
- SSLCipherSuite selected_ciphers[NUM_OF_CIPHERS];
+ CURLcode ret = CURLE_SSL_CIPHER;
+ size_t count = 0, i;
+ const char *ptr, *end;
+ OSStatus err;
+ size_t supported_len;
+ SSLCipherSuite *supported = NULL;
+ SSLCipherSuite *selected = NULL;
- if(!ciphers)
- return CURLE_OK;
+ supported = sectransp_get_supported_ciphers(ssl_ctx, &supported_len);
+ if(!supported) {
+ failf(data, "SSL: Failed to get supported ciphers");
+ goto failed;
+ }
- while(sectransp_is_separator(*ciphers)) /* Skip initial separators. */
- ciphers++;
- if(!*ciphers)
- return CURLE_OK;
+ selected = malloc(supported_len * sizeof(SSLCipherSuite));
+ if(!selected) {
+ failf(data, "SSL: Failed to allocate memory");
+ goto failed;
+ }
- cipher_start = ciphers;
- while(*cipher_start && ciphers_count < NUM_OF_CIPHERS) {
- bool cipher_found = FALSE;
- size_t cipher_len = 0;
- const char *cipher_end = NULL;
- bool tls_name = FALSE;
- size_t i;
-
- /* Skip separators */
- 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' && !sectransp_is_separator(*cipher_end)) {
- ++cipher_end;
- }
+ for(ptr = ciphers; ptr[0] != '\0' && count < supported_len; ptr = end) {
+ uint16_t id = sectransp_cipher_suite_walk_str(&ptr, &end);
- /* IANA cipher names start with the TLS_ or SSL_ prefix.
- If the 4th symbol of the cipher is '_' we look for a cipher in the
- table by its (TLS) name.
- Otherwise, we try to match cipher by an alias. */
- if(cipher_start[3] == '_') {
- tls_name = TRUE;
+ /* Check if cipher is supported */
+ if(id) {
+ for(i = 0; i < supported_len && supported[i] != id; i++);
+ if(i == supported_len)
+ id = 0;
}
- /* Iterate through the cipher table and look for the cipher, starting
- the cipher number 0x01 because the 0x00 is not the real cipher */
- cipher_len = cipher_end - cipher_start;
- for(i = 1; i < NUM_OF_CIPHERS; ++i) {
- const char *table_cipher_name = NULL;
- if(tls_name) {
- table_cipher_name = ciphertable[i].name;
- }
- else if(ciphertable[i].alias_name) {
- table_cipher_name = ciphertable[i].alias_name;
- }
- else {
- continue;
- }
- /* Compare a part of the string between separators with a cipher name
- in the table and make sure we matched the whole cipher name */
- if(strncmp(cipher_start, table_cipher_name, cipher_len) == 0
- && table_cipher_name[cipher_len] == '\0') {
- selected_ciphers[ciphers_count] = ciphertable[i].num;
- ++ciphers_count;
- cipher_found = TRUE;
- break;
- }
- }
- if(!cipher_found) {
- /* It would be more human-readable if we print the wrong cipher name
- but we don't want to allocate any additional memory and copy the name
- into it, then add it into logs.
- Also, we do not modify an original cipher list string. We just point
- to positions where cipher starts and ends in the cipher list string.
- The message is a bit cryptic and longer than necessary but can be
- understood by humans. */
- failf(data, "SSL: cipher string \"%s\" contains unsupported cipher name"
- " starting position %zd and ending position %zd",
- ciphers,
- cipher_start - ciphers,
- cipher_end - ciphers);
- return CURLE_SSL_CIPHER;
- }
- if(*cipher_end) {
- cipher_start = cipher_end + 1;
+ if(!id) {
+ if(ptr[0] != '\0')
+ infof(data, "SSL: unknown cipher in list: \"%.*s\"", (int) (end - ptr),
+ ptr);
+ continue;
}
- else {
- break;
+
+ /* No duplicates allowed (so selected cannot overflow) */
+ for(i = 0; i < count && selected[i] != id; i++);
+ if(i < count) {
+ infof(data, "SSL: duplicate cipher in list: \"%.*s\"", (int) (end - ptr),
+ ptr);
+ continue;
}
+
+ selected[count++] = id;
+ }
+
+ if(count == 0) {
+ failf(data, "SSL: no supported cipher in list");
+ goto failed;
}
- /* All cipher suites in the list are found. Report to logs as-is */
- infof(data, "SSL: Setting cipher suites list \"%s\"", ciphers);
- err = SSLSetEnabledCiphers(ssl_ctx, selected_ciphers, ciphers_count);
+ err = SSLSetEnabledCiphers(ssl_ctx, selected, count);
if(err != noErr) {
failf(data, "SSL: SSLSetEnabledCiphers() failed: OSStatus %d", err);
- return CURLE_SSL_CIPHER;
+ goto failed;
}
- return CURLE_OK;
+
+ ret = CURLE_OK;
+failed:
+ Curl_safefree(supported);
+ Curl_safefree(selected);
+ return ret;
}
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
+ function that does this, but I do not 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... */
@@ -1665,6 +1088,7 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
const struct curl_blob *ssl_cert_blob = ssl_config->primary.cert_blob;
char *ciphers;
OSStatus err = noErr;
+ CURLcode result;
#if CURL_BUILD_MAC
int darwinver_maj = 0, darwinver_min = 0;
@@ -1675,23 +1099,23 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
#endif /* CURL_BUILD_MAC */
#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
- if(SSLCreateContext) { /* use the newer API if available */
+ if(&SSLCreateContext) { /* use the newer API if available */
if(backend->ssl_ctx)
CFRelease(backend->ssl_ctx);
backend->ssl_ctx = SSLCreateContext(NULL, kSSLClientSide, kSSLStreamType);
if(!backend->ssl_ctx) {
- failf(data, "SSL: couldn't create a context");
+ failf(data, "SSL: could not create a context");
return CURLE_OUT_OF_MEMORY;
}
}
else {
- /* The old ST API does not exist under iOS, so don't compile it: */
+ /* The old ST API does not exist under iOS, so do not compile it: */
#if CURL_SUPPORT_MAC_10_8
if(backend->ssl_ctx)
(void)SSLDisposeContext(backend->ssl_ctx);
err = SSLNewContext(false, &(backend->ssl_ctx));
if(err != noErr) {
- failf(data, "SSL: couldn't create a context: OSStatus %d", err);
+ failf(data, "SSL: could not create a context: OSStatus %d", err);
return CURLE_OUT_OF_MEMORY;
}
#endif /* CURL_SUPPORT_MAC_10_8 */
@@ -1701,19 +1125,20 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
(void)SSLDisposeContext(backend->ssl_ctx);
err = SSLNewContext(false, &(backend->ssl_ctx));
if(err != noErr) {
- failf(data, "SSL: couldn't create a context: OSStatus %d", err);
+ failf(data, "SSL: could not create a context: OSStatus %d", err);
return CURLE_OUT_OF_MEMORY;
}
#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
backend->ssl_write_buffered_length = 0UL; /* reset buffered write length */
- /* check to see if we've been told to use an explicit SSL/TLS version */
+ /* check to see if we have been told to use an explicit SSL/TLS version */
#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
- if(SSLSetProtocolVersionMax) {
+ if(&SSLSetProtocolVersionMax) {
switch(conn_config->version) {
case CURL_SSLVERSION_TLSv1:
(void)SSLSetProtocolVersionMin(backend->ssl_ctx, kTLSProtocol1);
-#if (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && HAVE_BUILTIN_AVAILABLE == 1
+#if (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && \
+ defined(HAVE_BUILTIN_AVAILABLE)
if(__builtin_available(macOS 10.13, iOS 11.0, *)) {
(void)SSLSetProtocolVersionMax(backend->ssl_ctx, kTLSProtocol13);
}
@@ -1723,19 +1148,17 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
#else
(void)SSLSetProtocolVersionMax(backend->ssl_ctx, kTLSProtocol12);
#endif /* (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) &&
- HAVE_BUILTIN_AVAILABLE == 1 */
+ defined(HAVE_BUILTIN_AVAILABLE) */
break;
case CURL_SSLVERSION_DEFAULT:
case CURL_SSLVERSION_TLSv1_0:
case CURL_SSLVERSION_TLSv1_1:
case CURL_SSLVERSION_TLSv1_2:
case CURL_SSLVERSION_TLSv1_3:
- {
- CURLcode result = set_ssl_version_min_max(cf, data);
- if(result != CURLE_OK)
- return result;
- break;
- }
+ result = set_ssl_version_min_max(cf, data);
+ if(result != CURLE_OK)
+ return result;
+ break;
case CURL_SSLVERSION_SSLv3:
case CURL_SSLVERSION_SSLv2:
failf(data, "SSL versions not supported");
@@ -1767,12 +1190,10 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
case CURL_SSLVERSION_TLSv1_1:
case CURL_SSLVERSION_TLSv1_2:
case CURL_SSLVERSION_TLSv1_3:
- {
- CURLcode result = set_ssl_version_min_max(cf, data);
- if(result != CURLE_OK)
- return result;
- break;
- }
+ result = set_ssl_version_min_max(cf, data);
+ if(result != CURLE_OK)
+ return result;
+ break;
case CURL_SSLVERSION_SSLv3:
case CURL_SSLVERSION_SSLv2:
failf(data, "SSL versions not supported");
@@ -1817,7 +1238,8 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
}
#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
-#if (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && HAVE_BUILTIN_AVAILABLE == 1
+#if (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && \
+ defined(HAVE_BUILTIN_AVAILABLE)
if(connssl->alpn) {
if(__builtin_available(macOS 10.13.4, iOS 11, tvOS 11, *)) {
struct alpn_proto_buf proto;
@@ -1886,7 +1308,7 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
err = SecIdentityCopyCertificate(cert_and_key, &cert);
if(err == noErr) {
char *certp;
- CURLcode result = CopyCertSubject(data, cert, &certp);
+ result = CopyCertSubject(data, cert, &certp);
if(!result) {
infof(data, "Client certificate: %s", certp);
free(certp);
@@ -1929,11 +1351,11 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
cert_showfilename_error);
break;
case errSecItemNotFound:
- failf(data, "SSL: Can't find the certificate \"%s\" and its private "
+ failf(data, "SSL: cannot find the certificate \"%s\" and its private "
"key in the Keychain.", cert_showfilename_error);
break;
default:
- failf(data, "SSL: Can't load the certificate \"%s\" and its private "
+ failf(data, "SSL: cannot load the certificate \"%s\" and its private "
"key: OSStatus %d", cert_showfilename_error, err);
break;
}
@@ -1948,7 +1370,7 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
#if CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS
/* Snow Leopard introduced the SSLSetSessionOption() function, but due to
a library bug with the way the kSSLSessionOptionBreakOnServerAuth flag
- works, it doesn't work as expected under Snow Leopard, Lion or
+ works, it does not work as expected under Snow Leopard, Lion or
Mountain Lion.
So we need to call SSLSetEnableCertVerify() on those older cats in order
to disable certificate validation if the user turned that off.
@@ -1962,9 +1384,9 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
Darwin 15.x.x is El Capitan (10.11)
*/
#if CURL_BUILD_MAC
- if(SSLSetSessionOption && darwinver_maj >= 13) {
+ if(&SSLSetSessionOption && darwinver_maj >= 13) {
#else
- if(SSLSetSessionOption) {
+ if(&SSLSetSessionOption) {
#endif /* CURL_BUILD_MAC */
bool break_on_auth = !conn_config->verifypeer ||
ssl_cafile || ssl_cablob;
@@ -2000,7 +1422,7 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
bool is_cert_file = (!is_cert_data) && is_file(ssl_cafile);
if(!(is_cert_file || is_cert_data)) {
- failf(data, "SSL: can't load CA certificate file %s",
+ failf(data, "SSL: cannot load CA certificate file %s",
ssl_cafile ? ssl_cafile : "(blob memory)");
return CURLE_SSL_CACERT_BADFILE;
}
@@ -2031,21 +1453,21 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
ciphers = conn_config->cipher_list;
if(ciphers) {
- err = sectransp_set_selected_ciphers(data, backend->ssl_ctx, ciphers);
+ result = sectransp_set_selected_ciphers(data, backend->ssl_ctx, ciphers);
}
else {
- err = sectransp_set_default_ciphers(data, backend->ssl_ctx);
+ result = sectransp_set_default_ciphers(data, backend->ssl_ctx);
}
- if(err != noErr) {
+ if(result != CURLE_OK) {
failf(data, "SSL: Unable to set ciphers for SSL/TLS handshake. "
- "Error code: %d", err);
+ "Error code: %d", (int)result);
return CURLE_SSL_CIPHER;
}
#if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7
/* We want to enable 1/n-1 when using a CBC cipher unless the user
- specifically doesn't want us doing that: */
- if(SSLSetSessionOption) {
+ specifically does not want us doing that: */
+ if(&SSLSetSessionOption) {
SSLSetSessionOption(backend->ssl_ctx, kSSLSessionOptionSendOneByteRecord,
!ssl_config->enable_beast);
SSLSetSessionOption(backend->ssl_ctx, kSSLSessionOptionFalseStart,
@@ -2053,8 +1475,8 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
}
#endif /* CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 */
- /* Check if there's a cached ID we can/should use here! */
- if(ssl_config->primary.sessionid) {
+ /* Check if there is a cached ID we can/should use here! */
+ if(ssl_config->primary.cache_session) {
char *ssl_sessionid;
size_t ssl_sessionid_len;
@@ -2071,10 +1493,9 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
/* Informational message */
infof(data, "SSL reusing session ID");
}
- /* If there isn't one, then let's make one up! This has to be done prior
+ /* If there is not one, then let's make one up! This has to be done prior
to starting the handshake. */
else {
- CURLcode result;
ssl_sessionid =
aprintf("%s:%d:%d:%s:%d",
ssl_cafile ? ssl_cafile : "(blob memory)",
@@ -2089,9 +1510,9 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
return CURLE_SSL_CONNECT_ERROR;
}
- result = Curl_ssl_addsessionid(cf, data, &connssl->peer, ssl_sessionid,
- ssl_sessionid_len,
- sectransp_session_free);
+ result = Curl_ssl_set_sessionid(cf, data, &connssl->peer, ssl_sessionid,
+ ssl_sessionid_len,
+ sectransp_session_free);
Curl_ssl_sessionid_unlock(data);
if(result)
return result;
@@ -2121,7 +1542,7 @@ static long pem_to_der(const char *in, unsigned char **out, size_t *outlen)
char *sep_start, *sep_end, *cert_start, *cert_end;
size_t i, j, err;
size_t len;
- unsigned char *b64;
+ char *b64;
/* Jump through the separators at the beginning of the certificate. */
sep_start = strstr(in, "-----");
@@ -2202,16 +1623,16 @@ static int read_cert(const char *file, unsigned char **out, size_t *outlen)
return 0;
}
-static int append_cert_to_array(struct Curl_easy *data,
- const unsigned char *buf, size_t buflen,
- CFMutableArrayRef array)
+static CURLcode append_cert_to_array(struct Curl_easy *data,
+ const unsigned char *buf, size_t buflen,
+ CFMutableArrayRef array)
{
char *certp;
CURLcode result;
SecCertificateRef cacert;
CFDataRef certdata;
- certdata = CFDataCreate(kCFAllocatorDefault, buf, buflen);
+ certdata = CFDataCreate(kCFAllocatorDefault, buf, (CFIndex)buflen);
if(!certdata) {
failf(data, "SSL: failed to allocate array for CA certificate");
return CURLE_OUT_OF_MEMORY;
@@ -2248,7 +1669,8 @@ static CURLcode verify_cert_buf(struct Curl_cfilter *cf,
const unsigned char *certbuf, size_t buflen,
SSLContextRef ctx)
{
- int n = 0, rc;
+ int n = 0;
+ CURLcode rc;
long res;
unsigned char *der;
size_t derlen, offset = 0;
@@ -2419,7 +1841,7 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
/* Result is returned to caller */
CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
- /* if a path wasn't specified, don't pin */
+ /* if a path was not specified, do not pin */
if(!pinnedpubkey)
return CURLE_OK;
@@ -2451,17 +1873,17 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
#elif SECTRANSP_PINNEDPUBKEY_V2
{
- OSStatus success;
- success = SecItemExport(keyRef, kSecFormatOpenSSL, 0, NULL,
- &publicKeyBits);
- CFRelease(keyRef);
- if(success != errSecSuccess || !publicKeyBits)
- break;
+ OSStatus success;
+ success = SecItemExport(keyRef, kSecFormatOpenSSL, 0, NULL,
+ &publicKeyBits);
+ CFRelease(keyRef);
+ if(success != errSecSuccess || !publicKeyBits)
+ break;
}
#endif /* SECTRANSP_PINNEDPUBKEY_V2 */
- pubkeylen = CFDataGetLength(publicKeyBits);
+ pubkeylen = (size_t)CFDataGetLength(publicKeyBits);
pubkey = (unsigned char *)CFDataGetBytePtr(publicKeyBits);
switch(pubkeylen) {
@@ -2530,24 +1952,23 @@ static CURLcode sectransp_connect_step2(struct Curl_cfilter *cf,
SSLCipherSuite cipher;
SSLProtocol protocol = 0;
- DEBUGASSERT(ssl_connect_2 == connssl->connecting_state
- || ssl_connect_2_reading == connssl->connecting_state
- || ssl_connect_2_writing == connssl->connecting_state);
+ DEBUGASSERT(ssl_connect_2 == connssl->connecting_state);
DEBUGASSERT(backend);
CURL_TRC_CF(data, cf, "connect_step2");
/* Here goes nothing: */
check_handshake:
+ connssl->io_need = CURL_SSL_IO_NEED_NONE;
err = SSLHandshake(backend->ssl_ctx);
if(err != noErr) {
switch(err) {
- case errSSLWouldBlock: /* they're not done with us yet */
- connssl->connecting_state = backend->ssl_direction ?
- ssl_connect_2_writing : ssl_connect_2_reading;
+ case errSSLWouldBlock: /* they are not done with us yet */
+ connssl->io_need = backend->ssl_direction ?
+ CURL_SSL_IO_NEED_SEND : CURL_SSL_IO_NEED_RECV;
return CURLE_OK;
- /* The below is errSSLServerAuthCompleted; it's not defined in
+ /* The below is errSSLServerAuthCompleted; it is not defined in
Leopard's headers */
case -9841:
if((conn_config->CAfile || conn_config->ca_info_blob) &&
@@ -2657,8 +2078,8 @@ check_handshake:
"authority");
break;
- /* This error is raised if the server's cert didn't match the server's
- host name: */
+ /* This error is raised if the server's cert did not match the server's
+ hostname: */
case errSSLHostNameMismatch:
failf(data, "SSL certificate peer verification failed, the "
"certificate did not match \"%s\"\n", connssl->peer.dispname);
@@ -2759,7 +2180,8 @@ check_handshake:
return CURLE_SSL_CONNECT_ERROR;
}
else {
- /* we have been connected fine, we're not waiting for anything else. */
+ char cipher_str[64];
+ /* we have been connected fine, we are not waiting for anything else. */
connssl->connecting_state = ssl_connect_3;
#ifdef SECTRANSP_PINNEDPUBKEY
@@ -2777,33 +2199,30 @@ check_handshake:
/* Informational message */
(void)SSLGetNegotiatedCipher(backend->ssl_ctx, &cipher);
(void)SSLGetNegotiatedProtocolVersion(backend->ssl_ctx, &protocol);
+
+ sectransp_cipher_suite_get_str((uint16_t) cipher, cipher_str,
+ sizeof(cipher_str), true);
switch(protocol) {
case kSSLProtocol2:
- infof(data, "SSL 2.0 connection using %s",
- TLSCipherNameForNumber(cipher));
+ infof(data, "SSL 2.0 connection using %s", cipher_str);
break;
case kSSLProtocol3:
- infof(data, "SSL 3.0 connection using %s",
- TLSCipherNameForNumber(cipher));
+ infof(data, "SSL 3.0 connection using %s", cipher_str);
break;
case kTLSProtocol1:
- infof(data, "TLS 1.0 connection using %s",
- TLSCipherNameForNumber(cipher));
+ infof(data, "TLS 1.0 connection using %s", cipher_str);
break;
#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
case kTLSProtocol11:
- infof(data, "TLS 1.1 connection using %s",
- TLSCipherNameForNumber(cipher));
+ infof(data, "TLS 1.1 connection using %s", cipher_str);
break;
case kTLSProtocol12:
- infof(data, "TLS 1.2 connection using %s",
- TLSCipherNameForNumber(cipher));
+ infof(data, "TLS 1.2 connection using %s", cipher_str);
break;
#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
#if CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11
case kTLSProtocol13:
- infof(data, "TLS 1.3 connection using %s",
- TLSCipherNameForNumber(cipher));
+ infof(data, "TLS 1.3 connection using %s", cipher_str);
break;
#endif /* CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11 */
default:
@@ -2811,7 +2230,8 @@ check_handshake:
break;
}
-#if(CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && HAVE_BUILTIN_AVAILABLE == 1
+#if (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && \
+ defined(HAVE_BUILTIN_AVAILABLE)
if(connssl->alpn) {
if(__builtin_available(macOS 10.13.4, iOS 11, tvOS 11, *)) {
CFArrayRef alpnArr = NULL;
@@ -2839,7 +2259,7 @@ check_handshake:
BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
/* chosenProtocol is a reference to the string within alpnArr
- and doesn't need to be freed separately */
+ and does not need to be freed separately */
if(alpnArr)
CFRelease(alpnArr);
}
@@ -2941,10 +2361,10 @@ static CURLcode collect_server_cert(struct Curl_cfilter *cf,
/* SSLCopyPeerCertificates() is deprecated as of Mountain Lion.
The function SecTrustGetCertificateAtIndex() is officially present
in Lion, but it is unfortunately also present in Snow Leopard as
- private API and doesn't work as expected. So we have to look for
+ private API and does not work as expected. So we have to look for
a different symbol to make sure this code is only executed under
Lion or later. */
- if(SecTrustCopyPublicKey) {
+ if(&SecTrustCopyPublicKey) {
#pragma unused(server_certs)
err = SSLCopyPeerTrust(backend->ssl_ctx, &trust);
/* For some reason, SSLCopyPeerTrust() can return noErr and yet return
@@ -3030,7 +2450,7 @@ sectransp_connect_common(struct Curl_cfilter *cf, struct Curl_easy *data,
}
if(ssl_connect_1 == connssl->connecting_state) {
- /* Find out how much more time we're allowed */
+ /* Find out how much more time we are allowed */
const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
if(timeout_ms < 0) {
@@ -3044,9 +2464,7 @@ sectransp_connect_common(struct Curl_cfilter *cf, struct Curl_easy *data,
return result;
}
- while(ssl_connect_2 == connssl->connecting_state ||
- ssl_connect_2_reading == connssl->connecting_state ||
- ssl_connect_2_writing == connssl->connecting_state) {
+ while(ssl_connect_2 == connssl->connecting_state) {
/* check allowed time left */
const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
@@ -3057,14 +2475,13 @@ sectransp_connect_common(struct Curl_cfilter *cf, struct Curl_easy *data,
return CURLE_OPERATION_TIMEDOUT;
}
- /* if ssl is expecting something, check if it's available. */
- if(connssl->connecting_state == ssl_connect_2_reading ||
- connssl->connecting_state == ssl_connect_2_writing) {
+ /* if ssl is expecting something, check if it is available. */
+ if(connssl->io_need) {
- curl_socket_t writefd = ssl_connect_2_writing ==
- connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
- curl_socket_t readfd = ssl_connect_2_reading ==
- connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
+ curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND)?
+ sockfd:CURL_SOCKET_BAD;
+ curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV)?
+ sockfd:CURL_SOCKET_BAD;
what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
nonblocking ? 0 : timeout_ms);
@@ -3094,10 +2511,7 @@ sectransp_connect_common(struct Curl_cfilter *cf, struct Curl_easy *data,
* or epoll() will always have a valid fdset to wait on.
*/
result = sectransp_connect_step2(cf, data);
- if(result || (nonblocking &&
- (ssl_connect_2 == connssl->connecting_state ||
- ssl_connect_2_reading == connssl->connecting_state ||
- ssl_connect_2_writing == connssl->connecting_state)))
+ if(result || (nonblocking && (ssl_connect_2 == connssl->connecting_state)))
return result;
} /* repeat step2 until all transactions are done. */
@@ -3146,6 +2560,92 @@ static CURLcode sectransp_connect(struct Curl_cfilter *cf,
return CURLE_OK;
}
+static ssize_t sectransp_recv(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ char *buf,
+ size_t buffersize,
+ CURLcode *curlcode);
+
+static CURLcode sectransp_shutdown(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool send_shutdown, bool *done)
+{
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct st_ssl_backend_data *backend =
+ (struct st_ssl_backend_data *)connssl->backend;
+ CURLcode result = CURLE_OK;
+ ssize_t nread;
+ char buf[1024];
+ size_t i;
+
+ DEBUGASSERT(backend);
+ if(!backend->ssl_ctx || cf->shutdown) {
+ *done = TRUE;
+ goto out;
+ }
+
+ connssl->io_need = CURL_SSL_IO_NEED_NONE;
+ *done = FALSE;
+
+ if(send_shutdown && !backend->sent_shutdown) {
+ OSStatus err;
+
+ CURL_TRC_CF(data, cf, "shutdown, send close notify");
+ err = SSLClose(backend->ssl_ctx);
+ switch(err) {
+ case noErr:
+ backend->sent_shutdown = TRUE;
+ break;
+ case errSSLWouldBlock:
+ connssl->io_need = CURL_SSL_IO_NEED_SEND;
+ result = CURLE_OK;
+ goto out;
+ default:
+ CURL_TRC_CF(data, cf, "shutdown, error: %d", (int)err);
+ result = CURLE_SEND_ERROR;
+ goto out;
+ }
+ }
+
+ for(i = 0; i < 10; ++i) {
+ if(!backend->sent_shutdown) {
+ nread = sectransp_recv(cf, data, buf, (int)sizeof(buf), &result);
+ }
+ else {
+ /* We would like to read the close notify from the server using
+ * secure transport, however SSLRead() no longer works after we
+ * sent the notify from our side. So, we just read from the
+ * underlying filter and hope it will end. */
+ nread = Curl_conn_cf_recv(cf->next, data, buf, sizeof(buf), &result);
+ }
+ CURL_TRC_CF(data, cf, "shutdown read -> %zd, %d", nread, result);
+ if(nread <= 0)
+ break;
+ }
+
+ if(nread > 0) {
+ /* still data coming in? */
+ connssl->io_need = CURL_SSL_IO_NEED_RECV;
+ }
+ else if(nread == 0) {
+ /* We got the close notify alert and are done. */
+ CURL_TRC_CF(data, cf, "shutdown done");
+ *done = TRUE;
+ }
+ else if(result == CURLE_AGAIN) {
+ connssl->io_need = CURL_SSL_IO_NEED_RECV;
+ result = CURLE_OK;
+ }
+ else {
+ DEBUGASSERT(result);
+ CURL_TRC_CF(data, cf, "shutdown, error: %d", result);
+ }
+
+out:
+ cf->shutdown = (result || *done);
+ return result;
+}
+
static void sectransp_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
struct ssl_connect_data *connssl = cf->ctx;
@@ -3158,9 +2658,8 @@ static void sectransp_close(struct Curl_cfilter *cf, struct Curl_easy *data)
if(backend->ssl_ctx) {
CURL_TRC_CF(data, cf, "close");
- (void)SSLClose(backend->ssl_ctx);
#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
- if(SSLCreateContext)
+ if(&SSLCreateContext)
CFRelease(backend->ssl_ctx);
#if CURL_SUPPORT_MAC_10_8
else
@@ -3173,69 +2672,6 @@ static void sectransp_close(struct Curl_cfilter *cf, struct Curl_easy *data)
}
}
-static int sectransp_shutdown(struct Curl_cfilter *cf,
- struct Curl_easy *data)
-{
- struct ssl_connect_data *connssl = cf->ctx;
- struct st_ssl_backend_data *backend =
- (struct st_ssl_backend_data *)connssl->backend;
- ssize_t nread;
- int what;
- int rc;
- char buf[120];
- int loop = 10; /* avoid getting stuck */
- CURLcode result;
-
- DEBUGASSERT(backend);
-
- if(!backend->ssl_ctx)
- return 0;
-
-#ifndef CURL_DISABLE_FTP
- if(data->set.ftp_ccc != CURLFTPSSL_CCC_ACTIVE)
- return 0;
-#endif
-
- sectransp_close(cf, data);
-
- rc = 0;
-
- what = SOCKET_READABLE(Curl_conn_cf_get_socket(cf, data),
- SSL_SHUTDOWN_TIMEOUT);
-
- CURL_TRC_CF(data, cf, "shutdown");
- while(loop--) {
- if(what < 0) {
- /* anything that gets here is fatally bad */
- failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
- rc = -1;
- break;
- }
-
- if(!what) { /* timeout */
- failf(data, "SSL shutdown timeout");
- break;
- }
-
- /* Something to read, let's do it and hope that it is the close
- notify alert from the server. No way to SSL_Read now, so use read(). */
-
- nread = Curl_conn_cf_recv(cf->next, data, buf, sizeof(buf), &result);
-
- if(nread < 0) {
- failf(data, "read: %s", curl_easy_strerror(result));
- rc = -1;
- }
-
- if(nread <= 0)
- break;
-
- what = SOCKET_READABLE(Curl_conn_cf_get_socket(cf, data), 0);
- }
-
- return rc;
-}
-
static size_t sectransp_version(char *buffer, size_t size)
{
return msnprintf(buffer, size, "SecureTransport");
@@ -3267,7 +2703,7 @@ static bool sectransp_data_pending(struct Curl_cfilter *cf,
static CURLcode sectransp_random(struct Curl_easy *data UNUSED_PARAM,
unsigned char *entropy, size_t length)
{
- /* arc4random_buf() isn't available on cats older than Lion, so let's
+ /* arc4random_buf() is not available on cats older than Lion, so let's
do this manually for the benefit of the older cats. */
size_t i;
u_int32_t random_number = 0;
@@ -3298,7 +2734,7 @@ static CURLcode sectransp_sha256sum(const unsigned char *tmp, /* input */
static bool sectransp_false_start(void)
{
#if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7
- if(SSLSetSessionOption)
+ if(&SSLSetSessionOption)
return TRUE;
#endif
return FALSE;
@@ -3325,7 +2761,7 @@ static ssize_t sectransp_send(struct Curl_cfilter *cf,
Now, one could interpret that as "written to the socket," but actually,
it returns the amount of data that was written to a buffer internal to
- the SSLContextRef instead. So it's possible for SSLWrite() to return
+ the SSLContextRef instead. So it is possible for SSLWrite() to return
errSSLWouldBlock and a number of bytes "written" because those bytes were
encrypted and written to a buffer, not to the socket.
@@ -3338,7 +2774,7 @@ static ssize_t sectransp_send(struct Curl_cfilter *cf,
err = SSLWrite(backend->ssl_ctx, NULL, 0UL, &processed);
switch(err) {
case noErr:
- /* processed is always going to be 0 because we didn't write to
+ /* processed is always going to be 0 because we did not write to
the buffer, so return how much was written to the socket */
processed = backend->ssl_write_buffered_length;
backend->ssl_write_buffered_length = 0UL;
@@ -3353,7 +2789,7 @@ static ssize_t sectransp_send(struct Curl_cfilter *cf,
}
}
else {
- /* We've got new data to write: */
+ /* We have got new data to write: */
err = SSLWrite(backend->ssl_ctx, mem, len, &processed);
if(err != noErr) {
switch(err) {
@@ -3410,7 +2846,7 @@ again:
*curlcode = CURLE_OK;
return 0;
- /* The below is errSSLPeerAuthCompleted; it's not defined in
+ /* The below is errSSLPeerAuthCompleted; it is not defined in
Leopard's headers */
case -9841:
if((conn_config->CAfile || conn_config->ca_info_blob) &&
@@ -3476,7 +2912,6 @@ const struct Curl_ssl Curl_ssl_sectransp = {
sectransp_sha256sum, /* sha256sum */
NULL, /* associate_connection */
NULL, /* disassociate_connection */
- NULL, /* free_multi_ssl_backend_data */
sectransp_recv, /* recv decrypted data */
sectransp_send, /* send data to encrypt */
};
diff --git a/libs/libcurl/src/vtls/vtls.c b/libs/libcurl/src/vtls/vtls.c
index f4633a5f1c..8e5f8a5491 100644
--- a/libs/libcurl/src/vtls/vtls.c
+++ b/libs/libcurl/src/vtls/vtls.c
@@ -68,6 +68,8 @@
#include "curl_base64.h"
#include "curl_printf.h"
#include "inet_pton.h"
+#include "connect.h"
+#include "select.h"
#include "strdup.h"
/* The last #include files should be: */
@@ -103,7 +105,7 @@ static CURLcode blobdup(struct curl_blob **dest,
DEBUGASSERT(dest);
DEBUGASSERT(!*dest);
if(src) {
- /* only if there's data to dupe! */
+ /* only if there is data to dupe! */
struct curl_blob *d;
d = malloc(sizeof(struct curl_blob) + src->len);
if(!d)
@@ -152,7 +154,7 @@ static const struct alpn_spec *alpn_get_spec(int httpwant, bool use_alpn)
(void)httpwant;
#endif
/* Use the ALPN protocol "http/1.1" for HTTP/1.x.
- Avoid "http/1.0" because some servers don't support it. */
+ Avoid "http/1.0" because some servers do not support it. */
return &ALPN_SPEC_H11;
}
#endif /* USE_SSL */
@@ -166,7 +168,7 @@ void Curl_ssl_easy_config_init(struct Curl_easy *data)
*/
data->set.ssl.primary.verifypeer = TRUE;
data->set.ssl.primary.verifyhost = TRUE;
- data->set.ssl.primary.sessionid = TRUE; /* session ID caching by default */
+ data->set.ssl.primary.cache_session = TRUE; /* caching by default */
#ifndef CURL_DISABLE_PROXY
data->set.proxy_ssl = data->set.ssl;
#endif
@@ -228,7 +230,7 @@ static bool clone_ssl_primary_config(struct ssl_primary_config *source,
dest->verifypeer = source->verifypeer;
dest->verifyhost = source->verifyhost;
dest->verifystatus = source->verifystatus;
- dest->sessionid = source->sessionid;
+ dest->cache_session = source->cache_session;
dest->ssl_options = source->ssl_options;
CLONE_BLOB(cert_blob);
@@ -453,7 +455,7 @@ static bool ssl_prefs_check(struct Curl_easy *data)
}
static struct ssl_connect_data *cf_ctx_new(struct Curl_easy *data,
- const struct alpn_spec *alpn)
+ const struct alpn_spec *alpn)
{
struct ssl_connect_data *ctx;
@@ -529,8 +531,8 @@ void Curl_ssl_sessionid_unlock(struct Curl_easy *data)
}
/*
- * Check if there's a session ID for the given connection in the cache, and if
- * there's one suitable, it is provided. Returns TRUE when no entry matched.
+ * Check if there is a session ID for the given connection in the cache, and if
+ * there is one suitable, it is provided. Returns TRUE when no entry matched.
*/
bool Curl_ssl_getsessionid(struct Curl_cfilter *cf,
struct Curl_easy *data,
@@ -549,9 +551,9 @@ bool Curl_ssl_getsessionid(struct Curl_cfilter *cf,
if(!ssl_config)
return TRUE;
- DEBUGASSERT(ssl_config->primary.sessionid);
+ DEBUGASSERT(ssl_config->primary.cache_session);
- if(!ssl_config->primary.sessionid || !data->state.session)
+ if(!ssl_config->primary.cache_session || !data->state.session)
/* session ID reuse is disabled or the session cache has not been
setup */
return TRUE;
@@ -590,7 +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",
+ no_match? "Did not find": "Found",
Curl_ssl_cf_is_proxy(cf) ? "proxy" : "host",
cf->conn->handler->scheme, peer->hostname, peer->port));
return no_match;
@@ -635,18 +637,12 @@ void Curl_ssl_delsessionid(struct Curl_easy *data, void *ssl_sessionid)
}
}
-/*
- * Store session id in the session cache. The ID passed on to this function
- * must already have been extracted and allocated the proper way for the SSL
- * layer. Curl_XXXX_session_free() will be called to free/kill the session ID
- * later on.
- */
-CURLcode Curl_ssl_addsessionid(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- const struct ssl_peer *peer,
- void *ssl_sessionid,
- size_t idsize,
- Curl_ssl_sessionid_dtor *sessionid_free_cb)
+CURLcode Curl_ssl_set_sessionid(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ const struct ssl_peer *peer,
+ void *ssl_sessionid,
+ size_t idsize,
+ Curl_ssl_sessionid_dtor *sessionid_free_cb)
{
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);
@@ -657,6 +653,8 @@ CURLcode Curl_ssl_addsessionid(struct Curl_cfilter *cf,
char *clone_conn_to_host = NULL;
int conn_to_port;
long *general_age;
+ void *old_sessionid;
+ size_t old_size;
CURLcode result = CURLE_OUT_OF_MEMORY;
DEBUGASSERT(ssl_sessionid);
@@ -667,9 +665,20 @@ CURLcode Curl_ssl_addsessionid(struct Curl_cfilter *cf,
return CURLE_OK;
}
+ if(!Curl_ssl_getsessionid(cf, data, peer, &old_sessionid, &old_size)) {
+ if((old_size == idsize) &&
+ ((old_sessionid == ssl_sessionid) ||
+ (idsize && !memcmp(old_sessionid, ssl_sessionid, idsize)))) {
+ /* the very same */
+ sessionid_free_cb(ssl_sessionid, idsize);
+ return CURLE_OK;
+ }
+ Curl_ssl_delsessionid(data, old_sessionid);
+ }
+
store = &data->state.session[0];
oldest_age = data->state.session[0].age; /* zero if unused */
- DEBUGASSERT(ssl_config->primary.sessionid);
+ DEBUGASSERT(ssl_config->primary.cache_session);
(void)ssl_config;
clone_host = strdup(peer->hostname);
@@ -687,7 +696,7 @@ CURLcode Curl_ssl_addsessionid(struct Curl_cfilter *cf,
else
conn_to_port = -1;
- /* Now we should add the session ID and the host name to the cache, (remove
+ /* Now we should add the session ID and the hostname to the cache, (remove
the oldest if necessary) */
/* If using shared SSL session, lock! */
@@ -722,12 +731,12 @@ CURLcode Curl_ssl_addsessionid(struct Curl_cfilter *cf,
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 it if there is one already present */
free(store->name);
free(store->conn_to_host);
- store->name = clone_host; /* clone host name */
+ store->name = clone_host; /* clone hostname */
clone_host = NULL;
- store->conn_to_host = clone_conn_to_host; /* clone connect to host name */
+ store->conn_to_host = clone_conn_to_host; /* clone connect to hostname */
clone_conn_to_host = NULL;
store->conn_to_port = conn_to_port; /* connect to port number */
/* port number */
@@ -753,12 +762,6 @@ out:
return CURLE_OK;
}
-void Curl_free_multi_ssl_backend_data(struct multi_ssl_backend_data *mbackend)
-{
- if(Curl_ssl->free_multi_ssl_backend_data && mbackend)
- Curl_ssl->free_multi_ssl_backend_data(mbackend);
-}
-
void Curl_ssl_close_all(struct Curl_easy *data)
{
/* kill the session ID cache if not shared */
@@ -778,11 +781,12 @@ void Curl_ssl_close_all(struct Curl_easy *data)
void Curl_ssl_adjust_pollset(struct Curl_cfilter *cf, struct Curl_easy *data,
struct easy_pollset *ps)
{
- if(!cf->connected) {
- struct ssl_connect_data *connssl = cf->ctx;
+ struct ssl_connect_data *connssl = cf->ctx;
+
+ if(connssl->io_need) {
curl_socket_t sock = Curl_conn_cf_get_socket(cf->next, data);
if(sock != CURL_SOCKET_BAD) {
- if(connssl->connecting_state == ssl_connect_2_writing) {
+ if(connssl->io_need & CURL_SSL_IO_NEED_SEND) {
Curl_pollset_set_out_only(data, ps, sock);
CURL_TRC_CF(data, cf, "adjust_pollset, POLLOUT fd=%"
CURL_FORMAT_SOCKET_T, sock);
@@ -1000,7 +1004,7 @@ CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data,
(void)data;
#endif
- /* if a path wasn't specified, don't pin */
+ /* if a path was not specified, do not pin */
if(!pinnedpubkey)
return CURLE_OK;
if(!pubkey || !pubkeylen)
@@ -1048,7 +1052,7 @@ CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data,
end_pos = strstr(begin_pos, ";sha256//");
/*
* if there is an end_pos, null terminate,
- * otherwise it'll go to the end of the original string
+ * otherwise it will go to the end of the original string
*/
if(end_pos)
end_pos[0] = '\0';
@@ -1094,7 +1098,7 @@ CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data,
/*
* if the size of our certificate is bigger than the file
- * size then it can't match
+ * size then it cannot match
*/
size = curlx_sotouz((curl_off_t) filesize);
if(pubkeylen > size)
@@ -1112,7 +1116,7 @@ CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data,
if((int) fread(buf, size, 1, fp) != 1)
break;
- /* If the sizes are the same, it can't be base64 encoded, must be der */
+ /* If the sizes are the same, it cannot be base64 encoded, must be der */
if(pubkeylen == size) {
if(!memcmp(pubkey, buf, pubkeylen))
result = CURLE_OK;
@@ -1120,18 +1124,18 @@ CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data,
}
/*
- * Otherwise we will assume it's PEM and try to decode it
+ * Otherwise we will assume it is PEM and try to decode it
* after placing null terminator
*/
buf[size] = '\0';
pem_read = pubkey_pem_to_der((const char *)buf, &pem_ptr, &pem_len);
- /* if it wasn't read successfully, exit */
+ /* if it was not read successfully, exit */
if(pem_read)
break;
/*
- * if the size of our certificate doesn't match the size of
- * the decoded file, they can't be the same, otherwise compare
+ * if the size of our certificate does not match the size of
+ * the decoded file, they cannot be the same, otherwise compare
*/
if(pubkeylen == pem_len && !memcmp(pubkey, pem_ptr, pubkeylen))
result = CURLE_OK;
@@ -1173,12 +1177,18 @@ int Curl_none_init(void)
void Curl_none_cleanup(void)
{ }
-int Curl_none_shutdown(struct Curl_cfilter *cf UNUSED_PARAM,
- struct Curl_easy *data UNUSED_PARAM)
+CURLcode Curl_none_shutdown(struct Curl_cfilter *cf UNUSED_PARAM,
+ struct Curl_easy *data UNUSED_PARAM,
+ bool send_shutdown UNUSED_PARAM,
+ bool *done)
{
(void)data;
(void)cf;
- return 0;
+ (void)send_shutdown;
+ /* Every SSL backend should have a shutdown implementation. Until we
+ * have implemented that, we put this fake in place. */
+ *done = TRUE;
+ return CURLE_OK;
}
int Curl_none_check_cxn(struct Curl_cfilter *cf, struct Curl_easy *data)
@@ -1339,7 +1349,6 @@ static const struct Curl_ssl Curl_ssl_multi = {
NULL, /* sha256sum */
NULL, /* associate_connection */
NULL, /* disassociate_connection */
- NULL, /* free_multi_ssl_backend_data */
multissl_recv_plain, /* recv decrypted data */
multissl_send_plain, /* send data to encrypt */
};
@@ -1349,8 +1358,6 @@ const struct Curl_ssl *Curl_ssl =
&Curl_ssl_multi;
#elif defined(USE_WOLFSSL)
&Curl_ssl_wolfssl;
-#elif defined(USE_SECTRANSP)
- &Curl_ssl_sectransp;
#elif defined(USE_GNUTLS)
&Curl_ssl_gnutls;
#elif defined(USE_MBEDTLS)
@@ -1359,6 +1366,8 @@ const struct Curl_ssl *Curl_ssl =
&Curl_ssl_rustls;
#elif defined(USE_OPENSSL)
&Curl_ssl_openssl;
+#elif defined(USE_SECTRANSP)
+ &Curl_ssl_sectransp;
#elif defined(USE_SCHANNEL)
&Curl_ssl_schannel;
#elif defined(USE_BEARSSL)
@@ -1371,9 +1380,6 @@ static const struct Curl_ssl *available_backends[] = {
#if defined(USE_WOLFSSL)
&Curl_ssl_wolfssl,
#endif
-#if defined(USE_SECTRANSP)
- &Curl_ssl_sectransp,
-#endif
#if defined(USE_GNUTLS)
&Curl_ssl_gnutls,
#endif
@@ -1383,6 +1389,9 @@ static const struct Curl_ssl *available_backends[] = {
#if defined(USE_OPENSSL)
&Curl_ssl_openssl,
#endif
+#if defined(USE_SECTRANSP)
+ &Curl_ssl_sectransp,
+#endif
#if defined(USE_SCHANNEL)
&Curl_ssl_schannel,
#endif
@@ -1564,10 +1573,10 @@ CURLcode Curl_ssl_peer_init(struct ssl_peer *peer, struct Curl_cfilter *cf,
const char *ehostname, *edispname;
int eport;
- /* We need the hostname for SNI negotiation. Once handshaked, this
- * remains the SNI hostname for the TLS connection. But when the
- * connection is reused, the settings in cf->conn might change.
- * So we keep a copy of the hostname we use for SNI.
+ /* We need the hostname for SNI negotiation. Once handshaked, this remains
+ * the SNI hostname for the TLS connection. When the connection is reused,
+ * the settings in cf->conn might change. We keep a copy of the hostname we
+ * use for SNI.
*/
#ifndef CURL_DISABLE_PROXY
if(Curl_ssl_cf_is_proxy(cf)) {
@@ -1751,17 +1760,34 @@ static ssize_t ssl_cf_recv(struct Curl_cfilter *cf,
return nread;
}
-static void ssl_cf_adjust_pollset(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- struct easy_pollset *ps)
+static CURLcode ssl_cf_shutdown(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool *done)
{
- struct cf_call_data save;
+ CURLcode result = CURLE_OK;
+
+ *done = TRUE;
+ if(!cf->shutdown) {
+ struct cf_call_data save;
- if(!cf->connected) {
CF_DATA_SAVE(save, cf, data);
- Curl_ssl->adjust_pollset(cf, data, ps);
+ result = Curl_ssl->shut_down(cf, data, TRUE, done);
+ CURL_TRC_CF(data, cf, "cf_shutdown -> %d, done=%d", result, *done);
CF_DATA_RESTORE(cf, save);
+ cf->shutdown = (result || *done);
}
+ return result;
+}
+
+static void ssl_cf_adjust_pollset(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct easy_pollset *ps)
+{
+ struct cf_call_data save;
+
+ CF_DATA_SAVE(save, cf, data);
+ Curl_ssl->adjust_pollset(cf, data, ps);
+ CF_DATA_RESTORE(cf, save);
}
static CURLcode ssl_cf_cntrl(struct Curl_cfilter *cf,
@@ -1851,6 +1877,7 @@ struct Curl_cftype Curl_cft_ssl = {
ssl_cf_destroy,
ssl_cf_connect,
ssl_cf_close,
+ ssl_cf_shutdown,
Curl_cf_def_get_host,
ssl_cf_adjust_pollset,
ssl_cf_data_pending,
@@ -1871,6 +1898,7 @@ struct Curl_cftype Curl_cft_ssl_proxy = {
ssl_cf_destroy,
ssl_cf_connect,
ssl_cf_close,
+ ssl_cf_shutdown,
Curl_cf_def_get_host,
ssl_cf_adjust_pollset,
ssl_cf_data_pending,
@@ -1982,10 +2010,10 @@ CURLcode Curl_cf_ssl_proxy_insert_after(struct Curl_cfilter *cf_at,
#endif /* !CURL_DISABLE_PROXY */
-bool Curl_ssl_supports(struct Curl_easy *data, int option)
+bool Curl_ssl_supports(struct Curl_easy *data, unsigned int ssl_option)
{
(void)data;
- return (Curl_ssl->supports & option)? TRUE : FALSE;
+ return (Curl_ssl->supports & ssl_option)? TRUE : FALSE;
}
static struct Curl_cfilter *get_ssl_filter(struct Curl_cfilter *cf)
@@ -2021,19 +2049,77 @@ void *Curl_ssl_get_internals(struct Curl_easy *data, int sockindex,
return result;
}
+static CURLcode vtls_shutdown_blocking(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool send_shutdown, bool *done)
+{
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct cf_call_data save;
+ CURLcode result = CURLE_OK;
+ timediff_t timeout_ms;
+ int what, loop = 10;
+
+ if(cf->shutdown) {
+ *done = TRUE;
+ return CURLE_OK;
+ }
+ CF_DATA_SAVE(save, cf, data);
+
+ *done = FALSE;
+ while(!result && !*done && loop--) {
+ timeout_ms = Curl_shutdown_timeleft(cf->conn, cf->sockindex, NULL);
+
+ if(timeout_ms < 0) {
+ /* no need to continue if time is already up */
+ failf(data, "SSL shutdown timeout");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+
+ result = Curl_ssl->shut_down(cf, data, send_shutdown, done);
+ if(result ||*done)
+ goto out;
+
+ if(connssl->io_need) {
+ what = Curl_conn_cf_poll(cf, data, timeout_ms);
+ if(what < 0) {
+ /* fatal error */
+ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
+ result = CURLE_RECV_ERROR;
+ goto out;
+ }
+ else if(0 == what) {
+ /* timeout */
+ failf(data, "SSL shutdown timeout");
+ result = CURLE_OPERATION_TIMEDOUT;
+ goto out;
+ }
+ /* socket is readable or writable */
+ }
+ }
+out:
+ CF_DATA_RESTORE(cf, save);
+ cf->shutdown = (result || *done);
+ return result;
+}
+
CURLcode Curl_ssl_cfilter_remove(struct Curl_easy *data,
- int sockindex)
+ int sockindex, bool send_shutdown)
{
struct Curl_cfilter *cf, *head;
CURLcode result = CURLE_OK;
- (void)data;
head = data->conn? data->conn->cfilter[sockindex] : NULL;
for(cf = head; cf; cf = cf->next) {
if(cf->cft == &Curl_cft_ssl) {
- if(Curl_ssl->shut_down(cf, data))
+ bool done;
+ CURL_TRC_CF(data, cf, "shutdown and remove SSL, start");
+ Curl_shutdown_start(data, sockindex, NULL);
+ result = vtls_shutdown_blocking(cf, data, send_shutdown, &done);
+ Curl_shutdown_clear(data, sockindex);
+ if(!result && !done) /* blocking failed? */
result = CURLE_SSL_SHUTDOWN_FAILED;
Curl_conn_cf_discard_sub(head, cf, data, FALSE);
+ CURL_TRC_CF(data, cf, "shutdown and remove SSL, done -> %d", result);
break;
}
}
diff --git a/libs/libcurl/src/vtls/vtls.h b/libs/libcurl/src/vtls/vtls.h
index 4eedc707e4..c81b048a68 100644
--- a/libs/libcurl/src/vtls/vtls.h
+++ b/libs/libcurl/src/vtls/vtls.h
@@ -38,6 +38,7 @@ struct Curl_ssl_session;
#define SSLSUPP_TLS13_CIPHERSUITES (1<<5) /* supports TLS 1.3 ciphersuites */
#define SSLSUPP_CAINFO_BLOB (1<<6)
#define SSLSUPP_ECH (1<<7)
+#define SSLSUPP_CA_CACHE (1<<8)
#define ALPN_ACCEPTED "ALPN: server accepted "
@@ -52,7 +53,6 @@ struct Curl_ssl_session;
/* Curl_multi SSL backend-specific data; declared differently by each SSL
backend */
-struct multi_ssl_backend_data;
struct Curl_cfilter;
CURLsslset Curl_init_sslset_nolock(curl_sslbackend id, const char *name,
@@ -181,8 +181,6 @@ bool Curl_ssl_cert_status_request(void);
bool Curl_ssl_false_start(struct Curl_easy *data);
-void Curl_free_multi_ssl_backend_data(struct multi_ssl_backend_data *mbackend);
-
#define SSL_SHUTDOWN_TIMEOUT 10000 /* ms */
CURLcode Curl_ssl_cfilter_add(struct Curl_easy *data,
@@ -193,7 +191,7 @@ CURLcode Curl_cf_ssl_insert_after(struct Curl_cfilter *cf_at,
struct Curl_easy *data);
CURLcode Curl_ssl_cfilter_remove(struct Curl_easy *data,
- int sockindex);
+ int sockindex, bool send_shutdown);
#ifndef CURL_DISABLE_PROXY
CURLcode Curl_cf_ssl_proxy_insert_after(struct Curl_cfilter *cf_at,
@@ -205,7 +203,7 @@ CURLcode Curl_cf_ssl_proxy_insert_after(struct Curl_cfilter *cf_at,
* Option is one of the defined SSLSUPP_* values.
* `data` maybe NULL for the features of the default implementation.
*/
-bool Curl_ssl_supports(struct Curl_easy *data, int ssl_option);
+bool Curl_ssl_supports(struct Curl_easy *data, unsigned int ssl_option);
/**
* Get the internal ssl instance (like OpenSSL's SSL*) from the filter
@@ -252,7 +250,7 @@ extern struct Curl_cftype Curl_cft_ssl_proxy;
#define Curl_ssl_get_internals(a,b,c,d) NULL
#define Curl_ssl_supports(a,b) FALSE
#define Curl_ssl_cfilter_add(a,b,c) CURLE_NOT_BUILT_IN
-#define Curl_ssl_cfilter_remove(a,b) CURLE_OK
+#define Curl_ssl_cfilter_remove(a,b,c) CURLE_OK
#define Curl_ssl_cf_get_config(a,b) NULL
#define Curl_ssl_cf_get_primary_config(a) NULL
#endif
diff --git a/libs/libcurl/src/vtls/vtls_int.h b/libs/libcurl/src/vtls/vtls_int.h
index d9f73f720d..7fc93c0ebe 100644
--- a/libs/libcurl/src/vtls/vtls_int.h
+++ b/libs/libcurl/src/vtls/vtls_int.h
@@ -64,15 +64,34 @@ CURLcode Curl_alpn_set_negotiated(struct Curl_cfilter *cf,
const unsigned char *proto,
size_t proto_len);
+/* enum for the nonblocking SSL connection state machine */
+typedef enum {
+ ssl_connect_1,
+ ssl_connect_2,
+ ssl_connect_3,
+ ssl_connect_done
+} ssl_connect_state;
+
+typedef enum {
+ ssl_connection_none,
+ ssl_connection_negotiating,
+ ssl_connection_complete
+} ssl_connection_state;
+
+#define CURL_SSL_IO_NEED_NONE (0)
+#define CURL_SSL_IO_NEED_RECV (1<<0)
+#define CURL_SSL_IO_NEED_SEND (1<<1)
+
/* Information in each SSL cfilter context: cf->ctx */
struct ssl_connect_data {
- ssl_connection_state state;
- ssl_connect_state connecting_state;
struct ssl_peer peer;
const struct alpn_spec *alpn; /* ALPN to use or NULL for none */
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 */
+ ssl_connection_state state;
+ ssl_connect_state connecting_state;
+ int io_need; /* TLS signals special SEND/RECV needs */
BIT(use_alpn); /* if ALPN shall be used in handshake */
BIT(peer_closed); /* peer has closed connection */
};
@@ -99,8 +118,8 @@ struct Curl_ssl {
size_t (*version)(char *buffer, size_t size);
int (*check_cxn)(struct Curl_cfilter *cf, struct Curl_easy *data);
- int (*shut_down)(struct Curl_cfilter *cf,
- struct Curl_easy *data);
+ CURLcode (*shut_down)(struct Curl_cfilter *cf, struct Curl_easy *data,
+ bool send_shutdown, bool *done);
bool (*data_pending)(struct Curl_cfilter *cf,
const struct Curl_easy *data);
@@ -115,9 +134,8 @@ struct Curl_ssl {
struct Curl_easy *data,
bool *done);
- /* During handshake, adjust the pollset to include the socket
- * for POLLOUT or POLLIN as needed.
- * Mandatory. */
+ /* During handshake/shutdown, adjust the pollset to include the socket
+ * for POLLOUT or POLLIN as needed. Mandatory. */
void (*adjust_pollset)(struct Curl_cfilter *cf, struct Curl_easy *data,
struct easy_pollset *ps);
void *(*get_internals)(struct ssl_connect_data *connssl, CURLINFO info);
@@ -135,8 +153,6 @@ struct Curl_ssl {
bool (*attach_data)(struct Curl_cfilter *cf, struct Curl_easy *data);
void (*detach_data)(struct Curl_cfilter *cf, struct Curl_easy *data);
- void (*free_multi_ssl_backend_data)(struct multi_ssl_backend_data *mbackend);
-
ssize_t (*recv_plain)(struct Curl_cfilter *cf, struct Curl_easy *data,
char *buf, size_t len, CURLcode *code);
ssize_t (*send_plain)(struct Curl_cfilter *cf, struct Curl_easy *data,
@@ -149,7 +165,8 @@ extern const struct Curl_ssl *Curl_ssl;
int Curl_none_init(void);
void Curl_none_cleanup(void);
-int Curl_none_shutdown(struct Curl_cfilter *cf, struct Curl_easy *data);
+CURLcode Curl_none_shutdown(struct Curl_cfilter *cf, struct Curl_easy *data,
+ bool send_shutdown, bool *done);
int Curl_none_check_cxn(struct Curl_cfilter *cf, struct Curl_easy *data);
CURLcode Curl_none_random(struct Curl_easy *data, unsigned char *entropy,
size_t length);
@@ -181,19 +198,22 @@ bool Curl_ssl_getsessionid(struct Curl_cfilter *cf,
const struct ssl_peer *peer,
void **ssl_sessionid,
size_t *idsize); /* set 0 if unknown */
-/* add a new session ID
+
+/* Set a TLS session ID for `peer`. Replaces an existing session ID if
+ * not already the very same.
* Sessionid mutex must be locked (see Curl_ssl_sessionid_lock).
+ * Call takes ownership of `ssl_sessionid`, using `sessionid_free_cb`
+ * to deallocate it. Is called in all outcomes, either right away or
+ * later when the session cache is cleaned up.
* 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,
- Curl_ssl_sessionid_dtor *sessionid_free_cb);
+CURLcode Curl_ssl_set_sessionid(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ const struct ssl_peer *peer,
+ void *sessionid,
+ size_t sessionid_size,
+ 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 53e7f0e895..a305b5f080 100644
--- a/libs/libcurl/src/vtls/wolfssl.c
+++ b/libs/libcurl/src/vtls/wolfssl.c
@@ -99,17 +99,11 @@
#undef USE_BIO_CHAIN
#endif
-struct wolfssl_ssl_backend_data {
- WOLFSSL_CTX *ctx;
- WOLFSSL *handle;
- CURLcode io_result; /* result of last BIO cfilter operation */
-};
-
#ifdef OPENSSL_EXTRA
/*
* Availability note:
* The TLS 1.3 secret callback (wolfSSL_set_tls13_secret_cb) was added in
- * WolfSSL 4.4.0, but requires the -DHAVE_SECRET_CALLBACK build option. If that
+ * wolfSSL 4.4.0, but requires the -DHAVE_SECRET_CALLBACK build option. If that
* option is not set, then TLS 1.3 will not be logged.
* For TLS 1.2 and before, we use wolfSSL_get_keys().
* SSL_get_client_random and wolfSSL_get_keys require OPENSSL_EXTRA
@@ -290,8 +284,8 @@ static int wolfssl_bio_cf_out_write(WOLFSSL_BIO *bio,
{
struct Curl_cfilter *cf = wolfSSL_BIO_get_data(bio);
struct ssl_connect_data *connssl = cf->ctx;
- struct wolfssl_ssl_backend_data *backend =
- (struct wolfssl_ssl_backend_data *)connssl->backend;
+ struct wolfssl_ctx *backend =
+ (struct wolfssl_ctx *)connssl->backend;
struct Curl_easy *data = CF_DATA_CURRENT(cf);
ssize_t nwritten;
CURLcode result = CURLE_OK;
@@ -311,8 +305,8 @@ static int wolfssl_bio_cf_in_read(WOLFSSL_BIO *bio, char *buf, int blen)
{
struct Curl_cfilter *cf = wolfSSL_BIO_get_data(bio);
struct ssl_connect_data *connssl = cf->ctx;
- struct wolfssl_ssl_backend_data *backend =
- (struct wolfssl_ssl_backend_data *)connssl->backend;
+ struct wolfssl_ctx *backend =
+ (struct wolfssl_ctx *)connssl->backend;
struct Curl_easy *data = CF_DATA_CURRENT(cf);
ssize_t nread;
CURLcode result = CURLE_OK;
@@ -357,6 +351,252 @@ static void wolfssl_bio_cf_free_methods(void)
#endif /* !USE_BIO_CHAIN */
+static CURLcode populate_x509_store(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ X509_STORE *store,
+ struct wolfssl_ctx *wssl)
+{
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+ const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
+ const char * const ssl_cafile =
+ /* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */
+ (ca_info_blob ? NULL : conn_config->CAfile);
+ const char * const ssl_capath = conn_config->CApath;
+ struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+ bool imported_native_ca = false;
+
+#if !defined(NO_FILESYSTEM) && defined(WOLFSSL_SYS_CA_CERTS)
+ /* load native CA certificates */
+ if(ssl_config->native_ca_store) {
+ if(wolfSSL_CTX_load_system_CA_certs(wssl->ctx) != WOLFSSL_SUCCESS) {
+ infof(data, "error importing native CA store, continuing anyway");
+ }
+ else {
+ imported_native_ca = true;
+ infof(data, "successfully imported native CA store");
+ wssl->x509_store_setup = TRUE;
+ }
+ }
+#endif /* !NO_FILESYSTEM */
+
+ /* load certificate blob */
+ if(ca_info_blob) {
+ if(wolfSSL_CTX_load_verify_buffer(wssl->ctx, ca_info_blob->data,
+ (long)ca_info_blob->len,
+ SSL_FILETYPE_PEM) != SSL_SUCCESS) {
+ if(imported_native_ca) {
+ infof(data, "error importing CA certificate blob, continuing anyway");
+ }
+ else {
+ failf(data, "error importing CA certificate blob");
+ return CURLE_SSL_CACERT_BADFILE;
+ }
+ }
+ else {
+ infof(data, "successfully imported CA certificate blob");
+ wssl->x509_store_setup = TRUE;
+ }
+ }
+
+#ifndef NO_FILESYSTEM
+ /* load trusted cacert from file if not blob */
+
+ CURL_TRC_CF(data, cf, "populate_x509_store, path=%s, blob=%d",
+ ssl_cafile? ssl_cafile : "none", !!ca_info_blob);
+ if(!store)
+ return CURLE_OUT_OF_MEMORY;
+
+ if((ssl_cafile || ssl_capath) && (!wssl->x509_store_setup)) {
+ int rc =
+ wolfSSL_CTX_load_verify_locations_ex(wssl->ctx,
+ ssl_cafile,
+ ssl_capath,
+ WOLFSSL_LOAD_FLAG_IGNORE_ERR);
+ if(SSL_SUCCESS != rc) {
+ if(conn_config->verifypeer) {
+ /* Fail if we insist on successfully verifying the server. */
+ failf(data, "error setting certificate verify locations:"
+ " CAfile: %s CApath: %s",
+ ssl_cafile ? ssl_cafile : "none",
+ ssl_capath ? ssl_capath : "none");
+ return CURLE_SSL_CACERT_BADFILE;
+ }
+ else {
+ /* Just continue with a warning if no strict certificate
+ verification is required. */
+ infof(data, "error setting certificate verify locations,"
+ " continuing anyway:");
+ }
+ }
+ else {
+ /* Everything is fine. */
+ infof(data, "successfully set certificate verify locations:");
+ }
+ infof(data, " CAfile: %s", ssl_cafile ? ssl_cafile : "none");
+ infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none");
+ wssl->x509_store_setup = TRUE;
+ }
+#endif
+ (void)store;
+ return CURLE_OK;
+}
+
+/* key to use at `multi->proto_hash` */
+#define MPROTO_WSSL_X509_KEY "tls:wssl:x509:share"
+
+struct wssl_x509_share {
+ char *CAfile; /* CAfile path used to generate X509 store */
+ WOLFSSL_X509_STORE *store; /* cached X509 store or NULL if none */
+ struct curltime time; /* when the cached store was created */
+};
+
+static void wssl_x509_share_free(void *key, size_t key_len, void *p)
+{
+ struct wssl_x509_share *share = p;
+ DEBUGASSERT(key_len == (sizeof(MPROTO_WSSL_X509_KEY)-1));
+ DEBUGASSERT(!memcmp(MPROTO_WSSL_X509_KEY, key, key_len));
+ (void)key;
+ (void)key_len;
+ if(share->store) {
+ wolfSSL_X509_STORE_free(share->store);
+ }
+ free(share->CAfile);
+ free(share);
+}
+
+static bool
+cached_x509_store_expired(const struct Curl_easy *data,
+ const struct wssl_x509_share *mb)
+{
+ const struct ssl_general_config *cfg = &data->set.general_ssl;
+ struct curltime now = Curl_now();
+ timediff_t elapsed_ms = Curl_timediff(now, mb->time);
+ timediff_t timeout_ms = cfg->ca_cache_timeout * (timediff_t)1000;
+
+ if(timeout_ms < 0)
+ return false;
+
+ return elapsed_ms >= timeout_ms;
+}
+
+static bool
+cached_x509_store_different(struct Curl_cfilter *cf,
+ const struct wssl_x509_share *mb)
+{
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+ if(!mb->CAfile || !conn_config->CAfile)
+ return mb->CAfile != conn_config->CAfile;
+
+ return strcmp(mb->CAfile, conn_config->CAfile);
+}
+
+static X509_STORE *get_cached_x509_store(struct Curl_cfilter *cf,
+ const struct Curl_easy *data)
+{
+ struct Curl_multi *multi = data->multi;
+ struct wssl_x509_share *share;
+ WOLFSSL_X509_STORE *store = NULL;
+
+ DEBUGASSERT(multi);
+ share = multi? Curl_hash_pick(&multi->proto_hash,
+ (void *)MPROTO_WSSL_X509_KEY,
+ sizeof(MPROTO_WSSL_X509_KEY)-1) : NULL;
+ if(share && share->store &&
+ !cached_x509_store_expired(data, share) &&
+ !cached_x509_store_different(cf, share)) {
+ store = share->store;
+ }
+
+ return store;
+}
+
+static void set_cached_x509_store(struct Curl_cfilter *cf,
+ const struct Curl_easy *data,
+ X509_STORE *store)
+{
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+ struct Curl_multi *multi = data->multi;
+ struct wssl_x509_share *share;
+
+ DEBUGASSERT(multi);
+ if(!multi)
+ return;
+ share = Curl_hash_pick(&multi->proto_hash,
+ (void *)MPROTO_WSSL_X509_KEY,
+ sizeof(MPROTO_WSSL_X509_KEY)-1);
+
+ if(!share) {
+ share = calloc(1, sizeof(*share));
+ if(!share)
+ return;
+ if(!Curl_hash_add2(&multi->proto_hash,
+ (void *)MPROTO_WSSL_X509_KEY,
+ sizeof(MPROTO_WSSL_X509_KEY)-1,
+ share, wssl_x509_share_free)) {
+ free(share);
+ return;
+ }
+ }
+
+ if(wolfSSL_X509_STORE_up_ref(store)) {
+ char *CAfile = NULL;
+
+ if(conn_config->CAfile) {
+ CAfile = strdup(conn_config->CAfile);
+ if(!CAfile) {
+ X509_STORE_free(store);
+ return;
+ }
+ }
+
+ if(share->store) {
+ X509_STORE_free(share->store);
+ free(share->CAfile);
+ }
+
+ share->time = Curl_now();
+ share->store = store;
+ share->CAfile = CAfile;
+ }
+}
+
+CURLcode Curl_wssl_setup_x509_store(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct wolfssl_ctx *wssl)
+{
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+ struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+ CURLcode result = CURLE_OK;
+ WOLFSSL_X509_STORE *cached_store;
+ bool cache_criteria_met;
+
+ /* Consider the X509 store cacheable if it comes exclusively from a CAfile,
+ or no source is provided and we are falling back to OpenSSL's built-in
+ default. */
+ cache_criteria_met = (data->set.general_ssl.ca_cache_timeout != 0) &&
+ conn_config->verifypeer &&
+ !conn_config->CApath &&
+ !conn_config->ca_info_blob &&
+ !ssl_config->primary.CRLfile &&
+ !ssl_config->native_ca_store;
+
+ cached_store = get_cached_x509_store(cf, data);
+ if(cached_store && cache_criteria_met
+ && wolfSSL_X509_STORE_up_ref(cached_store)) {
+ wolfSSL_CTX_set_cert_store(wssl->ctx, cached_store);
+ }
+ else {
+ X509_STORE *store = wolfSSL_CTX_get_cert_store(wssl->ctx);
+
+ result = populate_x509_store(cf, data, store, wssl);
+ if(result == CURLE_OK && cache_criteria_met) {
+ set_cached_x509_store(cf, data, store);
+ }
+ }
+
+ return result;
+}
+
/*
* This function loads all the client/CA certificates and CRLs. Setup the TLS
* layer and do all necessary magic.
@@ -366,15 +606,10 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
{
char *ciphers, *curves;
struct ssl_connect_data *connssl = cf->ctx;
- struct wolfssl_ssl_backend_data *backend =
- (struct wolfssl_ssl_backend_data *)connssl->backend;
+ struct wolfssl_ctx *backend =
+ (struct wolfssl_ctx *)connssl->backend;
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
- const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
const struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
- const char * const ssl_cafile =
- /* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */
- (ca_info_blob ? NULL : conn_config->CAfile);
- const char * const ssl_capath = conn_config->CApath;
WOLFSSL_METHOD* req_method = NULL;
#ifdef HAVE_LIBOQS
word16 oqsAlg = 0;
@@ -386,8 +621,6 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
#else
#define use_sni(x) Curl_nop_stmt
#endif
- bool imported_native_ca = false;
- bool imported_ca_info_blob = false;
DEBUGASSERT(backend);
@@ -399,7 +632,7 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
return CURLE_SSL_CONNECT_ERROR;
}
- /* check to see if we've been told to use an explicit SSL/TLS version */
+ /* check to see if we have been told to use an explicit SSL/TLS version */
switch(conn_config->version) {
case CURL_SSLVERSION_DEFAULT:
case CURL_SSLVERSION_TLSv1:
@@ -426,11 +659,11 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
#ifndef NO_OLD_TLS
req_method = TLSv1_1_client_method();
use_sni(TRUE);
+ break;
#else
failf(data, "wolfSSL does not support TLS 1.1");
return CURLE_NOT_BUILT_IN;
#endif
- break;
case CURL_SSLVERSION_TLSv1_2:
#ifndef WOLFSSL_NO_TLS12
req_method = TLSv1_2_client_method();
@@ -455,7 +688,7 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
}
if(!req_method) {
- failf(data, "SSL: couldn't create a method");
+ failf(data, "SSL: could not create a method");
return CURLE_OUT_OF_MEMORY;
}
@@ -464,7 +697,7 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
backend->ctx = wolfSSL_CTX_new(req_method);
if(!backend->ctx) {
- failf(data, "SSL: couldn't create a context");
+ failf(data, "SSL: could not create a context");
return CURLE_OUT_OF_MEMORY;
}
@@ -485,7 +718,7 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
&& (wolfSSL_CTX_SetMinVersion(backend->ctx, WOLFSSL_TLSV1_3) != 1)
#endif
) {
- failf(data, "SSL: couldn't set the minimum protocol version");
+ failf(data, "SSL: could not set the minimum protocol version");
return CURLE_SSL_CONNECT_ERROR;
}
#endif
@@ -524,73 +757,10 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
}
}
-#if !defined(NO_FILESYSTEM) && defined(WOLFSSL_SYS_CA_CERTS)
- /* load native CA certificates */
- if(ssl_config->native_ca_store) {
- if(wolfSSL_CTX_load_system_CA_certs(backend->ctx) != WOLFSSL_SUCCESS) {
- infof(data, "error importing native CA store, continuing anyway");
- }
- else {
- imported_native_ca = true;
- infof(data, "successfully imported native CA store");
- }
- }
-#endif /* !NO_FILESYSTEM */
-
- /* load certificate blob */
- if(ca_info_blob) {
- if(wolfSSL_CTX_load_verify_buffer(backend->ctx, ca_info_blob->data,
- ca_info_blob->len,
- SSL_FILETYPE_PEM) != SSL_SUCCESS) {
- if(imported_native_ca) {
- infof(data, "error importing CA certificate blob, continuing anyway");
- }
- else {
- failf(data, "error importing CA certificate blob");
- return CURLE_SSL_CACERT_BADFILE;
- }
- }
- else {
- imported_ca_info_blob = true;
- infof(data, "successfully imported CA certificate blob");
- }
- }
-
#ifndef NO_FILESYSTEM
- /* load trusted cacert from file if not blob */
- if(ssl_cafile || ssl_capath) {
- int rc =
- wolfSSL_CTX_load_verify_locations_ex(backend->ctx,
- ssl_cafile,
- ssl_capath,
- WOLFSSL_LOAD_FLAG_IGNORE_ERR);
- if(SSL_SUCCESS != rc) {
- if(conn_config->verifypeer && !imported_ca_info_blob &&
- !imported_native_ca) {
- /* Fail if we insist on successfully verifying the server. */
- failf(data, "error setting certificate verify locations:"
- " CAfile: %s CApath: %s",
- ssl_cafile ? ssl_cafile : "none",
- ssl_capath ? ssl_capath : "none");
- return CURLE_SSL_CACERT_BADFILE;
- }
- else {
- /* Just continue with a warning if no strict certificate
- verification is required. */
- infof(data, "error setting certificate verify locations,"
- " continuing anyway:");
- }
- }
- else {
- /* Everything is fine. */
- infof(data, "successfully set certificate verify locations:");
- }
- infof(data, " CAfile: %s", ssl_cafile ? ssl_cafile : "none");
- infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none");
- }
-
/* Load the client certificate, and private key */
- if(ssl_config->primary.clientcert && ssl_config->key) {
+ if(ssl_config->primary.clientcert) {
+ char *key_file = ssl_config->key;
int file_type = do_file_type(ssl_config->cert_type);
if(file_type == WOLFSSL_FILETYPE_PEM) {
@@ -614,8 +784,12 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
return CURLE_BAD_FUNCTION_ARGUMENT;
}
- file_type = do_file_type(ssl_config->key_type);
- if(wolfSSL_CTX_use_PrivateKey_file(backend->ctx, ssl_config->key,
+ if(!key_file)
+ key_file = ssl_config->primary.clientcert;
+ else
+ file_type = do_file_type(ssl_config->key_type);
+
+ if(wolfSSL_CTX_use_PrivateKey_file(backend->ctx, key_file,
file_type) != 1) {
failf(data, "unable to set private key");
return CURLE_SSL_CONNECT_ERROR;
@@ -656,7 +830,7 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
}
#ifdef NO_FILESYSTEM
else if(conn_config->verifypeer) {
- failf(data, "SSL: Certificates can't be loaded because wolfSSL was built"
+ failf(data, "SSL: Certificates cannot be loaded because wolfSSL was built"
" with \"no filesystem\". Either disable peer verification"
" (insecure) or if you are building an application with libcurl you"
" can load certificates via CURLOPT_SSL_CTX_FUNCTION.");
@@ -669,7 +843,7 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
wolfSSL_free(backend->handle);
backend->handle = wolfSSL_new(backend->ctx);
if(!backend->handle) {
- failf(data, "SSL: couldn't create a handle");
+ failf(data, "SSL: could not create a handle");
return CURLE_OUT_OF_MEMORY;
}
@@ -688,7 +862,8 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
result = Curl_alpn_to_proto_str(&proto, connssl->alpn);
if(result ||
- wolfSSL_UseALPN(backend->handle, (char *)proto.data, proto.len,
+ wolfSSL_UseALPN(backend->handle,
+ (char *)proto.data, (unsigned int)proto.len,
WOLFSSL_ALPN_CONTINUE_ON_MISMATCH) != SSL_SUCCESS) {
failf(data, "SSL: failed setting ALPN protocols");
return CURLE_SSL_CONNECT_ERROR;
@@ -715,8 +890,8 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
}
#endif /* HAVE_SECURE_RENEGOTIATION */
- /* Check if there's a cached ID we can/should use here! */
- if(ssl_config->primary.sessionid) {
+ /* Check if there is a cached ID we can/should use here! */
+ if(ssl_config->primary.cache_session) {
void *ssl_sessionid = NULL;
Curl_ssl_sessionid_lock(data);
@@ -725,7 +900,7 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
/* we got a session id, use it! */
if(!SSL_set_session(backend->handle, ssl_sessionid)) {
Curl_ssl_delsessionid(data, ssl_sessionid);
- infof(data, "Can't use session ID, going on without");
+ infof(data, "cannot use session ID, going on without");
}
else
infof(data, "SSL reusing session ID");
@@ -738,7 +913,7 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
int trying_ech_now = 0;
if(data->set.str[STRING_ECH_PUBLIC]) {
- infof(data, "ECH: outername not (yet) supported with WolfSSL");
+ infof(data, "ECH: outername not (yet) supported with wolfSSL");
return CURLE_SSL_CONNECT_ERROR;
}
if(data->set.tls_ech == CURLECH_GREASE) {
@@ -802,7 +977,7 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
if(trying_ech_now
&& SSL_set_min_proto_version(backend->handle, TLS1_3_VERSION) != 1) {
- infof(data, "ECH: Can't force TLSv1.3 [ERROR]");
+ infof(data, "ECH: cannot force TLSv1.3 [ERROR]");
return CURLE_SSL_CONNECT_ERROR;
}
@@ -834,13 +1009,31 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
}
+static char *wolfssl_strerror(unsigned long error, char *buf,
+ unsigned long size)
+{
+ DEBUGASSERT(size);
+ *buf = '\0';
+
+ wolfSSL_ERR_error_string_n(error, buf, size);
+
+ if(!*buf) {
+ const char *msg = error ? "Unknown error" : "No error";
+ strncpy(buf, msg, size - 1);
+ buf[size - 1] = '\0';
+ }
+
+ return buf;
+}
+
+
static CURLcode
wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
{
int ret = -1;
struct ssl_connect_data *connssl = cf->ctx;
- struct wolfssl_ssl_backend_data *backend =
- (struct wolfssl_ssl_backend_data *)connssl->backend;
+ struct wolfssl_ctx *backend =
+ (struct wolfssl_ctx *)connssl->backend;
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
#ifndef CURL_DISABLE_PROXY
const char * const pinnedpubkey = Curl_ssl_cf_is_proxy(cf)?
@@ -862,6 +1055,22 @@ wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
return CURLE_SSL_CONNECT_ERROR;
}
+ if(!backend->x509_store_setup) {
+ /* After having send off the ClientHello, we prepare the x509
+ * store to verify the coming certificate from the server */
+ CURLcode result;
+ struct wolfssl_ctx wssl;
+ wssl.ctx = backend->ctx;
+ wssl.handle = backend->handle;
+ wssl.io_result = CURLE_OK;
+ wssl.x509_store_setup = FALSE;
+ result = Curl_wssl_setup_x509_store(cf, data, &wssl);
+ if(result)
+ return result;
+ backend->x509_store_setup = wssl.x509_store_setup;
+ }
+
+ connssl->io_need = CURL_SSL_IO_NEED_NONE;
ret = wolfSSL_connect(backend->handle);
#ifdef OPENSSL_EXTRA
@@ -889,15 +1098,14 @@ wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
#endif /* OPENSSL_EXTRA */
if(ret != 1) {
- char error_buffer[WOLFSSL_MAX_ERROR_SZ];
- int detail = wolfSSL_get_error(backend->handle, ret);
+ int detail = wolfSSL_get_error(backend->handle, ret);
if(SSL_ERROR_WANT_READ == detail) {
- connssl->connecting_state = ssl_connect_2_reading;
+ connssl->io_need = CURL_SSL_IO_NEED_RECV;
return CURLE_OK;
}
else if(SSL_ERROR_WANT_WRITE == detail) {
- connssl->connecting_state = ssl_connect_2_writing;
+ connssl->io_need = CURL_SSL_IO_NEED_SEND;
return CURLE_OK;
}
/* There is no easy way to override only the CN matching.
@@ -950,7 +1158,7 @@ wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
word32 echConfigsLen = 1000;
int rv = 0;
- /* this currently doesn't produce the retry_configs */
+ /* this currently does not produce the retry_configs */
rv = wolfSSL_GetEchConfigs(backend->handle, echConfigs,
&echConfigsLen);
if(rv != WOLFSSL_SUCCESS) {
@@ -972,8 +1180,10 @@ wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
return CURLE_OK;
}
else {
+ char error_buffer[256];
failf(data, "SSL_connect failed with error %d: %s", detail,
- wolfSSL_ERR_error_string(detail, error_buffer));
+ wolfssl_strerror((unsigned long)detail, error_buffer,
+ sizeof(error_buffer)));
return CURLE_SSL_CONNECT_ERROR;
}
}
@@ -1070,31 +1280,23 @@ wolfssl_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
{
CURLcode result = CURLE_OK;
struct ssl_connect_data *connssl = cf->ctx;
- struct wolfssl_ssl_backend_data *backend =
- (struct wolfssl_ssl_backend_data *)connssl->backend;
+ struct wolfssl_ctx *backend =
+ (struct wolfssl_ctx *)connssl->backend;
const struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
DEBUGASSERT(backend);
- if(ssl_config->primary.sessionid) {
+ if(ssl_config->primary.cache_session) {
/* wolfSSL_get1_session allocates memory that has to be freed. */
WOLFSSL_SESSION *our_ssl_sessionid = wolfSSL_get1_session(backend->handle);
if(our_ssl_sessionid) {
- void *old_ssl_sessionid = NULL;
- bool incache;
Curl_ssl_sessionid_lock(data);
- incache = !(Curl_ssl_getsessionid(cf, data, &connssl->peer,
- &old_ssl_sessionid, NULL));
- if(incache) {
- Curl_ssl_delsessionid(data, old_ssl_sessionid);
- }
-
/* call takes ownership of `our_ssl_sessionid` */
- result = Curl_ssl_addsessionid(cf, data, &connssl->peer,
- our_ssl_sessionid, 0,
- wolfssl_session_free);
+ result = Curl_ssl_set_sessionid(cf, data, &connssl->peer,
+ our_ssl_sessionid, 0,
+ wolfssl_session_free);
Curl_ssl_sessionid_unlock(data);
if(result) {
failf(data, "failed to store ssl session");
@@ -1116,9 +1318,8 @@ static ssize_t wolfssl_send(struct Curl_cfilter *cf,
CURLcode *curlcode)
{
struct ssl_connect_data *connssl = cf->ctx;
- struct wolfssl_ssl_backend_data *backend =
- (struct wolfssl_ssl_backend_data *)connssl->backend;
- char error_buffer[WOLFSSL_MAX_ERROR_SZ];
+ struct wolfssl_ctx *backend =
+ (struct wolfssl_ctx *)connssl->backend;
int memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len;
int rc;
@@ -1133,7 +1334,7 @@ static ssize_t wolfssl_send(struct Curl_cfilter *cf,
switch(err) {
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
- /* there's data pending, re-invoke SSL_write() */
+ /* there is data pending, re-invoke SSL_write() */
CURL_TRC_CF(data, cf, "wolfssl_send(len=%zu) -> AGAIN", len);
*curlcode = CURLE_AGAIN;
return -1;
@@ -1144,9 +1345,13 @@ static ssize_t wolfssl_send(struct Curl_cfilter *cf,
return -1;
}
CURL_TRC_CF(data, cf, "wolfssl_send(len=%zu) -> %d, %d", len, rc, err);
- failf(data, "SSL write: %s, errno %d",
- wolfSSL_ERR_error_string(err, error_buffer),
- SOCKERRNO);
+ {
+ char error_buffer[256];
+ failf(data, "SSL write: %s, errno %d",
+ wolfssl_strerror((unsigned long)err, error_buffer,
+ sizeof(error_buffer)),
+ SOCKERRNO);
+ }
*curlcode = CURLE_SEND_ERROR;
return -1;
}
@@ -1155,23 +1360,111 @@ static ssize_t wolfssl_send(struct Curl_cfilter *cf,
return rc;
}
+static CURLcode wolfssl_shutdown(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool send_shutdown, bool *done)
+{
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct wolfssl_ctx *wctx = (struct wolfssl_ctx *)connssl->backend;
+ CURLcode result = CURLE_OK;
+ char buf[1024];
+ int nread, err;
+
+ DEBUGASSERT(wctx);
+ if(!wctx->handle || cf->shutdown) {
+ *done = TRUE;
+ goto out;
+ }
+
+ connssl->io_need = CURL_SSL_IO_NEED_NONE;
+ *done = FALSE;
+ if(!(wolfSSL_get_shutdown(wctx->handle) & SSL_SENT_SHUTDOWN)) {
+ /* We have not started the shutdown from our side yet. Check
+ * if the server already sent us one. */
+ ERR_clear_error();
+ nread = wolfSSL_read(wctx->handle, buf, (int)sizeof(buf));
+ err = wolfSSL_get_error(wctx->handle, nread);
+ if(!nread && err == SSL_ERROR_ZERO_RETURN) {
+ bool input_pending;
+ /* Yes, it did. */
+ if(!send_shutdown) {
+ CURL_TRC_CF(data, cf, "SSL shutdown received, not sending");
+ *done = TRUE;
+ goto out;
+ }
+ else if(!cf->next->cft->is_alive(cf->next, data, &input_pending)) {
+ /* Server closed the connection after its closy notify. It
+ * seems not interested to see our close notify, so do not
+ * send it. We are done. */
+ CURL_TRC_CF(data, cf, "peer closed connection");
+ connssl->peer_closed = TRUE;
+ *done = TRUE;
+ goto out;
+ }
+ }
+ }
+
+ if(send_shutdown && wolfSSL_shutdown(wctx->handle) == 1) {
+ CURL_TRC_CF(data, cf, "SSL shutdown finished");
+ *done = TRUE;
+ goto out;
+ }
+ else {
+ size_t i;
+ /* SSL should now have started the shutdown from our side. Since it
+ * was not complete, we are lacking the close notify from the server. */
+ for(i = 0; i < 10; ++i) {
+ ERR_clear_error();
+ nread = wolfSSL_read(wctx->handle, buf, (int)sizeof(buf));
+ if(nread <= 0)
+ break;
+ }
+ err = wolfSSL_get_error(wctx->handle, nread);
+ switch(err) {
+ case SSL_ERROR_ZERO_RETURN: /* no more data */
+ CURL_TRC_CF(data, cf, "SSL shutdown received");
+ *done = TRUE;
+ break;
+ case SSL_ERROR_NONE: /* just did not get anything */
+ case SSL_ERROR_WANT_READ:
+ /* SSL has send its notify and now wants to read the reply
+ * from the server. We are not really interested in that. */
+ CURL_TRC_CF(data, cf, "SSL shutdown sent, want receive");
+ connssl->io_need = CURL_SSL_IO_NEED_RECV;
+ break;
+ case SSL_ERROR_WANT_WRITE:
+ CURL_TRC_CF(data, cf, "SSL shutdown send blocked");
+ connssl->io_need = CURL_SSL_IO_NEED_SEND;
+ break;
+ default: {
+ char error_buffer[256];
+ int detail = wolfSSL_get_error(wctx->handle, err);
+ CURL_TRC_CF(data, cf, "SSL shutdown, error: '%s'(%d)",
+ wolfssl_strerror((unsigned long)err, error_buffer,
+ sizeof(error_buffer)),
+ detail);
+ result = CURLE_RECV_ERROR;
+ break;
+ }
+ }
+ }
+
+out:
+ cf->shutdown = (result || *done);
+ return result;
+}
+
static void wolfssl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
struct ssl_connect_data *connssl = cf->ctx;
- struct wolfssl_ssl_backend_data *backend =
- (struct wolfssl_ssl_backend_data *)connssl->backend;
+ struct wolfssl_ctx *backend =
+ (struct wolfssl_ctx *)connssl->backend;
(void) data;
DEBUGASSERT(backend);
if(backend->handle) {
- char buf[32];
- /* Maybe the server has already sent a close notify alert.
- Read it to avoid an RST on the TCP connection. */
- (void)wolfSSL_read(backend->handle, buf, (int)sizeof(buf));
- if(!connssl->peer_closed)
- (void)wolfSSL_shutdown(backend->handle);
wolfSSL_free(backend->handle);
backend->handle = NULL;
}
@@ -1187,9 +1480,8 @@ static ssize_t wolfssl_recv(struct Curl_cfilter *cf,
CURLcode *curlcode)
{
struct ssl_connect_data *connssl = cf->ctx;
- struct wolfssl_ssl_backend_data *backend =
- (struct wolfssl_ssl_backend_data *)connssl->backend;
- char error_buffer[WOLFSSL_MAX_ERROR_SZ];
+ struct wolfssl_ctx *backend =
+ (struct wolfssl_ctx *)connssl->backend;
int buffsize = (blen > (size_t)INT_MAX) ? INT_MAX : (int)blen;
int nread;
@@ -1211,7 +1503,7 @@ static ssize_t wolfssl_recv(struct Curl_cfilter *cf,
case SSL_ERROR_NONE:
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
- /* there's data pending, re-invoke wolfSSL_read() */
+ /* there is data pending, re-invoke wolfSSL_read() */
CURL_TRC_CF(data, cf, "wolfssl_recv(len=%zu) -> AGAIN", blen);
*curlcode = CURLE_AGAIN;
return -1;
@@ -1221,8 +1513,13 @@ static ssize_t wolfssl_recv(struct Curl_cfilter *cf,
*curlcode = CURLE_AGAIN;
return -1;
}
- failf(data, "SSL read: %s, errno %d",
- wolfSSL_ERR_error_string(err, error_buffer), SOCKERRNO);
+ {
+ char error_buffer[256];
+ failf(data, "SSL read: %s, errno %d",
+ wolfssl_strerror((unsigned long)err, error_buffer,
+ sizeof(error_buffer)),
+ SOCKERRNO);
+ }
*curlcode = CURLE_RECV_ERROR;
return -1;
}
@@ -1269,43 +1566,18 @@ static bool wolfssl_data_pending(struct Curl_cfilter *cf,
const struct Curl_easy *data)
{
struct ssl_connect_data *ctx = cf->ctx;
- struct wolfssl_ssl_backend_data *backend;
+ struct wolfssl_ctx *backend;
(void)data;
DEBUGASSERT(ctx && ctx->backend);
- backend = (struct wolfssl_ssl_backend_data *)ctx->backend;
+ backend = (struct wolfssl_ctx *)ctx->backend;
if(backend->handle) /* SSL is in use */
return (0 != wolfSSL_pending(backend->handle)) ? TRUE : FALSE;
else
return FALSE;
}
-
-/*
- * This function is called to shut down the SSL layer but keep the
- * socket open (CCC - Clear Command Channel)
- */
-static int wolfssl_shutdown(struct Curl_cfilter *cf,
- struct Curl_easy *data)
-{
- struct ssl_connect_data *ctx = cf->ctx;
- struct wolfssl_ssl_backend_data *backend;
- int retval = 0;
-
- (void)data;
- DEBUGASSERT(ctx && ctx->backend);
-
- backend = (struct wolfssl_ssl_backend_data *)ctx->backend;
- if(backend->handle) {
- wolfSSL_ERR_clear_error();
- wolfSSL_free(backend->handle);
- backend->handle = NULL;
- }
- return retval;
-}
-
-
static CURLcode
wolfssl_connect_common(struct Curl_cfilter *cf,
struct Curl_easy *data,
@@ -1324,7 +1596,7 @@ wolfssl_connect_common(struct Curl_cfilter *cf,
}
if(ssl_connect_1 == connssl->connecting_state) {
- /* Find out how much more time we're allowed */
+ /* Find out how much more time we are allowed */
const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
if(timeout_ms < 0) {
@@ -1338,9 +1610,7 @@ wolfssl_connect_common(struct Curl_cfilter *cf,
return result;
}
- while(ssl_connect_2 == connssl->connecting_state ||
- ssl_connect_2_reading == connssl->connecting_state ||
- ssl_connect_2_writing == connssl->connecting_state) {
+ while(ssl_connect_2 == connssl->connecting_state) {
/* check allowed time left */
const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
@@ -1351,14 +1621,13 @@ wolfssl_connect_common(struct Curl_cfilter *cf,
return CURLE_OPERATION_TIMEDOUT;
}
- /* if ssl is expecting something, check if it's available. */
- if(connssl->connecting_state == ssl_connect_2_reading
- || connssl->connecting_state == ssl_connect_2_writing) {
+ /* if ssl is expecting something, check if it is available. */
+ if(connssl->io_need) {
- curl_socket_t writefd = ssl_connect_2_writing ==
- connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
- curl_socket_t readfd = ssl_connect_2_reading ==
- connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
+ curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND)?
+ sockfd:CURL_SOCKET_BAD;
+ curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV)?
+ sockfd:CURL_SOCKET_BAD;
what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
nonblocking?0:timeout_ms);
@@ -1389,10 +1658,7 @@ wolfssl_connect_common(struct Curl_cfilter *cf,
* have a valid fdset to wait on.
*/
result = wolfssl_connect_step2(cf, data);
- if(result || (nonblocking &&
- (ssl_connect_2 == connssl->connecting_state ||
- ssl_connect_2_reading == connssl->connecting_state ||
- ssl_connect_2_writing == connssl->connecting_state)))
+ if(result || (nonblocking && (ssl_connect_2 == connssl->connecting_state)))
return result;
} /* repeat step2 until all transactions are done. */
@@ -1472,15 +1738,15 @@ static CURLcode wolfssl_sha256sum(const unsigned char *tmp, /* input */
static void *wolfssl_get_internals(struct ssl_connect_data *connssl,
CURLINFO info UNUSED_PARAM)
{
- struct wolfssl_ssl_backend_data *backend =
- (struct wolfssl_ssl_backend_data *)connssl->backend;
+ struct wolfssl_ctx *backend =
+ (struct wolfssl_ctx *)connssl->backend;
(void)info;
DEBUGASSERT(backend);
return backend->handle;
}
const struct Curl_ssl Curl_ssl_wolfssl = {
- { CURLSSLBACKEND_WOLFSSL, "WolfSSL" }, /* info */
+ { CURLSSLBACKEND_WOLFSSL, "wolfssl" }, /* info */
#ifdef KEEP_PEER_CERT
SSLSUPP_PINNEDPUBKEY |
@@ -1493,9 +1759,10 @@ const struct Curl_ssl Curl_ssl_wolfssl = {
#ifdef USE_ECH
SSLSUPP_ECH |
#endif
- SSLSUPP_SSL_CTX,
+ SSLSUPP_SSL_CTX |
+ SSLSUPP_CA_CACHE,
- sizeof(struct wolfssl_ssl_backend_data),
+ sizeof(struct wolfssl_ctx),
wolfssl_init, /* init */
wolfssl_cleanup, /* cleanup */
@@ -1518,7 +1785,6 @@ const struct Curl_ssl Curl_ssl_wolfssl = {
wolfssl_sha256sum, /* sha256sum */
NULL, /* associate_connection */
NULL, /* disassociate_connection */
- NULL, /* free_multi_ssl_backend_data */
wolfssl_recv, /* recv decrypted data */
wolfssl_send, /* send data to encrypt */
};
diff --git a/libs/libcurl/src/vtls/wolfssl.h b/libs/libcurl/src/vtls/wolfssl.h
index 8633d3375c..fcc1b6a625 100644
--- a/libs/libcurl/src/vtls/wolfssl.h
+++ b/libs/libcurl/src/vtls/wolfssl.h
@@ -26,8 +26,25 @@
#include "curl_setup.h"
#ifdef USE_WOLFSSL
+#include <wolfssl/version.h>
+#include <wolfssl/options.h>
+#include <wolfssl/ssl.h>
+#include <wolfssl/error-ssl.h>
+
+#include "urldata.h"
extern const struct Curl_ssl Curl_ssl_wolfssl;
+struct wolfssl_ctx {
+ WOLFSSL_CTX *ctx;
+ WOLFSSL *handle;
+ CURLcode io_result; /* result of last BIO cfilter operation */
+ BIT(x509_store_setup); /* x509 store has been set up */
+};
+
+CURLcode Curl_wssl_setup_x509_store(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct wolfssl_ctx *wssl);
+
#endif /* USE_WOLFSSL */
#endif /* HEADER_CURL_WOLFSSL_H */
diff --git a/libs/libcurl/src/vtls/x509asn1.c b/libs/libcurl/src/vtls/x509asn1.c
index 0887b34049..f8b0dd38e5 100644
--- a/libs/libcurl/src/vtls/x509asn1.c
+++ b/libs/libcurl/src/vtls/x509asn1.c
@@ -25,13 +25,15 @@
#include "curl_setup.h"
#if defined(USE_GNUTLS) || defined(USE_WOLFSSL) || \
- defined(USE_SCHANNEL) || defined(USE_SECTRANSP)
+ defined(USE_SCHANNEL) || defined(USE_SECTRANSP) || \
+ defined(USE_MBEDTLS)
#if defined(USE_WOLFSSL) || defined(USE_SCHANNEL)
#define WANT_PARSEX509 /* uses Curl_parseX509() */
#endif
-#if defined(USE_GNUTLS) || defined(USE_SCHANNEL) || defined(USE_SECTRANSP)
+#if defined(USE_GNUTLS) || defined(USE_SCHANNEL) || defined(USE_SECTRANSP) || \
+ defined(USE_MBEDTLS)
#define WANT_EXTRACT_CERTINFO /* uses Curl_extract_certinfo() */
#define WANT_PARSEX509 /* ... uses Curl_parseX509() */
#endif
@@ -110,15 +112,16 @@ struct Curl_OID {
};
/* ASN.1 OIDs. */
-static const char cnOID[] = "2.5.4.3"; /* Common name. */
-static const char sanOID[] = "2.5.29.17"; /* Subject alternative name. */
-
static const struct Curl_OID OIDtable[] = {
{ "1.2.840.10040.4.1", "dsa" },
{ "1.2.840.10040.4.3", "dsa-with-sha1" },
{ "1.2.840.10045.2.1", "ecPublicKey" },
{ "1.2.840.10045.3.0.1", "c2pnb163v1" },
{ "1.2.840.10045.4.1", "ecdsa-with-SHA1" },
+ { "1.2.840.10045.4.3.1", "ecdsa-with-SHA224" },
+ { "1.2.840.10045.4.3.2", "ecdsa-with-SHA256" },
+ { "1.2.840.10045.4.3.3", "ecdsa-with-SHA384" },
+ { "1.2.840.10045.4.3.4", "ecdsa-with-SHA512" },
{ "1.2.840.10046.2.1", "dhpublicnumber" },
{ "1.2.840.113549.1.1.1", "rsaEncryption" },
{ "1.2.840.113549.1.1.2", "md2WithRSAEncryption" },
@@ -132,7 +135,7 @@ static const struct Curl_OID OIDtable[] = {
{ "1.2.840.113549.2.2", "md2" },
{ "1.2.840.113549.2.5", "md5" },
{ "1.3.14.3.2.26", "sha1" },
- { cnOID, "CN" },
+ { "2.5.4.3", "CN" },
{ "2.5.4.4", "SN" },
{ "2.5.4.5", "serialNumber" },
{ "2.5.4.6", "C" },
@@ -153,7 +156,7 @@ static const struct Curl_OID OIDtable[] = {
{ "2.5.4.65", "pseudonym" },
{ "1.2.840.113549.1.9.1", "emailAddress" },
{ "2.5.4.72", "role" },
- { sanOID, "subjectAltName" },
+ { "2.5.29.17", "subjectAltName" },
{ "2.5.29.18", "issuerAltName" },
{ "2.5.29.19", "basicConstraints" },
{ "2.16.840.1.101.3.4.2.4", "sha224" },
@@ -372,7 +375,7 @@ utf8asn1str(struct dynbuf *to, int type, const char *from, const char *end)
else {
while(!result && (from < end)) {
char buf[4]; /* decode buffer */
- int charsize = 1;
+ size_t charsize = 1;
unsigned int wc = 0;
switch(size) {
@@ -390,7 +393,6 @@ utf8asn1str(struct dynbuf *to, int type, const char *from, const char *end)
if(wc >= 0x00000800) {
if(wc >= 0x00010000) {
if(wc >= 0x00200000) {
- free(buf);
/* Invalid char. size for target encoding. */
return CURLE_WEIRD_SERVER_REPLY;
}
@@ -469,7 +471,7 @@ static CURLcode OID2str(struct dynbuf *store,
if(op)
result = Curl_dyn_add(store, op->textoid);
else
- result = CURLE_BAD_FUNCTION_ARGUMENT;
+ result = Curl_dyn_add(store, Curl_dyn_ptr(&buf));
Curl_dyn_free(&buf);
}
}
@@ -598,7 +600,7 @@ static CURLcode ASN1tostr(struct dynbuf *store,
{
CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT;
if(elem->constructed)
- return CURLE_OK; /* No conversion of structured elements. */
+ return result; /* No conversion of structured elements. */
if(!type)
type = elem->tag; /* Type not forced: use element tag as type. */
@@ -692,6 +694,11 @@ static CURLcode encodeDN(struct dynbuf *store, struct Curl_asn1Element *dn)
str = Curl_dyn_ptr(&temp);
+ if(!str) {
+ result = CURLE_BAD_FUNCTION_ARGUMENT;
+ goto error;
+ }
+
/* Encode delimiter.
If attribute has a short uppercase name, delimiter is ", ". */
for(p3 = str; ISUPPER(*p3); p3++)
@@ -959,7 +966,8 @@ static int do_pubkey(struct Curl_easy *data, int certnum,
if(ssl_push_certinfo(data, certnum, "ECC Public Key", q))
return 1;
}
- return do_pubkey_field(data, certnum, "ecPublicKey", pubkey);
+ return do_pubkey_field(data, certnum, "ecPublicKey", pubkey) == CURLE_OK
+ ? 0 : 1;
}
/* Get the public key (single element). */
@@ -1223,6 +1231,8 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data,
result = ssl_push_certinfo_dyn(data, certnum, "Cert", &out);
done:
+ if(result)
+ failf(data, "Failed extracting certificate chain");
Curl_dyn_free(&out);
return result;
}
diff --git a/libs/libcurl/src/vtls/x509asn1.h b/libs/libcurl/src/vtls/x509asn1.h
index 646aac390a..8d245c2d6d 100644
--- a/libs/libcurl/src/vtls/x509asn1.h
+++ b/libs/libcurl/src/vtls/x509asn1.h
@@ -28,7 +28,8 @@
#include "curl_setup.h"
#if defined(USE_GNUTLS) || defined(USE_WOLFSSL) || \
- defined(USE_SCHANNEL) || defined(USE_SECTRANSP)
+ defined(USE_SCHANNEL) || defined(USE_SECTRANSP) || \
+ defined(USE_MBEDTLS)
#include "cfilters.h"
#include "urldata.h"