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.

1450 lines
39 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1995.
  5. //
  6. // File: cert.c
  7. //
  8. // Contents:
  9. //
  10. // Classes:
  11. //
  12. // Functions:
  13. //
  14. // History: 09-23-97 jbanes LSA integration stuff.
  15. // 01-05-98 jbanes Use WinVerifyTrust to validate certs.
  16. // 03-26-99 jbanes Fix CTL support, bug #303246
  17. //
  18. //----------------------------------------------------------------------------
  19. #include <stdlib.h>
  20. #include <spbase.h>
  21. #include <ssl2msg.h>
  22. #include <ssl3msg.h>
  23. #include <wincrypt.h>
  24. #include <oidenc.h>
  25. #include <softpub.h>
  26. #define CERT_HEADER_CONST "certificate"
  27. #define CERT_HEADER_LENGTH 11
  28. #define CERT_HEADER_OFFSET 6
  29. SP_STATUS
  30. SchGetTrustedRoots(
  31. HCERTSTORE *phClientRootStore);
  32. BOOL
  33. WINAPI
  34. SchCreateWorldStore (
  35. IN HCERTSTORE hRoot,
  36. IN DWORD cAdditionalStore,
  37. IN HCERTSTORE* rghAdditionalStore,
  38. OUT HCERTSTORE* phWorld);
  39. BOOL
  40. IsCertSelfSigned(PCCERT_CONTEXT pCertContext);
  41. // typedef struct _OIDPROVMAP
  42. // {
  43. // LPSTR szOid;
  44. // DWORD dwExchSpec;
  45. // DWORD dwCertType; // used for SSL 3.0 client auth
  46. // } OIDPROVMAP, *POIDPROVMAP;
  47. OIDPROVMAP g_CertTypes[] =
  48. {
  49. { szOID_RSA_RSA, SP_EXCH_RSA_PKCS1, SSL3_CERTTYPE_RSA_SIGN},
  50. { szOID_RSA_MD2RSA, SP_EXCH_RSA_PKCS1, SSL3_CERTTYPE_RSA_SIGN},
  51. { szOID_RSA_MD4RSA, SP_EXCH_RSA_PKCS1, SSL3_CERTTYPE_RSA_SIGN},
  52. { szOID_RSA_MD5RSA, SP_EXCH_RSA_PKCS1, SSL3_CERTTYPE_RSA_SIGN},
  53. { szOID_RSA_SHA1RSA, SP_EXCH_RSA_PKCS1, SSL3_CERTTYPE_RSA_SIGN},
  54. { szOID_OIWSEC_dsa, SP_EXCH_DH_PKCS3, SSL3_CERTTYPE_DSS_SIGN},
  55. { szOID_X957_DSA, SP_EXCH_DH_PKCS3, SSL3_CERTTYPE_DSS_SIGN},
  56. };
  57. DWORD g_cCertTypes = sizeof(g_CertTypes)/sizeof(OIDPROVMAP);
  58. DWORD
  59. MapOidToKeyExch(LPSTR szOid)
  60. {
  61. DWORD i;
  62. for(i = 0; i < g_cCertTypes; i++)
  63. {
  64. if(strcmp(szOid, g_CertTypes[i].szOid) == 0)
  65. {
  66. return g_CertTypes[i].dwExchSpec;
  67. }
  68. }
  69. return 0;
  70. }
  71. DWORD
  72. MapOidToCertType(LPSTR szOid)
  73. {
  74. DWORD i;
  75. for(i = 0; i < g_cCertTypes; i++)
  76. {
  77. if(strcmp(szOid, g_CertTypes[i].szOid) == 0)
  78. {
  79. return g_CertTypes[i].dwCertType;
  80. }
  81. }
  82. return 0;
  83. }
  84. // SPLoadCertificate takes a string of encoded cert bytes
  85. // and decodes them into the local certificate cache. It
  86. // then returns the first certificate of the group.
  87. SP_STATUS
  88. SPLoadCertificate(
  89. DWORD fProtocol,
  90. DWORD dwCertEncodingType,
  91. PUCHAR pCertificate,
  92. DWORD cbCertificate,
  93. PCCERT_CONTEXT *ppCertContext)
  94. {
  95. HCERTSTORE hCertStore = NULL;
  96. PCCERT_CONTEXT pCertContext = NULL;
  97. PBYTE pbCurrentRaw;
  98. DWORD cbCurrentRaw;
  99. BOOL fLeafCert;
  100. SP_STATUS pctRet;
  101. //
  102. // Dereference the cert that we are replacing.
  103. //
  104. if(ppCertContext == NULL)
  105. {
  106. return SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR);
  107. }
  108. if(*ppCertContext != NULL)
  109. {
  110. CertFreeCertificateContext(*ppCertContext);
  111. }
  112. *ppCertContext = NULL;
  113. //
  114. // Create an in-memory certificate store.
  115. //
  116. hCertStore = CertOpenStore(CERT_STORE_PROV_MEMORY,
  117. 0, 0,
  118. CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG,
  119. 0);
  120. if(hCertStore == NULL)
  121. {
  122. SP_LOG_RESULT(GetLastError());
  123. return SEC_E_INSUFFICIENT_MEMORY;
  124. }
  125. fLeafCert = TRUE;
  126. pbCurrentRaw = pCertificate;
  127. cbCurrentRaw = cbCertificate;
  128. do
  129. {
  130. //
  131. // Skip to beginning of certificate.
  132. //
  133. if((fProtocol & SP_PROT_SSL3TLS1) && cbCurrentRaw > 3)
  134. {
  135. // SSL3 style cert chain, where the length
  136. // of each cert is prepended.
  137. pbCurrentRaw += 3;
  138. cbCurrentRaw -= 3;
  139. }
  140. // Skip past the "certificate" header
  141. if((cbCurrentRaw > (CERT_HEADER_OFFSET + CERT_HEADER_LENGTH)) &&
  142. (memcmp(pbCurrentRaw + CERT_HEADER_OFFSET, CERT_HEADER_CONST, CERT_HEADER_LENGTH) == 0))
  143. {
  144. pbCurrentRaw += CERT_HEADER_OFFSET + CERT_HEADER_LENGTH;
  145. cbCurrentRaw -= CERT_HEADER_OFFSET + CERT_HEADER_LENGTH;
  146. }
  147. //
  148. // Decode this certificate context.
  149. //
  150. if(!CertAddEncodedCertificateToStore(hCertStore,
  151. dwCertEncodingType,
  152. pbCurrentRaw,
  153. cbCurrentRaw,
  154. CERT_STORE_ADD_USE_EXISTING,
  155. &pCertContext))
  156. {
  157. SP_LOG_RESULT(GetLastError());
  158. pctRet = PCT_ERR_BAD_CERTIFICATE;
  159. goto cleanup;
  160. }
  161. pbCurrentRaw += pCertContext->cbCertEncoded;
  162. if(cbCurrentRaw < pCertContext->cbCertEncoded)
  163. {
  164. pctRet = SP_LOG_RESULT(PCT_ERR_BAD_CERTIFICATE);
  165. goto cleanup;
  166. }
  167. cbCurrentRaw -= pCertContext->cbCertEncoded;
  168. if(fLeafCert)
  169. {
  170. fLeafCert = FALSE;
  171. *ppCertContext = pCertContext;
  172. }
  173. else
  174. {
  175. CertFreeCertificateContext(pCertContext);
  176. }
  177. pCertContext = NULL;
  178. } while(cbCurrentRaw);
  179. pctRet = PCT_ERR_OK;
  180. cleanup:
  181. CertCloseStore(hCertStore, 0);
  182. if(pctRet != PCT_ERR_OK)
  183. {
  184. if(pCertContext)
  185. {
  186. CertFreeCertificateContext(pCertContext);
  187. }
  188. if(*ppCertContext)
  189. {
  190. CertFreeCertificateContext(*ppCertContext);
  191. *ppCertContext = NULL;
  192. }
  193. }
  194. return pctRet;
  195. }
  196. SP_STATUS
  197. SPPublicKeyFromCert(
  198. PCCERT_CONTEXT pCert,
  199. PUBLICKEY ** ppKey,
  200. ExchSpec * pdwExchSpec)
  201. {
  202. PCERT_PUBLIC_KEY_INFO pPubKeyInfo;
  203. PUBLICKEY * pPublicKey;
  204. DWORD dwExchSpec;
  205. DWORD cbBlob;
  206. SP_STATUS pctRet;
  207. //
  208. // Log the subject and issuer names.
  209. //
  210. LogDistinguishedName(DEB_TRACE,
  211. "Subject: %s\n",
  212. pCert->pCertInfo->Subject.pbData,
  213. pCert->pCertInfo->Subject.cbData);
  214. LogDistinguishedName(DEB_TRACE,
  215. "Issuer: %s\n",
  216. pCert->pCertInfo->Issuer.pbData,
  217. pCert->pCertInfo->Issuer.cbData);
  218. //
  219. // Determine type of public key embedded in the certificate.
  220. //
  221. pPubKeyInfo = &pCert->pCertInfo->SubjectPublicKeyInfo;
  222. if(pPubKeyInfo == NULL)
  223. {
  224. return SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR);
  225. }
  226. dwExchSpec = MapOidToKeyExch(pPubKeyInfo->Algorithm.pszObjId);
  227. if(dwExchSpec == 0)
  228. {
  229. return PCT_INT_UNKNOWN_CREDENTIAL;
  230. }
  231. //
  232. // Build public key blob from encoded public key.
  233. //
  234. switch(dwExchSpec)
  235. {
  236. case SP_EXCH_RSA_PKCS1:
  237. pctRet = RsaPublicKeyFromCert(pPubKeyInfo,
  238. NULL,
  239. &cbBlob);
  240. if(pctRet != PCT_ERR_OK)
  241. {
  242. return pctRet;
  243. }
  244. pPublicKey = SPExternalAlloc(sizeof(PUBLICKEY) + cbBlob);
  245. if(pPublicKey == NULL)
  246. {
  247. return SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
  248. }
  249. pPublicKey->pPublic = (BLOBHEADER *)(pPublicKey + 1);
  250. pPublicKey->cbPublic = cbBlob;
  251. pctRet = RsaPublicKeyFromCert(pPubKeyInfo,
  252. pPublicKey->pPublic,
  253. &pPublicKey->cbPublic);
  254. if(pctRet != PCT_ERR_OK)
  255. {
  256. SPExternalFree(pPublicKey);
  257. return pctRet;
  258. }
  259. break;
  260. case SP_EXCH_DH_PKCS3:
  261. pctRet = DssPublicKeyFromCert(pPubKeyInfo,
  262. NULL,
  263. &cbBlob);
  264. if(pctRet != PCT_ERR_OK)
  265. {
  266. return pctRet;
  267. }
  268. pPublicKey = SPExternalAlloc(sizeof(PUBLICKEY) + cbBlob);
  269. if(pPublicKey == NULL)
  270. {
  271. return SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
  272. }
  273. pPublicKey->pPublic = (BLOBHEADER *)(pPublicKey + 1);
  274. pPublicKey->cbPublic = cbBlob;
  275. pctRet = DssPublicKeyFromCert(pPubKeyInfo,
  276. pPublicKey->pPublic,
  277. &pPublicKey->cbPublic);
  278. if(pctRet != PCT_ERR_OK)
  279. {
  280. SPExternalFree(pPublicKey);
  281. return pctRet;
  282. }
  283. break;
  284. default:
  285. return SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR);
  286. }
  287. //
  288. // Set function outputs.
  289. //
  290. *ppKey = pPublicKey;
  291. if(pdwExchSpec)
  292. {
  293. *pdwExchSpec = dwExchSpec;
  294. }
  295. return PCT_ERR_OK;
  296. }
  297. SP_STATUS
  298. SPSerializeCertificate(
  299. DWORD dwProtocol, // in
  300. BOOL fBuildChain, // in
  301. PBYTE * ppCertChain, // out
  302. DWORD * pcbCertChain, // out
  303. PCCERT_CONTEXT pCertContext, // in
  304. DWORD dwChainingFlags) // in
  305. {
  306. PCCERT_CHAIN_CONTEXT pChainContext = NULL;
  307. CERT_CHAIN_PARA ChainPara;
  308. PCERT_SIMPLE_CHAIN pSimpleChain;
  309. PCCERT_CONTEXT pCurrentCert;
  310. BOOL fSuccess = FALSE;
  311. PBYTE pbCertChain;
  312. DWORD cbCertChain;
  313. DWORD i;
  314. SP_STATUS pctRet;
  315. BOOL fImpersonating = FALSE;
  316. SP_BEGIN("SPSerializeCertificate");
  317. if(pcbCertChain == NULL)
  318. {
  319. SP_RETURN( SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR));
  320. }
  321. if(fBuildChain)
  322. {
  323. ZeroMemory(&ChainPara, sizeof(ChainPara));
  324. ChainPara.cbSize = sizeof(ChainPara);
  325. fImpersonating = SslImpersonateClient();
  326. if(!(fSuccess = CertGetCertificateChain(
  327. NULL,
  328. pCertContext,
  329. NULL,
  330. NULL,
  331. &ChainPara,
  332. dwChainingFlags,
  333. NULL,
  334. &pChainContext)))
  335. {
  336. DebugLog((DEB_WARN, "Error 0x%x returned by CertGetCertificateChain!\n", GetLastError()));
  337. pChainContext = NULL;
  338. }
  339. if(fImpersonating)
  340. {
  341. RevertToSelf();
  342. fImpersonating = FALSE;
  343. }
  344. }
  345. if(!fSuccess)
  346. {
  347. //
  348. // Send the leaf certificate only.
  349. //
  350. // Compute size of chain.
  351. cbCertChain = pCertContext->cbCertEncoded;
  352. if(dwProtocol & SP_PROT_SSL3TLS1)
  353. {
  354. cbCertChain += CB_SSL3_CERT_VECTOR;
  355. }
  356. // Allocate memory for chain.
  357. if(ppCertChain == NULL)
  358. {
  359. *pcbCertChain = cbCertChain;
  360. pctRet = PCT_ERR_OK;
  361. goto cleanup;
  362. }
  363. else if(*ppCertChain == NULL)
  364. {
  365. *ppCertChain = SPExternalAlloc(cbCertChain);
  366. if(*ppCertChain == NULL)
  367. {
  368. pctRet = SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
  369. goto cleanup;
  370. }
  371. }
  372. else if(*pcbCertChain < cbCertChain)
  373. {
  374. pctRet = SP_LOG_RESULT(PCT_INT_BUFF_TOO_SMALL);
  375. goto cleanup;
  376. }
  377. *pcbCertChain = cbCertChain;
  378. // Place chain in output buffer.
  379. pbCertChain = *ppCertChain;
  380. if(dwProtocol & SP_PROT_SSL3TLS1)
  381. {
  382. pbCertChain[0] = MS24BOF(pCertContext->cbCertEncoded);
  383. pbCertChain[1] = MSBOF(pCertContext->cbCertEncoded);
  384. pbCertChain[2] = LSBOF(pCertContext->cbCertEncoded);
  385. pbCertChain += CB_SSL3_CERT_VECTOR;
  386. }
  387. CopyMemory(pbCertChain, pCertContext->pbCertEncoded, pCertContext->cbCertEncoded);
  388. pctRet = PCT_ERR_OK;
  389. goto cleanup;
  390. }
  391. //
  392. // Compute size of chain.
  393. //
  394. pSimpleChain = pChainContext->rgpChain[0];
  395. cbCertChain = 0;
  396. for(i = 0; i < pSimpleChain->cElement; i++)
  397. {
  398. pCurrentCert = pSimpleChain->rgpElement[i]->pCertContext;
  399. if(i > 0)
  400. {
  401. // Verify that this is not a root certificate.
  402. if(CertCompareCertificateName(pCurrentCert->dwCertEncodingType,
  403. &pCurrentCert->pCertInfo->Issuer,
  404. &pCurrentCert->pCertInfo->Subject))
  405. {
  406. break;
  407. }
  408. }
  409. cbCertChain += pCurrentCert->cbCertEncoded;
  410. if(dwProtocol & SP_PROT_SSL3TLS1)
  411. {
  412. cbCertChain += CB_SSL3_CERT_VECTOR;
  413. }
  414. }
  415. //
  416. // Allocate memory for chain.
  417. //
  418. if(ppCertChain == NULL)
  419. {
  420. *pcbCertChain = cbCertChain;
  421. pctRet = PCT_ERR_OK;
  422. goto cleanup;
  423. }
  424. else if(*ppCertChain == NULL)
  425. {
  426. *ppCertChain = SPExternalAlloc(cbCertChain);
  427. if(*ppCertChain == NULL)
  428. {
  429. pctRet = SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
  430. goto cleanup;
  431. }
  432. }
  433. else if(*pcbCertChain < cbCertChain)
  434. {
  435. pctRet = SP_LOG_RESULT(PCT_INT_BUFF_TOO_SMALL);
  436. goto cleanup;
  437. }
  438. *pcbCertChain = cbCertChain;
  439. //
  440. // Place chain in output buffer.
  441. //
  442. pbCertChain = *ppCertChain;
  443. for(i = 0; i < pSimpleChain->cElement; i++)
  444. {
  445. pCurrentCert = pSimpleChain->rgpElement[i]->pCertContext;
  446. if(i > 0)
  447. {
  448. // Verify that this is not a root certificate.
  449. if(CertCompareCertificateName(pCurrentCert->dwCertEncodingType,
  450. &pCurrentCert->pCertInfo->Issuer,
  451. &pCurrentCert->pCertInfo->Subject))
  452. {
  453. break;
  454. }
  455. }
  456. if(dwProtocol & SP_PROT_SSL3TLS1)
  457. {
  458. pbCertChain[0] = MS24BOF(pCurrentCert->cbCertEncoded);
  459. pbCertChain[1] = MSBOF(pCurrentCert->cbCertEncoded);
  460. pbCertChain[2] = LSBOF(pCurrentCert->cbCertEncoded);
  461. pbCertChain += CB_SSL3_CERT_VECTOR;
  462. }
  463. CopyMemory(pbCertChain, pCurrentCert->pbCertEncoded, pCurrentCert->cbCertEncoded);
  464. pbCertChain += pCurrentCert->cbCertEncoded;
  465. }
  466. SP_ASSERT(*ppCertChain + cbCertChain == pbCertChain);
  467. pctRet = PCT_ERR_OK;
  468. cleanup:
  469. if(pChainContext)
  470. {
  471. CertFreeCertificateChain(pChainContext);
  472. }
  473. SP_RETURN(pctRet);
  474. }
  475. /*****************************************************************************/
  476. SP_STATUS
  477. ExtractIssuerNamesFromStore(
  478. HCERTSTORE hStore, // in
  479. PBYTE pbIssuers, // out
  480. DWORD *pcbIssuers) // in, out
  481. {
  482. DWORD cbCurIssuerLen = 0;
  483. DWORD cbIssuerLen = *pcbIssuers;
  484. PBYTE pbCurIssuer = pbIssuers;
  485. PCCERT_CONTEXT pCurrent = NULL;
  486. SECURITY_STATUS scRet;
  487. BOOL fIsAllowed;
  488. // Initialize output to zero.
  489. *pcbIssuers = 0;
  490. while(TRUE)
  491. {
  492. pCurrent = CertEnumCertificatesInStore(hStore, pCurrent);
  493. if(pCurrent == NULL) break;
  494. // Is this a client-auth certificate?
  495. scRet = SPCheckKeyUsage(pCurrent,
  496. szOID_PKIX_KP_CLIENT_AUTH,
  497. FALSE,
  498. &fIsAllowed);
  499. if(scRet != SEC_E_OK)
  500. {
  501. continue;
  502. }
  503. if(!fIsAllowed)
  504. {
  505. continue;
  506. }
  507. cbCurIssuerLen += 2 + pCurrent->pCertInfo->Subject.cbData;
  508. // Are we writing?
  509. if(pbIssuers)
  510. {
  511. if(cbCurIssuerLen > cbIssuerLen)
  512. {
  513. // Memory overrun
  514. CertFreeCertificateContext(pCurrent);
  515. return SP_LOG_RESULT(PCT_INT_DATA_OVERFLOW);
  516. }
  517. pbCurIssuer[0] = MSBOF(pCurrent->pCertInfo->Subject.cbData);
  518. pbCurIssuer[1] = LSBOF(pCurrent->pCertInfo->Subject.cbData);
  519. pbCurIssuer += 2;
  520. CopyMemory(pbCurIssuer, pCurrent->pCertInfo->Subject.pbData,
  521. pCurrent->pCertInfo->Subject.cbData);
  522. pbCurIssuer += pCurrent->pCertInfo->Subject.cbData;
  523. }
  524. }
  525. *pcbIssuers = cbCurIssuerLen;
  526. return PCT_ERR_OK;
  527. }
  528. /*****************************************************************************/
  529. SP_STATUS
  530. GetDefaultIssuers(
  531. PBYTE pbIssuers, // out
  532. DWORD *pcbIssuers) // in, out
  533. {
  534. HCERTSTORE hStore;
  535. SP_STATUS pctRet;
  536. pctRet = SchGetTrustedRoots(&hStore);
  537. if(pctRet != PCT_ERR_OK)
  538. {
  539. return pctRet;
  540. }
  541. pctRet = ExtractIssuerNamesFromStore(hStore, pbIssuers, pcbIssuers);
  542. if(pctRet != PCT_ERR_OK)
  543. {
  544. CertCloseStore(hStore, 0);
  545. return pctRet;
  546. }
  547. CertCloseStore(hStore, 0);
  548. return PCT_ERR_OK;
  549. }
  550. SP_STATUS
  551. SchGetTrustedRoots(
  552. HCERTSTORE *phClientRootStore)
  553. {
  554. HTTPSPolicyCallbackData polHttps;
  555. CERT_CHAIN_POLICY_PARA PolicyPara;
  556. CERT_CHAIN_POLICY_STATUS PolicyStatus;
  557. CERT_CHAIN_PARA ChainPara;
  558. PCCERT_CHAIN_CONTEXT pChainContext = NULL;
  559. LPSTR pszUsage;
  560. PCCERT_CONTEXT pCertContext;
  561. HCERTSTORE hClientRootStore = 0;
  562. HCERTSTORE hRootStore = 0;
  563. HCERTSTORE hWorldStore = 0;
  564. SP_STATUS Status = SEC_E_OK;
  565. BOOL fImpersonating = FALSE;
  566. // Open output store.
  567. hClientRootStore = CertOpenStore(CERT_STORE_PROV_MEMORY,
  568. 0, 0,
  569. CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG,
  570. 0);
  571. if(hClientRootStore == NULL)
  572. {
  573. //SP_LOG_RESULT(GetLastError());
  574. Status = SEC_E_INSUFFICIENT_MEMORY;
  575. goto cleanup;
  576. }
  577. fImpersonating = SslImpersonateClient();
  578. // Open root store.
  579. hRootStore = CertOpenSystemStore(0, "ROOT");
  580. if(hRootStore == NULL)
  581. {
  582. DebugLog((DEB_WARN, "Error 0x%x opening root store\n", GetLastError()));
  583. }
  584. // Create world store.
  585. if(!SchCreateWorldStore(hRootStore,
  586. 0, NULL,
  587. &hWorldStore))
  588. {
  589. DebugLog((DEB_ERROR, "Error 0x%x creating world store\n", GetLastError()));
  590. goto cleanup;
  591. }
  592. // Enumerate the certificates in the world store, looking
  593. // for trusted roots. This approach will automatically take
  594. // advantage of any CTLs that are installed on the system.
  595. pCertContext = NULL;
  596. while(TRUE)
  597. {
  598. pCertContext = CertEnumCertificatesInStore(hWorldStore, pCertContext);
  599. if(pCertContext == NULL) break;
  600. if(!IsCertSelfSigned(pCertContext))
  601. {
  602. continue;
  603. }
  604. pszUsage = szOID_PKIX_KP_CLIENT_AUTH;
  605. ZeroMemory(&ChainPara, sizeof(ChainPara));
  606. ChainPara.cbSize = sizeof(ChainPara);
  607. ChainPara.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR;
  608. ChainPara.RequestedUsage.Usage.cUsageIdentifier = 1;
  609. ChainPara.RequestedUsage.Usage.rgpszUsageIdentifier = &pszUsage;
  610. if(!CertGetCertificateChain(
  611. NULL,
  612. pCertContext,
  613. NULL,
  614. 0,
  615. &ChainPara,
  616. 0,
  617. NULL,
  618. &pChainContext))
  619. {
  620. SP_LOG_RESULT(GetLastError());
  621. continue;
  622. }
  623. // Set up validate chain structures.
  624. ZeroMemory(&polHttps, sizeof(HTTPSPolicyCallbackData));
  625. polHttps.cbStruct = sizeof(HTTPSPolicyCallbackData);
  626. polHttps.dwAuthType = AUTHTYPE_CLIENT;
  627. polHttps.fdwChecks = 0;
  628. polHttps.pwszServerName = NULL;
  629. ZeroMemory(&PolicyStatus, sizeof(PolicyStatus));
  630. PolicyStatus.cbSize = sizeof(PolicyStatus);
  631. ZeroMemory(&PolicyPara, sizeof(PolicyPara));
  632. PolicyPara.cbSize = sizeof(PolicyPara);
  633. PolicyPara.pvExtraPolicyPara= &polHttps;
  634. PolicyPara.dwFlags = CERT_CHAIN_POLICY_IGNORE_ALL_NOT_TIME_VALID_FLAGS;
  635. // Validate chain
  636. if(!CertVerifyCertificateChainPolicy(
  637. CERT_CHAIN_POLICY_SSL,
  638. pChainContext,
  639. &PolicyPara,
  640. &PolicyStatus))
  641. {
  642. SP_LOG_RESULT(GetLastError());
  643. CertFreeCertificateChain(pChainContext);
  644. continue;
  645. }
  646. if(PolicyStatus.dwError)
  647. {
  648. // Certificate did not validate, move on to the next one.
  649. CertFreeCertificateChain(pChainContext);
  650. continue;
  651. }
  652. CertFreeCertificateChain(pChainContext);
  653. // Add the root certificate to the list of trusted ones.
  654. if(!CertAddCertificateContextToStore(hClientRootStore,
  655. pCertContext,
  656. CERT_STORE_ADD_USE_EXISTING,
  657. NULL))
  658. {
  659. SP_LOG_RESULT(GetLastError());
  660. }
  661. }
  662. cleanup:
  663. if(hRootStore)
  664. {
  665. CertCloseStore(hRootStore, 0);
  666. }
  667. if(hWorldStore)
  668. {
  669. CertCloseStore(hWorldStore, 0);
  670. }
  671. if(fImpersonating)
  672. {
  673. RevertToSelf();
  674. }
  675. if(Status == SEC_E_OK)
  676. {
  677. *phClientRootStore = hClientRootStore;
  678. }
  679. return Status;
  680. }
  681. //+---------------------------------------------------------------------------
  682. //
  683. // Function: ChainCreateCollectionIncludingCtlCertificates
  684. //
  685. // Synopsis: create a collection which includes the source store hStore and
  686. // any CTL certificates from it
  687. //
  688. //----------------------------------------------------------------------------
  689. BOOL WINAPI
  690. ChainCreateCollectionIncludingCtlCertificates (
  691. IN HCERTSTORE hStore,
  692. OUT HCERTSTORE* phCollection
  693. )
  694. {
  695. BOOL fResult = FALSE;
  696. HCERTSTORE hCollection;
  697. PCCTL_CONTEXT pCtlContext = NULL;
  698. HCERTSTORE hCtlStore;
  699. hCollection = CertOpenStore(
  700. CERT_STORE_PROV_COLLECTION,
  701. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  702. 0,
  703. CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG,
  704. NULL
  705. );
  706. if ( hCollection == NULL )
  707. {
  708. return( FALSE );
  709. }
  710. fResult = CertAddStoreToCollection( hCollection, hStore, 0, 0 );
  711. while ( ( fResult == TRUE ) &&
  712. ( ( pCtlContext = CertEnumCTLsInStore(
  713. hStore,
  714. pCtlContext
  715. ) ) != NULL ) )
  716. {
  717. hCtlStore = CertOpenStore(
  718. CERT_STORE_PROV_MSG,
  719. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  720. 0,
  721. 0,
  722. pCtlContext->hCryptMsg
  723. );
  724. if ( hCtlStore != NULL )
  725. {
  726. fResult = CertAddStoreToCollection(
  727. hCollection,
  728. hCtlStore,
  729. 0,
  730. 0
  731. );
  732. CertCloseStore( hCtlStore, 0 );
  733. }
  734. }
  735. if ( fResult == TRUE )
  736. {
  737. *phCollection = hCollection;
  738. }
  739. else
  740. {
  741. CertCloseStore( hCollection, 0 );
  742. }
  743. return( fResult );
  744. }
  745. BOOL
  746. WINAPI
  747. SchCreateWorldStore (
  748. IN HCERTSTORE hRoot,
  749. IN DWORD cAdditionalStore,
  750. IN HCERTSTORE* rghAdditionalStore,
  751. OUT HCERTSTORE* phWorld)
  752. {
  753. BOOL fResult;
  754. HCERTSTORE hWorld;
  755. HCERTSTORE hStore, hCtl;
  756. DWORD cCount;
  757. hWorld = CertOpenStore(
  758. CERT_STORE_PROV_COLLECTION,
  759. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  760. 0,
  761. CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG,
  762. NULL
  763. );
  764. if ( hWorld == NULL )
  765. {
  766. return( FALSE );
  767. }
  768. fResult = CertAddStoreToCollection( hWorld, hRoot, 0, 0 );
  769. for ( cCount = 0;
  770. ( cCount < cAdditionalStore ) && ( fResult == TRUE );
  771. cCount++ )
  772. {
  773. fResult = CertAddStoreToCollection(
  774. hWorld,
  775. rghAdditionalStore[ cCount ],
  776. 0,
  777. 0
  778. );
  779. }
  780. if ( fResult == TRUE )
  781. {
  782. hStore = CertOpenSystemStore(0, "trust");
  783. if( hStore != NULL )
  784. {
  785. if(ChainCreateCollectionIncludingCtlCertificates(hStore, &hCtl))
  786. {
  787. if(!CertAddStoreToCollection( hWorld, hCtl, 0, 0 ))
  788. {
  789. DebugLog((DEB_WARN, "Error 0x%x adding CTL collection\n", GetLastError()));
  790. }
  791. CertCloseStore( hCtl, 0 );
  792. }
  793. else
  794. {
  795. DebugLog((DEB_WARN, "Error 0x%x creating CTL collection\n", GetLastError()));
  796. }
  797. CertCloseStore( hStore, 0 );
  798. }
  799. }
  800. if ( fResult == TRUE )
  801. {
  802. hStore = CertOpenSystemStore(0, "ca");
  803. if ( hStore != NULL )
  804. {
  805. fResult = CertAddStoreToCollection( hWorld, hStore, 0, 0 );
  806. CertCloseStore( hStore, 0 );
  807. }
  808. else
  809. {
  810. fResult = FALSE;
  811. }
  812. }
  813. if ( fResult == TRUE )
  814. {
  815. hStore = CertOpenSystemStore(0, "my");
  816. if ( hStore != NULL )
  817. {
  818. fResult = CertAddStoreToCollection( hWorld, hStore, 0, 0 );
  819. CertCloseStore( hStore, 0 );
  820. }
  821. else
  822. {
  823. fResult = FALSE;
  824. }
  825. }
  826. if ( fResult == TRUE )
  827. {
  828. *phWorld = hWorld;
  829. }
  830. else
  831. {
  832. CertCloseStore( hWorld, 0 );
  833. }
  834. return( fResult );
  835. }
  836. BOOL
  837. IsCertSelfSigned(PCCERT_CONTEXT pCertContext)
  838. {
  839. // Compare subject and issuer names.
  840. if(pCertContext->pCertInfo->Subject.cbData == pCertContext->pCertInfo->Issuer.cbData)
  841. {
  842. if(memcmp(pCertContext->pCertInfo->Subject.pbData,
  843. pCertContext->pCertInfo->Issuer.pbData,
  844. pCertContext->pCertInfo->Issuer.cbData) == 0)
  845. {
  846. return TRUE;
  847. }
  848. }
  849. return FALSE;
  850. }
  851. SECURITY_STATUS
  852. MapWinTrustError(
  853. SECURITY_STATUS Status,
  854. SECURITY_STATUS DefaultError,
  855. DWORD dwIgnoreErrors)
  856. {
  857. if((Status == CRYPT_E_NO_REVOCATION_CHECK) &&
  858. (dwIgnoreErrors & CRED_FLAG_IGNORE_NO_REVOCATION_CHECK))
  859. {
  860. DebugLog((DEB_WARN, "MapWinTrustError: Ignoring CRYPT_E_NO_REVOCATION_CHECK\n"));
  861. Status = STATUS_SUCCESS;
  862. }
  863. if((Status == CRYPT_E_REVOCATION_OFFLINE) &&
  864. (dwIgnoreErrors & CRED_FLAG_IGNORE_REVOCATION_OFFLINE))
  865. {
  866. DebugLog((DEB_WARN, "MapWinTrustError: Ignoring CRYPT_E_REVOCATION_OFFLINE\n"));
  867. Status = STATUS_SUCCESS;
  868. }
  869. if(HRESULT_FACILITY(Status) == FACILITY_SECURITY)
  870. {
  871. return (Status);
  872. }
  873. switch(Status)
  874. {
  875. case ERROR_SUCCESS:
  876. return SEC_E_OK;
  877. // Expired certificate.
  878. case CERT_E_EXPIRED:
  879. case CERT_E_VALIDITYPERIODNESTING:
  880. return SEC_E_CERT_EXPIRED;
  881. // Unknown CA
  882. case CERT_E_UNTRUSTEDROOT:
  883. case CERT_E_UNTRUSTEDCA:
  884. return SEC_E_UNTRUSTED_ROOT;
  885. // Certificate revoked.
  886. case CERT_E_REVOKED:
  887. return CRYPT_E_REVOKED;
  888. // Target name doesn't match name in certificate.
  889. case CERT_E_CN_NO_MATCH:
  890. return SEC_E_WRONG_PRINCIPAL;
  891. // Certificate contains wrong EKU.
  892. case CERT_E_WRONG_USAGE:
  893. return SEC_E_CERT_WRONG_USAGE;
  894. // Some other error.
  895. default:
  896. if(DefaultError)
  897. {
  898. return DefaultError;
  899. }
  900. else
  901. {
  902. return SEC_E_CERT_UNKNOWN;
  903. }
  904. }
  905. }
  906. NTSTATUS
  907. VerifyClientCertificate(
  908. PCCERT_CONTEXT pCertContext,
  909. DWORD dwCertFlags,
  910. DWORD dwIgnoreErrors,
  911. LPCSTR pszPolicyOID,
  912. PCCERT_CHAIN_CONTEXT *ppChainContext) // optional
  913. {
  914. HTTPSPolicyCallbackData polHttps;
  915. CERT_CHAIN_POLICY_PARA PolicyPara;
  916. CERT_CHAIN_POLICY_STATUS PolicyStatus;
  917. CERT_CHAIN_PARA ChainPara;
  918. PCCERT_CHAIN_CONTEXT pChainContext = NULL;
  919. DWORD Status;
  920. LPSTR pszUsage;
  921. BOOL fImpersonating = FALSE;
  922. //
  923. // Build certificate chain.
  924. //
  925. fImpersonating = SslImpersonateClient();
  926. pszUsage = szOID_PKIX_KP_CLIENT_AUTH;
  927. ZeroMemory(&ChainPara, sizeof(ChainPara));
  928. ChainPara.cbSize = sizeof(ChainPara);
  929. ChainPara.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR;
  930. ChainPara.RequestedUsage.Usage.cUsageIdentifier = 1;
  931. ChainPara.RequestedUsage.Usage.rgpszUsageIdentifier = &pszUsage;
  932. if(!CertGetCertificateChain(
  933. NULL, // hChainEngine
  934. pCertContext, // pCertContext
  935. NULL, // pTime
  936. pCertContext->hCertStore, // hAdditionalStore
  937. &ChainPara, // pChainPara
  938. dwCertFlags, // dwFlags
  939. NULL, // pvReserved
  940. &pChainContext)) // ppChainContext
  941. {
  942. Status = SP_LOG_RESULT(GetLastError());
  943. goto cleanup;
  944. }
  945. //
  946. // Validate certificate chain.
  947. //
  948. if(pszPolicyOID == CERT_CHAIN_POLICY_NT_AUTH)
  949. {
  950. ZeroMemory(&PolicyPara, sizeof(PolicyPara));
  951. PolicyPara.cbSize = sizeof(PolicyPara);
  952. PolicyPara.dwFlags = BASIC_CONSTRAINTS_CERT_CHAIN_POLICY_END_ENTITY_FLAG;
  953. }
  954. else
  955. {
  956. ZeroMemory(&polHttps, sizeof(HTTPSPolicyCallbackData));
  957. polHttps.cbStruct = sizeof(HTTPSPolicyCallbackData);
  958. polHttps.dwAuthType = AUTHTYPE_CLIENT;
  959. polHttps.fdwChecks = 0;
  960. ZeroMemory(&PolicyPara, sizeof(PolicyPara));
  961. PolicyPara.cbSize = sizeof(PolicyPara);
  962. PolicyPara.pvExtraPolicyPara = &polHttps;
  963. }
  964. ZeroMemory(&PolicyStatus, sizeof(PolicyStatus));
  965. PolicyStatus.cbSize = sizeof(PolicyStatus);
  966. if(!CertVerifyCertificateChainPolicy(
  967. pszPolicyOID,
  968. pChainContext,
  969. &PolicyPara,
  970. &PolicyStatus))
  971. {
  972. Status = SP_LOG_RESULT(GetLastError());
  973. goto cleanup;
  974. }
  975. #if DBG
  976. if(PolicyStatus.dwError)
  977. {
  978. DebugLog((DEB_WARN, "CertVerifyCertificateChainPolicy returned 0x%x\n", PolicyStatus.dwError));
  979. }
  980. #endif
  981. Status = MapWinTrustError(PolicyStatus.dwError, 0, dwIgnoreErrors);
  982. if(Status)
  983. {
  984. DebugLog((DEB_ERROR, "MapWinTrustError returned 0x%x\n", Status));
  985. goto cleanup;
  986. }
  987. Status = STATUS_SUCCESS;
  988. if(ppChainContext != NULL)
  989. {
  990. *ppChainContext = pChainContext;
  991. pChainContext = NULL;
  992. }
  993. cleanup:
  994. if(pChainContext)
  995. {
  996. CertFreeCertificateChain(pChainContext);
  997. }
  998. if(fImpersonating) RevertToSelf();
  999. return Status;
  1000. }
  1001. NTSTATUS
  1002. AutoVerifyServerCertificate(PSPContext pContext)
  1003. {
  1004. PSPCredentialGroup pCredGroup;
  1005. DWORD dwCertFlags = 0;
  1006. DWORD dwIgnoreErrors = 0;
  1007. if(pContext->Flags & CONTEXT_FLAG_MANUAL_CRED_VALIDATION)
  1008. {
  1009. return STATUS_SUCCESS;
  1010. }
  1011. pCredGroup = pContext->pCredGroup;
  1012. if(pCredGroup == NULL)
  1013. {
  1014. return SP_LOG_RESULT(SEC_E_INTERNAL_ERROR);
  1015. }
  1016. if(pCredGroup->dwFlags & CRED_FLAG_REVCHECK_END_CERT)
  1017. dwCertFlags |= CERT_CHAIN_REVOCATION_CHECK_END_CERT;
  1018. if(pCredGroup->dwFlags & CRED_FLAG_REVCHECK_CHAIN)
  1019. dwCertFlags |= CERT_CHAIN_REVOCATION_CHECK_CHAIN;
  1020. if(pCredGroup->dwFlags & CRED_FLAG_REVCHECK_CHAIN_EXCLUDE_ROOT)
  1021. dwCertFlags |= CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT;
  1022. if(pCredGroup->dwFlags & CRED_FLAG_IGNORE_NO_REVOCATION_CHECK)
  1023. dwIgnoreErrors |= CRED_FLAG_IGNORE_NO_REVOCATION_CHECK;
  1024. if(pCredGroup->dwFlags & CRED_FLAG_IGNORE_REVOCATION_OFFLINE)
  1025. dwIgnoreErrors |= CRED_FLAG_IGNORE_REVOCATION_OFFLINE;
  1026. return VerifyServerCertificate(pContext, dwCertFlags, dwIgnoreErrors);
  1027. }
  1028. NTSTATUS
  1029. VerifyServerCertificate(
  1030. PSPContext pContext,
  1031. DWORD dwCertFlags,
  1032. DWORD dwIgnoreErrors)
  1033. {
  1034. HTTPSPolicyCallbackData polHttps;
  1035. CERT_CHAIN_POLICY_PARA PolicyPara;
  1036. CERT_CHAIN_POLICY_STATUS PolicyStatus;
  1037. CERT_CHAIN_PARA ChainPara;
  1038. PCCERT_CHAIN_CONTEXT pChainContext = NULL;
  1039. #define SERVER_USAGE_COUNT 3
  1040. LPSTR rgszUsages[SERVER_USAGE_COUNT] = {
  1041. szOID_PKIX_KP_SERVER_AUTH,
  1042. szOID_SERVER_GATED_CRYPTO,
  1043. szOID_SGC_NETSCAPE };
  1044. NTSTATUS Status;
  1045. PWSTR pwszServerName = NULL;
  1046. PSPCredentialGroup pCred;
  1047. PCCERT_CONTEXT pCertContext;
  1048. BOOL fImpersonating = FALSE;
  1049. pCred = pContext->pCredGroup;
  1050. if(pCred == NULL)
  1051. {
  1052. return SEC_E_INTERNAL_ERROR;
  1053. }
  1054. pCertContext = pContext->RipeZombie->pRemoteCert;
  1055. if(pCertContext == NULL)
  1056. {
  1057. return SEC_E_INTERNAL_ERROR;
  1058. }
  1059. //
  1060. // Build certificate chain.
  1061. //
  1062. fImpersonating = SslImpersonateClient();
  1063. ZeroMemory(&ChainPara, sizeof(ChainPara));
  1064. ChainPara.cbSize = sizeof(ChainPara);
  1065. ChainPara.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR;
  1066. ChainPara.RequestedUsage.Usage.cUsageIdentifier = SERVER_USAGE_COUNT;
  1067. ChainPara.RequestedUsage.Usage.rgpszUsageIdentifier = rgszUsages;
  1068. if(!CertGetCertificateChain(
  1069. NULL, // hChainEngine
  1070. pCertContext, // pCertContext
  1071. NULL, // pTime
  1072. pCertContext->hCertStore, // hAdditionalStore
  1073. &ChainPara, // pChainPara
  1074. dwCertFlags, // dwFlags
  1075. NULL, // pvReserved
  1076. &pChainContext)) // ppChainContext
  1077. {
  1078. Status = SP_LOG_RESULT(GetLastError());
  1079. goto cleanup;
  1080. }
  1081. //
  1082. // Validate certificate chain.
  1083. //
  1084. if(!(pCred->dwFlags & CRED_FLAG_NO_SERVERNAME_CHECK))
  1085. {
  1086. pwszServerName = pContext->RipeZombie->szCacheID;
  1087. if(pwszServerName == NULL || lstrlenW(pwszServerName) == 0)
  1088. {
  1089. Status = SP_LOG_RESULT(SEC_E_WRONG_PRINCIPAL);
  1090. goto cleanup;
  1091. }
  1092. }
  1093. ZeroMemory(&polHttps, sizeof(HTTPSPolicyCallbackData));
  1094. polHttps.cbStruct = sizeof(HTTPSPolicyCallbackData);
  1095. polHttps.dwAuthType = AUTHTYPE_SERVER;
  1096. polHttps.fdwChecks = 0;
  1097. polHttps.pwszServerName = pwszServerName;
  1098. ZeroMemory(&PolicyPara, sizeof(PolicyPara));
  1099. PolicyPara.cbSize = sizeof(PolicyPara);
  1100. PolicyPara.pvExtraPolicyPara = &polHttps;
  1101. ZeroMemory(&PolicyStatus, sizeof(PolicyStatus));
  1102. PolicyStatus.cbSize = sizeof(PolicyStatus);
  1103. if(!CertVerifyCertificateChainPolicy(
  1104. CERT_CHAIN_POLICY_SSL,
  1105. pChainContext,
  1106. &PolicyPara,
  1107. &PolicyStatus))
  1108. {
  1109. Status = SP_LOG_RESULT(GetLastError());
  1110. goto cleanup;
  1111. }
  1112. #if DBG
  1113. if(PolicyStatus.dwError)
  1114. {
  1115. DebugLog((DEB_WARN, "CertVerifyCertificateChainPolicy returned 0x%x\n", PolicyStatus.dwError));
  1116. }
  1117. #endif
  1118. Status = MapWinTrustError(PolicyStatus.dwError, 0, dwIgnoreErrors);
  1119. if(Status)
  1120. {
  1121. DebugLog((DEB_ERROR, "MapWinTrustError returned 0x%x\n", Status));
  1122. LogBogusServerCertEvent(pCertContext, pwszServerName, Status);
  1123. goto cleanup;
  1124. }
  1125. Status = STATUS_SUCCESS;
  1126. cleanup:
  1127. if(pChainContext)
  1128. {
  1129. CertFreeCertificateChain(pChainContext);
  1130. }
  1131. if(fImpersonating) RevertToSelf();
  1132. return Status;
  1133. }
  1134. SECURITY_STATUS
  1135. SPCheckKeyUsage(
  1136. PCCERT_CONTEXT pCertContext,
  1137. PSTR pszUsage,
  1138. BOOL fOnCertOnly,
  1139. PBOOL pfIsAllowed)
  1140. {
  1141. PCERT_ENHKEY_USAGE pKeyUsage;
  1142. DWORD cbKeyUsage;
  1143. DWORD j;
  1144. BOOL fFound;
  1145. DWORD dwFlags = 0;
  1146. if(fOnCertOnly)
  1147. {
  1148. dwFlags = CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG;
  1149. }
  1150. // Determine size of usage information.
  1151. if(!CertGetEnhancedKeyUsage(pCertContext,
  1152. dwFlags,
  1153. NULL,
  1154. &cbKeyUsage))
  1155. {
  1156. // No usage information exists.
  1157. *pfIsAllowed = TRUE;
  1158. return SEC_E_OK;
  1159. }
  1160. SafeAllocaAllocate(pKeyUsage, cbKeyUsage);
  1161. if(pKeyUsage == NULL)
  1162. {
  1163. *pfIsAllowed = FALSE;
  1164. return SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
  1165. }
  1166. // Read key usage information.
  1167. if(!CertGetEnhancedKeyUsage(pCertContext,
  1168. dwFlags,
  1169. pKeyUsage,
  1170. &cbKeyUsage))
  1171. {
  1172. // No usage information exists.
  1173. SafeAllocaFree(pKeyUsage);
  1174. *pfIsAllowed = TRUE;
  1175. return SEC_E_OK;
  1176. }
  1177. if(pKeyUsage->cUsageIdentifier == 0 && GetLastError() == CRYPT_E_NOT_FOUND)
  1178. {
  1179. // No usage information exists.
  1180. SafeAllocaFree(pKeyUsage);
  1181. *pfIsAllowed = TRUE;
  1182. return SEC_E_OK;
  1183. }
  1184. // See if requested usage is in list of supported usages.
  1185. fFound = FALSE;
  1186. for(j = 0; j < pKeyUsage->cUsageIdentifier; j++)
  1187. {
  1188. if(strcmp(pszUsage, pKeyUsage->rgpszUsageIdentifier[j]) == 0)
  1189. {
  1190. fFound = TRUE;
  1191. break;
  1192. }
  1193. }
  1194. SafeAllocaFree(pKeyUsage);
  1195. if(!fFound)
  1196. {
  1197. // Usage extensions found, but doesn't list ours.
  1198. *pfIsAllowed = FALSE;
  1199. }
  1200. else
  1201. {
  1202. *pfIsAllowed = TRUE;
  1203. }
  1204. return SEC_E_OK;
  1205. }