diff options
Diffstat (limited to 'libs/libcurl/src/vtls/openssl.c')
-rw-r--r-- | libs/libcurl/src/vtls/openssl.c | 1916 |
1 files changed, 1098 insertions, 818 deletions
diff --git a/libs/libcurl/src/vtls/openssl.c b/libs/libcurl/src/vtls/openssl.c index 86931089b1..2556b5c57f 100644 --- a/libs/libcurl/src/vtls/openssl.c +++ b/libs/libcurl/src/vtls/openssl.c @@ -27,14 +27,14 @@ * but vtls.c should ever call or use these functions.
*/
-#include "curl_setup.h"
+#include "../curl_setup.h"
#if defined(USE_QUICHE) || defined(USE_OPENSSL)
#include <limits.h>
/* Wincrypt must be included before anything that could include OpenSSL. */
-#if defined(USE_WIN32_CRYPTO)
+#ifdef USE_WIN32_CRYPTO
#include <wincrypt.h>
/* Undefine wincrypt conflicting symbols for BoringSSL. */
#undef X509_NAME
@@ -45,24 +45,27 @@ #undef OCSP_RESPONSE
#endif
-#include "urldata.h"
-#include "sendf.h"
-#include "formdata.h" /* for the boundary function */
-#include "url.h" /* for the ssl config check function */
-#include "inet_pton.h"
+#include "../urldata.h"
+#include "../sendf.h"
+#include "../formdata.h" /* for the boundary function */
+#include "../url.h" /* for the ssl config check function */
+#include "../curlx/inet_pton.h"
#include "openssl.h"
-#include "connect.h"
-#include "slist.h"
-#include "select.h"
+#include "../connect.h"
+#include "../slist.h"
+#include "../select.h"
#include "vtls.h"
#include "vtls_int.h"
-#include "vauth/vauth.h"
+#include "vtls_scache.h"
+#include "../vauth/vauth.h"
#include "keylog.h"
-#include "strcase.h"
+#include "../strcase.h"
#include "hostcheck.h"
-#include "multiif.h"
-#include "strerror.h"
-#include "curl_printf.h"
+#include "../multiif.h"
+#include "../curlx/strparse.h"
+#include "../strdup.h"
+#include "../strerror.h"
+#include "../curl_printf.h"
#include <openssl/ssl.h>
#include <openssl/rand.h>
@@ -82,37 +85,49 @@ #include <openssl/tls1.h>
#include <openssl/evp.h>
-#ifdef USE_ECH
-# ifndef OPENSSL_IS_BORINGSSL
+#ifdef HAVE_SSL_SET1_ECH_CONFIG_LIST
+#define USE_ECH_OPENSSL
+#endif
+
+#ifdef USE_ECH_OPENSSL
+# if !defined(OPENSSL_IS_BORINGSSL) && !defined(OPENSSL_IS_AWSLC)
# include <openssl/ech.h>
# endif
-# include "curl_base64.h"
-# define ECH_ENABLED(__data__) \
- (__data__->set.tls_ech && \
- !(__data__->set.tls_ech & CURLECH_DISABLE)\
- )
-#endif /* USE_ECH */
-
-#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_OCSP)
+#endif /* USE_ECH_OPENSSL */
+
+#ifndef OPENSSL_NO_OCSP
#include <openssl/ocsp.h>
#endif
-#if (OPENSSL_VERSION_NUMBER >= 0x0090700fL) && /* 0.9.7 or later */ \
- !defined(OPENSSL_NO_ENGINE) && !defined(OPENSSL_NO_UI_CONSOLE)
+#if !defined(OPENSSL_NO_ENGINE) && !defined(OPENSSL_NO_UI_CONSOLE)
#define USE_OPENSSL_ENGINE
#include <openssl/engine.h>
#endif
-#include "warnless.h"
+#ifdef LIBRESSL_VERSION_NUMBER
+# /* As of LibreSSL 2.0.0-4.0.0: OPENSSL_VERSION_NUMBER == 0x20000000L */
+# if LIBRESSL_VERSION_NUMBER < 0x2090100fL /* 2019-04-13 */
+# error "LibreSSL 2.9.1 or later required"
+# endif
+#elif OPENSSL_VERSION_NUMBER < 0x1000201fL /* 2015-03-19 */
+# error "OpenSSL 1.0.2a or later required"
+#endif
-/* The last #include files should be: */
-#include "curl_memory.h"
-#include "memdebug.h"
+#if OPENSSL_VERSION_NUMBER >= 0x3000000fL && !defined(OPENSSL_NO_UI_CONSOLE)
+#include <openssl/provider.h>
+#include <openssl/store.h>
+/* this is used in the following conditions to make them easier to read */
+#define OPENSSL_HAS_PROVIDERS
-#ifndef ARRAYSIZE
-#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
+static void ossl_provider_cleanup(struct Curl_easy *data);
#endif
+#include "../curlx/warnless.h"
+
+/* The last #include files should be: */
+#include "../curl_memory.h"
+#include "../memdebug.h"
+
/* Uncomment the ALLOW_RENEG line to a real #define if you want to allow TLS
renegotiations when built with BoringSSL. Renegotiating is non-compliant
with HTTP/2 and "an extremely dangerous protocol feature". Beware.
@@ -124,57 +139,28 @@ #error "OPENSSL_VERSION_NUMBER not defined"
#endif
-#ifdef USE_OPENSSL_ENGINE
+#if defined(USE_OPENSSL_ENGINE) || defined(OPENSSL_HAS_PROVIDERS)
#include <openssl/ui.h>
#endif
-#if OPENSSL_VERSION_NUMBER >= 0x00909000L
-#define SSL_METHOD_QUAL const
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+#define OSSL_UI_METHOD_CAST(x) (x)
#else
-#define SSL_METHOD_QUAL
+#define OSSL_UI_METHOD_CAST(x) CURL_UNCONST(x)
#endif
-#if (OPENSSL_VERSION_NUMBER >= 0x10000000L)
-#define HAVE_ERR_REMOVE_THREAD_STATE 1
-#endif
-
-#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && /* OpenSSL 1.1.0+ */ \
- !(defined(LIBRESSL_VERSION_NUMBER) && \
- LIBRESSL_VERSION_NUMBER < 0x20700000L)
-#define SSLEAY_VERSION_NUMBER OPENSSL_VERSION_NUMBER
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L /* OpenSSL 1.1.0+ and LibreSSL */
#define HAVE_X509_GET0_EXTENSIONS 1 /* added in 1.1.0 -pre1 */
#define HAVE_OPAQUE_EVP_PKEY 1 /* since 1.1.0 -pre3 */
#define HAVE_OPAQUE_RSA_DSA_DH 1 /* since 1.1.0 -pre5 */
-#define CONST_EXTS const
#define HAVE_ERR_REMOVE_THREAD_STATE_DEPRECATED 1
-
-/* funny typecast define due to difference in API */
-#ifdef LIBRESSL_VERSION_NUMBER
-#define ARG2_X509_signature_print (X509_ALGOR *)
-#else
-#define ARG2_X509_signature_print
-#endif
-
#else
/* For OpenSSL before 1.1.0 */
#define ASN1_STRING_get0_data(x) ASN1_STRING_data(x)
#define X509_get0_notBefore(x) X509_get_notBefore(x)
#define X509_get0_notAfter(x) X509_get_notAfter(x)
-#define CONST_EXTS /* nope */
-#ifndef LIBRESSL_VERSION_NUMBER
#define OpenSSL_version_num() SSLeay()
#endif
-#endif
-
-#if (OPENSSL_VERSION_NUMBER >= 0x1000200fL) && /* 1.0.2 or later */ \
- !(defined(LIBRESSL_VERSION_NUMBER) && \
- LIBRESSL_VERSION_NUMBER < 0x20700000L)
-#define HAVE_X509_GET0_SIGNATURE 1
-#endif
-
-#if (OPENSSL_VERSION_NUMBER >= 0x1000200fL) /* 1.0.2 or later */
-#define HAVE_SSL_GET_SHUTDOWN 1
-#endif
#if OPENSSL_VERSION_NUMBER >= 0x10002003L && \
OPENSSL_VERSION_NUMBER <= 0x10002FFFL && \
@@ -182,11 +168,6 @@ #define HAVE_SSL_COMP_FREE_COMPRESSION_METHODS 1
#endif
-#if (OPENSSL_VERSION_NUMBER < 0x0090808fL)
-/* not present in older OpenSSL */
-#define OPENSSL_load_builtin_modules(x)
-#endif
-
#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
#define HAVE_EVP_PKEY_GET_PARAMS 1
#endif
@@ -200,18 +181,6 @@ #define FREE_PKEY_PARAM_BIGNUM(name)
#endif
-/*
- * Whether SSL_CTX_set_keylog_callback is available.
- * OpenSSL: supported since 1.1.1 https://github.com/openssl/openssl/pull/2287
- * BoringSSL: supported since d28f59c27bac (committed 2015-11-19)
- * LibreSSL: not supported. 3.5.0+ has a stub function that does nothing.
- */
-#if (OPENSSL_VERSION_NUMBER >= 0x10101000L && \
- !defined(LIBRESSL_VERSION_NUMBER)) || \
- defined(OPENSSL_IS_BORINGSSL)
-#define HAVE_KEYLOG_CALLBACK
-#endif
-
/* Whether SSL_CTX_set_ciphersuites is available.
* OpenSSL: supported since 1.1.1 (commit a53b5be6a05)
* BoringSSL: no
@@ -223,35 +192,32 @@ LIBRESSL_VERSION_NUMBER >= 0x3040100fL)) && \
!defined(OPENSSL_IS_BORINGSSL)
#define HAVE_SSL_CTX_SET_CIPHERSUITES
- #if !defined(OPENSSL_IS_AWSLC)
+ #ifndef OPENSSL_IS_AWSLC
#define HAVE_SSL_CTX_SET_POST_HANDSHAKE_AUTH
#endif
#endif
-/*
- * Whether SSL_CTX_set1_curves_list is available.
- * OpenSSL: supported since 1.0.2, see
- * https://docs.openssl.org/master/man3/SSL_CTX_set1_curves/
- * BoringSSL: supported since 5fd1807d95f7 (committed 2016-09-30)
- * LibreSSL: since 2.5.3 (April 12, 2017)
+/* Whether SSL_CTX_set1_sigalgs_list is available
+ * OpenSSL: supported since 1.0.2 (commit 0b362de5f575)
+ * BoringSSL: supported since 0.20240913.0 (commit 826ce15)
+ * LibreSSL: no
*/
-#if (OPENSSL_VERSION_NUMBER >= 0x10002000L) || \
- defined(OPENSSL_IS_BORINGSSL)
-#define HAVE_SSL_CTX_SET_EC_CURVES
+#if (OPENSSL_VERSION_NUMBER >= 0x10002000L && \
+ !defined(LIBRESSL_VERSION_NUMBER))
+ #define HAVE_SSL_CTX_SET1_SIGALGS
#endif
-#if defined(LIBRESSL_VERSION_NUMBER)
+#ifdef LIBRESSL_VERSION_NUMBER
#define OSSL_PACKAGE "LibreSSL"
#elif defined(OPENSSL_IS_BORINGSSL)
#define OSSL_PACKAGE "BoringSSL"
#elif defined(OPENSSL_IS_AWSLC)
#define OSSL_PACKAGE "AWS-LC"
+#elif (defined(USE_NGTCP2) && defined(USE_NGHTTP3) && \
+ !defined(OPENSSL_QUIC_API2)) || defined(USE_MSH3)
+#define OSSL_PACKAGE "quictls"
#else
-# if (defined(USE_NGTCP2) && defined(USE_NGHTTP3)) || defined(USE_MSH3)
-# define OSSL_PACKAGE "quictls"
-# else
-# define OSSL_PACKAGE "OpenSSL"
-#endif
+#define OSSL_PACKAGE "OpenSSL"
#endif
#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)
@@ -285,8 +251,6 @@ typedef int numcert_t; #endif
#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && \
- !(defined(LIBRESSL_VERSION_NUMBER) && \
- LIBRESSL_VERSION_NUMBER < 0x2070100fL) && \
!defined(OPENSSL_IS_BORINGSSL) && \
!defined(OPENSSL_IS_AWSLC)
#define HAVE_OPENSSL_VERSION
@@ -307,13 +271,6 @@ typedef unsigned long sslerr_t; #define HAVE_SSL_X509_STORE_SHARE
#endif
-/* What API version do we use? */
-#if defined(LIBRESSL_VERSION_NUMBER)
-#define USE_PRE_1_1_API (LIBRESSL_VERSION_NUMBER < 0x2070000f)
-#else /* !LIBRESSL_VERSION_NUMBER */
-#define USE_PRE_1_1_API (OPENSSL_VERSION_NUMBER < 0x10100000L)
-#endif /* !LIBRESSL_VERSION_NUMBER */
-
static CURLcode ossl_certchain(struct Curl_easy *data, SSL *ssl);
static CURLcode push_certinfo(struct Curl_easy *data,
@@ -377,10 +334,16 @@ static int asn1_object_dump(ASN1_OBJECT *a, char *buf, size_t len) static CURLcode X509V3_ext(struct Curl_easy *data,
int certnum,
- CONST_EXTS STACK_OF(X509_EXTENSION) *exts)
+ const STACK_OF(X509_EXTENSION) *extsarg)
{
int i;
CURLcode result = CURLE_OK;
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \
+ !defined(LIBRESSL_VERSION_NUMBER)
+ const STACK_OF(X509_EXTENSION) *exts = extsarg;
+#else
+ STACK_OF(X509_EXTENSION) *exts = CURL_UNCONST(extsarg);
+#endif
if((int)sk_X509_EXTENSION_num(exts) <= 0)
/* no extensions, bail out */
@@ -469,7 +432,7 @@ static CURLcode ossl_certchain(struct Curl_easy *data, SSL *ssl) if(result)
break;
-#if defined(HAVE_X509_GET0_SIGNATURE) && defined(HAVE_X509_GET0_EXTENSIONS)
+#ifdef HAVE_X509_GET0_EXTENSIONS
{
const X509_ALGOR *sigalg = NULL;
X509_PUBKEY *xpubkey = NULL;
@@ -686,21 +649,19 @@ static CURLcode ossl_certchain(struct Curl_easy *data, SSL *ssl) #ifdef USE_OPENSSL
-#if USE_PRE_1_1_API
-#if !defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER < 0x2070000fL
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
#define BIO_set_init(x,v) ((x)->init=(v))
#define BIO_get_data(x) ((x)->ptr)
#define BIO_set_data(x,v) ((x)->ptr=(v))
-#endif
#define BIO_get_shutdown(x) ((x)->shutdown)
#define BIO_set_shutdown(x,v) ((x)->shutdown=(v))
-#endif /* USE_PRE_1_1_API */
+#endif /* HAVE_PRE_1_1_API */
static int ossl_bio_cf_create(BIO *bio)
{
BIO_set_shutdown(bio, 1);
BIO_set_init(bio, 1);
-#if USE_PRE_1_1_API
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
bio->num = -1;
#endif
BIO_set_data(bio, NULL);
@@ -737,9 +698,11 @@ static long ossl_bio_cf_ctrl(BIO *bio, int cmd, long num, void *ptr) ret = 1;
break;
#ifdef BIO_CTRL_EOF
- case BIO_CTRL_EOF:
+ case BIO_CTRL_EOF: {
/* EOF has been reached on input? */
- return (!cf->next || !cf->next->connected);
+ struct ssl_connect_data *connssl = cf->ctx;
+ return connssl->peer_closed;
+ }
#endif
default:
ret = 0;
@@ -817,7 +780,7 @@ static int ossl_bio_cf_in_read(BIO *bio, char *buf, int blen) return (int)nread;
}
-#if USE_PRE_1_1_API
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
static BIO_METHOD ossl_bio_cf_meth_1_0 = {
BIO_TYPE_MEM,
@@ -863,14 +826,6 @@ static void ossl_bio_cf_method_free(BIO_METHOD *m) #endif
-/*
- * Number of bytes to read from the random number seed file. This must be
- * a finite value (because some entropy "files" like /dev/urandom have
- * an infinite length), but must be large enough to provide enough
- * entropy to properly seed OpenSSL's PRNG.
- */
-#define RAND_LOAD_LENGTH 1024
-
#ifdef HAVE_KEYLOG_CALLBACK
static void ossl_keylog_callback(const SSL *ssl, const char *line)
{
@@ -894,9 +849,7 @@ ossl_log_tls12_secret(const SSL *ssl, bool *keylog_done) if(!session || *keylog_done)
return;
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \
- !(defined(LIBRESSL_VERSION_NUMBER) && \
- LIBRESSL_VERSION_NUMBER < 0x20700000L)
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
/* 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);
@@ -943,15 +896,15 @@ static const char *SSL_ERROR_to_str(int err) return "SSL_ERROR_WANT_CONNECT";
case SSL_ERROR_WANT_ACCEPT:
return "SSL_ERROR_WANT_ACCEPT";
-#if defined(SSL_ERROR_WANT_ASYNC)
+#ifdef SSL_ERROR_WANT_ASYNC
case SSL_ERROR_WANT_ASYNC:
return "SSL_ERROR_WANT_ASYNC";
#endif
-#if defined(SSL_ERROR_WANT_ASYNC_JOB)
+#ifdef SSL_ERROR_WANT_ASYNC_JOB
case SSL_ERROR_WANT_ASYNC_JOB:
return "SSL_ERROR_WANT_ASYNC_JOB";
#endif
-#if defined(SSL_ERROR_WANT_EARLY)
+#ifdef SSL_ERROR_WANT_EARLY
case SSL_ERROR_WANT_EARLY:
return "SSL_ERROR_WANT_EARLY";
#endif
@@ -960,8 +913,6 @@ static const char *SSL_ERROR_to_str(int err) }
}
-static size_t ossl_version(char *buffer, size_t size);
-
/* Return error string for last OpenSSL error
*/
static char *ossl_strerror(unsigned long error, char *buf, size_t size)
@@ -970,7 +921,7 @@ static char *ossl_strerror(unsigned long error, char *buf, size_t size) DEBUGASSERT(size);
*buf = '\0';
- len = ossl_version(buf, size);
+ len = Curl_ossl_version(buf, size);
DEBUGASSERT(len < (size - 2));
if(len < (size - 2)) {
buf += len;
@@ -996,14 +947,14 @@ static char *ossl_strerror(unsigned long error, char *buf, size_t size) }
static int passwd_callback(char *buf, int num, int encrypting,
- void *global_passwd)
+ void *password)
{
DEBUGASSERT(0 == encrypting);
- if(!encrypting && num >= 0) {
- int klen = curlx_uztosi(strlen((char *)global_passwd));
+ if(!encrypting && num >= 0 && password) {
+ int klen = curlx_uztosi(strlen((char *)password));
if(num > klen) {
- memcpy(buf, global_passwd, klen + 1);
+ memcpy(buf, password, klen + 1);
return klen;
}
}
@@ -1015,7 +966,7 @@ static int passwd_callback(char *buf, int num, int encrypting, */
static bool rand_enough(void)
{
- return (0 != RAND_status());
+ return 0 != RAND_status();
}
static CURLcode ossl_seed(struct Curl_easy *data)
@@ -1043,13 +994,13 @@ static CURLcode ossl_seed(struct Curl_easy *data) size_t len = sizeof(randb);
size_t i, i_max;
for(i = 0, i_max = len / sizeof(struct curltime); i < i_max; ++i) {
- struct curltime tv = Curl_now();
+ struct curltime tv = curlx_now();
Curl_wait_ms(1);
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) *
+ tv.tv_sec ^= ((curlx_now().tv_sec + (time_t)curlx_now().tv_usec) *
(time_t)(i + 3)) << 8;
- tv.tv_usec ^= (int) ((Curl_now().tv_sec + (time_t)Curl_now().tv_usec) *
+ tv.tv_usec ^= (int) ((curlx_now().tv_sec + (time_t)curlx_now().tv_usec) *
(time_t)(i + 4)) << 16;
memcpy(&randb[i * sizeof(struct curltime)], &tv,
sizeof(struct curltime));
@@ -1057,6 +1008,14 @@ static CURLcode ossl_seed(struct Curl_easy *data) RAND_add(randb, (int)len, (double)len/2);
} while(!rand_enough());
+ /*
+ * Number of bytes to read from the random number seed file. This must be
+ * a finite value (because some entropy "files" like /dev/urandom have
+ * an infinite length), but must be large enough to provide enough
+ * entropy to properly seed OpenSSL's PRNG.
+ */
+# define RAND_LOAD_LENGTH 1024
+
{
/* generates a default path for the random seed file */
char fname[256];
@@ -1071,8 +1030,8 @@ static CURLcode ossl_seed(struct Curl_easy *data) }
infof(data, "libcurl is now using a weak random seed");
- return (rand_enough() ? CURLE_OK :
- CURLE_SSL_CONNECT_ERROR /* confusing error code */);
+ return rand_enough() ? CURLE_OK :
+ CURLE_SSL_CONNECT_ERROR; /* confusing error code */
#endif
}
@@ -1082,6 +1041,9 @@ static CURLcode ossl_seed(struct Curl_easy *data) #ifndef SSL_FILETYPE_PKCS12
#define SSL_FILETYPE_PKCS12 43
#endif
+#ifndef SSL_FILETYPE_PROVIDER
+#define SSL_FILETYPE_PROVIDER 44
+#endif
static int ossl_do_file_type(const char *type)
{
if(!type || !type[0])
@@ -1090,6 +1052,8 @@ static int ossl_do_file_type(const char *type) return SSL_FILETYPE_PEM;
if(strcasecompare(type, "DER"))
return SSL_FILETYPE_ASN1;
+ if(strcasecompare(type, "PROV"))
+ return SSL_FILETYPE_PROVIDER;
if(strcasecompare(type, "ENG"))
return SSL_FILETYPE_ENGINE;
if(strcasecompare(type, "P12"))
@@ -1097,7 +1061,7 @@ static int ossl_do_file_type(const char *type) return -1;
}
-#ifdef USE_OPENSSL_ENGINE
+#if defined(USE_OPENSSL_ENGINE) || defined(OPENSSL_HAS_PROVIDERS)
/*
* Supply default password to the engine user interface conversation.
* The password is passed by OpenSSL engine from ENGINE_load_private_key()
@@ -1145,16 +1109,19 @@ static int ssl_ui_writer(UI *ui, UI_STRING *uis) */
static bool is_pkcs11_uri(const char *string)
{
- return (string && strncasecompare(string, "pkcs11:", 7));
+ return string && strncasecompare(string, "pkcs11:", 7);
}
#endif
static CURLcode ossl_set_engine(struct Curl_easy *data, const char *engine);
+#if defined(OPENSSL_HAS_PROVIDERS)
+static CURLcode ossl_set_provider(struct Curl_easy *data,
+ const char *provider);
+#endif
-static int
-SSL_CTX_use_certificate_blob(SSL_CTX *ctx, const struct curl_blob *blob,
- int type, const char *key_passwd)
+static int use_certificate_blob(SSL_CTX *ctx, const struct curl_blob *blob,
+ int type, const char *key_passwd)
{
int ret = 0;
X509 *x = NULL;
@@ -1171,7 +1138,7 @@ SSL_CTX_use_certificate_blob(SSL_CTX *ctx, const struct curl_blob *blob, else if(type == SSL_FILETYPE_PEM) {
/* ERR_R_PEM_LIB; */
x = PEM_read_bio_X509(in, NULL,
- passwd_callback, (void *)key_passwd);
+ passwd_callback, CURL_UNCONST(key_passwd));
}
else {
ret = 0;
@@ -1190,9 +1157,8 @@ end: return ret;
}
-static int
-SSL_CTX_use_PrivateKey_blob(SSL_CTX *ctx, const struct curl_blob *blob,
- int type, const char *key_passwd)
+static int use_privatekey_blob(SSL_CTX *ctx, const struct curl_blob *blob,
+ int type, const char *key_passwd)
{
int ret = 0;
EVP_PKEY *pkey = NULL;
@@ -1202,17 +1168,15 @@ SSL_CTX_use_PrivateKey_blob(SSL_CTX *ctx, const struct curl_blob *blob, if(type == SSL_FILETYPE_PEM)
pkey = PEM_read_bio_PrivateKey(in, NULL, passwd_callback,
- (void *)key_passwd);
+ CURL_UNCONST(key_passwd));
else if(type == SSL_FILETYPE_ASN1)
pkey = d2i_PrivateKey_bio(in, NULL);
- else {
- ret = 0;
+ else
goto end;
- }
- if(!pkey) {
- ret = 0;
+
+ if(!pkey)
goto end;
- }
+
ret = SSL_CTX_use_PrivateKey(ctx, pkey);
EVP_PKEY_free(pkey);
end:
@@ -1221,16 +1185,11 @@ end: }
static int
-SSL_CTX_use_certificate_chain_blob(SSL_CTX *ctx, const struct curl_blob *blob,
- const char *key_passwd)
+use_certificate_chain_blob(SSL_CTX *ctx, const struct curl_blob *blob,
+ const char *key_passwd)
{
-/* SSL_CTX_add1_chain_cert introduced in OpenSSL 1.0.2 */
-#if (OPENSSL_VERSION_NUMBER >= 0x1000200fL) && /* OpenSSL 1.0.2 or later */ \
- !(defined(LIBRESSL_VERSION_NUMBER) && \
- (LIBRESSL_VERSION_NUMBER < 0x2090100fL)) /* LibreSSL 2.9.1 or later */
int ret = 0;
X509 *x = NULL;
- void *passwd_callback_userdata = (void *)key_passwd;
BIO *in = BIO_new_mem_buf(blob->data, (int)(blob->len));
if(!in)
return CURLE_OUT_OF_MEMORY;
@@ -1238,12 +1197,9 @@ SSL_CTX_use_certificate_chain_blob(SSL_CTX *ctx, const struct curl_blob *blob, ERR_clear_error();
x = PEM_read_bio_X509_AUX(in, NULL,
- passwd_callback, (void *)key_passwd);
-
- if(!x) {
- ret = 0;
+ passwd_callback, CURL_UNCONST(key_passwd));
+ if(!x)
goto end;
- }
ret = SSL_CTX_use_certificate(ctx, x);
@@ -1260,7 +1216,7 @@ SSL_CTX_use_certificate_chain_blob(SSL_CTX *ctx, const struct curl_blob *blob, }
while((ca = PEM_read_bio_X509(in, NULL, passwd_callback,
- passwd_callback_userdata))
+ CURL_UNCONST(key_passwd)))
!= NULL) {
if(!SSL_CTX_add0_chain_cert(ctx, ca)) {
@@ -1282,12 +1238,6 @@ end: X509_free(x);
BIO_free(in);
return ret;
-#else
- (void)ctx; /* unused */
- (void)blob; /* unused */
- (void)key_passwd; /* unused */
- return 0;
-#endif
}
static
@@ -1306,7 +1256,8 @@ int cert_stuff(struct Curl_easy *data, int file_type = ossl_do_file_type(cert_type);
- if(cert_file || cert_blob || (file_type == SSL_FILETYPE_ENGINE)) {
+ if(cert_file || cert_blob || (file_type == SSL_FILETYPE_ENGINE) ||
+ (file_type == SSL_FILETYPE_PROVIDER)) {
SSL *ssl;
X509 *x509;
int cert_done = 0;
@@ -1324,7 +1275,7 @@ int cert_stuff(struct Curl_easy *data, case SSL_FILETYPE_PEM:
/* SSL_CTX_use_certificate_chain_file() only works on PEM files */
cert_use_result = cert_blob ?
- SSL_CTX_use_certificate_chain_blob(ctx, cert_blob, key_passwd) :
+ use_certificate_chain_blob(ctx, cert_blob, key_passwd) :
SSL_CTX_use_certificate_chain_file(ctx, cert_file);
if(cert_use_result != 1) {
failf(data,
@@ -1344,8 +1295,7 @@ int cert_stuff(struct Curl_easy *data, ASN1 files. */
cert_use_result = cert_blob ?
- SSL_CTX_use_certificate_blob(ctx, cert_blob,
- file_type, key_passwd) :
+ use_certificate_blob(ctx, cert_blob, file_type, key_passwd) :
SSL_CTX_use_certificate_file(ctx, cert_file, file_type);
if(cert_use_result != 1) {
failf(data,
@@ -1383,7 +1333,7 @@ int cert_stuff(struct Curl_easy *data, /* Does the engine supports LOAD_CERT_CTRL ? */
if(!ENGINE_ctrl(data->state.engine, ENGINE_CTRL_GET_CMD_FROM_NAME,
- 0, (void *)cmd_name, NULL)) {
+ 0, CURL_UNCONST(cmd_name), NULL)) {
failf(data, "ssl engine does not support loading certificates");
return 0;
}
@@ -1418,9 +1368,70 @@ int cert_stuff(struct Curl_easy *data, }
}
break;
-#else
- failf(data, "file type ENG for certificate not implemented");
- return 0;
+#endif
+#if defined(OPENSSL_HAS_PROVIDERS)
+ /* fall through to compatible provider */
+ case SSL_FILETYPE_PROVIDER:
+ {
+ /* Implicitly use pkcs11 provider if none was provided and the
+ * cert_file is a PKCS#11 URI */
+ if(!data->state.provider) {
+ if(is_pkcs11_uri(cert_file)) {
+ if(ossl_set_provider(data, "pkcs11") != CURLE_OK) {
+ return 0;
+ }
+ }
+ }
+
+ if(data->state.provider) {
+ /* Load the certificate from the provider */
+ OSSL_STORE_INFO *info = NULL;
+ X509 *cert = NULL;
+ OSSL_STORE_CTX *store =
+ OSSL_STORE_open_ex(cert_file, data->state.libctx,
+ NULL, NULL, NULL, NULL, NULL, NULL);
+ if(!store) {
+ failf(data, "Failed to open OpenSSL store: %s",
+ ossl_strerror(ERR_get_error(), error_buffer,
+ sizeof(error_buffer)));
+ return 0;
+ }
+ if(OSSL_STORE_expect(store, OSSL_STORE_INFO_CERT) != 1) {
+ failf(data, "Failed to set store preference. Ignoring the error: %s",
+ ossl_strerror(ERR_get_error(), error_buffer,
+ sizeof(error_buffer)));
+ }
+
+ info = OSSL_STORE_load(store);
+ if(info) {
+ int ossl_type = OSSL_STORE_INFO_get_type(info);
+
+ if(ossl_type == OSSL_STORE_INFO_CERT)
+ cert = OSSL_STORE_INFO_get1_CERT(info);
+ OSSL_STORE_INFO_free(info);
+ }
+ OSSL_STORE_close(store);
+ if(!cert) {
+ failf(data, "No cert found in the openssl store: %s",
+ ossl_strerror(ERR_get_error(), error_buffer,
+ sizeof(error_buffer)));
+ return 0;
+ }
+
+ if(SSL_CTX_use_certificate(ctx, cert) != 1) {
+ failf(data, "unable to set client certificate [%s]",
+ ossl_strerror(ERR_get_error(), error_buffer,
+ sizeof(error_buffer)));
+ return 0;
+ }
+ X509_free(cert); /* we do not need the handle any more... */
+ }
+ else {
+ failf(data, "crypto provider not set, cannot load certificate");
+ return 0;
+ }
+ }
+ break;
#endif
case SSL_FILETYPE_PKCS12:
@@ -1469,8 +1480,7 @@ int cert_stuff(struct Curl_easy *data, PKCS12_PBE_add();
- if(!PKCS12_parse(p12, key_passwd, &pri, &x509,
- &ca)) {
+ if(!PKCS12_parse(p12, key_passwd, &pri, &x509, &ca)) {
failf(data,
"could not parse PKCS12 file, check password, " OSSL_PACKAGE
" error %s",
@@ -1554,7 +1564,7 @@ fail: FALLTHROUGH();
case SSL_FILETYPE_ASN1:
cert_use_result = key_blob ?
- SSL_CTX_use_PrivateKey_blob(ctx, key_blob, file_type, key_passwd) :
+ use_privatekey_blob(ctx, key_blob, file_type, key_passwd) :
SSL_CTX_use_PrivateKey_file(ctx, key_file, file_type);
if(cert_use_result != 1) {
failf(data, "unable to set private key file: '%s' type %s",
@@ -1580,7 +1590,7 @@ fail: if(data->state.engine) {
UI_METHOD *ui_method =
- UI_create_method((char *)"curl user interface");
+ UI_create_method(OSSL_UI_METHOD_CAST("curl user interface"));
if(!ui_method) {
failf(data, "unable do create " OSSL_PACKAGE
" user-interface method");
@@ -1611,10 +1621,87 @@ fail: }
}
break;
-#else
- failf(data, "file type ENG for private key not supported");
- return 0;
#endif
+#if defined(OPENSSL_HAS_PROVIDERS)
+ /* fall through to compatible provider */
+ case SSL_FILETYPE_PROVIDER:
+ {
+ /* Implicitly use pkcs11 provider if none was provided and the
+ * key_file is a PKCS#11 URI */
+ if(!data->state.provider) {
+ if(is_pkcs11_uri(key_file)) {
+ if(ossl_set_provider(data, "pkcs11") != CURLE_OK) {
+ return 0;
+ }
+ }
+ }
+
+ if(data->state.provider) {
+ /* Load the private key from the provider */
+ EVP_PKEY *priv_key = NULL;
+ OSSL_STORE_CTX *store = NULL;
+ OSSL_STORE_INFO *info = NULL;
+ UI_METHOD *ui_method =
+ UI_create_method(OSSL_UI_METHOD_CAST("curl user interface"));
+ if(!ui_method) {
+ failf(data, "unable do create " OSSL_PACKAGE
+ " user-interface method");
+ return 0;
+ }
+ UI_method_set_opener(ui_method, UI_method_get_opener(UI_OpenSSL()));
+ UI_method_set_closer(ui_method, UI_method_get_closer(UI_OpenSSL()));
+ UI_method_set_reader(ui_method, ssl_ui_reader);
+ UI_method_set_writer(ui_method, ssl_ui_writer);
+
+ store = OSSL_STORE_open_ex(key_file, data->state.libctx,
+ data->state.propq, ui_method, NULL, NULL,
+ NULL, NULL);
+ if(!store) {
+ failf(data, "Failed to open OpenSSL store: %s",
+ ossl_strerror(ERR_get_error(), error_buffer,
+ sizeof(error_buffer)));
+ return 0;
+ }
+ if(OSSL_STORE_expect(store, OSSL_STORE_INFO_PKEY) != 1) {
+ failf(data, "Failed to set store preference. Ignoring the error: %s",
+ ossl_strerror(ERR_get_error(), error_buffer,
+ sizeof(error_buffer)));
+ }
+
+ info = OSSL_STORE_load(store);
+ if(info) {
+ int ossl_type = OSSL_STORE_INFO_get_type(info);
+
+ if(ossl_type == OSSL_STORE_INFO_PKEY)
+ priv_key = OSSL_STORE_INFO_get1_PKEY(info);
+ OSSL_STORE_INFO_free(info);
+ }
+ OSSL_STORE_close(store);
+ UI_destroy_method(ui_method);
+ if(!priv_key) {
+ failf(data, "No private key found in the openssl store: %s",
+ ossl_strerror(ERR_get_error(), error_buffer,
+ sizeof(error_buffer)));
+ return 0;
+ }
+
+ if(SSL_CTX_use_PrivateKey(ctx, priv_key) != 1) {
+ failf(data, "unable to set private key [%s]",
+ ossl_strerror(ERR_get_error(), error_buffer,
+ sizeof(error_buffer)));
+ EVP_PKEY_free(priv_key);
+ return 0;
+ }
+ EVP_PKEY_free(priv_key); /* we do not need the handle any more... */
+ }
+ else {
+ failf(data, "crypto provider not set, cannot load private key");
+ return 0;
+ }
+ }
+ break;
+#endif
+
case SSL_FILETYPE_PKCS12:
if(!cert_done) {
failf(data, "file type P12 for private key not supported");
@@ -1689,11 +1776,11 @@ static CURLcode x509_name_oneline(X509_NAME *a, struct dynbuf *d) CURLcode result = CURLE_OUT_OF_MEMORY;
if(bio_out) {
- Curl_dyn_reset(d);
+ curlx_dyn_reset(d);
rc = X509_NAME_print_ex(bio_out, a, 0, XN_FLAG_SEP_SPLUS_SPC);
if(rc != -1) {
BIO_get_mem_ptr(bio_out, &biomem);
- result = Curl_dyn_addn(d, biomem->data, biomem->length);
+ result = curlx_dyn_addn(d, biomem->data, biomem->length);
BIO_free(bio_out);
}
}
@@ -1708,8 +1795,7 @@ static CURLcode x509_name_oneline(X509_NAME *a, struct dynbuf *d) */
static int ossl_init(void)
{
-#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && \
- (!defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER >= 0x2070000fL)
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
const uint64_t flags =
#ifdef OPENSSL_INIT_ENGINE_ALL_BUILTIN
/* not present in BoringSSL */
@@ -1759,8 +1845,7 @@ static int ossl_init(void) /* Global cleanup */
static void ossl_cleanup(void)
{
-#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && \
- (!defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER >= 0x2070000fL)
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
/* OpenSSL 1.1 deprecates all these cleanup functions and
turns them into no-ops in OpenSSL 1.0 compatibility mode */
#else
@@ -1776,11 +1861,7 @@ static void ossl_cleanup(void) ERR_free_strings();
/* Free thread local error state, destroying hash upon zero refcount */
-#ifdef HAVE_ERR_REMOVE_THREAD_STATE
ERR_remove_thread_state(NULL);
-#else
- ERR_remove_state(0);
-#endif
/* Free all memory allocated by all configuration modules */
CONF_modules_free();
@@ -1793,47 +1874,39 @@ static void ossl_cleanup(void) Curl_tls_keylog_close();
}
-/* Selects an OpenSSL crypto engine
+/* Selects an OpenSSL crypto engine or provider.
*/
-static CURLcode ossl_set_engine(struct Curl_easy *data, const char *engine)
+static CURLcode ossl_set_engine(struct Curl_easy *data, const char *name)
{
#ifdef USE_OPENSSL_ENGINE
- ENGINE *e;
+ CURLcode result = CURLE_SSL_ENGINE_NOTFOUND;
+ ENGINE *e = ENGINE_by_id(name);
-#if OPENSSL_VERSION_NUMBER >= 0x00909000L
- e = ENGINE_by_id(engine);
-#else
- /* avoid memory leak */
- for(e = ENGINE_get_first(); e; e = ENGINE_get_next(e)) {
- const char *e_id = ENGINE_get_id(e);
- if(!strcmp(engine, e_id))
- break;
- }
-#endif
-
- if(!e) {
- failf(data, "SSL Engine '%s' not found", engine);
- return CURLE_SSL_ENGINE_NOTFOUND;
- }
+ if(e) {
- if(data->state.engine) {
- ENGINE_finish(data->state.engine);
- ENGINE_free(data->state.engine);
- data->state.engine = NULL;
- }
- if(!ENGINE_init(e)) {
- char buf[256];
-
- ENGINE_free(e);
- failf(data, "Failed to initialise SSL Engine '%s': %s",
- engine, ossl_strerror(ERR_get_error(), buf, sizeof(buf)));
- return CURLE_SSL_ENGINE_INITFAILED;
+ if(data->state.engine) {
+ ENGINE_finish(data->state.engine);
+ ENGINE_free(data->state.engine);
+ data->state.engine = NULL;
+ }
+ if(!ENGINE_init(e)) {
+ char buf[256];
+
+ ENGINE_free(e);
+ failf(data, "Failed to initialise SSL Engine '%s': %s",
+ name, ossl_strerror(ERR_get_error(), buf, sizeof(buf)));
+ result = CURLE_SSL_ENGINE_INITFAILED;
+ e = NULL;
+ }
+ data->state.engine = e;
+ return result;
}
- data->state.engine = e;
- return CURLE_OK;
+#endif
+#ifdef OPENSSL_HAS_PROVIDERS
+ return ossl_set_provider(data, name);
#else
- (void)engine;
- failf(data, "SSL Engine not supported");
+ (void)name;
+ failf(data, "OpenSSL engine not found");
return CURLE_SSL_ENGINE_NOTFOUND;
#endif
}
@@ -1882,6 +1955,102 @@ static struct curl_slist *ossl_engines_list(struct Curl_easy *data) return list;
}
+#if defined(OPENSSL_HAS_PROVIDERS)
+
+static void ossl_provider_cleanup(struct Curl_easy *data)
+{
+ if(data->state.baseprov) {
+ OSSL_PROVIDER_unload(data->state.baseprov);
+ data->state.baseprov = NULL;
+ }
+ if(data->state.provider) {
+ OSSL_PROVIDER_unload(data->state.provider);
+ data->state.provider = NULL;
+ }
+ OSSL_LIB_CTX_free(data->state.libctx);
+ data->state.libctx = NULL;
+ Curl_safefree(data->state.propq);
+ data->state.provider_loaded = FALSE;
+}
+
+#define MAX_PROVIDER_LEN 128 /* reasonable */
+
+/* Selects an OpenSSL crypto provider.
+ *
+ * A provider might need an associated property, a string passed on to
+ * OpenSSL. Specify this as [PROVIDER][:PROPERTY]: separate the name and the
+ * property with a colon. No colon means no property is set.
+ *
+ * An example provider + property looks like "tpm2:?provider=tpm2".
+ */
+static CURLcode ossl_set_provider(struct Curl_easy *data, const char *iname)
+{
+ char name[MAX_PROVIDER_LEN + 1];
+ struct Curl_str prov;
+ const char *propq = NULL;
+
+ if(!iname) {
+ /* clear and cleanup provider use */
+ ossl_provider_cleanup(data);
+ return CURLE_OK;
+ }
+ if(curlx_str_until(&iname, &prov, MAX_PROVIDER_LEN, ':'))
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+
+ if(!curlx_str_single(&iname, ':'))
+ /* there was a colon, get the propq until the end of string */
+ propq = iname;
+
+ /* we need the name in a buffer, null-terminated */
+ memcpy(name, curlx_str(&prov), curlx_strlen(&prov));
+ name[curlx_strlen(&prov)] = 0;
+
+ if(!data->state.libctx) {
+ OSSL_LIB_CTX *libctx = OSSL_LIB_CTX_new();
+ if(!libctx)
+ return CURLE_OUT_OF_MEMORY;
+ if(propq) {
+ data->state.propq = strdup(propq);
+ if(!data->state.propq) {
+ OSSL_LIB_CTX_free(libctx);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ }
+ data->state.libctx = libctx;
+ }
+
+ if(OSSL_PROVIDER_available(data->state.libctx, name)) {
+ /* already loaded through the configuration - no action needed */
+ data->state.provider_loaded = TRUE;
+ return CURLE_OK;
+ }
+
+ data->state.provider =
+ OSSL_PROVIDER_try_load(data->state.libctx, name, 1);
+ if(!data->state.provider) {
+ char error_buffer[256];
+ failf(data, "Failed to initialize provider: %s",
+ ossl_strerror(ERR_get_error(), error_buffer,
+ sizeof(error_buffer)));
+ ossl_provider_cleanup(data);
+ return CURLE_SSL_ENGINE_NOTFOUND;
+ }
+
+ /* load the base provider as well */
+ data->state.baseprov =
+ OSSL_PROVIDER_try_load(data->state.libctx, "base", 1);
+ if(!data->state.baseprov) {
+ ossl_provider_cleanup(data);
+ failf(data, "Failed to load base");
+ return CURLE_SSL_ENGINE_NOTFOUND;
+ }
+ else
+ data->state.provider_loaded = TRUE;
+ return CURLE_OK;
+}
+#endif
+
+
static CURLcode ossl_shutdown(struct Curl_cfilter *cf,
struct Curl_easy *data,
bool send_shutdown, bool *done)
@@ -2021,13 +2190,6 @@ static void ossl_close(struct Curl_cfilter *cf, struct Curl_easy *data) }
}
-static void ossl_session_free(void *sessionid, size_t idsize)
-{
- /* free the ID */
- (void)idsize;
- free(sessionid);
-}
-
/*
* This function is called when the 'data' struct is going away. Close
* down everything and free all resources!
@@ -2043,8 +2205,10 @@ static void ossl_close_all(struct Curl_easy *data) #else
(void)data;
#endif
-#if !defined(HAVE_ERR_REMOVE_THREAD_STATE_DEPRECATED) && \
- defined(HAVE_ERR_REMOVE_THREAD_STATE)
+#ifdef OPENSSL_HAS_PROVIDERS
+ ossl_provider_cleanup(data);
+#endif
+#ifndef HAVE_ERR_REMOVE_THREAD_STATE_DEPRECATED
/* OpenSSL 1.0.1 and 1.0.2 build an error queue that is stored per-thread
so we need to clean it here in case the thread will be killed. All OpenSSL
code should extract the error in association with the error so clearing
@@ -2121,14 +2285,14 @@ static CURLcode ossl_verifyhost(struct Curl_easy *data, hostlen = strlen(peer->hostname);
switch(peer->type) {
case CURL_SSL_PEER_IPV4:
- if(!Curl_inet_pton(AF_INET, peer->hostname, &addr))
+ if(!curlx_inet_pton(AF_INET, peer->hostname, &addr))
return CURLE_PEER_FAILED_VERIFICATION;
target = GEN_IPADD;
addrlen = sizeof(struct in_addr);
break;
#ifdef USE_IPV6
case CURL_SSL_PEER_IPV6:
- if(!Curl_inet_pton(AF_INET6, peer->hostname, &addr))
+ if(!curlx_inet_pton(AF_INET6, peer->hostname, &addr))
return CURLE_PEER_FAILED_VERIFICATION;
target = GEN_IPADD;
addrlen = sizeof(struct in6_addr);
@@ -2174,7 +2338,7 @@ static CURLcode ossl_verifyhost(struct Curl_easy *data, /* only check alternatives of the same type the target is */
if(check->type == target) {
/* get data and length */
- const char *altptr = (char *)ASN1_STRING_get0_data(check->d.ia5);
+ const char *altptr = (const char *)ASN1_STRING_get0_data(check->d.ia5);
size_t altlen = (size_t) ASN1_STRING_length(check->d.ia5);
switch(target) {
@@ -2260,7 +2424,7 @@ static CURLcode ossl_verifyhost(struct Curl_easy *data, if(tmp) {
if(ASN1_STRING_type(tmp) == V_ASN1_UTF8STRING) {
cnlen = ASN1_STRING_length(tmp);
- cn = (unsigned char *) ASN1_STRING_get0_data(tmp);
+ cn = (unsigned char *)CURL_UNCONST(ASN1_STRING_get0_data(tmp));
}
else { /* not a UTF8 name */
cnlen = ASN1_STRING_to_UTF8(&cn, tmp);
@@ -2302,14 +2466,13 @@ static CURLcode ossl_verifyhost(struct Curl_easy *data, return result;
}
-#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
- !defined(OPENSSL_NO_OCSP)
+#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_OCSP)
static CURLcode verifystatus(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct ossl_ctx *octx)
{
int i, ocsp_status;
-#if defined(OPENSSL_IS_AWSLC)
+#ifdef OPENSSL_IS_AWSLC
const uint8_t *status;
#else
unsigned char *status;
@@ -2368,34 +2531,6 @@ static CURLcode verifystatus(struct Curl_cfilter *cf, }
st = SSL_CTX_get_cert_store(octx->ssl_ctx);
-#if ((OPENSSL_VERSION_NUMBER <= 0x1000201fL) /* Fixed after 1.0.2a */ || \
- (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 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. */
-
- /* First make sure the peer cert chain includes both a peer and an issuer,
- and the OCSP response contains a responder cert. */
- if(sk_X509_num(ch) >= 2 && sk_X509_num(br->certs) >= 1) {
- X509 *responder = sk_X509_value(br->certs, sk_X509_num(br->certs) - 1);
-
- /* Find issuer of responder cert and add it to the OCSP response chain */
- for(i = 0; i < sk_X509_num(ch); i++) {
- X509 *issuer = sk_X509_value(ch, i);
- if(X509_check_issued(issuer, responder) == X509_V_OK) {
- if(!OCSP_basic_add1_cert(br, issuer)) {
- failf(data, "Could not add issuer cert to OCSP response");
- result = CURLE_SSL_INVALIDCERTSTATUS;
- goto end;
- }
- }
- }
- }
-#endif
-
if(OCSP_basic_verify(br, ch, st, 0) <= 0) {
failf(data, "OCSP response verification failed");
result = CURLE_SSL_INVALIDCERTSTATUS;
@@ -2667,15 +2802,15 @@ static void ossl_trace(int direction, int ssl_ver, int content_type, tls_rt_name = "";
if(content_type == SSL3_RT_CHANGE_CIPHER_SPEC) {
- msg_type = *(char *)buf;
+ msg_type = *(const char *)buf;
msg_name = "Change cipher spec";
}
else if(content_type == SSL3_RT_ALERT) {
- msg_type = (((char *)buf)[0] << 8) + ((char *)buf)[1];
+ msg_type = (((const char *)buf)[0] << 8) + ((const char *)buf)[1];
msg_name = SSL_alert_desc_string_long(msg_type);
}
else {
- msg_type = *(char *)buf;
+ msg_type = *(const char *)buf;
msg_name = ssl_msg_type(ssl_ver, msg_type);
}
@@ -2687,7 +2822,7 @@ static void ossl_trace(int direction, int ssl_ver, int content_type, }
Curl_debug(data, (direction == 1) ? CURLINFO_SSL_DATA_OUT :
- CURLINFO_SSL_DATA_IN, (char *)buf, len);
+ CURLINFO_SSL_DATA_IN, (const char *)buf, len);
(void) ssl;
}
#endif
@@ -2695,11 +2830,9 @@ static void ossl_trace(int direction, int ssl_ver, int content_type, #ifdef USE_OPENSSL
/* ====================================================== */
-/* Check for OpenSSL 1.0.2 which has ALPN support. */
-#undef HAS_ALPN
-#if OPENSSL_VERSION_NUMBER >= 0x10002000L \
- && !defined(OPENSSL_NO_TLSEXT)
-# define HAS_ALPN 1
+/* Check for ALPN support. */
+#ifndef OPENSSL_NO_TLSEXT
+# define HAS_ALPN_OPENSSL
#endif
#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) /* 1.1.0 */
@@ -2831,20 +2964,10 @@ ossl_set_ssl_version_min_max_legacy(ctx_option_t *ctx_options, #endif
FALLTHROUGH();
case CURL_SSLVERSION_TLSv1_2:
-#if OPENSSL_VERSION_NUMBER >= 0x1000100FL
*ctx_options |= SSL_OP_NO_TLSv1_1;
-#else
- failf(data, OSSL_PACKAGE " was built without TLS 1.2 support");
- return CURLE_NOT_BUILT_IN;
-#endif
FALLTHROUGH();
case CURL_SSLVERSION_TLSv1_1:
-#if OPENSSL_VERSION_NUMBER >= 0x1000100FL
*ctx_options |= SSL_OP_NO_TLSv1;
-#else
- failf(data, OSSL_PACKAGE " was built without TLS 1.1 support");
- return CURLE_NOT_BUILT_IN;
-#endif
FALLTHROUGH();
case CURL_SSLVERSION_TLSv1_0:
case CURL_SSLVERSION_TLSv1:
@@ -2853,14 +2976,10 @@ ossl_set_ssl_version_min_max_legacy(ctx_option_t *ctx_options, switch(ssl_version_max) {
case CURL_SSLVERSION_MAX_TLSv1_0:
-#if OPENSSL_VERSION_NUMBER >= 0x1000100FL
*ctx_options |= SSL_OP_NO_TLSv1_1;
-#endif
FALLTHROUGH();
case CURL_SSLVERSION_MAX_TLSv1_1:
-#if OPENSSL_VERSION_NUMBER >= 0x1000100FL
*ctx_options |= SSL_OP_NO_TLSv1_2;
-#endif
FALLTHROUGH();
case CURL_SSLVERSION_MAX_TLSv1_2:
#ifdef TLS1_3_VERSION
@@ -2881,20 +3000,27 @@ ossl_set_ssl_version_min_max_legacy(ctx_option_t *ctx_options, CURLcode Curl_ossl_add_session(struct Curl_cfilter *cf,
struct Curl_easy *data,
- const struct ssl_peer *peer,
- SSL_SESSION *session)
+ const char *ssl_peer_key,
+ SSL_SESSION *session,
+ int ietf_tls_id,
+ const char *alpn,
+ unsigned char *quic_tp,
+ size_t quic_tp_len)
{
const struct ssl_config_data *config;
+ unsigned char *der_session_buf = NULL;
+ unsigned char *qtp_clone = NULL;
CURLcode result = CURLE_OK;
- size_t der_session_size;
- unsigned char *der_session_buf;
- unsigned char *der_session_ptr;
if(!cf || !data)
goto out;
config = Curl_ssl_cf_get_config(cf, data);
if(config->primary.cache_session) {
+ struct Curl_ssl_session *sc_session = NULL;
+ size_t der_session_size;
+ unsigned char *der_session_ptr;
+ size_t earlydata_max = 0;
der_session_size = i2d_SSL_SESSION(session, NULL);
if(der_session_size == 0) {
@@ -2911,17 +3037,35 @@ CURLcode Curl_ossl_add_session(struct Curl_cfilter *cf, der_session_size = i2d_SSL_SESSION(session, &der_session_ptr);
if(der_session_size == 0) {
result = CURLE_OUT_OF_MEMORY;
- free(der_session_buf);
goto out;
}
- Curl_ssl_sessionid_lock(data);
- result = Curl_ssl_set_sessionid(cf, data, peer, NULL, der_session_buf,
- der_session_size, ossl_session_free);
- Curl_ssl_sessionid_unlock(data);
+#ifdef HAVE_OPENSSL_EARLYDATA
+ earlydata_max = SSL_SESSION_get_max_early_data(session);
+#endif
+ if(quic_tp && quic_tp_len) {
+ qtp_clone = Curl_memdup0((char *)quic_tp, quic_tp_len);
+ if(!qtp_clone) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto out;
+ }
+ }
+
+ result = Curl_ssl_session_create2(der_session_buf, der_session_size,
+ ietf_tls_id, alpn,
+ (curl_off_t)time(NULL) +
+ SSL_SESSION_get_timeout(session),
+ earlydata_max, qtp_clone, quic_tp_len,
+ &sc_session);
+ der_session_buf = NULL; /* took ownership of sdata */
+ if(!result) {
+ result = Curl_ssl_scache_put(cf, data, ssl_peer_key, sc_session);
+ /* took ownership of `sc_session` */
+ }
}
out:
+ free(der_session_buf);
return result;
}
@@ -2930,14 +3074,14 @@ out: */
static int ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid)
{
- struct Curl_cfilter *cf;
- struct Curl_easy *data;
- struct ssl_connect_data *connssl;
-
- cf = (struct Curl_cfilter*) SSL_get_app_data(ssl);
- connssl = cf ? cf->ctx : NULL;
- data = connssl ? CF_DATA_CURRENT(cf) : NULL;
- Curl_ossl_add_session(cf, data, &connssl->peer, ssl_sessionid);
+ struct Curl_cfilter *cf = (struct Curl_cfilter*) SSL_get_app_data(ssl);
+ if(cf) {
+ struct Curl_easy *data = CF_DATA_CURRENT(cf);
+ struct ssl_connect_data *connssl = cf->ctx;
+ Curl_ossl_add_session(cf, data, connssl->peer.scache_key, ssl_sessionid,
+ SSL_version(ssl), connssl->negotiated.alpn,
+ NULL, 0);
+ }
return 0;
}
@@ -2997,7 +3141,7 @@ static CURLcode load_cacert_from_memory(X509_STORE *store, return (count > 0) ? CURLE_OK : CURLE_SSL_CACERT_BADFILE;
}
-#if defined(USE_WIN32_CRYPTO)
+#ifdef USE_WIN32_CRYPTO
static CURLcode import_windows_cert_store(struct Curl_easy *data,
const char *name,
X509_STORE *store,
@@ -3141,9 +3285,9 @@ static CURLcode import_windows_cert_store(struct Curl_easy *data, }
#endif
-static CURLcode populate_x509_store(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- X509_STORE *store)
+static CURLcode ossl_populate_x509_store(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ X509_STORE *store)
{
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);
@@ -3159,13 +3303,13 @@ static CURLcode populate_x509_store(struct Curl_cfilter *cf, bool imported_native_ca = FALSE;
bool imported_ca_info_blob = FALSE;
- CURL_TRC_CF(data, cf, "populate_x509_store, path=%s, blob=%d",
+ CURL_TRC_CF(data, cf, "ossl_populate_x509_store, path=%s, blob=%d",
ssl_cafile ? ssl_cafile : "none", !!ca_info_blob);
if(!store)
return CURLE_OUT_OF_MEMORY;
if(verifypeer) {
-#if defined(USE_WIN32_CRYPTO)
+#ifdef USE_WIN32_CRYPTO
/* Import certificates from the Windows root certificate store if
requested.
https://stackoverflow.com/questions/9507184/
@@ -3177,7 +3321,7 @@ static CURLcode populate_x509_store(struct Curl_cfilter *cf, "CA" /* Intermediate Certification Authorities */
};
size_t i;
- for(i = 0; i < ARRAYSIZE(storeNames); ++i) {
+ for(i = 0; i < CURL_ARRAYSIZE(storeNames); ++i) {
bool imported = FALSE;
result = import_windows_cert_store(data, storeNames[i], store,
&imported);
@@ -3283,7 +3427,7 @@ static CURLcode populate_x509_store(struct Curl_cfilter *cf, https://web.archive.org/web/20190422050538/
rt.openssl.org/Ticket/Display.html?id=3621
*/
-#if defined(X509_V_FLAG_TRUSTED_FIRST)
+#ifdef X509_V_FLAG_TRUSTED_FIRST
X509_STORE_set_flags(store, X509_V_FLAG_TRUSTED_FIRST);
#endif
#ifdef X509_V_FLAG_PARTIAL_CHAIN
@@ -3304,7 +3448,7 @@ static CURLcode populate_x509_store(struct Curl_cfilter *cf, return result;
}
-#if defined(HAVE_SSL_X509_STORE_SHARE)
+#ifdef HAVE_SSL_X509_STORE_SHARE
/* key to use at `multi->proto_hash` */
#define MPROTO_OSSL_X509_KEY "tls:ossl:x509:share"
@@ -3330,15 +3474,15 @@ static void oss_x509_share_free(void *key, size_t key_len, void *p) }
static bool
-cached_x509_store_expired(const struct Curl_easy *data,
- const struct ossl_x509_share *mb)
+ossl_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);
+ struct curltime now = curlx_now();
+ timediff_t elapsed_ms = curlx_timediff(now, mb->time);
timediff_t timeout_ms = cfg->ca_cache_timeout * (timediff_t)1000;
return elapsed_ms >= timeout_ms;
@@ -3346,8 +3490,8 @@ cached_x509_store_expired(const struct Curl_easy *data, }
static bool
-cached_x509_store_different(struct Curl_cfilter *cf,
- const struct ossl_x509_share *mb)
+ossl_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)
@@ -3356,8 +3500,8 @@ cached_x509_store_different(struct Curl_cfilter *cf, return strcmp(mb->CAfile, conn_config->CAfile);
}
-static X509_STORE *get_cached_x509_store(struct Curl_cfilter *cf,
- const struct Curl_easy *data)
+static X509_STORE *ossl_get_cached_x509_store(struct Curl_cfilter *cf,
+ const struct Curl_easy *data)
{
struct Curl_multi *multi = data->multi;
struct ossl_x509_share *share;
@@ -3365,20 +3509,20 @@ static X509_STORE *get_cached_x509_store(struct Curl_cfilter *cf, DEBUGASSERT(multi);
share = multi ? Curl_hash_pick(&multi->proto_hash,
- (void *)MPROTO_OSSL_X509_KEY,
+ CURL_UNCONST(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)) {
+ !ossl_cached_x509_store_expired(data, share) &&
+ !ossl_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)
+static void ossl_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;
@@ -3388,7 +3532,7 @@ static void set_cached_x509_store(struct Curl_cfilter *cf, if(!multi)
return;
share = Curl_hash_pick(&multi->proto_hash,
- (void *)MPROTO_OSSL_X509_KEY,
+ CURL_UNCONST(MPROTO_OSSL_X509_KEY),
sizeof(MPROTO_OSSL_X509_KEY)-1);
if(!share) {
@@ -3396,7 +3540,7 @@ static void set_cached_x509_store(struct Curl_cfilter *cf, if(!share)
return;
if(!Curl_hash_add2(&multi->proto_hash,
- (void *)MPROTO_OSSL_X509_KEY,
+ CURL_UNCONST(MPROTO_OSSL_X509_KEY),
sizeof(MPROTO_OSSL_X509_KEY)-1,
share, oss_x509_share_free)) {
free(share);
@@ -3420,7 +3564,7 @@ static void set_cached_x509_store(struct Curl_cfilter *cf, free(share->CAfile);
}
- share->time = Curl_now();
+ share->time = curlx_now();
share->store = store;
share->CAfile = CAfile;
}
@@ -3446,16 +3590,16 @@ CURLcode Curl_ssl_setup_x509_store(struct Curl_cfilter *cf, !ssl_config->primary.CRLfile &&
!ssl_config->native_ca_store;
- cached_store = get_cached_x509_store(cf, data);
+ cached_store = ossl_get_cached_x509_store(cf, data);
if(cached_store && cache_criteria_met && X509_STORE_up_ref(cached_store)) {
SSL_CTX_set_cert_store(ssl_ctx, cached_store);
}
else {
X509_STORE *store = SSL_CTX_get_cert_store(ssl_ctx);
- result = populate_x509_store(cf, data, store);
+ result = ossl_populate_x509_store(cf, data, store);
if(result == CURLE_OK && cache_criteria_met) {
- set_cached_x509_store(cf, data, store);
+ ossl_set_cached_x509_store(cf, data, store);
}
}
@@ -3468,48 +3612,303 @@ CURLcode Curl_ssl_setup_x509_store(struct Curl_cfilter *cf, {
X509_STORE *store = SSL_CTX_get_cert_store(ssl_ctx);
- return populate_x509_store(cf, data, store);
+ return ossl_populate_x509_store(cf, data, store);
}
#endif /* HAVE_SSL_X509_STORE_SHARE */
-CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx,
+
+static CURLcode
+ossl_init_session_and_alpns(struct ossl_ctx *octx,
struct Curl_cfilter *cf,
struct Curl_easy *data,
struct ssl_peer *peer,
- int transport, /* TCP or QUIC */
- const unsigned char *alpn, size_t alpn_len,
- Curl_ossl_ctx_setup_cb *cb_setup,
- void *cb_user_data,
- Curl_ossl_new_session_cb *cb_new_session,
- void *ssl_user_data)
+ const struct alpn_spec *alpns_requested,
+ Curl_ossl_init_session_reuse_cb *sess_reuse_cb)
{
- CURLcode result = CURLE_OK;
- const char *ciphers;
- SSL_METHOD_QUAL SSL_METHOD *req_method = NULL;
- ctx_option_t ctx_options = 0;
- SSL_SESSION *ssl_session = NULL;
- const unsigned char *der_sessionid = NULL;
- size_t der_sessionid_size = 0;
- 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_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;
+ struct alpn_spec alpns;
char error_buffer[256];
+ CURLcode result;
- /* Make funny stuff to get random input */
- result = ossl_seed(data);
- if(result)
- return result;
+ Curl_alpn_copy(&alpns, alpns_requested);
- ssl_config->certverifyresult = !X509_V_OK;
+ octx->reused_session = FALSE;
+ if(ssl_config->primary.cache_session) {
+ struct Curl_ssl_session *scs = NULL;
+
+ result = Curl_ssl_scache_take(cf, data, peer->scache_key, &scs);
+ if(!result && scs && scs->sdata && scs->sdata_len) {
+ const unsigned char *der_sessionid = scs->sdata;
+ size_t der_sessionid_size = scs->sdata_len;
+ SSL_SESSION *ssl_session = NULL;
+
+ /* If OpenSSL does not accept the session from the cache, this
+ * is not an error. We just continue without it. */
+ ssl_session = d2i_SSL_SESSION(NULL, &der_sessionid,
+ (long)der_sessionid_size);
+ if(ssl_session) {
+ if(!SSL_set_session(octx->ssl, ssl_session)) {
+ infof(data, "SSL: SSL_set_session not accepted, "
+ "continuing without: %s",
+ ossl_strerror(ERR_get_error(), error_buffer,
+ sizeof(error_buffer)));
+ }
+ else {
+ infof(data, "SSL reusing session with ALPN '%s'",
+ scs->alpn ? scs->alpn : "-");
+ octx->reused_session = TRUE;
+#ifdef HAVE_OPENSSL_EARLYDATA
+ if(ssl_config->earlydata && scs->alpn &&
+ SSL_SESSION_get_max_early_data(ssl_session) &&
+ !cf->conn->connect_only &&
+ (SSL_version(octx->ssl) == TLS1_3_VERSION)) {
+ bool do_early_data = FALSE;
+ if(sess_reuse_cb) {
+ result = sess_reuse_cb(cf, data, &alpns, scs, &do_early_data);
+ if(result)
+ return result;
+ }
+ if(do_early_data) {
+ /* We only try the ALPN protocol the session used before,
+ * otherwise we might send early data for the wrong protocol */
+ Curl_alpn_restrict_to(&alpns, scs->alpn);
+ }
+ }
+#else
+ (void)sess_reuse_cb;
+#endif
+ }
+ SSL_SESSION_free(ssl_session);
+ }
+ else {
+ infof(data, "SSL session not accepted by OpenSSL, continuing without");
+ }
+ }
+ Curl_ssl_scache_return(cf, data, peer->scache_key, scs);
+ }
+
+#ifdef HAS_ALPN_OPENSSL
+ if(alpns.count) {
+ struct alpn_proto_buf proto;
+ memset(&proto, 0, sizeof(proto));
+ result = Curl_alpn_to_proto_buf(&proto, &alpns);
+ if(result) {
+ failf(data, "Error determining ALPN");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ if(SSL_set_alpn_protos(octx->ssl, proto.data, (int)proto.len)) {
+ failf(data, "Error setting ALPN");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ }
+#endif
+
+ return CURLE_OK;
+}
+
+#ifdef USE_ECH_OPENSSL
+static CURLcode ossl_init_ech(struct ossl_ctx *octx,
+ struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct ssl_peer *peer)
+{
+ unsigned char *ech_config = NULL;
+ size_t ech_config_len = 0;
+ char *outername = data->set.str[STRING_ECH_PUBLIC];
+ int trying_ech_now = 0;
+ CURLcode result;
+
+ if(!ECH_ENABLED(data))
+ return CURLE_OK;
+
+ if(data->set.tls_ech & CURLECH_GREASE) {
+ infof(data, "ECH: will GREASE ClientHello");
+# if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)
+ SSL_set_enable_ech_grease(octx->ssl, 1);
+# else
+ SSL_set_options(octx->ssl, SSL_OP_ECH_GREASE);
+# endif
+ }
+ else if(data->set.tls_ech & CURLECH_CLA_CFG) {
+# if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)
+ /* have to do base64 decode here for BoringSSL */
+ const char *b64 = data->set.str[STRING_ECH_CONFIG];
- switch(transport) {
+ if(!b64) {
+ infof(data, "ECH: ECHConfig from command line empty");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ ech_config_len = 2 * strlen(b64);
+ result = curlx_base64_decode(b64, &ech_config, &ech_config_len);
+ if(result || !ech_config) {
+ infof(data, "ECH: cannot base64 decode ECHConfig from command line");
+ if(data->set.tls_ech & CURLECH_HARD)
+ return result;
+ }
+ if(SSL_set1_ech_config_list(octx->ssl, ech_config,
+ ech_config_len) != 1) {
+ infof(data, "ECH: SSL_ECH_set1_ech_config_list failed");
+ if(data->set.tls_ech & CURLECH_HARD) {
+ free(ech_config);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ }
+ free(ech_config);
+ trying_ech_now = 1;
+# else
+ ech_config = (unsigned char *) data->set.str[STRING_ECH_CONFIG];
+ if(!ech_config) {
+ infof(data, "ECH: ECHConfig from command line empty");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ ech_config_len = strlen(data->set.str[STRING_ECH_CONFIG]);
+ if(SSL_set1_ech_config_list(octx->ssl, ech_config,
+ ech_config_len) != 1) {
+ infof(data, "ECH: SSL_ECH_set1_ech_config_list failed");
+ if(data->set.tls_ech & CURLECH_HARD)
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ else
+ trying_ech_now = 1;
+# endif
+ infof(data, "ECH: ECHConfig from command line");
+ }
+ else {
+ struct Curl_dns_entry *dns = NULL;
+
+ if(peer->hostname)
+ dns = Curl_dnscache_get(data, peer->hostname, peer->port,
+ cf->conn->ip_version);
+ if(!dns) {
+ infof(data, "ECH: requested but no DNS info available");
+ if(data->set.tls_ech & CURLECH_HARD)
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ else {
+ struct Curl_https_rrinfo *rinfo = NULL;
+
+ rinfo = dns->hinfo;
+ if(rinfo && rinfo->echconfiglist) {
+ unsigned char *ecl = rinfo->echconfiglist;
+ size_t elen = rinfo->echconfiglist_len;
+
+ infof(data, "ECH: ECHConfig from DoH HTTPS RR");
+ if(SSL_set1_ech_config_list(octx->ssl, ecl, elen) != 1) {
+ infof(data, "ECH: SSL_set1_ech_config_list failed");
+ if(data->set.tls_ech & CURLECH_HARD)
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ else {
+ trying_ech_now = 1;
+ infof(data, "ECH: imported ECHConfigList of length %zu", elen);
+ }
+ }
+ else {
+ infof(data, "ECH: requested but no ECHConfig available");
+ if(data->set.tls_ech & CURLECH_HARD)
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ Curl_resolv_unlink(data, &dns);
+ }
+ }
+# if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)
+ if(trying_ech_now && outername) {
+ infof(data, "ECH: setting public_name not supported with BoringSSL");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+# else
+ if(trying_ech_now && outername) {
+ infof(data, "ECH: inner: '%s', outer: '%s'",
+ peer->hostname ? peer->hostname : "NULL", outername);
+ result = SSL_ech_set1_server_names(octx->ssl,
+ peer->hostname, outername,
+ 0 /* do send outer */);
+ if(result != 1) {
+ infof(data, "ECH: rv failed to set server name(s) %d [ERROR]", result);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ }
+# endif /* OPENSSL_IS_BORINGSSL || OPENSSL_IS_AWSLC */
+ if(trying_ech_now
+ && SSL_set_min_proto_version(octx->ssl, TLS1_3_VERSION) != 1) {
+ infof(data, "ECH: cannot force TLSv1.3 [ERROR]");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ return CURLE_OK;
+}
+#endif /* USE_ECH_OPENSSL */
+
+
+static CURLcode ossl_init_ssl(struct ossl_ctx *octx,
+ struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct ssl_peer *peer,
+ const struct alpn_spec *alpns_requested,
+ void *ssl_user_data,
+ Curl_ossl_init_session_reuse_cb *sess_reuse_cb)
+{
+ /* Let's make an SSL structure */
+ if(octx->ssl)
+ SSL_free(octx->ssl);
+ octx->ssl = SSL_new(octx->ssl_ctx);
+ if(!octx->ssl) {
+ failf(data, "SSL: could not create a context (handle)");
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ SSL_set_app_data(octx->ssl, ssl_user_data);
+
+#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_OCSP)
+ if(Curl_ssl_cf_get_primary_config(cf)->verifystatus)
+ SSL_set_tlsext_status_type(octx->ssl, TLSEXT_STATUSTYPE_ocsp);
+#endif
+
+#if (defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)) && \
+ defined(ALLOW_RENEG)
+ SSL_set_renegotiate_mode(octx->ssl, ssl_renegotiate_freely);
+#endif
+
+ SSL_set_connect_state(octx->ssl);
+
+ octx->server_cert = NULL;
+#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
+ if(peer->sni) {
+ if(!SSL_set_tlsext_host_name(octx->ssl, peer->sni)) {
+ failf(data, "Failed set SNI");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ }
+
+#ifdef USE_ECH_OPENSSL
+ {
+ CURLcode result = ossl_init_ech(octx, cf, data, peer);
+ if(result)
+ return result;
+ }
+#endif /* USE_ECH_OPENSSL */
+
+#endif
+
+ return ossl_init_session_and_alpns(octx, cf, data, peer,
+ alpns_requested, sess_reuse_cb);
+}
+
+
+static CURLcode ossl_init_method(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct ssl_peer *peer,
+ const SSL_METHOD **pmethod,
+ unsigned int *pssl_version_min)
+{
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+
+ *pmethod = NULL;
+ *pssl_version_min = conn_config->version;
+ switch(peer->transport) {
case TRNSPRT_TCP:
/* check to see if we have been told to use an explicit SSL/TLS version */
- switch(ssl_version_min) {
+ switch(*pssl_version_min) {
case CURL_SSLVERSION_DEFAULT:
case CURL_SSLVERSION_TLSv1:
case CURL_SSLVERSION_TLSv1_0:
@@ -3518,9 +3917,9 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx, case CURL_SSLVERSION_TLSv1_3:
/* it will be handled later with the context options */
#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
- req_method = TLS_client_method();
+ *pmethod = TLS_client_method();
#else
- req_method = SSLv23_client_method();
+ *pmethod = SSLv23_client_method();
#endif
break;
case CURL_SSLVERSION_SSLv2:
@@ -3535,6 +3934,7 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx, }
break;
case TRNSPRT_QUIC:
+ *pssl_version_min = 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");
@@ -3542,21 +3942,65 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx, }
#ifdef USE_OPENSSL_QUIC
- req_method = OSSL_QUIC_client_method();
+ *pmethod = OSSL_QUIC_client_method();
#elif (OPENSSL_VERSION_NUMBER >= 0x10100000L)
- req_method = TLS_method();
+ *pmethod = TLS_method();
#else
- req_method = SSLv23_client_method();
+ *pmethod = SSLv23_client_method();
#endif
break;
default:
- failf(data, "unsupported transport %d in SSL init", transport);
+ failf(data, "unsupported transport %d in SSL init", peer->transport);
return CURLE_SSL_CONNECT_ERROR;
}
+ return *pmethod ? CURLE_OK : CURLE_SSL_CONNECT_ERROR;
+}
+
+
+CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx,
+ struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct ssl_peer *peer,
+ const struct alpn_spec *alpns_requested,
+ Curl_ossl_ctx_setup_cb *cb_setup,
+ void *cb_user_data,
+ Curl_ossl_new_session_cb *cb_new_session,
+ void *ssl_user_data,
+ Curl_ossl_init_session_reuse_cb *sess_reuse_cb)
+{
+ CURLcode result = CURLE_OK;
+ const char *ciphers;
+ const SSL_METHOD *req_method = NULL;
+ ctx_option_t ctx_options = 0;
+ 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);
+ 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;
+ unsigned int ssl_version_min;
+ char error_buffer[256];
+
+ /* Make funny stuff to get random input */
+ result = ossl_seed(data);
+ if(result)
+ return result;
+
+ ssl_config->certverifyresult = !X509_V_OK;
+
+ result = ossl_init_method(cf, data, peer, &req_method, &ssl_version_min);
+ if(result)
+ return result;
+ DEBUGASSERT(req_method);
DEBUGASSERT(!octx->ssl_ctx);
- octx->ssl_ctx = SSL_CTX_new(req_method);
+ octx->ssl_ctx =
+#ifdef OPENSSL_HAS_PROVIDERS
+ data->state.libctx ?
+ SSL_CTX_new_ex(data->state.libctx, data->state.propq, req_method):
+#endif
+ SSL_CTX_new(req_method);
if(!octx->ssl_ctx) {
failf(data, "SSL: could not create a context: %s",
@@ -3606,7 +4050,7 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx, CVE-2010-4180 when using previous OpenSSL versions we no longer enable
this option regardless of OpenSSL version and SSL_OP_ALL definition.
- OpenSSL added a work-around for a SSL 3.0/TLS 1.0 CBC vulnerability:
+ OpenSSL added a work-around for an SSL 3.0/TLS 1.0 CBC vulnerability:
https://web.archive.org/web/20240114184648/openssl.org/~bodo/tls-cbc.txt.
In 0.9.6e they added a bit to SSL_OP_ALL that _disables_ that work-around
despite the fact that SSL_OP_ALL is documented to do "rather harmless"
@@ -3674,31 +4118,10 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx, SSL_CTX_set_mode(octx->ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
#endif
-#ifdef HAS_ALPN
- if(alpn && alpn_len) {
- if(SSL_CTX_set_alpn_protos(octx->ssl_ctx, alpn, (int)alpn_len)) {
- failf(data, "Error setting ALPN");
- return CURLE_SSL_CONNECT_ERROR;
- }
- }
-#endif
-
- if(ssl_cert || ssl_cert_blob || ssl_cert_type) {
- if(!result &&
- !cert_stuff(data, octx->ssl_ctx,
- ssl_cert, ssl_cert_blob, ssl_cert_type,
- ssl_config->key, ssl_config->key_blob,
- ssl_config->key_type, ssl_config->key_passwd))
- result = CURLE_SSL_CERTPROBLEM;
- if(result)
- /* failf() is already done in cert_stuff() */
- return result;
- }
-
ciphers = conn_config->cipher_list;
if(!ciphers && (peer->transport != TRNSPRT_QUIC))
ciphers = DEFAULT_CIPHER_SELECTION;
- if(ciphers) {
+ if(ciphers && (ssl_version_min < CURL_SSLVERSION_TLSv1_3)) {
if(!SSL_CTX_set_cipher_list(octx->ssl_ctx, ciphers)) {
failf(data, "failed setting cipher list: %s", ciphers);
return CURLE_SSL_CIPHER;
@@ -3709,7 +4132,9 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx, #ifdef HAVE_SSL_CTX_SET_CIPHERSUITES
{
const char *ciphers13 = conn_config->cipher_list13;
- if(ciphers13) {
+ if(ciphers13 &&
+ (!conn_config->version_max ||
+ (conn_config->version_max >= CURL_SSLVERSION_MAX_TLSv1_3))) {
if(!SSL_CTX_set_ciphersuites(octx->ssl_ctx, ciphers13)) {
failf(data, "failed setting TLS 1.3 cipher suite: %s", ciphers13);
return CURLE_SSL_CIPHER;
@@ -3719,21 +4144,51 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx, }
#endif
+ if(ssl_cert || ssl_cert_blob || ssl_cert_type) {
+ if(!result &&
+ !cert_stuff(data, octx->ssl_ctx,
+ ssl_cert, ssl_cert_blob, ssl_cert_type,
+ ssl_config->key, ssl_config->key_blob,
+ ssl_config->key_type, ssl_config->key_passwd))
+ result = CURLE_SSL_CERTPROBLEM;
+ if(result)
+ /* failf() is already done in cert_stuff() */
+ return result;
+ }
+
#ifdef HAVE_SSL_CTX_SET_POST_HANDSHAKE_AUTH
/* OpenSSL 1.1.1 requires clients to opt-in for PHA */
SSL_CTX_set_post_handshake_auth(octx->ssl_ctx, 1);
#endif
-#ifdef HAVE_SSL_CTX_SET_EC_CURVES
{
const char *curves = conn_config->curves;
if(curves) {
- if(!SSL_CTX_set1_curves_list(octx->ssl_ctx, curves)) {
+#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)
+#define OSSL_CURVE_CAST(x) (x)
+#else
+#define OSSL_CURVE_CAST(x) (char *)CURL_UNCONST(x)
+#endif
+ if(!SSL_CTX_set1_curves_list(octx->ssl_ctx, OSSL_CURVE_CAST(curves))) {
failf(data, "failed setting curves list: '%s'", curves);
return CURLE_SSL_CIPHER;
}
}
}
+
+#ifdef HAVE_SSL_CTX_SET1_SIGALGS
+#define OSSL_SIGALG_CAST(x) OSSL_CURVE_CAST(x)
+ {
+ const char *signature_algorithms = conn_config->signature_algorithms;
+ if(signature_algorithms) {
+ if(!SSL_CTX_set1_sigalgs_list(octx->ssl_ctx,
+ OSSL_SIGALG_CAST(signature_algorithms))) {
+ failf(data, "failed setting signature algorithms: '%s'",
+ signature_algorithms);
+ return CURLE_SSL_CIPHER;
+ }
+ }
+ }
#endif
#ifdef USE_OPENSSL_SRP
@@ -3807,201 +4262,38 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx, }
}
- /* Let's make an SSL structure */
- if(octx->ssl)
- SSL_free(octx->ssl);
- octx->ssl = SSL_new(octx->ssl_ctx);
- if(!octx->ssl) {
- failf(data, "SSL: could not create a context (handle)");
- return CURLE_OUT_OF_MEMORY;
- }
-
- SSL_set_app_data(octx->ssl, ssl_user_data);
-
-#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
- !defined(OPENSSL_NO_OCSP)
- if(conn_config->verifystatus)
- SSL_set_tlsext_status_type(octx->ssl, TLSEXT_STATUSTYPE_ocsp);
-#endif
-
-#if (defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)) && \
- defined(ALLOW_RENEG)
- SSL_set_renegotiate_mode(octx->ssl, ssl_renegotiate_freely);
-#endif
+ return ossl_init_ssl(octx, cf, data, peer, alpns_requested,
+ ssl_user_data, sess_reuse_cb);
+}
- SSL_set_connect_state(octx->ssl);
+static CURLcode ossl_on_session_reuse(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct alpn_spec *alpns,
+ struct Curl_ssl_session *scs,
+ bool *do_early_data)
+{
+ struct ssl_connect_data *connssl = cf->ctx;
+ CURLcode result = CURLE_OK;
- octx->server_cert = 0x0;
-#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
- if(peer->sni) {
- if(!SSL_set_tlsext_host_name(octx->ssl, peer->sni)) {
- failf(data, "Failed set SNI");
- return CURLE_SSL_CONNECT_ERROR;
- }
+ *do_early_data = FALSE;
+ connssl->earlydata_max = scs->earlydata_max;
+ if(!connssl->earlydata_max) {
+ CURL_TRC_CF(data, cf, "SSL session does not allow earlydata");
}
-
-#ifdef USE_ECH
- if(ECH_ENABLED(data)) {
- unsigned char *ech_config = NULL;
- size_t ech_config_len = 0;
- char *outername = data->set.str[STRING_ECH_PUBLIC];
- int trying_ech_now = 0;
-
- if(data->set.tls_ech & CURLECH_GREASE) {
- infof(data, "ECH: will GREASE ClientHello");
-# ifdef OPENSSL_IS_BORINGSSL
- SSL_set_enable_ech_grease(octx->ssl, 1);
-# else
- SSL_set_options(octx->ssl, SSL_OP_ECH_GREASE);
-# endif
- }
- else if(data->set.tls_ech & CURLECH_CLA_CFG) {
-# ifdef OPENSSL_IS_BORINGSSL
- /* have to do base64 decode here for boring */
- const char *b64 = data->set.str[STRING_ECH_CONFIG];
-
- if(!b64) {
- infof(data, "ECH: ECHConfig from command line empty");
- return CURLE_SSL_CONNECT_ERROR;
- }
- ech_config_len = 2 * strlen(b64);
- result = Curl_base64_decode(b64, &ech_config, &ech_config_len);
- if(result || !ech_config) {
- infof(data, "ECH: cannot base64 decode ECHConfig from command line");
- if(data->set.tls_ech & CURLECH_HARD)
- return result;
- }
- if(SSL_set1_ech_config_list(octx->ssl, ech_config,
- ech_config_len) != 1) {
- infof(data, "ECH: SSL_ECH_set1_echconfig failed");
- if(data->set.tls_ech & CURLECH_HARD) {
- free(ech_config);
- return CURLE_SSL_CONNECT_ERROR;
- }
- }
- free(ech_config);
- trying_ech_now = 1;
-# else
- ech_config = (unsigned char *) data->set.str[STRING_ECH_CONFIG];
- if(!ech_config) {
- infof(data, "ECH: ECHConfig from command line empty");
- return CURLE_SSL_CONNECT_ERROR;
- }
- ech_config_len = strlen(data->set.str[STRING_ECH_CONFIG]);
- if(SSL_ech_set1_echconfig(octx->ssl, ech_config, ech_config_len) != 1) {
- infof(data, "ECH: SSL_ECH_set1_echconfig failed");
- if(data->set.tls_ech & CURLECH_HARD)
- return CURLE_SSL_CONNECT_ERROR;
- }
- else
- trying_ech_now = 1;
-# endif
- infof(data, "ECH: ECHConfig from command line");
- }
- else {
- struct Curl_dns_entry *dns = NULL;
-
- 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)
- return CURLE_SSL_CONNECT_ERROR;
- }
- else {
- struct Curl_https_rrinfo *rinfo = NULL;
-
- rinfo = dns->hinfo;
- if(rinfo && rinfo->echconfiglist) {
- unsigned char *ecl = rinfo->echconfiglist;
- size_t elen = rinfo->echconfiglist_len;
-
- infof(data, "ECH: ECHConfig from DoH HTTPS RR");
-# ifndef OPENSSL_IS_BORINGSSL
- if(SSL_ech_set1_echconfig(octx->ssl, ecl, elen) != 1) {
- infof(data, "ECH: SSL_ECH_set1_echconfig failed");
- if(data->set.tls_ech & CURLECH_HARD)
- return CURLE_SSL_CONNECT_ERROR;
- }
-# else
- if(SSL_set1_ech_config_list(octx->ssl, ecl, elen) != 1) {
- infof(data, "ECH: SSL_set1_ech_config_list failed (boring)");
- if(data->set.tls_ech & CURLECH_HARD)
- return CURLE_SSL_CONNECT_ERROR;
- }
-# endif
- else {
- trying_ech_now = 1;
- infof(data, "ECH: imported ECHConfigList of length %zu", elen);
- }
- }
- else {
- infof(data, "ECH: requested but no ECHConfig available");
- if(data->set.tls_ech & CURLECH_HARD)
- return CURLE_SSL_CONNECT_ERROR;
- }
- Curl_resolv_unlink(data, &dns);
- }
- }
-# ifdef OPENSSL_IS_BORINGSSL
- if(trying_ech_now && outername) {
- infof(data, "ECH: setting public_name not supported with BoringSSL");
- return CURLE_SSL_CONNECT_ERROR;
- }
-# else
- if(trying_ech_now && outername) {
- infof(data, "ECH: inner: '%s', outer: '%s'",
- peer->hostname ? peer->hostname : "NULL", outername);
- result = SSL_ech_set_server_names(octx->ssl,
- peer->hostname, outername,
- 0 /* do send outer */);
- if(result != 1) {
- infof(data, "ECH: rv failed to set server name(s) %d [ERROR]", result);
- return CURLE_SSL_CONNECT_ERROR;
- }
- }
-# endif /* not BORING */
- if(trying_ech_now
- && SSL_set_min_proto_version(octx->ssl, TLS1_3_VERSION) != 1) {
- infof(data, "ECH: cannot force TLSv1.3 [ERROR]");
- return CURLE_SSL_CONNECT_ERROR;
- }
+ else if(!Curl_alpn_contains_proto(alpns, scs->alpn)) {
+ CURL_TRC_CF(data, cf, "SSL session has different ALPN, no early data");
}
-#endif /* USE_ECH */
-
-#endif
-
- octx->reused_session = FALSE;
- if(ssl_config->primary.cache_session) {
- Curl_ssl_sessionid_lock(data);
- if(!Curl_ssl_getsessionid(cf, data, peer, (void **)&der_sessionid,
- &der_sessionid_size, NULL)) {
- /* we got a session id, use it! */
- ssl_session = d2i_SSL_SESSION(NULL, &der_sessionid,
- (long)der_sessionid_size);
- if(ssl_session) {
- if(!SSL_set_session(octx->ssl, ssl_session)) {
- Curl_ssl_sessionid_unlock(data);
- SSL_SESSION_free(ssl_session);
- failf(data, "SSL: SSL_set_session failed: %s",
- ossl_strerror(ERR_get_error(), error_buffer,
- sizeof(error_buffer)));
- return CURLE_SSL_CONNECT_ERROR;
- }
- SSL_SESSION_free(ssl_session);
- /* Informational message */
- infof(data, "SSL reusing session ID");
- octx->reused_session = TRUE;
- }
- else {
- Curl_ssl_sessionid_unlock(data);
- return CURLE_SSL_CONNECT_ERROR;
- }
- }
- Curl_ssl_sessionid_unlock(data);
+ else {
+ infof(data, "SSL session allows %zu bytes of early data, "
+ "reusing ALPN '%s'", connssl->earlydata_max, scs->alpn);
+ connssl->earlydata_state = ssl_earlydata_await;
+ connssl->state = ssl_connection_deferred;
+ result = Curl_alpn_set_negotiated(cf, data, connssl,
+ (const unsigned char *)scs->alpn,
+ scs->alpn ? strlen(scs->alpn) : 0);
+ *do_early_data = !result;
}
-
- return CURLE_OK;
+ return result;
}
static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,
@@ -4009,26 +4301,16 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf, {
struct ssl_connect_data *connssl = cf->ctx;
struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
- struct alpn_proto_buf proto;
BIO *bio;
CURLcode result;
DEBUGASSERT(ssl_connect_1 == connssl->connecting_state);
DEBUGASSERT(octx);
- memset(&proto, 0, sizeof(proto));
-#ifdef HAS_ALPN
- if(connssl->alpn) {
- result = Curl_alpn_to_proto_buf(&proto, connssl->alpn);
- if(result) {
- failf(data, "Error determining ALPN");
- return CURLE_SSL_CONNECT_ERROR;
- }
- }
-#endif
- result = Curl_ossl_ctx_init(octx, cf, data, &connssl->peer, TRNSPRT_TCP,
- proto.data, proto.len, NULL, NULL,
- ossl_new_session_cb, cf);
+ result = Curl_ossl_ctx_init(octx, cf, data, &connssl->peer,
+ connssl->alpn, NULL, NULL,
+ ossl_new_session_cb, cf,
+ ossl_on_session_reuse);
if(result)
return result;
@@ -4053,8 +4335,10 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf, SSL_set_bio(octx->ssl, bio, bio);
#endif
-#ifdef HAS_ALPN
- if(connssl->alpn) {
+#ifdef HAS_ALPN_OPENSSL
+ if(connssl->alpn && (connssl->state != ssl_connection_deferred)) {
+ struct alpn_proto_buf proto;
+ memset(&proto, 0, sizeof(proto));
Curl_alpn_to_proto_str(&proto, connssl->alpn);
infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data);
}
@@ -4063,7 +4347,7 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf, return CURLE_OK;
}
-#ifdef USE_ECH
+#ifdef USE_ECH_OPENSSL
/* If we have retry configs, then trace those out */
static void ossl_trace_ech_retry_configs(struct Curl_easy *data, SSL* ssl,
int reason)
@@ -4071,7 +4355,7 @@ static void ossl_trace_ech_retry_configs(struct Curl_easy *data, SSL* ssl, CURLcode result = CURLE_OK;
size_t rcl = 0;
int rv = 1;
-# ifndef OPENSSL_IS_BORINGSSL
+# if !defined(OPENSSL_IS_BORINGSSL) && !defined(OPENSSL_IS_AWSLC)
char *inner = NULL;
unsigned char *rcs = NULL;
char *outer = NULL;
@@ -4086,40 +4370,38 @@ static void ossl_trace_ech_retry_configs(struct Curl_easy *data, SSL* ssl, /* nothing to trace if not doing ECH */
if(!ECH_ENABLED(data))
return;
-# ifndef OPENSSL_IS_BORINGSSL
- rv = SSL_ech_get_retry_config(ssl, &rcs, &rcl);
+# if !defined(OPENSSL_IS_BORINGSSL) && !defined(OPENSSL_IS_AWSLC)
+ rv = SSL_ech_get1_retry_config(ssl, &rcs, &rcl);
# else
SSL_get0_ech_retry_configs(ssl, &rcs, &rcl);
rv = (int)rcl;
# endif
if(rv && rcs) {
-# define HEXSTR_MAX 800
char *b64str = NULL;
size_t blen = 0;
- result = Curl_base64_encode((const char *)rcs, rcl,
- &b64str, &blen);
- if(!result && b64str)
+ result = curlx_base64_encode((const char *)rcs, rcl, &b64str, &blen);
+ if(!result && b64str) {
infof(data, "ECH: retry_configs %s", b64str);
- free(b64str);
-# ifndef OPENSSL_IS_BORINGSSL
- rv = SSL_ech_get_status(ssl, &inner, &outer);
- infof(data, "ECH: retry_configs for %s from %s, %d %d",
- inner ? inner : "NULL", outer ? outer : "NULL", reason, rv);
+ free(b64str);
+#if !defined(OPENSSL_IS_BORINGSSL) && !defined(OPENSSL_IS_AWSLC)
+ rv = SSL_ech_get1_status(ssl, &inner, &outer);
+ infof(data, "ECH: retry_configs for %s from %s, %d %d",
+ inner ? inner : "NULL", outer ? outer : "NULL", reason, rv);
#else
- rv = SSL_ech_accepted(ssl);
- servername_type = SSL_get_servername_type(ssl);
- inner = SSL_get_servername(ssl, servername_type);
- SSL_get0_ech_name_override(ssl, &outer, &out_name_len);
- /* TODO: get the inner from boring */
- infof(data, "ECH: retry_configs for %s from %s, %d %d",
- inner ? inner : "NULL", outer ? outer : "NULL", reason, rv);
+ rv = SSL_ech_accepted(ssl);
+ servername_type = SSL_get_servername_type(ssl);
+ inner = SSL_get_servername(ssl, servername_type);
+ SSL_get0_ech_name_override(ssl, &outer, &out_name_len);
+ infof(data, "ECH: retry_configs for %s from %s, %d %d",
+ inner ? inner : "NULL", outer ? outer : "NULL", reason, rv);
#endif
+ }
}
else
infof(data, "ECH: no retry_configs (rv = %d)", rv);
-# ifndef OPENSSL_IS_BORINGSSL
+# if !defined(OPENSSL_IS_BORINGSSL) && !defined(OPENSSL_IS_AWSLC)
OPENSSL_free((void *)rcs);
# endif
return;
@@ -4169,27 +4451,25 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf, if(SSL_ERROR_WANT_READ == detail) {
CURL_TRC_CF(data, cf, "SSL_connect() -> want recv");
connssl->io_need = CURL_SSL_IO_NEED_RECV;
- return CURLE_OK;
+ return CURLE_AGAIN;
}
if(SSL_ERROR_WANT_WRITE == detail) {
CURL_TRC_CF(data, cf, "SSL_connect() -> want send");
connssl->io_need = CURL_SSL_IO_NEED_SEND;
- return CURLE_OK;
+ return CURLE_AGAIN;
}
#ifdef SSL_ERROR_WANT_ASYNC
if(SSL_ERROR_WANT_ASYNC == detail) {
CURL_TRC_CF(data, cf, "SSL_connect() -> want async");
connssl->io_need = CURL_SSL_IO_NEED_RECV;
- connssl->connecting_state = ssl_connect_2;
- return CURLE_OK;
+ return CURLE_AGAIN;
}
#endif
#ifdef SSL_ERROR_WANT_RETRY_VERIFY
if(SSL_ERROR_WANT_RETRY_VERIFY == detail) {
CURL_TRC_CF(data, cf, "SSL_connect() -> want retry_verify");
connssl->io_need = CURL_SSL_IO_NEED_RECV;
- connssl->connecting_state = ssl_connect_2;
- return CURLE_OK;
+ return CURLE_AGAIN;
}
#endif
else {
@@ -4220,16 +4500,13 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf, lerr = SSL_get_verify_result(octx->ssl);
if(lerr != X509_V_OK) {
ssl_config->certverifyresult = lerr;
- msnprintf(error_buffer, sizeof(error_buffer),
- "SSL certificate problem: %s",
- X509_verify_cert_error_string(lerr));
+ failf(data, "SSL certificate problem: %s",
+ X509_verify_cert_error_string(lerr));
}
- else {
+ else
failf(data, "%s", "SSL certificate verification failed");
- return result;
- }
}
-#if defined(SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED)
+#ifdef SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED
/* SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED is only available on
OpenSSL version above v1.1.1, not LibreSSL, BoringSSL, or AWS-LC */
else if((lib == ERR_LIB_SSL) &&
@@ -4241,9 +4518,9 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf, ossl_strerror(errdetail, error_buffer, sizeof(error_buffer)));
}
#endif
-#ifdef USE_ECH
+#ifdef USE_ECH_OPENSSL
else if((lib == ERR_LIB_SSL) &&
-# ifndef OPENSSL_IS_BORINGSSL
+# if !defined(OPENSSL_IS_BORINGSSL) && !defined(OPENSSL_IS_AWSLC)
(reason == SSL_R_ECH_REQUIRED)) {
# else
(reason == SSL_R_ECH_REJECTED)) {
@@ -4278,7 +4555,6 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf, failf(data, OSSL_PACKAGE " SSL_connect: %s in connection to %s:%d ",
extramsg[0] ? extramsg : SSL_ERROR_to_str(detail),
connssl->peer.hostname, connssl->peer.port);
- return result;
}
return result;
@@ -4308,14 +4584,14 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf, negotiated_group_name ? negotiated_group_name : "[blank]",
OBJ_nid2sn(psigtype_nid));
-#ifdef USE_ECH
-# ifndef OPENSSL_IS_BORINGSSL
+#ifdef USE_ECH_OPENSSL
+# if !defined(OPENSSL_IS_BORINGSSL) && !defined(OPENSSL_IS_AWSLC)
if(ECH_ENABLED(data)) {
char *inner = NULL, *outer = NULL;
const char *status = NULL;
int rv;
- rv = SSL_ech_get_status(octx->ssl, &inner, &outer);
+ rv = SSL_ech_get1_status(octx->ssl, &inner, &outer);
switch(rv) {
case SSL_ECH_STATUS_SUCCESS:
status = "succeeded";
@@ -4367,10 +4643,10 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf, else {
infof(data, "ECH: result: status is not attempted");
}
-# endif /* BORING */
-#endif /* USE_ECH */
+# endif /* !OPENSSL_IS_BORINGSSL && !OPENSSL_IS_AWSLC */
+#endif /* USE_ECH_OPENSSL */
-#ifdef HAS_ALPN
+#ifdef HAS_ALPN_OPENSSL
/* Sets data and len to negotiated protocol, len is 0 if no protocol was
* negotiated
*/
@@ -4496,7 +4772,7 @@ static void infof_certstack(struct Curl_easy *data, const SSL *ssl) sizeof(group_name), NULL);
msnprintf(group_name_final, sizeof(group_name_final), "/%s", group_name);
}
- type_name = EVP_PKEY_get0_type_name(current_pkey);
+ type_name = current_pkey ? EVP_PKEY_get0_type_name(current_pkey) : NULL;
#else
get_group_name = 0;
type_name = NULL;
@@ -4536,7 +4812,7 @@ CURLcode Curl_oss_check_peer_cert(struct Curl_cfilter *cf, DEBUGASSERT(octx);
- Curl_dyn_init(&dname, MAX_CERT_NAME_LENGTH);
+ curlx_dyn_init(&dname, MAX_CERT_NAME_LENGTH);
if(!mem) {
failf(data,
@@ -4566,19 +4842,20 @@ CURLcode Curl_oss_check_peer_cert(struct Curl_cfilter *cf, result = x509_name_oneline(X509_get_subject_name(octx->server_cert),
&dname);
- infof(data, " subject: %s", result ? "[NONE]" : Curl_dyn_ptr(&dname));
+ infof(data, " subject: %s", result ? "[NONE]" : curlx_dyn_ptr(&dname));
#ifndef CURL_DISABLE_VERBOSE_STRINGS
{
+ char *buf;
long len;
ASN1_TIME_print(mem, X509_get0_notBefore(octx->server_cert));
- len = BIO_get_mem_data(mem, (char **) &ptr);
- infof(data, " start date: %.*s", (int)len, ptr);
+ len = BIO_get_mem_data(mem, (char **) &buf);
+ infof(data, " start date: %.*s", (int)len, buf);
(void)BIO_reset(mem);
ASN1_TIME_print(mem, X509_get0_notAfter(octx->server_cert));
- len = BIO_get_mem_data(mem, (char **) &ptr);
- infof(data, " expire date: %.*s", (int)len, ptr);
+ len = BIO_get_mem_data(mem, (char **) &buf);
+ infof(data, " expire date: %.*s", (int)len, buf);
(void)BIO_reset(mem);
}
#endif
@@ -4590,7 +4867,7 @@ CURLcode Curl_oss_check_peer_cert(struct Curl_cfilter *cf, if(result) {
X509_free(octx->server_cert);
octx->server_cert = NULL;
- Curl_dyn_free(&dname);
+ curlx_dyn_free(&dname);
return result;
}
}
@@ -4603,8 +4880,8 @@ CURLcode Curl_oss_check_peer_cert(struct Curl_cfilter *cf, result = CURLE_PEER_FAILED_VERIFICATION;
}
else {
- infof(data, " issuer: %s", Curl_dyn_ptr(&dname));
- Curl_dyn_free(&dname);
+ infof(data, " issuer: %s", curlx_dyn_ptr(&dname));
+ curlx_dyn_free(&dname);
/* We could do all sorts of certificate verification stuff here before
deallocating the certificate. */
@@ -4699,27 +4976,11 @@ CURLcode Curl_oss_check_peer_cert(struct Curl_cfilter *cf, }
infof_certstack(data, octx->ssl);
-#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
- !defined(OPENSSL_NO_OCSP)
+#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_OCSP)
if(conn_config->verifystatus && !octx->reused_session) {
/* 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 */
- if(!Curl_ssl_cf_is_proxy(cf)) {
- void *old_ssl_sessionid = NULL;
- bool incache;
- Curl_ssl_sessionid_lock(data);
- incache = !(Curl_ssl_getsessionid(cf, data, peer,
- &old_ssl_sessionid, NULL, NULL));
- if(incache) {
- infof(data, "Remove session ID again from cache");
- Curl_ssl_delsessionid(data, old_ssl_sessionid);
- }
- Curl_ssl_sessionid_unlock(data);
- }
-
X509_free(octx->server_cert);
octx->server_cert = NULL;
return result;
@@ -4767,134 +5028,169 @@ static CURLcode ossl_connect_step3(struct Curl_cfilter *cf, */
result = Curl_oss_check_peer_cert(cf, data, octx, &connssl->peer);
- if(!result)
- connssl->connecting_state = ssl_connect_done;
+ if(result)
+ /* on error, remove sessions we might have in the pool */
+ Curl_ssl_scache_remove_all(cf, data, connssl->peer.scache_key);
return result;
}
-static CURLcode ossl_connect_common(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- bool nonblocking,
- bool *done)
+#ifdef HAVE_OPENSSL_EARLYDATA
+static CURLcode ossl_send_earlydata(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
+{
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
+ CURLcode result = CURLE_OK;
+ const unsigned char *buf;
+ size_t blen, nwritten;
+ int rc;
+
+ DEBUGASSERT(connssl->earlydata_state == ssl_earlydata_sending);
+ octx->io_result = CURLE_OK;
+ while(Curl_bufq_peek(&connssl->earlydata, &buf, &blen)) {
+ nwritten = 0;
+ rc = SSL_write_early_data(octx->ssl, buf, blen, &nwritten);
+ CURL_TRC_CF(data, cf, "SSL_write_early_data(len=%zu) -> %d, %zu",
+ blen, rc, nwritten);
+ if(rc <= 0) {
+ long sslerror;
+ char error_buffer[256];
+ int err = SSL_get_error(octx->ssl, rc);
+
+ switch(err) {
+ case SSL_ERROR_WANT_READ:
+ connssl->io_need = CURL_SSL_IO_NEED_RECV;
+ result = CURLE_AGAIN;
+ goto out;
+ case SSL_ERROR_WANT_WRITE:
+ connssl->io_need = CURL_SSL_IO_NEED_SEND;
+ result = CURLE_AGAIN;
+ goto out;
+ case SSL_ERROR_SYSCALL: {
+ int sockerr = SOCKERRNO;
+
+ if(octx->io_result == CURLE_AGAIN) {
+ result = CURLE_AGAIN;
+ goto out;
+ }
+ sslerror = ERR_get_error();
+ if(sslerror)
+ ossl_strerror(sslerror, error_buffer, sizeof(error_buffer));
+ else if(sockerr)
+ Curl_strerror(sockerr, error_buffer, sizeof(error_buffer));
+ else
+ msnprintf(error_buffer, sizeof(error_buffer), "%s",
+ SSL_ERROR_to_str(err));
+
+ failf(data, OSSL_PACKAGE " SSL_write:early_data: %s, errno %d",
+ error_buffer, sockerr);
+ result = CURLE_SEND_ERROR;
+ goto out;
+ }
+ case SSL_ERROR_SSL: {
+ /* A failure in the SSL library occurred, usually a protocol error.
+ The OpenSSL error queue contains more information on the error. */
+ sslerror = ERR_get_error();
+ failf(data, "SSL_write_early_data() error: %s",
+ ossl_strerror(sslerror, error_buffer, sizeof(error_buffer)));
+ result = CURLE_SEND_ERROR;
+ goto out;
+ }
+ default:
+ /* a true error */
+ failf(data, OSSL_PACKAGE " SSL_write_early_data: %s, errno %d",
+ SSL_ERROR_to_str(err), SOCKERRNO);
+ result = CURLE_SEND_ERROR;
+ goto out;
+ }
+ }
+ Curl_bufq_skip(&connssl->earlydata, nwritten);
+ }
+ /* sent everything there was */
+ infof(data, "SSL sending %zu bytes of early data", connssl->earlydata_skip);
+out:
+ return result;
+}
+#endif /* HAVE_OPENSSL_EARLYDATA */
+
+static CURLcode ossl_connect(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool *done)
{
CURLcode result = CURLE_OK;
struct ssl_connect_data *connssl = cf->ctx;
- curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data);
- int what;
- connssl->io_need = CURL_SSL_IO_NEED_NONE;
/* check if the connection has already been established */
if(ssl_connection_complete == connssl->state) {
*done = TRUE;
return CURLE_OK;
}
- if(ssl_connect_1 == connssl->connecting_state) {
- /* Find out how much more time we are allowed */
- const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
-
- if(timeout_ms < 0) {
- /* no need to continue if time is already up */
- failf(data, "SSL connection timeout");
- return CURLE_OPERATION_TIMEDOUT;
- }
+ *done = FALSE;
+ connssl->io_need = CURL_SSL_IO_NEED_NONE;
+ if(ssl_connect_1 == connssl->connecting_state) {
+ CURL_TRC_CF(data, cf, "ossl_connect, step1");
result = ossl_connect_step1(cf, data);
if(result)
goto out;
}
- while(ssl_connect_2 == connssl->connecting_state) {
-
- /* check allowed time left */
- const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
-
- if(timeout_ms < 0) {
- /* no need to continue if time already is up */
- failf(data, "SSL connection timeout");
- result = CURLE_OPERATION_TIMEDOUT;
+ if(ssl_connect_2 == connssl->connecting_state) {
+ CURL_TRC_CF(data, cf, "ossl_connect, step2");
+#ifdef HAVE_OPENSSL_EARLYDATA
+ if(connssl->earlydata_state == ssl_earlydata_await) {
goto out;
}
-
- /* if ssl is expecting something, check if it is available. */
- if(!nonblocking && connssl->io_need) {
- curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND) ?
- sockfd : CURL_SOCKET_BAD;
- curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV) ?
- sockfd : CURL_SOCKET_BAD;
-
- what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
- timeout_ms);
- if(what < 0) {
- /* fatal error */
- failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
- result = CURLE_SSL_CONNECT_ERROR;
- goto out;
- }
- if(0 == what) {
- /* timeout */
- failf(data, "SSL connection timeout");
- result = CURLE_OPERATION_TIMEDOUT;
+ else if(connssl->earlydata_state == ssl_earlydata_sending) {
+ result = ossl_send_earlydata(cf, data);
+ if(result)
goto out;
- }
- /* socket is readable or writable */
+ connssl->earlydata_state = ssl_earlydata_sent;
}
+#endif
+ DEBUGASSERT((connssl->earlydata_state == ssl_earlydata_none) ||
+ (connssl->earlydata_state == ssl_earlydata_sent));
- /* Run transaction, and return to the caller if it failed or if this
- * connection is done nonblocking and this loop would execute again. This
- * permits the owner of a multi handle to abort a connection attempt
- * before step2 has completed while ensuring that a client using select()
- * 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)))
+ if(result)
goto out;
-
- } /* repeat step2 until all transactions are done. */
+ }
if(ssl_connect_3 == connssl->connecting_state) {
+ CURL_TRC_CF(data, cf, "ossl_connect, step3");
result = ossl_connect_step3(cf, data);
if(result)
goto out;
+ connssl->connecting_state = ssl_connect_done;
+#ifdef HAVE_OPENSSL_EARLYDATA
+ if(connssl->earlydata_state > ssl_earlydata_none) {
+ struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
+ /* We should be in this state by now */
+ DEBUGASSERT(connssl->earlydata_state == ssl_earlydata_sent);
+ connssl->earlydata_state =
+ (SSL_get_early_data_status(octx->ssl) == SSL_EARLY_DATA_ACCEPTED) ?
+ ssl_earlydata_accepted : ssl_earlydata_rejected;
+ }
+#endif
}
if(ssl_connect_done == connssl->connecting_state) {
+ CURL_TRC_CF(data, cf, "ossl_connect, done");
connssl->state = ssl_connection_complete;
- *done = TRUE;
}
- else
- *done = FALSE;
-
- /* Reset our connect state machine */
- connssl->connecting_state = ssl_connect_1;
out:
+ if(result == CURLE_AGAIN) {
+ *done = FALSE;
+ return CURLE_OK;
+ }
+ *done = ((connssl->state == ssl_connection_complete) ||
+ (connssl->state == ssl_connection_deferred));
return result;
}
-static CURLcode ossl_connect_nonblocking(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- bool *done)
-{
- return ossl_connect_common(cf, data, TRUE, done);
-}
-
-static CURLcode ossl_connect(struct Curl_cfilter *cf,
- struct Curl_easy *data)
-{
- CURLcode result;
- bool done = FALSE;
-
- result = ossl_connect_common(cf, data, FALSE, &done);
- if(result)
- return result;
-
- DEBUGASSERT(done);
-
- return CURLE_OK;
-}
-
static bool ossl_data_pending(struct Curl_cfilter *cf,
const struct Curl_easy *data)
{
@@ -5168,10 +5464,10 @@ static CURLcode ossl_get_channel_binding(struct Curl_easy *data, int sockindex, }
/* Append "tls-server-end-point:" */
- if(Curl_dyn_addn(binding, prefix, sizeof(prefix) - 1) != CURLE_OK)
+ if(curlx_dyn_addn(binding, prefix, sizeof(prefix) - 1) != CURLE_OK)
return CURLE_OUT_OF_MEMORY;
/* Append digest */
- if(Curl_dyn_addn(binding, buf, length))
+ if(curlx_dyn_addn(binding, buf, length))
return CURLE_OUT_OF_MEMORY;
return CURLE_OK;
@@ -5184,10 +5480,9 @@ static CURLcode ossl_get_channel_binding(struct Curl_easy *data, int sockindex, #endif
}
-static size_t ossl_version(char *buffer, size_t size)
+size_t Curl_ossl_version(char *buffer, size_t size)
{
#ifdef LIBRESSL_VERSION_NUMBER
-#ifdef HAVE_OPENSSL_VERSION
char *p;
size_t count;
const char *ver = OpenSSL_version(OPENSSL_VERSION);
@@ -5201,13 +5496,6 @@ static size_t ossl_version(char *buffer, size_t size) *p = '_';
}
return count;
-#else
- return msnprintf(buffer, size, "%s/%lx.%lx.%lx",
- OSSL_PACKAGE,
- (LIBRESSL_VERSION_NUMBER >> 28) & 0xf,
- (LIBRESSL_VERSION_NUMBER >> 20) & 0xff,
- (LIBRESSL_VERSION_NUMBER >> 12) & 0xff);
-#endif
#elif defined(OPENSSL_IS_BORINGSSL)
#ifdef CURL_BORINGSSL_VERSION
return msnprintf(buffer, size, "%s/%s",
@@ -5231,25 +5519,19 @@ static size_t ossl_version(char *buffer, size_t size) sub[2]='\0';
sub[1]='\0';
ssleay_value = OpenSSL_version_num();
- if(ssleay_value < 0x906000) {
- ssleay_value = SSLEAY_VERSION_NUMBER;
- sub[0]='\0';
- }
- else {
- if(ssleay_value&0xff0) {
- int minor_ver = (ssleay_value >> 4) & 0xff;
- if(minor_ver > 26) {
- /* handle extended version introduced for 0.9.8za */
- sub[1] = (char) ((minor_ver - 1) % 26 + 'a' + 1);
- sub[0] = 'z';
- }
- else {
- sub[0] = (char) (minor_ver + 'a' - 1);
- }
+ if(ssleay_value&0xff0) {
+ int minor_ver = (ssleay_value >> 4) & 0xff;
+ if(minor_ver > 26) {
+ /* handle extended version introduced for 0.9.8za */
+ sub[1] = (char) ((minor_ver - 1) % 26 + 'a' + 1);
+ sub[0] = 'z';
+ }
+ else {
+ sub[0] = (char) (minor_ver + 'a' - 1);
}
- else
- sub[0]='\0';
}
+ else
+ sub[0]='\0';
return msnprintf(buffer, size, "%s/%lx.%lx.%lx%s"
#ifdef OPENSSL_FIPS
@@ -5279,10 +5561,10 @@ static CURLcode ossl_random(struct Curl_easy *data, }
/* RAND_bytes() returns 1 on success, 0 otherwise. */
rc = RAND_bytes(entropy, (ossl_valsize_t)curlx_uztosi(length));
- return (rc == 1 ? CURLE_OK : CURLE_FAILED_INIT);
+ return rc == 1 ? CURLE_OK : CURLE_FAILED_INIT;
}
-#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256)
+#ifndef OPENSSL_NO_SHA256
static CURLcode ossl_sha256sum(const unsigned char *tmp, /* input */
size_t tmplen,
unsigned char *sha256sum /* output */,
@@ -5308,8 +5590,7 @@ static CURLcode ossl_sha256sum(const unsigned char *tmp, /* input */ static bool ossl_cert_status_request(void)
{
-#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
- !defined(OPENSSL_NO_OCSP)
+#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_OCSP)
return TRUE;
#else
return FALSE;
@@ -5337,7 +5618,10 @@ const struct Curl_ssl Curl_ssl_openssl = { #ifdef HAVE_SSL_CTX_SET_CIPHERSUITES
SSLSUPP_TLS13_CIPHERSUITES |
#endif
-#ifdef USE_ECH
+#ifdef HAVE_SSL_CTX_SET1_SIGALGS
+ SSLSUPP_SIGNATURE_ALGORITHMS |
+#endif
+#ifdef USE_ECH_OPENSSL
SSLSUPP_ECH |
#endif
SSLSUPP_CA_CACHE |
@@ -5348,29 +5632,25 @@ const struct Curl_ssl Curl_ssl_openssl = { ossl_init, /* init */
ossl_cleanup, /* cleanup */
- ossl_version, /* version */
- Curl_none_check_cxn, /* check_cxn */
+ Curl_ossl_version, /* version */
ossl_shutdown, /* shutdown */
ossl_data_pending, /* data_pending */
ossl_random, /* random */
ossl_cert_status_request, /* cert_status_request */
ossl_connect, /* connect */
- ossl_connect_nonblocking, /* connect_nonblocking */
Curl_ssl_adjust_pollset, /* adjust_pollset */
ossl_get_internals, /* get_internals */
ossl_close, /* close_one */
ossl_close_all, /* close_all */
- ossl_set_engine, /* set_engine */
+ ossl_set_engine, /* set_engine or provider */
ossl_set_engine_default, /* set_engine_default */
ossl_engines_list, /* engines_list */
- Curl_none_false_start, /* false_start */
-#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256)
+ NULL, /* false_start */
+#ifndef OPENSSL_NO_SHA256
ossl_sha256sum, /* sha256sum */
#else
NULL, /* sha256sum */
#endif
- NULL, /* use of data in this connection */
- NULL, /* remote of data from this connection */
ossl_recv, /* recv decrypted data */
ossl_send, /* send data to encrypt */
ossl_get_channel_binding /* get_channel_binding */
|