vtls/schannel.c \
vtls/schannel_verify.c \
vtls/vtls.c \
+ vtls/vtls_config.c \
vtls/vtls_scache.c \
vtls/vtls_spack.c \
vtls/wolfssl.c \
vtls/schannel.h \
vtls/schannel_int.h \
vtls/vtls.h \
+ vtls/vtls_config.h \
vtls/vtls_int.h \
vtls/vtls_scache.h \
vtls/vtls_spack.h \
Curl_netrc_cleanup(&data->state.netrc);
#ifndef CURL_DISABLE_DIGEST_AUTH
curlx_free(data->state.envproxy);
+#endif
+ Curl_ssl_config_cleanup(&data->set.ssl.primary);
+#ifndef CURL_DISABLE_PROXY
+ Curl_ssl_config_cleanup(&data->set.proxy_ssl.primary);
#endif
curlx_free(data);
return CURLE_OK;
set->httpauth = CURLAUTH_BASIC; /* defaults to basic */
+ Curl_ssl_config_init(&data->set.ssl.primary);
#ifndef CURL_DISABLE_PROXY
+ Curl_ssl_config_init(&data->set.proxy_ssl.primary);
set->proxyport = 0;
set->proxytype = CURLPROXY_HTTP; /* defaults to HTTP proxy */
set->proxyauth = CURLAUTH_BASIC; /* defaults to basic */
set->socks5auth = CURLAUTH_BASIC | CURLAUTH_GSSAPI;
#endif
- Curl_ssl_easy_config_init(data);
#ifndef CURL_DISABLE_DOH
set->doh_verifyhost = TRUE;
set->doh_verifypeer = TRUE;
#endif
/* Complete the easy's SSL configuration for connection cache matching */
- result = Curl_ssl_easy_config_complete(data);
+ result = Curl_ssl_easy_config_complete(data, needle->origin);
if(result)
goto out;
#include "request.h"
#include "ratelimit.h"
#include "netrc.h"
+#include "vtls/vtls_config.h"
/* On error return, the value of `pnwritten` has no meaning */
typedef CURLcode (Curl_send)(struct Curl_easy *data, /* transfer */
((x) && ((x)->magic == CURLEASY_MAGIC_NUMBER))
#endif
-struct ssl_primary_config {
- char *CApath; /* certificate directory (does not work on Windows) */
- char *CAfile; /* certificate to verify peer against */
- char *issuercert; /* optional issuer certificate filename */
- char *clientcert;
- char *cipher_list; /* list of ciphers to use */
- char *cipher_list13; /* list of TLS 1.3 cipher suites to use */
- char *signature_algorithms; /* list of signature algorithms to use */
- char *pinned_key;
- char *CRLfile; /* CRL to check certificate revocation */
- char *cert_type; /* format for certificate (default: PEM) */
- char *key; /* private key filename */
- char *key_type; /* format for private key (default: PEM) */
- char *key_passwd; /* plain text private key password */
- struct curl_blob *cert_blob;
- struct curl_blob *ca_info_blob;
- struct curl_blob *issuercert_blob;
- struct curl_blob *key_blob;
-#ifdef USE_TLS_SRP
- char *username; /* TLS username (for, e.g., SRP) */
- char *password; /* TLS password (for, e.g., SRP) */
-#endif
- char *curves; /* list of curves to use */
- uint32_t version_max; /* max supported version the client wants to use */
- uint8_t ssl_options; /* the CURLOPT_SSL_OPTIONS bitmask */
- uint8_t version; /* what version the client wants to use */
- BIT(verifypeer); /* set TRUE if this is desired */
- BIT(verifyhost); /* set TRUE if CN/SAN must match hostname */
- BIT(verifystatus); /* set TRUE if certificate status must be checked */
- BIT(cache_session); /* cache session or not */
-};
-
-struct ssl_config_data {
- struct ssl_primary_config primary;
- long certverifyresult; /* result from the certificate verification */
- curl_ssl_ctx_callback fsslctx; /* function to initialize SSL ctx */
- void *fsslctxp; /* parameter for call back */
- BIT(certinfo); /* gather lots of certificate info */
- BIT(earlydata); /* use TLS 1.3 early data */
- BIT(enable_beast); /* allow this flaw for interoperability's sake */
- BIT(no_revoke); /* disable SSL certificate revocation checks */
- BIT(no_partialchain); /* do not accept partial certificate chains */
- BIT(revoke_best_effort); /* ignore SSL revocation offline/missing revocation
- list errors */
- BIT(native_ca_store); /* use the native CA store of operating system */
- BIT(auto_client_cert); /* automatically locate and use a client
- certificate for authentication (Schannel) */
- BIT(custom_cafile); /* application has set custom CA file */
- BIT(custom_capath); /* application has set custom CA path */
- BIT(custom_cablob); /* application has set custom CA blob */
-};
-
-struct ssl_general_config {
- int ca_cache_timeout; /* Certificate store cache timeout (seconds) */
-};
-
#ifdef USE_WINDOWS_SSPI
#include "curl_sspi.h"
#endif
#include <Security/Security.h>
#endif
-
-#define CLONE_STRING(var) \
- do { \
- if(source->var) { \
- dest->var = curlx_strdup(source->var); \
- if(!dest->var) \
- return FALSE; \
- } \
- else \
- dest->var = NULL; \
- } while(0)
-
-#define CLONE_BLOB(var) \
- do { \
- if(blobdup(&dest->var, source->var)) \
- return FALSE; \
- } while(0)
-
-static CURLcode blobdup(struct curl_blob **dest, struct curl_blob *src)
-{
- DEBUGASSERT(dest);
- DEBUGASSERT(!*dest);
- if(src) {
- /* only if there is data to dupe! */
- struct curl_blob *d;
- d = curlx_malloc(sizeof(struct curl_blob) + src->len);
- if(!d)
- return CURLE_OUT_OF_MEMORY;
- d->len = src->len;
- /* Always duplicate because the connection may survive longer than the
- handle that passed in the blob. */
- d->flags = CURL_BLOB_COPY;
- d->data = (void *)((char *)d + sizeof(struct curl_blob));
- memcpy(d->data, src->data, src->len);
- *dest = d;
- }
- return CURLE_OK;
-}
-
-/* returns TRUE if the blobs are identical */
-static bool blobcmp(struct curl_blob *first, struct curl_blob *second)
-{
- if(!first && !second) /* both are NULL */
- return TRUE;
- if(!first || !second) /* one is NULL */
- return FALSE;
- if(first->len != second->len) /* different sizes */
- return FALSE;
- return !memcmp(first->data, second->data, first->len); /* same data */
-}
-
#ifdef USE_SSL
#if !defined(CURL_DISABLE_HTTP) || !defined(CURL_DISABLE_PROXY)
static const struct alpn_spec ALPN_SPEC_H11 = {
#endif /* !CURL_DISABLE_HTTP || !CURL_DISABLE_PROXY */
#endif /* USE_SSL */
-void Curl_ssl_easy_config_init(struct Curl_easy *data)
-{
- /*
- * libcurl 7.10 introduced SSL verification *by default*! This needs to be
- * switched off unless wanted.
- */
- data->set.ssl.primary.verifypeer = TRUE;
- data->set.ssl.primary.verifyhost = TRUE;
- data->set.ssl.primary.cache_session = TRUE; /* caching by default */
-#ifndef CURL_DISABLE_PROXY
- data->set.proxy_ssl = data->set.ssl;
-#endif
-}
-
-static bool match_ssl_primary_config(struct Curl_easy *data,
- struct ssl_primary_config *c1,
- struct ssl_primary_config *c2)
-{
- (void)data;
- if((c1->version == c2->version) &&
- (c1->version_max == c2->version_max) &&
- (c1->ssl_options == c2->ssl_options) &&
- (c1->verifypeer == c2->verifypeer) &&
- (c1->verifyhost == c2->verifyhost) &&
- (c1->verifystatus == c2->verifystatus) &&
- blobcmp(c1->cert_blob, c2->cert_blob) &&
- blobcmp(c1->ca_info_blob, c2->ca_info_blob) &&
- blobcmp(c1->issuercert_blob, c2->issuercert_blob) &&
- blobcmp(c1->key_blob, c2->key_blob) &&
- Curl_safecmp(c1->CApath, c2->CApath) &&
- Curl_safecmp(c1->CAfile, c2->CAfile) &&
- Curl_safecmp(c1->issuercert, c2->issuercert) &&
- Curl_safecmp(c1->clientcert, c2->clientcert) &&
-#ifdef USE_TLS_SRP
- !Curl_timestrcmp(c1->username, c2->username) &&
- !Curl_timestrcmp(c1->password, c2->password) &&
-#endif
- curl_strequal(c1->cipher_list, c2->cipher_list) &&
- curl_strequal(c1->cipher_list13, c2->cipher_list13) &&
- curl_strequal(c1->curves, c2->curves) &&
- curl_strequal(c1->signature_algorithms, c2->signature_algorithms) &&
- Curl_safecmp(c1->CRLfile, c2->CRLfile) &&
- Curl_safecmp(c1->pinned_key, c2->pinned_key) &&
- curl_strequal(c1->cert_type, c2->cert_type) &&
- Curl_safecmp(c1->key, c2->key) &&
- curl_strequal(c1->key_type, c2->key_type) &&
- !Curl_timestrcmp(c1->key_passwd, c2->key_passwd))
- return TRUE;
-
- return FALSE;
-}
-
-bool Curl_ssl_conn_config_match(struct Curl_easy *data,
- struct connectdata *candidate,
- bool proxy)
-{
-#ifndef CURL_DISABLE_PROXY
- if(proxy)
- return match_ssl_primary_config(data, &data->set.proxy_ssl.primary,
- &candidate->proxy_ssl_config);
-#else
- (void)proxy;
-#endif
- return match_ssl_primary_config(data, &data->set.ssl.primary,
- &candidate->ssl_config);
-}
-
-static bool clone_ssl_primary_config(struct ssl_primary_config *source,
- struct ssl_primary_config *dest)
-{
- dest->version = source->version;
- dest->version_max = source->version_max;
- dest->verifypeer = source->verifypeer;
- dest->verifyhost = source->verifyhost;
- dest->verifystatus = source->verifystatus;
- dest->cache_session = source->cache_session;
- dest->ssl_options = source->ssl_options;
-
- CLONE_BLOB(cert_blob);
- CLONE_BLOB(ca_info_blob);
- CLONE_BLOB(issuercert_blob);
- CLONE_BLOB(key_blob);
- CLONE_STRING(CApath);
- CLONE_STRING(CAfile);
- CLONE_STRING(issuercert);
- CLONE_STRING(clientcert);
- CLONE_STRING(cipher_list);
- CLONE_STRING(cipher_list13);
- CLONE_STRING(pinned_key);
- CLONE_STRING(curves);
- CLONE_STRING(signature_algorithms);
- CLONE_STRING(CRLfile);
- CLONE_STRING(cert_type);
- CLONE_STRING(key);
- CLONE_STRING(key_type);
- CLONE_STRING(key_passwd);
-#ifdef USE_TLS_SRP
- CLONE_STRING(username);
- CLONE_STRING(password);
-#endif
-
- return TRUE;
-}
-
-static void free_primary_ssl_config(struct ssl_primary_config *sslc)
-{
- curlx_safefree(sslc->CApath);
- curlx_safefree(sslc->CAfile);
- curlx_safefree(sslc->issuercert);
- curlx_safefree(sslc->clientcert);
- curlx_safefree(sslc->cipher_list);
- curlx_safefree(sslc->cipher_list13);
- curlx_safefree(sslc->pinned_key);
- curlx_safefree(sslc->cert_blob);
- curlx_safefree(sslc->ca_info_blob);
- curlx_safefree(sslc->issuercert_blob);
- curlx_safefree(sslc->key_blob);
- curlx_safefree(sslc->curves);
- curlx_safefree(sslc->signature_algorithms);
- curlx_safefree(sslc->CRLfile);
- curlx_safefree(sslc->cert_type);
- curlx_safefree(sslc->key);
- curlx_safefree(sslc->key_type);
- curlx_safefree(sslc->key_passwd);
-#ifdef USE_TLS_SRP
- curlx_safefree(sslc->username);
- curlx_safefree(sslc->password);
-#endif
-}
-
-CURLcode Curl_ssl_easy_config_complete(struct Curl_easy *data)
-{
- struct ssl_config_data *sslc = &data->set.ssl;
-#if defined(CURL_CA_PATH) || defined(CURL_CA_BUNDLE)
- struct UserDefined *set = &data->set;
- CURLcode result;
-#endif
-
- if(Curl_ssl_backend() != CURLSSLBACKEND_SCHANNEL) {
-#if defined(USE_APPLE_SECTRUST) || defined(CURL_CA_NATIVE)
- if(!sslc->custom_capath && !sslc->custom_cafile && !sslc->custom_cablob)
- sslc->native_ca_store = TRUE;
-#endif
-#ifdef CURL_CA_PATH
- if(!sslc->custom_capath && !set->str[STRING_SSL_CAPATH]) {
- result = Curl_setstropt(&set->str[STRING_SSL_CAPATH], CURL_CA_PATH);
- if(result)
- return result;
- }
-#endif
-#ifdef CURL_CA_BUNDLE
- if(!sslc->custom_cafile && !set->str[STRING_SSL_CAFILE]) {
- result = Curl_setstropt(&set->str[STRING_SSL_CAFILE], CURL_CA_BUNDLE);
- if(result)
- return result;
- }
-#endif
- }
- sslc->primary.CAfile = data->set.str[STRING_SSL_CAFILE];
- sslc->primary.CRLfile = data->set.str[STRING_SSL_CRLFILE];
- sslc->primary.CApath = data->set.str[STRING_SSL_CAPATH];
- sslc->primary.issuercert = data->set.str[STRING_SSL_ISSUERCERT];
- sslc->primary.issuercert_blob = data->set.blobs[BLOB_SSL_ISSUERCERT];
- sslc->primary.cipher_list = data->set.str[STRING_SSL_CIPHER_LIST];
- sslc->primary.cipher_list13 = data->set.str[STRING_SSL_CIPHER13_LIST];
- sslc->primary.signature_algorithms =
- data->set.str[STRING_SSL_SIGNATURE_ALGORITHMS];
- sslc->primary.pinned_key = data->set.str[STRING_SSL_PINNEDPUBLICKEY];
- sslc->primary.cert_blob = data->set.blobs[BLOB_CERT];
- sslc->primary.ca_info_blob = data->set.blobs[BLOB_CAINFO];
- sslc->primary.curves = data->set.str[STRING_SSL_EC_CURVES];
-#ifdef USE_TLS_SRP
- sslc->primary.username = data->set.str[STRING_TLSAUTH_USERNAME];
- sslc->primary.password = data->set.str[STRING_TLSAUTH_PASSWORD];
-#endif
- sslc->primary.cert_type = data->set.str[STRING_CERT_TYPE];
- sslc->primary.key = data->set.str[STRING_KEY];
- sslc->primary.key_type = data->set.str[STRING_KEY_TYPE];
- sslc->primary.key_passwd = data->set.str[STRING_KEY_PASSWD];
- sslc->primary.clientcert = data->set.str[STRING_CERT];
- sslc->primary.key_blob = data->set.blobs[BLOB_KEY];
-
-#ifndef CURL_DISABLE_PROXY
- sslc = &data->set.proxy_ssl;
- if(Curl_ssl_backend() != CURLSSLBACKEND_SCHANNEL) {
-#if defined(USE_APPLE_SECTRUST) || defined(CURL_CA_NATIVE)
- if(!sslc->custom_capath && !sslc->custom_cafile && !sslc->custom_cablob)
- sslc->native_ca_store = TRUE;
-#endif
-#ifdef CURL_CA_PATH
- if(!sslc->custom_capath && !set->str[STRING_SSL_CAPATH_PROXY]) {
- result = Curl_setstropt(&set->str[STRING_SSL_CAPATH_PROXY],
- CURL_CA_PATH);
- if(result)
- return result;
- }
-#endif
-#ifdef CURL_CA_BUNDLE
- if(!sslc->custom_cafile && !set->str[STRING_SSL_CAFILE_PROXY]) {
- result = Curl_setstropt(&set->str[STRING_SSL_CAFILE_PROXY],
- CURL_CA_BUNDLE);
- if(result)
- return result;
- }
-#endif
- }
- sslc->primary.CAfile = data->set.str[STRING_SSL_CAFILE_PROXY];
- sslc->primary.CApath = data->set.str[STRING_SSL_CAPATH_PROXY];
- sslc->primary.cipher_list = data->set.str[STRING_SSL_CIPHER_LIST_PROXY];
- sslc->primary.cipher_list13 = data->set.str[STRING_SSL_CIPHER13_LIST_PROXY];
- sslc->primary.pinned_key = data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY];
- sslc->primary.cert_blob = data->set.blobs[BLOB_CERT_PROXY];
- sslc->primary.ca_info_blob = data->set.blobs[BLOB_CAINFO_PROXY];
- sslc->primary.issuercert = data->set.str[STRING_SSL_ISSUERCERT_PROXY];
- sslc->primary.issuercert_blob = data->set.blobs[BLOB_SSL_ISSUERCERT_PROXY];
- sslc->primary.CRLfile = data->set.str[STRING_SSL_CRLFILE_PROXY];
- sslc->primary.cert_type = data->set.str[STRING_CERT_TYPE_PROXY];
- sslc->primary.key = data->set.str[STRING_KEY_PROXY];
- sslc->primary.key_type = data->set.str[STRING_KEY_TYPE_PROXY];
- sslc->primary.key_passwd = data->set.str[STRING_KEY_PASSWD_PROXY];
- sslc->primary.clientcert = data->set.str[STRING_CERT_PROXY];
- sslc->primary.key_blob = data->set.blobs[BLOB_KEY_PROXY];
-#ifdef USE_TLS_SRP
- sslc->primary.username = data->set.str[STRING_TLSAUTH_USERNAME_PROXY];
- sslc->primary.password = data->set.str[STRING_TLSAUTH_PASSWORD_PROXY];
-#endif
-#endif /* CURL_DISABLE_PROXY */
-
- return CURLE_OK;
-}
-
-CURLcode Curl_ssl_conn_config_init(struct Curl_easy *data,
- struct connectdata *conn)
-{
- /* Clone "primary" SSL configurations from the easy handle to
- * the connection. They are used for connection cache matching and
- * probably outlive the easy handle */
- if(!clone_ssl_primary_config(&data->set.ssl.primary, &conn->ssl_config))
- return CURLE_OUT_OF_MEMORY;
-#ifndef CURL_DISABLE_PROXY
- if(!clone_ssl_primary_config(&data->set.proxy_ssl.primary,
- &conn->proxy_ssl_config))
- return CURLE_OUT_OF_MEMORY;
-#endif
- return CURLE_OK;
-}
-
-void Curl_ssl_conn_config_cleanup(struct connectdata *conn)
-{
- free_primary_ssl_config(&conn->ssl_config);
-#ifndef CURL_DISABLE_PROXY
- free_primary_ssl_config(&conn->proxy_ssl_config);
-#endif
-}
-
-void Curl_ssl_conn_config_update(struct Curl_easy *data, bool for_proxy)
-{
- /* May be called on an easy that has no connection yet */
- if(data->conn) {
- struct ssl_primary_config *src, *dest;
-#ifndef CURL_DISABLE_PROXY
- src = for_proxy ? &data->set.proxy_ssl.primary : &data->set.ssl.primary;
- dest = for_proxy ? &data->conn->proxy_ssl_config : &data->conn->ssl_config;
-#else
- (void)for_proxy;
- src = &data->set.ssl.primary;
- dest = &data->conn->ssl_config;
-#endif
- dest->verifyhost = src->verifyhost;
- dest->verifypeer = src->verifypeer;
- dest->verifystatus = src->verifystatus;
- }
-}
-
#ifdef USE_SSL
static int multissl_setup(const struct Curl_ssl *backend);
#endif
curl_sslbackend Curl_ssl_backend(void);
-/**
- * Init SSL config for a new easy handle.
- */
-void Curl_ssl_easy_config_init(struct Curl_easy *data);
-
-/**
- * Init the `data->set.ssl` and `data->set.proxy_ssl` for
- * connection matching use.
- */
-CURLcode Curl_ssl_easy_config_complete(struct Curl_easy *data);
-
-/**
- * Init SSL configs (main + proxy) for a new connection from the easy handle.
- */
-CURLcode Curl_ssl_conn_config_init(struct Curl_easy *data,
- struct connectdata *conn);
-
-/**
- * Free allocated resources in SSL configs (main + proxy) for
- * the given connection.
- */
-void Curl_ssl_conn_config_cleanup(struct connectdata *conn);
-
-/**
- * Return TRUE iff SSL configuration from `data` is functionally the
- * same as the one on `candidate`.
- * @param proxy match the proxy SSL config or the main one
- */
-bool Curl_ssl_conn_config_match(struct Curl_easy *data,
- struct connectdata *candidate,
- bool proxy);
-
-/* Update certain connection SSL config flags after they have
- * been changed on the easy handle. Works for `verifypeer`,
- * `verifyhost` and `verifystatus`. */
-void Curl_ssl_conn_config_update(struct Curl_easy *data, bool for_proxy);
-
/**
* Init SSL peer information for filter. Can be called repeatedly.
*/
--- /dev/null
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+/* This file is for implementing all "generic" SSL functions that all libcurl
+ internals should use. It is then responsible for calling the proper
+ "backend" function.
+
+ SSL-functions in libcurl should call functions in this source file, and not
+ to any specific SSL-layer.
+
+ Curl_ssl_ - prefix for generic ones
+
+ Note that this source code uses the functions of the configured SSL
+ backend via the global Curl_ssl instance.
+
+ "SSL/TLS Strong Encryption: An Introduction"
+ https://httpd.apache.org/docs/2.0/ssl/ssl_intro.html
+*/
+
+#include "curl_setup.h"
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include "urldata.h"
+#include "setopt.h"
+#include "strcase.h"
+#include "vtls/vtls.h"
+#include "vtls/vtls_config.h"
+
+
+#define CLONE_STRING(var) \
+ do { \
+ if(source->var) { \
+ dest->var = curlx_strdup(source->var); \
+ if(!dest->var) \
+ return FALSE; \
+ } \
+ else \
+ dest->var = NULL; \
+ } while(0)
+
+#define CLONE_BLOB(var) \
+ do { \
+ if(blobdup(&dest->var, source->var)) \
+ return FALSE; \
+ } while(0)
+
+static CURLcode blobdup(struct curl_blob **dest, struct curl_blob *src)
+{
+ DEBUGASSERT(dest);
+ DEBUGASSERT(!*dest);
+ if(src) {
+ /* only if there is data to dupe! */
+ struct curl_blob *d;
+ d = curlx_malloc(sizeof(struct curl_blob) + src->len);
+ if(!d)
+ return CURLE_OUT_OF_MEMORY;
+ d->len = src->len;
+ /* Always duplicate because the connection may survive longer than the
+ handle that passed in the blob. */
+ d->flags = CURL_BLOB_COPY;
+ d->data = (void *)((char *)d + sizeof(struct curl_blob));
+ memcpy(d->data, src->data, src->len);
+ *dest = d;
+ }
+ return CURLE_OK;
+}
+
+/* returns TRUE if the blobs are identical */
+static bool blobcmp(struct curl_blob *first, struct curl_blob *second)
+{
+ if(!first && !second) /* both are NULL */
+ return TRUE;
+ if(!first || !second) /* one is NULL */
+ return FALSE;
+ if(first->len != second->len) /* different sizes */
+ return FALSE;
+ return !memcmp(first->data, second->data, first->len); /* same data */
+}
+
+void Curl_ssl_config_init(struct ssl_primary_config *sslc)
+{
+ /*
+ * libcurl 7.10 introduced SSL verification *by default*! This needs to be
+ * switched off unless wanted.
+ */
+ sslc->verifypeer = TRUE;
+ sslc->verifyhost = TRUE;
+ sslc->cache_session = TRUE; /* caching by default */
+}
+
+void Curl_ssl_config_cleanup(struct ssl_primary_config *sslc)
+{
+ if(sslc->deep_copy) {
+ curlx_safefree(sslc->CApath);
+ curlx_safefree(sslc->CAfile);
+ curlx_safefree(sslc->issuercert);
+ curlx_safefree(sslc->clientcert);
+ curlx_safefree(sslc->cipher_list);
+ curlx_safefree(sslc->cipher_list13);
+ curlx_safefree(sslc->pinned_key);
+ curlx_safefree(sslc->cert_blob);
+ curlx_safefree(sslc->ca_info_blob);
+ curlx_safefree(sslc->issuercert_blob);
+ curlx_safefree(sslc->key_blob);
+ curlx_safefree(sslc->curves);
+ curlx_safefree(sslc->signature_algorithms);
+ curlx_safefree(sslc->CRLfile);
+ curlx_safefree(sslc->cert_type);
+ curlx_safefree(sslc->key);
+ curlx_safefree(sslc->key_type);
+ curlx_safefree(sslc->key_passwd);
+#ifdef USE_TLS_SRP
+ curlx_safefree(sslc->username);
+ curlx_safefree(sslc->password);
+#endif
+ sslc->deep_copy = FALSE;
+ }
+}
+
+static bool match_ssl_primary_config(struct Curl_easy *data,
+ struct ssl_primary_config *c1,
+ struct ssl_primary_config *c2)
+{
+ (void)data;
+ if((c1->version == c2->version) &&
+ (c1->version_max == c2->version_max) &&
+ (c1->ssl_options == c2->ssl_options) &&
+ (c1->verifypeer == c2->verifypeer) &&
+ (c1->verifyhost == c2->verifyhost) &&
+ (c1->verifystatus == c2->verifystatus) &&
+ blobcmp(c1->cert_blob, c2->cert_blob) &&
+ blobcmp(c1->ca_info_blob, c2->ca_info_blob) &&
+ blobcmp(c1->issuercert_blob, c2->issuercert_blob) &&
+ blobcmp(c1->key_blob, c2->key_blob) &&
+ Curl_safecmp(c1->CApath, c2->CApath) &&
+ Curl_safecmp(c1->CAfile, c2->CAfile) &&
+ Curl_safecmp(c1->issuercert, c2->issuercert) &&
+ Curl_safecmp(c1->clientcert, c2->clientcert) &&
+#ifdef USE_TLS_SRP
+ !Curl_timestrcmp(c1->username, c2->username) &&
+ !Curl_timestrcmp(c1->password, c2->password) &&
+#endif
+ curl_strequal(c1->cipher_list, c2->cipher_list) &&
+ curl_strequal(c1->cipher_list13, c2->cipher_list13) &&
+ curl_strequal(c1->curves, c2->curves) &&
+ curl_strequal(c1->signature_algorithms, c2->signature_algorithms) &&
+ Curl_safecmp(c1->CRLfile, c2->CRLfile) &&
+ Curl_safecmp(c1->pinned_key, c2->pinned_key) &&
+ curl_strequal(c1->cert_type, c2->cert_type) &&
+ Curl_safecmp(c1->key, c2->key) &&
+ curl_strequal(c1->key_type, c2->key_type) &&
+ !Curl_timestrcmp(c1->key_passwd, c2->key_passwd))
+ return TRUE;
+
+ return FALSE;
+}
+
+bool Curl_ssl_conn_config_match(struct Curl_easy *data,
+ struct connectdata *candidate,
+ bool proxy)
+{
+#ifndef CURL_DISABLE_PROXY
+ if(proxy)
+ return match_ssl_primary_config(data, &data->set.proxy_ssl.primary,
+ &candidate->proxy_ssl_config);
+#else
+ (void)proxy;
+#endif
+ return match_ssl_primary_config(data, &data->set.ssl.primary,
+ &candidate->ssl_config);
+}
+
+static bool clone_ssl_primary_config(struct ssl_primary_config *source,
+ struct ssl_primary_config *dest)
+{
+ DEBUGASSERT(!dest->deep_copy);
+ dest->deep_copy = TRUE;
+ dest->version = source->version;
+ dest->version_max = source->version_max;
+ dest->verifypeer = source->verifypeer;
+ dest->verifyhost = source->verifyhost;
+ dest->verifystatus = source->verifystatus;
+ dest->cache_session = source->cache_session;
+ dest->ssl_options = source->ssl_options;
+
+ CLONE_BLOB(cert_blob);
+ CLONE_BLOB(ca_info_blob);
+ CLONE_BLOB(issuercert_blob);
+ CLONE_STRING(CApath);
+ CLONE_STRING(CAfile);
+ CLONE_STRING(issuercert);
+ CLONE_STRING(cipher_list);
+ CLONE_STRING(cipher_list13);
+ CLONE_STRING(pinned_key);
+ CLONE_STRING(curves);
+ CLONE_STRING(signature_algorithms);
+ CLONE_STRING(CRLfile);
+ /* SSL credentials: client certificate, SRP auth */
+ CLONE_STRING(clientcert);
+ CLONE_STRING(cert_type);
+ CLONE_STRING(key);
+ CLONE_STRING(key_type);
+ CLONE_STRING(key_passwd);
+ CLONE_BLOB(key_blob);
+#ifdef USE_TLS_SRP
+ CLONE_STRING(username);
+ CLONE_STRING(password);
+#endif
+
+ return TRUE;
+}
+
+CURLcode Curl_ssl_easy_config_complete(struct Curl_easy *data,
+ struct Curl_peer *origin)
+{
+ struct ssl_config_data *sslc = &data->set.ssl;
+#if defined(CURL_CA_PATH) || defined(CURL_CA_BUNDLE)
+ struct UserDefined *set = &data->set;
+ CURLcode result;
+#endif
+
+ if(Curl_ssl_backend() != CURLSSLBACKEND_SCHANNEL) {
+#if defined(USE_APPLE_SECTRUST) || defined(CURL_CA_NATIVE)
+ if(!sslc->custom_capath && !sslc->custom_cafile && !sslc->custom_cablob)
+ sslc->native_ca_store = TRUE;
+#endif
+#ifdef CURL_CA_PATH
+ if(!sslc->custom_capath && !set->str[STRING_SSL_CAPATH]) {
+ result = Curl_setstropt(&set->str[STRING_SSL_CAPATH], CURL_CA_PATH);
+ if(result)
+ return result;
+ }
+#endif
+#ifdef CURL_CA_BUNDLE
+ if(!sslc->custom_cafile && !set->str[STRING_SSL_CAFILE]) {
+ result = Curl_setstropt(&set->str[STRING_SSL_CAFILE], CURL_CA_BUNDLE);
+ if(result)
+ return result;
+ }
+#endif
+ }
+ sslc->primary.CAfile = data->set.str[STRING_SSL_CAFILE];
+ sslc->primary.CRLfile = data->set.str[STRING_SSL_CRLFILE];
+ sslc->primary.CApath = data->set.str[STRING_SSL_CAPATH];
+ sslc->primary.cipher_list = data->set.str[STRING_SSL_CIPHER_LIST];
+ sslc->primary.cipher_list13 = data->set.str[STRING_SSL_CIPHER13_LIST];
+ sslc->primary.signature_algorithms =
+ data->set.str[STRING_SSL_SIGNATURE_ALGORITHMS];
+ sslc->primary.ca_info_blob = data->set.blobs[BLOB_CAINFO];
+ sslc->primary.curves = data->set.str[STRING_SSL_EC_CURVES];
+ /* Maybe these should not be used for another origin. But for
+ * backwards compatibility, keep them in. */
+ sslc->primary.issuercert = data->set.str[STRING_SSL_ISSUERCERT];
+ sslc->primary.issuercert_blob = data->set.blobs[BLOB_SSL_ISSUERCERT];
+
+ if(Curl_peer_equal(data->state.initial_origin, origin)) {
+ sslc->primary.pinned_key = data->set.str[STRING_SSL_PINNEDPUBLICKEY];
+ sslc->primary.cert_blob = data->set.blobs[BLOB_CERT];
+ sslc->primary.cert_type = data->set.str[STRING_CERT_TYPE];
+ sslc->primary.key = data->set.str[STRING_KEY];
+ sslc->primary.key_type = data->set.str[STRING_KEY_TYPE];
+ sslc->primary.key_passwd = data->set.str[STRING_KEY_PASSWD];
+ sslc->primary.clientcert = data->set.str[STRING_CERT];
+ sslc->primary.key_blob = data->set.blobs[BLOB_KEY];
+#ifdef USE_TLS_SRP
+ sslc->primary.username = data->set.str[STRING_TLSAUTH_USERNAME];
+ sslc->primary.password = data->set.str[STRING_TLSAUTH_PASSWORD];
+#endif
+ }
+ else {
+ sslc->primary.pinned_key = NULL;
+ sslc->primary.cert_blob = NULL;
+ sslc->primary.cert_type = NULL;
+ sslc->primary.key = NULL;
+ sslc->primary.key_type = NULL;
+ sslc->primary.key_passwd = NULL;
+ sslc->primary.clientcert = NULL;
+ sslc->primary.key_blob = NULL;
+#ifdef USE_TLS_SRP
+ sslc->primary.username = NULL;
+ sslc->primary.password = NULL;
+#endif
+ }
+
+#ifndef CURL_DISABLE_PROXY
+ sslc = &data->set.proxy_ssl;
+ if(Curl_ssl_backend() != CURLSSLBACKEND_SCHANNEL) {
+#if defined(USE_APPLE_SECTRUST) || defined(CURL_CA_NATIVE)
+ if(!sslc->custom_capath && !sslc->custom_cafile && !sslc->custom_cablob)
+ sslc->native_ca_store = TRUE;
+#endif
+#ifdef CURL_CA_PATH
+ if(!sslc->custom_capath && !set->str[STRING_SSL_CAPATH_PROXY]) {
+ result = Curl_setstropt(&set->str[STRING_SSL_CAPATH_PROXY],
+ CURL_CA_PATH);
+ if(result)
+ return result;
+ }
+#endif
+#ifdef CURL_CA_BUNDLE
+ if(!sslc->custom_cafile && !set->str[STRING_SSL_CAFILE_PROXY]) {
+ result = Curl_setstropt(&set->str[STRING_SSL_CAFILE_PROXY],
+ CURL_CA_BUNDLE);
+ if(result)
+ return result;
+ }
+#endif
+ }
+ sslc->primary.CAfile = data->set.str[STRING_SSL_CAFILE_PROXY];
+ sslc->primary.CApath = data->set.str[STRING_SSL_CAPATH_PROXY];
+ sslc->primary.cipher_list = data->set.str[STRING_SSL_CIPHER_LIST_PROXY];
+ sslc->primary.cipher_list13 = data->set.str[STRING_SSL_CIPHER13_LIST_PROXY];
+ sslc->primary.pinned_key = data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY];
+ sslc->primary.cert_blob = data->set.blobs[BLOB_CERT_PROXY];
+ sslc->primary.ca_info_blob = data->set.blobs[BLOB_CAINFO_PROXY];
+ sslc->primary.issuercert = data->set.str[STRING_SSL_ISSUERCERT_PROXY];
+ sslc->primary.issuercert_blob = data->set.blobs[BLOB_SSL_ISSUERCERT_PROXY];
+ sslc->primary.CRLfile = data->set.str[STRING_SSL_CRLFILE_PROXY];
+ sslc->primary.cert_type = data->set.str[STRING_CERT_TYPE_PROXY];
+ sslc->primary.key = data->set.str[STRING_KEY_PROXY];
+ sslc->primary.key_type = data->set.str[STRING_KEY_TYPE_PROXY];
+ sslc->primary.key_passwd = data->set.str[STRING_KEY_PASSWD_PROXY];
+ sslc->primary.clientcert = data->set.str[STRING_CERT_PROXY];
+ sslc->primary.key_blob = data->set.blobs[BLOB_KEY_PROXY];
+#ifdef USE_TLS_SRP
+ sslc->primary.username = data->set.str[STRING_TLSAUTH_USERNAME_PROXY];
+ sslc->primary.password = data->set.str[STRING_TLSAUTH_PASSWORD_PROXY];
+#endif
+#endif /* CURL_DISABLE_PROXY */
+
+ return CURLE_OK;
+}
+
+CURLcode Curl_ssl_conn_config_init(struct Curl_easy *data,
+ struct connectdata *conn)
+{
+ /* Clone "primary" SSL configurations from the easy handle to
+ * the connection. They are used for connection cache matching and
+ * probably outlive the easy handle */
+ if(!clone_ssl_primary_config(&data->set.ssl.primary, &conn->ssl_config))
+ return CURLE_OUT_OF_MEMORY;
+#ifndef CURL_DISABLE_PROXY
+ if(!clone_ssl_primary_config(&data->set.proxy_ssl.primary,
+ &conn->proxy_ssl_config))
+ return CURLE_OUT_OF_MEMORY;
+#endif
+ return CURLE_OK;
+}
+
+void Curl_ssl_conn_config_cleanup(struct connectdata *conn)
+{
+ Curl_ssl_config_cleanup(&conn->ssl_config);
+#ifndef CURL_DISABLE_PROXY
+ Curl_ssl_config_cleanup(&conn->proxy_ssl_config);
+#endif
+}
+
+void Curl_ssl_conn_config_update(struct Curl_easy *data, bool for_proxy)
+{
+ /* May be called on an easy that has no connection yet */
+ if(data->conn) {
+ struct ssl_primary_config *src, *dest;
+#ifndef CURL_DISABLE_PROXY
+ src = for_proxy ? &data->set.proxy_ssl.primary : &data->set.ssl.primary;
+ dest = for_proxy ? &data->conn->proxy_ssl_config : &data->conn->ssl_config;
+#else
+ (void)for_proxy;
+ src = &data->set.ssl.primary;
+ dest = &data->conn->ssl_config;
+#endif
+ dest->verifyhost = src->verifyhost;
+ dest->verifypeer = src->verifypeer;
+ dest->verifystatus = src->verifystatus;
+ }
+}
--- /dev/null
+#ifndef HEADER_CURL_VTLS_CONFIG_H
+#define HEADER_CURL_VTLS_CONFIG_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+struct Curl_easy;
+struct connectdata;
+struct Curl_peer;
+
+struct ssl_primary_config {
+ char *CApath; /* certificate directory (does not work on Windows) */
+ char *CAfile; /* certificate to verify peer against */
+ char *issuercert; /* optional issuer certificate filename */
+ char *clientcert;
+ char *cipher_list; /* list of ciphers to use */
+ char *cipher_list13; /* list of TLS 1.3 cipher suites to use */
+ char *signature_algorithms; /* list of signature algorithms to use */
+ char *pinned_key;
+ char *CRLfile; /* CRL to check certificate revocation */
+ char *cert_type; /* format for certificate (default: PEM) */
+ char *key; /* private key filename */
+ char *key_type; /* format for private key (default: PEM) */
+ char *key_passwd; /* plain text private key password */
+ struct curl_blob *cert_blob;
+ struct curl_blob *ca_info_blob;
+ struct curl_blob *issuercert_blob;
+ struct curl_blob *key_blob;
+#ifdef USE_TLS_SRP
+ char *username; /* TLS username (for, e.g., SRP) */
+ char *password; /* TLS password (for, e.g., SRP) */
+#endif
+ char *curves; /* list of curves to use */
+ uint32_t version_max; /* max supported version the client wants to use */
+ uint8_t ssl_options; /* the CURLOPT_SSL_OPTIONS bitmask */
+ uint8_t version; /* what version the client wants to use */
+ BIT(verifypeer); /* set TRUE if this is desired */
+ BIT(verifyhost); /* set TRUE if CN/SAN must match hostname */
+ BIT(verifystatus); /* set TRUE if certificate status must be checked */
+ BIT(cache_session); /* cache session or not */
+ BIT(deep_copy); /* members are deep copies, eg. owned here */
+};
+
+struct ssl_config_data {
+ struct ssl_primary_config primary;
+ long certverifyresult; /* result from the certificate verification */
+ curl_ssl_ctx_callback fsslctx; /* function to initialize SSL ctx */
+ void *fsslctxp; /* parameter for call back */
+ BIT(certinfo); /* gather lots of certificate info */
+ BIT(earlydata); /* use TLS 1.3 early data */
+ BIT(enable_beast); /* allow this flaw for interoperability's sake */
+ BIT(no_revoke); /* disable SSL certificate revocation checks */
+ BIT(no_partialchain); /* do not accept partial certificate chains */
+ BIT(revoke_best_effort); /* ignore SSL revocation offline/missing revocation
+ list errors */
+ BIT(native_ca_store); /* use the native CA store of operating system */
+ BIT(auto_client_cert); /* automatically locate and use a client
+ certificate for authentication (Schannel) */
+ BIT(custom_cafile); /* application has set custom CA file */
+ BIT(custom_capath); /* application has set custom CA path */
+ BIT(custom_cablob); /* application has set custom CA blob */
+};
+
+struct ssl_general_config {
+ int ca_cache_timeout; /* Certificate store cache timeout (seconds) */
+};
+
+void Curl_ssl_config_init(struct ssl_primary_config *sslc);
+void Curl_ssl_config_cleanup(struct ssl_primary_config *sslc);
+
+/**
+ * Init the `data->set.ssl` and `data->set.proxy_ssl` for
+ * connection matching use.
+ */
+CURLcode Curl_ssl_easy_config_complete(struct Curl_easy *data,
+ struct Curl_peer *origin);
+
+/**
+ * Init SSL configs (main + proxy) for a new connection from the easy handle.
+ */
+CURLcode Curl_ssl_conn_config_init(struct Curl_easy *data,
+ struct connectdata *conn);
+
+/**
+ * Free allocated resources in SSL configs (main + proxy) for
+ * the given connection.
+ */
+void Curl_ssl_conn_config_cleanup(struct connectdata *conn);
+
+/**
+ * Return TRUE iff SSL configuration from `data` is functionally the
+ * same as the one on `candidate`.
+ * @param proxy match the proxy SSL config or the main one
+ */
+bool Curl_ssl_conn_config_match(struct Curl_easy *data,
+ struct connectdata *candidate,
+ bool proxy);
+
+/* Update certain connection SSL config flags after they have
+ * been changed on the easy handle. Works for `verifypeer`,
+ * `verifyhost` and `verifystatus`. */
+void Curl_ssl_conn_config_update(struct Curl_easy *data, bool for_proxy);
+
+#endif /* HEADER_CURL_VTLS_CONFIG_H */
static char alt_key[] = "other.key";
static char alt_ktype[] = "DER";
static char alt_ctype[] = "P12";
+ struct Curl_peer *origin = NULL;
+ CURLcode result;
curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
goto unit_test_abort;
}
+ result = Curl_peer_create((struct Curl_easy *)curl,
+ &Curl_scheme_https,
+ "test.curl.se", 1234, &origin);
+ if(result) {
+ curl_easy_cleanup(curl);
+ curl_global_cleanup();
+ goto unit_test_abort;
+ }
+ Curl_peer_link(&((struct Curl_easy *)curl)->state.initial_origin, origin);
+
curl_easy_setopt(curl, CURLOPT_SSLCERT, "client.pem");
curl_easy_setopt(curl, CURLOPT_SSLKEY, "client.key");
curl_easy_setopt(curl, CURLOPT_KEYPASSWD, "secret");
curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, "PEM");
curl_easy_setopt(curl, CURLOPT_SSLKEYTYPE, "PEM");
- if(Curl_ssl_easy_config_complete((struct Curl_easy *)curl)) {
+ if(Curl_ssl_easy_config_complete((struct Curl_easy *)curl, origin)) {
+ Curl_peer_unlink(&origin);
curl_easy_cleanup(curl);
curl_global_cleanup();
goto unit_test_abort;
if(conn)
Curl_ssl_conn_config_cleanup(conn);
curlx_free(conn);
+ Curl_peer_unlink(&origin);
curl_easy_cleanup(curl);
curl_global_cleanup();
goto unit_test_abort;
Curl_ssl_conn_config_cleanup(conn);
curlx_free(conn);
curl_easy_cleanup(curl);
+ Curl_peer_unlink(&origin);
curl_global_cleanup();
#endif /* USE_SSL */