|
|
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1997 - 1999
//
// File: Certifct.cpp
//
// Contents: Implementation of CCertmgrApp and DLL registration.
//
//----------------------------------------------------------------------------
#include "stdafx.h"
#include "certca.h"
#include "tfcprop.h"
#include "genpage.h"
#include "Certifct.h"
/////////////////////////////////////////////////////////////////////////////
//
enum { FIELD_CAN_DELETE = 0x00000001 };
CCertificate::CCertificate(const PCCERT_CONTEXT pCertContext, HCERTSTORE hCertStore) : m_pCertContext (::CertDuplicateCertificateContext (pCertContext)), m_pCertInfo (0), m_hCertStore (::CertDuplicateStore (hCertStore)), m_bCertContextFreed (false), m_fieldChecked (0), m_bCanDelete (false) { ASSERT (m_pCertContext); if ( m_pCertContext ) m_pCertInfo = m_pCertContext->pCertInfo; }
CCertificate::~CCertificate() {
if ( m_pCertContext && !m_bCertContextFreed ) ::CertFreeCertificateContext (m_pCertContext);
if ( m_hCertStore ) ::CertCloseStore (m_hCertStore, 0); }
HRESULT CCertificate::GetIssuerName (PWSTR *ppszIssuerName) { HRESULT hResult = S_OK;
ASSERT (m_pCertInfo && ppszIssuerName); if ( m_pCertInfo && ppszIssuerName ) { // Decode issuer name if not already present
if ( m_szIssuerName.IsEmpty() ) { hResult = GetNameString (CERT_NAME_ISSUER_FLAG, m_szIssuerName); } if ( SUCCEEDED (hResult) ) { if ( *ppszIssuerName ) delete [] *ppszIssuerName; *ppszIssuerName = new WCHAR[wcslen (m_szIssuerName) + 1]; if ( *ppszIssuerName ) { wcscpy (*ppszIssuerName, m_szIssuerName); } else hResult = E_OUTOFMEMORY; } } else hResult = E_POINTER;
return hResult; }
///////////////////////////////////////////////////////////////////////////
// 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.
///////////////////////////////////////////////////////////////////////////
HRESULT CCertificate::GetSubjectName(PWSTR *ppszSubjectName) { HRESULT hResult = S_OK;
ASSERT (m_pCertInfo && ppszSubjectName); if ( m_pCertInfo && ppszSubjectName ) { // Decode issuer name if not already present
if ( m_szSubjectName.IsEmpty() ) { hResult = GetNameString (0, m_szSubjectName); } if ( SUCCEEDED (hResult) ) { if ( *ppszSubjectName ) delete [] *ppszSubjectName; *ppszSubjectName = new WCHAR[wcslen (m_szSubjectName) + 1]; if ( *ppszSubjectName ) { wcscpy (*ppszSubjectName, m_szSubjectName); } else hResult = E_OUTOFMEMORY; } } else hResult = E_POINTER;
return hResult; }
///////////////////////////////////////////////////////////////////////////
// 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.
///////////////////////////////////////////////////////////////////////////
HRESULT CCertificate::GetValidNotAfter (PWSTR* ppszValidNotAfter) { HRESULT hResult = S_OK;
ASSERT (m_pCertInfo && ppszValidNotAfter); if ( m_pCertInfo && ppszValidNotAfter ) { // Format date/time string if not already present
if ( m_szValidNotAfter.IsEmpty() ) { hResult = FormatDate (m_pCertInfo->NotAfter, m_szValidNotAfter); if ( SUCCEEDED (hResult) ) { if ( *ppszValidNotAfter ) delete [] *ppszValidNotAfter; *ppszValidNotAfter = new WCHAR[wcslen (m_szValidNotAfter)+1]; if ( *ppszValidNotAfter ) { wcscpy (*ppszValidNotAfter, m_szValidNotAfter); } else hResult = E_OUTOFMEMORY; } } } else hResult = E_POINTER;
return hResult; }
HRESULT CCertificate::GetEnhancedKeyUsage (PWSTR* ppszUsages) { HRESULT hResult = S_OK;
ASSERT (m_pCertInfo && ppszUsages); if ( m_pCertInfo && ppszUsages ) { // Format date/time string if not already present
if ( m_szEnhancedKeyUsage.IsEmpty() ) { hResult = FormatEnhancedKeyUsagePropertyString (); if ( SUCCEEDED (hResult) && !m_szEnhancedKeyUsage.IsEmpty() ) { if ( *ppszUsages ) delete [] *ppszUsages; *ppszUsages = new WCHAR[wcslen (m_szEnhancedKeyUsage)+1]; if ( *ppszUsages ) { wcscpy (*ppszUsages, m_szEnhancedKeyUsage); } else hResult = E_OUTOFMEMORY; } } } else hResult = E_POINTER;
return hResult; }
HRESULT CCertificate::FormatEnhancedKeyUsagePropertyString () { HRESULT hResult = S_OK; DWORD cbUsage = 0; DWORD dwErr = 0; LPWSTR wszEnhUsage = NULL; BOOL bReturn = ::CertGetEnhancedKeyUsage (m_pCertContext, 0, // get extension and property
NULL, &cbUsage); if ( bReturn ) { PCERT_ENHKEY_USAGE pUsage = (PCERT_ENHKEY_USAGE) new BYTE[cbUsage]; if ( pUsage ) { bReturn = ::CertGetEnhancedKeyUsage (m_pCertContext, 0, // get extension and property
pUsage, &cbUsage); if ( bReturn ) { size_t dwLen = 0; PWSTR pszComma = _T(", "); size_t dwCommaLen = wcslen (pszComma); PWSTR pszUsageName = 0;
// Get accumulated lengths first
for (DWORD dwIndex = 0; dwIndex < pUsage->cUsageIdentifier; dwIndex++) { hResult = GetOIDInfo (&pszUsageName, pUsage->rgpszUsageIdentifier[dwIndex]); if ( SUCCEEDED (hResult) ) { // add delimeter if not first iteration
if ( dwIndex != 0 ) dwLen += dwCommaLen; dwLen += wcslen (pszUsageName); delete [] pszUsageName; pszUsageName = 0; } else break; }
// Allocate buffer and get strings
wszEnhUsage = m_szEnhancedKeyUsage.GetBuffer(dwLen+1); if ( wszEnhUsage ) { ::ZeroMemory (wszEnhUsage, (dwLen+1)* sizeof (WCHAR)); for (DWORD dwIndex = 0; dwIndex < pUsage->cUsageIdentifier; dwIndex++) { hResult = GetOIDInfo (&pszUsageName, pUsage->rgpszUsageIdentifier[dwIndex]); if ( SUCCEEDED (hResult) ) { // add delimeter if not first iteration
if ( dwIndex != 0 ) wcscat (wszEnhUsage, pszComma); wcscat (wszEnhUsage, pszUsageName); ASSERT (wcslen (wszEnhUsage) <= dwLen); delete [] pszUsageName; pszUsageName = 0; } else break; } } else hResult = E_OUTOFMEMORY; } else { dwErr = GetLastError (); ASSERT (dwErr == CRYPT_E_NOT_FOUND); if ( dwErr == CRYPT_E_NOT_FOUND ) { if ( !m_szEnhancedKeyUsage.LoadString (IDS_ANY) ) hResult = E_UNEXPECTED; } else { hResult = HRESULT_FROM_WIN32(dwErr); } } delete [] pUsage; } else hResult = E_OUTOFMEMORY; } else { dwErr = GetLastError (); ASSERT (dwErr == CRYPT_E_NOT_FOUND); if ( dwErr != CRYPT_E_NOT_FOUND ) { hResult = HRESULT_FROM_WIN32(dwErr); } } return hResult; }
///////////////////////////////////////////////////////////////////////////
// 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.
///////////////////////////////////////////////////////////////////////////
HRESULT CCertificate::GetAlternateIssuerName (PWSTR* ppszAltIssuerName) { HRESULT hResult = S_OK;
ASSERT (m_pCertInfo && ppszAltIssuerName); if ( m_pCertInfo && ppszAltIssuerName ) { if ( m_szAltIssuerName.IsEmpty() ) { hResult = ConvertAltNameToString (_T(szOID_ISSUER_ALT_NAME), CERT_ALT_NAME_URL, m_szAltIssuerName); ASSERT (SUCCEEDED (hResult)); if ( SUCCEEDED (hResult) ) { if ( *ppszAltIssuerName ) delete [] *ppszAltIssuerName; *ppszAltIssuerName = new WCHAR[wcslen (m_szAltIssuerName)+1]; if ( *ppszAltIssuerName ) { wcscpy (*ppszAltIssuerName, m_szAltIssuerName); } else hResult = E_OUTOFMEMORY; } } } else hResult = E_POINTER; return hResult; }
///////////////////////////////////////////////////////////////////////////
// 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.
///////////////////////////////////////////////////////////////////////////
HRESULT CCertificate::GetAlternateSubjectName (PWSTR* ppszAltSubjectName) { HRESULT hResult = S_OK; ASSERT (m_pCertInfo && ppszAltSubjectName); if ( m_pCertInfo && ppszAltSubjectName ) { if ( m_szAltSubjectName.IsEmpty() ) { hResult = ConvertAltNameToString (_T(szOID_SUBJECT_ALT_NAME), CERT_ALT_NAME_URL, m_szAltSubjectName); ASSERT (SUCCEEDED (hResult)); if ( SUCCEEDED (hResult) ) { if ( *ppszAltSubjectName ) delete [] *ppszAltSubjectName; *ppszAltSubjectName = new WCHAR[wcslen (m_szAltSubjectName)+1]; if ( *ppszAltSubjectName ) { wcscpy (*ppszAltSubjectName, m_szAltSubjectName); } else hResult = E_OUTOFMEMORY; } } } else hResult = E_POINTER; return hResult; }
//////////////////////////////////////////////////////////////////////////////
// ConvertAltNameToString ()
//
// szOID (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 (PWSTR szOID, const DWORD dwNameChoice, CString & strAltName) { HRESULT hResult = S_OK; ASSERT (szOID); if ( !szOID ) return E_POINTER;
// Iterate through the extensions until the one indicated by the
// passed-in szOID is found.
for (DWORD index = 0; index < m_pCertInfo->cExtension; index++) { ASSERT (m_pCertInfo->rgExtension); size_t len = strlen (m_pCertInfo->rgExtension[index].pszObjId); LPTSTR wcsObjId = new WCHAR[len]; if ( !wcsObjId ) { hResult = E_OUTOFMEMORY; break; } else wcsObjId[0] = L'\0'; mbstowcs (wcsObjId, m_pCertInfo->rgExtension[index].pszObjId, len);
if ( !wcscmp (wcsObjId, szOID) ) { 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 index1 = 0; index1 < nameInfo.cAltEntry; index1++) { if ( nameInfo.rgAltEntry[index1].dwAltNameChoice == dwNameChoice ) { strAltName = nameInfo.rgAltEntry[index1].pwszURL; break; } } } else hResult = E_UNEXPECTED; break; } delete [] wcsObjId; }
return hResult; }
HCERTSTORE CCertificate::GetCertStore() const { return m_hCertStore; }
PCCERT_CONTEXT CCertificate::GetCertContext() const { return m_pCertContext; }
HRESULT CCertificate::GetNameString (DWORD dwFlag, CString &strName) { HRESULT hResult = S_OK;
DWORD dwTypePara = CERT_SIMPLE_NAME_STR; DWORD cchNameString = 0; DWORD dwResult = ::CertGetNameString (m_pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, dwFlag, &dwTypePara, NULL, cchNameString); if ( dwResult > 1 ) { cchNameString = dwResult; dwResult = ::CertGetNameString (m_pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, dwFlag, &dwTypePara, strName.GetBuffer(cchNameString), cchNameString); ASSERT (dwResult > 1); if ( dwResult <= 1 ) { if ( !strName.LoadString (IDS_NOT_AVAILABLE) ) hResult = E_FAIL; } } else { dwResult = ::CertGetNameString (m_pCertContext, CERT_NAME_EMAIL_TYPE, dwFlag, NULL, NULL, cchNameString); if ( dwResult > 1 ) { cchNameString = dwResult; dwResult = ::CertGetNameString (m_pCertContext, CERT_NAME_EMAIL_TYPE, dwFlag, NULL, strName.GetBuffer(cchNameString), cchNameString); ASSERT (dwResult > 1); if ( dwResult <= 1 ) { if ( !strName.LoadString (IDS_NOT_AVAILABLE) ) hResult = E_FAIL; } } else { if ( !strName.LoadString (IDS_NOT_AVAILABLE)) hResult = E_FAIL; } }
return hResult; }
int CCertificate::CompareExpireDate(const CCertificate & cert) const { int compVal = 0;
ASSERT (m_pCertInfo && cert.m_pCertInfo); if ( m_pCertInfo && cert.m_pCertInfo ) { compVal = ::CompareFileTime (&m_pCertInfo->NotAfter, &cert.m_pCertInfo->NotAfter); }
return compVal; }
HRESULT CCertificate::GetOIDInfo (PWSTR* ppszString, PSTR pszObjId) { HRESULT hResult = S_OK; ASSERT (pszObjId && ppszString); if ( pszObjId && ppszString ) { PCCRYPT_OID_INFO pOIDInfo; BOOL bResult = TRUE; pOIDInfo = ::CryptFindOIDInfo (CRYPT_OID_INFO_OID_KEY, (void *) pszObjId, 0);
if ( pOIDInfo ) { if ( *ppszString ) delete [] *ppszString; *ppszString = new WCHAR[wcslen (pOIDInfo->pwszName)+1]; if ( *ppszString ) { wcscpy (*ppszString, pOIDInfo->pwszName); } else hResult = E_OUTOFMEMORY; } else { int nLen = ::MultiByteToWideChar (CP_ACP, 0, pszObjId, -1, NULL, 0); ASSERT (nLen); if ( nLen ) { if ( *ppszString ) delete [] *ppszString; *ppszString = new WCHAR[nLen]; if ( *ppszString ) { nLen = ::MultiByteToWideChar (CP_ACP, 0, pszObjId, -1, *ppszString, nLen); ASSERT (nLen); if ( !nLen ) hResult = E_UNEXPECTED; } else hResult = E_OUTOFMEMORY; } else hResult = E_FAIL; } } else hResult = E_POINTER;
return hResult; }
///////////////////////////////////////////////////////////////////////////////
// FormatDate ()
//
// utcDateTime (IN) - A FILETIME in UTC format.
// pszDateTime (OUT) - A string containing the local date and time
// formatted by locale and user preference
//
///////////////////////////////////////////////////////////////////////////////
HRESULT CCertificate::FormatDate (FILETIME utcDateTime, CString &strDateTime) { // Time is returned as UTC, will be displayed as local.
// Use FileTimeToLocalFileTime () to make it local,
// then call FileTimeToSystemTime () to convert to system time, then
// format with GetDateFormat () and GetTimeFormat () to display
// according to user and locale preferences
HRESULT hResult = S_OK; FILETIME localDateTime;
BOOL bResult = FileTimeToLocalFileTime (&utcDateTime, // pointer to UTC file time to convert
&localDateTime); // pointer to converted file time
ASSERT (bResult); if ( bResult ) { SYSTEMTIME sysTime;
bResult = FileTimeToSystemTime ( &localDateTime, // pointer to file time to convert
&sysTime); // pointer to structure to receive system time
if ( bResult ) {
// Get date
// Get length to allocate buffer of sufficient size
int iLen = GetDateFormat ( LOCALE_USER_DEFAULT, // locale for which date is to be formatted
0, // flags specifying function options
&sysTime, // date to be formatted
0, // date format string
0, // buffer for storing formatted string
0); // size of buffer
ASSERT (iLen > 0); if ( iLen > 0 ) { int iResult = GetDateFormat ( LOCALE_USER_DEFAULT, // locale for which date is to be formatted
0, // flags specifying function options
&sysTime, // date to be formatted
0, // date format string
strDateTime.GetBuffer(iLen), // buffer for storing formatted string
iLen); // size of buffer
ASSERT (iResult); if ( !iResult ) { hResult = GetLastError(); hResult = HRESULT_FROM_WIN32(hResult); } } else { hResult = GetLastError(); hResult = HRESULT_FROM_WIN32(hResult); } } else { hResult = GetLastError(); hResult = HRESULT_FROM_WIN32(hResult); } } else { hResult = GetLastError(); hResult = HRESULT_FROM_WIN32(hResult); }
return hResult; }
void CCertificate::Refresh() { }
HRESULT CCertificate::WriteToFile(HANDLE hFile) { ASSERT (hFile && hFile != INVALID_HANDLE_VALUE && m_pCertContext); HRESULT hResult = S_OK;
if ( hFile && hFile != INVALID_HANDLE_VALUE && m_pCertContext ) { DWORD dwBytesWritten = 0; BOOL bResult = ::WriteFile (hFile, m_pCertContext->pbCertEncoded, m_pCertContext->cbCertEncoded, &dwBytesWritten, NULL); ASSERT (bResult && (dwBytesWritten == m_pCertContext->cbCertEncoded)); if ( !bResult ) hResult = E_FAIL; } else hResult = E_FAIL;
return hResult; }
BOOL CCertificate::DeleteFromStore() { BOOL bResult = ::CertDeleteCertificateFromStore (m_pCertContext); if ( bResult ) { // NB: PhilH says "CertDeleteCertificateFromStore (), always does an
// implicit CertFreeCertificateContext."
// Can't set m_pCertContext to 0 because it is const - set this flag instead
m_bCertContextFreed = true; }
return bResult; }
bool CCertificate::CanDelete() { 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; }
return m_bCanDelete; }
|