/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Microsoft Windows, Copyright (C) Microsoft Corporation, 2000 File: Certificate.cpp Content: Implementation of CCertificate. History: 11-15-99 dsie created ------------------------------------------------------------------------------*/ #include "StdAfx.h" #include "CAPICOM.h" #include "Certificate.h" #include "CertHlpr.h" #include "Convert.h" #include "Common.h" #include "PFXHlpr.h" #include "PrivateKey.h" #include "Settings.h" //////////////////////////////////////////////////////////////////////////////// // // typedefs. // typedef BOOL (WINAPI * PCRYPTUIDLGVIEWCERTIFICATEW) (IN PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo, OUT BOOL *pfPropertiesChanged); //////////////////////////////////////////////////////////////////////////////// // // Exported functions. // /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Function : CreateCertificateObject Synopsis : Create an ICertificate object. Parameter: PCCERT_CONTEXT pCertContext - Pointer to CERT_CONTEXT to be used to initialize the ICertificate object. DWORD dwCurrentSafety - Current safety setting. ICertificate2 ** ppICertificate - Pointer to pointer ICertificate object. Remark : ------------------------------------------------------------------------------*/ HRESULT CreateCertificateObject (PCCERT_CONTEXT pCertContext, DWORD dwCurrentSafety, ICertificate2 ** ppICertificate) { HRESULT hr = S_OK; CComObject * pCCertificate = NULL; DebugTrace("Entering CreateCertificateObject().\n", hr); // // Sanity check. // ATLASSERT(pCertContext); ATLASSERT(ppICertificate); try { // // Create the object. Note that the ref count will still be 0 // after the object is created. // if (FAILED(hr = CComObject::CreateInstance(&pCCertificate))) { DebugTrace("Error [%#x]: CComObject::CreateInstance() failed.\n", hr); goto ErrorExit; } // // Initialize object. // if (FAILED(hr = pCCertificate->PutContext(pCertContext, dwCurrentSafety))) { DebugTrace("Error [%#x]: pCCertificate->PutContext() failed.\n", hr); goto ErrorExit; } // // Return interface pointer to caller. // if (FAILED(hr = pCCertificate->QueryInterface(ppICertificate))) { DebugTrace("Error [%#x]: pCCertificate->QueryInterface() failed.\n", hr); goto ErrorExit; } } catch(...) { hr = E_POINTER; DebugTrace("Exception: invalid parameter.\n"); goto ErrorExit; } CommonExit: DebugTrace("Leaving CreateCertificateObject().\n"); return hr; ErrorExit: // // Sanity check. // ATLASSERT(FAILED(hr)); if (pCCertificate) { delete pCCertificate; } goto CommonExit; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Function : GetCertContext Synopsis : Return the certificate's PCERT_CONTEXT. Parameter: ICertificate * pICertificate - Pointer to ICertificate for which the PCERT_CONTEXT is to be returned. PCCERT_CONTEXT * ppCertContext - Pointer to PCERT_CONTEXT. Remark : ------------------------------------------------------------------------------*/ HRESULT GetCertContext (ICertificate * pICertificate, PCCERT_CONTEXT * ppCertContext) { HRESULT hr = S_OK; CComPtr pICertContext = NULL; DebugTrace("Entering GetCertContext().\n"); // // Sanity check. // ATLASSERT(pICertificate); ATLASSERT(ppCertContext); // // Get ICCertificate interface pointer. // if (FAILED(hr = pICertificate->QueryInterface(IID_ICertContext, (void **) &pICertContext))) { DebugTrace("Error [%#x]: pICertificate->QueryInterface() failed.\n", hr); goto ErrorExit; } // // Get the CERT_CONTEXT. // if (FAILED(hr = pICertContext->get_CertContext((long *) ppCertContext))) { DebugTrace("Error [%#x]: pICertContext->get_CertContext() failed.\n", hr); goto ErrorExit; } CommonExit: DebugTrace("Leaving GetCertContext().\n"); return hr; ErrorExit: // // Sanity check. // ATLASSERT(FAILED(hr)); goto CommonExit; } //////////////////////////////////////////////////////////////////////////////// // // Local functions. // /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Function : GetCertNameInfo Synopsis : Return the name for the subject or issuer field. Parameter: PCCERT_CONTEXT pCertContext - Pointer to CERT_CONTEXT. DWORD dwNameType - 0 for subject name or CERT_NAME_ISSUER_FLAG for issuer name. DWORD dwDisplayType - Display type. BSTR * pbstrName - Pointer to BSTR to receive resulting name string. Remark : It is the caller's responsibility to free the BSTR. No checking of any of the flags is done, so be sure to call with the right flags. ------------------------------------------------------------------------------*/ static HRESULT GetCertNameInfo (PCCERT_CONTEXT pCertContext, DWORD dwNameType, DWORD dwDisplayType, BSTR * pbstrName) { HRESULT hr = S_OK; DWORD cbNameLen = 0; LPWSTR pwszName = NULL; DWORD dwStrType = CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG; DebugTrace("Entering GetCertNameInfo().\n"); // // Sanity check. // ATLASSERT(pCertContext); ATLASSERT(pbstrName); // // Get the length needed. // if (!(cbNameLen = ::CertGetNameStringW(pCertContext, dwDisplayType, dwNameType, dwDisplayType == CERT_NAME_RDN_TYPE ? (LPVOID) &dwStrType : NULL, NULL, 0))) { hr = HRESULT_FROM_WIN32(CRYPT_E_NOT_FOUND); DebugTrace("Error [%#x]: CertGetNameStringW() failed.\n", hr); goto ErrorExit; } // // Create returned BSTR. // if (!(pwszName = (LPWSTR) ::CoTaskMemAlloc(cbNameLen * sizeof(WCHAR)))) { hr = E_OUTOFMEMORY; DebugTrace("Error: out of memory.\n"); goto ErrorExit; } // // Now actually get the name string. // if (!::CertGetNameStringW(pCertContext, dwDisplayType, dwNameType, dwDisplayType == CERT_NAME_RDN_TYPE ? (LPVOID) &dwStrType : NULL, (LPWSTR) pwszName, cbNameLen)) { hr = HRESULT_FROM_WIN32(CRYPT_E_NOT_FOUND); DebugTrace("Error [%#x]: CertGetNameStringW() failed.\n", hr); goto ErrorExit; } // // Return BSTR to caller. // if (!(*pbstrName = ::SysAllocString(pwszName))) { hr = E_OUTOFMEMORY; DebugTrace("Error: out of memory.\n"); goto ErrorExit; } CommonExit: // // Free resource. // if (pwszName) { ::CoTaskMemFree(pwszName); } DebugTrace("Leaving GetCertNameInfo().\n"); return hr; ErrorExit: // // Sanity check. // ATLASSERT(FAILED(hr)); goto CommonExit; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Function : CertToStore Synopsis : Add the cert, optionally with the chain, to the store. Parameter: PCCERT_CONTEXT pCertContext - Pointer to CERT_CONTEXT. CAPICOM_CERTIFICATE_INCLUDE_OPTION IncludeOption - Include option. HCERTSTORE hCertStore - Store to add to. Remark : ------------------------------------------------------------------------------*/ static HRESULT CertToStore(PCCERT_CONTEXT pCertContext, CAPICOM_CERTIFICATE_INCLUDE_OPTION IncludeOption, HCERTSTORE hCertStore) { HRESULT hr = S_OK; PCCERT_CHAIN_CONTEXT pChainContext = NULL; DebugTrace("Entering CertToStore().\n"); // // Sanity check. // ATLASSERT(pCertContext); ATLASSERT(hCertStore); // // No need to build chain if only including end cert. // if (CAPICOM_CERTIFICATE_INCLUDE_END_ENTITY_ONLY == IncludeOption) { // // Add the only cert to store. // if (!::CertAddCertificateContextToStore(hCertStore, pCertContext, CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES, NULL)) { hr = HRESULT_FROM_WIN32(::GetLastError()); DebugTrace("Error [%#x]: CertAddCertificateContextToStore() failed.\n", hr); goto ErrorExit; } } else { DWORD i; BOOL bAddRoot; CERT_CHAIN_PARA ChainPara = {0}; // // Initialize. // ChainPara.cbSize = sizeof(ChainPara); switch (IncludeOption) { case CAPICOM_CERTIFICATE_INCLUDE_WHOLE_CHAIN: { bAddRoot = TRUE; break; } case CAPICOM_CERTIFICATE_INCLUDE_CHAIN_EXCEPT_ROOT: // // Fall thru to default. // default: { bAddRoot = FALSE; break; } } // // Build the chain. // if (!::CertGetCertificateChain(NULL, pCertContext, NULL, NULL, &ChainPara, 0, NULL, &pChainContext)) { hr = HRESULT_FROM_WIN32(::GetLastError()); DebugTrace("Error [%#x]: CertGetCertificateChain() failed.\n", hr); goto ErrorExit; } // // Sanity check. // ATLASSERT(pChainContext->cChain); // // Now add the chain to store and skip root cert if requested. // for (i = 0; i < pChainContext->rgpChain[0]->cElement; i++) { // // Skip the root cert, if requested. // if (!bAddRoot && (pChainContext->rgpChain[0]->rgpElement[i]->TrustStatus.dwInfoStatus & CERT_TRUST_IS_SELF_SIGNED)) { continue; } // // Add to store. // if (!::CertAddCertificateContextToStore(hCertStore, pChainContext->rgpChain[0]->rgpElement[i]->pCertContext, CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES, NULL)) { hr = HRESULT_FROM_WIN32(::GetLastError()); DebugTrace("Error [%#x]: CertAddCertificateContextToStore() failed.\n", hr); goto ErrorExit; } } } CommonExit: // // Free resource. // if (pChainContext) { ::CertFreeCertificateChain(pChainContext); } DebugTrace("Leaving CertToStore().\n"); return hr; ErrorExit: // // Sanity check. // ATLASSERT(FAILED(hr)); goto CommonExit; } //////////////////////////////////////////////////////////////////////////////// // // CCertificate // /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Function : CCertificate::get_Version Synopsis : Return the cert version number. Parameter: long * pVersion - Pointer to long to receive version number. Remark : The returned value is 1 for V1, 2 for V2, 3 for V3, and so on. ------------------------------------------------------------------------------*/ STDMETHODIMP CCertificate::get_Version (long * pVal) { HRESULT hr = S_OK; DebugTrace("Entering CCertificate::get_Version().\n"); try { // // Lock access to this object. // m_Lock.Lock(); // // Check parameters. // if (NULL == pVal) { hr = E_INVALIDARG; DebugTrace("Error [%#x]: Parameter pVal is NULL.\n", hr); goto ErrorExit; } // // Make sure cert is already initialized. // if (!m_pCertContext) { hr = CAPICOM_E_CERTIFICATE_NOT_INITIALIZED; DebugTrace("Error [%#x]: Certificate object has not been initalized.\n", hr); goto ErrorExit; } *pVal = (long) m_pCertContext->pCertInfo->dwVersion + 1; } catch(...) { hr = E_POINTER; DebugTrace("Exception: invalid parameter.\n"); goto ErrorExit; } UnlockExit: // // Unlock access to this object. // m_Lock.Unlock(); DebugTrace("Leaving CCertificate::get_Version().\n"); return hr; ErrorExit: // // Sanity check. // ATLASSERT(FAILED(hr)); ReportError(hr); goto UnlockExit; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Function : CCertificate::get_SerialNumber Synopsis : Return the Serial Number field as HEX string in BSTR. Parameter: BSTR * pVal - Pointer to BSTR to receive the serial number. Remark : Upper case 'A' - 'F' is used for the returned HEX string with no embeded space (i.e. 46A2FC01). ------------------------------------------------------------------------------*/ STDMETHODIMP CCertificate::get_SerialNumber (BSTR * pVal) { HRESULT hr = S_OK; DebugTrace("Entering CCertificate::get_SerialNumber().\n"); try { // // Lock access to this object. // m_Lock.Lock(); // // Check parameters. // if (NULL == pVal) { hr = E_INVALIDARG; DebugTrace("Error [%#x]: Parameter pVal is NULL.\n", hr); goto ErrorExit; } // // Make sure cert is already initialized. // if (!m_pCertContext) { hr = CAPICOM_E_CERTIFICATE_NOT_INITIALIZED; DebugTrace("Error [%#x]: object does not represent an initialized certificate.\n", hr); goto ErrorExit; } // // Convert integer blob to BSTR. // if (FAILED(hr = ::IntBlobToHexString(&m_pCertContext->pCertInfo->SerialNumber, pVal))) { DebugTrace("Error [%#x]: IntBlobToHexString() failed.\n", hr); goto ErrorExit; } } catch(...) { hr = E_POINTER; DebugTrace("Exception: invalid parameter.\n"); goto ErrorExit; } UnlockExit: // // Unlock access to this object. // m_Lock.Unlock(); DebugTrace("Leaving CCertificate::get_SerialNumber().\n"); return hr; ErrorExit: // // Sanity check. // ATLASSERT(FAILED(hr)); ReportError(hr); goto UnlockExit; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Function : CCertificate::get_SubjectName Synopsis : Return the Subject field. Parameter: BSTR * pVal - Pointer to BSTR to receive the subject's name. Remark : This method returns the full DN in the SubjectName field in the form of "CN = Daniel Sie OU = Outlook O = Microsoft L = Redmond S = WA C = US" The returned name has the same format as specifying CERT_NAME_RDN_TYPE for the CertGetNameString() API.. ------------------------------------------------------------------------------*/ STDMETHODIMP CCertificate::get_SubjectName (BSTR * pVal) { HRESULT hr = S_OK; DebugTrace("Entering CCertificate::get_SubjectName().\n"); try { // // Lock access to this object. // m_Lock.Lock(); // // Check parameters. // if (NULL == pVal) { hr = E_INVALIDARG; DebugTrace("Error [%#x]: Parameter pVal is NULL.\n", hr); goto ErrorExit; } // // Make sure cert is already initialized. // if (!m_pCertContext) { hr = CAPICOM_E_CERTIFICATE_NOT_INITIALIZED; DebugTrace("Error [%#x]: object does not represent an initialized certificate.\n", hr); goto ErrorExit; } // // Return requested name string. // if (FAILED(hr = ::GetCertNameInfo(m_pCertContext, 0, CERT_NAME_RDN_TYPE, pVal))) { DebugTrace("Error [%#x]: GetCertNameInfo() failed.\n", hr); goto ErrorExit; } } catch(...) { hr = E_POINTER; DebugTrace("Exception: invalid parameter.\n"); goto ErrorExit; } UnlockExit: // // Unlock access to this object. // m_Lock.Unlock(); DebugTrace("Leaving CCertificate::get_SubjectName().\n"); return hr; ErrorExit: // // Sanity check. // ATLASSERT(FAILED(hr)); ReportError(hr); goto UnlockExit; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Function : CCertificate::get_IssuerName Synopsis : Return the Issuer field. Parameter: BSTR * pVal - Pointer to BSTR to receive the issuer's name. Remark : This method returns the full DN in the IssuerName field in the form of "CN = Daniel Sie OU = Outlook O = Microsoft L = Redmond S = WA C = US" The returned name has the same format as specifying CERT_NAME_RDN_TYPE for the CertGetNameString() API. ------------------------------------------------------------------------------*/ STDMETHODIMP CCertificate::get_IssuerName (BSTR * pVal) { HRESULT hr = S_OK; DebugTrace("Entering CCertificate::get_IssuerName().\n"); try { // // Lock access to this object. // m_Lock.Lock(); // // Check parameters. // if (NULL == pVal) { hr = E_INVALIDARG; DebugTrace("Error [%#x]: Parameter pVal is NULL.\n", hr); goto ErrorExit; } // // Make sure cert is already initialized. // if (!m_pCertContext) { hr = CAPICOM_E_CERTIFICATE_NOT_INITIALIZED; DebugTrace("Error [%#x]: object does not represent an initialized certificate.\n", hr); goto ErrorExit; } // // Return requested name string. // if (FAILED(hr = ::GetCertNameInfo(m_pCertContext, CERT_NAME_ISSUER_FLAG, CERT_NAME_RDN_TYPE, pVal))) { DebugTrace("Error [%#x]: GetCertNameInfo() failed.\n", hr); goto ErrorExit; } } catch(...) { hr = E_POINTER; DebugTrace("Exception: invalid parameter.\n"); goto ErrorExit; } UnlockExit: // // Unlock access to this object. // m_Lock.Unlock(); DebugTrace("Leaving CCertificate::get_IssuerName().\n"); return hr; ErrorExit: // // Sanity check. // ATLASSERT(FAILED(hr)); ReportError(hr); goto UnlockExit; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Function : CCertificate::get_ValidFromDate Synopsis : Return the NotBefore field. Parameter: DATE * pDate - Pointer to DATE to receive the valid from date. Remark : ------------------------------------------------------------------------------*/ STDMETHODIMP CCertificate::get_ValidFromDate (DATE * pVal) { HRESULT hr = S_OK; FILETIME ftLocal; SYSTEMTIME stLocal; DebugTrace("Entering CCertificate::get_ValidFromDate().\n"); try { // // Lock access to this object. // m_Lock.Lock(); // // Check parameters. // if (NULL == pVal) { hr = E_INVALIDARG; DebugTrace("Error [%#x]: Parameter pVal is NULL.\n", hr); goto ErrorExit; } // // Make sure cert is already initialized. // if (!m_pCertContext) { hr = CAPICOM_E_CERTIFICATE_NOT_INITIALIZED; DebugTrace("Error [%#x]: object does not represent an initialized certificate.\n", hr); goto ErrorExit; } // // Convert to local time. // if (!(::FileTimeToLocalFileTime(&m_pCertContext->pCertInfo->NotBefore, &ftLocal) && ::FileTimeToSystemTime(&ftLocal, &stLocal) && ::SystemTimeToVariantTime(&stLocal, pVal))) { hr = HRESULT_FROM_WIN32(::GetLastError()); DebugTrace("Error [%#x]: unable to convert FILETIME to DATE.\n", hr); goto ErrorExit; } } catch(...) { hr = E_POINTER; DebugTrace("Exception: invalid parameter.\n"); goto ErrorExit; } UnlockExit: // // Unlock access to this object. // m_Lock.Unlock(); DebugTrace("Leaving CCertificate::get_ValidFromDate().\n"); return hr; ErrorExit: // // Sanity check. // ATLASSERT(FAILED(hr)); ReportError(hr); goto UnlockExit; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Function : CCertificate::get_ValidToDate Synopsis : Return the NotAfter field. Parameter: DATE * pDate - Pointer to DATE to receive valid to date. Remark : ------------------------------------------------------------------------------*/ STDMETHODIMP CCertificate::get_ValidToDate (DATE * pVal) { HRESULT hr = S_OK; FILETIME ftLocal; SYSTEMTIME stLocal; DebugTrace("Entering CCertificate::get_ValidToDate().\n"); try { // // Lock access to this object. // m_Lock.Lock(); // // Check parameters. // if (NULL == pVal) { hr = E_INVALIDARG; DebugTrace("Error [%#x]: Parameter pVal is NULL.\n", hr); goto ErrorExit; } // // Make sure cert is already initialized. // if (!m_pCertContext) { hr = CAPICOM_E_CERTIFICATE_NOT_INITIALIZED; DebugTrace("Error [%#x]: object does not represent an initialized certificate.\n", hr); goto ErrorExit; } // // Convert to local time. // if (!(::FileTimeToLocalFileTime(&m_pCertContext->pCertInfo->NotAfter, &ftLocal) && ::FileTimeToSystemTime(&ftLocal, &stLocal) && ::SystemTimeToVariantTime(&stLocal, pVal))) { hr = HRESULT_FROM_WIN32(::GetLastError()); DebugTrace("Error [%#x]: unable to convert FILETIME to DATE.\n", hr); goto ErrorExit; } } catch(...) { hr = E_POINTER; DebugTrace("Exception: invalid parameter.\n"); goto ErrorExit; } UnlockExit: // // Unlock access to this object. // m_Lock.Unlock(); DebugTrace("Leaving CCertificate::get_ValidToDate().\n"); return hr; ErrorExit: // // Sanity check. // ATLASSERT(FAILED(hr)); ReportError(hr); goto UnlockExit; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Function : CCertificate::get_Thumbprint Synopsis : Return the SHA1 hash as HEX string. Parameter: BSTR * pVal - Pointer to BSTR to receive hash. Remark : ------------------------------------------------------------------------------*/ STDMETHODIMP CCertificate::get_Thumbprint (BSTR * pVal) { HRESULT hr = S_OK; BYTE * pbHash = NULL; DWORD cbHash = 0; DebugTrace("Entering CCertificate::get_Thumbprint().\n"); try { // // Lock access to this object. // m_Lock.Lock(); // // Check parameters. // if (NULL == pVal) { hr = E_INVALIDARG; DebugTrace("Error [%#x]: Parameter pVal is NULL.\n", hr); goto ErrorExit; } // // Make sure cert is already initialized. // if (!m_pCertContext) { hr = CAPICOM_E_CERTIFICATE_NOT_INITIALIZED; DebugTrace("Error [%#x]: object does not represent an initialized certificate.\n", hr); goto ErrorExit; } // // Calculate length needed. // if (!::CertGetCertificateContextProperty(m_pCertContext, CERT_SHA1_HASH_PROP_ID, NULL, &cbHash)) { hr = HRESULT_FROM_WIN32(::GetLastError()); DebugTrace("Error [%#x]: CertGetCertificateContextProperty() failed.\n", hr); goto ErrorExit; } // // Allocate memory. // if (!(pbHash = (BYTE *) ::CoTaskMemAlloc(cbHash))) { hr = E_OUTOFMEMORY; DebugTrace("Error: out of memory.\n"); goto ErrorExit; } // // Now get the hash. // if (!::CertGetCertificateContextProperty(m_pCertContext, CERT_SHA1_HASH_PROP_ID, (LPVOID) pbHash, &cbHash)) { hr = HRESULT_FROM_WIN32(GetLastError()); DebugTrace("Error [%#x]: CertGetCertificateContextProperty() failed.\n", hr); goto ErrorExit; } // // Conver to HEX BSTR. // if (FAILED(hr = ::BinaryToHexString(pbHash, cbHash, pVal))) { DebugTrace("Error [%#x]: BinaryToHexString() failed.\n", hr); goto ErrorExit; } } catch(...) { hr = E_POINTER; DebugTrace("Exception: invalid parameter.\n"); goto ErrorExit; } UnlockExit: // // Free resource. // if (pbHash) { ::CoTaskMemFree((LPVOID) pbHash); } // // Unlock access to this object. // m_Lock.Unlock(); DebugTrace("Leaving CCertificate::get_Thumbprint().\n"); return hr; ErrorExit: // // Sanity check. // ATLASSERT(FAILED(hr)); ReportError(hr); goto UnlockExit; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Function : CCertificate::HasPrivateKey Synopsis : Check to see if the cert has the associated private key. Parameter: VARIANT_BOOL * pVal - Pointer to BOOL to receive result. Remark : ------------------------------------------------------------------------------*/ STDMETHODIMP CCertificate::HasPrivateKey (VARIANT_BOOL * pVal) { HRESULT hr = S_OK; DWORD cb = 0; DebugTrace("Entering CCertificate::HasPrivateKey().\n"); try { // // Lock access to this object. // m_Lock.Lock(); // // Check parameters. // if (NULL == pVal) { hr = E_INVALIDARG; DebugTrace("Error [%#x]: Parameter pVal is NULL.\n", hr); goto ErrorExit; } // // Make sure cert is already initialized. // if (!m_pCertContext) { hr = CAPICOM_E_CERTIFICATE_NOT_INITIALIZED; DebugTrace("Error [%#x]: object does not represent an initialized certificate.\n", hr); goto ErrorExit; } // // Return result. // *pVal = ::CertGetCertificateContextProperty(m_pCertContext, CERT_KEY_PROV_INFO_PROP_ID, NULL, &cb) ? VARIANT_TRUE : VARIANT_FALSE; } catch(...) { hr = E_POINTER; DebugTrace("Exception: invalid parameter.\n"); goto ErrorExit; } UnlockExit: // // Unlock access to this object. // m_Lock.Unlock(); DebugTrace("Leaving CCertificate::HasPrivateKey().\n"); return hr; ErrorExit: // // Sanity check. // ATLASSERT(FAILED(hr)); ReportError(hr); goto UnlockExit; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Function : CCertificate::GetInfo Synopsis : Get other simple info from the certificate. Parameter: CAPICOM_CERT_INFO_TYPE InfoType - Info type BSTR * pVal - Pointer to BSTR to receive the result. Remark : Note that an empty string "" is returned if the requested info is not available in the certificate. ------------------------------------------------------------------------------*/ STDMETHODIMP CCertificate::GetInfo (CAPICOM_CERT_INFO_TYPE InfoType, BSTR * pVal) { HRESULT hr = S_OK; DWORD dwFlags = 0; DWORD dwDisplayType = 0; DebugTrace("Entering CCertificate::GetInfo().\n"); try { // // Lock access to this object. // m_Lock.Lock(); // // Check parameters. // if (NULL == pVal) { hr = E_INVALIDARG; DebugTrace("Error [%#x]: Parameter pVal is NULL.\n", hr); goto ErrorExit; } // // Make sure cert is already initialized. // if (!m_pCertContext) { hr = CAPICOM_E_CERTIFICATE_NOT_INITIALIZED; DebugTrace("Error [%#x]: object does not represent an initialized certificate.\n", hr); goto ErrorExit; } // // Process request. // switch (InfoType) { case CAPICOM_CERT_INFO_ISSUER_SIMPLE_NAME: { dwFlags = CERT_NAME_ISSUER_FLAG; // // Warning: dropping thru. // } case CAPICOM_CERT_INFO_SUBJECT_SIMPLE_NAME: { // // Get requested simple name string. // dwDisplayType = CERT_NAME_SIMPLE_DISPLAY_TYPE; break; } case CAPICOM_CERT_INFO_ISSUER_EMAIL_NAME: { dwFlags = CERT_NAME_ISSUER_FLAG; // // Warning: dropping thru. // } case CAPICOM_CERT_INFO_SUBJECT_EMAIL_NAME: { // // Get requested email name string. // dwDisplayType = CERT_NAME_EMAIL_TYPE; break; } case CAPICOM_CERT_INFO_ISSUER_UPN: { dwFlags = CERT_NAME_ISSUER_FLAG; // // Warning: dropping thru. // } case CAPICOM_CERT_INFO_SUBJECT_UPN: { // // Get requested UPN name string. // dwDisplayType = CERT_NAME_UPN_TYPE; break; } case CAPICOM_CERT_INFO_ISSUER_DNS_NAME: { dwFlags = CERT_NAME_ISSUER_FLAG; // // Warning: dropping thru. // } case CAPICOM_CERT_INFO_SUBJECT_DNS_NAME: { // // Get requested DNS name string. // dwDisplayType = CERT_NAME_DNS_TYPE; break; } default: { hr = E_INVALIDARG; DebugTrace("Error [%#x]: Unknown cert info type (%#x).\n", hr, InfoType); goto ErrorExit; } } if (FAILED(hr = ::GetCertNameInfo(m_pCertContext, dwFlags, dwDisplayType, pVal))) { DebugTrace("Error [%#x]: GetCertNameInfo() failed for display type = %d.\n", hr, dwDisplayType); goto ErrorExit; } } catch(...) { hr = E_POINTER; DebugTrace("Exception: invalid parameter.\n"); goto ErrorExit; } UnlockExit: // // Unlock access to this object. // m_Lock.Unlock(); DebugTrace("Leaving CCertificate::GetInfo().\n"); return hr; ErrorExit: // // Sanity check. // ATLASSERT(FAILED(hr)); ReportError(hr); goto UnlockExit; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Function : CCertificate::IsValid Synopsis : Return an ICertificateStatus object for certificate validity check. Parameter: ICertificateStatus ** pVal - Pointer to pointer to ICertificateStatus object to receive the interface pointer. Remark : ------------------------------------------------------------------------------*/ STDMETHODIMP CCertificate::IsValid (ICertificateStatus ** pVal) { HRESULT hr = S_OK; DebugTrace("Entering CCertificate::IsValid().\n"); try { // // Lock access to this object. // m_Lock.Lock(); // // Check parameters. // if (NULL == pVal) { hr = E_INVALIDARG; DebugTrace("Error [%#x]: Parameter pVal is NULL.\n", hr); goto ErrorExit; } // // Make sure cert is already initialized. // if (!m_pCertContext) { hr = CAPICOM_E_CERTIFICATE_NOT_INITIALIZED; DebugTrace("Error [%#x]: object does not represent an initialized certificate.\n", hr); goto ErrorExit; } // // Create the embeded ICertificateStatus object, if not already done so. // if (!m_pICertificateStatus) { if (FAILED(hr = ::CreateCertificateStatusObject(m_pCertContext, &m_pICertificateStatus))) { DebugTrace("Error [%#x]: CreateCertificateStatusObject() failed.\n", hr); goto ErrorExit; } } // // Sanity check. // ATLASSERT(m_pICertificateStatus); // // Return interface pointer to user. // if (FAILED(hr = m_pICertificateStatus->QueryInterface(pVal))) { DebugTrace("Error [%#x]: m_pICertificateStatus->QueryInterface() failed.\n", hr); goto ErrorExit; } } catch(...) { hr = E_POINTER; DebugTrace("Exception: invalid parameter.\n"); goto ErrorExit; } UnlockExit: // // Unlock access to this object. // m_Lock.Unlock(); DebugTrace("Leaving CCertificate::IsValid().\n"); return hr; ErrorExit: // // Sanity check. // ATLASSERT(FAILED(hr)); ReportError(hr); goto UnlockExit; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Function : CCertificate::KeyUsage Synopsis : Return the Key Usage extension as an IKeyUsage object. Parameter: IKeyUsage ** pVal - Pointer to pointer to IKeyUsage to receive the interface pointer. Remark : ------------------------------------------------------------------------------*/ STDMETHODIMP CCertificate::KeyUsage (IKeyUsage ** pVal) { HRESULT hr = S_OK; DebugTrace("Entering CCertificate::KeyUsage().\n"); try { // // Lock access to this object. // m_Lock.Lock(); // // Check parameters. // if (NULL == pVal) { hr = E_INVALIDARG; DebugTrace("Error [%#x]: Parameter pVal is NULL.\n", hr); goto ErrorExit; } // // Make sure cert is already initialized. // if (!m_pCertContext) { hr = CAPICOM_E_CERTIFICATE_NOT_INITIALIZED; DebugTrace("Error [%#x]: object does not represent an initialized certificate.\n", hr); goto ErrorExit; } // // Create the embeded IKeyUsage object, if not already done so. // if (!m_pIKeyUsage) { if (FAILED(hr = ::CreateKeyUsageObject(m_pCertContext, &m_pIKeyUsage))) { DebugTrace("Error [%#x]: CreateKeyUsageObject() failed.\n", hr); goto ErrorExit; } } // // Sanity check. // ATLASSERT(m_pIKeyUsage); // // Return interface pointer to user. // if (FAILED(hr = m_pIKeyUsage->QueryInterface(pVal))) { DebugTrace("Error [%#x]: m_pIKeyUsage->QueryInterface() failed.\n", hr); goto ErrorExit; } } catch(...) { hr = E_POINTER; DebugTrace("Exception: invalid parameter.\n"); goto ErrorExit; } UnlockExit: // // Unlock access to this object. // m_Lock.Unlock(); DebugTrace("Leaving CCertificate::KeyUsage().\n"); return hr; ErrorExit: // // Sanity check. // ATLASSERT(FAILED(hr)); ReportError(hr); goto UnlockExit; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Function : CCertificate::ExtendedKeyUsage Synopsis : Return the EKU extension as an IExtendedKeyUsage object. Parameter: IExtendedKeyUsage ** pVal - Pointer to pointer to IExtendedKeyUsage to receive the interface pointer. Remark : ------------------------------------------------------------------------------*/ STDMETHODIMP CCertificate::ExtendedKeyUsage (IExtendedKeyUsage ** pVal) { HRESULT hr = S_OK; DebugTrace("Entering CCertificate::ExtendedKeyUsage().\n"); try { // // Lock access to this object. // m_Lock.Lock(); // // Check parameters. // if (NULL == pVal) { hr = E_INVALIDARG; DebugTrace("Error [%#x]: Parameter pVal is NULL.\n", hr); goto ErrorExit; } // // Make sure cert is already initialized. // if (!m_pCertContext) { hr = CAPICOM_E_CERTIFICATE_NOT_INITIALIZED; DebugTrace("Error [%#x]: object does not represent an initialized certificate.\n", hr); goto ErrorExit; } // // Create the embeded IExtendedKeyUsage object, if not already done so. // if (!m_pIExtendedKeyUsage) { if (FAILED(hr = ::CreateExtendedKeyUsageObject(m_pCertContext, &m_pIExtendedKeyUsage))) { DebugTrace("Error [%#x]: CreateExtendedKeyUsageObject() failed.\n", hr); goto ErrorExit; } } // // Sanity check. // ATLASSERT(m_pIExtendedKeyUsage); // // Return interface pointer to user. // if (FAILED(hr = m_pIExtendedKeyUsage->QueryInterface(pVal))) { DebugTrace("Error [%#x]: m_pIExtendedKeyUsage->QueryInterface() failed.\n", hr); goto ErrorExit; } } catch(...) { hr = E_POINTER; DebugTrace("Exception: invalid parameter.\n"); goto ErrorExit; } UnlockExit: // // Unlock access to this object. // m_Lock.Unlock(); DebugTrace("Leaving CCertificate::ExtendedKeyUsage().\n"); return hr; ErrorExit: // // Sanity check. // ATLASSERT(FAILED(hr)); ReportError(hr); goto UnlockExit; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Function : CCertificate::BasicConstraints Synopsis : Return the BasicConstraints extension as an IBasicConstraints object. Parameter: IBasicConstraints ** pVal - Pointer to pointer to IBasicConstraints to receive the interface pointer. Remark : ------------------------------------------------------------------------------*/ STDMETHODIMP CCertificate::BasicConstraints (IBasicConstraints ** pVal) { HRESULT hr = S_OK; DebugTrace("Entering CCertificate::BasicConstraints().\n"); try { // // Lock access to this object. // m_Lock.Lock(); // // Check parameters. // if (NULL == pVal) { hr = E_INVALIDARG; DebugTrace("Error [%#x]: Parameter pVal is NULL.\n", hr); goto ErrorExit; } // // Make sure cert is already initialized. // if (!m_pCertContext) { hr = CAPICOM_E_CERTIFICATE_NOT_INITIALIZED; DebugTrace("Error [%#x]: object does not represent an initialized certificate.\n", hr); goto ErrorExit; } // // Create the embeded IBasicConstraints object, if not already done so. // if (!m_pIBasicConstraints) { if (FAILED(hr = ::CreateBasicConstraintsObject(m_pCertContext, &m_pIBasicConstraints))) { DebugTrace("Error [%#x]: CreateBasicConstraintsObject() failed.\n", hr); goto ErrorExit; } } // // Sanity check. // ATLASSERT(m_pIBasicConstraints); // // Return interface pointer to user. // if (FAILED(hr = m_pIBasicConstraints->QueryInterface(pVal))) { DebugTrace("Error [%#x]: m_pIBasicConstraints->QueryInterface() failed.\n", hr); goto ErrorExit; } } catch(...) { hr = E_POINTER; DebugTrace("Exception: invalid parameter.\n"); goto ErrorExit; } UnlockExit: // // Unlock access to this object. // m_Lock.Unlock(); DebugTrace("Leaving CCertificate::BasicConstraints().\n"); return hr; ErrorExit: // // Sanity check. // ATLASSERT(FAILED(hr)); ReportError(hr); goto UnlockExit; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Function : CCertificate::Export Synopsis : Export the certificate. Parameter: CAPICOM_ENCODING_TYPE EncodingType - Encoding type. BSTR * pVal - Pointer to BSTR to receive the certificate blob. Remark : ------------------------------------------------------------------------------*/ STDMETHODIMP CCertificate::Export (CAPICOM_ENCODING_TYPE EncodingType, BSTR * pVal) { HRESULT hr = S_OK; DATA_BLOB CertBlob = {0, NULL}; DebugTrace("Entering CCertificate::Export().\n"); try { // // Lock access to this object. // m_Lock.Lock(); // // Check parameters. // if (NULL == pVal) { hr = E_INVALIDARG; DebugTrace("Error [%#x]: Parameter pVal is NULL.\n", hr); goto ErrorExit; } // // Make sure cert is already initialized. // if (!m_pCertContext) { hr = CAPICOM_E_CERTIFICATE_NOT_INITIALIZED; DebugTrace("Error [%#x]: object does not represent an initialized certificate.\n", hr); goto ErrorExit; } // // Determine encoding type. // CertBlob.cbData = m_pCertContext->cbCertEncoded; CertBlob.pbData = m_pCertContext->pbCertEncoded; // // Export certificate. // if (FAILED(hr = ::ExportData(CertBlob, EncodingType, pVal))) { DebugTrace("Error [%#x]: ExportData() failed.\n", hr); goto ErrorExit; } } catch(...) { hr = E_POINTER; DebugTrace("Exception: invalid parameter.\n"); goto ErrorExit; } UnlockExit: // // Unlock access to this object. // m_Lock.Unlock(); DebugTrace("Leaving CCertificate::Export().\n"); return hr; ErrorExit: // // Sanity check. // ATLASSERT(FAILED(hr)); ReportError(hr); goto UnlockExit; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Function : CCertificate::Import Synopsis : Imoprt a certificate. Parameter: BSTR EncodedCertificate - BSTR containing the encoded certificate blob. Remark : ------------------------------------------------------------------------------*/ STDMETHODIMP CCertificate::Import (BSTR EncodedCertificate) { HRESULT hr = S_OK; DATA_BLOB CertBlob = {0, NULL}; DebugTrace("Entering CCertificate::Import().\n"); try { // // Lock access to this object. // m_Lock.Lock(); // // Make sure parameter is valid. // if ((NULL == (CertBlob.pbData = (LPBYTE) EncodedCertificate)) || (0 == (CertBlob.cbData = ::SysStringByteLen(EncodedCertificate)))) { hr = E_INVALIDARG; DebugTrace("Error [%#x]: EncodedCertificate = %#x, SysStringByteLen(EncodedCertificate) = %d.\n", hr, EncodedCertificate, EncodedCertificate); goto ErrorExit; } // // Now import the blob. // if (FAILED(hr = ImportBlob(&CertBlob, FALSE, (CAPICOM_KEY_LOCATION) 0, NULL, (CAPICOM_KEY_STORAGE_FLAG) 0))) { DebugTrace("Error [%#x]: CCertificate::ImportBlob() failed.\n", hr); goto ErrorExit; } } catch(...) { hr = E_POINTER; DebugTrace("Exception: invalid parameter.\n"); goto ErrorExit; } UnlockExit: // // Unlock access to this object. // m_Lock.Unlock(); DebugTrace("Entering CCertificate::Import().\n"); return hr; ErrorExit: // // Sanity check. // ATLASSERT(FAILED(hr)); ReportError(hr); goto UnlockExit; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Function : CCertificate::Display Synopsis : Display the certificate using CryptUIDlgViewCertificateW() API. Parameter: None Remark : ------------------------------------------------------------------------------*/ STDMETHODIMP CCertificate::Display() { HRESULT hr = S_OK; HINSTANCE hDLL = NULL; PCRYPTUIDLGVIEWCERTIFICATEW pCryptUIDlgViewCertificateW = NULL; CRYPTUI_VIEWCERTIFICATE_STRUCTW ViewInfo; DebugTrace("Entering CCertificate::Display().\n"); // // Lock access to this object. // m_Lock.Lock(); // // Make sure cert is already initialized. // if (!m_pCertContext) { hr = CAPICOM_E_CERTIFICATE_NOT_INITIALIZED; DebugTrace("Error [%#x]: object does not represent an initialized certificate.\n", hr); goto ErrorExit; } // // Get pointer to CryptUIDlgViewCertificateW(). // if (hDLL = ::LoadLibrary("CryptUI.dll")) { pCryptUIDlgViewCertificateW = (PCRYPTUIDLGVIEWCERTIFICATEW) ::GetProcAddress(hDLL, "CryptUIDlgViewCertificateW"); } // // Is CryptUIDlgViewCertificateW() available? // if (!pCryptUIDlgViewCertificateW) { hr = CAPICOM_E_NOT_SUPPORTED; DebugTrace("Error: CryptUIDlgViewCertificateW() API not available.\n"); goto ErrorExit; } // // Initialize view structure. // ::ZeroMemory((void *) &ViewInfo, sizeof(ViewInfo)); ViewInfo.dwSize = sizeof(ViewInfo); ViewInfo.pCertContext = m_pCertContext; // // View it. // if (!pCryptUIDlgViewCertificateW(&ViewInfo, 0)) { // // CryptUIDlgViewCertificateW() returns ERROR_CANCELLED if user closed // the window through the x button!!! // DWORD dwWinError = ::GetLastError(); if (ERROR_CANCELLED != dwWinError) { hr = HRESULT_FROM_WIN32(dwWinError); DebugTrace("Error [%#x]: CryptUIDlgViewCertificateW() failed.\n", hr); goto ErrorExit; } } UnlockExit: // // Release resources. // if (hDLL) { ::FreeLibrary(hDLL); } // // Unlock access to this object. // m_Lock.Unlock(); DebugTrace("Leaving CCertificate::Display().\n"); return hr; ErrorExit: // // Sanity check. // ATLASSERT(FAILED(hr)); ReportError(hr); goto UnlockExit; } //////////////////////////////////////////////////////////////////////////////// // // Certificate2 // /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Function : CCertificate::get_Archived Synopsis : Return the archived status. Parameter: VARIANT_BOOL * pVal - Pointer to BOOL to receive result. Remark : ------------------------------------------------------------------------------*/ STDMETHODIMP CCertificate::get_Archived (VARIANT_BOOL * pVal) { HRESULT hr = S_OK; DWORD cb = 0; DebugTrace("Entering CCertificate::get_Archived().\n"); try { // // Lock access to this object. // m_Lock.Lock(); // // Check parameters. // if (NULL == pVal) { hr = E_INVALIDARG; DebugTrace("Error [%#x]: Parameter pVal is NULL.\n", hr); goto ErrorExit; } // // Make sure cert is already initialized. // if (!m_pCertContext) { hr = CAPICOM_E_CERTIFICATE_NOT_INITIALIZED; DebugTrace("Error [%#x]: object does not represent an initialized certificate.\n", hr); goto ErrorExit; } // // Return result. // *pVal = ::CertGetCertificateContextProperty(m_pCertContext, CERT_ARCHIVED_PROP_ID, NULL, &cb) ? VARIANT_TRUE : VARIANT_FALSE; } catch(...) { hr = E_POINTER; DebugTrace("Exception: invalid parameter.\n"); goto ErrorExit; } UnlockExit: // // Unlock access to this object. // m_Lock.Unlock(); DebugTrace("Leaving CCertificate::get_Archived().\n"); return hr; ErrorExit: // // Sanity check. // ATLASSERT(FAILED(hr)); ReportError(hr); goto UnlockExit; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Function : CCertificate::put_Archived Synopsis : Set the archived status. Parameter: VARIANT_BOOL newVal - Pointer to BOOL to receive result. Remark : ------------------------------------------------------------------------------*/ STDMETHODIMP CCertificate::put_Archived (VARIANT_BOOL newVal) { HRESULT hr = S_OK; LPVOID pvData = NULL; DATA_BLOB DataBlob = {0, NULL}; DebugTrace("Entering CCertificate::put_Archived().\n"); try { // // Lock access to this object. // m_Lock.Lock(); // // Make sure cert is already initialized. // if (!m_pCertContext) { hr = CAPICOM_E_CERTIFICATE_NOT_INITIALIZED; DebugTrace("Error [%#x]: object does not represent an initialized certificate.\n", hr); goto ErrorExit; } // // Not allowed if called from WEB script. // if (m_dwCurrentSafety) { hr = CAPICOM_E_NOT_ALLOWED; DebugTrace("Error [%#x]: Changing archived bit from within WEB script is not allowed.\n", hr); goto ErrorExit; } // // Set/Reset archive property. // if (newVal) { pvData = (LPVOID) &DataBlob; } if (!::CertSetCertificateContextProperty(m_pCertContext, CERT_ARCHIVED_PROP_ID, 0, pvData)) { hr = HRESULT_FROM_WIN32(::GetLastError()); DebugTrace("Error [%#x]: CertSetCertificateContextProperty() failed.\n", hr); goto ErrorExit; } } catch(...) { hr = E_POINTER; DebugTrace("Exception: invalid parameter.\n"); goto ErrorExit; } UnlockExit: // // Unlock access to this object. // m_Lock.Unlock(); DebugTrace("Leaving CCertificate::put_Archived().\n"); return hr; ErrorExit: // // Sanity check. // ATLASSERT(FAILED(hr)); ReportError(hr); goto UnlockExit; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Function : CCertificate::Template Synopsis : Return the ITemplate object. Parameter: ITemplate ** pVal - Pointer to pointer to ITemplate to receive the interface pointer. Remark : ------------------------------------------------------------------------------*/ STDMETHODIMP CCertificate::Template (ITemplate ** pVal) { HRESULT hr = S_OK; DebugTrace("Entering CCertificate::Template().\n"); try { // // Lock access to this object. // m_Lock.Lock(); // // Check parameters. // if (NULL == pVal) { hr = E_INVALIDARG; DebugTrace("Error [%#x]: Parameter pVal is NULL.\n", hr); goto ErrorExit; } // // Make sure cert is already initialized. // if (!m_pCertContext) { hr = CAPICOM_E_CERTIFICATE_NOT_INITIALIZED; DebugTrace("Error [%#x]: object does not represent an initialized certificate.\n", hr); goto ErrorExit; } // // Create the embeded ITemplate object, if not already done so. // if (!m_pITemplate) { if (FAILED(hr = ::CreateTemplateObject(m_pCertContext, &m_pITemplate))) { DebugTrace("Error [%#x]: CreateTemplateObject() failed.\n", hr); goto ErrorExit; } } // // Sanity check. // ATLASSERT(m_pITemplate); // // Return interface pointer to user. // if (FAILED(hr = m_pITemplate->QueryInterface(pVal))) { DebugTrace("Error [%#x]: m_pITemplate->QueryInterface() failed.\n", hr); goto ErrorExit; } ATLASSERT(*pVal); DebugTrace("Info: ITemplate vtable value = %#x\n", (PVOID) *pVal); } catch(...) { hr = E_POINTER; DebugTrace("Exception: invalid parameter.\n"); goto ErrorExit; } UnlockExit: // // Unlock access to this object. // m_Lock.Unlock(); DebugTrace("Leaving CCertificate::Template().\n"); return hr; ErrorExit: // // Sanity check. // ATLASSERT(FAILED(hr)); ReportError(hr); goto UnlockExit; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Function : CCertificate::PublicKey Synopsis : Return the IPublicKey object. Parameter: IPublicKey ** pVal - Pointer to pointer to IPublicKey to receive the interface pointer. Remark : ------------------------------------------------------------------------------*/ STDMETHODIMP CCertificate::PublicKey (IPublicKey ** pVal) { HRESULT hr = S_OK; DebugTrace("Entering CCertificate::PublicKey().\n"); try { // // Lock access to this object. // m_Lock.Lock(); // // Check parameters. // if (NULL == pVal) { hr = E_INVALIDARG; DebugTrace("Error [%#x]: Parameter pVal is NULL.\n", hr); goto ErrorExit; } // // Make sure cert is already initialized. // if (!m_pCertContext) { hr = CAPICOM_E_CERTIFICATE_NOT_INITIALIZED; DebugTrace("Error [%#x]: object does not represent an initialized certificate.\n", hr); goto ErrorExit; } // // Create the embeded IPublicKey object, if not already done so. // if (!m_pIPublicKey) { if (FAILED(hr = ::CreatePublicKeyObject(m_pCertContext, &m_pIPublicKey))) { DebugTrace("Error [%#x]: CreatePublicKeybject() failed.\n", hr); goto ErrorExit; } } // // Sanity check. // ATLASSERT(m_pIPublicKey); // // Return interface pointer to user. // if (FAILED(hr = m_pIPublicKey->QueryInterface(pVal))) { DebugTrace("Error [%#x]: m_pIPublicKey->QueryInterface() failed.\n", hr); goto ErrorExit; } ATLASSERT(*pVal); DebugTrace("Info: IPublicKey vtable value = %#x\n", (PVOID) *pVal); } catch(...) { hr = E_POINTER; DebugTrace("Exception: invalid parameter.\n"); goto ErrorExit; } UnlockExit: // // Unlock access to this object. // m_Lock.Unlock(); DebugTrace("Leaving CCertificate::PublicKey().\n"); return hr; ErrorExit: // // Sanity check. // ATLASSERT(FAILED(hr)); ReportError(hr); goto UnlockExit; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Function : CCertificate::get_PrivateKey Synopsis : Return the IPrivateKey object. Parameter: IPrivateKey ** pVal - Pointer to pointer to IPrivateKey to receive the interface pointer. Remark : ------------------------------------------------------------------------------*/ STDMETHODIMP CCertificate::get_PrivateKey (IPrivateKey ** pVal) { HRESULT hr = S_OK; CComPtr pIPrivateKey = NULL; DebugTrace("Entering CCertificate::get_PrivateKey().\n"); try { // // Lock access to this object. // m_Lock.Lock(); // // Check parameters. // if (NULL == pVal) { hr = E_INVALIDARG; DebugTrace("Error [%#x]: Parameter pVal is NULL.\n", hr); goto ErrorExit; } // // Make sure cert is already initialized. // if (!m_pCertContext) { hr = CAPICOM_E_CERTIFICATE_NOT_INITIALIZED; DebugTrace("Error [%#x]: object does not represent an initialized certificate.\n", hr); goto ErrorExit; } // // Create the object on the fly (read-only if called from WEB script). // if (FAILED(hr = ::CreatePrivateKeyObject(m_pCertContext, m_dwCurrentSafety ? TRUE : FALSE, &pIPrivateKey))) { DebugTrace("Error [%#x]: CreatePrivateKeybject() failed.\n", hr); goto ErrorExit; } // // Return interface pointer to user. // if (FAILED(hr = pIPrivateKey->QueryInterface(pVal))) { DebugTrace("Error [%#x]: pIPrivateKey->QueryInterface() failed.\n", hr); goto ErrorExit; } } catch(...) { hr = E_POINTER; DebugTrace("Exception: invalid parameter.\n"); goto ErrorExit; } UnlockExit: // // Unlock access to this object. // m_Lock.Unlock(); DebugTrace("Leaving CCertificate::get_PrivateKey().\n"); return hr; ErrorExit: // // Sanity check. // ATLASSERT(FAILED(hr)); ReportError(hr); goto UnlockExit; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Function : CCertificate::put_PrivateKey Synopsis : Set the IPrivateKey object. Parameter: IPrivateKey * newVal - Pointer to IPrivateKey. Remark : ------------------------------------------------------------------------------*/ STDMETHODIMP CCertificate::put_PrivateKey (IPrivateKey * newVal) { HRESULT hr = S_OK; PCRYPT_KEY_PROV_INFO pKeyProvInfo = NULL; DebugTrace("Entering CCertificate::put_PrivateKey().\n"); try { // // Lock access to this object. // m_Lock.Lock(); // // Not allowed if called from WEB script. // if (m_dwCurrentSafety) { hr = CAPICOM_E_NOT_ALLOWED; DebugTrace("Error [%#x]: Changing PrivateKey from within WEB script is not allowed.\n", hr); goto ErrorExit; } // // Check parameters. // if (NULL == newVal) { hr = E_INVALIDARG; DebugTrace("Error [%#x]: Parameter newVal is NULL.\n", hr); goto ErrorExit; } // // Make sure cert is already initialized. // if (!m_pCertContext) { hr = CAPICOM_E_CERTIFICATE_NOT_INITIALIZED; DebugTrace("Error [%#x]: object does not represent an initialized certificate.\n", hr); goto ErrorExit; } // // NULL to disassociate. // if (newVal) { // // Get copy of key prov info. // if (FAILED(hr = ::GetKeyProvInfo(newVal, &pKeyProvInfo))) { DebugTrace("Error [%#x]: GetKeyProvInfo() failed.\n", hr); goto ErrorExit; } // // Make sure public keys match. // if (FAILED(hr = ::CompareCertAndContainerPublicKey(m_pCertContext, pKeyProvInfo->pwszContainerName, pKeyProvInfo->pwszProvName, pKeyProvInfo->dwProvType, pKeyProvInfo->dwKeySpec, pKeyProvInfo->dwFlags & CRYPT_MACHINE_KEYSET))) { DebugTrace("Error [%#x]: CompareCertAndContainerPublicKey() failed.\n", hr); goto ErrorExit; } } // // Set the association. // if (!::CertSetCertificateContextProperty(m_pCertContext, CERT_KEY_PROV_INFO_PROP_ID, 0, pKeyProvInfo)) { hr = HRESULT_FROM_WIN32(::GetLastError()); DebugTrace("Error [%#x]: CertSetCertificateContextProperty() failed.\n", hr); goto ErrorExit; } } catch(...) { hr = E_POINTER; DebugTrace("Exception: invalid parameter.\n"); goto ErrorExit; } UnlockExit: // // Free resources. // if (pKeyProvInfo) { ::CoTaskMemFree(pKeyProvInfo); } // // Unlock access to this object. // m_Lock.Unlock(); DebugTrace("Leaving CCertificate::put_PrivateKey().\n"); return hr; ErrorExit: // // Sanity check. // ATLASSERT(FAILED(hr)); ReportError(hr); goto UnlockExit; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Function : CCertificate::Extensions Synopsis : Return the IExtensions collection object. Parameter: IExtensions ** pVal - Pointer to pointer to IExtensions to receive the interface pointer. Remark : ------------------------------------------------------------------------------*/ STDMETHODIMP CCertificate::Extensions (IExtensions ** pVal) { HRESULT hr = S_OK; DebugTrace("Entering CCertificate::Extensions().\n"); try { // // Lock access to this object. // m_Lock.Lock(); // // Check parameters. // if (NULL == pVal) { hr = E_INVALIDARG; DebugTrace("Error [%#x]: Parameter pVal is NULL.\n", hr); goto ErrorExit; } // // Make sure cert is already initialized. // if (!m_pCertContext) { hr = CAPICOM_E_CERTIFICATE_NOT_INITIALIZED; DebugTrace("Error [%#x]: object does not represent an initialized certificate.\n", hr); goto ErrorExit; } // // Create the embeded IExtensions object, if not already done so. // if (!m_pIExtensions) { if (FAILED(hr = ::CreateExtensionsObject(m_pCertContext, &m_pIExtensions))) { DebugTrace("Error [%#x]: CreateExtensionsObject() failed.\n", hr); goto ErrorExit; } } // // Sanity check. // ATLASSERT(m_pIExtensions); // // Return interface pointer to user. // if (FAILED(hr = m_pIExtensions->QueryInterface(pVal))) { DebugTrace("Error [%#x]: m_pIExtensions->QueryInterface() failed.\n", hr); goto ErrorExit; } } catch(...) { hr = E_POINTER; DebugTrace("Exception: invalid parameter.\n"); goto ErrorExit; } UnlockExit: // // Unlock access to this object. // m_Lock.Unlock(); DebugTrace("Leaving CCertificate::Extensions().\n"); return hr; ErrorExit: // // Sanity check. // ATLASSERT(FAILED(hr)); ReportError(hr); goto UnlockExit; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Function : CCertificate::ExtendedProperties Synopsis : Return the IExtendedProperties collection object. Parameter: IExtendedProperties ** pVal - Pointer to pointer to IExtendedProperties to receive the interface pointer. Remark : ------------------------------------------------------------------------------*/ STDMETHODIMP CCertificate::ExtendedProperties (IExtendedProperties ** pVal) { HRESULT hr = S_OK; DebugTrace("Entering CCertificate::ExtendedProperties().\n"); try { // // Lock access to this object. // m_Lock.Lock(); // // Check parameters. // if (NULL == pVal) { hr = E_INVALIDARG; DebugTrace("Error [%#x]: Parameter pVal is NULL.\n", hr); goto ErrorExit; } // // Make sure cert is already initialized. // if (!m_pCertContext) { hr = CAPICOM_E_CERTIFICATE_NOT_INITIALIZED; DebugTrace("Error [%#x]: object does not represent an initialized certificate.\n", hr); goto ErrorExit; } // // Create the dynamic IExtendedProperties object. // if (FAILED(hr = ::CreateExtendedPropertiesObject(m_pCertContext, m_dwCurrentSafety ? TRUE : FALSE, pVal))) { DebugTrace("Error [%#x]: CreateExtendedPropertiesObject() failed.\n", hr); goto ErrorExit; } } catch(...) { hr = E_POINTER; DebugTrace("Exception: invalid parameter.\n"); goto ErrorExit; } UnlockExit: // // Unlock access to this object. // m_Lock.Unlock(); DebugTrace("Leaving CCertificate::ExtendedProperties().\n"); return hr; ErrorExit: // // Sanity check. // ATLASSERT(FAILED(hr)); ReportError(hr); goto UnlockExit; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Function : CCertificate::Load Synopsis : Method to load certificate(s) from a file. Parameter: BSTR FileName - File name. BSTR Password - Password (required for PFX file.) CAPICOM_KEY_STORAGE_FLAG KeyStorageFlag - Key storage flag. CAPICOM_KEY_LOCATION KeyLocation - Key location. Remark : ------------------------------------------------------------------------------*/ STDMETHODIMP CCertificate::Load (BSTR FileName, BSTR Password, CAPICOM_KEY_STORAGE_FLAG KeyStorageFlag, CAPICOM_KEY_LOCATION KeyLocation) { HRESULT hr = S_OK; DATA_BLOB CertBlob = {0, NULL}; DebugTrace("Entering CCertificate::Load().\n"); try { // // Lock access to this object. // m_Lock.Lock(); // // Not allowed if called from WEB script. // if (m_dwCurrentSafety) { hr = CAPICOM_E_NOT_ALLOWED; DebugTrace("Error [%#x]: Loading cert file from WEB script is not allowed.\n", hr); goto ErrorExit; } // // Check parameters. // if (0 == ::SysStringLen(FileName)) { hr = E_INVALIDARG; DebugTrace("Error [%#x]: Parameter FileName is NULL or empty.\n", hr); goto ErrorExit; } // // Work around MIDL problem. // if (0 == ::SysStringLen(Password)) { Password = NULL; } // // Read entire file in. // if (FAILED(hr = ::ReadFileContent((LPWSTR) FileName, &CertBlob))) { DebugTrace("Error [%#x]: ReadFileContent() failed.\n", hr); goto ErrorExit; } // // Now import the blob. // if (FAILED(hr = ImportBlob(&CertBlob, TRUE, KeyLocation, Password, KeyStorageFlag))) { DebugTrace("Error [%#x]: CCertificate::ImportBlob() failed.\n", hr); goto ErrorExit; } } catch(...) { hr = E_POINTER; DebugTrace("Exception: invalid parameter.\n"); goto ErrorExit; } UnlockExit: // // Free resource. // if (CertBlob.pbData) { ::UnmapViewOfFile(CertBlob.pbData); } // // Unlock access to this object. // m_Lock.Unlock(); DebugTrace("Leaving CCertificate::Load().\n"); return hr; ErrorExit: // // Sanity check. // ATLASSERT(FAILED(hr)); ReportError(hr); goto UnlockExit; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Function : CCertificate::Save Synopsis : Method to save certificate(s) to a file. Parameter: BSTR FileName - File name. BSTR Password - Password (required for PFX file.) CAPICOM_CERTIFICATE_SAVE_AS_TYPE FileType - SaveAs type. CAPICOM_CERTIFICATE_INCLUDE_OPTION IncludeOption - Include option. Remark : ------------------------------------------------------------------------------*/ STDMETHODIMP CCertificate::Save (BSTR FileName, BSTR Password, CAPICOM_CERTIFICATE_SAVE_AS_TYPE SaveAs, CAPICOM_CERTIFICATE_INCLUDE_OPTION IncludeOption) { HRESULT hr = S_OK; HCERTSTORE hCertStore = NULL; DebugTrace("Entering CCertificate::Save().\n"); try { // // Lock access to this object. // m_Lock.Lock(); // // Not allowed if called from WEB script. // if (m_dwCurrentSafety) { hr = CAPICOM_E_NOT_ALLOWED; DebugTrace("Error [%#x]: Saving cert file from WEB script is not allowed.\n", hr); goto ErrorExit; } // // Check parameters. // if (0 == ::SysStringLen(FileName)) { hr = E_INVALIDARG; DebugTrace("Error [%#x]: Parameter FileName is NULL or empty.\n", hr); goto ErrorExit; } // // Work around MIDL problem. // if (0 == ::SysStringLen(Password)) { Password = NULL; } // // Make sure cert is already initialized. // if (!m_pCertContext) { hr = CAPICOM_E_CERTIFICATE_NOT_INITIALIZED; DebugTrace("Error [%#x]: object does not represent an initialized certificate.\n", hr); goto ErrorExit; } // // Check file type. // switch (SaveAs) { case CAPICOM_CERTIFICATE_SAVE_AS_CER: { DATA_BLOB DataBlob; // // Simply write the encoded cert blob to file. // DataBlob.cbData = m_pCertContext->cbCertEncoded; DataBlob.pbData = m_pCertContext->pbCertEncoded; if (FAILED(hr = ::WriteFileContent(FileName, DataBlob))) { DebugTrace("Error [%#x]: WriteFileContent() failed.\n", hr); goto ErrorExit; } break; } case CAPICOM_CERTIFICATE_SAVE_AS_PFX: { // // Create a memory store. // if (!(hCertStore = ::CertOpenStore(CERT_STORE_PROV_MEMORY, CAPICOM_ASN_ENCODING, 0, 0, NULL))) { hr = HRESULT_FROM_WIN32(::GetLastError()); DebugTrace("Error [%#x]: CertOpenStore() failed.\n", hr); goto ErrorExit; } // // Add all requested certs to the store. // if (FAILED(hr = ::CertToStore(m_pCertContext, IncludeOption, hCertStore))) { DebugTrace("Error [%#x]: CertToStore() failed.\n", hr); goto ErrorExit; } // // Save as PFX file. // if (FAILED(hr = ::PFXSaveStore(hCertStore, FileName, Password, EXPORT_PRIVATE_KEYS | REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY))) { DebugTrace("Error [%#x]: PFXSaveStore() failed.\n", hr); goto ErrorExit; } break; } default: { hr = E_INVALIDARG; DebugTrace("Error: invalid parameter, unknown save as type.\n"); goto ErrorExit; } } } catch(...) { hr = E_POINTER; DebugTrace("Exception: invalid parameter.\n"); goto ErrorExit; } UnlockExit: // // Free resources. // if (hCertStore) { ::CertCloseStore(hCertStore, 0); } // // Unlock access to this object. // m_Lock.Unlock(); DebugTrace("Leaving CCertificate::Save().\n"); return hr; ErrorExit: // // Sanity check. // ATLASSERT(FAILED(hr)); ReportError(hr); goto UnlockExit; } //////////////////////////////////////////////////////////////////////////////// // // Custom interfaces. // /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Function : CCertificate::get_CertContext Synopsis : Return the certificate's PCCERT_CONTEXT. Parameter: long * ppCertContext - Pointer to PCCERT_CONTEXT disguished in a long. Remark : We need to use long instead of PCCERT_CONTEXT because VB can't handle double indirection (i.e. vb would bark on this PCCERT_CONTEXT * ppCertContext). ------------------------------------------------------------------------------*/ STDMETHODIMP CCertificate::get_CertContext (long * ppCertContext) { HRESULT hr = S_OK; DebugTrace("Entering CCertificate::get_CertContext().\n"); try { // // Lock access to this object. // m_Lock.Lock(); // // Return cert context to caller. // if (FAILED(hr = GetContext((PCCERT_CONTEXT *) ppCertContext))) { DebugTrace("Error [%#x]: CCertificate::GetContext() failed.\n", hr); goto ErrorExit; } } catch(...) { hr = E_POINTER; DebugTrace("Exception: invalid parameter.\n"); goto ErrorExit; } UnlockExit: // // Unlock access to this object. // m_Lock.Unlock(); DebugTrace("Leaving CCertificate::get_CertContext().\n"); return hr; ErrorExit: // // Sanity check. // ATLASSERT(FAILED(hr)); ReportError(hr); goto UnlockExit; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Function : CCertificate::put_CertContext Synopsis : Initialize the object with a CERT_CONTEXT. Parameter: long pCertContext - Poiner to CERT_CONTEXT, disguised in a long, used to initialize this object. Remark : Note that this is NOT 64-bit compatiable. Plese see remark of get_CertContext for more detail. ------------------------------------------------------------------------------*/ STDMETHODIMP CCertificate::put_CertContext (long pCertContext) { HRESULT hr = S_OK; DebugTrace("Entering CCertificate::put_CertContext().\n"); try { // // Lock access to this object. // m_Lock.Lock(); // // Reset the object with this context. // if (FAILED(hr = PutContext((PCCERT_CONTEXT) pCertContext, m_dwCurrentSafety))) { DebugTrace("Error [%#x]: CCertificate::PutContext() failed.\n", hr); goto ErrorExit; } } catch(...) { hr = E_POINTER; DebugTrace("Exception: invalid parameter.\n"); goto ErrorExit; } UnlockExit: // // Unlock access to this object. // m_Lock.Unlock(); DebugTrace("Leaving CCertificate::put_CertContext().\n"); return hr; ErrorExit: // // Sanity check. // ATLASSERT(FAILED(hr)); ReportError(hr); goto UnlockExit; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Function : CCertificate::FreeContext Synopsis : Free a CERT_CONTEXT. Parameter: long pCertContext - Poiner to CERT_CONTEXT, disguised in a long, to be freed. Remark : Note that this is NOT 64-bit compatiable. Plese see remark of get_CertContext for more detail. ------------------------------------------------------------------------------*/ STDMETHODIMP CCertificate::FreeContext (long pCertContext) { HRESULT hr = S_OK; DebugTrace("Entering CCertificate::FreeContext().\n"); try { // // Lock access to this object. // m_Lock.Lock(); // // Free the context. // if (!::CertFreeCertificateContext((PCCERT_CONTEXT) pCertContext)) { hr = HRESULT_FROM_WIN32(::GetLastError()); DebugTrace("Error [%#x]: CertFreeCertificateContext() failed.\n", hr); goto ErrorExit; } } catch(...) { hr = E_POINTER; DebugTrace("Exception: invalid parameter.\n"); goto ErrorExit; } UnlockExit: // // Unlock access to this object. // m_Lock.Unlock(); DebugTrace("Leaving CCertificate::FreeContext().\n"); return hr; ErrorExit: // // Sanity check. // ATLASSERT(FAILED(hr)); ReportError(hr); goto UnlockExit; } //////////////////////////////////////////////////////////////////////////////// // // Private methods. // /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Function : CCertificate::ImportBlob Synopsis : Private function to load a certificate from blob. Parameter: DATA_BLOB * pCertBlob BOOL bAllowPfx CAPICOM_KEY_LOCATION KeyLocation - Key location. BSTR pwszPassword - Password (required for PFX file.) CAPICOM_KEY_STORAGE_FLAG KeyStorageFlag - Key storage flag. Remark : ------------------------------------------------------------------------------*/ STDMETHODIMP CCertificate::ImportBlob (DATA_BLOB * pCertBlob, BOOL bAllowPfx, CAPICOM_KEY_LOCATION KeyLocation, BSTR pwszPassword, CAPICOM_KEY_STORAGE_FLAG KeyStorageFlag) { HRESULT hr = S_OK; HCERTSTORE hCertStore = NULL; PCCERT_CONTEXT pEnumContext = NULL; PCCERT_CONTEXT pCertContext = NULL; DWORD dwContentType = 0; DWORD cb = 0; DWORD dwFlags = 0; DWORD dwExpectedType = CERT_QUERY_CONTENT_FLAG_CERT | CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT; DebugTrace("Entering CCertificate::ImportBlob().\n"); // // Sanity check. // ATLASSERT(pCertBlob); // // Set PFX flag, if allowed. // if (bAllowPfx) { dwExpectedType |= CERT_QUERY_CONTENT_FLAG_PFX; } // // Crack the blob. // if (!::CryptQueryObject(CERT_QUERY_OBJECT_BLOB, (LPCVOID) pCertBlob, dwExpectedType, CERT_QUERY_FORMAT_FLAG_ALL, 0, NULL, &dwContentType, NULL, &hCertStore, NULL, NULL)) { hr = HRESULT_FROM_WIN32(::GetLastError()); DebugTrace("Error [%#x]: CryptQueryObject() failed.\n", hr); goto ErrorExit; } DebugTrace("Info: CryptQueryObject() returns dwContentType = %#x.\n", dwContentType); // // Need to import it ourselves for PFX file. // if (CERT_QUERY_CONTENT_PFX == dwContentType) { // // Make sure PFX is allowed. // if (!bAllowPfx) { hr = CAPICOM_E_NOT_SUPPORTED; DebugTrace("Error [%#x]: Importing PFX where not supported.\n", hr); goto ErrorExit; } // // Setup import flags. // if (CAPICOM_LOCAL_MACHINE_KEY == KeyLocation) { dwFlags |= CRYPT_MACHINE_KEYSET; } else if (IsWin2KAndAbove()) { dwFlags |= CRYPT_USER_KEYSET; } if (KeyStorageFlag & CAPICOM_KEY_STORAGE_EXPORTABLE) { dwFlags |= CRYPT_EXPORTABLE; } if (KeyStorageFlag & CAPICOM_KEY_STORAGE_USER_PROTECTED) { dwFlags |= CRYPT_USER_PROTECTED; } DebugTrace("Info: dwFlags = %#x.", dwFlags); // // Now import the blob to store. // if (!(hCertStore = ::PFXImportCertStore((CRYPT_DATA_BLOB *) pCertBlob, pwszPassword, dwFlags))) { hr = HRESULT_FROM_WIN32(::GetLastError()); DebugTrace("Error [%#x]: PFXImportCertStore() failed.\n", hr); goto ErrorExit; } // // Sanity check. // ATLASSERT(hCertStore); // // Find the first cert with private key, if none, then simply take // the very first cert. // while (pEnumContext = ::CertEnumCertificatesInStore(hCertStore, pEnumContext)) { // // Does this cert has a private key? // if (::CertGetCertificateContextProperty(pEnumContext, CERT_KEY_PROV_INFO_PROP_ID, NULL, &cb)) { // // Yes, so free the one without private key, had we found one previously. // if (pCertContext) { if (!::CertFreeCertificateContext(pCertContext)) { hr = HRESULT_FROM_WIN32(::GetLastError()); DebugTrace("Error [%#x]: CertFreeCertificateContext() failed.\n", hr); goto ErrorExit; } } if (!(pCertContext = ::CertDuplicateCertificateContext(pEnumContext))) { hr = HRESULT_FROM_WIN32(::GetLastError()); DebugTrace("Error [%#x]: CertDuplicateCertificateContext() failed.\n", hr); goto ErrorExit; } // // Set last error before we break out of loop. // ::SetLastError((DWORD) CRYPT_E_NOT_FOUND); break; } else { // // Keep the first one. // if (!pCertContext) { if (!(pCertContext = ::CertDuplicateCertificateContext(pEnumContext))) { hr = HRESULT_FROM_WIN32(::GetLastError()); DebugTrace("Error [%#x]: CertDuplicateCertificateContext() failed.\n", hr); goto ErrorExit; } } } } // // Above loop can exit either because there is no more certificate in // the store or an error. Need to check last error to be certain. // if (CRYPT_E_NOT_FOUND != ::GetLastError()) { hr = HRESULT_FROM_WIN32(::GetLastError()); DebugTrace("Error [%#x]: CertEnumCertificatesInStore() failed.\n", hr); goto ErrorExit; } } else { // // It is a CER file, so it must have only 1 cert. // if (!(pCertContext = ::CertEnumCertificatesInStore(hCertStore, NULL))) { hr = HRESULT_FROM_WIN32(::GetLastError()); DebugTrace("Error [%#x]: CertEnumCertificatesInStore() failed.\n", hr); goto ErrorExit; } } // // Sanity check. // ATLASSERT(pCertContext); // // Now initialize the object with the found cert. // if (FAILED(hr = PutContext(pCertContext, m_dwCurrentSafety))) { DebugTrace("Error [%#x]: CCertificate::PutContext() failed.\n", hr); goto ErrorExit; } CommonExit: // // Free resource. // if (pCertContext) { ::CertFreeCertificateContext(pCertContext); } if (pEnumContext) { ::CertFreeCertificateContext(pEnumContext); } if (hCertStore) { ::CertCloseStore(hCertStore, 0); } DebugTrace("Leaving CCertificate::ImportBlob().\n"); return hr; ErrorExit: // // Sanity check. // ATLASSERT(FAILED(hr)); goto CommonExit; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Function : CCertificate::GetContext Synopsis : Return the certificate's PCCERT_CONTEXT. Parameter: PCCERT_CONTEXT * ppCertContext - Pointer to PCCERT_CONTEXT. Remark : This method is designed for internal use only, and therefore, should not be exposed to user. Note that this is a custom interface, not a dispinterface. Note that the cert context ref count is incremented by CertDuplicateCertificateContext(), so it is the caller's responsibility to free the context. ------------------------------------------------------------------------------*/ STDMETHODIMP CCertificate::GetContext (PCCERT_CONTEXT * ppCertContext) { HRESULT hr = S_OK; DebugTrace("Entering CCertificate::GetContext().\n"); // // Make sure cert is already initialized. // if (!m_pCertContext) { hr = CAPICOM_E_CERTIFICATE_NOT_INITIALIZED; DebugTrace("Error [%#x]: object does not represent an initialized certificate.\n", hr); goto ErrorExit; } // // Sanity check. // ATLASSERT(ppCertContext); // // Duplicate the cert context. // if (!(*ppCertContext = ::CertDuplicateCertificateContext(m_pCertContext))) { hr = HRESULT_FROM_WIN32(::GetLastError()); DebugTrace("Error [%#x]: CertDuplicateCertificateContext() failed.\n"); goto ErrorExit; } CommonExit: DebugTrace("Leaving CCertificate::GetContext().\n"); return hr; ErrorExit: // // Sanity check. // ATLASSERT(FAILED(hr)); goto CommonExit; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Function : CCertificate::PutContext Synopsis : Initialize the object with a CERT_CONTEXT. Parameter: PCERT_CONTEXT pCertContext - Poiner to CERT_CONTEXT used to initialize this object. DWORD dwCurrentSafety - Current safety setting. Remark : This method is not part of the COM interface (it is a normal C++ member function). We need it to initialize the object created internally by us. Since it is only a normal C++ member function, this function can only be called from a C++ class pointer, not an interface pointer. ------------------------------------------------------------------------------*/ STDMETHODIMP CCertificate::PutContext (PCCERT_CONTEXT pCertContext, DWORD dwCurrentSafety) { HRESULT hr = S_OK; PCCERT_CONTEXT pCertContext2 = NULL; DebugTrace("Entering CCertificate::PutContext().\n"); // // Sanity check. // ATLASSERT(pCertContext); // // Duplicate the cert context. // if (!(pCertContext2 = ::CertDuplicateCertificateContext(pCertContext))) { hr = HRESULT_FROM_WIN32(::GetLastError()); DebugTrace("Error [%#x]: CertDupliacteCertificateContext() failed.\n"); goto ErrorExit; } // // Free previous context, if any. // if (m_pCertContext) { if (!::CertFreeCertificateContext(m_pCertContext)) { hr = HRESULT_FROM_WIN32(::GetLastError()); DebugTrace("Error [%#x]: CertFreeCertificateContext() failed.\n"); goto ErrorExit; } } // // Reset. // m_pCertContext = pCertContext2; m_pIKeyUsage.Release(); m_pIExtendedKeyUsage.Release(); m_pIBasicConstraints.Release(); m_pICertificateStatus.Release(); m_pITemplate.Release(); m_pIPublicKey.Release(); m_pIExtensions.Release(); m_dwCurrentSafety = dwCurrentSafety; CommonExit: DebugTrace("Leaving CCertificate::PutContext().\n"); return hr; ErrorExit: // // Sanity check. // ATLASSERT(FAILED(hr)); // // Free resources. // if (pCertContext2) { ::CertFreeCertificateContext(pCertContext2); } goto CommonExit; }