//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1997-2002. // // File: Certifct.cpp // // Contents: Implementation of CCertmgrApp and DLL registration. // //---------------------------------------------------------------------------- #include "stdafx.h" #include "Certifct.h" #ifdef _DEBUG #ifndef ALPHA #define new DEBUG_NEW #endif #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif USE_HANDLE_MACROS("CERTMGR(Certifct.cpp)") ///////////////////////////////////////////////////////////////////////////// // const int FIELD_ISSUER_ALT_NAME = 0x00000001; const int FIELD_SUBJECT_ALT_NAME = 0x00000002; const int FIELD_CAN_DELETE = 0x00000004; const int FIELD_IS_ARCHIVED = 0x00000008; const int FIELD_TEMPLATE_NAME = 0x00000010; CCertificate::CCertificate(const PCCERT_CONTEXT pCertContext, CCertStore* pCertStore) : CCertMgrCookie (CERTMGR_CERTIFICATE), m_pCertContext (::CertDuplicateCertificateContext (pCertContext)), m_pCertInfo (0), m_fieldChecked (0), m_pCertStore (pCertStore), m_bCanDelete (false), m_bIsArchived (false) { // _TRACE (1, L"Entering CCertificate::CCertificate\n"); ASSERT (CERTMGR_CERTIFICATE == m_objecttype); ASSERT (m_pCertStore); if ( m_pCertStore ) m_pCertStore->AddRef (); ASSERT (m_pCertContext); if ( m_pCertContext ) m_pCertInfo = m_pCertContext->pCertInfo; // _TRACE (-1, L"Leaving CCertificate::CCertificate\n"); } CCertificate::~CCertificate() { // _TRACE (1, L"Entering CCertificate::~CCertificate\n"); ASSERT (CERTMGR_CERTIFICATE == m_objecttype); if ( m_pCertContext ) ::CertFreeCertificateContext (m_pCertContext); if ( m_pCertStore ) m_pCertStore->Release (); // _TRACE (-1, L"Leaving CCertificate::~CCertificate\n"); } CString CCertificate::GetFriendlyName () { // _TRACE (1, L"Entering CCertificate::GetFriendlyName\n"); ASSERT (CERTMGR_CERTIFICATE == m_objecttype); ASSERT (m_pCertContext); if ( m_pCertContext && m_szFriendlyName.IsEmpty () ) { AFX_MANAGE_STATE (AfxGetStaticModuleState ()); DWORD cbData = 0; BOOL bResult = ::CertGetCertificateContextProperty ( m_pCertContext, CERT_FRIENDLY_NAME_PROP_ID, NULL, &cbData); if ( bResult ) { LPWSTR pszName = new WCHAR[cbData]; if ( pszName ) { // security review 2/22/2002 BryanWal ok ::ZeroMemory (pszName, cbData*sizeof (WCHAR)); bResult = ::CertGetCertificateContextProperty ( m_pCertContext, CERT_FRIENDLY_NAME_PROP_ID, pszName, &cbData); ASSERT (bResult); if ( bResult ) { m_szFriendlyName = pszName; } else { VERIFY (m_szFriendlyName.LoadString (IDS_NOT_AVAILABLE)); } delete [] pszName; } } else { if ( GetLastError () == CRYPT_E_NOT_FOUND ) { VERIFY (m_szFriendlyName.LoadString (IDS_NONE)); } else { ASSERT (0); VERIFY (m_szFriendlyName.LoadString (IDS_NOT_AVAILABLE)); } } } // _TRACE (-1, L"Leaving CCertificate::GetFriendlyName\n"); return m_szFriendlyName; } CString CCertificate::GetIssuerName () { // _TRACE (1, L"Entering CCertificate::GetIssuerName\n"); ASSERT (CERTMGR_CERTIFICATE == m_objecttype); ASSERT (m_pCertInfo); if ( m_pCertInfo ) { // Decode issuer name if not already present if ( m_szIssuerName.IsEmpty () ) { m_szIssuerName = ::GetNameString (m_pCertContext, CERT_NAME_ISSUER_FLAG); } } else return _T(""); // _TRACE (-1, L"Leaving CCertificate::GetIssuerName\n"); return m_szIssuerName; } /////////////////////////////////////////////////////////////////////////// // GetSubjectName () // // pszName (IN / OPTIONAL) - returns the alternate issuer name. An empty // string is a valid return value // cbName (IN / OUT) - If pszName is NULL, then the required length // of pszName is returned. // Otherwise, contains the length of pszName. /////////////////////////////////////////////////////////////////////////// CString CCertificate::GetSubjectName() { // _TRACE (1, L"Entering CCertificate::GetSubjectName\n"); ASSERT (CERTMGR_CERTIFICATE == m_objecttype); ASSERT (m_pCertInfo); if ( m_pCertInfo ) { // Decode subject name if not already present if ( m_szSubjectName.IsEmpty () ) { m_szSubjectName = ::GetNameString (m_pCertContext, 0); } } else return _T(""); // _TRACE (-1, L"Leaving CCertificate::GetSubjectName\n"); return m_szSubjectName; } /////////////////////////////////////////////////////////////////////////// // GetValidNotBefore () // // pszDateTime (IN / OPTIONAL) - returns the formatted date and time. // cbDateTime (IN / OUT) - If pszDateTime is NULL, then the required length // of pszDateTime is returned. // Otherwise, contains the length of pszDateTime. /////////////////////////////////////////////////////////////////////////// CString CCertificate::GetValidNotBefore() { // _TRACE (1, L"Entering CCertificate::GetValidNotBefore\n"); ASSERT (CERTMGR_CERTIFICATE == m_objecttype); ASSERT (m_pCertInfo); if ( m_pCertInfo ) { // Format date/time string if not already present if ( m_szValidNotBefore.IsEmpty () ) { HRESULT hr = FormatDate (m_pCertInfo->NotBefore, m_szValidNotBefore); if ( !SUCCEEDED (hr) ) return _T(""); } } else return _T(""); // _TRACE (-1, L"Leaving CCertificate::GetValidNotBefore\n"); return m_szValidNotBefore; } /////////////////////////////////////////////////////////////////////////// // GetValidNotAfter () // // pszDateTime (IN / OPTIONAL) - returns the formatted date and time. // cbDateTime (IN / OUT) - If pszDateTime is NULL, then the required length // of pszDateTime is returned. // Otherwise, contains the length of pszDateTime. /////////////////////////////////////////////////////////////////////////// CString CCertificate::GetValidNotAfter () { // _TRACE (1, L"Entering CCertificate::GetValidNotAfter\n"); ASSERT (CERTMGR_CERTIFICATE == m_objecttype); ASSERT (m_pCertInfo); if ( m_pCertInfo ) { // Format date/time string if not already present if ( m_szValidNotAfter.IsEmpty () ) { HRESULT hr = FormatDate (m_pCertInfo->NotAfter, m_szValidNotAfter); if ( !SUCCEEDED (hr) ) m_szValidNotAfter = _T(""); } } else m_szValidNotAfter = _T(""); // _TRACE (-1, L"Leaving CCertificate::GetValidNotAfter\n"); return m_szValidNotAfter; } CString CCertificate::GetEnhancedKeyUsage () { // _TRACE (1, L"Entering CCertificate::GetEnhancedKeyUsage\n"); ASSERT (CERTMGR_CERTIFICATE == m_objecttype); ASSERT (m_pCertInfo); if ( m_pCertInfo ) { // Format date/time string if not already present if ( m_szEnhancedKeyUsage.IsEmpty () ) { FormatEnhancedKeyUsagePropertyString ( m_szEnhancedKeyUsage); } } else m_szEnhancedKeyUsage = _T(""); // _TRACE (-1, L"Leaving CCertificate::GetEnhancedKeyUsage\n"); return m_szEnhancedKeyUsage; } bool CCertificate::FormatEnhancedKeyUsagePropertyString (CString& string) { // _TRACE (1, L"Entering CCertificate::FormatEnhancedKeyUsagePropertyString\n"); AFX_MANAGE_STATE(AfxGetStaticModuleState()); ASSERT (CERTMGR_CERTIFICATE == m_objecttype); BOOL bReturn = TRUE; DWORD cbUsage = 0; bReturn = ::CertGetEnhancedKeyUsage (m_pCertContext, 0, // get extension and property NULL, &cbUsage); if ( bReturn ) { CString usageName; PCERT_ENHKEY_USAGE pUsage = (PCERT_ENHKEY_USAGE) ::LocalAlloc (LPTR, cbUsage); if ( pUsage ) { bReturn = ::CertGetEnhancedKeyUsage (m_pCertContext, 0, // get extension and property pUsage, &cbUsage); if ( bReturn ) { if ( !pUsage->cUsageIdentifier ) { switch (GetLastError ()) { case CRYPT_E_NOT_FOUND: VERIFY (string.LoadString (IDS_ANY)); break; case 0: VERIFY (string.LoadString (IDS_NONE)); break; default: break; } } else { for (DWORD dwIndex = 0; dwIndex < pUsage->cUsageIdentifier; dwIndex++) { if ( MyGetOIDInfo (usageName, pUsage->rgpszUsageIdentifier[dwIndex]) ) { // add delimeter if not first iteration if ( dwIndex ) string += _T(", "); string += usageName; } } } } else { switch (GetLastError ()) { case CRYPT_E_NOT_FOUND: VERIFY (string.LoadString (IDS_ANY)); break; case 0: VERIFY (string.LoadString (IDS_NONE)); break; default: break; } } ::LocalFree (pUsage); } else { bReturn = FALSE; } } else { switch (GetLastError ()) { case CRYPT_E_NOT_FOUND: VERIFY (string.LoadString (IDS_ANY)); break; case 0: VERIFY (string.LoadString (IDS_NONE)); break; default: break; } } // _TRACE (-1, L"Leaving CCertificate::FormatEnhancedKeyUsagePropertyString\n"); return bReturn ? true : false; } /////////////////////////////////////////////////////////////////////////// // GetAlternateIssuerName () // // pszName (IN / OPTIONAL) - returns the alternate issuer name. An empty // string is a valid return value // cbName (IN / OUT) - If pszName is NULL, then the required length // of pszName is returned. // Otherwise, contains the length of pszName. /////////////////////////////////////////////////////////////////////////// CString CCertificate::GetAlternateIssuerName () { // _TRACE (1, L"Entering CCertificate::GetAlternateIssuerName\n"); ASSERT (CERTMGR_CERTIFICATE == m_objecttype); ASSERT (m_pCertInfo); if ( m_pCertInfo ) { if ( !(m_fieldChecked & FIELD_ISSUER_ALT_NAME) ) { HRESULT hr = ConvertAltNameToString (_T(szOID_ISSUER_ALT_NAME), CERT_ALT_NAME_URL, m_szAltIssuerName); ASSERT (SUCCEEDED (hr)); if ( !SUCCEEDED (hr) ) m_szAltIssuerName = _T(""); m_fieldChecked |= FIELD_ISSUER_ALT_NAME; } } else m_szAltIssuerName = _T(""); // _TRACE (-1, L"Leaving CCertificate::GetAlternateIssuerName\n"); return m_szAltIssuerName; } /////////////////////////////////////////////////////////////////////////// // GetAlternateSubjectName () // // pszName (IN / OPTIONAL) - returns the alternate issuer name. An empty // string is a valid return value // cbName (IN / OUT) - If pszName is NULL, then the required length // of pszName is returned. // Otherwise, contains the length of pszName. /////////////////////////////////////////////////////////////////////////// CString CCertificate::GetAlternateSubjectName () { // _TRACE (1, L"Entering CCertificate::GetAlternateSubjectName\n"); ASSERT (CERTMGR_CERTIFICATE == m_objecttype); ASSERT (m_pCertInfo); if ( m_pCertInfo ) { if ( !(m_fieldChecked & FIELD_SUBJECT_ALT_NAME) ) { HRESULT hr = ConvertAltNameToString (_T(szOID_SUBJECT_ALT_NAME), CERT_ALT_NAME_URL, m_szAltSubjectName); if ( !SUCCEEDED (hr) ) m_szAltSubjectName = _T(""); m_fieldChecked |= FIELD_SUBJECT_ALT_NAME; } } else m_szAltSubjectName = _T(""); // _TRACE (-1, L"Leaving CCertificate::GetAlternateSubjectName\n"); return m_szAltSubjectName; } /////////////////////////////////////////////////////////////////////////// // GetSerialNumber () // // pszSerNum (IN / OPTIONAL) - returns the alternate issuer name. An empty // string is a valid return value // cbSerNum (IN / OUT) - If pszSerNum is NULL, then the required length // of pszSerNum is returned. // Otherwise, contains the length of pszSerNum. /////////////////////////////////////////////////////////////////////////// CString CCertificate::GetSerialNumber () { // _TRACE (1, L"Entering CCertificate::GetSerialNumber\n"); ASSERT (CERTMGR_CERTIFICATE == m_objecttype); ASSERT (m_pCertInfo); if ( m_pCertInfo ) { // Decode issuer name if not already present if ( m_szSerNum.IsEmpty () ) { LPWSTR pwszText = 0; if ( SUCCEEDED (FormatSerialNoString (&pwszText, & (m_pCertInfo->SerialNumber))) ) { m_szSerNum = pwszText; CoTaskMemFree (pwszText); } } } else m_szSerNum = _T(""); // _TRACE (-1, L"Leaving CCertificate::GetSerialNumber\n"); return m_szSerNum; } ////////////////////////////////////////////////////////////////////////////// // ConvertAltNameToString () // // pszOID (IN) - The OID of the alternate name to retrieve // dwNameChoice (IN) - The type of alternate name to return // altName (OUT) - The version of the desired alternate name indicated // by dwNameChoice ////////////////////////////////////////////////////////////////////////////// HRESULT CCertificate::ConvertAltNameToString(LPCWSTR pszOID, const DWORD dwNameChoice, CString & altName) { // _TRACE (1, L"Entering CCertificate::ConvertAltNameToString\n"); ASSERT (CERTMGR_CERTIFICATE == m_objecttype); HRESULT hr = S_OK; ASSERT (pszOID); if ( !pszOID ) return E_POINTER; // Iterate through the extensions until the one indicated by the // passed-in pszOID is found. for (DWORD index = 0; index < m_pCertInfo->cExtension; index++) { ASSERT (m_pCertInfo->rgExtension); if ( !m_pCertInfo->rgExtension ) { hr = E_FAIL; break; } // security review 2/22/2002 BryanWal ok size_t len = strlen (m_pCertInfo->rgExtension[index].pszObjId); LPWSTR wcsObjId = new WCHAR[len+1]; if ( wcsObjId ) { // security review BryanWal 02/02/2002 ok ::ZeroMemory (wcsObjId, (len + 1) * sizeof (WCHAR)); // security review 2/22/2002 BryanWal ok mbstowcs (wcsObjId, m_pCertInfo->rgExtension[index].pszObjId, len+1); // last arg includes NULL terminator if ( !wcscmp (wcsObjId, pszOID) ) { CERT_ALT_NAME_INFO nameInfo; DWORD cbNameInfo = sizeof (CERT_ALT_NAME_INFO); BOOL bResult = CryptDecodeObject( MY_ENCODING_TYPE, X509_ALTERNATE_NAME, // in m_pCertInfo->rgExtension[index].Value.pbData, // in m_pCertInfo->rgExtension[index].Value.cbData, // in 0, // in (void *) &nameInfo, // out &cbNameInfo); // in/out ASSERT (bResult); if ( bResult ) { // We've found the right extension, now iterate through // the alternate names until we find the desired type. for (DWORD dwAltEntryIndex = 0; dwAltEntryIndex < nameInfo.cAltEntry; dwAltEntryIndex++) { if ( nameInfo.rgAltEntry[dwAltEntryIndex].dwAltNameChoice == dwNameChoice ) { altName = nameInfo.rgAltEntry[dwAltEntryIndex].pwszURL; break; } } } else hr = E_UNEXPECTED; break; } delete [] wcsObjId; } else { hr = E_OUTOFMEMORY; } } // _TRACE (-1, L"Leaving CCertificate::ConvertAltNameToString\n"); return hr; } CCertStore* CCertificate::GetCertStore() const { // _TRACE (0, L"Entering and leaving CCertificate::GetCertStore\n"); ASSERT (CERTMGR_CERTIFICATE == m_objecttype); return m_pCertStore; } PCCERT_CONTEXT CCertificate::GetCertContext() const { // _TRACE (0, L"Entering and leaving CCertificate::GetCertContext\n"); ASSERT (CERTMGR_CERTIFICATE == m_objecttype); return m_pCertContext; } bool CCertificate::IsValid() { // _TRACE (1, L"Entering CCertificate::IsValid\n"); ASSERT (CERTMGR_CERTIFICATE == m_objecttype); bool bIsValid = false; ASSERT (m_pCertInfo); if ( m_pCertInfo ) { FILETIME systemTime; ::GetSystemTimeAsFileTime (&systemTime); LONG lBefore = ::CompareFileTime (&m_pCertInfo->NotBefore, &systemTime); LONG lAfter = ::CompareFileTime (&systemTime, &m_pCertInfo->NotAfter); if ( lBefore < 1 && lAfter < 1 ) bIsValid = true; } // _TRACE (-1, L"Leaving CCertificate::IsValid\n"); return bIsValid; } const SPECIAL_STORE_TYPE CCertificate::GetStoreType () const { // _TRACE (0, L"Entering and leaving CCertificate::GetStoreType\n"); ASSERT (CERTMGR_CERTIFICATE == m_objecttype); if ( m_pCertStore ) return m_pCertStore->GetStoreType (); else return NO_SPECIAL_TYPE; } void CCertificate::Refresh() { // _TRACE (1, L"Entering CCertificate::Refresh\n"); ASSERT (CERTMGR_CERTIFICATE == m_objecttype); // Clearing all fields forces rereading of the data. m_szAltIssuerName = L""; m_szAltSubjectName = L""; m_szAuthorityKeyID = L""; m_szEnhancedKeyUsage = L""; m_szFriendlyName = L""; m_szIssuerName = L""; m_szMD5Hash = L""; m_szPolicyURL = L""; m_szSerNum = L""; m_szSHAHash = L""; m_szSubjectKeyID = L""; m_szSubjectName = L""; m_szValidNotAfter = L""; m_szValidNotBefore = L""; m_fieldChecked = 0; // _TRACE (-1, L"Leaving CCertificate::Refresh\n"); } CString CCertificate::GetMD5Hash() { // _TRACE (1, L"Entering CCertificate::GetMD5Hash\n"); ASSERT (CERTMGR_CERTIFICATE == m_objecttype); ASSERT (m_pCertContext); if ( m_pCertContext && m_szMD5Hash.IsEmpty ()) { m_szMD5Hash = GetGenericHash (CERT_MD5_HASH_PROP_ID); } // _TRACE (-1, L"Leaving CCertificate::GetMD5Hash\n"); return m_szMD5Hash; } CString CCertificate::GetSHAHash() { // _TRACE (1, L"Entering CCertificate::GetSHAHash\n"); ASSERT (CERTMGR_CERTIFICATE == m_objecttype); ASSERT (m_pCertContext); if ( m_pCertContext && m_szSHAHash.IsEmpty ()) { m_szSHAHash = GetGenericHash (CERT_SHA1_HASH_PROP_ID); } // _TRACE (-1, L"Leaving CCertificate::GetSHAHash\n"); return m_szSHAHash; } CString CCertificate::GetGenericHash(DWORD dwPropId) { // _TRACE (1, L"Entering CCertificate::GetGenericHash\n"); ASSERT (CERTMGR_CERTIFICATE == m_objecttype); CString szHash; DWORD cbData = 0; BOOL bReturn = ::CertGetCertificateContextProperty ( m_pCertContext, dwPropId, NULL, &cbData); if ( bReturn ) { cbData += 2; // for null terminator BYTE* pCertHash = new BYTE[cbData]; if ( pCertHash ) { // security review 2/22/2002 BryanWal ok ::ZeroMemory (pCertHash, cbData); bReturn = CertGetCertificateContextProperty ( m_pCertContext, dwPropId, pCertHash, &cbData); ASSERT (bReturn); if ( bReturn ) { DataToHex (pCertHash, szHash, cbData, false); } delete [] pCertHash; } } // _TRACE (-1, L"Leaving CCertificate::GetGenericHash\n"); return szHash; } int CCertificate::CompareExpireDate(const CCertificate & cert) const { // _TRACE (1, L"Entering CCertificate::CompareExpireDate\n"); ASSERT (CERTMGR_CERTIFICATE == m_objecttype); int compVal = 0; ASSERT (m_pCertInfo && cert.m_pCertInfo); if ( m_pCertInfo && cert.m_pCertInfo ) { compVal = ::CompareFileTime (&m_pCertInfo->NotAfter, &cert.m_pCertInfo->NotAfter); } // _TRACE (-1, L"Leaving CCertificate::CompareExpireDate\n"); return compVal; } bool CCertificate::CanDelete() { // _TRACE (1, L"Entering CCertificate::CanDelete\n"); if ( m_pCertContext && !(m_fieldChecked & FIELD_CAN_DELETE) ) { DWORD dwAccessFlags = 0; DWORD cbData = sizeof (DWORD); BOOL bResult = ::CertGetCertificateContextProperty ( m_pCertContext, CERT_ACCESS_STATE_PROP_ID, &dwAccessFlags, &cbData); if ( bResult ) { if ( dwAccessFlags & CERT_ACCESS_STATE_WRITE_PERSIST_FLAG ) m_bCanDelete = true; } m_fieldChecked |= FIELD_CAN_DELETE; } // _TRACE (-1, L"Leaving CCertificate::CanDelete\n"); return m_bCanDelete; } bool CCertificate::IsReadOnly() { bool bResult = false; if ( m_pCertStore ) bResult = (m_pCertStore->IsReadOnly () || !CanDelete ()); return bResult; } bool CCertificate::IsArchived() { // _TRACE (1, L"Entering CCertificate::IsArchived\n"); if ( m_pCertContext && !(m_fieldChecked & FIELD_IS_ARCHIVED) ) { DWORD cbData = sizeof (DWORD); BOOL bResult = ::CertGetCertificateContextProperty ( m_pCertContext, CERT_ARCHIVED_PROP_ID, NULL, &cbData); if ( bResult ) { m_bIsArchived = true; } else m_bIsArchived = false; m_fieldChecked |= FIELD_IS_ARCHIVED; } // _TRACE (-1, L"Leaving CCertificate::IsArchived\n"); return m_bIsArchived; } BOOL CCertificate::DeleteFromStore(bool bDoCommit) { _TRACE (1, L"Entering CCertificate::DeleteFromStore\n"); BOOL bResult = FALSE; if ( m_pCertStore ) { PCCERT_CONTEXT pCertContext = GetNewCertContext (); if ( pCertContext ) { bResult = ::CertDeleteCertificateFromStore (pCertContext); if ( bResult ) { m_pCertStore->InvalidateCertCount (); m_pCertStore->SetDirty (); if ( bDoCommit ) { m_pCertStore->SetDeleting (); HRESULT hr = m_pCertStore->Commit (); m_pCertStore->SetAdding (); if ( SUCCEEDED (hr) ) m_pCertStore->Resync (); else bResult = FALSE; } m_pCertStore->Release (); m_pCertStore = 0; } } } _TRACE (-1, L"Leaving CCertificate::DeleteFromStore\n"); return bResult; } PCCERT_CONTEXT CCertificate::GetNewCertContext() { PCCERT_CONTEXT pCertContext = 0; if ( m_pCertStore ) { HCERTSTORE hCertStore = m_pCertStore->GetStoreHandle (); if ( hCertStore ) { DWORD cbData = 20; BYTE certHash[20]; BOOL bReturn = ::CertGetCertificateContextProperty ( m_pCertContext, CERT_SHA1_HASH_PROP_ID, certHash, &cbData); ASSERT (bReturn); if ( bReturn ) { CRYPT_DATA_BLOB blob = {sizeof (certHash), certHash}; pCertContext = CertFindCertificateInStore( hCertStore, 0, 0, CERT_FIND_SHA1_HASH, &blob, 0); if ( pCertContext ) { ::CertFreeCertificateContext (m_pCertContext); m_pCertContext = ::CertDuplicateCertificateContext (pCertContext); } } } } return pCertContext; } CString CCertificate::FormatStatus() { CString status; // security review 2/22/2002 BryanWal ok status.FormatMessage (L"%1 %2", (IsReadOnly () ? L"R" : L" "), (IsArchived () ? L"A" : L" ")); return status; } ////////////////////////////////////////////////////////////////////////////////////// // Stolen from private\ispu\ui\cryptui\frmtutil.cpp ////////////////////////////////////////////////////////////////////////////////////// const WCHAR RgwchHex[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; HRESULT CCertificate::FormatSerialNoString(LPWSTR *ppString, CRYPT_INTEGER_BLOB const *pblob) { if ( !ppString || !pblob ) return E_POINTER; DWORD i = 0; LPBYTE pb; DWORD numCharsInserted = 0; // // calculate size needed // pb = &pblob->pbData[pblob->cbData-1]; while (pb >= &pblob->pbData[0]) { if (numCharsInserted == 4) { i += sizeof(WCHAR); numCharsInserted = 0; } else { i += 2 * sizeof(WCHAR); pb--; numCharsInserted += 2; } } if (NULL == (*ppString = (LPWSTR) CoTaskMemAlloc (i+sizeof(WCHAR)))) { return E_OUTOFMEMORY; } // fill the buffer i=0; numCharsInserted = 0; pb = &pblob->pbData[pblob->cbData-1]; while (pb >= &pblob->pbData[0]) { if (numCharsInserted == 4) { (*ppString)[i++] = L' '; numCharsInserted = 0; } else { (*ppString)[i++] = RgwchHex[(*pb & 0xf0) >> 4]; (*ppString)[i++] = RgwchHex[*pb & 0x0f]; pb--; numCharsInserted += 2; } } (*ppString)[i] = 0; return S_OK; } CString CCertificate::GetDescription() { ASSERT (CERTMGR_CERTIFICATE == m_objecttype); if ( m_pCertContext && m_szDescription.IsEmpty () ) { AFX_MANAGE_STATE (AfxGetStaticModuleState ()); DWORD cbData = 0; BOOL bResult = ::CertGetCertificateContextProperty ( m_pCertContext, CERT_DESCRIPTION_PROP_ID, NULL, &cbData); if ( bResult ) { LPWSTR pszName = new WCHAR[cbData]; if ( pszName ) { // security review 2/22/2002 BryanWal ok ::ZeroMemory (pszName, cbData*sizeof (WCHAR)); bResult = ::CertGetCertificateContextProperty ( m_pCertContext, CERT_DESCRIPTION_PROP_ID, pszName, &cbData); ASSERT (bResult); if ( bResult ) { m_szDescription = pszName; } delete [] pszName; } } else { DWORD dwErr = GetLastError (); if ( CRYPT_E_NOT_FOUND == dwErr ) { _TRACE (0, L"CertGetCertificateContextProperty (CERT_DESCRIPTION_PROP_ID) found no description.\n"); } else { _TRACE (0, L"CertGetCertificateContextProperty (CERT_DESCRIPTION_PROP_ID) failed: 0x%x\n", dwErr); } } } return m_szDescription; } HRESULT CCertificate::SetDescription(const CString &szDescription) { _TRACE (1, L"Entering CCertificate::SetDescription (%s)\n", (PCWSTR) szDescription); HRESULT hr = S_OK; CRYPT_DATA_BLOB cryptDataBlob; // security review 2/22/2002 BryanWal ok ::ZeroMemory (&cryptDataBlob, sizeof (cryptDataBlob)); cryptDataBlob.pbData = (LPBYTE) (PCWSTR) szDescription; // security review 2/22/2002 BryanWal ok cryptDataBlob.cbData = (DWORD) (wcslen (szDescription) + 1) * sizeof (WCHAR); BOOL bResult = ::CertSetCertificateContextProperty (m_pCertContext, CERT_DESCRIPTION_PROP_ID, 0, &cryptDataBlob); ASSERT (bResult); if ( bResult ) { m_szDescription = szDescription; } else { DWORD dwErr = GetLastError (); _TRACE (0, L"CertSetCertificateContextProperty (CERT_DESCRIPTION_PROP_ID, %s) failed: %d\n", (PCWSTR) szDescription, dwErr); hr = HRESULT_FROM_WIN32 (dwErr); } _TRACE (1, L"Entering CCertificate::SetDescription (%s): 0x%x\n", (PCWSTR) szDescription, hr); return hr; } HRESULT CCertificate::SetLastModified () { HRESULT hr = S_OK; if ( m_pCertContext ) { SYSTEMTIME st; FILETIME ft; GetSystemTime (&st); VERIFY (SystemTimeToFileTime(&st, &ft)); CRYPT_DATA_BLOB cryptDataBlob; // security review 2/22/2002 BryanWal ok ::ZeroMemory (&cryptDataBlob, sizeof (cryptDataBlob)); cryptDataBlob.pbData = (LPBYTE) &ft; cryptDataBlob.cbData = sizeof (FILETIME); BOOL bResult = ::CertSetCertificateContextProperty ( m_pCertContext, CERT_DATE_STAMP_PROP_ID, 0, &cryptDataBlob); ASSERT (bResult); if ( !bResult ) { DWORD dwErr = GetLastError (); _TRACE (0, L"CertSetCertificateContextProperty (CERT_DATE_STAMP_PROP_ID) failed: %d\n", dwErr); hr = HRESULT_FROM_WIN32 (dwErr); } } return hr; } CString CCertificate::GetShortLastModified () { return GetLastModified (DATE_SHORTDATE); } CString CCertificate::GetLongLastModified () { return GetLastModified (DATE_LONGDATE); } /////////////////////////////////////////////////////////////////////////////// // // Method: GetLastModified // Purpose: Get the date stamp property of the cert and format for display // Inputs: dwDateFlags - as defined in SDK, specify DATE_SHORTDATE or // DATE_LONGDATE // bRetryIfNotPresent - to prevent stack overflow. Used if the property // is not set, to set the property to the current time and // retrieve again. // // Output: locale-formatted date and time string // /////////////////////////////////////////////////////////////////////////////// CString CCertificate::GetLastModified(DWORD dwDateFlags, bool bRetryIfNotPresent /* true */) { _TRACE (1, L"Entering CCertificate::GetLastModified ()\n"); CString szDate; ASSERT (CERTMGR_CERTIFICATE == m_objecttype); if ( m_pCertContext ) { AFX_MANAGE_STATE (AfxGetStaticModuleState ()); FILETIME ft; // security review 2/22/2002 BryanWal ok ::ZeroMemory (&ft, sizeof (ft)); DWORD cbData = sizeof (ft); BOOL bResult = ::CertGetCertificateContextProperty ( m_pCertContext, CERT_DATE_STAMP_PROP_ID, &ft, &cbData); if ( bResult ) { VERIFY (SUCCEEDED (FormatDate (ft, szDate, dwDateFlags, true)) ); } else { DWORD dwErr = GetLastError (); _TRACE (0, L"CertGetCertificateContextProperty (CERT_DATE_STAMP_PROP_ID) returned 0x%x\n", dwErr); if ( bRetryIfNotPresent && CRYPT_E_NOT_FOUND == dwErr ) { // NTRAID# 461474 SAFER: last modified date is being updated // everytime the rules are refreshed. GetNewCertContext (); if ( SUCCEEDED (SetLastModified ()) ) // not present - set the value { szDate = GetLastModified (dwDateFlags, false); CCertStore* pCertStore = GetCertStore (); if ( pCertStore ) { pCertStore->SetDirty (); pCertStore->Commit (); } } } dwErr = GetLastError (); if ( CRYPT_E_NOT_FOUND == dwErr ) { _TRACE (0, L"CertGetCertificateContextProperty (CERT_DATE_STAMP_PROP_ID) found no property.\n"); } else { _TRACE (0, L"CertGetCertificateContextProperty (CERT_DATE_STAMP_PROP_ID) failed: 0x%x\n", dwErr); } } } _TRACE (-1, L"Leaving CCertificate::GetLastModified (): %s\n", (PCWSTR) szDate); return szDate; } HRESULT CCertificate::GetLastModifiedFileTime (FILETIME& ft) { HRESULT hr = S_OK; ASSERT (CERTMGR_CERTIFICATE == m_objecttype); ASSERT (m_pCertContext); if ( m_pCertContext ) { DWORD cbData = sizeof (ft); BOOL bResult = ::CertGetCertificateContextProperty ( m_pCertContext, CERT_DATE_STAMP_PROP_ID, &ft, &cbData); if ( !bResult ) { DWORD dwErr = GetLastError (); if ( CRYPT_E_NOT_FOUND == dwErr ) { _TRACE (0, L"CertGetCertificateContextProperty (CERT_DATE_STAMP_PROP_ID) found no property.\n"); } else { _TRACE (0, L"CertGetCertificateContextProperty (CERT_DATE_STAMP_PROP_ID) failed: 0x%x\n", dwErr); } hr = HRESULT_FROM_WIN32 (dwErr); } } else hr = E_FAIL; return hr; } BOOL CCertificate::operator==(CCertificate& rCert) { if ( GetMD5Hash () == rCert.GetMD5Hash () ) return TRUE; else return FALSE; } // NTRAID# 247237 Cert UI: Cert Snapin: Certificates snapin should show template name CString CCertificate::GetTemplateName() { if ( m_pCertInfo && !(m_fieldChecked & FIELD_TEMPLATE_NAME) ) { // Iterate through the extensions until szOID_CERTIFICATE_TEMPLATE is found. for (DWORD index = 0; index < m_pCertInfo->cExtension; index++) { ASSERT (m_pCertInfo->rgExtension); if ( !m_pCertInfo->rgExtension ) break; // security review 2/22/2002 BryanWal ok if ( !strcmp (szOID_CERTIFICATE_TEMPLATE, m_pCertInfo->rgExtension[index].pszObjId) ) { m_szTemplateName = DecodeV2TemplateName (m_pCertInfo); if ( m_szTemplateName.IsEmpty () ) { m_szTemplateName = OriginalDecodeV2TemplateName (&(m_pCertInfo->rgExtension[index])); } break; } // security review 2/22/2002 BryanWal ok else if ( !strcmp (szOID_ENROLL_CERTTYPE_EXTENSION, m_pCertInfo->rgExtension[index].pszObjId) ) { m_szTemplateName = DecodeV1TemplateName (&(m_pCertInfo->rgExtension[index])); break; } } m_fieldChecked |= FIELD_TEMPLATE_NAME; } return m_szTemplateName; } // NTRAID# 247237 Cert UI: Cert Snapin: Certificates snapin should show template name CString CCertificate::DecodeV1TemplateName (PCERT_EXTENSION pCertExtension) { CString szTemplateName; ASSERT (pCertExtension); if ( pCertExtension ) { DWORD cbValue = 0; if ( ::CryptDecodeObject( CRYPT_ASN_ENCODING, X509_UNICODE_ANY_STRING, pCertExtension->Value.pbData, pCertExtension->Value.cbData, 0, 0, &cbValue) ) { CERT_NAME_VALUE* pCNValue = (CERT_NAME_VALUE*) ::LocalAlloc(LPTR, cbValue); if ( pCNValue ) { if ( ::CryptDecodeObject( CRYPT_ASN_ENCODING, X509_UNICODE_ANY_STRING, pCertExtension->Value.pbData, pCertExtension->Value.cbData, 0, pCNValue, &cbValue) ) { szTemplateName = (LPWSTR) pCNValue->Value.pbData; // NTRAID# 395173 Certificates Snapin:The column " // Certificate Template" should contain value of "Template // Name" for V1 templates HCERTTYPE hCertType = 0; HRESULT hr = ::CAFindCertTypeByName (szTemplateName, NULL, CT_ENUM_MACHINE_TYPES | CT_ENUM_USER_TYPES, &hCertType); if ( SUCCEEDED (hr) ) { PWSTR* rgwszProp = 0; hr = ::CAGetCertTypePropertyEx (hCertType, CERTTYPE_PROP_FRIENDLY_NAME, &rgwszProp); if ( SUCCEEDED (hr) && rgwszProp ) { szTemplateName = *rgwszProp; ::CAFreeCertTypeProperty (hCertType, rgwszProp); } else { _TRACE (0, L"CAGetCertTypePropertyEx (CERTTYPE_PROP_FRIENDLY_NAME) failed: 0x%x\n", hr); } ::CACloseCertType (hCertType); } } else { _TRACE (0, L"CryptDecodeObject (CRYPT_ASN_ENCODING, X509_UNICODE_ANY_STRING, ...) failed: 0x%x\n", GetLastError ()); } ::LocalFree (pCNValue); } } else { _TRACE (0, L"CryptDecodeObject (CRYPT_ASN_ENCODING, X509_UNICODE_ANY_STRING, ...) failed: 0x%x\n", GetLastError ()); } } return szTemplateName; } BOOL ConvertSzToWsz ( OUT WCHAR **ppwsz, IN CHAR const *pch, IN LONG cch) { HRESULT hr = S_OK; LONG cwc = 0; UINT codePage = ::GetACP (); *ppwsz = NULL; for (;;) { cwc = ::MultiByteToWideChar (codePage, 0, pch, cch, *ppwsz, cwc); if (0 >= cwc) { hr = HRESULT_FROM_WIN32 (GetLastError()); _TRACE (0, L"MultiByteToWideChar () failed: 0x%x\n", hr); if (NULL != *ppwsz) { ::LocalFree(*ppwsz); *ppwsz = NULL; } break; } if (NULL != *ppwsz) { (*ppwsz)[cwc] = L'\0'; hr = S_OK; break; } *ppwsz = (WCHAR *) ::LocalAlloc (LMEM_FIXED, (cwc + 1) * sizeof (WCHAR)); if ( !*ppwsz ) { hr = E_OUTOFMEMORY; break; } } if (S_OK != hr) { ::SetLastError (hr); } return (S_OK == hr); } HRESULT GetTemplateDisplayName( IN const CString& szTemplateObjId, CString& szDisplayName) { HRESULT hr = S_OK; PWSTR pwszDisplayName = NULL; HCERTTYPE hCertType = NULL; DWORD dwFlags = 0; PWSTR* apwszCertTypeName = NULL; dwFlags = CT_ENUM_USER_TYPES | CT_ENUM_MACHINE_TYPES; hr = ::CAFindCertTypeByName (szTemplateObjId, NULL, dwFlags, &hCertType); if ( HRESULT_FROM_WIN32 (ERROR_NOT_FOUND) == hr ) { hr = ::CAFindCertTypeByName ( szTemplateObjId, NULL, CT_FIND_BY_OID | dwFlags, &hCertType); } if ( SUCCEEDED (hr) ) { hr = ::CAGetCertTypeProperty ( hCertType, CERTTYPE_PROP_FRIENDLY_NAME, &apwszCertTypeName); if ( SUCCEEDED (hr) ) { if ( apwszCertTypeName && apwszCertTypeName[0]) szDisplayName = apwszCertTypeName[0]; } else { _TRACE (0, L"CAGetCertTypeProperty (CERTTYPE_PROP_FRIENDLY_NAME) failed: 0x%x\n", hr); } } else { _TRACE (0, L"CAFindCertTypeByName (%s) failed: 0x%x\n", (PCWSTR) szTemplateObjId, hr); } if ( apwszCertTypeName ) ::CAFreeCertTypeProperty (hCertType, apwszCertTypeName); if ( hCertType ) ::CACloseCertType (hCertType); if ( pwszDisplayName ) ::LocalFree (pwszDisplayName); return hr; } CString CCertificate::DecodeV2TemplateName (PCERT_INFO pCertInfo) { CWaitCursor waitCursor; CString szTemplateName; ASSERT (pCertInfo); if ( pCertInfo ) { CERT_EXTENSION* pExt = ::CertFindExtension( szOID_CERTIFICATE_TEMPLATE, pCertInfo->cExtension, pCertInfo->rgExtension); if ( pExt ) { DWORD cbTemplate = 0; CERT_TEMPLATE_EXT* pTemplate = NULL; BOOL bResult = ::CryptDecodeObjectEx( X509_ASN_ENCODING, X509_CERTIFICATE_TEMPLATE, pExt->Value.pbData, pExt->Value.cbData, CRYPT_DECODE_ALLOC_FLAG, // dwFlags NULL, // use LocalAlloc and LocalFree &pTemplate, &cbTemplate); if (bResult && !pTemplate) { ::SetLastError((DWORD) HRESULT_FROM_WIN32(ERROR_INVALID_DATA)); bResult = FALSE; } if ( bResult ) { WCHAR *pwszCertTypeObjId = NULL; CString szDisplayName; if ( ConvertSzToWsz(&pwszCertTypeObjId, pTemplate->pszObjId, -1) ) { HRESULT hr = GetTemplateDisplayName(pwszCertTypeObjId, szDisplayName); if ( SUCCEEDED (hr) ) { szTemplateName = szDisplayName; } if (NULL != pwszCertTypeObjId) { ::LocalFree(pwszCertTypeObjId); } if (NULL != pTemplate) { ::LocalFree(pTemplate); } } } } } return szTemplateName; } // NTRAID# 247237 Cert UI: Cert Snapin: Certificates snapin should show template name CString CCertificate::OriginalDecodeV2TemplateName (PCERT_EXTENSION pCertExtension) { CString szTemplateName; ASSERT (pCertExtension); if ( pCertExtension ) { DWORD cbData = 0; if ( CryptDecodeObject(X509_ASN_ENCODING, szOID_CERTIFICATE_TEMPLATE, pCertExtension->Value.pbData, pCertExtension->Value.cbData, 0, NULL, &cbData) ) { CERT_TEMPLATE_EXT* pbTemplate = (CERT_TEMPLATE_EXT*) LocalAlloc(LPTR, cbData); if ( pbTemplate ) { if ( CryptDecodeObject(X509_ASN_ENCODING, szOID_CERTIFICATE_TEMPLATE, pCertExtension->Value.pbData, pCertExtension->Value.cbData, 0, pbTemplate, &cbData) ) { CString text; CString description; //copy the extension oid if ( pbTemplate->pszObjId ) { MyGetOIDInfo (szTemplateName, pbTemplate->pszObjId); } } else { _TRACE (0, L"CryptDecodeObject (X509_ASN_ENCODING, szOID_CERTIFICATE_TEMPLATE, ...) failed: 0x%x\n", GetLastError ()); } LocalFree (pbTemplate); } } else { _TRACE (0, L"CryptDecodeObject (X509_ASN_ENCODING, szOID_CERTIFICATE_TEMPLATE, ...) failed: 0x%x\n", GetLastError ()); } } return szTemplateName; } void CCertificate::SetStore (CCertStore* pStore) { if ( !m_pCertStore && !pStore ) return; if ( m_pCertStore && pStore ) { if ( *m_pCertStore == *pStore ) return; // don't change if the same } if ( m_pCertStore ) { m_pCertStore->Release (); m_pCertStore = 0; } if ( pStore ) { m_pCertStore = pStore; m_pCertStore->AddRef (); } if ( m_pCertContext ) { PCCERT_CONTEXT pCertContext = GetNewCertContext (); ::CertFreeCertificateContext (m_pCertContext); m_pCertInfo = 0; m_pCertContext = 0; m_pCertContext = pCertContext; if ( m_pCertContext ) m_pCertInfo = m_pCertContext->pCertInfo; } } bool CCertificate::IsCertStillInStore() const { bool bCertFound = false; if ( m_pCertStore ) { PCCERT_CONTEXT pFoundCertContext = m_pCertStore->FindCertificate (0, CERT_FIND_EXISTING, (void*) m_pCertContext, NULL); if ( pFoundCertContext ) { ::CertFreeCertificateContext (pFoundCertContext); bCertFound = true; } } return bCertFound; }