Leaked source code of windows server 2003
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.

566 lines
15 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1997 - 1999
  6. //
  7. // File: trustdb.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. //
  11. // PersonalTrustDb.cpp
  12. //
  13. // Code that maintains a list of trusted publishers, agencies, and so on.
  14. #include "global.hxx"
  15. #include "cryptreg.h"
  16. #include "trustdb.h"
  17. /////////////////////////////////////////////////////////
  18. DECLARE_INTERFACE (IUnkInner)
  19. {
  20. STDMETHOD(InnerQueryInterface) (THIS_ REFIID iid, LPVOID* ppv) PURE;
  21. STDMETHOD_ (ULONG, InnerAddRef) (THIS) PURE;
  22. STDMETHOD_ (ULONG, InnerRelease) (THIS) PURE;
  23. };
  24. /////////////////////////////////////////////////////////
  25. extern "C" const GUID IID_IPersonalTrustDB = IID_IPersonalTrustDB_Data;
  26. /////////////////////////////////////////////////////////
  27. HRESULT WINAPI OpenTrustDB(IUnknown* punkOuter, REFIID iid, void** ppv);
  28. class CTrustDB : IPersonalTrustDB, IUnkInner
  29. {
  30. LONG m_refs; // our reference count
  31. IUnknown* m_punkOuter; // our controlling unknown (may be us ourselves)
  32. HCERTSTORE m_hPubStore; // publisher store
  33. public:
  34. static HRESULT CreateInstance(IUnknown* punkOuter, REFIID iid, void** ppv);
  35. private:
  36. STDMETHODIMP QueryInterface(THIS_ REFIID riid, LPVOID FAR* ppvObj);
  37. STDMETHODIMP_(ULONG) AddRef(THIS);
  38. STDMETHODIMP_(ULONG) Release(THIS);
  39. STDMETHODIMP InnerQueryInterface(REFIID iid, LPVOID* ppv);
  40. STDMETHODIMP_(ULONG) InnerAddRef();
  41. STDMETHODIMP_(ULONG) InnerRelease();
  42. STDMETHODIMP IsTrustedCert(DWORD dwEncodingType, PCCERT_CONTEXT pCert, LONG iLevel, BOOL fCommercial, PCCERT_CONTEXT *ppPubCert);
  43. STDMETHODIMP AddTrustCert(PCCERT_CONTEXT pCert, LONG iLevel, BOOL fLowerLevelsToo);
  44. STDMETHODIMP RemoveTrustCert(PCCERT_CONTEXT pCert, LONG iLevel, BOOL fLowerLevelsToo);
  45. STDMETHODIMP RemoveTrustToken(LPWSTR, LONG iLevel, BOOL fLowerLevelsToo);
  46. STDMETHODIMP AreCommercialPublishersTrusted();
  47. STDMETHODIMP SetCommercialPublishersTrust(BOOL fTrust);
  48. STDMETHODIMP GetTrustList(
  49. LONG iLevel, // the cert chain level to get
  50. BOOL fLowerLevelsToo, // included lower levels, remove duplicates
  51. TRUSTLISTENTRY** prgTrustList, // place to return the trust list
  52. ULONG* pcTrustList // place to return the size of the returned trust list
  53. );
  54. private:
  55. CTrustDB(IUnknown* punkOuter);
  56. ~CTrustDB();
  57. HRESULT Init();
  58. };
  59. // Helper functions
  60. // # of bytes for a hash. Such as, SHA (20) or MD5 (16)
  61. #define MAX_HASH_LEN 20
  62. #define SHA1_HASH_LEN 20
  63. // Null terminated ascii hex characters of the hash.
  64. #define MAX_HASH_NAME_LEN (2 * MAX_HASH_LEN + 1)
  65. PCCERT_CONTEXT FindCertificateInOtherStore(
  66. IN HCERTSTORE hOtherStore,
  67. IN PCCERT_CONTEXT pCert
  68. )
  69. {
  70. BYTE rgbHash[SHA1_HASH_LEN];
  71. CRYPT_DATA_BLOB HashBlob;
  72. HashBlob.pbData = rgbHash;
  73. HashBlob.cbData = SHA1_HASH_LEN;
  74. if (!CertGetCertificateContextProperty(
  75. pCert,
  76. CERT_SHA1_HASH_PROP_ID,
  77. rgbHash,
  78. &HashBlob.cbData
  79. ) || SHA1_HASH_LEN != HashBlob.cbData)
  80. return NULL;
  81. return CertFindCertificateInStore(
  82. hOtherStore,
  83. 0, // dwCertEncodingType
  84. 0, // dwFindFlags
  85. CERT_FIND_SHA1_HASH,
  86. (const void *) &HashBlob,
  87. NULL //pPrevCertContext
  88. );
  89. }
  90. BOOL IsCertificateInOtherStore(
  91. IN HCERTSTORE hOtherStore,
  92. IN PCCERT_CONTEXT pCert,
  93. OUT OPTIONAL PCCERT_CONTEXT *ppOtherCert
  94. )
  95. {
  96. PCCERT_CONTEXT pOtherCert;
  97. if (pOtherCert = FindCertificateInOtherStore(hOtherStore, pCert)) {
  98. if (ppOtherCert)
  99. *ppOtherCert = pOtherCert;
  100. else
  101. CertFreeCertificateContext(pOtherCert);
  102. return TRUE;
  103. } else {
  104. if (ppOtherCert)
  105. *ppOtherCert = NULL;
  106. return FALSE;
  107. }
  108. }
  109. BOOL DeleteCertificateFromOtherStore(
  110. IN HCERTSTORE hOtherStore,
  111. IN PCCERT_CONTEXT pCert
  112. )
  113. {
  114. BOOL fResult;
  115. PCCERT_CONTEXT pOtherCert;
  116. if (pOtherCert = FindCertificateInOtherStore(hOtherStore, pCert))
  117. fResult = CertDeleteCertificateFromStore(pOtherCert);
  118. else
  119. fResult = FALSE;
  120. return fResult;
  121. }
  122. //+-------------------------------------------------------------------------
  123. // Converts the bytes into UNICODE ASCII HEX
  124. //
  125. // Needs (cb * 2 + 1) * sizeof(WCHAR) bytes of space in wsz
  126. //--------------------------------------------------------------------------
  127. void BytesToWStr(DWORD cb, void* pv, LPWSTR wsz)
  128. {
  129. BYTE* pb = (BYTE*) pv;
  130. for (DWORD i = 0; i<cb; i++) {
  131. int b;
  132. b = (*pb & 0xF0) >> 4;
  133. *wsz++ = (b <= 9) ? b + L'0' : (b - 10) + L'A';
  134. b = *pb & 0x0F;
  135. *wsz++ = (b <= 9) ? b + L'0' : (b - 10) + L'A';
  136. pb++;
  137. }
  138. *wsz++ = 0;
  139. }
  140. //+-------------------------------------------------------------------------
  141. // Converts the UNICODE ASCII HEX to an array of bytes
  142. //--------------------------------------------------------------------------
  143. void WStrToBytes(
  144. IN const WCHAR wsz[MAX_HASH_NAME_LEN],
  145. OUT BYTE rgb[MAX_HASH_LEN],
  146. OUT DWORD *pcb
  147. )
  148. {
  149. BOOL fUpperNibble = TRUE;
  150. DWORD cb = 0;
  151. LPCWSTR pwsz = wsz;
  152. WCHAR wch;
  153. while (cb < MAX_HASH_LEN && (wch = *pwsz++)) {
  154. BYTE b;
  155. // only convert ascii hex characters 0..9, a..f, A..F
  156. // silently ignore all others
  157. if (wch >= L'0' && wch <= L'9')
  158. b = (BYTE) (wch - L'0');
  159. else if (wch >= L'a' && wch <= L'f')
  160. b = (BYTE) (10 + wch - L'a');
  161. else if (wch >= L'A' && wch <= L'F')
  162. b = (BYTE) (10 + wch - L'A');
  163. else
  164. continue;
  165. if (fUpperNibble) {
  166. rgb[cb] = b << 4;
  167. fUpperNibble = FALSE;
  168. } else {
  169. rgb[cb] = rgb[cb] | b;
  170. cb++;
  171. fUpperNibble = TRUE;
  172. }
  173. }
  174. *pcb = cb;
  175. }
  176. /////////////////////////////////////////////////////////////////////////////
  177. HRESULT CTrustDB::IsTrustedCert(DWORD dwEncodingType,
  178. PCCERT_CONTEXT pCert,
  179. LONG iLevel,
  180. BOOL fCommercial,
  181. PCCERT_CONTEXT *ppPubCert
  182. )
  183. {
  184. HRESULT hr;
  185. if (NULL == m_hPubStore)
  186. {
  187. return S_FALSE;
  188. }
  189. // See if the cert is in the trusted publisher store
  190. if (IsCertificateInOtherStore(m_hPubStore, pCert, ppPubCert))
  191. {
  192. hr = S_OK;
  193. }
  194. else
  195. {
  196. hr = S_FALSE;
  197. }
  198. return hr;
  199. }
  200. HRESULT CTrustDB::AddTrustCert(PCCERT_CONTEXT pCert, LONG iLevel, BOOL fLowerLevelsToo)
  201. {
  202. HRESULT hr;
  203. if (NULL == m_hPubStore)
  204. {
  205. return S_FALSE;
  206. }
  207. if (CertAddCertificateContextToStore(
  208. m_hPubStore,
  209. pCert,
  210. CERT_STORE_ADD_USE_EXISTING,
  211. NULL
  212. ))
  213. {
  214. hr = S_OK;
  215. }
  216. else
  217. {
  218. hr = HRESULT_FROM_WIN32(GetLastError());
  219. }
  220. return hr;
  221. }
  222. HRESULT CTrustDB::RemoveTrustCert(PCCERT_CONTEXT pCert, LONG iLevel, BOOL fLowerLevelsToo)
  223. {
  224. HRESULT hr;
  225. if (NULL == m_hPubStore)
  226. {
  227. return S_FALSE;
  228. }
  229. CertDuplicateCertificateContext(pCert);
  230. if (DeleteCertificateFromOtherStore(
  231. m_hPubStore,
  232. pCert
  233. ))
  234. {
  235. hr = S_OK;
  236. }
  237. else
  238. {
  239. hr = HRESULT_FROM_WIN32(GetLastError());
  240. }
  241. return hr;
  242. }
  243. HRESULT CTrustDB::RemoveTrustToken(LPWSTR szToken, LONG iLevel, BOOL fLowerLevelsToo)
  244. {
  245. HRESULT hr;
  246. DWORD cbHash;
  247. BYTE rgbHash[SHA1_HASH_LEN];
  248. CRYPT_DATA_BLOB HashBlob;
  249. PCCERT_CONTEXT pDeleteCert;
  250. if (NULL == m_hPubStore)
  251. {
  252. return S_FALSE;
  253. }
  254. WStrToBytes(szToken, rgbHash, &cbHash);
  255. HashBlob.pbData = rgbHash;
  256. HashBlob.cbData = cbHash;
  257. pDeleteCert = CertFindCertificateInStore(
  258. m_hPubStore,
  259. 0, // dwCertEncodingType
  260. 0, // dwFindFlags
  261. CERT_FIND_SHA1_HASH,
  262. (const void *) &HashBlob,
  263. NULL //pPrevCertContext
  264. );
  265. if (NULL == pDeleteCert)
  266. {
  267. hr = HRESULT_FROM_WIN32(GetLastError());
  268. }
  269. else
  270. {
  271. if (CertDeleteCertificateFromStore(pDeleteCert))
  272. {
  273. hr = S_OK;
  274. }
  275. else
  276. {
  277. hr = HRESULT_FROM_WIN32(GetLastError());
  278. }
  279. }
  280. return hr;
  281. }
  282. HRESULT CTrustDB::AreCommercialPublishersTrusted()
  283. // Answer whether commercial publishers are trusted.
  284. // S_OK == yes
  285. // S_FALSE == no
  286. // other == can't tell
  287. {
  288. return( S_FALSE );
  289. }
  290. HRESULT CTrustDB::SetCommercialPublishersTrust(BOOL fTrust)
  291. // Set the commercial trust setting
  292. {
  293. return( S_OK );
  294. }
  295. /////////////////////////////////////////////////////////////////////////////
  296. HRESULT CTrustDB::GetTrustList(
  297. // Return the (unsorted) list of trusted certificate names and their
  298. // corresponding display names
  299. //
  300. LONG iLevel, // the cert chain level to get
  301. BOOL fLowerLevelsToo, // included lower levels, remove duplicates
  302. TRUSTLISTENTRY** prgTrustList, // place to return the trust list
  303. ULONG* pcTrustList // place to return the size of the returned trust list
  304. ) {
  305. HRESULT hr = S_OK;
  306. ULONG cTrust = 0;
  307. ULONG cAllocTrust = 0;
  308. TRUSTLISTENTRY* rgTrustList = NULL;
  309. PCCERT_CONTEXT pCert = NULL;
  310. *prgTrustList = NULL;
  311. *pcTrustList = 0;
  312. if (NULL == m_hPubStore)
  313. {
  314. return S_OK;
  315. }
  316. // Get count of trusted publisher certs
  317. pCert = NULL;
  318. while (pCert = CertEnumCertificatesInStore(m_hPubStore, pCert))
  319. {
  320. cTrust++;
  321. }
  322. if (0 == cTrust)
  323. {
  324. return S_OK;
  325. }
  326. rgTrustList = (TRUSTLISTENTRY*) CoTaskMemAlloc(cTrust *
  327. sizeof(TRUSTLISTENTRY));
  328. if (NULL == rgTrustList)
  329. {
  330. return E_OUTOFMEMORY;
  331. }
  332. memset(rgTrustList, 0, cTrust * sizeof(TRUSTLISTENTRY));
  333. cAllocTrust = cTrust;
  334. cTrust = 0;
  335. pCert = NULL;
  336. while (pCert = CertEnumCertificatesInStore(m_hPubStore, pCert))
  337. {
  338. BYTE rgbHash[MAX_HASH_LEN];
  339. DWORD cbHash = MAX_HASH_LEN;
  340. // get the thumbprint
  341. if(!CertGetCertificateContextProperty(
  342. pCert,
  343. CERT_SHA1_HASH_PROP_ID,
  344. rgbHash,
  345. &cbHash))
  346. {
  347. continue;
  348. }
  349. // convert to a string
  350. BytesToWStr(cbHash, rgbHash, rgTrustList[cTrust].szToken);
  351. if (1 >= CertGetNameStringW(
  352. pCert,
  353. CERT_NAME_FRIENDLY_DISPLAY_TYPE,
  354. 0, // dwFlags
  355. NULL, // pvTypePara
  356. rgTrustList[cTrust].szDisplayName,
  357. sizeof(rgTrustList[cTrust].szDisplayName)/sizeof(WCHAR)
  358. ))
  359. {
  360. continue;
  361. }
  362. cTrust++;
  363. if (cTrust >= cAllocTrust)
  364. {
  365. CertFreeCertificateContext(pCert);
  366. break;
  367. }
  368. }
  369. if (0 == cTrust)
  370. {
  371. CoTaskMemFree(rgTrustList);
  372. rgTrustList = NULL;
  373. }
  374. *pcTrustList = cTrust;
  375. *prgTrustList = rgTrustList;
  376. return S_OK;
  377. }
  378. /////////////////////////////////////////////////////////////////////////////
  379. STDMETHODIMP CTrustDB::QueryInterface(REFIID iid, LPVOID* ppv)
  380. {
  381. return (m_punkOuter->QueryInterface(iid, ppv));
  382. }
  383. STDMETHODIMP_(ULONG) CTrustDB::AddRef(void)
  384. {
  385. return (m_punkOuter->AddRef());
  386. }
  387. STDMETHODIMP_(ULONG) CTrustDB::Release(void)
  388. {
  389. return (m_punkOuter->Release());
  390. }
  391. /////////////////////////////////////////////////////////////////////////////
  392. STDMETHODIMP CTrustDB::InnerQueryInterface(REFIID iid, LPVOID* ppv)
  393. {
  394. *ppv = NULL;
  395. while (TRUE)
  396. {
  397. if (iid == IID_IUnknown)
  398. {
  399. *ppv = (LPVOID)((IUnkInner*)this);
  400. break;
  401. }
  402. if (iid == IID_IPersonalTrustDB)
  403. {
  404. *ppv = (LPVOID) ((IPersonalTrustDB *) this);
  405. break;
  406. }
  407. return E_NOINTERFACE;
  408. }
  409. ((IUnknown*)*ppv)->AddRef();
  410. return S_OK;
  411. }
  412. STDMETHODIMP_(ULONG) CTrustDB::InnerAddRef(void)
  413. {
  414. return ++m_refs;
  415. }
  416. STDMETHODIMP_(ULONG) CTrustDB::InnerRelease(void)
  417. {
  418. ULONG refs = --m_refs;
  419. if (refs == 0)
  420. {
  421. m_refs = 1;
  422. delete this;
  423. }
  424. return refs;
  425. }
  426. /////////////////////////////////////////////////////////////////////////////
  427. HRESULT OpenTrustDB(IUnknown* punkOuter, REFIID iid, void** ppv)
  428. {
  429. return CTrustDB::CreateInstance(punkOuter, iid, ppv);
  430. }
  431. HRESULT CTrustDB::CreateInstance(IUnknown* punkOuter, REFIID iid, void** ppv)
  432. {
  433. HRESULT hr;
  434. *ppv = NULL;
  435. CTrustDB* pnew = new CTrustDB(punkOuter);
  436. if (pnew == NULL) return E_OUTOFMEMORY;
  437. if ((hr = pnew->Init()) != S_OK)
  438. {
  439. delete pnew;
  440. return hr;
  441. }
  442. IUnkInner* pme = (IUnkInner*)pnew;
  443. hr = pme->InnerQueryInterface(iid, ppv);
  444. pme->InnerRelease(); // balance starting ref cnt of one
  445. return hr;
  446. }
  447. CTrustDB::CTrustDB(IUnknown* punkOuter) :
  448. m_refs(1),
  449. m_hPubStore(NULL)
  450. {
  451. if (punkOuter == NULL)
  452. m_punkOuter = (IUnknown *) ((LPVOID) ((IUnkInner *) this));
  453. else
  454. m_punkOuter = punkOuter;
  455. }
  456. CTrustDB::~CTrustDB()
  457. {
  458. if (m_hPubStore)
  459. CertCloseStore(m_hPubStore, 0);
  460. }
  461. HRESULT CTrustDB::Init()
  462. {
  463. m_hPubStore = OpenTrustedPublisherStore();
  464. if (NULL == m_hPubStore)
  465. {
  466. return HRESULT_FROM_WIN32(GetLastError());
  467. }
  468. return S_OK;
  469. }