summaryrefslogtreecommitdiffstats
path: root/Utilities/cmcurl/lib/vtls
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2018-05-18 14:16:50 (GMT)
committerBrad King <brad.king@kitware.com>2018-05-18 14:16:50 (GMT)
commit3e913b819d8d8118d5e8dc3b7289f622e9ca92e5 (patch)
tree82c19f5ec814c84b986e54e3fc6fa0a83622fd81 /Utilities/cmcurl/lib/vtls
parentf3c73b878c594d40119e480ca1074e733d7ba1ce (diff)
parentd431136e029c652f5913bcebeaab3b9236b114c4 (diff)
downloadCMake-3e913b819d8d8118d5e8dc3b7289f622e9ca92e5.zip
CMake-3e913b819d8d8118d5e8dc3b7289f622e9ca92e5.tar.gz
CMake-3e913b819d8d8118d5e8dc3b7289f622e9ca92e5.tar.bz2
Merge branch 'upstream-curl' into update-curl
* upstream-curl: curl 2018-05-15 (cb013830)
Diffstat (limited to 'Utilities/cmcurl/lib/vtls')
-rw-r--r--Utilities/cmcurl/lib/vtls/axtls.c10
-rw-r--r--Utilities/cmcurl/lib/vtls/cyassl.c31
-rw-r--r--Utilities/cmcurl/lib/vtls/darwinssl.c90
-rw-r--r--Utilities/cmcurl/lib/vtls/gskit.c10
-rw-r--r--Utilities/cmcurl/lib/vtls/gtls.c31
-rw-r--r--Utilities/cmcurl/lib/vtls/mbedtls.c21
-rw-r--r--Utilities/cmcurl/lib/vtls/nss.c27
-rw-r--r--Utilities/cmcurl/lib/vtls/openssl.c227
-rw-r--r--Utilities/cmcurl/lib/vtls/polarssl.c16
-rw-r--r--Utilities/cmcurl/lib/vtls/schannel.c483
-rw-r--r--Utilities/cmcurl/lib/vtls/schannel.h40
-rw-r--r--Utilities/cmcurl/lib/vtls/schannel_verify.c551
-rw-r--r--Utilities/cmcurl/lib/vtls/vtls.c25
-rw-r--r--Utilities/cmcurl/lib/vtls/vtls.h21
14 files changed, 1228 insertions, 355 deletions
diff --git a/Utilities/cmcurl/lib/vtls/axtls.c b/Utilities/cmcurl/lib/vtls/axtls.c
index 9294f49..5ed898b 100644
--- a/Utilities/cmcurl/lib/vtls/axtls.c
+++ b/Utilities/cmcurl/lib/vtls/axtls.c
@@ -6,7 +6,7 @@
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2010, DirecTV, Contact: Eric Hu, <ehu@directv.com>.
- * Copyright (C) 2010 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2010 - 2018, 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
@@ -703,13 +703,7 @@ static void *Curl_axtls_get_internals(struct ssl_connect_data *connssl,
const struct Curl_ssl Curl_ssl_axtls = {
{ CURLSSLBACKEND_AXTLS, "axtls" }, /* info */
-
- 0, /* have_ca_path */
- 0, /* have_certinfo */
- 0, /* have_pinnedpubkey */
- 0, /* have_ssl_ctx */
- 0, /* support_https_proxy */
-
+ 0, /* no fancy stuff */
sizeof(struct ssl_backend_data),
/*
diff --git a/Utilities/cmcurl/lib/vtls/cyassl.c b/Utilities/cmcurl/lib/vtls/cyassl.c
index 46b71bf..20ce460 100644
--- a/Utilities/cmcurl/lib/vtls/cyassl.c
+++ b/Utilities/cmcurl/lib/vtls/cyassl.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2018, 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
@@ -187,8 +187,13 @@ cyassl_connect_step1(struct connectdata *conn,
use_sni(TRUE);
break;
case CURL_SSLVERSION_TLSv1_0:
+#ifdef WOLFSSL_ALLOW_TLSV10
req_method = TLSv1_client_method();
use_sni(TRUE);
+#else
+ failf(data, "CyaSSL does not support TLS 1.0");
+ return CURLE_NOT_BUILT_IN;
+#endif
break;
case CURL_SSLVERSION_TLSv1_1:
req_method = TLSv1_1_client_method();
@@ -199,8 +204,14 @@ cyassl_connect_step1(struct connectdata *conn,
use_sni(TRUE);
break;
case CURL_SSLVERSION_TLSv1_3:
+#ifdef WOLFSSL_TLS13
+ req_method = wolfTLSv1_3_client_method();
+ use_sni(TRUE);
+ break;
+#else
failf(data, "CyaSSL: TLS 1.3 is not yet supported");
return CURLE_SSL_CONNECT_ERROR;
+#endif
case CURL_SSLVERSION_SSLv3:
#ifdef WOLFSSL_ALLOW_SSLV3
req_method = SSLv3_client_method();
@@ -245,7 +256,11 @@ cyassl_connect_step1(struct connectdata *conn,
*/
if((wolfSSL_CTX_SetMinVersion(BACKEND->ctx, WOLFSSL_TLSV1) != 1) &&
(wolfSSL_CTX_SetMinVersion(BACKEND->ctx, WOLFSSL_TLSV1_1) != 1) &&
- (wolfSSL_CTX_SetMinVersion(BACKEND->ctx, WOLFSSL_TLSV1_2) != 1)) {
+ (wolfSSL_CTX_SetMinVersion(BACKEND->ctx, WOLFSSL_TLSV1_2) != 1)
+#ifdef WOLFSSL_TLS13
+ && (wolfSSL_CTX_SetMinVersion(BACKEND->ctx, WOLFSSL_TLSV1_3) != 1)
+#endif
+ ) {
failf(data, "SSL: couldn't set the minimum protocol version");
return CURLE_SSL_CONNECT_ERROR;
}
@@ -956,7 +971,7 @@ static CURLcode Curl_cyassl_random(struct Curl_easy *data,
return CURLE_OK;
}
-static void Curl_cyassl_sha256sum(const unsigned char *tmp, /* input */
+static CURLcode Curl_cyassl_sha256sum(const unsigned char *tmp, /* input */
size_t tmplen,
unsigned char *sha256sum /* output */,
size_t unused)
@@ -966,6 +981,7 @@ static void Curl_cyassl_sha256sum(const unsigned char *tmp, /* input */
InitSha256(&SHA256pw);
Sha256Update(&SHA256pw, tmp, (word32)tmplen);
Sha256Final(&SHA256pw, sha256sum);
+ return CURLE_OK;
}
static void *Curl_cyassl_get_internals(struct ssl_connect_data *connssl,
@@ -978,15 +994,10 @@ static void *Curl_cyassl_get_internals(struct ssl_connect_data *connssl,
const struct Curl_ssl Curl_ssl_cyassl = {
{ CURLSSLBACKEND_WOLFSSL, "WolfSSL" }, /* info */
- 0, /* have_ca_path */
- 0, /* have_certinfo */
#ifdef KEEP_PEER_CERT
- 1, /* have_pinnedpubkey */
-#else
- 0, /* have_pinnedpubkey */
+ SSLSUPP_PINNEDPUBKEY |
#endif
- 1, /* have_ssl_ctx */
- 0, /* support_https_proxy */
+ SSLSUPP_SSL_CTX,
sizeof(struct ssl_backend_data),
diff --git a/Utilities/cmcurl/lib/vtls/darwinssl.c b/Utilities/cmcurl/lib/vtls/darwinssl.c
index 53a7ec3..45fe49d 100644
--- a/Utilities/cmcurl/lib/vtls/darwinssl.c
+++ b/Utilities/cmcurl/lib/vtls/darwinssl.c
@@ -6,7 +6,7 @@
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2012 - 2017, Nick Zitzmann, <nickzman@gmail.com>.
- * Copyright (C) 2012 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2012 - 2018, 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
@@ -1135,28 +1135,79 @@ static OSStatus CopyIdentityFromPKCS12File(const char *cPath,
raise linker errors when used on that cat for some reason. */
#if CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS
if(CFURLCreateDataAndPropertiesFromResource(NULL, pkcs_url, &pkcs_data,
- NULL, NULL, &status)) {
+ NULL, NULL, &status)) {
+ CFArrayRef items = NULL;
+
+ /* On iOS SecPKCS12Import will never add the client certificate to the
+ * Keychain.
+ *
+ * It gives us back a SecIdentityRef that we can use directly. */
+#if CURL_BUILD_IOS
const void *cKeys[] = {kSecImportExportPassphrase};
const void *cValues[] = {password};
CFDictionaryRef options = CFDictionaryCreate(NULL, cKeys, cValues,
password ? 1L : 0L, NULL, NULL);
- CFArrayRef items = NULL;
- /* Here we go: */
- status = SecPKCS12Import(pkcs_data, options, &items);
- if(status == errSecSuccess && items && CFArrayGetCount(items)) {
- CFDictionaryRef identity_and_trust = CFArrayGetValueAtIndex(items, 0L);
- const void *temp_identity = CFDictionaryGetValue(identity_and_trust,
- kSecImportItemIdentity);
+ if(options != NULL) {
+ status = SecPKCS12Import(pkcs_data, options, &items);
+ CFRelease(options);
+ }
+
+
+ /* On macOS SecPKCS12Import will always add the client certificate to
+ * the Keychain.
+ *
+ * As this doesn't match iOS, and apps may not want to see their client
+ * certificate saved in the the user's keychain, we use SecItemImport
+ * with a NULL keychain to avoid importing it.
+ *
+ * This returns a SecCertificateRef from which we can construct a
+ * SecIdentityRef.
+ */
+#elif CURL_BUILD_MAC_10_7
+ SecItemImportExportKeyParameters keyParams;
+ SecExternalFormat inputFormat = kSecFormatPKCS12;
+ SecExternalItemType inputType = kSecItemTypeCertificate;
- /* Retain the identity; we don't care about any other data... */
- CFRetain(temp_identity);
- *out_cert_and_key = (SecIdentityRef)temp_identity;
+ memset(&keyParams, 0x00, sizeof(keyParams));
+ keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
+ keyParams.passphrase = password;
+
+ status = SecItemImport(pkcs_data, NULL, &inputFormat, &inputType,
+ 0, &keyParams, NULL, &items);
+#endif
+
+
+ /* Extract the SecIdentityRef */
+ if(status == errSecSuccess && items && CFArrayGetCount(items)) {
+ CFIndex i, count;
+ count = CFArrayGetCount(items);
+
+ for(i = 0; i < count; i++) {
+ CFTypeRef item = (CFTypeRef) CFArrayGetValueAtIndex(items, i);
+ CFTypeID itemID = CFGetTypeID(item);
+
+ if(itemID == CFDictionaryGetTypeID()) {
+ CFTypeRef identity = (CFTypeRef) CFDictionaryGetValue(
+ (CFDictionaryRef) item,
+ kSecImportItemIdentity);
+ CFRetain(identity);
+ *out_cert_and_key = (SecIdentityRef) identity;
+ break;
+ }
+#if CURL_BUILD_MAC_10_7
+ else if(itemID == SecCertificateGetTypeID()) {
+ status = SecIdentityCreateWithCertificate(NULL,
+ (SecCertificateRef) item,
+ out_cert_and_key);
+ break;
+ }
+#endif
+ }
}
if(items)
CFRelease(items);
- CFRelease(options);
CFRelease(pkcs_data);
}
#endif /* CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS */
@@ -1340,7 +1391,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
#endif /* CURL_BUILD_MAC */
#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
- if(SSLCreateContext != NULL) { /* use the newer API if avaialble */
+ if(SSLCreateContext != NULL) { /* use the newer API if available */
if(BACKEND->ssl_ctx)
CFRelease(BACKEND->ssl_ctx);
BACKEND->ssl_ctx = SSLCreateContext(NULL, kSSLClientSide, kSSLStreamType);
@@ -2843,13 +2894,14 @@ static CURLcode Curl_darwinssl_md5sum(unsigned char *tmp, /* input */
return CURLE_OK;
}
-static void Curl_darwinssl_sha256sum(const unsigned char *tmp, /* input */
+static CURLcode Curl_darwinssl_sha256sum(const unsigned char *tmp, /* input */
size_t tmplen,
unsigned char *sha256sum, /* output */
size_t sha256len)
{
assert(sha256len >= CURL_SHA256_DIGEST_LENGTH);
(void)CC_SHA256(tmp, (CC_LONG)tmplen, sha256sum);
+ return CURLE_OK;
}
static bool Curl_darwinssl_false_start(void)
@@ -2977,15 +3029,11 @@ static void *Curl_darwinssl_get_internals(struct ssl_connect_data *connssl,
const struct Curl_ssl Curl_ssl_darwinssl = {
{ CURLSSLBACKEND_DARWINSSL, "darwinssl" }, /* info */
- 0, /* have_ca_path */
- 0, /* have_certinfo */
#ifdef DARWIN_SSL_PINNEDPUBKEY
- 1, /* have_pinnedpubkey */
+ SSLSUPP_PINNEDPUBKEY,
#else
- 0, /* have_pinnedpubkey */
+ 0,
#endif /* DARWIN_SSL_PINNEDPUBKEY */
- 0, /* have_ssl_ctx */
- 0, /* support_https_proxy */
sizeof(struct ssl_backend_data),
diff --git a/Utilities/cmcurl/lib/vtls/gskit.c b/Utilities/cmcurl/lib/vtls/gskit.c
index 8f0cc0b..b0856cd 100644
--- a/Utilities/cmcurl/lib/vtls/gskit.c
+++ b/Utilities/cmcurl/lib/vtls/gskit.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2018, 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
@@ -1353,12 +1353,8 @@ static void *Curl_gskit_get_internals(struct ssl_connect_data *connssl,
const struct Curl_ssl Curl_ssl_gskit = {
{ CURLSSLBACKEND_GSKIT, "gskit" }, /* info */
- 0, /* have_ca_path */
- 1, /* have_certinfo */
- 0, /* have_pinnedpubkey */
- 0, /* have_ssl_ctx */
- /* TODO: convert to 1 and fix test #1014 (if need) */
- 0, /* support_https_proxy */
+ SSLSUPP_CERTINFO |
+ SSLSUPP_PINNEDPUBKEY,
sizeof(struct ssl_backend_data),
diff --git a/Utilities/cmcurl/lib/vtls/gtls.c b/Utilities/cmcurl/lib/vtls/gtls.c
index 30b255b..207b0fd 100644
--- a/Utilities/cmcurl/lib/vtls/gtls.c
+++ b/Utilities/cmcurl/lib/vtls/gtls.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2018, 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
@@ -60,15 +60,6 @@
/* The last #include file should be: */
#include "memdebug.h"
-#ifndef GNUTLS_POINTER_TO_SOCKET_CAST
-#define GNUTLS_POINTER_TO_SOCKET_CAST(p) \
- ((curl_socket_t) ((char *)(p) - (char *)NULL))
-#endif
-#ifndef GNUTLS_SOCKET_TO_POINTER_CAST
-#define GNUTLS_SOCKET_TO_POINTER_CAST(s) \
- ((void *) ((char *)NULL + (s)))
-#endif
-
/* Enable GnuTLS debugging by defining GTLSDEBUG */
/*#define GTLSDEBUG */
@@ -161,7 +152,8 @@ static int gtls_mapped_sockerrno(void)
static ssize_t Curl_gtls_push(void *s, const void *buf, size_t len)
{
- ssize_t ret = swrite(GNUTLS_POINTER_TO_SOCKET_CAST(s), buf, len);
+ curl_socket_t sock = *(curl_socket_t *)s;
+ ssize_t ret = swrite(sock, buf, len);
#if defined(USE_WINSOCK) && !defined(GNUTLS_MAPS_WINSOCK_ERRORS)
if(ret < 0)
gnutls_transport_set_global_errno(gtls_mapped_sockerrno());
@@ -171,7 +163,8 @@ static ssize_t Curl_gtls_push(void *s, const void *buf, size_t len)
static ssize_t Curl_gtls_pull(void *s, void *buf, size_t len)
{
- ssize_t ret = sread(GNUTLS_POINTER_TO_SOCKET_CAST(s), buf, len);
+ curl_socket_t sock = *(curl_socket_t *)s;
+ ssize_t ret = sread(sock, buf, len);
#if defined(USE_WINSOCK) && !defined(GNUTLS_MAPS_WINSOCK_ERRORS)
if(ret < 0)
gnutls_transport_set_global_errno(gtls_mapped_sockerrno());
@@ -857,7 +850,7 @@ gtls_connect_step1(struct connectdata *conn,
}
else {
/* file descriptor for the socket */
- transport_ptr = GNUTLS_SOCKET_TO_POINTER_CAST(conn->sock[sockindex]);
+ transport_ptr = &conn->sock[sockindex];
gnutls_transport_push = Curl_gtls_push;
gnutls_transport_pull = Curl_gtls_pull;
}
@@ -1770,7 +1763,7 @@ static CURLcode Curl_gtls_md5sum(unsigned char *tmp, /* input */
return CURLE_OK;
}
-static void Curl_gtls_sha256sum(const unsigned char *tmp, /* input */
+static CURLcode Curl_gtls_sha256sum(const unsigned char *tmp, /* input */
size_t tmplen,
unsigned char *sha256sum, /* output */
size_t sha256len)
@@ -1787,6 +1780,7 @@ static void Curl_gtls_sha256sum(const unsigned char *tmp, /* input */
memcpy(sha256sum, gcry_md_read(SHA256pw, 0), sha256len);
gcry_md_close(SHA256pw);
#endif
+ return CURLE_OK;
}
static bool Curl_gtls_cert_status_request(void)
@@ -1808,11 +1802,10 @@ static void *Curl_gtls_get_internals(struct ssl_connect_data *connssl,
const struct Curl_ssl Curl_ssl_gnutls = {
{ CURLSSLBACKEND_GNUTLS, "gnutls" }, /* info */
- 1, /* have_ca_path */
- 1, /* have_certinfo */
- 1, /* have_pinnedpubkey */
- 0, /* have_ssl_ctx */
- 1, /* support_https_proxy */
+ SSLSUPP_CA_PATH |
+ SSLSUPP_CERTINFO |
+ SSLSUPP_PINNEDPUBKEY |
+ SSLSUPP_HTTPS_PROXY,
sizeof(struct ssl_backend_data),
diff --git a/Utilities/cmcurl/lib/vtls/mbedtls.c b/Utilities/cmcurl/lib/vtls/mbedtls.c
index 28251a3..d7759dc 100644
--- a/Utilities/cmcurl/lib/vtls/mbedtls.c
+++ b/Utilities/cmcurl/lib/vtls/mbedtls.c
@@ -6,7 +6,7 @@
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2010 - 2011, Hoi-Ho Chan, <hoiho.chan@gmail.com>
- * Copyright (C) 2012 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2012 - 2018, 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
@@ -815,7 +815,7 @@ static void Curl_mbedtls_session_free(void *ptr)
static size_t Curl_mbedtls_version(char *buffer, size_t size)
{
unsigned int version = mbedtls_version_get_number();
- return snprintf(buffer, size, "mbedTLS/%d.%d.%d", version>>24,
+ return snprintf(buffer, size, "mbedTLS/%u.%u.%u", version>>24,
(version>>16)&0xff, (version>>8)&0xff);
}
@@ -1023,13 +1023,20 @@ static bool Curl_mbedtls_data_pending(const struct connectdata *conn,
return mbedtls_ssl_get_bytes_avail(&BACKEND->ssl) != 0;
}
-static void Curl_mbedtls_sha256sum(const unsigned char *input,
+static CURLcode Curl_mbedtls_sha256sum(const unsigned char *input,
size_t inputlen,
unsigned char *sha256sum,
size_t sha256len UNUSED_PARAM)
{
(void)sha256len;
+#if MBEDTLS_VERSION_NUMBER < 0x02070000
mbedtls_sha256(input, inputlen, sha256sum, 0);
+#else
+ /* returns 0 on success, otherwise failure */
+ if(mbedtls_sha256_ret(input, inputlen, sha256sum, 0) != 0)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+#endif
+ return CURLE_OK;
}
static void *Curl_mbedtls_get_internals(struct ssl_connect_data *connssl,
@@ -1042,11 +1049,9 @@ static void *Curl_mbedtls_get_internals(struct ssl_connect_data *connssl,
const struct Curl_ssl Curl_ssl_mbedtls = {
{ CURLSSLBACKEND_MBEDTLS, "mbedtls" }, /* info */
- 1, /* have_ca_path */
- 0, /* have_certinfo */
- 1, /* have_pinnedpubkey */
- 1, /* have_ssl_ctx */
- 0, /* support_https_proxy */
+ SSLSUPP_CA_PATH |
+ SSLSUPP_PINNEDPUBKEY |
+ SSLSUPP_SSL_CTX,
sizeof(struct ssl_backend_data),
diff --git a/Utilities/cmcurl/lib/vtls/nss.c b/Utilities/cmcurl/lib/vtls/nss.c
index a3ef37a..7cd450c 100644
--- a/Utilities/cmcurl/lib/vtls/nss.c
+++ b/Utilities/cmcurl/lib/vtls/nss.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2018, 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
@@ -440,7 +440,17 @@ static CURLcode nss_create_object(struct ssl_connect_data *connssl,
PK11_SETATTRS(attrs, attr_cnt, CKA_TRUST, pval, sizeof(*pval));
}
- obj = PK11_CreateGenericObject(slot, attrs, attr_cnt, PR_FALSE);
+ /* PK11_CreateManagedGenericObject() was introduced in NSS 3.34 because
+ * PK11_DestroyGenericObject() does not release resources allocated by
+ * PK11_CreateGenericObject() early enough. */
+ obj =
+#ifdef HAVE_PK11_CREATEMANAGEDGENERICOBJECT
+ PK11_CreateManagedGenericObject
+#else
+ PK11_CreateGenericObject
+#endif
+ (slot, attrs, attr_cnt, PR_FALSE);
+
PK11_FreeSlot(slot);
if(!obj)
return result;
@@ -2304,7 +2314,7 @@ static CURLcode Curl_nss_md5sum(unsigned char *tmp, /* input */
return CURLE_OK;
}
-static void Curl_nss_sha256sum(const unsigned char *tmp, /* input */
+static CURLcode Curl_nss_sha256sum(const unsigned char *tmp, /* input */
size_t tmplen,
unsigned char *sha256sum, /* output */
size_t sha256len)
@@ -2315,6 +2325,8 @@ static void Curl_nss_sha256sum(const unsigned char *tmp, /* input */
PK11_DigestOp(SHA256pw, tmp, curlx_uztoui(tmplen));
PK11_DigestFinal(SHA256pw, sha256sum, &SHA256out, curlx_uztoui(sha256len));
PK11_DestroyContext(SHA256pw, PR_TRUE);
+
+ return CURLE_OK;
}
static bool Curl_nss_cert_status_request(void)
@@ -2345,11 +2357,10 @@ static void *Curl_nss_get_internals(struct ssl_connect_data *connssl,
const struct Curl_ssl Curl_ssl_nss = {
{ CURLSSLBACKEND_NSS, "nss" }, /* info */
- 1, /* have_ca_path */
- 1, /* have_certinfo */
- 1, /* have_pinnedpubkey */
- 0, /* have_ssl_ctx */
- 1, /* support_https_proxy */
+ SSLSUPP_CA_PATH |
+ SSLSUPP_CERTINFO |
+ SSLSUPP_PINNEDPUBKEY |
+ SSLSUPP_HTTPS_PROXY,
sizeof(struct ssl_backend_data),
diff --git a/Utilities/cmcurl/lib/vtls/openssl.c b/Utilities/cmcurl/lib/vtls/openssl.c
index 93faa6f..f6a4bd3 100644
--- a/Utilities/cmcurl/lib/vtls/openssl.c
+++ b/Utilities/cmcurl/lib/vtls/openssl.c
@@ -104,13 +104,22 @@
#endif
#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && /* OpenSSL 1.1.0+ */ \
- !defined(LIBRESSL_VERSION_NUMBER)
+ !(defined(LIBRESSL_VERSION_NUMBER) && \
+ LIBRESSL_VERSION_NUMBER < 0x20700000L)
#define SSLEAY_VERSION_NUMBER OPENSSL_VERSION_NUMBER
#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)
@@ -128,7 +137,8 @@ static unsigned long OpenSSL_version_num(void)
#endif
#if (OPENSSL_VERSION_NUMBER >= 0x1000200fL) && /* 1.0.2 or later */ \
- !defined(LIBRESSL_VERSION_NUMBER)
+ !(defined(LIBRESSL_VERSION_NUMBER) && \
+ LIBRESSL_VERSION_NUMBER < 0x20700000L)
#define HAVE_X509_GET0_SIGNATURE 1
#endif
@@ -147,7 +157,7 @@ static unsigned long OpenSSL_version_num(void)
* 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: unsupported in at least 2.5.1 (explicitly check for it since it
+ * LibreSSL: unsupported in at least 2.7.2 (explicitly check for it since it
* lies and pretends to be OpenSSL 2.0.0).
*/
#if (OPENSSL_VERSION_NUMBER >= 0x10101000L && \
@@ -259,7 +269,9 @@ static void tap_ssl_key(const SSL *ssl, ssl_tap_state_t *state)
if(!session || !keylog_file_fp)
return;
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \
+ !(defined(LIBRESSL_VERSION_NUMBER) && \
+ LIBRESSL_VERSION_NUMBER < 0x20700000L)
/* ssl->s3 is not checked in openssl 1.1.0-pre6, but let's assume that
* we have a valid SSL context if we have a non-NULL session. */
SSL_get_client_random(ssl, client_random, SSL3_RANDOM_SIZE);
@@ -649,18 +661,28 @@ int cert_stuff(struct connectdata *conn,
case SSL_FILETYPE_PKCS12:
{
- FILE *f;
- PKCS12 *p12;
+ BIO *fp = NULL;
+ PKCS12 *p12 = NULL;
EVP_PKEY *pri;
STACK_OF(X509) *ca = NULL;
- f = fopen(cert_file, "rb");
- if(!f) {
+ fp = BIO_new(BIO_s_file());
+ if(fp == NULL) {
+ failf(data,
+ "BIO_new return NULL, " OSSL_PACKAGE
+ " error %s",
+ ossl_strerror(ERR_get_error(), error_buffer,
+ sizeof(error_buffer)) );
+ return 0;
+ }
+
+ if(BIO_read_filename(fp, cert_file) <= 0) {
failf(data, "could not open PKCS12 file '%s'", cert_file);
+ BIO_free(fp);
return 0;
}
- p12 = d2i_PKCS12_fp(f, NULL);
- fclose(f);
+ p12 = d2i_PKCS12_bio(fp, NULL);
+ BIO_free(fp);
if(!p12) {
failf(data, "error reading PKCS12 file '%s'", cert_file);
@@ -1311,6 +1333,51 @@ static void Curl_ossl_close_all(struct Curl_easy *data)
/* ====================================================== */
+/*
+ * Match subjectAltName against the host name. This requires a conversion
+ * in CURL_DOES_CONVERSIONS builds.
+ */
+static bool subj_alt_hostcheck(struct Curl_easy *data,
+ const char *match_pattern, const char *hostname,
+ const char *dispname)
+#ifdef CURL_DOES_CONVERSIONS
+{
+ bool res = FALSE;
+
+ /* Curl_cert_hostcheck uses host encoding, but we get ASCII from
+ OpenSSl.
+ */
+ char *match_pattern2 = strdup(match_pattern);
+
+ if(match_pattern2) {
+ if(Curl_convert_from_network(data, match_pattern2,
+ strlen(match_pattern2)) == CURLE_OK) {
+ if(Curl_cert_hostcheck(match_pattern2, hostname)) {
+ res = TRUE;
+ infof(data,
+ " subjectAltName: host \"%s\" matched cert's \"%s\"\n",
+ dispname, match_pattern2);
+ }
+ }
+ free(match_pattern2);
+ }
+ else {
+ failf(data,
+ "SSL: out of memory when allocating temporary for subjectAltName");
+ }
+ return res;
+}
+#else
+{
+ if(Curl_cert_hostcheck(match_pattern, hostname)) {
+ infof(data, " subjectAltName: host \"%s\" matched cert's \"%s\"\n",
+ dispname, match_pattern);
+ return TRUE;
+ }
+ return FALSE;
+}
+#endif
+
/* Quote from RFC2818 section 3.1 "Server Identity"
@@ -1410,11 +1477,8 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert)
if((altlen == strlen(altptr)) &&
/* if this isn't true, there was an embedded zero in the name
string and we cannot match it. */
- Curl_cert_hostcheck(altptr, hostname)) {
+ subj_alt_hostcheck(data, altptr, hostname, dispname)) {
dnsmatched = TRUE;
- infof(data,
- " subjectAltName: host \"%s\" matched cert's \"%s\"\n",
- dispname, altptr);
}
break;
@@ -1725,13 +1789,40 @@ static const char *ssl_msg_type(int ssl_ver, int msg)
case SSL3_MT_CERTIFICATE_STATUS:
return "Certificate Status";
#endif
+#ifdef SSL3_MT_ENCRYPTED_EXTENSIONS
+ case SSL3_MT_ENCRYPTED_EXTENSIONS:
+ return "Encrypted Extensions";
+#endif
+#ifdef SSL3_MT_END_OF_EARLY_DATA
+ case SSL3_MT_END_OF_EARLY_DATA:
+ return "End of early data";
+#endif
+#ifdef SSL3_MT_KEY_UPDATE
+ case SSL3_MT_KEY_UPDATE:
+ return "Key update";
+#endif
+#ifdef SSL3_MT_NEXT_PROTO
+ case SSL3_MT_NEXT_PROTO:
+ return "Next protocol";
+#endif
+#ifdef SSL3_MT_MESSAGE_HASH
+ case SSL3_MT_MESSAGE_HASH:
+ return "Message hash";
+#endif
}
}
return "Unknown";
}
-static const char *tls_rt_type(int type)
+static const char *tls_rt_type(int type, const void *buf, size_t buflen)
{
+ (void)buf;
+ (void)buflen;
+#ifdef SSL3_RT_INNER_CONTENT_TYPE
+ if(type == SSL3_RT_INNER_CONTENT_TYPE && buf && buflen >= 1)
+ type = *(unsigned char *)buf;
+#endif
+
switch(type) {
#ifdef SSL3_RT_HEADER
case SSL3_RT_HEADER:
@@ -1759,10 +1850,7 @@ static void ssl_tls_trace(int direction, int ssl_ver, int content_type,
void *userp)
{
struct Curl_easy *data;
- const char *msg_name, *tls_rt_name;
- char ssl_buf[1024];
char unknown[32];
- int msg_type, txt_len;
const char *verstr = NULL;
struct connectdata *conn = userp;
@@ -1810,6 +1898,10 @@ static void ssl_tls_trace(int direction, int ssl_ver, int content_type,
}
if(ssl_ver) {
+ const char *msg_name, *tls_rt_name;
+ char ssl_buf[1024];
+ int msg_type, txt_len;
+
/* the info given when the version is zero is not that useful for us */
ssl_ver >>= 8; /* check the upper 8 bits only below */
@@ -1819,17 +1911,28 @@ static void ssl_tls_trace(int direction, int ssl_ver, int content_type,
* is at 'buf[0]'.
*/
if(ssl_ver == SSL3_VERSION_MAJOR && content_type)
- tls_rt_name = tls_rt_type(content_type);
+ tls_rt_name = tls_rt_type(content_type, buf, len);
else
tls_rt_name = "";
- msg_type = *(char *)buf;
- msg_name = ssl_msg_type(ssl_ver, msg_type);
+#ifdef SSL3_RT_INNER_CONTENT_TYPE
+ if(content_type == SSL3_RT_INNER_CONTENT_TYPE) {
+ msg_type = 0;
+ msg_name = "[no content]";
+ }
+ else
+#endif
+ {
+ msg_type = *(char *)buf;
+ msg_name = ssl_msg_type(ssl_ver, msg_type);
+ }
txt_len = snprintf(ssl_buf, sizeof(ssl_buf), "%s (%s), %s, %s (%d):\n",
verstr, direction?"OUT":"IN",
tls_rt_name, msg_name, msg_type);
- Curl_debug(data, CURLINFO_TEXT, ssl_buf, (size_t)txt_len, NULL);
+ if(0 <= txt_len && (unsigned)txt_len < sizeof(ssl_buf)) {
+ Curl_debug(data, CURLINFO_TEXT, ssl_buf, (size_t)txt_len, NULL);
+ }
}
Curl_debug(data, (direction == 1) ? CURLINFO_SSL_DATA_OUT :
@@ -2082,8 +2185,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
case CURL_SSLVERSION_TLSv1_2:
case CURL_SSLVERSION_TLSv1_3:
/* it will be handled later with the context options */
-#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && \
- !defined(LIBRESSL_VERSION_NUMBER)
+#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
req_method = TLS_client_method();
#else
req_method = SSLv23_client_method();
@@ -2800,7 +2902,7 @@ static CURLcode get_cert_chain(struct connectdata *conn,
ASN1_STRING *a = ASN1_STRING_new();
if(a) {
X509_get0_signature(&psig, &palg, x);
- X509_signature_print(mem, palg, a);
+ X509_signature_print(mem, ARG2_X509_signature_print palg, a);
ASN1_STRING_free(a);
if(palg) {
@@ -3035,7 +3137,8 @@ static CURLcode servercert(struct connectdata *conn,
long lerr, len;
struct Curl_easy *data = conn->data;
X509 *issuer;
- FILE *fp;
+ BIO *fp = NULL;
+ char error_buffer[256]="";
char buffer[2048];
const char *ptr;
long * const certverifyresult = SSL_IS_PROXY() ?
@@ -3046,8 +3149,20 @@ static CURLcode servercert(struct connectdata *conn,
/* we've been asked to gather certificate info! */
(void)get_cert_chain(conn, connssl);
+ fp = BIO_new(BIO_s_file());
+ if(fp == NULL) {
+ failf(data,
+ "BIO_new return NULL, " OSSL_PACKAGE
+ " error %s",
+ ossl_strerror(ERR_get_error(), error_buffer,
+ sizeof(error_buffer)) );
+ BIO_free(mem);
+ return 0;
+ }
+
BACKEND->server_cert = SSL_get_peer_certificate(BACKEND->handle);
if(!BACKEND->server_cert) {
+ BIO_free(fp);
BIO_free(mem);
if(!strict)
return CURLE_OK;
@@ -3077,6 +3192,7 @@ static CURLcode servercert(struct connectdata *conn,
if(SSL_CONN_CONFIG(verifyhost)) {
result = verifyhost(conn, BACKEND->server_cert);
if(result) {
+ BIO_free(fp);
X509_free(BACKEND->server_cert);
BACKEND->server_cert = NULL;
return result;
@@ -3098,35 +3214,35 @@ static CURLcode servercert(struct connectdata *conn,
/* e.g. match issuer name with provided issuer certificate */
if(SSL_SET_OPTION(issuercert)) {
- fp = fopen(SSL_SET_OPTION(issuercert), FOPEN_READTEXT);
- if(!fp) {
+ if(BIO_read_filename(fp, SSL_SET_OPTION(issuercert)) <= 0) {
if(strict)
failf(data, "SSL: Unable to open issuer cert (%s)",
SSL_SET_OPTION(issuercert));
+ BIO_free(fp);
X509_free(BACKEND->server_cert);
BACKEND->server_cert = NULL;
return CURLE_SSL_ISSUER_ERROR;
}
- issuer = PEM_read_X509(fp, NULL, ZERO_NULL, NULL);
+ issuer = PEM_read_bio_X509(fp, NULL, ZERO_NULL, NULL);
if(!issuer) {
if(strict)
failf(data, "SSL: Unable to read issuer cert (%s)",
SSL_SET_OPTION(issuercert));
- X509_free(BACKEND->server_cert);
+ BIO_free(fp);
X509_free(issuer);
- fclose(fp);
+ X509_free(BACKEND->server_cert);
+ BACKEND->server_cert = NULL;
return CURLE_SSL_ISSUER_ERROR;
}
- fclose(fp);
-
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));
- X509_free(BACKEND->server_cert);
+ BIO_free(fp);
X509_free(issuer);
+ X509_free(BACKEND->server_cert);
BACKEND->server_cert = NULL;
return CURLE_SSL_ISSUER_ERROR;
}
@@ -3161,6 +3277,7 @@ static CURLcode servercert(struct connectdata *conn,
if(SSL_CONN_CONFIG(verifystatus)) {
result = verifystatus(conn, connssl);
if(result) {
+ BIO_free(fp);
X509_free(BACKEND->server_cert);
BACKEND->server_cert = NULL;
return result;
@@ -3180,6 +3297,7 @@ static CURLcode servercert(struct connectdata *conn,
failf(data, "SSL: public key does not match pinned public key!");
}
+ BIO_free(fp);
X509_free(BACKEND->server_cert);
BACKEND->server_cert = NULL;
connssl->connecting_state = ssl_connect_done;
@@ -3580,25 +3698,34 @@ static CURLcode Curl_ossl_md5sum(unsigned char *tmp, /* input */
unsigned char *md5sum /* output */,
size_t unused)
{
- MD5_CTX MD5pw;
- (void)unused;
- MD5_Init(&MD5pw);
- MD5_Update(&MD5pw, tmp, tmplen);
- MD5_Final(md5sum, &MD5pw);
+ EVP_MD_CTX *mdctx;
+ unsigned int len = 0;
+ (void) unused;
+
+ mdctx = EVP_MD_CTX_create();
+ EVP_DigestInit_ex(mdctx, EVP_md5(), NULL);
+ EVP_DigestUpdate(mdctx, tmp, tmplen);
+ EVP_DigestFinal_ex(mdctx, md5sum, &len);
+ EVP_MD_CTX_destroy(mdctx);
return CURLE_OK;
}
#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256)
-static void Curl_ossl_sha256sum(const unsigned char *tmp, /* input */
+static CURLcode Curl_ossl_sha256sum(const unsigned char *tmp, /* input */
size_t tmplen,
unsigned char *sha256sum /* output */,
size_t unused)
{
- SHA256_CTX SHA256pw;
- (void)unused;
- SHA256_Init(&SHA256pw);
- SHA256_Update(&SHA256pw, tmp, tmplen);
- SHA256_Final(sha256sum, &SHA256pw);
+ EVP_MD_CTX *mdctx;
+ unsigned int len = 0;
+ (void) unused;
+
+ mdctx = EVP_MD_CTX_create();
+ EVP_DigestInit_ex(mdctx, EVP_sha256(), NULL);
+ EVP_DigestUpdate(mdctx, tmp, tmplen);
+ EVP_DigestFinal_ex(mdctx, sha256sum, &len);
+ EVP_MD_CTX_destroy(mdctx);
+ return CURLE_OK;
}
#endif
@@ -3623,11 +3750,11 @@ static void *Curl_ossl_get_internals(struct ssl_connect_data *connssl,
const struct Curl_ssl Curl_ssl_openssl = {
{ CURLSSLBACKEND_OPENSSL, "openssl" }, /* info */
- 1, /* have_ca_path */
- 1, /* have_certinfo */
- 1, /* have_pinnedpubkey */
- 1, /* have_ssl_ctx */
- 1, /* support_https_proxy */
+ SSLSUPP_CA_PATH |
+ SSLSUPP_CERTINFO |
+ SSLSUPP_PINNEDPUBKEY |
+ SSLSUPP_SSL_CTX |
+ SSLSUPP_HTTPS_PROXY,
sizeof(struct ssl_backend_data),
diff --git a/Utilities/cmcurl/lib/vtls/polarssl.c b/Utilities/cmcurl/lib/vtls/polarssl.c
index df29fa9..604cb4c 100644
--- a/Utilities/cmcurl/lib/vtls/polarssl.c
+++ b/Utilities/cmcurl/lib/vtls/polarssl.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 2012 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2012 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 2010 - 2011, Hoi-Ho Chan, <hoiho.chan@gmail.com>
*
* This software is licensed as described in the file COPYING, which
@@ -620,12 +620,10 @@ polarssl_connect_step3(struct connectdata *conn,
ssl_session *our_ssl_sessionid;
void *old_ssl_sessionid = NULL;
- our_ssl_sessionid = malloc(sizeof(ssl_session));
+ our_ssl_sessionid = calloc(1, sizeof(ssl_session));
if(!our_ssl_sessionid)
return CURLE_OUT_OF_MEMORY;
- memset(our_ssl_sessionid, 0, sizeof(ssl_session));
-
ret = ssl_get_session(&BACKEND->ssl, our_ssl_sessionid);
if(ret) {
failf(data, "ssl_get_session returned -0x%x", -ret);
@@ -882,13 +880,14 @@ static bool Curl_polarssl_data_pending(const struct connectdata *conn,
return ssl_get_bytes_avail(&BACKEND->ssl) != 0;
}
-static void Curl_polarssl_sha256sum(const unsigned char *input,
+static CURLcode Curl_polarssl_sha256sum(const unsigned char *input,
size_t inputlen,
unsigned char *sha256sum,
size_t sha256len UNUSED_PARAM)
{
(void)sha256len;
sha256(input, inputlen, sha256sum, 0);
+ return CURLE_OK;
}
static void *Curl_polarssl_get_internals(struct ssl_connect_data *connssl,
@@ -901,11 +900,8 @@ static void *Curl_polarssl_get_internals(struct ssl_connect_data *connssl,
const struct Curl_ssl Curl_ssl_polarssl = {
{ CURLSSLBACKEND_POLARSSL, "polarssl" }, /* info */
- 1, /* have_ca_path */
- 0, /* have_certinfo */
- 1, /* have_pinnedpubkey */
- 0, /* have_ssl_ctx */
- 0, /* support_https_proxy */
+ SSLSUPP_CA_PATH |
+ SSLSUPP_PINNEDPUBKEY,
sizeof(struct ssl_backend_data),
diff --git a/Utilities/cmcurl/lib/vtls/schannel.c b/Utilities/cmcurl/lib/vtls/schannel.c
index 85c64cf..2cfd5c1 100644
--- a/Utilities/cmcurl/lib/vtls/schannel.c
+++ b/Utilities/cmcurl/lib/vtls/schannel.c
@@ -7,7 +7,7 @@
*
* Copyright (C) 2012 - 2016, Marc Hoersken, <info@marc-hoersken.de>
* Copyright (C) 2012, Mark Salisbury, <mark.salisbury@hp.com>
- * Copyright (C) 2012 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2012 - 2018, 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
@@ -42,13 +42,12 @@
#ifdef USE_SCHANNEL
+#define EXPOSE_SCHANNEL_INTERNAL_STRUCTS
+
#ifndef USE_WINDOWS_SSPI
# error "Can't compile SCHANNEL support without SSPI."
#endif
-#include <schnlsp.h>
-#include <schannel.h>
-#include "curl_sspi.h"
#include "schannel.h"
#include "vtls.h"
#include "sendf.h"
@@ -61,7 +60,6 @@
#include "x509asn1.h"
#include "curl_printf.h"
#include "system_win32.h"
-#include "hostcheck.h"
/* The last #include file should be: */
#include "curl_memory.h"
@@ -92,6 +90,12 @@
#endif
#endif
+#ifdef UNICODE
+#define CURL_CERT_STORE_PROV_SYSTEM CERT_STORE_PROV_SYSTEM_W
+#else
+#define CURL_CERT_STORE_PROV_SYSTEM CERT_STORE_PROV_SYSTEM_A
+#endif
+
#ifndef SP_PROT_SSL2_CLIENT
#define SP_PROT_SSL2_CLIENT 0x00000008
#endif
@@ -124,50 +128,25 @@
#define CURL_SCHANNEL_BUFFER_INIT_SIZE 4096
#define CURL_SCHANNEL_BUFFER_FREE_SIZE 1024
+#define CERT_THUMBPRINT_STR_LEN 40
+#define CERT_THUMBPRINT_DATA_LEN 20
+
/* Uncomment to force verbose output
* #define infof(x, y, ...) printf(y, __VA_ARGS__)
* #define failf(x, y, ...) printf(y, __VA_ARGS__)
*/
-/* Structs to store Schannel handles */
-struct curl_schannel_cred {
- CredHandle cred_handle;
- TimeStamp time_stamp;
- int refcount;
-};
-
-struct curl_schannel_ctxt {
- CtxtHandle ctxt_handle;
- TimeStamp time_stamp;
-};
-
-struct ssl_backend_data {
- struct curl_schannel_cred *cred;
- struct curl_schannel_ctxt *ctxt;
- SecPkgContext_StreamSizes stream_sizes;
- size_t encdata_length, decdata_length;
- size_t encdata_offset, decdata_offset;
- unsigned char *encdata_buffer, *decdata_buffer;
- /* encdata_is_incomplete: if encdata contains only a partial record that
- can't be decrypted without another Curl_read_plain (that is, status is
- SEC_E_INCOMPLETE_MESSAGE) then set this true. after Curl_read_plain writes
- more bytes into encdata then set this back to false. */
- bool encdata_is_incomplete;
- unsigned long req_flags, ret_flags;
- CURLcode recv_unrecoverable_err; /* schannel_recv had an unrecoverable err */
- bool recv_sspi_close_notify; /* true if connection closed by close_notify */
- bool recv_connection_closed; /* true if connection closed, regardless how */
- bool use_alpn; /* true if ALPN is used for this connection */
-};
+#ifndef CALG_SHA_256
+# define CALG_SHA_256 0x0000800c
+#endif
#define BACKEND connssl->backend
static Curl_recv schannel_recv;
static Curl_send schannel_send;
-#ifdef _WIN32_WCE
-static CURLcode verify_certificate(struct connectdata *conn, int sockindex);
-#endif
+static CURLcode pkp_pin_peer_pubkey(struct connectdata *conn, int sockindex,
+ const char *pinnedpubkey);
static void InitSecBuffer(SecBuffer *buffer, unsigned long BufType,
void *BufDataPtr, unsigned long BufByteSize)
@@ -221,6 +200,56 @@ set_ssl_version_min_max(SCHANNEL_CRED *schannel_cred, struct connectdata *conn)
}
static CURLcode
+get_cert_location(TCHAR *path, DWORD *store_name, TCHAR **store_path,
+ TCHAR **thumbprint)
+{
+ TCHAR *sep;
+ size_t store_name_len;
+
+ sep = _tcschr(path, TEXT('\\'));
+ if(sep == NULL)
+ return CURLE_SSL_CONNECT_ERROR;
+
+ store_name_len = sep - path;
+
+ if(_tcsnccmp(path, TEXT("CurrentUser"), store_name_len) == 0)
+ *store_name = CERT_SYSTEM_STORE_CURRENT_USER;
+ else if(_tcsnccmp(path, TEXT("LocalMachine"), store_name_len) == 0)
+ *store_name = CERT_SYSTEM_STORE_LOCAL_MACHINE;
+ else if(_tcsnccmp(path, TEXT("CurrentService"), store_name_len) == 0)
+ *store_name = CERT_SYSTEM_STORE_CURRENT_SERVICE;
+ else if(_tcsnccmp(path, TEXT("Services"), store_name_len) == 0)
+ *store_name = CERT_SYSTEM_STORE_SERVICES;
+ else if(_tcsnccmp(path, TEXT("Users"), store_name_len) == 0)
+ *store_name = CERT_SYSTEM_STORE_USERS;
+ else if(_tcsnccmp(path, TEXT("CurrentUserGroupPolicy"),
+ store_name_len) == 0)
+ *store_name = CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY;
+ else if(_tcsnccmp(path, TEXT("LocalMachineGroupPolicy"),
+ store_name_len) == 0)
+ *store_name = CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY;
+ else if(_tcsnccmp(path, TEXT("LocalMachineEnterprise"),
+ store_name_len) == 0)
+ *store_name = CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE;
+ else
+ return CURLE_SSL_CONNECT_ERROR;
+
+ *store_path = sep + 1;
+
+ sep = _tcschr(*store_path, TEXT('\\'));
+ if(sep == NULL)
+ return CURLE_SSL_CONNECT_ERROR;
+
+ *sep = 0;
+
+ *thumbprint = sep + 1;
+ if(_tcslen(*thumbprint) != CERT_THUMBPRINT_STR_LEN)
+ return CURLE_SSL_CONNECT_ERROR;
+
+ return CURLE_OK;
+}
+
+static CURLcode
schannel_connect_step1(struct connectdata *conn, int sockindex)
{
ssize_t written = -1;
@@ -234,6 +263,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
unsigned char alpn_buffer[128];
#endif
SCHANNEL_CRED schannel_cred;
+ PCCERT_CONTEXT client_certs[1] = { NULL };
SECURITY_STATUS sspi_status = SEC_E_OK;
struct curl_schannel_cred *old_cred = NULL;
struct in_addr addr;
@@ -268,6 +298,26 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
BACKEND->use_alpn = false;
#endif
+#ifdef _WIN32_WCE
+ /* certificate validation on CE doesn't seem to work right; we'll
+ * do it following a more manual process. */
+ BACKEND->use_manual_cred_validation = true;
+#else
+ if(SSL_CONN_CONFIG(CAfile)) {
+ if(Curl_verify_windows_version(6, 1, PLATFORM_WINNT,
+ VERSION_GREATER_THAN_EQUAL)) {
+ BACKEND->use_manual_cred_validation = true;
+ }
+ else {
+ failf(data, "schannel: this version of Windows is too old to support "
+ "certificate verification via CA bundle file.");
+ return CURLE_SSL_CACERT_BADFILE;
+ }
+ }
+ else
+ BACKEND->use_manual_cred_validation = false;
+#endif
+
BACKEND->cred = NULL;
/* check for an existing re-usable credential handle */
@@ -291,26 +341,23 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
if(conn->ssl_config.verifypeer) {
-#ifdef _WIN32_WCE
- /* certificate validation on CE doesn't seem to work right; we'll
- do it following a more manual process. */
- schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION |
- SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
- SCH_CRED_IGNORE_REVOCATION_OFFLINE;
-#else
- schannel_cred.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION;
+ if(BACKEND->use_manual_cred_validation)
+ schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION;
+ else
+ schannel_cred.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION;
+
/* TODO s/data->set.ssl.no_revoke/SSL_SET_OPTION(no_revoke)/g */
- if(data->set.ssl.no_revoke)
+ if(data->set.ssl.no_revoke) {
schannel_cred.dwFlags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
- SCH_CRED_IGNORE_REVOCATION_OFFLINE;
- else
- schannel_cred.dwFlags |= SCH_CRED_REVOCATION_CHECK_CHAIN;
-#endif
- if(data->set.ssl.no_revoke)
+ SCH_CRED_IGNORE_REVOCATION_OFFLINE;
+
infof(data, "schannel: disabled server certificate revocation "
"checks\n");
- else
+ }
+ else {
+ schannel_cred.dwFlags |= SCH_CRED_REVOCATION_CHECK_CHAIN;
infof(data, "schannel: checking server certificate revocation\n");
+ }
}
else {
schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION |
@@ -354,14 +401,70 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
return CURLE_SSL_CONNECT_ERROR;
}
+ /* client certificate */
+ if(data->set.ssl.cert) {
+ DWORD cert_store_name;
+ TCHAR *cert_store_path;
+ TCHAR *cert_thumbprint_str;
+ CRYPT_HASH_BLOB cert_thumbprint;
+ BYTE cert_thumbprint_data[CERT_THUMBPRINT_DATA_LEN];
+ HCERTSTORE cert_store;
+
+ TCHAR *cert_path = Curl_convert_UTF8_to_tchar(data->set.ssl.cert);
+ if(!cert_path)
+ return CURLE_OUT_OF_MEMORY;
+
+ result = get_cert_location(cert_path, &cert_store_name,
+ &cert_store_path, &cert_thumbprint_str);
+ if(result != CURLE_OK) {
+ Curl_unicodefree(cert_path);
+ return result;
+ }
+
+ cert_store = CertOpenStore(CURL_CERT_STORE_PROV_SYSTEM, 0,
+ (HCRYPTPROV)NULL,
+ cert_store_name, cert_store_path);
+ if(!cert_store) {
+ Curl_unicodefree(cert_path);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ cert_thumbprint.pbData = cert_thumbprint_data;
+ cert_thumbprint.cbData = CERT_THUMBPRINT_DATA_LEN;
+
+ if(!CryptStringToBinary(cert_thumbprint_str, CERT_THUMBPRINT_STR_LEN,
+ CRYPT_STRING_HEX,
+ cert_thumbprint_data, &cert_thumbprint.cbData,
+ NULL, NULL)) {
+ Curl_unicodefree(cert_path);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ client_certs[0] = CertFindCertificateInStore(
+ cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0,
+ CERT_FIND_HASH, &cert_thumbprint, NULL);
+
+ Curl_unicodefree(cert_path);
+
+ if(client_certs[0]) {
+ schannel_cred.cCreds = 1;
+ schannel_cred.paCred = client_certs;
+ }
+
+ CertCloseStore(cert_store, 0);
+ }
+
/* allocate memory for the re-usable credential handle */
BACKEND->cred = (struct curl_schannel_cred *)
- malloc(sizeof(struct curl_schannel_cred));
+ calloc(1, sizeof(struct curl_schannel_cred));
if(!BACKEND->cred) {
failf(data, "schannel: unable to allocate memory");
+
+ if(client_certs[0])
+ CertFreeCertificateContext(client_certs[0]);
+
return CURLE_OUT_OF_MEMORY;
}
- memset(BACKEND->cred, 0, sizeof(struct curl_schannel_cred));
BACKEND->cred->refcount = 1;
/* https://msdn.microsoft.com/en-us/library/windows/desktop/aa374716.aspx
@@ -373,6 +476,9 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
&BACKEND->cred->cred_handle,
&BACKEND->cred->time_stamp);
+ if(client_certs[0])
+ CertFreeCertificateContext(client_certs[0]);
+
if(sspi_status != SEC_E_OK) {
if(sspi_status == SEC_E_WRONG_PRINCIPAL)
failf(data, "schannel: SNI or certificate check failed: %s",
@@ -438,8 +544,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
InitSecBuffer(&inbuf, SECBUFFER_APPLICATION_PROTOCOLS, alpn_buffer, cur);
InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
}
- else
- {
+ else {
InitSecBuffer(&inbuf, SECBUFFER_EMPTY, NULL, 0);
InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
}
@@ -459,12 +564,11 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
/* allocate memory for the security context handle */
BACKEND->ctxt = (struct curl_schannel_ctxt *)
- malloc(sizeof(struct curl_schannel_ctxt));
+ calloc(1, sizeof(struct curl_schannel_ctxt));
if(!BACKEND->ctxt) {
failf(data, "schannel: unable to allocate memory");
return CURLE_OUT_OF_MEMORY;
}
- memset(BACKEND->ctxt, 0, sizeof(struct curl_schannel_ctxt));
host_name = Curl_convert_UTF8_to_tchar(hostname);
if(!host_name)
@@ -542,6 +646,7 @@ schannel_connect_step2(struct connectdata *conn, int sockindex)
bool doread;
char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
conn->host.name;
+ const char *pubkey_ptr;
doread = (connssl->connecting_state != ssl_connect_2_writing) ? TRUE : FALSE;
@@ -761,12 +866,20 @@ schannel_connect_step2(struct connectdata *conn, int sockindex)
infof(data, "schannel: SSL/TLS handshake complete\n");
}
-#ifdef _WIN32_WCE
- /* Windows CE doesn't do any server certificate validation.
- We have to do it manually. */
- if(conn->ssl_config.verifypeer)
+ pubkey_ptr = SSL_IS_PROXY() ?
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
+ if(pubkey_ptr) {
+ result = pkp_pin_peer_pubkey(conn, sockindex, pubkey_ptr);
+ if(result) {
+ failf(data, "SSL: public key does not match pinned public key!");
+ return result;
+ }
+ }
+
+ if(conn->ssl_config.verifypeer && BACKEND->use_manual_cred_validation) {
return verify_certificate(conn, sockindex);
-#endif
+ }
return CURLE_OK;
}
@@ -1669,145 +1782,136 @@ static CURLcode Curl_schannel_random(struct Curl_easy *data UNUSED_PARAM,
return CURLE_OK;
}
-#ifdef _WIN32_WCE
-static CURLcode verify_certificate(struct connectdata *conn, int sockindex)
+static CURLcode pkp_pin_peer_pubkey(struct connectdata *conn, int sockindex,
+ const char *pinnedpubkey)
{
SECURITY_STATUS status;
struct Curl_easy *data = conn->data;
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- CURLcode result = CURLE_OK;
CERT_CONTEXT *pCertContextServer = NULL;
- const CERT_CHAIN_CONTEXT *pChainContext = NULL;
- const char * const conn_hostname = SSL_IS_PROXY() ?
- conn->http_proxy.host.name :
- conn->host.name;
+ const char *x509_der;
+ DWORD x509_der_len;
+ curl_X509certificate x509_parsed;
+ curl_asn1Element *pubkey;
- status = s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
- SECPKG_ATTR_REMOTE_CERT_CONTEXT,
- &pCertContextServer);
+ /* Result is returned to caller */
+ CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
- if((status != SEC_E_OK) || (pCertContextServer == NULL)) {
- failf(data, "schannel: Failed to read remote certificate context: %s",
- Curl_sspi_strerror(conn, status));
- result = CURLE_PEER_FAILED_VERIFICATION;
- }
+ /* if a path wasn't specified, don't pin */
+ if(!pinnedpubkey)
+ return CURLE_OK;
- if(result == CURLE_OK) {
- CERT_CHAIN_PARA ChainPara;
- memset(&ChainPara, 0, sizeof(ChainPara));
- ChainPara.cbSize = sizeof(ChainPara);
-
- if(!CertGetCertificateChain(NULL,
- pCertContextServer,
- NULL,
- pCertContextServer->hCertStore,
- &ChainPara,
- (data->set.ssl.no_revoke ? 0 :
- CERT_CHAIN_REVOCATION_CHECK_CHAIN),
- NULL,
- &pChainContext)) {
- failf(data, "schannel: CertGetCertificateChain failed: %s",
- Curl_sspi_strerror(conn, GetLastError()));
- pChainContext = NULL;
- result = CURLE_PEER_FAILED_VERIFICATION;
- }
+ do {
+ status = s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
+ SECPKG_ATTR_REMOTE_CERT_CONTEXT,
+ &pCertContextServer);
- if(result == CURLE_OK) {
- CERT_SIMPLE_CHAIN *pSimpleChain = pChainContext->rgpChain[0];
- DWORD dwTrustErrorMask = ~(DWORD)(CERT_TRUST_IS_NOT_TIME_NESTED);
- dwTrustErrorMask &= pSimpleChain->TrustStatus.dwErrorStatus;
- if(dwTrustErrorMask) {
- if(dwTrustErrorMask & CERT_TRUST_IS_REVOKED)
- failf(data, "schannel: CertGetCertificateChain trust error"
- " CERT_TRUST_IS_REVOKED");
- else if(dwTrustErrorMask & CERT_TRUST_IS_PARTIAL_CHAIN)
- failf(data, "schannel: CertGetCertificateChain trust error"
- " CERT_TRUST_IS_PARTIAL_CHAIN");
- else if(dwTrustErrorMask & CERT_TRUST_IS_UNTRUSTED_ROOT)
- failf(data, "schannel: CertGetCertificateChain trust error"
- " CERT_TRUST_IS_UNTRUSTED_ROOT");
- else if(dwTrustErrorMask & CERT_TRUST_IS_NOT_TIME_VALID)
- failf(data, "schannel: CertGetCertificateChain trust error"
- " CERT_TRUST_IS_NOT_TIME_VALID");
- else
- failf(data, "schannel: CertGetCertificateChain error mask: 0x%08x",
- dwTrustErrorMask);
- result = CURLE_PEER_FAILED_VERIFICATION;
- }
+ if((status != SEC_E_OK) || (pCertContextServer == NULL)) {
+ failf(data, "schannel: Failed to read remote certificate context: %s",
+ Curl_sspi_strerror(conn, status));
+ break; /* failed */
}
- }
- if(result == CURLE_OK) {
- if(conn->ssl_config.verifyhost) {
- TCHAR cert_hostname_buff[256];
- DWORD len;
-
- /* TODO: Fix this for certificates with multiple alternative names.
- Right now we're only asking for the first preferred alternative name.
- Instead we'd need to do all via CERT_NAME_SEARCH_ALL_NAMES_FLAG
- (if WinCE supports that?) and run this section in a loop for each.
- https://msdn.microsoft.com/en-us/library/windows/desktop/aa376086.aspx
- curl: (51) schannel: CertGetNameString() certificate hostname
- (.google.com) did not match connection (google.com)
- */
- len = CertGetNameString(pCertContextServer,
- CERT_NAME_DNS_TYPE,
- CERT_NAME_DISABLE_IE4_UTF8_FLAG,
- NULL,
- cert_hostname_buff,
- 256);
- if(len > 0) {
- const char *cert_hostname;
-
- /* Comparing the cert name and the connection hostname encoded as UTF-8
- * is acceptable since both values are assumed to use ASCII
- * (or some equivalent) encoding
- */
- cert_hostname = Curl_convert_tchar_to_UTF8(cert_hostname_buff);
- if(!cert_hostname) {
- result = CURLE_OUT_OF_MEMORY;
- }
- else{
- int match_result;
-
- match_result = Curl_cert_hostcheck(cert_hostname, conn->host.name);
- if(match_result == CURL_HOST_MATCH) {
- infof(data,
- "schannel: connection hostname (%s) validated "
- "against certificate name (%s)\n",
- conn->host.name,
- cert_hostname);
- result = CURLE_OK;
- }
- else{
- failf(data,
- "schannel: connection hostname (%s) "
- "does not match certificate name (%s)",
- conn->host.name,
- cert_hostname);
- result = CURLE_PEER_FAILED_VERIFICATION;
- }
- Curl_unicodefree(cert_hostname);
- }
- }
- else {
- failf(data,
- "schannel: CertGetNameString did not provide any "
- "certificate name information");
- result = CURLE_PEER_FAILED_VERIFICATION;
- }
+
+ if(!(((pCertContextServer->dwCertEncodingType & X509_ASN_ENCODING) != 0) &&
+ (pCertContextServer->cbCertEncoded > 0)))
+ break;
+
+ x509_der = (const char *)pCertContextServer->pbCertEncoded;
+ x509_der_len = pCertContextServer->cbCertEncoded;
+ memset(&x509_parsed, 0, sizeof x509_parsed);
+ if(Curl_parseX509(&x509_parsed, x509_der, x509_der + x509_der_len))
+ break;
+
+ pubkey = &x509_parsed.subjectPublicKeyInfo;
+ if(!pubkey->header || pubkey->end <= pubkey->header) {
+ failf(data, "SSL: failed retrieving public key from server certificate");
+ break;
}
- }
- if(pChainContext)
- CertFreeCertificateChain(pChainContext);
+ result = Curl_pin_peer_pubkey(data,
+ pinnedpubkey,
+ (const unsigned char *)pubkey->header,
+ (size_t)(pubkey->end - pubkey->header));
+ if(result) {
+ failf(data, "SSL: public key does not match pinned public key!");
+ }
+ } while(0);
if(pCertContextServer)
CertFreeCertificateContext(pCertContextServer);
return result;
}
-#endif /* _WIN32_WCE */
+
+static void Curl_schannel_checksum(const unsigned char *input,
+ size_t inputlen,
+ unsigned char *checksum,
+ size_t checksumlen,
+ DWORD provType,
+ const unsigned int algId)
+{
+ HCRYPTPROV hProv = 0;
+ HCRYPTHASH hHash = 0;
+ DWORD cbHashSize = 0;
+ DWORD dwHashSizeLen = (DWORD)sizeof(cbHashSize);
+ DWORD dwChecksumLen = (DWORD)checksumlen;
+
+ /* since this can fail in multiple ways, zero memory first so we never
+ * return old data
+ */
+ memset(checksum, 0, checksumlen);
+
+ if(!CryptAcquireContext(&hProv, NULL, NULL, provType,
+ CRYPT_VERIFYCONTEXT))
+ return; /* failed */
+
+ do {
+ if(!CryptCreateHash(hProv, algId, 0, 0, &hHash))
+ break; /* failed */
+
+ if(!CryptHashData(hHash, (const BYTE*)input, (DWORD)inputlen, 0))
+ break; /* failed */
+
+ /* get hash size */
+ if(!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE *)&cbHashSize,
+ &dwHashSizeLen, 0))
+ break; /* failed */
+
+ /* check hash size */
+ if(checksumlen < cbHashSize)
+ break; /* failed */
+
+ if(CryptGetHashParam(hHash, HP_HASHVAL, checksum, &dwChecksumLen, 0))
+ break; /* failed */
+ } while(0);
+
+ if(hHash)
+ CryptDestroyHash(hHash);
+
+ if(hProv)
+ CryptReleaseContext(hProv, 0);
+}
+
+static CURLcode Curl_schannel_md5sum(unsigned char *input,
+ size_t inputlen,
+ unsigned char *md5sum,
+ size_t md5len)
+{
+ Curl_schannel_checksum(input, inputlen, md5sum, md5len,
+ PROV_RSA_FULL, CALG_MD5);
+ return CURLE_OK;
+}
+
+static CURLcode Curl_schannel_sha256sum(const unsigned char *input,
+ size_t inputlen,
+ unsigned char *sha256sum,
+ size_t sha256len)
+{
+ Curl_schannel_checksum(input, inputlen, sha256sum, sha256len,
+ PROV_RSA_AES, CALG_SHA_256);
+ return CURLE_OK;
+}
static void *Curl_schannel_get_internals(struct ssl_connect_data *connssl,
CURLINFO info UNUSED_PARAM)
@@ -1819,11 +1923,8 @@ static void *Curl_schannel_get_internals(struct ssl_connect_data *connssl,
const struct Curl_ssl Curl_ssl_schannel = {
{ CURLSSLBACKEND_SCHANNEL, "schannel" }, /* info */
- 0, /* have_ca_path */
- 1, /* have_certinfo */
- 0, /* have_pinnedpubkey */
- 0, /* have_ssl_ctx */
- 0, /* support_https_proxy */
+ SSLSUPP_CERTINFO |
+ SSLSUPP_PINNEDPUBKEY,
sizeof(struct ssl_backend_data),
@@ -1845,8 +1946,8 @@ const struct Curl_ssl Curl_ssl_schannel = {
Curl_none_set_engine_default, /* set_engine_default */
Curl_none_engines_list, /* engines_list */
Curl_none_false_start, /* false_start */
- Curl_none_md5sum, /* md5sum */
- NULL /* sha256sum */
+ Curl_schannel_md5sum, /* md5sum */
+ Curl_schannel_sha256sum /* sha256sum */
};
#endif /* USE_SCHANNEL */
diff --git a/Utilities/cmcurl/lib/vtls/schannel.h b/Utilities/cmcurl/lib/vtls/schannel.h
index 932103d..4476900 100644
--- a/Utilities/cmcurl/lib/vtls/schannel.h
+++ b/Utilities/cmcurl/lib/vtls/schannel.h
@@ -26,9 +26,49 @@
#ifdef USE_SCHANNEL
+#include <schnlsp.h>
+#include <schannel.h>
+#include "curl_sspi.h"
+
#include "urldata.h"
extern const struct Curl_ssl Curl_ssl_schannel;
+CURLcode verify_certificate(struct connectdata *conn, int sockindex);
+
+/* structs to expose only in schannel.c and schannel_verify.c */
+#ifdef EXPOSE_SCHANNEL_INTERNAL_STRUCTS
+struct curl_schannel_cred {
+ CredHandle cred_handle;
+ TimeStamp time_stamp;
+ int refcount;
+};
+
+struct curl_schannel_ctxt {
+ CtxtHandle ctxt_handle;
+ TimeStamp time_stamp;
+};
+
+struct ssl_backend_data {
+ struct curl_schannel_cred *cred;
+ struct curl_schannel_ctxt *ctxt;
+ SecPkgContext_StreamSizes stream_sizes;
+ size_t encdata_length, decdata_length;
+ size_t encdata_offset, decdata_offset;
+ unsigned char *encdata_buffer, *decdata_buffer;
+ /* encdata_is_incomplete: if encdata contains only a partial record that
+ can't be decrypted without another Curl_read_plain (that is, status is
+ SEC_E_INCOMPLETE_MESSAGE) then set this true. after Curl_read_plain writes
+ more bytes into encdata then set this back to false. */
+ bool encdata_is_incomplete;
+ unsigned long req_flags, ret_flags;
+ CURLcode recv_unrecoverable_err; /* schannel_recv had an unrecoverable err */
+ bool recv_sspi_close_notify; /* true if connection closed by close_notify */
+ bool recv_connection_closed; /* true if connection closed, regardless how */
+ bool use_alpn; /* true if ALPN is used for this connection */
+ bool use_manual_cred_validation; /* true if manual cred validation is used */
+};
+#endif /* EXPOSE_SCHANNEL_INTERNAL_STRUCTS */
+
#endif /* USE_SCHANNEL */
#endif /* HEADER_CURL_SCHANNEL_H */
diff --git a/Utilities/cmcurl/lib/vtls/schannel_verify.c b/Utilities/cmcurl/lib/vtls/schannel_verify.c
new file mode 100644
index 0000000..db187dd
--- /dev/null
+++ b/Utilities/cmcurl/lib/vtls/schannel_verify.c
@@ -0,0 +1,551 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2012 - 2016, Marc Hoersken, <info@marc-hoersken.de>
+ * Copyright (C) 2012, Mark Salisbury, <mark.salisbury@hp.com>
+ * Copyright (C) 2012 - 2018, 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.haxx.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.
+ *
+ ***************************************************************************/
+
+/*
+ * Source file for SChannel-specific certificate verification. This code should
+ * only be invoked by code in schannel.c.
+ */
+
+#include "curl_setup.h"
+
+#ifdef USE_SCHANNEL
+
+#define EXPOSE_SCHANNEL_INTERNAL_STRUCTS
+
+#ifndef USE_WINDOWS_SSPI
+# error "Can't compile SCHANNEL support without SSPI."
+#endif
+
+#include "schannel.h"
+#include "vtls.h"
+#include "sendf.h"
+#include "strerror.h"
+#include "curl_multibyte.h"
+#include "curl_printf.h"
+#include "hostcheck.h"
+#include "system_win32.h"
+
+/* The last #include file should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#define BACKEND connssl->backend
+
+#define MAX_CAFILE_SIZE 1048576 /* 1 MiB */
+#define BEGIN_CERT "-----BEGIN CERTIFICATE-----\n"
+#define END_CERT "\n-----END CERTIFICATE-----"
+
+typedef struct {
+ DWORD cbSize;
+ HCERTSTORE hRestrictedRoot;
+ HCERTSTORE hRestrictedTrust;
+ HCERTSTORE hRestrictedOther;
+ DWORD cAdditionalStore;
+ HCERTSTORE *rghAdditionalStore;
+ DWORD dwFlags;
+ DWORD dwUrlRetrievalTimeout;
+ DWORD MaximumCachedCertificates;
+ DWORD CycleDetectionModulus;
+ HCERTSTORE hExclusiveRoot;
+ HCERTSTORE hExclusiveTrustedPeople;
+} CERT_CHAIN_ENGINE_CONFIG_WIN7, *PCERT_CHAIN_ENGINE_CONFIG_WIN7;
+
+
+static CURLcode add_certs_to_store(HCERTSTORE trust_store,
+ const char *ca_file,
+ struct connectdata *conn)
+{
+ CURLcode result;
+ struct Curl_easy *data = conn->data;
+ HANDLE ca_file_handle = INVALID_HANDLE_VALUE;
+ LARGE_INTEGER file_size;
+ char *ca_file_buffer = NULL;
+ char *current_ca_file_ptr = NULL;
+ const TCHAR *ca_file_tstr = NULL;
+ size_t ca_file_bufsize = 0;
+ DWORD total_bytes_read = 0;
+ bool more_certs = 0;
+ int num_certs = 0;
+ size_t END_CERT_LEN;
+
+ ca_file_tstr = Curl_convert_UTF8_to_tchar(ca_file);
+ if(!ca_file_tstr) {
+ failf(data,
+ "schannel: invalid path name for CA file '%s': %s",
+ ca_file, Curl_strerror(conn, GetLastError()));
+ result = CURLE_SSL_CACERT_BADFILE;
+ goto cleanup;
+ }
+
+ /*
+ * Read the CA file completely into memory before parsing it. This
+ * optimizes for the common case where the CA file will be relatively
+ * small ( < 1 MiB ).
+ */
+ ca_file_handle = CreateFile(ca_file_tstr,
+ GENERIC_READ,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ if(ca_file_handle == INVALID_HANDLE_VALUE) {
+ failf(data,
+ "schannel: failed to open CA file '%s': %s",
+ ca_file, Curl_strerror(conn, GetLastError()));
+ result = CURLE_SSL_CACERT_BADFILE;
+ goto cleanup;
+ }
+
+ if(!GetFileSizeEx(ca_file_handle, &file_size)) {
+ failf(data,
+ "schannel: failed to determine size of CA file '%s': %s",
+ ca_file, Curl_strerror(conn, GetLastError()));
+ result = CURLE_SSL_CACERT_BADFILE;
+ goto cleanup;
+ }
+
+ if(file_size.QuadPart > MAX_CAFILE_SIZE) {
+ failf(data,
+ "schannel: CA file exceeds max size of %u bytes",
+ MAX_CAFILE_SIZE);
+ result = CURLE_OUT_OF_MEMORY;
+ goto cleanup;
+ }
+
+ ca_file_bufsize = (size_t)file_size.QuadPart;
+ ca_file_buffer = (char *)malloc(ca_file_bufsize + 1);
+ if(!ca_file_buffer) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto cleanup;
+ }
+
+ result = CURLE_OK;
+ while(total_bytes_read < ca_file_bufsize) {
+ DWORD bytes_to_read = (DWORD)(ca_file_bufsize - total_bytes_read);
+ DWORD bytes_read = 0;
+
+ if(!ReadFile(ca_file_handle, ca_file_buffer + total_bytes_read,
+ bytes_to_read, &bytes_read, NULL)) {
+
+ failf(data,
+ "schannel: failed to read from CA file '%s': %s",
+ ca_file, Curl_strerror(conn, GetLastError()));
+ result = CURLE_SSL_CACERT_BADFILE;
+ goto cleanup;
+ }
+ if(bytes_read == 0) {
+ /* Premature EOF -- adjust the bufsize to the new value */
+ ca_file_bufsize = total_bytes_read;
+ }
+ else {
+ total_bytes_read += bytes_read;
+ }
+ }
+
+ /* Null terminate the buffer */
+ ca_file_buffer[ca_file_bufsize] = '\0';
+
+ if(result != CURLE_OK) {
+ goto cleanup;
+ }
+
+ END_CERT_LEN = strlen(END_CERT);
+
+ more_certs = 1;
+ current_ca_file_ptr = ca_file_buffer;
+ while(more_certs && *current_ca_file_ptr != '\0') {
+ char *begin_cert_ptr = strstr(current_ca_file_ptr, BEGIN_CERT);
+ if(!begin_cert_ptr) {
+ more_certs = 0;
+ }
+ else {
+ char *end_cert_ptr = strstr(begin_cert_ptr, END_CERT);
+ if(!end_cert_ptr) {
+ failf(data,
+ "schannel: CA file '%s' is not correctly formatted",
+ ca_file);
+ result = CURLE_SSL_CACERT_BADFILE;
+ more_certs = 0;
+ }
+ else {
+ CERT_BLOB cert_blob;
+ CERT_CONTEXT *cert_context = NULL;
+ BOOL add_cert_result = FALSE;
+ DWORD actual_content_type = 0;
+ DWORD cert_size = (DWORD)
+ ((end_cert_ptr + END_CERT_LEN) - begin_cert_ptr);
+
+ cert_blob.pbData = (BYTE *)begin_cert_ptr;
+ cert_blob.cbData = cert_size;
+ if(!CryptQueryObject(CERT_QUERY_OBJECT_BLOB,
+ &cert_blob,
+ CERT_QUERY_CONTENT_FLAG_CERT,
+ CERT_QUERY_FORMAT_FLAG_ALL,
+ 0,
+ NULL,
+ &actual_content_type,
+ NULL,
+ NULL,
+ NULL,
+ &cert_context)) {
+
+ failf(data,
+ "schannel: failed to extract certificate from CA file "
+ "'%s': %s",
+ ca_file, Curl_strerror(conn, GetLastError()));
+ result = CURLE_SSL_CACERT_BADFILE;
+ more_certs = 0;
+ }
+ else {
+ current_ca_file_ptr = begin_cert_ptr + cert_size;
+
+ /* Sanity check that the cert_context object is the right type */
+ if(CERT_QUERY_CONTENT_CERT != actual_content_type) {
+ failf(data,
+ "schannel: unexpected content type '%d' when extracting "
+ "certificate from CA file '%s'",
+ actual_content_type, ca_file);
+ result = CURLE_SSL_CACERT_BADFILE;
+ more_certs = 0;
+ }
+ else {
+ add_cert_result =
+ CertAddCertificateContextToStore(trust_store,
+ cert_context,
+ CERT_STORE_ADD_ALWAYS,
+ NULL);
+ CertFreeCertificateContext(cert_context);
+ if(!add_cert_result) {
+ failf(data,
+ "schannel: failed to add certificate from CA file '%s'"
+ "to certificate store: %s",
+ ca_file, Curl_strerror(conn, GetLastError()));
+ result = CURLE_SSL_CACERT_BADFILE;
+ more_certs = 0;
+ }
+ else {
+ num_certs++;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if(result == CURLE_OK) {
+ if(!num_certs) {
+ infof(data,
+ "schannel: did not add any certificates from CA file '%s'\n",
+ ca_file);
+ }
+ else {
+ infof(data,
+ "schannel: added %d certificate(s) from CA file '%s'\n",
+ num_certs, ca_file);
+ }
+ }
+
+cleanup:
+ if(ca_file_handle != INVALID_HANDLE_VALUE) {
+ CloseHandle(ca_file_handle);
+ }
+ Curl_safefree(ca_file_buffer);
+ Curl_unicodefree(ca_file_tstr);
+
+ return result;
+}
+
+static CURLcode verify_host(struct Curl_easy *data,
+ CERT_CONTEXT *pCertContextServer,
+ const char * const conn_hostname)
+{
+ CURLcode result = CURLE_PEER_FAILED_VERIFICATION;
+ TCHAR *cert_hostname_buff = NULL;
+ size_t cert_hostname_buff_index = 0;
+ DWORD len = 0;
+ DWORD actual_len = 0;
+
+ /* CertGetNameString will provide the 8-bit character string without
+ * any decoding */
+ DWORD name_flags = CERT_NAME_DISABLE_IE4_UTF8_FLAG;
+
+#ifdef CERT_NAME_SEARCH_ALL_NAMES_FLAG
+ name_flags |= CERT_NAME_SEARCH_ALL_NAMES_FLAG;
+#endif
+
+ /* Determine the size of the string needed for the cert hostname */
+ len = CertGetNameString(pCertContextServer,
+ CERT_NAME_DNS_TYPE,
+ name_flags,
+ NULL,
+ NULL,
+ 0);
+ if(len == 0) {
+ failf(data,
+ "schannel: CertGetNameString() returned no "
+ "certificate name information");
+ result = CURLE_PEER_FAILED_VERIFICATION;
+ goto cleanup;
+ }
+
+ /* CertGetNameString guarantees that the returned name will not contain
+ * embedded null bytes. This appears to be undocumented behavior.
+ */
+ cert_hostname_buff = (LPTSTR)malloc(len * sizeof(TCHAR));
+ actual_len = CertGetNameString(pCertContextServer,
+ CERT_NAME_DNS_TYPE,
+ name_flags,
+ NULL,
+ (LPTSTR) cert_hostname_buff,
+ len);
+
+ /* Sanity check */
+ if(actual_len != len) {
+ failf(data,
+ "schannel: CertGetNameString() returned certificate "
+ "name information of unexpected size");
+ result = CURLE_PEER_FAILED_VERIFICATION;
+ goto cleanup;
+ }
+
+ /* If HAVE_CERT_NAME_SEARCH_ALL_NAMES is available, the output
+ * will contain all DNS names, where each name is null-terminated
+ * and the last DNS name is double null-terminated. Due to this
+ * encoding, use the length of the buffer to iterate over all names.
+ */
+ result = CURLE_PEER_FAILED_VERIFICATION;
+ while(cert_hostname_buff_index < len &&
+ cert_hostname_buff[cert_hostname_buff_index] != TEXT('\0') &&
+ result == CURLE_PEER_FAILED_VERIFICATION) {
+
+ char *cert_hostname;
+
+ /* Comparing the cert name and the connection hostname encoded as UTF-8
+ * is acceptable since both values are assumed to use ASCII
+ * (or some equivalent) encoding
+ */
+ cert_hostname = Curl_convert_tchar_to_UTF8(
+ &cert_hostname_buff[cert_hostname_buff_index]);
+ if(!cert_hostname) {
+ result = CURLE_OUT_OF_MEMORY;
+ }
+ else {
+ int match_result;
+
+ match_result = Curl_cert_hostcheck(cert_hostname, conn_hostname);
+ if(match_result == CURL_HOST_MATCH) {
+ infof(data,
+ "schannel: connection hostname (%s) validated "
+ "against certificate name (%s)\n",
+ conn_hostname, cert_hostname);
+ result = CURLE_OK;
+ }
+ else {
+ size_t cert_hostname_len;
+
+ infof(data,
+ "schannel: connection hostname (%s) did not match "
+ "against certificate name (%s)\n",
+ conn_hostname, cert_hostname);
+
+ cert_hostname_len = _tcslen(
+ &cert_hostname_buff[cert_hostname_buff_index]);
+
+ /* Move on to next cert name */
+ cert_hostname_buff_index += cert_hostname_len + 1;
+
+ result = CURLE_PEER_FAILED_VERIFICATION;
+ }
+ Curl_unicodefree(cert_hostname);
+ }
+ }
+
+ if(result == CURLE_PEER_FAILED_VERIFICATION) {
+ failf(data,
+ "schannel: CertGetNameString() failed to match "
+ "connection hostname (%s) against server certificate names",
+ conn_hostname);
+ }
+ else if(result != CURLE_OK)
+ failf(data, "schannel: server certificate name verification failed");
+
+cleanup:
+ Curl_unicodefree(cert_hostname_buff);
+
+ return result;
+}
+
+CURLcode verify_certificate(struct connectdata *conn, int sockindex)
+{
+ SECURITY_STATUS status;
+ struct Curl_easy *data = conn->data;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ CURLcode result = CURLE_OK;
+ CERT_CONTEXT *pCertContextServer = NULL;
+ const CERT_CHAIN_CONTEXT *pChainContext = NULL;
+ HCERTCHAINENGINE cert_chain_engine = NULL;
+ HCERTSTORE trust_store = NULL;
+ const char * const conn_hostname = SSL_IS_PROXY() ?
+ conn->http_proxy.host.name :
+ conn->host.name;
+
+ status = s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
+ SECPKG_ATTR_REMOTE_CERT_CONTEXT,
+ &pCertContextServer);
+
+ if((status != SEC_E_OK) || (pCertContextServer == NULL)) {
+ failf(data, "schannel: Failed to read remote certificate context: %s",
+ Curl_sspi_strerror(conn, status));
+ result = CURLE_PEER_FAILED_VERIFICATION;
+ }
+
+ if(result == CURLE_OK && SSL_CONN_CONFIG(CAfile) &&
+ BACKEND->use_manual_cred_validation) {
+ /*
+ * Create a chain engine that uses the certificates in the CA file as
+ * trusted certificates. This is only supported on Windows 7+.
+ */
+
+ if(Curl_verify_windows_version(6, 1, PLATFORM_WINNT, VERSION_LESS_THAN)) {
+ failf(data, "schannel: this version of Windows is too old to support "
+ "certificate verification via CA bundle file.");
+ result = CURLE_SSL_CACERT_BADFILE;
+ }
+ else {
+ /* Open the certificate store */
+ trust_store = CertOpenStore(CERT_STORE_PROV_MEMORY,
+ 0,
+ (HCRYPTPROV)NULL,
+ CERT_STORE_CREATE_NEW_FLAG,
+ NULL);
+ if(!trust_store) {
+ failf(data, "schannel: failed to create certificate store: %s",
+ Curl_strerror(conn, GetLastError()));
+ result = CURLE_SSL_CACERT_BADFILE;
+ }
+ else {
+ result = add_certs_to_store(trust_store, SSL_CONN_CONFIG(CAfile),
+ conn);
+ }
+ }
+
+ if(result == CURLE_OK) {
+ CERT_CHAIN_ENGINE_CONFIG_WIN7 engine_config;
+ BOOL create_engine_result;
+
+ memset(&engine_config, 0, sizeof(engine_config));
+ engine_config.cbSize = sizeof(engine_config);
+ engine_config.hExclusiveRoot = trust_store;
+
+ /* CertCreateCertificateChainEngine will check the expected size of the
+ * CERT_CHAIN_ENGINE_CONFIG structure and fail if the specified size
+ * does not match the expected size. When this occurs, it indicates that
+ * CAINFO is not supported on the version of Windows in use.
+ */
+ create_engine_result =
+ CertCreateCertificateChainEngine(
+ (CERT_CHAIN_ENGINE_CONFIG *)&engine_config, &cert_chain_engine);
+ if(!create_engine_result) {
+ failf(data,
+ "schannel: failed to create certificate chain engine: %s",
+ Curl_strerror(conn, GetLastError()));
+ result = CURLE_SSL_CACERT_BADFILE;
+ }
+ }
+ }
+
+ if(result == CURLE_OK) {
+ CERT_CHAIN_PARA ChainPara;
+
+ memset(&ChainPara, 0, sizeof(ChainPara));
+ ChainPara.cbSize = sizeof(ChainPara);
+
+ if(!CertGetCertificateChain(cert_chain_engine,
+ pCertContextServer,
+ NULL,
+ pCertContextServer->hCertStore,
+ &ChainPara,
+ (data->set.ssl.no_revoke ? 0 :
+ CERT_CHAIN_REVOCATION_CHECK_CHAIN),
+ NULL,
+ &pChainContext)) {
+ failf(data, "schannel: CertGetCertificateChain failed: %s",
+ Curl_sspi_strerror(conn, GetLastError()));
+ pChainContext = NULL;
+ result = CURLE_PEER_FAILED_VERIFICATION;
+ }
+
+ if(result == CURLE_OK) {
+ CERT_SIMPLE_CHAIN *pSimpleChain = pChainContext->rgpChain[0];
+ DWORD dwTrustErrorMask = ~(DWORD)(CERT_TRUST_IS_NOT_TIME_NESTED);
+ dwTrustErrorMask &= pSimpleChain->TrustStatus.dwErrorStatus;
+ if(dwTrustErrorMask) {
+ if(dwTrustErrorMask & CERT_TRUST_IS_REVOKED)
+ failf(data, "schannel: CertGetCertificateChain trust error"
+ " CERT_TRUST_IS_REVOKED");
+ else if(dwTrustErrorMask & CERT_TRUST_IS_PARTIAL_CHAIN)
+ failf(data, "schannel: CertGetCertificateChain trust error"
+ " CERT_TRUST_IS_PARTIAL_CHAIN");
+ else if(dwTrustErrorMask & CERT_TRUST_IS_UNTRUSTED_ROOT)
+ failf(data, "schannel: CertGetCertificateChain trust error"
+ " CERT_TRUST_IS_UNTRUSTED_ROOT");
+ else if(dwTrustErrorMask & CERT_TRUST_IS_NOT_TIME_VALID)
+ failf(data, "schannel: CertGetCertificateChain trust error"
+ " CERT_TRUST_IS_NOT_TIME_VALID");
+ else if(dwTrustErrorMask & CERT_TRUST_REVOCATION_STATUS_UNKNOWN)
+ failf(data, "schannel: CertGetCertificateChain trust error"
+ " CERT_TRUST_REVOCATION_STATUS_UNKNOWN");
+ else
+ failf(data, "schannel: CertGetCertificateChain error mask: 0x%08x",
+ dwTrustErrorMask);
+ result = CURLE_PEER_FAILED_VERIFICATION;
+ }
+ }
+ }
+
+ if(result == CURLE_OK) {
+ if(SSL_CONN_CONFIG(verifyhost)) {
+ result = verify_host(conn->data, pCertContextServer, conn_hostname);
+ }
+ }
+
+ if(cert_chain_engine) {
+ CertFreeCertificateChainEngine(cert_chain_engine);
+ }
+
+ if(trust_store) {
+ CertCloseStore(trust_store, 0);
+ }
+
+ if(pChainContext)
+ CertFreeCertificateChain(pChainContext);
+
+ if(pCertContextServer)
+ CertFreeCertificateContext(pCertContextServer);
+
+ return result;
+}
+
+#endif /* USE_SCHANNEL */
diff --git a/Utilities/cmcurl/lib/vtls/vtls.c b/Utilities/cmcurl/lib/vtls/vtls.c
index def1d30..ee5bc7a 100644
--- a/Utilities/cmcurl/lib/vtls/vtls.c
+++ b/Utilities/cmcurl/lib/vtls/vtls.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2018, 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
@@ -211,7 +211,7 @@ ssl_connect_init_proxy(struct connectdata *conn, int sockindex)
!conn->proxy_ssl[sockindex].use) {
struct ssl_backend_data *pbdata;
- if(!Curl_ssl->support_https_proxy)
+ if(!(Curl_ssl->supports & SSLSUPP_HTTPS_PROXY))
return CURLE_NOT_BUILT_IN;
/* The pointers to the ssl backend data, which is opaque here, are swapped
@@ -511,7 +511,7 @@ void Curl_ssl_close_all(struct Curl_easy *data)
#if defined(USE_OPENSSL) || defined(USE_GNUTLS) || defined(USE_SCHANNEL) || \
defined(USE_DARWINSSL) || defined(USE_POLARSSL) || defined(USE_NSS) || \
- defined(USE_MBEDTLS)
+ defined(USE_MBEDTLS) || defined(USE_CYASSL)
int Curl_ssl_getsock(struct connectdata *conn, curl_socket_t *socks,
int numsocks)
{
@@ -831,8 +831,12 @@ CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data,
sha256sumdigest = malloc(CURL_SHA256_DIGEST_LENGTH);
if(!sha256sumdigest)
return CURLE_OUT_OF_MEMORY;
- Curl_ssl->sha256sum(pubkey, pubkeylen,
+ encode = Curl_ssl->sha256sum(pubkey, pubkeylen,
sha256sumdigest, CURL_SHA256_DIGEST_LENGTH);
+
+ if(encode != CURLE_OK)
+ return encode;
+
encode = Curl_base64_encode(data, (char *)sha256sumdigest,
CURL_SHA256_DIGEST_LENGTH, &encoded,
&encodedlen);
@@ -1127,13 +1131,7 @@ static void Curl_multissl_close(struct connectdata *conn, int sockindex)
static const struct Curl_ssl Curl_ssl_multi = {
{ CURLSSLBACKEND_NONE, "multi" }, /* info */
-
- 0, /* have_ca_path */
- 0, /* have_certinfo */
- 0, /* have_pinnedpubkey */
- 0, /* have_ssl_ctx */
- 0, /* support_https_proxy */
-
+ 0, /* supports nothing */
(size_t)-1, /* something insanely large to be on the safe side */
Curl_multissl_init, /* init */
@@ -1300,6 +1298,9 @@ CURLsslset curl_global_sslset(curl_sslbackend id, const char *name,
{
int i;
+ if(avail)
+ *avail = (const curl_ssl_backend **)&available_backends;
+
if(Curl_ssl != &Curl_ssl_multi)
return id == Curl_ssl->info.id ? CURLSSLSET_OK : CURLSSLSET_TOO_LATE;
@@ -1311,8 +1312,6 @@ CURLsslset curl_global_sslset(curl_sslbackend id, const char *name,
}
}
- if(avail)
- *avail = (const curl_ssl_backend **)&available_backends;
return CURLSSLSET_UNKNOWN_BACKEND;
}
diff --git a/Utilities/cmcurl/lib/vtls/vtls.h b/Utilities/cmcurl/lib/vtls/vtls.h
index c5f9d4a..e7b87c4 100644
--- a/Utilities/cmcurl/lib/vtls/vtls.h
+++ b/Utilities/cmcurl/lib/vtls/vtls.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2018, 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
@@ -26,20 +26,19 @@
struct connectdata;
struct ssl_connect_data;
+#define SSLSUPP_CA_PATH (1<<0) /* supports CAPATH */
+#define SSLSUPP_CERTINFO (1<<1) /* supports CURLOPT_CERTINFO */
+#define SSLSUPP_PINNEDPUBKEY (1<<2) /* supports CURLOPT_PINNEDPUBLICKEY */
+#define SSLSUPP_SSL_CTX (1<<3) /* supports CURLOPT_SSL_CTX */
+#define SSLSUPP_HTTPS_PROXY (1<<4) /* supports access via HTTPS proxies */
+
struct Curl_ssl {
/*
* This *must* be the first entry to allow returning the list of available
* backends in curl_global_sslset().
*/
curl_ssl_backend info;
-
- unsigned have_ca_path:1; /* supports CAPATH */
- unsigned have_certinfo:1; /* supports CURLOPT_CERTINFO */
- unsigned have_pinnedpubkey:1; /* supports CURLOPT_PINNEDPUBLICKEY */
- unsigned have_ssl_ctx:1; /* supports CURLOPT_SSL_CTX_* */
-
- unsigned support_https_proxy:1; /* supports access via HTTPS proxies */
-
+ unsigned int supports; /* bitfield, see above */
size_t sizeof_ssl_backend_data;
int (*init)(void);
@@ -72,7 +71,7 @@ struct Curl_ssl {
CURLcode (*md5sum)(unsigned char *input, size_t inputlen,
unsigned char *md5sum, size_t md5sumlen);
- void (*sha256sum)(const unsigned char *input, size_t inputlen,
+ CURLcode (*sha256sum)(const unsigned char *input, size_t inputlen,
unsigned char *sha256sum, size_t sha256sumlen);
};
@@ -113,8 +112,10 @@ CURLcode Curl_none_md5sum(unsigned char *input, size_t inputlen,
#endif
#ifndef MD5_DIGEST_LENGTH
+#ifndef LIBWOLFSSL_VERSION_HEX /* because WolfSSL borks this */
#define MD5_DIGEST_LENGTH 16 /* fixed size */
#endif
+#endif
#ifndef CURL_SHA256_DIGEST_LENGTH
#define CURL_SHA256_DIGEST_LENGTH 32 /* fixed size */