summaryrefslogtreecommitdiff
path: root/libs/libcurl/src/vtls/schannel.c
diff options
context:
space:
mode:
Diffstat (limited to 'libs/libcurl/src/vtls/schannel.c')
-rw-r--r--libs/libcurl/src/vtls/schannel.c336
1 files changed, 202 insertions, 134 deletions
diff --git a/libs/libcurl/src/vtls/schannel.c b/libs/libcurl/src/vtls/schannel.c
index d172b567c4..6fef076099 100644
--- a/libs/libcurl/src/vtls/schannel.c
+++ b/libs/libcurl/src/vtls/schannel.c
@@ -34,7 +34,7 @@
#ifdef USE_SCHANNEL
#ifndef USE_WINDOWS_SSPI
-# error "Can't compile SCHANNEL support without SSPI."
+# error "cannot compile SCHANNEL support without SSPI."
#endif
#include "schannel.h"
@@ -171,7 +171,7 @@ schannel_set_ssl_version_min_max(DWORD *enabled_protocols,
{
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
long ssl_version = conn_config->version;
- long ssl_version_max = conn_config->version_max;
+ long ssl_version_max = (long)conn_config->version_max;
long i = ssl_version;
switch(ssl_version_max) {
@@ -364,7 +364,7 @@ set_ssl_ciphers(SCHANNEL_CRED *schannel_cred, char *ciphers,
if(!alg)
alg = get_alg_id_by_name(startCur);
if(alg)
- algIds[algCount++] = alg;
+ algIds[algCount++] = (ALG_ID)alg;
else if(!strncmp(startCur, "USE_STRONG_CRYPTO",
sizeof("USE_STRONG_CRYPTO") - 1) ||
!strncmp(startCur, "SCH_USE_STRONG_CRYPTO",
@@ -377,7 +377,7 @@ set_ssl_ciphers(SCHANNEL_CRED *schannel_cred, char *ciphers,
startCur++;
}
schannel_cred->palgSupportedAlgs = algIds;
- schannel_cred->cSupportedAlgs = algCount;
+ schannel_cred->cSupportedAlgs = (DWORD)algCount;
return CURLE_OK;
}
@@ -513,7 +513,7 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf,
}
if(!ssl_config->auto_client_cert) {
- flags &= ~SCH_CRED_USE_DEFAULT_CREDS;
+ flags &= ~(DWORD)SCH_CRED_USE_DEFAULT_CREDS;
flags |= SCH_CRED_NO_DEFAULT_CREDS;
infof(data, "schannel: disabled automatic use of client certificate");
}
@@ -950,7 +950,7 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf,
tls_parameters.pDisabledCrypto = crypto_settings;
/* The number of blocked suites */
- tls_parameters.cDisabledCrypto = crypto_settings_idx;
+ tls_parameters.cDisabledCrypto = (DWORD)crypto_settings_idx;
credentials.pTlsParameters = &tls_parameters;
credentials.cTlsParameters = 1;
@@ -976,7 +976,7 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf,
}
else {
/* Pre-Windows 10 1809 or the user set a legacy algorithm list. Although MS
- doesn't document it, currently Schannel will not negotiate TLS 1.3 when
+ does not document it, currently Schannel will not negotiate TLS 1.3 when
SCHANNEL_CRED is used. */
ALG_ID algIds[NUM_CIPHERS];
char *ciphers = conn_config->cipher_list;
@@ -1083,7 +1083,7 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
#ifdef HAS_ALPN
/* ALPN is only supported on Windows 8.1 / Server 2012 R2 and above.
- Also it doesn't seem to be supported for Wine, see curl bug #983. */
+ Also it does not seem to be supported for Wine, see curl bug #983. */
backend->use_alpn = connssl->alpn &&
!GetProcAddress(GetModuleHandle(TEXT("ntdll")),
"wine_get_version") &&
@@ -1095,7 +1095,7 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
#ifdef _WIN32_WCE
#ifdef HAS_MANUAL_VERIFY_API
- /* certificate validation on CE doesn't seem to work right; we'll
+ /* certificate validation on CE does not seem to work right; we will
* do it following a more manual process. */
backend->use_manual_cred_validation = true;
#else
@@ -1127,7 +1127,7 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
backend->cred = NULL;
/* check for an existing reusable credential handle */
- if(ssl_config->primary.sessionid) {
+ if(ssl_config->primary.cache_session) {
Curl_ssl_sessionid_lock(data);
if(!Curl_ssl_getsessionid(cf, data, &connssl->peer,
(void **)&old_cred, NULL)) {
@@ -1241,7 +1241,7 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
/* Schannel InitializeSecurityContext:
https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx
- At the moment we don't pass inbuf unless we're using ALPN since we only
+ At the moment we do not pass inbuf unless we are using ALPN since we only
use it for that, and Wine (for which we currently disable ALPN) is giving
us problems with inbuf regardless. https://github.com/curl/curl/issues/983
*/
@@ -1332,7 +1332,8 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
DEBUGASSERT(backend);
- doread = (connssl->connecting_state != ssl_connect_2_writing) ? TRUE : FALSE;
+ doread = (connssl->io_need & CURL_SSL_IO_NEED_SEND)? FALSE : TRUE;
+ connssl->io_need = CURL_SSL_IO_NEED_NONE;
DEBUGF(infof(data,
"schannel: SSL/TLS connection with %s port %d (step 2/3)",
@@ -1393,8 +1394,7 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
backend->encdata_offset,
&result);
if(result == CURLE_AGAIN) {
- if(connssl->connecting_state != ssl_connect_2_writing)
- connssl->connecting_state = ssl_connect_2_reading;
+ connssl->io_need = CURL_SSL_IO_NEED_RECV;
DEBUGF(infof(data, "schannel: failed to receive handshake, "
"need more data"));
return CURLE_OK;
@@ -1448,7 +1448,7 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
/* check if the handshake was incomplete */
if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
backend->encdata_is_incomplete = true;
- connssl->connecting_state = ssl_connect_2_reading;
+ connssl->io_need = CURL_SSL_IO_NEED_RECV;
DEBUGF(infof(data,
"schannel: received incomplete message, need more data"));
return CURLE_OK;
@@ -1460,7 +1460,7 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
if(sspi_status == SEC_I_INCOMPLETE_CREDENTIALS &&
!(backend->req_flags & ISC_REQ_USE_SUPPLIED_CREDS)) {
backend->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS;
- connssl->connecting_state = ssl_connect_2_writing;
+ connssl->io_need = CURL_SSL_IO_NEED_SEND;
DEBUGF(infof(data,
"schannel: a client certificate has been requested"));
return CURLE_OK;
@@ -1531,7 +1531,7 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
inbuf[1].cbBuffer));
/*
There are two cases where we could be getting extra data here:
- 1) If we're renegotiating a connection and the handshake is already
+ 1) If we are renegotiating a connection and the handshake is already
complete (from the server perspective), it can encrypted app data
(not handshake data) in an extra buffer at this point.
2) (sspi_status == SEC_I_CONTINUE_NEEDED) We are negotiating a
@@ -1560,7 +1560,7 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
/* check if the handshake needs to be continued */
if(sspi_status == SEC_I_CONTINUE_NEEDED) {
- connssl->connecting_state = ssl_connect_2_reading;
+ connssl->io_need = CURL_SSL_IO_NEED_RECV;
return CURLE_OK;
}
@@ -1593,7 +1593,7 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
#endif
/* Verify the hostname manually when certificate verification is disabled,
- because in that case Schannel won't verify it. */
+ because in that case Schannel will not verify it. */
if(!conn_config->verifypeer && conn_config->verifyhost)
return Curl_verify_host(cf, data);
@@ -1772,34 +1772,16 @@ schannel_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
#endif
/* save the current session data for possible reuse */
- if(ssl_config->primary.sessionid) {
- bool incache;
- struct Curl_schannel_cred *old_cred = NULL;
-
+ if(ssl_config->primary.cache_session) {
Curl_ssl_sessionid_lock(data);
- incache = !(Curl_ssl_getsessionid(cf, data, &connssl->peer,
- (void **)&old_cred, NULL));
- if(incache) {
- if(old_cred != backend->cred) {
- DEBUGF(infof(data,
- "schannel: old credential handle is stale, removing"));
- /* we're not taking old_cred ownership here, no refcount++ is needed */
- Curl_ssl_delsessionid(data, (void *)old_cred);
- incache = FALSE;
- }
- }
- if(!incache) {
- /* Up ref count since call takes ownership */
- backend->cred->refcount++;
- result = Curl_ssl_addsessionid(cf, data, &connssl->peer, backend->cred,
- sizeof(struct Curl_schannel_cred),
- schannel_session_free);
- if(result) {
- Curl_ssl_sessionid_unlock(data);
- return result;
- }
- }
+ /* Up ref count since call takes ownership */
+ backend->cred->refcount++;
+ result = Curl_ssl_set_sessionid(cf, data, &connssl->peer, backend->cred,
+ sizeof(struct Curl_schannel_cred),
+ schannel_session_free);
Curl_ssl_sessionid_unlock(data);
+ if(result)
+ return result;
}
if(data->set.ssl.certinfo) {
@@ -1853,7 +1835,7 @@ schannel_connect_common(struct Curl_cfilter *cf,
}
if(ssl_connect_1 == connssl->connecting_state) {
- /* check out how much more time we're allowed */
+ /* check out how much more time we are allowed */
timeout_ms = Curl_timeleft(data, NULL, TRUE);
if(timeout_ms < 0) {
@@ -1867,11 +1849,9 @@ schannel_connect_common(struct Curl_cfilter *cf,
return result;
}
- while(ssl_connect_2 == connssl->connecting_state ||
- ssl_connect_2_reading == connssl->connecting_state ||
- ssl_connect_2_writing == connssl->connecting_state) {
+ while(ssl_connect_2 == connssl->connecting_state) {
- /* check out how much more time we're allowed */
+ /* check out how much more time we are allowed */
timeout_ms = Curl_timeleft(data, NULL, TRUE);
if(timeout_ms < 0) {
@@ -1880,14 +1860,13 @@ schannel_connect_common(struct Curl_cfilter *cf,
return CURLE_OPERATION_TIMEDOUT;
}
- /* if ssl is expecting something, check if it's available. */
- if(connssl->connecting_state == ssl_connect_2_reading
- || connssl->connecting_state == ssl_connect_2_writing) {
+ /* if ssl is expecting something, check if it is available. */
+ if(connssl->io_need) {
- curl_socket_t writefd = ssl_connect_2_writing ==
- connssl->connecting_state ? sockfd : CURL_SOCKET_BAD;
- curl_socket_t readfd = ssl_connect_2_reading ==
- connssl->connecting_state ? sockfd : CURL_SOCKET_BAD;
+ curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND)?
+ sockfd : CURL_SOCKET_BAD;
+ curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV)?
+ sockfd : CURL_SOCKET_BAD;
what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
nonblocking ? 0 : timeout_ms);
@@ -1918,10 +1897,7 @@ schannel_connect_common(struct Curl_cfilter *cf,
* have a valid fdset to wait on.
*/
result = schannel_connect_step2(cf, data);
- if(result || (nonblocking &&
- (ssl_connect_2 == connssl->connecting_state ||
- ssl_connect_2_reading == connssl->connecting_state ||
- ssl_connect_2_writing == connssl->connecting_state)))
+ if(result || (nonblocking && (ssl_connect_2 == connssl->connecting_state)))
return result;
} /* repeat step2 until all transactions are done. */
@@ -2029,10 +2005,10 @@ schannel_send(struct Curl_cfilter *cf, struct Curl_easy *data,
len = outbuf[0].cbBuffer + outbuf[1].cbBuffer + outbuf[2].cbBuffer;
/*
- It's important to send the full message which includes the header,
- encrypted payload, and trailer. Until the client receives all the
+ it is important to send the full message which includes the header,
+ encrypted payload, and trailer. Until the client receives all the
data a coherent message has not been delivered and the client
- can't read any of it.
+ cannot read any of it.
If we wanted to buffer the unwritten encrypted bytes, we would
tell the client that all data it has requested to be sent has been
@@ -2129,8 +2105,9 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
DEBUGASSERT(backend);
/****************************************************************************
- * Don't return or set backend->recv_unrecoverable_err unless in the cleanup.
- * The pattern for return error is set *err, optional infof, goto cleanup.
+ * Do not return or set backend->recv_unrecoverable_err unless in the
+ * cleanup. The pattern for return error is set *err, optional infof, goto
+ * cleanup.
*
* Our priority is to always return as much decrypted data to the caller as
* possible, even if an error occurs. The state of the decrypted buffer must
@@ -2155,7 +2132,7 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
infof(data, "schannel: server indicated shutdown in a prior call");
goto cleanup;
}
- /* It's debatable what to return when !len. Regardless we can't return
+ /* it is debatable what to return when !len. Regardless we cannot return
immediately because there may be data to decrypt (in the case we want to
decrypt all encrypted cached data) so handle !len later in cleanup.
*/
@@ -2313,14 +2290,15 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
if(sspi_status == SEC_I_RENEGOTIATE) {
infof(data, "schannel: remote party requests renegotiation");
if(*err && *err != CURLE_AGAIN) {
- infof(data, "schannel: can't renegotiate, an error is pending");
+ infof(data, "schannel: cannot renegotiate, an error is pending");
goto cleanup;
}
/* begin renegotiation */
infof(data, "schannel: renegotiating SSL/TLS connection");
connssl->state = ssl_connection_negotiating;
- connssl->connecting_state = ssl_connect_2_writing;
+ connssl->connecting_state = ssl_connect_2;
+ connssl->io_need = CURL_SSL_IO_NEED_SEND;
backend->recv_renegotiating = true;
*err = schannel_connect_common(cf, data, FALSE, &done);
backend->recv_renegotiating = false;
@@ -2377,13 +2355,13 @@ cleanup:
/* Error if the connection has closed without a close_notify.
- The behavior here is a matter of debate. We don't want to be vulnerable
- to a truncation attack however there's some browser precedent for
+ The behavior here is a matter of debate. We do not want to be vulnerable
+ to a truncation attack however there is some browser precedent for
ignoring the close_notify for compatibility reasons.
Additionally, Windows 2000 (v5.0) is a special case since it seems it
- doesn't return close_notify. In that case if the connection was closed we
- assume it was graceful (close_notify) since there doesn't seem to be a
+ does not return close_notify. In that case if the connection was closed we
+ assume it was graceful (close_notify) since there does not seem to be a
way to tell.
*/
if(len && !backend->decdata_offset && backend->recv_connection_closed &&
@@ -2420,7 +2398,7 @@ cleanup:
if(!*err && !backend->recv_connection_closed)
*err = CURLE_AGAIN;
- /* It's debatable what to return when !len. We could return whatever error
+ /* it is debatable what to return when !len. We could return whatever error
we got from decryption but instead we override here so the return is
consistent.
*/
@@ -2475,8 +2453,9 @@ static bool schannel_data_pending(struct Curl_cfilter *cf,
/* shut down the SSL connection and clean up related memory.
this function can be called multiple times on the same connection including
if the SSL connection failed (eg connection made but failed handshake). */
-static int schannel_shutdown(struct Curl_cfilter *cf,
- struct Curl_easy *data)
+static CURLcode schannel_shutdown(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool send_shutdown, bool *done)
{
/* See https://msdn.microsoft.com/en-us/library/windows/desktop/aa380138.aspx
* Shutting Down an Schannel Connection
@@ -2484,22 +2463,36 @@ static int schannel_shutdown(struct Curl_cfilter *cf,
struct ssl_connect_data *connssl = cf->ctx;
struct schannel_ssl_backend_data *backend =
(struct schannel_ssl_backend_data *)connssl->backend;
+ CURLcode result = CURLE_OK;
+
+ if(cf->shutdown) {
+ *done = TRUE;
+ return CURLE_OK;
+ }
DEBUGASSERT(data);
DEBUGASSERT(backend);
+ /* Not supported in schannel */
+ (void)send_shutdown;
+
+ *done = FALSE;
if(backend->ctxt) {
infof(data, "schannel: shutting down SSL/TLS connection with %s port %d",
connssl->peer.hostname, connssl->peer.port);
}
- if(backend->cred && backend->ctxt) {
+ if(!backend->ctxt || cf->shutdown) {
+ *done = TRUE;
+ goto out;
+ }
+
+ if(backend->cred && backend->ctxt && !backend->sent_shutdown) {
SecBufferDesc BuffDesc;
SecBuffer Buffer;
SECURITY_STATUS sspi_status;
SecBuffer outbuf;
SecBufferDesc outbuf_desc;
- CURLcode result;
DWORD dwshut = SCHANNEL_SHUTDOWN;
InitSecBuffer(&Buffer, SECBUFFER_TOKEN, &dwshut, sizeof(dwshut));
@@ -2512,6 +2505,8 @@ static int schannel_shutdown(struct Curl_cfilter *cf,
char buffer[STRERROR_LEN];
failf(data, "schannel: ApplyControlToken failure: %s",
Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
+ result = CURLE_SEND_ERROR;
+ goto out;
}
/* setup output buffer */
@@ -2538,13 +2533,75 @@ static int schannel_shutdown(struct Curl_cfilter *cf,
outbuf.pvBuffer, outbuf.cbBuffer,
&result);
s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
- if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) {
- infof(data, "schannel: failed to send close msg: %s"
- " (bytes written: %zd)", curl_easy_strerror(result), written);
+ if(!result) {
+ if(written < (ssize_t)outbuf.cbBuffer) {
+ /* TODO: handle partial sends */
+ infof(data, "schannel: failed to send close msg: %s"
+ " (bytes written: %zd)", curl_easy_strerror(result), written);
+ result = CURLE_SEND_ERROR;
+ goto out;
+ }
+ backend->sent_shutdown = TRUE;
+ *done = TRUE;
+ }
+ else if(result == CURLE_AGAIN) {
+ connssl->io_need = CURL_SSL_IO_NEED_SEND;
+ result = CURLE_OK;
+ goto out;
+ }
+ else {
+ if(!backend->recv_connection_closed) {
+ infof(data, "schannel: error sending close msg: %d", result);
+ result = CURLE_SEND_ERROR;
+ goto out;
+ }
+ /* Looks like server already closed the connection.
+ * An error to send our close notify is not a failure. */
+ *done = TRUE;
+ result = CURLE_OK;
}
}
}
+ /* If the connection seems open and we have not seen the close notify
+ * from the server yet, try to receive it. */
+ if(backend->cred && backend->ctxt &&
+ !backend->recv_sspi_close_notify && !backend->recv_connection_closed) {
+ char buffer[1024];
+ ssize_t nread;
+
+ nread = schannel_recv(cf, data, buffer, sizeof(buffer), &result);
+ if(nread > 0) {
+ /* still data coming in? */
+ }
+ else if(nread == 0) {
+ /* We got the close notify alert and are done. */
+ backend->recv_connection_closed = TRUE;
+ *done = TRUE;
+ }
+ else if(nread < 0 && result == CURLE_AGAIN) {
+ connssl->io_need = CURL_SSL_IO_NEED_RECV;
+ }
+ else {
+ CURL_TRC_CF(data, cf, "SSL shutdown, error %d", result);
+ result = CURLE_RECV_ERROR;
+ }
+ }
+
+out:
+ cf->shutdown = (result || *done);
+ return result;
+}
+
+static void schannel_close(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct schannel_ssl_backend_data *backend =
+ (struct schannel_ssl_backend_data *)connssl->backend;
+
+ DEBUGASSERT(data);
+ DEBUGASSERT(backend);
+
/* free SSPI Schannel API security context handle */
if(backend->ctxt) {
DEBUGF(infof(data, "schannel: clear security context handle"));
@@ -2574,13 +2631,6 @@ static int schannel_shutdown(struct Curl_cfilter *cf,
backend->decdata_length = 0;
backend->decdata_offset = 0;
}
-
- return CURLE_OK;
-}
-
-static void schannel_close(struct Curl_cfilter *cf, struct Curl_easy *data)
-{
- schannel_shutdown(cf, data);
}
static int schannel_init(void)
@@ -2595,9 +2645,7 @@ static void schannel_cleanup(void)
static size_t schannel_version(char *buffer, size_t size)
{
- size = msnprintf(buffer, size, "Schannel");
-
- return size;
+ return msnprintf(buffer, size, "Schannel");
}
static CURLcode schannel_random(struct Curl_easy *data UNUSED_PARAM,
@@ -2622,7 +2670,7 @@ static CURLcode schannel_pkp_pin_peer_pubkey(struct Curl_cfilter *cf,
DEBUGASSERT(backend);
- /* if a path wasn't specified, don't pin */
+ /* if a path was not specified, do not pin */
if(!pinnedpubkey)
return CURLE_OK;
@@ -2684,6 +2732,13 @@ static void schannel_checksum(const unsigned char *input,
DWORD provType,
const unsigned int algId)
{
+#ifdef CURL_WINDOWS_APP
+ (void)input;
+ (void)inputlen;
+ (void)provType;
+ (void)algId;
+ memset(checksum, 0, checksumlen);
+#else
HCRYPTPROV hProv = 0;
HCRYPTHASH hHash = 0;
DWORD cbHashSize = 0;
@@ -2724,6 +2779,7 @@ static void schannel_checksum(const unsigned char *input,
if(hProv)
CryptReleaseContext(hProv, 0);
+#endif
}
static CURLcode schannel_sha256sum(const unsigned char *input,
@@ -2752,7 +2808,7 @@ HCERTSTORE Curl_schannel_get_cached_cert_store(struct Curl_cfilter *cf,
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
struct Curl_multi *multi = data->multi;
const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
- struct schannel_multi_ssl_backend_data *mbackend;
+ struct schannel_cert_share *share;
const struct ssl_general_config *cfg = &data->set.general_ssl;
timediff_t timeout_ms;
timediff_t elapsed_ms;
@@ -2761,12 +2817,14 @@ HCERTSTORE Curl_schannel_get_cached_cert_store(struct Curl_cfilter *cf,
DEBUGASSERT(multi);
- if(!multi || !multi->ssl_backend_data) {
+ if(!multi) {
return NULL;
}
- mbackend = (struct schannel_multi_ssl_backend_data *)multi->ssl_backend_data;
- if(!mbackend->cert_store) {
+ share = Curl_hash_pick(&multi->proto_hash,
+ (void *)MPROTO_SCHANNEL_CERT_SHARE_KEY,
+ sizeof(MPROTO_SCHANNEL_CERT_SHARE_KEY)-1);
+ if(!share || !share->cert_store) {
return NULL;
}
@@ -2781,37 +2839,52 @@ HCERTSTORE Curl_schannel_get_cached_cert_store(struct Curl_cfilter *cf,
timeout_ms = cfg->ca_cache_timeout * (timediff_t)1000;
if(timeout_ms >= 0) {
now = Curl_now();
- elapsed_ms = Curl_timediff(now, mbackend->time);
+ elapsed_ms = Curl_timediff(now, share->time);
if(elapsed_ms >= timeout_ms) {
return NULL;
}
}
if(ca_info_blob) {
- if(!mbackend->CAinfo_blob_digest) {
+ if(!share->CAinfo_blob_digest) {
return NULL;
}
- if(mbackend->CAinfo_blob_size != ca_info_blob->len) {
+ if(share->CAinfo_blob_size != ca_info_blob->len) {
return NULL;
}
schannel_sha256sum((const unsigned char *)ca_info_blob->data,
ca_info_blob->len,
info_blob_digest,
CURL_SHA256_DIGEST_LENGTH);
- if(memcmp(mbackend->CAinfo_blob_digest,
+ if(memcmp(share->CAinfo_blob_digest,
info_blob_digest,
CURL_SHA256_DIGEST_LENGTH)) {
return NULL;
}
}
else {
- if(!conn_config->CAfile || !mbackend->CAfile ||
- strcmp(mbackend->CAfile, conn_config->CAfile)) {
+ if(!conn_config->CAfile || !share->CAfile ||
+ strcmp(share->CAfile, conn_config->CAfile)) {
return NULL;
}
}
- return mbackend->cert_store;
+ return share->cert_store;
+}
+
+static void schannel_cert_share_free(void *key, size_t key_len, void *p)
+{
+ struct schannel_cert_share *share = p;
+ DEBUGASSERT(key_len == (sizeof(MPROTO_SCHANNEL_CERT_SHARE_KEY)-1));
+ DEBUGASSERT(!memcmp(MPROTO_SCHANNEL_CERT_SHARE_KEY, key, key_len));
+ (void)key;
+ (void)key_len;
+ if(share->cert_store) {
+ CertCloseStore(share->cert_store, 0);
+ }
+ free(share->CAinfo_blob_digest);
+ free(share->CAfile);
+ free(share);
}
bool Curl_schannel_set_cached_cert_store(struct Curl_cfilter *cf,
@@ -2821,7 +2894,7 @@ bool Curl_schannel_set_cached_cert_store(struct Curl_cfilter *cf,
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
struct Curl_multi *multi = data->multi;
const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
- struct schannel_multi_ssl_backend_data *mbackend;
+ struct schannel_cert_share *share;
unsigned char *CAinfo_blob_digest = NULL;
size_t CAinfo_blob_size = 0;
char *CAfile = NULL;
@@ -2832,17 +2905,23 @@ bool Curl_schannel_set_cached_cert_store(struct Curl_cfilter *cf,
return false;
}
- if(!multi->ssl_backend_data) {
- multi->ssl_backend_data =
- calloc(1, sizeof(struct schannel_multi_ssl_backend_data));
- if(!multi->ssl_backend_data) {
+ share = Curl_hash_pick(&multi->proto_hash,
+ (void *)MPROTO_SCHANNEL_CERT_SHARE_KEY,
+ sizeof(MPROTO_SCHANNEL_CERT_SHARE_KEY)-1);
+ if(!share) {
+ share = calloc(1, sizeof(*share));
+ if(!share) {
+ return false;
+ }
+ if(!Curl_hash_add2(&multi->proto_hash,
+ (void *)MPROTO_SCHANNEL_CERT_SHARE_KEY,
+ sizeof(MPROTO_SCHANNEL_CERT_SHARE_KEY)-1,
+ share, schannel_cert_share_free)) {
+ free(share);
return false;
}
}
- mbackend = (struct schannel_multi_ssl_backend_data *)multi->ssl_backend_data;
-
-
if(ca_info_blob) {
CAinfo_blob_digest = malloc(CURL_SHA256_DIGEST_LENGTH);
if(!CAinfo_blob_digest) {
@@ -2864,33 +2943,20 @@ bool Curl_schannel_set_cached_cert_store(struct Curl_cfilter *cf,
}
/* free old cache data */
- if(mbackend->cert_store) {
- CertCloseStore(mbackend->cert_store, 0);
+ if(share->cert_store) {
+ CertCloseStore(share->cert_store, 0);
}
- free(mbackend->CAinfo_blob_digest);
- free(mbackend->CAfile);
+ free(share->CAinfo_blob_digest);
+ free(share->CAfile);
- mbackend->time = Curl_now();
- mbackend->cert_store = cert_store;
- mbackend->CAinfo_blob_digest = CAinfo_blob_digest;
- mbackend->CAinfo_blob_size = CAinfo_blob_size;
- mbackend->CAfile = CAfile;
+ share->time = Curl_now();
+ share->cert_store = cert_store;
+ share->CAinfo_blob_digest = CAinfo_blob_digest;
+ share->CAinfo_blob_size = CAinfo_blob_size;
+ share->CAfile = CAfile;
return true;
}
-static void schannel_free_multi_ssl_backend_data(
- struct multi_ssl_backend_data *msbd)
-{
- struct schannel_multi_ssl_backend_data *mbackend =
- (struct schannel_multi_ssl_backend_data*)msbd;
- if(mbackend->cert_store) {
- CertCloseStore(mbackend->cert_store, 0);
- }
- free(mbackend->CAinfo_blob_digest);
- free(mbackend->CAfile);
- free(mbackend);
-}
-
const struct Curl_ssl Curl_ssl_schannel = {
{ CURLSSLBACKEND_SCHANNEL, "schannel" }, /* info */
@@ -2898,8 +2964,11 @@ const struct Curl_ssl Curl_ssl_schannel = {
#ifdef HAS_MANUAL_VERIFY_API
SSLSUPP_CAINFO_BLOB |
#endif
+#ifndef CURL_WINDOWS_APP
SSLSUPP_PINNEDPUBKEY |
+#endif
SSLSUPP_TLS13_CIPHERSUITES |
+ SSLSUPP_CA_CACHE |
SSLSUPP_HTTPS_PROXY,
sizeof(struct schannel_ssl_backend_data),
@@ -2925,7 +2994,6 @@ const struct Curl_ssl Curl_ssl_schannel = {
schannel_sha256sum, /* sha256sum */
NULL, /* associate_connection */
NULL, /* disassociate_connection */
- schannel_free_multi_ssl_backend_data, /* free_multi_ssl_backend_data */
schannel_recv, /* recv decrypted data */
schannel_send, /* send data to encrypt */
};