/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Microsoft Windows, Copyright (C) Microsoft Corporation, 2000 File: CertificateStatus.cpp Contents: Implementation of CCertificateStatus Remarks: This object is not creatable by user directly. It can only be created via property/method of other CAPICOM objects. History: 11-15-99 dsie created ------------------------------------------------------------------------------*/ #include "StdAfx.h" #include "CAPICOM.h" #include "CertificateStatus.h" #include "Chain.h" #include "OIDs.h" /////////////// // // Local // #define DEFAULT_CHECK_FLAGS ((CAPICOM_CHECK_FLAG) (CAPICOM_CHECK_SIGNATURE_VALIDITY | \ CAPICOM_CHECK_TIME_VALIDITY | \ CAPICOM_CHECK_TRUSTED_ROOT)) //////////////////////////////////////////////////////////////////////////////// // // Exported functions. // /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Function : CreateCertificateStatusObject Synopsis : Create an ICertificateStatus object. Parameter: PCCERT_CONTEXT pCertContext - Pointer to CERT_CONTEXT. ICertificateStatus ** ppICertificateStatus - Pointer to pointer ICertificateStatus object. Remark : ------------------------------------------------------------------------------*/ HRESULT CreateCertificateStatusObject (PCCERT_CONTEXT pCertContext, ICertificateStatus ** ppICertificateStatus) { HRESULT hr = S_OK; CComObject * pCCertificateStatus = NULL; DebugTrace("Entering CreateCertificateStatusObject().\n"); // // Sanity check. // ATLASSERT(pCertContext); ATLASSERT(ppICertificateStatus); try { // // Create the object. Note that the ref count will still be 0 // after the object is created. // if (FAILED(hr = CComObject::CreateInstance(&pCCertificateStatus))) { DebugTrace("Error [%#x]: CComObject::CreateInstance() failed.\n", hr); goto ErrorExit; } // // Initialize the object. // if (FAILED(hr = pCCertificateStatus->Init(pCertContext))) { DebugTrace("Error [%#x]: pCCertificateStatus->Init() failed.\n", hr); goto ErrorExit; } // // Return ICertificateStatus pointer to caller. // if (FAILED(hr = pCCertificateStatus->QueryInterface(ppICertificateStatus))) { DebugTrace("Error [%#x]: pCCertificateStatus->QueryInterface() failed.\n", hr); goto ErrorExit; } } catch(...) { hr = E_POINTER; DebugTrace("Exception: invalid parameter.\n"); goto ErrorExit; } CommonExit: DebugTrace("Leaving CreateCertificateStatusObject().\n"); return hr; ErrorExit: // // Sanity check. // ATLASSERT(FAILED(hr)); // // Free resource. // if (pCCertificateStatus) { delete pCCertificateStatus; } goto CommonExit; } //////////////////////////////////////////////////////////////////////////////// // // CCertificateStatus // /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Function : CCertificateStatus::get_Result Synopsis : Return the overall validity result of the cert, based on the currently set check flags and EKU. Parameter: VARIANT_BOOL * pVal - Pointer to VARIANT_BOOL to receive result. Remark : ------------------------------------------------------------------------------*/ STDMETHODIMP CCertificateStatus::get_Result (VARIANT_BOOL * pVal) { HRESULT hr = S_OK; CComPtr pIChain = NULL; DebugTrace("Entering CCertificateStatus::get_Result().\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; } // // Sanity check. // ATLASSERT(m_pCertContext); // // Build the chain and return the result. // if (FAILED(hr = ::CreateChainObject(m_pCertContext, this, NULL, pVal, &pIChain))) { DebugTrace("Error [%#x]: CreateChainObject() 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 CCertificateStatus::get_Result().\n"); return hr; ErrorExit: // // Sanity check. // ATLASSERT(FAILED(hr)); ReportError(hr); goto UnlockExit; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Function : CCertificateStatus::get_CheckFlag Synopsis : Return the currently set validity check flag. Parameter: CAPICOM_CHECK_FLAG * pVal - Pointer to CAPICOM_CHECK_FLAG to receive check flag. Remark : ------------------------------------------------------------------------------*/ STDMETHODIMP CCertificateStatus::get_CheckFlag (CAPICOM_CHECK_FLAG * pVal) { HRESULT hr = S_OK; DebugTrace("Entering CCertificateStatus::get_CheckFlag().\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; } // // Return flag to user. // *pVal = m_CheckFlag; } catch(...) { hr = E_POINTER; DebugTrace("Exception: invalid parameter.\n"); goto ErrorExit; } UnlockExit: // // Unlock access to this object. // m_Lock.Unlock(); DebugTrace("Leaving CCertificateStatus::get_CheckFlag().\n"); return hr; ErrorExit: // // Sanity check. // ATLASSERT(FAILED(hr)); ReportError(hr); goto UnlockExit; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Function : CCertificateStatus::put_CheckFlag Synopsis : Set validity check flag. Parameter: CAPICOM_CHECK_FLAG newVal - Check flag. Remark : Note that CHECK_ONLINE_REVOCATION_STATUS and CHECK_OFFLINE_REVOCATION_STATUS is mutually exclusive. ------------------------------------------------------------------------------*/ STDMETHODIMP CCertificateStatus::put_CheckFlag (CAPICOM_CHECK_FLAG newVal) { HRESULT hr = S_OK; DebugTrace("Entering CCertificateStatus::put_CheckFlag().\n"); // // Lock access to this object. // m_Lock.Lock(); // // Make sure flag is valid (maximum is CAPICOM_CHECK_OFFLINE_ALL). // if ((newVal & CAPICOM_CHECK_FLAG_LO_MASK) > CAPICOM_CHECK_OFFLINE_ALL) { hr = E_INVALIDARG; DebugTrace("Error [%#x]: invalid check flag (%#x).\n", hr, newVal); goto ErrorExit; } // // Store check flag. // m_CheckFlag = newVal; UnlockExit: // // Unlock access to this object. // m_Lock.Unlock(); DebugTrace("Leaving CCertificateStatus::put_CheckFlag().\n"); return hr; ErrorExit: // // Sanity check. // ATLASSERT(FAILED(hr)); ReportError(hr); goto UnlockExit; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Function : CCertificateStatus::EKU Synopsis : Return the EKU object. Parameter: IEKU ** pVal - Pointer to pointer to IEKU to receive the interface pointer. Remark : ------------------------------------------------------------------------------*/ STDMETHODIMP CCertificateStatus::EKU (IEKU ** pVal) { HRESULT hr = S_OK; DebugTrace("Entering CCertificateStatus::EKU().\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; } // // Sanity check. // ATLASSERT(m_pIEKU); // // Return interface pointer to user. // if (FAILED(hr = m_pIEKU->QueryInterface(pVal))) { DebugTrace("Error [%#x]: m_pIEKU->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 CCertificateStatus::EKU().\n"); return hr; ErrorExit: // // Sanity check. // ATLASSERT(FAILED(hr)); ReportError(hr); goto UnlockExit; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Function : CCertificateStatus::get_VerificationTime Synopsis : Return the verification time. Parameter: DATE * pVal - Pointer to DATE to receive the value. Remark : ------------------------------------------------------------------------------*/ STDMETHODIMP CCertificateStatus::get_VerificationTime (DATE * pVal) { HRESULT hr = S_OK; SYSTEMTIME st = {0}; DebugTrace("Entering CCertificateStatus::get_VerificationTime().\n"); try { // // Lock access to this object. // m_Lock.Lock(); // // Make sure paremeters are valid. // if (NULL == pVal) { hr = E_INVALIDARG; DebugTrace("Error [%#x]: Paremeter pVal is NULL.\n", hr); goto ErrorExit; } // // If the time was never explicit set by user, return the current time. // if ((DATE) 0 == m_VerificationTime) { ::GetLocalTime(&st); // // Convert to DATE. // if (0 == ::SystemTimeToVariantTime(&st, pVal)) { hr = E_INVALIDARG; DebugTrace("Error [%#x]: SystemTimeToVariantTime() failed.\n", hr); goto ErrorExit; } } else { // // Return previously set verification time to caller. // *pVal = m_VerificationTime; } } catch(...) { hr = E_POINTER; DebugTrace("Exception: invalid parameter.\n"); goto ErrorExit; } UnlockExit: // // Unlock access to this object. // m_Lock.Unlock(); DebugTrace("Leaving CCertificateStatus::get_VerificationTime().\n"); return hr; ErrorExit: // // Sanity check. // ATLASSERT(FAILED(hr)); ReportError(hr); goto UnlockExit; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Function : CCertificateStatus::put_VerificationTime Synopsis : Set the verification time. Parameter: DATE newVal - New DATE value. Remark : ------------------------------------------------------------------------------*/ STDMETHODIMP CCertificateStatus::put_VerificationTime (DATE newVal) { HRESULT hr = S_OK; DebugTrace("Entering CCertificateStatus::put_VerificationTime().\n"); try { // // Lock access to this object. // m_Lock.Lock(); // // Update verification time. // m_VerificationTime = newVal; } catch(...) { hr = E_POINTER; DebugTrace("Exception: invalid parameter.\n"); goto ErrorExit; } UnlockExit: // // Unlock access to this object. // m_Lock.Unlock(); DebugTrace("Leaving CCertificateStatus::put_VerificationTime().\n"); return hr; ErrorExit: // // Sanity check. // ATLASSERT(FAILED(hr)); ReportError(hr); goto UnlockExit; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Function : CCertificateStatus::get_UrlRetrievalTimeout Synopsis : Get the URL retrieval timeout value in seconds. Parameter: long * pVal - Pointer to long to receive the value. Remark : ------------------------------------------------------------------------------*/ STDMETHODIMP CCertificateStatus::get_UrlRetrievalTimeout (long * pVal) { HRESULT hr = S_OK; DebugTrace("Entering CCertificateStatus::get_UrlRetrievalTimeout().\n"); try { // // Lock access to this object. // m_Lock.Lock(); // // Make sure paremeters are valid. // if (NULL == pVal) { hr = E_INVALIDARG; DebugTrace("Error [%#x]: Paremeter pVal is NULL.\n", hr); goto ErrorExit; } // // Return previously set URL retrieval timeout to caller. // *pVal = m_dwUrlRetrievalTimeout; } catch(...) { hr = E_POINTER; DebugTrace("Exception: invalid parameter.\n"); goto ErrorExit; } UnlockExit: // // Unlock access to this object. // m_Lock.Unlock(); DebugTrace("Leaving CCertificateStatus::get_UrlRetrievalTimeout().\n"); return hr; ErrorExit: // // Sanity check. // ATLASSERT(FAILED(hr)); ReportError(hr); goto UnlockExit; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Function : CCertificateStatus::put_UrlRetrievalTimeout Synopsis : Set the URL retrieval timeout value in seconds. Parameter: long newVal - New URL retrieval timeout value.. Remark : ------------------------------------------------------------------------------*/ STDMETHODIMP CCertificateStatus::put_UrlRetrievalTimeout (long newVal) { HRESULT hr = S_OK; DebugTrace("Entering CCertificateStatus::put_UrlRetrievalTimeout().\n"); try { // // Lock access to this object. // m_Lock.Lock(); // // Make sure paremeters are valid. // if (CAPICOM_MAX_URL_RETRIEVAL_TIMEOUT < (DWORD) newVal) { hr = E_INVALIDARG; DebugTrace("Error [%#x]: newVal (%#x) is greater than max retrieval timeout allowed.\n", hr, newVal); goto ErrorExit; } // // Update URL retrieval timeout. // m_dwUrlRetrievalTimeout = newVal; } catch(...) { hr = E_POINTER; DebugTrace("Exception: invalid parameter.\n"); goto ErrorExit; } UnlockExit: // // Unlock access to this object. // m_Lock.Unlock(); DebugTrace("Leaving CCertificateStatus::put_UrlRetrievalTimeout().\n"); return hr; ErrorExit: // // Sanity check. // ATLASSERT(FAILED(hr)); ReportError(hr); goto UnlockExit; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Function : CCertificateStatus::CertificatePolicies Synopsis : Return the certificate policies OIDs collection for which this chain is valid. Parameter: IOID ** pVal - Pointer to pointer to IOIDs to receive the interface pointer. Remark : ------------------------------------------------------------------------------*/ STDMETHODIMP CCertificateStatus::CertificatePolicies (IOIDs ** pVal) { HRESULT hr = S_OK; DebugTrace("Entering CCertificateStatus::CertificatePolicies().\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; } // // Sanity check. // ATLASSERT(m_pICertificatePolicies); // // Return interface pointer to user. // if (FAILED(hr = m_pICertificatePolicies->QueryInterface(pVal))) { DebugTrace("Error [%#x]: m_pICertificatePolicies->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 CCertificateStatus::CertificatePolicies().\n"); return hr; ErrorExit: // // Sanity check. // ATLASSERT(FAILED(hr)); ReportError(hr); goto UnlockExit; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Function : CCertificateStatus::ApplicationPolicies Synopsis : Return the application policies OIDs collection for which this chain is valid. Parameter: IOID ** pVal - Pointer to pointer to IOIDs to receive the interface pointer. Remark : ------------------------------------------------------------------------------*/ STDMETHODIMP CCertificateStatus::ApplicationPolicies (IOIDs ** pVal) { HRESULT hr = S_OK; DebugTrace("Entering CCertificateStatus::ApplicationPolicies().\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; } // // Sanity check. // ATLASSERT(m_pIApplicationPolicies); // // Return interface pointer to user. // if (FAILED(hr = m_pIApplicationPolicies->QueryInterface(pVal))) { DebugTrace("Error [%#x]: m_pIApplicationPolicies->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 CCertificateStatus::ApplicationPolicies().\n"); return hr; ErrorExit: // // Sanity check. // ATLASSERT(FAILED(hr)); ReportError(hr); goto UnlockExit; } //////////////////////////////////////////////////////////////////////////////// // // Private methods. // /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Function : CCertificateStatus::Init Synopsis : Initialize the object. Parameter: PCCERT_CONTEXT pCertContext - Pointer to CERT_CONTEXT. 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 with CERT_CONTEXT. 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 CCertificateStatus::Init (PCCERT_CONTEXT pCertContext) { HRESULT hr = S_OK; CERT_ENHKEY_USAGE eku = {0, NULL}; DebugTrace("Entering CCertificateStatus::Init().\n"); // // Sanity check. // ATLASSERT(pCertContext); // // Set default check flags. // m_CheckFlag = DEFAULT_CHECK_FLAGS; // // Create the EKU object (default no EKU check). // if (FAILED(hr = ::CreateEKUObject(NULL, &m_pIEKU))) { DebugTrace("Error [%#x]: CreateEKUObject() failed.\n", hr); goto CommonExit; } // // Create the OIDs collection for certificate policies. // if (FAILED(hr = ::CreateOIDsObject(&eku, TRUE, &m_pICertificatePolicies))) { DebugTrace("Error [%#x]: CreateOIDsObject() failed.\n", hr); goto CommonExit; } // // Create the OIDs collection for application policies. // if (FAILED(hr = ::CreateOIDsObject(&eku, FALSE, &m_pIApplicationPolicies))) { DebugTrace("Error [%#x]: CreateOIDsObject() failed.\n", hr); goto CommonExit; } // // Save cert context. // if (!(m_pCertContext = ::CertDuplicateCertificateContext(pCertContext))) { hr = HRESULT_FROM_WIN32(::GetLastError()); DebugTrace("Error [%#x]: CertDuplicateCertificateContext() failed.\n", hr); } m_VerificationTime = (DATE) 0; m_dwUrlRetrievalTimeout = 0; CommonExit: DebugTrace("Leaving CCertificateStatus::Init().\n"); return hr; }