NT4/private/windows/base/advapi/digsig/softpub/person~1.cpp
2020-09-30 17:12:29 +02:00

876 lines
26 KiB
C++

//
// PersonalTrustDb.cpp
//
// Code that maintains a list of trusted publishers, agencies, and so on.
// The list is stored in the registry under the root
//
// HKEY_CURRENT_USER\Software\Microsoft\Secure\WinTrust\
// Trust Providers\Software Publishing\Trust Database
//
// (Note the fact that this is user-sensitive.)
//
// Under this key are the keys "0", "1", "2", and so on. Each of these represents
// the (exact) distance from the leaf of the certification hierarchy for which a
// given certificate is trusted.
//
// Under each of these keys is a list of values, where
// value name == stringized form of a cert's (issuer name, serial number)
// value value == display name of cert to show in UI
//
// In addition, there is a value under the root key with the name
// Trust Commercial Publishers
// If this value is absent, or if it is present and has a non "0" value
// then commercial publishers are trusted. Otherwise they are not
#include "stdpch.h"
#include "common.h"
/////////////////////////////////////////////////////////
DECLARE_INTERFACE (IUnkInner)
{
STDMETHOD(InnerQueryInterface) (THIS_ REFIID iid, LPVOID* ppv) PURE;
STDMETHOD_ (ULONG, InnerAddRef) (THIS) PURE;
STDMETHOD_ (ULONG, InnerRelease) (THIS) PURE;
};
/////////////////////////////////////////////////////////
const TCHAR szTrustDB[] = TEXT(REGPATH_WINTRUST_USER REGPATH_SPUB "\\Trust Database");
const TCHAR szCommercial[] = TEXT("Trust Commercial Publishers");
extern "C" const GUID IID_IPersonalTrustDB = IID_IPersonalTrustDB_Data;
/////////////////////////////////////////////////////////
HRESULT OpenTrustDB(IUnknown* punkOuter, REFIID iid, void** ppv);
class CTrustDB : IPersonalTrustDB, IUnkInner
{
LONG m_refs; // our reference count
IUnknown* m_punkOuter; // our controlling unknown (may be us ourselves)
HKEY m_hkeyTrustDB; // the root of our trust database
HKEY m_hkeyZero; // cached leaf key
HKEY m_hkeyOne; // cached agency key
HCRYPTPROV m_hprov; // cryptographic provider for name hashing
public:
static HRESULT CreateInstance(IUnknown* punkOuter, REFIID iid, void** ppv);
private:
STDMETHODIMP QueryInterface(THIS_ REFIID riid, LPVOID FAR* ppvObj);
STDMETHODIMP_(ULONG) AddRef(THIS);
STDMETHODIMP_(ULONG) Release(THIS);
STDMETHODIMP InnerQueryInterface(REFIID iid, LPVOID* ppv);
STDMETHODIMP_(ULONG) InnerAddRef();
STDMETHODIMP_(ULONG) InnerRelease();
STDMETHODIMP IsTrustedCert(IX509* p509, LONG iLevel, BOOL fCommercial);
STDMETHODIMP IsTrustedName(CERTISSUERSERIAL*, LONG iLevel);
STDMETHODIMP AddTrustCert(IX509* p509, LONG iLevel, BOOL fLowerLevelsToo);
STDMETHODIMP RemoveTrustCert(IX509* p509, LONG iLevel, BOOL fLowerLevelsToo);
STDMETHODIMP RemoveTrustName(CERTISSUERSERIAL*, LONG iLevel, BOOL fLowerLevelsToo);
STDMETHODIMP RemoveTrustToken(LPTSTR, LONG iLevel, BOOL fLowerLevelsToo);
STDMETHODIMP AreCommercialPublishersTrusted();
STDMETHODIMP SetCommercialPublishersTrust(BOOL fTrust);
STDMETHODIMP GetTrustList(
LONG iLevel, // the cert chain level to get
BOOL fLowerLevelsToo, // included lower levels, remove duplicates
TRUSTLISTENTRY** prgTrustList, // place to return the trust list
ULONG* pcTrustList // place to return the size of the returned trust list
);
private:
CTrustDB(IUnknown* punkOuter);
~CTrustDB();
HRESULT Init();
void BytesToString(ULONG cb, void* pv, LPTSTR sz);
HRESULT X500NAMEToString(ULONG cb, void*pv, LPTSTR szDest);
LPTSTR IssuerSerialToString(CERTISSUERSERIAL& is);
HRESULT GetIssuerSerial(IX509*, CERTISSUERSERIAL&);
HKEY KeyOfLevel(LONG iLevel);
BOOL ShouldClose(LONG iLevel) { return iLevel > 1; }
void FreeTaskMem(CERTISSUERSERIAL&);
void FreeTaskMem(BLOB& b);
};
/////////////////////////////////////////////////////////////////////////////
HRESULT CTrustDB::IsTrustedCert(IX509* p509, LONG iLevel, BOOL fCommercial)
{
if (!p509)
return E_INVALIDARG;
//
// Get the value name to query by
//
CERTISSUERSERIAL issuerSerial;
HRESULT hr = GetIssuerSerial(p509, issuerSerial);
if (hr==S_OK)
{
//
// Ask the question using that name
//
hr = IsTrustedName(&issuerSerial, iLevel);
FreeTaskMem(issuerSerial);
}
//
// If we don't trust this guy explicitly, then does
// he fall under the 'trust all commercial publishers'
// check box?
//
if (hr==S_FALSE)
{
//
// That checkbox only applies to a cert at the leaf level and if
// the caller explicitly says that commercial usage is intended
//
if (fCommercial && iLevel==0)
{
ISelectedAttributes* pattrs = NULL;
hr = p509->QueryInterface(IID_ISelectedAttributes, (LPVOID*)&pattrs);
if (hr==S_OK)
{
//
// We assume the caller has done the check that this cert and
// everything up its chain is in fact suitable for commercial
// use. However, we have the one additional policy to enforce
// here that the caller has met our minimal financial criteria;
// those commercial publishers that don't don't have the checkbox
// apply to them
//
BOOL fMeets;
BOOL fAvail;
hr = pattrs->get_MeetsMinimalFinancialCriteria(&fAvail, &fMeets);
if (hr==S_OK && (fMeets || !fAvail))
{
//
// Ok. He's an elligible commercial cert at the leaf level.
// Is the checkbox on?
//
hr = AreCommercialPublishersTrusted()==S_OK ? S_OK : S_FALSE;
}
else
hr = S_FALSE;
pattrs->Release();
}
}
}
return hr;
}
HRESULT CTrustDB::IsTrustedName(CERTISSUERSERIAL* pissuerSerial, LONG iLevel)
// Answer whether the given certificate is trusted at the indicated level
{
HRESULT hr = S_OK;
//
// Get the key to query under
//
HKEY hkey = KeyOfLevel(iLevel);
if (hkey)
{
if (hr==S_OK)
{
//
// Stringize the name
//
LPTSTR szValueName = IssuerSerialToString(*pissuerSerial);
if (szValueName)
{
//
// Do the query. If present, it's trusted.
//
DWORD dwType;
if (RegQueryValueEx(hkey, szValueName, NULL, &dwType, NULL, NULL) == ERROR_SUCCESS)
{
hr = S_OK; // trusted
}
else
{
hr = S_FALSE; // not trusted
}
CoTaskMemFree(szValueName);
}
}
if (ShouldClose(iLevel))
RegCloseKey(hkey);
}
else
hr = E_UNEXPECTED;
return hr;
}
HRESULT CTrustDB::AddTrustCert(IX509* p509, LONG iLevel, BOOL fLowerLevelsToo)
// Add trust in the indicated certificate at the indicated level
{
HRESULT hr = S_OK;
//
// Get the key to query under
//
HKEY hkey = KeyOfLevel(iLevel);
if (hkey)
{
//
// Get the name of the certificate
//
CERTISSUERSERIAL issuerSerial;
hr = GetIssuerSerial(p509, issuerSerial);
if (hr==S_OK)
{
//
// Stringize the name of the trusted party
//
LPTSTR szValueName = IssuerSerialToString(issuerSerial);
if (szValueName)
{
//
// Get the value value to set. This is the display name of the party.
//
LPOLESTR wszValue = NULL;
ISelectedAttributes* pattrs = NULL;
if (hr==S_OK) hr=p509->QueryInterface(IID_ISelectedAttributes, (LPVOID*)&pattrs);
if (hr==S_OK)
{
switch (iLevel)
{
case 0:
hr = GetPublisherNameOfCert(pattrs, &wszValue);
break;
case 1:
hr = GetAgencyNameOfCert(pattrs, &wszValue);
break;
default:
hr=pattrs->get_CommonName(&wszValue);
break;
}
}
if (pattrs) pattrs->Release();
if (hr==S_OK)
{
//
// Convert value to TCHAR
//
TCHAR sz[128];
WideCharToMultiByte(CP_ACP,0,wszValue,-1,(LPSTR)sz,128,NULL,NULL);
//
// Set the value
//
if (RegSetValueEx(hkey, szValueName, NULL, REG_SZ, (BYTE*)sz, _tcslen(sz)+1) == ERROR_SUCCESS)
{
// Success!
}
else
hr = E_UNEXPECTED;
CoTaskMemFree ( wszValue );
}
CoTaskMemFree(szValueName);
}
FreeTaskMem(issuerSerial);
}
if (ShouldClose(iLevel))
RegCloseKey(hkey);
}
else
hr = E_UNEXPECTED;
#ifdef _DEBUG
if (hr==S_OK)
{
ASSERT(IsTrustedCert(p509, iLevel, FALSE) == S_OK);
}
#endif
//
// If we are succesful, then recurse to lower levels if necessary
// REVIEW: this can be made zippier, but that's probably not worth
// it given how infrequently this is called.
//
if (hr==S_OK && fLowerLevelsToo && iLevel > 0)
{
hr = AddTrustCert(p509, iLevel-1, fLowerLevelsToo);
}
return hr;
}
HRESULT CTrustDB::RemoveTrustCert(IX509* p509, LONG iLevel, BOOL fLowerLevelsToo)
{
//
// Get the value name to query by
//
CERTISSUERSERIAL issuerSerial;
HRESULT hr = GetIssuerSerial(p509, issuerSerial);
if (hr==S_OK)
{
//
// Do the real work using this name
//
hr = RemoveTrustName(&issuerSerial, iLevel, fLowerLevelsToo);
FreeTaskMem(issuerSerial);
}
return hr;
}
HRESULT CTrustDB::RemoveTrustName(CERTISSUERSERIAL* pissuerSerial, LONG iLevel, BOOL fLowerLevelsToo)
// Remove trust in the indicated certificate at the indicated level
{
HRESULT hr = S_OK;
if (hr==S_OK)
{
//
// Stringize the name
//
LPTSTR szValueName = IssuerSerialToString(*pissuerSerial);
if (szValueName)
{
//
// Remove the value
//
RemoveTrustToken(szValueName, iLevel, fLowerLevelsToo);
CoTaskMemFree(szValueName);
}
}
#ifdef _DEBUG
if (hr==S_OK)
{
ASSERT(IsTrustedName(pissuerSerial, iLevel) == S_FALSE);
}
#endif
return hr;
}
HRESULT CTrustDB::RemoveTrustToken(LPTSTR szToken, LONG iLevel, BOOL fLowerLevelsToo)
{
HRESULT hr = S_OK;
//
// Get the key to query under
//
HKEY hkey = KeyOfLevel(iLevel);
if (hkey)
{
//
// Remove the value
//
RegDeleteValue(hkey, szToken);
//
// Clean up
//
if (ShouldClose(iLevel))
RegCloseKey(hkey);
}
else
hr = E_UNEXPECTED;
//
// If we are succesful, then recurse to lower levels if necessary
//
if (hr==S_OK && fLowerLevelsToo && iLevel > 0)
{
hr = RemoveTrustToken(szToken, iLevel-1, fLowerLevelsToo);
}
return hr;
}
/////////////////////////////////////////////////////////////////////////////
HRESULT CTrustDB::AreCommercialPublishersTrusted()
// Answer whether commercial publishers are trusted.
// S_OK == yes
// S_FALSE == no
// other == can't tell
{
DWORD dwType;
TCHAR sz[10];
ULONG cbSz = 10;
HRESULT hr = S_OK;
HRESULT hrDefault = S_FALSE; // default is no trust
if (RegQueryValueEx(m_hkeyTrustDB, szCommercial, 0, &dwType, (BYTE*)sz, &cbSz) == ERROR_SUCCESS)
{
if (dwType != REG_SZ)
hr = hrDefault;
else if (lstrcmp((LPCTSTR)sz, TEXT("0")) == 0)
hr = S_FALSE; // not trusted
else
hr = S_OK; // trusted
}
else
{
// There is no explicit entry; use the default
hr = hrDefault;
}
return hr;
}
HRESULT CTrustDB::SetCommercialPublishersTrust(BOOL fTrust)
// Set the commercial trust setting
{
HRESULT hr = S_OK;
static const TCHAR szTrust[] = "1";
static const TCHAR szNoTrust[] = "0";
if (RegSetValueEx(m_hkeyTrustDB, szCommercial, 0, REG_SZ, (BYTE*)(fTrust ? szTrust : szNoTrust), 2) == ERROR_SUCCESS)
{
}
else
hr = E_UNEXPECTED;
#ifdef _DEBUG
if (hr==S_OK)
{
ASSERT(AreCommercialPublishersTrusted() == (fTrust ? S_OK : S_FALSE));
}
#endif
return hr;
}
/////////////////////////////////////////////////////////////////////////////
HRESULT CTrustDB::GetTrustList(
// Return the (unsorted) list of trusted certificate names and their
// corresponding display names
//
LONG iLevel, // the cert chain level to get
BOOL fLowerLevelsToo, // included lower levels, remove duplicates
TRUSTLISTENTRY** prgTrustList, // place to return the trust list
ULONG* pcTrustList // place to return the size of the returned trust list
) {
HRESULT hr = S_OK;
*prgTrustList = NULL;
*pcTrustList = 0;
// We just enumerate all the subkeys of the database root. The sum of the
// number of values contained under each is an upper bound on the number
// of trusted entries that we have.
//
ULONG cTrust = 0;
DWORD dwRootIndex;
TCHAR szSubkey[MAX_PATH+1];
for (dwRootIndex = 0;
RegEnumKey(m_hkeyTrustDB, dwRootIndex, (LPTSTR)szSubkey, MAX_PATH+1)!=ERROR_NO_MORE_ITEMS;
dwRootIndex++
)
{
HKEY hkey;
if (RegOpenKey(m_hkeyTrustDB, (LPTSTR)szSubkey, &hkey) == ERROR_SUCCESS)
{
// We've found a subkey. Count the values thereunder.
//
TCHAR achClass[MAX_PATH]; /* buffer for class name */
DWORD cchClassName = MAX_PATH; /* length of class string */
DWORD cSubKeys; /* number of subkeys */
DWORD cbMaxSubKey; /* longest subkey size */
DWORD cchMaxClass; /* longest class string */
DWORD cValues; /* number of values for key */
DWORD cchMaxValue; /* longest value name */
DWORD cbMaxValueData; /* longest value data */
DWORD cbSecurityDescriptor; /* size of security descriptor */
FILETIME ftLastWriteTime; /* last write time */
// Get the value count.
if (ERROR_SUCCESS==
RegQueryInfoKey(hkey, /* key handle */
achClass, /* buffer for class name */
&cchClassName, /* length of class string */
NULL, /* reserved */
&cSubKeys, /* number of subkeys */
&cbMaxSubKey, /* longest subkey size */
&cchMaxClass, /* longest class string */
&cValues, /* number of values for this key */
&cchMaxValue, /* longest value name */
&cbMaxValueData, /* longest value data */
&cbSecurityDescriptor, /* security descriptor */
&ftLastWriteTime)) /* last write time */
{
cTrust += cValues;
}
else
{
hr = E_UNEXPECTED;
break;
}
RegCloseKey(hkey);
}
else
{
hr = E_UNEXPECTED;
break;
}
}
if (hr==S_OK)
{
// At this point, cTrust has an upper bound on the number of
// trust entries that we'll find. Assume that we need them all
// and, accordingly, allocate the output buffer.
//
*prgTrustList = (TRUSTLISTENTRY*) CoTaskMemAlloc(cTrust * sizeof(TRUSTLISTENTRY));
if (*prgTrustList)
{
// Once again, iterate through each of the subkeys of the root key
//
DWORD dwRootIndex;
TCHAR szSubkey[MAX_PATH+1];
for (dwRootIndex = 0;
RegEnumKey(m_hkeyTrustDB, dwRootIndex, (LPTSTR)szSubkey, MAX_PATH+1)!=ERROR_NO_MORE_ITEMS;
dwRootIndex++
)
{
HKEY hkey;
LONG iLevel = atol(szSubkey);
if (RegOpenKey(m_hkeyTrustDB, (LPTSTR)szSubkey, &hkey) == ERROR_SUCCESS)
{
// We've found a subkey. Enumerate the values thereunder.
//
DWORD dwIndex, cbToken, dwType, cbValue, dw;
TRUSTLISTENTRY* pEntry;
for (dwIndex = 0;
// ---------
pEntry = &(*prgTrustList)[*pcTrustList],
cbToken = MAX_PATH * sizeof(TCHAR),
cbValue = 64 * sizeof(TCHAR),
*pcTrustList < cTrust
&& (dw = RegEnumValue(hkey,
dwIndex,
(LPTSTR)(&pEntry->szToken),
&cbToken,
NULL,
&dwType,
(BYTE*)(&pEntry->szDisplayName),
&cbValue
)) != ERROR_NO_MORE_ITEMS
&& (dw != ERROR_INVALID_PARAMETER) // Win95 hack
;
// ---------
*pcTrustList += 1, // nb: only bump this on success
dwIndex++
) {
//
// Remember the level at which we found this
//
pEntry->iLevel = iLevel;
//
// If this was in fact a duplicate, then forget about it
//
ULONG i;
for (i=0; i < *pcTrustList; i++)
{
TRUSTLISTENTRY* pHim = &(*prgTrustList)[i];
if (lstrcmp(pHim->szToken, pEntry->szToken) == 0)
{
//
// REVIEW: put in a better display name in the
// same-name-but-different-level case
//
if (pHim->iLevel == iLevel)
{
// If it's a complete duplicate, omit it
*pcTrustList -= 1;
}
break;
}
} // end loop looking for duplicates
} // end loop over values
RegCloseKey(hkey);
}
}
}
else
hr = E_OUTOFMEMORY;
}
return hr;
}
/////////////////////////////////////////////////////////////////////////////
HKEY CTrustDB::KeyOfLevel(LONG iLevel)
// Answer the key to use for accessing the given level of the cert chain
{
#ifdef _UNICODE
#error NYI
#endif
HKEY hkey = NULL;
switch (iLevel)
{
case 0: hkey = m_hkeyZero; break;
case 1: hkey = m_hkeyOne; break;
default:
{
DWORD dwDisposition;
TCHAR sz[10];
_ltoa(iLevel, (TCHAR*)sz, 10); // nb: won't work in Unicode
if (RegCreateKeyEx(m_hkeyTrustDB, sz, 0, NULL, REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS, NULL, &hkey, &dwDisposition) != ERROR_SUCCESS)
hkey = NULL;
} // end default
} // end switch
return hkey;
}
/////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CTrustDB::QueryInterface(REFIID iid, LPVOID* ppv)
{
return (m_punkOuter->QueryInterface(iid, ppv));
}
STDMETHODIMP_(ULONG) CTrustDB::AddRef(void)
{
return (m_punkOuter->AddRef());
}
STDMETHODIMP_(ULONG) CTrustDB::Release(void)
{
return (m_punkOuter->Release());
}
/////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CTrustDB::InnerQueryInterface(REFIID iid, LPVOID* ppv)
{
*ppv = NULL;
while (TRUE)
{
if (iid == IID_IUnknown)
{
*ppv = (LPVOID)((IUnkInner*)this);
break;
}
if (iid == IID_IPersonalTrustDB)
{
*ppv = (LPVOID) ((IPersonalTrustDB *) this);
break;
}
return E_NOINTERFACE;
}
((IUnknown*)*ppv)->AddRef();
return S_OK;
}
STDMETHODIMP_(ULONG) CTrustDB::InnerAddRef(void)
{
return ++m_refs;
}
STDMETHODIMP_(ULONG) CTrustDB::InnerRelease(void)
{
ULONG refs = --m_refs;
if (refs == 0)
{
m_refs = 1;
delete this;
}
return refs;
}
/////////////////////////////////////////////////////////////////////////////
HRESULT OpenTrustDB(IUnknown* punkOuter, REFIID iid, void** ppv)
{
return CTrustDB::CreateInstance(punkOuter, iid, ppv);
}
HRESULT CTrustDB::CreateInstance(IUnknown* punkOuter, REFIID iid, void** ppv)
{
HRESULT hr;
ASSERT(punkOuter == NULL || iid == IID_IUnknown);
*ppv = NULL;
CTrustDB* pnew = new CTrustDB(punkOuter);
if (pnew == NULL) return E_OUTOFMEMORY;
if ((hr = pnew->Init()) != S_OK)
{
delete pnew;
return hr;
}
IUnkInner* pme = (IUnkInner*)pnew;
hr = pme->InnerQueryInterface(iid, ppv);
pme->InnerRelease(); // balance starting ref cnt of one
return hr;
}
CTrustDB::CTrustDB(IUnknown* punkOuter) :
m_refs(1),
m_hkeyTrustDB(NULL),
m_hkeyZero(NULL),
m_hkeyOne(NULL),
m_hprov(NULL)
{
if (punkOuter == NULL)
m_punkOuter = (IUnknown *) ((LPVOID) ((IUnkInner *) this));
else
m_punkOuter = punkOuter;
}
CTrustDB::~CTrustDB()
{
if (m_hkeyOne)
RegCloseKey(m_hkeyOne);
if (m_hkeyZero)
RegCloseKey(m_hkeyZero);
if (m_hkeyTrustDB)
RegCloseKey(m_hkeyTrustDB);
if (m_hprov)
CryptReleaseContext(m_hprov, 0);
}
HRESULT CTrustDB::Init()
{
HRESULT hr = S_OK;
DWORD dwDisposition;
if (RegCreateKeyEx(HKEY_CURRENT_USER, szTrustDB, 0, NULL, REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS, NULL, &m_hkeyTrustDB, &dwDisposition) != ERROR_SUCCESS
|| RegCreateKeyEx(m_hkeyTrustDB, TEXT("0"), 0, NULL, REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS, NULL, &m_hkeyZero, &dwDisposition) != ERROR_SUCCESS
|| RegCreateKeyEx(m_hkeyTrustDB, TEXT("1"), 0, NULL, REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS, NULL, &m_hkeyOne, &dwDisposition) != ERROR_SUCCESS)
return HError();
if (!CryptAcquireContext(&m_hprov, NULL, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
return HError();
return S_OK;
}
/////////////////////////////////////////////////////////////////////////////
void CTrustDB::BytesToString(ULONG cb, void* pv, LPTSTR sz)
// Convert the bytes into some string form.
// Needs (cb * 2 + 1) * sizeof(TCHAR) bytes of space in sz
{
BYTE* pb = (BYTE*)pv;
#ifdef UNICODE
#error Unicode NYI
#else
for (ULONG i = 0; i<cb; i++)
{
int b = *pb;
*sz++ = (((b & 0xF0)>>4) + 'a');
*sz++ = ((b & 0x0F) + 'a');
pb++;
}
*sz++ = 0;
#endif
}
HRESULT CTrustDB::X500NAMEToString(ULONG cb, void*pv, LPTSTR szDest)
//
// X500 names can have VERY long encodings, so we can't just
// do a literal vanilla encoding
//
// There must be CBX500NAME characters of space in the destination
//
// NOTE: We rely on the lack of collision in the hash values.
// Chance of a collision for a set of 'p' names is approx:
//
// p^2 / n
//
// (if p<<n) where n (with MD5) is 2^128. An amazingly small chance.
//
{
#define CBHASH 16 // MD5
#define CBX500NAME (2*CBHASH + 1)
HRESULT hr = S_OK;
HCRYPTHASH hash;
if (CryptCreateHash(m_hprov, CALG_MD5, NULL, NULL, &hash))
{
if (CryptHashData(hash, (BYTE*)pv, cb, 0))
{
BYTE rgb[CBHASH];
ULONG cb = CBHASH;
if (CryptGetHashParam(hash, HP_HASHVAL, &rgb[0], &cb, 0))
{
BytesToString(cb, &rgb[0], szDest);
}
else
hr = HError();
}
else
hr = HError();
CryptDestroyHash(hash);
}
else
hr = HError();
return hr;
}
LPTSTR CTrustDB::IssuerSerialToString(CERTISSUERSERIAL& is)
// Conver the issuer and serial number to some reasonable string form.
// The allocator used here is task.
{
ULONG cbIssuer = CBX500NAME;
ULONG cbSerial = (is.serialNumber.cbSize*2+1) * sizeof(TCHAR);
TCHAR* sz = (TCHAR*)CoTaskMemAlloc(cbSerial + sizeof(TCHAR) + cbIssuer);
if (sz)
{
if (X500NAMEToString(is.issuerName.cbSize, is.issuerName.pBlobData, sz) == S_OK)
{
TCHAR* szNext = &sz[CBX500NAME-1];
ASSERT(*szNext == 0);
*szNext++ = ' ';
BytesToString(is.serialNumber.cbSize, is.serialNumber.pBlobData, szNext);
}
else
{
CoTaskMemFree(sz);
sz = NULL;
}
}
return sz;
}
////////////////////////////////////////////////////
HRESULT CTrustDB::GetIssuerSerial(IX509* p509, CERTISSUERSERIAL& issuerSerial)
{
// Zero out parameters
memset(&issuerSerial, 0, sizeof(issuerSerial));
// Get the serial number
HRESULT hr = p509->get_SerialNumber(&issuerSerial.serialNumber);
// Get the issuer name
if (hr == S_OK)
{
IPersistMemory* pPerMem;
hr = p509->get_Issuer(IID_IPersistMemory, (LPVOID*)&pPerMem);
if (hr == S_OK)
{
hr = pPerMem->Save(&issuerSerial.issuerName, FALSE);
pPerMem->Release();
}
}
return hr;
}
void CTrustDB::FreeTaskMem(CERTISSUERSERIAL& issuerSerial)
{
FreeTaskMem(issuerSerial.issuerName);
FreeTaskMem(issuerSerial.serialNumber);
}
void CTrustDB::FreeTaskMem(BLOB& b)
{
CoTaskMemFree(b.pBlobData);
}