*
* Copyright (C) 2012 - 2016, Marc Hoersken, <info@marc-hoersken.de>
* Copyright (C) 2012, Mark Salisbury, <mark.salisbury@hp.com>
- * Copyright (C) 2012 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2012 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
#include "x509asn1.h"
#include "curl_printf.h"
#include "system_win32.h"
-#include "hostcheck.h"
/* The last #include file should be: */
#include "curl_memory.h"
#endif
TCHAR *host_name;
CURLcode result;
- const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
- conn->host.name;
infof(data, "schannel: SSL/TLS connection with %s port %hu (step 1/3)\n",
- hostname, conn->remote_port);
-
- if(Curl_verify_windows_version(5, 1, PLATFORM_WINNT,
- VERSION_LESS_THAN_EQUAL)) {
- /* SChannel in Windows XP (OS version 5.1) uses legacy handshakes and
- algorithms that may not be supported by all servers. */
- infof(data, "schannel: WinSSL version is old and may not be able to "
- "connect to some servers due to lack of SNI, algorithms, etc.\n");
- }
+ conn->host.name, conn->remote_port);
#ifdef HAS_ALPN
/* ALPN is only supported on Windows 8.1 / Server 2012 R2 and above.
connssl->cred = NULL;
/* check for an existing re-usable credential handle */
- if(data->set.general_ssl.sessionid) {
+ if(conn->ssl_config.sessionid) {
Curl_ssl_sessionid_lock(conn);
- if(!Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL, sockindex)) {
+ if(!Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL)) {
connssl->cred = old_cred;
infof(data, "schannel: re-using existing credential handle\n");
memset(&schannel_cred, 0, sizeof(schannel_cred));
schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
- if(conn->ssl_config.verifypeer) {
+ if(data->set.ssl.verifypeer) {
#ifdef _WIN32_WCE
/* certificate validation on CE doesn't seem to work right; we'll
do it following a more manual process. */
SCH_CRED_IGNORE_REVOCATION_OFFLINE;
#else
schannel_cred.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION;
- /* TODO s/data->set.ssl.no_revoke/SSL_SET_OPTION(no_revoke)/g */
- if(data->set.ssl.no_revoke)
+ if(data->set.ssl_no_revoke)
schannel_cred.dwFlags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
SCH_CRED_IGNORE_REVOCATION_OFFLINE;
else
schannel_cred.dwFlags |= SCH_CRED_REVOCATION_CHECK_CHAIN;
#endif
- if(data->set.ssl.no_revoke)
+ if(data->set.ssl_no_revoke)
infof(data, "schannel: disabled server certificate revocation "
"checks\n");
else
infof(data, "schannel: disabled server certificate revocation checks\n");
}
- if(!conn->ssl_config.verifyhost) {
+ if(!data->set.ssl.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.\n");
+ "names in server certificates. Also disables SNI.\n");
}
- switch(conn->ssl_config.version) {
+ switch(data->set.ssl.version) {
+ default:
case CURL_SSLVERSION_DEFAULT:
case CURL_SSLVERSION_TLSv1:
schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_0_CLIENT |
case CURL_SSLVERSION_TLSv1_2:
schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_2_CLIENT;
break;
- case CURL_SSLVERSION_TLSv1_3:
- failf(data, "Schannel: TLS 1.3 is not yet supported");
- return CURLE_SSL_CONNECT_ERROR;
case CURL_SSLVERSION_SSLv3:
schannel_cred.grbitEnabledProtocols = SP_PROT_SSL3_CLIENT;
break;
case CURL_SSLVERSION_SSLv2:
schannel_cred.grbitEnabledProtocols = SP_PROT_SSL2_CLIENT;
break;
- default:
- failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
- return CURLE_SSL_CONNECT_ERROR;
}
/* allocate memory for the re-usable credential handle */
}
/* Warn if SNI is disabled due to use of an IP address */
- if(Curl_inet_pton(AF_INET, hostname, &addr)
+ if(Curl_inet_pton(AF_INET, conn->host.name, &addr)
#ifdef ENABLE_IPV6
- || Curl_inet_pton(AF_INET6, hostname, &addr6)
+ || Curl_inet_pton(AF_INET6, conn->host.name, &addr6)
#endif
) {
infof(data, "schannel: using IP address, SNI is not supported by OS.\n");
if(connssl->use_alpn) {
int cur = 0;
int list_start_index = 0;
- unsigned int *extension_len = NULL;
+ unsigned int* extension_len = NULL;
unsigned short* list_len = NULL;
/* The first four bytes will be an unsigned int indicating number
of bytes of data in the rest of the the buffer. */
- extension_len = (unsigned int *)(&alpn_buffer[cur]);
+ extension_len = (unsigned int*)(&alpn_buffer[cur]);
cur += sizeof(unsigned int);
/* The next four bytes are an indicator that this buffer will contain
ALPN data, as opposed to NPN, for example. */
- *(unsigned int *)&alpn_buffer[cur] =
+ *(unsigned int*)&alpn_buffer[cur] =
SecApplicationProtocolNegotiationExt_ALPN;
cur += sizeof(unsigned int);
}
memset(connssl->ctxt, 0, sizeof(struct curl_schannel_ctxt));
- host_name = Curl_convert_UTF8_to_tchar(hostname);
+ host_name = Curl_convert_UTF8_to_tchar(conn->host.name);
if(!host_name)
return CURLE_OUT_OF_MEMORY;
TCHAR *host_name;
CURLcode result;
bool doread;
- const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
- conn->host.name;
doread = (connssl->connecting_state != ssl_connect_2_writing) ? TRUE : FALSE;
infof(data, "schannel: SSL/TLS connection with %s port %hu (step 2/3)\n",
- hostname, conn->remote_port);
+ conn->host.name, conn->remote_port);
if(!connssl->cred || !connssl->ctxt)
return CURLE_SSL_CONNECT_ERROR;
memcpy(inbuf[0].pvBuffer, connssl->encdata_buffer,
connssl->encdata_offset);
- host_name = Curl_convert_UTF8_to_tchar(hostname);
+ host_name = Curl_convert_UTF8_to_tchar(conn->host.name);
if(!host_name)
return CURLE_OUT_OF_MEMORY;
#ifdef _WIN32_WCE
/* Windows CE doesn't do any server certificate validation.
We have to do it manually. */
- if(conn->ssl_config.verifypeer)
+ if(data->set.ssl.verifypeer)
return verify_certificate(conn, sockindex);
#endif
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
SECURITY_STATUS sspi_status = SEC_E_OK;
CERT_CONTEXT *ccert_context = NULL;
- const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
- conn->host.name;
#ifdef HAS_ALPN
SecPkgContext_ApplicationProtocol alpn_result;
#endif
DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
infof(data, "schannel: SSL/TLS connection with %s port %hu (step 3/3)\n",
- hostname, conn->remote_port);
+ conn->host.name, conn->remote_port);
if(!connssl->cred)
return CURLE_SSL_CONNECT_ERROR;
#endif
/* save the current session data for possible re-use */
- if(data->set.general_ssl.sessionid) {
+ if(conn->ssl_config.sessionid) {
bool incache;
struct curl_schannel_cred *old_cred = NULL;
Curl_ssl_sessionid_lock(conn);
- incache = !(Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL,
- sockindex));
+ incache = !(Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL));
if(incache) {
if(old_cred != connssl->cred) {
infof(data, "schannel: old credential handle is stale, removing\n");
}
if(!incache) {
result = Curl_ssl_addsessionid(conn, (void *)connssl->cred,
- sizeof(struct curl_schannel_cred),
- sockindex);
+ sizeof(struct curl_schannel_cred));
if(result) {
Curl_ssl_sessionid_unlock(conn);
failf(data, "schannel: failed to store credential handle");
struct Curl_easy *data = conn->data;
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
curl_socket_t sockfd = conn->sock[sockindex];
- time_t timeout_ms;
+ long timeout_ms;
int what;
/* check if the connection has already been established */
curl_socket_t readfd = ssl_connect_2_reading ==
connssl->connecting_state ? sockfd : CURL_SOCKET_BAD;
- what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
- nonblocking ? 0 : timeout_ms);
+ what = Curl_socket_ready(readfd, writefd, nonblocking ? 0 : timeout_ms);
if(what < 0) {
/* fatal error */
failf(data, "select/poll on SSL/TLS socket, errno: %d", SOCKERRNO);
/* send entire message or fail */
while(len > (size_t)written) {
ssize_t this_write;
- time_t timeleft;
+ long timeleft;
int what;
this_write = 0;
break;
}
- what = SOCKET_WRITABLE(conn->sock[sockindex], timeleft);
+ what = Curl_socket_ready(CURL_SOCKET_BAD, conn->sock[sockindex],
+ timeleft);
if(what < 0) {
/* fatal error */
failf(conn->data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
*/
struct Curl_easy *data = conn->data;
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
- conn->host.name;
infof(data, "schannel: shutting down SSL/TLS connection with %s port %hu\n",
- hostname, conn->remote_port);
+ conn->host.name, conn->remote_port);
if(connssl->cred && connssl->ctxt) {
SecBufferDesc BuffDesc;
failf(data, "schannel: ApplyControlToken failure: %s",
Curl_sspi_strerror(conn, sspi_status));
- host_name = Curl_convert_UTF8_to_tchar(hostname);
+ host_name = Curl_convert_UTF8_to_tchar(conn->host.name);
if(!host_name)
return CURLE_OUT_OF_MEMORY;
return size;
}
-CURLcode Curl_schannel_random(unsigned char *entropy, size_t length)
+int Curl_schannel_random(unsigned char *entropy, size_t length)
{
HCRYPTPROV hCryptProv = 0;
if(!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
- return CURLE_FAILED_INIT;
+ return 1;
if(!CryptGenRandom(hCryptProv, (DWORD)length, entropy)) {
CryptReleaseContext(hCryptProv, 0UL);
- return CURLE_FAILED_INIT;
+ return 1;
}
CryptReleaseContext(hCryptProv, 0UL);
- return CURLE_OK;
+ return 0;
}
#ifdef _WIN32_WCE
CURLcode result = CURLE_OK;
CERT_CONTEXT *pCertContextServer = NULL;
const CERT_CHAIN_CONTEXT *pChainContext = NULL;
- const char * const conn_hostname = SSL_IS_PROXY() ?
- conn->http_proxy.host.name :
- conn->host.name;
status = s_pSecFn->QueryContextAttributes(&connssl->ctxt->ctxt_handle,
SECPKG_ATTR_REMOTE_CERT_CONTEXT,
NULL,
pCertContextServer->hCertStore,
&ChainPara,
- (data->set.ssl.no_revoke ? 0 :
+ (data->set.ssl_no_revoke ? 0 :
CERT_CHAIN_REVOCATION_CHECK_CHAIN),
NULL,
&pChainContext)) {
}
if(result == CURLE_OK) {
- if(conn->ssl_config.verifyhost) {
- TCHAR cert_hostname_buff[256];
+ if(data->set.ssl.verifyhost) {
+ TCHAR cert_hostname_buff[128];
+ xcharp_u hostname;
+ xcharp_u cert_hostname;
DWORD len;
+ cert_hostname.const_tchar_ptr = cert_hostname_buff;
+ hostname.tchar_ptr = Curl_convert_UTF8_to_tchar(conn->host.name);
+
/* TODO: Fix this for certificates with multiple alternative names.
Right now we're only asking for the first preferred alternative name.
Instead we'd need to do all via CERT_NAME_SEARCH_ALL_NAMES_FLAG
*/
len = CertGetNameString(pCertContextServer,
CERT_NAME_DNS_TYPE,
- CERT_NAME_DISABLE_IE4_UTF8_FLAG,
+ 0,
NULL,
- cert_hostname_buff,
- 256);
- if(len > 0) {
- const char *cert_hostname;
-
- /* Comparing the cert name and the connection hostname encoded as UTF-8
- * is acceptable since both values are assumed to use ASCII
- * (or some equivalent) encoding
- */
- cert_hostname = Curl_convert_tchar_to_UTF8(cert_hostname_buff);
- if(!cert_hostname) {
- result = CURLE_OUT_OF_MEMORY;
- }
- else{
- int match_result;
-
- match_result = Curl_cert_hostcheck(cert_hostname, conn->host.name);
- if(match_result == CURL_HOST_MATCH) {
- infof(data,
- "schannel: connection hostname (%s) validated "
- "against certificate name (%s)\n",
- conn->host.name,
- cert_hostname);
- result = CURLE_OK;
- }
- else{
- failf(data,
- "schannel: connection hostname (%s) "
- "does not match certificate name (%s)",
- conn->host.name,
- cert_hostname);
- result = CURLE_PEER_FAILED_VERIFICATION;
- }
- Curl_unicodefree(cert_hostname);
- }
+ cert_hostname.tchar_ptr,
+ 128);
+ if(len > 0 && *cert_hostname.tchar_ptr == '*') {
+ /* this is a wildcard cert. try matching the last len - 1 chars */
+ int hostname_len = strlen(conn->host.name);
+ cert_hostname.tchar_ptr++;
+ if(_tcsicmp(cert_hostname.const_tchar_ptr,
+ hostname.const_tchar_ptr + hostname_len - len + 2) != 0)
+ result = CURLE_PEER_FAILED_VERIFICATION;
}
- else {
- failf(data,
- "schannel: CertGetNameString did not provide any "
- "certificate name information");
+ else if(len == 0 || _tcsicmp(hostname.const_tchar_ptr,
+ cert_hostname.const_tchar_ptr) != 0) {
result = CURLE_PEER_FAILED_VERIFICATION;
}
+ if(result == CURLE_PEER_FAILED_VERIFICATION) {
+ char *_cert_hostname;
+ _cert_hostname = Curl_convert_tchar_to_UTF8(cert_hostname.tchar_ptr);
+ failf(data, "schannel: CertGetNameString() certificate hostname "
+ "(%s) did not match connection (%s)",
+ _cert_hostname, conn->host.name);
+ Curl_unicodefree(_cert_hostname);
+ }
+ Curl_unicodefree(hostname.tchar_ptr);
}
}