69 changes: 36 additions & 33 deletions lib/vtls/axtls.c
Expand Up @@ -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;
Expand All @@ -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:
Expand All @@ -205,47 +205,47 @@ 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++;
}
/* 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;
}
}

/* 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++;
}
/* 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;
}
}
Expand All @@ -256,13 +256,14 @@ 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");
ssl = ssl_client_new(ssl_ctx, conn->sock[sockindex],
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -328,32 +333,30 @@ 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;
}
}

/* 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;
Expand All @@ -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);
}
}
}
Expand All @@ -383,12 +386,12 @@ 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)
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);
}
Expand Down
82 changes: 45 additions & 37 deletions lib/vtls/cyassl.c
Expand Up @@ -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 */
Expand Down Expand Up @@ -208,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 */
Expand All @@ -231,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 {
Expand All @@ -259,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;
Expand All @@ -290,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
Expand All @@ -299,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");
Expand Down Expand Up @@ -334,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"
Expand Down Expand Up @@ -380,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);
Expand Down Expand Up @@ -417,13 +420,17 @@ 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;

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;
}
Expand All @@ -447,31 +454,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;
}
Expand Down Expand Up @@ -587,15 +594,16 @@ 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;

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");
Expand All @@ -606,7 +614,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");
Expand Down
24 changes: 13 additions & 11 deletions lib/vtls/darwinssl.c
Expand Up @@ -1088,7 +1088,7 @@ 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) {
switch(conn->ssl_config.version) {
case CURL_SSLVERSION_DEFAULT:
case CURL_SSLVERSION_TLSv1:
(void)SSLSetProtocolVersionMin(connssl->ssl_ctx, kTLSProtocol1);
Expand Down Expand Up @@ -1135,7 +1135,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
(void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
kSSLProtocolAll,
false);
switch (data->set.ssl.version) {
switch (conn->ssl_config.version) {
case CURL_SSLVERSION_DEFAULT:
case CURL_SSLVERSION_TLSv1:
(void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
Expand Down Expand Up @@ -1192,7 +1192,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
}
#else
(void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, kSSLProtocolAll, false);
switch(data->set.ssl.version) {
switch(conn->ssl_config.version) {
case CURL_SSLVERSION_DEFAULT:
case CURL_SSLVERSION_TLSv1:
case CURL_SSLVERSION_TLSv1_0:
Expand Down Expand Up @@ -1349,7 +1349,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 ||
bool break_on_auth = !conn->ssl_config.verifypeer ||
data->set.str[STRING_SSL_CAFILE];
err = SSLSetSessionOption(connssl->ssl_ctx,
kSSLSessionOptionBreakOnServerAuth,
Expand All @@ -1362,7 +1362,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;
Expand All @@ -1371,7 +1371,7 @@ 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;
Expand All @@ -1396,7 +1396,7 @@ 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) {
if(conn->ssl_config.verifyhost) {
err = SSLSetPeerDomainName(connssl->ssl_ctx, conn->host.name,
strlen(conn->host.name));

Expand Down Expand Up @@ -1526,21 +1526,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);
Expand Down Expand Up @@ -1568,7 +1569,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");
Expand Down
317 changes: 275 additions & 42 deletions lib/vtls/gskit.c

Large diffs are not rendered by default.

241 changes: 144 additions & 97 deletions lib/vtls/gtls.c

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion lib/vtls/gtls.h
Expand Up @@ -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);
Expand Down Expand Up @@ -81,7 +83,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)
Expand Down
10 changes: 5 additions & 5 deletions lib/vtls/mbedtls.c
Expand Up @@ -372,11 +372,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);
Expand Down Expand Up @@ -613,7 +613,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;
Expand All @@ -632,10 +632,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);
Expand Down
168 changes: 106 additions & 62 deletions lib/vtls/nss.c
Expand Up @@ -337,9 +337,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))
Expand Down Expand Up @@ -585,6 +584,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 */

Expand All @@ -602,8 +602,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;
Expand Down Expand Up @@ -682,7 +681,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);
Expand All @@ -708,7 +707,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;
}
Expand Down Expand Up @@ -933,9 +932,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;

Expand Down Expand Up @@ -1372,36 +1374,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
Expand Down Expand Up @@ -1442,8 +1463,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);
Expand Down Expand Up @@ -1491,9 +1512,10 @@ 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) {
switch (SSL_CONN_CONFIG(version)) {
case CURL_SSLVERSION_DEFAULT:
/* map CURL_SSLVERSION_DEFAULT to NSS default */
if(SSL_VersionRangeGetDefault(ssl_variant_stream, sslver) != SECSuccess)
Expand Down Expand Up @@ -1614,6 +1636,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 */
Expand Down Expand Up @@ -1672,18 +1695,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 */
Expand All @@ -1695,54 +1718,59 @@ 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
* verify peer */
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;
goto error;
}
}

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;
Expand All @@ -1762,15 +1790,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;
}

Expand All @@ -1779,28 +1816,30 @@ 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;
}

/* 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;
}

PR_Close(model); /* We don't need this any more */
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;
Expand Down Expand Up @@ -1860,11 +1899,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;
Expand All @@ -1882,6 +1924,8 @@ 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;

/* check timeout situation */
const long time_left = Curl_timeleft(data, NULL, TRUE);
Expand All @@ -1897,9 +1941,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;
}
Expand All @@ -1908,11 +1952,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);
}
Expand Down
232 changes: 134 additions & 98 deletions lib/vtls/openssl.c

Large diffs are not rendered by default.

64 changes: 33 additions & 31 deletions lib/vtls/polarssl.c
Expand Up @@ -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;
}
Expand Down Expand Up @@ -180,56 +184,55 @@ 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;
}
}

/* 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)
Expand All @@ -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;
}
Expand All @@ -250,28 +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) {
switch(SSL_CONN_CONFIG(version)) {
case CURL_SSLVERSION_DEFAULT:
case CURL_SSLVERSION_TLSv1:
ssl_set_min_version(&connssl->ssl, SSL_MAJOR_VERSION_3,
Expand Down Expand Up @@ -325,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);
Expand All @@ -344,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. */
Expand Down Expand Up @@ -428,7 +430,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");

Expand Down Expand Up @@ -549,7 +551,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;
Expand All @@ -568,10 +570,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);
Expand Down
29 changes: 16 additions & 13 deletions lib/vtls/schannel.c
Expand Up @@ -142,9 +142,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");

Expand All @@ -161,7 +161,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. */
Expand All @@ -170,13 +170,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
Expand All @@ -189,14 +190,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) {
switch(conn->ssl_config.version) {
case CURL_SSLVERSION_DEFAULT:
case CURL_SSLVERSION_TLSv1:
schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_0_CLIENT |
Expand Down Expand Up @@ -628,7 +629,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

Expand Down Expand Up @@ -706,12 +707,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");
Expand All @@ -722,7 +724,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");
Expand Down Expand Up @@ -1551,7 +1554,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)) {
Expand Down Expand Up @@ -1587,7 +1590,7 @@ static CURLcode verify_certificate(struct connectdata *conn, int sockindex)
}

if(result == CURLE_OK) {
if(data->set.ssl.verifyhost) {
if(conn->ssl_config.verifyhost) {
TCHAR cert_hostname_buff[128];
xcharp_u hostname;
xcharp_u cert_hostname;
Expand Down
209 changes: 121 additions & 88 deletions lib/vtls/vtls.c
Expand Up @@ -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"
Expand All @@ -80,94 +81,48 @@
(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);
Expand Down Expand Up @@ -217,19 +172,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(USE_OPENSSL) || defined(USE_GNUTLS) || defined(USE_NSS) || \
defined(USE_GSKIT)
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;

Expand All @@ -250,6 +227,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;
Expand Down Expand Up @@ -292,19 +274,27 @@ 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;
size_t i;
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;

Expand All @@ -314,21 +304,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 */
Expand Down Expand Up @@ -357,7 +347,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);
Expand All @@ -372,7 +362,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) {
Expand All @@ -390,7 +380,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 */
Expand All @@ -400,10 +391,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 */

Expand Down Expand Up @@ -434,14 +429,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
Expand All @@ -457,10 +452,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);
Expand All @@ -476,7 +472,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]);

Expand All @@ -487,6 +483,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));
Expand Down Expand Up @@ -544,7 +577,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;
Expand Down
29 changes: 22 additions & 7 deletions lib/vtls/vtls.h
Expand Up @@ -50,11 +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);
/* 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);

Expand Down Expand Up @@ -114,15 +127,17 @@ 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
* object with cache (e.g. incrementing refcount on success)
*/
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
Expand Down
21 changes: 13 additions & 8 deletions lib/x509asn1.c
Expand Up @@ -1078,6 +1078,11 @@ CURLcode Curl_verifyhost(struct connectdata * conn,
int matched = -1;
size_t addrlen = (size_t) -1;
ssize_t len;
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
struct in6_addr addr;
#else
Expand All @@ -1087,19 +1092,19 @@ CURLcode Curl_verifyhost(struct connectdata * conn,
/* Verify that connection server matches info in X509 certificate at
`beg'..`end'. */

if(!data->set.ssl.verifyhost)
if(!SSL_CONN_CONFIG(verifyhost))
return CURLE_OK;

if(Curl_parseX509(&cert, beg, end))
return CURLE_PEER_FAILED_VERIFICATION;

/* Get the server IP address. */
#ifdef ENABLE_IPV6
if(conn->bits.ipv6_ip && Curl_inet_pton(AF_INET6, conn->host.name, &addr))
if(conn->bits.ipv6_ip && Curl_inet_pton(AF_INET6, hostname, &addr))
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))
addrlen = sizeof(struct in_addr);

/* Process extensions. */
Expand All @@ -1122,7 +1127,7 @@ CURLcode Curl_verifyhost(struct connectdata * conn,
len = utf8asn1str(&dnsname, CURL_ASN1_IA5_STRING,
name.beg, name.end);
if(len > 0 && (size_t)len == strlen(dnsname))
matched = Curl_cert_hostcheck(dnsname, conn->host.name);
matched = Curl_cert_hostcheck(dnsname, hostname);
else
matched = 0;
free(dnsname);
Expand All @@ -1140,12 +1145,12 @@ CURLcode Curl_verifyhost(struct connectdata * conn,
switch (matched) {
case 1:
/* an alternative name matched the server hostname */
infof(data, "\t subjectAltName: %s matched\n", conn->host.dispname);
infof(data, "\t subjectAltName: %s matched\n", dispname);
return CURLE_OK;
case 0:
/* an alternative name field existed, but didn't match and then
we MUST fail */
infof(data, "\t subjectAltName does not match %s\n", conn->host.dispname);
infof(data, "\t subjectAltName does not match %s\n", dispname);
return CURLE_PEER_FAILED_VERIFICATION;
}

Expand Down Expand Up @@ -1177,14 +1182,14 @@ CURLcode Curl_verifyhost(struct connectdata * conn,
}
if(strlen(dnsname) != (size_t) len) /* Nul byte in string ? */
failf(data, "SSL: illegal cert name field");
else if(Curl_cert_hostcheck((const char *) dnsname, conn->host.name)) {
else if(Curl_cert_hostcheck((const char *) dnsname, hostname)) {
infof(data, "\t common name: %s (matched)\n", dnsname);
free(dnsname);
return CURLE_OK;
}
else
failf(data, "SSL: certificate subject name '%s' does not match "
"target host name '%s'", dnsname, conn->host.dispname);
"target host name '%s'", dnsname, dispname);
free(dnsname);
}

Expand Down
13 changes: 13 additions & 0 deletions packages/OS400/README.OS400
Expand Up @@ -94,7 +94,19 @@ options:
CURLOPT_PROXYPASSWORD
CURLOPT_PROXYUSERNAME
CURLOPT_PROXYUSERPWD
CURLOPT_PROXY_CAINFO
CURLOPT_PROXY_CAPATH
CURLOPT_PROXY_CRLFILE
CURLOPT_PROXY_KEYPASSWD
CURLOPT_PROXY_SERVICE_NAME
CURLOPT_PROXY_SSLCERT
CURLOPT_PROXY_SSLCERTTYPE
CURLOPT_PROXY_SSL_CIPHER_LIST
CURLOPT_PROXY_SSLKEY
CURLOPT_PROXY_SSLKEYTYPE
CURLOPT_PROXY_TLSAUTH_PASSWORD
CURLOPT_PROXY_TLSAUTH_TYPE
CURLOPT_PROXY_TLSAUTH_USERNAME
CURLOPT_RANDOM_FILE
CURLOPT_RANGE
CURLOPT_REFERER
Expand All @@ -103,6 +115,7 @@ options:
CURLOPT_RTSP_TRANSPORT
CURLOPT_SERVICE_NAME
CURLOPT_SOCKS5_GSSAPI_SERVICE
CURLOPT_SOCKS_PROXY
CURLOPT_SSH_HOST_PUBLIC_KEY_MD5
CURLOPT_SSH_KNOWNHOSTS
CURLOPT_SSH_PRIVATE_KEYFILE
Expand Down
13 changes: 13 additions & 0 deletions packages/OS400/ccsidcurl.c
Expand Up @@ -1165,7 +1165,19 @@ curl_easy_setopt_ccsid(CURL * curl, CURLoption tag, ...)
case CURLOPT_PROXYPASSWORD:
case CURLOPT_PROXYUSERNAME:
case CURLOPT_PROXYUSERPWD:
case CURLOPT_PROXY_CAINFO:
case CURLOPT_PROXY_CAPATH:
case CURLOPT_PROXY_CRLFILE:
case CURLOPT_PROXY_KEYPASSWD:
case CURLOPT_PROXY_SERVICE_NAME:
case CURLOPT_PROXY_SSLCERT:
case CURLOPT_PROXY_SSLCERTTYPE:
case CURLOPT_PROXY_SSL_CIPHER_LIST:
case CURLOPT_PROXY_SSLKEY:
case CURLOPT_PROXY_SSLKEYTYPE:
case CURLOPT_PROXY_TLSAUTH_PASSWORD:
case CURLOPT_PROXY_TLSAUTH_TYPE:
case CURLOPT_PROXY_TLSAUTH_USERNAME:
case CURLOPT_RANDOM_FILE:
case CURLOPT_RANGE:
case CURLOPT_REFERER:
Expand All @@ -1174,6 +1186,7 @@ curl_easy_setopt_ccsid(CURL * curl, CURLoption tag, ...)
case CURLOPT_RTSP_TRANSPORT:
case CURLOPT_SERVICE_NAME:
case CURLOPT_SOCKS5_GSSAPI_SERVICE:
case CURLOPT_SOCKS_PROXY:
case CURLOPT_SSH_HOST_PUBLIC_KEY_MD5:
case CURLOPT_SSH_KNOWNHOSTS:
case CURLOPT_SSH_PRIVATE_KEYFILE:
Expand Down
40 changes: 40 additions & 0 deletions packages/OS400/curl.inc.in
Expand Up @@ -657,6 +657,8 @@
d c 0
d CURLPROXY_HTTP_1_0...
d c 1
d CURLPROXY_HTTPS...
d c 2
d CURLPROXY_SOCKS4...
d c 4
d CURLPROXY_SOCKS5...
Expand Down Expand Up @@ -1258,6 +1260,42 @@
d c 00244
d CURLOPT_KEEP_SENDING_ON_ERROR...
d c 00245
d CURLOPT_PROXY_CAINFO...
d c 10246
d CURLOPT_PROXY_CAPATH...
d c 10247
d CURLOPT_PROXY_SSL_VERIFYPEER...
d c 00248
d CURLOPT_PROXY_SSL_VERIFYHOST...
d c 00249
d CURLOPT_PROXY_SSLVERSION...
d c 00250
d CURLOPT_PROXY_TLSAUTH_USERNAME...
d c 10251
d CURLOPT_PROXY_TLSAUTH_PASSWORD...
d c 10252
d CURLOPT_PROXY_TLSAUTH_TYPE...
d c 10253
d CURLOPT_PROXY_SSLCERT...
d c 10254
d CURLOPT_PROXY_SSLCERTTYPE...
d c 10255
d CURLOPT_PROXY_SSLKEY...
d c 10256
d CURLOPT_PROXY_SSLKEYTYPE...
d c 10257
d CURLOPT_PROXY_KEYPASSWD...
d c 10258
d CURLOPT_PROXY_SSL_CIPHER_LIST...
d c 10259
d CURLOPT_PROXY_CRLFILE...
d c 10260
d CURLOPT_PROXY_SSL_OPTIONS...
d c 00261
d CURLOPT_SOCKS_PROXY...
d c 10262
d CURLOPT_SOCKS_PROXYTYPE...
d c 00263
*
/if not defined(CURL_NO_OLDIES)
d CURLOPT_FILE c 10001
Expand Down Expand Up @@ -1444,6 +1482,8 @@
d c X'0040002D'
d CURLINFO_HTTP_VERSION... CURLINFO_LONG + 46
d c X'0020002E'
d CURLINFO_PROXY_SSL_VERIFYRESULT... CURLINFO_LONG + 45
d c X'0020002F'
*
d CURLINFO_HTTP_CODE... Old ...RESPONSE_CODE
d c X'00200002'
Expand Down
12 changes: 12 additions & 0 deletions src/tool_cfgable.c
Expand Up @@ -68,6 +68,9 @@ static void free_config_fields(struct OperationConfig *config)
Curl_safefree(config->tls_username);
Curl_safefree(config->tls_password);
Curl_safefree(config->tls_authtype);
Curl_safefree(config->proxy_tls_username);
Curl_safefree(config->proxy_tls_password);
Curl_safefree(config->proxy_tls_authtype);
Curl_safefree(config->proxyuserpwd);
Curl_safefree(config->proxy);

Expand Down Expand Up @@ -99,15 +102,24 @@ static void free_config_fields(struct OperationConfig *config)
config->url_out = NULL;

Curl_safefree(config->cipher_list);
Curl_safefree(config->proxy_cipher_list);
Curl_safefree(config->cert);
Curl_safefree(config->proxy_cert);
Curl_safefree(config->cert_type);
Curl_safefree(config->proxy_cert_type);
Curl_safefree(config->cacert);
Curl_safefree(config->proxy_cacert);
Curl_safefree(config->capath);
Curl_safefree(config->proxy_capath);
Curl_safefree(config->crlfile);
Curl_safefree(config->pinnedpubkey);
Curl_safefree(config->proxy_crlfile);
Curl_safefree(config->key);
Curl_safefree(config->proxy_key);
Curl_safefree(config->key_type);
Curl_safefree(config->proxy_key_type);
Curl_safefree(config->key_passwd);
Curl_safefree(config->proxy_key_passwd);
Curl_safefree(config->pubkey);
Curl_safefree(config->hostpubmd5);
Curl_safefree(config->engine);
Expand Down
18 changes: 18 additions & 0 deletions src/tool_cfgable.h
Expand Up @@ -78,6 +78,9 @@ struct OperationConfig {
char *tls_username;
char *tls_password;
char *tls_authtype;
char *proxy_tls_username;
char *proxy_tls_password;
char *proxy_tls_authtype;
char *proxyuserpwd;
char *proxy;
int proxyver; /* set to CURLPROXY_HTTP* define */
Expand Down Expand Up @@ -106,15 +109,24 @@ struct OperationConfig {
struct getout *url_get; /* point to the node to fill in URL */
struct getout *url_out; /* point to the node to fill in outfile */
char *cipher_list;
char *proxy_cipher_list;
char *cert;
char *proxy_cert;
char *cert_type;
char *proxy_cert_type;
char *cacert;
char *proxy_cacert;
char *capath;
char *proxy_capath;
char *crlfile;
char *proxy_crlfile;
char *pinnedpubkey;
char *key;
char *proxy_key;
char *key_type;
char *proxy_key_type;
char *key_passwd;
char *proxy_key_passwd;
char *pubkey;
char *hostpubmd5;
char *engine;
Expand All @@ -127,6 +139,8 @@ struct OperationConfig {
bool globoff;
bool use_httpget;
bool insecure_ok; /* set TRUE to allow insecure SSL connects */
bool proxy_insecure_ok; /* set TRUE to allow insecure SSL connects
for proxy */
bool verifystatus;
bool create_dirs;
bool ftp_create_dirs;
Expand All @@ -142,6 +156,7 @@ struct OperationConfig {
struct curl_slist *postquote;
struct curl_slist *prequote;
long ssl_version;
long proxy_ssl_version;
long ip_version;
curl_TimeCond timecond;
time_t condtime;
Expand Down Expand Up @@ -202,7 +217,10 @@ struct OperationConfig {
bool xattr; /* store metadata in extended attributes */
long gssapi_delegation;
bool ssl_allow_beast; /* allow this SSL vulnerability */
bool proxy_ssl_allow_beast; /* allow this SSL vulnerability for proxy*/

bool ssl_no_revoke; /* disable SSL certificate revocation checks */
/*bool proxy_ssl_no_revoke; */

bool use_metalink; /* process given URLs as metalink XML file */
metalinkfile *metalinkfile_list; /* point to the first node */
Expand Down
138 changes: 128 additions & 10 deletions src/tool_getparam.c
Expand Up @@ -230,6 +230,24 @@ static const struct LongShort aliases[]= {
{"Er", "false-start", FALSE},
{"Es", "ssl-no-revoke", FALSE},
{"Et", "tcp-fastopen", FALSE},
{"Eu", "proxy-tlsuser", TRUE},
{"Ev", "proxy-tlspassword", TRUE},
{"Ew", "proxy-tlsauthtype", TRUE},
{"Ex", "proxy-cert", TRUE},
{"Ey", "proxy-cert-type", TRUE},
{"Ez", "proxy-key", TRUE},
{"E0", "proxy-key-type", TRUE},
{"E1", "proxy-pass", TRUE},
{"E2", "proxy-ciphers", TRUE},
{"E3", "proxy-crlfile", TRUE},
{"E4", "proxy-ssl-allow-beast", FALSE},
{"E5", "login-options", TRUE},
{"E6", "proxy-cacert", TRUE},
{"E7", "proxy-capath", TRUE},
{"E8", "proxy-insecure", FALSE},
{"E9", "proxy-tlsv1", FALSE},
{"EA", "proxy-sslv2", FALSE},
{"EB", "proxy-sslv3", FALSE},
{"f", "fail", FALSE},
{"fa", "fail-early", FALSE},
{"F", "form", TRUE},
Expand Down Expand Up @@ -384,6 +402,20 @@ void parse_cert_parameter(const char *cert_parameter,
*certname_place = '\0';
}

static void
GetFileAndPassword(char *nextarg, char **file, char **password)
{
char *certname, *passphrase;
parse_cert_parameter(nextarg, &certname, &passphrase);
Curl_safefree(*file);
*file = certname;
if(passphrase) {
Curl_safefree(*password);
*password = passphrase;
}
cleanarg(nextarg);
}

ParameterError getparameter(char *flag, /* f or -long-flag */
char *nextarg, /* NULL if unset */
bool *usedarg, /* set to TRUE if the arg
Expand Down Expand Up @@ -1334,6 +1366,9 @@ ParameterError getparameter(char *flag, /* f or -long-flag */
break;
case 'E':
switch(subletter) {
case '\0': /* certificate file */
GetFileAndPassword(nextarg, &config->cert, &config->key_passwd);
break;
case 'a': /* CA info PEM file */
/* CA info PEM file */
GetStr(&config->cacert, nextarg);
Expand Down Expand Up @@ -1424,18 +1459,101 @@ ParameterError getparameter(char *flag, /* f or -long-flag */
config->tcp_fastopen = TRUE;
break;

default: /* certificate file */
{
char *certname, *passphrase;
parse_cert_parameter(nextarg, &certname, &passphrase);
Curl_safefree(config->cert);
config->cert = certname;
if(passphrase) {
Curl_safefree(config->key_passwd);
config->key_passwd = passphrase;
case 'u': /* TLS username for proxy */
if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP)
GetStr(&config->proxy_tls_username, nextarg);
else
return PARAM_LIBCURL_DOESNT_SUPPORT;
break;

case 'v': /* TLS password for proxy */
if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP)
GetStr(&config->proxy_tls_password, nextarg);
else
return PARAM_LIBCURL_DOESNT_SUPPORT;
break;

case 'w': /* TLS authentication type for proxy */
if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP) {
GetStr(&config->proxy_tls_authtype, nextarg);
if(!curl_strequal(config->proxy_tls_authtype, "SRP"))
return PARAM_LIBCURL_DOESNT_SUPPORT; /* only support TLS-SRP */
}
else
return PARAM_LIBCURL_DOESNT_SUPPORT;
break;

case 'x': /* certificate file for proxy */
GetFileAndPassword(nextarg, &config->proxy_cert,
&config->proxy_key_passwd);
break;

case 'y': /* cert file type for proxy */
GetStr(&config->proxy_cert_type, nextarg);
break;

case 'z': /* private key file for proxy */
GetStr(&config->proxy_key, nextarg);
break;

case '0': /* private key file type for proxy */
GetStr(&config->proxy_key_type, nextarg);
break;

case '1': /* private key passphrase for proxy */
GetStr(&config->proxy_key_passwd, nextarg);
cleanarg(nextarg);
}
break;

case '2': /* ciphers for proxy */
GetStr(&config->proxy_cipher_list, nextarg);
break;

case '3': /* CRL info PEM file for proxy */
/* CRL file */
GetStr(&config->proxy_crlfile, nextarg);
break;

case '4': /* no empty SSL fragments for proxy */
if(curlinfo->features & CURL_VERSION_SSL)
config->proxy_ssl_allow_beast = toggle;
break;

case '5': /* --login-options */
GetStr(&config->login_options, nextarg);
break;

case '6': /* CA info PEM file for proxy */
/* CA info PEM file */
GetStr(&config->proxy_cacert, nextarg);
break;

case '7': /* CA info PEM file for proxy */
/* CA cert directory */
GetStr(&config->proxy_capath, nextarg);
break;

case '8': /* allow insecure SSL connects for proxy */
config->proxy_insecure_ok = toggle;
break;

case '9':
/* TLS version 1 for proxy */
config->proxy_ssl_version = CURL_SSLVERSION_TLSv1;
break;

case 'A':
/* SSL version 2 for proxy */
config->proxy_ssl_version = CURL_SSLVERSION_SSLv2;
break;

case 'B':
/* SSL version 3 for proxy */
config->proxy_ssl_version = CURL_SSLVERSION_SSLv3;
break;

default: /* unknown flag */
return PARAM_OPTION_UNKNOWN;
}
break;
case 'f':
Expand Down
26 changes: 26 additions & 0 deletions src/tool_help.c
Expand Up @@ -176,10 +176,36 @@ static const char *const helptext[] = {
" --proxy-anyauth Pick \"any\" proxy authentication method (H)",
" --proxy-basic Use Basic authentication on the proxy (H)",
" --proxy-digest Use Digest authentication on the proxy (H)",
" --proxy-cacert FILE "
"CA certificate to verify peer against for proxy (SSL)",
" --proxy-capath DIR "
"CA directory to verify peer against for proxy (SSL)",
" --proxy-cert CERT[:PASSWD] "
"Client certificate file and password for proxy (SSL)",
" --proxy-cert-type TYPE "
"Certificate file type (DER/PEM/ENG) for proxy (SSL)",
" --proxy-ciphers LIST SSL ciphers to use for proxy (SSL)",
" --proxy-crlfile FILE "
"Get a CRL list in PEM format from the given file for proxy",
" --proxy-insecure "
"Allow connections to SSL sites without certs for proxy (H)",
" --proxy-key KEY Private key file name for proxy (SSL)",
" --proxy-key-type TYPE "
"Private key file type for proxy (DER/PEM/ENG) (SSL)",
" --proxy-negotiate "
"Use HTTP Negotiate (SPNEGO) authentication on the proxy (H)",
" --proxy-ntlm Use NTLM authentication on the proxy (H)",
" --proxy-header LINE Pass custom header LINE to proxy (H)",
" --proxy-pass PASS Pass phrase for the private key for proxy (SSL)",
" --proxy-ssl-allow-beast "
"Allow security flaw to improve interop for proxy (SSL)",
" --proxy-sslv2 Use SSLv2 for proxy (SSL)",
" --proxy-sslv3 Use SSLv3 for proxy (SSL)",
" --proxy-tlsv1 Use TLSv1 for proxy (SSL)",
" --proxy-tlsuser USER TLS username for proxy",
" --proxy-tlspassword STRING TLS password for proxy",
" --proxy-tlsauthtype STRING "
"TLS authentication type for proxy (default SRP)",
" --proxy-service-name NAME SPNEGO proxy service name",
" --service-name NAME SPNEGO service name",
" -U, --proxy-user USER[:PASSWORD] Proxy user and password",
Expand Down
49 changes: 47 additions & 2 deletions src/tool_operate.c
Expand Up @@ -869,8 +869,9 @@ static CURLcode operate_do(struct GlobalConfig *global,

/* new in libcurl 7.10 */
if(config->socksproxy) {
my_setopt_str(curl, CURLOPT_PROXY, config->socksproxy);
my_setopt_enum(curl, CURLOPT_PROXYTYPE, (long)config->socksver);
my_setopt_str(curl, CURLOPT_SOCKS_PROXY, config->socksproxy);
my_setopt_enum(curl, CURLOPT_SOCKS_PROXYTYPE,
(long)config->socksver);
}

/* new in libcurl 7.10.6 */
Expand Down Expand Up @@ -1000,6 +1001,7 @@ static CURLcode operate_do(struct GlobalConfig *global,
my_setopt(curl, CURLOPT_RESUME_FROM_LARGE, CURL_OFF_T_C(0));

my_setopt_str(curl, CURLOPT_KEYPASSWD, config->key_passwd);
my_setopt_str(curl, CURLOPT_PROXY_KEYPASSWD, config->proxy_key_passwd);

if(built_in_protos & (CURLPROTO_SCP|CURLPROTO_SFTP)) {

Expand All @@ -1017,6 +1019,8 @@ static CURLcode operate_do(struct GlobalConfig *global,

if(config->cacert)
my_setopt_str(curl, CURLOPT_CAINFO, config->cacert);
if(config->proxy_cacert)
my_setopt_str(curl, CURLOPT_PROXY_CAINFO, config->proxy_cacert);
if(config->capath) {
result = res_setopt_str(curl, CURLOPT_CAPATH, config->capath);
if(result == CURLE_NOT_BUILT_IN) {
Expand All @@ -1027,17 +1031,32 @@ static CURLcode operate_do(struct GlobalConfig *global,
else if(result)
goto show_error;
}
if(config->proxy_capath)
my_setopt_str(curl, CURLOPT_PROXY_CAPATH, config->proxy_capath);
else if(config->capath) /* CURLOPT_PROXY_CAPATH default is capath */
my_setopt_str(curl, CURLOPT_PROXY_CAPATH, config->capath);

if(config->crlfile)
my_setopt_str(curl, CURLOPT_CRLFILE, config->crlfile);
if(config->proxy_crlfile)
my_setopt_str(curl, CURLOPT_PROXY_CRLFILE, config->proxy_crlfile);
else if(config->crlfile) /* CURLOPT_PROXY_CRLFILE default is crlfile */
my_setopt_str(curl, CURLOPT_PROXY_CRLFILE, config->crlfile);

if(config->pinnedpubkey)
my_setopt_str(curl, CURLOPT_PINNEDPUBLICKEY, config->pinnedpubkey);

if(curlinfo->features & CURL_VERSION_SSL) {
my_setopt_str(curl, CURLOPT_SSLCERT, config->cert);
my_setopt_str(curl, CURLOPT_PROXY_SSLCERT, config->proxy_cert);
my_setopt_str(curl, CURLOPT_SSLCERTTYPE, config->cert_type);
my_setopt_str(curl, CURLOPT_PROXY_SSLCERTTYPE,
config->proxy_cert_type);
my_setopt_str(curl, CURLOPT_SSLKEY, config->key);
my_setopt_str(curl, CURLOPT_PROXY_SSLKEY, config->proxy_key);
my_setopt_str(curl, CURLOPT_SSLKEYTYPE, config->key_type);
my_setopt_str(curl, CURLOPT_PROXY_SSLKEYTYPE,
config->proxy_key_type);

if(config->insecure_ok) {
my_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
Expand All @@ -1048,6 +1067,13 @@ static CURLcode operate_do(struct GlobalConfig *global,
/* libcurl default is strict verifyhost -> 2L */
/* my_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L); */
}
if(config->proxy_insecure_ok) {
my_setopt(curl, CURLOPT_PROXY_SSL_VERIFYPEER, 0L);
my_setopt(curl, CURLOPT_PROXY_SSL_VERIFYHOST, 0L);
}
else {
my_setopt(curl, CURLOPT_PROXY_SSL_VERIFYPEER, 1L);
}

if(config->verifystatus)
my_setopt(curl, CURLOPT_SSL_VERIFYSTATUS, 1L);
Expand All @@ -1056,6 +1082,8 @@ static CURLcode operate_do(struct GlobalConfig *global,
my_setopt(curl, CURLOPT_SSL_FALSESTART, 1L);

my_setopt_enum(curl, CURLOPT_SSLVERSION, config->ssl_version);
my_setopt_enum(curl, CURLOPT_PROXY_SSLVERSION,
config->proxy_ssl_version);
}
if(config->path_as_is)
my_setopt(curl, CURLOPT_PATH_AS_IS, 1L);
Expand Down Expand Up @@ -1157,6 +1185,10 @@ static CURLcode operate_do(struct GlobalConfig *global,
if(config->cipher_list)
my_setopt_str(curl, CURLOPT_SSL_CIPHER_LIST, config->cipher_list);

if(config->proxy_cipher_list)
my_setopt_str(curl, CURLOPT_PROXY_SSL_CIPHER_LIST,
config->proxy_cipher_list);

/* new in libcurl 7.9.2: */
if(config->disable_epsv)
/* disable it */
Expand Down Expand Up @@ -1325,6 +1357,15 @@ static CURLcode operate_do(struct GlobalConfig *global,
if(config->tls_authtype)
my_setopt_str(curl, CURLOPT_TLSAUTH_TYPE,
config->tls_authtype);
if(config->proxy_tls_username)
my_setopt_str(curl, CURLOPT_PROXY_TLSAUTH_USERNAME,
config->proxy_tls_username);
if(config->proxy_tls_password)
my_setopt_str(curl, CURLOPT_PROXY_TLSAUTH_PASSWORD,
config->proxy_tls_password);
if(config->proxy_tls_authtype)
my_setopt_str(curl, CURLOPT_PROXY_TLSAUTH_TYPE,
config->proxy_tls_authtype);
}

/* new in 7.22.0 */
Expand All @@ -1340,6 +1381,10 @@ static CURLcode operate_do(struct GlobalConfig *global,
my_setopt_bitmask(curl, CURLOPT_SSL_OPTIONS, mask);
}

if(config->proxy_ssl_allow_beast)
my_setopt(curl, CURLOPT_PROXY_SSL_OPTIONS,
(long)CURLSSLOPT_ALLOW_BEAST);

if(config->mail_auth)
my_setopt_str(curl, CURLOPT_MAIL_AUTH, config->mail_auth);

Expand Down
11 changes: 11 additions & 0 deletions src/tool_setopt.c
Expand Up @@ -45,6 +45,15 @@
const NameValue setopt_nv_CURLPROXY[] = {
NV(CURLPROXY_HTTP),
NV(CURLPROXY_HTTP_1_0),
NV(CURLPROXY_HTTPS),
NV(CURLPROXY_SOCKS4),
NV(CURLPROXY_SOCKS5),
NV(CURLPROXY_SOCKS4A),
NV(CURLPROXY_SOCKS5_HOSTNAME),
NVEND,
};

const NameValue setopt_nv_CURL_SOCKS_PROXY[] = {
NV(CURLPROXY_SOCKS4),
NV(CURLPROXY_SOCKS5),
NV(CURLPROXY_SOCKS4A),
Expand Down Expand Up @@ -159,6 +168,8 @@ static const NameValue setopt_nv_CURLNONZERODEFAULTS[] = {
NV1(CURLOPT_SSL_ENABLE_NPN, 1),
NV1(CURLOPT_SSL_ENABLE_ALPN, 1),
NV1(CURLOPT_TCP_NODELAY, 1),
NV1(CURLOPT_PROXY_SSL_VERIFYPEER, 1),
NV1(CURLOPT_PROXY_SSL_VERIFYHOST, 1),
NVEND
};

Expand Down
3 changes: 3 additions & 0 deletions src/tool_setopt.h
Expand Up @@ -47,6 +47,7 @@ typedef struct {
} NameValueUnsigned;

extern const NameValue setopt_nv_CURLPROXY[];
extern const NameValue setopt_nv_CURL_SOCKS_PROXY[];
extern const NameValue setopt_nv_CURL_HTTP_VERSION[];
extern const NameValue setopt_nv_CURL_SSLVERSION[];
extern const NameValue setopt_nv_CURL_TIMECOND[];
Expand All @@ -61,6 +62,7 @@ extern const NameValueUnsigned setopt_nv_CURLAUTH[];
#define setopt_nv_CURLOPT_HTTP_VERSION setopt_nv_CURL_HTTP_VERSION
#define setopt_nv_CURLOPT_HTTPAUTH setopt_nv_CURLAUTH
#define setopt_nv_CURLOPT_SSLVERSION setopt_nv_CURL_SSLVERSION
#define setopt_nv_CURLOPT_PROXY_SSLVERSION setopt_nv_CURL_SSLVERSION
#define setopt_nv_CURLOPT_TIMECONDITION setopt_nv_CURL_TIMECOND
#define setopt_nv_CURLOPT_FTP_SSL_CCC setopt_nv_CURLFTPSSL_CCC
#define setopt_nv_CURLOPT_USE_SSL setopt_nv_CURLUSESSL
Expand All @@ -69,6 +71,7 @@ extern const NameValueUnsigned setopt_nv_CURLAUTH[];
#define setopt_nv_CURLOPT_PROTOCOLS setopt_nv_CURLPROTO
#define setopt_nv_CURLOPT_REDIR_PROTOCOLS setopt_nv_CURLPROTO
#define setopt_nv_CURLOPT_PROXYTYPE setopt_nv_CURLPROXY
#define setopt_nv_CURLOPT_SOCKS_PROXYTYPE setopt_nv_CURL_SOCKS_PROXY
#define setopt_nv_CURLOPT_PROXYAUTH setopt_nv_CURLAUTH

/* Intercept setopt calls for --libcurl */
Expand Down
8 changes: 8 additions & 0 deletions src/tool_writeout.c
Expand Up @@ -52,6 +52,7 @@ typedef enum {
VAR_FTP_ENTRY_PATH,
VAR_REDIRECT_URL,
VAR_SSL_VERIFY_RESULT,
VAR_PROXY_SSL_VERIFY_RESULT,
VAR_EFFECTIVE_FILENAME,
VAR_PRIMARY_IP,
VAR_PRIMARY_PORT,
Expand Down Expand Up @@ -91,6 +92,7 @@ static const struct variable replacements[]={
{"ftp_entry_path", VAR_FTP_ENTRY_PATH},
{"redirect_url", VAR_REDIRECT_URL},
{"ssl_verify_result", VAR_SSL_VERIFY_RESULT},
{"proxy_ssl_verify_result", VAR_PROXY_SSL_VERIFY_RESULT},
{"filename_effective", VAR_EFFECTIVE_FILENAME},
{"remote_ip", VAR_PRIMARY_IP},
{"remote_port", VAR_PRIMARY_PORT},
Expand Down Expand Up @@ -252,6 +254,12 @@ void ourWriteOut(CURL *curl, struct OutStruct *outs, const char *writeinfo)
&longinfo))
fprintf(stream, "%ld", longinfo);
break;
case VAR_PROXY_SSL_VERIFY_RESULT:
if(CURLE_OK ==
curl_easy_getinfo(curl, CURLINFO_PROXY_SSL_VERIFYRESULT,
&longinfo))
fprintf(stream, "%ld", longinfo);
break;
case VAR_EFFECTIVE_FILENAME:
if(outs->filename)
fprintf(stream, "%s", outs->filename);
Expand Down