blob: f09704c8a91cada405a47937f1b12fef4235b90a [file] [log] [blame]
From 205cf19fc374ee8eb848c5448e31fa703392832e Mon Sep 17 00:00:00 2001
From: Daniel Stenberg <daniel@haxx.se>
Date: Wed, 4 Aug 2021 01:52:40 +0000
Subject: [PATCH] vtls: fix connection reuse checks for issuer cert and case
sensitivity
CVE-2021-22924
Reported-by: Harry Sintonen
Bug: https://curl.se/docs/CVE-2021-22924.html
CVE: CVE-2021-22924
Upstream-Status: Backport [https://github.com/curl/curl/commit/5ea3145850ebff1dc2b13d17440300a01ca38161]
Signed-off-by: Mingli Yu <mingli.yu@windriver.com>
---
lib/url.c | 10 ++++++----
lib/urldata.h | 6 ++++--
lib/vtls/gtls.c | 10 +++++-----
lib/vtls/nss.c | 4 ++--
lib/vtls/openssl.c | 18 +++++++++---------
lib/vtls/vtls.c | 26 +++++++++++++++++++++-----
6 files changed, 47 insertions(+), 27 deletions(-)
diff --git a/lib/url.c b/lib/url.c
index c02d2c2..474c53b 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -3695,6 +3695,8 @@ static CURLcode create_conn(struct Curl_easy *data,
*/
data->set.ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH_ORIG];
data->set.ssl.primary.CAfile = data->set.str[STRING_SSL_CAFILE_ORIG];
+ data->set.ssl.primary.issuercert = data->set.str[STRING_SSL_ISSUERCERT];
+ data->set.ssl.primary.issuercert_blob = data->set.blobs[BLOB_SSL_ISSUERCERT];
data->set.ssl.primary.random_file = data->set.str[STRING_SSL_RANDOM_FILE];
data->set.ssl.primary.egdsocket = data->set.str[STRING_SSL_EGDSOCKET];
data->set.ssl.primary.cipher_list =
@@ -3719,8 +3721,11 @@ static CURLcode create_conn(struct Curl_easy *data,
data->set.proxy_ssl.primary.pinned_key =
data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY];
data->set.proxy_ssl.primary.cert_blob = data->set.blobs[BLOB_CERT_PROXY];
+ data->set.proxy_ssl.primary.issuercert =
+ data->set.str[STRING_SSL_ISSUERCERT_PROXY];
+ data->set.proxy_ssl.primary.issuercert_blob =
+ data->set.blobs[BLOB_SSL_ISSUERCERT_PROXY];
data->set.proxy_ssl.CRLfile = data->set.str[STRING_SSL_CRLFILE_PROXY];
- data->set.proxy_ssl.issuercert = data->set.str[STRING_SSL_ISSUERCERT_PROXY];
data->set.proxy_ssl.cert_type = data->set.str[STRING_CERT_TYPE_PROXY];
data->set.proxy_ssl.key = data->set.str[STRING_KEY_PROXY];
data->set.proxy_ssl.key_type = data->set.str[STRING_KEY_TYPE_PROXY];
@@ -3729,7 +3734,6 @@ static CURLcode create_conn(struct Curl_easy *data,
data->set.proxy_ssl.key_blob = data->set.blobs[BLOB_KEY_PROXY];
#endif
data->set.ssl.CRLfile = data->set.str[STRING_SSL_CRLFILE_ORIG];
- data->set.ssl.issuercert = data->set.str[STRING_SSL_ISSUERCERT_ORIG];
data->set.ssl.cert_type = data->set.str[STRING_CERT_TYPE_ORIG];
data->set.ssl.key = data->set.str[STRING_KEY_ORIG];
data->set.ssl.key_type = data->set.str[STRING_KEY_TYPE_ORIG];
@@ -3743,9 +3747,7 @@ static CURLcode create_conn(struct Curl_easy *data,
data->set.proxy_ssl.password = data->set.str[STRING_TLSAUTH_PASSWORD_PROXY];
#endif
#endif
-
data->set.ssl.key_blob = data->set.blobs[BLOB_KEY_ORIG];
- data->set.ssl.issuercert_blob = data->set.blobs[BLOB_SSL_ISSUERCERT_ORIG];
if(!Curl_clone_primary_ssl_config(&data->set.ssl.primary,
&conn->ssl_config)) {
diff --git a/lib/urldata.h b/lib/urldata.h
index f7d60b2..7d01874 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -246,6 +246,7 @@ struct ssl_primary_config {
long version_max; /* max supported version the client wants to use*/
char *CApath; /* certificate dir (doesn't work on windows) */
char *CAfile; /* certificate to verify peer against */
+ char *issuercert; /* optional issuer certificate filename */
char *clientcert;
char *random_file; /* path to file containing "random" data */
char *egdsocket; /* path to file containing the EGD daemon socket */
@@ -253,6 +254,7 @@ struct ssl_primary_config {
char *cipher_list13; /* list of TLS 1.3 cipher suites to use */
char *pinned_key;
struct curl_blob *cert_blob;
+ struct curl_blob *issuercert_blob;
char *curves; /* list of curves to use */
BIT(verifypeer); /* set TRUE if this is desired */
BIT(verifyhost); /* set TRUE if CN/SAN must match hostname */
@@ -264,8 +266,6 @@ struct ssl_config_data {
struct ssl_primary_config primary;
long certverifyresult; /* result from the certificate verification */
char *CRLfile; /* CRL to check certificate revocation */
- char *issuercert;/* optional issuer certificate filename */
- struct curl_blob *issuercert_blob;
curl_ssl_ctx_callback fsslctx; /* function to initialize ssl ctx */
void *fsslctxp; /* parameter for call back */
char *cert_type; /* format for certificate (default: PEM)*/
@@ -1545,6 +1545,7 @@ enum dupstring {
STRING_SSL_CRLFILE_ORIG, /* crl file to check certificate */
STRING_SSL_CRLFILE_PROXY, /* crl file to check certificate */
STRING_SSL_ISSUERCERT_ORIG, /* issuer cert file to check certificate */
+ STRING_SSL_ISSUERCERT, /* issuer cert file to check certificate */
STRING_SSL_ISSUERCERT_PROXY, /* issuer cert file to check certificate */
STRING_SSL_ENGINE, /* name of ssl engine */
STRING_USERNAME, /* <username>, if used */
@@ -1600,6 +1601,7 @@ enum dupblob {
BLOB_CERT_PROXY,
BLOB_KEY_ORIG,
BLOB_KEY_PROXY,
+ BLOB_SSL_ISSUERCERT,
BLOB_SSL_ISSUERCERT_ORIG,
BLOB_SSL_ISSUERCERT_PROXY,
BLOB_LAST
diff --git a/lib/vtls/gtls.c b/lib/vtls/gtls.c
index 2c65ba0..d1c3919 100644
--- a/lib/vtls/gtls.c
+++ b/lib/vtls/gtls.c
@@ -855,7 +855,7 @@ gtls_connect_step3(struct Curl_easy *data,
if(!chainp) {
if(SSL_CONN_CONFIG(verifypeer) ||
SSL_CONN_CONFIG(verifyhost) ||
- SSL_SET_OPTION(issuercert)) {
+ SSL_CONN_CONFIG(issuercert)) {
#ifdef HAVE_GNUTLS_SRP
if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP
&& SSL_SET_OPTION(username) != NULL
@@ -1039,21 +1039,21 @@ gtls_connect_step3(struct Curl_easy *data,
gnutls_x509_crt_t format */
gnutls_x509_crt_import(x509_cert, chainp, GNUTLS_X509_FMT_DER);
- if(SSL_SET_OPTION(issuercert)) {
+ if(SSL_CONN_CONFIG(issuercert)) {
gnutls_x509_crt_init(&x509_issuer);
- issuerp = load_file(SSL_SET_OPTION(issuercert));
+ issuerp = load_file(SSL_CONN_CONFIG(issuercert));
gnutls_x509_crt_import(x509_issuer, &issuerp, GNUTLS_X509_FMT_PEM);
rc = gnutls_x509_crt_check_issuer(x509_cert, x509_issuer);
gnutls_x509_crt_deinit(x509_issuer);
unload_file(issuerp);
if(rc <= 0) {
failf(data, "server certificate issuer check failed (IssuerCert: %s)",
- SSL_SET_OPTION(issuercert)?SSL_SET_OPTION(issuercert):"none");
+ SSL_CONN_CONFIG(issuercert)?SSL_CONN_CONFIG(issuercert):"none");
gnutls_x509_crt_deinit(x509_cert);
return CURLE_SSL_ISSUER_ERROR;
}
infof(data, "\t server certificate issuer check OK (Issuer Cert: %s)\n",
- SSL_SET_OPTION(issuercert)?SSL_SET_OPTION(issuercert):"none");
+ SSL_CONN_CONFIG(issuercert)?SSL_CONN_CONFIG(issuercert):"none");
}
size = sizeof(certname);
diff --git a/lib/vtls/nss.c b/lib/vtls/nss.c
index fb9f763..dab12b6 100644
--- a/lib/vtls/nss.c
+++ b/lib/vtls/nss.c
@@ -2159,9 +2159,9 @@ static CURLcode nss_do_connect(struct Curl_easy *data,
if(result)
goto error;
- if(SSL_SET_OPTION(issuercert)) {
+ if(SSL_CONN_CONFIG(issuercert)) {
SECStatus ret = SECFailure;
- char *nickname = dup_nickname(data, SSL_SET_OPTION(issuercert));
+ char *nickname = dup_nickname(data, SSL_CONN_CONFIG(issuercert));
if(nickname) {
/* we support only nicknames in case of issuercert for now */
ret = check_issuer_cert(backend->handle, nickname);
diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c
index 946b4c5..85e1ee5 100644
--- a/lib/vtls/openssl.c
+++ b/lib/vtls/openssl.c
@@ -3881,10 +3881,10 @@ static CURLcode servercert(struct Curl_easy *data,
deallocating the certificate. */
/* e.g. match issuer name with provided issuer certificate */
- if(SSL_SET_OPTION(issuercert) || SSL_SET_OPTION(issuercert_blob)) {
- if(SSL_SET_OPTION(issuercert_blob))
- fp = BIO_new_mem_buf(SSL_SET_OPTION(issuercert_blob)->data,
- (int)SSL_SET_OPTION(issuercert_blob)->len);
+ if(SSL_CONN_CONFIG(issuercert) || SSL_CONN_CONFIG(issuercert_blob)) {
+ if(SSL_CONN_CONFIG(issuercert_blob))
+ fp = BIO_new_mem_buf(SSL_CONN_CONFIG(issuercert_blob)->data,
+ (int)SSL_CONN_CONFIG(issuercert_blob)->len);
else {
fp = BIO_new(BIO_s_file());
if(fp == NULL) {
@@ -3898,10 +3898,10 @@ static CURLcode servercert(struct Curl_easy *data,
return CURLE_OUT_OF_MEMORY;
}
- if(BIO_read_filename(fp, SSL_SET_OPTION(issuercert)) <= 0) {
+ if(BIO_read_filename(fp, SSL_CONN_CONFIG(issuercert)) <= 0) {
if(strict)
failf(data, "SSL: Unable to open issuer cert (%s)",
- SSL_SET_OPTION(issuercert));
+ SSL_CONN_CONFIG(issuercert));
BIO_free(fp);
X509_free(backend->server_cert);
backend->server_cert = NULL;
@@ -3913,7 +3913,7 @@ static CURLcode servercert(struct Curl_easy *data,
if(!issuer) {
if(strict)
failf(data, "SSL: Unable to read issuer cert (%s)",
- SSL_SET_OPTION(issuercert));
+ SSL_CONN_CONFIG(issuercert));
BIO_free(fp);
X509_free(issuer);
X509_free(backend->server_cert);
@@ -3924,7 +3924,7 @@ static CURLcode servercert(struct Curl_easy *data,
if(X509_check_issued(issuer, backend->server_cert) != X509_V_OK) {
if(strict)
failf(data, "SSL: Certificate issuer check failed (%s)",
- SSL_SET_OPTION(issuercert));
+ SSL_CONN_CONFIG(issuercert));
BIO_free(fp);
X509_free(issuer);
X509_free(backend->server_cert);
@@ -3933,7 +3933,7 @@ static CURLcode servercert(struct Curl_easy *data,
}
infof(data, " SSL certificate issuer check ok (%s)\n",
- SSL_SET_OPTION(issuercert));
+ SSL_CONN_CONFIG(issuercert));
BIO_free(fp);
X509_free(issuer);
}
diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c
index 59a7efb..eb885da 100644
--- a/lib/vtls/vtls.c
+++ b/lib/vtls/vtls.c
@@ -125,6 +125,16 @@ static bool blobcmp(struct curl_blob *first, struct curl_blob *second)
return !memcmp(first->data, second->data, first->len); /* same data */
}
+static bool safecmp(char *a, char *b)
+{
+ if(a && b)
+ return !strcmp(a, b);
+ else if(!a && !b)
+ return TRUE; /* match */
+ return FALSE; /* no match */
+}
+
+
bool
Curl_ssl_config_matches(struct ssl_primary_config *data,
struct ssl_primary_config *needle)
@@ -135,11 +145,13 @@ Curl_ssl_config_matches(struct ssl_primary_config *data,
(data->verifyhost == needle->verifyhost) &&
(data->verifystatus == needle->verifystatus) &&
blobcmp(data->cert_blob, needle->cert_blob) &&
- Curl_safe_strcasecompare(data->CApath, needle->CApath) &&
- Curl_safe_strcasecompare(data->CAfile, needle->CAfile) &&
- Curl_safe_strcasecompare(data->clientcert, needle->clientcert) &&
- Curl_safe_strcasecompare(data->random_file, needle->random_file) &&
- Curl_safe_strcasecompare(data->egdsocket, needle->egdsocket) &&
+ blobcmp(data->issuercert_blob, needle->issuercert_blob) &&
+ safecmp(data->CApath, needle->CApath) &&
+ safecmp(data->CAfile, needle->CAfile) &&
+ safecmp(data->issuercert, needle->issuercert) &&
+ safecmp(data->clientcert, needle->clientcert) &&
+ safecmp(data->random_file, needle->random_file) &&
+ safecmp(data->egdsocket, needle->egdsocket) &&
Curl_safe_strcasecompare(data->cipher_list, needle->cipher_list) &&
Curl_safe_strcasecompare(data->cipher_list13, needle->cipher_list13) &&
Curl_safe_strcasecompare(data->curves, needle->curves) &&
@@ -161,8 +173,10 @@ Curl_clone_primary_ssl_config(struct ssl_primary_config *source,
dest->sessionid = source->sessionid;
CLONE_BLOB(cert_blob);
+ CLONE_BLOB(issuercert_blob);
CLONE_STRING(CApath);
CLONE_STRING(CAfile);
+ CLONE_STRING(issuercert);
CLONE_STRING(clientcert);
CLONE_STRING(random_file);
CLONE_STRING(egdsocket);
@@ -178,6 +192,7 @@ void Curl_free_primary_ssl_config(struct ssl_primary_config *sslc)
{
Curl_safefree(sslc->CApath);
Curl_safefree(sslc->CAfile);
+ Curl_safefree(sslc->issuercert);
Curl_safefree(sslc->clientcert);
Curl_safefree(sslc->random_file);
Curl_safefree(sslc->egdsocket);
@@ -185,6 +200,7 @@ void Curl_free_primary_ssl_config(struct ssl_primary_config *sslc)
Curl_safefree(sslc->cipher_list13);
Curl_safefree(sslc->pinned_key);
Curl_safefree(sslc->cert_blob);
+ Curl_safefree(sslc->issuercert_blob);
Curl_safefree(sslc->curves);
}
--
2.31.1