diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c index 2653f5dfc4..134726f91d 100644 --- a/lib/vtls/schannel.c +++ b/lib/vtls/schannel.c @@ -115,11 +115,6 @@ #define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0])) #endif -#if defined(CryptStringToBinary) && defined(CRYPT_STRING_HEX) \ - && !defined(DISABLE_SCHANNEL_CLIENT_CERT) -#define HAS_CLIENT_CERT_PATH -#endif - #ifdef HAS_CLIENT_CERT_PATH #ifdef UNICODE #define CURL_CERT_STORE_PROV_SYSTEM CERT_STORE_PROV_SYSTEM_W @@ -186,6 +181,10 @@ #define ALG_CLASS_DHASH ALG_CLASS_HASH #endif +#ifndef PKCS12_NO_PERSIST_KEY +#define PKCS12_NO_PERSIST_KEY 0x00008000 +#endif + static Curl_recv schannel_recv; static Curl_send schannel_send; @@ -486,6 +485,7 @@ schannel_acquire_credential_handle(struct Curl_easy *data, #ifdef HAS_CLIENT_CERT_PATH PCCERT_CONTEXT client_certs[1] = { NULL }; + HCERTSTORE client_cert_store = NULL; #endif SECURITY_STATUS sspi_status = SEC_E_OK; CURLcode result; @@ -676,7 +676,13 @@ schannel_acquire_credential_handle(struct Curl_easy *data, else pszPassword[0] = 0; - cert_store = PFXImportCertStore(&datablob, pszPassword, 0); + if(curlx_verify_windows_version(6, 0, 0, PLATFORM_WINNT, + VERSION_GREATER_THAN_EQUAL)) + cert_store = PFXImportCertStore(&datablob, pszPassword, + PKCS12_NO_PERSIST_KEY); + else + cert_store = PFXImportCertStore(&datablob, pszPassword, 0); + free(pszPassword); } if(!blob) @@ -748,7 +754,7 @@ schannel_acquire_credential_handle(struct Curl_easy *data, return CURLE_SSL_CERTPROBLEM; } } - CertCloseStore(cert_store, 0); + client_cert_store = cert_store; } #else if(data->set.ssl.primary.clientcert || data->set.ssl.primary.cert_blob) { @@ -766,12 +772,21 @@ schannel_acquire_credential_handle(struct Curl_easy *data, #ifdef HAS_CLIENT_CERT_PATH if(client_certs[0]) CertFreeCertificateContext(client_certs[0]); + if(client_cert_store) + CertCloseStore(client_cert_store, 0); #endif return CURLE_OUT_OF_MEMORY; } backend->cred->refcount = 1; +#ifdef HAS_CLIENT_CERT_PATH + /* Since we did not persist the key, we need to extend the store's + * lifetime until the end of the connection + */ + backend->cred->client_cert_store = client_cert_store; +#endif + /* Windows 10, 1809 (a.k.a. Windows 10 build 17763) */ if(curlx_verify_windows_version(10, 0, 17763, PLATFORM_WINNT, VERSION_GREATER_THAN_EQUAL)) { @@ -2464,6 +2479,12 @@ static void schannel_session_free(void *ptr) if(cred->refcount == 0) { s_pSecFn->FreeCredentialsHandle(&cred->cred_handle); curlx_unicodefree(cred->sni_hostname); +#ifdef HAS_CLIENT_CERT_PATH + if(cred->client_cert_store) { + CertCloseStore(cred->client_cert_store, 0); + cred->client_cert_store = NULL; + } +#endif Curl_safefree(cred); } } diff --git a/lib/vtls/schannel.h b/lib/vtls/schannel.h index 000d1e7b30..24d7eff25b 100644 --- a/lib/vtls/schannel.h +++ b/lib/vtls/schannel.h @@ -83,17 +83,23 @@ CURLcode Curl_verify_certificate(struct Curl_easy *data, /* structs to expose only in schannel.c and schannel_verify.c */ #ifdef EXPOSE_SCHANNEL_INTERNAL_STRUCTS +#include + #ifdef __MINGW32__ #ifdef __MINGW64_VERSION_MAJOR #define HAS_MANUAL_VERIFY_API #endif #else -#include #ifdef CERT_CHAIN_REVOCATION_CHECK_CHAIN #define HAS_MANUAL_VERIFY_API #endif #endif +#if defined(CryptStringToBinary) && defined(CRYPT_STRING_HEX) \ + && !defined(DISABLE_SCHANNEL_CLIENT_CERT) +#define HAS_CLIENT_CERT_PATH +#endif + #ifndef SCH_CREDENTIALS_VERSION #define SCH_CREDENTIALS_VERSION 0x00000005 @@ -155,6 +161,9 @@ struct Curl_schannel_cred { CredHandle cred_handle; TimeStamp time_stamp; TCHAR *sni_hostname; +#ifdef HAS_CLIENT_CERT_PATH + HCERTSTORE client_cert_store; +#endif int refcount; };