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.

4529 lines
100 KiB

  1. //+--------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996 - 1999
  5. //
  6. // File: crypt.cpp
  7. //
  8. // Contents: Cert Server wrapper routines
  9. //
  10. //---------------------------------------------------------------------------
  11. #include <pch.cpp>
  12. #pragma hdrstop
  13. #include <stdlib.h>
  14. #include <winldap.h>
  15. #include "csdisp.h"
  16. #include "cscsp.h"
  17. #include "csprop.h"
  18. #include "csber.h"
  19. #include "csldap.h"
  20. #define __dwFILE__ __dwFILE_CERTLIB_CRYPT_CPP__
  21. HRESULT
  22. myGenerateKeys(
  23. IN WCHAR const *pwszContainer,
  24. OPTIONAL IN WCHAR const *pwszProvName,
  25. IN DWORD dwFlags,
  26. IN BOOL fMachineKeySet,
  27. IN DWORD dwKeySpec,
  28. IN DWORD dwProvType,
  29. IN DWORD dwKeySize,
  30. OUT HCRYPTPROV *phProv)
  31. {
  32. HRESULT hr;
  33. HCRYPTKEY hKey = NULL;
  34. *phProv = NULL;
  35. if (fMachineKeySet)
  36. {
  37. dwFlags |= CRYPT_MACHINE_KEYSET;
  38. }
  39. // see if the container already exists
  40. if (CryptAcquireContext(
  41. phProv,
  42. pwszContainer,
  43. pwszProvName,
  44. dwProvType,
  45. dwFlags))
  46. {
  47. if (NULL != *phProv)
  48. {
  49. CryptReleaseContext(*phProv, 0);
  50. *phProv = NULL;
  51. }
  52. // container exists -- remove old keys and generate new ones.
  53. if (!CryptAcquireContext(
  54. phProv,
  55. pwszContainer,
  56. pwszProvName,
  57. dwProvType,
  58. CRYPT_DELETEKEYSET | dwFlags))
  59. {
  60. hr = myHLastError();
  61. _JumpError(hr, error, "CryptAcquireContextEx");
  62. }
  63. }
  64. // create new container
  65. if (!CryptAcquireContext(
  66. phProv,
  67. pwszContainer,
  68. pwszProvName,
  69. dwProvType,
  70. CRYPT_NEWKEYSET | dwFlags)) // force new container
  71. {
  72. hr = myHLastError();
  73. _JumpError(hr, error, "CryptAcquireContextEx");
  74. }
  75. // create keys
  76. if (!CryptGenKey(*phProv, dwKeySpec, dwKeySize << 16, &hKey))
  77. {
  78. hr = myHLastError();
  79. _JumpError(hr, error, "CryptGenKey");
  80. }
  81. hr = S_OK;
  82. error:
  83. if (NULL != hKey)
  84. {
  85. CryptDestroyKey(hKey);
  86. }
  87. return(hr);
  88. }
  89. HRESULT
  90. myCryptExportPrivateKey(
  91. IN HCRYPTKEY hKey,
  92. OUT BYTE **ppbKey,
  93. OUT DWORD *pcbKey)
  94. {
  95. HRESULT hr;
  96. BYTE *pbKey = NULL;
  97. *ppbKey = NULL;
  98. // export the key set to a CAPI blob
  99. if (!CryptExportKey(hKey, NULL, PRIVATEKEYBLOB, 0, NULL, pcbKey))
  100. {
  101. hr = myHLastError();
  102. _JumpError2(hr, error, "CryptExportKey", NTE_BAD_KEY_STATE);
  103. }
  104. pbKey = (BYTE *) LocalAlloc(LMEM_FIXED, *pcbKey);
  105. if (NULL == pbKey)
  106. {
  107. hr = E_OUTOFMEMORY;
  108. _JumpError(hr, error, "LocalAlloc");
  109. }
  110. if (!CryptExportKey(hKey, NULL, PRIVATEKEYBLOB, 0, pbKey, pcbKey))
  111. {
  112. hr = myHLastError();
  113. _JumpError(hr, error, "CryptExportKey");
  114. }
  115. *ppbKey = pbKey;
  116. pbKey = NULL;
  117. hr = S_OK;
  118. error:
  119. if (NULL != pbKey)
  120. {
  121. LocalFree(pbKey);
  122. }
  123. return(hr);
  124. }
  125. HRESULT
  126. myVerifyPublicKeyFromHProv(
  127. IN HCRYPTPROV hProv,
  128. IN DWORD dwKeySpec,
  129. IN OPTIONAL CERT_CONTEXT const *pCert,
  130. IN BOOL fV1Cert,
  131. IN OPTIONAL CERT_PUBLIC_KEY_INFO const *pPublicKeyInfo,
  132. OPTIONAL OUT BOOL *pfMatchingKey)
  133. {
  134. HRESULT hr;
  135. DWORD cb;
  136. CERT_PUBLIC_KEY_INFO *pPublicKeyInfoExported = NULL;
  137. if (NULL != pfMatchingKey)
  138. {
  139. *pfMatchingKey = FALSE;
  140. }
  141. if (!myCryptExportPublicKeyInfo(
  142. hProv,
  143. dwKeySpec,
  144. CERTLIB_USE_LOCALALLOC,
  145. &pPublicKeyInfoExported,
  146. &cb))
  147. {
  148. hr = myHLastError();
  149. _JumpError(hr, error, "myCryptExportPublicKeyInfo");
  150. }
  151. if (NULL == pPublicKeyInfo)
  152. {
  153. if (NULL == pCert)
  154. {
  155. hr = E_POINTER;
  156. _JumpError(hr, error, "No cert & no SubjectPublicKeyInfo");
  157. }
  158. pPublicKeyInfo = &pCert->pCertInfo->SubjectPublicKeyInfo;
  159. }
  160. if (!myCertComparePublicKeyInfo(
  161. X509_ASN_ENCODING,
  162. fV1Cert,
  163. pPublicKeyInfoExported,
  164. pPublicKeyInfo))
  165. {
  166. // by design, (my)CertComparePublicKeyInfo doesn't set last error!
  167. hr = NTE_BAD_KEY;
  168. _JumpError(hr, error, "myCertComparePublicKeyInfo");
  169. }
  170. if (NULL != pfMatchingKey)
  171. {
  172. *pfMatchingKey = TRUE;
  173. }
  174. hr = S_OK;
  175. error:
  176. if (NULL != pPublicKeyInfoExported)
  177. {
  178. LocalFree(pPublicKeyInfoExported);
  179. }
  180. return(hr);
  181. }
  182. HRESULT
  183. myVerifyPublicKey(
  184. IN OPTIONAL CERT_CONTEXT const *pCert,
  185. IN BOOL fV1Cert,
  186. IN OPTIONAL CRYPT_KEY_PROV_INFO const *pKeyProvInfo,
  187. IN OPTIONAL CERT_PUBLIC_KEY_INFO const *pPublicKeyInfo,
  188. OPTIONAL OUT BOOL *pfMatchingKey)
  189. {
  190. HRESULT hr;
  191. HCRYPTPROV hProv = NULL;
  192. DWORD dwKeySpec;
  193. if (NULL != pfMatchingKey)
  194. {
  195. *pfMatchingKey = FALSE;
  196. }
  197. if (NULL == pCert ||
  198. !CryptAcquireCertificatePrivateKey(
  199. pCert,
  200. 0, // dwFlags
  201. NULL, // pvReserved
  202. &hProv,
  203. &dwKeySpec,
  204. NULL)) // pfCallerFreeProv
  205. {
  206. if (NULL != pKeyProvInfo)
  207. {
  208. // ok, try passed kpi
  209. if (!myCertSrvCryptAcquireContext(
  210. &hProv,
  211. pKeyProvInfo->pwszContainerName,
  212. pKeyProvInfo->pwszProvName,
  213. pKeyProvInfo->dwProvType,
  214. ~CRYPT_MACHINE_KEYSET & pKeyProvInfo->dwFlags,
  215. (CRYPT_MACHINE_KEYSET & pKeyProvInfo->dwFlags)? TRUE : FALSE))
  216. {
  217. hr = myHLastError();
  218. _JumpErrorStr(
  219. hr,
  220. error,
  221. "myCertSrvCryptAcquireContextEx",
  222. pKeyProvInfo->pwszContainerName);
  223. }
  224. dwKeySpec = pKeyProvInfo->dwKeySpec;
  225. }
  226. else if (NULL != pCert)
  227. {
  228. hr = myHLastError();
  229. _JumpError(hr, error, "CryptAcquireCertificatePrivateKey");
  230. }
  231. else
  232. {
  233. hr = E_POINTER;
  234. _JumpError(hr, error, "No cert & no KeyProvInfo");
  235. }
  236. }
  237. hr = myVerifyPublicKeyFromHProv(
  238. hProv,
  239. dwKeySpec,
  240. pCert,
  241. fV1Cert,
  242. pPublicKeyInfo,
  243. pfMatchingKey);
  244. _JumpIfError(hr, error, "myVerifyPublicKeyFromHProv");
  245. error:
  246. if (NULL != hProv)
  247. {
  248. CryptReleaseContext(hProv, 0);
  249. }
  250. return(hr);
  251. }
  252. DWORD
  253. myASNGetDataIndex(
  254. IN BYTE bBERTag,
  255. IN DWORD iStart,
  256. IN BYTE const *pb,
  257. IN DWORD cb,
  258. OUT DWORD *pdwLen)
  259. {
  260. DWORD iData = MAXDWORD;
  261. pb += iStart;
  262. if (iStart + 2 <= cb && bBERTag == pb[0])
  263. {
  264. DWORD cbLen = 0;
  265. if (0x7f >= pb[1])
  266. {
  267. *pdwLen = pb[1];
  268. cbLen = 1;
  269. }
  270. else if (iStart + 3 <= cb && 0x81 == pb[1])
  271. {
  272. *pdwLen = pb[2];
  273. cbLen = 2;
  274. }
  275. else if (iStart + 4 <= cb && 0x82 == pb[1])
  276. {
  277. *pdwLen = (pb[2] << 8) | pb[3];
  278. cbLen = 3;
  279. }
  280. if (0 != cbLen &&
  281. iStart + cbLen + *pdwLen <= cb)
  282. {
  283. iData = iStart + 1 + cbLen;
  284. }
  285. }
  286. return(iData);
  287. }
  288. DWORD
  289. myASNStoreLength(
  290. IN DWORD dwLen,
  291. IN OUT BYTE *pb,
  292. IN DWORD cb)
  293. {
  294. DWORD cbLen = MAXDWORD;
  295. if (1 <= cb && 0x7f >= dwLen)
  296. {
  297. pb[0] = (BYTE) dwLen;
  298. cbLen = 1;
  299. }
  300. else if (2 <= cb && 0xff >= dwLen)
  301. {
  302. pb[0] = 0x81;
  303. pb[1] = (BYTE) dwLen;
  304. cbLen = 2;
  305. }
  306. else if (3 <= cb && 0xffff >= dwLen)
  307. {
  308. pb[0] = 0x82;
  309. pb[1] = (BYTE) (dwLen >> 8);
  310. pb[2] = (BYTE) dwLen;
  311. cbLen = 3;
  312. }
  313. return(cbLen);
  314. }
  315. // If this is a valid public key with a missing leading zero byte before the
  316. // sign bit set in the first public key byte, add a zero byte and increment
  317. // the lengths. This canonicalizes the old incorrect V1 public key encoding
  318. // used in EPF files.
  319. HRESULT
  320. myCanonicalizePublicKey(
  321. IN BYTE const *pbKeyIn,
  322. IN DWORD cbKeyIn,
  323. OUT BYTE **ppbKeyOut,
  324. OUT DWORD *pcbKeyOut)
  325. {
  326. HRESULT hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  327. DWORD iDataSequence;
  328. DWORD dwLenSequence;
  329. DWORD iDataModulus;
  330. DWORD dwLenModulus;
  331. BYTE *pbKeyOut = NULL;
  332. DWORD cbKeyOut;
  333. BYTE *pb;
  334. DWORD cb;
  335. DWORD cbLen;
  336. *ppbKeyOut = NULL;
  337. iDataSequence = myASNGetDataIndex(
  338. BER_SEQUENCE,
  339. 0,
  340. pbKeyIn,
  341. cbKeyIn,
  342. &dwLenSequence);
  343. if (MAXDWORD == iDataSequence)
  344. {
  345. _JumpError(hr, error, "iDataSequence");
  346. }
  347. iDataModulus = myASNGetDataIndex(
  348. BER_INTEGER,
  349. iDataSequence,
  350. pbKeyIn,
  351. cbKeyIn,
  352. &dwLenModulus);
  353. if (MAXDWORD == iDataModulus)
  354. {
  355. _JumpError(hr, error, "iDataModulus");
  356. }
  357. if (iDataSequence + dwLenSequence == cbKeyIn - 1 &&
  358. 1 == pbKeyIn[cbKeyIn - 1])
  359. {
  360. cbKeyIn--;
  361. }
  362. if (0 == (0x80 & pbKeyIn[iDataModulus]))
  363. {
  364. _JumpError2(hr, error, "key sign", hr);
  365. }
  366. cbKeyOut = cbKeyIn + 1;
  367. pbKeyOut = (BYTE *) LocalAlloc(LMEM_FIXED, cbKeyOut);
  368. if (NULL == pbKeyOut)
  369. {
  370. hr = E_OUTOFMEMORY;
  371. _JumpError(hr, error, "LocalAlloc");
  372. }
  373. pb = pbKeyOut;
  374. cb = cbKeyOut;
  375. // Set the sequence tag and new length:
  376. *pb++ = BER_SEQUENCE;
  377. cb--;
  378. cbLen = myASNStoreLength(dwLenSequence + 1, pb, cb);
  379. if (MAXDWORD == cbLen)
  380. {
  381. _JumpError(hr, error, "new dwLenSequence");
  382. }
  383. pb += cbLen;
  384. cb -= cbLen;
  385. // Set the modulus tag and new length:
  386. *pb++ = BER_INTEGER;
  387. cb--;
  388. cbLen = myASNStoreLength(dwLenModulus + 1, pb, cb);
  389. if (MAXDWORD == cbLen)
  390. {
  391. _JumpError(hr, error, "new dwLenModulus");
  392. }
  393. pb += cbLen;
  394. cb -= cbLen;
  395. *pb++ = 0;
  396. cb--;
  397. if (cb != cbKeyIn - (iDataModulus))
  398. {
  399. // crossed an encoding length boundary -- shouldn't happen!
  400. // new and old sequence and modulus lengths expected:
  401. // 0x10a <== 0x109, 0x101 <== 0x100
  402. // 0x89 <== 0x88, 0x81 <== 0x80
  403. // 0x48 <== 0x47, 0x41 <== 0x40
  404. _JumpError(hr, error, "new key length");
  405. }
  406. CopyMemory(pb, &pbKeyIn[iDataModulus], cb);
  407. *pcbKeyOut = cbKeyOut;
  408. *ppbKeyOut = pbKeyOut;
  409. pbKeyOut = NULL;
  410. hr = S_OK;
  411. error:
  412. if (NULL != pbKeyOut)
  413. {
  414. LocalFree(pbKeyOut);
  415. }
  416. return(hr);
  417. }
  418. // If this is a valid public key with a proper leading zero byte before the
  419. // sign bit set in the next public key byte, remove the zero byte and decrement
  420. // the lengths. This conforms to the old incorrect V1 public key encoding
  421. // used in EPF files.
  422. HRESULT
  423. mySqueezePublicKey(
  424. IN BYTE const *pbKeyIn,
  425. IN DWORD cbKeyIn,
  426. OUT BYTE **ppbKeyOut,
  427. OUT DWORD *pcbKeyOut)
  428. {
  429. HRESULT hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  430. DWORD iDataSequence;
  431. DWORD dwLenSequence;
  432. DWORD iDataModulus;
  433. DWORD dwLenModulus;
  434. BYTE *pbKeyOut = NULL;
  435. DWORD cbKeyOut;
  436. BYTE *pb;
  437. DWORD cb;
  438. DWORD cbLen;
  439. *ppbKeyOut = NULL;
  440. iDataSequence = myASNGetDataIndex(
  441. BER_SEQUENCE,
  442. 0,
  443. pbKeyIn,
  444. cbKeyIn,
  445. &dwLenSequence);
  446. if (MAXDWORD == iDataSequence)
  447. {
  448. _JumpError(hr, error, "iDataSequence");
  449. }
  450. iDataModulus = myASNGetDataIndex(
  451. BER_INTEGER,
  452. iDataSequence,
  453. pbKeyIn,
  454. cbKeyIn,
  455. &dwLenModulus);
  456. if (MAXDWORD == iDataModulus)
  457. {
  458. _JumpError(hr, error, "iDataModulus");
  459. }
  460. if (0 != pbKeyIn[iDataModulus] ||
  461. 0 == (0x80 & pbKeyIn[iDataModulus + 1]))
  462. {
  463. _JumpError(hr, error, "key sign");
  464. }
  465. cbKeyOut = cbKeyIn - 1;
  466. pbKeyOut = (BYTE *) LocalAlloc(LMEM_FIXED, cbKeyOut);
  467. if (NULL == pbKeyOut)
  468. {
  469. hr = E_OUTOFMEMORY;
  470. _JumpError(hr, error, "LocalAlloc");
  471. }
  472. pb = pbKeyOut;
  473. cb = cbKeyOut;
  474. // Set the sequence tag and new length:
  475. *pb++ = BER_SEQUENCE;
  476. cb--;
  477. cbLen = myASNStoreLength(dwLenSequence - 1, pb, cb);
  478. if (MAXDWORD == cbLen)
  479. {
  480. _JumpError(hr, error, "new dwLenSequence");
  481. }
  482. pb += cbLen;
  483. cb -= cbLen;
  484. // Set the modulus tag and new length:
  485. *pb++ = BER_INTEGER;
  486. cb--;
  487. cbLen = myASNStoreLength(dwLenModulus - 1, pb, cb);
  488. if (MAXDWORD == cbLen)
  489. {
  490. _JumpError(hr, error, "new dwLenModulus");
  491. }
  492. pb += cbLen;
  493. cb -= cbLen;
  494. if (cb != cbKeyIn - (iDataModulus + 1))
  495. {
  496. // crossed an encoding length boundary -- shouldn't happen!
  497. // new and old sequence and modulus lengths expected:
  498. // 0x10a ==> 0x109, 0x101 ==> 0x100
  499. // 0x89 ==> 0x88, 0x81 ==> 0x80
  500. // 0x48 ==> 0x47, 0x41 ==> 0x40
  501. _JumpError(hr, error, "new key length");
  502. }
  503. CopyMemory(pb, &pbKeyIn[iDataModulus + 1], cb);
  504. *pcbKeyOut = cbKeyOut;
  505. *ppbKeyOut = pbKeyOut;
  506. pbKeyOut = NULL;
  507. hr = S_OK;
  508. error:
  509. if (NULL != pbKeyOut)
  510. {
  511. LocalFree(pbKeyOut);
  512. }
  513. return(hr);
  514. }
  515. // by design, (my)CertComparePublicKeyInfo doesn't set last error!
  516. BOOL
  517. myCertComparePublicKeyInfo(
  518. IN DWORD dwCertEncodingType,
  519. IN BOOL fV1Cert,
  520. IN CERT_PUBLIC_KEY_INFO const *pPubKey1,
  521. IN CERT_PUBLIC_KEY_INFO const *pPubKey2)
  522. {
  523. BOOL fMatch = FALSE;
  524. BYTE *pbKeyNew = NULL;
  525. if (CertComparePublicKeyInfo(
  526. dwCertEncodingType,
  527. const_cast<CERT_PUBLIC_KEY_INFO *>(pPubKey1),
  528. const_cast<CERT_PUBLIC_KEY_INFO *>(pPubKey2)))
  529. {
  530. fMatch = TRUE;
  531. goto error;
  532. }
  533. #if 0
  534. wprintf(L"pPubKey1:\n");
  535. DumpHex(
  536. DH_NOADDRESS | DH_NOTABPREFIX | 8,
  537. pPubKey1->PublicKey.pbData,
  538. pPubKey1->PublicKey.cbData);
  539. wprintf(L"pPubKey2:\n");
  540. DumpHex(
  541. DH_NOADDRESS | DH_NOTABPREFIX | 8,
  542. pPubKey2->PublicKey.pbData,
  543. pPubKey2->PublicKey.cbData);
  544. #endif
  545. // If this is a V1 X509 cert with the sign bit set in the first public key
  546. // byte -- without a leading zero pad byte, and there's a wasted byte at
  547. // the end of the public key, squeeze out the leading zero byte from the
  548. // correctly encoded key, and compare the result.
  549. if (fV1Cert &&
  550. (pPubKey1->PublicKey.cbData == pPubKey2->PublicKey.cbData ||
  551. pPubKey1->PublicKey.cbData == pPubKey2->PublicKey.cbData + 1))
  552. {
  553. HRESULT hr;
  554. CERT_PUBLIC_KEY_INFO PubKey1;
  555. CERT_PUBLIC_KEY_INFO PubKey2;
  556. PubKey1 = *pPubKey1;
  557. PubKey2 = *pPubKey2;
  558. hr = mySqueezePublicKey(
  559. PubKey1.PublicKey.pbData,
  560. PubKey1.PublicKey.cbData,
  561. &pbKeyNew,
  562. &PubKey1.PublicKey.cbData);
  563. _JumpIfError(hr, error, "mySqueezePublicKey");
  564. //PubKey1.PublicKey.cbData--;
  565. PubKey1.PublicKey.pbData = pbKeyNew;
  566. if (2 < PubKey2.PublicKey.cbData &&
  567. PubKey2.PublicKey.cbData == 1 + PubKey1.PublicKey.cbData &&
  568. 1 == PubKey2.PublicKey.pbData[PubKey2.PublicKey.cbData - 1] &&
  569. 1 == PubKey2.PublicKey.pbData[PubKey2.PublicKey.cbData - 2])
  570. {
  571. PubKey2.PublicKey.cbData--;
  572. }
  573. #if 0
  574. wprintf(L"PubKey1:\n");
  575. DumpHex(
  576. DH_NOADDRESS | DH_NOTABPREFIX | 8,
  577. PubKey1.PublicKey.pbData,
  578. PubKey1.PublicKey.cbData);
  579. wprintf(L"PubKey2:\n");
  580. DumpHex(
  581. DH_NOADDRESS | DH_NOTABPREFIX | 8,
  582. PubKey2.PublicKey.pbData,
  583. PubKey2.PublicKey.cbData);
  584. #endif
  585. if (CertComparePublicKeyInfo(
  586. dwCertEncodingType,
  587. &PubKey1,
  588. &PubKey2))
  589. {
  590. fMatch = TRUE;
  591. }
  592. }
  593. error:
  594. if (NULL != pbKeyNew)
  595. {
  596. LocalFree(pbKeyNew);
  597. }
  598. return(fMatch);
  599. }
  600. BOOL
  601. myCryptSignMessage(
  602. IN CRYPT_SIGN_MESSAGE_PARA const *pcsmp,
  603. IN BYTE const *pbToBeSigned,
  604. IN DWORD cbToBeSigned,
  605. IN CERTLIB_ALLOCATOR allocType,
  606. OUT BYTE **ppbSignedBlob,
  607. OUT DWORD *pcbSignedBlob)
  608. {
  609. BOOL b;
  610. *ppbSignedBlob = NULL;
  611. *pcbSignedBlob = 0;
  612. for (;;)
  613. {
  614. b = CryptSignMessage(
  615. const_cast<CRYPT_SIGN_MESSAGE_PARA *>(pcsmp),
  616. TRUE, // fDetachedSignature
  617. 1, // cToBeSigned
  618. &pbToBeSigned, // rgpbToBeSigned
  619. &cbToBeSigned, // rgcbToBeSigned
  620. *ppbSignedBlob,
  621. pcbSignedBlob);
  622. if (b && 0 == *pcbSignedBlob)
  623. {
  624. SetLastError((DWORD) HRESULT_FROM_WIN32(ERROR_INVALID_DATA));
  625. b = FALSE;
  626. }
  627. if (!b)
  628. {
  629. if (NULL != *ppbSignedBlob)
  630. {
  631. myFree(*ppbSignedBlob, allocType);
  632. *ppbSignedBlob = NULL;
  633. }
  634. break;
  635. }
  636. if (NULL != *ppbSignedBlob)
  637. {
  638. break;
  639. }
  640. *ppbSignedBlob = (BYTE *) myAlloc(*pcbSignedBlob, allocType);
  641. if (NULL == *ppbSignedBlob)
  642. {
  643. b = FALSE;
  644. break;
  645. }
  646. }
  647. return(b);
  648. }
  649. BOOL
  650. myEncodeCert(
  651. IN DWORD dwEncodingType,
  652. IN CERT_SIGNED_CONTENT_INFO const *pInfo,
  653. IN CERTLIB_ALLOCATOR allocType,
  654. OUT BYTE **ppbEncoded,
  655. OUT DWORD *pcbEncoded)
  656. {
  657. return(myEncodeObject(
  658. dwEncodingType,
  659. X509_CERT,
  660. pInfo,
  661. 0,
  662. allocType,
  663. ppbEncoded,
  664. pcbEncoded));
  665. }
  666. BOOL
  667. myEncodeName(
  668. IN DWORD dwEncodingType,
  669. IN CERT_NAME_INFO const *pInfo,
  670. IN DWORD dwFlags,
  671. IN CERTLIB_ALLOCATOR allocType,
  672. OUT BYTE **ppbEncoded,
  673. OUT DWORD *pcbEncoded)
  674. {
  675. return(myEncodeObject(
  676. dwEncodingType,
  677. X509_UNICODE_NAME,
  678. pInfo,
  679. dwFlags,
  680. allocType,
  681. ppbEncoded,
  682. pcbEncoded));
  683. }
  684. BOOL
  685. myEncodeKeyAttributes(
  686. IN DWORD dwEncodingType,
  687. IN CERT_KEY_ATTRIBUTES_INFO const *pInfo,
  688. IN CERTLIB_ALLOCATOR allocType,
  689. OUT BYTE **ppbEncoded,
  690. OUT DWORD *pcbEncoded)
  691. {
  692. return(myEncodeObject(
  693. dwEncodingType,
  694. X509_KEY_ATTRIBUTES,
  695. pInfo,
  696. 0,
  697. allocType,
  698. ppbEncoded,
  699. pcbEncoded));
  700. }
  701. BOOL
  702. myEncodeKeyUsage(
  703. IN DWORD dwEncodingType,
  704. IN CRYPT_BIT_BLOB const *pInfo,
  705. IN CERTLIB_ALLOCATOR allocType,
  706. OUT BYTE **ppbEncoded,
  707. OUT DWORD *pcbEncoded)
  708. {
  709. return(myEncodeObject(
  710. dwEncodingType,
  711. X509_KEY_USAGE,
  712. pInfo,
  713. 0,
  714. allocType,
  715. ppbEncoded,
  716. pcbEncoded));
  717. }
  718. BOOL
  719. myEncodeKeyAuthority2(
  720. IN DWORD dwEncodingType,
  721. IN CERT_AUTHORITY_KEY_ID2_INFO const *pInfo,
  722. IN CERTLIB_ALLOCATOR allocType,
  723. OUT BYTE **ppbEncoded,
  724. OUT DWORD *pcbEncoded)
  725. {
  726. return(myEncodeObject(
  727. dwEncodingType,
  728. X509_AUTHORITY_KEY_ID2,
  729. pInfo,
  730. 0,
  731. allocType,
  732. ppbEncoded,
  733. pcbEncoded));
  734. }
  735. BOOL
  736. myEncodeToBeSigned(
  737. DWORD dwEncodingType,
  738. CERT_INFO const *pInfo,
  739. IN CERTLIB_ALLOCATOR allocType,
  740. BYTE **ppbEncoded,
  741. DWORD *pcbEncoded)
  742. {
  743. return(myEncodeObject(
  744. dwEncodingType,
  745. X509_CERT_TO_BE_SIGNED,
  746. pInfo,
  747. 0,
  748. allocType,
  749. ppbEncoded,
  750. pcbEncoded));
  751. }
  752. BOOL
  753. myDecodeName(
  754. IN DWORD dwEncodingType,
  755. IN LPCSTR lpszStructType,
  756. IN BYTE const *pbEncoded,
  757. IN DWORD cbEncoded,
  758. IN CERTLIB_ALLOCATOR allocType,
  759. OUT CERT_NAME_INFO **ppNameInfo,
  760. OUT DWORD *pcbNameInfo)
  761. {
  762. return(myDecodeObject(
  763. dwEncodingType,
  764. lpszStructType,
  765. pbEncoded,
  766. cbEncoded,
  767. allocType,
  768. (VOID **) ppNameInfo,
  769. pcbNameInfo));
  770. }
  771. BOOL
  772. myDecodeKeyAuthority(
  773. IN DWORD dwEncodingType,
  774. IN BYTE const *pbEncoded,
  775. IN DWORD cbEncoded,
  776. IN CERTLIB_ALLOCATOR allocType,
  777. OUT CERT_AUTHORITY_KEY_ID_INFO const **ppInfo,
  778. OUT DWORD *pcbInfo)
  779. {
  780. return(myDecodeObject(
  781. dwEncodingType,
  782. X509_AUTHORITY_KEY_ID,
  783. pbEncoded,
  784. cbEncoded,
  785. allocType,
  786. (VOID **) ppInfo,
  787. pcbInfo));
  788. }
  789. BOOL
  790. myDecodeKeyAuthority2(
  791. IN DWORD dwEncodingType,
  792. IN BYTE const *pbEncoded,
  793. IN DWORD cbEncoded,
  794. IN CERTLIB_ALLOCATOR allocType,
  795. OUT CERT_AUTHORITY_KEY_ID2_INFO const **ppInfo,
  796. OUT DWORD *pcbInfo)
  797. {
  798. return(myDecodeObject(
  799. dwEncodingType,
  800. X509_AUTHORITY_KEY_ID2,
  801. pbEncoded,
  802. cbEncoded,
  803. allocType,
  804. (VOID **) ppInfo,
  805. pcbInfo));
  806. }
  807. BOOL
  808. myDecodeExtensions(
  809. IN DWORD dwEncodingType,
  810. IN BYTE const *pbEncoded,
  811. IN DWORD cbEncoded,
  812. IN CERTLIB_ALLOCATOR allocType,
  813. OUT CERT_EXTENSIONS **ppInfo,
  814. OUT DWORD *pcbInfo)
  815. {
  816. return(myDecodeObject(
  817. dwEncodingType,
  818. X509_NAME,
  819. pbEncoded,
  820. cbEncoded,
  821. allocType,
  822. (VOID **) ppInfo,
  823. pcbInfo));
  824. }
  825. BOOL
  826. myDecodeKeyGenRequest(
  827. IN BYTE const *pbRequest,
  828. IN DWORD cbRequest,
  829. IN CERTLIB_ALLOCATOR allocType,
  830. OUT CERT_KEYGEN_REQUEST_INFO **ppKeyGenRequest,
  831. OUT DWORD *pcbKeyGenRequest)
  832. {
  833. return(myDecodeObject(
  834. X509_ASN_ENCODING,
  835. X509_KEYGEN_REQUEST_TO_BE_SIGNED,
  836. pbRequest,
  837. cbRequest,
  838. allocType,
  839. (VOID **) ppKeyGenRequest,
  840. pcbKeyGenRequest));
  841. }
  842. HRESULT
  843. myDecodeCSPProviderAttribute(
  844. IN BYTE const *pbCSPEncoded,
  845. IN DWORD cbCSPEncoded,
  846. OUT CRYPT_CSP_PROVIDER **ppccp)
  847. {
  848. HRESULT hr;
  849. CRYPT_SEQUENCE_OF_ANY *pCSPProviderSeq = NULL;
  850. DWORD cb;
  851. CRYPT_CSP_PROVIDER *pccp;
  852. DWORD dwKeySpec;
  853. CERT_NAME_VALUE *pName = NULL;
  854. CRYPT_BIT_BLOB *pBlob = NULL;
  855. BYTE *pb;
  856. *ppccp = NULL;
  857. if (!myDecodeObject(
  858. X509_ASN_ENCODING,
  859. X509_SEQUENCE_OF_ANY,
  860. pbCSPEncoded,
  861. cbCSPEncoded,
  862. CERTLIB_USE_LOCALALLOC,
  863. (VOID **) &pCSPProviderSeq,
  864. &cb))
  865. {
  866. hr = myHLastError();
  867. _JumpError(hr, error, "myDecodeObject");
  868. }
  869. if (3 > pCSPProviderSeq->cValue)
  870. {
  871. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  872. _JumpError(hr, error, "Sequence count < 3");
  873. }
  874. dwKeySpec = 0;
  875. if (NULL != pCSPProviderSeq->rgValue[0].pbData &&
  876. 0 != pCSPProviderSeq->rgValue[0].cbData)
  877. {
  878. cb = sizeof(dwKeySpec);
  879. if (!CryptDecodeObject(
  880. X509_ASN_ENCODING,
  881. X509_INTEGER,
  882. pCSPProviderSeq->rgValue[0].pbData,
  883. pCSPProviderSeq->rgValue[0].cbData,
  884. 0,
  885. &dwKeySpec,
  886. &cb))
  887. {
  888. hr = myHLastError();
  889. _JumpError(hr, error, "CryptDecodeObject");
  890. }
  891. }
  892. if (NULL != pCSPProviderSeq->rgValue[1].pbData &&
  893. 0 != pCSPProviderSeq->rgValue[1].cbData)
  894. {
  895. if (!myDecodeObject(
  896. X509_ASN_ENCODING,
  897. X509_UNICODE_ANY_STRING,
  898. pCSPProviderSeq->rgValue[1].pbData,
  899. pCSPProviderSeq->rgValue[1].cbData,
  900. CERTLIB_USE_LOCALALLOC,
  901. (VOID **) &pName,
  902. &cb))
  903. {
  904. hr = myHLastError();
  905. _JumpError(hr, error, "myDecodeObject");
  906. }
  907. }
  908. if (NULL != pCSPProviderSeq->rgValue[2].pbData &&
  909. 0 != pCSPProviderSeq->rgValue[2].cbData)
  910. {
  911. if (!myDecodeObject(
  912. X509_ASN_ENCODING,
  913. X509_BITS,
  914. pCSPProviderSeq->rgValue[2].pbData,
  915. pCSPProviderSeq->rgValue[2].cbData,
  916. CERTLIB_USE_LOCALALLOC,
  917. (VOID **) &pBlob,
  918. &cb))
  919. {
  920. hr = myHLastError();
  921. _JumpError(hr, error, "myDecodeObject");
  922. }
  923. }
  924. cb = sizeof(*pccp);
  925. if (NULL != pName && NULL != pName->Value.pbData)
  926. {
  927. cb += POINTERROUND((wcslen((WCHAR const *) pName->Value.pbData) + 1) *
  928. sizeof(WCHAR));
  929. }
  930. if (NULL != pBlob && NULL != pBlob->pbData)
  931. {
  932. cb += POINTERROUND(pBlob->cbData);
  933. }
  934. pccp = (CRYPT_CSP_PROVIDER *) LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, cb);
  935. if (NULL == pccp)
  936. {
  937. hr = E_OUTOFMEMORY;
  938. _JumpError(hr, error, "LocalAlloc");
  939. }
  940. *ppccp = pccp;
  941. pb = (BYTE *) (pccp + 1);
  942. pccp->dwKeySpec = dwKeySpec;
  943. if (NULL != pName->Value.pbData)
  944. {
  945. pccp->pwszProviderName = (WCHAR *) pb;
  946. wcscpy(pccp->pwszProviderName, (WCHAR const *) pName->Value.pbData);
  947. pb += POINTERROUND((wcslen((WCHAR const *) pName->Value.pbData) + 1) *
  948. sizeof(WCHAR));
  949. }
  950. if (NULL != pBlob && NULL != pBlob->pbData)
  951. {
  952. pccp->Signature.pbData = pb;
  953. pccp->Signature.cbData = pBlob->cbData;
  954. pccp->Signature.cUnusedBits = pBlob->cUnusedBits;
  955. CopyMemory(pccp->Signature.pbData, pBlob->pbData, pBlob->cbData);
  956. }
  957. hr = S_OK;
  958. error:
  959. if (NULL != pCSPProviderSeq)
  960. {
  961. LocalFree(pCSPProviderSeq);
  962. }
  963. if (NULL != pName)
  964. {
  965. LocalFree(pName);
  966. }
  967. if (NULL != pBlob)
  968. {
  969. LocalFree(pBlob);
  970. }
  971. return(hr);
  972. }
  973. BOOL
  974. myCertGetCertificateContextProperty(
  975. IN CERT_CONTEXT const *pCertContext,
  976. IN DWORD dwPropId,
  977. IN CERTLIB_ALLOCATOR allocType,
  978. OUT VOID **ppvData,
  979. OUT DWORD *pcbData)
  980. {
  981. BOOL b;
  982. *ppvData = NULL;
  983. *pcbData = 0;
  984. for (;;)
  985. {
  986. b = CertGetCertificateContextProperty(
  987. pCertContext,
  988. dwPropId,
  989. *ppvData,
  990. pcbData);
  991. if (b && 0 == *pcbData)
  992. {
  993. SetLastError((DWORD) HRESULT_FROM_WIN32(ERROR_INVALID_DATA));
  994. b = FALSE;
  995. }
  996. if (!b)
  997. {
  998. if (NULL != *ppvData)
  999. {
  1000. myFree(*ppvData, allocType);
  1001. *ppvData = NULL;
  1002. }
  1003. break;
  1004. }
  1005. if (NULL != *ppvData)
  1006. {
  1007. break;
  1008. }
  1009. *ppvData = (VOID *) myAlloc(*pcbData, allocType);
  1010. if (NULL == *ppvData)
  1011. {
  1012. b = FALSE;
  1013. break;
  1014. }
  1015. }
  1016. return(b);
  1017. }
  1018. HRESULT
  1019. myCertGetKeyProviderInfo(
  1020. IN CERT_CONTEXT const *pCert,
  1021. OUT CRYPT_KEY_PROV_INFO **ppkpi)
  1022. {
  1023. HRESULT hr;
  1024. DWORD cb;
  1025. *ppkpi = NULL;
  1026. if (!CertGetCertificateContextProperty(
  1027. pCert,
  1028. CERT_KEY_PROV_INFO_PROP_ID,
  1029. NULL,
  1030. &cb))
  1031. {
  1032. hr = myHLastError();
  1033. _JumpError2(
  1034. hr,
  1035. error,
  1036. "CertGetCertificateContextProperty",
  1037. CRYPT_E_NOT_FOUND);
  1038. }
  1039. *ppkpi = (CRYPT_KEY_PROV_INFO *) LocalAlloc(LMEM_FIXED, cb);
  1040. if (NULL == *ppkpi)
  1041. {
  1042. hr = E_OUTOFMEMORY;
  1043. _JumpError(hr, error, "LocalAlloc");
  1044. }
  1045. if (!CertGetCertificateContextProperty(
  1046. pCert,
  1047. CERT_KEY_PROV_INFO_PROP_ID,
  1048. *ppkpi,
  1049. &cb))
  1050. {
  1051. hr = myHLastError();
  1052. _JumpError(hr, error, "CertGetCertificateContextProperty");
  1053. }
  1054. hr = S_OK;
  1055. error:
  1056. return(hr);
  1057. }
  1058. HRESULT
  1059. myCryptExportKey(
  1060. IN HCRYPTKEY hKey,
  1061. IN HCRYPTKEY hKeyExp,
  1062. IN DWORD dwBlobType,
  1063. IN DWORD dwFlags,
  1064. OUT BYTE **ppbKey,
  1065. OUT DWORD *pcbKey)
  1066. {
  1067. HRESULT hr;
  1068. if (!CryptExportKey(hKey, hKeyExp, dwBlobType, dwFlags, NULL, pcbKey))
  1069. {
  1070. hr = myHLastError();
  1071. _JumpError(hr, error, "CryptExportKey");
  1072. }
  1073. *ppbKey = (BYTE *) LocalAlloc(LMEM_FIXED, *pcbKey);
  1074. if (NULL == *ppbKey)
  1075. {
  1076. hr = E_OUTOFMEMORY;
  1077. _JumpError(hr, error, "LocalAlloc");
  1078. }
  1079. if (!CryptExportKey(hKey, hKeyExp, dwBlobType, dwFlags, *ppbKey, pcbKey))
  1080. {
  1081. hr = myHLastError();
  1082. LocalFree(*ppbKey);
  1083. *ppbKey = NULL;
  1084. _JumpError(hr, error, "CryptExportKey");
  1085. }
  1086. hr = S_OK;
  1087. error:
  1088. return(hr);
  1089. }
  1090. HRESULT
  1091. myCryptEncrypt(
  1092. IN HCRYPTKEY hKey,
  1093. IN BYTE const *pbIn,
  1094. IN DWORD cbIn,
  1095. OUT BYTE **ppbEncrypted,
  1096. OUT DWORD *pcbEncrypted)
  1097. {
  1098. HRESULT hr;
  1099. BYTE *pbEncrypted = NULL;
  1100. DWORD cbEncrypted;
  1101. DWORD cbAlloc;
  1102. BOOL fRetried = FALSE;
  1103. cbAlloc = cbIn + 64; // may be enough to prevent overflow
  1104. for (;;)
  1105. {
  1106. cbEncrypted = cbIn;
  1107. pbEncrypted = (BYTE *) LocalAlloc(LMEM_FIXED, cbAlloc);
  1108. if (NULL == pbEncrypted)
  1109. {
  1110. hr = E_OUTOFMEMORY;
  1111. _JumpError(hr, error, "LocalAlloc");
  1112. }
  1113. CopyMemory(pbEncrypted, pbIn, cbIn);
  1114. if (!CryptEncrypt(
  1115. hKey,
  1116. NULL, // hHash
  1117. TRUE, // Final
  1118. 0, // dwFlags
  1119. pbEncrypted, // pbData
  1120. &cbEncrypted, // pdwDataLen
  1121. cbAlloc)) // dwBufLen
  1122. {
  1123. hr = myHLastError();
  1124. if (!fRetried && HRESULT_FROM_WIN32(ERROR_MORE_DATA) == hr)
  1125. {
  1126. SecureZeroMemory(pbEncrypted, cbAlloc); // only zero size we alloced last time around
  1127. LocalFree(pbEncrypted);
  1128. pbEncrypted = NULL;
  1129. DBGPRINT((
  1130. DBG_SS_CERTLIB,
  1131. "CryptEncrypt(MORE DATA): %u -> %u\n",
  1132. cbAlloc,
  1133. cbEncrypted));
  1134. cbAlloc = cbEncrypted;
  1135. fRetried = TRUE;
  1136. continue;
  1137. }
  1138. _JumpError(hr, error, "CryptEncrypt");
  1139. }
  1140. break;
  1141. }
  1142. *ppbEncrypted = pbEncrypted;
  1143. *pcbEncrypted = cbEncrypted;
  1144. pbEncrypted = NULL;
  1145. hr = S_OK;
  1146. error:
  1147. if (NULL != pbEncrypted)
  1148. {
  1149. LocalFree(pbEncrypted);
  1150. }
  1151. return(hr);
  1152. }
  1153. HRESULT
  1154. myCryptDecrypt(
  1155. IN HCRYPTKEY hKey,
  1156. IN BYTE const *pbIn,
  1157. IN DWORD cbIn,
  1158. OUT BYTE **ppbDecrypted,
  1159. OUT DWORD *pcbDecrypted)
  1160. {
  1161. HRESULT hr;
  1162. BYTE *pbDecrypted = NULL;
  1163. DWORD cbDecrypted;
  1164. // init
  1165. *ppbDecrypted = NULL;
  1166. *pcbDecrypted = 0;
  1167. cbDecrypted = cbIn;
  1168. pbDecrypted = (BYTE *) LocalAlloc(LMEM_FIXED, cbIn);
  1169. if (NULL == pbDecrypted)
  1170. {
  1171. hr = E_OUTOFMEMORY;
  1172. _JumpError(hr, error, "LocalAlloc");
  1173. }
  1174. CopyMemory(pbDecrypted, pbIn, cbIn);
  1175. if (!CryptDecrypt(
  1176. hKey,
  1177. NULL, // hHash
  1178. TRUE, // Final
  1179. 0, // dwFlags
  1180. pbDecrypted, // pbData
  1181. &cbDecrypted)) // pdwDataLen
  1182. {
  1183. hr = myHLastError();
  1184. _JumpError(hr, error, "CryptDecrypt");
  1185. }
  1186. *ppbDecrypted = pbDecrypted;
  1187. *pcbDecrypted = cbDecrypted;
  1188. pbDecrypted = NULL;
  1189. hr = S_OK;
  1190. error:
  1191. if (NULL != pbDecrypted)
  1192. {
  1193. LocalFree(pbDecrypted);
  1194. }
  1195. return(hr);
  1196. }
  1197. HRESULT
  1198. myCryptEncryptMessage(
  1199. IN ALG_ID algId,
  1200. IN DWORD cCertRecipient,
  1201. IN CERT_CONTEXT const **rgCertRecipient,
  1202. IN BYTE const *pbIn,
  1203. IN DWORD cbIn,
  1204. IN OPTIONAL HCRYPTPROV hCryptProv,
  1205. OUT BYTE **ppbEncrypted,
  1206. OUT DWORD *pcbEncrypted)
  1207. {
  1208. HRESULT hr;
  1209. CRYPT_ENCRYPT_MESSAGE_PARA cemp;
  1210. CRYPT_OID_INFO const *pOidInfo;
  1211. // Convert to an Object Id
  1212. pOidInfo = CryptFindOIDInfo(
  1213. CRYPT_OID_INFO_ALGID_KEY,
  1214. &algId,
  1215. CRYPT_ENCRYPT_ALG_OID_GROUP_ID);
  1216. if (NULL == pOidInfo)
  1217. {
  1218. // function is not doc'd to set GetLastError()
  1219. hr = CRYPT_E_NOT_FOUND;
  1220. DBGPRINT((DBG_SS_ERROR, "algId = %x\n", algId));
  1221. _JumpError(hr, error, "CryptFindOIDInfo");
  1222. }
  1223. // Encrypt the data with the public key
  1224. ZeroMemory(&cemp, sizeof(cemp));
  1225. cemp.cbSize = sizeof(cemp);
  1226. cemp.dwMsgEncodingType = PKCS_7_ASN_ENCODING | CRYPT_ASN_ENCODING;
  1227. cemp.ContentEncryptionAlgorithm.pszObjId = const_cast<char *>(pOidInfo->pszOID);
  1228. cemp.hCryptProv = hCryptProv;
  1229. *pcbEncrypted = 0;
  1230. for (;;)
  1231. {
  1232. if (!CryptEncryptMessage(
  1233. &cemp,
  1234. cCertRecipient, // cRecipientCert
  1235. rgCertRecipient, // rgpRecipientCert IN
  1236. pbIn, // pbToBeEncrypted
  1237. cbIn, // cbToBeEncrypted
  1238. *ppbEncrypted, // pbEncryptedBlob
  1239. pcbEncrypted)) // pcbEncryptedBlob
  1240. {
  1241. hr = myHLastError();
  1242. if (NULL != *ppbEncrypted)
  1243. {
  1244. LocalFree(*ppbEncrypted);
  1245. *ppbEncrypted = NULL;
  1246. }
  1247. _JumpError(hr, error, "CryptEncryptMessage");
  1248. }
  1249. if (NULL != *ppbEncrypted)
  1250. {
  1251. break;
  1252. }
  1253. *ppbEncrypted = (BYTE *) LocalAlloc(LMEM_FIXED, *pcbEncrypted);
  1254. if (NULL == *ppbEncrypted)
  1255. {
  1256. hr = E_OUTOFMEMORY;
  1257. _JumpError(hr, error, "LocalAlloc");
  1258. }
  1259. }
  1260. hr = S_OK;
  1261. error:
  1262. CSASSERT(S_OK == hr || FAILED(hr));
  1263. return(hr);
  1264. }
  1265. HRESULT
  1266. myCryptDecryptMessage(
  1267. IN HCERTSTORE hStore,
  1268. IN BYTE const *pbEncrypted,
  1269. IN DWORD cbEncrypted,
  1270. IN CERTLIB_ALLOCATOR allocType,
  1271. OUT BYTE **ppbDecrypted,
  1272. OUT DWORD *pcbDecrypted)
  1273. {
  1274. HRESULT hr;
  1275. CRYPT_DECRYPT_MESSAGE_PARA cdmp;
  1276. ZeroMemory(&cdmp, sizeof(cdmp));
  1277. cdmp.cbSize = sizeof(cdmp);
  1278. cdmp.dwMsgAndCertEncodingType = PKCS_7_ASN_ENCODING | X509_ASN_ENCODING;
  1279. cdmp.cCertStore = 1;
  1280. cdmp.rghCertStore = &hStore;
  1281. *ppbDecrypted = NULL;
  1282. *pcbDecrypted = 0;
  1283. for (;;)
  1284. {
  1285. if (!CryptDecryptMessage(
  1286. &cdmp,
  1287. pbEncrypted,
  1288. cbEncrypted,
  1289. *ppbDecrypted,
  1290. pcbDecrypted,
  1291. NULL)) // ppXchgCert
  1292. {
  1293. hr = myHLastError();
  1294. if (NULL != *ppbDecrypted)
  1295. {
  1296. myFree(*ppbDecrypted, allocType);
  1297. *ppbDecrypted = NULL;
  1298. }
  1299. _JumpError(hr, error, "CryptDecryptMessage");
  1300. }
  1301. if (NULL != *ppbDecrypted)
  1302. {
  1303. break;
  1304. }
  1305. *ppbDecrypted = (BYTE *) myAlloc(*pcbDecrypted, allocType);
  1306. if (NULL == *ppbDecrypted)
  1307. {
  1308. hr = E_OUTOFMEMORY;
  1309. _JumpError(hr, error, "myAlloc");
  1310. }
  1311. }
  1312. hr = S_OK;
  1313. error:
  1314. return(hr);
  1315. }
  1316. HRESULT
  1317. myGetInnerPKCS10(
  1318. IN HCRYPTMSG hMsg,
  1319. IN char const *pszInnerContentObjId,
  1320. OUT CERT_REQUEST_INFO **ppRequest)
  1321. {
  1322. HRESULT hr;
  1323. BYTE *pbContent = NULL;
  1324. DWORD cbContent;
  1325. CMC_DATA_INFO *pcmcData = NULL;
  1326. DWORD cbcmcData;
  1327. CMC_TAGGED_CERT_REQUEST const *pTaggedCertRequest;
  1328. DWORD cbRequest;
  1329. *ppRequest = NULL;
  1330. if (0 != strcmp(pszInnerContentObjId, szOID_CT_PKI_DATA))
  1331. {
  1332. hr = CRYPT_E_INVALID_MSG_TYPE;
  1333. _JumpError(hr, error, "Not a CMC request");
  1334. }
  1335. // Get the request content, then search for the PKCS10's public key.
  1336. hr = myCryptMsgGetParam(
  1337. hMsg,
  1338. CMSG_CONTENT_PARAM,
  1339. 0,
  1340. CERTLIB_USE_LOCALALLOC,
  1341. (VOID **) &pbContent,
  1342. &cbContent);
  1343. _JumpIfError(hr, error, "myCryptMsgGetParam");
  1344. if (!myDecodeObject(
  1345. X509_ASN_ENCODING,
  1346. CMC_DATA,
  1347. pbContent,
  1348. cbContent,
  1349. CERTLIB_USE_LOCALALLOC,
  1350. (VOID **) &pcmcData,
  1351. &cbcmcData))
  1352. {
  1353. hr = myHLastError();
  1354. _JumpError(hr, error, "myDecodeObject");
  1355. }
  1356. if (1 != pcmcData->cTaggedRequest ||
  1357. CMC_TAGGED_CERT_REQUEST_CHOICE !=
  1358. pcmcData->rgTaggedRequest[0].dwTaggedRequestChoice)
  1359. {
  1360. hr = CRYPT_E_INVALID_MSG_TYPE;
  1361. _JumpError(hr, error, "Must be 1 PKCS10");
  1362. }
  1363. pTaggedCertRequest = pcmcData->rgTaggedRequest[0].pTaggedCertRequest;
  1364. if (!myDecodeObject(
  1365. X509_ASN_ENCODING,
  1366. X509_CERT_REQUEST_TO_BE_SIGNED,
  1367. pTaggedCertRequest->SignedCertRequest.pbData,
  1368. pTaggedCertRequest->SignedCertRequest.cbData,
  1369. CERTLIB_USE_LOCALALLOC,
  1370. (VOID **) ppRequest,
  1371. &cbRequest))
  1372. {
  1373. hr = myHLastError();
  1374. _JumpError(hr, error, "myDecodeObject");
  1375. }
  1376. hr = S_OK;
  1377. error:
  1378. if (NULL != pbContent)
  1379. {
  1380. LocalFree(pbContent);
  1381. }
  1382. if (NULL != pcmcData)
  1383. {
  1384. LocalFree(pcmcData);
  1385. }
  1386. return(hr);
  1387. }
  1388. HRESULT
  1389. myPKCSEncodeString(
  1390. IN WCHAR const *pwsz,
  1391. OUT BYTE **ppbOut,
  1392. OUT DWORD *pcbOut)
  1393. {
  1394. HRESULT hr = S_OK;
  1395. CERT_NAME_VALUE cnv;
  1396. // encode the string as an IA5 string
  1397. cnv.dwValueType = CERT_RDN_IA5_STRING;
  1398. cnv.Value.pbData = (BYTE *) pwsz;
  1399. cnv.Value.cbData = 0; // Use L'\0' termination for the length
  1400. if (!myEncodeObject(
  1401. X509_ASN_ENCODING,
  1402. X509_UNICODE_NAME_VALUE,
  1403. &cnv,
  1404. 0,
  1405. CERTLIB_USE_LOCALALLOC,
  1406. ppbOut,
  1407. pcbOut))
  1408. {
  1409. hr = myHLastError();
  1410. _JumpError(hr, error, "myEncodeObject");
  1411. }
  1412. error:
  1413. return(hr);
  1414. }
  1415. HRESULT
  1416. myPKCSDecodeString(
  1417. IN BYTE const *pbIn,
  1418. IN DWORD cbIn,
  1419. OUT WCHAR **ppwszOut)
  1420. {
  1421. HRESULT hr = S_OK;
  1422. CERT_NAME_VALUE *pcnv = NULL;
  1423. DWORD cbOut;
  1424. *ppwszOut = NULL;
  1425. // decode the string from an IA5 string
  1426. if (!myDecodeObject(
  1427. X509_ASN_ENCODING,
  1428. X509_UNICODE_NAME_VALUE,
  1429. pbIn,
  1430. cbIn,
  1431. CERTLIB_USE_LOCALALLOC,
  1432. (VOID **) &pcnv,
  1433. &cbOut))
  1434. {
  1435. hr = myHLastError();
  1436. _JumpError(hr, error, "myDecodeObject");
  1437. }
  1438. if (CERT_RDN_IA5_STRING != pcnv->dwValueType)
  1439. {
  1440. hr = E_INVALIDARG;
  1441. _JumpError(hr, error, "Not an IA5 string");
  1442. }
  1443. cbOut = (wcslen((WCHAR const *) pcnv->Value.pbData) + 1) * sizeof(WCHAR);
  1444. *ppwszOut = (WCHAR *) LocalAlloc(LMEM_FIXED, cbOut);
  1445. if (NULL == *ppwszOut)
  1446. {
  1447. hr = E_OUTOFMEMORY;
  1448. _JumpError(hr, error, "LocalAlloc");
  1449. }
  1450. CopyMemory(*ppwszOut, pcnv->Value.pbData, cbOut);
  1451. error:
  1452. if (NULL != pcnv)
  1453. {
  1454. LocalFree(pcnv);
  1455. }
  1456. return(hr);
  1457. }
  1458. HRESULT
  1459. myPKCSEncodeLong(
  1460. IN LONG Value,
  1461. OUT BYTE **ppbOut,
  1462. OUT DWORD *pcbOut)
  1463. {
  1464. HRESULT hr = S_OK;
  1465. // encode the long value
  1466. if (!myEncodeObject(
  1467. X509_ASN_ENCODING,
  1468. X509_INTEGER,
  1469. &Value,
  1470. 0,
  1471. CERTLIB_USE_LOCALALLOC,
  1472. ppbOut,
  1473. pcbOut))
  1474. {
  1475. hr = myHLastError();
  1476. _JumpError(hr, error, "myEncodeObject");
  1477. }
  1478. error:
  1479. return(hr);
  1480. }
  1481. HRESULT
  1482. myPKCSDecodeLong(
  1483. IN BYTE const *pbIn,
  1484. IN DWORD cbIn,
  1485. OUT LONG **ppValue)
  1486. {
  1487. HRESULT hr = S_OK;
  1488. DWORD cbOut;
  1489. // encode the long value
  1490. if (!myDecodeObject(
  1491. X509_ASN_ENCODING,
  1492. X509_INTEGER,
  1493. pbIn,
  1494. cbIn,
  1495. CERTLIB_USE_LOCALALLOC,
  1496. (VOID **) ppValue,
  1497. &cbOut))
  1498. {
  1499. hr = myHLastError();
  1500. _JumpError(hr, error, "myDecodeObject");
  1501. }
  1502. CSASSERT(sizeof(**ppValue) == cbOut);
  1503. error:
  1504. return(hr);
  1505. }
  1506. HRESULT
  1507. myPKCSEncodeDate(
  1508. IN FILETIME const *pft,
  1509. OUT BYTE **ppbOut,
  1510. OUT DWORD *pcbOut)
  1511. {
  1512. HRESULT hr = S_OK;
  1513. // encode the time value
  1514. if (!myEncodeObject(
  1515. X509_ASN_ENCODING,
  1516. X509_CHOICE_OF_TIME,
  1517. pft,
  1518. 0,
  1519. CERTLIB_USE_LOCALALLOC,
  1520. ppbOut,
  1521. pcbOut))
  1522. {
  1523. hr = myHLastError();
  1524. _JumpError(hr, error, "myEncodeObject");
  1525. }
  1526. error:
  1527. return(hr);
  1528. }
  1529. HRESULT
  1530. myPKCSDecodeDate(
  1531. IN BYTE const *pbIn,
  1532. IN DWORD cbIn,
  1533. OUT FILETIME **ppftOut)
  1534. {
  1535. HRESULT hr = S_OK;
  1536. DWORD cbOut;
  1537. // encode the time value
  1538. if (!myDecodeObject(
  1539. X509_ASN_ENCODING,
  1540. X509_CHOICE_OF_TIME,
  1541. pbIn,
  1542. cbIn,
  1543. CERTLIB_USE_LOCALALLOC,
  1544. (VOID **) ppftOut,
  1545. &cbOut))
  1546. {
  1547. hr = myHLastError();
  1548. _JumpError(hr, error, "myDecodeObject");
  1549. }
  1550. CSASSERT(sizeof(**ppftOut) == cbOut);
  1551. error:
  1552. return(hr);
  1553. }
  1554. HRESULT
  1555. myEncodeExtension(
  1556. IN DWORD Flags,
  1557. IN BYTE const *pbIn,
  1558. IN DWORD cbIn,
  1559. OUT BYTE **ppbOut,
  1560. OUT DWORD *pcbOut)
  1561. {
  1562. HRESULT hr = E_INVALIDARG;
  1563. // everyone assumes pbIn != NULL
  1564. if (NULL == pbIn || 0 == cbIn)
  1565. {
  1566. _JumpError(hr, error, "NULL param");
  1567. }
  1568. switch (PROPTYPE_MASK & Flags)
  1569. {
  1570. case PROPTYPE_STRING:
  1571. if (0 == (PROPMARSHAL_LOCALSTRING & Flags) &&
  1572. sizeof(WCHAR) <= cbIn)
  1573. {
  1574. cbIn -= sizeof(WCHAR);
  1575. }
  1576. if (wcslen((WCHAR const *) pbIn) * sizeof(WCHAR) != cbIn)
  1577. {
  1578. _JumpError(hr, error, "bad string len");
  1579. }
  1580. hr = myPKCSEncodeString((WCHAR const *) pbIn, ppbOut, pcbOut);
  1581. _JumpIfError(hr, error, "myPKCSEncodeString");
  1582. break;
  1583. case PROPTYPE_LONG:
  1584. CSASSERT(sizeof(DWORD) == cbIn);
  1585. hr = myPKCSEncodeLong(*(DWORD const *) pbIn, ppbOut, pcbOut);
  1586. _JumpIfError(hr, error, "myPKCSEncodeLong");
  1587. break;
  1588. case PROPTYPE_DATE:
  1589. CSASSERT(sizeof(FILETIME) == cbIn);
  1590. hr = myPKCSEncodeDate((FILETIME const *) pbIn, ppbOut, pcbOut);
  1591. _JumpIfError(hr, error, "myPKCSEncodeDate");
  1592. break;
  1593. default:
  1594. _JumpError(hr, error, "variant type/value");
  1595. }
  1596. hr = S_OK;
  1597. error:
  1598. return(hr);
  1599. }
  1600. HRESULT
  1601. myDecodeExtension(
  1602. IN DWORD Flags,
  1603. IN BYTE const *pbIn,
  1604. IN DWORD cbIn,
  1605. OUT BYTE **ppbOut,
  1606. OUT DWORD *pcbOut)
  1607. {
  1608. HRESULT hr;
  1609. switch (PROPTYPE_MASK & Flags)
  1610. {
  1611. case PROPTYPE_STRING:
  1612. hr = myPKCSDecodeString(pbIn, cbIn, (WCHAR **) ppbOut);
  1613. _JumpIfError(hr, error, "myPKCSDecodeString");
  1614. *pcbOut = wcslen((WCHAR const *) *ppbOut) * sizeof(WCHAR);
  1615. break;
  1616. case PROPTYPE_LONG:
  1617. hr = myPKCSDecodeLong(pbIn, cbIn, (LONG **) ppbOut);
  1618. _JumpIfError(hr, error, "myPKCSDecodeLong");
  1619. *pcbOut = sizeof(LONG);
  1620. break;
  1621. case PROPTYPE_DATE:
  1622. hr = myPKCSDecodeDate(pbIn, cbIn, (FILETIME **) ppbOut);
  1623. _JumpIfError(hr, error, "myPKCSDecodeDate");
  1624. *pcbOut = sizeof(FILETIME);
  1625. break;
  1626. default:
  1627. hr = E_INVALIDARG;
  1628. _JumpError(hr, error, "Flags: Invalid type");
  1629. }
  1630. error:
  1631. return(hr);
  1632. }
  1633. // szOID_ENROLLMENT_NAME_VALUE_PAIR
  1634. BOOL
  1635. myDecodeNameValuePair(
  1636. IN DWORD dwEncodingType,
  1637. IN BYTE const *pbEncoded,
  1638. IN DWORD cbEncoded,
  1639. IN CERTLIB_ALLOCATOR allocType,
  1640. OUT CRYPT_ENROLLMENT_NAME_VALUE_PAIR **ppInfo,
  1641. OUT DWORD *pcbInfo)
  1642. {
  1643. return(myDecodeObject(
  1644. dwEncodingType,
  1645. szOID_ENROLLMENT_NAME_VALUE_PAIR,
  1646. pbEncoded,
  1647. cbEncoded,
  1648. allocType,
  1649. (VOID **) ppInfo,
  1650. pcbInfo));
  1651. }
  1652. //+-------------------------------------------------------------------------
  1653. // myVerifyObjIdA - verify the passed pszObjId is valid as per X.208
  1654. //
  1655. // Encode and Decode the Object Id and make sure it survives the round trip.
  1656. // The first number must be 0, 1 or 2.
  1657. // Enforce all characters are digits and dots.
  1658. // Enforce that no dot starts or ends the Object Id, and disallow double dots.
  1659. // Enforce there is at least one dot separator.
  1660. // If the first number is 0 or 1, the second number must be between 0 & 39.
  1661. // If the first number is 2, the second number can be any value.
  1662. //--------------------------------------------------------------------------
  1663. HRESULT
  1664. myVerifyObjIdA(
  1665. IN CHAR const *pszObjId)
  1666. {
  1667. HRESULT hr;
  1668. BYTE *pbEncoded = NULL;
  1669. DWORD cbEncoded;
  1670. CRYPT_ATTRIBUTE ainfo;
  1671. CRYPT_ATTRIBUTE *painfo = NULL;
  1672. DWORD cbainfo;
  1673. char const *psz;
  1674. int i;
  1675. BOOL fNoisy = FALSE;
  1676. hr = E_INVALIDARG;
  1677. for (psz = pszObjId; '\0' != *psz; psz++)
  1678. {
  1679. // must be a digit or a dot separator
  1680. if (!isdigit(*psz))
  1681. {
  1682. if ('.' != *psz)
  1683. {
  1684. _JumpError2(hr, error, "bad ObjId: bad char", hr);
  1685. }
  1686. // can't have dot at start, double dots or dot at end
  1687. if (psz == pszObjId || '.' == psz[1] || '\0' == psz[1])
  1688. {
  1689. _JumpError2(hr, error, "bad ObjId: dot location", hr);
  1690. }
  1691. }
  1692. }
  1693. psz = strchr(pszObjId, '.');
  1694. if (NULL == psz)
  1695. {
  1696. _JumpError2(hr, error, "bad ObjId: must have at least one dot", hr);
  1697. }
  1698. i = atoi(pszObjId);
  1699. switch (i)
  1700. {
  1701. case 0:
  1702. case 1:
  1703. i = atoi(++psz);
  1704. if (0 > i || 39 < i)
  1705. {
  1706. _JumpError(hr, error, "bad ObjId: 0. or 1. must be followed by 0..39");
  1707. }
  1708. break;
  1709. case 2:
  1710. break;
  1711. default:
  1712. fNoisy = TRUE;
  1713. _JumpError(hr, error, "bad ObjId: must start with 0, 1 or 2");
  1714. }
  1715. fNoisy = TRUE;
  1716. ainfo.pszObjId = const_cast<char *>(pszObjId);
  1717. ainfo.cValue = 0;
  1718. ainfo.rgValue = NULL;
  1719. if (!myEncodeObject(
  1720. X509_ASN_ENCODING,
  1721. PKCS_ATTRIBUTE,
  1722. &ainfo,
  1723. 0,
  1724. CERTLIB_USE_LOCALALLOC,
  1725. &pbEncoded,
  1726. &cbEncoded))
  1727. {
  1728. hr = myHLastError();
  1729. _JumpError(hr, error, "myEncodeObject");
  1730. }
  1731. if (!myDecodeObject(
  1732. X509_ASN_ENCODING,
  1733. PKCS_ATTRIBUTE,
  1734. pbEncoded,
  1735. cbEncoded,
  1736. CERTLIB_USE_LOCALALLOC,
  1737. (VOID **) &painfo,
  1738. &cbainfo))
  1739. {
  1740. hr = myHLastError();
  1741. _JumpError(hr, error, "myDecodeObject");
  1742. }
  1743. if (0 != strcmp(pszObjId, painfo->pszObjId))
  1744. {
  1745. hr = E_INVALIDARG;
  1746. _JumpError(hr, error, "bad ObjId: decode mismatch");
  1747. }
  1748. hr = S_OK;
  1749. error:
  1750. if (S_OK != hr)
  1751. {
  1752. DBGPRINT((
  1753. fNoisy? DBG_SS_CERTLIB : DBG_SS_CERTLIBI,
  1754. "myVerifyObjIdA(%hs): %x\n",
  1755. pszObjId,
  1756. hr));
  1757. }
  1758. if (NULL != pbEncoded)
  1759. {
  1760. LocalFree(pbEncoded);
  1761. }
  1762. if (NULL != painfo)
  1763. {
  1764. LocalFree(painfo);
  1765. }
  1766. return(hr);
  1767. }
  1768. HRESULT
  1769. myVerifyObjId(
  1770. IN WCHAR const *pwszObjId)
  1771. {
  1772. HRESULT hr;
  1773. CHAR *pszObjId = NULL;
  1774. if (!ConvertWszToSz(&pszObjId, pwszObjId, -1))
  1775. {
  1776. hr = E_OUTOFMEMORY;
  1777. _JumpError(hr, error, "ConvertWszToSz");
  1778. }
  1779. hr = myVerifyObjIdA(pszObjId);
  1780. _JumpIfErrorStr2(hr, error, "myVerifyObjIdA", pwszObjId, E_INVALIDARG);
  1781. error:
  1782. if (NULL != pszObjId)
  1783. {
  1784. LocalFree(pszObjId);
  1785. }
  1786. return(hr);
  1787. }
  1788. // The returned pszObjId is a constant that must not be freed. CryptFindOIDInfo
  1789. // has a static internal database that is valid until crypt32.dll is unloaded.
  1790. #define GON_GROUP 0x00000001
  1791. #define GON_GENERIC 0x00000002
  1792. typedef struct _OIDNAME
  1793. {
  1794. char const *pszObjId;
  1795. WCHAR const *pwszDisplayName;
  1796. } OIDNAME;
  1797. #if DBG
  1798. #define wszCERTLIB L"(certlib)"
  1799. #else
  1800. #define wszCERTLIB L""
  1801. #endif
  1802. OIDNAME s_aOIDName[] = {
  1803. { szOID_CT_PKI_DATA, L"CMC Data" wszCERTLIB, },
  1804. { szOID_CT_PKI_RESPONSE, L"CMC Response" wszCERTLIB, },
  1805. { szOID_CMC, L"Unsigned CMC Request" wszCERTLIB, },
  1806. { szOID_CMC_TRANSACTION_ID, L"Transaction Id" wszCERTLIB, },
  1807. { szOID_CMC_SENDER_NONCE, L"Sender Nonce" wszCERTLIB, },
  1808. { szOID_CMC_RECIPIENT_NONCE, L"Recipient Nonce" wszCERTLIB, },
  1809. { szOID_CMC_REG_INFO, L"Reg Info" wszCERTLIB, },
  1810. { szOID_CMC_GET_CERT, L"Get Certificate" wszCERTLIB, },
  1811. { szOID_CMC_GET_CRL, L"Get CRL" wszCERTLIB, },
  1812. { szOID_CMC_REVOKE_REQUEST, L"Revoke Request" wszCERTLIB, },
  1813. { szOID_CMC_QUERY_PENDING, L"Query Pending" wszCERTLIB, },
  1814. { szOID_CMC_ID_CONFIRM_CERT_ACCEPTANCE, L"Confirm Certificate Acceptance" wszCERTLIB, },
  1815. { szOID_CMC_STATUS_INFO, L"Unsigned CMC Response" wszCERTLIB, },
  1816. { szOID_CMC_ADD_EXTENSIONS, L"CMC Extensions" wszCERTLIB, },
  1817. { szOID_CMC_ADD_ATTRIBUTES, L"CMC Attributes" wszCERTLIB, },
  1818. { szOID_VERISIGN_ONSITE_JURISDICTION_HASH, L"Jurisdiction Hash" wszCERTLIB, },
  1819. { szOID_PKCS_7_DATA, L"PKCS 7 Data" wszCERTLIB, },
  1820. { szOID_ARCHIVED_KEY_ATTR, L"Archived Key" wszCERTLIB, },
  1821. { szOID_CTL, L"Certifcate Trust List" wszCERTLIB, },
  1822. { szOID_ARCHIVED_KEY_CERT_HASH, L"Archived Key Certificate Hash" wszCERTLIB, },
  1823. { szOID_ROOT_LIST_SIGNER, L"Root List Signer" wszCERTLIB, },
  1824. { szOID_PRIVATEKEY_USAGE_PERIOD, L"Private Key Usage Period" wszCERTLIB, },
  1825. { szOID_REQUEST_CLIENT_INFO, L"Client Information" wszCERTLIB, },
  1826. { szOID_NTDS_REPLICATION, L"DS object Guid" wszCERTLIB, },
  1827. { szOID_CERTSRV_CROSSCA_VERSION, L"Cross CA Version" wszCERTLIB, },
  1828. };
  1829. WCHAR const *
  1830. myGetOIDNameA(
  1831. IN char const *pszObjId)
  1832. {
  1833. CRYPT_OID_INFO const *pInfo = NULL;
  1834. WCHAR const *pwszName = L"";
  1835. DWORD Flags = GON_GROUP | GON_GENERIC;
  1836. if ('+' == *pszObjId)
  1837. {
  1838. Flags = GON_GROUP; // Group lookup only
  1839. pszObjId++;
  1840. }
  1841. else
  1842. if ('-' == *pszObjId)
  1843. {
  1844. Flags = GON_GENERIC; // Generic lookup only
  1845. pszObjId++;
  1846. }
  1847. // First try looking up the ObjectId as an Extension or Attribute, because
  1848. // we get a better Display Name, especially for Subject RDNs: CN, L, etc.
  1849. // If that fails, look it up without restricting the group.
  1850. if (GON_GROUP & Flags)
  1851. {
  1852. pInfo = CryptFindOIDInfo(
  1853. CRYPT_OID_INFO_OID_KEY,
  1854. (VOID *) pszObjId,
  1855. CRYPT_EXT_OR_ATTR_OID_GROUP_ID);
  1856. }
  1857. if ((GON_GENERIC & Flags) &&
  1858. (NULL == pInfo ||
  1859. NULL == pInfo->pwszName ||
  1860. L'\0' == pInfo->pwszName[0]))
  1861. {
  1862. pInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, (VOID *) pszObjId, 0);
  1863. }
  1864. if (NULL != pInfo && NULL != pInfo->pwszName && L'\0' != pInfo->pwszName[0])
  1865. {
  1866. pwszName = pInfo->pwszName;
  1867. }
  1868. else
  1869. {
  1870. OIDNAME const *pOIDName;
  1871. for (pOIDName = s_aOIDName;
  1872. pOIDName < &s_aOIDName[ARRAYSIZE(s_aOIDName)];
  1873. pOIDName++)
  1874. {
  1875. if (0 == strcmp(pOIDName->pszObjId, pszObjId))
  1876. {
  1877. pwszName = pOIDName->pwszDisplayName;
  1878. break;
  1879. }
  1880. }
  1881. }
  1882. return(pwszName);
  1883. }
  1884. WCHAR const *
  1885. myGetOIDName(
  1886. IN WCHAR const *pwszObjId)
  1887. {
  1888. char *pszObjId = NULL;
  1889. WCHAR const *pwszName = L"";
  1890. if (!ConvertWszToSz(&pszObjId, pwszObjId, -1))
  1891. {
  1892. _JumpError(E_OUTOFMEMORY, error, "ConvertWszToSz");
  1893. }
  1894. pwszName = myGetOIDNameA(pszObjId);
  1895. error:
  1896. if (NULL != pszObjId)
  1897. {
  1898. LocalFree(pszObjId);
  1899. }
  1900. return(pwszName);
  1901. }
  1902. typedef struct _DUMPFLAGS
  1903. {
  1904. DWORD Mask;
  1905. DWORD Value;
  1906. WCHAR const *pwszDescription;
  1907. } DUMPFLAGS;
  1908. #define _DFBIT(def) { (def), (def), L#def }
  1909. #define _DFBIT2(mask, def) { (mask), (def), L#def }
  1910. DUMPFLAGS g_adfErrorStatus[] =
  1911. {
  1912. _DFBIT(CERT_TRUST_IS_NOT_TIME_VALID),
  1913. _DFBIT(CERT_TRUST_IS_NOT_TIME_NESTED),
  1914. _DFBIT(CERT_TRUST_IS_REVOKED),
  1915. _DFBIT(CERT_TRUST_IS_NOT_SIGNATURE_VALID),
  1916. _DFBIT(CERT_TRUST_IS_NOT_VALID_FOR_USAGE),
  1917. _DFBIT(CERT_TRUST_IS_UNTRUSTED_ROOT),
  1918. _DFBIT(CERT_TRUST_REVOCATION_STATUS_UNKNOWN),
  1919. _DFBIT(CERT_TRUST_IS_CYCLIC),
  1920. _DFBIT(CERT_TRUST_INVALID_EXTENSION),
  1921. _DFBIT(CERT_TRUST_INVALID_POLICY_CONSTRAINTS),
  1922. _DFBIT(CERT_TRUST_INVALID_BASIC_CONSTRAINTS),
  1923. _DFBIT(CERT_TRUST_INVALID_NAME_CONSTRAINTS),
  1924. _DFBIT(CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT),
  1925. _DFBIT(CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT),
  1926. _DFBIT(CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT),
  1927. _DFBIT(CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT),
  1928. _DFBIT(CERT_TRUST_IS_OFFLINE_REVOCATION),
  1929. _DFBIT(CERT_TRUST_NO_ISSUANCE_CHAIN_POLICY),
  1930. _DFBIT(CERT_TRUST_IS_PARTIAL_CHAIN),
  1931. _DFBIT(CERT_TRUST_CTL_IS_NOT_TIME_VALID),
  1932. _DFBIT(CERT_TRUST_CTL_IS_NOT_SIGNATURE_VALID),
  1933. _DFBIT(CERT_TRUST_CTL_IS_NOT_VALID_FOR_USAGE),
  1934. { 0, 0, NULL }
  1935. };
  1936. DUMPFLAGS g_adfInfoStatus[] =
  1937. {
  1938. _DFBIT(CERT_TRUST_HAS_EXACT_MATCH_ISSUER),
  1939. _DFBIT(CERT_TRUST_HAS_KEY_MATCH_ISSUER),
  1940. _DFBIT(CERT_TRUST_HAS_NAME_MATCH_ISSUER),
  1941. _DFBIT(CERT_TRUST_IS_SELF_SIGNED),
  1942. _DFBIT(CERT_TRUST_HAS_PREFERRED_ISSUER),
  1943. _DFBIT(CERT_TRUST_HAS_ISSUANCE_CHAIN_POLICY),
  1944. _DFBIT(CERT_TRUST_HAS_VALID_NAME_CONSTRAINTS),
  1945. _DFBIT(CERT_TRUST_IS_COMPLEX_CHAIN),
  1946. { 0, 0, NULL }
  1947. };
  1948. DUMPFLAGS g_adfChainFlags[] =
  1949. {
  1950. _DFBIT(CERT_CHAIN_CACHE_END_CERT),
  1951. _DFBIT(CERT_CHAIN_THREAD_STORE_SYNC),
  1952. _DFBIT(CERT_CHAIN_CACHE_ONLY_URL_RETRIEVAL),
  1953. _DFBIT(CERT_CHAIN_USE_LOCAL_MACHINE_STORE),
  1954. _DFBIT(CERT_CHAIN_ENABLE_CACHE_AUTO_UPDATE),
  1955. _DFBIT(CERT_CHAIN_ENABLE_SHARE_STORE),
  1956. _DFBIT(CERT_CHAIN_DISABLE_PASS1_QUALITY_FILTERING),
  1957. _DFBIT(CERT_CHAIN_RETURN_LOWER_QUALITY_CONTEXTS),
  1958. _DFBIT(CERT_CHAIN_DISABLE_AUTH_ROOT_AUTO_UPDATE),
  1959. _DFBIT(CERT_CHAIN_TIMESTAMP_TIME),
  1960. _DFBIT(CERT_CHAIN_REVOCATION_ACCUMULATIVE_TIMEOUT),
  1961. _DFBIT(CERT_CHAIN_REVOCATION_CHECK_END_CERT),
  1962. _DFBIT(CERT_CHAIN_REVOCATION_CHECK_CHAIN),
  1963. _DFBIT(CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT),
  1964. _DFBIT(CERT_CHAIN_REVOCATION_CHECK_CACHE_ONLY),
  1965. { 0, 0, NULL }
  1966. };
  1967. DUMPFLAGS g_adfVerifyFlags[] =
  1968. {
  1969. _DFBIT(CA_VERIFY_FLAGS_ALLOW_UNTRUSTED_ROOT),
  1970. _DFBIT(CA_VERIFY_FLAGS_IGNORE_OFFLINE),
  1971. _DFBIT(CA_VERIFY_FLAGS_NO_REVOCATION),
  1972. _DFBIT(CA_VERIFY_FLAGS_FULL_CHAIN_REVOCATION),
  1973. _DFBIT(CA_VERIFY_FLAGS_NT_AUTH),
  1974. _DFBIT(CA_VERIFY_FLAGS_IGNORE_INVALID_POLICIES),
  1975. _DFBIT(CA_VERIFY_FLAGS_IGNORE_NOREVCHECK),
  1976. _DFBIT(CA_VERIFY_FLAGS_DUMP_CHAIN),
  1977. _DFBIT(CA_VERIFY_FLAGS_SAVE_CHAIN),
  1978. { 0, 0, NULL }
  1979. };
  1980. VOID
  1981. DumpFlags(
  1982. IN DWORD Flags,
  1983. IN WCHAR const *pwsz,
  1984. IN DUMPFLAGS const *pdf)
  1985. {
  1986. for ( ; NULL != pdf->pwszDescription; pdf++)
  1987. {
  1988. if ((Flags & pdf->Mask) == pdf->Value)
  1989. {
  1990. CONSOLEPRINT3((
  1991. MAXDWORD,
  1992. "%ws = %ws (0x%x)\n",
  1993. pwsz,
  1994. pdf->pwszDescription,
  1995. pdf->Value));
  1996. }
  1997. }
  1998. }
  1999. VOID
  2000. DumpUsage(
  2001. IN WCHAR const *pwsz,
  2002. OPTIONAL IN CERT_ENHKEY_USAGE const *pUsage)
  2003. {
  2004. DWORD i;
  2005. if (NULL != pUsage)
  2006. {
  2007. for (i = 0; i < pUsage->cUsageIdentifier; i++)
  2008. {
  2009. CONSOLEPRINT4((
  2010. MAXDWORD,
  2011. "%ws[%u] = %hs %ws\n",
  2012. pwsz,
  2013. i,
  2014. pUsage->rgpszUsageIdentifier[i],
  2015. myGetOIDNameA(pUsage->rgpszUsageIdentifier[i])));
  2016. }
  2017. }
  2018. }
  2019. HRESULT
  2020. WriteBlob(
  2021. IN FILE *pf,
  2022. IN BYTE const *pb,
  2023. IN DWORD cb,
  2024. IN DWORD Flags)
  2025. {
  2026. HRESULT hr;
  2027. char *pszBase64 = NULL;
  2028. hr = myCryptBinaryToStringA(
  2029. pb,
  2030. cb,
  2031. Flags | CRYPT_STRING_NOCR,
  2032. &pszBase64);
  2033. _JumpIfError(hr, error, "myCryptBinaryToStringA");
  2034. fputs(pszBase64, pf);
  2035. fflush(pf);
  2036. if (ferror(pf))
  2037. {
  2038. hr = HRESULT_FROM_WIN32(ERROR_DISK_FULL);
  2039. _JumpError(hr, error, "fputs");
  2040. }
  2041. hr = S_OK;
  2042. error:
  2043. if (NULL != pszBase64)
  2044. {
  2045. LocalFree(pszBase64);
  2046. }
  2047. return(hr);
  2048. }
  2049. DWORD
  2050. myCRLNumber(
  2051. IN CRL_CONTEXT const *pCRL)
  2052. {
  2053. HRESULT hr;
  2054. CERT_EXTENSION const *pExt;
  2055. DWORD CRLNumber = 0;
  2056. DWORD dw;
  2057. DWORD cb;
  2058. pExt = CertFindExtension(
  2059. szOID_CRL_NUMBER,
  2060. pCRL->pCrlInfo->cExtension,
  2061. pCRL->pCrlInfo->rgExtension);
  2062. if (NULL == pExt)
  2063. {
  2064. // This API doesn't set LastError
  2065. hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  2066. _JumpError(hr, error, "CertFindExtension(CRLNumber)");
  2067. }
  2068. cb = sizeof(dw);
  2069. dw = 0;
  2070. if (!CryptDecodeObject(
  2071. X509_ASN_ENCODING,
  2072. X509_INTEGER,
  2073. pExt->Value.pbData,
  2074. pExt->Value.cbData,
  2075. 0,
  2076. &dw,
  2077. &cb))
  2078. {
  2079. hr = myHLastError();
  2080. _JumpError(hr, error, "CryptDecodeObject");
  2081. }
  2082. CRLNumber = dw;
  2083. error:
  2084. return(CRLNumber);
  2085. }
  2086. VOID
  2087. WriteChain(
  2088. IN CERT_SIMPLE_CHAIN const *pChain,
  2089. IN DWORD SaveIndex,
  2090. IN DWORD ChainIndex)
  2091. {
  2092. HRESULT hr;
  2093. #define szCHAINFORMAT "Chain%d_%d.txt"
  2094. char szPath[MAX_PATH + ARRAYSIZE(szCHAINFORMAT) + 2 * cwcDWORDSPRINTF];
  2095. DWORD i;
  2096. FILE *pf = NULL;
  2097. DWORD cch;
  2098. cch = GetEnvironmentVariableA("temp", szPath, MAX_PATH);
  2099. if (0 == cch || MAX_PATH <= cch)
  2100. {
  2101. strcpy(szPath, "\\");
  2102. }
  2103. i = strlen(szPath);
  2104. if (0 == i || '\\' != szPath[i - 1])
  2105. {
  2106. szPath[i++] = '\\';
  2107. }
  2108. sprintf(&szPath[i], szCHAINFORMAT, SaveIndex, ChainIndex);
  2109. pf = fopen(szPath, "w");
  2110. if (NULL == pf)
  2111. {
  2112. hr = errno;
  2113. _JumpError(hr, error, "fopen");
  2114. }
  2115. for (i = 0; i < pChain->cElement; i++)
  2116. {
  2117. CERT_CHAIN_ELEMENT const *pElement = pChain->rgpElement[i];
  2118. CERT_REVOCATION_INFO *pRevocationInfo;
  2119. if (0 < i)
  2120. {
  2121. fputs("\n", pf);
  2122. }
  2123. fprintf(pf, "Certificate %d:\n", i);
  2124. hr = WriteBlob(
  2125. pf,
  2126. pElement->pCertContext->pbCertEncoded,
  2127. pElement->pCertContext->cbCertEncoded,
  2128. CRYPT_STRING_BASE64HEADER);
  2129. _JumpIfError(hr, error, "WriteBlob");
  2130. pRevocationInfo = pElement->pRevocationInfo;
  2131. if (NULL != pRevocationInfo &&
  2132. CCSIZEOF_STRUCT(CERT_REVOCATION_INFO, pCrlInfo) <=
  2133. pRevocationInfo->cbSize &&
  2134. NULL != pRevocationInfo->pCrlInfo)
  2135. {
  2136. CERT_REVOCATION_CRL_INFO *pCrlInfo;
  2137. pCrlInfo = pRevocationInfo->pCrlInfo;
  2138. if (NULL != pCrlInfo)
  2139. {
  2140. if (NULL != pCrlInfo->pBaseCrlContext)
  2141. {
  2142. fprintf(
  2143. pf,
  2144. "\nCRL %u:\n",
  2145. myCRLNumber(pCrlInfo->pBaseCrlContext));
  2146. hr = WriteBlob(
  2147. pf,
  2148. pCrlInfo->pBaseCrlContext->pbCrlEncoded,
  2149. pCrlInfo->pBaseCrlContext->cbCrlEncoded,
  2150. CRYPT_STRING_BASE64X509CRLHEADER);
  2151. _JumpIfError(hr, error, "WriteBlob");
  2152. }
  2153. if (NULL != pCrlInfo->pDeltaCrlContext)
  2154. {
  2155. fprintf(
  2156. pf,
  2157. "\nDelta CRL %u:\n",
  2158. myCRLNumber(pCrlInfo->pDeltaCrlContext));
  2159. hr = WriteBlob(
  2160. pf,
  2161. pCrlInfo->pDeltaCrlContext->pbCrlEncoded,
  2162. pCrlInfo->pDeltaCrlContext->cbCrlEncoded,
  2163. CRYPT_STRING_BASE64X509CRLHEADER);
  2164. _JumpIfError(hr, error, "WriteBlob");
  2165. }
  2166. }
  2167. }
  2168. }
  2169. error:
  2170. if (NULL != pf)
  2171. {
  2172. fclose(pf);
  2173. }
  2174. }
  2175. HRESULT
  2176. DumpChainOpenHash(
  2177. OUT HCRYPTPROV *phProv,
  2178. OUT HCRYPTHASH *phHash)
  2179. {
  2180. HRESULT hr;
  2181. *phProv = NULL;
  2182. *phHash = NULL;
  2183. if (!CryptAcquireContext(
  2184. phProv,
  2185. NULL, // container
  2186. MS_DEF_PROV,
  2187. PROV_RSA_FULL,
  2188. CRYPT_VERIFYCONTEXT))
  2189. {
  2190. *phProv = NULL;
  2191. hr = myHLastError();
  2192. _JumpError(hr, error, "CryptAcquireContext");
  2193. }
  2194. if (!CryptCreateHash(*phProv, CALG_SHA1, 0, 0, phHash))
  2195. {
  2196. *phHash = NULL;
  2197. hr = myHLastError();
  2198. _JumpError(hr, error, "CryptCreateHash");
  2199. }
  2200. hr = S_OK;
  2201. error:
  2202. if (S_OK != hr && NULL != *phProv)
  2203. {
  2204. if (!CryptReleaseContext(*phProv, 0))
  2205. {
  2206. HRESULT hr2 = myHLastError();
  2207. _PrintError(hr, "CryptReleaseContext");
  2208. if (hr == S_OK)
  2209. {
  2210. hr = hr2;
  2211. }
  2212. }
  2213. *phProv = NULL;
  2214. }
  2215. return(hr);
  2216. }
  2217. VOID
  2218. DumpChainName(
  2219. IN char const *pszType,
  2220. IN CERT_NAME_BLOB const *pName)
  2221. {
  2222. HRESULT hr;
  2223. WCHAR *pwsz;
  2224. pwsz = NULL;
  2225. hr = myCertNameToStr(
  2226. X509_ASN_ENCODING,
  2227. pName,
  2228. CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
  2229. &pwsz);
  2230. _PrintIfError(hr, "myCertNameToStr");
  2231. if (NULL != pwsz)
  2232. {
  2233. CONSOLEPRINT2((MAXDWORD, "%hs: %ws\n", pszType, pwsz));
  2234. LocalFree(pwsz);
  2235. }
  2236. }
  2237. HRESULT
  2238. DumpChainSerial(
  2239. IN char const *pszType,
  2240. IN CRYPT_INTEGER_BLOB const *pSerial)
  2241. {
  2242. HRESULT hr;
  2243. BSTR strSerial = NULL;
  2244. hr = MultiByteIntegerToBstr(
  2245. FALSE,
  2246. pSerial->cbData,
  2247. pSerial->pbData,
  2248. &strSerial);
  2249. _JumpIfError(hr, error, "MultiByteIntegerToBstr");
  2250. CONSOLEPRINT2((MAXDWORD, "%hs: %ws\n", pszType, strSerial));
  2251. error:
  2252. if (NULL != strSerial)
  2253. {
  2254. SysFreeString(strSerial);
  2255. }
  2256. return(hr);
  2257. }
  2258. HRESULT
  2259. DumpChainHash(
  2260. IN BYTE const *pbHash,
  2261. IN DWORD cbHash)
  2262. {
  2263. HRESULT hr;
  2264. WCHAR wszHash[CBMAX_CRYPT_HASH_LEN * 3];
  2265. DWORD cbwszHash;
  2266. cbwszHash = sizeof(wszHash);
  2267. hr = MultiByteIntegerToWszBuf(
  2268. TRUE, // byte multiple
  2269. cbHash,
  2270. pbHash,
  2271. &cbwszHash,
  2272. wszHash);
  2273. _JumpIfError(hr, error, "MultiByteIntegerToWszBuf");
  2274. CONSOLEPRINT1((MAXDWORD, " %ws\n", wszHash));
  2275. hr = S_OK;
  2276. error:
  2277. return(hr);
  2278. }
  2279. HRESULT
  2280. DumpChainAddHash(
  2281. IN OPTIONAL HCRYPTHASH hHash,
  2282. IN BYTE const *pb,
  2283. IN DWORD cb)
  2284. {
  2285. HRESULT hr;
  2286. if (NULL != hHash)
  2287. {
  2288. if (!CryptHashData(hHash, pb, cb, 0))
  2289. {
  2290. hr = myHLastError();
  2291. _JumpError(hr, error, "CryptHashData");
  2292. }
  2293. }
  2294. hr = S_OK;
  2295. error:
  2296. return(hr);
  2297. }
  2298. HRESULT
  2299. DumpChainHashResult(
  2300. IN OPTIONAL HCRYPTHASH hHash,
  2301. IN char const *pszType)
  2302. {
  2303. HRESULT hr;
  2304. HCRYPTHASH hHashT = NULL;
  2305. BYTE abHash[CBMAX_CRYPT_HASH_LEN];
  2306. DWORD cbHash;
  2307. if (NULL != hHash)
  2308. {
  2309. if (!CryptDuplicateHash(
  2310. hHash,
  2311. NULL, // pdwReserved
  2312. 0, // dwFlags
  2313. &hHashT))
  2314. {
  2315. hr = myHLastError();
  2316. _JumpError(hr, error, "CryptDuplicateHash");
  2317. }
  2318. if (!CryptGetHashParam(hHashT, HP_HASHVAL, abHash, &cbHash, 0))
  2319. {
  2320. hr = myHLastError();
  2321. _JumpError(hr, error, "CryptGetHashParam");
  2322. }
  2323. CONSOLEPRINT2((MAXDWORD, "%hs:\n", pszType));
  2324. hr = DumpChainHash(abHash, cbHash);
  2325. _JumpIfError(hr, error, "DumpChainHash");
  2326. }
  2327. hr = S_OK;
  2328. error:
  2329. if (NULL != hHashT)
  2330. {
  2331. CryptDestroyHash(hHashT);
  2332. }
  2333. return(hr);
  2334. }
  2335. VOID
  2336. DumpChainTemplate(
  2337. IN CERT_INFO const *pCertInfo)
  2338. {
  2339. HRESULT hr;
  2340. CERT_NAME_VALUE *pbName = NULL;
  2341. CERT_TEMPLATE_EXT *pTemplate = NULL;
  2342. CERT_EXTENSION *pExt;
  2343. DWORD cb;
  2344. // display v1 template extension first
  2345. pExt = CertFindExtension(
  2346. szOID_ENROLL_CERTTYPE_EXTENSION,
  2347. pCertInfo->cExtension,
  2348. pCertInfo->rgExtension);
  2349. if (NULL != pExt)
  2350. {
  2351. if (!myDecodeObject(
  2352. X509_ASN_ENCODING,
  2353. X509_UNICODE_ANY_STRING,
  2354. pExt->Value.pbData,
  2355. pExt->Value.cbData,
  2356. CERTLIB_USE_LOCALALLOC,
  2357. (VOID **) &pbName,
  2358. &cb))
  2359. {
  2360. hr = myHLastError();
  2361. _PrintError(hr, "myDecodeObject");
  2362. }
  2363. else
  2364. {
  2365. CONSOLEPRINT1((MAXDWORD, " Template: %ws\n", pbName->Value.pbData));
  2366. }
  2367. }
  2368. pExt = CertFindExtension(
  2369. szOID_CERTIFICATE_TEMPLATE,
  2370. pCertInfo->cExtension,
  2371. pCertInfo->rgExtension);
  2372. if (NULL != pExt)
  2373. {
  2374. if (!myDecodeObject(
  2375. X509_ASN_ENCODING,
  2376. X509_CERTIFICATE_TEMPLATE,
  2377. pExt->Value.pbData,
  2378. pExt->Value.cbData,
  2379. CERTLIB_USE_LOCALALLOC,
  2380. (VOID **) &pTemplate,
  2381. &cb))
  2382. {
  2383. hr = myHLastError();
  2384. _PrintError(hr, "myDecodeObject");
  2385. }
  2386. else
  2387. {
  2388. WCHAR const *pwsz;
  2389. pwsz = myGetOIDNameA(pTemplate->pszObjId); // Static: do not free!
  2390. if (NULL != pwsz && L'\0' != *pwsz)
  2391. {
  2392. CONSOLEPRINT1((MAXDWORD, " Template: %ws\n", pwsz));
  2393. }
  2394. else
  2395. {
  2396. CONSOLEPRINT1((MAXDWORD, " Template: %hs\n", pTemplate->pszObjId));
  2397. }
  2398. }
  2399. }
  2400. //error:
  2401. LOCAL_FREE(pTemplate);
  2402. LOCAL_FREE(pbName);
  2403. }
  2404. HRESULT
  2405. DumpChainCert(
  2406. IN CERT_CONTEXT const *pcc)
  2407. {
  2408. HRESULT hr;
  2409. BYTE abHash[CBMAX_CRYPT_HASH_LEN];
  2410. DWORD cbHash;
  2411. DumpChainName(" Issuer", &pcc->pCertInfo->Issuer);
  2412. DumpChainName(" Subject", &pcc->pCertInfo->Subject);
  2413. DumpChainSerial(" Serial", &pcc->pCertInfo->SerialNumber);
  2414. DumpChainTemplate(pcc->pCertInfo);
  2415. if (!CertGetCertificateContextProperty(
  2416. pcc,
  2417. CERT_SHA1_HASH_PROP_ID,
  2418. abHash,
  2419. &cbHash))
  2420. {
  2421. hr = myHLastError();
  2422. _JumpError(hr, error, "CertGetCertificateContextProperty");
  2423. }
  2424. hr = DumpChainHash(abHash, cbHash);
  2425. _JumpIfError(hr, error, "DumpChainHash");
  2426. error:
  2427. return(hr);
  2428. }
  2429. HRESULT
  2430. DumpChainCRL(
  2431. IN BOOL fDelta,
  2432. OPTIONAL IN CRL_CONTEXT const *pCRL,
  2433. IN OPTIONAL HCRYPTHASH hHash)
  2434. {
  2435. HRESULT hr;
  2436. BYTE abHash[CBMAX_CRYPT_HASH_LEN];
  2437. DWORD cbHash;
  2438. if (NULL != pCRL)
  2439. {
  2440. CONSOLEPRINT2((
  2441. MAXDWORD,
  2442. " %hsCRL %u:\n",
  2443. fDelta? "Delta " : "",
  2444. myCRLNumber(pCRL)));
  2445. DumpChainName(" Issuer", &pCRL->pCrlInfo->Issuer);
  2446. if (!CertGetCRLContextProperty(
  2447. pCRL,
  2448. CERT_SHA1_HASH_PROP_ID,
  2449. abHash,
  2450. &cbHash))
  2451. {
  2452. hr = myHLastError();
  2453. _PrintError(hr, "CertGetCRLContextProperty");
  2454. }
  2455. else
  2456. {
  2457. CONSOLEPRINT0((MAXDWORD, " "));
  2458. hr = DumpChainHash(abHash, cbHash);
  2459. _PrintIfError(hr, "DumpChainHash");
  2460. }
  2461. hr = DumpChainAddHash(hHash, pCRL->pbCrlEncoded, pCRL->cbCrlEncoded);
  2462. _JumpIfError(hr, error, "DumpChainAddHash");
  2463. }
  2464. hr = S_OK;
  2465. error:
  2466. return(hr);
  2467. }
  2468. VOID
  2469. DumpChainSeconds(
  2470. IN WCHAR const *pwszField,
  2471. IN DWORD dwSeconds)
  2472. {
  2473. HRESULT hr;
  2474. LLFILETIME llftPeriod;
  2475. WCHAR *pwszTimePeriod;
  2476. llftPeriod.ft.dwHighDateTime = 0;
  2477. llftPeriod.ft.dwLowDateTime = dwSeconds;
  2478. llftPeriod.ll *= CVT_BASE;
  2479. llftPeriod.ll = -llftPeriod.ll;
  2480. hr = myFileTimePeriodToWszTimePeriod(&llftPeriod.ft, TRUE, &pwszTimePeriod);
  2481. if (S_OK != hr)
  2482. {
  2483. _PrintError(hr, "myFileTimePeriodToWszTimePeriod");
  2484. CONSOLEPRINT2((MAXDWORD, "%ws: %us\n", pwszField, dwSeconds));
  2485. }
  2486. else
  2487. {
  2488. CONSOLEPRINT2((MAXDWORD, "%ws: %ws\n", pwszField, pwszTimePeriod));
  2489. LocalFree(pwszTimePeriod);
  2490. }
  2491. }
  2492. VOID
  2493. myDumpChain(
  2494. IN HRESULT hrVerify,
  2495. IN DWORD dwFlags,
  2496. IN CERT_CONTEXT const *pCert,
  2497. OPTIONAL IN FNSIMPLECHAINELEMENTCALLBACK *pfnCallback,
  2498. OPTIONAL IN WCHAR const *pwszMissingIssuer,
  2499. IN CERT_CHAIN_CONTEXT const *pChainContext)
  2500. {
  2501. HRESULT hr;
  2502. DWORD i;
  2503. DWORD j;
  2504. static BOOL s_fEnvChecked = FALSE;
  2505. static BOOL s_fDumpEnabled = FALSE;
  2506. static DWORD s_SaveCount = 0;
  2507. static DWORD s_SaveIndex;
  2508. BOOL fDump;
  2509. BOOL fSave;
  2510. HCRYPTPROV hProv = NULL;
  2511. HCRYPTHASH hHash = NULL;
  2512. if (!s_fEnvChecked)
  2513. {
  2514. WCHAR wszBuf[20];
  2515. DWORD cwc;
  2516. cwc = GetEnvironmentVariable(
  2517. L"CertSrv_Chain",
  2518. wszBuf,
  2519. ARRAYSIZE(wszBuf));
  2520. if (0 < cwc && ARRAYSIZE(wszBuf) > cwc)
  2521. {
  2522. s_fDumpEnabled = TRUE;
  2523. s_SaveCount = _wtoi(wszBuf);
  2524. s_SaveIndex = s_SaveCount;
  2525. }
  2526. s_fEnvChecked = TRUE;
  2527. }
  2528. fSave = 0 != s_SaveCount || (CA_VERIFY_FLAGS_SAVE_CHAIN & dwFlags);
  2529. fDump = s_fDumpEnabled ||
  2530. S_OK != hrVerify ||
  2531. (CA_VERIFY_FLAGS_DUMP_CHAIN & dwFlags);
  2532. #if DBG_CERTSRV
  2533. if (DbgIsSSActive(DBG_SS_CERTLIBI))
  2534. {
  2535. fDump = TRUE;
  2536. }
  2537. #endif
  2538. if (!fSave && !fDump)
  2539. {
  2540. return;
  2541. }
  2542. if (0 != s_SaveCount)
  2543. {
  2544. if (++s_SaveIndex >= s_SaveCount)
  2545. {
  2546. s_SaveIndex = 0;
  2547. }
  2548. }
  2549. if (fDump)
  2550. {
  2551. CONSOLEPRINT0((MAXDWORD, "-------- CERT_CHAIN_CONTEXT --------\n"));
  2552. DumpFlags(
  2553. pChainContext->TrustStatus.dwInfoStatus,
  2554. L"ChainContext.dwInfoStatus",
  2555. g_adfInfoStatus);
  2556. DumpFlags(
  2557. pChainContext->TrustStatus.dwErrorStatus,
  2558. L"ChainContext.dwErrorStatus",
  2559. g_adfErrorStatus);
  2560. if (CCSIZEOF_STRUCT(CERT_CHAIN_CONTEXT, dwRevocationFreshnessTime) <=
  2561. pChainContext->cbSize &&
  2562. pChainContext->fHasRevocationFreshnessTime)
  2563. {
  2564. DumpChainSeconds(
  2565. L"ChainContext.dwRevocationFreshnessTime",
  2566. pChainContext->dwRevocationFreshnessTime);
  2567. }
  2568. }
  2569. for (i = 0; i < pChainContext->cChain; i++)
  2570. {
  2571. if (fSave)
  2572. {
  2573. WriteChain(pChainContext->rgpChain[i], s_SaveIndex, i);
  2574. }
  2575. if (fDump)
  2576. {
  2577. DumpFlags(
  2578. pChainContext->rgpChain[i]->TrustStatus.dwInfoStatus,
  2579. L"\nSimpleChain.dwInfoStatus",
  2580. g_adfInfoStatus);
  2581. DumpFlags(
  2582. pChainContext->rgpChain[i]->TrustStatus.dwErrorStatus,
  2583. L"SimpleChain.dwErrorStatus",
  2584. g_adfErrorStatus);
  2585. if (CCSIZEOF_STRUCT(CERT_SIMPLE_CHAIN, dwRevocationFreshnessTime) <=
  2586. pChainContext->rgpChain[i]->cbSize &&
  2587. pChainContext->rgpChain[i]->fHasRevocationFreshnessTime)
  2588. {
  2589. DumpChainSeconds(
  2590. L"SimpleChain.dwRevocationFreshnessTime",
  2591. pChainContext->rgpChain[i]->dwRevocationFreshnessTime);
  2592. }
  2593. }
  2594. if (NULL != hHash)
  2595. {
  2596. CryptDestroyHash(hHash);
  2597. hHash = NULL;
  2598. }
  2599. if (NULL != hProv)
  2600. {
  2601. CryptReleaseContext(hProv, 0);
  2602. hProv = NULL;
  2603. }
  2604. hr = DumpChainOpenHash(&hProv, &hHash);
  2605. _PrintIfError(hr, "DumpChainOpenHash");
  2606. for (j = 0; j < pChainContext->rgpChain[i]->cElement; j++)
  2607. {
  2608. CERT_CHAIN_ELEMENT const *pElement;
  2609. pElement = pChainContext->rgpChain[i]->rgpElement[j];
  2610. if (fDump ||
  2611. S_OK != hrVerify ||
  2612. 0 != pElement->TrustStatus.dwErrorStatus)
  2613. {
  2614. CERT_REVOCATION_INFO *pRevocationInfo;
  2615. CONSOLEPRINT4((
  2616. MAXDWORD,
  2617. "\nCertContext[%u][%u]: dwInfoStatus=%x dwErrorStatus=%x\n",
  2618. i,
  2619. j,
  2620. pElement->TrustStatus.dwInfoStatus,
  2621. pElement->TrustStatus.dwErrorStatus));
  2622. hr = DumpChainCert(pElement->pCertContext);
  2623. _PrintIfError(hr, "DumpChainCert");
  2624. DumpFlags(
  2625. pElement->TrustStatus.dwInfoStatus,
  2626. L" Element.dwInfoStatus",
  2627. g_adfInfoStatus);
  2628. DumpFlags(
  2629. pElement->TrustStatus.dwErrorStatus,
  2630. L" Element.dwErrorStatus",
  2631. g_adfErrorStatus);
  2632. if (NULL != pfnCallback)
  2633. {
  2634. (*pfnCallback)(dwFlags, j, pChainContext->rgpChain[i]);
  2635. }
  2636. pRevocationInfo = pElement->pRevocationInfo;
  2637. if (NULL != pRevocationInfo &&
  2638. CCSIZEOF_STRUCT(CERT_REVOCATION_INFO, pCrlInfo) <=
  2639. pRevocationInfo->cbSize &&
  2640. NULL != pRevocationInfo->pCrlInfo)
  2641. {
  2642. hr = DumpChainCRL(
  2643. FALSE,
  2644. pRevocationInfo->pCrlInfo->pBaseCrlContext,
  2645. hHash);
  2646. _PrintIfError(hr, "DumpChainCRL");
  2647. hr = DumpChainCRL(
  2648. TRUE,
  2649. pRevocationInfo->pCrlInfo->pDeltaCrlContext,
  2650. hHash);
  2651. _PrintIfError(hr, "DumpChainCRL");
  2652. }
  2653. if (CCSIZEOF_STRUCT(CERT_CHAIN_ELEMENT, pIssuanceUsage) <=
  2654. pElement->cbSize)
  2655. {
  2656. DumpUsage(L" Issuance", pElement->pIssuanceUsage);
  2657. }
  2658. if (CCSIZEOF_STRUCT(CERT_CHAIN_ELEMENT, pApplicationUsage) <=
  2659. pElement->cbSize)
  2660. {
  2661. DumpUsage(L" Application", pElement->pApplicationUsage);
  2662. }
  2663. if (CCSIZEOF_STRUCT(CERT_CHAIN_ELEMENT, pwszExtendedErrorInfo) <=
  2664. pElement->cbSize &&
  2665. NULL != pElement->pwszExtendedErrorInfo)
  2666. {
  2667. CONSOLEPRINT1((
  2668. MAXDWORD,
  2669. " %ws",
  2670. pElement->pwszExtendedErrorInfo));
  2671. }
  2672. if (1 + j == pChainContext->rgpChain[i]->cElement)
  2673. {
  2674. DumpChainHashResult(hHash, "\nExclude leaf cert");
  2675. }
  2676. hr = DumpChainAddHash(
  2677. hHash,
  2678. pElement->pCertContext->pbCertEncoded,
  2679. pElement->pCertContext->cbCertEncoded);
  2680. _PrintIfError(hr, "DumpChainAddHash");
  2681. if (1 + j == pChainContext->rgpChain[i]->cElement)
  2682. {
  2683. hr = DumpChainHashResult(hHash, "Full chain");
  2684. _PrintIfError(hr, "DumpChainAddHash");
  2685. }
  2686. }
  2687. }
  2688. }
  2689. if (fDump)
  2690. {
  2691. if (S_OK != hrVerify)
  2692. {
  2693. WCHAR const *pwszErr = myGetErrorMessageText(hrVerify, TRUE);
  2694. if (NULL != pwszMissingIssuer)
  2695. {
  2696. CONSOLEPRINT1((
  2697. MAXDWORD,
  2698. "Missing Issuer: %ws\n",
  2699. pwszMissingIssuer));
  2700. }
  2701. DumpChainCert(pCert);
  2702. if (NULL != pwszErr)
  2703. {
  2704. CONSOLEPRINT1((MAXDWORD, "%ws\n", pwszErr));
  2705. LocalFree(const_cast<WCHAR *>(pwszErr));
  2706. }
  2707. }
  2708. CONSOLEPRINT0((MAXDWORD, "------------------------------------\n"));
  2709. }
  2710. if (NULL != hHash)
  2711. {
  2712. CryptDestroyHash(hHash);
  2713. }
  2714. if (NULL != hProv)
  2715. {
  2716. CryptReleaseContext(hProv, 0);
  2717. }
  2718. }
  2719. #pragma warning(push)
  2720. #pragma warning(disable: 4706) // assignment within conditional expression: while (*pwsz++ = *psz++)
  2721. HRESULT
  2722. SavePolicies(
  2723. OPTIONAL IN CERT_ENHKEY_USAGE const *pUsage,
  2724. OUT WCHAR **ppwszzPolicies)
  2725. {
  2726. HRESULT hr;
  2727. DWORD i;
  2728. DWORD cwc;
  2729. char const *psz;
  2730. WCHAR *pwsz;
  2731. // pUsage == NULL means the cert is good for *all* policies.
  2732. // Do nothing here, which returns *ppwszzPolicies == NULL.
  2733. //
  2734. // pUsage->cUsageIdentifier == 0 means the cert is good for *no* policies.
  2735. // Return a double L'\0' terminated string containing no policy OIDs.
  2736. if (NULL != pUsage)
  2737. {
  2738. BOOL fEmpty = 0 == pUsage->cUsageIdentifier ||
  2739. NULL == pUsage->rgpszUsageIdentifier;
  2740. cwc = 1;
  2741. if (fEmpty)
  2742. {
  2743. cwc++;
  2744. }
  2745. else
  2746. {
  2747. for (i = 0; i < pUsage->cUsageIdentifier; i++)
  2748. {
  2749. cwc += strlen(pUsage->rgpszUsageIdentifier[i]) + 1;
  2750. }
  2751. }
  2752. pwsz = (WCHAR *) LocalAlloc(LMEM_FIXED, cwc * sizeof(WCHAR));
  2753. if (NULL == pwsz)
  2754. {
  2755. hr = E_OUTOFMEMORY;
  2756. _JumpError(hr, error, "LocalAlloc");
  2757. }
  2758. *ppwszzPolicies = pwsz;
  2759. if (fEmpty)
  2760. {
  2761. *pwsz++ = L'\0';
  2762. }
  2763. else
  2764. {
  2765. for (i = 0; i < pUsage->cUsageIdentifier; i++)
  2766. {
  2767. psz = pUsage->rgpszUsageIdentifier[i];
  2768. while (*pwsz++ = *psz++)
  2769. ;
  2770. }
  2771. }
  2772. *pwsz++ = L'\0';
  2773. CSASSERT(pwsz == &(*ppwszzPolicies)[cwc]);
  2774. }
  2775. hr = S_OK;
  2776. error:
  2777. return(hr);
  2778. }
  2779. #pragma warning(pop)
  2780. HRESULT
  2781. myVerifyCertContextEx(
  2782. IN CERT_CONTEXT const *pCert,
  2783. IN DWORD dwFlags,
  2784. IN DWORD dwmsTimeout,
  2785. IN DWORD cUsageOids,
  2786. OPTIONAL IN CHAR const * const *apszUsageOids,
  2787. IN DWORD cIssuanceOids,
  2788. OPTIONAL IN CHAR const * const *apszIssuanceOids,
  2789. OPTIONAL IN HCERTCHAINENGINE hChainEngine,
  2790. OPTIONAL IN FILETIME const *pft,
  2791. OPTIONAL IN HCERTSTORE hAdditionalStore,
  2792. OPTIONAL IN FNSIMPLECHAINELEMENTCALLBACK *pfnCallback,
  2793. OPTIONAL OUT WCHAR **ppwszMissingIssuer,
  2794. OPTIONAL OUT WCHAR **ppwszzIssuancePolicies,
  2795. OPTIONAL OUT WCHAR **ppwszzApplicationPolicies,
  2796. OPTIONAL OUT WCHAR **ppwszExtendedErrorInfo,
  2797. OPTIONAL OUT CERT_TRUST_STATUS *pTrustStatus)
  2798. {
  2799. HRESULT hr;
  2800. DWORD ChainFlags;
  2801. CERT_CHAIN_PARA ChainParams;
  2802. CERT_CHAIN_POLICY_PARA ChainPolicy;
  2803. CERT_CHAIN_POLICY_STATUS PolicyStatus;
  2804. CERT_CHAIN_CONTEXT const *pChainContext = NULL;
  2805. LPCSTR pszChainPolicyFlags;
  2806. WCHAR *pwszMissingIssuer = NULL;
  2807. CERT_CHAIN_ELEMENT const *pElement;
  2808. WCHAR const *pwsz;
  2809. if (NULL != ppwszMissingIssuer)
  2810. {
  2811. *ppwszMissingIssuer = NULL;
  2812. }
  2813. if (NULL != ppwszzIssuancePolicies)
  2814. {
  2815. *ppwszzIssuancePolicies = NULL;
  2816. }
  2817. if (NULL != ppwszzApplicationPolicies)
  2818. {
  2819. *ppwszzApplicationPolicies = NULL;
  2820. }
  2821. if (NULL != ppwszExtendedErrorInfo)
  2822. {
  2823. *ppwszExtendedErrorInfo = NULL;
  2824. }
  2825. if (NULL != pTrustStatus)
  2826. {
  2827. ZeroMemory(pTrustStatus, sizeof(*pTrustStatus));
  2828. }
  2829. ZeroMemory(&ChainParams, sizeof(ChainParams));
  2830. ChainParams.cbSize = sizeof(ChainParams);
  2831. ChainParams.dwUrlRetrievalTimeout = dwmsTimeout;
  2832. if (0 != cUsageOids && NULL != apszUsageOids)
  2833. {
  2834. ChainParams.RequestedUsage.dwType = USAGE_MATCH_TYPE_AND;
  2835. ChainParams.RequestedUsage.Usage.cUsageIdentifier = cUsageOids;
  2836. ChainParams.RequestedUsage.Usage.rgpszUsageIdentifier = const_cast<char **>(apszUsageOids);
  2837. }
  2838. if (0 != cIssuanceOids && NULL != apszIssuanceOids)
  2839. {
  2840. ChainParams.RequestedIssuancePolicy.dwType = USAGE_MATCH_TYPE_AND;
  2841. ChainParams.RequestedIssuancePolicy.Usage.cUsageIdentifier = cIssuanceOids;
  2842. ChainParams.RequestedIssuancePolicy.Usage.rgpszUsageIdentifier = const_cast<char **>(apszIssuanceOids);
  2843. }
  2844. ChainFlags = 0;
  2845. if (0 == (CA_VERIFY_FLAGS_NO_REVOCATION & dwFlags))
  2846. {
  2847. if (CA_VERIFY_FLAGS_FULL_CHAIN_REVOCATION & dwFlags)
  2848. {
  2849. ChainFlags = CERT_CHAIN_REVOCATION_CHECK_CHAIN;
  2850. }
  2851. else
  2852. {
  2853. ChainFlags = CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT;
  2854. }
  2855. }
  2856. if (CA_VERIFY_FLAGS_DUMP_CHAIN & dwFlags)
  2857. {
  2858. DumpFlags(dwFlags, L"dwFlags", g_adfVerifyFlags);
  2859. if (0 != cIssuanceOids && NULL != apszIssuanceOids)
  2860. {
  2861. DumpUsage(L"Issuance", &ChainParams.RequestedIssuancePolicy.Usage);
  2862. }
  2863. if (0 != cUsageOids && NULL != apszUsageOids)
  2864. {
  2865. DumpUsage(L"Application", &ChainParams.RequestedUsage.Usage);
  2866. }
  2867. DumpFlags(ChainFlags, L"ChainFlags", g_adfChainFlags);
  2868. pwsz = NULL;
  2869. if (HCCE_LOCAL_MACHINE == hChainEngine)
  2870. {
  2871. pwsz = L"HCCE_LOCAL_MACHINE";
  2872. }
  2873. else if (HCCE_CURRENT_USER == hChainEngine)
  2874. {
  2875. pwsz = L"HCCE_CURRENT_USER";
  2876. }
  2877. if (NULL != pwsz)
  2878. {
  2879. CONSOLEPRINT1((MAXDWORD, "%ws\n", pwsz));
  2880. }
  2881. }
  2882. // use NTAuth policy if (usage oids being added) & (caller asks us to check(EntCA))
  2883. pwsz = NULL;
  2884. if (0 != cUsageOids &&
  2885. NULL != apszUsageOids &&
  2886. (CA_VERIFY_FLAGS_NT_AUTH & dwFlags))
  2887. {
  2888. pszChainPolicyFlags = CERT_CHAIN_POLICY_NT_AUTH;
  2889. pwsz = L"CERT_CHAIN_POLICY_NT_AUTH";
  2890. }
  2891. else
  2892. {
  2893. pszChainPolicyFlags = CERT_CHAIN_POLICY_BASE;
  2894. pwsz = L"CERT_CHAIN_POLICY_BASE";
  2895. }
  2896. if (NULL != pwsz && (CA_VERIFY_FLAGS_DUMP_CHAIN & dwFlags))
  2897. {
  2898. CONSOLEPRINT1((MAXDWORD, "%ws\n", pwsz));
  2899. }
  2900. // Get the chain and verify the cert:
  2901. DBGPRINT((DBG_SS_CERTLIBI, "Calling CertGetCertificateChain...\n"));
  2902. if (!CertGetCertificateChain(
  2903. hChainEngine, // hChainEngine
  2904. pCert, // pCertContext
  2905. const_cast<FILETIME *>(pft), // pTime
  2906. hAdditionalStore, // hAdditionalStore
  2907. &ChainParams, // pChainPara
  2908. ChainFlags, // dwFlags
  2909. NULL, // pvReserved
  2910. &pChainContext)) // ppChainContext
  2911. {
  2912. hr = myHLastError();
  2913. _JumpError(hr, error, "CertGetCertificateChain");
  2914. }
  2915. DBGPRINT((DBG_SS_CERTLIBI, "CertGetCertificateChain done\n"));
  2916. ZeroMemory(&ChainPolicy, sizeof(ChainPolicy));
  2917. ChainPolicy.cbSize = sizeof(ChainPolicy);
  2918. ChainPolicy.dwFlags = CERT_CHAIN_POLICY_IGNORE_NOT_TIME_NESTED_FLAG;
  2919. //ChainPolicy.pvExtraPolicyPara = NULL;
  2920. ZeroMemory(&PolicyStatus, sizeof(PolicyStatus));
  2921. PolicyStatus.cbSize = sizeof(PolicyStatus);
  2922. //PolicyStatus.dwError = 0;
  2923. PolicyStatus.lChainIndex = -1;
  2924. PolicyStatus.lElementIndex = -1;
  2925. //PolicyStatus.pvExtraPolicyStatus = NULL;
  2926. if (!CertVerifyCertificateChainPolicy(
  2927. pszChainPolicyFlags,
  2928. pChainContext,
  2929. &ChainPolicy,
  2930. &PolicyStatus))
  2931. {
  2932. hr = myHLastError();
  2933. _JumpError(hr, error, "CertVerifyCertificateChainPolicy");
  2934. }
  2935. hr = myHError(PolicyStatus.dwError);
  2936. if ((CA_VERIFY_FLAGS_IGNORE_OFFLINE |
  2937. CA_VERIFY_FLAGS_IGNORE_NOREVCHECK |
  2938. CA_VERIFY_FLAGS_NO_REVOCATION) & dwFlags)
  2939. {
  2940. if (CRYPT_E_NO_REVOCATION_CHECK == hr ||
  2941. (CRYPT_E_REVOCATION_OFFLINE == hr &&
  2942. ((CA_VERIFY_FLAGS_IGNORE_OFFLINE |
  2943. CA_VERIFY_FLAGS_IGNORE_NOREVCHECK) & dwFlags)))
  2944. {
  2945. hr = S_OK;
  2946. }
  2947. }
  2948. if (CA_VERIFY_FLAGS_ALLOW_UNTRUSTED_ROOT & dwFlags)
  2949. {
  2950. if (CERT_E_UNTRUSTEDROOT == hr)
  2951. {
  2952. hr = S_OK;
  2953. }
  2954. }
  2955. if (CA_VERIFY_FLAGS_IGNORE_INVALID_POLICIES & dwFlags)
  2956. {
  2957. if (CERT_E_INVALID_POLICY == hr)
  2958. {
  2959. hr = S_OK;
  2960. }
  2961. }
  2962. if (S_OK != hr &&
  2963. 0 < pChainContext->cChain &&
  2964. 0 < pChainContext->rgpChain[0]->cElement)
  2965. {
  2966. pElement = pChainContext->rgpChain[0]->rgpElement[
  2967. pChainContext->rgpChain[0]->cElement - 1];
  2968. if (0 == (CERT_TRUST_IS_SELF_SIGNED & pElement->TrustStatus.dwInfoStatus))
  2969. {
  2970. HRESULT hr2;
  2971. hr2 = myCertNameToStr(
  2972. X509_ASN_ENCODING,
  2973. &pElement->pCertContext->pCertInfo->Issuer,
  2974. CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
  2975. &pwszMissingIssuer);
  2976. _PrintIfError(hr2, "myCertNameToStr");
  2977. }
  2978. }
  2979. if (NULL != pTrustStatus)
  2980. {
  2981. *pTrustStatus = pChainContext->TrustStatus;
  2982. }
  2983. myDumpChain(
  2984. hr,
  2985. dwFlags,
  2986. pCert,
  2987. pfnCallback,
  2988. pwszMissingIssuer,
  2989. pChainContext);
  2990. if (NULL != ppwszMissingIssuer)
  2991. {
  2992. *ppwszMissingIssuer = pwszMissingIssuer;
  2993. pwszMissingIssuer = NULL;
  2994. }
  2995. if (NULL != ppwszExtendedErrorInfo)
  2996. {
  2997. CERT_CHAIN_ELEMENT **ppElement;
  2998. CERT_CHAIN_ELEMENT **ppElementEnd;
  2999. ppElement = &pChainContext->rgpChain[0]->rgpElement[0];
  3000. ppElementEnd = &ppElement[pChainContext->rgpChain[0]->cElement];
  3001. while (ppElement < ppElementEnd)
  3002. {
  3003. if (CCSIZEOF_STRUCT(CERT_CHAIN_ELEMENT, pwszExtendedErrorInfo) <=
  3004. (*ppElement)->cbSize &&
  3005. NULL != (*ppElement)->pwszExtendedErrorInfo)
  3006. {
  3007. HRESULT hr2;
  3008. hr2 = myDupString(
  3009. (*ppElement)->pwszExtendedErrorInfo,
  3010. ppwszExtendedErrorInfo);
  3011. _PrintIfError(hr2, "myDupString");
  3012. break;
  3013. }
  3014. ppElement++;
  3015. }
  3016. }
  3017. _JumpIfError(hr, error, "PolicyStatus.dwError");
  3018. pElement = pChainContext->rgpChain[0]->rgpElement[0];
  3019. if (NULL != ppwszzIssuancePolicies &&
  3020. CCSIZEOF_STRUCT(CERT_CHAIN_ELEMENT, pIssuanceUsage) <= pElement->cbSize)
  3021. {
  3022. hr = SavePolicies(
  3023. pElement->pIssuanceUsage,
  3024. ppwszzIssuancePolicies);
  3025. _JumpIfError(hr, error, "SavePolicies");
  3026. }
  3027. if (NULL != ppwszzApplicationPolicies &&
  3028. CCSIZEOF_STRUCT(CERT_CHAIN_ELEMENT, pApplicationUsage) <= pElement->cbSize)
  3029. {
  3030. hr = SavePolicies(
  3031. pElement->pApplicationUsage,
  3032. ppwszzApplicationPolicies);
  3033. _JumpIfError(hr, error, "SavePolicies");
  3034. }
  3035. error:
  3036. if (S_OK != hr)
  3037. {
  3038. if (NULL != ppwszzIssuancePolicies && NULL != *ppwszzIssuancePolicies)
  3039. {
  3040. LocalFree(*ppwszzIssuancePolicies);
  3041. *ppwszzIssuancePolicies = NULL;
  3042. }
  3043. if (NULL != ppwszzApplicationPolicies && NULL != *ppwszzApplicationPolicies)
  3044. {
  3045. LocalFree(*ppwszzApplicationPolicies);
  3046. *ppwszzApplicationPolicies = NULL;
  3047. }
  3048. }
  3049. if (NULL != pwszMissingIssuer)
  3050. {
  3051. LocalFree(pwszMissingIssuer);
  3052. }
  3053. if (NULL != pChainContext)
  3054. {
  3055. CertFreeCertificateChain(pChainContext);
  3056. }
  3057. return(hr);
  3058. }
  3059. HRESULT
  3060. myVerifyCertContext(
  3061. IN CERT_CONTEXT const *pCert,
  3062. IN DWORD dwFlags,
  3063. IN DWORD cUsageOids,
  3064. OPTIONAL IN CHAR const * const *apszUsageOids,
  3065. OPTIONAL IN HCERTCHAINENGINE hChainEngine,
  3066. OPTIONAL IN HCERTSTORE hAdditionalStore,
  3067. OPTIONAL OUT WCHAR **ppwszMissingIssuer)
  3068. {
  3069. HRESULT hr;
  3070. hr = myVerifyCertContextEx(
  3071. pCert,
  3072. dwFlags,
  3073. 0, // dwmsTimeout
  3074. cUsageOids,
  3075. apszUsageOids,
  3076. 0, // cIssuanceOids
  3077. NULL, // apszIssuanceOids
  3078. hChainEngine,
  3079. NULL, // pft
  3080. hAdditionalStore,
  3081. NULL, // pfnCallback
  3082. ppwszMissingIssuer,
  3083. NULL, // ppwszzIssuancePolicies
  3084. NULL, // ppwszzApplicationPolicies
  3085. NULL, // ppwszExtendedErrorInfo
  3086. NULL); // pTrustStatus
  3087. _JumpIfError2(hr, error, "myVerifyCertContextEx", hr);
  3088. error:
  3089. return(hr);
  3090. }
  3091. HRESULT
  3092. myIsFirstSigner(
  3093. IN CERT_NAME_BLOB const *pNameBlob,
  3094. OUT BOOL *pfFirst)
  3095. {
  3096. HRESULT hr;
  3097. CERT_NAME_INFO *pNameInfo = NULL;
  3098. DWORD cbNameInfo;
  3099. DWORD i;
  3100. *pfFirst = FALSE;
  3101. if (!myDecodeName(
  3102. X509_ASN_ENCODING,
  3103. X509_UNICODE_NAME,
  3104. pNameBlob->pbData,
  3105. pNameBlob->cbData,
  3106. CERTLIB_USE_LOCALALLOC,
  3107. &pNameInfo,
  3108. &cbNameInfo))
  3109. {
  3110. hr = myHLastError();
  3111. _JumpError(hr, error, "myDecodeName");
  3112. }
  3113. for (i = 0; i < pNameInfo->cRDN; i++)
  3114. {
  3115. CERT_RDN const *prdn;
  3116. DWORD j;
  3117. prdn = &pNameInfo->rgRDN[i];
  3118. for (j = 0; j < prdn->cRDNAttr; j++)
  3119. {
  3120. if (0 == strcmp(
  3121. prdn->rgRDNAttr[j].pszObjId,
  3122. szOID_RDN_DUMMY_SIGNER))
  3123. {
  3124. *pfFirst = TRUE;
  3125. i = pNameInfo->cRDN; // terminate outer loop
  3126. break;
  3127. }
  3128. }
  3129. }
  3130. hr = S_OK;
  3131. error:
  3132. if (NULL != pNameInfo)
  3133. {
  3134. LocalFree(pNameInfo);
  3135. }
  3136. return(hr);
  3137. }
  3138. HCERTSTORE
  3139. myPFXImportCertStore(
  3140. IN CRYPT_DATA_BLOB *ppfx,
  3141. OPTIONAL IN WCHAR const *pwszPassword,
  3142. IN DWORD dwFlags)
  3143. {
  3144. HCERTSTORE hStore;
  3145. HRESULT hr;
  3146. if (NULL == pwszPassword)
  3147. {
  3148. pwszPassword = L""; // Try empty password first, then NULL
  3149. }
  3150. for (;;)
  3151. {
  3152. hStore = PFXImportCertStore(ppfx, pwszPassword, dwFlags);
  3153. if (NULL == hStore)
  3154. {
  3155. hr = myHLastError();
  3156. if (HRESULT_FROM_WIN32(ERROR_INVALID_PASSWORD) != hr ||
  3157. NULL == pwszPassword ||
  3158. L'\0' != *pwszPassword)
  3159. {
  3160. _JumpError2(
  3161. hr,
  3162. error,
  3163. "PFXImportCertStore",
  3164. HRESULT_FROM_WIN32(ERROR_INVALID_PASSWORD));
  3165. }
  3166. pwszPassword = NULL; // empty password failed; try NULL
  3167. continue;
  3168. }
  3169. break;
  3170. }
  3171. error:
  3172. return(hStore);
  3173. }
  3174. // No longer support versions before IE3.02 - Auth2 update, advisory only
  3175. HRESULT
  3176. CertCheck7f(
  3177. IN CERT_CONTEXT const *pcc)
  3178. {
  3179. HRESULT hr;
  3180. DWORD State;
  3181. DWORD Index1;
  3182. DWORD Index2;
  3183. DWORD cwcField;
  3184. WCHAR wszField[128];
  3185. DWORD cwcObjectId;
  3186. WCHAR wszObjectId[128];
  3187. WCHAR const *pwszObjectIdDescription = NULL;
  3188. cwcField = sizeof(wszField)/sizeof(wszField[0]);
  3189. cwcObjectId = sizeof(wszObjectId)/sizeof(wszObjectId[0]);
  3190. hr = myCheck7f(
  3191. pcc->pbCertEncoded,
  3192. pcc->cbCertEncoded,
  3193. FALSE,
  3194. &State,
  3195. &Index1,
  3196. &Index2,
  3197. &cwcField,
  3198. wszField,
  3199. &cwcObjectId,
  3200. wszObjectId,
  3201. &pwszObjectIdDescription); // Static: do not free!
  3202. _JumpIfError(hr, error, "myCheck7f");
  3203. if (CHECK7F_NONE != State)
  3204. {
  3205. hr = CERTSRV_E_ENCODING_LENGTH;
  3206. #if DBG_CERTSRV
  3207. WCHAR wszIndex[5 + 2 * cwcDWORDSPRINTF];
  3208. wszIndex[0] = L'\0';
  3209. if (0 != Index1)
  3210. {
  3211. wsprintf(
  3212. wszIndex,
  3213. 0 != Index2? L"[%u,%u]" : L"[%u]",
  3214. Index1 - 1,
  3215. Index2 - 1);
  3216. }
  3217. DBGPRINT((
  3218. DBG_SS_CERTLIB,
  3219. "CertCheck7f: %ws%ws%ws%ws%ws%ws%ws, hr=%x\n",
  3220. wszField,
  3221. wszIndex,
  3222. 0 != cwcObjectId? L" ObjectId=" : L"",
  3223. 0 != cwcObjectId? wszObjectId : L"",
  3224. NULL != pwszObjectIdDescription? L" " wszLPAREN : L"",
  3225. NULL != pwszObjectIdDescription? pwszObjectIdDescription : L"",
  3226. NULL != pwszObjectIdDescription? wszRPAREN : L"",
  3227. hr));
  3228. #endif // DBG_CERTSRV
  3229. }
  3230. error:
  3231. return(hr);
  3232. }
  3233. HRESULT
  3234. myAddCertToStore(
  3235. IN HCERTSTORE hStore,
  3236. IN CERT_CONTEXT const *pCertContext,
  3237. OPTIONAL IN CRYPT_KEY_PROV_INFO const *pkpi,
  3238. OPTIONAL OUT CERT_CONTEXT const **ppCert)
  3239. {
  3240. HRESULT hr;
  3241. CERT_CONTEXT const *pcc = NULL;
  3242. if (NULL != ppCert)
  3243. {
  3244. *ppCert = NULL;
  3245. }
  3246. // for root cert, if it shows related private key, it will
  3247. // pfx import failure for other applications
  3248. // Add as encoded blob to avoid all properties, key prov info, etc.
  3249. if (!CertAddEncodedCertificateToStore(
  3250. hStore,
  3251. X509_ASN_ENCODING,
  3252. pCertContext->pbCertEncoded,
  3253. pCertContext->cbCertEncoded,
  3254. NULL != pkpi?
  3255. CERT_STORE_ADD_REPLACE_EXISTING :
  3256. CERT_STORE_ADD_USE_EXISTING,
  3257. &pcc)) // ppCertContext
  3258. {
  3259. hr = myHLastError();
  3260. _JumpError(hr, error, "CertAddEncodedCertificateToStore");
  3261. }
  3262. if (NULL != pkpi)
  3263. {
  3264. if (!CertSetCertificateContextProperty(
  3265. pcc,
  3266. CERT_KEY_PROV_INFO_PROP_ID,
  3267. 0,
  3268. pkpi))
  3269. {
  3270. hr = myHLastError();
  3271. _JumpError(hr, error, "CertSetCertificateContextProperty");
  3272. }
  3273. }
  3274. if (NULL != ppCert)
  3275. {
  3276. *ppCert = pcc;
  3277. pcc = NULL;
  3278. }
  3279. hr = S_OK;
  3280. error:
  3281. if (NULL != pcc)
  3282. {
  3283. CertFreeCertificateContext(pcc);
  3284. }
  3285. return(hr);
  3286. }
  3287. HRESULT
  3288. mySaveChainAndKeys(
  3289. IN CERT_SIMPLE_CHAIN const *pSimpleChain,
  3290. IN WCHAR const *pwszStore,
  3291. IN DWORD dwStoreFlags,
  3292. IN CRYPT_KEY_PROV_INFO const *pkpi,
  3293. OPTIONAL IN CERT_CONTEXT const **ppCert)
  3294. {
  3295. HRESULT hr;
  3296. HCERTSTORE hRootStore = NULL;
  3297. HCERTSTORE hCAStore = NULL;
  3298. HCERTSTORE hMyStore = NULL;
  3299. DWORD i;
  3300. if (NULL != ppCert)
  3301. {
  3302. *ppCert = NULL;
  3303. }
  3304. hRootStore = CertOpenStore(
  3305. CERT_STORE_PROV_SYSTEM_REGISTRY_W,
  3306. X509_ASN_ENCODING,
  3307. NULL, // hProv
  3308. dwStoreFlags,
  3309. wszROOT_CERTSTORE);
  3310. if (NULL == hRootStore)
  3311. {
  3312. hr = myHLastError();
  3313. _JumpErrorStr(hr, error, "CertOpenStore", wszROOT_CERTSTORE);
  3314. }
  3315. hCAStore = CertOpenStore(
  3316. CERT_STORE_PROV_SYSTEM_REGISTRY_W,
  3317. X509_ASN_ENCODING,
  3318. NULL, // hProv
  3319. dwStoreFlags,
  3320. wszCA_CERTSTORE);
  3321. if (NULL == hCAStore)
  3322. {
  3323. hr = myHLastError();
  3324. _JumpErrorStr(hr, error, "CertOpenStore", wszCA_CERTSTORE);
  3325. }
  3326. hMyStore = CertOpenStore(
  3327. CERT_STORE_PROV_SYSTEM_REGISTRY_W,
  3328. X509_ASN_ENCODING,
  3329. NULL, // hProv
  3330. dwStoreFlags,
  3331. pwszStore);
  3332. if (NULL == hMyStore)
  3333. {
  3334. hr = myHLastError();
  3335. _JumpErrorStr(hr, error, "CertOpenStore", pwszStore);
  3336. }
  3337. for (i = 0; i < pSimpleChain->cElement; i++)
  3338. {
  3339. CERT_CONTEXT const *pcc = pSimpleChain->rgpElement[i]->pCertContext;
  3340. HCERTSTORE hStore;
  3341. // CertCheck7f(pcc);
  3342. // if leaf CA cert, add to MY store
  3343. if (0 == i)
  3344. {
  3345. CERT_CONTEXT const *pccFound = CertFindCertificateInStore(
  3346. hMyStore,
  3347. X509_ASN_ENCODING,
  3348. 0,
  3349. CERT_FIND_EXISTING,
  3350. pcc,
  3351. NULL);
  3352. if (NULL == pccFound)
  3353. {
  3354. hr = myAddCertToStore(hMyStore, pcc, pkpi, ppCert);
  3355. _JumpIfError(hr, error, "myAddCertToStore");
  3356. }
  3357. else
  3358. {
  3359. if (NULL != ppCert)
  3360. {
  3361. *ppCert = pccFound;
  3362. }
  3363. else
  3364. {
  3365. CertFreeCertificateContext(pccFound);
  3366. }
  3367. }
  3368. }
  3369. // if root cert, add to ROOT store (without key); else add to CA store
  3370. hStore = hCAStore;
  3371. if (CERT_TRUST_IS_SELF_SIGNED &
  3372. pSimpleChain->rgpElement[i]->TrustStatus.dwInfoStatus)
  3373. {
  3374. hStore = hRootStore;
  3375. }
  3376. hr = myAddCertToStore(hStore, pcc, NULL, NULL);
  3377. _JumpIfError(hr, error, "myAddCertToStore");
  3378. }
  3379. hr = S_OK;
  3380. error:
  3381. if (NULL != hRootStore)
  3382. {
  3383. CertCloseStore(hRootStore, CERT_CLOSE_STORE_CHECK_FLAG);
  3384. }
  3385. if (NULL != hCAStore)
  3386. {
  3387. CertCloseStore(hCAStore, CERT_CLOSE_STORE_CHECK_FLAG);
  3388. }
  3389. if (NULL != hMyStore)
  3390. {
  3391. CertCloseStore(hMyStore, CERT_CLOSE_STORE_CHECK_FLAG);
  3392. }
  3393. return(hr);
  3394. }
  3395. HRESULT
  3396. myGetNameIdExtension(
  3397. IN DWORD cExtension,
  3398. IN CERT_EXTENSION const *rgExtension,
  3399. OUT DWORD *pdwNameId)
  3400. {
  3401. HRESULT hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  3402. CERT_EXTENSION const *pExt;
  3403. DWORD NameId;
  3404. DWORD cb;
  3405. *pdwNameId = MAXDWORD;
  3406. pExt = CertFindExtension(
  3407. szOID_CERTSRV_CA_VERSION,
  3408. cExtension,
  3409. const_cast<CERT_EXTENSION *>(rgExtension));
  3410. if (NULL == pExt)
  3411. {
  3412. // This API doesn't set LastError
  3413. _JumpError(hr, error, "CertFindExtension(CA Version)");
  3414. }
  3415. cb = sizeof(NameId);
  3416. NameId = 0;
  3417. if (!CryptDecodeObject(
  3418. X509_ASN_ENCODING,
  3419. X509_INTEGER,
  3420. pExt->Value.pbData,
  3421. pExt->Value.cbData,
  3422. 0,
  3423. &NameId,
  3424. &cb))
  3425. {
  3426. hr = myHLastError();
  3427. _JumpError(hr, error, "CryptDecodeObject");
  3428. }
  3429. *pdwNameId = NameId;
  3430. hr = S_OK;
  3431. error:
  3432. return(hr);
  3433. }
  3434. HRESULT
  3435. myGetNameId(
  3436. IN CERT_CONTEXT const *pCACert,
  3437. OUT DWORD *pdwNameId)
  3438. {
  3439. HRESULT hr;
  3440. hr = myGetNameIdExtension(
  3441. pCACert->pCertInfo->cExtension,
  3442. pCACert->pCertInfo->rgExtension,
  3443. pdwNameId);
  3444. _JumpIfError2(hr, error, "myGetNameIdExtension", hr);
  3445. error:
  3446. return(hr);
  3447. }
  3448. HRESULT
  3449. myGetCRLNameId(
  3450. IN CRL_CONTEXT const *pCRL,
  3451. OUT DWORD *pdwNameId)
  3452. {
  3453. HRESULT hr;
  3454. hr = myGetNameIdExtension(
  3455. pCRL->pCrlInfo->cExtension,
  3456. pCRL->pCrlInfo->rgExtension,
  3457. pdwNameId);
  3458. _JumpIfError2(hr, error, "myGetNameIdExtension", hr);
  3459. error:
  3460. return(hr);
  3461. }
  3462. HRESULT
  3463. myGetCertSubjectField(
  3464. IN CERT_CONTEXT const *pCert,
  3465. IN LPCSTR pcszFieldOID,
  3466. OUT WCHAR **ppwszField)
  3467. {
  3468. HRESULT hr;
  3469. CERT_NAME_INFO *pCertNameInfo = NULL;
  3470. DWORD cbCertNameInfo;
  3471. WCHAR const *pwszName;
  3472. if (!myDecodeName(
  3473. X509_ASN_ENCODING,
  3474. X509_UNICODE_NAME,
  3475. pCert->pCertInfo->Subject.pbData,
  3476. pCert->pCertInfo->Subject.cbData,
  3477. CERTLIB_USE_LOCALALLOC,
  3478. &pCertNameInfo,
  3479. &cbCertNameInfo))
  3480. {
  3481. hr = myHLastError();
  3482. _JumpError(hr, error, "myDecodeName");
  3483. }
  3484. hr = myGetCertNameProperty(
  3485. CERT_V1 == pCert->pCertInfo->dwVersion,
  3486. pCertNameInfo,
  3487. pcszFieldOID,
  3488. &pwszName);
  3489. _JumpIfError(hr, error, "myGetCertNameProperty");
  3490. *ppwszField = (WCHAR *) LocalAlloc(
  3491. LMEM_FIXED,
  3492. (wcslen(pwszName) + 1) * sizeof(WCHAR));
  3493. if (NULL == *ppwszField)
  3494. {
  3495. hr = E_OUTOFMEMORY;
  3496. _JumpError(hr, error, "LocalAlloc");
  3497. }
  3498. wcscpy(*ppwszField, pwszName);
  3499. hr = S_OK;
  3500. error:
  3501. if (NULL != pCertNameInfo)
  3502. {
  3503. LocalFree(pCertNameInfo);
  3504. }
  3505. return(hr);
  3506. }
  3507. HRESULT
  3508. myGetCertSubjectCommonName(
  3509. IN CERT_CONTEXT const *pCert,
  3510. OUT WCHAR **ppwszCommonName)
  3511. {
  3512. return myGetCertSubjectField(
  3513. pCert,
  3514. szOID_COMMON_NAME,
  3515. ppwszCommonName);
  3516. }
  3517. HRESULT
  3518. myCertGetNameString(
  3519. IN CERT_CONTEXT const *pcc,
  3520. IN DWORD dwType,
  3521. OUT WCHAR **ppwszSimpleName)
  3522. {
  3523. HRESULT hr;
  3524. WCHAR *pwsz = NULL;
  3525. *ppwszSimpleName = NULL;
  3526. if (CERT_NAME_SIMPLE_DISPLAY_TYPE == dwType &&
  3527. CERT_V1 == pcc->pCertInfo->dwVersion)
  3528. {
  3529. hr = myGetCertSubjectCommonName(pcc, &pwsz);
  3530. _PrintIfError(hr, "myGetCertSubjectCommonName");
  3531. }
  3532. if (NULL == pwsz)
  3533. {
  3534. DWORD cwc = 0;
  3535. for (;;)
  3536. {
  3537. cwc = CertGetNameString(
  3538. pcc,
  3539. CERT_NAME_SIMPLE_DISPLAY_TYPE,
  3540. 0, // dwFlags
  3541. NULL, // pvTypePara
  3542. pwsz,
  3543. cwc);
  3544. if (1 >= cwc)
  3545. {
  3546. hr = HRESULT_FROM_WIN32(ERROR_OBJECT_NOT_FOUND);
  3547. _JumpError(hr, error, "CertGetNameString");
  3548. }
  3549. if (NULL != pwsz)
  3550. {
  3551. break;
  3552. }
  3553. pwsz = (WCHAR *) LocalAlloc(LMEM_FIXED, cwc * sizeof(WCHAR));
  3554. if (NULL == pwsz)
  3555. {
  3556. hr = E_OUTOFMEMORY;
  3557. _JumpError(hr, error, "LocalAlloc");
  3558. }
  3559. }
  3560. }
  3561. *ppwszSimpleName = pwsz;
  3562. pwsz = NULL;
  3563. hr = S_OK;
  3564. error:
  3565. if (NULL != pwsz)
  3566. {
  3567. LocalFree(pwsz);
  3568. }
  3569. return(hr);
  3570. }
  3571. HRESULT
  3572. myCertStrToName(
  3573. IN DWORD dwCertEncodingType,
  3574. IN LPCWSTR pszX500,
  3575. IN DWORD dwStrType,
  3576. IN OPTIONAL void *pvReserved,
  3577. OUT BYTE **ppbEncoded,
  3578. OUT DWORD *pcbEncoded,
  3579. OUT OPTIONAL LPCWSTR *ppszError)
  3580. {
  3581. HRESULT hr;
  3582. *ppbEncoded = NULL;
  3583. *pcbEncoded = 0;
  3584. for (;;)
  3585. {
  3586. if (!CertStrToName(
  3587. dwCertEncodingType,
  3588. pszX500,
  3589. dwStrType,
  3590. pvReserved,
  3591. *ppbEncoded,
  3592. pcbEncoded,
  3593. ppszError))
  3594. {
  3595. hr = myHLastError();
  3596. if (NULL != *ppbEncoded)
  3597. {
  3598. LocalFree(*ppbEncoded);
  3599. *ppbEncoded = NULL;
  3600. }
  3601. _JumpError(hr, error, "CertStrToName");
  3602. }
  3603. if (NULL != *ppbEncoded)
  3604. {
  3605. break;
  3606. }
  3607. *ppbEncoded = (BYTE *) LocalAlloc(LMEM_FIXED, *pcbEncoded);
  3608. if (NULL == *ppbEncoded)
  3609. {
  3610. hr = E_OUTOFMEMORY;
  3611. _JumpError(hr, error, "LocalAlloc");
  3612. }
  3613. }
  3614. hr = S_OK;
  3615. error:
  3616. return(hr);
  3617. }
  3618. HRESULT
  3619. myCertNameToStr(
  3620. IN DWORD dwCertEncodingType,
  3621. IN CERT_NAME_BLOB const *pName,
  3622. IN DWORD dwStrType,
  3623. OUT WCHAR **ppwszName)
  3624. {
  3625. HRESULT hr;
  3626. DWORD cwc = 0;
  3627. WCHAR *pwszName = NULL;
  3628. for (;;)
  3629. {
  3630. cwc = CertNameToStr(
  3631. dwCertEncodingType,
  3632. const_cast<CERT_NAME_BLOB *>(pName),
  3633. dwStrType,
  3634. pwszName,
  3635. cwc);
  3636. if (1 > cwc)
  3637. {
  3638. hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  3639. _JumpError(hr, error, "CertNameToStr");
  3640. }
  3641. if (NULL != pwszName)
  3642. {
  3643. break;
  3644. }
  3645. pwszName = (WCHAR *) LocalAlloc(
  3646. LMEM_FIXED,
  3647. (cwc + 1) * sizeof(WCHAR));
  3648. if (NULL == pwszName)
  3649. {
  3650. hr = E_OUTOFMEMORY;
  3651. _JumpError(hr, error, "LocalAlloc");
  3652. }
  3653. }
  3654. *ppwszName = pwszName;
  3655. pwszName = NULL;
  3656. hr = S_OK;
  3657. error:
  3658. if (NULL != pwszName)
  3659. {
  3660. LocalFree(pwszName);
  3661. }
  3662. return(hr);
  3663. }
  3664. HRESULT
  3665. myVerifyKRACertContext(
  3666. IN CERT_CONTEXT const *pCert,
  3667. IN DWORD dwFlags)
  3668. {
  3669. HRESULT hr;
  3670. WCHAR *pwszzAppPolicies = NULL;
  3671. WCHAR *pwszCrt;
  3672. DWORD dwKeyUsage;
  3673. DWORD cb = sizeof(dwKeyUsage);
  3674. hr = myVerifyCertContextEx(
  3675. pCert,
  3676. dwFlags,
  3677. 0, // dwmsTimeout
  3678. 0, // cUsageOids
  3679. NULL, // apszUsageOids
  3680. 0, // cIssuanceOids
  3681. NULL, // apszIssuanceOids
  3682. HCCE_LOCAL_MACHINE, // hChainEngine
  3683. NULL, // pft
  3684. NULL, // hAdditionalStore
  3685. NULL, // pfnCallback
  3686. NULL, // ppwszMissingIssuer
  3687. NULL, // ppwszzIssuancePolicies
  3688. &pwszzAppPolicies,
  3689. NULL, // ppwszExtendedErrorInfo
  3690. NULL); // pTrustStatus
  3691. _JumpIfError(hr, error, "myVerifyCertContextEx");
  3692. if (!CertGetIntendedKeyUsage(
  3693. X509_ASN_ENCODING,
  3694. pCert->pCertInfo,
  3695. (BYTE*)&dwKeyUsage,
  3696. cb))
  3697. {
  3698. hr = myHLastError();
  3699. _JumpError(hr, error, "CertGetIntendedKeyUsage");
  3700. }
  3701. if(!(dwKeyUsage & CERT_KEY_ENCIPHERMENT_KEY_USAGE))
  3702. {
  3703. hr = CERT_E_WRONG_USAGE;
  3704. _JumpError(hr, error, "Key usage not containing key encipherment");
  3705. }
  3706. hr = CERT_E_WRONG_USAGE;
  3707. for (pwszCrt = pwszzAppPolicies;
  3708. pwszCrt && L'\0' != *pwszCrt;
  3709. pwszCrt += wcslen(pwszCrt) + 1)
  3710. {
  3711. if(0==wcscmp(TEXT(szOID_KP_KEY_RECOVERY_AGENT), pwszCrt))
  3712. {
  3713. hr = S_OK;
  3714. break;
  3715. }
  3716. }
  3717. _JumpIfError(hr, error, "myVerifyKRACertContext");
  3718. error:
  3719. if(pwszzAppPolicies)
  3720. {
  3721. LocalFree(pwszzAppPolicies);
  3722. }
  3723. return(hr);
  3724. }
  3725. HRESULT
  3726. myIsDeltaCRL(
  3727. IN CRL_CONTEXT const *pCRL,
  3728. OUT BOOL *pfIsDeltaCRL)
  3729. {
  3730. HRESULT hr;
  3731. CERT_EXTENSION *pExt;
  3732. *pfIsDeltaCRL = FALSE;
  3733. pExt = CertFindExtension(
  3734. szOID_DELTA_CRL_INDICATOR,
  3735. pCRL->pCrlInfo->cExtension,
  3736. pCRL->pCrlInfo->rgExtension);
  3737. if (NULL != pExt)
  3738. {
  3739. *pfIsDeltaCRL = TRUE;
  3740. }
  3741. hr = S_OK;
  3742. //error:
  3743. return(hr);
  3744. }
  3745. typedef BOOL (WINAPI fnCryptRetrieveObjectByUrlW) (
  3746. IN LPCWSTR pszUrl,
  3747. IN LPCSTR pszObjectOid,
  3748. IN DWORD dwRetrievalFlags,
  3749. IN DWORD dwTimeout,
  3750. OUT LPVOID* ppvObject,
  3751. IN HCRYPTASYNC hAsyncRetrieve,
  3752. IN OPTIONAL PCRYPT_CREDENTIALS pCredentials,
  3753. IN OPTIONAL LPVOID pvVerify,
  3754. IN OPTIONAL PCRYPT_RETRIEVE_AUX_INFO pAuxInfo
  3755. );
  3756. HCERTSTORE
  3757. myUrlCertOpenStore(
  3758. IN DWORD dwFlags,
  3759. IN WCHAR const *pwszURL)
  3760. {
  3761. HRESULT hr;
  3762. HMODULE hModule = NULL;
  3763. fnCryptRetrieveObjectByUrlW *pfn = NULL;
  3764. HCERTSTORE hStore = NULL;
  3765. hModule = LoadLibrary(TEXT("cryptnet.dll"));
  3766. if (NULL == hModule)
  3767. {
  3768. hr = myHLastError();
  3769. _JumpError(hr, error, "LoadLibrary(cryptnet.dll)");
  3770. }
  3771. pfn = (fnCryptRetrieveObjectByUrlW *) GetProcAddress(
  3772. hModule,
  3773. "CryptRetrieveObjectByUrlW");
  3774. if (NULL == pfn)
  3775. {
  3776. hr = myHLastError();
  3777. _JumpError(hr, error, "CryptRetrieveObjectByUrl");
  3778. }
  3779. if (!(*pfn)(
  3780. pwszURL,
  3781. CONTEXT_OID_CAPI2_ANY,
  3782. dwFlags,
  3783. csecLDAPTIMEOUT * 1000, // ms
  3784. (VOID **) &hStore,
  3785. NULL,
  3786. NULL,
  3787. NULL,
  3788. NULL))
  3789. {
  3790. hr = myHLastError();
  3791. _JumpErrorStr(hr, error, "CryptRetrieveObjectByUrl", pwszURL);
  3792. }
  3793. hr = S_OK;
  3794. error:
  3795. if (NULL != hModule)
  3796. {
  3797. FreeLibrary(hModule);
  3798. }
  3799. if (NULL == hStore)
  3800. {
  3801. SetLastError(hr);
  3802. }
  3803. return(hStore);
  3804. }
  3805. HRESULT
  3806. mySetEnablePrivateKeyUsageCount(
  3807. IN HCRYPTPROV hProv,
  3808. IN BOOL fEnabled)
  3809. {
  3810. HRESULT hr;
  3811. DWORD dwEnableKeyUsageCount = fEnabled? 1 : 0;
  3812. if (!CryptSetProvParam(
  3813. hProv,
  3814. PP_CRYPT_COUNT_KEY_USE,
  3815. (BYTE *) &dwEnableKeyUsageCount,
  3816. 0))
  3817. {
  3818. hr = myHLastError();
  3819. _JumpErrorStr(hr, error, "CryptSetProvParam", L"PP_CRYPT_COUNT_KEY_USE");
  3820. }
  3821. hr = S_OK;
  3822. error:
  3823. return(hr);
  3824. }
  3825. HRESULT
  3826. myGetSigningKeyUsageCount(
  3827. IN HCRYPTPROV hProv,
  3828. OUT BOOL *pfSupported,
  3829. OUT BOOL *pfEnabled,
  3830. OPTIONAL OUT ULARGE_INTEGER *puliCount)
  3831. {
  3832. HRESULT hr;
  3833. HCRYPTKEY hKey = NULL;
  3834. DWORD cb;
  3835. DWORD dwEnableKeyUsageCount;
  3836. ULARGE_INTEGER uliCount;
  3837. BOOL fPropSupported;
  3838. *pfSupported = FALSE;
  3839. *pfEnabled = FALSE;
  3840. if (NULL != puliCount)
  3841. {
  3842. puliCount->QuadPart = 0;
  3843. }
  3844. #define CSP_DBGPRINT
  3845. #ifdef CSP_DBGPRINT
  3846. uliCount.QuadPart = 0; // zero only for the debug print
  3847. #endif
  3848. // An old CSP supports setting PP_CRYPT_COUNT_KEY_USE, but not fetching!
  3849. // The new CSP supports setting and fetching PP_CRYPT_COUNT_KEY_USE,
  3850. // but always returns with dwEnableKeyUsageCount set to zero on a freshly
  3851. // acquired hProv (the flag is not persistent, and is only used to control
  3852. // key use counting for newly created keys).
  3853. // Always fetch the actual count, if the CSP supports the feature.
  3854. // To distinguish between supported but not enabled & enabled but not yet
  3855. // used (count is zero), fetching the actual count should fail when not
  3856. // enabled, leaving *pfEnabled set to FALSE.
  3857. cb = sizeof(dwEnableKeyUsageCount);
  3858. fPropSupported = CryptGetProvParam(
  3859. hProv,
  3860. PP_CRYPT_COUNT_KEY_USE,
  3861. (BYTE *) &dwEnableKeyUsageCount,
  3862. &cb,
  3863. 0);
  3864. if (!fPropSupported)
  3865. {
  3866. hr = myHLastError();
  3867. _PrintErrorStr2(
  3868. hr,
  3869. "CryptGetProvParam",
  3870. L"PP_CRYPT_COUNT_KEY_USE",
  3871. NTE_BAD_TYPE);
  3872. }
  3873. else
  3874. {
  3875. *pfSupported = TRUE;
  3876. if (!CryptGetUserKey(hProv, AT_SIGNATURE, &hKey))
  3877. {
  3878. hr = myHLastError();
  3879. _JumpError(hr, error, "CryptGetUserKey");
  3880. }
  3881. cb = sizeof(uliCount);
  3882. if (!CryptGetKeyParam(
  3883. hKey,
  3884. KP_GET_USE_COUNT,
  3885. (BYTE *) &uliCount,
  3886. &cb,
  3887. 0))
  3888. {
  3889. hr = myHLastError();
  3890. _PrintErrorStr2(
  3891. hr,
  3892. "CryptGetKeyParam",
  3893. L"KP_GET_USE_COUNT",
  3894. NTE_BAD_TYPE);
  3895. }
  3896. else
  3897. {
  3898. *pfEnabled = TRUE;
  3899. if (NULL != puliCount)
  3900. {
  3901. *puliCount = uliCount;
  3902. }
  3903. }
  3904. }
  3905. hr = S_OK;
  3906. error:
  3907. #ifdef CSP_DBGPRINT
  3908. DBGPRINT((
  3909. DBG_SS_CERTLIB,
  3910. "myGetSigningKeyUsageCount:%hs hr=%x Supported=%u Enabled=%u Count=%I64u\n",
  3911. fPropSupported? "NEW" : "OLD",
  3912. hr,
  3913. *pfSupported,
  3914. *pfEnabled,
  3915. NULL != puliCount? puliCount->QuadPart : uliCount.QuadPart));
  3916. #endif
  3917. if (NULL != hKey)
  3918. {
  3919. CryptDestroyKey(hKey);
  3920. }
  3921. return(hr);
  3922. }
  3923. HRESULT
  3924. myCertGetEnhancedKeyUsage(
  3925. IN CERT_CONTEXT const *pcc,
  3926. IN DWORD dwFlags,
  3927. OUT CERT_ENHKEY_USAGE **ppUsage)
  3928. {
  3929. HRESULT hr;
  3930. CERT_ENHKEY_USAGE *pUsage = NULL;
  3931. DWORD cb;
  3932. *ppUsage = NULL;
  3933. for (;;)
  3934. {
  3935. if (!CertGetEnhancedKeyUsage(pcc, dwFlags, pUsage, &cb))
  3936. {
  3937. hr = myHLastError();
  3938. _JumpError2(hr, error, "CertGetEnhancedKeyUsage", CRYPT_E_NOT_FOUND);
  3939. }
  3940. if (NULL != pUsage)
  3941. {
  3942. *ppUsage = pUsage;
  3943. pUsage = NULL;
  3944. break;
  3945. }
  3946. pUsage = (CERT_ENHKEY_USAGE *) LocalAlloc(LMEM_FIXED, cb);
  3947. if (NULL == pUsage)
  3948. {
  3949. hr = E_OUTOFMEMORY;
  3950. _JumpError(hr, error, "LocalAlloc");
  3951. }
  3952. }
  3953. hr = S_OK;
  3954. error:
  3955. if (NULL != pUsage)
  3956. {
  3957. LocalFree(pUsage);
  3958. }
  3959. return(hr);
  3960. }
  3961. // if app policies extension was empty, myConvertAppPoliciesToEKU returns S_OK and NULL pbEKU
  3962. HRESULT
  3963. myConvertAppPoliciesToEKU(
  3964. IN BYTE * pbAppPolicies,
  3965. IN DWORD cbAppPolicies,
  3966. OUT BYTE **ppbEKU,
  3967. OUT DWORD *pcbEKU)
  3968. {
  3969. HRESULT hr = S_OK;
  3970. CERT_POLICIES_INFO *pcpsi = NULL;
  3971. DWORD cb, i;
  3972. CERT_ENHKEY_USAGE ceu;
  3973. ZeroMemory(&ceu, sizeof(ceu));
  3974. *ppbEKU = NULL;
  3975. *pcbEKU = 0;
  3976. if (!myDecodeObject(
  3977. X509_ASN_ENCODING,
  3978. X509_CERT_POLICIES,
  3979. pbAppPolicies,
  3980. cbAppPolicies,
  3981. CERTLIB_USE_LOCALALLOC,
  3982. (VOID **) &pcpsi,
  3983. &cb))
  3984. {
  3985. hr = myHLastError();
  3986. _JumpError(hr, error, "myDecodeObject");
  3987. }
  3988. if(0 < pcpsi->cPolicyInfo)
  3989. {
  3990. ceu.rgpszUsageIdentifier = (char **) LocalAlloc(
  3991. LMEM_FIXED,
  3992. pcpsi->cPolicyInfo * sizeof(ceu.rgpszUsageIdentifier[0]));
  3993. if (NULL == ceu.rgpszUsageIdentifier)
  3994. {
  3995. hr = E_OUTOFMEMORY;
  3996. _JumpError(hr, error, "Policy:myLocalAlloc");
  3997. }
  3998. for (i = 0; i < pcpsi->cPolicyInfo; i++)
  3999. {
  4000. ceu.rgpszUsageIdentifier[i] = pcpsi->rgPolicyInfo[i].pszPolicyIdentifier;
  4001. }
  4002. ceu.cUsageIdentifier = pcpsi->cPolicyInfo;
  4003. if (!myEncodeObject(
  4004. X509_ASN_ENCODING,
  4005. X509_ENHANCED_KEY_USAGE,
  4006. &ceu,
  4007. 0,
  4008. CERTLIB_USE_LOCALALLOC,
  4009. ppbEKU,
  4010. pcbEKU))
  4011. {
  4012. hr = myHLastError();
  4013. _JumpError(hr, error, "Policy:myEncodeObject");
  4014. }
  4015. }
  4016. hr = S_OK;
  4017. error:
  4018. if (NULL != ceu.rgpszUsageIdentifier)
  4019. {
  4020. LocalFree(ceu.rgpszUsageIdentifier);
  4021. }
  4022. return hr;
  4023. }