/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Microsoft Windows, Copyright (C) Microsoft Corporation, 2000 File: EncodedData.cpp Content: Implementation of CEncodedData. History: 06-15-2001 dsie created ------------------------------------------------------------------------------*/ #include "StdAfx.h" #include "CAPICOM.h" #include "EncodedData.h" #include "Convert.h" #include "Decoder.h" #include "OID.h" //////////////////////////////////////////////////////////////////////////////// // // Exported functions. // /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Function : CreateEncodedDataObject Synopsis : Create and initialize an CEncodedData object. Parameter: LPSTR pszOid - Pointer to OID string. CRYPT_DATA_BLOB * pEncodedBlob - Pointer to encoded data blob. IEncodedData ** ppIEncodedData - Pointer to pointer IEncodedData object. Remark : ------------------------------------------------------------------------------*/ HRESULT CreateEncodedDataObject (LPSTR pszOid, CRYPT_DATA_BLOB * pEncodedBlob, IEncodedData ** ppIEncodedData) { HRESULT hr = S_OK; CComObject * pCEncodedData = NULL; DebugTrace("Entering CreateEncodedDataObject().\n"); // // Sanity check. // ATLASSERT(pszOid); ATLASSERT(pEncodedBlob); ATLASSERT(ppIEncodedData); try { // // Create the object. Note that the ref count will still be 0 // after the object is created. // if (FAILED(hr = CComObject::CreateInstance(&pCEncodedData))) { DebugTrace("Error [%#x]: CComObject::CreateInstance() failed.\n", hr); goto ErrorExit; } // // Initialize object. // if (FAILED(hr = pCEncodedData->Init(pszOid, pEncodedBlob))) { DebugTrace("Error [%#x]: pCEncodedData->Init() failed.\n", hr); goto ErrorExit; } // // Return interface pointer to caller. // if (FAILED(hr = pCEncodedData->QueryInterface(ppIEncodedData))) { DebugTrace("Error [%#x]: pCEncodedData->QueryInterface() failed.\n", hr); goto ErrorExit; } } catch(...) { hr = E_POINTER; DebugTrace("Exception: invalid parameter.\n"); goto ErrorExit; } CommonExit: DebugTrace("Leaving CreateEncodedDataObject().\n"); return hr; ErrorExit: // // Sanity check. // ATLASSERT(FAILED(hr)); if (pCEncodedData) { delete pCEncodedData; } goto CommonExit; } //////////////////////////////////////////////////////////////////////////////// // // CEncodedData // /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Function : CEncodedData::get_Value Synopsis : Return the encoded data. Parameter: CAPICOM_ENCODING_TYPE EncodingType - Encoding type. BSTR * pVal - Pointer to BSTR to receive the EncodedData blob. Remark : NOTE : The OID is not exported, so it is up to the caller to corelate the blob to the proper OID it represents. ------------------------------------------------------------------------------*/ STDMETHODIMP CEncodedData::get_Value (CAPICOM_ENCODING_TYPE EncodingType, BSTR * pVal) { HRESULT hr = S_OK; DebugTrace("Entering CEncodedData::get_Value().\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_pszOid); ATLASSERT(m_EncodedBlob.cbData); ATLASSERT(m_EncodedBlob.pbData); // // Export EncodedData. // if (FAILED(hr = ::ExportData(m_EncodedBlob, 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 CEncodedData::get_Value().\n"); return hr; ErrorExit: // // Sanity check. // ATLASSERT(FAILED(hr)); ReportError(hr); goto UnlockExit; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Function : CEncodedData::Format Synopsis : Format the encoded data. Parameter: VARIANT_BOOL bMultiLines - True for multi-lines format. BSTR * pVal - Pointer to BSTR to receive formatted output. Remark : ------------------------------------------------------------------------------*/ STDMETHODIMP CEncodedData::Format (VARIANT_BOOL bMultiLines, BSTR * pVal) { HRESULT hr = S_OK; DWORD cbFormat = 0; LPWSTR pwszFormat = NULL; DebugTrace("Entering CEncodedData::Format().\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_pszOid); ATLASSERT(m_EncodedBlob.cbData); ATLASSERT(m_EncodedBlob.pbData); // // Format. // if (!::CryptFormatObject(X509_ASN_ENCODING, 0, bMultiLines ? CRYPT_FORMAT_STR_MULTI_LINE : 0, NULL, m_pszOid, m_EncodedBlob.pbData, m_EncodedBlob.cbData, NULL, &cbFormat)) { hr = HRESULT_FROM_WIN32(::GetLastError()); DebugTrace("Info [%#x]: CryptFormatObject() failed to get size, so converting to hex.\n", hr); // // Most likely CryptFormatObject() does not understand the OID (downlevel platforms), // so try to convert it to hex ourselves. // if (FAILED(hr = ::BinaryToString(m_EncodedBlob.pbData, m_EncodedBlob.cbData, CRYPT_STRING_HEX, &*pVal, NULL))) { DebugTrace("Error [%#x]: BinaryToString() failed.\n", hr); goto ErrorExit; } goto UnlockExit; } if (!(pwszFormat = (LPWSTR) ::CoTaskMemAlloc(cbFormat))) { hr = E_OUTOFMEMORY; DebugTrace("Error: out of memory.\n"); goto ErrorExit; } if (!::CryptFormatObject(X509_ASN_ENCODING, 0, bMultiLines ? CRYPT_FORMAT_STR_MULTI_LINE : 0, NULL, m_pszOid, m_EncodedBlob.pbData, m_EncodedBlob.cbData, (LPVOID) pwszFormat, &cbFormat)) { hr = HRESULT_FROM_WIN32(::GetLastError()); DebugTrace("Error [%#x]: CryptFormatObject() failed to get data.\n", hr); goto ErrorExit; } // // Return formatted string to caller. // if (!(*pVal = ::SysAllocString(pwszFormat))) { hr = E_OUTOFMEMORY; DebugTrace("Error: out of memory.\n"); goto ErrorExit; } } catch(...) { hr = E_POINTER; DebugTrace("Exception: invalid parameter.\n"); goto ErrorExit; } UnlockExit: // // Free resources. // if (pwszFormat) { ::CoTaskMemFree((LPVOID) pwszFormat); } // // Unlock access to this object. // m_Lock.Unlock(); DebugTrace("Leaving CEncodedData::Format().\n"); return hr; ErrorExit: // // Sanity check. // ATLASSERT(FAILED(hr)); ReportError(hr); goto UnlockExit; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Function : CEncodedData::Decoder Synopsis : Return the decoder object. Parameter: IDispatch ** pVal - Pointer to pointer to IDispatch to receive the decoder object. Remark : Not all EncodedData has an associated decoder. CAPICOM only provides certain decoders. ------------------------------------------------------------------------------*/ STDMETHODIMP CEncodedData::Decoder (IDispatch ** pVal) { HRESULT hr = S_OK; DebugTrace("Entering CEncodedData::Decoder().\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; } #if (0) // DSIE: is only created by us, so it is always initialized. // // Make sure object is already initialized. // if (!m_pszOid) { hr = CAPICOM_E_ENCODE_NOT_INITIALIZED; DebugTrace("Error [%#x]: encode object has not been initialized.\n", hr); goto ErrorExit; } #endif // // Sanity check. // ATLASSERT(m_pszOid); ATLASSERT(m_EncodedBlob.cbData); ATLASSERT(m_EncodedBlob.pbData); // // Do we have a decoder? // if (!m_pIDecoder) { // // Attempt to create one. // if (FAILED(hr = ::CreateDecoderObject(m_pszOid, &m_EncodedBlob, &m_pIDecoder))) { DebugTrace("Error [%#x]: CreateDecoderObject() failed for OID = %s.\n", hr, m_pszOid); goto ErrorExit; } // // Did we get a decoder? if (!m_pIDecoder) { DebugTrace("Info: no decoder found for OID = %s.\n", hr, m_pszOid); goto UnlockExit; } } // // Return result. // if (FAILED(hr = m_pIDecoder->QueryInterface(pVal))) { DebugTrace("Error [%#x]: m_pIDecoder->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 CEncodedData::Decoder().\n"); return hr; ErrorExit: // // Sanity check. // ATLASSERT(FAILED(hr)); ReportError(hr); goto UnlockExit; } //////////////////////////////////////////////////////////////////////////////// // // Private methods. // /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Function : CEncodedData::Init Synopsis : Initialize the object. Parameter: LPSTR pszOid - Pointer to OID string. CRYPT_DATA_BLOB * pEncodedBlob - Pointer to encoded data blob. 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 CEncodedData::Init (LPSTR pszOid, CRYPT_DATA_BLOB * pEncodedBlob) { HRESULT hr = S_OK; LPSTR pszOid2 = NULL; PBYTE pbEncodedData = NULL; DebugTrace("Entering CEncodedData::Init().\n"); // // Sanity check. // ATLASSERT(pszOid); ATLASSERT(pEncodedBlob); ATLASSERT(pEncodedBlob->cbData); ATLASSERT(pEncodedBlob->pbData); // // Allocate memory for OID. // if (NULL == (pszOid2 = (LPSTR) ::CoTaskMemAlloc(::strlen(pszOid) + 1))) { hr = E_OUTOFMEMORY; DebugTrace("Error [%#x]: CoTaskMemAlloc() failed.\n", hr); goto ErrorExit; } // // Copy. // ::strcpy(pszOid2, pszOid); // // Allocate memory for encoded blob. // if (NULL == (pbEncodedData = (PBYTE) ::CoTaskMemAlloc(pEncodedBlob->cbData))) { hr = E_OUTOFMEMORY; DebugTrace("Error [%#x]: CoTaskMemAlloc() failed.\n", hr); goto ErrorExit; } // // Copy. // ::CopyMemory(pbEncodedData, pEncodedBlob->pbData, pEncodedBlob->cbData); // // Update states. // m_pszOid = pszOid2; m_pIDecoder = NULL; m_EncodedBlob.cbData = pEncodedBlob->cbData; m_EncodedBlob.pbData = pbEncodedData; CommonExit: DebugTrace("Leaving CEncodedData::Init().\n"); return hr; ErrorExit: // // Sanity check. // ATLASSERT(FAILED(hr)); // // Free resources. // if (pszOid2) { ::CoTaskMemFree(pszOid2); } if (pbEncodedData) { ::CoTaskMemFree(pbEncodedData); } goto CommonExit; }