You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1530 lines
48 KiB
1530 lines
48 KiB
//+---------------------------------------------------------------------------
|
|
//
|
|
// 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;
|
|
}
|