locked
Getting winhttp client cert context without showing the pin password prompt RRS feed

  • Question

  • Hi,

    I am trying to use a client certificate with winhttp without having the pin prompt. So far i have a version that ask for pin which is working :

    if (!(hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, NULL, CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG, L"my")))
    {
    	return false;
    }
    
    
    if (!(pSignerCertContext = CertFindCertificateInStore(hCertStore,  X509_ASN_ENCODING, 0, CERT_FIND_HASH, &hashBlob, NULL)))
    {
    	return false;
    }
    
    WinHttpSetOption(hRequest, WINHTTP_OPTION_CLIENT_CERT_CONTEXT, (LPVOID)pSignerCertContext, sizeof(CERT_CONTEXT));

    The problem is when i try to set programatically the pin, and the code is here :

    std::wstring strProvider = L"Microsoft Base Smart Card Crypto Provider";
    std::wstring strContainer = L"key container from the card"; // got it with certutil.exe -scinfo
    
    if (!CryptAcquireContext(&hCryptProv, strContainer.c_str(), strProvider.c_str(), PROV_RSA_FULL, CRYPT_SILENT))
    {
    	//cleanup
    	std::wstring strErr = ErrorFormat();
    	return false;
    } /*doesnt fail but i got debug info output "Exception thrown at 0x758501E2 (KernelBase.dll) in test.exe: 0x80100030: The requested key container does not exist on the smart card.
    	Exception thrown at 0x758501E2 (KernelBase.dll) in test.exe: 0x8010002C: The requested certificate does not exist.*/
    
    if (!CryptSetProvParam(hCryptProv, PP_KEYEXCHANGE_PIN, pPin, NULL))
    {
    	//cleanup
    	std::wstring strErr = ErrorFormat();
    	return false;
    } /*doesnt fail but i get debug info output "The smart card has been reset, so any shared state information is invalid."
    
    if (!(hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, NULL, CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG, L"my")))
    {
    	//cleanup
    	return false;
    }
    
    if (!(pSignerCertContext = CertFindCertificateInStore(hCertStore,  X509_ASN_ENCODING, 0, CERT_FIND_HASH, &hashBlob, NULL)))
    {
    	//cleanup
    	return false;
    }
    
    if (!CertSetCertificateContextProperty(pSignerCertContext, CERT_KEY_PROV_HANDLE_PROP_ID, 0, &hCryptProv)) {
    	std::wstring strErr = ErrorFormat();
    	//cleanup
    	return false;
    }
    
    
    WinHttpSetOption(hRequest, WINHTTP_OPTION_CLIENT_CERT_CONTEXT, (LPVOID)pSignerCertContext, sizeof(CERT_CONTEXT));
    ...
    /*after the sendrequest is done i get winhttp error with 	WINHTTP_CALLBACK_STATUS_FLAG_SECURITY_CHANNEL_ERROR  -> "The application experienced an internal error loading the SSL libraries." */

    Help will be welcomed as documentation is scarce !

    Thanks,

    Alex

    Wednesday, August 1, 2018 6:55 AM

All replies

  • Finally i found a way... I'll leave this maybe someone else will need it ...thing is that i don't know why using CertSetCertificateContextProperty with CERT_KEY_PROV_HANDLE_PROP_ID  doesn't work. However using directly the certificate from the card and then setting CertSetCertificateContextProperty with CERT_KEY_PROV_INFO_PROP_ID flag seems to do it.

    Maybe someone will shed some light about this :)

    if (!CryptAcquireContext(&hCryptProv, NULL, MS_SCARD_PROV, PROV_RSA_FULL, CRYPT_SILENT | CRYPT_DEFAULT_CONTAINER_OPTIONAL))
    {
    	/*cleanup*/
    	return false;
    }
    
    if (!CryptSetProvParam(hCryptProv, PP_KEYEXCHANGE_PIN, (const byte*)m_strPin.c_str() , NULL))
    {
    	/*cleanup*/
    	return false;
    }
    
    if (!CryptGetUserKey(hCryptProv, AT_KEYEXCHANGE, &hKey)) {
    
    	/*cleanup*/
    	return false;
    }
    
    DWORD dwCertLen = 0;
    
    if (!CryptGetKeyParam(hKey, KP_CERTIFICATE, NULL, &dwCertLen, 0)) {
    	/*cleanup*/
    	return false;
    }
    
    pCertBlob = (BYTE*)malloc(dwCertLen);
    
    if (!CryptGetKeyParam(hKey, KP_CERTIFICATE, pCertBlob, &dwCertLen, 0)) {
    	/*cleanup*/
    	return false;
    }
    
    pCertContext = CertCreateCertificateContext(PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, pCertBlob, dwCertLen);
    DWORD dwKeySpec;
    BOOL bFree;
    
    
    keyProvInfo.pwszContainerName = (LPWSTR)m_strKeyContainer.c_str();
    keyProvInfo.pwszProvName = (LPWSTR)MS_SCARD_PROV;
    keyProvInfo.dwProvType = PROV_RSA_FULL;
    keyProvInfo.dwFlags = CRYPT_SILENT | CERT_SET_KEY_PROV_HANDLE_PROP_ID;
    keyProvInfo.cProvParam = 0;
    keyProvInfo.rgProvParam = NULL;
    keyProvInfo.dwKeySpec = AT_KEYEXCHANGE;
    
    if (!CertSetCertificateContextProperty(pCertContext, CERT_KEY_PROV_INFO_PROP_ID, 0, &keyProvInfo)) {
    	/*cleanup*/
    	return false;
    }
    
    
    if (!CryptAcquireCertificatePrivateKey(pCertContext, CRYPT_ACQUIRE_USE_PROV_INFO_FLAG | CRYPT_ACQUIRE_COMPARE_KEY_FLAG | CRYPT_ACQUIRE_SILENT_FLAG, NULL, &hCryptProv1, &dwKeySpec, &bFree)) {
    	/*cleanup*/
    	return false;
    }
    
    if (!CryptSetProvParam(hCryptProv1, PP_KEYEXCHANGE_PIN, (const byte*)m_strPin.c_str(), NULL))
    {
    	/*cleanup*/
    	return false;
    }
    
    ...
    WinHttpSetOption(hRequest, WINHTTP_OPTION_CLIENT_CERT_CONTEXT, (LPVOID)pCertContext, sizeof(CERT_CONTEXT));

    Monday, August 20, 2018 2:08 PM