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.

3653 lines
122 KiB

  1. #include "pch.hxx"
  2. #ifndef WIN16
  3. #include <wintrust.h>
  4. #endif // !WIN16
  5. #include "demand.h"
  6. #include <stdio.h>
  7. #pragma warning(disable: 4127) // conditional expression is constant
  8. #ifndef CPD_REVOCATION_CHECK_NONE
  9. #define CPD_REVOCATION_CHECK_NONE 0x00010000
  10. #define CPD_REVOCATION_CHECK_END_CERT 0x00020000
  11. #define CPD_REVOCATION_CHECK_CHAIN 0x00040000
  12. #define CPD_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT 0x00080000
  13. #endif
  14. #define CPD_REVOCATION_MASK (CPD_REVOCATION_CHECK_NONE | \
  15. CPD_REVOCATION_CHECK_END_CERT | \
  16. CPD_REVOCATION_CHECK_CHAIN | \
  17. CPD_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT)
  18. #define TIME_DELTA_SECONDS 600 // 10 minutes in seconds
  19. #define FILETIME_SECOND 10000000 // 100ns intervals per second
  20. const char SzOID_CTL_ATTR_YESNO_TRUST[] = szOID_YESNO_TRUST_ATTR;
  21. const char SzOID_KP_CTL_USAGE_SIGNING[] = szOID_KP_CTL_USAGE_SIGNING;
  22. const BYTE RgbTrustYes[] = {2, 1, 1};
  23. const BYTE RgbTrustNo[] = {2, 1, 2};
  24. const BYTE RgbTrustParent[] = {2, 1, 0};
  25. const char SzOID_OLD_CTL_YESNO_TRUST[] = "1.3.6.1.4.1.311.1000.1.1.2";
  26. const char SzTrustListSigner[] = "Trust List Signer";
  27. const char SzTrustDN[] = "cn=%s, cn=Trust List Signer, cn=%s";
  28. const char SzPolicyKey[] =
  29. "SOFTWARE\\Microsoft\\Cryptography\\"szCERT_CERTIFICATE_ACTION_VERIFY;
  30. const char SzPolicyData[] = "PolicyFlags";
  31. const DWORD CTL_MODIFY_ERR_NOT_YET_PROCESSED = (DWORD) -1;
  32. extern HINSTANCE HinstDll;
  33. PCCERT_CONTEXT CreateTrustSigningCert(HWND hwnd, HCERTSTORE hcertstoreRoot, BOOL);
  34. const int COtherProviders = 2;
  35. #ifndef WIN16
  36. LPWSTR RgszProvider[] = {
  37. L"CA", L"MY"
  38. };
  39. #else // WIN16
  40. LPWSTR RgszProvider[] = {
  41. "CA", "MY"
  42. };
  43. #endif // !WIN16
  44. #ifdef NT5BUILD
  45. typedef struct {
  46. DWORD cbSize;
  47. DWORD dwFlags;
  48. DWORD cRootStores;
  49. HCERTSTORE * rghRootStores;
  50. DWORD cTrustStores;
  51. HCERTSTORE * rghTrustStores;
  52. LPCSTR pszUsageOid;
  53. HCRYPTDEFAULTCONTEXT hdefaultcontext; // from CryptInstallDefaultContext
  54. } INTERNAL_DATA, * PINTERNAL_DATA;
  55. const GUID MyGuid = CERT_CERTIFICATE_ACTION_VERIFY;
  56. #pragma message("Building for NT5")
  57. void FreeWVTHandle(HANDLE hWVTState) {
  58. if (hWVTState) {
  59. HRESULT hr;
  60. WINTRUST_DATA data = {0};
  61. data.cbStruct = sizeof(WINTRUST_DATA);
  62. data.pPolicyCallbackData = NULL;
  63. data.pSIPClientData = NULL;
  64. data.dwUIChoice = WTD_UI_NONE;
  65. data.fdwRevocationChecks = WTD_REVOKE_NONE;
  66. data.dwUnionChoice = WTD_CHOICE_BLOB;
  67. data.pBlob = NULL; // &blob;
  68. data.dwStateAction = WTD_STATEACTION_CLOSE;
  69. data.hWVTStateData = hWVTState;
  70. hr = WinVerifyTrust(NULL, (GUID *)&GuidCertValidate, &data);
  71. }
  72. }
  73. HRESULT HrDoTrustWork(PCCERT_CONTEXT pccertToCheck, DWORD dwControl,
  74. DWORD dwValidityMask,
  75. DWORD /*cPurposes*/, LPSTR * rgszPurposes, HCRYPTPROV hprov,
  76. DWORD cRoots, HCERTSTORE * rgRoots,
  77. DWORD cCAs, HCERTSTORE * rgCAs,
  78. DWORD cTrust, HCERTSTORE * rgTrust,
  79. PFNTRUSTHELPER pfn, DWORD lCustData,
  80. PCCertFrame * /*ppcf*/, DWORD * pcNodes,
  81. PCCertFrame * rgpcfResult,
  82. HANDLE * phReturnStateData) // optional: return WinVerifyTrust state handle here
  83. {
  84. DWORD cbData;
  85. DWORD cCerts = 0;
  86. WINTRUST_BLOB_INFO blob = {0};
  87. WINTRUST_DATA data = {0};
  88. DWORD dwErrors;
  89. BOOL f;
  90. HRESULT hr;
  91. int i;
  92. DWORD j;
  93. PCCERT_CONTEXT * rgCerts = NULL;
  94. DWORD * rgdwErrors = NULL;
  95. DATA_BLOB * rgblobTrust = NULL;
  96. CERT_VERIFY_CERTIFICATE_TRUST trust;
  97. UNALIGNED CRYPT_ATTR_BLOB *pVal = NULL;
  98. data.cbStruct = sizeof(WINTRUST_DATA);
  99. data.pPolicyCallbackData = NULL;
  100. data.pSIPClientData = NULL;
  101. data.dwUIChoice = WTD_UI_NONE;
  102. data.fdwRevocationChecks = WTD_REVOKE_NONE;
  103. data.dwUnionChoice = WTD_CHOICE_BLOB;
  104. data.pBlob = &blob;
  105. if (phReturnStateData) {
  106. data.dwStateAction = WTD_STATEACTION_VERIFY;
  107. }
  108. blob.cbStruct = sizeof(WINTRUST_BLOB_INFO);
  109. blob.pcwszDisplayName = NULL;
  110. blob.cbMemObject = sizeof(trust);
  111. blob.pbMemObject = (LPBYTE) &trust;
  112. trust.cbSize = sizeof(trust);
  113. trust.pccert = pccertToCheck;
  114. trust.dwFlags = (CERT_TRUST_DO_FULL_SEARCH |
  115. CERT_TRUST_PERMIT_MISSING_CRLS |
  116. CERT_TRUST_DO_FULL_TRUST | dwControl);
  117. trust.dwIgnoreErr = dwValidityMask;
  118. trust.pdwErrors = &dwErrors;
  119. // Assert(cPurposes == 1);
  120. if (rgszPurposes != NULL) {
  121. trust.pszUsageOid = rgszPurposes[0];
  122. }
  123. else {
  124. trust.pszUsageOid = NULL;
  125. }
  126. trust.hprov = hprov;
  127. trust.cRootStores = cRoots;
  128. trust.rghstoreRoots = rgRoots;
  129. trust.cStores = cCAs;
  130. trust.rghstoreCAs = rgCAs;
  131. trust.cTrustStores = cTrust;
  132. trust.rghstoreTrust = rgTrust;
  133. trust.lCustData = lCustData;
  134. trust.pfnTrustHelper = pfn;
  135. trust.pcChain = &cCerts;
  136. trust.prgChain = &rgCerts;
  137. trust.prgdwErrors = &rgdwErrors;
  138. trust.prgpbTrustInfo = &rgblobTrust;
  139. hr = WinVerifyTrust(NULL, (GUID *) &GuidCertValidate, &data);
  140. if ((TRUST_E_CERT_SIGNATURE == hr) ||
  141. (CERT_E_REVOKED == hr) ||
  142. (CERT_E_REVOCATION_FAILURE == hr)) {
  143. hr = S_OK;
  144. }
  145. else if (FAILED(hr)) {
  146. return hr;
  147. }
  148. if (cCerts == 0) {
  149. return(E_INVALIDARG);
  150. }
  151. if (phReturnStateData) {
  152. *phReturnStateData = data.hWVTStateData; // Caller must use WinVerifyTrust to free
  153. }
  154. //Assert( cCerts <= 20);
  155. *pcNodes = cCerts;
  156. for (i=cCerts-1; i >= 0; i--) {
  157. rgpcfResult[i] = new CCertFrame(rgCerts[i]);
  158. if(!rgpcfResult[i])
  159. {
  160. hr=E_OUTOFMEMORY;
  161. goto ExitHere;
  162. }
  163. rgpcfResult[i]->m_dwFlags = rgdwErrors[i];
  164. if (rgszPurposes == NULL) {
  165. continue;
  166. }
  167. rgpcfResult[i]->m_cTrust = 1;
  168. rgpcfResult[i]->m_rgTrust = new STrustDesc[1];
  169. memset(rgpcfResult[i]->m_rgTrust, 0, sizeof(STrustDesc));
  170. //
  171. // We are going to fill in the trust information which we use
  172. // to fill in the fields of the dialog box.
  173. //
  174. // Start with the question of the cert being self signed
  175. //
  176. rgpcfResult[i]->m_fSelfSign = WTHelperCertIsSelfSigned(X509_ASN_ENCODING, rgCerts[i]->pCertInfo);
  177. //
  178. // We may or may not have trust data information returned, we now
  179. // build up the trust info for a single cert
  180. //
  181. // If we don't have any explicit data, then we just chain the data
  182. // down from the next level up.
  183. //
  184. if (rgblobTrust[i].cbData == 0) {
  185. // chain:
  186. rgpcfResult[i]->m_rgTrust[0].fExplicitTrust = FALSE;
  187. rgpcfResult[i]->m_rgTrust[0].fExplicitDistrust = FALSE;
  188. //
  189. // We return a special code to say that we found it in the root store
  190. //
  191. rgpcfResult[i]->m_rgTrust[0].fRootStore = rgpcfResult[i]->m_fRootStore =
  192. (rgblobTrust[i].pbData == (LPBYTE) 1);
  193. if (i != (int) (cCerts-1)) {
  194. rgpcfResult[i]->m_rgTrust[0].fTrust = rgpcfResult[i+1]->m_rgTrust[0].fTrust;
  195. rgpcfResult[i]->m_rgTrust[0].fDistrust= rgpcfResult[i+1]->m_rgTrust[0].fDistrust;
  196. } else {
  197. // Oops -- there is no level up one, so just make some
  198. // good defaults
  199. //
  200. rgpcfResult[i]->m_rgTrust[0].fTrust = rgpcfResult[i]->m_fRootStore;
  201. rgpcfResult[i]->m_rgTrust[0].fDistrust= FALSE;
  202. }
  203. }
  204. else {
  205. //
  206. //
  207. f = CryptDecodeObject(X509_ASN_ENCODING, "1.3.6.1.4.1.311.16.1.1",
  208. rgblobTrust[i].pbData, rgblobTrust[i].cbData,
  209. 0, NULL, &cbData);
  210. if (!f || (cbData == 0)) {
  211. chain:
  212. rgpcfResult[i]->m_fRootStore = FALSE;
  213. rgpcfResult[i]->m_rgTrust[0].fRootStore = rgpcfResult[i]->m_fRootStore;
  214. rgpcfResult[i]->m_rgTrust[0].fExplicitTrust = FALSE;
  215. rgpcfResult[i]->m_rgTrust[0].fExplicitDistrust = FALSE;
  216. if (i != (int) (cCerts-1)) {
  217. rgpcfResult[i]->m_rgTrust[0].fTrust = rgpcfResult[i+1]->m_rgTrust[0].fTrust;
  218. rgpcfResult[i]->m_rgTrust[0].fDistrust = rgpcfResult[i+1]->m_rgTrust[0].fDistrust;
  219. }
  220. else {
  221. rgpcfResult[i]->m_rgTrust[0].fTrust = FALSE;
  222. rgpcfResult[i]->m_rgTrust[0].fDistrust= FALSE;
  223. }
  224. }
  225. else {
  226. PCRYPT_ATTRIBUTES pattrs;
  227. pattrs = (PCRYPT_ATTRIBUTES) malloc(cbData);
  228. if (pattrs == NULL) {
  229. goto chain;
  230. }
  231. CryptDecodeObject(X509_ASN_ENCODING, "1.3.6.1.4.1.311.16.1.1",
  232. rgblobTrust[i].pbData, rgblobTrust[i].cbData,
  233. 0, pattrs, &cbData);
  234. for (j=0; j<pattrs->cAttr; j++) {
  235. if ((strcmp(pattrs->rgAttr[j].pszObjId, SzOID_CTL_ATTR_YESNO_TRUST) == 0) ||
  236. (strcmp(pattrs->rgAttr[j].pszObjId, SzOID_OLD_CTL_YESNO_TRUST) == 0))
  237. {
  238. pVal = &(pattrs->rgAttr[j].rgValue[0]);
  239. if ((pVal->cbData == sizeof(RgbTrustYes)) &&
  240. (memcmp(pVal->pbData,
  241. RgbTrustYes, sizeof(RgbTrustYes)) == 0)) {
  242. rgpcfResult[i]->m_rgTrust[0].fExplicitTrust = TRUE;
  243. rgpcfResult[i]->m_rgTrust[0].fTrust = TRUE;
  244. break;
  245. }
  246. else if ((pVal->cbData == sizeof(RgbTrustNo)) &&
  247. (memcmp(pVal->pbData,
  248. RgbTrustNo, sizeof(RgbTrustNo)) == 0)) {
  249. rgpcfResult[i]->m_rgTrust[0].fExplicitDistrust = TRUE;
  250. rgpcfResult[i]->m_rgTrust[0].fDistrust= TRUE;
  251. break;
  252. }
  253. else if ((pVal->cbData == sizeof(RgbTrustParent)) &&
  254. (memcmp(pVal->pbData,
  255. RgbTrustParent, sizeof(RgbTrustParent)) == 0)) {
  256. goto chain;
  257. }
  258. else {
  259. goto chain;
  260. }
  261. }
  262. }
  263. if (j == pattrs->cAttr) {
  264. goto chain;
  265. }
  266. }
  267. }
  268. }
  269. //
  270. // Clean up all returned values
  271. //
  272. ExitHere:
  273. if (rgCerts != NULL) {
  274. //bobn If the loop has been broken because "new" failed, free what we allocated so far...
  275. for ((hr==E_OUTOFMEMORY?i++:i=0); i< (int) cCerts; i++) {
  276. //@ REVIEW check CertFreeCertificateContext to see if it will accept a null pointer
  277. //if it will, we can remove the E_OUTOFMEMORY test above.
  278. CertFreeCertificateContext(rgCerts[i]);
  279. }
  280. LocalFree(rgCerts);
  281. }
  282. if (rgdwErrors != NULL) LocalFree(rgdwErrors);
  283. if (rgblobTrust != NULL) {
  284. for (i=0; i<(int) cCerts; i++) {
  285. if (rgblobTrust[i].cbData > 0) {
  286. LocalFree(rgblobTrust[i].pbData);
  287. }
  288. }
  289. LocalFree(rgblobTrust);
  290. }
  291. return hr;
  292. }
  293. HRESULT CertTrustInit(PCRYPT_PROVIDER_DATA pdata)
  294. {
  295. DWORD cbSize;
  296. DWORD dwPolicy = 0;
  297. DWORD dwType;
  298. HKEY hkPolicy;
  299. HCERTSTORE hstore;
  300. DWORD i;
  301. PCERT_VERIFY_CERTIFICATE_TRUST pcerttrust;
  302. CRYPT_PROVIDER_PRIVDATA privdata;
  303. PINTERNAL_DATA pmydata;
  304. //
  305. // Make sure all of the fields we want are there. If not then it is a
  306. // complete fatal error.
  307. //
  308. if (! WVT_ISINSTRUCT(CRYPT_PROVIDER_DATA, pdata->cbStruct, pszUsageOID)) {
  309. return(E_FAIL);
  310. }
  311. if (pdata->pWintrustData->pBlob->cbStruct < sizeof(WINTRUST_BLOB_INFO)) {
  312. pdata->dwError = ERROR_INVALID_PARAMETER;
  313. return S_FALSE;
  314. }
  315. pcerttrust = (PCERT_VERIFY_CERTIFICATE_TRUST)
  316. pdata->pWintrustData->pBlob->pbMemObject;
  317. if ((pcerttrust == NULL) ||
  318. (pcerttrust->cbSize < sizeof(*pcerttrust))) {
  319. pdata->dwError = ERROR_INVALID_PARAMETER;
  320. return S_FALSE;
  321. }
  322. if (pdata->dwError != 0) {
  323. return S_FALSE;
  324. }
  325. for (i=TRUSTERROR_STEP_FINAL_WVTINIT; i<TRUSTERROR_STEP_FINAL_CERTCHKPROV; i++) {
  326. if (pdata->padwTrustStepErrors[i] != 0) {
  327. return S_FALSE;
  328. }
  329. }
  330. //
  331. // Allocate the space to hold the internal data we use to talk to ourselfs with
  332. //
  333. cbSize = sizeof(INTERNAL_DATA) + (pcerttrust->cRootStores + 1 +
  334. pcerttrust->cTrustStores + 1) * sizeof(HCERTSTORE);
  335. pmydata = (PINTERNAL_DATA)pdata->psPfns->pfnAlloc(cbSize);
  336. if (! pmydata) {
  337. return(E_OUTOFMEMORY);
  338. }
  339. memset(pmydata, 0, sizeof(*pmydata));
  340. pmydata->cbSize = sizeof(*pmydata);
  341. pmydata->rghRootStores = (HCERTSTORE *) (((LPBYTE) pmydata) + sizeof(*pmydata));
  342. pmydata->rghTrustStores = &pmydata->rghRootStores[pcerttrust->cRootStores+1];
  343. privdata.cbStruct = sizeof(privdata);
  344. memcpy(&privdata.gProviderID, &MyGuid, sizeof(GUID));
  345. privdata.cbProvData = cbSize;
  346. privdata.pvProvData = pmydata;
  347. pdata->psPfns->pfnAddPrivData2Chain(pdata, &privdata);
  348. pmydata->pszUsageOid = pcerttrust->pszUsageOid;
  349. pmydata->dwFlags = pcerttrust->dwFlags;
  350. //
  351. // Set the restriction OID back into the full provider information to
  352. // make sure chaining is correct
  353. //
  354. pdata->pszUsageOID = pcerttrust->pszUsageOid;
  355. //
  356. // Retrieve the default revocation check from the policy flags in the
  357. // registry.
  358. //
  359. if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, SzPolicyKey, 0, KEY_READ,
  360. &hkPolicy) == ERROR_SUCCESS) {
  361. cbSize = sizeof(dwPolicy);
  362. if ((ERROR_SUCCESS != RegQueryValueExA(hkPolicy,
  363. SzPolicyData,
  364. 0, &dwType,
  365. (LPBYTE)&dwPolicy,
  366. &cbSize)) ||
  367. (REG_DWORD != dwType)) {
  368. dwPolicy = 0;
  369. }
  370. RegCloseKey(hkPolicy);
  371. }
  372. //
  373. // Set the default revocation check level
  374. //
  375. if (dwPolicy & ACTION_REVOCATION_DEFAULT_ONLINE) {
  376. // Allow full online revocation checking
  377. pdata->dwProvFlags |= CPD_REVOCATION_CHECK_CHAIN;
  378. }
  379. else if (dwPolicy & ACTION_REVOCATION_DEFAULT_CACHE) {
  380. // Allow local revocation checks only, do not hit the network
  381. // NOTE: Currently not supported by NT Crypto, default to none
  382. //Assert(!dwPolicy & ACTION_REVOCATION_DEFAULT_CACHE)
  383. pdata->dwProvFlags |= CPD_REVOCATION_CHECK_NONE;
  384. }
  385. else {
  386. // For backwards compatibility default to no revocation
  387. pdata->dwProvFlags |= CPD_REVOCATION_CHECK_NONE;
  388. }
  389. //
  390. // Update the revocation state based on what the user has specifically
  391. // requested.
  392. //
  393. if (pcerttrust->dwFlags & CRYPTDLG_REVOCATION_ONLINE) {
  394. // Allow full online revocation checking
  395. pdata->dwProvFlags &= ~CPD_REVOCATION_MASK;
  396. pdata->dwProvFlags |= CPD_REVOCATION_CHECK_CHAIN;
  397. }
  398. else if (pcerttrust->dwFlags & CRYPTDLG_REVOCATION_CACHE) {
  399. // Allow local revocation checks only, do not hit the network.
  400. // NOTE: Currently not supported by NT, for now we just ignore
  401. // the revocakation
  402. // Assert(!pcerttrust->dwFlags & CRYPTDLG_REVOCATION_CACHE);
  403. pdata->dwProvFlags &= ~CPD_REVOCATION_MASK;
  404. pdata->dwProvFlags |= CPD_REVOCATION_CHECK_NONE;
  405. }
  406. else if (pcerttrust->dwFlags & CRYPTDLG_REVOCATION_NONE) {
  407. // Allow full online revocation checking
  408. pdata->dwProvFlags &= ~CPD_REVOCATION_MASK;
  409. pdata->dwProvFlags |= CPD_REVOCATION_CHECK_NONE;
  410. }
  411. //
  412. // Set the default crypt provider so we can make sure that ours is used
  413. //
  414. if (pcerttrust->hprov != NULL) {
  415. if (!CryptInstallDefaultContext(pcerttrust->hprov,
  416. CRYPT_DEFAULT_CONTEXT_CERT_SIGN_OID,
  417. szOID_OIWSEC_md5RSA, 0, NULL,
  418. &pmydata->hdefaultcontext)) {
  419. return S_FALSE;
  420. }
  421. }
  422. //
  423. // Setup the stores to be used by the search step.
  424. //
  425. // Root ("God") stores
  426. //
  427. if (pcerttrust->cRootStores != 0) {
  428. for (i=0; i<pcerttrust->cRootStores; i++) {
  429. if (!pdata->psPfns->pfnAddStore2Chain(pdata,
  430. pcerttrust->rghstoreRoots[i])) {
  431. pdata->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_INITPROV] = ERROR_NOT_ENOUGH_MEMORY;
  432. return S_FALSE;
  433. }
  434. pmydata->rghRootStores[i] = CertDuplicateStore(pcerttrust->rghstoreRoots[i]);
  435. }
  436. pmydata->cRootStores = i;
  437. }
  438. else {
  439. hstore = CertOpenStore(CERT_STORE_PROV_SYSTEM, X509_ASN_ENCODING,
  440. pcerttrust->hprov, CERT_SYSTEM_STORE_CURRENT_USER |
  441. CERT_STORE_NO_CRYPT_RELEASE_FLAG,
  442. L"Root");
  443. if (hstore == NULL) {
  444. pdata->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_INITPROV] = ::GetLastError();
  445. return S_FALSE;
  446. }
  447. if (!pdata->psPfns->pfnAddStore2Chain(pdata, hstore)) {
  448. CertCloseStore(hstore, 0);
  449. pmydata->rghRootStores[0] = CertDuplicateStore(pcerttrust->rghstoreRoots[i]);
  450. return S_FALSE;
  451. }
  452. pmydata->rghRootStores[0] = CertDuplicateStore(hstore);
  453. pmydata->cRootStores = 1;
  454. CertCloseStore(hstore, 0);
  455. }
  456. // "Trust" stores
  457. if (pcerttrust->cTrustStores != 0) {
  458. for (i=0; i<pcerttrust->cTrustStores; i++) {
  459. pmydata->rghTrustStores[i] = CertDuplicateStore(pcerttrust->rghstoreTrust[i]);
  460. }
  461. pmydata->cTrustStores = i;
  462. }
  463. else {
  464. hstore = CertOpenStore(CERT_STORE_PROV_SYSTEM, X509_ASN_ENCODING,
  465. pcerttrust->hprov, CERT_SYSTEM_STORE_CURRENT_USER |
  466. CERT_STORE_NO_CRYPT_RELEASE_FLAG,
  467. L"Trust");
  468. if (hstore == NULL) {
  469. pdata->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_INITPROV] = ::GetLastError();
  470. return S_FALSE;
  471. }
  472. pmydata->rghTrustStores[0] = CertDuplicateStore(hstore);
  473. pmydata->cTrustStores = 1;
  474. CertCloseStore(hstore, 0);
  475. }
  476. // "CA" stores
  477. if (pcerttrust->cStores != 0) {
  478. for (i=0; i<pcerttrust->cStores; i++) {
  479. if (!pdata->psPfns->pfnAddStore2Chain(pdata,
  480. pcerttrust->rghstoreCAs[i])) {
  481. pdata->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_INITPROV] = ERROR_NOT_ENOUGH_MEMORY;
  482. return S_FALSE;
  483. }
  484. }
  485. }
  486. if ((pcerttrust->cStores == 0) ||
  487. (pcerttrust->dwFlags & CERT_TRUST_ADD_CERT_STORES)) {
  488. for (i=0; i<COtherProviders; i++) {
  489. hstore = CertOpenStore(CERT_STORE_PROV_SYSTEM, X509_ASN_ENCODING,
  490. pcerttrust->hprov, CERT_SYSTEM_STORE_CURRENT_USER |
  491. CERT_STORE_NO_CRYPT_RELEASE_FLAG,
  492. RgszProvider[i]);
  493. if (hstore == NULL) {
  494. pdata->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_INITPROV] = ::GetLastError();
  495. return S_FALSE;
  496. }
  497. if (!pdata->psPfns->pfnAddStore2Chain(pdata, hstore)) {
  498. CertCloseStore(hstore, 0);
  499. pdata->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_INITPROV] = ERROR_NOT_ENOUGH_MEMORY;
  500. return S_FALSE;
  501. }
  502. CertCloseStore(hstore, 0);
  503. }
  504. }
  505. //
  506. // We have exactly one signature object to be added in, that is the certificate
  507. // that we are going to verify.
  508. //
  509. CRYPT_PROVIDER_SGNR sgnr;
  510. memset(&sgnr, 0, sizeof(sgnr));
  511. sgnr.cbStruct = sizeof(sgnr);
  512. GetSystemTimeAsFileTime(&sgnr.sftVerifyAsOf);
  513. // memcpy(&sgnr.sftVerifyAsOf, &pcerttrust->pccert->pCertInfo->NotBefore,
  514. // sizeof(FILETIME));
  515. // sgnr.csCertChain = 0;
  516. // sgnr.pasCertChain = NULL;
  517. // sgnr.dwSignerType = 0;
  518. // sgnr.psSigner = NULL;
  519. // sgnr.dwError = 0;
  520. // sgnr.csCounterSigners = 0;
  521. // sgnr.pasCounterSigners = NULL;
  522. if (!pdata->psPfns->pfnAddSgnr2Chain(pdata, FALSE, 0, &sgnr)) {
  523. pdata->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_INITPROV] = ERROR_NOT_ENOUGH_MEMORY;
  524. return S_FALSE;
  525. }
  526. if (!pdata->psPfns->pfnAddCert2Chain(pdata, 0, FALSE, 0, pcerttrust->pccert)) {
  527. pdata->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_INITPROV] = ERROR_NOT_ENOUGH_MEMORY;
  528. return S_FALSE;
  529. }
  530. return S_OK;
  531. }
  532. #ifdef DEBUG
  533. void DebugFileTime(FILETIME ft) {
  534. SYSTEMTIME st = {0};
  535. TCHAR szBuffer[256];
  536. FileTimeToSystemTime(&ft, &st);
  537. wnsprintf(szBuffer, ARRAYSIZE(szBuffer), L"%02d/%02d/%04d %02d:%02d:%02d\n", st.wMonth, st.wDay, st.wYear, st.wHour, st.wMinute, st.wSecond);
  538. OutputDebugString(szBuffer);
  539. }
  540. #endif
  541. LONG CertVerifyTimeValidityWithDelta(LPFILETIME pTimeToVerify, PCERT_INFO pCertInfo, ULONG ulOffset) {
  542. LONG lRet;
  543. FILETIME ftNow;
  544. FILETIME ftDelta;
  545. __int64 i64Delta;
  546. __int64 i64Offset;
  547. lRet = CertVerifyTimeValidity(pTimeToVerify, pCertInfo);
  548. if (lRet < 0) {
  549. if (! pTimeToVerify) {
  550. // Get the current time in filetime format so we can add the offset
  551. GetSystemTimeAsFileTime(&ftNow);
  552. pTimeToVerify = &ftNow;
  553. }
  554. #ifdef DEBUG
  555. DebugFileTime(*pTimeToVerify);
  556. #endif
  557. i64Delta = pTimeToVerify->dwHighDateTime;
  558. i64Delta = i64Delta << 32;
  559. i64Delta += pTimeToVerify->dwLowDateTime;
  560. // Add the offset into the original time to get us a new time to check
  561. i64Offset = FILETIME_SECOND;
  562. i64Offset *= ulOffset;
  563. i64Delta += i64Offset;
  564. ftDelta.dwLowDateTime = (ULONG)i64Delta & 0xFFFFFFFF;
  565. ftDelta.dwHighDateTime = (ULONG)(i64Delta >> 32);
  566. #ifdef DEBUG
  567. DebugFileTime(ftDelta);
  568. #endif
  569. lRet = CertVerifyTimeValidity(&ftDelta, pCertInfo);
  570. }
  571. return(lRet);
  572. }
  573. //// FCheckCTLCert
  574. //
  575. // Description:
  576. // This function is called when we find a CTL signed by a certificate. At this
  577. // point we are going to check to see if we believe in the cert which was
  578. // used to sign the CTL.
  579. //
  580. // We know that the certificate was already one of the ROOT stores and is
  581. // therefore explicity trusted as this is enforced by the caller.
  582. //
  583. BOOL FCheckCTLCert(PCCERT_CONTEXT pccert)
  584. {
  585. DWORD cbData;
  586. BOOL f;
  587. FILETIME ftZero;
  588. DWORD i;
  589. PCERT_ENHKEY_USAGE pUsage;
  590. memset(&ftZero, 0, sizeof(ftZero));
  591. //
  592. // Start by checking the time validity of the cert. We are going to
  593. // allow two special cases as well as the time being valid.
  594. //
  595. // 1. The start and end time are the same -- and indication that we
  596. // made this in an earlier incarnation, or
  597. // 2. The end time is 0.
  598. //
  599. if ((memcmp(&pccert->pCertInfo->NotBefore, &pccert->pCertInfo->NotAfter,
  600. sizeof(FILETIME)) == 0) ||
  601. memcmp(&pccert->pCertInfo->NotAfter, &ftZero, sizeof(FILETIME)) == 0) {
  602. DWORD err;
  603. HCERTSTORE hcertstore;
  604. HKEY hkey;
  605. PCCERT_CONTEXT pccertNew;
  606. PCCERT_CONTEXT pccertOld;
  607. err = RegOpenKeyExA(HKEY_CURRENT_USER,
  608. "Software\\Microsoft\\SystemCertificates\\ROOT",
  609. 0, KEY_ALL_ACCESS, &hkey);
  610. hcertstore = CertOpenStore(CERT_STORE_PROV_REG, X509_ASN_ENCODING,
  611. NULL, 0, hkey);
  612. if (hcertstore != NULL) {
  613. pccertOld = CertGetSubjectCertificateFromStore(hcertstore,
  614. X509_ASN_ENCODING, pccert->pCertInfo);
  615. pccertNew = CreateTrustSigningCert(NULL, hcertstore, FALSE);
  616. CertFreeCertificateContext(pccertNew);
  617. if (pccertOld != NULL) {
  618. CertDeleteCertificateFromStore(pccertOld);
  619. }
  620. CertCloseStore(hcertstore, 0);
  621. }
  622. RegCloseKey(hkey);
  623. }
  624. else if (CertVerifyTimeValidityWithDelta(NULL, pccert->pCertInfo,
  625. TIME_DELTA_SECONDS) != 0) {
  626. return FALSE;
  627. }
  628. //
  629. // Must have a correct enhanced key usage to be viable.
  630. //
  631. // Crack the usage on the cert
  632. f = CertGetEnhancedKeyUsage(pccert, 0, NULL, &cbData);
  633. if (!f || (cbData == 0)) {
  634. return FALSE;
  635. }
  636. pUsage = (PCERT_ENHKEY_USAGE) malloc(cbData);
  637. if (pUsage == NULL) {
  638. return FALSE;
  639. }
  640. if (!CertGetEnhancedKeyUsage(pccert, 0, pUsage, &cbData)) {
  641. free(pUsage);
  642. return FALSE;
  643. }
  644. //
  645. // Look for the CTL_USAGE_SIGNING purpose on the cert. If its not there
  646. // then we don't allow it to be used.
  647. //
  648. for (i=0; i<pUsage->cUsageIdentifier; i++) {
  649. if (strcmp(pUsage->rgpszUsageIdentifier[i],
  650. szOID_KP_CTL_USAGE_SIGNING) == 0) {
  651. break;
  652. }
  653. }
  654. if (i == pUsage->cUsageIdentifier) {
  655. free(pUsage);
  656. return FALSE;
  657. }
  658. free(pUsage);
  659. //
  660. // Add any other tests.
  661. //
  662. return TRUE;
  663. }
  664. //// CertTrustCertPolicy
  665. //
  666. // Description:
  667. // This code looks for trust information and puts it into the certificate
  668. // chain. The behavior that we follow is going to depend on what type of
  669. // searching we are going to look for.
  670. //
  671. // If we are just looking for trust, then we follow up the CTL looking for
  672. // trust information.
  673. //
  674. BOOL CertTrustCertPolicy(PCRYPT_PROVIDER_DATA pdata, DWORD, BOOL, DWORD)
  675. {
  676. DWORD cb;
  677. BOOL f;
  678. BOOL fContinue = TRUE;
  679. DWORD i;
  680. CTL_VERIFY_USAGE_STATUS vus;
  681. CTL_VERIFY_USAGE_PARA vup;
  682. PCCTL_CONTEXT pctlTrust = NULL;
  683. PCRYPT_PROVIDER_CERT ptcert;
  684. CTL_USAGE ctlusage;
  685. PCCERT_CONTEXT pccert = NULL;
  686. PCRYPT_PROVIDER_SGNR psigner;
  687. PINTERNAL_DATA pmydata;
  688. PCRYPT_PROVIDER_PRIVDATA pprivdata;
  689. BYTE rgbHash[20];
  690. CRYPT_HASH_BLOB blob;
  691. //
  692. // Make sure all of the fields we want are there. If not then it is a
  693. // complete fatal error.
  694. //
  695. if (! WVT_ISINSTRUCT(CRYPT_PROVIDER_DATA, pdata->cbStruct, pszUsageOID)) {
  696. fContinue = FALSE;
  697. goto Exit;
  698. }
  699. if (pdata->pWintrustData->pBlob->cbStruct < sizeof(WINTRUST_BLOB_INFO)) {
  700. pdata->dwError = ERROR_INVALID_PARAMETER;
  701. fContinue = FALSE;
  702. goto Exit;
  703. }
  704. //
  705. // Look to see if we already have an error to deal with
  706. //
  707. if (pdata->dwError != 0) {
  708. fContinue = FALSE;
  709. goto Exit;
  710. }
  711. for (i=TRUSTERROR_STEP_FINAL_WVTINIT; i<TRUSTERROR_STEP_FINAL_CERTCHKPROV; i++) {
  712. if (pdata->padwTrustStepErrors[i] != 0) {
  713. fContinue = FALSE;
  714. goto Exit;
  715. }
  716. }
  717. //
  718. // Get our internal data structure
  719. //
  720. pprivdata = WTHelperGetProvPrivateDataFromChain(pdata, (LPGUID) &MyGuid);
  721. if (pprivdata)
  722. pmydata = (PINTERNAL_DATA)pprivdata->pvProvData;
  723. else
  724. {
  725. fContinue = FALSE;
  726. goto Exit;
  727. }
  728. //
  729. // We only work with a single signer --
  730. psigner = WTHelperGetProvSignerFromChain(pdata, 0, FALSE, 0);
  731. if (psigner == NULL)
  732. {
  733. fContinue = FALSE;
  734. goto Exit;
  735. }
  736. //
  737. // Extract the certificate at the top of the stack
  738. //
  739. ptcert = WTHelperGetProvCertFromChain(psigner, psigner->csCertChain-1);
  740. //
  741. // Does this certificate meet the definitions of "TRUSTED".
  742. //
  743. // Definition #1. It exists in a Root store
  744. //
  745. blob.cbData = sizeof(rgbHash);
  746. blob.pbData = rgbHash;
  747. cb = sizeof(rgbHash);
  748. CertGetCertificateContextProperty(ptcert->pCert, CERT_SHA1_HASH_PROP_ID,
  749. rgbHash, &cb);
  750. for (i=0; i<pmydata->cRootStores; i++) {
  751. pccert = CertFindCertificateInStore(pmydata->rghRootStores[i], X509_ASN_ENCODING,
  752. 0, CERT_FIND_SHA1_HASH, &blob, NULL);
  753. if (pccert != NULL) {
  754. ptcert->fTrustedRoot = TRUE;
  755. fContinue = FALSE;
  756. goto Exit;
  757. }
  758. }
  759. //
  760. // Build up the structures we will use to do a search in the
  761. // trust stores
  762. //
  763. memset(&ctlusage, 0, sizeof(ctlusage));
  764. ctlusage.cUsageIdentifier = 1;
  765. ctlusage.rgpszUsageIdentifier = (LPSTR *) &pmydata->pszUsageOid;
  766. memset(&vup, 0, sizeof(vup));
  767. vup.cbSize = sizeof(vup);
  768. vup.cCtlStore = pmydata->cTrustStores;
  769. vup.rghCtlStore = pmydata->rghTrustStores;
  770. vup.cSignerStore = pmydata->cRootStores;
  771. vup.rghSignerStore = pmydata->rghRootStores;
  772. memset(&vus, 0, sizeof(vus));
  773. vus.cbSize = sizeof(vus);
  774. vus.ppCtl = &pctlTrust;
  775. vus.ppSigner = &pccert;
  776. //
  777. // Now search for the CTL on this certificate, if we don't find anything then
  778. // we return TRUE to state that we want the search to continue
  779. //
  780. //
  781. f = CertVerifyCTLUsage(X509_ASN_ENCODING, CTL_CERT_SUBJECT_TYPE,
  782. (LPVOID) ptcert->pCert, &ctlusage,
  783. CERT_VERIFY_INHIBIT_CTL_UPDATE_FLAG |
  784. CERT_VERIFY_NO_TIME_CHECK_FLAG |
  785. CERT_VERIFY_TRUSTED_SIGNERS_FLAG, &vup, &vus);
  786. if (!f) {
  787. goto Exit;
  788. }
  789. //
  790. // We found a CTL for this certificate. First step is to see if the signing
  791. // certificate is one which we can respect. We know that the cert is in
  792. // a root store, since we told the system it could only accept root store
  793. // certs
  794. //
  795. if (!FCheckCTLCert(pccert)) {
  796. f = FALSE;
  797. goto Exit;
  798. }
  799. // OK -- the signing cert passed it sanity check -- so see if the CTL contains
  800. // relevent information or is just a "keep looking" CTL.
  801. //
  802. ptcert->pTrustListContext = (PCTL_CONTEXT) pctlTrust;
  803. pctlTrust = NULL;
  804. //
  805. // We we are trying to do a full trust verification, then we need to
  806. // just skip to the next cert without bothering to look at the ctl
  807. //
  808. if (pmydata->dwFlags & CERT_TRUST_DO_FULL_SEARCH) {
  809. goto Exit;
  810. }
  811. //
  812. // Look to see if this is a "pass" item. If it is then we need to
  813. // continue looking, if it is not then we have reached the
  814. // decision point
  815. //
  816. PCTL_ENTRY pentry;
  817. pentry = &ptcert->pTrustListContext->pCtlInfo->rgCTLEntry[vus.dwCtlEntryIndex];
  818. for (i=0; i<pentry->cAttribute; i++) {
  819. if ((strcmp(pentry->rgAttribute[i].pszObjId, SzOID_CTL_ATTR_YESNO_TRUST) == 0) ||
  820. (strcmp(pentry->rgAttribute[i].pszObjId, SzOID_OLD_CTL_YESNO_TRUST) == 0)) {
  821. if ((pentry->rgAttribute[i].rgValue[0].cbData == sizeof(RgbTrustParent)) &&
  822. (memcmp(pentry->rgAttribute[i].rgValue[0].pbData,
  823. RgbTrustParent, sizeof(RgbTrustParent)) == 0)) {
  824. // Defer to parent
  825. goto Exit;
  826. }
  827. //
  828. // We have the decision point, push the signer onto the the stack
  829. //
  830. fContinue = !!(pmydata->dwFlags & CERT_TRUST_DO_FULL_TRUST);
  831. goto Exit;
  832. }
  833. }
  834. Exit:
  835. if (pccert != NULL) CertFreeCertificateContext(pccert);
  836. if (pctlTrust != NULL) CertFreeCTLContext(pctlTrust);
  837. return fContinue;
  838. }
  839. //// HrCheckPolicies
  840. //
  841. // Description:
  842. // Given an array of certificates, figure out what errors we have
  843. //
  844. // We enforce the following set of extensions
  845. //
  846. // enhancedKeyUsage
  847. // basicConstraints
  848. // keyUsage
  849. // nameConstraints
  850. //
  851. HRESULT HrCheckPolicies(PCRYPT_PROVIDER_SGNR psigner, DWORD cChain,
  852. DWORD * rgdwErrors, LPCSTR pszUsage)
  853. {
  854. DWORD cbData;
  855. DWORD cExt;
  856. DWORD dwPolicy = 0;
  857. DWORD dwType;
  858. HKEY hkPolicy;
  859. DWORD i;
  860. DWORD iCert;
  861. DWORD iExt;
  862. PCRYPT_PROVIDER_CERT ptcert;
  863. PCERT_EXTENSION rgExt;
  864. // Retrieve policy information from the registry
  865. if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, SzPolicyKey, 0, KEY_READ,
  866. &hkPolicy) == ERROR_SUCCESS) {
  867. cbData = sizeof(dwPolicy);
  868. if ((ERROR_SUCCESS != RegQueryValueExA(hkPolicy,
  869. SzPolicyData,
  870. 0, &dwType,
  871. (LPBYTE)&dwPolicy,
  872. &cbData)) ||
  873. (REG_DWORD != dwType)) {
  874. dwPolicy = 0;
  875. }
  876. RegCloseKey(hkPolicy);
  877. }
  878. // Check the policy on each cert in the chain
  879. for (iCert=0; iCert<cChain; iCert++) {
  880. //
  881. // Get the next cert to examine
  882. //
  883. ptcert = WTHelperGetProvCertFromChain(psigner, iCert);
  884. //
  885. // Setup to process the certs extensions
  886. //
  887. if (!ptcert || !(ptcert->pCert) || !(ptcert->pCert->pCertInfo))
  888. continue;
  889. cExt = ptcert->pCert->pCertInfo->cExtension;
  890. rgExt = ptcert->pCert->pCertInfo->rgExtension;
  891. //
  892. // Process the extensions
  893. //
  894. ProcessExtensions:
  895. for (iExt=0; iExt<cExt; iExt++) {
  896. if (strcmp(rgExt[iExt].pszObjId, szOID_ENHANCED_KEY_USAGE) == 0) {
  897. if (pszUsage == NULL) {
  898. continue;
  899. }
  900. PCERT_ENHKEY_USAGE pUsage;
  901. pUsage = (PCERT_ENHKEY_USAGE) PVCryptDecode(rgExt[iExt].pszObjId,
  902. rgExt[iExt].Value.cbData,
  903. rgExt[iExt].Value.pbData);
  904. if ((pUsage == NULL) && rgExt[iExt].fCritical) {
  905. rgdwErrors[iCert] |= CERT_VALIDITY_UNKNOWN_CRITICAL_EXTENSION;
  906. continue;
  907. }
  908. if(pUsage)
  909. {
  910. for (i=0; i<pUsage->cUsageIdentifier; i++) {
  911. if (strcmp(pUsage->rgpszUsageIdentifier[i], pszUsage) == 0) {
  912. break;
  913. }
  914. }
  915. if (i == pUsage->cUsageIdentifier) {
  916. rgdwErrors[iCert] |= CERT_VALIDITY_EXTENDED_USAGE_FAILURE;
  917. }
  918. free(pUsage);
  919. }
  920. }
  921. else if (strcmp(rgExt[iExt].pszObjId, szOID_BASIC_CONSTRAINTS2) == 0) {
  922. PCERT_BASIC_CONSTRAINTS2_INFO p;
  923. // If Basic Constraints is not marked critical (in opposition
  924. // to PKIX) we allow the administrator to overrule our
  925. // processing to deal with bad NT CertSrv SP1 hierarchies
  926. // used with Exchange KMS.
  927. if ((dwPolicy & POLICY_IGNORE_NON_CRITICAL_BC) &&
  928. !(rgExt[iExt].fCritical)) {
  929. continue;
  930. }
  931. // Verify the basic constraint extension
  932. p = (PCERT_BASIC_CONSTRAINTS2_INFO)
  933. PVCryptDecode(rgExt[iExt].pszObjId,
  934. rgExt[iExt].Value.cbData,
  935. rgExt[iExt].Value.pbData);
  936. if ((p == NULL) && rgExt[iExt].fCritical) {
  937. rgdwErrors[iCert] |= CERT_VALIDITY_UNKNOWN_CRITICAL_EXTENSION;
  938. continue;
  939. }
  940. if(p)
  941. {
  942. if ((!p->fCA) && (iCert > 0) && (iCert < cChain-1)) {
  943. rgdwErrors[iCert] |= CERT_VALIDITY_OTHER_EXTENSION_FAILURE;
  944. }
  945. if (p->fPathLenConstraint) {
  946. if (p->dwPathLenConstraint+1 < iCert) {
  947. rgdwErrors[iCert] |= CERT_VALIDITY_OTHER_EXTENSION_FAILURE;
  948. }
  949. }
  950. free(p);
  951. }
  952. }
  953. else if (strcmp(rgExt[iExt].pszObjId, szOID_KEY_USAGE) == 0) {
  954. PCERT_KEY_ATTRIBUTES_INFO p;
  955. p = (PCERT_KEY_ATTRIBUTES_INFO)
  956. PVCryptDecode(rgExt[iExt].pszObjId,
  957. rgExt[iExt].Value.cbData,
  958. rgExt[iExt].Value.pbData);
  959. if ((p == NULL) && rgExt[iExt].fCritical) {
  960. rgdwErrors[iCert] |= CERT_VALIDITY_KEY_USAGE_EXT_FAILURE;
  961. continue;
  962. }
  963. if(p)
  964. {
  965. if (p->IntendedKeyUsage.cbData >= 1) {
  966. if (iCert != 0) {
  967. #if 0
  968. if (!((*p->IntendedKeyUsage.pbData) & CERT_KEY_CERT_SIGN_KEY_USAGE)) {
  969. rgdwErrors[iCert] |= CERT_VALIDITY_KEY_USAGE_EXT_FAILURE;
  970. }
  971. #endif // 0
  972. }
  973. }
  974. free(p);
  975. }
  976. }
  977. else if ((strcmp(rgExt[iExt].pszObjId, szOID_SUBJECT_ALT_NAME2) == 0) ||
  978. (strcmp(rgExt[iExt].pszObjId, szOID_CRL_DIST_POINTS) == 0)/* ||
  979. (strcmp(rgExt[iExt].pszObjId, szOID_CERT_POLICIES) == 0) ||
  980. (strcmp(rgExt[iExt].pszObjId, "2.5.29.30") == 0) ||
  981. (strcmp(rgExt[iExt].pszObjId, "2.5.29.36") == 0)*/) {
  982. ;
  983. }
  984. else if (rgExt[iExt].fCritical) {
  985. rgdwErrors[iCert] |= CERT_VALIDITY_UNKNOWN_CRITICAL_EXTENSION;
  986. }
  987. }
  988. //
  989. // If we have a CTL for this cert, and we have not already done so
  990. // then process the extensions that it has.
  991. //
  992. if ((ptcert->pTrustListContext != NULL) &&
  993. (rgExt != ptcert->pTrustListContext->pCtlInfo->rgExtension)) {
  994. cExt = ptcert->pTrustListContext->pCtlInfo->cExtension;
  995. rgExt = ptcert->pTrustListContext->pCtlInfo->rgExtension;
  996. goto ProcessExtensions;
  997. }
  998. //
  999. // Need to support turn off of certificates
  1000. //
  1001. if (CertGetEnhancedKeyUsage(ptcert->pCert, CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG,
  1002. NULL, &cbData)) {
  1003. BOOL fFound = FALSE;
  1004. PCERT_ENHKEY_USAGE pUsage;
  1005. pUsage = (PCERT_ENHKEY_USAGE) malloc(cbData);
  1006. CertGetEnhancedKeyUsage(ptcert->pCert, CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG,
  1007. pUsage, &cbData);
  1008. for (i=0; i<pUsage->cUsageIdentifier; i++) {
  1009. if ((pszUsage != NULL) &&
  1010. strcmp(pUsage->rgpszUsageIdentifier[i], pszUsage) == 0) {
  1011. fFound = TRUE;
  1012. }
  1013. else if (strcmp(pUsage->rgpszUsageIdentifier[i], szOID_YESNO_TRUST_ATTR) == 0) {
  1014. rgdwErrors[iCert] |= CERT_VALIDITY_OTHER_EXTENSION_FAILURE;
  1015. break;
  1016. }
  1017. }
  1018. if ((pszUsage != NULL) && !fFound) {
  1019. rgdwErrors[iCert] |= CERT_VALIDITY_EXTENDED_USAGE_FAILURE;
  1020. }
  1021. free(pUsage);
  1022. }
  1023. //
  1024. // If we jump past a CTL, then we need to change our purpose
  1025. //
  1026. if (ptcert->pCtlContext != NULL) {
  1027. pszUsage = SzOID_KP_CTL_USAGE_SIGNING;
  1028. }
  1029. }
  1030. return S_OK;
  1031. }
  1032. //// GetErrorFromCert
  1033. //
  1034. // Description:
  1035. // Get the internal error from the provider certificate
  1036. //
  1037. DWORD GetErrorFromCert(PCRYPT_PROVIDER_CERT pCryptProviderCert)
  1038. {
  1039. //
  1040. // if this is true then the cert is OK
  1041. //
  1042. if ((pCryptProviderCert->dwError == 0) &&
  1043. (pCryptProviderCert->dwConfidence & CERT_CONFIDENCE_SIG) &&
  1044. (pCryptProviderCert->dwConfidence & CERT_CONFIDENCE_TIME) &&
  1045. (pCryptProviderCert->dwConfidence & CERT_CONFIDENCE_TIMENEST) &&
  1046. (!pCryptProviderCert->fIsCyclic))
  1047. {
  1048. return 0;
  1049. }
  1050. if (pCryptProviderCert->dwError == CERT_E_REVOKED)
  1051. {
  1052. return CERT_VALIDITY_CERTIFICATE_REVOKED;
  1053. }
  1054. else if (pCryptProviderCert->dwError == CERT_E_REVOCATION_FAILURE)
  1055. {
  1056. return CERT_VALIDITY_NO_CRL_FOUND;
  1057. }
  1058. else if (!(pCryptProviderCert->dwConfidence & CERT_CONFIDENCE_SIG) ||
  1059. (pCryptProviderCert->dwError == TRUST_E_CERT_SIGNATURE))
  1060. {
  1061. return CERT_VALIDITY_SIGNATURE_FAILS;
  1062. }
  1063. else if (!(pCryptProviderCert->dwConfidence & CERT_CONFIDENCE_TIME) ||
  1064. (pCryptProviderCert->dwError == CERT_E_EXPIRED))
  1065. {
  1066. return CERT_VALIDITY_AFTER_END;
  1067. }
  1068. else if (!(pCryptProviderCert->dwConfidence & CERT_CONFIDENCE_TIMENEST) ||
  1069. (pCryptProviderCert->dwError == CERT_E_VALIDITYPERIODNESTING))
  1070. {
  1071. return CERT_VALIDITY_PERIOD_NESTING_FAILURE;
  1072. }
  1073. else if (pCryptProviderCert->dwError == CERT_E_WRONG_USAGE)
  1074. {
  1075. return CERT_VALIDITY_KEY_USAGE_EXT_FAILURE;
  1076. }
  1077. else if (pCryptProviderCert->dwError == TRUST_E_BASIC_CONSTRAINTS)
  1078. {
  1079. return CERT_VALIDITY_OTHER_EXTENSION_FAILURE;
  1080. }
  1081. else if (pCryptProviderCert->dwError == CERT_E_PURPOSE)
  1082. {
  1083. return CERT_VALIDITY_EXTENDED_USAGE_FAILURE;
  1084. }
  1085. else if (pCryptProviderCert->dwError == CERT_E_CHAINING)
  1086. {
  1087. return CERT_VALIDITY_NO_ISSUER_CERT_FOUND;
  1088. }
  1089. else if (pCryptProviderCert->dwError == TRUST_E_EXPLICIT_DISTRUST)
  1090. {
  1091. return CERT_VALIDITY_EXPLICITLY_DISTRUSTED;
  1092. }
  1093. else if (pCryptProviderCert->fIsCyclic)
  1094. {
  1095. return CERT_VALIDITY_ISSUER_INVALID;
  1096. }
  1097. else
  1098. {
  1099. //
  1100. // this is not an error we know about, so call return general error
  1101. //
  1102. return CERT_VALIDITY_OTHER_ERROR;
  1103. }
  1104. }
  1105. //// MapErrorToTrustError
  1106. //
  1107. // Description:
  1108. // Map the internal error value to a WINTRUST recognized value.
  1109. // The CryptUI dialogs recognize these values:
  1110. // CERT_E_UNTRUSTEDROOT
  1111. // CERT_E_REVOKED
  1112. // TRUST_E_CERT_SIGNATURE
  1113. // CERT_E_EXPIRED
  1114. // CERT_E_VALIDITYPERIODNESTING
  1115. // CERT_E_WRONG_USAGE
  1116. // TRUST_E_BASIC_CONSTRAINTS
  1117. // CERT_E_PURPOSE
  1118. // CERT_E_REVOCATION_FAILURE
  1119. // CERT_E_CHAINING - this is set if a full chain cannot be built
  1120. //
  1121. //
  1122. HRESULT MapErrorToTrustError(DWORD dwInternalError) {
  1123. HRESULT hrWinTrustError = S_OK;
  1124. // Look at them in decreasing order of importance
  1125. if (dwInternalError) {
  1126. if (dwInternalError & CERT_VALIDITY_EXPLICITLY_DISTRUSTED) {
  1127. hrWinTrustError = /*TRUST_E_EXPLICIT_DISTRUST*/ 0x800B0111;
  1128. } else if (dwInternalError & CERT_VALIDITY_SIGNATURE_FAILS) {
  1129. hrWinTrustError = TRUST_E_CERT_SIGNATURE;
  1130. } else if (dwInternalError & CERT_VALIDITY_CERTIFICATE_REVOKED) {
  1131. hrWinTrustError = CERT_E_REVOKED;
  1132. } else if (dwInternalError & CERT_VALIDITY_BEFORE_START || dwInternalError & CERT_VALIDITY_AFTER_END) {
  1133. hrWinTrustError = CERT_E_EXPIRED;
  1134. } else if (dwInternalError & CERT_VALIDITY_ISSUER_DISTRUST) {
  1135. hrWinTrustError = CERT_E_UNTRUSTEDROOT;
  1136. } else if (dwInternalError & CERT_VALIDITY_ISSUER_INVALID) {
  1137. hrWinTrustError = CERT_E_UNTRUSTEDROOT;
  1138. } else if (dwInternalError & CERT_VALIDITY_NO_ISSUER_CERT_FOUND) {
  1139. hrWinTrustError = CERT_E_CHAINING;
  1140. } else if (dwInternalError & CERT_VALIDITY_NO_CRL_FOUND) {
  1141. hrWinTrustError = CERT_E_REVOCATION_FAILURE;
  1142. } else if (dwInternalError & CERT_VALIDITY_PERIOD_NESTING_FAILURE) {
  1143. hrWinTrustError = CERT_E_VALIDITYPERIODNESTING;
  1144. } else if (dwInternalError & CERT_VALIDITY_EXTENDED_USAGE_FAILURE) {
  1145. hrWinTrustError = CERT_E_WRONG_USAGE;
  1146. } else if (dwInternalError & CERT_VALIDITY_OTHER_ERROR) {
  1147. hrWinTrustError = TRUST_E_FAIL; // BUGBUG: Will this give a good error?;
  1148. } else if (dwInternalError & CERT_VALIDITY_NO_TRUST_DATA) {
  1149. hrWinTrustError = CERT_E_UNTRUSTEDROOT;
  1150. } else {
  1151. hrWinTrustError = TRUST_E_FAIL; // BUGBUG: Will this give a good error?;
  1152. }
  1153. }
  1154. // CERT_E_UNTRUSTEDROOT
  1155. // CERT_E_REVOKED
  1156. // TRUST_E_CERT_SIGNATURE
  1157. // CERT_E_EXPIRED
  1158. // X CERT_E_VALIDITYPERIODNESTING
  1159. // X CERT_E_WRONG_USAGE
  1160. // TRUST_E_BASIC_CONSTRAINTS
  1161. // CERT_E_PURPOSE
  1162. // CERT_E_REVOCATION_FAILURE What is this?
  1163. // CERT_E_CHAINING - this is set if a full chain cannot be built
  1164. return(hrWinTrustError);
  1165. }
  1166. //// CertTrustFinalPolicy
  1167. //
  1168. // Description:
  1169. // This code does the enforcement of all restrictions on the certificate
  1170. // chain that we understand.
  1171. //
  1172. HRESULT CertTrustFinalPolicy(PCRYPT_PROVIDER_DATA pdata)
  1173. {
  1174. int cChain = 0;
  1175. DWORD dwFlags;
  1176. FILETIME ftZero = {0, 0};
  1177. HRESULT hr;
  1178. HRESULT hrStepError = S_OK;
  1179. int i;
  1180. DWORD j;
  1181. PCERT_VERIFY_CERTIFICATE_TRUST pcerttrust;
  1182. PINTERNAL_DATA pmydata;
  1183. PCRYPT_PROVIDER_PRIVDATA pprivdata;
  1184. PCRYPT_PROVIDER_SGNR psigner;
  1185. PCRYPT_PROVIDER_CERT ptcert = NULL;
  1186. PCRYPT_PROVIDER_CERT ptcertIssuer;
  1187. DATA_BLOB * rgblobTrustInfo = NULL;
  1188. LPBYTE rgbTrust = NULL;
  1189. DWORD * rgdwErrors = NULL;
  1190. PCCERT_CONTEXT * rgpccertChain = NULL;
  1191. int iExplicitlyTrusted;
  1192. //
  1193. // Make sure all of the fields we want are there. If not then it is a
  1194. // complete fatal error.
  1195. //
  1196. if (! WVT_ISINSTRUCT(CRYPT_PROVIDER_DATA, pdata->cbStruct, pszUsageOID)) {
  1197. hr = E_INVALIDARG;
  1198. goto XXX;
  1199. }
  1200. if (pdata->pWintrustData->pBlob->cbStruct < sizeof(WINTRUST_BLOB_INFO)) {
  1201. hr = E_INVALIDARG;
  1202. goto XXX;
  1203. }
  1204. pcerttrust = (PCERT_VERIFY_CERTIFICATE_TRUST)
  1205. pdata->pWintrustData->pBlob->pbMemObject;
  1206. if ((pcerttrust == NULL) ||
  1207. (pcerttrust->cbSize < sizeof(*pcerttrust))) {
  1208. hr = E_INVALIDARG;
  1209. goto XXX;
  1210. }
  1211. //
  1212. // Get our internal data structure
  1213. //
  1214. pprivdata = WTHelperGetProvPrivateDataFromChain(pdata, (LPGUID) &MyGuid);
  1215. if (pprivdata == NULL) {
  1216. hr = E_INVALIDARG;
  1217. goto XXX;
  1218. }
  1219. pmydata = (PINTERNAL_DATA) pprivdata->pvProvData;
  1220. //
  1221. // Check for an existing error -- If so then skip to any UI
  1222. //
  1223. if (pdata->dwError != 0) {
  1224. hr = pdata->dwError;
  1225. goto XXX;
  1226. }
  1227. for (i=TRUSTERROR_STEP_FINAL_WVTINIT; i<TRUSTERROR_STEP_FINAL_POLICYPROV; i++) {
  1228. if (pdata->padwTrustStepErrors[i] != 0) {
  1229. // for these errors we still want to continue processing
  1230. if ((TRUST_E_CERT_SIGNATURE == pdata->padwTrustStepErrors[i]) ||
  1231. (CERT_E_REVOKED == pdata->padwTrustStepErrors[i]) ||
  1232. (CERT_E_REVOCATION_FAILURE == pdata->padwTrustStepErrors[i])) {
  1233. hrStepError = pdata->padwTrustStepErrors[i];
  1234. }
  1235. else {
  1236. hr = pdata->padwTrustStepErrors[i];
  1237. goto XXX;
  1238. }
  1239. }
  1240. }
  1241. //
  1242. // We only work with a single signer --
  1243. psigner = WTHelperGetProvSignerFromChain(pdata, 0, FALSE, 0);
  1244. if (psigner == NULL) {
  1245. hr = E_INVALIDARG;
  1246. goto XXX;
  1247. }
  1248. //
  1249. // If we are not getting a full chain, then build up the set of
  1250. // certs and pass it to the validator
  1251. //
  1252. if (!(pmydata->dwFlags & CERT_TRUST_DO_FULL_SEARCH)) {
  1253. }
  1254. //
  1255. // We are going to compute some return values at this point
  1256. // either a full chain or a full chain with complete trust.
  1257. //
  1258. // Allocate space to return the chain of certs back to the caller.
  1259. // We allocate space for the full chain, even though we may not
  1260. // actually use it.
  1261. //
  1262. cChain = psigner->csCertChain;
  1263. rgpccertChain = (PCCERT_CONTEXT *) LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT,
  1264. cChain * sizeof(PCCERT_CONTEXT));
  1265. rgdwErrors = (DWORD *) LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, cChain * sizeof(DWORD));
  1266. rgblobTrustInfo = (DATA_BLOB *) LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, cChain * sizeof(DATA_BLOB));
  1267. rgbTrust = (BYTE *) LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, cChain*sizeof(BLOB));
  1268. if ((rgpccertChain == NULL) || (rgdwErrors == NULL) ||
  1269. (rgblobTrustInfo == NULL) || (rgbTrust == NULL)) {
  1270. hr = E_OUTOFMEMORY;
  1271. goto XXX;
  1272. }
  1273. //
  1274. // Build the first set of returned values. At this
  1275. // point we are creating the arrays to return both
  1276. // the relevent trust information and the chain of
  1277. // certificates in
  1278. //
  1279. for (i=0; i<cChain; i++) {
  1280. //
  1281. // Start by duplicating the certificate into the return
  1282. // location
  1283. //
  1284. ptcert = WTHelperGetProvCertFromChain(psigner, i);
  1285. rgpccertChain[i] = CertDuplicateCertificateContext(ptcert->pCert);
  1286. if (i < cChain-1) {
  1287. ptcertIssuer = WTHelperGetProvCertFromChain(psigner, i+1);
  1288. }
  1289. else {
  1290. ptcertIssuer = NULL;
  1291. if (!ptcert->fSelfSigned) {
  1292. rgdwErrors[i] |= CERT_VALIDITY_NO_ISSUER_CERT_FOUND;
  1293. }
  1294. }
  1295. //
  1296. // Check for some simple items
  1297. //
  1298. dwFlags = CertVerifyTimeValidityWithDelta(NULL,
  1299. ptcert->pCert->pCertInfo,
  1300. TIME_DELTA_SECONDS);
  1301. if (((LONG)dwFlags) < 0) {
  1302. rgdwErrors[i] |= CERT_VALIDITY_BEFORE_START;
  1303. }
  1304. else if (dwFlags > 0) {
  1305. if (!ptcert->fTrustListSignerCert ||
  1306. memcmp(&ptcert->pCert->pCertInfo->NotAfter, &ftZero,
  1307. sizeof(ftZero)) != 0) {
  1308. rgdwErrors[i] |= CERT_VALIDITY_AFTER_END;
  1309. }
  1310. else {
  1311. if (!(ptcert->dwConfidence & CERT_CONFIDENCE_TIME)) {
  1312. ptcert->dwConfidence |= CERT_CONFIDENCE_TIME;
  1313. }
  1314. if (ptcert->dwError == CERT_E_EXPIRED) {
  1315. ptcert->dwError = S_OK;
  1316. }
  1317. }
  1318. }
  1319. //
  1320. // Check for error in Certificate
  1321. //
  1322. rgdwErrors[i] |= GetErrorFromCert(ptcert);
  1323. //
  1324. // If we find an issuer, then lets go after the questions we have
  1325. // about CRLs.
  1326. //
  1327. // Question -- do we get everything here? How do we know if the
  1328. // CRL is out of date.
  1329. //
  1330. if ((ptcertIssuer != NULL) && (ptcert->pCtlContext == NULL)) {
  1331. dwFlags = CERT_STORE_SIGNATURE_FLAG;
  1332. if ((pdata->dwProvFlags & CPD_REVOCATION_CHECK_NONE) ||
  1333. (psigner->pChainContext == NULL))
  1334. dwFlags |= CERT_STORE_REVOCATION_FLAG;
  1335. if (CertVerifySubjectCertificateContext(ptcert->pCert, ptcertIssuer->pCert, &dwFlags) &&
  1336. (dwFlags != 0)) {
  1337. if (dwFlags & CERT_STORE_SIGNATURE_FLAG) {
  1338. rgdwErrors[i] |= CERT_VALIDITY_SIGNATURE_FAILS;
  1339. }
  1340. if (dwFlags & CERT_STORE_REVOCATION_FLAG) {
  1341. if (dwFlags & CERT_STORE_NO_CRL_FLAG) {
  1342. rgdwErrors[i] |= CERT_VALIDITY_NO_CRL_FOUND;
  1343. }
  1344. else {
  1345. rgdwErrors[i] |= CERT_VALIDITY_CERTIFICATE_REVOKED;
  1346. }
  1347. }
  1348. }
  1349. // If both CRL not found and revoked are set, choose the most
  1350. // conservative state- the cert is revoked.
  1351. if ((CERT_VALIDITY_NO_CRL_FOUND & rgdwErrors[i]) &&
  1352. (CERT_VALIDITY_CERTIFICATE_REVOKED & rgdwErrors[i])) {
  1353. rgdwErrors[i] &= ~CERT_VALIDITY_NO_CRL_FOUND;
  1354. }
  1355. }
  1356. //
  1357. //
  1358. //
  1359. if (ptcert->fTrustedRoot) {
  1360. rgblobTrustInfo[i].cbData = 0;
  1361. rgblobTrustInfo[i].pbData = (LPBYTE) 1;
  1362. rgbTrust[i] = 1;
  1363. }
  1364. else if (ptcert->pTrustListContext != NULL) {
  1365. CRYPT_ATTRIBUTES attrs;
  1366. DWORD cbData;
  1367. BOOL f;
  1368. LPBYTE pb;
  1369. PCTL_ENTRY pctlentry;
  1370. pctlentry = CertFindSubjectInCTL(X509_ASN_ENCODING, CTL_CERT_SUBJECT_TYPE,
  1371. (LPVOID) ptcert->pCert, ptcert->pTrustListContext,
  1372. 0);
  1373. attrs.cAttr = pctlentry->cAttribute;
  1374. attrs.rgAttr = pctlentry->rgAttribute;
  1375. for (j=0; j<attrs.cAttr; j++) {
  1376. if ((strcmp(attrs.rgAttr[j].pszObjId, SzOID_CTL_ATTR_YESNO_TRUST) == 0) ||
  1377. (strcmp(attrs.rgAttr[j].pszObjId, SzOID_OLD_CTL_YESNO_TRUST) == 0)) {
  1378. if ((attrs.rgAttr[j].rgValue[0].cbData == sizeof(RgbTrustYes)) &&
  1379. (memcmp(attrs.rgAttr[j].rgValue[0].pbData,
  1380. RgbTrustYes, sizeof(RgbTrustYes)) == 0)) {
  1381. rgbTrust[i] = 2;
  1382. break;
  1383. }
  1384. else if ((attrs.rgAttr[j].rgValue[0].cbData == sizeof(RgbTrustNo)) &&
  1385. (memcmp(attrs.rgAttr[j].rgValue[0].pbData,
  1386. RgbTrustNo, sizeof(RgbTrustNo)) == 0)) {
  1387. rgdwErrors[i] |= CERT_VALIDITY_EXPLICITLY_DISTRUSTED;
  1388. rgbTrust[i] = (BYTE) -1;
  1389. break;
  1390. }
  1391. else if ((attrs.rgAttr[j].rgValue[0].cbData == sizeof(RgbTrustParent)) &&
  1392. (memcmp(attrs.rgAttr[j].rgValue[0].pbData,
  1393. RgbTrustParent, sizeof(RgbTrustParent)) == 0)) {
  1394. rgbTrust[i] = 0;
  1395. break;
  1396. }
  1397. else {
  1398. rgdwErrors[i] |= CERT_VALIDITY_NO_TRUST_DATA;
  1399. rgbTrust[i] = (BYTE) -2;
  1400. break;
  1401. }
  1402. }
  1403. }
  1404. if (j == attrs.cAttr) {
  1405. rgbTrust[i] = 0;
  1406. }
  1407. f = CryptEncodeObject(X509_ASN_ENCODING, "1.3.6.1.4.1.311.16.1.1",
  1408. &attrs, NULL, &cbData);
  1409. if (f && (cbData != 0)) {
  1410. pb = (LPBYTE) LocalAlloc(LMEM_FIXED, cbData);
  1411. if (pb != NULL) {
  1412. f = CryptEncodeObject(X509_ASN_ENCODING, "1.3.6.1.4.1.311.16.1.1",
  1413. &attrs, pb, &cbData);
  1414. rgblobTrustInfo[i].cbData = cbData;
  1415. rgblobTrustInfo[i].pbData = pb;
  1416. }
  1417. }
  1418. }
  1419. }
  1420. //
  1421. //
  1422. //
  1423. DWORD rgiCert[32];
  1424. for (i=0; i<cChain; i++) {
  1425. rgiCert[i] = i;
  1426. }
  1427. //
  1428. // Apply policies to it
  1429. //
  1430. hr = HrCheckPolicies(psigner, cChain, rgdwErrors, pcerttrust->pszUsageOid);
  1431. if (FAILED(hr)) {
  1432. goto XXX;
  1433. }
  1434. //
  1435. // Mask out the bits which the caller says are un-important
  1436. //
  1437. if (pcerttrust->pdwErrors != NULL) {
  1438. *pcerttrust->pdwErrors = 0;
  1439. }
  1440. // Find the lowest index explicitly trusted cert in chain
  1441. iExplicitlyTrusted = cChain; // > index of root cert
  1442. for (i = 0; i < cChain; i++) {
  1443. if (rgbTrust[i] == 2) {
  1444. iExplicitlyTrusted = i;
  1445. break;
  1446. }
  1447. }
  1448. for (i=cChain-1; i>=0; i--) {
  1449. //
  1450. // Build a better idea of basic trust
  1451. //
  1452. switch (rgbTrust[i]) {
  1453. // We are explicity trusted -- clear out any trust errors which may
  1454. // have been located for this certificate They are no longer
  1455. // relevent.
  1456. case 1: // Explicitly trusted (root)
  1457. case 2: // Explicitly trusted (CTL)
  1458. rgdwErrors[i] &= ~(CERT_VALIDITY_MASK_TRUST |
  1459. CERT_VALIDITY_CERTIFICATE_REVOKED);
  1460. break;
  1461. case -2: // Unknown CTL data
  1462. case -1: // Explicitly distrusted (CTL)
  1463. rgdwErrors[i] |= CERT_VALIDITY_EXPLICITLY_DISTRUSTED;
  1464. break;
  1465. case 0: // Chain trusted (CTL or no CTL)
  1466. if (i == cChain-1) {
  1467. rgdwErrors[i] |= CERT_VALIDITY_NO_TRUST_DATA;
  1468. }
  1469. break;
  1470. }
  1471. rgdwErrors[i] &= ~pcerttrust->dwIgnoreErr;
  1472. if (i > 0) {
  1473. if (rgdwErrors[i] & CERT_VALIDITY_MASK_VALIDITY) {
  1474. rgdwErrors[i-1] |= CERT_VALIDITY_ISSUER_INVALID;
  1475. }
  1476. if (rgdwErrors[i] & CERT_VALIDITY_MASK_TRUST) {
  1477. rgdwErrors[i-1] |= CERT_VALIDITY_ISSUER_DISTRUST;
  1478. }
  1479. }
  1480. if (pcerttrust->pdwErrors != NULL) {
  1481. DWORD dwThisTrust = rgdwErrors[i];
  1482. if (i >= iExplicitlyTrusted) {
  1483. // If we have an explicitly trusted cert or one of it's issuer's,
  1484. // we assume trust all the way up the chain.
  1485. dwThisTrust &= ~(CERT_VALIDITY_MASK_TRUST | CERT_VALIDITY_CERTIFICATE_REVOKED);
  1486. }
  1487. *pcerttrust->pdwErrors |= dwThisTrust;
  1488. }
  1489. // Set the trust state for this chain cert
  1490. if (WVT_ISINSTRUCT(CRYPT_PROVIDER_CERT, ptcert->cbStruct, dwError)) {
  1491. ptcert = WTHelperGetProvCertFromChain(psigner, i);
  1492. ptcert->dwError = (DWORD)MapErrorToTrustError(rgdwErrors[i]);
  1493. }
  1494. }
  1495. if (rgdwErrors[0] != 0) {
  1496. hr = S_FALSE;
  1497. }
  1498. else {
  1499. hr = S_OK;
  1500. }
  1501. if (WVT_ISINSTRUCT(CRYPT_PROVIDER_DATA, pdata->cbStruct, dwFinalError)) {
  1502. pdata->dwFinalError = (DWORD)MapErrorToTrustError(rgdwErrors[0]);
  1503. if (pdata->dwFinalError) {
  1504. // Assert(hr != S_OK);
  1505. }
  1506. }
  1507. //
  1508. // We have succeded and are finished.
  1509. // Setup the return values
  1510. //
  1511. if (pcerttrust->pcChain != NULL) {
  1512. *pcerttrust->pcChain = cChain;
  1513. }
  1514. if (pcerttrust->prgChain != NULL) {
  1515. *pcerttrust->prgChain = rgpccertChain;
  1516. rgpccertChain = NULL;
  1517. }
  1518. if (pcerttrust->prgdwErrors != NULL) {
  1519. *pcerttrust->prgdwErrors = rgdwErrors;
  1520. rgdwErrors = NULL;
  1521. }
  1522. if (pcerttrust->prgpbTrustInfo != NULL) {
  1523. *pcerttrust->prgpbTrustInfo = rgblobTrustInfo;
  1524. rgblobTrustInfo = NULL;
  1525. }
  1526. XXX:
  1527. if (rgpccertChain != NULL) {
  1528. for (i=0; i<cChain; i++) {
  1529. CertFreeCertificateContext(rgpccertChain[i]);
  1530. }
  1531. LocalFree(rgpccertChain);
  1532. }
  1533. if (rgdwErrors != NULL) LocalFree(rgdwErrors);
  1534. if (rgblobTrustInfo != NULL) {
  1535. for (i=0; i<cChain; i++) {
  1536. if (rgblobTrustInfo[i].cbData > 0) {
  1537. LocalFree(rgblobTrustInfo[i].pbData);
  1538. }
  1539. }
  1540. LocalFree(rgblobTrustInfo);
  1541. }
  1542. if (rgbTrust != NULL) LocalFree(rgbTrust);
  1543. // If everything worked then reurn any step error we ignored
  1544. if (FAILED(hrStepError) && SUCCEEDED(hr))
  1545. hr = hrStepError;
  1546. return hr;
  1547. }
  1548. //// CertTrustCleanup
  1549. //
  1550. // Description:
  1551. // This code knows how to cleanup all allocated data we have.
  1552. //
  1553. HRESULT CertTrustCleanup(PCRYPT_PROVIDER_DATA pdata)
  1554. {
  1555. DWORD i;
  1556. PCRYPT_PROVIDER_PRIVDATA pprivdata;
  1557. PINTERNAL_DATA pmydata;
  1558. //
  1559. // Get our internal data structure
  1560. //
  1561. pprivdata = WTHelperGetProvPrivateDataFromChain(pdata, (LPGUID) &MyGuid);
  1562. if (pprivdata == NULL) {
  1563. return S_OK;
  1564. }
  1565. pmydata = (PINTERNAL_DATA) pprivdata->pvProvData;
  1566. //
  1567. // Release all of the stores we have cached here
  1568. //
  1569. for (i=0; i<pmydata->cRootStores; i++) {
  1570. CertCloseStore(pmydata->rghRootStores[i], 0);
  1571. }
  1572. for (i=0; i<pmydata->cTrustStores; i++) {
  1573. CertCloseStore(pmydata->rghTrustStores[i], 0);
  1574. }
  1575. //
  1576. // If we installed a default crypt context, uninstall it now
  1577. //
  1578. i = CryptUninstallDefaultContext(pmydata->hdefaultcontext, 0, NULL);
  1579. // Assert(i == TRUE);
  1580. return S_OK;
  1581. }
  1582. #else // !NT5BUILD
  1583. #pragma message("Building for IE")
  1584. //// HrCheckTrust
  1585. //
  1586. // Description:
  1587. //
  1588. HRESULT HrCheckTrust(PCCertFrame pcf, int iTrust)
  1589. {
  1590. HRESULT hr;
  1591. HRESULT hrRet = S_OK;
  1592. int i;
  1593. //
  1594. // If this node has trust information on it, then compute the trust at this
  1595. // point. If we either succeed or fail then return the indication.
  1596. //
  1597. if ((pcf->m_rgTrust != NULL) && (pcf->m_rgTrust[iTrust].szOid != NULL)) {
  1598. if (pcf->m_fRootStore) {
  1599. pcf->m_rgTrust[iTrust].fExplicitTrust = TRUE;
  1600. pcf->m_rgTrust[iTrust].fTrust = TRUE;
  1601. return S_OK;
  1602. }
  1603. if ((strcmp(pcf->m_rgTrust[iTrust].szOid, SzOID_CTL_ATTR_YESNO_TRUST) == 0) ||
  1604. (strcmp(pcf->m_rgTrust[iTrust].szOid, SzOID_OLD_CTL_YESNO_TRUST) == 0)){
  1605. if ((pcf->m_rgTrust[iTrust].cbTrustData == 3) &&
  1606. memcmp(pcf->m_rgTrust[iTrust].pbTrustData, RgbTrustYes, 3) == 0) {
  1607. pcf->m_rgTrust[iTrust].fExplicitTrust = TRUE;
  1608. pcf->m_rgTrust[iTrust].fTrust = TRUE;
  1609. return S_OK;
  1610. }
  1611. else if ((pcf->m_rgTrust[iTrust].cbTrustData == 3) &&
  1612. memcmp(pcf->m_rgTrust[iTrust].pbTrustData,
  1613. RgbTrustParent, 3) == 0) {
  1614. // Need to ceck with the parent to find out what is going on.
  1615. }
  1616. else {
  1617. // Assume it must be RgbTrustNo
  1618. pcf->m_rgTrust[iTrust].fExplicitDistrust = TRUE;
  1619. pcf->m_rgTrust[iTrust].fDistrust = TRUE;
  1620. return S_FALSE;
  1621. }
  1622. }
  1623. else {
  1624. pcf->m_rgTrust[iTrust].fError = TRUE;
  1625. return S_FALSE;
  1626. }
  1627. }
  1628. if (pcf->m_fRootStore) {
  1629. pcf->m_rgTrust[iTrust].fExplicitTrust = TRUE;
  1630. pcf->m_rgTrust[iTrust].fTrust = TRUE;
  1631. return S_OK;
  1632. }
  1633. //
  1634. // We are marked as inherit -- so start asking all of our parents
  1635. //
  1636. if (pcf->m_cParents == 0) {
  1637. // No parents -- so not trusted.
  1638. hrRet = S_FALSE;
  1639. }
  1640. else {
  1641. for (i=0; i<pcf->m_cParents; i++) {
  1642. hr = HrCheckTrust(pcf->m_rgpcfParents[i], iTrust);
  1643. if (FAILED(hr)) {
  1644. pcf->m_rgTrust[iTrust].fError = TRUE;
  1645. return hr;
  1646. }
  1647. pcf->m_rgTrust[iTrust].fTrust = pcf->m_rgpcfParents[i]->m_rgTrust[iTrust].fTrust;
  1648. pcf->m_rgTrust[iTrust].fDistrust = pcf->m_rgpcfParents[i]->m_rgTrust[iTrust].fDistrust;
  1649. if (hr != S_OK) {
  1650. hrRet = S_FALSE;
  1651. }
  1652. }
  1653. }
  1654. return hrRet;
  1655. }
  1656. //// HrCheckValidity
  1657. //
  1658. // Description:
  1659. // This function will walk through the tree of certificates looking
  1660. // for the invalid certificates. It masks in the fact that the issuer
  1661. // certificate is invalid as necessary
  1662. HRESULT HrCheckValidity(PCCertFrame pcf)
  1663. {
  1664. HRESULT hr;
  1665. int i;
  1666. //
  1667. // If we do not have an issuer certificate, then our parent cannot possibly
  1668. // be invalid
  1669. //
  1670. if (pcf->m_cParents > 0) {
  1671. for (i=0; i<pcf->m_cParents; i++) {
  1672. hr = HrCheckValidity(pcf->m_rgpcfParents[i]);
  1673. // Assert(SUCCEEDED(hr));
  1674. if (hr != S_OK) {
  1675. pcf->m_dwFlags |= CERT_VALIDITY_ISSUER_INVALID;
  1676. return hr;
  1677. }
  1678. }
  1679. }
  1680. return (pcf->m_dwFlags == 0) ? S_OK : S_FALSE;
  1681. }
  1682. //// HrPerformUserCheck
  1683. //
  1684. HRESULT HrPerformUserCheck(PCCertFrame pcf, BOOL fComplete,
  1685. DWORD * pcNodes, int iDepth, PCCertFrame * rgpcf)
  1686. {
  1687. int iTrust = 0;
  1688. //
  1689. // We can only deal with up to 20-nodes in the chain of trust
  1690. //
  1691. if (iDepth == 20) {
  1692. return E_OUTOFMEMORY;
  1693. }
  1694. //
  1695. // Put our node in so we can do array process checking
  1696. //
  1697. rgpcf[iDepth] = pcf;
  1698. //
  1699. // Handle the case where we don't have a trust usage
  1700. // User should still have a chance to invalidate the cert
  1701. //
  1702. if (NULL == pcf->m_rgTrust) {
  1703. if (pcf->m_cParents != 0) {
  1704. return HrPerformUserCheck(pcf->m_rgpcfParents[0], fComplete, pcNodes,
  1705. iDepth+1, rgpcf);
  1706. }
  1707. *pcNodes = iDepth+1;
  1708. return S_OK;
  1709. }
  1710. //
  1711. // If trust is really bad -- don't bother asking, just fail
  1712. //
  1713. if (pcf->m_rgTrust[iTrust].fError) {
  1714. return E_FAIL;
  1715. }
  1716. //
  1717. // See what the trust on this node is, if we explicity trust the node
  1718. // then ask the user his option on the entire array
  1719. //
  1720. if (pcf->m_rgTrust[iTrust].fExplicitTrust) {
  1721. if (fComplete && (pcf->m_cParents != 0)) {
  1722. HrPerformUserCheck(pcf->m_rgpcfParents[0], fComplete, pcNodes,
  1723. iDepth+1, rgpcf);
  1724. }
  1725. else {
  1726. // M00TODO Insert check to the user's function at this point
  1727. // Found nirvana
  1728. *pcNodes = iDepth+1;
  1729. }
  1730. return S_OK;
  1731. }
  1732. if ((pcf->m_rgTrust[iTrust].fExplicitDistrust) ||
  1733. (pcf->m_rgTrust[iTrust].fDistrust)) {
  1734. if (fComplete && (pcf->m_cParents != 0)) {
  1735. HrPerformUserCheck(pcf->m_rgpcfParents[0], fComplete, pcNodes,
  1736. iDepth+1, rgpcf);
  1737. }
  1738. else {
  1739. // I don't think we should be here -- but the result is a NO trust
  1740. // decision
  1741. *pcNodes = iDepth+1;
  1742. }
  1743. return S_FALSE;
  1744. }
  1745. //
  1746. // If we get here -- we should have inheritence trust. Continue
  1747. // walking up the tree and make sure
  1748. //
  1749. if (pcf->m_cParents == 0) {
  1750. *pcNodes = iDepth+1;
  1751. return S_FALSE;
  1752. }
  1753. // M00BUG -- need to check multliple parents?
  1754. return HrPerformUserCheck(pcf->m_rgpcfParents[0], fComplete, pcNodes,
  1755. iDepth+1, rgpcf);
  1756. }
  1757. //// HrDoTrustWork
  1758. //
  1759. // Description:
  1760. // This function does the core code of determining if a certificate
  1761. // can be trusted. This needs to be moved to a WinTrust provider in
  1762. // the near future.
  1763. //
  1764. HRESULT HrDoTrustWork(PCCERT_CONTEXT pccertToCheck, DWORD dwControl,
  1765. DWORD dwValidityMask,
  1766. DWORD cPurposes, LPSTR * rgszPurposes, HCRYPTPROV hprov,
  1767. DWORD cRoots, HCERTSTORE * rgRoots,
  1768. DWORD cCAs, HCERTSTORE * rgCAs,
  1769. DWORD cTrust, HCERTSTORE * rgTrust,
  1770. PFNTRUSTHELPER /*pfn*/, DWORD /*lCustData*/,
  1771. PCCertFrame * ppcf, DWORD * pcNodes,
  1772. PCCertFrame * rgpcfResult,
  1773. HANDLE * phReturnStateData) // optional: return WinVerifyTrust state handle here
  1774. {
  1775. DWORD dwFlags;
  1776. HRESULT hr;
  1777. HCERTSTORE hstoreRoot=NULL;
  1778. HCERTSTORE hstoreTrust=NULL;
  1779. DWORD i;
  1780. int iParent;
  1781. PCCERT_CONTEXT pccert;
  1782. PCCERT_CONTEXT pccert2;
  1783. PCCertFrame pcf;
  1784. PCCertFrame pcf2;
  1785. PCCertFrame pcf3;
  1786. PCCertFrame pcfLeaf = NULL;
  1787. HCERTSTORE rghcertstore[COtherProviders+30] = {NULL};
  1788. Assert(!phReturnStateData); // How would I support this without the WinVerifyTrust call?
  1789. //
  1790. // We may need to open some stores at this point. Check to see if we do
  1791. // and open new stores as required.
  1792. //
  1793. // Check for Root stores
  1794. if (cRoots == 0) {
  1795. #ifndef WIN16
  1796. hstoreRoot = CertOpenStore(CERT_STORE_PROV_SYSTEM, X509_ASN_ENCODING,
  1797. hprov, CERT_SYSTEM_STORE_CURRENT_USER,
  1798. L"Root");
  1799. #else
  1800. hstoreRoot = CertOpenStore(CERT_STORE_PROV_SYSTEM, X509_ASN_ENCODING,
  1801. hprov, CERT_SYSTEM_STORE_CURRENT_USER,
  1802. "Root");
  1803. #endif // !WIN16
  1804. if (hstoreRoot == NULL) {
  1805. hr = E_FAIL;
  1806. goto ExitHere;
  1807. }
  1808. cRoots = 1;
  1809. rgRoots = &hstoreRoot;
  1810. }
  1811. // Check for Trust stores
  1812. if (cTrust == 0) {
  1813. #ifndef WIN16
  1814. hstoreTrust = CertOpenStore(CERT_STORE_PROV_SYSTEM, X509_ASN_ENCODING,
  1815. hprov, CERT_SYSTEM_STORE_CURRENT_USER,
  1816. L"Trust");
  1817. #else
  1818. hstoreTrust = CertOpenStore(CERT_STORE_PROV_SYSTEM, X509_ASN_ENCODING,
  1819. hprov, CERT_SYSTEM_STORE_CURRENT_USER,
  1820. "Trust");
  1821. #endif // !WIN16
  1822. if (hstoreTrust == NULL) {
  1823. hr = E_FAIL;
  1824. goto ExitHere;
  1825. }
  1826. cTrust = 1;
  1827. rgTrust = &hstoreTrust;
  1828. }
  1829. // Check for Random CA stores
  1830. for (i=0; i<cCAs; i++) {
  1831. rghcertstore[i] = CertDuplicateStore(rgCAs[i]);
  1832. }
  1833. if ((cCAs == 0) || (dwControl & CM_ADD_CERT_STORES)) {
  1834. for (i=0; i<COtherProviders; i++) {
  1835. rghcertstore[cCAs] = CertOpenStore(CERT_STORE_PROV_SYSTEM, X509_ASN_ENCODING,
  1836. hprov, CERT_SYSTEM_STORE_CURRENT_USER,
  1837. RgszProvider[i]);
  1838. if (rghcertstore[cCAs] == NULL) {
  1839. hr = E_FAIL;
  1840. goto ExitHere;
  1841. }
  1842. cCAs += 1;
  1843. }
  1844. }
  1845. rgCAs = rghcertstore;
  1846. //
  1847. // Find the graph of issuer nodes
  1848. //
  1849. pcfLeaf = new CCertFrame(pccertToCheck);
  1850. if(!pcfLeaf)
  1851. {
  1852. hr=E_OUTOFMEMORY;
  1853. goto ExitHere;
  1854. }
  1855. //
  1856. // Process every certificate that we found in the ancestor graph
  1857. //
  1858. for (pcf = pcfLeaf; pcf != NULL; pcf = pcf->m_pcfNext) {
  1859. //
  1860. // Check the time validity on the certificate
  1861. //
  1862. i = CertVerifyTimeValidityWithDelta(NULL, pcf->m_pccert->pCertInfo, TIME_DELTA_SECONDS);
  1863. if (((LONG)i) < 0) {
  1864. pcf->m_dwFlags |= CERT_VALIDITY_BEFORE_START;
  1865. }
  1866. else if (i > 0) {
  1867. pcf->m_dwFlags |= CERT_VALIDITY_AFTER_END;
  1868. }
  1869. //
  1870. // For Every Certificate Store we are going to search
  1871. //
  1872. for (i=0; i<cCAs+cRoots; i++) {
  1873. pccert2 = NULL;
  1874. do {
  1875. //
  1876. // Ask the store to find the next cert for us to examine
  1877. //
  1878. dwFlags = (CERT_STORE_SIGNATURE_FLAG |
  1879. CERT_STORE_REVOCATION_FLAG);
  1880. pccert = CertGetIssuerCertificateFromStore(
  1881. i < cRoots ? rgRoots[i] : rgCAs[i-cRoots],
  1882. pcf->m_pccert, pccert2,
  1883. &dwFlags);
  1884. //
  1885. // If no cert is found, then we should move to the next store
  1886. //
  1887. if (pccert == NULL) {
  1888. // Check to see if this cert was self-signed
  1889. if (GetLastError() == CRYPT_E_SELF_SIGNED) {
  1890. pcf->m_fSelfSign = TRUE;
  1891. }
  1892. break;
  1893. }
  1894. //
  1895. // Deterimine all of the failue modes for the certificate
  1896. // validity.
  1897. //
  1898. // Start by looking for the ones that WinCrypt gives to
  1899. // us for free.
  1900. //
  1901. if (dwFlags != 0) {
  1902. if (dwFlags & CERT_STORE_SIGNATURE_FLAG) {
  1903. pcf->m_dwFlags |= CERT_VALIDITY_SIGNATURE_FAILS;
  1904. }
  1905. if (dwFlags & CERT_STORE_REVOCATION_FLAG) {
  1906. if (dwFlags & CERT_STORE_NO_CRL_FLAG) {
  1907. pcf->m_dwFlags |= CERT_VALIDITY_NO_CRL_FOUND;
  1908. }
  1909. else {
  1910. pcf->m_dwFlags |= CERT_VALIDITY_CERTIFICATE_REVOKED;
  1911. }
  1912. }
  1913. }
  1914. //
  1915. // Setup to find the next possible parent, we may continue out
  1916. // of the loop at a later time
  1917. //
  1918. pccert2 = pccert;
  1919. //
  1920. // Check to see this cert is already a found parent of the
  1921. // current node
  1922. //
  1923. for (iParent = 0; iParent < pcf->m_cParents; iParent++) {
  1924. if (CertCompareCertificate(X509_ASN_ENCODING, pccert->pCertInfo,
  1925. pcf->m_rgpcfParents[iParent]->m_pccert->pCertInfo)){
  1926. break;
  1927. }
  1928. }
  1929. if (iParent != pcf->m_cParents) {
  1930. // Duplicate found -- go to next possible parent
  1931. continue;
  1932. }
  1933. if (iParent == MaxCertificateParents) {
  1934. // To many parents -- go to next possible parent
  1935. continue;
  1936. }
  1937. //
  1938. // Build a node to hold the cert we found and shove it onto the
  1939. // end of the list. We want to eleminate work so combine
  1940. // the same nodes if found.
  1941. //
  1942. for (pcf3 = pcf2 = pcfLeaf; pcf2 != NULL;
  1943. pcf3 = pcf2, pcf2 = pcf2->m_pcfNext) {
  1944. if (CertCompareCertificate(X509_ASN_ENCODING,
  1945. pccert->pCertInfo,
  1946. pcf2->m_pccert->pCertInfo)) {
  1947. break;
  1948. }
  1949. }
  1950. if (pcf2 == NULL) {
  1951. pcf3->m_pcfNext = new CCertFrame(pccert);
  1952. if (pcf3->m_pcfNext == NULL) {
  1953. // Out of memory during processing -- do the best one
  1954. // can to deal with it.
  1955. continue;
  1956. }
  1957. //
  1958. // Add in the parent to the structure
  1959. //
  1960. pcf->m_rgpcfParents[pcf->m_cParents++] = pcf3->m_pcfNext;
  1961. if (i < cRoots) {
  1962. pcf3->m_pcfNext->m_fRootStore = TRUE;
  1963. }
  1964. }
  1965. } while (pccert2 != NULL);
  1966. }
  1967. }
  1968. //
  1969. // Nix off errors the caller wants us to ignore
  1970. //
  1971. for (pcf = pcfLeaf; pcf != NULL; pcf = pcf->m_pcfNext) {
  1972. pcf->m_dwFlags &= dwValidityMask;
  1973. }
  1974. //
  1975. // Need to check the complete set of validity on all certificates.
  1976. //
  1977. hr = HrCheckValidity(pcfLeaf);
  1978. if (FAILED(hr)) {
  1979. goto ExitHere;
  1980. }
  1981. //
  1982. // If there are validity problems with the root cert, and we are not
  1983. // asked to do a compelete check. We are done and the operation was
  1984. // not successful.
  1985. //
  1986. if ((pcfLeaf->m_dwFlags != 0) && !(dwControl & CERT_TRUST_DO_FULL_SEARCH)) {
  1987. hr = S_FALSE;
  1988. *ppcf = pcfLeaf;
  1989. pcfLeaf = NULL; // don't want it freed
  1990. // BUGBUG: should we return at least the root in the chain var?
  1991. *pcNodes = 0;
  1992. goto ExitHere;
  1993. }
  1994. //
  1995. // Ok -- we have the graph of roots, now lets start looking for all of the
  1996. // different possible trust problems
  1997. //
  1998. if (cPurposes)
  1999. {
  2000. CTL_VERIFY_USAGE_PARA vup;
  2001. memset(&vup, 0, sizeof(vup));
  2002. vup.cbSize = sizeof(vup);
  2003. vup.cCtlStore = cTrust;
  2004. vup.rghCtlStore = rgTrust; // "TRUST"
  2005. vup.cSignerStore = cRoots;
  2006. vup.rghSignerStore = rgRoots; // "Roots"
  2007. CTL_VERIFY_USAGE_STATUS vus;
  2008. PCCTL_CONTEXT pctlTrust;
  2009. pctlTrust = NULL;
  2010. memset(&vus, 0, sizeof(vus));
  2011. vus.cbSize = sizeof(vus);
  2012. vus.ppCtl = &pctlTrust;
  2013. for (i=0; i<cPurposes; i++) {
  2014. CTL_USAGE ctlusage;
  2015. BOOL f;
  2016. ctlusage.cUsageIdentifier = 1;
  2017. ctlusage.rgpszUsageIdentifier = &rgszPurposes[i];
  2018. for (pcf = pcfLeaf; pcf != NULL; pcf = pcf->m_pcfNext) {
  2019. if (pcf->m_rgTrust == NULL) {
  2020. pcf->m_rgTrust = new STrustDesc[cPurposes];
  2021. if (pcf->m_rgTrust == NULL) {
  2022. continue;
  2023. }
  2024. memset(pcf->m_rgTrust, 0, cPurposes * sizeof(STrustDesc));
  2025. }
  2026. if (pcf->m_fRootStore) {
  2027. continue;
  2028. }
  2029. f = CertVerifyCTLUsage(X509_ASN_ENCODING, CTL_CERT_SUBJECT_TYPE,
  2030. (LPVOID) pcf->m_pccert, &ctlusage,
  2031. CERT_VERIFY_INHIBIT_CTL_UPDATE_FLAG |
  2032. CERT_VERIFY_NO_TIME_CHECK_FLAG |
  2033. CERT_VERIFY_TRUSTED_SIGNERS_FLAG, &vup, &vus);
  2034. if (f) {
  2035. PCTL_ENTRY pentry;
  2036. pentry = &pctlTrust->pCtlInfo->rgCTLEntry[vus.dwCtlEntryIndex];
  2037. pcf->m_rgTrust[i].szOid = _strdup(pentry->rgAttribute[0].pszObjId);
  2038. // Assert(pentry->rgAttribute[0].cAttr == 1);
  2039. pcf->m_rgTrust[i].cbTrustData =
  2040. pentry->rgAttribute[0].rgValue[0].cbData;
  2041. pcf->m_rgTrust[i].pbTrustData =
  2042. (LPBYTE) malloc(pcf->m_rgTrust[i].cbTrustData);
  2043. memcpy(pcf->m_rgTrust[i].pbTrustData,
  2044. pentry->rgAttribute[0].rgValue[0].pbData,
  2045. pentry->rgAttribute[0].rgValue[0].cbData);
  2046. }
  2047. }
  2048. }
  2049. //
  2050. // We have all of the data needed to make a trust decision. See if we
  2051. // do trust
  2052. //
  2053. if (cPurposes == 1) {
  2054. hr = HrCheckTrust(pcfLeaf, 0);
  2055. if (FAILED(hr)) {
  2056. goto ExitHere;
  2057. }
  2058. if ((hr == S_FALSE) && !(dwControl & CERT_TRUST_DO_FULL_SEARCH)) {
  2059. *pcNodes = 0;
  2060. pcfLeaf->m_dwFlags |= (CERT_VALIDITY_NO_TRUST_DATA & dwValidityMask);
  2061. *ppcf = pcfLeaf;
  2062. pcfLeaf = NULL;
  2063. goto ExitHere;
  2064. }
  2065. }
  2066. else {
  2067. for (i=0; i<cPurposes; i++) {
  2068. HrCheckTrust(pcfLeaf, i);
  2069. }
  2070. }
  2071. }
  2072. //
  2073. // Now let the user have his crack at the tree and build the final
  2074. // trust path at the same time. If the user did not provide a check
  2075. // function then all certs are acceptable
  2076. //
  2077. hr = HrPerformUserCheck(pcfLeaf, TRUE, pcNodes, 0, rgpcfResult);
  2078. if (FAILED(hr)) {
  2079. goto ExitHere;
  2080. }
  2081. *ppcf = pcfLeaf;
  2082. pcfLeaf = NULL;
  2083. //
  2084. // We jump here on a failure and fall in on success. Clean up the items we
  2085. // have created.
  2086. //
  2087. ExitHere:
  2088. if (hstoreRoot && rgRoots == &hstoreRoot) {
  2089. CertCloseStore(hstoreRoot, 0);
  2090. }
  2091. if (hstoreTrust && rgTrust == &hstoreTrust) {
  2092. CertCloseStore(hstoreTrust, 0);
  2093. }
  2094. if (rgCAs == rghcertstore) {
  2095. for (i=0; i<cCAs; i++) {
  2096. if (rgCAs[i] != NULL) {
  2097. CertCloseStore(rgCAs[i], 0);
  2098. }
  2099. }
  2100. }
  2101. if (pcfLeaf != NULL) {
  2102. delete pcfLeaf;
  2103. }
  2104. return hr;
  2105. }
  2106. ////////////////////////////////////////////////////////////////////
  2107. ////////////////////////////////////////////////////////////////////
  2108. //
  2109. // TRUST PROVIDER INTERFACE
  2110. //
  2111. ////////////////////////////////////////////////////////////////////
  2112. ////////////////////////////////////////////////////////////////////
  2113. VOID ClientUnload(LPVOID /*pTrustProviderInfo*/)
  2114. {
  2115. ;
  2116. }
  2117. VOID SubmitCertificate(LPWIN_CERTIFICATE /*pCert*/)
  2118. {
  2119. ;
  2120. }
  2121. //// VerifyTrust
  2122. //
  2123. // Description:
  2124. // This is the core program in a trust system.
  2125. //
  2126. HRESULT WINAPI VerifyTrust(HWND /*hwnd*/, GUID * pguid, LPVOID pv)
  2127. {
  2128. DWORD cFrames;
  2129. HRESULT hr;
  2130. DWORD i;
  2131. PCCertFrame pcfLeaf = NULL;
  2132. PCERT_VERIFY_CERTIFICATE_TRUST pinfo = (PCERT_VERIFY_CERTIFICATE_TRUST) pv;
  2133. DWORD * rgdwErrors = NULL;
  2134. LPBYTE * rgpbTrust = NULL;
  2135. PCCERT_CONTEXT * rgpccert = NULL;
  2136. PCCertFrame rgpcf[20];
  2137. //
  2138. // Ensuer that we got called appropriately for our data
  2139. //
  2140. if (memcmp(pguid, &GuidCertValidate, sizeof(GuidCertValidate)) != 0) {
  2141. return E_FAIL;
  2142. }
  2143. //
  2144. // Make sure we have some data to play with
  2145. //
  2146. if ((pinfo->cbSize != sizeof(*pinfo)) || (pinfo->pccert == NULL)) {
  2147. return E_INVALIDARG;
  2148. }
  2149. //
  2150. // Call the core trust routine to do all of the intersting work
  2151. //
  2152. hr = HrDoTrustWork(pinfo->pccert, pinfo->dwFlags, ~(pinfo->dwIgnoreErr),
  2153. (pinfo->pszUsageOid != NULL ? 1 : 0),
  2154. &pinfo->pszUsageOid, pinfo->hprov,
  2155. pinfo->cRootStores, pinfo->rghstoreRoots,
  2156. pinfo->cStores, pinfo->rghstoreCAs,
  2157. pinfo->cTrustStores, pinfo->rghstoreTrust,
  2158. pinfo->pfnTrustHelper, pinfo->lCustData, &pcfLeaf,
  2159. &cFrames, rgpcf, NULL);
  2160. if (FAILED(hr)) {
  2161. return hr;
  2162. }
  2163. //
  2164. // We succeeded in getting some type of answer from the trust system, so
  2165. // format and return answers if any are requested.
  2166. //
  2167. if (pinfo->pdwErrors != NULL) {
  2168. *pinfo->pdwErrors = pcfLeaf->m_dwFlags;
  2169. }
  2170. if (pinfo->pcChain != NULL) {
  2171. *pinfo->pcChain = cFrames;
  2172. }
  2173. if (pinfo->prgChain != NULL) {
  2174. rgpccert = (PCCERT_CONTEXT*) LocalAlloc(LMEM_FIXED,
  2175. cFrames * sizeof(PCCERT_CONTEXT));
  2176. if (rgpccert == NULL) {
  2177. hr = E_OUTOFMEMORY;
  2178. goto ExitHere;
  2179. }
  2180. for (i=0; i<cFrames; i++) {
  2181. rgpccert[i] = CertDuplicateCertificateContext(rgpcf[i]->m_pccert);
  2182. }
  2183. }
  2184. if (pinfo->prgdwErrors != NULL) {
  2185. rgdwErrors = (DWORD *) LocalAlloc(LMEM_FIXED,
  2186. (*pinfo->pcChain)*sizeof(DWORD));
  2187. if (rgdwErrors == NULL) {
  2188. hr = E_OUTOFMEMORY;
  2189. goto ExitHere;
  2190. }
  2191. for (i=0; i<cFrames; i++) {
  2192. rgdwErrors[i] = rgpcf[i]->m_dwFlags;
  2193. }
  2194. }
  2195. if (pinfo->prgpbTrustInfo != NULL) {
  2196. rgpbTrust = (LPBYTE *) LocalAlloc(LMEM_FIXED,
  2197. (*pinfo->pcChain)*sizeof(LPBYTE));
  2198. if (rgpbTrust == NULL) {
  2199. hr = E_OUTOFMEMORY;
  2200. goto ExitHere;
  2201. }
  2202. rgpbTrust[0] = NULL;
  2203. }
  2204. ExitHere:
  2205. if (FAILED(hr)) {
  2206. #ifndef WIN16
  2207. if (rgpccert != NULL) LocalFree(rgpccert);
  2208. if (rgpbTrust != NULL) LocalFree(rgpbTrust);
  2209. if (rgdwErrors != NULL) LocalFree(rgdwErrors);
  2210. #else
  2211. if (rgpccert != NULL) LocalFree((HLOCAL)rgpccert);
  2212. if (rgpbTrust != NULL) LocalFree((HLOCAL)rgpbTrust);
  2213. if (rgdwErrors != NULL) LocalFree((HLOCAL)rgdwErrors);
  2214. #endif // !WIN16
  2215. }
  2216. else {
  2217. if (rgpccert != NULL) *pinfo->prgChain = rgpccert;
  2218. if (rgdwErrors != NULL) *pinfo->prgdwErrors = rgdwErrors;
  2219. if (rgpbTrust != NULL) *pinfo->prgpbTrustInfo = (DATA_BLOB *) rgpbTrust;
  2220. }
  2221. delete pcfLeaf;
  2222. return hr;
  2223. }
  2224. extern const GUID rgguidActions[];
  2225. #if !defined(WIN16) && !defined(MAC)
  2226. WINTRUST_PROVIDER_CLIENT_SERVICES WinTrustProviderClientServices = {
  2227. ClientUnload, VerifyTrust, SubmitCertificate
  2228. };
  2229. const WINTRUST_PROVIDER_CLIENT_INFO ProvInfo = {
  2230. WIN_TRUST_REVISION_1_0, &WinTrustProviderClientServices,
  2231. 1, (GUID *) &GuidCertValidate
  2232. };
  2233. //// WinTrustProviderClientInitialize
  2234. //
  2235. // Description:
  2236. // Client initialization routine. Called by WinTrust when the dll
  2237. // is loaded.
  2238. //
  2239. // Parameters:
  2240. // dwWinTrustRevision - Provides revision information
  2241. // lpWinTrustInfo - Provides a list of services available to the
  2242. // trust provider from WinTrust
  2243. // lpProvidername - Supplies a null terminated string representing the
  2244. // provider's name. Shouldb passed back to WinTrust
  2245. // when required without modification.
  2246. // lpTrustProviderInfo - Used to return trust provider information.
  2247. //
  2248. // Returns:
  2249. // TRUE on success and FALSE on failure. Must set last error on failure.
  2250. //
  2251. BOOL WINAPI WinTrustProviderClientInitialize(DWORD /*dwWinTrustRevision*/,
  2252. LPWINTRUST_CLIENT_TP_INFO /*pWinTrustInfo*/,
  2253. LPWSTR /*lpProviderName*/,
  2254. LPWINTRUST_PROVIDER_CLIENT_INFO * ppTrustProvInfo)
  2255. {
  2256. *ppTrustProvInfo = (LPWINTRUST_PROVIDER_CLIENT_INFO) &ProvInfo;
  2257. return TRUE;
  2258. }
  2259. #endif // !WIN16 && !MAC
  2260. #endif // NT5BUILD
  2261. LPWSTR FormatValidityFailures(DWORD dwFlags)
  2262. {
  2263. DWORD cch = 0;
  2264. LPWSTR pwsz = NULL;
  2265. WCHAR rgwch[200];
  2266. if (dwFlags == 0) {
  2267. return NULL;
  2268. }
  2269. cch = 100;
  2270. pwsz = (LPWSTR) malloc(cch*sizeof(WCHAR));
  2271. if (pwsz == NULL) {
  2272. return NULL;
  2273. }
  2274. if (dwFlags & CERT_VALIDITY_BEFORE_START) {
  2275. LoadString(HinstDll, IDS_WHY_NOT_YET, rgwch, sizeof(rgwch)/sizeof(WCHAR));
  2276. StrCpyNW(pwsz, rgwch, cch);
  2277. } else {
  2278. StrCpyNW(pwsz, L"", cch);
  2279. }
  2280. if (dwFlags & CERT_VALIDITY_AFTER_END) {
  2281. LoadString(HinstDll, IDS_WHY_EXPIRED, rgwch, sizeof(rgwch)/sizeof(WCHAR));
  2282. if (wcslen(pwsz) + wcslen(rgwch) + 2 > cch) {
  2283. cch += 200;
  2284. pwsz = (LPWSTR) realloc(pwsz, cch*sizeof(WCHAR));
  2285. if (pwsz == NULL) {
  2286. return pwsz;
  2287. }
  2288. }
  2289. if (wcslen(pwsz) > 0)
  2290. StrCatBuffW(pwsz, wszCRLF, cch);
  2291. StrCatBuffW(pwsz, rgwch, cch);
  2292. }
  2293. if (dwFlags & CERT_VALIDITY_SIGNATURE_FAILS) {
  2294. LoadString(HinstDll, IDS_WHY_CERT_SIG, rgwch, sizeof(rgwch)/sizeof(WCHAR));
  2295. if (wcslen(pwsz) + wcslen(rgwch) + 2 > cch) {
  2296. cch += 200;
  2297. pwsz = (LPWSTR) realloc(pwsz, cch*sizeof(WCHAR));
  2298. if (pwsz == NULL) {
  2299. return pwsz;
  2300. }
  2301. }
  2302. if (wcslen(pwsz) > 0)
  2303. StrCatBuffW(pwsz, wszCRLF, cch);
  2304. StrCatBuffW(pwsz, rgwch, cch);
  2305. }
  2306. if (dwFlags & CERT_VALIDITY_NO_ISSUER_CERT_FOUND) {
  2307. LoadString(HinstDll, IDS_WHY_NO_PARENT, rgwch, sizeof(rgwch)/sizeof(WCHAR));
  2308. if (wcslen(pwsz) + wcslen(rgwch) + 2 > cch) {
  2309. cch += 200;
  2310. pwsz = (LPWSTR) realloc(pwsz, cch*sizeof(WCHAR));
  2311. if (pwsz == NULL) {
  2312. return pwsz;
  2313. }
  2314. }
  2315. if (wcslen(pwsz) > 0)
  2316. StrCatBuffW(pwsz, wszCRLF, cch);
  2317. StrCatBuffW(pwsz, rgwch, cch);
  2318. }
  2319. if (dwFlags & CERT_VALIDITY_NO_CRL_FOUND) {
  2320. LoadString(HinstDll, IDS_WHY_NO_CRL, rgwch, sizeof(rgwch)/sizeof(WCHAR));
  2321. if (wcslen(pwsz) + wcslen(rgwch) + 2 > cch) {
  2322. cch += 200;
  2323. pwsz = (LPWSTR) realloc(pwsz, cch*sizeof(WCHAR));
  2324. if (pwsz == NULL) {
  2325. return pwsz;
  2326. }
  2327. }
  2328. if (wcslen(pwsz) > 0)
  2329. StrCatBuffW(pwsz, wszCRLF, cch);
  2330. StrCatBuffW(pwsz, rgwch, cch);
  2331. }
  2332. if (dwFlags & CERT_VALIDITY_CERTIFICATE_REVOKED) {
  2333. LoadString(HinstDll, IDS_WHY_REVOKED, rgwch, sizeof(rgwch)/sizeof(WCHAR));
  2334. if (wcslen(pwsz) + wcslen(rgwch) + 2 > cch) {
  2335. cch += 200;
  2336. pwsz = (LPWSTR) realloc(pwsz, cch*sizeof(WCHAR));
  2337. if (pwsz == NULL) {
  2338. return pwsz;
  2339. }
  2340. }
  2341. if (wcslen(pwsz) > 0)
  2342. StrCatBuffW(pwsz, wszCRLF, cch);
  2343. StrCatBuffW(pwsz, rgwch, cch);
  2344. }
  2345. if (dwFlags & CERT_VALIDITY_CRL_OUT_OF_DATE) {
  2346. LoadString(HinstDll, IDS_WHY_CRL_EXPIRED, rgwch, sizeof(rgwch)/sizeof(WCHAR));
  2347. if (wcslen(pwsz) + wcslen(rgwch) + 2 > cch) {
  2348. cch += 200;
  2349. pwsz = (LPWSTR) realloc(pwsz, cch*sizeof(WCHAR));
  2350. if (pwsz == NULL) {
  2351. return pwsz;
  2352. }
  2353. }
  2354. if (wcslen(pwsz) > 0)
  2355. StrCatBuffW(pwsz, wszCRLF, cch);
  2356. StrCatBuffW(pwsz, rgwch, cch);
  2357. }
  2358. if (dwFlags & CERT_VALIDITY_KEY_USAGE_EXT_FAILURE) {
  2359. LoadString(HinstDll, IDS_WHY_KEY_USAGE, rgwch, sizeof(rgwch)/sizeof(WCHAR));
  2360. if (wcslen(pwsz) + wcslen(rgwch) + 2 > cch) {
  2361. cch += 200;
  2362. pwsz = (LPWSTR) realloc(pwsz, cch*sizeof(WCHAR));
  2363. if (pwsz == NULL) {
  2364. return pwsz;
  2365. }
  2366. }
  2367. if (wcslen(pwsz) > 0)
  2368. StrCatBuffW(pwsz, wszCRLF, cch);
  2369. StrCatBuffW(pwsz, rgwch, cch);
  2370. }
  2371. if (dwFlags & CERT_VALIDITY_EXTENDED_USAGE_FAILURE) {
  2372. LoadString(HinstDll, IDS_WHY_EXTEND_USE, rgwch, sizeof(rgwch)/sizeof(WCHAR));
  2373. if (wcslen(pwsz) + wcslen(rgwch) + 2 > cch) {
  2374. cch += 200;
  2375. pwsz = (LPWSTR) realloc(pwsz, cch*sizeof(WCHAR));
  2376. if (pwsz == NULL) {
  2377. return pwsz;
  2378. }
  2379. }
  2380. if (wcslen(pwsz) > 0)
  2381. StrCatBuffW(pwsz, wszCRLF, cch);
  2382. StrCatBuffW(pwsz, rgwch, cch);
  2383. }
  2384. if (dwFlags & CERT_VALIDITY_NAME_CONSTRAINTS_FAILURE) {
  2385. LoadString(HinstDll, IDS_WHY_NAME_CONST, rgwch, sizeof(rgwch)/sizeof(WCHAR));
  2386. if (wcslen(pwsz) + wcslen(rgwch) + 2 > cch) {
  2387. cch += 200;
  2388. pwsz = (LPWSTR) realloc(pwsz, cch*sizeof(WCHAR));
  2389. if (pwsz == NULL) {
  2390. return pwsz;
  2391. }
  2392. }
  2393. if (wcslen(pwsz) > 0)
  2394. StrCatBuffW(pwsz, wszCRLF, cch);
  2395. StrCatBuffW(pwsz, rgwch, cch);
  2396. }
  2397. if (dwFlags & CERT_VALIDITY_UNKNOWN_CRITICAL_EXTENSION) {
  2398. LoadString(HinstDll, IDS_WHY_CRITICAL_EXT, rgwch, sizeof(rgwch)/sizeof(WCHAR));
  2399. if (wcslen(pwsz) + wcslen(rgwch) + 2 > cch) {
  2400. cch += 200;
  2401. pwsz = (LPWSTR) realloc(pwsz, cch*sizeof(WCHAR));
  2402. if (pwsz == NULL) {
  2403. return pwsz;
  2404. }
  2405. }
  2406. if (wcslen(pwsz) > 0)
  2407. StrCatBuffW(pwsz, wszCRLF, cch);
  2408. StrCatBuffW(pwsz, rgwch, cch);
  2409. }
  2410. return pwsz;
  2411. }
  2412. //////////////////////////////////////////////////////////////////////////////////
  2413. HRESULT CTLModifyHelper(int cCertsToModify, PCTL_MODIFY_REQUEST rgCertMods,
  2414. LPCSTR szPurpose, HWND /*hwnd*/,
  2415. HCERTSTORE hcertstorTrust,
  2416. PCCERT_CONTEXT pccertSigner)
  2417. {
  2418. DWORD cb;
  2419. DWORD cbData;
  2420. DWORD cbOut;
  2421. CTL_INFO ctlInfo;
  2422. CTL_USAGE ctlUsage;
  2423. DWORD dwOne = 1;
  2424. HCRYPTPROV hprov = NULL;
  2425. HRESULT hr = S_OK;
  2426. DWORD i;
  2427. int iCert;
  2428. LPBYTE pbEncode = NULL;
  2429. LPBYTE pbHash;
  2430. PCCTL_CONTEXT pcctl = NULL;
  2431. PCRYPT_KEY_PROV_INFO pprovinfo = NULL;
  2432. CTL_ENTRY * rgctlEntry = NULL;
  2433. //
  2434. // Build the attributes blob which says that we actually trust/distrust a certificate.
  2435. //
  2436. CRYPT_ATTRIBUTE attributeYes;
  2437. CRYPT_ATTR_BLOB attrBlobYes;
  2438. CRYPT_ATTRIBUTE attributeNo;
  2439. CRYPT_ATTR_BLOB attrBlobNo;
  2440. CRYPT_ATTRIBUTE attributeParent;
  2441. CRYPT_ATTR_BLOB attrBlobParent;
  2442. attributeYes.pszObjId = (LPSTR) SzOID_CTL_ATTR_YESNO_TRUST;
  2443. attributeYes.cValue = 1;
  2444. attributeYes.rgValue = &attrBlobYes;
  2445. attrBlobYes.cbData = sizeof(RgbTrustYes); // MUST BE ASN
  2446. attrBlobYes.pbData = (LPBYTE) RgbTrustYes;
  2447. attributeNo.pszObjId = (LPSTR) SzOID_CTL_ATTR_YESNO_TRUST;
  2448. attributeNo.cValue = 1;
  2449. attributeNo.rgValue = &attrBlobNo;
  2450. attrBlobNo.cbData = sizeof(RgbTrustNo); // MUST BE ASN
  2451. attrBlobNo.pbData = (LPBYTE) RgbTrustNo;
  2452. attributeParent.pszObjId = (LPSTR) SzOID_CTL_ATTR_YESNO_TRUST;
  2453. attributeParent.cValue = 1;
  2454. attributeParent.rgValue = &attrBlobParent;
  2455. attrBlobParent.cbData = sizeof(RgbTrustParent); // MUST BE ASN
  2456. attrBlobParent.pbData = (LPBYTE) RgbTrustParent;
  2457. //
  2458. // Get the crypt provider for the certificate we are going to use in the trust
  2459. //
  2460. if (!CertGetCertificateContextProperty(pccertSigner, CERT_KEY_PROV_INFO_PROP_ID,
  2461. NULL, &cbData)) {
  2462. hr = E_FAIL;
  2463. goto Exit;
  2464. }
  2465. pprovinfo = (PCRYPT_KEY_PROV_INFO) malloc(cbData);
  2466. CertGetCertificateContextProperty(pccertSigner, CERT_KEY_PROV_INFO_PROP_ID,
  2467. pprovinfo, &cbData);
  2468. if (!CryptAcquireContextW(&hprov, pprovinfo->pwszContainerName,
  2469. pprovinfo->pwszProvName,
  2470. pprovinfo->dwProvType, 0)) {
  2471. hr = GetLastError();
  2472. goto Exit;
  2473. }
  2474. //
  2475. // We have a certificate and a provider to use for signing purposes.
  2476. // Look for a possible CTL to be emended by us.
  2477. //
  2478. //
  2479. // Search for a CTL signed by this cert and for the requested usage
  2480. //
  2481. CTL_FIND_USAGE_PARA ctlFind;
  2482. ctlFind.cbSize = sizeof(ctlFind);
  2483. ctlFind.SubjectUsage.cUsageIdentifier = 1;
  2484. ctlFind.SubjectUsage.rgpszUsageIdentifier = (LPSTR *) &szPurpose;
  2485. ctlFind.ListIdentifier.cbData = 0;
  2486. ctlFind.ListIdentifier.pbData = 0;
  2487. ctlFind.pSigner = pccertSigner->pCertInfo;
  2488. pcctl = CertFindCTLInStore(hcertstorTrust, X509_ASN_ENCODING, 0,
  2489. CTL_FIND_USAGE, &ctlFind, NULL);
  2490. if (pcctl == NULL) {
  2491. //
  2492. // No CTL currently exists, so build one from scratch
  2493. //
  2494. //
  2495. // Allocate space to hold the CTL entries
  2496. //
  2497. // size = (sizeof CTL_ENTRY + sizeof of SHA1 hash) * # certs to add
  2498. //
  2499. cb = cCertsToModify * (sizeof(CTL_ENTRY) + 20);
  2500. rgctlEntry = (PCTL_ENTRY) malloc(cb);
  2501. memset(rgctlEntry, 0, cb);
  2502. pbHash = ((LPBYTE) rgctlEntry) + (cCertsToModify * sizeof(CTL_ENTRY));
  2503. //
  2504. // Get the identifier for each of the certs and setup the Trust List
  2505. // entry for each of the certs. Note that they all point
  2506. // to the same attribute, this is possible since we are going to
  2507. // have the exact same amount of trust on each cert -- YES!!!! --
  2508. //
  2509. for (iCert = 0; iCert < cCertsToModify; iCert++, pbHash += 20) {
  2510. rgctlEntry[iCert].SubjectIdentifier.cbData = 20;
  2511. rgctlEntry[iCert].SubjectIdentifier.pbData = pbHash;
  2512. rgctlEntry[iCert].cAttribute = 1;
  2513. cb = 20;
  2514. CertGetCertificateContextProperty(rgCertMods[iCert].pccert,
  2515. CERT_SHA1_HASH_PROP_ID, pbHash, &cb);
  2516. rgCertMods[iCert].dwError = 0;
  2517. switch (rgCertMods[iCert].dwOperation) {
  2518. case CTL_MODIFY_REQUEST_ADD_TRUSTED:
  2519. rgctlEntry[iCert].rgAttribute = &attributeYes;
  2520. break;
  2521. case CTL_MODIFY_REQUEST_REMOVE:
  2522. rgctlEntry[iCert].rgAttribute = &attributeParent;
  2523. break;
  2524. case CTL_MODIFY_REQUEST_ADD_NOT_TRUSTED:
  2525. rgctlEntry[iCert].rgAttribute = &attributeNo;
  2526. break;
  2527. default:
  2528. rgCertMods[iCert].dwError = (DWORD) E_FAIL;
  2529. iCert -= 1; // Don't include this one
  2530. break;
  2531. }
  2532. }
  2533. //
  2534. // Now setup the the overall structure of the Trust List for later
  2535. // encoding and signing.
  2536. //
  2537. ctlUsage.cUsageIdentifier = 1;
  2538. ctlUsage.rgpszUsageIdentifier = (LPSTR *) &szPurpose;
  2539. memset(&ctlInfo, 0, sizeof(ctlInfo));
  2540. ctlInfo.dwVersion = 0;
  2541. ctlInfo.SubjectUsage = ctlUsage;
  2542. // ctlInfo.ListIdentifier = 0;
  2543. ctlInfo.SequenceNumber.cbData = sizeof(dwOne);
  2544. ctlInfo.SequenceNumber.pbData = (LPBYTE) &dwOne;
  2545. GetSystemTimeAsFileTime(&ctlInfo.ThisUpdate);
  2546. // ctlInfo.NextUpdate = 0;
  2547. ctlInfo.SubjectAlgorithm.pszObjId = szOID_OIWSEC_sha1;
  2548. // ctlInfo.SubjectAlgorithm.Parameters.cbData = 0;
  2549. ctlInfo.cCTLEntry = cCertsToModify;
  2550. ctlInfo.rgCTLEntry = rgctlEntry;
  2551. // ctlInfo.cExtension = 0;
  2552. // ctlInfo.rgExtension = NULL;
  2553. }
  2554. else {
  2555. BOOL fRewrite;
  2556. memcpy(&ctlInfo, pcctl->pCtlInfo, sizeof(ctlInfo));
  2557. //
  2558. // We found a CTL with the right usage, now lets see if we need to add
  2559. // certificate to it.
  2560. //
  2561. // Start by assuming that we will need to add to the CTL so allocate
  2562. // space to hold the new set of Trust Entries
  2563. //
  2564. cb = (pcctl->pCtlInfo->cCTLEntry * sizeof(CTL_ENTRY) +
  2565. cCertsToModify * (sizeof(CTL_ENTRY) + 20));
  2566. rgctlEntry = (PCTL_ENTRY) malloc(cb);
  2567. memset(rgctlEntry, 0, cb);
  2568. pbHash = (((LPBYTE) rgctlEntry) +
  2569. (cCertsToModify + pcctl->pCtlInfo->cCTLEntry) * sizeof(CTL_ENTRY));
  2570. memcpy(rgctlEntry, pcctl->pCtlInfo->rgCTLEntry,
  2571. pcctl->pCtlInfo->cCTLEntry * sizeof(CTL_ENTRY));
  2572. ctlInfo.rgCTLEntry = rgctlEntry;
  2573. //
  2574. // For each certificate, see if the certificate is already in the list
  2575. // and append it to the end if it isn't
  2576. //
  2577. fRewrite = FALSE;
  2578. for (iCert = 0; iCert < cCertsToModify; iCert++) {
  2579. rgCertMods[iCert].dwError = 0;
  2580. cb = 20;
  2581. CertGetCertificateContextProperty(rgCertMods[iCert].pccert,
  2582. CERT_SHA1_HASH_PROP_ID, pbHash, &cb);
  2583. for (i=0; i<pcctl->pCtlInfo->cCTLEntry; i++) {
  2584. if (memcmp(pbHash, rgctlEntry[i].SubjectIdentifier.pbData, 20) == 0){
  2585. break;
  2586. }
  2587. }
  2588. //
  2589. // If we did not find a matching item, then add a new one to the
  2590. // end of the list
  2591. //
  2592. if (i == pcctl->pCtlInfo->cCTLEntry) {
  2593. rgctlEntry[i].SubjectIdentifier.cbData = 20;
  2594. rgctlEntry[i].SubjectIdentifier.pbData = pbHash;
  2595. rgctlEntry[i].cAttribute = 1;
  2596. pbHash += 20;
  2597. ctlInfo.cCTLEntry += 1;
  2598. fRewrite = TRUE;
  2599. switch (rgCertMods[iCert].dwOperation) {
  2600. case CTL_MODIFY_REQUEST_ADD_TRUSTED:
  2601. rgctlEntry[i].rgAttribute = &attributeYes;
  2602. break;
  2603. case CTL_MODIFY_REQUEST_REMOVE:
  2604. rgctlEntry[i].rgAttribute = &attributeParent;
  2605. break;
  2606. case CTL_MODIFY_REQUEST_ADD_NOT_TRUSTED:
  2607. rgctlEntry[i].rgAttribute = &attributeNo;
  2608. break;
  2609. default:
  2610. rgCertMods[i].dwError = (DWORD) E_FAIL;
  2611. ctlInfo.cCTLEntry -= 1; // Don't include this one
  2612. break;
  2613. }
  2614. }
  2615. //
  2616. // If we did find a matching, then put the new attribute into the
  2617. // list (may replace trust with distrust)
  2618. //
  2619. else {
  2620. switch (rgCertMods[iCert].dwOperation) {
  2621. case CTL_MODIFY_REQUEST_ADD_TRUSTED:
  2622. rgctlEntry[i].rgAttribute = &attributeYes;
  2623. break;
  2624. case CTL_MODIFY_REQUEST_REMOVE:
  2625. rgctlEntry[i].rgAttribute = &attributeParent;
  2626. break;
  2627. default:
  2628. case CTL_MODIFY_REQUEST_ADD_NOT_TRUSTED:
  2629. rgctlEntry[i].rgAttribute = &attributeNo;
  2630. break;
  2631. }
  2632. fRewrite = TRUE;
  2633. }
  2634. }
  2635. //
  2636. // Nothing to be added at this time -- exit and say success
  2637. //
  2638. if (!fRewrite) {
  2639. hr = S_OK;
  2640. goto Exit;
  2641. }
  2642. //
  2643. // Increment the sequence number
  2644. //
  2645. // M00MAC -- this may be cheating, however I think that we can use it
  2646. // one the mac without change, I don't really care that the sequence
  2647. // is understandable at this point, as long as it does sequence.
  2648. //
  2649. dwOne = 0;
  2650. memcpy(&dwOne, ctlInfo.SequenceNumber.pbData,
  2651. ctlInfo.SequenceNumber.cbData);
  2652. dwOne += 1;
  2653. ctlInfo.SequenceNumber.cbData = sizeof(dwOne);
  2654. ctlInfo.SequenceNumber.pbData = (LPBYTE) &dwOne;
  2655. }
  2656. //
  2657. // OK --- We have the basic information built up for a Cert Trust List,
  2658. // now we just need to encode and sign the blasted thing
  2659. //
  2660. CMSG_SIGNER_ENCODE_INFO signer1;
  2661. memset(&signer1, 0, sizeof(signer1));
  2662. signer1.cbSize = sizeof(signer1);
  2663. signer1.pCertInfo = pccertSigner->pCertInfo;
  2664. signer1.hCryptProv = hprov;
  2665. signer1.dwKeySpec = AT_SIGNATURE;
  2666. signer1.HashAlgorithm.pszObjId = szOID_OIWSEC_sha1;
  2667. // signer1.HashAlgorithm.Parameters.cbData = 0;
  2668. // signer1.pvHashAuxInfo = 0;
  2669. // signer1.cAuthAttrib = 0;
  2670. // signer1.cUnauthAttr = 0;
  2671. CMSG_SIGNED_ENCODE_INFO signinfo;
  2672. memset(&signinfo, 0, sizeof(signinfo));
  2673. signinfo.cbSize = sizeof(signinfo);
  2674. signinfo.cSigners = 1;
  2675. signinfo.rgSigners = &signer1;
  2676. signinfo.cCertEncoded = 0;
  2677. signinfo.cCrlEncoded = 0;
  2678. if (!CryptMsgEncodeAndSignCTL(PKCS_7_ASN_ENCODING, &ctlInfo, &signinfo,
  2679. 0, NULL, &cbOut)) {
  2680. hr = GetLastError();
  2681. goto Exit;
  2682. }
  2683. pbEncode = (LPBYTE) malloc(cbOut);
  2684. if (!CryptMsgEncodeAndSignCTL(PKCS_7_ASN_ENCODING, &ctlInfo, &signinfo,
  2685. 0, pbEncode, &cbOut)) {
  2686. hr = GetLastError();
  2687. goto Exit;
  2688. }
  2689. //
  2690. // Now put it into the trust store
  2691. //
  2692. if (!CertAddEncodedCTLToStore(hcertstorTrust, PKCS_7_ASN_ENCODING,
  2693. pbEncode, cbOut,
  2694. CERT_STORE_ADD_REPLACE_EXISTING, NULL)) {
  2695. //
  2696. // If we fail, and we in debug mode then create an output file so
  2697. // we can figure out what we did wrong.
  2698. //
  2699. #ifdef DEBUG
  2700. HANDLE hfile;
  2701. hfile = CreateFileA("c:\\output.t", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
  2702. 0, 0);
  2703. WriteFile(hfile, pbEncode, cbOut, &cb, NULL);
  2704. CloseHandle(hfile);
  2705. #endif // DEBUG
  2706. hr = GetLastError();
  2707. goto Exit;
  2708. }
  2709. //
  2710. // We succeeded in the operation
  2711. //
  2712. hr = S_OK;
  2713. //
  2714. // A single point of clean up and exit for everything.
  2715. //
  2716. Exit:
  2717. if (rgctlEntry != NULL) free(rgctlEntry);
  2718. if (pprovinfo != NULL) free(pprovinfo);
  2719. if (pcctl != NULL) CertFreeCTLContext(pcctl);
  2720. if (pbEncode != NULL) free(pbEncode);
  2721. if (hprov != NULL) CryptReleaseContext(hprov, 0);
  2722. if (SUCCEEDED(hr) && (hr != S_OK)) hr = E_FAIL;
  2723. return hr;
  2724. }
  2725. PCCERT_CONTEXT CreateTrustSigningCert(HWND hwnd, HCERTSTORE hcertstoreRoot,
  2726. BOOL fDialog)
  2727. {
  2728. BYTE bSerialNumber = 1;
  2729. DWORD cb;
  2730. CERT_INFO certInfo;
  2731. DWORD dw;
  2732. HCRYPTKEY hkey;
  2733. HCRYPTPROV hprov = NULL;
  2734. HRESULT hr = S_OK;
  2735. CERT_NAME_BLOB nameblob = {0, NULL};
  2736. LPBYTE pbEncode = NULL;
  2737. PCCERT_CONTEXT pccert = NULL;
  2738. PCERT_PUBLIC_KEY_INFO pkeyinfo = NULL;
  2739. CRYPT_KEY_PROV_INFO provinfo;
  2740. LPSTR psz;
  2741. char rgchTitle[256];
  2742. char rgchMsg[256];
  2743. char rgch[256];
  2744. char rgch1[256];
  2745. char rgch2[256];
  2746. CERT_EXTENSION rgExt[1] = {0};
  2747. SYSTEMTIME st;
  2748. //
  2749. // We always use RSA base for this purpose. We should never run
  2750. // across a system where rsabase does not exist.
  2751. //
  2752. // We assume that we need to create a new keyset and fallback to
  2753. // openning the existing keyset in the event that it already exists
  2754. //
  2755. if (!CryptAcquireContextA(&hprov, SzTrustListSigner, NULL, PROV_RSA_FULL, 0)) {
  2756. hr = GetLastError();
  2757. if ((hr != NTE_NOT_FOUND) && (hr != NTE_BAD_KEYSET)) {
  2758. goto ExitHere;
  2759. }
  2760. hr = S_OK;
  2761. if (!CryptAcquireContextA(&hprov, SzTrustListSigner, NULL, PROV_RSA_FULL,
  2762. CRYPT_NEWKEYSET)) {
  2763. hr = GetLastError();
  2764. goto ExitHere;
  2765. }
  2766. }
  2767. //
  2768. // Now we need to create the signing key in the keyset. Again
  2769. // we assume that we just created the keyset so we attempt to create
  2770. // the key in all cases. Note we don't need to open the key in the
  2771. // event we fail to create it as we never directly use it.
  2772. //
  2773. // Since we want security. We first try for a 1024-bit key before
  2774. // using the default (usually 512-bit) size.
  2775. //
  2776. if (!CryptGetUserKey(hprov, AT_SIGNATURE, &hkey)) {
  2777. dw = MAKELONG(0, 1024);
  2778. retry_keygen:
  2779. if (!CryptGenKey(hprov, AT_SIGNATURE, 0, &hkey)) {
  2780. #ifndef WIN16
  2781. hr = ::GetLastError();
  2782. #else
  2783. hr = GetLastError();
  2784. #endif // !WIN16
  2785. if ((hr == ERROR_INVALID_PARAMETER) && (dw != 0)) {
  2786. dw = 0;
  2787. goto retry_keygen;
  2788. }
  2789. if (hr != NTE_EXISTS) {
  2790. goto ExitHere;
  2791. }
  2792. }
  2793. }
  2794. CryptDestroyKey(hkey);
  2795. //
  2796. // Now we need to create a certificate which corresponds to the
  2797. // signing key we just created.
  2798. //
  2799. // Start by creating the DN to be stored in the certificate. The
  2800. // DN we are going to use is of the following format.
  2801. //
  2802. // cn=<machine name>/cn=Trust List Signer/cn=<user name>
  2803. //
  2804. // We make the simplifying assumption that neither machine names
  2805. // or user names can contain commas.
  2806. //
  2807. dw = sizeof(rgch1);
  2808. GetUserNameA(rgch1, &dw);
  2809. dw = sizeof(rgch2);
  2810. GetComputerNameA(rgch2, &dw);
  2811. wnsprintf(rgch, ARRAYSIZE(rgch), SzTrustDN, rgch2, rgch1);
  2812. if (!CertStrToNameA(X509_ASN_ENCODING, rgch,
  2813. CERT_X500_NAME_STR | CERT_NAME_STR_COMMA_FLAG, NULL,
  2814. NULL, &cb, NULL)) {
  2815. hr = E_FAIL;
  2816. goto ExitHere;
  2817. }
  2818. nameblob.pbData = (LPBYTE) malloc(cb);
  2819. nameblob.cbData = cb;
  2820. CertStrToNameA(X509_ASN_ENCODING, rgch,
  2821. CERT_X500_NAME_STR | CERT_NAME_STR_COMMA_FLAG, NULL,
  2822. nameblob.pbData, &nameblob.cbData, NULL);
  2823. //
  2824. // Extract the public portion of the signing key and ASN encode it
  2825. //
  2826. if (!CryptExportPublicKeyInfo(hprov, AT_SIGNATURE, X509_ASN_ENCODING,
  2827. NULL, &cb)) {
  2828. goto ExitHere;
  2829. }
  2830. pkeyinfo = (PCERT_PUBLIC_KEY_INFO) malloc(cb);
  2831. if (!CryptExportPublicKeyInfo(hprov, AT_SIGNATURE, X509_ASN_ENCODING,
  2832. pkeyinfo, &cb)) {
  2833. goto ExitHere;
  2834. }
  2835. //
  2836. // We are going to sign the certificate using SHA-1/RSA
  2837. //
  2838. CRYPT_ALGORITHM_IDENTIFIER sigalg;
  2839. memset(&sigalg, 0, sizeof(sigalg));
  2840. sigalg.pszObjId = szOID_OIWSEC_sha1RSASign;
  2841. // sigalg.Parameters.cbData = 0;
  2842. // sigalg.Parameters.pbData = NULL;
  2843. //
  2844. // We are putting one critical section on the extension. Enhanced
  2845. // key usage is CTL signing. Note that this is the only use that
  2846. // we are going to allow for this key.
  2847. //
  2848. rgExt[0].pszObjId = szOID_ENHANCED_KEY_USAGE;
  2849. rgExt[0].fCritical = TRUE;
  2850. CTL_USAGE ctlUsage2;
  2851. ctlUsage2.cUsageIdentifier = 1;
  2852. ctlUsage2.rgpszUsageIdentifier = &psz;
  2853. psz = (LPSTR) SzOID_KP_CTL_USAGE_SIGNING;
  2854. CryptEncodeObject(X509_ASN_ENCODING, X509_ENHANCED_KEY_USAGE, &ctlUsage2,
  2855. NULL, &cb);
  2856. rgExt[0].Value.pbData = (LPBYTE) malloc(cb);
  2857. rgExt[0].Value.cbData = cb;
  2858. CryptEncodeObject(X509_ASN_ENCODING, X509_ENHANCED_KEY_USAGE, &ctlUsage2,
  2859. rgExt[0].Value.pbData, &rgExt[0].Value.cbData);
  2860. //
  2861. // Now we can setup the rest of the certifiate information and
  2862. // encode it.
  2863. //
  2864. memset(&certInfo, 0, sizeof(certInfo));
  2865. // certInfo.dwVersion = 0;
  2866. certInfo.SerialNumber.cbData = 1;
  2867. certInfo.SerialNumber.pbData = &bSerialNumber;
  2868. certInfo.SignatureAlgorithm.pszObjId = szOID_OIWSEC_sha1RSASign;
  2869. // certInfo.SignatureAlgorithm.Parameter.cbData = 0;
  2870. // certInfo.SignatureAlgorithm.Parameter.pbData = NULL;
  2871. certInfo.Issuer = nameblob;
  2872. GetSystemTimeAsFileTime(&certInfo.NotBefore);
  2873. // certInfo.NotAfter = certInfo.NotBefore;
  2874. // M00BUG -- must increase the NotAfter date by some amount.
  2875. FileTimeToSystemTime(&certInfo.NotBefore, &st);
  2876. st.wYear += 50;
  2877. SystemTimeToFileTime(&st, &certInfo.NotAfter);
  2878. certInfo.Subject = nameblob;
  2879. certInfo.SubjectPublicKeyInfo = *pkeyinfo;
  2880. // certInfo.IssuerUniqueId = ;
  2881. // certInfo.SubjectUniqueId = ;
  2882. certInfo.cExtension = 1;
  2883. certInfo.rgExtension = rgExt;
  2884. if (!CryptSignAndEncodeCertificate(hprov, AT_SIGNATURE,
  2885. X509_ASN_ENCODING,
  2886. X509_CERT_TO_BE_SIGNED, &certInfo,
  2887. &sigalg, NULL, NULL, &cb)) {
  2888. #ifndef WIN16
  2889. hr = ::GetLastError();
  2890. #else
  2891. hr = GetLastError();
  2892. #endif // !WIN16
  2893. goto ExitHere;
  2894. }
  2895. pbEncode = (LPBYTE) malloc(cb);
  2896. if (!CryptSignAndEncodeCertificate(hprov, AT_SIGNATURE,
  2897. X509_ASN_ENCODING,
  2898. X509_CERT_TO_BE_SIGNED, &certInfo,
  2899. &sigalg, NULL, pbEncode, &cb)) {
  2900. #ifndef WIN16
  2901. hr = ::GetLastError();
  2902. #else
  2903. hr = GetLastError();
  2904. #endif // !WIN16
  2905. goto ExitHere;
  2906. }
  2907. //
  2908. // M00TODO Print the GOD IS ABOUT TO STRIKE message
  2909. //
  2910. if (fDialog) {
  2911. LoadStringA(HinstDll, IDS_ROOT_ADD_STRING, rgchMsg,
  2912. sizeof(rgchMsg)/sizeof(rgchMsg[0]));
  2913. LoadStringA(HinstDll, IDS_ROOT_ADD_TITLE, rgchTitle,
  2914. sizeof(rgchTitle)/sizeof(rgchTitle[0]));
  2915. MessageBoxA(hwnd, rgchMsg, rgchTitle, MB_APPLMODAL | MB_OK |
  2916. MB_ICONINFORMATION);
  2917. }
  2918. //
  2919. // Now we have warned the user, save our new cert in the root store
  2920. //
  2921. if (!CertAddEncodedCertificateToStore(hcertstoreRoot, X509_ASN_ENCODING,
  2922. pbEncode, cb,
  2923. CERT_STORE_ADD_REPLACE_EXISTING,
  2924. &pccert)) {
  2925. #ifndef WIN16
  2926. hr = ::GetLastError();
  2927. #else
  2928. hr = GetLastError();
  2929. #endif // !WIN16
  2930. goto ExitHere;
  2931. }
  2932. //
  2933. // Set the key-info property on the store so we can reference it later
  2934. //
  2935. memset(&provinfo, 0, sizeof(provinfo));
  2936. #ifndef WIN16
  2937. provinfo.pwszContainerName = L"Trust List Signer";
  2938. #else
  2939. provinfo.pwszContainerName = "Trust List Signer";
  2940. #endif // !WIN16
  2941. // provinfo.pwszProvName = NULL;
  2942. provinfo.dwProvType = PROV_RSA_FULL;
  2943. // provinfo.dwFlags = 0;
  2944. // provinfo.cProvParam = 0;
  2945. provinfo.dwKeySpec = AT_SIGNATURE;
  2946. CertSetCertificateContextProperty(pccert, CERT_KEY_PROV_INFO_PROP_ID,
  2947. 0, &provinfo);
  2948. ExitHere:
  2949. if (hprov != NULL) CryptReleaseContext(hprov, 0);
  2950. if (nameblob.pbData != NULL) free(nameblob.pbData);
  2951. if (pkeyinfo != NULL) free(pkeyinfo);
  2952. if (rgExt[0].Value.pbData != NULL) free(rgExt[0].Value.pbData);
  2953. if (pbEncode != NULL) free(pbEncode);
  2954. if (FAILED(hr) && (pccert != NULL)) {
  2955. CertFreeCertificateContext(pccert);
  2956. pccert = NULL;
  2957. }
  2958. return pccert;
  2959. }
  2960. //// CertModifyCertificatesToTrust
  2961. //
  2962. // Description:
  2963. // This routine is used to build the Certificate Trust List for
  2964. // a purpose. It is possible that we will need to create the root
  2965. // signing key for this.
  2966. //
  2967. HRESULT CertModifyCertificatesToTrust(int cCertsToModify, PCTL_MODIFY_REQUEST rgCertMods,
  2968. LPCSTR szPurpose, HWND hwnd, HCERTSTORE hcertstorTrust,
  2969. PCCERT_CONTEXT pccertSigner)
  2970. {
  2971. HCERTSTORE hcertstorRoot = NULL;
  2972. HRESULT hr = E_FAIL;
  2973. int i;
  2974. //
  2975. // Some quick parameter checking
  2976. //
  2977. if (szPurpose == NULL) {
  2978. return E_INVALIDARG;
  2979. }
  2980. //
  2981. // Add a reference to the cert store, so we can just release it on exit.
  2982. //
  2983. if (hcertstorTrust != NULL) {
  2984. CertDuplicateStore(hcertstorTrust);
  2985. }
  2986. if (pccertSigner != NULL) {
  2987. CertDuplicateCertificateContext(pccertSigner);
  2988. }
  2989. //
  2990. // Open a trust store if we don't have one yet.
  2991. //
  2992. if (hcertstorTrust == NULL) {
  2993. #ifndef WIN16
  2994. hcertstorTrust = CertOpenStore(CERT_STORE_PROV_SYSTEM, X509_ASN_ENCODING,
  2995. NULL, CERT_SYSTEM_STORE_CURRENT_USER,
  2996. L"Trust");
  2997. #else
  2998. hcertstorTrust = CertOpenStore(CERT_STORE_PROV_SYSTEM, X509_ASN_ENCODING,
  2999. NULL, CERT_SYSTEM_STORE_CURRENT_USER,
  3000. "Trust");
  3001. #endif // !WIN16
  3002. if (hcertstorTrust == NULL) {
  3003. hr = GetLastError();
  3004. goto ExitHere;
  3005. }
  3006. }
  3007. //
  3008. // Clear out errors and mark each item as not yet processed
  3009. //
  3010. for (i=0; i<cCertsToModify; i++) {
  3011. rgCertMods[i].dwError = CTL_MODIFY_ERR_NOT_YET_PROCESSED;
  3012. }
  3013. //
  3014. // If we were given a specific cert to sign with, then call the helper routine with
  3015. // that specific certificate
  3016. //
  3017. if (pccertSigner != NULL) {
  3018. hr = CTLModifyHelper(cCertsToModify, rgCertMods, szPurpose, hwnd, hcertstorTrust,
  3019. pccertSigner);
  3020. }
  3021. else {
  3022. DWORD cbData;
  3023. CTL_USAGE ctlUsage;
  3024. BOOL fSomeCertFound;
  3025. LPSTR psz;
  3026. //
  3027. // Walk through the list of certificates in the root store testing againist each
  3028. // valid cert for trust signing abilities and key material
  3029. //
  3030. //
  3031. // Open the root store, this is the only place we can store a signing
  3032. // cert that we can fully trust. The gods have decreed that items
  3033. // in this store cannot be corrupted or modified without user
  3034. // consent.
  3035. // Note: the previous statement is propaganda and should not be taken
  3036. // as having any relationship to the truth.
  3037. //
  3038. #ifndef WIN16
  3039. hcertstorRoot = CertOpenStore(CERT_STORE_PROV_SYSTEM, X509_ASN_ENCODING,
  3040. NULL, CERT_SYSTEM_STORE_CURRENT_USER,
  3041. L"Root");
  3042. #else
  3043. hcertstorRoot = CertOpenStore(CERT_STORE_PROV_SYSTEM, X509_ASN_ENCODING,
  3044. NULL, CERT_SYSTEM_STORE_CURRENT_USER,
  3045. "Root");
  3046. #endif // !WIN16
  3047. if (hcertstorRoot == NULL) {
  3048. hr = E_FAIL;
  3049. goto ExitHere;
  3050. }
  3051. //
  3052. // To be accepted, the cert must have the ability to sign trust lists
  3053. // and have key material
  3054. //
  3055. ctlUsage.cUsageIdentifier = 1;
  3056. ctlUsage.rgpszUsageIdentifier = &psz;
  3057. psz = (LPSTR) SzOID_KP_CTL_USAGE_SIGNING;
  3058. fSomeCertFound = FALSE;
  3059. while (TRUE) {
  3060. pccertSigner = CertFindCertificateInStore(hcertstorRoot, X509_ASN_ENCODING,
  3061. 0, CERT_FIND_CTL_USAGE, &ctlUsage,
  3062. pccertSigner);
  3063. if (pccertSigner == NULL) {
  3064. // No certs found
  3065. break;
  3066. }
  3067. //
  3068. // The certificate must also have an associated set of key provider
  3069. // information, or we must reject it.
  3070. if (CertGetCertificateContextProperty(pccertSigner, CERT_KEY_PROV_INFO_PROP_ID,
  3071. NULL, &cbData) && (cbData > 0)) {
  3072. fSomeCertFound = TRUE;
  3073. hr = CTLModifyHelper(cCertsToModify, rgCertMods, szPurpose, hwnd,
  3074. hcertstorTrust, pccertSigner);
  3075. }
  3076. }
  3077. if (!fSomeCertFound) {
  3078. pccertSigner = CreateTrustSigningCert(hwnd, hcertstorRoot, TRUE);
  3079. if (pccertSigner != NULL) {
  3080. hr = CTLModifyHelper(cCertsToModify, rgCertMods, szPurpose, hwnd,
  3081. hcertstorTrust, pccertSigner);
  3082. }
  3083. else {
  3084. hr = E_FAIL;
  3085. goto ExitHere;
  3086. }
  3087. }
  3088. }
  3089. //
  3090. // Check for errors returned
  3091. //
  3092. for (i=0; i<cCertsToModify; i++) {
  3093. if (rgCertMods[i].dwError == CTL_MODIFY_ERR_NOT_YET_PROCESSED) {
  3094. rgCertMods[i].dwError = (DWORD) E_FAIL;
  3095. }
  3096. if (FAILED(rgCertMods[i].dwError)) {
  3097. hr = S_FALSE;
  3098. }
  3099. }
  3100. ExitHere:
  3101. //
  3102. // Release the items we have created
  3103. //
  3104. if (hcertstorTrust != NULL) CertCloseStore(hcertstorTrust, 0);
  3105. if (pccertSigner != NULL) CertFreeCertificateContext(pccertSigner);
  3106. if (hcertstorRoot != NULL) CertCloseStore(hcertstorRoot, 0);
  3107. return hr;
  3108. }
  3109. BOOL FModifyTrust(HWND hwnd, PCCERT_CONTEXT pccert, DWORD dwNewTrust,
  3110. LPSTR szPurpose)
  3111. {
  3112. HRESULT hr;
  3113. CTL_MODIFY_REQUEST certmod;
  3114. certmod.pccert = pccert;
  3115. certmod.dwOperation = dwNewTrust;
  3116. hr = CertModifyCertificatesToTrust(1, &certmod, szPurpose, hwnd, NULL, NULL);
  3117. return (hr == S_OK) && (certmod.dwError == 0);
  3118. }