//+--------------------------------------------------------------------------- // // Microsoft Widows // Copyright (C) Microsoft Corporation, 1992 - 1997. // // File: defcreds.c // // Contents: Routines for acquiring default credentials. // // Classes: // // Functions: // // History: 12-05-97 jbanes Created. // //---------------------------------------------------------------------------- #include #include void GetImplementationType( PCCERT_CONTEXT pCertContext, PDWORD pdwImpType); NTSTATUS AssignNewClientCredential( PSPContext pContext, PCCERT_CONTEXT pCertContext, BOOL fPromptNow) { PSPCredential pCred = NULL; NTSTATUS Status; BOOL fEventLogged; LSA_SCHANNEL_SUB_CRED SubCred; // // Does this certificate have an acceptable public key type? // { BOOL fFound; DWORD dwKeyType; DWORD i; fFound = FALSE; dwKeyType = MapOidToCertType(pCertContext->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId); for(i = 0; i < pContext->cSsl3ClientCertTypes; i++) { if(pContext->Ssl3ClientCertTypes[i] == dwKeyType) { fFound = TRUE; break; } } if(!fFound) { // Don't use this certificate. Status = SP_LOG_RESULT(PCT_INT_UNKNOWN_CREDENTIAL); goto cleanup; } } // // Build a credential structure for the certificate. // pCred = SPExternalAlloc(sizeof(SPCredential)); if(pCred == NULL) { Status = SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY); goto cleanup; } memset(&SubCred, 0, sizeof(SubCred)); SubCred.pCert = pCertContext; Status = SPCreateCred(pContext->dwProtocol, &SubCred, pCred, &fEventLogged); if(Status != PCT_ERR_OK) { goto cleanup; } // // Release the existing credential, if one exists. // if(pContext->RipeZombie->pClientCred) { SPDeleteCred(pContext->RipeZombie->pClientCred); pContext->RipeZombie->pClientCred = NULL; } // // Assign the credential to the cache element. // pContext->RipeZombie->pClientCred = pCred; pContext->pActiveClientCred = pCred; if(fPromptNow == FALSE) { pContext->RipeZombie->dwFlags |= SP_CACHE_FLAG_USE_VALIDATED; } Status = PCT_ERR_OK; cleanup: if(pCred && Status != PCT_ERR_OK) { SPDeleteCred(pCred); } return Status; } NTSTATUS QueryCredentialManagerForCert( PSPContext pContext, LPWSTR pszTarget) { PCCERT_CONTEXT pCertContext = NULL; LUID LogonId; PENCRYPTED_CREDENTIALW pCredential = NULL; BOOL fImpersonating = FALSE; CRYPT_HASH_BLOB HashBlob; NTSTATUS Status; HCERTSTORE hStore = 0; PCERT_CREDENTIAL_INFO pCertInfo = NULL; CRED_MARSHAL_TYPE CredType; // // Obtain client logon id. // Status = SslGetClientLogonId(&LogonId); if(!NT_SUCCESS(Status)) { SP_LOG_RESULT(Status); goto cleanup; } fImpersonating = SslImpersonateClient(); // // Query the credential manager for a certificate. // Status = LsaTable->CrediRead(&LogonId, CREDP_FLAGS_IN_PROCESS, pszTarget, CRED_TYPE_DOMAIN_CERTIFICATE, 0, &pCredential); if(!NT_SUCCESS(Status)) { if(Status == STATUS_NOT_FOUND) { DebugLog((DEB_WARN, "No certificate found in credential manager.\n")); } else { SP_LOG_RESULT(Status); } goto cleanup; } // // Extract the certificate thumbprint and (optional) PIN. // if(!CredIsMarshaledCredentialW(pCredential->Cred.UserName)) { Status = SP_LOG_RESULT(SEC_E_UNKNOWN_CREDENTIALS); goto cleanup; } if(!CredUnmarshalCredentialW(pCredential->Cred.UserName, &CredType, &pCertInfo)) { Status = SP_LOG_RESULT(SEC_E_UNKNOWN_CREDENTIALS); goto cleanup; } if(CredType != CertCredential) { Status = SP_LOG_RESULT(SEC_E_UNKNOWN_CREDENTIALS); goto cleanup; } // // Look up the certificate in the MY certificate store. // hStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_W, X509_ASN_ENCODING, 0, CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG, L"MY"); if(!hStore) { SP_LOG_RESULT(GetLastError()); Status = SEC_E_NO_CREDENTIALS; goto cleanup; } HashBlob.cbData = sizeof(pCertInfo->rgbHashOfCert); HashBlob.pbData = pCertInfo->rgbHashOfCert; pCertContext = CertFindCertificateInStore(hStore, X509_ASN_ENCODING, 0, CERT_FIND_HASH, &HashBlob, NULL); if(pCertContext == NULL) { DebugLog((DEB_ERROR, "Certificate designated by credential manager was not found in certificate store (0x%x).\n", GetLastError())); Status = SEC_E_NO_CREDENTIALS; goto cleanup; } // // Attempt to add this certificate context to the current credential. // Status = AssignNewClientCredential(pContext, pCertContext, pCredential->Cred.Flags & CRED_FLAGS_PROMPT_NOW); if(!NT_SUCCESS(Status)) { SP_LOG_RESULT(Status); goto cleanup; } Status = STATUS_SUCCESS; cleanup: if(pCertContext) { CertFreeCertificateContext(pCertContext); } if(hStore) { CertCloseStore(hStore, 0); } if(pCredential) { LsaTable->FreeLsaHeap(pCredential); } if(pCertInfo) { CredFree(pCertInfo); } if(fImpersonating) { RevertToSelf(); } return Status; } DWORD IsThreadLocalSystem( BOOL *pfIsLocalSystem) { DWORD Status; HANDLE hToken = 0; UCHAR InfoBuffer[1024]; DWORD dwInfoBufferSize = sizeof(InfoBuffer); PTOKEN_USER SlowBuffer = NULL; PTOKEN_USER pTokenUser = (PTOKEN_USER)InfoBuffer; PSID psidLocalSystem = NULL; PSID psidNetworkService = NULL; SID_IDENTIFIER_AUTHORITY siaNtAuthority = SECURITY_NT_AUTHORITY; *pfIsLocalSystem = FALSE; // // Get SID of calling thread. // if(!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, TRUE, &hToken)) { Status = GetLastError(); goto cleanup; } if(!GetTokenInformation(hToken, TokenUser, pTokenUser, dwInfoBufferSize, &dwInfoBufferSize)) { // // if fast buffer wasn't big enough, allocate enough storage // and try again. // Status = GetLastError(); if(Status != ERROR_INSUFFICIENT_BUFFER) { goto cleanup; } SlowBuffer = (PTOKEN_USER)LocalAlloc(LPTR, dwInfoBufferSize); if(NULL == SlowBuffer) { Status = ERROR_NOT_ENOUGH_MEMORY; goto cleanup; } pTokenUser = SlowBuffer; if(!GetTokenInformation(hToken, TokenUser, pTokenUser, dwInfoBufferSize, &dwInfoBufferSize)) { Status = GetLastError(); goto cleanup; } } // // Check for local system. // if(!AllocateAndInitializeSid(&siaNtAuthority, 1, SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0, &psidLocalSystem)) { Status = GetLastError(); goto cleanup; } if (EqualSid(psidLocalSystem, pTokenUser->User.Sid)) { DebugLog((DEB_TRACE, "Client is using the LOCAL SYSTEM account.\n")); *pfIsLocalSystem = TRUE; Status = ERROR_SUCCESS; goto cleanup; } // // Check for network service. // if(!AllocateAndInitializeSid(&siaNtAuthority, 1, SECURITY_NETWORK_SERVICE_RID, 0, 0, 0, 0, 0, 0, 0, &psidNetworkService)) { Status = GetLastError(); goto cleanup; } if (EqualSid(psidNetworkService, pTokenUser->User.Sid)) { DebugLog((DEB_TRACE, "Client is using the NETWORK SERVICE account.\n")); *pfIsLocalSystem = TRUE; Status = ERROR_SUCCESS; goto cleanup; } Status = ERROR_SUCCESS; cleanup: if(NULL != SlowBuffer) { LocalFree(SlowBuffer); } if(NULL != psidLocalSystem) { FreeSid(psidLocalSystem); } if(NULL != psidNetworkService) { FreeSid(psidNetworkService); } if(NULL != hToken) { CloseHandle(hToken); } return Status; } NTSTATUS FindClientCertificate( PSPContext pContext, HCERTSTORE hMyStore, CERT_CHAIN_FIND_BY_ISSUER_PARA *pFindByIssuerPara, BOOL fSkipExpiredCerts, BOOL fSoftwareCspOnly) { PCCERT_CHAIN_CONTEXT pChainContext = NULL; HTTPSPolicyCallbackData polHttps; CERT_CHAIN_POLICY_PARA PolicyPara; CERT_CHAIN_POLICY_STATUS PolicyStatus; PCCERT_CONTEXT pCertContext; NTSTATUS Status; ULONG j; pChainContext = NULL; while(TRUE) { // Find a certificate chain. pChainContext = CertFindChainInStore(hMyStore, X509_ASN_ENCODING, 0, CERT_CHAIN_FIND_BY_ISSUER, pFindByIssuerPara, pChainContext); if(pChainContext == NULL) { break; } // Make sure that every certificate in the chain either has the // client auth EKU or it has no EKUs at all. { PCERT_SIMPLE_CHAIN pSimpleChain; PCCERT_CONTEXT pCurrentCert; BOOL fIsAllowed = FALSE; pSimpleChain = pChainContext->rgpChain[0]; for(j = 0; j < pSimpleChain->cElement; j++) { pCurrentCert = pSimpleChain->rgpElement[j]->pCertContext; Status = SPCheckKeyUsage(pCurrentCert, szOID_PKIX_KP_CLIENT_AUTH, TRUE, &fIsAllowed); if(Status != SEC_E_OK || !fIsAllowed) { fIsAllowed = FALSE; break; } } if(!fIsAllowed) { // skip this certificate chain. continue; } } // Set up validate chain structures. ZeroMemory(&polHttps, sizeof(HTTPSPolicyCallbackData)); polHttps.cbStruct = sizeof(HTTPSPolicyCallbackData); polHttps.dwAuthType = AUTHTYPE_CLIENT; polHttps.fdwChecks = 0; polHttps.pwszServerName = NULL; ZeroMemory(&PolicyStatus, sizeof(PolicyStatus)); PolicyStatus.cbSize = sizeof(PolicyStatus); ZeroMemory(&PolicyPara, sizeof(PolicyPara)); PolicyPara.cbSize = sizeof(PolicyPara); PolicyPara.pvExtraPolicyPara= &polHttps; PolicyPara.dwFlags = CERT_CHAIN_POLICY_IGNORE_WRONG_USAGE_FLAG | CERT_CHAIN_POLICY_ALLOW_UNKNOWN_CA_FLAG; if(!fSkipExpiredCerts) { PolicyPara.dwFlags |= CERT_CHAIN_POLICY_IGNORE_ALL_NOT_TIME_VALID_FLAGS; } // Validate chain if(!CertVerifyCertificateChainPolicy( CERT_CHAIN_POLICY_SSL, pChainContext, &PolicyPara, &PolicyStatus)) { DebugLog((DEB_WARN,"Error 0x%x returned by CertVerifyCertificateChainPolicy!\n", GetLastError())); continue; } Status = MapWinTrustError(PolicyStatus.dwError, 0, 0); if(Status) { // Certificate did not validate, move on to the next one. DebugLog((DEB_WARN, "Client certificate failed validation with 0x%x\n", Status)); continue; } // Get pointer to leaf certificate context. if(pChainContext->cChain == 0 || pChainContext->rgpChain[0] == NULL) { Status = SP_LOG_RESULT(SEC_E_INTERNAL_ERROR); goto cleanup; } if(pChainContext->rgpChain[0]->cElement == 0 || pChainContext->rgpChain[0]->rgpElement == NULL) { Status = SP_LOG_RESULT(SEC_E_INTERNAL_ERROR); goto cleanup; } pCertContext = pChainContext->rgpChain[0]->rgpElement[0]->pCertContext; // // Is the private key stored in a software CSP? // if(fSoftwareCspOnly) { DWORD dwImpType; GetImplementationType(pCertContext, &dwImpType); if(dwImpType != CRYPT_IMPL_SOFTWARE) { // Skip this certificate continue; } } // // Assign the certificate to the current context. // Status = AssignNewClientCredential(pContext, pCertContext, FALSE); if(NT_SUCCESS(Status)) { // Success! Our work here is done. goto cleanup; } } // No suitable client credential was found. Status = SP_LOG_RESULT(SEC_E_INCOMPLETE_CREDENTIALS); cleanup: if(pChainContext) { CertFreeCertificateChain(pChainContext); } return Status; } NTSTATUS AcquireDefaultClientCredential( PSPContext pContext, BOOL fCredManagerOnly) { CERT_CHAIN_FIND_BY_ISSUER_PARA FindByIssuerPara; CERT_NAME_BLOB * prgIssuers = NULL; DWORD cIssuers = 0; HCERTSTORE hStore = 0; NTSTATUS Status; BOOL fImpersonating = FALSE; BOOL fLocalSystem = FALSE; ULONG i; DebugLog((DEB_TRACE,"AcquireDefaultClientCredential\n")); // // Is the application running under local system? // fImpersonating = SslImpersonateClient(); if(fImpersonating) { Status = IsThreadLocalSystem(&fLocalSystem); if(Status) { DebugLog((DEB_WARN, "IsThreadLocalSystem returned error 0x%x.\n", Status)); } RevertToSelf(); fImpersonating = FALSE; } // // Ask the credential manager to select a certificate for us. // Status = QueryCredentialManagerForCert( pContext, pContext->pszTarget); if(NT_SUCCESS(Status)) { DebugLog((DEB_TRACE, "Credential manager found a certificate for us.\n")); goto cleanup; } if(fCredManagerOnly) { // No suitable client credential was found. Status = SP_LOG_RESULT(SEC_I_INCOMPLETE_CREDENTIALS); goto cleanup; } // // Get list of trusted issuers as a list of CERT_NAME_BLOBs. // if(pContext->pbIssuerList && pContext->cbIssuerList > 2) { PBYTE pbIssuerList = pContext->pbIssuerList + 2; DWORD cbIssuerList = pContext->cbIssuerList - 2; PBYTE pbIssuer; // Count issuers. cIssuers = 0; pbIssuer = pbIssuerList; while(pbIssuer + 1 < pbIssuerList + cbIssuerList) { pbIssuer += 2 + COMBINEBYTES(pbIssuer[0], pbIssuer[1]); cIssuers++; } // Allocate memory for list of blobs. prgIssuers = SPExternalAlloc(cIssuers * sizeof(CERT_NAME_BLOB)); if(prgIssuers == NULL) { Status = SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY); goto cleanup; } // Build the issuer blob list. pbIssuer = pbIssuerList; for(i = 0; i < cIssuers; i++) { prgIssuers[i].pbData = pbIssuer + 2; prgIssuers[i].cbData = COMBINEBYTES(pbIssuer[0], pbIssuer[1]); pbIssuer += 2 + prgIssuers[i].cbData; } } // // Enumerate the certificates in the MY store, looking for a suitable // client certificate. // fImpersonating = SslImpersonateClient(); if(fLocalSystem) { hStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_W, X509_ASN_ENCODING, 0, CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_STORE_READONLY_FLAG | CERT_STORE_OPEN_EXISTING_FLAG, L"MY"); } else { hStore = CertOpenSystemStore(0, "MY"); } if(!hStore) { SP_LOG_RESULT(GetLastError()); Status = SEC_E_INTERNAL_ERROR; goto cleanup; } ZeroMemory(&FindByIssuerPara, sizeof(FindByIssuerPara)); FindByIssuerPara.cbSize = sizeof(FindByIssuerPara); FindByIssuerPara.pszUsageIdentifier = szOID_PKIX_KP_CLIENT_AUTH; FindByIssuerPara.dwKeySpec = 0; FindByIssuerPara.cIssuer = cIssuers; FindByIssuerPara.rgIssuer = prgIssuers; // // Attempt to find a suitable certificate. // Status = FindClientCertificate(pContext, hStore, &FindByIssuerPara, TRUE, // skip expired certs TRUE); // software CSPs only if(NT_SUCCESS(Status)) { // Success! Our work here is done. goto cleanup; } Status = FindClientCertificate(pContext, hStore, &FindByIssuerPara, TRUE, // skip expired certs FALSE); // software CSPs only if(NT_SUCCESS(Status)) { // Success! Our work here is done. goto cleanup; } Status = FindClientCertificate(pContext, hStore, &FindByIssuerPara, FALSE, // skip expired certs TRUE); // software CSPs only if(NT_SUCCESS(Status)) { // Success! Our work here is done. goto cleanup; } Status = FindClientCertificate(pContext, hStore, &FindByIssuerPara, FALSE, // skip expired certs FALSE); // software CSPs only if(NT_SUCCESS(Status)) { // Success! Our work here is done. goto cleanup; } // No suitable client credential was found. Status = SP_LOG_RESULT(SEC_I_INCOMPLETE_CREDENTIALS); cleanup: if(hStore) { CertCloseStore(hStore, 0); } if(fImpersonating) { RevertToSelf(); } if(prgIssuers) { SPExternalFree(prgIssuers); } DebugLog((DEB_TRACE,"AcquireDefaultClientCredential returned 0x%x\n", Status)); return Status; } NTSTATUS FindDefaultMachineCred( PSPCredentialGroup *ppCred, DWORD dwProtocol) { HTTPSPolicyCallbackData polHttps; CERT_CHAIN_POLICY_PARA PolicyPara; CERT_CHAIN_POLICY_STATUS PolicyStatus; CERT_CHAIN_PARA ChainPara; PCCERT_CHAIN_CONTEXT pChainContext = NULL; PCCERT_CONTEXT pCertContext = NULL; LSA_SCHANNEL_CRED SchannelCred; LSA_SCHANNEL_SUB_CRED SubCred; HCERTSTORE hStore = 0; #define SERVER_USAGE_COUNT 3 LPSTR rgszUsages[SERVER_USAGE_COUNT] = { szOID_PKIX_KP_SERVER_AUTH, szOID_SERVER_GATED_CRYPTO, szOID_SGC_NETSCAPE }; LPWSTR pwszMachineName = NULL; DWORD cchMachineName; DWORD Status; DWORD i; // Get the machine name cchMachineName = 0; if(!GetComputerNameExW(ComputerNameDnsFullyQualified, NULL, &cchMachineName)) { if(GetLastError() != ERROR_MORE_DATA) { DebugLog((DEB_ERROR,"Failed to get computer name size: 0x%x\n",GetLastError())); Status = SP_LOG_RESULT(SEC_E_WRONG_PRINCIPAL); goto cleanup; } } pwszMachineName = SPExternalAlloc(cchMachineName * sizeof(WCHAR)); if(pwszMachineName == NULL) { Status = SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY); goto cleanup; } if(!GetComputerNameExW(ComputerNameDnsFullyQualified, pwszMachineName, &cchMachineName)) { DebugLog((DEB_ERROR,"Failed to get computer name: 0x%x\n",GetLastError())); Status = SP_LOG_RESULT(SEC_E_WRONG_PRINCIPAL); goto cleanup; } // Remove the trailing "." if any. This can happen in the stand-alone // server case. cchMachineName = lstrlenW(pwszMachineName); if(cchMachineName > 0 && pwszMachineName[cchMachineName - 1] == L'.') { pwszMachineName[cchMachineName - 1] = L'\0'; } DebugLog((DEB_TRACE,"Computer name: %ls\n",pwszMachineName)); // Open the system MY store. hStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_W, X509_ASN_ENCODING, 0, CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_STORE_READONLY_FLAG | CERT_STORE_OPEN_EXISTING_FLAG, L"MY"); if(hStore == NULL) { SP_LOG_RESULT(GetLastError()); Status = SEC_E_NO_CREDENTIALS; goto cleanup; } // // Enumerate the certificates in the MY store, looking for a suitable // server certificate. Do this twice, the first time looking for the // perfect certificate, and if this fails then look again, this time // being a little less picky. // for(i = 0; i < 2; i++) { pCertContext = NULL; while(TRUE) { // Get leaf certificate in the MY store. pCertContext = CertEnumCertificatesInStore(hStore, pCertContext); if(pCertContext == NULL) { // No more certificates. break; } // // Build a certificate chain from the leaf certificate. // ZeroMemory(&ChainPara, sizeof(ChainPara)); ChainPara.cbSize = sizeof(ChainPara); ChainPara.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR; ChainPara.RequestedUsage.Usage.cUsageIdentifier = SERVER_USAGE_COUNT; ChainPara.RequestedUsage.Usage.rgpszUsageIdentifier = rgszUsages; if(!CertGetCertificateChain( NULL, pCertContext, NULL, 0, &ChainPara, CERT_CHAIN_REVOCATION_CHECK_END_CERT, NULL, &pChainContext)) { DebugLog((DEB_WARN, "Error 0x%x returned by CertGetCertificateChain!\n", GetLastError())); continue; } // Set up validate chain structures. ZeroMemory(&polHttps, sizeof(HTTPSPolicyCallbackData)); polHttps.cbStruct = sizeof(HTTPSPolicyCallbackData); polHttps.dwAuthType = AUTHTYPE_SERVER; polHttps.fdwChecks = 0; polHttps.pwszServerName = pwszMachineName; ZeroMemory(&PolicyStatus, sizeof(PolicyStatus)); PolicyStatus.cbSize = sizeof(PolicyStatus); ZeroMemory(&PolicyPara, sizeof(PolicyPara)); PolicyPara.cbSize = sizeof(PolicyPara); PolicyPara.pvExtraPolicyPara= &polHttps; if(i == 0) { // Look for the perfect certificate. PolicyPara.dwFlags = 0; } else { // Ignore expiration. PolicyPara.dwFlags = CERT_CHAIN_POLICY_IGNORE_ALL_NOT_TIME_VALID_FLAGS; } // Validate chain if(!CertVerifyCertificateChainPolicy( CERT_CHAIN_POLICY_SSL, pChainContext, &PolicyPara, &PolicyStatus)) { SP_LOG_RESULT(GetLastError()); CertFreeCertificateChain(pChainContext); continue; } Status = MapWinTrustError(PolicyStatus.dwError, 0, CRED_FLAG_IGNORE_NO_REVOCATION_CHECK | CRED_FLAG_IGNORE_REVOCATION_OFFLINE); if(Status) { // Certificate did not validate, move on to the next one. DebugLog((DEB_WARN, "Machine certificate failed validation with 0x%x\n", Status)); CertFreeCertificateChain(pChainContext); continue; } CertFreeCertificateChain(pChainContext); // Build an schannel credential. ZeroMemory(&SchannelCred, sizeof(SchannelCred)); SchannelCred.dwVersion = SCHANNEL_CRED_VERSION; SchannelCred.cSubCreds = 1; SchannelCred.paSubCred = &SubCred; ZeroMemory(&SubCred, sizeof(SubCred)); SubCred.pCert = pCertContext; Status = SPCreateCredential(ppCred, dwProtocol, &SchannelCred); if(Status != PCT_ERR_OK) { // Don't use this certificate. continue; } // We have a winner! DebugLog((DEB_TRACE, "Machine certificate automatically acquired\n")); Status = PCT_ERR_OK; goto cleanup; } } // No suitable machine credential was found. Status = SP_LOG_RESULT(SEC_E_NO_CREDENTIALS); cleanup: if(Status != PCT_ERR_OK) { LogNoDefaultServerCredEvent(); } if(pwszMachineName) { SPExternalFree(pwszMachineName); } if(pCertContext) { CertFreeCertificateContext(pCertContext); } if(hStore) { CertCloseStore(hStore, 0); } return Status; } void GetImplementationType( PCCERT_CONTEXT pCertContext, PDWORD pdwImpType) { PCRYPT_KEY_PROV_INFO pProvInfo = NULL; HCRYPTPROV hProv = 0; DWORD cbSize; DWORD dwImpType; *pdwImpType = CRYPT_IMPL_UNKNOWN; if(!CertGetCertificateContextProperty(pCertContext, CERT_KEY_PROV_INFO_PROP_ID, NULL, &cbSize)) { goto cleanup; } pProvInfo = SPExternalAlloc(cbSize); if(pProvInfo == NULL) { goto cleanup; } if(!CertGetCertificateContextProperty(pCertContext, CERT_KEY_PROV_INFO_PROP_ID, pProvInfo, &cbSize)) { goto cleanup; } // HACKHACK - clear the smart-card specific flag. pProvInfo->dwFlags &= ~CERT_SET_KEY_CONTEXT_PROP_ID; if(!CryptAcquireContextW(&hProv, pProvInfo->pwszContainerName, pProvInfo->pwszProvName, pProvInfo->dwProvType, pProvInfo->dwFlags | CRYPT_SILENT)) { goto cleanup; } cbSize = sizeof(dwImpType); if(!CryptGetProvParam(hProv, PP_IMPTYPE, (PBYTE)&dwImpType, &cbSize, 0)) { goto cleanup; } *pdwImpType = dwImpType; cleanup: if(pProvInfo) { SPExternalFree(pProvInfo); } if(hProv) { CryptReleaseContext(hProv, 0); } }