mirror of
https://github.com/curl/curl.git
synced 2025-03-25 15:50:32 +08:00
vtls/vquic, keep peer name information together
- add `struct ssl_peer` to keep hostname, dispname and sni for a filter - allocate `sni` for use in VTLS backend - eliminate `Curl_ssl_snihost()` and its use of the download buffer - use ssl_peer in SSL and QUIC filters Closes #12349
This commit is contained in:
parent
a9fd0d0083
commit
fa714830e9
@ -266,6 +266,13 @@ typedef enum {
|
||||
/* SSL backend-specific data; declared differently by each SSL backend */
|
||||
struct ssl_backend_data;
|
||||
|
||||
struct ssl_peer {
|
||||
char *hostname; /* hostname for verification */
|
||||
char *dispname; /* display version of hostname */
|
||||
char *sni; /* SNI version of hostname or NULL if not usable */
|
||||
BIT(is_ip_address); /* if hostname is an IPv4|6 address */
|
||||
};
|
||||
|
||||
struct ssl_primary_config {
|
||||
char *CApath; /* certificate dir (doesn't work on windows) */
|
||||
char *CAfile; /* certificate to verify peer against */
|
||||
|
@ -133,6 +133,7 @@ void Curl_ngtcp2_ver(char *p, size_t len)
|
||||
|
||||
struct cf_ngtcp2_ctx {
|
||||
struct cf_quic_ctx q;
|
||||
struct ssl_peer peer;
|
||||
ngtcp2_path connected_path;
|
||||
ngtcp2_conn *qconn;
|
||||
ngtcp2_cid dcid;
|
||||
@ -561,7 +562,6 @@ static CURLcode quic_init_ssl(struct Curl_cfilter *cf,
|
||||
struct cf_ngtcp2_ctx *ctx = cf->ctx;
|
||||
const uint8_t *alpn = NULL;
|
||||
size_t alpnlen = 0;
|
||||
unsigned char checkip[16];
|
||||
|
||||
DEBUGASSERT(!ctx->ssl);
|
||||
ctx->ssl = SSL_new(ctx->sslctx);
|
||||
@ -576,13 +576,8 @@ static CURLcode quic_init_ssl(struct Curl_cfilter *cf,
|
||||
SSL_set_alpn_protos(ctx->ssl, alpn, (int)alpnlen);
|
||||
|
||||
/* set SNI */
|
||||
if((0 == Curl_inet_pton(AF_INET, cf->conn->host.name, checkip))
|
||||
#ifdef ENABLE_IPV6
|
||||
&& (0 == Curl_inet_pton(AF_INET6, cf->conn->host.name, checkip))
|
||||
#endif
|
||||
) {
|
||||
char *snihost = Curl_ssl_snihost(data, cf->conn->host.name, NULL);
|
||||
if(!snihost || !SSL_set_tlsext_host_name(ctx->ssl, snihost)) {
|
||||
if(ctx->peer.sni) {
|
||||
if(!SSL_set_tlsext_host_name(ctx->ssl, ctx->peer.sni)) {
|
||||
failf(data, "Failed set SNI");
|
||||
SSL_free(ctx->ssl);
|
||||
ctx->ssl = NULL;
|
||||
@ -600,7 +595,6 @@ static CURLcode quic_init_ssl(struct Curl_cfilter *cf,
|
||||
CURLcode result;
|
||||
gnutls_datum_t alpn[2];
|
||||
/* this will need some attention when HTTPS proxy over QUIC get fixed */
|
||||
const char * const hostname = cf->conn->host.name;
|
||||
long * const pverifyresult = &data->set.ssl.certverifyresult;
|
||||
int rc;
|
||||
|
||||
@ -614,7 +608,7 @@ static CURLcode quic_init_ssl(struct Curl_cfilter *cf,
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
result = gtls_client_init(data, conn_config, &data->set.ssl,
|
||||
hostname, ctx->gtls, pverifyresult);
|
||||
&ctx->peer, ctx->gtls, pverifyresult);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
@ -1932,19 +1926,11 @@ static CURLcode qng_verify_peer(struct Curl_cfilter *cf,
|
||||
struct cf_ngtcp2_ctx *ctx = cf->ctx;
|
||||
struct ssl_primary_config *conn_config;
|
||||
CURLcode result = CURLE_OK;
|
||||
const char *hostname, *disp_hostname;
|
||||
int port;
|
||||
char *snihost;
|
||||
|
||||
conn_config = Curl_ssl_cf_get_primary_config(cf);
|
||||
if(!conn_config)
|
||||
return CURLE_FAILED_INIT;
|
||||
|
||||
Curl_conn_get_host(data, cf->sockindex, &hostname, &disp_hostname, &port);
|
||||
snihost = Curl_ssl_snihost(data, hostname, NULL);
|
||||
if(!snihost)
|
||||
return CURLE_PEER_FAILED_VERIFICATION;
|
||||
|
||||
cf->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
|
||||
cf->conn->httpversion = 30;
|
||||
cf->conn->bundle->multiuse = BUNDLE_MULTIPLEX;
|
||||
@ -1956,19 +1942,19 @@ static CURLcode qng_verify_peer(struct Curl_cfilter *cf,
|
||||
if(!server_cert) {
|
||||
return CURLE_PEER_FAILED_VERIFICATION;
|
||||
}
|
||||
result = Curl_ossl_verifyhost(data, cf->conn, server_cert);
|
||||
result = Curl_ossl_verifyhost(data, cf->conn, &ctx->peer, server_cert);
|
||||
X509_free(server_cert);
|
||||
if(result)
|
||||
return result;
|
||||
#elif defined(USE_GNUTLS)
|
||||
result = Curl_gtls_verifyserver(data, ctx->gtls->session,
|
||||
conn_config, &data->set.ssl,
|
||||
hostname, disp_hostname,
|
||||
conn_config, &data->set.ssl, &ctx->peer,
|
||||
data->set.str[STRING_SSL_PINNEDPUBLICKEY]);
|
||||
if(result)
|
||||
return result;
|
||||
#elif defined(USE_WOLFSSL)
|
||||
if(wolfSSL_check_domain_name(ctx->ssl, snihost) == SSL_FAILURE)
|
||||
if(!ctx->peer.sni ||
|
||||
wolfSSL_check_domain_name(ctx->ssl, ctx->peer.sni) == SSL_FAILURE)
|
||||
return CURLE_PEER_FAILED_VERIFICATION;
|
||||
#endif
|
||||
infof(data, "Verified certificate just fine");
|
||||
@ -2399,6 +2385,7 @@ static void cf_ngtcp2_ctx_clear(struct cf_ngtcp2_ctx *ctx)
|
||||
if(ctx->qconn)
|
||||
ngtcp2_conn_del(ctx->qconn);
|
||||
Curl_bufcp_free(&ctx->stream_bufcp);
|
||||
Curl_ssl_peer_cleanup(&ctx->peer);
|
||||
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
ctx->qlogfd = -1;
|
||||
@ -2470,6 +2457,10 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf,
|
||||
Curl_bufcp_init(&ctx->stream_bufcp, H3_STREAM_CHUNK_SIZE,
|
||||
H3_STREAM_POOL_SPARES);
|
||||
|
||||
result = Curl_ssl_peer_init(&ctx->peer, cf);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
#ifdef USE_OPENSSL
|
||||
result = quic_ssl_ctx(&ctx->sslctx, cf, data);
|
||||
if(result)
|
||||
|
@ -91,6 +91,7 @@ static void keylog_callback(const SSL *ssl, const char *line)
|
||||
|
||||
struct cf_quiche_ctx {
|
||||
struct cf_quic_ctx q;
|
||||
struct ssl_peer peer;
|
||||
quiche_conn *qconn;
|
||||
quiche_config *cfg;
|
||||
quiche_h3_conn *h3c;
|
||||
@ -131,6 +132,8 @@ static void cf_quiche_ctx_clear(struct cf_quiche_ctx *ctx)
|
||||
if(ctx->cfg)
|
||||
quiche_config_free(ctx->cfg);
|
||||
Curl_bufcp_free(&ctx->stream_bufcp);
|
||||
Curl_ssl_peer_cleanup(&ctx->peer);
|
||||
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
}
|
||||
}
|
||||
@ -182,12 +185,16 @@ static CURLcode quic_ssl_setup(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
{
|
||||
struct cf_quiche_ctx *ctx = cf->ctx;
|
||||
struct ssl_primary_config *conn_config;
|
||||
unsigned char checkip[16];
|
||||
CURLcode result;
|
||||
|
||||
conn_config = Curl_ssl_cf_get_primary_config(cf);
|
||||
if(!conn_config)
|
||||
return CURLE_FAILED_INIT;
|
||||
|
||||
result = Curl_ssl_peer_init(&ctx->peer, cf);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
DEBUGASSERT(!ctx->sslctx);
|
||||
ctx->sslctx = SSL_CTX_new(TLS_method());
|
||||
if(!ctx->sslctx)
|
||||
@ -218,13 +225,8 @@ static CURLcode quic_ssl_setup(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
|
||||
SSL_set_app_data(ctx->ssl, cf);
|
||||
|
||||
if((0 == Curl_inet_pton(AF_INET, cf->conn->host.name, checkip))
|
||||
#ifdef ENABLE_IPV6
|
||||
&& (0 == Curl_inet_pton(AF_INET6, cf->conn->host.name, checkip))
|
||||
#endif
|
||||
) {
|
||||
char *snihost = Curl_ssl_snihost(data, cf->conn->host.name, NULL);
|
||||
if(!snihost || !SSL_set_tlsext_host_name(ctx->ssl, snihost)) {
|
||||
if(ctx->peer.sni) {
|
||||
if(!SSL_set_tlsext_host_name(ctx->ssl, ctx->peer.sni)) {
|
||||
failf(data, "Failed set SNI");
|
||||
SSL_free(ctx->ssl);
|
||||
ctx->ssl = NULL;
|
||||
@ -1267,7 +1269,7 @@ static CURLcode cf_verify_peer(struct Curl_cfilter *cf,
|
||||
result = CURLE_PEER_FAILED_VERIFICATION;
|
||||
goto out;
|
||||
}
|
||||
result = Curl_ossl_verifyhost(data, cf->conn, server_cert);
|
||||
result = Curl_ossl_verifyhost(data, cf->conn, &ctx->peer, server_cert);
|
||||
X509_free(server_cert);
|
||||
if(result)
|
||||
goto out;
|
||||
|
@ -582,17 +582,12 @@ static CURLcode bearssl_connect_step1(struct Curl_cfilter *cf,
|
||||
const char * const ssl_cafile =
|
||||
/* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */
|
||||
(ca_info_blob ? NULL : conn_config->CAfile);
|
||||
const char *hostname = connssl->hostname;
|
||||
const char *hostname = connssl->peer.hostname;
|
||||
const bool verifypeer = conn_config->verifypeer;
|
||||
const bool verifyhost = conn_config->verifyhost;
|
||||
CURLcode ret;
|
||||
unsigned version_min, version_max;
|
||||
int session_set = 0;
|
||||
#ifdef ENABLE_IPV6
|
||||
struct in6_addr addr;
|
||||
#else
|
||||
struct in_addr addr;
|
||||
#endif
|
||||
|
||||
DEBUGASSERT(backend);
|
||||
CURL_TRC_CF(data, cf, "connect_step1");
|
||||
@ -706,11 +701,7 @@ static CURLcode bearssl_connect_step1(struct Curl_cfilter *cf,
|
||||
infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data);
|
||||
}
|
||||
|
||||
if((1 == Curl_inet_pton(AF_INET, hostname, &addr))
|
||||
#ifdef ENABLE_IPV6
|
||||
|| (1 == Curl_inet_pton(AF_INET6, hostname, &addr))
|
||||
#endif
|
||||
) {
|
||||
if(connssl->peer.is_ip_address) {
|
||||
if(verifyhost) {
|
||||
failf(data, "BearSSL: "
|
||||
"host verification of IP address is not supported");
|
||||
@ -719,12 +710,11 @@ static CURLcode bearssl_connect_step1(struct Curl_cfilter *cf,
|
||||
hostname = NULL;
|
||||
}
|
||||
else {
|
||||
char *snihost = Curl_ssl_snihost(data, hostname, NULL);
|
||||
if(!snihost) {
|
||||
if(!connssl->peer.sni) {
|
||||
failf(data, "Failed to set SNI");
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
hostname = snihost;
|
||||
hostname = connssl->peer.sni;
|
||||
CURL_TRC_CF(data, cf, "connect_step1, SNI set");
|
||||
}
|
||||
|
||||
|
@ -402,18 +402,13 @@ set_ssl_version_min_max(struct Curl_easy *data,
|
||||
CURLcode gtls_client_init(struct Curl_easy *data,
|
||||
struct ssl_primary_config *config,
|
||||
struct ssl_config_data *ssl_config,
|
||||
const char *hostname,
|
||||
struct ssl_peer *peer,
|
||||
struct gtls_instance *gtls,
|
||||
long *pverifyresult)
|
||||
{
|
||||
unsigned int init_flags;
|
||||
int rc;
|
||||
bool sni = TRUE; /* default is SNI enabled */
|
||||
#ifdef ENABLE_IPV6
|
||||
struct in6_addr addr;
|
||||
#else
|
||||
struct in_addr addr;
|
||||
#endif
|
||||
const char *prioritylist;
|
||||
const char *err = NULL;
|
||||
const char *tls13support;
|
||||
@ -547,15 +542,9 @@ CURLcode gtls_client_init(struct Curl_easy *data,
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
|
||||
if((0 == Curl_inet_pton(AF_INET, hostname, &addr)) &&
|
||||
#ifdef ENABLE_IPV6
|
||||
(0 == Curl_inet_pton(AF_INET6, hostname, &addr)) &&
|
||||
#endif
|
||||
sni) {
|
||||
size_t snilen;
|
||||
char *snihost = Curl_ssl_snihost(data, hostname, &snilen);
|
||||
if(!snihost || gnutls_server_name_set(gtls->session, GNUTLS_NAME_DNS,
|
||||
snihost, snilen) < 0) {
|
||||
if(sni && peer->sni) {
|
||||
if(gnutls_server_name_set(gtls->session, GNUTLS_NAME_DNS,
|
||||
peer->sni, strlen(peer->sni)) < 0) {
|
||||
failf(data, "Failed to set SNI");
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
@ -709,7 +698,7 @@ gtls_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
return CURLE_OK;
|
||||
|
||||
result = gtls_client_init(data, conn_config, ssl_config,
|
||||
connssl->hostname,
|
||||
&connssl->peer,
|
||||
&backend->gtls, pverifyresult);
|
||||
if(result)
|
||||
return result;
|
||||
@ -821,8 +810,7 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
|
||||
gnutls_session_t session,
|
||||
struct ssl_primary_config *config,
|
||||
struct ssl_config_data *ssl_config,
|
||||
const char *hostname,
|
||||
const char *dispname,
|
||||
struct ssl_peer *peer,
|
||||
const char *pinned_key)
|
||||
{
|
||||
unsigned int cert_list_size;
|
||||
@ -1078,7 +1066,7 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
|
||||
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, hostname);
|
||||
rc = gnutls_x509_crt_check_hostname(x509_cert, peer->hostname);
|
||||
#if GNUTLS_VERSION_NUMBER < 0x030306
|
||||
/* Before 3.3.6, gnutls_x509_crt_check_hostname() didn't check IP
|
||||
addresses. */
|
||||
@ -1091,10 +1079,10 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
|
||||
unsigned char addrbuf[sizeof(struct use_addr)];
|
||||
size_t addrlen = 0;
|
||||
|
||||
if(Curl_inet_pton(AF_INET, hostname, addrbuf) > 0)
|
||||
if(Curl_inet_pton(AF_INET, peer->hostname, addrbuf) > 0)
|
||||
addrlen = 4;
|
||||
#ifdef ENABLE_IPV6
|
||||
else if(Curl_inet_pton(AF_INET6, hostname, addrbuf) > 0)
|
||||
else if(Curl_inet_pton(AF_INET6, peer->hostname, addrbuf) > 0)
|
||||
addrlen = 16;
|
||||
#endif
|
||||
|
||||
@ -1124,13 +1112,13 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
|
||||
if(!rc) {
|
||||
if(config->verifyhost) {
|
||||
failf(data, "SSL: certificate subject name (%s) does not match "
|
||||
"target host name '%s'", certname, dispname);
|
||||
"target host name '%s'", certname, peer->dispname);
|
||||
gnutls_x509_crt_deinit(x509_cert);
|
||||
return CURLE_PEER_FAILED_VERIFICATION;
|
||||
}
|
||||
else
|
||||
infof(data, " common name: %s (does not match '%s')",
|
||||
certname, dispname);
|
||||
certname, peer->dispname);
|
||||
}
|
||||
else
|
||||
infof(data, " common name: %s (matched)", certname);
|
||||
@ -1263,8 +1251,7 @@ static CURLcode gtls_verifyserver(struct Curl_cfilter *cf,
|
||||
CURLcode result;
|
||||
|
||||
result = Curl_gtls_verifyserver(data, session, conn_config, ssl_config,
|
||||
connssl->hostname, connssl->dispname,
|
||||
pinned_key);
|
||||
&connssl->peer, pinned_key);
|
||||
if(result)
|
||||
goto out;
|
||||
|
||||
|
@ -43,6 +43,7 @@ struct Curl_easy;
|
||||
struct Curl_cfilter;
|
||||
struct ssl_primary_config;
|
||||
struct ssl_config_data;
|
||||
struct ssl_peer;
|
||||
|
||||
struct gtls_instance {
|
||||
gnutls_session_t session;
|
||||
@ -56,7 +57,7 @@ CURLcode
|
||||
gtls_client_init(struct Curl_easy *data,
|
||||
struct ssl_primary_config *config,
|
||||
struct ssl_config_data *ssl_config,
|
||||
const char *hostname,
|
||||
struct ssl_peer *peer,
|
||||
struct gtls_instance *gtls,
|
||||
long *pverifyresult);
|
||||
|
||||
@ -65,8 +66,7 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
|
||||
gnutls_session_t session,
|
||||
struct ssl_primary_config *config,
|
||||
struct ssl_config_data *ssl_config,
|
||||
const char *hostname,
|
||||
const char *dispname,
|
||||
struct ssl_peer *peer,
|
||||
const char *pinned_key);
|
||||
|
||||
extern const struct Curl_ssl Curl_ssl_gnutls;
|
||||
|
@ -322,7 +322,7 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
char * const ssl_cert = ssl_config->primary.clientcert;
|
||||
const struct curl_blob *ssl_cert_blob = ssl_config->primary.cert_blob;
|
||||
const char * const ssl_crlfile = ssl_config->primary.CRLfile;
|
||||
const char *hostname = connssl->hostname;
|
||||
const char *hostname = connssl->peer.hostname;
|
||||
int ret = -1;
|
||||
char errorbuf[128];
|
||||
|
||||
@ -639,9 +639,9 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
mbedtls_ssl_conf_own_cert(&backend->config,
|
||||
&backend->clicert, &backend->pk);
|
||||
}
|
||||
{
|
||||
char *snihost = Curl_ssl_snihost(data, hostname, NULL);
|
||||
if(!snihost || mbedtls_ssl_set_hostname(&backend->ssl, snihost)) {
|
||||
|
||||
if(connssl->peer.sni) {
|
||||
if(mbedtls_ssl_set_hostname(&backend->ssl, connssl->peer.sni)) {
|
||||
/* 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. */
|
||||
|
@ -2107,22 +2107,6 @@ static bool subj_alt_hostcheck(struct Curl_easy *data,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static CURLcode
|
||||
ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
|
||||
X509 *server_cert, const char *hostname,
|
||||
const char *dispname);
|
||||
|
||||
CURLcode Curl_ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
|
||||
X509 *server_cert)
|
||||
{
|
||||
const char *hostname, *dispname;
|
||||
int port;
|
||||
|
||||
(void)conn;
|
||||
Curl_conn_get_host(data, FIRSTSOCKET, &hostname, &dispname, &port);
|
||||
return ossl_verifyhost(data, conn, server_cert, hostname, dispname);
|
||||
}
|
||||
|
||||
/* Quote from RFC2818 section 3.1 "Server Identity"
|
||||
|
||||
If a subjectAltName extension of type dNSName is present, that MUST
|
||||
@ -2145,10 +2129,8 @@ CURLcode Curl_ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
|
||||
|
||||
This function is now used from ngtcp2 (QUIC) as well.
|
||||
*/
|
||||
static CURLcode
|
||||
ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
|
||||
X509 *server_cert, const char *hostname,
|
||||
const char *dispname)
|
||||
CURLcode Curl_ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
|
||||
struct ssl_peer *peer, X509 *server_cert)
|
||||
{
|
||||
bool matched = FALSE;
|
||||
int target = GEN_DNS; /* target type, GEN_DNS or GEN_IPADD */
|
||||
@ -2165,25 +2147,21 @@ ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
|
||||
size_t hostlen;
|
||||
|
||||
(void)conn;
|
||||
hostlen = strlen(hostname);
|
||||
|
||||
#ifndef ENABLE_IPV6
|
||||
/* Silence compiler warnings for unused params */
|
||||
(void) conn;
|
||||
#endif
|
||||
|
||||
hostlen = strlen(peer->hostname);
|
||||
if(peer->is_ip_address) {
|
||||
#ifdef ENABLE_IPV6
|
||||
if(conn->bits.ipv6_ip &&
|
||||
Curl_inet_pton(AF_INET6, hostname, &addr)) {
|
||||
target = GEN_IPADD;
|
||||
addrlen = sizeof(struct in6_addr);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if(Curl_inet_pton(AF_INET, hostname, &addr)) {
|
||||
if(conn->bits.ipv6_ip &&
|
||||
Curl_inet_pton(AF_INET6, peer->hostname, &addr)) {
|
||||
target = GEN_IPADD;
|
||||
addrlen = sizeof(struct in_addr);
|
||||
addrlen = sizeof(struct in6_addr);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if(Curl_inet_pton(AF_INET, peer->hostname, &addr)) {
|
||||
target = GEN_IPADD;
|
||||
addrlen = sizeof(struct in_addr);
|
||||
}
|
||||
}
|
||||
|
||||
/* get a "list" of alternative names */
|
||||
altnames = X509_get_ext_d2i(server_cert, NID_subject_alt_name, NULL, NULL);
|
||||
@ -2233,9 +2211,9 @@ ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
|
||||
if((altlen == strlen(altptr)) &&
|
||||
/* if this isn't true, there was an embedded zero in the name
|
||||
string and we cannot match it. */
|
||||
subj_alt_hostcheck(data,
|
||||
altptr,
|
||||
altlen, hostname, hostlen, dispname)) {
|
||||
subj_alt_hostcheck(data, altptr, altlen,
|
||||
peer->hostname, hostlen,
|
||||
peer->dispname)) {
|
||||
dnsmatched = TRUE;
|
||||
}
|
||||
break;
|
||||
@ -2247,7 +2225,7 @@ ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
|
||||
ipmatched = TRUE;
|
||||
infof(data,
|
||||
" subjectAltName: host \"%s\" matched cert's IP address!",
|
||||
dispname);
|
||||
peer->dispname);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -2263,9 +2241,9 @@ ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
|
||||
/* an alternative name matched */
|
||||
;
|
||||
else if(dNSName || iPAddress) {
|
||||
infof(data, " subjectAltName does not match %s", dispname);
|
||||
infof(data, " subjectAltName does not match %s", peer->dispname);
|
||||
failf(data, "SSL: no alternative certificate subject name matches "
|
||||
"target host name '%s'", dispname);
|
||||
"target host name '%s'", peer->dispname);
|
||||
result = CURLE_PEER_FAILED_VERIFICATION;
|
||||
}
|
||||
else {
|
||||
@ -2329,9 +2307,9 @@ ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
|
||||
result = CURLE_PEER_FAILED_VERIFICATION;
|
||||
}
|
||||
else if(!Curl_cert_hostcheck((const char *)peer_CN,
|
||||
peerlen, hostname, hostlen)) {
|
||||
peerlen, peer->hostname, hostlen)) {
|
||||
failf(data, "SSL: certificate subject name '%s' does not match "
|
||||
"target host name '%s'", peer_CN, dispname);
|
||||
"target host name '%s'", peer_CN, peer->dispname);
|
||||
result = CURLE_PEER_FAILED_VERIFICATION;
|
||||
}
|
||||
else {
|
||||
@ -2740,12 +2718,6 @@ static void ossl_trace(int direction, int ssl_ver, int content_type,
|
||||
#ifdef USE_OPENSSL
|
||||
/* ====================================================== */
|
||||
|
||||
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
|
||||
# define use_sni(x) sni = (x)
|
||||
#else
|
||||
# define use_sni(x) Curl_nop_stmt
|
||||
#endif
|
||||
|
||||
/* Check for OpenSSL 1.0.2 which has ALPN support. */
|
||||
#undef HAS_ALPN
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10002000L \
|
||||
@ -3490,17 +3462,6 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,
|
||||
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
|
||||
struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
|
||||
BIO *bio;
|
||||
|
||||
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
|
||||
bool sni;
|
||||
const char *hostname = connssl->hostname;
|
||||
|
||||
#ifdef ENABLE_IPV6
|
||||
struct in6_addr addr;
|
||||
#else
|
||||
struct in_addr addr;
|
||||
#endif
|
||||
#endif
|
||||
const long int ssl_version = conn_config->version;
|
||||
char * const ssl_cert = ssl_config->primary.clientcert;
|
||||
const struct curl_blob *ssl_cert_blob = ssl_config->primary.cert_blob;
|
||||
@ -3535,7 +3496,6 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,
|
||||
#else
|
||||
req_method = SSLv23_client_method();
|
||||
#endif
|
||||
use_sni(TRUE);
|
||||
break;
|
||||
case CURL_SSLVERSION_SSLv2:
|
||||
failf(data, "No SSLv2 support");
|
||||
@ -3828,13 +3788,8 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,
|
||||
|
||||
backend->server_cert = 0x0;
|
||||
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
|
||||
if((0 == Curl_inet_pton(AF_INET, hostname, &addr)) &&
|
||||
#ifdef ENABLE_IPV6
|
||||
(0 == Curl_inet_pton(AF_INET6, hostname, &addr)) &&
|
||||
#endif
|
||||
sni) {
|
||||
char *snihost = Curl_ssl_snihost(data, hostname, NULL);
|
||||
if(!snihost || !SSL_set_tlsext_host_name(backend->handle, snihost)) {
|
||||
if(connssl->peer.sni) {
|
||||
if(!SSL_set_tlsext_host_name(backend->handle, connssl->peer.sni)) {
|
||||
failf(data, "Failed set SNI");
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
@ -4016,7 +3971,7 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf,
|
||||
Curl_strerror(sockerr, extramsg, sizeof(extramsg));
|
||||
failf(data, OSSL_PACKAGE " SSL_connect: %s in connection to %s:%d ",
|
||||
extramsg[0] ? extramsg : SSL_ERROR_to_str(detail),
|
||||
connssl->hostname, connssl->port);
|
||||
connssl->peer.hostname, connssl->port);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -4257,8 +4212,8 @@ static CURLcode servercert(struct Curl_cfilter *cf,
|
||||
BIO_free(mem);
|
||||
|
||||
if(conn_config->verifyhost) {
|
||||
result = ossl_verifyhost(data, conn, backend->server_cert,
|
||||
connssl->hostname, connssl->dispname);
|
||||
result = Curl_ossl_verifyhost(data, conn, &connssl->peer,
|
||||
backend->server_cert);
|
||||
if(result) {
|
||||
X509_free(backend->server_cert);
|
||||
backend->server_cert = NULL;
|
||||
|
@ -43,6 +43,7 @@
|
||||
*/
|
||||
struct x509_st;
|
||||
CURLcode Curl_ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
|
||||
struct ssl_peer *peer,
|
||||
struct x509_st *server_cert);
|
||||
extern const struct Curl_ssl Curl_ssl_openssl;
|
||||
|
||||
@ -65,5 +66,9 @@ CURLcode Curl_ssl_setup_x509_store(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
SSL_CTX *ssl_ctx);
|
||||
|
||||
CURLcode Curl_ossl_ctx_configure(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
SSL_CTX *ssl_ctx);
|
||||
|
||||
#endif /* USE_OPENSSL */
|
||||
#endif /* HEADER_CURL_SSLUSE_H */
|
||||
|
@ -386,7 +386,7 @@ cr_init_backend(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
/* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */
|
||||
(ca_info_blob ? NULL : conn_config->CAfile);
|
||||
const bool verifypeer = conn_config->verifypeer;
|
||||
const char *hostname = connssl->hostname;
|
||||
const char *hostname = connssl->peer.hostname;
|
||||
char errorbuf[256];
|
||||
size_t errorlen;
|
||||
int result;
|
||||
@ -458,12 +458,11 @@ cr_init_backend(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
backend->config = rustls_client_config_builder_build(config_builder);
|
||||
DEBUGASSERT(rconn == NULL);
|
||||
{
|
||||
char *snihost = Curl_ssl_snihost(data, hostname, NULL);
|
||||
if(!snihost) {
|
||||
failf(data, "rustls: failed to get SNI");
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
result = rustls_client_connection_new(backend->config, snihost, &rconn);
|
||||
/* rustls claims to manage ip address hostnames as well here. So,
|
||||
* if we have an SNI, we use it, otherwise we pass the hostname */
|
||||
char *server = connssl->peer.sni?
|
||||
connssl->peer.sni : connssl->peer.hostname;
|
||||
result = rustls_client_connection_new(backend->config, server, &rconn);
|
||||
}
|
||||
if(result != RUSTLS_RESULT_OK) {
|
||||
rustls_error(result, errorbuf, sizeof(errorbuf), &errorlen);
|
||||
|
@ -1063,12 +1063,8 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
#endif
|
||||
SECURITY_STATUS sspi_status = SEC_E_OK;
|
||||
struct Curl_schannel_cred *old_cred = NULL;
|
||||
struct in_addr addr;
|
||||
#ifdef ENABLE_IPV6
|
||||
struct in6_addr addr6;
|
||||
#endif
|
||||
CURLcode result;
|
||||
const char *hostname = connssl->hostname;
|
||||
const char *hostname = connssl->peer.hostname;
|
||||
|
||||
DEBUGASSERT(backend);
|
||||
DEBUGF(infof(data,
|
||||
@ -1154,22 +1150,14 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
|
||||
/* A hostname associated with the credential is needed by
|
||||
InitializeSecurityContext for SNI and other reasons. */
|
||||
snihost = Curl_ssl_snihost(data, hostname, NULL);
|
||||
if(!snihost) {
|
||||
failf(data, "Failed to set SNI");
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
snihost = connssl->peer.sni? connssl->peer.sni : connssl->peer.hostname;
|
||||
backend->cred->sni_hostname = curlx_convert_UTF8_to_tchar(snihost);
|
||||
if(!backend->cred->sni_hostname)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
/* Warn if SNI is disabled due to use of an IP address */
|
||||
if(Curl_inet_pton(AF_INET, hostname, &addr)
|
||||
#ifdef ENABLE_IPV6
|
||||
|| Curl_inet_pton(AF_INET6, hostname, &addr6)
|
||||
#endif
|
||||
) {
|
||||
if(connssl->peer.is_ip_address) {
|
||||
infof(data, "schannel: using IP address, SNI is not supported by OS.");
|
||||
}
|
||||
|
||||
@ -1346,7 +1334,7 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
|
||||
DEBUGF(infof(data,
|
||||
"schannel: SSL/TLS connection with %s port %d (step 2/3)",
|
||||
connssl->hostname, connssl->port));
|
||||
connssl->peer.hostname, connssl->port));
|
||||
|
||||
if(!backend->cred || !backend->ctxt)
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
@ -1700,7 +1688,7 @@ schannel_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
|
||||
DEBUGF(infof(data,
|
||||
"schannel: SSL/TLS connection with %s port %d (step 3/3)",
|
||||
connssl->hostname, connssl->port));
|
||||
connssl->peer.hostname, connssl->port));
|
||||
|
||||
if(!backend->cred)
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
@ -2498,7 +2486,7 @@ static int schannel_shutdown(struct Curl_cfilter *cf,
|
||||
|
||||
if(backend->ctxt) {
|
||||
infof(data, "schannel: shutting down SSL/TLS connection with %s port %d",
|
||||
connssl->hostname, connssl->port);
|
||||
connssl->peer.hostname, connssl->port);
|
||||
}
|
||||
|
||||
if(backend->cred && backend->ctxt) {
|
||||
|
@ -470,7 +470,7 @@ CURLcode Curl_verify_host(struct Curl_cfilter *cf,
|
||||
CERT_CONTEXT *pCertContextServer = NULL;
|
||||
TCHAR *cert_hostname_buff = NULL;
|
||||
size_t cert_hostname_buff_index = 0;
|
||||
const char *conn_hostname = connssl->hostname;
|
||||
const char *conn_hostname = connssl->peer.hostname;
|
||||
size_t hostlen = strlen(conn_hostname);
|
||||
DWORD len = 0;
|
||||
DWORD actual_len = 0;
|
||||
|
@ -1652,11 +1652,6 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
|
||||
const bool verifypeer = conn_config->verifypeer;
|
||||
char * const ssl_cert = ssl_config->primary.clientcert;
|
||||
const struct curl_blob *ssl_cert_blob = ssl_config->primary.cert_blob;
|
||||
#ifdef ENABLE_IPV6
|
||||
struct in6_addr addr;
|
||||
#else
|
||||
struct in_addr addr;
|
||||
#endif /* ENABLE_IPV6 */
|
||||
char *ciphers;
|
||||
OSStatus err = noErr;
|
||||
#if CURL_BUILD_MAC
|
||||
@ -2004,13 +1999,9 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
|
||||
* Both hostname check and SNI require SSLSetPeerDomainName().
|
||||
* Also: the verifyhost setting influences SNI usage */
|
||||
if(conn_config->verifyhost) {
|
||||
size_t snilen;
|
||||
char *snihost = Curl_ssl_snihost(data, connssl->hostname, &snilen);
|
||||
if(!snihost) {
|
||||
failf(data, "Failed to set SNI");
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
err = SSLSetPeerDomainName(backend->ssl_ctx, snihost, snilen);
|
||||
char *server = connssl->peer.sni?
|
||||
connssl->peer.sni : connssl->peer.hostname;
|
||||
err = SSLSetPeerDomainName(backend->ssl_ctx, server, strlen(server));
|
||||
|
||||
if(err != noErr) {
|
||||
failf(data, "SSL: SSLSetPeerDomainName() failed: OSStatus %d",
|
||||
@ -2018,11 +2009,7 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
|
||||
if((Curl_inet_pton(AF_INET, connssl->hostname, &addr))
|
||||
#ifdef ENABLE_IPV6
|
||||
|| (Curl_inet_pton(AF_INET6, connssl->hostname, &addr))
|
||||
#endif
|
||||
) {
|
||||
if(connssl->peer.is_ip_address) {
|
||||
infof(data, "WARNING: using IP address, SNI is being disabled by "
|
||||
"the OS.");
|
||||
}
|
||||
@ -2080,7 +2067,7 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
|
||||
ssl_sessionid =
|
||||
aprintf("%s:%d:%d:%s:%d",
|
||||
ssl_cafile ? ssl_cafile : "(blob memory)",
|
||||
verifypeer, conn_config->verifyhost, connssl->hostname,
|
||||
verifypeer, conn_config->verifyhost, connssl->peer.hostname,
|
||||
connssl->port);
|
||||
ssl_sessionid_len = strlen(ssl_sessionid);
|
||||
|
||||
@ -2666,7 +2653,7 @@ check_handshake:
|
||||
host name: */
|
||||
case errSSLHostNameMismatch:
|
||||
failf(data, "SSL certificate peer verification failed, the "
|
||||
"certificate did not match \"%s\"\n", connssl->dispname);
|
||||
"certificate did not match \"%s\"\n", connssl->peer.dispname);
|
||||
return CURLE_PEER_FAILED_VERIFICATION;
|
||||
|
||||
/* Problem with SSL / TLS negotiation */
|
||||
@ -2758,7 +2745,7 @@ check_handshake:
|
||||
default:
|
||||
/* May also return codes listed in Security Framework Result Codes */
|
||||
failf(data, "Unknown SSL protocol error in connection to %s:%d",
|
||||
connssl->hostname, err);
|
||||
connssl->peer.hostname, err);
|
||||
break;
|
||||
}
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
|
106
lib/vtls/vtls.c
106
lib/vtls/vtls.c
@ -67,6 +67,7 @@
|
||||
#include "warnless.h"
|
||||
#include "curl_base64.h"
|
||||
#include "curl_printf.h"
|
||||
#include "inet_pton.h"
|
||||
#include "strdup.h"
|
||||
|
||||
/* The last #include files should be: */
|
||||
@ -566,7 +567,7 @@ bool Curl_ssl_getsessionid(struct Curl_cfilter *cf,
|
||||
if(!check->sessionid)
|
||||
/* not session ID means blank entry */
|
||||
continue;
|
||||
if(strcasecompare(connssl->hostname, check->name) &&
|
||||
if(strcasecompare(connssl->peer.hostname, check->name) &&
|
||||
((!cf->conn->bits.conn_to_host && !check->conn_to_host) ||
|
||||
(cf->conn->bits.conn_to_host && check->conn_to_host &&
|
||||
strcasecompare(cf->conn->conn_to_host.name, check->conn_to_host))) &&
|
||||
@ -590,7 +591,8 @@ bool Curl_ssl_getsessionid(struct Curl_cfilter *cf,
|
||||
DEBUGF(infof(data, "%s Session ID in cache for %s %s://%s:%d",
|
||||
no_match? "Didn't find": "Found",
|
||||
Curl_ssl_cf_is_proxy(cf) ? "proxy" : "host",
|
||||
cf->conn->handler->scheme, connssl->hostname, connssl->port));
|
||||
cf->conn->handler->scheme, connssl->peer.hostname,
|
||||
connssl->port));
|
||||
return no_match;
|
||||
}
|
||||
|
||||
@ -666,7 +668,7 @@ CURLcode Curl_ssl_addsessionid(struct Curl_cfilter *cf,
|
||||
(void)ssl_config;
|
||||
DEBUGASSERT(ssl_config->primary.sessionid);
|
||||
|
||||
clone_host = strdup(connssl->hostname);
|
||||
clone_host = strdup(connssl->peer.hostname);
|
||||
if(!clone_host)
|
||||
return CURLE_OUT_OF_MEMORY; /* bail out */
|
||||
|
||||
@ -918,32 +920,6 @@ CURLcode Curl_ssl_random(struct Curl_easy *data,
|
||||
return Curl_ssl->random(data, entropy, length);
|
||||
}
|
||||
|
||||
/*
|
||||
* Curl_ssl_snihost() converts the input host name to a suitable SNI name put
|
||||
* in data->state.buffer. Returns a pointer to the name (or NULL if a problem)
|
||||
* and stores the new length in 'olen'.
|
||||
*
|
||||
* SNI fields must not have any trailing dot and while RFC 6066 section 3 says
|
||||
* the SNI field is case insensitive, browsers always send the data lowercase
|
||||
* and subsequently there are numerous servers out there that don't work
|
||||
* unless the name is lowercased.
|
||||
*/
|
||||
|
||||
char *Curl_ssl_snihost(struct Curl_easy *data, const char *host, size_t *olen)
|
||||
{
|
||||
size_t len = strlen(host);
|
||||
if(len && (host[len-1] == '.'))
|
||||
len--;
|
||||
if(len >= data->set.buffer_size)
|
||||
return NULL;
|
||||
|
||||
Curl_strntolower(data->state.buffer, host, len);
|
||||
data->state.buffer[len] = 0;
|
||||
if(olen)
|
||||
*olen = len;
|
||||
return data->state.buffer;
|
||||
}
|
||||
|
||||
/*
|
||||
* Public key pem to der conversion
|
||||
*/
|
||||
@ -1542,12 +1518,14 @@ CURLsslset Curl_init_sslset_nolock(curl_sslbackend id, const char *name,
|
||||
|
||||
#ifdef USE_SSL
|
||||
|
||||
static void free_hostname(struct ssl_connect_data *connssl)
|
||||
void Curl_ssl_peer_cleanup(struct ssl_peer *peer)
|
||||
{
|
||||
if(connssl->dispname != connssl->hostname)
|
||||
free(connssl->dispname);
|
||||
free(connssl->hostname);
|
||||
connssl->hostname = connssl->dispname = NULL;
|
||||
if(peer->dispname != peer->hostname)
|
||||
free(peer->dispname);
|
||||
free(peer->sni);
|
||||
free(peer->hostname);
|
||||
peer->hostname = peer->sni = peer->dispname = NULL;
|
||||
peer->is_ip_address = FALSE;
|
||||
}
|
||||
|
||||
static void cf_close(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
@ -1556,12 +1534,26 @@ static void cf_close(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
if(connssl) {
|
||||
Curl_ssl->close(cf, data);
|
||||
connssl->state = ssl_connection_none;
|
||||
free_hostname(connssl);
|
||||
Curl_ssl_peer_cleanup(&connssl->peer);
|
||||
}
|
||||
cf->connected = FALSE;
|
||||
}
|
||||
|
||||
static CURLcode reinit_hostname(struct Curl_cfilter *cf)
|
||||
static int is_ip_address(const char *hostname)
|
||||
{
|
||||
#ifdef ENABLE_IPV6
|
||||
struct in6_addr addr;
|
||||
#else
|
||||
struct in_addr addr;
|
||||
#endif
|
||||
return (hostname && hostname[0] && (Curl_inet_pton(AF_INET, hostname, &addr)
|
||||
#ifdef ENABLE_IPV6
|
||||
|| Curl_inet_pton(AF_INET6, hostname, &addr)
|
||||
#endif
|
||||
));
|
||||
}
|
||||
|
||||
CURLcode Curl_ssl_peer_init(struct ssl_peer *peer, struct Curl_cfilter *cf)
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
const char *ehostname, *edispname;
|
||||
@ -1587,23 +1579,43 @@ static CURLcode reinit_hostname(struct Curl_cfilter *cf)
|
||||
}
|
||||
|
||||
/* change if ehostname changed */
|
||||
if(ehostname && (!connssl->hostname
|
||||
|| strcmp(ehostname, connssl->hostname))) {
|
||||
free_hostname(connssl);
|
||||
connssl->hostname = strdup(ehostname);
|
||||
if(!connssl->hostname) {
|
||||
free_hostname(connssl);
|
||||
if(ehostname && (!peer->hostname
|
||||
|| strcmp(ehostname, peer->hostname))) {
|
||||
Curl_ssl_peer_cleanup(peer);
|
||||
peer->hostname = strdup(ehostname);
|
||||
if(!peer->hostname) {
|
||||
Curl_ssl_peer_cleanup(peer);
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
if(!edispname || !strcmp(ehostname, edispname))
|
||||
connssl->dispname = connssl->hostname;
|
||||
peer->dispname = peer->hostname;
|
||||
else {
|
||||
connssl->dispname = strdup(edispname);
|
||||
if(!connssl->dispname) {
|
||||
free_hostname(connssl);
|
||||
peer->dispname = strdup(edispname);
|
||||
if(!peer->dispname) {
|
||||
Curl_ssl_peer_cleanup(peer);
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
peer->sni = NULL;
|
||||
peer->is_ip_address = is_ip_address(peer->hostname)? TRUE : FALSE;
|
||||
if(peer->hostname[0] && !peer->is_ip_address) {
|
||||
/* not an IP address, normalize according to RCC 6066 ch. 3,
|
||||
* max len of SNI is 2^16-1, no trailing dot */
|
||||
size_t len = strlen(peer->hostname);
|
||||
if(len && (peer->hostname[len-1] == '.'))
|
||||
len--;
|
||||
if(len < USHRT_MAX) {
|
||||
peer->sni = calloc(1, len + 1);
|
||||
if(!peer->sni) {
|
||||
Curl_ssl_peer_cleanup(peer);
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
Curl_strntolower(peer->sni, peer->hostname, len);
|
||||
peer->sni[len] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
connssl->port = eport;
|
||||
return CURLE_OK;
|
||||
@ -1658,7 +1670,7 @@ static CURLcode ssl_cf_connect(struct Curl_cfilter *cf,
|
||||
goto out;
|
||||
|
||||
*done = FALSE;
|
||||
result = reinit_hostname(cf);
|
||||
result = Curl_ssl_peer_init(&connssl->peer, cf);
|
||||
if(result)
|
||||
goto out;
|
||||
|
||||
|
@ -65,8 +65,6 @@ CURLsslset Curl_init_sslset_nolock(curl_sslbackend id, const char *name,
|
||||
#define CURL_SHA256_DIGEST_LENGTH 32 /* fixed size */
|
||||
#endif
|
||||
|
||||
char *Curl_ssl_snihost(struct Curl_easy *data, const char *host, size_t *olen);
|
||||
|
||||
curl_sslbackend Curl_ssl_backend(void);
|
||||
|
||||
/**
|
||||
@ -106,6 +104,15 @@ bool Curl_ssl_conn_config_match(struct Curl_easy *data,
|
||||
* `verifyhost` and `verifystatus`. */
|
||||
void Curl_ssl_conn_config_update(struct Curl_easy *data, bool for_proxy);
|
||||
|
||||
/**
|
||||
* Init SSL peer information for filter. Can be called repeatedly.
|
||||
*/
|
||||
CURLcode Curl_ssl_peer_init(struct ssl_peer *peer, struct Curl_cfilter *cf);
|
||||
/**
|
||||
* Free all allocated data and reset peer information.
|
||||
*/
|
||||
void Curl_ssl_peer_cleanup(struct ssl_peer *peer);
|
||||
|
||||
#ifdef USE_SSL
|
||||
int Curl_ssl_init(void);
|
||||
void Curl_ssl_cleanup(void);
|
||||
|
@ -68,8 +68,7 @@ CURLcode Curl_alpn_set_negotiated(struct Curl_cfilter *cf,
|
||||
struct ssl_connect_data {
|
||||
ssl_connection_state state;
|
||||
ssl_connect_state connecting_state;
|
||||
char *hostname; /* hostname for verification */
|
||||
char *dispname; /* display version of hostname */
|
||||
struct ssl_peer peer;
|
||||
const struct alpn_spec *alpn; /* ALPN to use or NULL for none */
|
||||
void *backend; /* vtls backend specific props */
|
||||
struct cf_call_data call_data; /* data handle used in current call */
|
||||
|
@ -609,24 +609,12 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
SSL_VERIFY_NONE, NULL);
|
||||
|
||||
#ifdef HAVE_SNI
|
||||
if(sni) {
|
||||
struct in_addr addr4;
|
||||
#ifdef ENABLE_IPV6
|
||||
struct in6_addr addr6;
|
||||
#endif
|
||||
size_t hostname_len = strlen(connssl->hostname);
|
||||
|
||||
if((hostname_len < USHRT_MAX) &&
|
||||
!Curl_inet_pton(AF_INET, connssl->hostname, &addr4)
|
||||
#ifdef ENABLE_IPV6
|
||||
&& !Curl_inet_pton(AF_INET6, connssl->hostname, &addr6)
|
||||
#endif
|
||||
) {
|
||||
size_t snilen;
|
||||
char *snihost = Curl_ssl_snihost(data, connssl->hostname, &snilen);
|
||||
if(!snihost ||
|
||||
wolfSSL_CTX_UseSNI(backend->ctx, WOLFSSL_SNI_HOST_NAME, snihost,
|
||||
(unsigned short)snilen) != 1) {
|
||||
if(sni && connssl->peer.sni) {
|
||||
size_t sni_len = strlen(connssl->peer.sni);
|
||||
if((sni_len < USHRT_MAX)) {
|
||||
if(wolfSSL_CTX_UseSNI(backend->ctx, WOLFSSL_SNI_HOST_NAME,
|
||||
connssl->peer.sni,
|
||||
(unsigned short)sni_len) != 1) {
|
||||
failf(data, "Failed to set SNI");
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
@ -764,9 +752,9 @@ wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
|
||||
/* Enable RFC2818 checks */
|
||||
if(conn_config->verifyhost) {
|
||||
char *snihost = Curl_ssl_snihost(data, connssl->hostname, NULL);
|
||||
if(!snihost ||
|
||||
(wolfSSL_check_domain_name(backend->handle, snihost) == SSL_FAILURE))
|
||||
char *snihost = connssl->peer.sni?
|
||||
connssl->peer.sni : connssl->peer.hostname;
|
||||
if(wolfSSL_check_domain_name(backend->handle, snihost) == SSL_FAILURE)
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
|
||||
@ -814,7 +802,7 @@ wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
else if(DOMAIN_NAME_MISMATCH == detail) {
|
||||
#if 1
|
||||
failf(data, " subject alt name(s) or common name do not match \"%s\"",
|
||||
connssl->dispname);
|
||||
connssl->peer.dispname);
|
||||
return CURLE_PEER_FAILED_VERIFICATION;
|
||||
#else
|
||||
/* When the wolfssl_check_domain_name() is used and you desire to
|
||||
|
@ -1317,16 +1317,16 @@ CURLcode Curl_verifyhost(struct Curl_cfilter *cf,
|
||||
if(Curl_parseX509(&cert, beg, end))
|
||||
return CURLE_PEER_FAILED_VERIFICATION;
|
||||
|
||||
hostlen = strlen(connssl->hostname);
|
||||
hostlen = strlen(connssl->peer.hostname);
|
||||
|
||||
/* Get the server IP address. */
|
||||
#ifdef ENABLE_IPV6
|
||||
if(cf->conn->bits.ipv6_ip &&
|
||||
Curl_inet_pton(AF_INET6, connssl->hostname, &addr))
|
||||
Curl_inet_pton(AF_INET6, connssl->peer.hostname, &addr))
|
||||
addrlen = sizeof(struct in6_addr);
|
||||
else
|
||||
#endif
|
||||
if(Curl_inet_pton(AF_INET, connssl->hostname, &addr))
|
||||
if(Curl_inet_pton(AF_INET, connssl->peer.hostname, &addr))
|
||||
addrlen = sizeof(struct in_addr);
|
||||
|
||||
/* Process extensions. */
|
||||
@ -1361,7 +1361,7 @@ CURLcode Curl_verifyhost(struct Curl_cfilter *cf,
|
||||
name.beg, name.end);
|
||||
if(len > 0 && (size_t)len == strlen(dnsname))
|
||||
matched = Curl_cert_hostcheck(dnsname, (size_t)len,
|
||||
connssl->hostname, hostlen);
|
||||
connssl->peer.hostname, hostlen);
|
||||
else
|
||||
matched = 0;
|
||||
free(dnsname);
|
||||
@ -1421,7 +1421,7 @@ CURLcode Curl_verifyhost(struct Curl_cfilter *cf,
|
||||
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,
|
||||
len, connssl->hostname, hostlen)) {
|
||||
len, connssl->peer.hostname, hostlen)) {
|
||||
infof(data, " common name: %s (matched)", dnsname);
|
||||
free(dnsname);
|
||||
return CURLE_OK;
|
||||
|
Loading…
x
Reference in New Issue
Block a user