The TLS backends convert the host name to SNI name and need to use that.
This involves cutting off any trailing dot and lowercasing.
Co-authored-by: Jay Satiro
Closes #8320
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 2019 - 2021, Michael Forney, <mforney@mforney.org>
+ * Copyright (C) 2019 - 2022, Michael Forney, <mforney@mforney.org>
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
}
hostname = NULL;
}
+ else {
+ char *snihost = Curl_ssl_snihost(data, hostname, NULL);
+ if(!snihost) {
+ failf(data, "Failed to set SNI");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ hostname = snihost;
+ }
if(!br_ssl_client_reset(&backend->ctx, hostname, 0))
return CURLE_FAILED_INIT;
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
/* Process SNI. Ignore if not supported (on OS400 < V7R1). */
if(sni) {
+ char *snihost = Curl_ssl_snihost(data, sni, NULL);
+ if(!snihost) {
+ failf(data, "Failed to set SNI");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
result = set_buffer(data, BACKEND->handle,
- GSK_SSL_EXTN_SERVERNAME_REQUEST, sni, TRUE);
+ GSK_SSL_EXTN_SERVERNAME_REQUEST, snihost, TRUE);
if(result == CURLE_UNSUPPORTED_PROTOCOL)
result = CURLE_OK;
}
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
#ifdef ENABLE_IPV6
(0 == Curl_inet_pton(AF_INET6, hostname, &addr)) &&
#endif
- sni &&
- (gnutls_server_name_set(session, GNUTLS_NAME_DNS, hostname,
- strlen(hostname)) < 0))
- infof(data, "WARNING: failed to configure server name indication (SNI) "
- "TLS extension");
+ sni) {
+ size_t snilen;
+ char *snihost = Curl_ssl_snihost(data, hostname, &snilen);
+ if(!snihost || gnutls_server_name_set(session, GNUTLS_NAME_DNS, snihost,
+ snilen) < 0) {
+ failf(data, "Failed to set SNI");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ }
/* Use default priorities */
rc = gnutls_set_default_priority(session);
mbedtls_ssl_conf_own_cert(&backend->config,
&backend->clicert, &backend->pk);
}
- if(mbedtls_ssl_set_hostname(&backend->ssl, hostname)) {
- /* mbedtls_ssl_set_hostname() sets the name to use in CN/SAN checks *and*
- the name to set in the SNI extension. So even if curl connects to a
- host specified as an IP address, this function must be used. */
- failf(data, "couldn't set hostname in mbedTLS");
- return CURLE_SSL_CONNECT_ERROR;
+ {
+ char *snihost = Curl_ssl_snihost(data, hostname, NULL);
+ if(!snihost || mbedtls_ssl_set_hostname(&backend->ssl, snihost)) {
+ /* 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. */
+ failf(data, "Failed to set SNI");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
}
#ifdef HAS_ALPN
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
CURLcode result;
bool second_layer = FALSE;
SSLVersionRange sslver_supported;
-
SSLVersionRange sslver = {
SSL_LIBRARY_VERSION_TLS_1_0, /* min */
#ifdef SSL_LIBRARY_VERSION_TLS_1_3
SSL_LIBRARY_VERSION_TLS_1_0
#endif
};
+ char *snihost = Curl_ssl_snihost(data, SSL_HOST_NAME(), NULL);
+ if(!snihost) {
+ failf(data, "Failed to set SNI");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
backend->data = data;
goto error;
/* propagate hostname to the TLS layer */
- if(SSL_SetURL(backend->handle, SSL_HOST_NAME()) != SECSuccess)
+ if(SSL_SetURL(backend->handle, snihost) != SECSuccess)
goto error;
/* prevent NSS from re-using the session for a different hostname */
- if(SSL_SetSockPeerID(backend->handle, SSL_HOST_NAME()) != SECSuccess)
+ if(SSL_SetSockPeerID(backend->handle, snihost) != SECSuccess)
goto error;
return CURLE_OK;
(0 == Curl_inet_pton(AF_INET6, hostname, &addr)) &&
#endif
sni) {
- size_t nlen = strlen(hostname);
- if((long)nlen >= data->set.buffer_size)
- /* this is seriously messed up */
+ char *snihost = Curl_ssl_snihost(data, hostname, NULL);
+ if(!snihost || !SSL_set_tlsext_host_name(backend->handle, snihost)) {
+ failf(data, "Failed set SNI");
return CURLE_SSL_CONNECT_ERROR;
-
- /* RFC 6066 section 3 says the SNI field is case insensitive, but browsers
- send the data lowercase and subsequently there are now numerous servers
- out there that don't work unless the name is lowercased */
- Curl_strntolower(data->state.buffer, hostname, nlen);
- data->state.buffer[nlen] = 0;
- DEBUGASSERT(nlen);
- DEBUGASSERT(data->state.buffer[nlen-1] != '.');
- if(!SSL_set_tlsext_host_name(backend->handle, data->state.buffer))
- infof(data, "WARNING: failed to configure server name indication (SNI) "
- "TLS extension");
+ }
}
#endif
backend->config = rustls_client_config_builder_build(config_builder);
DEBUGASSERT(rconn == NULL);
- result = rustls_client_connection_new(backend->config, hostname, &rconn);
+ {
+ char *snihost = Curl_ssl_snihost(data, hostname, NULL);
+ if(!snihost) {
+ failf(data, "Failed to set SNI");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ result = rustls_client_connection_new(backend->config, snihost, &rconn);
+ }
if(result != RUSTLS_RESULT_OK) {
rustls_error(result, errorbuf, sizeof(errorbuf), &errorlen);
failf(data, "rustls_client_connection_new: %.*s", errorlen, errorbuf);
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 2012 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2012 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 2012 - 2016, Marc Hoersken, <info@marc-hoersken.de>
* Copyright (C) 2012, Mark Salisbury, <mark.salisbury@hp.com>
*
#ifdef ENABLE_IPV6
struct in6_addr addr6;
#endif
- TCHAR *host_name;
CURLcode result;
char * const hostname = SSL_HOST_NAME();
struct ssl_backend_data *backend = connssl->backend;
}
if(!backend->cred) {
+ char *snihost;
result = schannel_acquire_credential_handle(data, conn, sockindex);
if(result != CURLE_OK) {
return result;
}
+ /* A hostname associated with the credential is needed by
+ InitializeSecurityContext for SNI and other reasons. */
+ snihost = Curl_ssl_snihost(data, SSL_HOST_NAME(), NULL);
+ if(!snihost) {
+ failf(data, "Failed to set SNI");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ 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 */
return CURLE_OUT_OF_MEMORY;
}
- host_name = curlx_convert_UTF8_to_tchar(hostname);
- if(!host_name)
- return CURLE_OUT_OF_MEMORY;
-
/* Schannel InitializeSecurityContext:
https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx
us problems with inbuf regardless. https://github.com/curl/curl/issues/983
*/
sspi_status = s_pSecFn->InitializeSecurityContext(
- &backend->cred->cred_handle, NULL, host_name, backend->req_flags, 0, 0,
+ &backend->cred->cred_handle, NULL, backend->cred->sni_hostname,
+ backend->req_flags, 0, 0,
(backend->use_alpn ? &inbuf_desc : NULL),
0, &backend->ctxt->ctxt_handle,
&outbuf_desc, &backend->ret_flags, &backend->ctxt->time_stamp);
- curlx_unicodefree(host_name);
-
if(sspi_status != SEC_I_CONTINUE_NEEDED) {
char buffer[STRERROR_LEN];
Curl_safefree(backend->ctxt);
SECURITY_STATUS sspi_status = SEC_E_OK;
CURLcode result;
bool doread;
- char * const hostname = SSL_HOST_NAME();
const char *pubkey_ptr;
struct ssl_backend_data *backend = connssl->backend;
doread = (connssl->connecting_state != ssl_connect_2_writing) ? TRUE : FALSE;
- DEBUGF(infof(data,
- "schannel: SSL/TLS connection with %s port %hu (step 2/3)",
- hostname, conn->remote_port));
-
if(!backend->cred || !backend->ctxt)
return CURLE_SSL_CONNECT_ERROR;
}
for(;;) {
- TCHAR *host_name;
if(doread) {
/* read encrypted handshake data from socket */
result = Curl_read_plain(conn->sock[sockindex],
memcpy(inbuf[0].pvBuffer, backend->encdata_buffer,
backend->encdata_offset);
- host_name = curlx_convert_UTF8_to_tchar(hostname);
- if(!host_name)
- return CURLE_OUT_OF_MEMORY;
-
sspi_status = s_pSecFn->InitializeSecurityContext(
&backend->cred->cred_handle, &backend->ctxt->ctxt_handle,
- host_name, backend->req_flags, 0, 0, &inbuf_desc, 0, NULL,
+ backend->cred->sni_hostname, backend->req_flags,
+ 0, 0, &inbuf_desc, 0, NULL,
&outbuf_desc, &backend->ret_flags, &backend->ctxt->time_stamp);
- curlx_unicodefree(host_name);
-
/* free buffer for received handshake data */
Curl_safefree(inbuf[0].pvBuffer);
cred->refcount--;
if(cred->refcount == 0) {
s_pSecFn->FreeCredentialsHandle(&cred->cred_handle);
+ curlx_unicodefree(cred->sni_hostname);
Curl_safefree(cred);
}
}
SecBuffer outbuf;
SecBufferDesc outbuf_desc;
CURLcode result;
- TCHAR *host_name;
DWORD dwshut = SCHANNEL_SHUTDOWN;
InitSecBuffer(&Buffer, SECBUFFER_TOKEN, &dwshut, sizeof(dwshut));
Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
}
- host_name = curlx_convert_UTF8_to_tchar(hostname);
- if(!host_name)
- return CURLE_OUT_OF_MEMORY;
-
/* setup output buffer */
InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0);
InitSecBufferDesc(&outbuf_desc, &outbuf, 1);
sspi_status = s_pSecFn->InitializeSecurityContext(
&backend->cred->cred_handle,
&backend->ctxt->ctxt_handle,
- host_name,
+ backend->cred->sni_hostname,
backend->req_flags,
0,
0,
&backend->ret_flags,
&backend->ctxt->time_stamp);
- curlx_unicodefree(host_name);
-
if((sspi_status == SEC_E_OK) || (sspi_status == SEC_I_CONTEXT_EXPIRED)) {
/* send close message which is in output buffer */
ssize_t written;
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2012, Marc Hoersken, <info@marc-hoersken.de>, et al.
- * Copyright (C) 2012 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2012 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
struct Curl_schannel_cred {
CredHandle cred_handle;
TimeStamp time_stamp;
+ TCHAR *sni_hostname;
int refcount;
};
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 2012 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2012 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 2012 - 2017, Nick Zitzmann, <nickzman@gmail.com>.
*
* This software is licensed as described in the file COPYING, which
* Both hostname check and SNI require SSLSetPeerDomainName().
* Also: the verifyhost setting influences SNI usage */
if(conn->ssl_config.verifyhost) {
- err = SSLSetPeerDomainName(backend->ssl_ctx, hostname,
- strlen(hostname));
+ size_t snilen;
+ char *snihost = Curl_ssl_snihost(data, hostname, &snilen);
+ if(!snihost) {
+ failf(data, "Failed to set SNI");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ err = SSLSetPeerDomainName(backend->ssl_ctx, snihost, snilen);
if(err != noErr) {
infof(data, "WARNING: SSL: SSLSetPeerDomainName() failed: OSStatus %d",
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((long)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
*/
data->set.str[STRING_SSL_PINNEDPUBLICKEY]
#endif
+char *Curl_ssl_snihost(struct Curl_easy *data, const char *host, size_t *olen);
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,
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
if((hostname_len < USHRT_MAX) &&
(0 == Curl_inet_pton(AF_INET, hostname, &addr4)) &&
#ifdef ENABLE_IPV6
- (0 == Curl_inet_pton(AF_INET6, hostname, &addr6)) &&
+ (0 == Curl_inet_pton(AF_INET6, hostname, &addr6))
#endif
- (wolfSSL_CTX_UseSNI(backend->ctx, WOLFSSL_SNI_HOST_NAME, hostname,
- (unsigned short)hostname_len) != 1)) {
- infof(data, "WARNING: failed to configure server name indication (SNI) "
- "TLS extension");
+ ) {
+ size_t snilen;
+ char *snihost = Curl_ssl_snihost(data, hostname, &snilen);
+ if(!snihost ||
+ wolfSSL_CTX_UseSNI(backend->ctx, WOLFSSL_SNI_HOST_NAME, snihost,
+ (unsigned short)snilen) != 1) {
+ failf(data, "Failed to set SNI");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
}
}
#endif
int ret = -1;
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
struct ssl_backend_data *backend = connssl->backend;
- const char * const hostname = SSL_HOST_NAME();
const char * const dispname = SSL_HOST_DISPNAME();
const char * const pinnedpubkey = SSL_PINNED_PUB_KEY();
/* Enable RFC2818 checks */
if(SSL_CONN_CONFIG(verifyhost)) {
- ret = wolfSSL_check_domain_name(backend->handle, hostname);
- if(ret == SSL_FAILURE)
- return CURLE_OUT_OF_MEMORY;
+ char *snihost = Curl_ssl_snihost(data, SSL_HOST_NAME(), NULL);
+ if(!snihost ||
+ (wolfSSL_check_domain_name(backend->handle, snihost) == SSL_FAILURE))
+ return CURLE_SSL_CONNECT_ERROR;
}
ret = SSL_connect(backend->handle);