]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
vtls_config: adjust to origin
authorStefan Eissing <stefan@eissing.org>
Wed, 20 May 2026 11:25:49 +0000 (13:25 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Mon, 1 Jun 2026 07:39:17 +0000 (09:39 +0200)
When a transfer goes against another origin than the initial one, do not
add the following to the ssl configuration: client cert, client key, srp
user/pass, pinned key.

Closes #21695

lib/Makefile.inc
lib/url.c
lib/urldata.h
lib/vtls/vtls.c
lib/vtls/vtls.h
lib/vtls/vtls_config.c [new file with mode: 0644]
lib/vtls/vtls_config.h [new file with mode: 0644]
tests/unit/unit3303.c

index 0a9e6ce3114304edb50920a25563fdb70dc1cb9f..28647baff4a93efe0ca5748dd44cfc8f3d04705d 100644 (file)
@@ -96,6 +96,7 @@ LIB_VTLS_CFILES =           \
   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            \
@@ -113,6 +114,7 @@ LIB_VTLS_HFILES =           \
   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         \
index 868767a772599e3f0172c5ac8482687b1de24957..76a8c2e3e7dcccb3ed817a36d8c3b521f2795e18 100644 (file)
--- a/lib/url.c
+++ b/lib/url.c
@@ -300,6 +300,10 @@ CURLcode Curl_close(struct Curl_easy **datap)
   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;
@@ -355,7 +359,9 @@ void Curl_init_userdefined(struct Curl_easy *data)
 
   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 */
@@ -363,7 +369,6 @@ void Curl_init_userdefined(struct Curl_easy *data)
   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;
@@ -2782,7 +2787,7 @@ static CURLcode url_find_or_create_conn(struct Curl_easy *data)
 #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;
 
index 4ee5108b17508f7ea6e89fd20c3c7a736be851df..e5363cf5696437f37a2e739738c864e6d96161cc 100644 (file)
@@ -69,6 +69,7 @@
 #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 */
@@ -140,62 +141,6 @@ typedef CURLcode (Curl_recv)(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
index eb0aa4277f9a04d49f2c5bf13418f9be43890ab3..c147a2ef19dfb47e767ce4fd3dc24a1e3773a434 100644 (file)
 #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 = {
@@ -177,280 +126,6 @@ static const struct alpn_spec *alpn_get_spec(http_majors wanted,
 #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
index dfda7d0f2ed15bd06e8c5ac1f2e9de649f7789e2..f0825c37ed9a3ee89d9234abf0ea817af5accbff 100644 (file)
@@ -103,43 +103,6 @@ CURLsslset Curl_init_sslset_nolock(curl_sslbackend id, const char *name,
 
 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.
  */
diff --git a/lib/vtls/vtls_config.c b/lib/vtls/vtls_config.c
new file mode 100644 (file)
index 0000000..771c610
--- /dev/null
@@ -0,0 +1,399 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  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;
+  }
+}
diff --git a/lib/vtls/vtls_config.h b/lib/vtls/vtls_config.h
new file mode 100644 (file)
index 0000000..44e691d
--- /dev/null
@@ -0,0 +1,125 @@
+#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 */
index e979cbec8d03e60e57f90cece1a743de6bc48ad5..56f52ebf57309fb2b16390eb1f68d21120d4d6c4 100644 (file)
@@ -41,6 +41,8 @@ static CURLcode test_unit3303(const char *arg)
   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();
@@ -49,13 +51,24 @@ static CURLcode test_unit3303(const char *arg)
     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;
@@ -66,6 +79,7 @@ static CURLcode test_unit3303(const char *arg)
     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;
@@ -118,6 +132,7 @@ static CURLcode test_unit3303(const char *arg)
   Curl_ssl_conn_config_cleanup(conn);
   curlx_free(conn);
   curl_easy_cleanup(curl);
+  Curl_peer_unlink(&origin);
   curl_global_cleanup();
 #endif /* USE_SSL */