//+------------------------------------------------------------------------- // // Microsoft Windows // // Copyright (C) Microsoft Corporation, 1997 - 1999 // // File: trustdb.cpp // //-------------------------------------------------------------------------- // // PersonalTrustDb.cpp // // Code that maintains a list of trusted publishers, agencies, and so on. #include "global.hxx" #include "cryptreg.h" #include "trustdb.h" ///////////////////////////////////////////////////////// DECLARE_INTERFACE (IUnkInner) { STDMETHOD(InnerQueryInterface) (THIS_ REFIID iid, LPVOID* ppv) PURE; STDMETHOD_ (ULONG, InnerAddRef) (THIS) PURE; STDMETHOD_ (ULONG, InnerRelease) (THIS) PURE; }; ///////////////////////////////////////////////////////// extern "C" const GUID IID_IPersonalTrustDB = IID_IPersonalTrustDB_Data; ///////////////////////////////////////////////////////// HRESULT WINAPI 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) HCERTSTORE m_hPubStore; // publisher store 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(DWORD dwEncodingType, PCCERT_CONTEXT pCert, LONG iLevel, BOOL fCommercial, PCCERT_CONTEXT *ppPubCert); STDMETHODIMP AddTrustCert(PCCERT_CONTEXT pCert, LONG iLevel, BOOL fLowerLevelsToo); STDMETHODIMP RemoveTrustCert(PCCERT_CONTEXT pCert, LONG iLevel, BOOL fLowerLevelsToo); STDMETHODIMP RemoveTrustToken(LPWSTR, 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(); }; // Helper functions // # of bytes for a hash. Such as, SHA (20) or MD5 (16) #define MAX_HASH_LEN 20 #define SHA1_HASH_LEN 20 // Null terminated ascii hex characters of the hash. #define MAX_HASH_NAME_LEN (2 * MAX_HASH_LEN + 1) PCCERT_CONTEXT FindCertificateInOtherStore( IN HCERTSTORE hOtherStore, IN PCCERT_CONTEXT pCert ) { BYTE rgbHash[SHA1_HASH_LEN]; CRYPT_DATA_BLOB HashBlob; HashBlob.pbData = rgbHash; HashBlob.cbData = SHA1_HASH_LEN; if (!CertGetCertificateContextProperty( pCert, CERT_SHA1_HASH_PROP_ID, rgbHash, &HashBlob.cbData ) || SHA1_HASH_LEN != HashBlob.cbData) return NULL; return CertFindCertificateInStore( hOtherStore, 0, // dwCertEncodingType 0, // dwFindFlags CERT_FIND_SHA1_HASH, (const void *) &HashBlob, NULL //pPrevCertContext ); } BOOL IsCertificateInOtherStore( IN HCERTSTORE hOtherStore, IN PCCERT_CONTEXT pCert, OUT OPTIONAL PCCERT_CONTEXT *ppOtherCert ) { PCCERT_CONTEXT pOtherCert; if (pOtherCert = FindCertificateInOtherStore(hOtherStore, pCert)) { if (ppOtherCert) *ppOtherCert = pOtherCert; else CertFreeCertificateContext(pOtherCert); return TRUE; } else { if (ppOtherCert) *ppOtherCert = NULL; return FALSE; } } BOOL DeleteCertificateFromOtherStore( IN HCERTSTORE hOtherStore, IN PCCERT_CONTEXT pCert ) { BOOL fResult; PCCERT_CONTEXT pOtherCert; if (pOtherCert = FindCertificateInOtherStore(hOtherStore, pCert)) fResult = CertDeleteCertificateFromStore(pOtherCert); else fResult = FALSE; return fResult; } //+------------------------------------------------------------------------- // Converts the bytes into UNICODE ASCII HEX // // Needs (cb * 2 + 1) * sizeof(WCHAR) bytes of space in wsz //-------------------------------------------------------------------------- void BytesToWStr(DWORD cb, void* pv, LPWSTR wsz) { BYTE* pb = (BYTE*) pv; for (DWORD i = 0; i> 4; *wsz++ = (b <= 9) ? b + L'0' : (b - 10) + L'A'; b = *pb & 0x0F; *wsz++ = (b <= 9) ? b + L'0' : (b - 10) + L'A'; pb++; } *wsz++ = 0; } //+------------------------------------------------------------------------- // Converts the UNICODE ASCII HEX to an array of bytes //-------------------------------------------------------------------------- void WStrToBytes( IN const WCHAR wsz[MAX_HASH_NAME_LEN], OUT BYTE rgb[MAX_HASH_LEN], OUT DWORD *pcb ) { BOOL fUpperNibble = TRUE; DWORD cb = 0; LPCWSTR pwsz = wsz; WCHAR wch; while (cb < MAX_HASH_LEN && (wch = *pwsz++)) { BYTE b; // only convert ascii hex characters 0..9, a..f, A..F // silently ignore all others if (wch >= L'0' && wch <= L'9') b = (BYTE) (wch - L'0'); else if (wch >= L'a' && wch <= L'f') b = (BYTE) (10 + wch - L'a'); else if (wch >= L'A' && wch <= L'F') b = (BYTE) (10 + wch - L'A'); else continue; if (fUpperNibble) { rgb[cb] = b << 4; fUpperNibble = FALSE; } else { rgb[cb] = rgb[cb] | b; cb++; fUpperNibble = TRUE; } } *pcb = cb; } ///////////////////////////////////////////////////////////////////////////// HRESULT CTrustDB::IsTrustedCert(DWORD dwEncodingType, PCCERT_CONTEXT pCert, LONG iLevel, BOOL fCommercial, PCCERT_CONTEXT *ppPubCert ) { HRESULT hr; if (NULL == m_hPubStore) { return S_FALSE; } // See if the cert is in the trusted publisher store if (IsCertificateInOtherStore(m_hPubStore, pCert, ppPubCert)) { hr = S_OK; } else { hr = S_FALSE; } return hr; } HRESULT CTrustDB::AddTrustCert(PCCERT_CONTEXT pCert, LONG iLevel, BOOL fLowerLevelsToo) { HRESULT hr; if (NULL == m_hPubStore) { return S_FALSE; } if (CertAddCertificateContextToStore( m_hPubStore, pCert, CERT_STORE_ADD_USE_EXISTING, NULL )) { hr = S_OK; } else { hr = HRESULT_FROM_WIN32(GetLastError()); } return hr; } HRESULT CTrustDB::RemoveTrustCert(PCCERT_CONTEXT pCert, LONG iLevel, BOOL fLowerLevelsToo) { HRESULT hr; if (NULL == m_hPubStore) { return S_FALSE; } CertDuplicateCertificateContext(pCert); if (DeleteCertificateFromOtherStore( m_hPubStore, pCert )) { hr = S_OK; } else { hr = HRESULT_FROM_WIN32(GetLastError()); } return hr; } HRESULT CTrustDB::RemoveTrustToken(LPWSTR szToken, LONG iLevel, BOOL fLowerLevelsToo) { HRESULT hr; DWORD cbHash; BYTE rgbHash[SHA1_HASH_LEN]; CRYPT_DATA_BLOB HashBlob; PCCERT_CONTEXT pDeleteCert; if (NULL == m_hPubStore) { return S_FALSE; } WStrToBytes(szToken, rgbHash, &cbHash); HashBlob.pbData = rgbHash; HashBlob.cbData = cbHash; pDeleteCert = CertFindCertificateInStore( m_hPubStore, 0, // dwCertEncodingType 0, // dwFindFlags CERT_FIND_SHA1_HASH, (const void *) &HashBlob, NULL //pPrevCertContext ); if (NULL == pDeleteCert) { hr = HRESULT_FROM_WIN32(GetLastError()); } else { if (CertDeleteCertificateFromStore(pDeleteCert)) { hr = S_OK; } else { hr = HRESULT_FROM_WIN32(GetLastError()); } } return hr; } HRESULT CTrustDB::AreCommercialPublishersTrusted() // Answer whether commercial publishers are trusted. // S_OK == yes // S_FALSE == no // other == can't tell { return( S_FALSE ); } HRESULT CTrustDB::SetCommercialPublishersTrust(BOOL fTrust) // Set the commercial trust setting { return( S_OK ); } ///////////////////////////////////////////////////////////////////////////// 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; ULONG cTrust = 0; ULONG cAllocTrust = 0; TRUSTLISTENTRY* rgTrustList = NULL; PCCERT_CONTEXT pCert = NULL; *prgTrustList = NULL; *pcTrustList = 0; if (NULL == m_hPubStore) { return S_OK; } // Get count of trusted publisher certs pCert = NULL; while (pCert = CertEnumCertificatesInStore(m_hPubStore, pCert)) { cTrust++; } if (0 == cTrust) { return S_OK; } rgTrustList = (TRUSTLISTENTRY*) CoTaskMemAlloc(cTrust * sizeof(TRUSTLISTENTRY)); if (NULL == rgTrustList) { return E_OUTOFMEMORY; } memset(rgTrustList, 0, cTrust * sizeof(TRUSTLISTENTRY)); cAllocTrust = cTrust; cTrust = 0; pCert = NULL; while (pCert = CertEnumCertificatesInStore(m_hPubStore, pCert)) { BYTE rgbHash[MAX_HASH_LEN]; DWORD cbHash = MAX_HASH_LEN; // get the thumbprint if(!CertGetCertificateContextProperty( pCert, CERT_SHA1_HASH_PROP_ID, rgbHash, &cbHash)) { continue; } // convert to a string BytesToWStr(cbHash, rgbHash, rgTrustList[cTrust].szToken); if (1 >= CertGetNameStringW( pCert, CERT_NAME_FRIENDLY_DISPLAY_TYPE, 0, // dwFlags NULL, // pvTypePara rgTrustList[cTrust].szDisplayName, sizeof(rgTrustList[cTrust].szDisplayName)/sizeof(WCHAR) )) { continue; } cTrust++; if (cTrust >= cAllocTrust) { CertFreeCertificateContext(pCert); break; } } if (0 == cTrust) { CoTaskMemFree(rgTrustList); rgTrustList = NULL; } *pcTrustList = cTrust; *prgTrustList = rgTrustList; return S_OK; } ///////////////////////////////////////////////////////////////////////////// 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; *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_hPubStore(NULL) { if (punkOuter == NULL) m_punkOuter = (IUnknown *) ((LPVOID) ((IUnkInner *) this)); else m_punkOuter = punkOuter; } CTrustDB::~CTrustDB() { if (m_hPubStore) CertCloseStore(m_hPubStore, 0); } HRESULT CTrustDB::Init() { m_hPubStore = OpenTrustedPublisherStore(); if (NULL == m_hPubStore) { return HRESULT_FROM_WIN32(GetLastError()); } return S_OK; }