summaryrefslogtreecommitdiff
path: root/Utilities/cmcurl/lib/vtls
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2017-02-07 11:38:00 -0500
committerBrad King <brad.king@kitware.com>2017-02-07 11:38:00 -0500
commit1df9d5f91944e0b5ba00815d55bb7dc545053b4c (patch)
tree7f3ac8bf78c485cd3254a16754657bd5d43bd561 /Utilities/cmcurl/lib/vtls
parentf4a3290ae7ae096f8b92f7adfba7088e6918bc0b (diff)
parent4cc2908fdaaf1ab8afe5c2ae5dbb3401859a9aab (diff)
downloadcmake-1df9d5f91944e0b5ba00815d55bb7dc545053b4c.tar.gz
Merge branch 'upstream-curl' into update-curl
* upstream-curl: curl 2016-12-22 (44b9b4d4)
Diffstat (limited to 'Utilities/cmcurl/lib/vtls')
-rw-r--r--Utilities/cmcurl/lib/vtls/axtls.c81
-rw-r--r--Utilities/cmcurl/lib/vtls/cyassl.c105
-rw-r--r--Utilities/cmcurl/lib/vtls/darwinssl.c412
-rw-r--r--Utilities/cmcurl/lib/vtls/gskit.c354
-rw-r--r--Utilities/cmcurl/lib/vtls/gskit.h7
-rw-r--r--Utilities/cmcurl/lib/vtls/gtls.c289
-rw-r--r--Utilities/cmcurl/lib/vtls/gtls.h7
-rw-r--r--Utilities/cmcurl/lib/vtls/mbedtls.c92
-rw-r--r--Utilities/cmcurl/lib/vtls/nss.c219
-rw-r--r--Utilities/cmcurl/lib/vtls/nssg.h3
-rw-r--r--Utilities/cmcurl/lib/vtls/openssl.c398
-rw-r--r--Utilities/cmcurl/lib/vtls/openssl.h3
-rw-r--r--Utilities/cmcurl/lib/vtls/polarssl.c81
-rw-r--r--Utilities/cmcurl/lib/vtls/schannel.c144
-rw-r--r--Utilities/cmcurl/lib/vtls/vtls.c300
-rw-r--r--Utilities/cmcurl/lib/vtls/vtls.h48
16 files changed, 1563 insertions, 980 deletions
diff --git a/Utilities/cmcurl/lib/vtls/axtls.c b/Utilities/cmcurl/lib/vtls/axtls.c
index 85b8bc4f60..ff4634e5b7 100644
--- a/Utilities/cmcurl/lib/vtls/axtls.c
+++ b/Utilities/cmcurl/lib/vtls/axtls.c
@@ -65,7 +65,7 @@ int Curl_axtls_cleanup(void)
static CURLcode map_error_to_curl(int axtls_err)
{
- switch (axtls_err) {
+ switch(axtls_err) {
case SSL_ERROR_NOT_SUPPORTED:
case SSL_ERROR_INVALID_VERSION:
case -70: /* protocol version alert from server */
@@ -121,7 +121,7 @@ static Curl_send axtls_send;
static void free_ssl_structs(struct ssl_connect_data *connssl)
{
if(connssl->ssl) {
- ssl_free (connssl->ssl);
+ ssl_free(connssl->ssl);
connssl->ssl = NULL;
}
if(connssl->ssl_ctx) {
@@ -158,7 +158,7 @@ static CURLcode connect_prep(struct connectdata *conn, int sockindex)
/* axTLS only supports TLSv1 */
/* check to see if we've been told to use an explicit SSL/TLS version */
- switch(data->set.ssl.version) {
+ switch(SSL_CONN_CONFIG(version)) {
case CURL_SSLVERSION_DEFAULT:
case CURL_SSLVERSION_TLSv1:
break;
@@ -183,17 +183,17 @@ static CURLcode connect_prep(struct connectdata *conn, int sockindex)
conn->ssl[sockindex].ssl = NULL;
/* Load the trusted CA cert bundle file */
- if(data->set.ssl.CAfile) {
- if(ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CACERT, data->set.ssl.CAfile, NULL)
- != SSL_OK) {
+ if(SSL_CONN_CONFIG(CAfile)) {
+ if(ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CACERT,
+ SSL_CONN_CONFIG(CAfile), NULL) != SSL_OK) {
infof(data, "error reading ca cert file %s \n",
- data->set.ssl.CAfile);
- if(data->set.ssl.verifypeer) {
+ SSL_CONN_CONFIG(CAfile));
+ if(SSL_CONN_CONFIG(verifypeer)) {
return CURLE_SSL_CACERT_BADFILE;
}
}
else
- infof(data, "found certificates in %s\n", data->set.ssl.CAfile);
+ infof(data, "found certificates in %s\n", SSL_CONN_CONFIG(CAfile));
}
/* gtls.c tasks we're skipping for now:
@@ -205,15 +205,15 @@ static CURLcode connect_prep(struct connectdata *conn, int sockindex)
*/
/* Load client certificate */
- if(data->set.str[STRING_CERT]) {
+ if(SSL_SET_OPTION(cert)) {
i=0;
/* Instead of trying to analyze cert type here, let axTLS try them all. */
while(cert_types[i] != 0) {
ssl_fcn_return = ssl_obj_load(ssl_ctx, cert_types[i],
- data->set.str[STRING_CERT], NULL);
+ SSL_SET_OPTION(cert), NULL);
if(ssl_fcn_return == SSL_OK) {
infof(data, "successfully read cert file %s \n",
- data->set.str[STRING_CERT]);
+ SSL_SET_OPTION(cert));
break;
}
i++;
@@ -221,7 +221,7 @@ static CURLcode connect_prep(struct connectdata *conn, int sockindex)
/* Tried all cert types, none worked. */
if(cert_types[i] == 0) {
failf(data, "%s is not x509 or pkcs12 format",
- data->set.str[STRING_CERT]);
+ SSL_SET_OPTION(cert));
return CURLE_SSL_CERTPROBLEM;
}
}
@@ -229,15 +229,15 @@ static CURLcode connect_prep(struct connectdata *conn, int sockindex)
/* Load client key.
If a pkcs12 file successfully loaded a cert, then there's nothing to do
because the key has already been loaded. */
- if(data->set.str[STRING_KEY] && cert_types[i] != SSL_OBJ_PKCS12) {
+ if(SSL_SET_OPTION(key) && cert_types[i] != SSL_OBJ_PKCS12) {
i=0;
/* Instead of trying to analyze key type here, let axTLS try them all. */
while(key_types[i] != 0) {
ssl_fcn_return = ssl_obj_load(ssl_ctx, key_types[i],
- data->set.str[STRING_KEY], NULL);
+ SSL_SET_OPTION(key), NULL);
if(ssl_fcn_return == SSL_OK) {
infof(data, "successfully read key file %s \n",
- data->set.str[STRING_KEY]);
+ SSL_SET_OPTION(key));
break;
}
i++;
@@ -245,7 +245,7 @@ static CURLcode connect_prep(struct connectdata *conn, int sockindex)
/* Tried all key types, none worked. */
if(key_types[i] == 0) {
failf(data, "Failure: %s is not a supported key file",
- data->set.str[STRING_KEY]);
+ SSL_SET_OPTION(key));
return CURLE_SSL_CONNECT_ERROR;
}
}
@@ -256,15 +256,16 @@ static CURLcode connect_prep(struct connectdata *conn, int sockindex)
* 2) setting up callbacks. these seem gnutls specific
*/
- if(conn->ssl_config.sessionid) {
+ if(data->set.general_ssl.sessionid) {
const uint8_t *ssl_sessionid;
size_t ssl_idsize;
/* In axTLS, handshaking happens inside ssl_client_new. */
Curl_ssl_sessionid_lock(conn);
- if(!Curl_ssl_getsessionid(conn, (void **) &ssl_sessionid, &ssl_idsize)) {
+ if(!Curl_ssl_getsessionid(conn, (void **) &ssl_sessionid, &ssl_idsize,
+ sockindex)) {
/* we got a session id, use it! */
- infof (data, "SSL re-using session ID\n");
+ infof(data, "SSL re-using session ID\n");
ssl = ssl_client_new(ssl_ctx, conn->sock[sockindex],
ssl_sessionid, (uint8_t)ssl_idsize);
}
@@ -291,13 +292,17 @@ static CURLcode connect_finish(struct connectdata *conn, int sockindex)
const char *dns_altname;
int8_t found_subject_alt_names = 0;
int8_t found_subject_alt_name_matching_conn = 0;
+ const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
+ conn->host.name;
+ const char * const dispname = SSL_IS_PROXY() ?
+ conn->http_proxy.host.dispname : conn->host.dispname;
/* Here, gtls.c gets the peer certificates and fails out depending on
* settings in "data." axTLS api doesn't have get cert chain fcn, so omit?
*/
/* Verify server's certificate */
- if(data->set.ssl.verifypeer) {
+ if(SSL_CONN_CONFIG(verifypeer)) {
if(ssl_verify_cert(ssl) != SSL_OK) {
Curl_axtls_close(conn, sockindex);
failf(data, "server cert verify failed");
@@ -328,8 +333,8 @@ static CURLcode connect_finish(struct connectdata *conn, int sockindex)
found_subject_alt_names = 1;
infof(data, "\tComparing subject alt name DNS with hostname: %s <-> %s\n",
- dns_altname, conn->host.name);
- if(Curl_cert_hostcheck(dns_altname, conn->host.name)) {
+ dns_altname, hostname);
+ if(Curl_cert_hostcheck(dns_altname, hostname)) {
found_subject_alt_name_matching_conn = 1;
break;
}
@@ -337,23 +342,21 @@ static CURLcode connect_finish(struct connectdata *conn, int sockindex)
/* RFC2818 checks */
if(found_subject_alt_names && !found_subject_alt_name_matching_conn) {
- if(data->set.ssl.verifyhost) {
+ if(SSL_CONN_CONFIG(verifyhost)) {
/* Break connection ! */
Curl_axtls_close(conn, sockindex);
- failf(data, "\tsubjectAltName(s) do not match %s\n",
- conn->host.dispname);
+ failf(data, "\tsubjectAltName(s) do not match %s\n", dispname);
return CURLE_PEER_FAILED_VERIFICATION;
}
else
- infof(data, "\tsubjectAltName(s) do not match %s\n",
- conn->host.dispname);
+ infof(data, "\tsubjectAltName(s) do not match %s\n", dispname);
}
else if(found_subject_alt_names == 0) {
/* Per RFC2818, when no Subject Alt Names were available, examine the peer
CN as a legacy fallback */
peer_CN = ssl_get_cert_dn(ssl, SSL_X509_CERT_COMMON_NAME);
if(peer_CN == NULL) {
- if(data->set.ssl.verifyhost) {
+ if(SSL_CONN_CONFIG(verifyhost)) {
Curl_axtls_close(conn, sockindex);
failf(data, "unable to obtain common name from peer certificate");
return CURLE_PEER_FAILED_VERIFICATION;
@@ -362,17 +365,17 @@ static CURLcode connect_finish(struct connectdata *conn, int sockindex)
infof(data, "unable to obtain common name from peer certificate");
}
else {
- if(!Curl_cert_hostcheck((const char *)peer_CN, conn->host.name)) {
- if(data->set.ssl.verifyhost) {
+ if(!Curl_cert_hostcheck((const char *)peer_CN, hostname)) {
+ if(SSL_CONN_CONFIG(verifyhost)) {
/* Break connection ! */
Curl_axtls_close(conn, sockindex);
failf(data, "\tcommon name \"%s\" does not match \"%s\"\n",
- peer_CN, conn->host.dispname);
+ peer_CN, dispname);
return CURLE_PEER_FAILED_VERIFICATION;
}
else
infof(data, "\tcommon name \"%s\" does not match \"%s\"\n",
- peer_CN, conn->host.dispname);
+ peer_CN, dispname);
}
}
}
@@ -383,13 +386,13 @@ static CURLcode connect_finish(struct connectdata *conn, int sockindex)
conn->send[sockindex] = axtls_send;
/* Put our freshly minted SSL session in cache */
- if(conn->ssl_config.sessionid) {
+ if(data->set.general_ssl.sessionid) {
const uint8_t *ssl_sessionid = ssl_get_session_id_size(ssl);
size_t ssl_idsize = ssl_get_session_id(ssl);
Curl_ssl_sessionid_lock(conn);
- if(Curl_ssl_addsessionid(conn, (void *) ssl_sessionid, ssl_idsize)
- != CURLE_OK)
- infof (data, "failed to add session to cache\n");
+ if(Curl_ssl_addsessionid(conn, (void *) ssl_sessionid, ssl_idsize,
+ sockindex) != CURLE_OK)
+ infof(data, "failed to add session to cache\n");
Curl_ssl_sessionid_unlock(conn);
}
@@ -437,7 +440,7 @@ CURLcode Curl_axtls_connect_nonblocking(
return CURLE_OK;
}
}
- infof (conn->data, "handshake completed successfully\n");
+ infof(conn->data, "handshake completed successfully\n");
conn->ssl[sockindex].connecting_state = ssl_connect_3;
}
@@ -503,7 +506,7 @@ Curl_axtls_connect(struct connectdata *conn,
/* TODO: avoid polling */
Curl_wait_ms(10);
}
- infof (conn->data, "handshake completed successfully\n");
+ infof(conn->data, "handshake completed successfully\n");
conn_step = connect_finish(conn, sockindex);
if(conn_step != CURLE_OK) {
diff --git a/Utilities/cmcurl/lib/vtls/cyassl.c b/Utilities/cmcurl/lib/vtls/cyassl.c
index 5d6dbfb8c9..fc4dde4a1a 100644
--- a/Utilities/cmcurl/lib/vtls/cyassl.c
+++ b/Utilities/cmcurl/lib/vtls/cyassl.c
@@ -149,7 +149,7 @@ cyassl_connect_step1(struct connectdata *conn,
return CURLE_OK;
/* check to see if we've been told to use an explicit SSL/TLS version */
- switch(data->set.ssl.version) {
+ switch(SSL_CONN_CONFIG(version)) {
case CURL_SSLVERSION_DEFAULT:
case CURL_SSLVERSION_TLSv1:
#if LIBCYASSL_VERSION_HEX >= 0x03003000 /* >= 3.3.0 */
@@ -174,12 +174,15 @@ cyassl_connect_step1(struct connectdata *conn,
req_method = TLSv1_2_client_method();
use_sni(TRUE);
break;
+ case CURL_SSLVERSION_TLSv1_3:
+ failf(data, "CyaSSL: TLS 1.3 is not yet supported");
+ return CURLE_SSL_CONNECT_ERROR;
case CURL_SSLVERSION_SSLv3:
#ifdef WOLFSSL_ALLOW_SSLV3
req_method = SSLv3_client_method();
use_sni(FALSE);
#else
- failf(data, "No support for SSLv3");
+ failf(data, "CyaSSL does not support SSLv3");
return CURLE_NOT_BUILT_IN;
#endif
break;
@@ -205,7 +208,7 @@ cyassl_connect_step1(struct connectdata *conn,
return CURLE_OUT_OF_MEMORY;
}
- switch(data->set.ssl.version) {
+ switch(SSL_CONN_CONFIG(version)) {
case CURL_SSLVERSION_DEFAULT:
case CURL_SSLVERSION_TLSv1:
#if LIBCYASSL_VERSION_HEX > 0x03004006 /* > 3.4.6 */
@@ -228,18 +231,18 @@ cyassl_connect_step1(struct connectdata *conn,
#ifndef NO_FILESYSTEM
/* load trusted cacert */
- if(data->set.str[STRING_SSL_CAFILE]) {
+ if(SSL_CONN_CONFIG(CAfile)) {
if(1 != SSL_CTX_load_verify_locations(conssl->ctx,
- data->set.str[STRING_SSL_CAFILE],
- data->set.str[STRING_SSL_CAPATH])) {
- if(data->set.ssl.verifypeer) {
+ SSL_CONN_CONFIG(CAfile),
+ SSL_CONN_CONFIG(CApath))) {
+ if(SSL_CONN_CONFIG(verifypeer)) {
/* Fail if we insist on successfully verifying the server. */
failf(data, "error setting certificate verify locations:\n"
" CAfile: %s\n CApath: %s",
- data->set.str[STRING_SSL_CAFILE]?
- data->set.str[STRING_SSL_CAFILE]: "none",
- data->set.str[STRING_SSL_CAPATH]?
- data->set.str[STRING_SSL_CAPATH] : "none");
+ SSL_CONN_CONFIG(CAfile)?
+ SSL_CONN_CONFIG(CAfile): "none",
+ SSL_CONN_CONFIG(CApath)?
+ SSL_CONN_CONFIG(CApath) : "none");
return CURLE_SSL_CACERT_BADFILE;
}
else {
@@ -256,25 +259,25 @@ cyassl_connect_step1(struct connectdata *conn,
infof(data,
" CAfile: %s\n"
" CApath: %s\n",
- data->set.str[STRING_SSL_CAFILE] ? data->set.str[STRING_SSL_CAFILE]:
+ SSL_CONN_CONFIG(CAfile) ? SSL_CONN_CONFIG(CAfile):
"none",
- data->set.str[STRING_SSL_CAPATH] ? data->set.str[STRING_SSL_CAPATH]:
+ SSL_CONN_CONFIG(CApath) ? SSL_CONN_CONFIG(CApath):
"none");
}
/* Load the client certificate, and private key */
- if(data->set.str[STRING_CERT] && data->set.str[STRING_KEY]) {
- int file_type = do_file_type(data->set.str[STRING_CERT_TYPE]);
+ if(SSL_SET_OPTION(cert) && SSL_SET_OPTION(key)) {
+ int file_type = do_file_type(SSL_SET_OPTION(cert_type));
- if(SSL_CTX_use_certificate_file(conssl->ctx, data->set.str[STRING_CERT],
+ if(SSL_CTX_use_certificate_file(conssl->ctx, SSL_SET_OPTION(cert),
file_type) != 1) {
failf(data, "unable to use client certificate (no key or wrong pass"
" phrase?)");
return CURLE_SSL_CONNECT_ERROR;
}
- file_type = do_file_type(data->set.str[STRING_KEY_TYPE]);
- if(SSL_CTX_use_PrivateKey_file(conssl->ctx, data->set.str[STRING_KEY],
+ file_type = do_file_type(SSL_SET_OPTION(key_type));
+ if(SSL_CTX_use_PrivateKey_file(conssl->ctx, SSL_SET_OPTION(key),
file_type) != 1) {
failf(data, "unable to set private key");
return CURLE_SSL_CONNECT_ERROR;
@@ -287,7 +290,8 @@ cyassl_connect_step1(struct connectdata *conn,
* anyway. In the latter case the result of the verification is checked with
* SSL_get_verify_result() below. */
SSL_CTX_set_verify(conssl->ctx,
- data->set.ssl.verifypeer?SSL_VERIFY_PEER:SSL_VERIFY_NONE,
+ SSL_CONN_CONFIG(verifypeer)?SSL_VERIFY_PEER:
+ SSL_VERIFY_NONE,
NULL);
#ifdef HAVE_SNI
@@ -296,13 +300,15 @@ cyassl_connect_step1(struct connectdata *conn,
#ifdef ENABLE_IPV6
struct in6_addr addr6;
#endif
- size_t hostname_len = strlen(conn->host.name);
+ const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
+ conn->host.name;
+ size_t hostname_len = strlen(hostname);
if((hostname_len < USHRT_MAX) &&
- (0 == Curl_inet_pton(AF_INET, conn->host.name, &addr4)) &&
+ (0 == Curl_inet_pton(AF_INET, hostname, &addr4)) &&
#ifdef ENABLE_IPV6
- (0 == Curl_inet_pton(AF_INET6, conn->host.name, &addr6)) &&
+ (0 == Curl_inet_pton(AF_INET6, hostname, &addr6)) &&
#endif
- (CyaSSL_CTX_UseSNI(conssl->ctx, CYASSL_SNI_HOST_NAME, conn->host.name,
+ (CyaSSL_CTX_UseSNI(conssl->ctx, CYASSL_SNI_HOST_NAME, hostname,
(unsigned short)hostname_len) != 1)) {
infof(data, "WARNING: failed to configure server name indication (SNI) "
"TLS extension\n");
@@ -331,7 +337,7 @@ cyassl_connect_step1(struct connectdata *conn,
}
}
#ifdef NO_FILESYSTEM
- else if(data->set.ssl.verifypeer) {
+ else if(SSL_CONN_CONFIG(verifypeer)) {
failf(data, "SSL: Certificates couldn't be loaded because CyaSSL was built"
" with \"no filesystem\". Either disable peer verification"
" (insecure) or if you are building an application with libcurl you"
@@ -377,11 +383,11 @@ cyassl_connect_step1(struct connectdata *conn,
#endif /* HAVE_ALPN */
/* Check if there's a cached ID we can/should use here! */
- if(conn->ssl_config.sessionid) {
+ if(data->set.general_ssl.sessionid) {
void *ssl_sessionid = NULL;
Curl_ssl_sessionid_lock(conn);
- if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL)) {
+ if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL, sockindex)) {
/* we got a session id, use it! */
if(!SSL_set_session(conssl->handle, ssl_sessionid)) {
Curl_ssl_sessionid_unlock(conn);
@@ -391,7 +397,7 @@ cyassl_connect_step1(struct connectdata *conn,
return CURLE_SSL_CONNECT_ERROR;
}
/* Informational message */
- infof (data, "SSL re-using session ID\n");
+ infof(data, "SSL re-using session ID\n");
}
Curl_ssl_sessionid_unlock(conn);
}
@@ -414,13 +420,20 @@ cyassl_connect_step2(struct connectdata *conn,
int ret = -1;
struct Curl_easy *data = conn->data;
struct ssl_connect_data* conssl = &conn->ssl[sockindex];
+ const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
+ conn->host.name;
+ const char * const dispname = SSL_IS_PROXY() ?
+ conn->http_proxy.host.dispname : conn->host.dispname;
+ const char * const pinnedpubkey = SSL_IS_PROXY() ?
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
conn->recv[sockindex] = cyassl_recv;
conn->send[sockindex] = cyassl_send;
/* Enable RFC2818 checks */
- if(data->set.ssl.verifyhost) {
- ret = CyaSSL_check_domain_name(conssl->handle, conn->host.name);
+ if(SSL_CONN_CONFIG(verifyhost)) {
+ ret = CyaSSL_check_domain_name(conssl->handle, hostname);
if(ret == SSL_FAILURE)
return CURLE_OUT_OF_MEMORY;
}
@@ -444,31 +457,31 @@ cyassl_connect_step2(struct connectdata *conn,
else if(DOMAIN_NAME_MISMATCH == detail) {
#if 1
failf(data, "\tsubject alt name(s) or common name do not match \"%s\"\n",
- conn->host.dispname);
+ dispname);
return CURLE_PEER_FAILED_VERIFICATION;
#else
/* When the CyaSSL_check_domain_name() is used and you desire to continue
- * on a DOMAIN_NAME_MISMATCH, i.e. 'data->set.ssl.verifyhost == 0',
+ * on a DOMAIN_NAME_MISMATCH, i.e. 'conn->ssl_config.verifyhost == 0',
* CyaSSL version 2.4.0 will fail with an INCOMPLETE_DATA error. The only
* way to do this is currently to switch the CyaSSL_check_domain_name()
- * in and out based on the 'data->set.ssl.verifyhost' value. */
- if(data->set.ssl.verifyhost) {
+ * in and out based on the 'conn->ssl_config.verifyhost' value. */
+ if(SSL_CONN_CONFIG(verifyhost)) {
failf(data,
"\tsubject alt name(s) or common name do not match \"%s\"\n",
- conn->host.dispname);
+ dispname);
return CURLE_PEER_FAILED_VERIFICATION;
}
else {
infof(data,
"\tsubject alt name(s) and/or common name do not match \"%s\"\n",
- conn->host.dispname);
+ dispname);
return CURLE_OK;
}
#endif
}
#if LIBCYASSL_VERSION_HEX >= 0x02007000 /* 2.7.0 */
else if(ASN_NO_SIGNER_E == detail) {
- if(data->set.ssl.verifypeer) {
+ if(SSL_CONN_CONFIG(verifypeer)) {
failf(data, "\tCA signer not available for verification\n");
return CURLE_SSL_CACERT_BADFILE;
}
@@ -487,7 +500,7 @@ cyassl_connect_step2(struct connectdata *conn,
}
}
- if(data->set.str[STRING_SSL_PINNEDPUBLICKEY]) {
+ if(pinnedpubkey) {
#ifdef KEEP_PEER_CERT
X509 *x509;
const char *x509_der;
@@ -509,7 +522,8 @@ cyassl_connect_step2(struct connectdata *conn,
}
memset(&x509_parsed, 0, sizeof x509_parsed);
- Curl_parseX509(&x509_parsed, x509_der, x509_der + x509_der_len);
+ if(Curl_parseX509(&x509_parsed, x509_der, x509_der + x509_der_len))
+ return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
pubkey = &x509_parsed.subjectPublicKeyInfo;
if(!pubkey->header || pubkey->end <= pubkey->header) {
@@ -518,7 +532,7 @@ cyassl_connect_step2(struct connectdata *conn,
}
result = Curl_pin_peer_pubkey(data,
- data->set.str[STRING_SSL_PINNEDPUBLICKEY],
+ pinnedpubkey,
(const unsigned char *)pubkey->header,
(size_t)(pubkey->end - pubkey->header));
if(result) {
@@ -583,7 +597,7 @@ cyassl_connect_step3(struct connectdata *conn,
DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
- if(conn->ssl_config.sessionid) {
+ if(data->set.general_ssl.sessionid) {
bool incache;
SSL_SESSION *our_ssl_sessionid;
void *old_ssl_sessionid = NULL;
@@ -591,7 +605,8 @@ cyassl_connect_step3(struct connectdata *conn,
our_ssl_sessionid = SSL_get_session(connssl->handle);
Curl_ssl_sessionid_lock(conn);
- incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL));
+ incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL,
+ sockindex));
if(incache) {
if(old_ssl_sessionid != our_ssl_sessionid) {
infof(data, "old SSL session ID is stale, removing\n");
@@ -602,7 +617,7 @@ cyassl_connect_step3(struct connectdata *conn,
if(!incache) {
result = Curl_ssl_addsessionid(conn, our_ssl_sessionid,
- 0 /* unknown size */);
+ 0 /* unknown size */, sockindex);
if(result) {
Curl_ssl_sessionid_unlock(conn);
failf(data, "failed to store ssl session");
@@ -654,11 +669,11 @@ void Curl_cyassl_close(struct connectdata *conn, int sockindex)
if(conssl->handle) {
(void)SSL_shutdown(conssl->handle);
- SSL_free (conssl->handle);
+ SSL_free(conssl->handle);
conssl->handle = NULL;
}
if(conssl->ctx) {
- SSL_CTX_free (conssl->ctx);
+ SSL_CTX_free(conssl->ctx);
conssl->ctx = NULL;
}
}
@@ -740,7 +755,7 @@ int Curl_cyassl_shutdown(struct connectdata *conn, int sockindex)
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
if(connssl->handle) {
- SSL_free (connssl->handle);
+ SSL_free(connssl->handle);
connssl->handle = NULL;
}
return retval;
diff --git a/Utilities/cmcurl/lib/vtls/darwinssl.c b/Utilities/cmcurl/lib/vtls/darwinssl.c
index 66e74f1ba5..a43e391258 100644
--- a/Utilities/cmcurl/lib/vtls/darwinssl.c
+++ b/Utilities/cmcurl/lib/vtls/darwinssl.c
@@ -197,7 +197,7 @@ static OSStatus SocketWrite(SSLConnectionRef connection,
do {
length = write(sock,
- (char*)dataPtr + bytesSent,
+ (char *)dataPtr + bytesSent,
dataLen - bytesSent);
} while((length > 0) &&
( (bytesSent += length) < dataLen) );
@@ -219,8 +219,9 @@ static OSStatus SocketWrite(SSLConnectionRef connection,
return ortn;
}
-CF_INLINE const char *SSLCipherNameForNumber(SSLCipherSuite cipher) {
- switch (cipher) {
+CF_INLINE const char *SSLCipherNameForNumber(SSLCipherSuite cipher)
+{
+ switch(cipher) {
/* SSL version 3.0 */
case SSL_RSA_WITH_NULL_MD5:
return "SSL_RSA_WITH_NULL_MD5";
@@ -364,7 +365,8 @@ CF_INLINE const char *SSLCipherNameForNumber(SSLCipherSuite cipher) {
return "SSL_NULL_WITH_NULL_NULL";
}
-CF_INLINE const char *TLSCipherNameForNumber(SSLCipherSuite cipher) {
+CF_INLINE const char *TLSCipherNameForNumber(SSLCipherSuite cipher)
+{
switch(cipher) {
/* TLS 1.0 with AES (RFC 3268) */
case TLS_RSA_WITH_AES_128_CBC_SHA:
@@ -883,14 +885,18 @@ static OSStatus CopyIdentityWithLabel(char *label,
SecIdentityRef *out_cert_and_key)
{
OSStatus status = errSecItemNotFound;
+ CFArrayRef keys_list;
+ CFIndex keys_list_count;
+ CFIndex i;
+ CFStringRef common_name;
#if CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS
/* SecItemCopyMatching() was introduced in iOS and Snow Leopard.
kSecClassIdentity was introduced in Lion. If both exist, let's use them
to find the certificate. */
if(SecItemCopyMatching != NULL && kSecClassIdentity != NULL) {
- CFTypeRef keys[4];
- CFTypeRef values[4];
+ CFTypeRef keys[5];
+ CFTypeRef values[5];
CFDictionaryRef query_dict;
CFStringRef label_cf = CFStringCreateWithCString(NULL, label,
kCFStringEncodingUTF8);
@@ -900,21 +906,53 @@ static OSStatus CopyIdentityWithLabel(char *label,
keys[0] = kSecClass;
values[1] = kCFBooleanTrue; /* we want a reference */
keys[1] = kSecReturnRef;
- values[2] = kSecMatchLimitOne; /* one is enough, thanks */
+ values[2] = kSecMatchLimitAll; /* kSecMatchLimitOne would be better if the
+ * label matching below worked correctly */
keys[2] = kSecMatchLimit;
/* identity searches need a SecPolicyRef in order to work */
- values[3] = SecPolicyCreateSSL(false, label_cf);
+ values[3] = SecPolicyCreateSSL(false, NULL);
keys[3] = kSecMatchPolicy;
+ /* match the name of the certificate (doesn't work in macOS 10.12.1) */
+ values[4] = label_cf;
+ keys[4] = kSecAttrLabel;
query_dict = CFDictionaryCreate(NULL, (const void **)keys,
- (const void **)values, 4L,
- &kCFCopyStringDictionaryKeyCallBacks,
- &kCFTypeDictionaryValueCallBacks);
+ (const void **)values, 5L,
+ &kCFCopyStringDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
CFRelease(values[3]);
- CFRelease(label_cf);
/* Do we have a match? */
- status = SecItemCopyMatching(query_dict, (CFTypeRef *)out_cert_and_key);
+ status = SecItemCopyMatching(query_dict, (CFTypeRef *) &keys_list);
+
+ /* Because kSecAttrLabel matching doesn't work with kSecClassIdentity,
+ * we need to find the correct identity ourselves */
+ if(status == noErr) {
+ keys_list_count = CFArrayGetCount(keys_list);
+ *out_cert_and_key = NULL;
+ for(i=0; i<keys_list_count; i++) {
+ OSStatus err = noErr;
+ SecCertificateRef cert = NULL;
+ *out_cert_and_key =
+ (SecIdentityRef) CFArrayGetValueAtIndex(keys_list, i);
+ err = SecIdentityCopyCertificate(*out_cert_and_key, &cert);
+ if(err == noErr) {
+ SecCertificateCopyCommonName(cert, &common_name);
+ if(CFStringCompare(common_name, label_cf, 0) == kCFCompareEqualTo) {
+ CFRelease(cert);
+ CFRelease(common_name);
+ status = noErr;
+ break;
+ }
+ CFRelease(common_name);
+ }
+ *out_cert_and_key = NULL;
+ status = 1;
+ CFRelease(cert);
+ }
+ }
+
CFRelease(query_dict);
+ CFRelease(label_cf);
}
else {
#if CURL_SUPPORT_MAC_10_6
@@ -1002,6 +1040,12 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
struct Curl_easy *data = conn->data;
curl_socket_t sockfd = conn->sock[sockindex];
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile);
+ const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
+ char * const ssl_cert = SSL_SET_OPTION(cert);
+ const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
+ conn->host.name;
+ const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port;
#ifdef ENABLE_IPV6
struct in6_addr addr;
#else
@@ -1052,40 +1096,46 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
/* check to see if we've been told to use an explicit SSL/TLS version */
#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
if(SSLSetProtocolVersionMax != NULL) {
- switch(data->set.ssl.version) {
- default:
- case CURL_SSLVERSION_DEFAULT:
- case CURL_SSLVERSION_TLSv1:
- (void)SSLSetProtocolVersionMin(connssl->ssl_ctx, kTLSProtocol1);
- (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kTLSProtocol12);
- break;
- case CURL_SSLVERSION_TLSv1_0:
- (void)SSLSetProtocolVersionMin(connssl->ssl_ctx, kTLSProtocol1);
- (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kTLSProtocol1);
- break;
- case CURL_SSLVERSION_TLSv1_1:
- (void)SSLSetProtocolVersionMin(connssl->ssl_ctx, kTLSProtocol11);
- (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kTLSProtocol11);
- break;
- case CURL_SSLVERSION_TLSv1_2:
- (void)SSLSetProtocolVersionMin(connssl->ssl_ctx, kTLSProtocol12);
- (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kTLSProtocol12);
- break;
- case CURL_SSLVERSION_SSLv3:
- err = SSLSetProtocolVersionMin(connssl->ssl_ctx, kSSLProtocol3);
- if(err != noErr) {
- failf(data, "Your version of the OS does not support SSLv3");
- return CURLE_SSL_CONNECT_ERROR;
- }
- (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kSSLProtocol3);
- break;
- case CURL_SSLVERSION_SSLv2:
- err = SSLSetProtocolVersionMin(connssl->ssl_ctx, kSSLProtocol2);
- if(err != noErr) {
- failf(data, "Your version of the OS does not support SSLv2");
- return CURLE_SSL_CONNECT_ERROR;
- }
- (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kSSLProtocol2);
+ switch(conn->ssl_config.version) {
+ case CURL_SSLVERSION_DEFAULT:
+ case CURL_SSLVERSION_TLSv1:
+ (void)SSLSetProtocolVersionMin(connssl->ssl_ctx, kTLSProtocol1);
+ (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kTLSProtocol12);
+ break;
+ case CURL_SSLVERSION_TLSv1_0:
+ (void)SSLSetProtocolVersionMin(connssl->ssl_ctx, kTLSProtocol1);
+ (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kTLSProtocol1);
+ break;
+ case CURL_SSLVERSION_TLSv1_1:
+ (void)SSLSetProtocolVersionMin(connssl->ssl_ctx, kTLSProtocol11);
+ (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kTLSProtocol11);
+ break;
+ case CURL_SSLVERSION_TLSv1_2:
+ (void)SSLSetProtocolVersionMin(connssl->ssl_ctx, kTLSProtocol12);
+ (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kTLSProtocol12);
+ break;
+ case CURL_SSLVERSION_TLSv1_3:
+ failf(data, "DarwinSSL: TLS 1.3 is not yet supported");
+ return CURLE_SSL_CONNECT_ERROR;
+ case CURL_SSLVERSION_SSLv3:
+ err = SSLSetProtocolVersionMin(connssl->ssl_ctx, kSSLProtocol3);
+ if(err != noErr) {
+ failf(data, "Your version of the OS does not support SSLv3");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kSSLProtocol3);
+ break;
+ case CURL_SSLVERSION_SSLv2:
+ err = SSLSetProtocolVersionMin(connssl->ssl_ctx, kSSLProtocol2);
+ if(err != noErr) {
+ failf(data, "Your version of the OS does not support SSLv2");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kSSLProtocol2);
+ break;
+ default:
+ failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
+ return CURLE_SSL_CONNECT_ERROR;
}
}
else {
@@ -1093,121 +1143,131 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
(void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
kSSLProtocolAll,
false);
- switch (data->set.ssl.version) {
- default:
- case CURL_SSLVERSION_DEFAULT:
- case CURL_SSLVERSION_TLSv1:
- (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
- kTLSProtocol1,
- true);
- (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
- kTLSProtocol11,
- true);
- (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
- kTLSProtocol12,
- true);
- break;
- case CURL_SSLVERSION_TLSv1_0:
- (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
- kTLSProtocol1,
- true);
- break;
- case CURL_SSLVERSION_TLSv1_1:
- (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
- kTLSProtocol11,
- true);
- break;
- case CURL_SSLVERSION_TLSv1_2:
- (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
- kTLSProtocol12,
- true);
- break;
- case CURL_SSLVERSION_SSLv3:
- err = SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
- kSSLProtocol3,
- true);
- if(err != noErr) {
- failf(data, "Your version of the OS does not support SSLv3");
- return CURLE_SSL_CONNECT_ERROR;
- }
- break;
- case CURL_SSLVERSION_SSLv2:
- err = SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
- kSSLProtocol2,
- true);
- if(err != noErr) {
- failf(data, "Your version of the OS does not support SSLv2");
- return CURLE_SSL_CONNECT_ERROR;
- }
- break;
- }
-#endif /* CURL_SUPPORT_MAC_10_8 */
- }
-#else
- (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, kSSLProtocolAll, false);
- switch(data->set.ssl.version) {
- default:
+ switch(conn->ssl_config.version) {
case CURL_SSLVERSION_DEFAULT:
case CURL_SSLVERSION_TLSv1:
+ (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
+ kTLSProtocol1,
+ true);
+ (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
+ kTLSProtocol11,
+ true);
+ (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
+ kTLSProtocol12,
+ true);
+ break;
case CURL_SSLVERSION_TLSv1_0:
(void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
kTLSProtocol1,
true);
break;
case CURL_SSLVERSION_TLSv1_1:
- failf(data, "Your version of the OS does not support TLSv1.1");
- return CURLE_SSL_CONNECT_ERROR;
+ (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
+ kTLSProtocol11,
+ true);
+ break;
case CURL_SSLVERSION_TLSv1_2:
- failf(data, "Your version of the OS does not support TLSv1.2");
+ (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
+ kTLSProtocol12,
+ true);
+ break;
+ case CURL_SSLVERSION_TLSv1_3:
+ failf(data, "DarwinSSL: TLS 1.3 is not yet supported");
return CURLE_SSL_CONNECT_ERROR;
- case CURL_SSLVERSION_SSLv2:
+ case CURL_SSLVERSION_SSLv3:
err = SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
- kSSLProtocol2,
+ kSSLProtocol3,
true);
if(err != noErr) {
- failf(data, "Your version of the OS does not support SSLv2");
+ failf(data, "Your version of the OS does not support SSLv3");
return CURLE_SSL_CONNECT_ERROR;
}
break;
- case CURL_SSLVERSION_SSLv3:
+ case CURL_SSLVERSION_SSLv2:
err = SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
- kSSLProtocol3,
+ kSSLProtocol2,
true);
if(err != noErr) {
- failf(data, "Your version of the OS does not support SSLv3");
+ failf(data, "Your version of the OS does not support SSLv2");
return CURLE_SSL_CONNECT_ERROR;
}
break;
+ default:
+ failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+#endif /* CURL_SUPPORT_MAC_10_8 */
+ }
+#else
+ (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, kSSLProtocolAll, false);
+ switch(conn->ssl_config.version) {
+ case CURL_SSLVERSION_DEFAULT:
+ case CURL_SSLVERSION_TLSv1:
+ case CURL_SSLVERSION_TLSv1_0:
+ (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
+ kTLSProtocol1,
+ true);
+ break;
+ case CURL_SSLVERSION_TLSv1_1:
+ failf(data, "Your version of the OS does not support TLSv1.1");
+ return CURLE_SSL_CONNECT_ERROR;
+ case CURL_SSLVERSION_TLSv1_2:
+ failf(data, "Your version of the OS does not support TLSv1.2");
+ return CURLE_SSL_CONNECT_ERROR;
+ case CURL_SSLVERSION_TLSv1_3:
+ failf(data, "Your version of the OS does not support TLSv1.3");
+ return CURLE_SSL_CONNECT_ERROR;
+ case CURL_SSLVERSION_SSLv2:
+ err = SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
+ kSSLProtocol2,
+ true);
+ if(err != noErr) {
+ failf(data, "Your version of the OS does not support SSLv2");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ break;
+ case CURL_SSLVERSION_SSLv3:
+ err = SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
+ kSSLProtocol3,
+ true);
+ if(err != noErr) {
+ failf(data, "Your version of the OS does not support SSLv3");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ break;
+ default:
+ failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
+ return CURLE_SSL_CONNECT_ERROR;
}
#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
- if(data->set.str[STRING_KEY]) {
+ if(SSL_SET_OPTION(key)) {
infof(data, "WARNING: SSL: CURLOPT_SSLKEY is ignored by Secure "
- "Transport. The private key must be in the Keychain.\n");
+ "Transport. The private key must be in the Keychain.\n");
}
- if(data->set.str[STRING_CERT]) {
+ if(ssl_cert) {
SecIdentityRef cert_and_key = NULL;
- bool is_cert_file = is_file(data->set.str[STRING_CERT]);
+ bool is_cert_file = is_file(ssl_cert);
/* User wants to authenticate with a client cert. Look for it:
If we detect that this is a file on disk, then let's load it.
Otherwise, assume that the user wants to use an identity loaded
from the Keychain. */
if(is_cert_file) {
- if(!data->set.str[STRING_CERT_TYPE])
+ if(!SSL_SET_OPTION(cert_type))
infof(data, "WARNING: SSL: Certificate type not set, assuming "
"PKCS#12 format.\n");
- else if(strncmp(data->set.str[STRING_CERT_TYPE], "P12",
- strlen(data->set.str[STRING_CERT_TYPE])) != 0)
+ else if(strncmp(SSL_SET_OPTION(cert_type), "P12",
+ strlen(SSL_SET_OPTION(cert_type))) != 0)
infof(data, "WARNING: SSL: The Security framework only supports "
"loading identities that are in PKCS#12 format.\n");
- err = CopyIdentityFromPKCS12File(data->set.str[STRING_CERT],
- data->set.str[STRING_KEY_PASSWD], &cert_and_key);
+ err = CopyIdentityFromPKCS12File(ssl_cert,
+ SSL_SET_OPTION(key_passwd), &cert_and_key);
}
else
- err = CopyIdentityWithLabel(data->set.str[STRING_CERT], &cert_and_key);
+ err = CopyIdentityWithLabel(ssl_cert, &cert_and_key);
if(err == noErr) {
SecCertificateRef cert = NULL;
@@ -1246,27 +1306,27 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
}
else {
switch(err) {
- case errSecAuthFailed: case -25264: /* errSecPkcs12VerifyFailure */
- failf(data, "SSL: Incorrect password for the certificate \"%s\" "
- "and its private key.", data->set.str[STRING_CERT]);
- break;
- case -26275: /* errSecDecode */ case -25257: /* errSecUnknownFormat */
- failf(data, "SSL: Couldn't make sense of the data in the "
- "certificate \"%s\" and its private key.",
- data->set.str[STRING_CERT]);
- break;
- case -25260: /* errSecPassphraseRequired */
- failf(data, "SSL The certificate \"%s\" requires a password.",
- data->set.str[STRING_CERT]);
- break;
- case errSecItemNotFound:
- failf(data, "SSL: Can't find the certificate \"%s\" and its private "
- "key in the Keychain.", data->set.str[STRING_CERT]);
- break;
- default:
- failf(data, "SSL: Can't load the certificate \"%s\" and its private "
- "key: OSStatus %d", data->set.str[STRING_CERT], err);
- break;
+ case errSecAuthFailed: case -25264: /* errSecPkcs12VerifyFailure */
+ failf(data, "SSL: Incorrect password for the certificate \"%s\" "
+ "and its private key.", ssl_cert);
+ break;
+ case -26275: /* errSecDecode */ case -25257: /* errSecUnknownFormat */
+ failf(data, "SSL: Couldn't make sense of the data in the "
+ "certificate \"%s\" and its private key.",
+ ssl_cert);
+ break;
+ case -25260: /* errSecPassphraseRequired */
+ failf(data, "SSL The certificate \"%s\" requires a password.",
+ ssl_cert);
+ break;
+ case errSecItemNotFound:
+ failf(data, "SSL: Can't find the certificate \"%s\" and its private "
+ "key in the Keychain.", ssl_cert);
+ break;
+ default:
+ failf(data, "SSL: Can't load the certificate \"%s\" and its private "
+ "key: OSStatus %d", ssl_cert, err);
+ break;
}
return CURLE_SSL_CERTPROBLEM;
}
@@ -1297,8 +1357,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
#else
if(SSLSetSessionOption != NULL) {
#endif /* CURL_BUILD_MAC */
- bool break_on_auth = !data->set.ssl.verifypeer ||
- data->set.str[STRING_SSL_CAFILE];
+ bool break_on_auth = !conn->ssl_config.verifypeer || ssl_cafile;
err = SSLSetSessionOption(connssl->ssl_ctx,
kSSLSessionOptionBreakOnServerAuth,
break_on_auth);
@@ -1310,7 +1369,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
else {
#if CURL_SUPPORT_MAC_10_8
err = SSLSetEnableCertVerify(connssl->ssl_ctx,
- data->set.ssl.verifypeer?true:false);
+ conn->ssl_config.verifypeer?true:false);
if(err != noErr) {
failf(data, "SSL: SSLSetEnableCertVerify() failed: OSStatus %d", err);
return CURLE_SSL_CONNECT_ERROR;
@@ -1319,22 +1378,21 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
}
#else
err = SSLSetEnableCertVerify(connssl->ssl_ctx,
- data->set.ssl.verifypeer?true:false);
+ conn->ssl_config.verifypeer?true:false);
if(err != noErr) {
failf(data, "SSL: SSLSetEnableCertVerify() failed: OSStatus %d", err);
return CURLE_SSL_CONNECT_ERROR;
}
#endif /* CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS */
- if(data->set.str[STRING_SSL_CAFILE]) {
- bool is_cert_file = is_file(data->set.str[STRING_SSL_CAFILE]);
+ if(ssl_cafile) {
+ bool is_cert_file = is_file(ssl_cafile);
if(!is_cert_file) {
- failf(data, "SSL: can't load CA certificate file %s",
- data->set.str[STRING_SSL_CAFILE]);
+ failf(data, "SSL: can't load CA certificate file %s", ssl_cafile);
return CURLE_SSL_CACERT_BADFILE;
}
- if(!data->set.ssl.verifypeer) {
+ if(!verifypeer) {
failf(data, "SSL: CA certificate set, but certificate verification "
"is disabled");
return CURLE_SSL_CONNECT_ERROR;
@@ -1344,22 +1402,22 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
/* Configure hostname check. SNI is used if available.
* Both hostname check and SNI require SSLSetPeerDomainName().
* Also: the verifyhost setting influences SNI usage */
- if(data->set.ssl.verifyhost) {
- err = SSLSetPeerDomainName(connssl->ssl_ctx, conn->host.name,
- strlen(conn->host.name));
+ if(conn->ssl_config.verifyhost) {
+ err = SSLSetPeerDomainName(connssl->ssl_ctx, hostname,
+ strlen(hostname));
if(err != noErr) {
infof(data, "WARNING: SSL: SSLSetPeerDomainName() failed: OSStatus %d\n",
err);
}
- if((Curl_inet_pton(AF_INET, conn->host.name, &addr))
+ if((Curl_inet_pton(AF_INET, hostname, &addr))
#ifdef ENABLE_IPV6
- || (Curl_inet_pton(AF_INET6, conn->host.name, &addr))
+ || (Curl_inet_pton(AF_INET6, hostname, &addr))
#endif
) {
- infof(data, "WARNING: using IP address, SNI is being disabled by "
- "the OS.\n");
+ infof(data, "WARNING: using IP address, SNI is being disabled by "
+ "the OS.\n");
}
}
@@ -1382,7 +1440,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
running in an affected version of OS X. */
if(darwinver_maj == 12 && darwinver_min <= 3 &&
all_ciphers[i] >= 0xC001 && all_ciphers[i] <= 0xC032) {
- continue;
+ continue;
}
#endif /* CURL_BUILD_MAC */
switch(all_ciphers[i]) {
@@ -1474,21 +1532,22 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
/* We want to enable 1/n-1 when using a CBC cipher unless the user
specifically doesn't want us doing that: */
if(SSLSetSessionOption != NULL) {
+ /* TODO s/data->set.ssl.enable_beast/SSL_SET_OPTION(enable_beast)/g */
SSLSetSessionOption(connssl->ssl_ctx, kSSLSessionOptionSendOneByteRecord,
- !data->set.ssl_enable_beast);
+ !data->set.ssl.enable_beast);
SSLSetSessionOption(connssl->ssl_ctx, kSSLSessionOptionFalseStart,
data->set.ssl.falsestart); /* false start support */
}
#endif /* CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 */
/* Check if there's a cached ID we can/should use here! */
- if(conn->ssl_config.sessionid) {
+ if(data->set.general_ssl.sessionid) {
char *ssl_sessionid;
size_t ssl_sessionid_len;
Curl_ssl_sessionid_lock(conn);
if(!Curl_ssl_getsessionid(conn, (void **)&ssl_sessionid,
- &ssl_sessionid_len)) {
+ &ssl_sessionid_len, sockindex)) {
/* we got a session id, use it! */
err = SSLSetPeerID(connssl->ssl_ctx, ssl_sessionid, ssl_sessionid_len);
Curl_ssl_sessionid_unlock(conn);
@@ -1504,9 +1563,8 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
else {
CURLcode result;
ssl_sessionid =
- aprintf("%s:%d:%d:%s:%hu", data->set.str[STRING_SSL_CAFILE],
- data->set.ssl.verifypeer, data->set.ssl.verifyhost,
- conn->host.name, conn->remote_port);
+ aprintf("%s:%d:%d:%s:%hu", ssl_cafile,
+ verifypeer, SSL_CONN_CONFIG(verifyhost), hostname, port);
ssl_sessionid_len = strlen(ssl_sessionid);
err = SSLSetPeerID(connssl->ssl_ctx, ssl_sessionid, ssl_sessionid_len);
@@ -1516,7 +1574,8 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
return CURLE_SSL_CONNECT_ERROR;
}
- result = Curl_ssl_addsessionid(conn, ssl_sessionid, ssl_sessionid_len);
+ result = Curl_ssl_addsessionid(conn, ssl_sessionid, ssl_sessionid_len,
+ sockindex);
Curl_ssl_sessionid_unlock(conn);
if(result) {
failf(data, "failed to store ssl session");
@@ -1820,7 +1879,7 @@ static int verify_cert(const char *cafile, struct Curl_easy *data,
return sslerr_to_curlerr(data, ret);
}
- switch (trust_eval) {
+ switch(trust_eval) {
case kSecTrustResultUnspecified:
case kSecTrustResultProceed:
return CURLE_OK;
@@ -1842,6 +1901,8 @@ darwinssl_connect_step2(struct connectdata *conn, int sockindex)
OSStatus err;
SSLCipherSuite cipher;
SSLProtocol protocol = 0;
+ const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
+ conn->host.name;
DEBUGASSERT(ssl_connect_2 == connssl->connecting_state
|| ssl_connect_2_reading == connssl->connecting_state
@@ -1851,7 +1912,7 @@ darwinssl_connect_step2(struct connectdata *conn, int sockindex)
err = SSLHandshake(connssl->ssl_ctx);
if(err != noErr) {
- switch (err) {
+ switch(err) {
case errSSLWouldBlock: /* they're not done with us yet */
connssl->connecting_state = connssl->ssl_direction ?
ssl_connect_2_writing : ssl_connect_2_reading;
@@ -1860,8 +1921,8 @@ darwinssl_connect_step2(struct connectdata *conn, int sockindex)
/* The below is errSSLServerAuthCompleted; it's not defined in
Leopard's headers */
case -9841:
- if(data->set.str[STRING_SSL_CAFILE]) {
- int res = verify_cert(data->set.str[STRING_SSL_CAFILE], data,
+ if(SSL_CONN_CONFIG(CAfile)) {
+ int res = verify_cert(SSL_CONN_CONFIG(CAfile), data,
connssl->ssl_ctx);
if(res != CURLE_OK)
return res;
@@ -1930,7 +1991,7 @@ darwinssl_connect_step2(struct connectdata *conn, int sockindex)
return CURLE_SSL_CONNECT_ERROR;
default:
failf(data, "Unknown SSL protocol error in connection to %s:%d",
- conn->host.name, err);
+ hostname, err);
return CURLE_SSL_CONNECT_ERROR;
}
}
@@ -1941,7 +2002,7 @@ darwinssl_connect_step2(struct connectdata *conn, int sockindex)
/* Informational message */
(void)SSLGetNegotiatedCipher(connssl->ssl_ctx, &cipher);
(void)SSLGetNegotiatedProtocolVersion(connssl->ssl_ctx, &protocol);
- switch (protocol) {
+ switch(protocol) {
case kSSLProtocol2:
infof(data, "SSL 2.0 connection using %s\n",
SSLCipherNameForNumber(cipher));
@@ -2390,7 +2451,8 @@ void Curl_darwinssl_md5sum(unsigned char *tmp, /* input */
(void)CC_MD5(tmp, (CC_LONG)tmplen, md5sum);
}
-bool Curl_darwinssl_false_start(void) {
+bool Curl_darwinssl_false_start(void)
+{
#if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7
if(SSLSetSessionOption != NULL)
return TRUE;
@@ -2427,7 +2489,7 @@ static ssize_t darwinssl_send(struct connectdata *conn,
if(connssl->ssl_write_buffered_length) {
/* Write the buffered data: */
err = SSLWrite(connssl->ssl_ctx, NULL, 0UL, &processed);
- switch (err) {
+ switch(err) {
case noErr:
/* processed is always going to be 0 because we didn't write to
the buffer, so return how much was written to the socket */
@@ -2447,7 +2509,7 @@ static ssize_t darwinssl_send(struct connectdata *conn,
/* We've got new data to write: */
err = SSLWrite(connssl->ssl_ctx, mem, len, &processed);
if(err != noErr) {
- switch (err) {
+ switch(err) {
case errSSLWouldBlock:
/* Data was buffered but not sent, we have to tell the caller
to try sending again, and remember how much was buffered */
@@ -2476,7 +2538,7 @@ static ssize_t darwinssl_recv(struct connectdata *conn,
OSStatus err = SSLRead(connssl->ssl_ctx, buf, buffersize, &processed);
if(err != noErr) {
- switch (err) {
+ switch(err) {
case errSSLWouldBlock: /* return how much we read (if anything) */
if(processed)
return (ssize_t)processed;
diff --git a/Utilities/cmcurl/lib/vtls/gskit.c b/Utilities/cmcurl/lib/vtls/gskit.c
index 3b0cfd5a0a..a0d462b70a 100644
--- a/Utilities/cmcurl/lib/vtls/gskit.c
+++ b/Utilities/cmcurl/lib/vtls/gskit.c
@@ -81,6 +81,10 @@
#include "memdebug.h"
+/* Directions. */
+#define SOS_READ 0x01
+#define SOS_WRITE 0x02
+
/* SSL version flags. */
#define CURL_GSKPROTO_SSLV2 0
#define CURL_GSKPROTO_SSLV2_MASK (1 << CURL_GSKPROTO_SSLV2)
@@ -151,7 +155,7 @@ static const gskit_cipher ciphertable[] = {
static bool is_separator(char c)
{
/* Return whether character is a cipher list separator. */
- switch (c) {
+ switch(c) {
case ' ':
case '\t':
case ':':
@@ -167,7 +171,7 @@ static CURLcode gskit_status(struct Curl_easy *data, int rc,
const char *procname, CURLcode defcode)
{
/* Process GSKit status and map it to a CURLcode. */
- switch (rc) {
+ switch(rc) {
case GSK_OK:
case GSK_OS400_ASYNCHRONOUS_SOC_INIT:
return CURLE_OK;
@@ -190,7 +194,7 @@ static CURLcode gskit_status(struct Curl_easy *data, int rc,
case GSK_OS400_ERROR_NOT_REGISTERED:
break;
case GSK_ERROR_IO:
- switch (errno) {
+ switch(errno) {
case ENOMEM:
return CURLE_OUT_OF_MEMORY;
default:
@@ -211,7 +215,7 @@ static CURLcode set_enum(struct Curl_easy *data, gsk_handle h,
{
int rc = gsk_attribute_set_enum(h, id, value);
- switch (rc) {
+ switch(rc) {
case GSK_OK:
return CURLE_OK;
case GSK_ERROR_IO:
@@ -233,7 +237,7 @@ static CURLcode set_buffer(struct Curl_easy *data, gsk_handle h,
{
int rc = gsk_attribute_set_buffer(h, id, buffer, 0);
- switch (rc) {
+ switch(rc) {
case GSK_OK:
return CURLE_OK;
case GSK_ERROR_IO:
@@ -255,7 +259,7 @@ static CURLcode set_numeric(struct Curl_easy *data,
{
int rc = gsk_attribute_set_numeric_value(h, id, value);
- switch (rc) {
+ switch(rc) {
case GSK_OK:
return CURLE_OK;
case GSK_ERROR_IO:
@@ -275,7 +279,7 @@ static CURLcode set_callback(struct Curl_easy *data,
{
int rc = gsk_attribute_set_callback(h, id, info);
- switch (rc) {
+ switch(rc) {
case GSK_OK:
return CURLE_OK;
case GSK_ERROR_IO:
@@ -289,10 +293,11 @@ static CURLcode set_callback(struct Curl_easy *data,
}
-static CURLcode set_ciphers(struct Curl_easy *data,
+static CURLcode set_ciphers(struct connectdata *conn,
gsk_handle h, unsigned int *protoflags)
{
- const char *cipherlist = data->set.str[STRING_SSL_CIPHER_LIST];
+ struct Curl_easy *data = conn->data;
+ const char *cipherlist = SSL_CONN_CONFIG(cipher_list);
const char *clp;
const gskit_cipher *ctp;
int i;
@@ -340,7 +345,7 @@ static CURLcode set_ciphers(struct Curl_easy *data,
break;
/* Search the cipher in our table. */
for(ctp = ciphertable; ctp->name; ctp++)
- if(strnequal(ctp->name, clp, l) && !ctp->name[l])
+ if(strncasecompare(ctp->name, clp, l) && !ctp->name[l])
break;
if(!ctp->name) {
failf(data, "Unknown cipher %.*s", l, clp);
@@ -448,7 +453,7 @@ static CURLcode init_environment(struct Curl_easy *data,
/* Creates the GSKit environment. */
rc = gsk_environment_open(&h);
- switch (rc) {
+ switch(rc) {
case GSK_OK:
break;
case GSK_INSUFFICIENT_STORAGE:
@@ -500,17 +505,195 @@ static void close_async_handshake(struct ssl_connect_data *connssl)
connssl->iocport = -1;
}
+/* SSL over SSL
+ * Problems:
+ * 1) GSKit can only perform SSL on an AF_INET or AF_INET6 stream socket. To
+ * pipe an SSL stream into another, it is therefore needed to have a pair
+ * of such communicating sockets and handle the pipelining explicitly.
+ * 2) OS/400 socketpair() is only implemented for domain AF_UNIX, thus cannot
+ * be used to produce the pipeline.
+ * The solution is to simulate socketpair() for AF_INET with low-level API
+ * listen(), bind() and connect().
+ */
+
+static int
+inetsocketpair(int sv[2])
+{
+ int lfd; /* Listening socket. */
+ int sfd; /* Server socket. */
+ int cfd; /* Client socket. */
+ int len;
+ struct sockaddr_in addr1;
+ struct sockaddr_in addr2;
+
+ /* Create listening socket on a local dynamic port. */
+ lfd = socket(AF_INET, SOCK_STREAM, 0);
+ if(lfd < 0)
+ return -1;
+ memset((char *) &addr1, 0, sizeof addr1);
+ addr1.sin_family = AF_INET;
+ addr1.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ addr1.sin_port = 0;
+ if(bind(lfd, (struct sockaddr *) &addr1, sizeof addr1) ||
+ listen(lfd, 2) < 0) {
+ close(lfd);
+ return -1;
+ }
+
+ /* Get the allocated port. */
+ len = sizeof addr1;
+ if(getsockname(lfd, (struct sockaddr *) &addr1, &len) < 0) {
+ close(lfd);
+ return -1;
+ }
+
+ /* Create the client socket. */
+ cfd = socket(AF_INET, SOCK_STREAM, 0);
+ if(cfd < 0) {
+ close(lfd);
+ return -1;
+ }
+
+ /* Request unblocking connection to the listening socket. */
+ curlx_nonblock(cfd, TRUE);
+ if(connect(cfd, (struct sockaddr *) &addr1, sizeof addr1) < 0 &&
+ errno != EINPROGRESS) {
+ close(lfd);
+ close(cfd);
+ return -1;
+ }
+
+ /* Get the client dynamic port for intrusion check below. */
+ len = sizeof addr2;
+ if(getsockname(cfd, (struct sockaddr *) &addr2, &len) < 0) {
+ close(lfd);
+ close(cfd);
+ return -1;
+ }
+
+ /* Accept the incoming connection and get the server socket. */
+ curlx_nonblock(lfd, TRUE);
+ for(;;) {
+ len = sizeof addr1;
+ sfd = accept(lfd, (struct sockaddr *) &addr1, &len);
+ if(sfd < 0) {
+ close(lfd);
+ close(cfd);
+ return -1;
+ }
-static void close_one(struct ssl_connect_data *conn,
- struct Curl_easy *data)
+ /* Check for possible intrusion from an external process. */
+ if(addr1.sin_addr.s_addr == addr2.sin_addr.s_addr &&
+ addr1.sin_port == addr2.sin_port)
+ break;
+
+ /* Intrusion: reject incoming connection. */
+ close(sfd);
+ }
+
+ /* Done, return sockets and succeed. */
+ close(lfd);
+ curlx_nonblock(cfd, FALSE);
+ sv[0] = cfd;
+ sv[1] = sfd;
+ return 0;
+}
+
+static int pipe_ssloverssl(struct connectdata *conn, int sockindex,
+ int directions)
{
- if(conn->handle) {
- gskit_status(data, gsk_secure_soc_close(&conn->handle),
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connproxyssl = &conn->proxy_ssl[sockindex];
+ fd_set fds_read;
+ fd_set fds_write;
+ int n;
+ int m;
+ int i;
+ int ret = 0;
+ struct timeval tv = {0, 0};
+ char buf[CURL_MAX_WRITE_SIZE];
+
+ if(!connssl->use || !connproxyssl->use)
+ return 0; /* No SSL over SSL: OK. */
+
+ FD_ZERO(&fds_read);
+ FD_ZERO(&fds_write);
+ n = -1;
+ if(directions & SOS_READ) {
+ FD_SET(connssl->remotefd, &fds_write);
+ n = connssl->remotefd;
+ }
+ if(directions & SOS_WRITE) {
+ FD_SET(connssl->remotefd, &fds_read);
+ n = connssl->remotefd;
+ FD_SET(conn->sock[sockindex], &fds_write);
+ if(n < conn->sock[sockindex])
+ n = conn->sock[sockindex];
+ }
+ i = select(n + 1, &fds_read, &fds_write, NULL, &tv);
+ if(i < 0)
+ return -1; /* Select error. */
+
+ if(FD_ISSET(connssl->remotefd, &fds_write)) {
+ /* Try getting data from HTTPS proxy and pipe it upstream. */
+ n = 0;
+ i = gsk_secure_soc_read(connproxyssl->handle, buf, sizeof buf, &n);
+ switch(i) {
+ case GSK_OK:
+ if(n) {
+ i = write(connssl->remotefd, buf, n);
+ if(i < 0)
+ return -1;
+ ret = 1;
+ }
+ break;
+ case GSK_OS400_ERROR_TIMED_OUT:
+ case GSK_WOULD_BLOCK:
+ break;
+ default:
+ return -1;
+ }
+ }
+
+ if(FD_ISSET(connssl->remotefd, &fds_read) &&
+ FD_ISSET(conn->sock[sockindex], &fds_write)) {
+ /* Pipe data to HTTPS proxy. */
+ n = read(connssl->remotefd, buf, sizeof buf);
+ if(n < 0)
+ return -1;
+ if(n) {
+ i = gsk_secure_soc_write(connproxyssl->handle, buf, n, &m);
+ if(i != GSK_OK || n != m)
+ return -1;
+ ret = 1;
+ }
+ }
+
+ return ret; /* OK */
+}
+
+
+static void close_one(struct ssl_connect_data *connssl,
+ struct connectdata *conn, int sockindex)
+{
+ if(connssl->handle) {
+ gskit_status(conn->data, gsk_secure_soc_close(&connssl->handle),
"gsk_secure_soc_close()", 0);
- conn->handle = (gsk_handle) NULL;
+ /* Last chance to drain output. */
+ while(pipe_ssloverssl(conn, sockindex, SOS_WRITE) > 0)
+ ;
+ connssl->handle = (gsk_handle) NULL;
+ if(connssl->localfd >= 0) {
+ close(connssl->localfd);
+ connssl->localfd = -1;
+ }
+ if(connssl->remotefd >= 0) {
+ close(connssl->remotefd);
+ connssl->remotefd = -1;
+ }
}
- if(conn->iocport >= 0)
- close_async_handshake(conn);
+ if(connssl->iocport >= 0)
+ close_async_handshake(connssl);
}
@@ -518,13 +701,18 @@ static ssize_t gskit_send(struct connectdata *conn, int sockindex,
const void *mem, size_t len, CURLcode *curlcode)
{
struct Curl_easy *data = conn->data;
- CURLcode cc;
+ CURLcode cc = CURLE_SEND_ERROR;
int written;
- cc = gskit_status(data,
- gsk_secure_soc_write(conn->ssl[sockindex].handle,
- (char *) mem, (int) len, &written),
- "gsk_secure_soc_write()", CURLE_SEND_ERROR);
+ if(pipe_ssloverssl(conn, sockindex, SOS_WRITE) >= 0) {
+ cc = gskit_status(data,
+ gsk_secure_soc_write(conn->ssl[sockindex].handle,
+ (char *) mem, (int) len, &written),
+ "gsk_secure_soc_write()", CURLE_SEND_ERROR);
+ if(cc == CURLE_OK)
+ if(pipe_ssloverssl(conn, sockindex, SOS_WRITE) < 0)
+ cc = CURLE_SEND_ERROR;
+ }
if(cc != CURLE_OK) {
*curlcode = cc;
written = -1;
@@ -539,15 +727,23 @@ static ssize_t gskit_recv(struct connectdata *conn, int num, char *buf,
struct Curl_easy *data = conn->data;
int buffsize;
int nread;
- CURLcode cc;
+ CURLcode cc = CURLE_RECV_ERROR;
- buffsize = buffersize > (size_t) INT_MAX? INT_MAX: (int) buffersize;
- cc = gskit_status(data, gsk_secure_soc_read(conn->ssl[num].handle,
- buf, buffsize, &nread),
- "gsk_secure_soc_read()", CURLE_RECV_ERROR);
- if(cc != CURLE_OK) {
+ if(pipe_ssloverssl(conn, num, SOS_READ) >= 0) {
+ buffsize = buffersize > (size_t) INT_MAX? INT_MAX: (int) buffersize;
+ cc = gskit_status(data, gsk_secure_soc_read(conn->ssl[num].handle,
+ buf, buffsize, &nread),
+ "gsk_secure_soc_read()", CURLE_RECV_ERROR);
+ }
+ switch(cc) {
+ case CURLE_OK:
+ break;
+ case CURLE_OPERATION_TIMEDOUT:
+ cc = CURLE_AGAIN;
+ default:
*curlcode = cc;
nread = -1;
+ break;
}
return (ssize_t) nread;
}
@@ -560,18 +756,26 @@ static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex)
gsk_handle envir;
CURLcode result;
int rc;
- char *keyringfile;
- char *keyringpwd;
- char *keyringlabel;
- char *sni;
+ const char * const keyringfile = SSL_CONN_CONFIG(CAfile);
+ const char * const keyringpwd = SSL_SET_OPTION(key_passwd);
+ const char * const keyringlabel = SSL_SET_OPTION(cert);
+ const long int ssl_version = SSL_CONN_CONFIG(version);
+ const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
+ const char * const hostname = SSL_IS_PROXY()? conn->http_proxy.host.name:
+ conn->host.name;
+ const char *sni;
unsigned int protoflags;
long timeout;
Qso_OverlappedIO_t commarea;
+ int sockpair[2];
+ static const int sobufsize = CURL_MAX_WRITE_SIZE;
/* Create SSL environment, start (preferably asynchronous) handshake. */
connssl->handle = (gsk_handle) NULL;
connssl->iocport = -1;
+ connssl->localfd = -1;
+ connssl->remotefd = -1;
/* GSKit supports two ways of specifying an SSL context: either by
* application identifier (that should have been defined at the system
@@ -586,9 +790,6 @@ static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex)
* application identifier mode is tried first, as recommended in IBM doc.
*/
- keyringfile = data->set.str[STRING_SSL_CAFILE];
- keyringpwd = data->set.str[STRING_KEY_PASSWD];
- keyringlabel = data->set.str[STRING_CERT];
envir = (gsk_handle) NULL;
if(keyringlabel && *keyringlabel && !keyringpwd &&
@@ -613,19 +814,36 @@ static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex)
if(result)
return result;
+ /* Establish a pipelining socket pair for SSL over SSL. */
+ if(conn->proxy_ssl[sockindex].use) {
+ if(inetsocketpair(sockpair))
+ return CURLE_SSL_CONNECT_ERROR;
+ connssl->localfd = sockpair[0];
+ connssl->remotefd = sockpair[1];
+ setsockopt(connssl->localfd, SOL_SOCKET, SO_RCVBUF,
+ (void *) sobufsize, sizeof sobufsize);
+ setsockopt(connssl->remotefd, SOL_SOCKET, SO_RCVBUF,
+ (void *) sobufsize, sizeof sobufsize);
+ setsockopt(connssl->localfd, SOL_SOCKET, SO_SNDBUF,
+ (void *) sobufsize, sizeof sobufsize);
+ setsockopt(connssl->remotefd, SOL_SOCKET, SO_SNDBUF,
+ (void *) sobufsize, sizeof sobufsize);
+ curlx_nonblock(connssl->localfd, TRUE);
+ curlx_nonblock(connssl->remotefd, TRUE);
+ }
+
/* Determine which SSL/TLS version should be enabled. */
- protoflags = CURL_GSKPROTO_TLSV10_MASK | CURL_GSKPROTO_TLSV11_MASK |
- CURL_GSKPROTO_TLSV12_MASK;
- sni = conn->host.name;
- switch (data->set.ssl.version) {
+ sni = hostname;
+ switch(ssl_version) {
case CURL_SSLVERSION_SSLv2:
protoflags = CURL_GSKPROTO_SSLV2_MASK;
- sni = (char *) NULL;
+ sni = NULL;
break;
case CURL_SSLVERSION_SSLv3:
protoflags = CURL_GSKPROTO_SSLV3_MASK;
- sni = (char *) NULL;
+ sni = NULL;
break;
+ case CURL_SSLVERSION_DEFAULT:
case CURL_SSLVERSION_TLSv1:
protoflags = CURL_GSKPROTO_TLSV10_MASK |
CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK;
@@ -639,6 +857,12 @@ static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex)
case CURL_SSLVERSION_TLSv1_2:
protoflags = CURL_GSKPROTO_TLSV12_MASK;
break;
+ case CURL_SSLVERSION_TLSv1_3:
+ failf(data, "GSKit: TLS 1.3 is not yet supported");
+ return CURLE_SSL_CONNECT_ERROR;
+ default:
+ failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
+ return CURLE_SSL_CONNECT_ERROR;
}
/* Process SNI. Ignore if not supported (on OS400 < V7R1). */
@@ -661,9 +885,12 @@ static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex)
(timeout + 999) / 1000);
}
if(!result)
- result = set_numeric(data, connssl->handle, GSK_FD, conn->sock[sockindex]);
+ result = set_numeric(data, connssl->handle, GSK_OS400_READ_TIMEOUT, 1);
if(!result)
- result = set_ciphers(data, connssl->handle, &protoflags);
+ result = set_numeric(data, connssl->handle, GSK_FD, connssl->localfd >= 0?
+ connssl->localfd: conn->sock[sockindex]);
+ if(!result)
+ result = set_ciphers(conn, connssl->handle, &protoflags);
if(!protoflags) {
failf(data, "No SSL protocol/cipher combination enabled");
result = CURLE_SSL_CIPHER;
@@ -706,7 +933,7 @@ static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex)
}
if(!result)
result = set_enum(data, connssl->handle, GSK_SERVER_AUTH_TYPE,
- data->set.ssl.verifypeer? GSK_SERVER_AUTH_FULL:
+ verifypeer? GSK_SERVER_AUTH_FULL:
GSK_SERVER_AUTH_PASSTHRU, FALSE);
if(!result) {
@@ -730,6 +957,10 @@ static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex)
else if(errno != ENOBUFS)
result = gskit_status(data, GSK_ERROR_IO,
"QsoCreateIOCompletionPort()", 0);
+ else if(conn->proxy_ssl[sockindex].use) {
+ /* Cannot pipeline while handshaking synchronously. */
+ result = CURLE_SSL_CONNECT_ERROR;
+ }
else {
/* No more completion port available. Use synchronous IO. */
result = gskit_status(data, gsk_secure_soc_init(connssl->handle),
@@ -742,7 +973,7 @@ static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex)
}
/* Error: rollback. */
- close_one(connssl, data);
+ close_one(connssl, conn, sockindex);
return result;
}
@@ -765,7 +996,7 @@ static CURLcode gskit_connect_step2(struct connectdata *conn, int sockindex,
timeout_ms = 0;
stmv.tv_sec = timeout_ms / 1000;
stmv.tv_usec = (timeout_ms - stmv.tv_sec * 1000) * 1000;
- switch (QsoWaitForIOCompletion(connssl->iocport, &cstat, &stmv)) {
+ switch(QsoWaitForIOCompletion(connssl->iocport, &cstat, &stmv)) {
case 1: /* Operation complete. */
break;
case -1: /* An error occurred: handshake still in progress. */
@@ -822,7 +1053,7 @@ static CURLcode gskit_connect_step3(struct connectdata *conn, int sockindex)
infof(data, "Server certificate:\n");
p = cdev;
for(i = 0; i++ < cdec; p++)
- switch (p->cert_data_id) {
+ switch(p->cert_data_id) {
case CERT_BODY_DER:
cert = p->cert_data_p;
certend = cert + cdev->cert_data_l;
@@ -865,14 +1096,14 @@ static CURLcode gskit_connect_step3(struct connectdata *conn, int sockindex)
}
/* Check pinned public key. */
- ptr = data->set.str[STRING_SSL_PINNEDPUBLICKEY];
+ ptr = SSL_IS_PROXY() ? data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
if(!result && ptr) {
curl_X509certificate x509;
curl_asn1Element *p;
- if(!cert)
+ if(Curl_parseX509(&x509, cert, certend))
return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
- Curl_parseX509(&x509, cert, certend);
p = &x509.subjectPublicKeyInfo;
result = Curl_pin_peer_pubkey(data, ptr, p->header, p->end - p->header);
if(result) {
@@ -913,6 +1144,11 @@ static CURLcode gskit_connect_common(struct connectdata *conn, int sockindex,
result = gskit_connect_step1(conn, sockindex);
}
+ /* Handle handshake pipelining. */
+ if(!result)
+ if(pipe_ssloverssl(conn, sockindex, SOS_READ | SOS_WRITE) < 0)
+ result = CURLE_SSL_CONNECT_ERROR;
+
/* Step 2: check if handshake is over. */
if(!result && connssl->connecting_state == ssl_connect_2) {
/* check allowed time left */
@@ -927,12 +1163,17 @@ static CURLcode gskit_connect_common(struct connectdata *conn, int sockindex,
result = gskit_connect_step2(conn, sockindex, nonblocking);
}
+ /* Handle handshake pipelining. */
+ if(!result)
+ if(pipe_ssloverssl(conn, sockindex, SOS_READ | SOS_WRITE) < 0)
+ result = CURLE_SSL_CONNECT_ERROR;
+
/* Step 3: gather certificate info, verify host. */
if(!result && connssl->connecting_state == ssl_connect_3)
result = gskit_connect_step3(conn, sockindex);
if(result)
- close_one(connssl, data);
+ close_one(connssl, conn, sockindex);
else if(connssl->connecting_state == ssl_connect_done) {
connssl->state = ssl_connection_complete;
connssl->connecting_state = ssl_connect_1;
@@ -976,11 +1217,8 @@ CURLcode Curl_gskit_connect(struct connectdata *conn, int sockindex)
void Curl_gskit_close(struct connectdata *conn, int sockindex)
{
- struct Curl_easy *data = conn->data;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
-
- if(connssl->use)
- close_one(connssl, data);
+ close_one(&conn->ssl[sockindex], conn, sockindex);
+ close_one(&conn->proxy_ssl[sockindex], conn, sockindex);
}
@@ -999,7 +1237,7 @@ int Curl_gskit_shutdown(struct connectdata *conn, int sockindex)
if(data->set.ftp_ccc != CURLFTPSSL_CCC_ACTIVE)
return 0;
- close_one(connssl, data);
+ close_one(connssl, conn, sockindex);
rc = 0;
what = SOCKET_READABLE(conn->sock[sockindex],
SSL_SHUTDOWN_TIMEOUT);
diff --git a/Utilities/cmcurl/lib/vtls/gskit.h b/Utilities/cmcurl/lib/vtls/gskit.h
index 41483cba62..229759217a 100644
--- a/Utilities/cmcurl/lib/vtls/gskit.h
+++ b/Utilities/cmcurl/lib/vtls/gskit.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, 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
@@ -41,6 +41,9 @@ int Curl_gskit_shutdown(struct connectdata *conn, int sockindex);
size_t Curl_gskit_version(char *buffer, size_t size);
int Curl_gskit_check_cxn(struct connectdata *cxn);
+/* Support HTTPS-proxy */
+/* TODO: add '#define HTTPS_PROXY_SUPPORT 1' and fix test #1014 (if need) */
+
/* Set the API backend definition to GSKit */
#define CURL_SSL_BACKEND CURLSSLBACKEND_GSKIT
@@ -64,7 +67,7 @@ int Curl_gskit_check_cxn(struct connectdata *cxn);
#define curlssl_version Curl_gskit_version
#define curlssl_check_cxn(x) Curl_gskit_check_cxn(x)
#define curlssl_data_pending(x,y) 0
-#define curlssl_random(x,y,z) -1
+#define curlssl_random(x,y,z) (x=x, y=y, z=z, CURLE_NOT_BUILT_IN)
#endif /* USE_GSKIT */
diff --git a/Utilities/cmcurl/lib/vtls/gtls.c b/Utilities/cmcurl/lib/vtls/gtls.c
index 5c87c7fe31..0e308cb79f 100644
--- a/Utilities/cmcurl/lib/vtls/gtls.c
+++ b/Utilities/cmcurl/lib/vtls/gtls.c
@@ -68,7 +68,7 @@
#define GNUTLS_POINTER_TO_INT_CAST(p) ((int) (long) (p))
#endif
#ifndef GNUTLS_INT_TO_POINTER_CAST
-#define GNUTLS_INT_TO_POINTER_CAST(i) ((void*) (long) (i))
+#define GNUTLS_INT_TO_POINTER_CAST(i) ((void *) (long) (i))
#endif
/* Enable GnuTLS debugging by defining GTLSDEBUG */
@@ -171,6 +171,16 @@ static ssize_t Curl_gtls_pull(void *s, void *buf, size_t len)
return ret;
}
+static ssize_t Curl_gtls_push_ssl(void *s, const void *buf, size_t len)
+{
+ return gnutls_record_send((gnutls_session_t) s, buf, len);
+}
+
+static ssize_t Curl_gtls_pull_ssl(void *s, void *buf, size_t len)
+{
+ return gnutls_record_recv((gnutls_session_t) s, buf, len);
+}
+
/* Curl_gtls_init()
*
* Global GnuTLS init, called from Curl_ssl_init(). This calls functions that
@@ -225,14 +235,15 @@ static void showtime(struct Curl_easy *data,
infof(data, "%s\n", data->state.buffer);
}
-static gnutls_datum_t load_file (const char *file)
+static gnutls_datum_t load_file(const char *file)
{
FILE *f;
gnutls_datum_t loaded_file = { NULL, 0 };
long filelen;
void *ptr;
- if(!(f = fopen(file, "rb")))
+ f = fopen(file, "rb");
+ if(!f)
return loaded_file;
if(fseek(f, 0, SEEK_END) != 0
|| (filelen = ftell(f)) < 0
@@ -251,7 +262,8 @@ out:
return loaded_file;
}
-static void unload_file(gnutls_datum_t data) {
+static void unload_file(gnutls_datum_t data)
+{
free(data.data);
}
@@ -371,6 +383,9 @@ gtls_connect_step1(struct connectdata *conn,
gnutls_session_t session;
int rc;
bool sni = TRUE; /* default is SNI enabled */
+ void *transport_ptr = NULL;
+ gnutls_push_func gnutls_transport_push = NULL;
+ gnutls_pull_func gnutls_transport_pull = NULL;
#ifdef ENABLE_IPV6
struct in6_addr addr;
#else
@@ -397,10 +412,13 @@ gtls_connect_step1(struct connectdata *conn,
requested in the priority string, so treat it specially
*/
#define GNUTLS_SRP "+SRP"
- const char* prioritylist;
+ const char *prioritylist;
const char *err = NULL;
#endif
+ const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
+ conn->host.name;
+
if(conn->ssl[sockindex].state == ssl_connection_complete)
/* to make us tolerant against being called more than once for the
same connection */
@@ -409,12 +427,11 @@ gtls_connect_step1(struct connectdata *conn,
if(!gtls_inited)
Curl_gtls_init();
- /* GnuTLS only supports SSLv3 and TLSv1 */
- if(data->set.ssl.version == CURL_SSLVERSION_SSLv2) {
+ if(SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv2) {
failf(data, "GnuTLS does not support SSLv2");
return CURLE_SSL_CONNECT_ERROR;
}
- else if(data->set.ssl.version == CURL_SSLVERSION_SSLv3)
+ else if(SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv3)
sni = FALSE; /* SSLv3 has no SNI */
/* allocate a cred struct */
@@ -425,8 +442,8 @@ gtls_connect_step1(struct connectdata *conn,
}
#ifdef USE_TLS_SRP
- if(data->set.ssl.authtype == CURL_TLSAUTH_SRP) {
- infof(data, "Using TLS-SRP username: %s\n", data->set.ssl.username);
+ if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP) {
+ infof(data, "Using TLS-SRP username: %s\n", SSL_SET_OPTION(username));
rc = gnutls_srp_allocate_client_credentials(
&conn->ssl[sockindex].srp_client_cred);
@@ -438,8 +455,8 @@ gtls_connect_step1(struct connectdata *conn,
rc = gnutls_srp_set_client_credentials(conn->ssl[sockindex].
srp_client_cred,
- data->set.ssl.username,
- data->set.ssl.password);
+ SSL_SET_OPTION(username),
+ SSL_SET_OPTION(password));
if(rc != GNUTLS_E_SUCCESS) {
failf(data, "gnutls_srp_set_client_cred() failed: %s",
gnutls_strerror(rc));
@@ -448,64 +465,64 @@ gtls_connect_step1(struct connectdata *conn,
}
#endif
- if(data->set.ssl.CAfile) {
+ if(SSL_CONN_CONFIG(CAfile)) {
/* set the trusted CA cert bundle file */
gnutls_certificate_set_verify_flags(conn->ssl[sockindex].cred,
GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);
rc = gnutls_certificate_set_x509_trust_file(conn->ssl[sockindex].cred,
- data->set.ssl.CAfile,
+ SSL_CONN_CONFIG(CAfile),
GNUTLS_X509_FMT_PEM);
if(rc < 0) {
infof(data, "error reading ca cert file %s (%s)\n",
- data->set.ssl.CAfile, gnutls_strerror(rc));
- if(data->set.ssl.verifypeer)
+ SSL_CONN_CONFIG(CAfile), gnutls_strerror(rc));
+ if(SSL_CONN_CONFIG(verifypeer))
return CURLE_SSL_CACERT_BADFILE;
}
else
- infof(data, "found %d certificates in %s\n",
- rc, data->set.ssl.CAfile);
+ infof(data, "found %d certificates in %s\n", rc,
+ SSL_CONN_CONFIG(CAfile));
}
#ifdef HAS_CAPATH
- if(data->set.ssl.CApath) {
+ if(SSL_CONN_CONFIG(CApath)) {
/* set the trusted CA cert directory */
rc = gnutls_certificate_set_x509_trust_dir(conn->ssl[sockindex].cred,
- data->set.ssl.CApath,
- GNUTLS_X509_FMT_PEM);
+ SSL_CONN_CONFIG(CApath),
+ GNUTLS_X509_FMT_PEM);
if(rc < 0) {
infof(data, "error reading ca cert file %s (%s)\n",
- data->set.ssl.CAfile, gnutls_strerror(rc));
- if(data->set.ssl.verifypeer)
+ SSL_CONN_CONFIG(CApath), gnutls_strerror(rc));
+ if(SSL_CONN_CONFIG(verifypeer))
return CURLE_SSL_CACERT_BADFILE;
}
else
infof(data, "found %d certificates in %s\n",
- rc, data->set.ssl.CApath);
+ rc, SSL_CONN_CONFIG(CApath));
}
#endif
#ifdef CURL_CA_FALLBACK
/* use system ca certificate store as fallback */
- if(data->set.ssl.verifypeer &&
- !(data->set.ssl.CAfile || data->set.ssl.CApath)) {
+ if(SSL_CONN_CONFIG(verifypeer) &&
+ !(SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(CApath))) {
gnutls_certificate_set_x509_system_trust(conn->ssl[sockindex].cred);
}
#endif
- if(data->set.ssl.CRLfile) {
+ if(SSL_SET_OPTION(CRLfile)) {
/* set the CRL list file */
rc = gnutls_certificate_set_x509_crl_file(conn->ssl[sockindex].cred,
- data->set.ssl.CRLfile,
+ SSL_SET_OPTION(CRLfile),
GNUTLS_X509_FMT_PEM);
if(rc < 0) {
failf(data, "error reading crl file %s (%s)",
- data->set.ssl.CRLfile, gnutls_strerror(rc));
+ SSL_SET_OPTION(CRLfile), gnutls_strerror(rc));
return CURLE_SSL_CRL_BADFILE;
}
else
infof(data, "found %d CRL in %s\n",
- rc, data->set.ssl.CRLfile);
+ rc, SSL_SET_OPTION(CRLfile));
}
/* Initialize TLS session as a client */
@@ -518,13 +535,13 @@ gtls_connect_step1(struct connectdata *conn,
/* convenient assign */
session = conn->ssl[sockindex].session;
- if((0 == Curl_inet_pton(AF_INET, conn->host.name, &addr)) &&
+ if((0 == Curl_inet_pton(AF_INET, hostname, &addr)) &&
#ifdef ENABLE_IPV6
- (0 == Curl_inet_pton(AF_INET6, conn->host.name, &addr)) &&
+ (0 == Curl_inet_pton(AF_INET6, hostname, &addr)) &&
#endif
sni &&
- (gnutls_server_name_set(session, GNUTLS_NAME_DNS, conn->host.name,
- strlen(conn->host.name)) < 0))
+ (gnutls_server_name_set(session, GNUTLS_NAME_DNS, hostname,
+ strlen(hostname)) < 0))
infof(data, "WARNING: failed to configure server name indication (SNI) "
"TLS extension\n");
@@ -545,13 +562,13 @@ gtls_connect_step1(struct connectdata *conn,
if(rc != GNUTLS_E_SUCCESS)
return CURLE_SSL_CONNECT_ERROR;
- if(data->set.ssl.cipher_list != NULL) {
+ if(SSL_CONN_CONFIG(cipher_list) != NULL) {
failf(data, "can't pass a custom cipher list to older GnuTLS"
" versions");
return CURLE_SSL_CONNECT_ERROR;
}
- switch (data->set.ssl.version) {
+ switch(SSL_CONN_CONFIG(version) {
case CURL_SSLVERSION_SSLv3:
protocol_priority[0] = GNUTLS_SSL3;
break;
@@ -569,12 +586,16 @@ gtls_connect_step1(struct connectdata *conn,
break;
case CURL_SSLVERSION_TLSv1_2:
protocol_priority[0] = GNUTLS_TLS1_2;
- break;
- case CURL_SSLVERSION_SSLv2:
- default:
+ break;
+ case CURL_SSLVERSION_TLSv1_3:
+ failf(data, "GnuTLS: TLS 1.3 is not yet supported");
+ return CURLE_SSL_CONNECT_ERROR;
+ case CURL_SSLVERSION_SSLv2:
failf(data, "GnuTLS does not support SSLv2");
return CURLE_SSL_CONNECT_ERROR;
- break;
+ default:
+ failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
+ return CURLE_SSL_CONNECT_ERROR;
}
rc = gnutls_protocol_set_priority(session, protocol_priority);
if(rc != GNUTLS_E_SUCCESS) {
@@ -586,7 +607,7 @@ gtls_connect_step1(struct connectdata *conn,
/* Ensure +SRP comes at the *end* of all relevant strings so that it can be
* removed if a run-time error indicates that SRP is not supported by this
* GnuTLS version */
- switch (data->set.ssl.version) {
+ switch(SSL_CONN_CONFIG(version)) {
case CURL_SSLVERSION_SSLv3:
prioritylist = GNUTLS_CIPHERS ":-VERS-TLS-ALL:+VERS-SSL3.0";
sni = false;
@@ -607,11 +628,15 @@ gtls_connect_step1(struct connectdata *conn,
prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
"+VERS-TLS1.2:" GNUTLS_SRP;
break;
+ case CURL_SSLVERSION_TLSv1_3:
+ failf(data, "GnuTLS: TLS 1.3 is not yet supported");
+ return CURLE_SSL_CONNECT_ERROR;
case CURL_SSLVERSION_SSLv2:
- default:
failf(data, "GnuTLS does not support SSLv2");
return CURLE_SSL_CONNECT_ERROR;
- break;
+ default:
+ failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
+ return CURLE_SSL_CONNECT_ERROR;
}
rc = gnutls_priority_set_direct(session, prioritylist, &err);
if((rc == GNUTLS_E_INVALID_REQUEST) && err) {
@@ -661,8 +686,8 @@ gtls_connect_step1(struct connectdata *conn,
}
#endif
- if(data->set.str[STRING_CERT]) {
- if(data->set.str[STRING_KEY_PASSWD]) {
+ if(SSL_SET_OPTION(cert)) {
+ if(SSL_SET_OPTION(key_passwd)) {
#if HAVE_GNUTLS_CERTIFICATE_SET_X509_KEY_FILE2
const unsigned int supported_key_encryption_algorithms =
GNUTLS_PKCS_USE_PKCS12_3DES | GNUTLS_PKCS_USE_PKCS12_ARCFOUR |
@@ -671,11 +696,11 @@ gtls_connect_step1(struct connectdata *conn,
GNUTLS_PKCS_USE_PBES2_AES_256;
rc = gnutls_certificate_set_x509_key_file2(
conn->ssl[sockindex].cred,
- data->set.str[STRING_CERT],
- data->set.str[STRING_KEY] ?
- data->set.str[STRING_KEY] : data->set.str[STRING_CERT],
- do_file_type(data->set.str[STRING_CERT_TYPE]),
- data->set.str[STRING_KEY_PASSWD],
+ SSL_SET_OPTION(cert),
+ SSL_SET_OPTION(key) ?
+ SSL_SET_OPTION(key) : SSL_SET_OPTION(cert),
+ do_file_type(SSL_SET_OPTION(cert_type)),
+ SSL_SET_OPTION(key_passwd),
supported_key_encryption_algorithms);
if(rc != GNUTLS_E_SUCCESS) {
failf(data,
@@ -689,15 +714,14 @@ gtls_connect_step1(struct connectdata *conn,
#endif
}
else {
- rc = gnutls_certificate_set_x509_key_file(
+ if(gnutls_certificate_set_x509_key_file(
conn->ssl[sockindex].cred,
- data->set.str[STRING_CERT],
- data->set.str[STRING_KEY] ?
- data->set.str[STRING_KEY] : data->set.str[STRING_CERT],
- do_file_type(data->set.str[STRING_CERT_TYPE]) );
- if(rc != GNUTLS_E_SUCCESS) {
- failf(data, "error reading X.509 key or certificate file: %s",
- gnutls_strerror(rc));
+ SSL_SET_OPTION(cert),
+ SSL_SET_OPTION(key) ?
+ SSL_SET_OPTION(key) : SSL_SET_OPTION(cert),
+ do_file_type(SSL_SET_OPTION(cert_type)) ) !=
+ GNUTLS_E_SUCCESS) {
+ failf(data, "error reading X.509 key or certificate file");
return CURLE_SSL_CONNECT_ERROR;
}
}
@@ -705,7 +729,7 @@ gtls_connect_step1(struct connectdata *conn,
#ifdef USE_TLS_SRP
/* put the credentials to the current session */
- if(data->set.ssl.authtype == CURL_TLSAUTH_SRP) {
+ if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP) {
rc = gnutls_credentials_set(session, GNUTLS_CRD_SRP,
conn->ssl[sockindex].srp_client_cred);
if(rc != GNUTLS_E_SUCCESS) {
@@ -724,19 +748,30 @@ gtls_connect_step1(struct connectdata *conn,
}
}
- /* set the connection handle (file descriptor for the socket) */
- gnutls_transport_set_ptr(session,
- GNUTLS_INT_TO_POINTER_CAST(conn->sock[sockindex]));
+ if(conn->proxy_ssl[sockindex].use) {
+ transport_ptr = conn->proxy_ssl[sockindex].session;
+ gnutls_transport_push = Curl_gtls_push_ssl;
+ gnutls_transport_pull = Curl_gtls_pull_ssl;
+ }
+ else {
+ /* file descriptor for the socket */
+ transport_ptr = GNUTLS_INT_TO_POINTER_CAST(conn->sock[sockindex]);
+ gnutls_transport_push = Curl_gtls_push;
+ gnutls_transport_pull = Curl_gtls_pull;
+ }
+
+ /* set the connection handle */
+ gnutls_transport_set_ptr(session, transport_ptr);
/* register callback functions to send and receive data. */
- gnutls_transport_set_push_function(session, Curl_gtls_push);
- gnutls_transport_set_pull_function(session, Curl_gtls_pull);
+ gnutls_transport_set_push_function(session, gnutls_transport_push);
+ gnutls_transport_set_pull_function(session, gnutls_transport_pull);
/* lowat must be set to zero when using custom push and pull functions. */
gnutls_transport_set_lowat(session, 0);
#ifdef HAS_OCSP
- if(data->set.ssl.verifystatus) {
+ if(SSL_CONN_CONFIG(verifystatus)) {
rc = gnutls_ocsp_status_request_enable_client(session, NULL, 0, NULL);
if(rc != GNUTLS_E_SUCCESS) {
failf(data, "gnutls_ocsp_status_request_enable_client() failed: %d", rc);
@@ -747,17 +782,17 @@ gtls_connect_step1(struct connectdata *conn,
/* This might be a reconnect, so we check for a session ID in the cache
to speed up things */
- if(conn->ssl_config.sessionid) {
+ if(data->set.general_ssl.sessionid) {
void *ssl_sessionid;
size_t ssl_idsize;
Curl_ssl_sessionid_lock(conn);
- if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, &ssl_idsize)) {
+ if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, &ssl_idsize, sockindex)) {
/* we got a session id, use it! */
gnutls_session_set_data(session, ssl_sessionid, ssl_idsize);
/* Informational message */
- infof (data, "SSL re-using session ID\n");
+ infof(data, "SSL re-using session ID\n");
}
Curl_ssl_sessionid_unlock(conn);
}
@@ -847,8 +882,9 @@ gtls_connect_step3(struct connectdata *conn,
gnutls_datum_t proto;
#endif
CURLcode result = CURLE_OK;
-
gnutls_protocol_t version = gnutls_protocol_get_version(session);
+ const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
+ conn->host.name;
/* the name of the cipher suite used, e.g. ECDHE_RSA_AES_256_GCM_SHA384. */
ptr = gnutls_cipher_suite_get_name(gnutls_kx_get(session),
@@ -866,13 +902,13 @@ gtls_connect_step3(struct connectdata *conn,
chainp = gnutls_certificate_get_peers(session, &cert_list_size);
if(!chainp) {
- if(data->set.ssl.verifypeer ||
- data->set.ssl.verifyhost ||
- data->set.ssl.issuercert) {
+ if(SSL_CONN_CONFIG(verifypeer) ||
+ SSL_CONN_CONFIG(verifyhost) ||
+ SSL_SET_OPTION(issuercert)) {
#ifdef USE_TLS_SRP
- if(data->set.ssl.authtype == CURL_TLSAUTH_SRP
- && data->set.ssl.username != NULL
- && !data->set.ssl.verifypeer
+ if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP
+ && SSL_SET_OPTION(username) != NULL
+ && !SSL_CONN_CONFIG(verifypeer)
&& gnutls_cipher_get(session)) {
/* no peer cert, but auth is ok if we have SRP user and cipher and no
peer verify */
@@ -905,7 +941,7 @@ gtls_connect_step3(struct connectdata *conn,
}
}
- if(data->set.ssl.verifypeer) {
+ if(SSL_CONN_CONFIG(verifypeer)) {
/* This function will try to verify the peer's certificate and return its
status (trusted, invalid etc.). The value of status should be one or
more of the gnutls_certificate_status_t enumerated elements bitwise
@@ -921,10 +957,11 @@ gtls_connect_step3(struct connectdata *conn,
/* verify_status is a bitmask of gnutls_certificate_status bits */
if(verify_status & GNUTLS_CERT_INVALID) {
- if(data->set.ssl.verifypeer) {
+ if(SSL_CONN_CONFIG(verifypeer)) {
failf(data, "server certificate verification failed. CAfile: %s "
- "CRLfile: %s", data->set.ssl.CAfile?data->set.ssl.CAfile:"none",
- data->set.ssl.CRLfile?data->set.ssl.CRLfile:"none");
+ "CRLfile: %s", SSL_CONN_CONFIG(CAfile) ? SSL_CONN_CONFIG(CAfile):
+ "none",
+ SSL_SET_OPTION(CRLfile)?SSL_SET_OPTION(CRLfile):"none");
return CURLE_SSL_CACERT;
}
else
@@ -937,7 +974,7 @@ gtls_connect_step3(struct connectdata *conn,
infof(data, "\t server certificate verification SKIPPED\n");
#ifdef HAS_OCSP
- if(data->set.ssl.verifystatus) {
+ if(SSL_CONN_CONFIG(verifystatus)) {
if(gnutls_ocsp_status_request_is_checked(session, 0) == 0) {
gnutls_datum_t status_request;
gnutls_ocsp_resp_t ocsp_resp;
@@ -1049,21 +1086,21 @@ gtls_connect_step3(struct connectdata *conn,
gnutls_x509_crt_t format */
gnutls_x509_crt_import(x509_cert, chainp, GNUTLS_X509_FMT_DER);
- if(data->set.ssl.issuercert) {
+ if(SSL_SET_OPTION(issuercert)) {
gnutls_x509_crt_init(&x509_issuer);
- issuerp = load_file(data->set.ssl.issuercert);
+ issuerp = load_file(SSL_SET_OPTION(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)",
- data->set.ssl.issuercert?data->set.ssl.issuercert:"none");
+ SSL_SET_OPTION(issuercert)?SSL_SET_OPTION(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",
- data->set.ssl.issuercert?data->set.ssl.issuercert:"none");
+ SSL_SET_OPTION(issuercert)?SSL_SET_OPTION(issuercert):"none");
}
size=sizeof(certbuf);
@@ -1082,7 +1119,7 @@ gtls_connect_step3(struct connectdata *conn,
in RFC2818 (HTTPS), which takes into account wildcards, and the subject
alternative name PKIX extension. Returns non zero on success, and zero on
failure. */
- rc = gnutls_x509_crt_check_hostname(x509_cert, conn->host.name);
+ rc = gnutls_x509_crt_check_hostname(x509_cert, hostname);
#if GNUTLS_VERSION_NUMBER < 0x030306
/* Before 3.3.6, gnutls_x509_crt_check_hostname() didn't check IP
addresses. */
@@ -1098,10 +1135,10 @@ gtls_connect_step3(struct connectdata *conn,
int i;
int ret = 0;
- if(Curl_inet_pton(AF_INET, conn->host.name, addrbuf) > 0)
+ if(Curl_inet_pton(AF_INET, hostname, addrbuf) > 0)
addrlen = 4;
#ifdef ENABLE_IPV6
- else if(Curl_inet_pton(AF_INET6, conn->host.name, addrbuf) > 0)
+ else if(Curl_inet_pton(AF_INET6, hostname, addrbuf) > 0)
addrlen = 16;
#endif
@@ -1126,15 +1163,18 @@ gtls_connect_step3(struct connectdata *conn,
}
#endif
if(!rc) {
- if(data->set.ssl.verifyhost) {
+ const char * const dispname = SSL_IS_PROXY() ?
+ conn->http_proxy.host.dispname : conn->host.dispname;
+
+ if(SSL_CONN_CONFIG(verifyhost)) {
failf(data, "SSL: certificate subject name (%s) does not match "
- "target host name '%s'", certbuf, conn->host.dispname);
+ "target host name '%s'", certbuf, dispname);
gnutls_x509_crt_deinit(x509_cert);
return CURLE_PEER_FAILED_VERIFICATION;
}
else
infof(data, "\t common name: %s (does not match '%s')\n",
- certbuf, conn->host.dispname);
+ certbuf, dispname);
}
else
infof(data, "\t common name: %s (matched)\n", certbuf);
@@ -1143,7 +1183,7 @@ gtls_connect_step3(struct connectdata *conn,
certclock = gnutls_x509_crt_get_expiration_time(x509_cert);
if(certclock == (time_t)-1) {
- if(data->set.ssl.verifypeer) {
+ if(SSL_CONN_CONFIG(verifypeer)) {
failf(data, "server cert expiration date verify failed");
gnutls_x509_crt_deinit(x509_cert);
return CURLE_SSL_CONNECT_ERROR;
@@ -1153,7 +1193,7 @@ gtls_connect_step3(struct connectdata *conn,
}
else {
if(certclock < time(NULL)) {
- if(data->set.ssl.verifypeer) {
+ if(SSL_CONN_CONFIG(verifypeer)) {
failf(data, "server certificate expiration date has passed.");
gnutls_x509_crt_deinit(x509_cert);
return CURLE_PEER_FAILED_VERIFICATION;
@@ -1168,7 +1208,7 @@ gtls_connect_step3(struct connectdata *conn,
certclock = gnutls_x509_crt_get_activation_time(x509_cert);
if(certclock == (time_t)-1) {
- if(data->set.ssl.verifypeer) {
+ if(SSL_CONN_CONFIG(verifypeer)) {
failf(data, "server cert activation date verify failed");
gnutls_x509_crt_deinit(x509_cert);
return CURLE_SSL_CONNECT_ERROR;
@@ -1178,7 +1218,7 @@ gtls_connect_step3(struct connectdata *conn,
}
else {
if(certclock > time(NULL)) {
- if(data->set.ssl.verifypeer) {
+ if(SSL_CONN_CONFIG(verifypeer)) {
failf(data, "server certificate not activated yet.");
gnutls_x509_crt_deinit(x509_cert);
return CURLE_PEER_FAILED_VERIFICATION;
@@ -1190,7 +1230,8 @@ gtls_connect_step3(struct connectdata *conn,
infof(data, "\t server certificate activation date OK\n");
}
- ptr = data->set.str[STRING_SSL_PINNEDPUBLICKEY];
+ ptr = SSL_IS_PROXY() ? data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
if(ptr) {
result = pkp_pin_peer_pubkey(data, x509_cert, ptr);
if(result != CURLE_OK) {
@@ -1270,7 +1311,7 @@ gtls_connect_step3(struct connectdata *conn,
conn->recv[sockindex] = gtls_recv;
conn->send[sockindex] = gtls_send;
- if(conn->ssl_config.sessionid) {
+ if(data->set.general_ssl.sessionid) {
/* we always unconditionally get the session id here, as even if we
already got it from the cache and asked to use it in the connection, it
might've been rejected and then a new one is in use now and we need to
@@ -1289,7 +1330,8 @@ gtls_connect_step3(struct connectdata *conn,
gnutls_session_get_data(session, connect_sessionid, &connect_idsize);
Curl_ssl_sessionid_lock(conn);
- incache = !(Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL));
+ incache = !(Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL,
+ sockindex));
if(incache) {
/* there was one before in the cache, so instead of risking that the
previous one was rejected, we just kill that and store the new */
@@ -1297,7 +1339,8 @@ gtls_connect_step3(struct connectdata *conn,
}
/* store this session id */
- result = Curl_ssl_addsessionid(conn, connect_sessionid, connect_idsize);
+ result = Curl_ssl_addsessionid(conn, connect_sessionid, connect_idsize,
+ sockindex);
Curl_ssl_sessionid_unlock(conn);
if(result) {
free(connect_sessionid);
@@ -1332,7 +1375,7 @@ gtls_connect_common(struct connectdata *conn,
/* Initiate the connection, if not already done */
if(ssl_connect_1==connssl->connecting_state) {
- rc = gtls_connect_step1 (conn, sockindex);
+ rc = gtls_connect_step1(conn, sockindex);
if(rc)
return rc;
}
@@ -1379,6 +1422,20 @@ Curl_gtls_connect(struct connectdata *conn,
return CURLE_OK;
}
+bool Curl_gtls_data_pending(const struct connectdata *conn, int connindex)
+{
+ bool res = FALSE;
+ if(conn->ssl[connindex].session &&
+ 0 != gnutls_record_check_pending(conn->ssl[connindex].session))
+ res = TRUE;
+
+ if(conn->proxy_ssl[connindex].session &&
+ 0 != gnutls_record_check_pending(conn->proxy_ssl[connindex].session))
+ res = TRUE;
+
+ return res;
+}
+
static ssize_t gtls_send(struct connectdata *conn,
int sockindex,
const void *mem,
@@ -1398,29 +1455,29 @@ static ssize_t gtls_send(struct connectdata *conn,
return rc;
}
-static void close_one(struct connectdata *conn,
- int idx)
+static void close_one(struct ssl_connect_data *ssl)
{
- if(conn->ssl[idx].session) {
- gnutls_bye(conn->ssl[idx].session, GNUTLS_SHUT_RDWR);
- gnutls_deinit(conn->ssl[idx].session);
- conn->ssl[idx].session = NULL;
+ if(ssl->session) {
+ gnutls_bye(ssl->session, GNUTLS_SHUT_RDWR);
+ gnutls_deinit(ssl->session);
+ ssl->session = NULL;
}
- if(conn->ssl[idx].cred) {
- gnutls_certificate_free_credentials(conn->ssl[idx].cred);
- conn->ssl[idx].cred = NULL;
+ if(ssl->cred) {
+ gnutls_certificate_free_credentials(ssl->cred);
+ ssl->cred = NULL;
}
#ifdef USE_TLS_SRP
- if(conn->ssl[idx].srp_client_cred) {
- gnutls_srp_free_client_credentials(conn->ssl[idx].srp_client_cred);
- conn->ssl[idx].srp_client_cred = NULL;
+ if(ssl->srp_client_cred) {
+ gnutls_srp_free_client_credentials(ssl->srp_client_cred);
+ ssl->srp_client_cred = NULL;
}
#endif
}
void Curl_gtls_close(struct connectdata *conn, int sockindex)
{
- close_one(conn, sockindex);
+ close_one(&conn->ssl[sockindex]);
+ close_one(&conn->proxy_ssl[sockindex]);
}
/*
@@ -1486,8 +1543,8 @@ int Curl_gtls_shutdown(struct connectdata *conn, int sockindex)
gnutls_certificate_free_credentials(conn->ssl[sockindex].cred);
#ifdef USE_TLS_SRP
- if(data->set.ssl.authtype == CURL_TLSAUTH_SRP
- && data->set.ssl.username != NULL)
+ if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP
+ && SSL_SET_OPTION(username) != NULL)
gnutls_srp_free_client_credentials(conn->ssl[sockindex].srp_client_cred);
#endif
@@ -1597,7 +1654,7 @@ void Curl_gtls_md5sum(unsigned char *tmp, /* input */
gcry_md_hd_t MD5pw;
gcry_md_open(&MD5pw, GCRY_MD_MD5, 0);
gcry_md_write(MD5pw, tmp, tmplen);
- memcpy(md5sum, gcry_md_read (MD5pw, 0), md5len);
+ memcpy(md5sum, gcry_md_read(MD5pw, 0), md5len);
gcry_md_close(MD5pw);
#endif
}
@@ -1616,7 +1673,7 @@ void Curl_gtls_sha256sum(const unsigned char *tmp, /* input */
gcry_md_hd_t SHA256pw;
gcry_md_open(&SHA256pw, GCRY_MD_SHA256, 0);
gcry_md_write(SHA256pw, tmp, tmplen);
- memcpy(sha256sum, gcry_md_read (SHA256pw, 0), sha256len);
+ memcpy(sha256sum, gcry_md_read(SHA256pw, 0), sha256len);
gcry_md_close(SHA256pw);
#endif
}
diff --git a/Utilities/cmcurl/lib/vtls/gtls.h b/Utilities/cmcurl/lib/vtls/gtls.h
index e0a95a7cc0..65312017ed 100644
--- a/Utilities/cmcurl/lib/vtls/gtls.h
+++ b/Utilities/cmcurl/lib/vtls/gtls.h
@@ -34,6 +34,8 @@ CURLcode Curl_gtls_connect(struct connectdata *conn, int sockindex);
CURLcode Curl_gtls_connect_nonblocking(struct connectdata *conn,
int sockindex,
bool *done);
+bool Curl_gtls_data_pending(const struct connectdata *conn,
+ int connindex);
/* close a SSL connection */
void Curl_gtls_close(struct connectdata *conn, int sockindex);
@@ -55,6 +57,9 @@ void Curl_gtls_sha256sum(const unsigned char *tmp, /* input */
bool Curl_gtls_cert_status_request(void);
+/* Support HTTPS-proxy */
+#define HTTPS_PROXY_SUPPORT 1
+
/* Set the API backend definition to GnuTLS */
#define CURL_SSL_BACKEND CURLSSLBACKEND_GNUTLS
@@ -81,7 +86,7 @@ bool Curl_gtls_cert_status_request(void);
#define curlssl_engines_list(x) ((void)x, (struct curl_slist *)NULL)
#define curlssl_version Curl_gtls_version
#define curlssl_check_cxn(x) ((void)x, -1)
-#define curlssl_data_pending(x,y) ((void)x, (void)y, 0)
+#define curlssl_data_pending(x,y) Curl_gtls_data_pending(x,y)
#define curlssl_random(x,y,z) Curl_gtls_random(x,y,z)
#define curlssl_md5sum(a,b,c,d) Curl_gtls_md5sum(a,b,c,d)
#define curlssl_sha256sum(a,b,c,d) Curl_gtls_sha256sum(a,b,c,d)
diff --git a/Utilities/cmcurl/lib/vtls/mbedtls.c b/Utilities/cmcurl/lib/vtls/mbedtls.c
index 24249dd65c..8bcaddd25a 100644
--- a/Utilities/cmcurl/lib/vtls/mbedtls.c
+++ b/Utilities/cmcurl/lib/vtls/mbedtls.c
@@ -31,11 +31,15 @@
#ifdef USE_MBEDTLS
+#include <mbedtls/version.h>
+#if MBEDTLS_VERSION_NUMBER >= 0x02040000
#include <mbedtls/net_sockets.h>
+#else
+#include <mbedtls/net.h>
+#endif
#include <mbedtls/ssl.h>
#include <mbedtls/certs.h>
#include <mbedtls/x509.h>
-#include <mbedtls/version.h>
#include <mbedtls/error.h>
#include <mbedtls/entropy.h>
@@ -159,13 +163,20 @@ mbed_connect_step1(struct connectdata *conn,
{
struct Curl_easy *data = conn->data;
struct ssl_connect_data* connssl = &conn->ssl[sockindex];
-
+ const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile);
+ const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
+ const char * const ssl_capath = SSL_CONN_CONFIG(CApath);
+ char * const ssl_cert = SSL_SET_OPTION(cert);
+ const char * const ssl_crlfile = SSL_SET_OPTION(CRLfile);
+ const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
+ conn->host.name;
+ const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port;
int ret = -1;
char errorbuf[128];
errorbuf[0]=0;
/* mbedTLS only supports SSLv3 and TLSv1 */
- if(data->set.ssl.version == CURL_SSLVERSION_SSLv2) {
+ if(SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv2) {
failf(data, "mbedTLS does not support SSLv2");
return CURLE_SSL_CONNECT_ERROR;
}
@@ -201,34 +212,32 @@ mbed_connect_step1(struct connectdata *conn,
/* Load the trusted CA */
mbedtls_x509_crt_init(&connssl->cacert);
- if(data->set.str[STRING_SSL_CAFILE]) {
- ret = mbedtls_x509_crt_parse_file(&connssl->cacert,
- data->set.str[STRING_SSL_CAFILE]);
+ if(ssl_cafile) {
+ ret = mbedtls_x509_crt_parse_file(&connssl->cacert, ssl_cafile);
if(ret<0) {
#ifdef MBEDTLS_ERROR_C
mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
#endif /* MBEDTLS_ERROR_C */
failf(data, "Error reading ca cert file %s - mbedTLS: (-0x%04X) %s",
- data->set.str[STRING_SSL_CAFILE], -ret, errorbuf);
+ ssl_cafile, -ret, errorbuf);
- if(data->set.ssl.verifypeer)
+ if(verifypeer)
return CURLE_SSL_CACERT_BADFILE;
}
}
- if(data->set.str[STRING_SSL_CAPATH]) {
- ret = mbedtls_x509_crt_parse_path(&connssl->cacert,
- data->set.str[STRING_SSL_CAPATH]);
+ if(ssl_capath) {
+ ret = mbedtls_x509_crt_parse_path(&connssl->cacert, ssl_capath);
if(ret<0) {
#ifdef MBEDTLS_ERROR_C
mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
#endif /* MBEDTLS_ERROR_C */
failf(data, "Error reading ca cert path %s - mbedTLS: (-0x%04X) %s",
- data->set.str[STRING_SSL_CAPATH], -ret, errorbuf);
+ ssl_capath, -ret, errorbuf);
- if(data->set.ssl.verifypeer)
+ if(verifypeer)
return CURLE_SSL_CACERT_BADFILE;
}
}
@@ -236,16 +245,15 @@ mbed_connect_step1(struct connectdata *conn,
/* Load the client certificate */
mbedtls_x509_crt_init(&connssl->clicert);
- if(data->set.str[STRING_CERT]) {
- ret = mbedtls_x509_crt_parse_file(&connssl->clicert,
- data->set.str[STRING_CERT]);
+ if(ssl_cert) {
+ ret = mbedtls_x509_crt_parse_file(&connssl->clicert, ssl_cert);
if(ret) {
#ifdef MBEDTLS_ERROR_C
mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
#endif /* MBEDTLS_ERROR_C */
failf(data, "Error reading client cert file %s - mbedTLS: (-0x%04X) %s",
- data->set.str[STRING_CERT], -ret, errorbuf);
+ ssl_cert, -ret, errorbuf);
return CURLE_SSL_CERTPROBLEM;
}
@@ -254,9 +262,9 @@ mbed_connect_step1(struct connectdata *conn,
/* Load the client private key */
mbedtls_pk_init(&connssl->pk);
- if(data->set.str[STRING_KEY]) {
- ret = mbedtls_pk_parse_keyfile(&connssl->pk, data->set.str[STRING_KEY],
- data->set.str[STRING_KEY_PASSWD]);
+ if(SSL_SET_OPTION(key)) {
+ ret = mbedtls_pk_parse_keyfile(&connssl->pk, SSL_SET_OPTION(key),
+ SSL_SET_OPTION(key_passwd));
if(ret == 0 && !mbedtls_pk_can_do(&connssl->pk, MBEDTLS_PK_RSA))
ret = MBEDTLS_ERR_PK_TYPE_MISMATCH;
@@ -265,7 +273,7 @@ mbed_connect_step1(struct connectdata *conn,
mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
#endif /* MBEDTLS_ERROR_C */
failf(data, "Error reading private key %s - mbedTLS: (-0x%04X) %s",
- data->set.str[STRING_KEY], -ret, errorbuf);
+ SSL_SET_OPTION(key), -ret, errorbuf);
return CURLE_SSL_CERTPROBLEM;
}
@@ -274,23 +282,21 @@ mbed_connect_step1(struct connectdata *conn,
/* Load the CRL */
mbedtls_x509_crl_init(&connssl->crl);
- if(data->set.str[STRING_SSL_CRLFILE]) {
- ret = mbedtls_x509_crl_parse_file(&connssl->crl,
- data->set.str[STRING_SSL_CRLFILE]);
+ if(ssl_crlfile) {
+ ret = mbedtls_x509_crl_parse_file(&connssl->crl, ssl_crlfile);
if(ret) {
#ifdef MBEDTLS_ERROR_C
mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
#endif /* MBEDTLS_ERROR_C */
failf(data, "Error reading CRL file %s - mbedTLS: (-0x%04X) %s",
- data->set.str[STRING_SSL_CRLFILE], -ret, errorbuf);
+ ssl_crlfile, -ret, errorbuf);
return CURLE_SSL_CRL_BADFILE;
}
}
- infof(data, "mbedTLS: Connecting to %s:%d\n",
- conn->host.name, conn->remote_port);
+ infof(data, "mbedTLS: Connecting to %s:%d\n", hostname, port);
mbedtls_ssl_config_init(&connssl->config);
@@ -312,7 +318,7 @@ mbed_connect_step1(struct connectdata *conn,
mbedtls_ssl_conf_cert_profile(&connssl->config,
&mbedtls_x509_crt_profile_fr);
- switch(data->set.ssl.version) {
+ switch(SSL_CONN_CONFIG(version)) {
case CURL_SSLVERSION_DEFAULT:
case CURL_SSLVERSION_TLSv1:
mbedtls_ssl_conf_min_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3,
@@ -347,8 +353,11 @@ mbed_connect_step1(struct connectdata *conn,
MBEDTLS_SSL_MINOR_VERSION_3);
infof(data, "mbedTLS: Set SSL version to TLS 1.2\n");
break;
+ case CURL_SSLVERSION_TLSv1_3:
+ failf(data, "mbedTLS: TLS 1.3 is not yet supported");
+ return CURLE_SSL_CONNECT_ERROR;
default:
- failf(data, "mbedTLS: Unsupported SSL protocol version");
+ failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
return CURLE_SSL_CONNECT_ERROR;
}
@@ -365,11 +374,11 @@ mbed_connect_step1(struct connectdata *conn,
mbedtls_ssl_list_ciphersuites());
/* Check if there's a cached ID we can/should use here! */
- if(conn->ssl_config.sessionid) {
+ if(data->set.general_ssl.sessionid) {
void *old_session = NULL;
Curl_ssl_sessionid_lock(conn);
- if(!Curl_ssl_getsessionid(conn, &old_session, NULL)) {
+ if(!Curl_ssl_getsessionid(conn, &old_session, NULL, sockindex)) {
ret = mbedtls_ssl_set_session(&connssl->ssl, old_session);
if(ret) {
Curl_ssl_sessionid_unlock(conn);
@@ -385,11 +394,11 @@ mbed_connect_step1(struct connectdata *conn,
&connssl->cacert,
&connssl->crl);
- if(data->set.str[STRING_KEY]) {
+ if(SSL_SET_OPTION(key)) {
mbedtls_ssl_conf_own_cert(&connssl->config,
&connssl->clicert, &connssl->pk);
}
- if(mbedtls_ssl_set_hostname(&connssl->ssl, conn->host.name)) {
+ if(mbedtls_ssl_set_hostname(&connssl->ssl, hostname)) {
/* mbedtls_ssl_set_hostname() sets the name to use in CN/SAN checks *and*
the name to set in the SNI extension. So even if curl connects to a
host specified as an IP address, this function must be used. */
@@ -443,9 +452,12 @@ mbed_connect_step2(struct connectdata *conn,
struct Curl_easy *data = conn->data;
struct ssl_connect_data* connssl = &conn->ssl[sockindex];
const mbedtls_x509_crt *peercert;
+ const char * const pinnedpubkey = SSL_IS_PROXY() ?
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
#ifdef HAS_ALPN
- const char* next_protocol;
+ const char *next_protocol;
#endif
char errorbuf[128];
@@ -479,7 +491,7 @@ mbed_connect_step2(struct connectdata *conn,
ret = mbedtls_ssl_get_verify_result(&conn->ssl[sockindex].ssl);
- if(ret && data->set.ssl.verifypeer) {
+ if(ret && SSL_CONN_CONFIG(verifypeer)) {
if(ret & MBEDTLS_X509_BADCERT_EXPIRED)
failf(data, "Cert verify failed: BADCERT_EXPIRED");
@@ -514,7 +526,7 @@ mbed_connect_step2(struct connectdata *conn,
free(buffer);
}
- if(data->set.str[STRING_SSL_PINNEDPUBLICKEY]) {
+ if(pinnedpubkey) {
int size;
CURLcode result;
mbedtls_x509_crt *p;
@@ -553,7 +565,7 @@ mbed_connect_step2(struct connectdata *conn,
/* mbedtls_pk_write_pubkey_der writes data at the end of the buffer. */
result = Curl_pin_peer_pubkey(data,
- data->set.str[STRING_SSL_PINNEDPUBLICKEY],
+ pinnedpubkey,
&pubkey[PUB_DER_MAX_BYTES - size], size);
if(result) {
mbedtls_x509_crt_free(p);
@@ -606,7 +618,7 @@ mbed_connect_step3(struct connectdata *conn,
DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
- if(conn->ssl_config.sessionid) {
+ if(data->set.general_ssl.sessionid) {
int ret;
mbedtls_ssl_session *our_ssl_sessionid;
void *old_ssl_sessionid = NULL;
@@ -625,10 +637,10 @@ mbed_connect_step3(struct connectdata *conn,
/* If there's already a matching session in the cache, delete it */
Curl_ssl_sessionid_lock(conn);
- if(!Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL))
+ if(!Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL, sockindex))
Curl_ssl_delsessionid(conn, old_ssl_sessionid);
- retcode = Curl_ssl_addsessionid(conn, our_ssl_sessionid, 0);
+ retcode = Curl_ssl_addsessionid(conn, our_ssl_sessionid, 0, sockindex);
Curl_ssl_sessionid_unlock(conn);
if(retcode) {
free(our_ssl_sessionid);
diff --git a/Utilities/cmcurl/lib/vtls/nss.c b/Utilities/cmcurl/lib/vtls/nss.c
index dff15758f7..ba8d58260b 100644
--- a/Utilities/cmcurl/lib/vtls/nss.c
+++ b/Utilities/cmcurl/lib/vtls/nss.c
@@ -200,14 +200,14 @@ static const cipher_s cipherlist[] = {
#endif
};
-static const char* pem_library = "libnsspem.so";
-static SECMODModule* mod = NULL;
+static const char *pem_library = "libnsspem.so";
+static SECMODModule *mod = NULL;
/* NSPR I/O layer we use to detect blocking direction during SSL handshake */
static PRDescIdentity nspr_io_identity = PR_INVALID_IO_LAYER;
static PRIOMethods nspr_io_methods;
-static const char* nss_error_to_name(PRErrorCode code)
+static const char *nss_error_to_name(PRErrorCode code)
{
const char *name = PR_ErrorToName(code);
if(name)
@@ -254,7 +254,8 @@ static SECStatus set_ciphers(struct Curl_easy *data, PRFileDesc * model,
while((*cipher) && (ISSPACE(*cipher)))
++cipher;
- if((cipher_list = strchr(cipher, ','))) {
+ cipher_list = strchr(cipher, ',');
+ if(cipher_list) {
*cipher_list++ = '\0';
}
@@ -337,9 +338,8 @@ static int is_file(const char *filename)
* should be later deallocated using free(). If the OOM failure occurs, we
* return NULL, too.
*/
-static char* dup_nickname(struct Curl_easy *data, enum dupstring cert_kind)
+static char *dup_nickname(struct Curl_easy *data, const char *str)
{
- const char *str = data->set.str[cert_kind];
const char *n;
if(!is_file(str))
@@ -514,7 +514,7 @@ static CURLcode nss_cache_crl(SECItem *crl_der)
return CURLE_OK;
}
-static CURLcode nss_load_crl(const char* crlfilename)
+static CURLcode nss_load_crl(const char *crlfilename)
{
PRFileDesc *infile;
PRFileInfo info;
@@ -540,7 +540,7 @@ static CURLcode nss_load_crl(const char* crlfilename)
goto fail;
/* place a trailing zero right after the visible data */
- body = (char*)filedata.data;
+ body = (char *)filedata.data;
body[--filedata.len] = '\0';
body = strstr(body, "-----BEGIN");
@@ -585,6 +585,7 @@ static CURLcode nss_load_key(struct connectdata *conn, int sockindex,
SECStatus status;
CURLcode result;
struct ssl_connect_data *ssl = conn->ssl;
+ struct Curl_easy *data = conn->data;
(void)sockindex; /* unused */
@@ -602,8 +603,7 @@ static CURLcode nss_load_key(struct connectdata *conn, int sockindex,
SECMOD_WaitForAnyTokenEvent(mod, 0, 0);
PK11_IsPresent(slot);
- status = PK11_Authenticate(slot, PR_TRUE,
- conn->data->set.str[STRING_KEY_PASSWD]);
+ status = PK11_Authenticate(slot, PR_TRUE, SSL_SET_OPTION(key_passwd));
PK11_FreeSlot(slot);
return (SECSuccess == status) ? CURLE_OK : CURLE_SSL_CERTPROBLEM;
@@ -664,7 +664,7 @@ static CURLcode cert_stuff(struct connectdata *conn, int sockindex,
return CURLE_OK;
}
-static char * nss_get_password(PK11SlotInfo * slot, PRBool retry, void *arg)
+static char *nss_get_password(PK11SlotInfo *slot, PRBool retry, void *arg)
{
(void)slot; /* unused */
@@ -682,7 +682,7 @@ static SECStatus nss_auth_cert_hook(void *arg, PRFileDesc *fd, PRBool checksig,
struct connectdata *conn = (struct connectdata *)arg;
#ifdef SSL_ENABLE_OCSP_STAPLING
- if(conn->data->set.ssl.verifystatus) {
+ if(SSL_CONN_CONFIG(verifystatus)) {
SECStatus cacheResult;
const SECItemArray *csa = SSL_PeerStapledOCSPResponses(fd);
@@ -708,7 +708,7 @@ static SECStatus nss_auth_cert_hook(void *arg, PRFileDesc *fd, PRBool checksig,
}
#endif
- if(!conn->data->set.ssl.verifypeer) {
+ if(!SSL_CONN_CONFIG(verifypeer)) {
infof(conn->data, "skipping SSL peer certificate verification\n");
return SECSuccess;
}
@@ -734,6 +734,11 @@ static void HandshakeCallback(PRFileDesc *sock, void *arg)
if(SSL_GetNextProto(sock, &state, buf, &buflen, buflenmax) == SECSuccess) {
switch(state) {
+#if NSSVERNUM >= 0x031a00 /* 3.26.0 */
+ /* used by NSS internally to implement 0-RTT */
+ case SSL_NEXT_PROTO_EARLY_VALUE:
+ /* fall through! */
+#endif
case SSL_NEXT_PROTO_NO_SUPPORT:
case SSL_NEXT_PROTO_NO_OVERLAP:
infof(conn->data, "ALPN/NPN, server did not agree to a protocol\n");
@@ -928,9 +933,12 @@ static SECStatus BadCertHandler(void *arg, PRFileDesc *sock)
CERTCertificate *cert;
/* remember the cert verification result */
- data->set.ssl.certverifyresult = err;
+ if(SSL_IS_PROXY())
+ data->set.proxy_ssl.certverifyresult = err;
+ else
+ data->set.ssl.certverifyresult = err;
- if(err == SSL_ERROR_BAD_CERT_DOMAIN && !data->set.ssl.verifyhost)
+ if(err == SSL_ERROR_BAD_CERT_DOMAIN && !SSL_CONN_CONFIG(verifyhost))
/* we are asked not to verify the host name */
return SECSuccess;
@@ -1367,36 +1375,55 @@ Curl_nss_check_cxn(struct connectdata *conn)
return -1; /* connection status unknown */
}
+static void nss_close(struct ssl_connect_data *connssl)
+{
+ /* before the cleanup, check whether we are using a client certificate */
+ const bool client_cert = (connssl->client_nickname != NULL)
+ || (connssl->obj_clicert != NULL);
+
+ free(connssl->client_nickname);
+ connssl->client_nickname = NULL;
+
+ /* destroy all NSS objects in order to avoid failure of NSS shutdown */
+ Curl_llist_destroy(connssl->obj_list, NULL);
+ connssl->obj_list = NULL;
+ connssl->obj_clicert = NULL;
+
+ if(connssl->handle) {
+ if(client_cert)
+ /* A server might require different authentication based on the
+ * particular path being requested by the client. To support this
+ * scenario, we must ensure that a connection will never reuse the
+ * authentication data from a previous connection. */
+ SSL_InvalidateSession(connssl->handle);
+
+ PR_Close(connssl->handle);
+ connssl->handle = NULL;
+ }
+}
+
/*
* This function is called when an SSL connection is closed.
*/
void Curl_nss_close(struct connectdata *conn, int sockindex)
{
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl_proxy = &conn->proxy_ssl[sockindex];
- if(connssl->handle) {
+ if(connssl->handle || connssl_proxy->handle) {
/* NSS closes the socket we previously handed to it, so we must mark it
as closed to avoid double close */
fake_sclose(conn->sock[sockindex]);
conn->sock[sockindex] = CURL_SOCKET_BAD;
+ }
- if((connssl->client_nickname != NULL) || (connssl->obj_clicert != NULL))
- /* A server might require different authentication based on the
- * particular path being requested by the client. To support this
- * scenario, we must ensure that a connection will never reuse the
- * authentication data from a previous connection. */
- SSL_InvalidateSession(connssl->handle);
-
- free(connssl->client_nickname);
- connssl->client_nickname = NULL;
- /* destroy all NSS objects in order to avoid failure of NSS shutdown */
- Curl_llist_destroy(connssl->obj_list, NULL);
- connssl->obj_list = NULL;
- connssl->obj_clicert = NULL;
+ if(connssl->handle)
+ /* nss_close(connssl) will transitively close also connssl_proxy->handle
+ if both are used. Clear it to avoid a double close leading to crash. */
+ connssl_proxy->handle = NULL;
- PR_Close(connssl->handle);
- connssl->handle = NULL;
- }
+ nss_close(connssl);
+ nss_close(connssl_proxy);
}
/* return true if NSS can provide error code (and possibly msg) for the
@@ -1437,8 +1464,8 @@ static CURLcode nss_load_ca_certificates(struct connectdata *conn,
int sockindex)
{
struct Curl_easy *data = conn->data;
- const char *cafile = data->set.ssl.CAfile;
- const char *capath = data->set.ssl.CApath;
+ const char *cafile = SSL_CONN_CONFIG(CAfile);
+ const char *capath = SSL_CONN_CONFIG(CApath);
if(cafile) {
CURLcode result = nss_load_cert(&conn->ssl[sockindex], cafile, PR_TRUE);
@@ -1486,13 +1513,22 @@ static CURLcode nss_load_ca_certificates(struct connectdata *conn,
}
static CURLcode nss_init_sslver(SSLVersionRange *sslver,
- struct Curl_easy *data)
+ struct Curl_easy *data,
+ struct connectdata *conn)
{
- switch(data->set.ssl.version) {
- default:
+ switch(SSL_CONN_CONFIG(version)) {
case CURL_SSLVERSION_DEFAULT:
+ /* map CURL_SSLVERSION_DEFAULT to NSS default */
+ if(SSL_VersionRangeGetDefault(ssl_variant_stream, sslver) != SECSuccess)
+ return CURLE_SSL_CONNECT_ERROR;
+ /* ... but make sure we use at least TLSv1.0 according to libcurl API */
+ if(sslver->min < SSL_LIBRARY_VERSION_TLS_1_0)
+ sslver->min = SSL_LIBRARY_VERSION_TLS_1_0;
+ return CURLE_OK;
+
case CURL_SSLVERSION_TLSv1:
sslver->min = SSL_LIBRARY_VERSION_TLS_1_0;
+ /* TODO: set sslver->max to SSL_LIBRARY_VERSION_TLS_1_3 once stable */
#ifdef SSL_LIBRARY_VERSION_TLS_1_2
sslver->max = SSL_LIBRARY_VERSION_TLS_1_2;
#elif defined SSL_LIBRARY_VERSION_TLS_1_1
@@ -1532,6 +1568,18 @@ static CURLcode nss_init_sslver(SSLVersionRange *sslver,
return CURLE_OK;
#endif
break;
+
+ case CURL_SSLVERSION_TLSv1_3:
+#ifdef SSL_LIBRARY_VERSION_TLS_1_3
+ sslver->min = SSL_LIBRARY_VERSION_TLS_1_3;
+ sslver->max = SSL_LIBRARY_VERSION_TLS_1_3;
+ return CURLE_OK;
+#endif
+ break;
+
+ default:
+ failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
+ return CURLE_SSL_CONNECT_ERROR;
}
failf(data, "TLS minor version cannot be set");
@@ -1589,6 +1637,7 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
curl_socket_t sockfd = conn->sock[sockindex];
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
CURLcode result;
+ bool second_layer = FALSE;
SSLVersionRange sslver = {
SSL_LIBRARY_VERSION_TLS_1_0, /* min */
@@ -1647,18 +1696,18 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
goto error;
/* do not use SSL cache if disabled or we are not going to verify peer */
- ssl_no_cache = (conn->ssl_config.sessionid && data->set.ssl.verifypeer) ?
- PR_FALSE : PR_TRUE;
+ ssl_no_cache = (data->set.general_ssl.sessionid
+ && SSL_CONN_CONFIG(verifypeer)) ? PR_FALSE : PR_TRUE;
if(SSL_OptionSet(model, SSL_NO_CACHE, ssl_no_cache) != SECSuccess)
goto error;
/* enable/disable the requested SSL version(s) */
- if(nss_init_sslver(&sslver, data) != CURLE_OK)
+ if(nss_init_sslver(&sslver, data, conn) != CURLE_OK)
goto error;
if(SSL_VersionRangeSet(model, &sslver) != SECSuccess)
goto error;
- ssl_cbc_random_iv = !data->set.ssl_enable_beast;
+ ssl_cbc_random_iv = !SSL_SET_OPTION(enable_beast);
#ifdef SSL_CBC_RANDOM_IV
/* unless the user explicitly asks to allow the protocol vulnerability, we
use the work-around */
@@ -1670,14 +1719,14 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
infof(data, "warning: support for SSL_CBC_RANDOM_IV not compiled in\n");
#endif
- if(data->set.ssl.cipher_list) {
- if(set_ciphers(data, model, data->set.ssl.cipher_list) != SECSuccess) {
+ if(SSL_CONN_CONFIG(cipher_list)) {
+ if(set_ciphers(data, model, SSL_CONN_CONFIG(cipher_list)) != SECSuccess) {
result = CURLE_SSL_CIPHER;
goto error;
}
}
- if(!data->set.ssl.verifypeer && data->set.ssl.verifyhost)
+ if(!SSL_CONN_CONFIG(verifypeer) && SSL_CONN_CONFIG(verifyhost))
infof(data, "warning: ignoring value of ssl.verifyhost\n");
/* bypass the default SSL_AuthCertificate() hook in case we do not want to
@@ -1685,14 +1734,19 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
if(SSL_AuthCertificateHook(model, nss_auth_cert_hook, conn) != SECSuccess)
goto error;
- data->set.ssl.certverifyresult=0; /* not checked yet */
+ /* not checked yet */
+ if(SSL_IS_PROXY())
+ data->set.proxy_ssl.certverifyresult = 0;
+ else
+ data->set.ssl.certverifyresult = 0;
+
if(SSL_BadCertHook(model, BadCertHandler, conn) != SECSuccess)
goto error;
if(SSL_HandshakeCallback(model, HandshakeCallback, conn) != SECSuccess)
goto error;
- if(data->set.ssl.verifypeer) {
+ if(SSL_CONN_CONFIG(verifypeer)) {
const CURLcode rv = nss_load_ca_certificates(conn, sockindex);
if(rv) {
result = rv;
@@ -1700,24 +1754,24 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
}
}
- if(data->set.ssl.CRLfile) {
- const CURLcode rv = nss_load_crl(data->set.ssl.CRLfile);
+ if(SSL_SET_OPTION(CRLfile)) {
+ const CURLcode rv = nss_load_crl(SSL_SET_OPTION(CRLfile));
if(rv) {
result = rv;
goto error;
}
- infof(data, " CRLfile: %s\n", data->set.ssl.CRLfile);
+ infof(data, " CRLfile: %s\n", SSL_SET_OPTION(CRLfile));
}
- if(data->set.str[STRING_CERT]) {
- char *nickname = dup_nickname(data, STRING_CERT);
+ if(SSL_SET_OPTION(cert)) {
+ char *nickname = dup_nickname(data, SSL_SET_OPTION(cert));
if(nickname) {
/* we are not going to use libnsspem.so to read the client cert */
connssl->obj_clicert = NULL;
}
else {
- CURLcode rv = cert_stuff(conn, sockindex, data->set.str[STRING_CERT],
- data->set.str[STRING_KEY]);
+ CURLcode rv = cert_stuff(conn, sockindex, SSL_SET_OPTION(cert),
+ SSL_SET_OPTION(key));
if(rv) {
/* failf() is already done in cert_stuff() */
result = rv;
@@ -1737,15 +1791,24 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
goto error;
}
- /* wrap OS file descriptor by NSPR's file descriptor abstraction */
- nspr_io = PR_ImportTCPSocket(sockfd);
- if(!nspr_io)
- goto error;
+ if(conn->proxy_ssl[sockindex].use) {
+ DEBUGASSERT(ssl_connection_complete == conn->proxy_ssl[sockindex].state);
+ DEBUGASSERT(conn->proxy_ssl[sockindex].handle != NULL);
+ nspr_io = conn->proxy_ssl[sockindex].handle;
+ second_layer = TRUE;
+ }
+ else {
+ /* wrap OS file descriptor by NSPR's file descriptor abstraction */
+ nspr_io = PR_ImportTCPSocket(sockfd);
+ if(!nspr_io)
+ goto error;
+ }
/* create our own NSPR I/O layer */
nspr_io_stub = PR_CreateIOLayerStub(nspr_io_identity, &nspr_io_methods);
if(!nspr_io_stub) {
- PR_Close(nspr_io);
+ if(!second_layer)
+ PR_Close(nspr_io);
goto error;
}
@@ -1754,7 +1817,8 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
/* push our new layer to the NSPR I/O stack */
if(PR_PushIOLayer(nspr_io, PR_TOP_IO_LAYER, nspr_io_stub) != PR_SUCCESS) {
- PR_Close(nspr_io);
+ if(!second_layer)
+ PR_Close(nspr_io);
PR_Close(nspr_io_stub);
goto error;
}
@@ -1762,7 +1826,8 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
/* import our model socket onto the current I/O stack */
connssl->handle = SSL_ImportFD(model, nspr_io);
if(!connssl->handle) {
- PR_Close(nspr_io);
+ if(!second_layer)
+ PR_Close(nspr_io);
goto error;
}
@@ -1770,12 +1835,12 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
model = NULL;
/* This is the password associated with the cert that we're using */
- if(data->set.str[STRING_KEY_PASSWD]) {
- SSL_SetPKCS11PinArg(connssl->handle, data->set.str[STRING_KEY_PASSWD]);
+ if(SSL_SET_OPTION(key_passwd)) {
+ SSL_SetPKCS11PinArg(connssl->handle, SSL_SET_OPTION(key_passwd));
}
#ifdef SSL_ENABLE_OCSP_STAPLING
- if(data->set.ssl.verifystatus) {
+ if(SSL_CONN_CONFIG(verifystatus)) {
if(SSL_OptionSet(connssl->handle, SSL_ENABLE_OCSP_STAPLING, PR_TRUE)
!= SECSuccess)
goto error;
@@ -1835,11 +1900,14 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
goto error;
/* propagate hostname to the TLS layer */
- if(SSL_SetURL(connssl->handle, conn->host.name) != SECSuccess)
+ if(SSL_SetURL(connssl->handle, SSL_IS_PROXY() ? conn->http_proxy.host.name :
+ conn->host.name) != SECSuccess)
goto error;
/* prevent NSS from re-using the session for a different hostname */
- if(SSL_SetSockPeerID(connssl->handle, conn->host.name) != SECSuccess)
+ if(SSL_SetSockPeerID(connssl->handle, SSL_IS_PROXY() ?
+ conn->http_proxy.host.name : conn->host.name)
+ != SECSuccess)
goto error;
return CURLE_OK;
@@ -1857,6 +1925,12 @@ static CURLcode nss_do_connect(struct connectdata *conn, int sockindex)
struct Curl_easy *data = conn->data;
CURLcode result = CURLE_SSL_CONNECT_ERROR;
PRUint32 timeout;
+ long * const certverifyresult = SSL_IS_PROXY() ?
+ &data->set.proxy_ssl.certverifyresult : &data->set.ssl.certverifyresult;
+ const char * const pinnedpubkey = SSL_IS_PROXY() ?
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
+
/* check timeout situation */
const long time_left = Curl_timeleft(data, NULL, TRUE);
@@ -1872,9 +1946,9 @@ static CURLcode nss_do_connect(struct connectdata *conn, int sockindex)
if(PR_GetError() == PR_WOULD_BLOCK_ERROR)
/* blocking direction is updated by nss_update_connecting_state() */
return CURLE_AGAIN;
- else if(conn->data->set.ssl.certverifyresult == SSL_ERROR_BAD_CERT_DOMAIN)
+ else if(*certverifyresult == SSL_ERROR_BAD_CERT_DOMAIN)
result = CURLE_PEER_FAILED_VERIFICATION;
- else if(conn->data->set.ssl.certverifyresult!=0)
+ else if(*certverifyresult != 0)
result = CURLE_SSL_CACERT;
goto error;
}
@@ -1883,11 +1957,11 @@ static CURLcode nss_do_connect(struct connectdata *conn, int sockindex)
if(result)
goto error;
- if(data->set.str[STRING_SSL_ISSUERCERT]) {
+ if(SSL_SET_OPTION(issuercert)) {
SECStatus ret = SECFailure;
- char *nickname = dup_nickname(data, STRING_SSL_ISSUERCERT);
+ char *nickname = dup_nickname(data, SSL_SET_OPTION(issuercert));
if(nickname) {
- /* we support only nicknames in case of STRING_SSL_ISSUERCERT for now */
+ /* we support only nicknames in case of issuercert for now */
ret = check_issuer_cert(connssl->handle, nickname);
free(nickname);
}
@@ -1902,7 +1976,7 @@ static CURLcode nss_do_connect(struct connectdata *conn, int sockindex)
}
}
- result = cmp_peer_pubkey(connssl, data->set.str[STRING_SSL_PINNEDPUBLICKEY]);
+ result = cmp_peer_pubkey(connssl, pinnedpubkey);
if(result)
/* status already printed */
goto error;
@@ -2112,7 +2186,8 @@ bool Curl_nss_cert_status_request(void)
#endif
}
-bool Curl_nss_false_start(void) {
+bool Curl_nss_false_start(void)
+{
#if NSSVERNUM >= 0x030f04 /* 3.15.4 */
return TRUE;
#else
diff --git a/Utilities/cmcurl/lib/vtls/nssg.h b/Utilities/cmcurl/lib/vtls/nssg.h
index ac67e6ab73..fd94003fb6 100644
--- a/Utilities/cmcurl/lib/vtls/nssg.h
+++ b/Utilities/cmcurl/lib/vtls/nssg.h
@@ -65,6 +65,9 @@ bool Curl_nss_cert_status_request(void);
bool Curl_nss_false_start(void);
+/* Support HTTPS-proxy */
+#define HTTPS_PROXY_SUPPORT 1
+
/* Set the API backend definition to NSS */
#define CURL_SSL_BACKEND CURLSSLBACKEND_NSS
diff --git a/Utilities/cmcurl/lib/vtls/openssl.c b/Utilities/cmcurl/lib/vtls/openssl.c
index c040928a18..d92e71365f 100644
--- a/Utilities/cmcurl/lib/vtls/openssl.c
+++ b/Utilities/cmcurl/lib/vtls/openssl.c
@@ -176,39 +176,34 @@ static int passwd_callback(char *buf, int num, int encrypting,
}
/*
- * rand_enough() is a function that returns TRUE if we have seeded the random
- * engine properly. We use some preprocessor magic to provide a seed_enough()
- * macro to use, just to prevent a compiler warning on this function if we
- * pass in an argument that is never used.
+ * rand_enough() returns TRUE if we have seeded the random engine properly.
*/
-
-#ifdef HAVE_RAND_STATUS
-#define seed_enough(x) rand_enough()
static bool rand_enough(void)
{
return (0 != RAND_status()) ? TRUE : FALSE;
}
-#else
-#define seed_enough(x) rand_enough(x)
-static bool rand_enough(int nread)
-{
- /* this is a very silly decision to make */
- return (nread > 500) ? TRUE : FALSE;
-}
-#endif
-static int ossl_seed(struct Curl_easy *data)
+static CURLcode Curl_ossl_seed(struct Curl_easy *data)
{
+ /* we have the "SSL is seeded" boolean static to prevent multiple
+ time-consuming seedings in vain */
+ static bool ssl_seeded = FALSE;
char *buf = data->state.buffer; /* point to the big buffer */
int nread=0;
- /* Q: should we add support for a random file name as a libcurl option?
- A: Yes, it is here */
+ if(ssl_seeded)
+ return CURLE_OK;
+
+ if(rand_enough()) {
+ /* OpenSSL 1.1.0+ will return here */
+ ssl_seeded = TRUE;
+ return CURLE_OK;
+ }
#ifndef RANDOM_FILE
/* if RANDOM_FILE isn't defined, we only perform this if an option tells
us to! */
- if(data->set.ssl.random_file)
+ if(data->set.str[STRING_SSL_RANDOM_FILE])
#define RANDOM_FILE "" /* doesn't matter won't be used */
#endif
{
@@ -217,7 +212,7 @@ static int ossl_seed(struct Curl_easy *data)
data->set.str[STRING_SSL_RANDOM_FILE]:
RANDOM_FILE),
RAND_LOAD_LENGTH);
- if(seed_enough(nread))
+ if(rand_enough())
return nread;
}
@@ -237,7 +232,7 @@ static int ossl_seed(struct Curl_easy *data)
data->set.str[STRING_SSL_EGDSOCKET]:EGD_SOCKET);
if(-1 != ret) {
nread += ret;
- if(seed_enough(nread))
+ if(rand_enough())
return nread;
}
}
@@ -248,9 +243,10 @@ static int ossl_seed(struct Curl_easy *data)
do {
unsigned char randb[64];
int len = sizeof(randb);
- RAND_bytes(randb, len);
+ if(!RAND_bytes(randb, len))
+ break;
RAND_add(randb, len, (len >> 1));
- } while(!RAND_status());
+ } while(!rand_enough());
/* generates a default path for the random seed file */
buf[0]=0; /* blank it first */
@@ -258,25 +254,12 @@ static int ossl_seed(struct Curl_easy *data)
if(buf[0]) {
/* we got a file name to try */
nread += RAND_load_file(buf, RAND_LOAD_LENGTH);
- if(seed_enough(nread))
+ if(rand_enough())
return nread;
}
infof(data, "libcurl is now using a weak random seed!\n");
- return nread;
-}
-
-static void Curl_ossl_seed(struct Curl_easy *data)
-{
- /* we have the "SSL is seeded" boolean static to prevent multiple
- time-consuming seedings in vain */
- static bool ssl_seeded = FALSE;
-
- if(!ssl_seeded || data->set.str[STRING_SSL_RANDOM_FILE] ||
- data->set.str[STRING_SSL_EGDSOCKET]) {
- ossl_seed(data);
- ssl_seeded = TRUE;
- }
+ return CURLE_SSL_CONNECT_ERROR; /* confusing error code */
}
#ifndef SSL_FILETYPE_ENGINE
@@ -312,7 +295,7 @@ static int ssl_ui_reader(UI *ui, UI_STRING *uis)
switch(UI_get_string_type(uis)) {
case UIT_PROMPT:
case UIT_VERIFY:
- password = (const char*)UI_get0_user_data(ui);
+ password = (const char *)UI_get0_user_data(ui);
if(password && (UI_get_input_flags(uis) & UI_INPUT_FLAG_DEFAULT_PWD)) {
UI_set_result(ui, uis, password);
return 1;
@@ -348,7 +331,8 @@ int cert_stuff(struct connectdata *conn,
char *cert_file,
const char *cert_type,
char *key_file,
- const char *key_type)
+ const char *key_type,
+ char *key_passwd)
{
struct Curl_easy *data = conn->data;
@@ -359,10 +343,9 @@ int cert_stuff(struct connectdata *conn,
X509 *x509;
int cert_done = 0;
- if(data->set.str[STRING_KEY_PASSWD]) {
+ if(key_passwd) {
/* set the password in the callback userdata */
- SSL_CTX_set_default_passwd_cb_userdata(ctx,
- data->set.str[STRING_KEY_PASSWD]);
+ SSL_CTX_set_default_passwd_cb_userdata(ctx, key_passwd);
/* Set passwd callback: */
SSL_CTX_set_default_passwd_cb(ctx, passwd_callback);
}
@@ -473,7 +456,7 @@ int cert_stuff(struct connectdata *conn,
PKCS12_PBE_add();
- if(!PKCS12_parse(p12, data->set.str[STRING_KEY_PASSWD], &pri, &x509,
+ if(!PKCS12_parse(p12, key_passwd, &pri, &x509,
&ca)) {
failf(data,
"could not parse PKCS12 file, check password, " OSSL_PACKAGE
@@ -571,7 +554,7 @@ int cert_stuff(struct connectdata *conn,
EVP_PKEY *priv_key = NULL;
if(data->state.engine) {
UI_METHOD *ui_method =
- UI_create_method((char *)"cURL user interface");
+ UI_create_method((char *)"curl user interface");
if(!ui_method) {
failf(data, "unable do create " OSSL_PACKAGE
" user-interface method");
@@ -585,7 +568,7 @@ int cert_stuff(struct connectdata *conn,
priv_key = (EVP_PKEY *)
ENGINE_load_private_key(data->state.engine, key_file,
ui_method,
- data->set.str[STRING_KEY_PASSWD]);
+ key_passwd);
UI_destroy_method(ui_method);
if(!priv_key) {
failf(data, "failed to load private key from crypto engine");
@@ -916,27 +899,31 @@ struct curl_slist *Curl_ossl_engines_list(struct Curl_easy *data)
}
-/*
- * This function is called when an SSL connection is closed.
- */
-void Curl_ossl_close(struct connectdata *conn, int sockindex)
+static void ossl_close(struct ssl_connect_data *connssl)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
-
if(connssl->handle) {
(void)SSL_shutdown(connssl->handle);
SSL_set_connect_state(connssl->handle);
- SSL_free (connssl->handle);
+ SSL_free(connssl->handle);
connssl->handle = NULL;
}
if(connssl->ctx) {
- SSL_CTX_free (connssl->ctx);
+ SSL_CTX_free(connssl->ctx);
connssl->ctx = NULL;
}
}
/*
+ * This function is called when an SSL connection is closed.
+ */
+void Curl_ossl_close(struct connectdata *conn, int sockindex)
+{
+ ossl_close(&conn->ssl[sockindex]);
+ ossl_close(&conn->proxy_ssl[sockindex]);
+}
+
+/*
* This function is called to shut down the SSL layer but keep the
* socket open (CCC - Clear Command Channel)
*/
@@ -1031,7 +1018,7 @@ int Curl_ossl_shutdown(struct connectdata *conn, int sockindex)
#endif
}
- SSL_free (connssl->handle);
+ SSL_free(connssl->handle);
connssl->handle = NULL;
}
return retval;
@@ -1107,16 +1094,20 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert)
CURLcode result = CURLE_OK;
bool dNSName = FALSE; /* if a dNSName field exists in the cert */
bool iPAddress = FALSE; /* if a iPAddress field exists in the cert */
+ const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
+ conn->host.name;
+ const char * const dispname = SSL_IS_PROXY() ?
+ conn->http_proxy.host.dispname : conn->host.dispname;
#ifdef ENABLE_IPV6
if(conn->bits.ipv6_ip &&
- Curl_inet_pton(AF_INET6, conn->host.name, &addr)) {
+ Curl_inet_pton(AF_INET6, hostname, &addr)) {
target = GEN_IPADD;
addrlen = sizeof(struct in6_addr);
}
else
#endif
- if(Curl_inet_pton(AF_INET, conn->host.name, &addr)) {
+ if(Curl_inet_pton(AF_INET, hostname, &addr)) {
target = GEN_IPADD;
addrlen = sizeof(struct in_addr);
}
@@ -1165,11 +1156,11 @@ 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, conn->host.name)) {
+ Curl_cert_hostcheck(altptr, hostname)) {
dnsmatched = TRUE;
infof(data,
" subjectAltName: host \"%s\" matched cert's \"%s\"\n",
- conn->host.dispname, altptr);
+ dispname, altptr);
}
break;
@@ -1180,7 +1171,7 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert)
ipmatched = TRUE;
infof(data,
" subjectAltName: host \"%s\" matched cert's IP address!\n",
- conn->host.dispname);
+ dispname);
}
break;
}
@@ -1196,9 +1187,9 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert)
/* an alternative name matched */
;
else if(dNSName || iPAddress) {
- infof(data, " subjectAltName does not match %s\n", conn->host.dispname);
+ infof(data, " subjectAltName does not match %s\n", dispname);
failf(data, "SSL: no alternative certificate subject name matches "
- "target host name '%s'", conn->host.dispname);
+ "target host name '%s'", dispname);
result = CURLE_PEER_FAILED_VERIFICATION;
}
else {
@@ -1272,9 +1263,9 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert)
"SSL: unable to obtain common name from peer certificate");
result = CURLE_PEER_FAILED_VERIFICATION;
}
- else if(!Curl_cert_hostcheck((const char *)peer_CN, conn->host.name)) {
+ else if(!Curl_cert_hostcheck((const char *)peer_CN, hostname)) {
failf(data, "SSL: certificate subject name '%s' does not match "
- "target host name '%s'", peer_CN, conn->host.dispname);
+ "target host name '%s'", peer_CN, dispname);
result = CURLE_PEER_FAILED_VERIFICATION;
}
else {
@@ -1425,7 +1416,7 @@ static const char *ssl_msg_type(int ssl_ver, int msg)
{
#ifdef SSL2_VERSION_MAJOR
if(ssl_ver == SSL2_VERSION_MAJOR) {
- switch (msg) {
+ switch(msg) {
case SSL2_MT_ERROR:
return "Error";
case SSL2_MT_CLIENT_HELLO:
@@ -1449,7 +1440,7 @@ static const char *ssl_msg_type(int ssl_ver, int msg)
else
#endif
if(ssl_ver == SSL3_VERSION_MAJOR) {
- switch (msg) {
+ switch(msg) {
case SSL3_MT_HELLO_REQUEST:
return "Hello request";
case SSL3_MT_CLIENT_HELLO:
@@ -1549,6 +1540,11 @@ static void ssl_tls_trace(int direction, int ssl_ver, int content_type,
verstr = "TLSv1.2";
break;
#endif
+#ifdef TLS1_3_VERSION
+ case TLS1_3_VERSION:
+ verstr = "TLSv1.3";
+ break;
+#endif
case 0:
break;
default:
@@ -1571,7 +1567,7 @@ static void ssl_tls_trace(int direction, int ssl_ver, int content_type,
else
tls_rt_name = "";
- msg_type = *(char*)buf;
+ 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",
@@ -1677,6 +1673,10 @@ get_ssl_version_txt(SSL *ssl)
return "";
switch(SSL_version(ssl)) {
+#ifdef TLS1_3_VERSION
+ case TLS1_3_VERSION:
+ return "TLSv1.3";
+#endif
#if OPENSSL_VERSION_NUMBER >= 0x1000100FL
case TLS1_2_VERSION:
return "TLSv1.2";
@@ -1711,23 +1711,39 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
struct in_addr addr;
#endif
#endif
+ long * const certverifyresult = SSL_IS_PROXY() ?
+ &data->set.proxy_ssl.certverifyresult : &data->set.ssl.certverifyresult;
+ const long int ssl_version = SSL_CONN_CONFIG(version);
+#ifdef USE_TLS_SRP
+ const enum CURL_TLSAUTH ssl_authtype = SSL_SET_OPTION(authtype);
+#endif
+ char * const ssl_cert = SSL_SET_OPTION(cert);
+ const char * const ssl_cert_type = SSL_SET_OPTION(cert_type);
+ const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile);
+ const char * const ssl_capath = SSL_CONN_CONFIG(CApath);
+ const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
+ const char * const ssl_crlfile = SSL_SET_OPTION(CRLfile);
+ const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
+ conn->host.name;
DEBUGASSERT(ssl_connect_1 == connssl->connecting_state);
/* Make funny stuff to get random input */
- Curl_ossl_seed(data);
+ result = Curl_ossl_seed(data);
+ if(result)
+ return result;
- data->set.ssl.certverifyresult = !X509_V_OK;
+ *certverifyresult = !X509_V_OK;
/* check to see if we've been told to use an explicit SSL/TLS version */
- switch(data->set.ssl.version) {
- default:
+ switch(ssl_version) {
case CURL_SSLVERSION_DEFAULT:
case CURL_SSLVERSION_TLSv1:
case CURL_SSLVERSION_TLSv1_0:
case CURL_SSLVERSION_TLSv1_1:
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)
@@ -1743,7 +1759,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
return CURLE_NOT_BUILT_IN;
#else
#ifdef USE_TLS_SRP
- if(data->set.ssl.authtype == CURL_TLSAUTH_SRP)
+ if(ssl_authtype == CURL_TLSAUTH_SRP)
return CURLE_SSL_CONNECT_ERROR;
#endif
req_method = SSLv2_client_method();
@@ -1756,13 +1772,16 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
return CURLE_NOT_BUILT_IN;
#else
#ifdef USE_TLS_SRP
- if(data->set.ssl.authtype == CURL_TLSAUTH_SRP)
+ if(ssl_authtype == CURL_TLSAUTH_SRP)
return CURLE_SSL_CONNECT_ERROR;
#endif
req_method = SSLv3_client_method();
use_sni(FALSE);
break;
#endif
+ default:
+ failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
+ return CURLE_SSL_CONNECT_ERROR;
}
if(connssl->ctx)
@@ -1841,14 +1860,14 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
/* unless the user explicitly ask to allow the protocol vulnerability we
use the work-around */
- if(!conn->data->set.ssl_enable_beast)
+ if(!SSL_SET_OPTION(enable_beast))
ctx_options &= ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
#endif
- switch(data->set.ssl.version) {
+ switch(ssl_version) {
case CURL_SSLVERSION_SSLv3:
#ifdef USE_TLS_SRP
- if(data->set.ssl.authtype == CURL_TLSAUTH_SRP) {
+ if(ssl_authtype == CURL_TLSAUTH_SRP) {
infof(data, "Set version TLSv1.x for SRP authorisation\n");
}
#endif
@@ -1857,6 +1876,9 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
#if OPENSSL_VERSION_NUMBER >= 0x1000100FL
ctx_options |= SSL_OP_NO_TLSv1_1;
ctx_options |= SSL_OP_NO_TLSv1_2;
+#ifdef TLS1_3_VERSION
+ ctx_options |= SSL_OP_NO_TLSv1_3;
+#endif
#endif
break;
@@ -1872,38 +1894,75 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
#if OPENSSL_VERSION_NUMBER >= 0x1000100FL
ctx_options |= SSL_OP_NO_TLSv1_1;
ctx_options |= SSL_OP_NO_TLSv1_2;
+#ifdef TLS1_3_VERSION
+ ctx_options |= SSL_OP_NO_TLSv1_3;
+#endif
#endif
break;
-#if OPENSSL_VERSION_NUMBER >= 0x1000100FL
case CURL_SSLVERSION_TLSv1_1:
+#if OPENSSL_VERSION_NUMBER >= 0x1000100FL
ctx_options |= SSL_OP_NO_SSLv2;
ctx_options |= SSL_OP_NO_SSLv3;
ctx_options |= SSL_OP_NO_TLSv1;
ctx_options |= SSL_OP_NO_TLSv1_2;
+#ifdef TLS1_3_VERSION
+ ctx_options |= SSL_OP_NO_TLSv1_3;
+#endif
break;
+#else
+ failf(data, OSSL_PACKAGE " was built without TLS 1.1 support");
+ return CURLE_NOT_BUILT_IN;
+#endif
case CURL_SSLVERSION_TLSv1_2:
+#if OPENSSL_VERSION_NUMBER >= 0x1000100FL
ctx_options |= SSL_OP_NO_SSLv2;
ctx_options |= SSL_OP_NO_SSLv3;
ctx_options |= SSL_OP_NO_TLSv1;
ctx_options |= SSL_OP_NO_TLSv1_1;
+#ifdef TLS1_3_VERSION
+ ctx_options |= SSL_OP_NO_TLSv1_3;
+#endif
break;
+#else
+ failf(data, OSSL_PACKAGE " was built without TLS 1.2 support");
+ return CURLE_NOT_BUILT_IN;
+#endif
+
+ case CURL_SSLVERSION_TLSv1_3:
+#ifdef TLS1_3_VERSION
+ SSL_CTX_set_max_proto_version(connssl->ctx, TLS1_3_VERSION);
+ ctx_options |= SSL_OP_NO_SSLv2;
+ ctx_options |= SSL_OP_NO_SSLv3;
+ ctx_options |= SSL_OP_NO_TLSv1;
+ ctx_options |= SSL_OP_NO_TLSv1_1;
+ ctx_options |= SSL_OP_NO_TLSv1_2;
+ break;
+#else
+ failf(data, OSSL_PACKAGE " was built without TLS 1.3 support");
+ return CURLE_NOT_BUILT_IN;
#endif
-#ifndef OPENSSL_NO_SSL2
case CURL_SSLVERSION_SSLv2:
+#ifndef OPENSSL_NO_SSL2
ctx_options |= SSL_OP_NO_SSLv3;
ctx_options |= SSL_OP_NO_TLSv1;
#if OPENSSL_VERSION_NUMBER >= 0x1000100FL
ctx_options |= SSL_OP_NO_TLSv1_1;
ctx_options |= SSL_OP_NO_TLSv1_2;
+#ifdef TLS1_3_VERSION
+ ctx_options |= SSL_OP_NO_TLSv1_3;
+#endif
#endif
break;
+#else
+ failf(data, OSSL_PACKAGE " was built without SSLv2 support");
+ return CURLE_NOT_BUILT_IN;
#endif
default:
- failf(data, "Unsupported SSL protocol version");
+ failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
return CURLE_SSL_CONNECT_ERROR;
}
@@ -1942,19 +2001,16 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
}
#endif
- if(data->set.str[STRING_CERT] || data->set.str[STRING_CERT_TYPE]) {
- if(!cert_stuff(conn,
- connssl->ctx,
- data->set.str[STRING_CERT],
- data->set.str[STRING_CERT_TYPE],
- data->set.str[STRING_KEY],
- data->set.str[STRING_KEY_TYPE])) {
+ if(ssl_cert || ssl_cert_type) {
+ if(!cert_stuff(conn, connssl->ctx, ssl_cert, ssl_cert_type,
+ SSL_SET_OPTION(key), SSL_SET_OPTION(key_type),
+ SSL_SET_OPTION(key_passwd))) {
/* failf() is already done in cert_stuff() */
return CURLE_SSL_CERTPROBLEM;
}
}
- ciphers = data->set.str[STRING_SSL_CIPHER_LIST];
+ ciphers = SSL_CONN_CONFIG(cipher_list);
if(!ciphers)
ciphers = (char *)DEFAULT_CIPHER_SELECTION;
if(!SSL_CTX_set_cipher_list(connssl->ctx, ciphers)) {
@@ -1964,18 +2020,20 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
infof(data, "Cipher selection: %s\n", ciphers);
#ifdef USE_TLS_SRP
- if(data->set.ssl.authtype == CURL_TLSAUTH_SRP) {
- infof(data, "Using TLS-SRP username: %s\n", data->set.ssl.username);
+ if(ssl_authtype == CURL_TLSAUTH_SRP) {
+ char * const ssl_username = SSL_SET_OPTION(username);
+
+ infof(data, "Using TLS-SRP username: %s\n", ssl_username);
- if(!SSL_CTX_set_srp_username(connssl->ctx, data->set.ssl.username)) {
+ if(!SSL_CTX_set_srp_username(connssl->ctx, ssl_username)) {
failf(data, "Unable to set SRP user name");
return CURLE_BAD_FUNCTION_ARGUMENT;
}
- if(!SSL_CTX_set_srp_password(connssl->ctx, data->set.ssl.password)) {
+ if(!SSL_CTX_set_srp_password(connssl->ctx, SSL_SET_OPTION(password))) {
failf(data, "failed setting SRP password");
return CURLE_BAD_FUNCTION_ARGUMENT;
}
- if(!data->set.str[STRING_SSL_CIPHER_LIST]) {
+ if(!SSL_CONN_CONFIG(cipher_list)) {
infof(data, "Setting cipher list SRP\n");
if(!SSL_CTX_set_cipher_list(connssl->ctx, "SRP")) {
@@ -1985,20 +2043,17 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
}
}
#endif
- if(data->set.str[STRING_SSL_CAFILE] || data->set.str[STRING_SSL_CAPATH]) {
+
+ if(ssl_cafile || ssl_capath) {
/* tell SSL where to find CA certificates that are used to verify
the servers certificate. */
- if(!SSL_CTX_load_verify_locations(connssl->ctx,
- data->set.str[STRING_SSL_CAFILE],
- data->set.str[STRING_SSL_CAPATH])) {
- if(data->set.ssl.verifypeer) {
+ if(!SSL_CTX_load_verify_locations(connssl->ctx, ssl_cafile, ssl_capath)) {
+ if(verifypeer) {
/* Fail if we insist on successfully verifying the server. */
failf(data, "error setting certificate verify locations:\n"
" CAfile: %s\n CApath: %s",
- data->set.str[STRING_SSL_CAFILE]?
- data->set.str[STRING_SSL_CAFILE]: "none",
- data->set.str[STRING_SSL_CAPATH]?
- data->set.str[STRING_SSL_CAPATH] : "none");
+ ssl_cafile ? ssl_cafile : "none",
+ ssl_capath ? ssl_capath : "none");
return CURLE_SSL_CACERT_BADFILE;
}
else {
@@ -2015,29 +2070,25 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
infof(data,
" CAfile: %s\n"
" CApath: %s\n",
- data->set.str[STRING_SSL_CAFILE] ? data->set.str[STRING_SSL_CAFILE]:
- "none",
- data->set.str[STRING_SSL_CAPATH] ? data->set.str[STRING_SSL_CAPATH]:
- "none");
+ ssl_cafile ? ssl_cafile : "none",
+ ssl_capath ? ssl_capath : "none");
}
#ifdef CURL_CA_FALLBACK
- else if(data->set.ssl.verifypeer) {
+ else if(verifypeer) {
/* verfying the peer without any CA certificates won't
work so use openssl's built in default as fallback */
SSL_CTX_set_default_verify_paths(connssl->ctx);
}
#endif
- if(data->set.str[STRING_SSL_CRLFILE]) {
+ if(ssl_crlfile) {
/* tell SSL where to find CRL file that is used to check certificate
* revocation */
lookup=X509_STORE_add_lookup(SSL_CTX_get_cert_store(connssl->ctx),
X509_LOOKUP_file());
if(!lookup ||
- (!X509_load_crl_file(lookup, data->set.str[STRING_SSL_CRLFILE],
- X509_FILETYPE_PEM)) ) {
- failf(data, "error loading CRL file: %s",
- data->set.str[STRING_SSL_CRLFILE]);
+ (!X509_load_crl_file(lookup, ssl_crlfile, X509_FILETYPE_PEM)) ) {
+ failf(data, "error loading CRL file: %s", ssl_crlfile);
return CURLE_SSL_CRL_BADFILE;
}
else {
@@ -2046,9 +2097,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
X509_STORE_set_flags(SSL_CTX_get_cert_store(connssl->ctx),
X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL);
}
- infof(data,
- " CRLfile: %s\n", data->set.str[STRING_SSL_CRLFILE] ?
- data->set.str[STRING_SSL_CRLFILE]: "none");
+ infof(data, " CRLfile: %s\n", ssl_crlfile);
}
/* Try building a chain using issuers in the trusted store first to avoid
@@ -2059,7 +2108,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
https://rt.openssl.org/Ticket/Display.html?id=3621&user=guest&pass=guest
*/
#if defined(X509_V_FLAG_TRUSTED_FIRST) && !defined(X509_V_FLAG_NO_ALT_CHAINS)
- if(data->set.ssl.verifypeer) {
+ if(verifypeer) {
X509_STORE_set_flags(SSL_CTX_get_cert_store(connssl->ctx),
X509_V_FLAG_TRUSTED_FIRST);
}
@@ -2070,8 +2119,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
* anyway. In the latter case the result of the verification is checked with
* SSL_get_verify_result() below. */
SSL_CTX_set_verify(connssl->ctx,
- data->set.ssl.verifypeer?SSL_VERIFY_PEER:SSL_VERIFY_NONE,
- NULL);
+ verifypeer ? SSL_VERIFY_PEER : SSL_VERIFY_NONE, NULL);
/* give application a chance to interfere with SSL set up. */
if(data->set.ssl.fsslctx) {
@@ -2094,31 +2142,30 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
!defined(OPENSSL_NO_OCSP)
- if(data->set.ssl.verifystatus)
+ if(SSL_CONN_CONFIG(verifystatus))
SSL_set_tlsext_status_type(connssl->handle, TLSEXT_STATUSTYPE_ocsp);
#endif
SSL_set_connect_state(connssl->handle);
connssl->server_cert = 0x0;
-
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
- if((0 == Curl_inet_pton(AF_INET, conn->host.name, &addr)) &&
+ if((0 == Curl_inet_pton(AF_INET, hostname, &addr)) &&
#ifdef ENABLE_IPV6
- (0 == Curl_inet_pton(AF_INET6, conn->host.name, &addr)) &&
+ (0 == Curl_inet_pton(AF_INET6, hostname, &addr)) &&
#endif
sni &&
- !SSL_set_tlsext_host_name(connssl->handle, conn->host.name))
+ !SSL_set_tlsext_host_name(connssl->handle, hostname))
infof(data, "WARNING: failed to configure server name indication (SNI) "
"TLS extension\n");
#endif
/* Check if there's a cached ID we can/should use here! */
- if(conn->ssl_config.sessionid) {
+ if(data->set.general_ssl.sessionid) {
void *ssl_sessionid = NULL;
Curl_ssl_sessionid_lock(conn);
- if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL)) {
+ if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL, sockindex)) {
/* we got a session id, use it! */
if(!SSL_set_session(connssl->handle, ssl_sessionid)) {
Curl_ssl_sessionid_unlock(conn);
@@ -2127,13 +2174,21 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
return CURLE_SSL_CONNECT_ERROR;
}
/* Informational message */
- infof (data, "SSL re-using session ID\n");
+ infof(data, "SSL re-using session ID\n");
}
Curl_ssl_sessionid_unlock(conn);
}
- /* pass the raw socket into the SSL layers */
- if(!SSL_set_fd(connssl->handle, (int)sockfd)) {
+ if(conn->proxy_ssl[sockindex].use) {
+ BIO *const bio = BIO_new(BIO_f_ssl());
+ DEBUGASSERT(ssl_connection_complete == conn->proxy_ssl[sockindex].state);
+ DEBUGASSERT(conn->proxy_ssl[sockindex].handle != NULL);
+ DEBUGASSERT(bio != NULL);
+ BIO_set_ssl(bio, conn->proxy_ssl[sockindex].handle, FALSE);
+ SSL_set_bio(connssl->handle, bio, bio);
+ }
+ else if(!SSL_set_fd(connssl->handle, (int)sockfd)) {
+ /* pass the raw socket into the SSL layers */
failf(data, "SSL: SSL_set_fd failed: %s",
ERR_error_string(ERR_get_error(), NULL));
return CURLE_SSL_CONNECT_ERROR;
@@ -2149,9 +2204,11 @@ static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex)
struct Curl_easy *data = conn->data;
int err;
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ long * const certverifyresult = SSL_IS_PROXY() ?
+ &data->set.proxy_ssl.certverifyresult : &data->set.ssl.certverifyresult;
DEBUGASSERT(ssl_connect_2 == connssl->connecting_state
- || ssl_connect_2_reading == connssl->connecting_state
- || ssl_connect_2_writing == connssl->connecting_state);
+ || ssl_connect_2_reading == connssl->connecting_state
+ || ssl_connect_2_writing == connssl->connecting_state);
ERR_clear_error();
@@ -2198,7 +2255,7 @@ static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex)
lerr = SSL_get_verify_result(connssl->handle);
if(lerr != X509_V_OK) {
- data->set.ssl.certverifyresult = lerr;
+ *certverifyresult = lerr;
snprintf(error_buffer, sizeof(error_buffer),
"SSL certificate problem: %s",
X509_verify_cert_error_string(lerr));
@@ -2220,8 +2277,11 @@ static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex)
* the SO_ERROR is also lost.
*/
if(CURLE_SSL_CONNECT_ERROR == result && errdetail == 0) {
+ const char * const hostname = SSL_IS_PROXY() ?
+ conn->http_proxy.host.name : conn->host.name;
+ const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port;
failf(data, "Unknown SSL protocol error in connection to %s:%ld ",
- conn->host.name, conn->remote_port);
+ hostname, port);
return result;
}
@@ -2245,7 +2305,7 @@ static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex)
* negotiated
*/
if(conn->bits.tls_enable_alpn) {
- const unsigned char* neg_protocol;
+ const unsigned char *neg_protocol;
unsigned int len;
SSL_get0_alpn_selected(connssl->handle, &neg_protocol, &len);
if(len != 0) {
@@ -2276,7 +2336,8 @@ static int asn1_object_dump(ASN1_OBJECT *a, char *buf, size_t len)
{
int i, ilen;
- if((ilen = (int)len) < 0)
+ ilen = (int)len;
+ if(ilen < 0)
return 1; /* buffer too big */
i = i2t_ASN1_OBJECT(buf, ilen, a);
@@ -2698,6 +2759,8 @@ static CURLcode servercert(struct connectdata *conn,
FILE *fp;
char *buffer = data->state.buffer;
const char *ptr;
+ long * const certverifyresult = SSL_IS_PROXY() ?
+ &data->set.proxy_ssl.certverifyresult : &data->set.ssl.certverifyresult;
BIO *mem = BIO_new(BIO_s_mem());
if(data->set.ssl.certinfo)
@@ -2713,7 +2776,7 @@ static CURLcode servercert(struct connectdata *conn,
return CURLE_PEER_FAILED_VERIFICATION;
}
- infof(data, "Server certificate:\n");
+ infof(data, "%s certificate:\n", SSL_IS_PROXY() ? "Proxy" : "Server");
rc = x509_name_oneline(X509_get_subject_name(connssl->server_cert),
buffer, BUFSIZE);
@@ -2731,7 +2794,7 @@ static CURLcode servercert(struct connectdata *conn,
BIO_free(mem);
- if(data->set.ssl.verifyhost) {
+ if(SSL_CONN_CONFIG(verifyhost)) {
result = verifyhost(conn, connssl->server_cert);
if(result) {
X509_free(connssl->server_cert);
@@ -2754,12 +2817,12 @@ static CURLcode servercert(struct connectdata *conn,
deallocating the certificate. */
/* e.g. match issuer name with provided issuer certificate */
- if(data->set.str[STRING_SSL_ISSUERCERT]) {
- fp = fopen(data->set.str[STRING_SSL_ISSUERCERT], FOPEN_READTEXT);
+ if(SSL_SET_OPTION(issuercert)) {
+ fp = fopen(SSL_SET_OPTION(issuercert), FOPEN_READTEXT);
if(!fp) {
if(strict)
failf(data, "SSL: Unable to open issuer cert (%s)",
- data->set.str[STRING_SSL_ISSUERCERT]);
+ SSL_SET_OPTION(issuercert));
X509_free(connssl->server_cert);
connssl->server_cert = NULL;
return CURLE_SSL_ISSUER_ERROR;
@@ -2769,7 +2832,7 @@ static CURLcode servercert(struct connectdata *conn,
if(!issuer) {
if(strict)
failf(data, "SSL: Unable to read issuer cert (%s)",
- data->set.str[STRING_SSL_ISSUERCERT]);
+ SSL_SET_OPTION(issuercert));
X509_free(connssl->server_cert);
X509_free(issuer);
fclose(fp);
@@ -2781,7 +2844,7 @@ static CURLcode servercert(struct connectdata *conn,
if(X509_check_issued(issuer, connssl->server_cert) != X509_V_OK) {
if(strict)
failf(data, "SSL: Certificate issuer check failed (%s)",
- data->set.str[STRING_SSL_ISSUERCERT]);
+ SSL_SET_OPTION(issuercert));
X509_free(connssl->server_cert);
X509_free(issuer);
connssl->server_cert = NULL;
@@ -2789,15 +2852,14 @@ static CURLcode servercert(struct connectdata *conn,
}
infof(data, " SSL certificate issuer check ok (%s)\n",
- data->set.str[STRING_SSL_ISSUERCERT]);
+ SSL_SET_OPTION(issuercert));
X509_free(issuer);
}
- lerr = data->set.ssl.certverifyresult =
- SSL_get_verify_result(connssl->handle);
+ lerr = *certverifyresult = SSL_get_verify_result(connssl->handle);
- if(data->set.ssl.certverifyresult != X509_V_OK) {
- if(data->set.ssl.verifypeer) {
+ if(*certverifyresult != X509_V_OK) {
+ if(SSL_CONN_CONFIG(verifypeer)) {
/* We probably never reach this, because SSL_connect() will fail
and we return earlier if verifypeer is set? */
if(strict)
@@ -2816,7 +2878,7 @@ static CURLcode servercert(struct connectdata *conn,
#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
!defined(OPENSSL_NO_OCSP)
- if(data->set.ssl.verifystatus) {
+ if(SSL_CONN_CONFIG(verifystatus)) {
result = verifystatus(conn, connssl);
if(result) {
X509_free(connssl->server_cert);
@@ -2830,7 +2892,8 @@ static CURLcode servercert(struct connectdata *conn,
/* when not strict, we don't bother about the verify cert problems */
result = CURLE_OK;
- ptr = data->set.str[STRING_SSL_PINNEDPUBLICKEY];
+ ptr = SSL_IS_PROXY() ? data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
if(!result && ptr) {
result = pkp_pin_peer_pubkey(data, connssl->server_cert, ptr);
if(result)
@@ -2852,7 +2915,7 @@ static CURLcode ossl_connect_step3(struct connectdata *conn, int sockindex)
DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
- if(conn->ssl_config.sessionid) {
+ if(data->set.general_ssl.sessionid) {
bool incache;
SSL_SESSION *our_ssl_sessionid;
void *old_ssl_sessionid = NULL;
@@ -2864,7 +2927,8 @@ static CURLcode ossl_connect_step3(struct connectdata *conn, int sockindex)
regardless of its state. */
Curl_ssl_sessionid_lock(conn);
- incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL));
+ incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL,
+ sockindex));
if(incache) {
if(old_ssl_sessionid != our_ssl_sessionid) {
infof(data, "old SSL session ID is stale, removing\n");
@@ -2875,7 +2939,7 @@ static CURLcode ossl_connect_step3(struct connectdata *conn, int sockindex)
if(!incache) {
result = Curl_ssl_addsessionid(conn, our_ssl_sessionid,
- 0 /* unknown size */);
+ 0 /* unknown size */, sockindex);
if(result) {
Curl_ssl_sessionid_unlock(conn);
failf(data, "failed to store ssl session");
@@ -2899,8 +2963,8 @@ static CURLcode ossl_connect_step3(struct connectdata *conn, int sockindex)
* operations.
*/
- result = servercert(conn, connssl,
- (data->set.ssl.verifypeer || data->set.ssl.verifyhost));
+ result = servercert(conn, connssl, (SSL_CONN_CONFIG(verifypeer) ||
+ SSL_CONN_CONFIG(verifyhost)));
if(!result)
connssl->connecting_state = ssl_connect_done;
@@ -2920,7 +2984,7 @@ static CURLcode ossl_connect_common(struct connectdata *conn,
struct Curl_easy *data = conn->data;
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
curl_socket_t sockfd = conn->sock[sockindex];
- long timeout_ms;
+ time_t timeout_ms;
int what;
/* check if the connection has already been established */
@@ -3048,7 +3112,10 @@ bool Curl_ossl_data_pending(const struct connectdata *conn, int connindex)
{
if(conn->ssl[connindex].handle)
/* SSL is in use */
- return (0 != SSL_pending(conn->ssl[connindex].handle)) ? TRUE : FALSE;
+ return (0 != SSL_pending(conn->ssl[connindex].handle) ||
+ (conn->proxy_ssl[connindex].handle &&
+ 0 != SSL_pending(conn->proxy_ssl[connindex].handle))) ?
+ TRUE : FALSE;
else
return FALSE;
}
@@ -3093,8 +3160,18 @@ static ssize_t ossl_send(struct connectdata *conn,
/* A failure in the SSL library occurred, usually a protocol error.
The OpenSSL error queue contains more information on the error. */
sslerror = ERR_get_error();
- failf(conn->data, "SSL_write() error: %s",
- ossl_strerror(sslerror, error_buffer, sizeof(error_buffer)));
+ if(ERR_GET_LIB(sslerror) == ERR_LIB_SSL &&
+ ERR_GET_REASON(sslerror) == SSL_R_BIO_NOT_SET &&
+ conn->ssl[sockindex].state == ssl_connection_complete &&
+ conn->proxy_ssl[sockindex].state == ssl_connection_complete) {
+ char ver[120];
+ Curl_ossl_version(ver, 120);
+ failf(conn->data, "Error: %s does not support double SSL tunneling.",
+ ver);
+ }
+ else
+ failf(conn->data, "SSL_write() error: %s",
+ ossl_strerror(sslerror, error_buffer, sizeof(error_buffer)));
*curlcode = CURLE_SEND_ERROR;
return -1;
}
@@ -3178,7 +3255,7 @@ size_t Curl_ossl_version(char *buffer, size_t size)
sub[0] = 'z';
}
else {
- sub[0]=(char)(((ssleay_value>>4)&0xff) + 'a' -1);
+ sub[0] = (char) (minor_ver + 'a' - 1);
}
}
else
@@ -3199,7 +3276,12 @@ int Curl_ossl_random(struct Curl_easy *data, unsigned char *entropy,
size_t length)
{
if(data) {
- Curl_ossl_seed(data); /* Initiate the seed if not already done */
+ if(Curl_ossl_seed(data)) /* Initiate the seed if not already done */
+ return 1; /* couldn't seed for some reason */
+ }
+ else {
+ if(!rand_enough())
+ return 1;
}
RAND_bytes(entropy, curlx_uztosi(length));
return 0; /* 0 as in no problem */
diff --git a/Utilities/cmcurl/lib/vtls/openssl.h b/Utilities/cmcurl/lib/vtls/openssl.h
index ee18e710fc..cff1e909cf 100644
--- a/Utilities/cmcurl/lib/vtls/openssl.h
+++ b/Utilities/cmcurl/lib/vtls/openssl.h
@@ -79,6 +79,9 @@ void Curl_ossl_sha256sum(const unsigned char *tmp, /* input */
bool Curl_ossl_cert_status_request(void);
+/* Support HTTPS-proxy */
+#define HTTPS_PROXY_SUPPORT 1
+
/* Set the API backend definition to OpenSSL */
#define CURL_SSL_BACKEND CURLSSLBACKEND_OPENSSL
diff --git a/Utilities/cmcurl/lib/vtls/polarssl.c b/Utilities/cmcurl/lib/vtls/polarssl.c
index 18b564e02d..4bba3e3f28 100644
--- a/Utilities/cmcurl/lib/vtls/polarssl.c
+++ b/Utilities/cmcurl/lib/vtls/polarssl.c
@@ -147,12 +147,16 @@ polarssl_connect_step1(struct connectdata *conn,
{
struct Curl_easy *data = conn->data;
struct ssl_connect_data* connssl = &conn->ssl[sockindex];
+ const char *capath = SSL_CONN_CONFIG(CApath);
+ const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
+ conn->host.name;
+ const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port;
int ret = -1;
char errorbuf[128];
errorbuf[0]=0;
/* PolarSSL only supports SSLv3 and TLSv1 */
- if(data->set.ssl.version == CURL_SSLVERSION_SSLv2) {
+ if(SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv2) {
failf(data, "PolarSSL does not support SSLv2");
return CURLE_SSL_CONNECT_ERROR;
}
@@ -180,30 +184,29 @@ polarssl_connect_step1(struct connectdata *conn,
/* Load the trusted CA */
memset(&connssl->cacert, 0, sizeof(x509_crt));
- if(data->set.str[STRING_SSL_CAFILE]) {
+ if(SSL_CONN_CONFIG(CAfile)) {
ret = x509_crt_parse_file(&connssl->cacert,
- data->set.str[STRING_SSL_CAFILE]);
+ SSL_CONN_CONFIG(CAfile));
if(ret<0) {
error_strerror(ret, errorbuf, sizeof(errorbuf));
failf(data, "Error reading ca cert file %s - PolarSSL: (-0x%04X) %s",
- data->set.str[STRING_SSL_CAFILE], -ret, errorbuf);
+ SSL_CONN_CONFIG(CAfile), -ret, errorbuf);
- if(data->set.ssl.verifypeer)
+ if(SSL_CONN_CONFIG(verifypeer))
return CURLE_SSL_CACERT_BADFILE;
}
}
- if(data->set.str[STRING_SSL_CAPATH]) {
- ret = x509_crt_parse_path(&connssl->cacert,
- data->set.str[STRING_SSL_CAPATH]);
+ if(capath) {
+ ret = x509_crt_parse_path(&connssl->cacert, capath);
if(ret<0) {
error_strerror(ret, errorbuf, sizeof(errorbuf));
failf(data, "Error reading ca cert path %s - PolarSSL: (-0x%04X) %s",
- data->set.str[STRING_SSL_CAPATH], -ret, errorbuf);
+ capath, -ret, errorbuf);
- if(data->set.ssl.verifypeer)
+ if(SSL_CONN_CONFIG(verifypeer))
return CURLE_SSL_CACERT_BADFILE;
}
}
@@ -211,25 +214,25 @@ polarssl_connect_step1(struct connectdata *conn,
/* Load the client certificate */
memset(&connssl->clicert, 0, sizeof(x509_crt));
- if(data->set.str[STRING_CERT]) {
+ if(SSL_SET_OPTION(cert)) {
ret = x509_crt_parse_file(&connssl->clicert,
- data->set.str[STRING_CERT]);
+ SSL_SET_OPTION(cert));
if(ret) {
error_strerror(ret, errorbuf, sizeof(errorbuf));
failf(data, "Error reading client cert file %s - PolarSSL: (-0x%04X) %s",
- data->set.str[STRING_CERT], -ret, errorbuf);
+ SSL_SET_OPTION(cert), -ret, errorbuf);
return CURLE_SSL_CERTPROBLEM;
}
}
/* Load the client private key */
- if(data->set.str[STRING_KEY]) {
+ if(SSL_SET_OPTION(key)) {
pk_context pk;
pk_init(&pk);
- ret = pk_parse_keyfile(&pk, data->set.str[STRING_KEY],
- data->set.str[STRING_KEY_PASSWD]);
+ ret = pk_parse_keyfile(&pk, SSL_SET_OPTION(key),
+ SSL_SET_OPTION(key_passwd));
if(ret == 0 && !pk_can_do(&pk, POLARSSL_PK_RSA))
ret = POLARSSL_ERR_PK_TYPE_MISMATCH;
if(ret == 0)
@@ -241,7 +244,7 @@ polarssl_connect_step1(struct connectdata *conn,
if(ret) {
error_strerror(ret, errorbuf, sizeof(errorbuf));
failf(data, "Error reading private key %s - PolarSSL: (-0x%04X) %s",
- data->set.str[STRING_KEY], -ret, errorbuf);
+ SSL_SET_OPTION(key), -ret, errorbuf);
return CURLE_SSL_CERTPROBLEM;
}
@@ -250,29 +253,27 @@ polarssl_connect_step1(struct connectdata *conn,
/* Load the CRL */
memset(&connssl->crl, 0, sizeof(x509_crl));
- if(data->set.str[STRING_SSL_CRLFILE]) {
+ if(SSL_SET_OPTION(CRLfile)) {
ret = x509_crl_parse_file(&connssl->crl,
- data->set.str[STRING_SSL_CRLFILE]);
+ SSL_SET_OPTION(CRLfile));
if(ret) {
error_strerror(ret, errorbuf, sizeof(errorbuf));
failf(data, "Error reading CRL file %s - PolarSSL: (-0x%04X) %s",
- data->set.str[STRING_SSL_CRLFILE], -ret, errorbuf);
+ SSL_SET_OPTION(CRLfile), -ret, errorbuf);
return CURLE_SSL_CRL_BADFILE;
}
}
- infof(data, "PolarSSL: Connecting to %s:%d\n",
- conn->host.name, conn->remote_port);
+ infof(data, "PolarSSL: Connecting to %s:%d\n", hostname, port);
if(ssl_init(&connssl->ssl)) {
failf(data, "PolarSSL: ssl_init failed");
return CURLE_SSL_CONNECT_ERROR;
}
- switch(data->set.ssl.version) {
- default:
+ switch(SSL_CONN_CONFIG(version)) {
case CURL_SSLVERSION_DEFAULT:
case CURL_SSLVERSION_TLSv1:
ssl_set_min_version(&connssl->ssl, SSL_MAJOR_VERSION_3,
@@ -306,6 +307,12 @@ polarssl_connect_step1(struct connectdata *conn,
SSL_MINOR_VERSION_3);
infof(data, "PolarSSL: Forced min. SSL Version to be TLS 1.2\n");
break;
+ case CURL_SSLVERSION_TLSv1_3:
+ failf(data, "PolarSSL: TLS 1.3 is not yet supported");
+ return CURLE_SSL_CONNECT_ERROR;
+ default:
+ failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
+ return CURLE_SSL_CONNECT_ERROR;
}
ssl_set_endpoint(&connssl->ssl, SSL_IS_CLIENT);
@@ -320,11 +327,11 @@ polarssl_connect_step1(struct connectdata *conn,
ssl_set_ciphersuites(&connssl->ssl, ssl_list_ciphersuites());
/* Check if there's a cached ID we can/should use here! */
- if(conn->ssl_config.sessionid) {
+ if(data->set.general_ssl.sessionid) {
void *old_session = NULL;
Curl_ssl_sessionid_lock(conn);
- if(!Curl_ssl_getsessionid(conn, &old_session, NULL)) {
+ if(!Curl_ssl_getsessionid(conn, &old_session, NULL, sockindex)) {
ret = ssl_set_session(&connssl->ssl, old_session);
if(ret) {
Curl_ssl_sessionid_unlock(conn);
@@ -339,12 +346,12 @@ polarssl_connect_step1(struct connectdata *conn,
ssl_set_ca_chain(&connssl->ssl,
&connssl->cacert,
&connssl->crl,
- conn->host.name);
+ hostname);
ssl_set_own_cert_rsa(&connssl->ssl,
&connssl->clicert, &connssl->rsa);
- if(ssl_set_hostname(&connssl->ssl, conn->host.name)) {
+ if(ssl_set_hostname(&connssl->ssl, hostname)) {
/* ssl_set_hostname() sets the name to use in CN/SAN checks *and* the name
to set in the SNI extension. So even if curl connects to a host
specified as an IP address, this function must be used. */
@@ -354,7 +361,7 @@ polarssl_connect_step1(struct connectdata *conn,
#ifdef HAS_ALPN
if(conn->bits.tls_enable_alpn) {
- static const char* protocols[3];
+ static const char *protocols[3];
int cur = 0;
#ifdef USE_NGHTTP2
@@ -390,6 +397,10 @@ polarssl_connect_step2(struct connectdata *conn,
struct Curl_easy *data = conn->data;
struct ssl_connect_data* connssl = &conn->ssl[sockindex];
char buffer[1024];
+ const char * const pinnedpubkey = SSL_IS_PROXY() ?
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
+
char errorbuf[128];
errorbuf[0] = 0;
@@ -423,7 +434,7 @@ polarssl_connect_step2(struct connectdata *conn,
ret = ssl_get_verify_result(&conn->ssl[sockindex].ssl);
- if(ret && data->set.ssl.verifypeer) {
+ if(ret && SSL_CONN_CONFIG(verifypeer)) {
if(ret & BADCERT_EXPIRED)
failf(data, "Cert verify failed: BADCERT_EXPIRED");
@@ -451,7 +462,7 @@ polarssl_connect_step2(struct connectdata *conn,
}
/* adapted from mbedtls.c */
- if(data->set.str[STRING_SSL_PINNEDPUBLICKEY]) {
+ if(pinnedpubkey) {
int size;
CURLcode result;
x509_crt *p;
@@ -493,7 +504,7 @@ polarssl_connect_step2(struct connectdata *conn,
/* pk_write_pubkey_der writes data at the end of the buffer. */
result = Curl_pin_peer_pubkey(data,
- data->set.str[STRING_SSL_PINNEDPUBLICKEY],
+ pinnedpubkey,
&pubkey[PUB_DER_MAX_BYTES - size], size);
if(result) {
x509_crt_free(p);
@@ -544,7 +555,7 @@ polarssl_connect_step3(struct connectdata *conn,
DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
- if(conn->ssl_config.sessionid) {
+ if(data->set.general_ssl.sessionid) {
int ret;
ssl_session *our_ssl_sessionid;
void *old_ssl_sessionid = NULL;
@@ -563,10 +574,10 @@ polarssl_connect_step3(struct connectdata *conn,
/* If there's already a matching session in the cache, delete it */
Curl_ssl_sessionid_lock(conn);
- if(!Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL))
+ if(!Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL, sockindex))
Curl_ssl_delsessionid(conn, old_ssl_sessionid);
- retcode = Curl_ssl_addsessionid(conn, our_ssl_sessionid, 0);
+ retcode = Curl_ssl_addsessionid(conn, our_ssl_sessionid, 0, sockindex);
Curl_ssl_sessionid_unlock(conn);
if(retcode) {
free(our_ssl_sessionid);
diff --git a/Utilities/cmcurl/lib/vtls/schannel.c b/Utilities/cmcurl/lib/vtls/schannel.c
index f731eebdc5..ac8b70556e 100644
--- a/Utilities/cmcurl/lib/vtls/schannel.c
+++ b/Utilities/cmcurl/lib/vtls/schannel.c
@@ -59,6 +59,7 @@
#include "x509asn1.h"
#include "curl_printf.h"
#include "system_win32.h"
+#include "hostcheck.h"
/* The last #include file should be: */
#include "curl_memory.h"
@@ -123,9 +124,11 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
#endif
TCHAR *host_name;
CURLcode result;
+ const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
+ conn->host.name;
infof(data, "schannel: SSL/TLS connection with %s port %hu (step 1/3)\n",
- conn->host.name, conn->remote_port);
+ hostname, conn->remote_port);
#ifdef HAS_ALPN
/* ALPN is only supported on Windows 8.1 / Server 2012 R2 and above.
@@ -142,9 +145,9 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
connssl->cred = NULL;
/* check for an existing re-usable credential handle */
- if(conn->ssl_config.sessionid) {
+ if(data->set.general_ssl.sessionid) {
Curl_ssl_sessionid_lock(conn);
- if(!Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL)) {
+ if(!Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL, sockindex)) {
connssl->cred = old_cred;
infof(data, "schannel: re-using existing credential handle\n");
@@ -161,7 +164,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
memset(&schannel_cred, 0, sizeof(schannel_cred));
schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
- if(data->set.ssl.verifypeer) {
+ 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. */
@@ -170,13 +173,14 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
SCH_CRED_IGNORE_REVOCATION_OFFLINE;
#else
schannel_cred.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION;
- if(data->set.ssl_no_revoke)
+ /* TODO s/data->set.ssl.no_revoke/SSL_SET_OPTION(no_revoke)/g */
+ 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)
+ if(data->set.ssl.no_revoke)
infof(data, "schannel: disabled server certificate revocation "
"checks\n");
else
@@ -189,15 +193,14 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
infof(data, "schannel: disabled server certificate revocation checks\n");
}
- if(!data->set.ssl.verifyhost) {
+ if(!conn->ssl_config.verifyhost) {
schannel_cred.dwFlags |= SCH_CRED_NO_SERVERNAME_CHECK;
infof(data, "schannel: verifyhost setting prevents Schannel from "
"comparing the supplied target name with the subject "
"names in server certificates. Also disables SNI.\n");
}
- switch(data->set.ssl.version) {
- default:
+ switch(conn->ssl_config.version) {
case CURL_SSLVERSION_DEFAULT:
case CURL_SSLVERSION_TLSv1:
schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_0_CLIENT |
@@ -213,12 +216,18 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
case CURL_SSLVERSION_TLSv1_2:
schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_2_CLIENT;
break;
+ case CURL_SSLVERSION_TLSv1_3:
+ failf(data, "Schannel: TLS 1.3 is not yet supported");
+ return CURLE_SSL_CONNECT_ERROR;
case CURL_SSLVERSION_SSLv3:
schannel_cred.grbitEnabledProtocols = SP_PROT_SSL3_CLIENT;
break;
case CURL_SSLVERSION_SSLv2:
schannel_cred.grbitEnabledProtocols = SP_PROT_SSL2_CLIENT;
break;
+ default:
+ failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
+ return CURLE_SSL_CONNECT_ERROR;
}
/* allocate memory for the re-usable credential handle */
@@ -253,9 +262,9 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
}
/* Warn if SNI is disabled due to use of an IP address */
- if(Curl_inet_pton(AF_INET, conn->host.name, &addr)
+ if(Curl_inet_pton(AF_INET, hostname, &addr)
#ifdef ENABLE_IPV6
- || Curl_inet_pton(AF_INET6, conn->host.name, &addr6)
+ || Curl_inet_pton(AF_INET6, hostname, &addr6)
#endif
) {
infof(data, "schannel: using IP address, SNI is not supported by OS.\n");
@@ -265,17 +274,17 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
if(connssl->use_alpn) {
int cur = 0;
int list_start_index = 0;
- unsigned int* extension_len = NULL;
+ unsigned int *extension_len = NULL;
unsigned short* list_len = NULL;
/* The first four bytes will be an unsigned int indicating number
of bytes of data in the rest of the the buffer. */
- extension_len = (unsigned int*)(&alpn_buffer[cur]);
+ extension_len = (unsigned int *)(&alpn_buffer[cur]);
cur += sizeof(unsigned int);
/* The next four bytes are an indicator that this buffer will contain
ALPN data, as opposed to NPN, for example. */
- *(unsigned int*)&alpn_buffer[cur] =
+ *(unsigned int *)&alpn_buffer[cur] =
SecApplicationProtocolNegotiationExt_ALPN;
cur += sizeof(unsigned int);
@@ -333,7 +342,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
}
memset(connssl->ctxt, 0, sizeof(struct curl_schannel_ctxt));
- host_name = Curl_convert_UTF8_to_tchar(conn->host.name);
+ host_name = Curl_convert_UTF8_to_tchar(hostname);
if(!host_name)
return CURLE_OUT_OF_MEMORY;
@@ -406,11 +415,13 @@ schannel_connect_step2(struct connectdata *conn, int sockindex)
TCHAR *host_name;
CURLcode result;
bool doread;
+ const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
+ conn->host.name;
doread = (connssl->connecting_state != ssl_connect_2_writing) ? TRUE : FALSE;
infof(data, "schannel: SSL/TLS connection with %s port %hu (step 2/3)\n",
- conn->host.name, conn->remote_port);
+ hostname, conn->remote_port);
if(!connssl->cred || !connssl->ctxt)
return CURLE_SSL_CONNECT_ERROR;
@@ -506,7 +517,7 @@ schannel_connect_step2(struct connectdata *conn, int sockindex)
memcpy(inbuf[0].pvBuffer, connssl->encdata_buffer,
connssl->encdata_offset);
- host_name = Curl_convert_UTF8_to_tchar(conn->host.name);
+ host_name = Curl_convert_UTF8_to_tchar(hostname);
if(!host_name)
return CURLE_OUT_OF_MEMORY;
@@ -623,7 +634,7 @@ schannel_connect_step2(struct connectdata *conn, int sockindex)
#ifdef _WIN32_WCE
/* Windows CE doesn't do any server certificate validation.
We have to do it manually. */
- if(data->set.ssl.verifypeer)
+ if(conn->ssl_config.verifypeer)
return verify_certificate(conn, sockindex);
#endif
@@ -638,6 +649,8 @@ schannel_connect_step3(struct connectdata *conn, int sockindex)
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
SECURITY_STATUS sspi_status = SEC_E_OK;
CERT_CONTEXT *ccert_context = NULL;
+ const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
+ conn->host.name;
#ifdef HAS_ALPN
SecPkgContext_ApplicationProtocol alpn_result;
#endif
@@ -645,7 +658,7 @@ schannel_connect_step3(struct connectdata *conn, int sockindex)
DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
infof(data, "schannel: SSL/TLS connection with %s port %hu (step 3/3)\n",
- conn->host.name, conn->remote_port);
+ hostname, conn->remote_port);
if(!connssl->cred)
return CURLE_SSL_CONNECT_ERROR;
@@ -701,12 +714,13 @@ schannel_connect_step3(struct connectdata *conn, int sockindex)
#endif
/* save the current session data for possible re-use */
- if(conn->ssl_config.sessionid) {
+ if(data->set.general_ssl.sessionid) {
bool incache;
struct curl_schannel_cred *old_cred = NULL;
Curl_ssl_sessionid_lock(conn);
- incache = !(Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL));
+ incache = !(Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL,
+ sockindex));
if(incache) {
if(old_cred != connssl->cred) {
infof(data, "schannel: old credential handle is stale, removing\n");
@@ -717,7 +731,8 @@ schannel_connect_step3(struct connectdata *conn, int sockindex)
}
if(!incache) {
result = Curl_ssl_addsessionid(conn, (void *)connssl->cred,
- sizeof(struct curl_schannel_cred));
+ sizeof(struct curl_schannel_cred),
+ sockindex);
if(result) {
Curl_ssl_sessionid_unlock(conn);
failf(data, "schannel: failed to store credential handle");
@@ -769,7 +784,7 @@ schannel_connect_common(struct connectdata *conn, int sockindex,
struct Curl_easy *data = conn->data;
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
curl_socket_t sockfd = conn->sock[sockindex];
- long timeout_ms;
+ time_t timeout_ms;
int what;
/* check if the connection has already been established */
@@ -957,7 +972,7 @@ schannel_send(struct connectdata *conn, int sockindex,
/* send entire message or fail */
while(len > (size_t)written) {
ssize_t this_write;
- long timeleft;
+ time_t timeleft;
int what;
this_write = 0;
@@ -1376,9 +1391,11 @@ int Curl_schannel_shutdown(struct connectdata *conn, int sockindex)
*/
struct Curl_easy *data = conn->data;
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
+ conn->host.name;
infof(data, "schannel: shutting down SSL/TLS connection with %s port %hu\n",
- conn->host.name, conn->remote_port);
+ hostname, conn->remote_port);
if(connssl->cred && connssl->ctxt) {
SecBufferDesc BuffDesc;
@@ -1400,7 +1417,7 @@ int Curl_schannel_shutdown(struct connectdata *conn, int sockindex)
failf(data, "schannel: ApplyControlToken failure: %s",
Curl_sspi_strerror(conn, sspi_status));
- host_name = Curl_convert_UTF8_to_tchar(conn->host.name);
+ host_name = Curl_convert_UTF8_to_tchar(hostname);
if(!host_name)
return CURLE_OUT_OF_MEMORY;
@@ -1525,6 +1542,9 @@ static CURLcode verify_certificate(struct connectdata *conn, int 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;
status = s_pSecFn->QueryContextAttributes(&connssl->ctxt->ctxt_handle,
SECPKG_ATTR_REMOTE_CERT_CONTEXT,
@@ -1546,7 +1566,7 @@ static CURLcode verify_certificate(struct connectdata *conn, int sockindex)
NULL,
pCertContextServer->hCertStore,
&ChainPara,
- (data->set.ssl_no_revoke ? 0 :
+ (data->set.ssl.no_revoke ? 0 :
CERT_CHAIN_REVOCATION_CHECK_CHAIN),
NULL,
&pChainContext)) {
@@ -1582,15 +1602,10 @@ static CURLcode verify_certificate(struct connectdata *conn, int sockindex)
}
if(result == CURLE_OK) {
- if(data->set.ssl.verifyhost) {
- TCHAR cert_hostname_buff[128];
- xcharp_u hostname;
- xcharp_u cert_hostname;
+ if(conn->ssl_config.verifyhost) {
+ TCHAR cert_hostname_buff[256];
DWORD len;
- cert_hostname.const_tchar_ptr = cert_hostname_buff;
- hostname.tchar_ptr = Curl_convert_UTF8_to_tchar(conn->host.name);
-
/* 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
@@ -1601,31 +1616,50 @@ static CURLcode verify_certificate(struct connectdata *conn, int sockindex)
*/
len = CertGetNameString(pCertContextServer,
CERT_NAME_DNS_TYPE,
- 0,
+ CERT_NAME_DISABLE_IE4_UTF8_FLAG,
NULL,
- cert_hostname.tchar_ptr,
- 128);
- if(len > 0 && *cert_hostname.tchar_ptr == '*') {
- /* this is a wildcard cert. try matching the last len - 1 chars */
- int hostname_len = strlen(conn->host.name);
- cert_hostname.tchar_ptr++;
- if(_tcsicmp(cert_hostname.const_tchar_ptr,
- hostname.const_tchar_ptr + hostname_len - len + 2) != 0)
- result = CURLE_PEER_FAILED_VERIFICATION;
+ 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 if(len == 0 || _tcsicmp(hostname.const_tchar_ptr,
- cert_hostname.const_tchar_ptr) != 0) {
+ else {
+ failf(data,
+ "schannel: CertGetNameString did not provide any "
+ "certificate name information");
result = CURLE_PEER_FAILED_VERIFICATION;
}
- if(result == CURLE_PEER_FAILED_VERIFICATION) {
- char *_cert_hostname;
- _cert_hostname = Curl_convert_tchar_to_UTF8(cert_hostname.tchar_ptr);
- failf(data, "schannel: CertGetNameString() certificate hostname "
- "(%s) did not match connection (%s)",
- _cert_hostname, conn->host.name);
- Curl_unicodefree(_cert_hostname);
- }
- Curl_unicodefree(hostname.tchar_ptr);
}
}
diff --git a/Utilities/cmcurl/lib/vtls/vtls.c b/Utilities/cmcurl/lib/vtls/vtls.c
index 56a8823412..b808e1c5fe 100644
--- a/Utilities/cmcurl/lib/vtls/vtls.c
+++ b/Utilities/cmcurl/lib/vtls/vtls.c
@@ -65,6 +65,7 @@
#include "url.h"
#include "progress.h"
#include "share.h"
+#include "multiif.h"
#include "timeval.h"
#include "curl_md5.h"
#include "warnless.h"
@@ -80,94 +81,49 @@
(data->share->specifier & \
(1<<CURL_LOCK_DATA_SSL_SESSION)))
-static bool safe_strequal(char* str1, char* str2)
-{
- if(str1 && str2)
- /* both pointers point to something then compare them */
- return (0 != strcasecompare(str1, str2)) ? TRUE : FALSE;
- else
- /* if both pointers are NULL then treat them as equal */
- return (!str1 && !str2) ? TRUE : FALSE;
-}
+#define CLONE_STRING(var) \
+ if(source->var) { \
+ dest->var = strdup(source->var); \
+ if(!dest->var) \
+ return FALSE; \
+ } \
+ else \
+ dest->var = NULL;
bool
-Curl_ssl_config_matches(struct ssl_config_data* data,
- struct ssl_config_data* needle)
+Curl_ssl_config_matches(struct ssl_primary_config* data,
+ struct ssl_primary_config* needle)
{
if((data->version == needle->version) &&
(data->verifypeer == needle->verifypeer) &&
(data->verifyhost == needle->verifyhost) &&
- safe_strequal(data->CApath, needle->CApath) &&
- safe_strequal(data->CAfile, needle->CAfile) &&
- safe_strequal(data->clientcert, needle->clientcert) &&
- safe_strequal(data->cipher_list, needle->cipher_list))
+ 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->cipher_list, needle->cipher_list))
return TRUE;
return FALSE;
}
bool
-Curl_clone_ssl_config(struct ssl_config_data *source,
- struct ssl_config_data *dest)
+Curl_clone_primary_ssl_config(struct ssl_primary_config *source,
+ struct ssl_primary_config *dest)
{
- dest->sessionid = source->sessionid;
dest->verifyhost = source->verifyhost;
dest->verifypeer = source->verifypeer;
dest->version = source->version;
- if(source->CAfile) {
- dest->CAfile = strdup(source->CAfile);
- if(!dest->CAfile)
- return FALSE;
- }
- else
- dest->CAfile = NULL;
-
- if(source->CApath) {
- dest->CApath = strdup(source->CApath);
- if(!dest->CApath)
- return FALSE;
- }
- else
- dest->CApath = NULL;
-
- if(source->cipher_list) {
- dest->cipher_list = strdup(source->cipher_list);
- if(!dest->cipher_list)
- return FALSE;
- }
- else
- dest->cipher_list = NULL;
-
- if(source->egdsocket) {
- dest->egdsocket = strdup(source->egdsocket);
- if(!dest->egdsocket)
- return FALSE;
- }
- else
- dest->egdsocket = NULL;
-
- if(source->random_file) {
- dest->random_file = strdup(source->random_file);
- if(!dest->random_file)
- return FALSE;
- }
- else
- dest->random_file = NULL;
-
- if(source->clientcert) {
- dest->clientcert = strdup(source->clientcert);
- if(!dest->clientcert)
- return FALSE;
- dest->sessionid = FALSE;
- }
- else
- dest->clientcert = NULL;
-
+ CLONE_STRING(CAfile);
+ CLONE_STRING(CApath);
+ CLONE_STRING(cipher_list);
+ CLONE_STRING(egdsocket);
+ CLONE_STRING(random_file);
+ CLONE_STRING(clientcert);
return TRUE;
}
-void Curl_free_ssl_config(struct ssl_config_data* sslc)
+void Curl_free_primary_ssl_config(struct ssl_primary_config* sslc)
{
Curl_safefree(sslc->CAfile);
Curl_safefree(sslc->CApath);
@@ -177,77 +133,6 @@ void Curl_free_ssl_config(struct ssl_config_data* sslc)
Curl_safefree(sslc->clientcert);
}
-
-/*
- * Curl_rand() returns a random unsigned integer, 32bit.
- *
- * This non-SSL function is put here only because this file is the only one
- * with knowledge of what the underlying SSL libraries provide in terms of
- * randomizers.
- *
- * NOTE: 'data' may be passed in as NULL when coming from external API without
- * easy handle!
- *
- */
-
-unsigned int Curl_rand(struct Curl_easy *data)
-{
- unsigned int r = 0;
- static unsigned int randseed;
- static bool seeded = FALSE;
-
-#ifdef CURLDEBUG
- char *force_entropy = getenv("CURL_ENTROPY");
- if(force_entropy) {
- if(!seeded) {
- size_t elen = strlen(force_entropy);
- size_t clen = sizeof(randseed);
- size_t min = elen < clen ? elen : clen;
- memcpy((char *)&randseed, force_entropy, min);
- seeded = TRUE;
- }
- else
- randseed++;
- return randseed;
- }
-#endif
-
- /* data may be NULL! */
- if(!Curl_ssl_random(data, (unsigned char *)&r, sizeof(r)))
- return r;
-
- /* If Curl_ssl_random() returns non-zero it couldn't offer randomness and we
- instead perform a "best effort" */
-
-#ifdef RANDOM_FILE
- if(!seeded) {
- /* if there's a random file to read a seed from, use it */
- int fd = open(RANDOM_FILE, O_RDONLY);
- if(fd > -1) {
- /* read random data into the randseed variable */
- ssize_t nread = read(fd, &randseed, sizeof(randseed));
- if(nread == sizeof(randseed))
- seeded = TRUE;
- close(fd);
- }
- }
-#endif
-
- if(!seeded) {
- struct timeval now = curlx_tvnow();
- infof(data, "WARNING: Using weak random seed\n");
- randseed += (unsigned int)now.tv_usec + (unsigned int)now.tv_sec;
- randseed = randseed * 1103515245 + 12345;
- randseed = randseed * 1103515245 + 12345;
- randseed = randseed * 1103515245 + 12345;
- seeded = TRUE;
- }
-
- /* Return an unsigned 32-bit pseudo-random number. */
- r = randseed = randseed * 1103515245 + 12345;
- return (r << 16) | ((r >> 16) & 0xFFFF);
-}
-
int Curl_ssl_backend(void)
{
return (int)CURL_SSL_BACKEND;
@@ -288,19 +173,41 @@ void Curl_ssl_cleanup(void)
static bool ssl_prefs_check(struct Curl_easy *data)
{
/* check for CURLOPT_SSLVERSION invalid parameter value */
- if((data->set.ssl.version < 0)
- || (data->set.ssl.version >= CURL_SSLVERSION_LAST)) {
+ if((data->set.ssl.primary.version < 0)
+ || (data->set.ssl.primary.version >= CURL_SSLVERSION_LAST)) {
failf(data, "Unrecognized parameter value passed via CURLOPT_SSLVERSION");
return FALSE;
}
return TRUE;
}
+static CURLcode
+ssl_connect_init_proxy(struct connectdata *conn, int sockindex)
+{
+ DEBUGASSERT(conn->bits.proxy_ssl_connected[sockindex]);
+ if(ssl_connection_complete == conn->ssl[sockindex].state &&
+ !conn->proxy_ssl[sockindex].use) {
+#if defined(HTTPS_PROXY_SUPPORT)
+ conn->proxy_ssl[sockindex] = conn->ssl[sockindex];
+ memset(&conn->ssl[sockindex], 0, sizeof(conn->ssl[sockindex]));
+#else
+ return CURLE_NOT_BUILT_IN;
+#endif
+ }
+ return CURLE_OK;
+}
+
CURLcode
Curl_ssl_connect(struct connectdata *conn, int sockindex)
{
CURLcode result;
+ if(conn->bits.proxy_ssl_connected[sockindex]) {
+ result = ssl_connect_init_proxy(conn, sockindex);
+ if(result)
+ return result;
+ }
+
if(!ssl_prefs_check(conn->data))
return CURLE_SSL_CONNECT_ERROR;
@@ -321,6 +228,11 @@ Curl_ssl_connect_nonblocking(struct connectdata *conn, int sockindex,
bool *done)
{
CURLcode result;
+ if(conn->bits.proxy_ssl_connected[sockindex]) {
+ result = ssl_connect_init_proxy(conn, sockindex);
+ if(result)
+ return result;
+ }
if(!ssl_prefs_check(conn->data))
return CURLE_SSL_CONNECT_ERROR;
@@ -363,7 +275,8 @@ void Curl_ssl_sessionid_unlock(struct connectdata *conn)
*/
bool Curl_ssl_getsessionid(struct connectdata *conn,
void **ssl_sessionid,
- size_t *idsize) /* set 0 if unknown */
+ size_t *idsize, /* set 0 if unknown */
+ int sockindex)
{
struct curl_ssl_session *check;
struct Curl_easy *data = conn->data;
@@ -371,11 +284,18 @@ bool Curl_ssl_getsessionid(struct connectdata *conn,
long *general_age;
bool no_match = TRUE;
+ const bool isProxy = CONNECT_PROXY_SSL();
+ struct ssl_primary_config * const ssl_config = isProxy ?
+ &conn->proxy_ssl_config :
+ &conn->ssl_config;
+ const char * const name = isProxy ? conn->http_proxy.host.name :
+ conn->host.name;
+ int port = isProxy ? (int)conn->port : conn->remote_port;
*ssl_sessionid = NULL;
- DEBUGASSERT(conn->ssl_config.sessionid);
+ DEBUGASSERT(data->set.general_ssl.sessionid);
- if(!conn->ssl_config.sessionid)
+ if(!data->set.general_ssl.sessionid)
/* session ID re-use is disabled */
return TRUE;
@@ -385,21 +305,21 @@ bool Curl_ssl_getsessionid(struct connectdata *conn,
else
general_age = &data->state.sessionage;
- for(i = 0; i < data->set.ssl.max_ssl_sessions; i++) {
+ for(i = 0; i < data->set.general_ssl.max_ssl_sessions; i++) {
check = &data->state.session[i];
if(!check->sessionid)
/* not session ID means blank entry */
continue;
- if(strcasecompare(conn->host.name, check->name) &&
+ if(strcasecompare(name, check->name) &&
((!conn->bits.conn_to_host && !check->conn_to_host) ||
(conn->bits.conn_to_host && check->conn_to_host &&
strcasecompare(conn->conn_to_host.name, check->conn_to_host))) &&
((!conn->bits.conn_to_port && check->conn_to_port == -1) ||
(conn->bits.conn_to_port && check->conn_to_port != -1 &&
conn->conn_to_port == check->conn_to_port)) &&
- (conn->remote_port == check->remote_port) &&
+ (port == check->remote_port) &&
strcasecompare(conn->handler->scheme, check->scheme) &&
- Curl_ssl_config_matches(&conn->ssl_config, &check->ssl_config)) {
+ Curl_ssl_config_matches(ssl_config, &check->ssl_config)) {
/* yes, we have a session ID! */
(*general_age)++; /* increase general age */
check->age = *general_age; /* set this as used in this age */
@@ -428,7 +348,7 @@ void Curl_ssl_kill_session(struct curl_ssl_session *session)
session->sessionid = NULL;
session->age = 0; /* fresh */
- Curl_free_ssl_config(&session->ssl_config);
+ Curl_free_primary_ssl_config(&session->ssl_config);
Curl_safefree(session->name);
Curl_safefree(session->conn_to_host);
@@ -443,7 +363,7 @@ void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid)
size_t i;
struct Curl_easy *data=conn->data;
- for(i = 0; i < data->set.ssl.max_ssl_sessions; i++) {
+ for(i = 0; i < data->set.general_ssl.max_ssl_sessions; i++) {
struct curl_ssl_session *check = &data->state.session[i];
if(check->sessionid == ssl_sessionid) {
@@ -461,7 +381,8 @@ void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid)
*/
CURLcode Curl_ssl_addsessionid(struct connectdata *conn,
void *ssl_sessionid,
- size_t idsize)
+ size_t idsize,
+ int sockindex)
{
size_t i;
struct Curl_easy *data=conn->data; /* the mother of all structs */
@@ -471,10 +392,14 @@ CURLcode Curl_ssl_addsessionid(struct connectdata *conn,
char *clone_conn_to_host;
int conn_to_port;
long *general_age;
+ const bool isProxy = CONNECT_PROXY_SSL();
+ struct ssl_primary_config * const ssl_config = isProxy ?
+ &conn->proxy_ssl_config :
+ &conn->ssl_config;
- DEBUGASSERT(conn->ssl_config.sessionid);
+ DEBUGASSERT(data->set.general_ssl.sessionid);
- clone_host = strdup(conn->host.name);
+ clone_host = strdup(isProxy ? conn->http_proxy.host.name : conn->host.name);
if(!clone_host)
return CURLE_OUT_OF_MEMORY; /* bail out */
@@ -505,14 +430,14 @@ CURLcode Curl_ssl_addsessionid(struct connectdata *conn,
}
/* find an empty slot for us, or find the oldest */
- for(i = 1; (i < data->set.ssl.max_ssl_sessions) &&
+ for(i = 1; (i < data->set.general_ssl.max_ssl_sessions) &&
data->state.session[i].sessionid; i++) {
if(data->state.session[i].age < oldest_age) {
oldest_age = data->state.session[i].age;
store = &data->state.session[i];
}
}
- if(i == data->set.ssl.max_ssl_sessions)
+ if(i == data->set.general_ssl.max_ssl_sessions)
/* cache is full, we must "kill" the oldest entry! */
Curl_ssl_kill_session(store);
else
@@ -528,10 +453,11 @@ CURLcode Curl_ssl_addsessionid(struct connectdata *conn,
store->name = clone_host; /* clone host name */
store->conn_to_host = clone_conn_to_host; /* clone connect to host name */
store->conn_to_port = conn_to_port; /* connect to port number */
- store->remote_port = conn->remote_port; /* port number */
+ /* port number */
+ store->remote_port = isProxy ? (int)conn->port : conn->remote_port;
store->scheme = conn->handler->scheme;
- if(!Curl_clone_ssl_config(&conn->ssl_config, &store->ssl_config)) {
+ if(!Curl_clone_primary_ssl_config(ssl_config, &store->ssl_config)) {
store->sessionid = NULL; /* let caller free sessionid */
free(clone_host);
free(clone_conn_to_host);
@@ -547,7 +473,7 @@ void Curl_ssl_close_all(struct Curl_easy *data)
size_t i;
/* kill the session ID cache if not shared */
if(data->state.session && !SSLSESSION_SHARED(data)) {
- for(i = 0; i < data->set.ssl.max_ssl_sessions; i++)
+ for(i = 0; i < data->set.general_ssl.max_ssl_sessions; i++)
/* the single-killer function handles empty table slots */
Curl_ssl_kill_session(&data->state.session[i]);
@@ -558,6 +484,43 @@ void Curl_ssl_close_all(struct Curl_easy *data)
curlssl_close_all(data);
}
+#if defined(USE_SSLEAY) || defined(USE_GNUTLS) || defined(USE_SCHANNEL) || \
+ defined(USE_DARWINSSL) || defined(USE_NSS)
+/* This function is for OpenSSL, GnuTLS, darwinssl, and schannel only. */
+int Curl_ssl_getsock(struct connectdata *conn, curl_socket_t *socks,
+ int numsocks)
+{
+ struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET];
+
+ if(!numsocks)
+ return GETSOCK_BLANK;
+
+ if(connssl->connecting_state == ssl_connect_2_writing) {
+ /* write mode */
+ socks[0] = conn->sock[FIRSTSOCKET];
+ return GETSOCK_WRITESOCK(0);
+ }
+ else if(connssl->connecting_state == ssl_connect_2_reading) {
+ /* read mode */
+ socks[0] = conn->sock[FIRSTSOCKET];
+ return GETSOCK_READSOCK(0);
+ }
+
+ return GETSOCK_BLANK;
+}
+#else
+int Curl_ssl_getsock(struct connectdata *conn,
+ curl_socket_t *socks,
+ int numsocks)
+{
+ (void)conn;
+ (void)socks;
+ (void)numsocks;
+ return GETSOCK_BLANK;
+}
+/* USE_SSLEAY || USE_GNUTLS || USE_SCHANNEL || USE_DARWINSSL || USE_NSS */
+#endif
+
void Curl_ssl_close(struct connectdata *conn, int sockindex)
{
DEBUGASSERT((sockindex <= 1) && (sockindex >= -1));
@@ -615,7 +578,7 @@ CURLcode Curl_ssl_initsessions(struct Curl_easy *data, size_t amount)
return CURLE_OUT_OF_MEMORY;
/* store the info in the SSL section */
- data->set.ssl.max_ssl_sessions = amount;
+ data->set.general_ssl.max_ssl_sessions = amount;
data->state.session = session;
data->state.sessionage = 1; /* this is brand new */
return CURLE_OK;
@@ -691,9 +654,9 @@ CURLcode Curl_ssl_push_certinfo_len(struct Curl_easy *data,
const char *value,
size_t valuelen)
{
- struct curl_certinfo * ci = &data->info.certs;
- char * output;
- struct curl_slist * nl;
+ struct curl_certinfo *ci = &data->info.certs;
+ char *output;
+ struct curl_slist *nl;
CURLcode result = CURLE_OK;
size_t labellen = strlen(label);
size_t outlen = labellen + 1 + valuelen + 1; /* label:value\0 */
@@ -736,11 +699,16 @@ CURLcode Curl_ssl_push_certinfo(struct Curl_easy *data,
return Curl_ssl_push_certinfo_len(data, certnum, label, value, valuelen);
}
-int Curl_ssl_random(struct Curl_easy *data,
- unsigned char *entropy,
- size_t length)
+CURLcode Curl_ssl_random(struct Curl_easy *data,
+ unsigned char *entropy,
+ size_t length)
{
- return curlssl_random(data, entropy, length);
+ int rc = curlssl_random(data, entropy, length);
+ if(rc) {
+ failf(data, "PRNG seeding failed");
+ return CURLE_FAILED_INIT; /* possibly weird return code */
+ }
+ return CURLE_OK;
}
/*
diff --git a/Utilities/cmcurl/lib/vtls/vtls.h b/Utilities/cmcurl/lib/vtls/vtls.h
index a41ecc3257..2aabeda20a 100644
--- a/Utilities/cmcurl/lib/vtls/vtls.h
+++ b/Utilities/cmcurl/lib/vtls/vtls.h
@@ -50,13 +50,24 @@
#define ALPN_HTTP_1_1_LENGTH 8
#define ALPN_HTTP_1_1 "http/1.1"
-bool Curl_ssl_config_matches(struct ssl_config_data* data,
- struct ssl_config_data* needle);
-bool Curl_clone_ssl_config(struct ssl_config_data* source,
- struct ssl_config_data* dest);
-void Curl_free_ssl_config(struct ssl_config_data* sslc);
-
-unsigned int Curl_rand(struct Curl_easy *);
+/* set of helper macros for the backends to access the correct fields. For the
+ proxy or for the remote host - to properly support HTTPS proxy */
+
+#define SSL_IS_PROXY() (CURLPROXY_HTTPS == conn->http_proxy.proxytype && \
+ ssl_connection_complete != conn->proxy_ssl[conn->sock[SECONDARYSOCKET] == \
+ CURL_SOCKET_BAD ? FIRSTSOCKET : SECONDARYSOCKET].state)
+#define SSL_SET_OPTION(var) (SSL_IS_PROXY() ? data->set.proxy_ssl.var : \
+ data->set.ssl.var)
+#define SSL_CONN_CONFIG(var) (SSL_IS_PROXY() ? \
+ conn->proxy_ssl_config.var : conn->ssl_config.var)
+
+bool Curl_ssl_config_matches(struct ssl_primary_config* data,
+ struct ssl_primary_config* needle);
+bool Curl_clone_primary_ssl_config(struct ssl_primary_config *source,
+ struct ssl_primary_config *dest);
+void Curl_free_primary_ssl_config(struct ssl_primary_config* sslc);
+int Curl_ssl_getsock(struct connectdata *conn, curl_socket_t *socks,
+ int numsocks);
int Curl_ssl_backend(void);
@@ -87,12 +98,12 @@ int Curl_ssl_check_cxn(struct connectdata *conn);
/* Certificate information list handling. */
void Curl_ssl_free_certinfo(struct Curl_easy *data);
-CURLcode Curl_ssl_init_certinfo(struct Curl_easy * data, int num);
-CURLcode Curl_ssl_push_certinfo_len(struct Curl_easy * data, int certnum,
- const char * label, const char * value,
+CURLcode Curl_ssl_init_certinfo(struct Curl_easy *data, int num);
+CURLcode Curl_ssl_push_certinfo_len(struct Curl_easy *data, int certnum,
+ const char *label, const char *value,
size_t valuelen);
-CURLcode Curl_ssl_push_certinfo(struct Curl_easy * data, int certnum,
- const char * label, const char * value);
+CURLcode Curl_ssl_push_certinfo(struct Curl_easy *data, int certnum,
+ const char *label, const char *value);
/* Functions to be used by SSL library adaptation functions */
@@ -116,7 +127,8 @@ void Curl_ssl_sessionid_unlock(struct connectdata *conn);
*/
bool Curl_ssl_getsessionid(struct connectdata *conn,
void **ssl_sessionid,
- size_t *idsize); /* set 0 if unknown */
+ size_t *idsize, /* set 0 if unknown */
+ int sockindex);
/* add a new session ID
* Sessionid mutex must be locked (see Curl_ssl_sessionid_lock).
* Caller must ensure that it has properly shared ownership of this sessionid
@@ -124,7 +136,8 @@ bool Curl_ssl_getsessionid(struct connectdata *conn,
*/
CURLcode Curl_ssl_addsessionid(struct connectdata *conn,
void *ssl_sessionid,
- size_t idsize);
+ size_t idsize,
+ int sockindex);
/* Kill a single session ID entry in the cache
* Sessionid mutex must be locked (see Curl_ssl_sessionid_lock).
* This will call engine-specific curlssl_session_free function, which must
@@ -140,10 +153,9 @@ void Curl_ssl_kill_session(struct curl_ssl_session *session);
*/
void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid);
-/* get N random bytes into the buffer, return 0 if a find random is filled
- in */
-int Curl_ssl_random(struct Curl_easy *data, unsigned char *buffer,
- size_t length);
+/* get N random bytes into the buffer */
+CURLcode Curl_ssl_random(struct Curl_easy *data, unsigned char *buffer,
+ size_t length);
CURLcode Curl_ssl_md5sum(unsigned char *tmp, /* input */
size_t tmplen,
unsigned char *md5sum, /* output */