Source code of Windows XP (NT5)
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.

3119 lines
66 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. // History: 17-Oct-96 vich created
  11. //
  12. //---------------------------------------------------------------------------
  13. #include <pch.cpp>
  14. #pragma hdrstop
  15. #include <stdlib.h>
  16. #include "csdisp.h"
  17. #include "cscsp.h"
  18. #include "csprop.h"
  19. #include "csber.h"
  20. HRESULT
  21. myGenerateKeys(
  22. IN WCHAR const *pwszContainer,
  23. OPTIONAL IN WCHAR const *pwszProvName,
  24. IN BOOL fMachineKeySet,
  25. IN DWORD dwKeySpec,
  26. IN DWORD dwProvType,
  27. IN DWORD dwKeySize,
  28. OUT HCRYPTPROV *phProv)
  29. {
  30. HRESULT hr;
  31. HCRYPTKEY hKey = NULL;
  32. DWORD dwFlags = 0;
  33. *phProv = NULL;
  34. if (fMachineKeySet)
  35. {
  36. dwFlags |= CRYPT_MACHINE_KEYSET;
  37. }
  38. // see if the container already exists
  39. if (CryptAcquireContext(
  40. phProv,
  41. pwszContainer,
  42. pwszProvName,
  43. dwProvType,
  44. dwFlags))
  45. {
  46. if (NULL != *phProv)
  47. {
  48. CryptReleaseContext(*phProv, 0);
  49. *phProv = NULL;
  50. }
  51. // container exists -- remove old keys and generate new ones.
  52. if (!CryptAcquireContext(
  53. phProv,
  54. pwszContainer,
  55. pwszProvName,
  56. dwProvType,
  57. CRYPT_DELETEKEYSET | dwFlags))
  58. {
  59. hr = myHLastError();
  60. _JumpError(hr, error, "CryptAcquireContextEx");
  61. }
  62. }
  63. // create new container
  64. if (!CryptAcquireContext(
  65. phProv,
  66. pwszContainer,
  67. pwszProvName,
  68. dwProvType,
  69. CRYPT_NEWKEYSET | dwFlags)) // force new container
  70. {
  71. hr = myHLastError();
  72. _JumpError(hr, error, "CryptAcquireContextEx");
  73. }
  74. // create keys
  75. if (!CryptGenKey(*phProv, dwKeySpec, dwKeySize << 16, &hKey))
  76. {
  77. hr = myHLastError();
  78. _JumpError(hr, error, "CryptGenKey");
  79. }
  80. hr = S_OK;
  81. error:
  82. if (NULL != hKey)
  83. {
  84. CryptDestroyKey(hKey);
  85. }
  86. return(hr);
  87. }
  88. HRESULT
  89. myCryptExportPrivateKey(
  90. IN HCRYPTKEY hKey,
  91. OUT BYTE **ppbKey,
  92. OUT DWORD *pcbKey)
  93. {
  94. HRESULT hr;
  95. BYTE *pbKey = NULL;
  96. *ppbKey = NULL;
  97. // export the key set to a CAPI blob
  98. if (!CryptExportKey(hKey, NULL, PRIVATEKEYBLOB, 0, NULL, pcbKey))
  99. {
  100. hr = myHLastError();
  101. _JumpError2(hr, error, "CryptExportKey", NTE_BAD_KEY_STATE);
  102. }
  103. pbKey = (BYTE *) LocalAlloc(LMEM_FIXED, *pcbKey);
  104. if (NULL == pbKey)
  105. {
  106. hr = E_OUTOFMEMORY;
  107. _JumpError(hr, error, "LocalAlloc");
  108. }
  109. if (!CryptExportKey(hKey, NULL, PRIVATEKEYBLOB, 0, pbKey, pcbKey))
  110. {
  111. hr = myHLastError();
  112. _JumpError(hr, error, "CryptExportKey");
  113. }
  114. *ppbKey = pbKey;
  115. pbKey = NULL;
  116. hr = S_OK;
  117. error:
  118. if (NULL != pbKey)
  119. {
  120. LocalFree(pbKey);
  121. }
  122. return(hr);
  123. }
  124. HRESULT
  125. myVerifyPublicKey(
  126. IN OPTIONAL CERT_CONTEXT const *pCert,
  127. IN BOOL fV1Cert,
  128. IN OPTIONAL CRYPT_KEY_PROV_INFO const *pKeyProvInfo,
  129. IN OPTIONAL CERT_PUBLIC_KEY_INFO const *pPublicKeyInfo,
  130. OPTIONAL OUT BOOL *pfMatchingKey)
  131. {
  132. HRESULT hr;
  133. HCRYPTPROV hProv = NULL;
  134. DWORD dwKeySpec;
  135. DWORD cb;
  136. CERT_PUBLIC_KEY_INFO *pPublicKeyInfoExported = NULL;
  137. if (NULL != pfMatchingKey)
  138. {
  139. *pfMatchingKey = FALSE;
  140. }
  141. if (NULL == pCert ||
  142. !CryptAcquireCertificatePrivateKey(
  143. pCert,
  144. 0, // dwFlags
  145. NULL, // pvReserved
  146. &hProv,
  147. &dwKeySpec,
  148. NULL)) // pfCallerFreeProv
  149. {
  150. if (NULL != pKeyProvInfo)
  151. {
  152. // ok, try passed kpi
  153. if (!myCertSrvCryptAcquireContext(
  154. &hProv,
  155. pKeyProvInfo->pwszContainerName,
  156. pKeyProvInfo->pwszProvName,
  157. pKeyProvInfo->dwProvType,
  158. ~CRYPT_MACHINE_KEYSET & pKeyProvInfo->dwFlags,
  159. (CRYPT_MACHINE_KEYSET & pKeyProvInfo->dwFlags)? TRUE : FALSE))
  160. {
  161. hr = myHLastError();
  162. _JumpErrorStr(
  163. hr,
  164. error,
  165. "myCertSrvCryptAcquireContextEx",
  166. pKeyProvInfo->pwszContainerName);
  167. }
  168. dwKeySpec = pKeyProvInfo->dwKeySpec;
  169. }
  170. else if (NULL != pCert)
  171. {
  172. hr = myHLastError();
  173. _JumpError(hr, error, "CryptAcquireCertificatePrivateKey");
  174. }
  175. else
  176. {
  177. hr = E_POINTER;
  178. _JumpError(hr, error, "No cert & no KeyProvInfo");
  179. }
  180. }
  181. if (!myCryptExportPublicKeyInfo(
  182. hProv,
  183. dwKeySpec,
  184. CERTLIB_USE_LOCALALLOC,
  185. &pPublicKeyInfoExported,
  186. &cb))
  187. {
  188. hr = myHLastError();
  189. _JumpError(hr, error, "myCryptExportPublicKeyInfo");
  190. }
  191. if (NULL == pPublicKeyInfo)
  192. {
  193. if (NULL == pCert)
  194. {
  195. hr = E_POINTER;
  196. _JumpError(hr, error, "No cert & no SubjectPublicKeyInfo");
  197. }
  198. pPublicKeyInfo = &pCert->pCertInfo->SubjectPublicKeyInfo;
  199. }
  200. if (!myCertComparePublicKeyInfo(
  201. X509_ASN_ENCODING,
  202. fV1Cert,
  203. pPublicKeyInfoExported,
  204. pPublicKeyInfo))
  205. {
  206. // by design, (my)CertComparePublicKeyInfo doesn't set last error!
  207. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  208. _JumpError(hr, error, "myCertComparePublicKeyInfo");
  209. }
  210. if (NULL != pfMatchingKey)
  211. {
  212. *pfMatchingKey = TRUE;
  213. }
  214. hr = S_OK;
  215. error:
  216. if (NULL != pPublicKeyInfoExported)
  217. {
  218. LocalFree(pPublicKeyInfoExported);
  219. }
  220. if (NULL != hProv)
  221. {
  222. CryptReleaseContext(hProv, 0);
  223. }
  224. return(hr);
  225. }
  226. DWORD
  227. GetLengthIndex(
  228. IN BYTE bBERTag,
  229. IN DWORD iStart,
  230. IN BYTE const *pb,
  231. IN DWORD cb)
  232. {
  233. DWORD Index = MAXDWORD;
  234. pb += iStart;
  235. if (iStart + 4 < cb && bBERTag == pb[0])
  236. {
  237. // make sure there's room to increment the length in place.
  238. if (0x7f > pb[1])
  239. {
  240. Index = iStart + 1;
  241. }
  242. else if (0x81 == pb[1] && 0xff > pb[2])
  243. {
  244. Index = iStart + 2;
  245. }
  246. }
  247. return(Index);
  248. }
  249. // by design, (my)CertComparePublicKeyInfo doesn't set last error!
  250. BOOL
  251. myCertComparePublicKeyInfo(
  252. IN DWORD dwCertEncodingType,
  253. IN BOOL fV1Cert,
  254. IN CERT_PUBLIC_KEY_INFO const *pPublicKey1,
  255. IN CERT_PUBLIC_KEY_INFO const *pPublicKey2)
  256. {
  257. BOOL fMatch = FALSE;
  258. BYTE *pbKeyNew = NULL;
  259. CERT_PUBLIC_KEY_INFO PublicKey;
  260. if (CertComparePublicKeyInfo(
  261. X509_ASN_ENCODING,
  262. const_cast<CERT_PUBLIC_KEY_INFO *>(pPublicKey1),
  263. const_cast<CERT_PUBLIC_KEY_INFO *>(pPublicKey2)))
  264. {
  265. fMatch = TRUE;
  266. goto error;
  267. }
  268. // If this is a V1 X509 cert with the sign bit set in the first public key
  269. // byte -- without a leading zero pad byte, and there's a wasted byte at
  270. // the end of the public key, insert the zero byte and bump up the lengths.
  271. PublicKey = *pPublicKey2;
  272. if (fV1Cert && BER_SEQUENCE == PublicKey.PublicKey.pbData[0])
  273. {
  274. DWORD iLenSequence;
  275. DWORD iLenModulus;
  276. BYTE *pbKey = PublicKey.PublicKey.pbData;
  277. DWORD cbKey = PublicKey.PublicKey.cbData;
  278. iLenSequence = GetLengthIndex(BER_SEQUENCE, 0, pbKey, cbKey);
  279. if (MAXDWORD == iLenSequence)
  280. {
  281. goto error;
  282. }
  283. iLenModulus = GetLengthIndex(
  284. BER_INTEGER,
  285. iLenSequence + 1,
  286. pbKey,
  287. cbKey);
  288. if (MAXDWORD == iLenSequence)
  289. {
  290. goto error;
  291. }
  292. if (0x80 & pbKey[iLenModulus + 1] &&
  293. (DWORD) (iLenSequence + 1 + pbKey[iLenSequence]) < cbKey)
  294. {
  295. pbKeyNew = (BYTE *) LocalAlloc(LMEM_FIXED, cbKey);
  296. if (NULL == pbKeyNew)
  297. {
  298. _JumpError(E_OUTOFMEMORY, error, "LocalAlloc");
  299. }
  300. CopyMemory(pbKeyNew, pbKey, iLenModulus + 1);
  301. pbKeyNew[iLenSequence]++;
  302. pbKeyNew[iLenModulus]++;
  303. pbKeyNew[iLenModulus + 1] = 0;
  304. CopyMemory(
  305. &pbKeyNew[iLenModulus + 2],
  306. &pbKey[iLenModulus + 1],
  307. cbKey - (iLenModulus + 2));
  308. PublicKey.PublicKey.pbData = pbKeyNew;
  309. if (CertComparePublicKeyInfo(
  310. X509_ASN_ENCODING,
  311. const_cast<CERT_PUBLIC_KEY_INFO *>(pPublicKey1),
  312. &PublicKey))
  313. {
  314. fMatch = TRUE;
  315. }
  316. }
  317. }
  318. error:
  319. if (NULL != pbKeyNew)
  320. {
  321. LocalFree(pbKeyNew);
  322. }
  323. return(fMatch);
  324. }
  325. BOOL
  326. myCryptSignMessage(
  327. IN CRYPT_SIGN_MESSAGE_PARA const *pcsmp,
  328. IN BYTE const *pbToBeSigned,
  329. IN DWORD cbToBeSigned,
  330. IN CERTLIB_ALLOCATOR allocType,
  331. OUT BYTE **ppbSignedBlob,
  332. OUT DWORD *pcbSignedBlob)
  333. {
  334. BOOL b;
  335. *ppbSignedBlob = NULL;
  336. *pcbSignedBlob = 0;
  337. while (TRUE)
  338. {
  339. b = CryptSignMessage(
  340. const_cast<CRYPT_SIGN_MESSAGE_PARA *>(pcsmp),
  341. TRUE, // fDetachedSignature
  342. 1, // cToBeSigned
  343. &pbToBeSigned, // rgpbToBeSigned
  344. &cbToBeSigned, // rgcbToBeSigned
  345. *ppbSignedBlob,
  346. pcbSignedBlob);
  347. if (b && 0 == *pcbSignedBlob)
  348. {
  349. SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_DATA));
  350. b = FALSE;
  351. }
  352. if (!b)
  353. {
  354. if (NULL != *ppbSignedBlob)
  355. {
  356. myFree(*ppbSignedBlob, allocType);
  357. *ppbSignedBlob = NULL;
  358. }
  359. break;
  360. }
  361. if (NULL != *ppbSignedBlob)
  362. {
  363. break;
  364. }
  365. *ppbSignedBlob = (BYTE *) myAlloc(*pcbSignedBlob, allocType);
  366. if (NULL == *ppbSignedBlob)
  367. {
  368. b = FALSE;
  369. break;
  370. }
  371. }
  372. return(b);
  373. }
  374. BOOL
  375. myEncodeCert(
  376. IN DWORD dwEncodingType,
  377. IN CERT_SIGNED_CONTENT_INFO const *pInfo,
  378. IN CERTLIB_ALLOCATOR allocType,
  379. OUT BYTE **ppbEncoded,
  380. OUT DWORD *pcbEncoded)
  381. {
  382. return(myEncodeObject(
  383. dwEncodingType,
  384. X509_CERT,
  385. pInfo,
  386. 0,
  387. allocType,
  388. ppbEncoded,
  389. pcbEncoded));
  390. }
  391. BOOL
  392. myEncodeName(
  393. IN DWORD dwEncodingType,
  394. IN CERT_NAME_INFO const *pInfo,
  395. IN DWORD dwFlags,
  396. IN CERTLIB_ALLOCATOR allocType,
  397. OUT BYTE **ppbEncoded,
  398. OUT DWORD *pcbEncoded)
  399. {
  400. return(myEncodeObject(
  401. dwEncodingType,
  402. X509_UNICODE_NAME,
  403. pInfo,
  404. dwFlags,
  405. allocType,
  406. ppbEncoded,
  407. pcbEncoded));
  408. }
  409. BOOL
  410. myEncodeKeyAttributes(
  411. IN DWORD dwEncodingType,
  412. IN CERT_KEY_ATTRIBUTES_INFO const *pInfo,
  413. IN CERTLIB_ALLOCATOR allocType,
  414. OUT BYTE **ppbEncoded,
  415. OUT DWORD *pcbEncoded)
  416. {
  417. return(myEncodeObject(
  418. dwEncodingType,
  419. X509_KEY_ATTRIBUTES,
  420. pInfo,
  421. 0,
  422. allocType,
  423. ppbEncoded,
  424. pcbEncoded));
  425. }
  426. BOOL
  427. myEncodeKeyUsage(
  428. IN DWORD dwEncodingType,
  429. IN CRYPT_BIT_BLOB const *pInfo,
  430. IN CERTLIB_ALLOCATOR allocType,
  431. OUT BYTE **ppbEncoded,
  432. OUT DWORD *pcbEncoded)
  433. {
  434. return(myEncodeObject(
  435. dwEncodingType,
  436. X509_KEY_USAGE,
  437. pInfo,
  438. 0,
  439. allocType,
  440. ppbEncoded,
  441. pcbEncoded));
  442. }
  443. BOOL
  444. myEncodeKeyAuthority2(
  445. IN DWORD dwEncodingType,
  446. IN CERT_AUTHORITY_KEY_ID2_INFO const *pInfo,
  447. IN CERTLIB_ALLOCATOR allocType,
  448. OUT BYTE **ppbEncoded,
  449. OUT DWORD *pcbEncoded)
  450. {
  451. return(myEncodeObject(
  452. dwEncodingType,
  453. X509_AUTHORITY_KEY_ID2,
  454. pInfo,
  455. 0,
  456. allocType,
  457. ppbEncoded,
  458. pcbEncoded));
  459. }
  460. BOOL
  461. myEncodeToBeSigned(
  462. DWORD dwEncodingType,
  463. CERT_INFO const *pInfo,
  464. IN CERTLIB_ALLOCATOR allocType,
  465. BYTE **ppbEncoded,
  466. DWORD *pcbEncoded)
  467. {
  468. return(myEncodeObject(
  469. dwEncodingType,
  470. X509_CERT_TO_BE_SIGNED,
  471. pInfo,
  472. 0,
  473. allocType,
  474. ppbEncoded,
  475. pcbEncoded));
  476. }
  477. BOOL
  478. myDecodeName(
  479. IN DWORD dwEncodingType,
  480. IN LPCSTR lpszStructType,
  481. IN BYTE const *pbEncoded,
  482. IN DWORD cbEncoded,
  483. IN CERTLIB_ALLOCATOR allocType,
  484. OUT CERT_NAME_INFO **ppNameInfo,
  485. OUT DWORD *pcbNameInfo)
  486. {
  487. return(myDecodeObject(
  488. dwEncodingType,
  489. lpszStructType,
  490. pbEncoded,
  491. cbEncoded,
  492. allocType,
  493. (VOID **) ppNameInfo,
  494. pcbNameInfo));
  495. }
  496. BOOL
  497. myDecodeKeyAuthority(
  498. IN DWORD dwEncodingType,
  499. IN BYTE const *pbEncoded,
  500. IN DWORD cbEncoded,
  501. IN CERTLIB_ALLOCATOR allocType,
  502. OUT CERT_AUTHORITY_KEY_ID_INFO const **ppInfo,
  503. OUT DWORD *pcbInfo)
  504. {
  505. return(myDecodeObject(
  506. dwEncodingType,
  507. X509_AUTHORITY_KEY_ID,
  508. pbEncoded,
  509. cbEncoded,
  510. allocType,
  511. (VOID **) ppInfo,
  512. pcbInfo));
  513. }
  514. BOOL
  515. myDecodeKeyAuthority2(
  516. IN DWORD dwEncodingType,
  517. IN BYTE const *pbEncoded,
  518. IN DWORD cbEncoded,
  519. IN CERTLIB_ALLOCATOR allocType,
  520. OUT CERT_AUTHORITY_KEY_ID2_INFO const **ppInfo,
  521. OUT DWORD *pcbInfo)
  522. {
  523. return(myDecodeObject(
  524. dwEncodingType,
  525. X509_AUTHORITY_KEY_ID2,
  526. pbEncoded,
  527. cbEncoded,
  528. allocType,
  529. (VOID **) ppInfo,
  530. pcbInfo));
  531. }
  532. BOOL
  533. myDecodeExtensions(
  534. IN DWORD dwEncodingType,
  535. IN BYTE const *pbEncoded,
  536. IN DWORD cbEncoded,
  537. IN CERTLIB_ALLOCATOR allocType,
  538. OUT CERT_EXTENSIONS **ppInfo,
  539. OUT DWORD *pcbInfo)
  540. {
  541. return(myDecodeObject(
  542. dwEncodingType,
  543. X509_NAME,
  544. pbEncoded,
  545. cbEncoded,
  546. allocType,
  547. (VOID **) ppInfo,
  548. pcbInfo));
  549. }
  550. BOOL
  551. myDecodeKeyGenRequest(
  552. IN BYTE const *pbRequest,
  553. IN DWORD cbRequest,
  554. IN CERTLIB_ALLOCATOR allocType,
  555. OUT CERT_KEYGEN_REQUEST_INFO **ppKeyGenRequest,
  556. OUT DWORD *pcbKeyGenRequest)
  557. {
  558. return(myDecodeObject(
  559. X509_ASN_ENCODING,
  560. X509_KEYGEN_REQUEST_TO_BE_SIGNED,
  561. pbRequest,
  562. cbRequest,
  563. allocType,
  564. (VOID **) ppKeyGenRequest,
  565. pcbKeyGenRequest));
  566. }
  567. HRESULT
  568. myDecodeCSPProviderAttribute(
  569. IN BYTE const *pbCSPEncoded,
  570. IN DWORD cbCSPEncoded,
  571. OUT CRYPT_CSP_PROVIDER **ppccp)
  572. {
  573. HRESULT hr;
  574. CRYPT_SEQUENCE_OF_ANY *pCSPProviderSeq = NULL;
  575. CERT_NAME_VALUE *pCSPProviderName = NULL;
  576. DWORD cb;
  577. CRYPT_CSP_PROVIDER *pccp;
  578. DWORD dwKeySpec;
  579. CERT_NAME_VALUE *pName = NULL;
  580. CRYPT_BIT_BLOB *pBlob = NULL;
  581. BYTE *pb;
  582. *ppccp = NULL;
  583. if (!myDecodeObject(
  584. X509_ASN_ENCODING,
  585. X509_SEQUENCE_OF_ANY,
  586. pbCSPEncoded,
  587. cbCSPEncoded,
  588. CERTLIB_USE_LOCALALLOC,
  589. (VOID **) &pCSPProviderSeq,
  590. &cb))
  591. {
  592. hr = myHLastError();
  593. _JumpError(hr, error, "myDecodeObject");
  594. }
  595. if (3 > pCSPProviderSeq->cValue)
  596. {
  597. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  598. _JumpError(hr, error, "Sequence count < 3");
  599. }
  600. dwKeySpec = 0;
  601. if (NULL != pCSPProviderSeq->rgValue[0].pbData &&
  602. 0 != pCSPProviderSeq->rgValue[0].cbData)
  603. {
  604. cb = sizeof(dwKeySpec);
  605. if (!CryptDecodeObject(
  606. X509_ASN_ENCODING,
  607. X509_INTEGER,
  608. pCSPProviderSeq->rgValue[0].pbData,
  609. pCSPProviderSeq->rgValue[0].cbData,
  610. 0,
  611. &dwKeySpec,
  612. &cb))
  613. {
  614. hr = myHLastError();
  615. _JumpError(hr, error, "CryptDecodeObject");
  616. }
  617. }
  618. if (NULL != pCSPProviderSeq->rgValue[1].pbData &&
  619. 0 != pCSPProviderSeq->rgValue[1].cbData)
  620. {
  621. if (!myDecodeObject(
  622. X509_ASN_ENCODING,
  623. X509_UNICODE_ANY_STRING,
  624. pCSPProviderSeq->rgValue[1].pbData,
  625. pCSPProviderSeq->rgValue[1].cbData,
  626. CERTLIB_USE_LOCALALLOC,
  627. (VOID **) &pName,
  628. &cb))
  629. {
  630. hr = myHLastError();
  631. _JumpError(hr, error, "myDecodeObject");
  632. }
  633. }
  634. if (NULL != pCSPProviderSeq->rgValue[2].pbData &&
  635. 0 != pCSPProviderSeq->rgValue[2].cbData)
  636. {
  637. if (!myDecodeObject(
  638. X509_ASN_ENCODING,
  639. X509_BITS,
  640. pCSPProviderSeq->rgValue[2].pbData,
  641. pCSPProviderSeq->rgValue[2].cbData,
  642. CERTLIB_USE_LOCALALLOC,
  643. (VOID **) &pBlob,
  644. &cb))
  645. {
  646. hr = myHLastError();
  647. _JumpError(hr, error, "myDecodeObject");
  648. }
  649. }
  650. cb = sizeof(*pccp);
  651. if (NULL != pName && NULL != pName->Value.pbData)
  652. {
  653. cb += POINTERROUND((wcslen((WCHAR const *) pName->Value.pbData) + 1) *
  654. sizeof(WCHAR));
  655. }
  656. if (NULL != pBlob && NULL != pBlob->pbData)
  657. {
  658. cb += POINTERROUND(pBlob->cbData);
  659. }
  660. pccp = (CRYPT_CSP_PROVIDER *) LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, cb);
  661. if (NULL == pccp)
  662. {
  663. hr = E_OUTOFMEMORY;
  664. _JumpError(hr, error, "LocalAlloc");
  665. }
  666. *ppccp = pccp;
  667. pb = (BYTE *) (pccp + 1);
  668. pccp->dwKeySpec = dwKeySpec;
  669. if (NULL != pName->Value.pbData)
  670. {
  671. pccp->pwszProviderName = (WCHAR *) pb;
  672. wcscpy(pccp->pwszProviderName, (WCHAR const *) pName->Value.pbData);
  673. pb += POINTERROUND((wcslen((WCHAR const *) pName->Value.pbData) + 1) *
  674. sizeof(WCHAR));
  675. }
  676. if (NULL != pBlob && NULL != pBlob->pbData)
  677. {
  678. pccp->Signature.pbData = pb;
  679. pccp->Signature.cbData = pBlob->cbData;
  680. pccp->Signature.cUnusedBits = pBlob->cUnusedBits;
  681. CopyMemory(pccp->Signature.pbData, pBlob->pbData, pBlob->cbData);
  682. }
  683. hr = S_OK;
  684. error:
  685. if (NULL != pCSPProviderSeq)
  686. {
  687. LocalFree(pCSPProviderSeq);
  688. }
  689. if (NULL != pName)
  690. {
  691. LocalFree(pName);
  692. }
  693. if (NULL != pBlob)
  694. {
  695. LocalFree(pBlob);
  696. }
  697. return(hr);
  698. }
  699. BOOL
  700. myCertGetCertificateContextProperty(
  701. IN CERT_CONTEXT const *pCertContext,
  702. IN DWORD dwPropId,
  703. IN CERTLIB_ALLOCATOR allocType,
  704. OUT VOID **ppvData,
  705. OUT DWORD *pcbData)
  706. {
  707. BOOL b;
  708. *ppvData = NULL;
  709. *pcbData = 0;
  710. while (TRUE)
  711. {
  712. b = CertGetCertificateContextProperty(
  713. pCertContext,
  714. dwPropId,
  715. *ppvData,
  716. pcbData);
  717. if (b && 0 == *pcbData)
  718. {
  719. SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_DATA));
  720. b = FALSE;
  721. }
  722. if (!b)
  723. {
  724. if (NULL != *ppvData)
  725. {
  726. myFree(*ppvData, allocType);
  727. *ppvData = NULL;
  728. }
  729. break;
  730. }
  731. if (NULL != *ppvData)
  732. {
  733. break;
  734. }
  735. *ppvData = (VOID *) myAlloc(*pcbData, allocType);
  736. if (NULL == *ppvData)
  737. {
  738. b = FALSE;
  739. break;
  740. }
  741. }
  742. return(b);
  743. }
  744. HRESULT
  745. myCertGetKeyProviderInfo(
  746. IN CERT_CONTEXT const *pCert,
  747. OUT CRYPT_KEY_PROV_INFO **ppkpi)
  748. {
  749. HRESULT hr;
  750. DWORD cb;
  751. *ppkpi = NULL;
  752. if (!CertGetCertificateContextProperty(
  753. pCert,
  754. CERT_KEY_PROV_INFO_PROP_ID,
  755. NULL,
  756. &cb))
  757. {
  758. hr = myHLastError();
  759. _JumpError2(
  760. hr,
  761. error,
  762. "CertGetCertificateContextProperty",
  763. CRYPT_E_NOT_FOUND);
  764. }
  765. *ppkpi = (CRYPT_KEY_PROV_INFO *) LocalAlloc(LMEM_FIXED, cb);
  766. if (NULL == *ppkpi)
  767. {
  768. hr = E_OUTOFMEMORY;
  769. _JumpError(hr, error, "LocalAlloc");
  770. }
  771. if (!CertGetCertificateContextProperty(
  772. pCert,
  773. CERT_KEY_PROV_INFO_PROP_ID,
  774. *ppkpi,
  775. &cb))
  776. {
  777. hr = myHLastError();
  778. _JumpError(hr, error, "CertGetCertificateContextProperty");
  779. }
  780. hr = S_OK;
  781. error:
  782. return(hr);
  783. }
  784. HRESULT
  785. myCryptExportKey(
  786. IN HCRYPTKEY hKey,
  787. IN HCRYPTKEY hKeyExp,
  788. IN DWORD dwBlobType,
  789. IN DWORD dwFlags,
  790. OUT BYTE **ppbKey,
  791. OUT DWORD *pcbKey)
  792. {
  793. HRESULT hr;
  794. if (!CryptExportKey(hKey, hKeyExp, dwBlobType, dwFlags, NULL, pcbKey))
  795. {
  796. hr = myHLastError();
  797. _JumpError(hr, error, "CryptExportKey");
  798. }
  799. *ppbKey = (BYTE *) LocalAlloc(LMEM_FIXED, *pcbKey);
  800. if (NULL == *ppbKey)
  801. {
  802. hr = E_OUTOFMEMORY;
  803. _JumpError(hr, error, "LocalAlloc");
  804. }
  805. if (!CryptExportKey(hKey, hKeyExp, dwBlobType, dwFlags, *ppbKey, pcbKey))
  806. {
  807. hr = myHLastError();
  808. LocalFree(*ppbKey);
  809. *ppbKey = NULL;
  810. _JumpError(hr, error, "CryptExportKey");
  811. }
  812. hr = S_OK;
  813. error:
  814. return(hr);
  815. }
  816. HRESULT
  817. myCryptEncrypt(
  818. IN HCRYPTKEY hKey,
  819. IN BYTE const *pbIn,
  820. IN DWORD cbIn,
  821. OUT BYTE **ppbEncrypted,
  822. OUT DWORD *pcbEncrypted)
  823. {
  824. HRESULT hr;
  825. BYTE *pbEncrypted = NULL;
  826. DWORD cbEncrypted;
  827. DWORD cbAlloc;
  828. BOOL fRetried = FALSE;
  829. cbAlloc = cbIn + 64; // may be enough to prevent overflow
  830. while (TRUE)
  831. {
  832. cbEncrypted = cbIn;
  833. pbEncrypted = (BYTE *) LocalAlloc(LMEM_FIXED, cbAlloc);
  834. if (NULL == pbEncrypted)
  835. {
  836. hr = E_OUTOFMEMORY;
  837. _JumpError(hr, error, "LocalAlloc");
  838. }
  839. CopyMemory(pbEncrypted, pbIn, cbIn);
  840. if (!CryptEncrypt(
  841. hKey,
  842. NULL, // hHash
  843. TRUE, // Final
  844. 0, // dwFlags
  845. pbEncrypted, // pbData
  846. &cbEncrypted, // pdwDataLen
  847. cbAlloc)) // dwBufLen
  848. {
  849. hr = myHLastError();
  850. if (!fRetried && HRESULT_FROM_WIN32(ERROR_MORE_DATA) == hr)
  851. {
  852. LocalFree(pbEncrypted);
  853. pbEncrypted = NULL;
  854. DBGPRINT((
  855. DBG_SS_CERTLIB,
  856. "CryptEncrypt(MORE DATA): %u -> %u\n",
  857. cbAlloc,
  858. cbEncrypted));
  859. cbAlloc = cbEncrypted;
  860. fRetried = TRUE;
  861. continue;
  862. }
  863. _JumpError(hr, error, "CryptEncrypt");
  864. }
  865. break;
  866. }
  867. *ppbEncrypted = pbEncrypted;
  868. *pcbEncrypted = cbEncrypted;
  869. pbEncrypted = NULL;
  870. hr = S_OK;
  871. error:
  872. if (NULL != pbEncrypted)
  873. {
  874. LocalFree(pbEncrypted);
  875. }
  876. return(hr);
  877. }
  878. HRESULT
  879. myCryptDecrypt(
  880. IN HCRYPTKEY hKey,
  881. IN BYTE const *pbIn,
  882. IN DWORD cbIn,
  883. OUT BYTE **ppbDecrypted,
  884. OUT DWORD *pcbDecrypted)
  885. {
  886. HRESULT hr;
  887. BYTE *pbDecrypted = NULL;
  888. DWORD cbDecrypted;
  889. // init
  890. *ppbDecrypted = NULL;
  891. *pcbDecrypted = 0;
  892. cbDecrypted = cbIn;
  893. pbDecrypted = (BYTE *) LocalAlloc(LMEM_FIXED, cbIn);
  894. if (NULL == pbDecrypted)
  895. {
  896. hr = E_OUTOFMEMORY;
  897. _JumpError(hr, error, "LocalAlloc");
  898. }
  899. CopyMemory(pbDecrypted, pbIn, cbIn);
  900. if (!CryptDecrypt(
  901. hKey,
  902. NULL, // hHash
  903. TRUE, // Final
  904. 0, // dwFlags
  905. pbDecrypted, // pbData
  906. &cbDecrypted)) // pdwDataLen
  907. {
  908. hr = myHLastError();
  909. _JumpError(hr, error, "CryptDecrypt");
  910. }
  911. *ppbDecrypted = pbDecrypted;
  912. *pcbDecrypted = cbDecrypted;
  913. pbDecrypted = NULL;
  914. hr = S_OK;
  915. error:
  916. if (NULL != pbDecrypted)
  917. {
  918. LocalFree(pbDecrypted);
  919. }
  920. return(hr);
  921. }
  922. HRESULT
  923. myCryptEncryptMessage(
  924. IN ALG_ID algId,
  925. IN DWORD cCertRecipient,
  926. IN CERT_CONTEXT const **rgCertRecipient,
  927. IN BYTE const *pbIn,
  928. IN DWORD cbIn,
  929. IN OPTIONAL HCRYPTPROV hCryptProv,
  930. OUT BYTE **ppbEncrypted,
  931. OUT DWORD *pcbEncrypted)
  932. {
  933. HRESULT hr;
  934. CRYPT_ENCRYPT_MESSAGE_PARA cemp;
  935. CRYPT_OID_INFO const *pOidInfo;
  936. CERT_CONTEXT const *pcc = NULL;
  937. // Convert to an Object Id
  938. pOidInfo = CryptFindOIDInfo(
  939. CRYPT_OID_INFO_ALGID_KEY,
  940. &algId,
  941. CRYPT_ENCRYPT_ALG_OID_GROUP_ID);
  942. if (NULL == pOidInfo)
  943. {
  944. // function is not doc'd to set GetLastError()
  945. hr = CRYPT_E_NOT_FOUND;
  946. DBGPRINT((DBG_SS_ERROR, "algId = %x\n", algId));
  947. _JumpError(hr, error, "CryptFindOIDInfo");
  948. }
  949. // Encrypt the data with the public key
  950. ZeroMemory(&cemp, sizeof(cemp));
  951. cemp.cbSize = sizeof(cemp);
  952. cemp.dwMsgEncodingType = PKCS_7_ASN_ENCODING | CRYPT_ASN_ENCODING;
  953. cemp.ContentEncryptionAlgorithm.pszObjId = const_cast<char *>(pOidInfo->pszOID);
  954. cemp.hCryptProv = hCryptProv;
  955. *pcbEncrypted = 0;
  956. while (TRUE)
  957. {
  958. if (!CryptEncryptMessage(
  959. &cemp,
  960. cCertRecipient, // cRecipientCert
  961. rgCertRecipient, // rgpRecipientCert IN
  962. pbIn, // pbToBeEncrypted
  963. cbIn, // cbToBeEncrypted
  964. *ppbEncrypted, // pbEncryptedBlob
  965. pcbEncrypted)) // pcbEncryptedBlob
  966. {
  967. hr = myHLastError();
  968. if (NULL != *ppbEncrypted)
  969. {
  970. LocalFree(*ppbEncrypted);
  971. *ppbEncrypted = NULL;
  972. }
  973. _JumpError(hr, error, "CryptEncryptMessage");
  974. }
  975. if (NULL != *ppbEncrypted)
  976. {
  977. break;
  978. }
  979. *ppbEncrypted = (BYTE *) LocalAlloc(LMEM_FIXED, *pcbEncrypted);
  980. if (NULL == *ppbEncrypted)
  981. {
  982. hr = E_OUTOFMEMORY;
  983. _JumpError(hr, error, "LocalAlloc");
  984. }
  985. }
  986. hr = S_OK;
  987. error:
  988. CSASSERT(S_OK == hr || FAILED(hr));
  989. return(hr);
  990. }
  991. HRESULT
  992. myCryptDecryptMessage(
  993. IN HCERTSTORE hStore,
  994. IN BYTE const *pbEncrypted,
  995. IN DWORD cbEncrypted,
  996. IN CERTLIB_ALLOCATOR allocType,
  997. OUT BYTE **ppbDecrypted,
  998. OUT DWORD *pcbDecrypted)
  999. {
  1000. HRESULT hr;
  1001. CRYPT_DECRYPT_MESSAGE_PARA cdmp;
  1002. ZeroMemory(&cdmp, sizeof(cdmp));
  1003. cdmp.cbSize = sizeof(cdmp);
  1004. cdmp.dwMsgAndCertEncodingType = PKCS_7_ASN_ENCODING | X509_ASN_ENCODING;
  1005. cdmp.cCertStore = 1;
  1006. cdmp.rghCertStore = &hStore;
  1007. *ppbDecrypted = NULL;
  1008. *pcbDecrypted = 0;
  1009. while (TRUE)
  1010. {
  1011. if (!CryptDecryptMessage(
  1012. &cdmp,
  1013. pbEncrypted,
  1014. cbEncrypted,
  1015. *ppbDecrypted,
  1016. pcbDecrypted,
  1017. NULL)) // ppXchgCert
  1018. {
  1019. hr = myHLastError();
  1020. if (NULL != *ppbDecrypted)
  1021. {
  1022. myFree(*ppbDecrypted, allocType);
  1023. *ppbDecrypted = NULL;
  1024. }
  1025. _JumpError(hr, error, "CryptDecryptMessage");
  1026. }
  1027. if (NULL != *ppbDecrypted)
  1028. {
  1029. break;
  1030. }
  1031. *ppbDecrypted = (BYTE *) myAlloc(*pcbDecrypted, allocType);
  1032. if (NULL == *ppbDecrypted)
  1033. {
  1034. hr = E_OUTOFMEMORY;
  1035. _JumpError(hr, error, "myAlloc");
  1036. }
  1037. }
  1038. hr = S_OK;
  1039. error:
  1040. return(hr);
  1041. }
  1042. HRESULT
  1043. myGetInnerPKCS10(
  1044. IN HCRYPTMSG hMsg,
  1045. IN char const *pszInnerContentObjId,
  1046. OUT CERT_REQUEST_INFO **ppRequest)
  1047. {
  1048. HRESULT hr;
  1049. BYTE *pbContent = NULL;
  1050. DWORD cbContent;
  1051. CMC_DATA_INFO *pcmcData = NULL;
  1052. DWORD cbcmcData;
  1053. CMC_TAGGED_CERT_REQUEST const *pTaggedCertRequest;
  1054. DWORD cbRequest;
  1055. *ppRequest = NULL;
  1056. #define szOID_CT_PKI_DATA_OLDRFC "1.3.6.1.5.5.7.5.2" // BUGBUG: temporary!!!
  1057. if (0 != strcmp(pszInnerContentObjId, szOID_CT_PKI_DATA) &&
  1058. 0 != strcmp(pszInnerContentObjId, szOID_CT_PKI_DATA_OLDRFC))
  1059. {
  1060. hr = CRYPT_E_INVALID_MSG_TYPE;
  1061. _JumpError(hr, error, "Not a CMC request");
  1062. }
  1063. // Get the request content, then search for the PKCS10's public key.
  1064. hr = myCryptMsgGetParam(
  1065. hMsg,
  1066. CMSG_CONTENT_PARAM,
  1067. 0,
  1068. CERTLIB_USE_LOCALALLOC,
  1069. (VOID **) &pbContent,
  1070. &cbContent);
  1071. _JumpIfError(hr, error, "myCryptMsgGetParam");
  1072. if (!myDecodeObject(
  1073. X509_ASN_ENCODING,
  1074. CMC_DATA,
  1075. pbContent,
  1076. cbContent,
  1077. CERTLIB_USE_LOCALALLOC,
  1078. (VOID **) &pcmcData,
  1079. &cbcmcData))
  1080. {
  1081. hr = myHLastError();
  1082. _JumpError(hr, error, "myDecodeObject");
  1083. }
  1084. if (1 != pcmcData->cTaggedRequest ||
  1085. CMC_TAGGED_CERT_REQUEST_CHOICE !=
  1086. pcmcData->rgTaggedRequest[0].dwTaggedRequestChoice)
  1087. {
  1088. hr = CRYPT_E_INVALID_MSG_TYPE;
  1089. _JumpError(hr, error, "Must be 1 PKCS10");
  1090. }
  1091. pTaggedCertRequest = pcmcData->rgTaggedRequest[0].pTaggedCertRequest;
  1092. if (!myDecodeObject(
  1093. X509_ASN_ENCODING,
  1094. X509_CERT_REQUEST_TO_BE_SIGNED,
  1095. pTaggedCertRequest->SignedCertRequest.pbData,
  1096. pTaggedCertRequest->SignedCertRequest.cbData,
  1097. CERTLIB_USE_LOCALALLOC,
  1098. (VOID **) ppRequest,
  1099. &cbRequest))
  1100. {
  1101. hr = myHLastError();
  1102. _JumpError(hr, error, "myDecodeObject");
  1103. }
  1104. hr = S_OK;
  1105. error:
  1106. if (NULL != pbContent)
  1107. {
  1108. LocalFree(pbContent);
  1109. }
  1110. if (NULL != pcmcData)
  1111. {
  1112. LocalFree(pcmcData);
  1113. }
  1114. return(hr);
  1115. }
  1116. HRESULT
  1117. myPKCSEncodeString(
  1118. IN WCHAR const *pwsz,
  1119. OUT BYTE **ppbOut,
  1120. OUT DWORD *pcbOut)
  1121. {
  1122. HRESULT hr = S_OK;
  1123. CERT_NAME_VALUE cnv;
  1124. // encode the string as an IA5 string
  1125. cnv.dwValueType = CERT_RDN_IA5_STRING;
  1126. cnv.Value.pbData = (BYTE *) pwsz;
  1127. cnv.Value.cbData = 0; // Use L'\0' termination for the length
  1128. if (!myEncodeObject(
  1129. X509_ASN_ENCODING,
  1130. X509_UNICODE_NAME_VALUE,
  1131. &cnv,
  1132. 0,
  1133. CERTLIB_USE_LOCALALLOC,
  1134. ppbOut,
  1135. pcbOut))
  1136. {
  1137. hr = myHLastError();
  1138. _JumpError(hr, error, "myEncodeObject");
  1139. }
  1140. error:
  1141. return(hr);
  1142. }
  1143. HRESULT
  1144. myPKCSDecodeString(
  1145. IN BYTE const *pbIn,
  1146. IN DWORD cbIn,
  1147. OUT WCHAR **ppwszOut)
  1148. {
  1149. HRESULT hr = S_OK;
  1150. CERT_NAME_VALUE *pcnv = NULL;
  1151. DWORD cbOut;
  1152. *ppwszOut = NULL;
  1153. // decode the string from an IA5 string
  1154. if (!myDecodeObject(
  1155. X509_ASN_ENCODING,
  1156. X509_UNICODE_NAME_VALUE,
  1157. pbIn,
  1158. cbIn,
  1159. CERTLIB_USE_LOCALALLOC,
  1160. (VOID **) &pcnv,
  1161. &cbOut))
  1162. {
  1163. hr = myHLastError();
  1164. _JumpError(hr, error, "myDecodeObject");
  1165. }
  1166. if (CERT_RDN_IA5_STRING != pcnv->dwValueType)
  1167. {
  1168. hr = E_INVALIDARG;
  1169. _JumpError(hr, error, "Not an IA5 string");
  1170. }
  1171. cbOut = (wcslen((WCHAR const *) pcnv->Value.pbData) + 1) * sizeof(WCHAR);
  1172. *ppwszOut = (WCHAR *) LocalAlloc(LMEM_FIXED, cbOut);
  1173. if (NULL == *ppwszOut)
  1174. {
  1175. hr = E_OUTOFMEMORY;
  1176. _JumpError(hr, error, "LocalAlloc");
  1177. }
  1178. CopyMemory(*ppwszOut, pcnv->Value.pbData, cbOut);
  1179. error:
  1180. if (NULL != pcnv)
  1181. {
  1182. LocalFree(pcnv);
  1183. }
  1184. return(hr);
  1185. }
  1186. HRESULT
  1187. myPKCSEncodeLong(
  1188. IN LONG Value,
  1189. OUT BYTE **ppbOut,
  1190. OUT DWORD *pcbOut)
  1191. {
  1192. HRESULT hr = S_OK;
  1193. // encode the long value
  1194. if (!myEncodeObject(
  1195. X509_ASN_ENCODING,
  1196. X509_INTEGER,
  1197. &Value,
  1198. 0,
  1199. CERTLIB_USE_LOCALALLOC,
  1200. ppbOut,
  1201. pcbOut))
  1202. {
  1203. hr = myHLastError();
  1204. _JumpError(hr, error, "myEncodeObject");
  1205. }
  1206. error:
  1207. return(hr);
  1208. }
  1209. HRESULT
  1210. myPKCSDecodeLong(
  1211. IN BYTE const *pbIn,
  1212. IN DWORD cbIn,
  1213. OUT LONG **ppValue)
  1214. {
  1215. HRESULT hr = S_OK;
  1216. DWORD cbOut;
  1217. // encode the long value
  1218. if (!myDecodeObject(
  1219. X509_ASN_ENCODING,
  1220. X509_INTEGER,
  1221. pbIn,
  1222. cbIn,
  1223. CERTLIB_USE_LOCALALLOC,
  1224. (VOID **) ppValue,
  1225. &cbOut))
  1226. {
  1227. hr = myHLastError();
  1228. _JumpError(hr, error, "myDecodeObject");
  1229. }
  1230. CSASSERT(sizeof(**ppValue) == cbOut);
  1231. error:
  1232. return(hr);
  1233. }
  1234. HRESULT
  1235. myPKCSEncodeDate(
  1236. IN FILETIME const *pft,
  1237. OUT BYTE **ppbOut,
  1238. OUT DWORD *pcbOut)
  1239. {
  1240. HRESULT hr = S_OK;
  1241. // encode the time value
  1242. if (!myEncodeObject(
  1243. X509_ASN_ENCODING,
  1244. X509_CHOICE_OF_TIME,
  1245. pft,
  1246. 0,
  1247. CERTLIB_USE_LOCALALLOC,
  1248. ppbOut,
  1249. pcbOut))
  1250. {
  1251. hr = myHLastError();
  1252. _JumpError(hr, error, "myEncodeObject");
  1253. }
  1254. error:
  1255. return(hr);
  1256. }
  1257. HRESULT
  1258. myPKCSDecodeDate(
  1259. IN BYTE const *pbIn,
  1260. IN DWORD cbIn,
  1261. OUT FILETIME **ppftOut)
  1262. {
  1263. HRESULT hr = S_OK;
  1264. DWORD cbOut;
  1265. // encode the time value
  1266. if (!myDecodeObject(
  1267. X509_ASN_ENCODING,
  1268. X509_CHOICE_OF_TIME,
  1269. pbIn,
  1270. cbIn,
  1271. CERTLIB_USE_LOCALALLOC,
  1272. (VOID **) ppftOut,
  1273. &cbOut))
  1274. {
  1275. hr = myHLastError();
  1276. _JumpError(hr, error, "myDecodeObject");
  1277. }
  1278. CSASSERT(sizeof(**ppftOut) == cbOut);
  1279. error:
  1280. return(hr);
  1281. }
  1282. HRESULT
  1283. myEncodeExtension(
  1284. IN DWORD Flags,
  1285. IN BYTE const *pbIn,
  1286. IN DWORD cbIn,
  1287. OUT BYTE **ppbOut,
  1288. OUT DWORD *pcbOut)
  1289. {
  1290. HRESULT hr = E_INVALIDARG;
  1291. // everyone assumes pbIn != NULL
  1292. if (NULL == pbIn || 0 == cbIn)
  1293. {
  1294. _JumpError(hr, error, "NULL param");
  1295. }
  1296. switch (PROPTYPE_MASK & Flags)
  1297. {
  1298. case PROPTYPE_STRING:
  1299. if (0 == (PROPMARSHAL_LOCALSTRING & Flags) &&
  1300. sizeof(WCHAR) <= cbIn)
  1301. {
  1302. cbIn -= sizeof(WCHAR);
  1303. }
  1304. if (wcslen((WCHAR const *) pbIn) * sizeof(WCHAR) != cbIn)
  1305. {
  1306. _JumpError(hr, error, "bad string len");
  1307. }
  1308. hr = myPKCSEncodeString((WCHAR const *) pbIn, ppbOut, pcbOut);
  1309. _JumpIfError(hr, error, "myPKCSEncodeString");
  1310. break;
  1311. case PROPTYPE_LONG:
  1312. CSASSERT(sizeof(DWORD) == cbIn);
  1313. hr = myPKCSEncodeLong(*(DWORD const *) pbIn, ppbOut, pcbOut);
  1314. _JumpIfError(hr, error, "myPKCSEncodeLong");
  1315. break;
  1316. case PROPTYPE_DATE:
  1317. CSASSERT(sizeof(FILETIME) == cbIn);
  1318. hr = myPKCSEncodeDate((FILETIME const *) pbIn, ppbOut, pcbOut);
  1319. _JumpIfError(hr, error, "myPKCSEncodeDate");
  1320. break;
  1321. default:
  1322. _JumpError(hr, error, "variant type/value");
  1323. }
  1324. hr = S_OK;
  1325. error:
  1326. return(hr);
  1327. }
  1328. HRESULT
  1329. myDecodeExtension(
  1330. IN DWORD Flags,
  1331. IN BYTE const *pbIn,
  1332. IN DWORD cbIn,
  1333. OUT BYTE **ppbOut,
  1334. OUT DWORD *pcbOut)
  1335. {
  1336. HRESULT hr;
  1337. switch (PROPTYPE_MASK & Flags)
  1338. {
  1339. case PROPTYPE_STRING:
  1340. hr = myPKCSDecodeString(pbIn, cbIn, (WCHAR **) ppbOut);
  1341. _JumpIfError(hr, error, "myPKCSDecodeString");
  1342. *pcbOut = wcslen((WCHAR const *) *ppbOut) * sizeof(WCHAR);
  1343. break;
  1344. case PROPTYPE_LONG:
  1345. hr = myPKCSDecodeLong(pbIn, cbIn, (LONG **) ppbOut);
  1346. _JumpIfError(hr, error, "myPKCSDecodeLong");
  1347. *pcbOut = sizeof(LONG);
  1348. break;
  1349. case PROPTYPE_DATE:
  1350. hr = myPKCSDecodeDate(pbIn, cbIn, (FILETIME **) ppbOut);
  1351. _JumpIfError(hr, error, "myPKCSDecodeDate");
  1352. *pcbOut = sizeof(FILETIME);
  1353. break;
  1354. default:
  1355. hr = E_INVALIDARG;
  1356. _JumpError(hr, error, "Flags: Invalid type");
  1357. }
  1358. error:
  1359. return(hr);
  1360. }
  1361. // szOID_ENROLLMENT_NAME_VALUE_PAIR
  1362. BOOL
  1363. myDecodeNameValuePair(
  1364. IN DWORD dwEncodingType,
  1365. IN BYTE const *pbEncoded,
  1366. IN DWORD cbEncoded,
  1367. IN CERTLIB_ALLOCATOR allocType,
  1368. OUT CRYPT_ENROLLMENT_NAME_VALUE_PAIR **ppInfo,
  1369. OUT DWORD *pcbInfo)
  1370. {
  1371. return(myDecodeObject(
  1372. X509_ASN_ENCODING,
  1373. szOID_ENROLLMENT_NAME_VALUE_PAIR,
  1374. pbEncoded,
  1375. cbEncoded,
  1376. allocType,
  1377. (VOID **) ppInfo,
  1378. pcbInfo));
  1379. }
  1380. //+-------------------------------------------------------------------------
  1381. // myVerifyObjIdA - verify the passed pszObjId is valid as per X.208
  1382. //
  1383. // Encode and Decode the Object Id and make sure it survives the round trip.
  1384. // The first number must be 0, 1 or 2.
  1385. // Enforce all characters are digits and dots.
  1386. // Enforce that no dot starts or ends the Object Id, and disallow double dots.
  1387. // Enforce there is at least one dot separator.
  1388. // If the first number is 0 or 1, the second number must be between 0 & 39.
  1389. // If the first number is 2, the second number can be any value.
  1390. //--------------------------------------------------------------------------
  1391. HRESULT
  1392. myVerifyObjIdA(
  1393. IN CHAR const *pszObjId)
  1394. {
  1395. HRESULT hr;
  1396. BYTE *pbEncoded = NULL;
  1397. DWORD cbEncoded;
  1398. CRYPT_ATTRIBUTE ainfo;
  1399. CRYPT_ATTRIBUTE *painfo = NULL;
  1400. DWORD cbainfo;
  1401. char const *psz;
  1402. int i;
  1403. BOOL fNoisy = FALSE;
  1404. hr = E_INVALIDARG;
  1405. for (psz = pszObjId; '\0' != *psz; psz++)
  1406. {
  1407. // must be a digit or a dot separator
  1408. if (!isdigit(*psz))
  1409. {
  1410. if ('.' != *psz)
  1411. {
  1412. _JumpError2(hr, error, "bad ObjId: bad char", hr);
  1413. }
  1414. // can't have dot at start, double dots or dot at end
  1415. if (psz == pszObjId || '.' == psz[1] || '\0' == psz[1])
  1416. {
  1417. _JumpError2(hr, error, "bad ObjId: dot location", hr);
  1418. }
  1419. }
  1420. }
  1421. psz = strchr(pszObjId, '.');
  1422. if (NULL == psz)
  1423. {
  1424. _JumpError2(hr, error, "bad ObjId: must have at least one dot", hr);
  1425. }
  1426. i = atoi(pszObjId);
  1427. switch (i)
  1428. {
  1429. case 0:
  1430. case 1:
  1431. i = atoi(++psz);
  1432. if (0 > i || 39 < i)
  1433. {
  1434. _JumpError(hr, error, "bad ObjId: 0. or 1. must be followed by 0..39");
  1435. }
  1436. break;
  1437. case 2:
  1438. break;
  1439. default:
  1440. fNoisy = TRUE;
  1441. _JumpError(hr, error, "bad ObjId: must start with 0, 1 or 2");
  1442. }
  1443. fNoisy = TRUE;
  1444. ainfo.pszObjId = const_cast<char *>(pszObjId);
  1445. ainfo.cValue = 0;
  1446. ainfo.rgValue = NULL;
  1447. if (!myEncodeObject(
  1448. X509_ASN_ENCODING,
  1449. PKCS_ATTRIBUTE,
  1450. &ainfo,
  1451. 0,
  1452. CERTLIB_USE_LOCALALLOC,
  1453. &pbEncoded,
  1454. &cbEncoded))
  1455. {
  1456. hr = myHLastError();
  1457. _JumpError(hr, error, "myEncodeObject");
  1458. }
  1459. if (!myDecodeObject(
  1460. X509_ASN_ENCODING,
  1461. PKCS_ATTRIBUTE,
  1462. pbEncoded,
  1463. cbEncoded,
  1464. CERTLIB_USE_LOCALALLOC,
  1465. (VOID **) &painfo,
  1466. &cbainfo))
  1467. {
  1468. hr = myHLastError();
  1469. _JumpError(hr, error, "myDecodeObject");
  1470. }
  1471. if (0 != strcmp(pszObjId, painfo->pszObjId))
  1472. {
  1473. hr = E_INVALIDARG;
  1474. _JumpError(hr, error, "bad ObjId: decode mismatch");
  1475. }
  1476. hr = S_OK;
  1477. error:
  1478. if (S_OK != hr)
  1479. {
  1480. DBGPRINT((
  1481. fNoisy? DBG_SS_CERTLIB : DBG_SS_CERTLIBI,
  1482. "myVerifyObjIdA(%hs): %x\n",
  1483. pszObjId,
  1484. hr));
  1485. }
  1486. if (NULL != pbEncoded)
  1487. {
  1488. LocalFree(pbEncoded);
  1489. }
  1490. if (NULL != painfo)
  1491. {
  1492. LocalFree(painfo);
  1493. }
  1494. return(hr);
  1495. }
  1496. HRESULT
  1497. myVerifyObjId(
  1498. IN WCHAR const *pwszObjId)
  1499. {
  1500. HRESULT hr;
  1501. CHAR *pszObjId = NULL;
  1502. if (!ConvertWszToSz(&pszObjId, pwszObjId, -1))
  1503. {
  1504. hr = E_OUTOFMEMORY;
  1505. _JumpError(hr, error, "ConvertWszToSz");
  1506. }
  1507. hr = myVerifyObjIdA(pszObjId);
  1508. _JumpIfErrorStr2(hr, error, "myVerifyObjIdA", pwszObjId, E_INVALIDARG);
  1509. error:
  1510. if (NULL != pszObjId)
  1511. {
  1512. LocalFree(pszObjId);
  1513. }
  1514. return(hr);
  1515. }
  1516. // The returned pszObjId is a constant that must not be freed. CryptFindOIDInfo
  1517. // has a static internal database that is valid until crypt32.dll is unloaded.
  1518. #define GON_GROUP 0x00000001
  1519. #define GON_GENERIC 0x00000002
  1520. typedef struct _OIDNAME
  1521. {
  1522. char const *pszObjId;
  1523. WCHAR const *pwszDisplayName;
  1524. } OIDNAME;
  1525. #if DBG
  1526. #define wszCERTLIB L"(certlib)"
  1527. #else
  1528. #define wszCERTLIB L""
  1529. #endif
  1530. OIDNAME s_aOIDName[] = {
  1531. { szOID_CT_PKI_DATA, L"CMC Data" wszCERTLIB, },
  1532. { szOID_CT_PKI_RESPONSE, L"CMC Response" wszCERTLIB, },
  1533. { szOID_CMC, L"Unsigned CMC Request" wszCERTLIB, },
  1534. { szOID_CMC_TRANSACTION_ID, L"Transaction Id" wszCERTLIB, },
  1535. { szOID_CMC_SENDER_NONCE, L"Sender Nonce" wszCERTLIB, },
  1536. { szOID_CMC_RECIPIENT_NONCE, L"Recipient Nonce" wszCERTLIB, },
  1537. { szOID_CMC_REG_INFO, L"Reg Info" wszCERTLIB, },
  1538. { szOID_CMC_GET_CERT, L"Get Certificate" wszCERTLIB, },
  1539. { szOID_CMC_GET_CRL, L"Get CRL" wszCERTLIB, },
  1540. { szOID_CMC_REVOKE_REQUEST, L"Revoke Request" wszCERTLIB, },
  1541. { szOID_CMC_QUERY_PENDING, L"Query Pending" wszCERTLIB, },
  1542. { szOID_CMC_ID_CONFIRM_CERT_ACCEPTANCE, L"Confirm Certificate Acceptance" wszCERTLIB, },
  1543. { szOID_CMC_STATUS_INFO, L"Unsigned CMC Response" wszCERTLIB, },
  1544. { szOID_CMC_ADD_EXTENSIONS, L"CMC Extensions" wszCERTLIB, },
  1545. { szOID_CMC_ADD_ATTRIBUTES, L"CMC Attributes" wszCERTLIB, },
  1546. { szOID_VERISIGN_ONSITE_JURISDICTION_HASH, L"Jurisdiction Hash" wszCERTLIB, },
  1547. { szOID_PKCS_7_DATA, L"PKCS 7 Data" wszCERTLIB, },
  1548. { szOID_ARCHIVED_KEY_ATTR, L"Archived Key" wszCERTLIB, },
  1549. { szOID_CTL, L"Certifcate Trust List" wszCERTLIB, },
  1550. { szOID_ARCHIVED_KEY_CERT_HASH, L"Archived Key Certificate Hash" wszCERTLIB, },
  1551. { szOID_ROOT_LIST_SIGNER, L"Root List Signer" wszCERTLIB, },
  1552. { szOID_PRIVATEKEY_USAGE_PERIOD, L"Private Key Usage Period" wszCERTLIB, },
  1553. { szOID_REQUEST_CLIENT_INFO, L"Client Information" wszCERTLIB, },
  1554. };
  1555. WCHAR const *
  1556. myGetOIDNameA(
  1557. IN char const *pszObjId)
  1558. {
  1559. CRYPT_OID_INFO const *pInfo = NULL;
  1560. WCHAR const *pwszName = L"";
  1561. DWORD Flags = GON_GROUP | GON_GENERIC;
  1562. if ('+' == *pszObjId)
  1563. {
  1564. Flags = GON_GROUP; // Group lookup only
  1565. pszObjId++;
  1566. }
  1567. else
  1568. if ('-' == *pszObjId)
  1569. {
  1570. Flags = GON_GENERIC; // Generic lookup only
  1571. pszObjId++;
  1572. }
  1573. // First try looking up the ObjectId as an Extension or Attribute, because
  1574. // we get a better Display Name, especially for Subject RDNs: CN, L, etc.
  1575. // If that fails, look it up withoput restricting the group.
  1576. if (GON_GROUP & Flags)
  1577. {
  1578. pInfo = CryptFindOIDInfo(
  1579. CRYPT_OID_INFO_OID_KEY,
  1580. (VOID *) pszObjId,
  1581. CRYPT_EXT_OR_ATTR_OID_GROUP_ID);
  1582. }
  1583. if ((GON_GENERIC & Flags) &&
  1584. (NULL == pInfo ||
  1585. NULL == pInfo->pwszName ||
  1586. L'\0' == pInfo->pwszName[0]))
  1587. {
  1588. pInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, (VOID *) pszObjId, 0);
  1589. }
  1590. if (NULL != pInfo && NULL != pInfo->pwszName && L'\0' != pInfo->pwszName[0])
  1591. {
  1592. pwszName = pInfo->pwszName;
  1593. }
  1594. else
  1595. {
  1596. OIDNAME const *pOIDName;
  1597. for (pOIDName = s_aOIDName;
  1598. pOIDName < &s_aOIDName[ARRAYSIZE(s_aOIDName)];
  1599. pOIDName++)
  1600. {
  1601. if (0 == strcmp(pOIDName->pszObjId, pszObjId))
  1602. {
  1603. pwszName = pOIDName->pwszDisplayName;
  1604. break;
  1605. }
  1606. }
  1607. }
  1608. return(pwszName);
  1609. }
  1610. WCHAR const *
  1611. myGetOIDName(
  1612. IN WCHAR const *pwszObjId)
  1613. {
  1614. char *pszObjId = NULL;
  1615. WCHAR const *pwszName = L"";
  1616. if (!ConvertWszToSz(&pszObjId, pwszObjId, -1))
  1617. {
  1618. _JumpError(E_OUTOFMEMORY, error, "ConvertWszToSz");
  1619. }
  1620. pwszName = myGetOIDNameA(pszObjId);
  1621. error:
  1622. if (NULL != pszObjId)
  1623. {
  1624. LocalFree(pszObjId);
  1625. }
  1626. return(pwszName);
  1627. }
  1628. typedef struct _DUMPFLAGS
  1629. {
  1630. DWORD Mask;
  1631. DWORD Value;
  1632. WCHAR const *pwszDescription;
  1633. } DUMPFLAGS;
  1634. #define _DFBIT(def) { (def), (def), L#def }
  1635. #define _DFBIT2(mask, def) { (mask), (def), L#def }
  1636. DUMPFLAGS g_adfErrorStatus[] =
  1637. {
  1638. _DFBIT(CERT_TRUST_IS_NOT_TIME_VALID),
  1639. _DFBIT(CERT_TRUST_IS_NOT_TIME_NESTED),
  1640. _DFBIT(CERT_TRUST_IS_REVOKED),
  1641. _DFBIT(CERT_TRUST_IS_NOT_SIGNATURE_VALID),
  1642. _DFBIT(CERT_TRUST_IS_NOT_VALID_FOR_USAGE),
  1643. _DFBIT(CERT_TRUST_IS_UNTRUSTED_ROOT),
  1644. _DFBIT(CERT_TRUST_REVOCATION_STATUS_UNKNOWN),
  1645. _DFBIT(CERT_TRUST_IS_CYCLIC),
  1646. _DFBIT(CERT_TRUST_INVALID_EXTENSION),
  1647. _DFBIT(CERT_TRUST_INVALID_POLICY_CONSTRAINTS),
  1648. _DFBIT(CERT_TRUST_INVALID_BASIC_CONSTRAINTS),
  1649. _DFBIT(CERT_TRUST_INVALID_NAME_CONSTRAINTS),
  1650. _DFBIT(CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT),
  1651. _DFBIT(CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT),
  1652. _DFBIT(CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT),
  1653. _DFBIT(CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT),
  1654. _DFBIT(CERT_TRUST_IS_OFFLINE_REVOCATION),
  1655. _DFBIT(CERT_TRUST_NO_ISSUANCE_CHAIN_POLICY),
  1656. _DFBIT(CERT_TRUST_IS_PARTIAL_CHAIN),
  1657. _DFBIT(CERT_TRUST_CTL_IS_NOT_TIME_VALID),
  1658. _DFBIT(CERT_TRUST_CTL_IS_NOT_SIGNATURE_VALID),
  1659. _DFBIT(CERT_TRUST_CTL_IS_NOT_VALID_FOR_USAGE),
  1660. { 0, 0, NULL }
  1661. };
  1662. DUMPFLAGS g_adfInfoStatus[] =
  1663. {
  1664. _DFBIT(CERT_TRUST_HAS_EXACT_MATCH_ISSUER),
  1665. _DFBIT(CERT_TRUST_HAS_KEY_MATCH_ISSUER),
  1666. _DFBIT(CERT_TRUST_HAS_NAME_MATCH_ISSUER),
  1667. _DFBIT(CERT_TRUST_IS_SELF_SIGNED),
  1668. _DFBIT(CERT_TRUST_HAS_PREFERRED_ISSUER),
  1669. _DFBIT(CERT_TRUST_HAS_ISSUANCE_CHAIN_POLICY),
  1670. _DFBIT(CERT_TRUST_HAS_VALID_NAME_CONSTRAINTS),
  1671. _DFBIT(CERT_TRUST_IS_COMPLEX_CHAIN),
  1672. { 0, 0, NULL }
  1673. };
  1674. VOID
  1675. DumpFlags(
  1676. IN DWORD Flags,
  1677. IN WCHAR const *pwsz,
  1678. IN DUMPFLAGS const *pdf)
  1679. {
  1680. for ( ; NULL != pdf->pwszDescription; pdf++)
  1681. {
  1682. if ((Flags & pdf->Mask) == pdf->Value)
  1683. {
  1684. CONSOLEPRINT2((
  1685. MAXDWORD,
  1686. "%ws = %ws\n",
  1687. pwsz,
  1688. pdf->pwszDescription));
  1689. }
  1690. }
  1691. }
  1692. VOID
  1693. DumpUsage(
  1694. IN WCHAR const *pwsz,
  1695. OPTIONAL IN CERT_ENHKEY_USAGE const *pUsage)
  1696. {
  1697. DWORD i;
  1698. if (NULL != pUsage)
  1699. {
  1700. for (i = 0; i < pUsage->cUsageIdentifier; i++)
  1701. {
  1702. CONSOLEPRINT4((
  1703. MAXDWORD,
  1704. "%ws[%u] = %hs %ws\n",
  1705. pwsz,
  1706. i,
  1707. pUsage->rgpszUsageIdentifier[i],
  1708. myGetOIDNameA(pUsage->rgpszUsageIdentifier[i])));
  1709. }
  1710. }
  1711. }
  1712. HRESULT
  1713. WriteBlob(
  1714. IN FILE *pf,
  1715. IN BYTE const *pb,
  1716. IN DWORD cb,
  1717. IN DWORD Flags)
  1718. {
  1719. HRESULT hr;
  1720. char *pszBase64 = NULL;
  1721. hr = myCryptBinaryToStringA(
  1722. pb,
  1723. cb,
  1724. Flags | CRYPT_STRING_NOCR,
  1725. &pszBase64);
  1726. _JumpIfError(hr, error, "myCryptBinaryToStringA");
  1727. fputs(pszBase64, pf);
  1728. fflush(pf);
  1729. if (ferror(pf))
  1730. {
  1731. hr = HRESULT_FROM_WIN32(ERROR_DISK_FULL);
  1732. _JumpError(hr, error, "fputs");
  1733. }
  1734. hr = S_OK;
  1735. error:
  1736. if (NULL != pszBase64)
  1737. {
  1738. LocalFree(pszBase64);
  1739. }
  1740. return(hr);
  1741. }
  1742. VOID
  1743. WriteChain(
  1744. IN CERT_SIMPLE_CHAIN const *pChain,
  1745. IN DWORD SaveIndex,
  1746. IN DWORD ChainIndex)
  1747. {
  1748. HRESULT hr;
  1749. char szPath[MAX_PATH];
  1750. DWORD i;
  1751. FILE *pf = NULL;
  1752. if (0 == GetEnvironmentVariableA("temp", szPath, ARRAYSIZE(szPath)))
  1753. {
  1754. strcpy(szPath, "\\");
  1755. }
  1756. i = strlen(szPath);
  1757. if (0 == i || '\\' != szPath[i - 1])
  1758. {
  1759. szPath[i++] = '\\';
  1760. }
  1761. sprintf(&szPath[i], "Chain%d_%d.txt", SaveIndex, ChainIndex);
  1762. pf = fopen(szPath, "w");
  1763. if (NULL == pf)
  1764. {
  1765. hr = errno;
  1766. _JumpError(hr, error, "fopen");
  1767. }
  1768. for (i = 0; i < pChain->cElement; i++)
  1769. {
  1770. CERT_CHAIN_ELEMENT const *pElement = pChain->rgpElement[i];
  1771. CERT_REVOCATION_INFO *pRevocationInfo;
  1772. if (0 < i)
  1773. {
  1774. fputs("\n", pf);
  1775. }
  1776. fprintf(pf, "Certificate %d:\n", i);
  1777. hr = WriteBlob(
  1778. pf,
  1779. pElement->pCertContext->pbCertEncoded,
  1780. pElement->pCertContext->cbCertEncoded,
  1781. CRYPT_STRING_BASE64HEADER);
  1782. _JumpIfError(hr, error, "WriteBlob");
  1783. pRevocationInfo = pElement->pRevocationInfo;
  1784. if (NULL != pRevocationInfo &&
  1785. CCSIZEOF_STRUCT(CERT_REVOCATION_INFO, pCrlInfo) <=
  1786. pRevocationInfo->cbSize &&
  1787. NULL != pRevocationInfo->pCrlInfo)
  1788. {
  1789. CERT_REVOCATION_CRL_INFO *pCrlInfo;
  1790. pCrlInfo = pRevocationInfo->pCrlInfo;
  1791. if (NULL != pCrlInfo)
  1792. {
  1793. if (NULL != pCrlInfo->pBaseCrlContext)
  1794. {
  1795. fprintf(pf, "\nCRL %d:\n", i);
  1796. hr = WriteBlob(
  1797. pf,
  1798. pCrlInfo->pBaseCrlContext->pbCrlEncoded,
  1799. pCrlInfo->pBaseCrlContext->cbCrlEncoded,
  1800. CRYPT_STRING_BASE64X509CRLHEADER);
  1801. _JumpIfError(hr, error, "WriteBlob");
  1802. }
  1803. if (NULL != pCrlInfo->pDeltaCrlContext)
  1804. {
  1805. fprintf(pf, "\nDelta CRL %d:\n", i);
  1806. hr = WriteBlob(
  1807. pf,
  1808. pCrlInfo->pDeltaCrlContext->pbCrlEncoded,
  1809. pCrlInfo->pDeltaCrlContext->cbCrlEncoded,
  1810. CRYPT_STRING_BASE64X509CRLHEADER);
  1811. _JumpIfError(hr, error, "WriteBlob");
  1812. }
  1813. }
  1814. }
  1815. }
  1816. error:
  1817. if (NULL != pf)
  1818. {
  1819. fclose(pf);
  1820. }
  1821. }
  1822. VOID
  1823. DumpChain(
  1824. IN HRESULT hrVerify,
  1825. IN DWORD dwFlags,
  1826. IN CERT_CONTEXT const *pCert,
  1827. OPTIONAL IN WCHAR const *pwszMissingIssuer,
  1828. IN CERT_CHAIN_CONTEXT const *pChainContext)
  1829. {
  1830. HRESULT hr;
  1831. DWORD i;
  1832. DWORD j;
  1833. static BOOL s_fEnvChecked = FALSE;
  1834. static BOOL s_fDumpEnabled = FALSE;
  1835. static DWORD s_SaveCount = 0;
  1836. static DWORD s_SaveIndex;
  1837. BOOL fDump;
  1838. BOOL fSave;
  1839. if (!s_fEnvChecked)
  1840. {
  1841. WCHAR wszBuf[20];
  1842. if (0 != GetEnvironmentVariable(
  1843. L"CertSrv_Chain",
  1844. wszBuf,
  1845. ARRAYSIZE(wszBuf)))
  1846. {
  1847. s_fDumpEnabled = TRUE;
  1848. s_SaveCount = _wtoi(wszBuf);
  1849. s_SaveIndex = s_SaveCount;
  1850. }
  1851. s_fEnvChecked = TRUE;
  1852. }
  1853. fSave = 0 != s_SaveCount || (CA_VERIFY_FLAGS_SAVE_CHAIN & dwFlags);
  1854. fDump = s_fDumpEnabled ||
  1855. S_OK != hrVerify ||
  1856. (CA_VERIFY_FLAGS_DUMP_CHAIN & dwFlags);
  1857. #if DBG_CERTSRV
  1858. if (DbgIsSSActive(DBG_SS_CERTLIBI))
  1859. {
  1860. fDump = TRUE;
  1861. }
  1862. #endif
  1863. if (!fSave && !fDump)
  1864. {
  1865. return;
  1866. }
  1867. if (0 != s_SaveCount)
  1868. {
  1869. if (++s_SaveIndex >= s_SaveCount)
  1870. {
  1871. s_SaveIndex = 0;
  1872. }
  1873. }
  1874. if (fDump)
  1875. {
  1876. DBGPRINT((MAXDWORD, "-------- Chain Start --------\n"));
  1877. DumpFlags(
  1878. pChainContext->TrustStatus.dwInfoStatus,
  1879. L"ChainContext.dwInfoStatus",
  1880. g_adfInfoStatus);
  1881. DumpFlags(
  1882. pChainContext->TrustStatus.dwErrorStatus,
  1883. L"ChainContext.dwErrorStatus",
  1884. g_adfErrorStatus);
  1885. }
  1886. for (i = 0; i < pChainContext->cChain; i++)
  1887. {
  1888. if (fSave)
  1889. {
  1890. WriteChain(pChainContext->rgpChain[i], s_SaveIndex, i);
  1891. }
  1892. if (fDump)
  1893. {
  1894. DumpFlags(
  1895. pChainContext->rgpChain[i]->TrustStatus.dwInfoStatus,
  1896. L"SimpleChain.dwInfoStatus",
  1897. g_adfInfoStatus);
  1898. DumpFlags(
  1899. pChainContext->rgpChain[i]->TrustStatus.dwErrorStatus,
  1900. L"SimpleChain.dwErrorStatus",
  1901. g_adfErrorStatus);
  1902. }
  1903. for (j = 0; j < pChainContext->rgpChain[i]->cElement; j++)
  1904. {
  1905. CERT_CHAIN_ELEMENT const *pElement;
  1906. pElement = pChainContext->rgpChain[i]->rgpElement[j];
  1907. if (fDump ||
  1908. S_OK != hrVerify ||
  1909. 0 != pElement->TrustStatus.dwErrorStatus)
  1910. {
  1911. WCHAR *pwsz;
  1912. CERT_REVOCATION_INFO *pRevocationInfo;
  1913. CONSOLEPRINT4((
  1914. MAXDWORD,
  1915. "CertContext[%u][%u]: dwInfoStatus=%x dwErrorStatus=%x\n",
  1916. i,
  1917. j,
  1918. pElement->TrustStatus.dwInfoStatus,
  1919. pElement->TrustStatus.dwErrorStatus));
  1920. pwsz = NULL;
  1921. hr = myCertNameToStr(
  1922. X509_ASN_ENCODING,
  1923. &pElement->pCertContext->pCertInfo->Issuer,
  1924. CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
  1925. &pwsz);
  1926. _PrintIfError(hr, "myCertNameToStr");
  1927. if (NULL != pwsz)
  1928. {
  1929. CONSOLEPRINT1((MAXDWORD, " Issuer: %ws\n", pwsz));
  1930. LocalFree(pwsz);
  1931. }
  1932. pwsz = NULL;
  1933. hr = myCertNameToStr(
  1934. X509_ASN_ENCODING,
  1935. &pElement->pCertContext->pCertInfo->Subject,
  1936. CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
  1937. &pwsz);
  1938. _PrintIfError(hr, "myCertNameToStr");
  1939. if (NULL != pwsz)
  1940. {
  1941. CONSOLEPRINT1((MAXDWORD, " Subject: %ws\n", pwsz));
  1942. LocalFree(pwsz);
  1943. }
  1944. DumpFlags(
  1945. pElement->TrustStatus.dwInfoStatus,
  1946. L" CertContext.dwInfoStatus",
  1947. g_adfInfoStatus);
  1948. DumpFlags(
  1949. pElement->TrustStatus.dwErrorStatus,
  1950. L" CertContext.dwErrorStatus",
  1951. g_adfErrorStatus);
  1952. pRevocationInfo = pElement->pRevocationInfo;
  1953. if (NULL != pRevocationInfo &&
  1954. CCSIZEOF_STRUCT(CERT_REVOCATION_INFO, pCrlInfo) <=
  1955. pRevocationInfo->cbSize &&
  1956. NULL != pRevocationInfo->pCrlInfo)
  1957. {
  1958. CERT_REVOCATION_CRL_INFO *pCrlInfo;
  1959. pCrlInfo = pRevocationInfo->pCrlInfo;
  1960. if (NULL != pCrlInfo)
  1961. {
  1962. if (NULL != pCrlInfo->pBaseCrlContext)
  1963. {
  1964. CONSOLEPRINT1((MAXDWORD, " CRL %d:\n", i));
  1965. }
  1966. if (NULL != pCrlInfo->pDeltaCrlContext)
  1967. {
  1968. CONSOLEPRINT1((MAXDWORD, " Delta CRL %d:\n", i));
  1969. }
  1970. }
  1971. }
  1972. if (FIELD_OFFSET(CERT_CHAIN_ELEMENT, pIssuanceUsage) <
  1973. pElement->cbSize)
  1974. {
  1975. DumpUsage(L" Issuance", pElement->pIssuanceUsage);
  1976. }
  1977. if (FIELD_OFFSET(CERT_CHAIN_ELEMENT, pApplicationUsage) <
  1978. pElement->cbSize)
  1979. {
  1980. DumpUsage(L" Application", pElement->pApplicationUsage);
  1981. }
  1982. if (FIELD_OFFSET(CERT_CHAIN_ELEMENT, pwszExtendedErrorInfo) <
  1983. pElement->cbSize &&
  1984. NULL != pElement->pwszExtendedErrorInfo)
  1985. {
  1986. CONSOLEPRINT1((
  1987. MAXDWORD,
  1988. " %ws",
  1989. pElement->pwszExtendedErrorInfo));
  1990. }
  1991. }
  1992. }
  1993. }
  1994. if (fDump)
  1995. {
  1996. if (S_OK != hrVerify)
  1997. {
  1998. WCHAR *pwszCertSubject;
  1999. WCHAR const *pwszErr = myGetErrorMessageText(hrVerify, TRUE);
  2000. if (NULL != pwszMissingIssuer)
  2001. {
  2002. CONSOLEPRINT1((
  2003. MAXDWORD,
  2004. "Missing Issuer: %ws\n",
  2005. pwszMissingIssuer));
  2006. }
  2007. hr = myCertNameToStr(
  2008. X509_ASN_ENCODING,
  2009. &pCert->pCertInfo->Subject,
  2010. CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
  2011. &pwszCertSubject);
  2012. _PrintIfError(hr, "myCertNameToStr");
  2013. if (S_OK == hr)
  2014. {
  2015. CONSOLEPRINT1((MAXDWORD, "Subject: %ws\n", pwszCertSubject));
  2016. LocalFree(pwszCertSubject);
  2017. }
  2018. if (NULL != pwszErr)
  2019. {
  2020. CONSOLEPRINT1((MAXDWORD, "%ws\n", pwszErr));
  2021. LocalFree(const_cast<WCHAR *>(pwszErr));
  2022. }
  2023. }
  2024. DBGPRINT((MAXDWORD, "-------- Chain End --------\n"));
  2025. }
  2026. }
  2027. HRESULT
  2028. SavePolicies(
  2029. OPTIONAL IN CERT_ENHKEY_USAGE const *pUsage,
  2030. OUT WCHAR **ppwszzPolicies)
  2031. {
  2032. HRESULT hr;
  2033. DWORD i;
  2034. DWORD cwc;
  2035. char const *psz;
  2036. WCHAR *pwsz;
  2037. if (NULL != pUsage &&
  2038. 0 != pUsage->cUsageIdentifier &&
  2039. NULL != pUsage->rgpszUsageIdentifier)
  2040. {
  2041. cwc = 1;
  2042. for (i = 0; i < pUsage->cUsageIdentifier; i++)
  2043. {
  2044. cwc += strlen(pUsage->rgpszUsageIdentifier[i]) + 1;
  2045. }
  2046. pwsz = (WCHAR *) LocalAlloc(LMEM_FIXED, cwc * sizeof(WCHAR));
  2047. if (NULL == pwsz)
  2048. {
  2049. hr = E_OUTOFMEMORY;
  2050. _JumpError(hr, error, "LocalAlloc");
  2051. }
  2052. *ppwszzPolicies = pwsz;
  2053. for (i = 0; i < pUsage->cUsageIdentifier; i++)
  2054. {
  2055. psz = pUsage->rgpszUsageIdentifier[i];
  2056. while (*pwsz++ = *psz++)
  2057. ;
  2058. }
  2059. *pwsz++ = L'\0';
  2060. CSASSERT(pwsz == &(*ppwszzPolicies)[cwc]);
  2061. }
  2062. hr = S_OK;
  2063. error:
  2064. return(hr);
  2065. }
  2066. HRESULT
  2067. myVerifyCertContextEx(
  2068. IN CERT_CONTEXT const *pCert,
  2069. IN DWORD dwFlags,
  2070. IN DWORD cUsageOids,
  2071. OPTIONAL IN CHAR const * const *apszUsageOids,
  2072. OPTIONAL IN HCERTCHAINENGINE hChainEngine,
  2073. OPTIONAL IN FILETIME const *pft,
  2074. OPTIONAL IN HCERTSTORE hAdditionalStore,
  2075. OPTIONAL OUT WCHAR **ppwszMissingIssuer,
  2076. OPTIONAL OUT WCHAR **ppwszzIssuancePolicies,
  2077. OPTIONAL OUT WCHAR **ppwszzApplicationPolicies)
  2078. {
  2079. HRESULT hr;
  2080. CERT_CHAIN_PARA ChainParams;
  2081. CERT_CHAIN_POLICY_PARA ChainPolicy;
  2082. CERT_CHAIN_POLICY_STATUS PolicyStatus;
  2083. CERT_CHAIN_CONTEXT const *pChainContext = NULL;
  2084. LPCSTR pszChainPolicyFlags;
  2085. WCHAR *pwszMissingIssuer = NULL;
  2086. CERT_CHAIN_ELEMENT const *pElement;
  2087. if (NULL != ppwszMissingIssuer)
  2088. {
  2089. *ppwszMissingIssuer = NULL;
  2090. }
  2091. if (NULL != ppwszzIssuancePolicies)
  2092. {
  2093. *ppwszzIssuancePolicies = NULL;
  2094. }
  2095. if (NULL != ppwszzApplicationPolicies)
  2096. {
  2097. *ppwszzApplicationPolicies = NULL;
  2098. }
  2099. ZeroMemory(&ChainParams, sizeof(ChainParams));
  2100. ChainParams.cbSize = sizeof(ChainParams);
  2101. ChainParams.RequestedUsage.dwType = USAGE_MATCH_TYPE_AND;
  2102. //ChainParams.RequestedUsage.Usage.cUsageIdentifier = 0;
  2103. //ChainParams.RequestedUsage.Usage.rgpszUsageIdentifier = NULL;
  2104. ChainParams.RequestedUsage.Usage.cUsageIdentifier = cUsageOids;
  2105. ChainParams.RequestedUsage.Usage.rgpszUsageIdentifier = (char **) apszUsageOids;
  2106. DBGPRINT((DBG_SS_CERTLIBI, "Calling CertGetCertificateChain...\n"));
  2107. // Get the chain and verify the cert:
  2108. if (!CertGetCertificateChain(
  2109. hChainEngine, // hChainEngine
  2110. pCert, // pCertContext
  2111. const_cast<FILETIME *>(pft), // pTime
  2112. hAdditionalStore, // hAdditionalStore
  2113. &ChainParams, // pChainPara
  2114. (dwFlags & CA_VERIFY_FLAGS_NO_REVOCATION)?
  2115. 0 : CERT_CHAIN_REVOCATION_CHECK_CHAIN,
  2116. NULL, // pvReserved
  2117. &pChainContext)) // ppChainContext
  2118. {
  2119. hr = myHLastError();
  2120. _JumpError(hr, error, "CertGetCertificateChain");
  2121. }
  2122. DBGPRINT((DBG_SS_CERTLIBI, "CertGetCertificateChain done\n"));
  2123. ZeroMemory(&ChainPolicy, sizeof(ChainPolicy));
  2124. ChainPolicy.cbSize = sizeof(ChainPolicy);
  2125. ChainPolicy.dwFlags = CERT_CHAIN_POLICY_IGNORE_NOT_TIME_NESTED_FLAG;
  2126. //ChainPolicy.pvExtraPolicyPara = NULL;
  2127. ZeroMemory(&PolicyStatus, sizeof(PolicyStatus));
  2128. PolicyStatus.cbSize = sizeof(PolicyStatus);
  2129. //PolicyStatus.dwError = 0;
  2130. PolicyStatus.lChainIndex = -1;
  2131. PolicyStatus.lElementIndex = -1;
  2132. //PolicyStatus.pvExtraPolicyStatus = NULL;
  2133. // use NTAuth policy if (usage oids being added) & (caller asks us to check(EntCA))
  2134. pszChainPolicyFlags =
  2135. (NULL != apszUsageOids && (CA_VERIFY_FLAGS_NT_AUTH & dwFlags))?
  2136. CERT_CHAIN_POLICY_NT_AUTH : CERT_CHAIN_POLICY_BASE;
  2137. if (!CertVerifyCertificateChainPolicy(
  2138. pszChainPolicyFlags,
  2139. pChainContext,
  2140. &ChainPolicy,
  2141. &PolicyStatus))
  2142. {
  2143. hr = myHLastError();
  2144. _JumpError(hr, error, "CertVerifyCertificateChainPolicy");
  2145. }
  2146. hr = myHError(PolicyStatus.dwError);
  2147. if ((CA_VERIFY_FLAGS_IGNORE_OFFLINE | CA_VERIFY_FLAGS_NO_REVOCATION) & dwFlags)
  2148. {
  2149. if (CRYPT_E_NO_REVOCATION_CHECK == hr ||
  2150. CRYPT_E_REVOCATION_OFFLINE == hr)
  2151. {
  2152. hr = S_OK;
  2153. }
  2154. }
  2155. if (CA_VERIFY_FLAGS_ALLOW_UNTRUSTED_ROOT & dwFlags)
  2156. {
  2157. if (CERT_E_UNTRUSTEDROOT == hr)
  2158. {
  2159. hr = S_OK;
  2160. }
  2161. }
  2162. if (S_OK != hr &&
  2163. 0 < pChainContext->cChain &&
  2164. 0 < pChainContext->rgpChain[0]->cElement)
  2165. {
  2166. pElement = pChainContext->rgpChain[0]->rgpElement[
  2167. pChainContext->rgpChain[0]->cElement - 1];
  2168. if (0 == (CERT_TRUST_IS_SELF_SIGNED & pElement->TrustStatus.dwInfoStatus))
  2169. {
  2170. HRESULT hr2;
  2171. hr2 = myCertNameToStr(
  2172. X509_ASN_ENCODING,
  2173. &pElement->pCertContext->pCertInfo->Issuer,
  2174. CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
  2175. &pwszMissingIssuer);
  2176. _PrintIfError(hr2, "myCertNameToStr");
  2177. }
  2178. }
  2179. DumpChain(hr, dwFlags, pCert, pwszMissingIssuer, pChainContext);
  2180. if (NULL != ppwszMissingIssuer)
  2181. {
  2182. *ppwszMissingIssuer = pwszMissingIssuer;
  2183. pwszMissingIssuer = NULL;
  2184. }
  2185. _JumpIfError(hr, error, "PolicyStatus.dwError");
  2186. pElement = pChainContext->rgpChain[0]->rgpElement[0];
  2187. if (NULL != ppwszzIssuancePolicies &&
  2188. FIELD_OFFSET(CERT_CHAIN_ELEMENT, pIssuanceUsage) < pElement->cbSize)
  2189. {
  2190. hr = SavePolicies(
  2191. pElement->pIssuanceUsage,
  2192. ppwszzIssuancePolicies);
  2193. _JumpIfError(hr, error, "SavePolicies");
  2194. }
  2195. if (NULL != ppwszzApplicationPolicies &&
  2196. FIELD_OFFSET(CERT_CHAIN_ELEMENT, pApplicationUsage) < pElement->cbSize)
  2197. {
  2198. hr = SavePolicies(
  2199. pElement->pApplicationUsage,
  2200. ppwszzApplicationPolicies);
  2201. _JumpIfError(hr, error, "SavePolicies");
  2202. }
  2203. error:
  2204. if (S_OK != hr)
  2205. {
  2206. if (NULL != ppwszzIssuancePolicies && NULL != *ppwszzIssuancePolicies)
  2207. {
  2208. LocalFree(*ppwszzIssuancePolicies);
  2209. *ppwszzIssuancePolicies = NULL;
  2210. }
  2211. }
  2212. if (NULL != pwszMissingIssuer)
  2213. {
  2214. LocalFree(pwszMissingIssuer);
  2215. }
  2216. if (NULL != pChainContext)
  2217. {
  2218. CertFreeCertificateChain(pChainContext);
  2219. }
  2220. return(hr);
  2221. }
  2222. HRESULT
  2223. myVerifyCertContext(
  2224. IN CERT_CONTEXT const *pCert,
  2225. IN DWORD dwFlags,
  2226. IN DWORD cUsageOids,
  2227. OPTIONAL IN CHAR const * const *apszUsageOids,
  2228. OPTIONAL IN HCERTCHAINENGINE hChainEngine,
  2229. OPTIONAL IN HCERTSTORE hAdditionalStore,
  2230. OPTIONAL OUT WCHAR **ppwszMissingIssuer)
  2231. {
  2232. HRESULT hr;
  2233. hr = myVerifyCertContextEx(
  2234. pCert,
  2235. dwFlags,
  2236. cUsageOids,
  2237. apszUsageOids,
  2238. hChainEngine,
  2239. NULL, // pft
  2240. hAdditionalStore,
  2241. ppwszMissingIssuer,
  2242. NULL, // ppwszzIssuancePolicies
  2243. NULL); // ppwszzApplicationPolicies
  2244. _JumpIfError2(hr, error, "myVerifyCertContextEx", hr);
  2245. error:
  2246. return(hr);
  2247. }
  2248. HRESULT
  2249. myIsFirstSigner(
  2250. IN CERT_NAME_BLOB const *pNameBlob,
  2251. OUT BOOL *pfFirst)
  2252. {
  2253. HRESULT hr;
  2254. CERT_NAME_INFO *pNameInfo = NULL;
  2255. DWORD cbNameInfo;
  2256. DWORD i;
  2257. *pfFirst = FALSE;
  2258. if (!myDecodeName(
  2259. X509_ASN_ENCODING,
  2260. X509_UNICODE_NAME,
  2261. pNameBlob->pbData,
  2262. pNameBlob->cbData,
  2263. CERTLIB_USE_LOCALALLOC,
  2264. &pNameInfo,
  2265. &cbNameInfo))
  2266. {
  2267. hr = myHLastError();
  2268. _JumpError(hr, error, "myDecodeName");
  2269. }
  2270. for (i = 0; i < pNameInfo->cRDN; i++)
  2271. {
  2272. CERT_RDN const *prdn;
  2273. DWORD j;
  2274. prdn = &pNameInfo->rgRDN[i];
  2275. for (j = 0; j < prdn->cRDNAttr; j++)
  2276. {
  2277. if (0 == strcmp(
  2278. prdn->rgRDNAttr[j].pszObjId,
  2279. szOID_RDN_DUMMY_SIGNER))
  2280. {
  2281. *pfFirst = TRUE;
  2282. i = pNameInfo->cRDN; // terminate outer loop
  2283. break;
  2284. }
  2285. }
  2286. }
  2287. hr = S_OK;
  2288. error:
  2289. if (NULL != pNameInfo)
  2290. {
  2291. LocalFree(pNameInfo);
  2292. }
  2293. return(hr);
  2294. }
  2295. HCERTSTORE
  2296. myPFXImportCertStore(
  2297. IN CRYPT_DATA_BLOB *ppfx,
  2298. OPTIONAL IN WCHAR const *pwszPassword,
  2299. IN DWORD dwFlags)
  2300. {
  2301. HCERTSTORE hStore;
  2302. HRESULT hr;
  2303. if (NULL == pwszPassword)
  2304. {
  2305. pwszPassword = L""; // Try empty password first, then NULL
  2306. }
  2307. while (TRUE)
  2308. {
  2309. hStore = PFXImportCertStore(ppfx, pwszPassword, dwFlags);
  2310. if (NULL == hStore)
  2311. {
  2312. hr = myHLastError();
  2313. if (HRESULT_FROM_WIN32(ERROR_INVALID_PASSWORD) != hr ||
  2314. NULL == pwszPassword ||
  2315. L'\0' != *pwszPassword)
  2316. {
  2317. _JumpError2(
  2318. hr,
  2319. error,
  2320. "PFXImportCertStore",
  2321. HRESULT_FROM_WIN32(ERROR_INVALID_PASSWORD));
  2322. }
  2323. pwszPassword = NULL; // empty password failed; try NULL
  2324. continue;
  2325. }
  2326. break;
  2327. }
  2328. error:
  2329. return(hStore);
  2330. }
  2331. // No longer support versions before IE3.02 - Auth2 update, advisory only
  2332. HRESULT
  2333. CertCheck7f(
  2334. IN CERT_CONTEXT const *pcc)
  2335. {
  2336. HRESULT hr;
  2337. DWORD State;
  2338. DWORD Index1;
  2339. DWORD Index2;
  2340. DWORD cwcField;
  2341. WCHAR wszField[128];
  2342. DWORD cwcObjectId;
  2343. WCHAR wszObjectId[128];
  2344. WCHAR const *pwszObjectIdDescription = NULL;
  2345. cwcField = sizeof(wszField)/sizeof(wszField[0]);
  2346. cwcObjectId = sizeof(wszObjectId)/sizeof(wszObjectId[0]);
  2347. hr = myCheck7f(
  2348. pcc->pbCertEncoded,
  2349. pcc->cbCertEncoded,
  2350. FALSE,
  2351. &State,
  2352. &Index1,
  2353. &Index2,
  2354. &cwcField,
  2355. wszField,
  2356. &cwcObjectId,
  2357. wszObjectId,
  2358. &pwszObjectIdDescription); // Static: do not free!
  2359. _JumpIfError(hr, error, "myCheck7f");
  2360. if (CHECK7F_NONE != State)
  2361. {
  2362. hr = CERTSRV_E_ENCODING_LENGTH;
  2363. #if DBG_CERTSRV
  2364. WCHAR wszBuf[2048];
  2365. wcscpy(wszBuf, wszField);
  2366. if (0 != Index1)
  2367. {
  2368. wsprintf(
  2369. &wszBuf[wcslen(wszBuf)],
  2370. 0 != Index2? L"[%u,%u]" : L"[%u]",
  2371. Index1 - 1,
  2372. Index2 - 1);
  2373. }
  2374. if (0 != cwcObjectId)
  2375. {
  2376. wcscat(wszBuf, L" ObjectId=");
  2377. wcscat(wszBuf, wszObjectId);
  2378. }
  2379. if (NULL != pwszObjectIdDescription)
  2380. {
  2381. wcscat(wszBuf, L" (");
  2382. wcscat(wszBuf, pwszObjectIdDescription);
  2383. wcscat(wszBuf, L")");
  2384. }
  2385. DBGPRINT((DBG_SS_CERTLIB, "CertCheck7f: %ws, hr=%x\n", wszBuf, hr));
  2386. #endif // DBG_CERTSRV
  2387. }
  2388. error:
  2389. return(hr);
  2390. }
  2391. HRESULT
  2392. myAddCertToStore(
  2393. IN HCERTSTORE hStore,
  2394. IN CERT_CONTEXT const *pCertContext,
  2395. OPTIONAL IN CRYPT_KEY_PROV_INFO const *pkpi,
  2396. OPTIONAL OUT CERT_CONTEXT const **ppCert)
  2397. {
  2398. HRESULT hr;
  2399. CERT_CONTEXT const *pcc = NULL;
  2400. if (NULL != ppCert)
  2401. {
  2402. *ppCert = NULL;
  2403. }
  2404. // for root cert, if it shows related private key, it will
  2405. // pfx import failure for other applications
  2406. // Add as encoded blob to avoid all properties, key prov info, etc.
  2407. if (!CertAddEncodedCertificateToStore(
  2408. hStore,
  2409. X509_ASN_ENCODING,
  2410. pCertContext->pbCertEncoded,
  2411. pCertContext->cbCertEncoded,
  2412. NULL != pkpi?
  2413. CERT_STORE_ADD_REPLACE_EXISTING :
  2414. CERT_STORE_ADD_USE_EXISTING,
  2415. &pcc)) // ppCertContext
  2416. {
  2417. hr = myHLastError();
  2418. _JumpError(hr, error, "CertAddEncodedCertificateToStore");
  2419. }
  2420. if (NULL != pkpi)
  2421. {
  2422. if (!CertSetCertificateContextProperty(
  2423. pcc,
  2424. CERT_KEY_PROV_INFO_PROP_ID,
  2425. 0,
  2426. pkpi))
  2427. {
  2428. hr = myHLastError();
  2429. _JumpError(hr, error, "CertSetCertificateContextProperty");
  2430. }
  2431. }
  2432. if (NULL != ppCert)
  2433. {
  2434. *ppCert = pcc;
  2435. pcc = NULL;
  2436. }
  2437. hr = S_OK;
  2438. error:
  2439. if (NULL != pcc)
  2440. {
  2441. CertFreeCertificateContext(pcc);
  2442. }
  2443. return(hr);
  2444. }
  2445. HRESULT
  2446. mySaveChainAndKeys(
  2447. IN CERT_SIMPLE_CHAIN const *pSimpleChain,
  2448. IN WCHAR const *pwszStore,
  2449. IN DWORD dwStoreFlags,
  2450. IN CRYPT_KEY_PROV_INFO const *pkpi,
  2451. OPTIONAL IN CERT_CONTEXT const **ppCert)
  2452. {
  2453. HRESULT hr;
  2454. HCERTSTORE hRootStore = NULL;
  2455. HCERTSTORE hCAStore = NULL;
  2456. HCERTSTORE hMyStore = NULL;
  2457. DWORD i;
  2458. if (NULL != ppCert)
  2459. {
  2460. *ppCert = NULL;
  2461. }
  2462. hRootStore = CertOpenStore(
  2463. CERT_STORE_PROV_SYSTEM_REGISTRY_W,
  2464. X509_ASN_ENCODING,
  2465. NULL, // hProv
  2466. dwStoreFlags,
  2467. wszROOT_CERTSTORE);
  2468. if (NULL == hRootStore)
  2469. {
  2470. hr = myHLastError();
  2471. _JumpErrorStr(hr, error, "CertOpenStore", wszROOT_CERTSTORE);
  2472. }
  2473. hCAStore = CertOpenStore(
  2474. CERT_STORE_PROV_SYSTEM_REGISTRY_W,
  2475. X509_ASN_ENCODING,
  2476. NULL, // hProv
  2477. dwStoreFlags,
  2478. wszCA_CERTSTORE);
  2479. if (NULL == hCAStore)
  2480. {
  2481. hr = myHLastError();
  2482. _JumpErrorStr(hr, error, "CertOpenStore", wszCA_CERTSTORE);
  2483. }
  2484. hMyStore = CertOpenStore(
  2485. CERT_STORE_PROV_SYSTEM_REGISTRY_W,
  2486. X509_ASN_ENCODING,
  2487. NULL, // hProv
  2488. dwStoreFlags,
  2489. pwszStore);
  2490. if (NULL == hMyStore)
  2491. {
  2492. hr = myHLastError();
  2493. _JumpErrorStr(hr, error, "CertOpenStore", pwszStore);
  2494. }
  2495. for (i = 0; i < pSimpleChain->cElement; i++)
  2496. {
  2497. CERT_CONTEXT const *pcc = pSimpleChain->rgpElement[i]->pCertContext;
  2498. HCERTSTORE hStore;
  2499. // CertCheck7f(pcc);
  2500. // if leaf CA cert, add to MY store
  2501. if (0 == i)
  2502. {
  2503. PCCERT_CONTEXT pFoundCC = CertFindCertificateInStore(
  2504. hMyStore,
  2505. X509_ASN_ENCODING,
  2506. 0,
  2507. CERT_FIND_EXISTING,
  2508. pcc,
  2509. NULL);
  2510. if(!pFoundCC)
  2511. {
  2512. hr = myAddCertToStore(hMyStore, pcc, pkpi, ppCert);
  2513. _JumpIfError(hr, error, "myAddCertToStore");
  2514. }
  2515. else
  2516. {
  2517. if(ppCert)
  2518. {
  2519. *ppCert = pFoundCC;
  2520. }
  2521. else
  2522. {
  2523. CertFreeCertificateContext(pFoundCC);
  2524. }
  2525. }
  2526. }
  2527. // if root cert, add to ROOT store (without key); else add to CA store
  2528. hStore = hCAStore;
  2529. if (CERT_TRUST_IS_SELF_SIGNED &
  2530. pSimpleChain->rgpElement[i]->TrustStatus.dwInfoStatus)
  2531. {
  2532. hStore = hRootStore;
  2533. }
  2534. hr = myAddCertToStore(hStore, pcc, NULL, NULL);
  2535. _JumpIfError(hr, error, "myAddCertToStore");
  2536. }
  2537. hr = S_OK;
  2538. error:
  2539. if (NULL != hRootStore)
  2540. {
  2541. CertCloseStore(hRootStore, CERT_CLOSE_STORE_CHECK_FLAG);
  2542. }
  2543. if (NULL != hCAStore)
  2544. {
  2545. CertCloseStore(hCAStore, CERT_CLOSE_STORE_CHECK_FLAG);
  2546. }
  2547. if (NULL != hMyStore)
  2548. {
  2549. CertCloseStore(hMyStore, CERT_CLOSE_STORE_CHECK_FLAG);
  2550. }
  2551. return(hr);
  2552. }
  2553. HRESULT
  2554. myGetNameId(
  2555. IN CERT_CONTEXT const *pCACert,
  2556. OUT DWORD *pdwNameId)
  2557. {
  2558. HRESULT hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  2559. CERT_EXTENSION const *pExt;
  2560. DWORD NameId;
  2561. DWORD cb;
  2562. *pdwNameId = MAXDWORD;
  2563. pExt = CertFindExtension(
  2564. szOID_CERTSRV_CA_VERSION,
  2565. pCACert->pCertInfo->cExtension,
  2566. pCACert->pCertInfo->rgExtension);
  2567. if (NULL == pExt)
  2568. {
  2569. // This API doesn't set LastError
  2570. _JumpError(hr, error, "CertFindExtension(CA Version)");
  2571. }
  2572. cb = sizeof(NameId);
  2573. NameId = 0;
  2574. if (!CryptDecodeObject(
  2575. X509_ASN_ENCODING,
  2576. X509_INTEGER,
  2577. pExt->Value.pbData,
  2578. pExt->Value.cbData,
  2579. 0,
  2580. &NameId,
  2581. &cb))
  2582. {
  2583. hr = myHLastError();
  2584. _JumpError(hr, error, "CryptDecodeObject");
  2585. }
  2586. *pdwNameId = NameId;
  2587. hr = S_OK;
  2588. error:
  2589. return(hr);
  2590. }
  2591. HRESULT
  2592. myCertGetNameString(
  2593. IN CERT_CONTEXT const *pcc,
  2594. IN DWORD dwType,
  2595. OUT WCHAR **ppwszSimpleName)
  2596. {
  2597. HRESULT hr;
  2598. WCHAR *pwsz = NULL;
  2599. DWORD cwc;
  2600. *ppwszSimpleName = NULL;
  2601. cwc = 0;
  2602. while (TRUE)
  2603. {
  2604. cwc = CertGetNameString(
  2605. pcc,
  2606. CERT_NAME_SIMPLE_DISPLAY_TYPE,
  2607. 0, // dwFlags
  2608. NULL, // pvTypePara
  2609. pwsz,
  2610. cwc);
  2611. if (1 >= cwc)
  2612. {
  2613. hr = HRESULT_FROM_WIN32(ERROR_OBJECT_NOT_FOUND);
  2614. _JumpError(hr, error, "CertGetNameString");
  2615. }
  2616. if (NULL != pwsz)
  2617. {
  2618. break;
  2619. }
  2620. pwsz = (WCHAR *) LocalAlloc(LMEM_FIXED, cwc * sizeof(WCHAR));
  2621. if (NULL == pwsz)
  2622. {
  2623. hr = E_OUTOFMEMORY;
  2624. _JumpError(hr, error, "LocalAlloc");
  2625. }
  2626. }
  2627. *ppwszSimpleName = pwsz;
  2628. pwsz = NULL;
  2629. hr = S_OK;
  2630. error:
  2631. if (NULL != pwsz)
  2632. {
  2633. LocalFree(pwsz);
  2634. }
  2635. return(hr);
  2636. }
  2637. HRESULT
  2638. myCertStrToName(
  2639. IN DWORD dwCertEncodingType,
  2640. IN LPCWSTR pszX500,
  2641. IN DWORD dwStrType,
  2642. IN OPTIONAL void *pvReserved,
  2643. OUT BYTE **ppbEncoded,
  2644. OUT DWORD *pcbEncoded,
  2645. OUT OPTIONAL LPCWSTR *ppszError)
  2646. {
  2647. HRESULT hr;
  2648. *ppbEncoded = NULL;
  2649. *pcbEncoded = 0;
  2650. while (TRUE)
  2651. {
  2652. if (!CertStrToName(
  2653. dwCertEncodingType,
  2654. pszX500,
  2655. dwStrType,
  2656. pvReserved,
  2657. *ppbEncoded,
  2658. pcbEncoded,
  2659. ppszError))
  2660. {
  2661. hr = myHLastError();
  2662. if (NULL != *ppbEncoded)
  2663. {
  2664. LocalFree(*ppbEncoded);
  2665. *ppbEncoded = NULL;
  2666. }
  2667. _JumpError(hr, error, "CertStrToName");
  2668. }
  2669. if (NULL != *ppbEncoded)
  2670. {
  2671. break;
  2672. }
  2673. *ppbEncoded = (BYTE *) LocalAlloc(LMEM_FIXED, *pcbEncoded);
  2674. if (NULL == *ppbEncoded)
  2675. {
  2676. hr = E_OUTOFMEMORY;
  2677. _JumpError(hr, error, "LocalAlloc");
  2678. }
  2679. }
  2680. hr = S_OK;
  2681. error:
  2682. return(hr);
  2683. }
  2684. HRESULT
  2685. myCertNameToStr(
  2686. IN DWORD dwCertEncodingType,
  2687. IN CERT_NAME_BLOB const *pName,
  2688. IN DWORD dwStrType,
  2689. OUT WCHAR **ppwszName)
  2690. {
  2691. HRESULT hr;
  2692. DWORD cwc = 0;
  2693. WCHAR *pwszName = NULL;
  2694. while (TRUE)
  2695. {
  2696. cwc = CertNameToStr(
  2697. dwCertEncodingType,
  2698. const_cast<CERT_NAME_BLOB *>(pName),
  2699. dwStrType,
  2700. pwszName,
  2701. cwc);
  2702. if (1 > cwc)
  2703. {
  2704. hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  2705. _JumpError(hr, error, "CertNameToStr");
  2706. }
  2707. if (NULL != pwszName)
  2708. {
  2709. break;
  2710. }
  2711. pwszName = (WCHAR *) LocalAlloc(
  2712. LMEM_FIXED,
  2713. (cwc + 1) * sizeof(WCHAR));
  2714. if (NULL == pwszName)
  2715. {
  2716. hr = E_OUTOFMEMORY;
  2717. _JumpError(hr, error, "LocalAlloc");
  2718. }
  2719. }
  2720. *ppwszName = pwszName;
  2721. pwszName = NULL;
  2722. hr = S_OK;
  2723. error:
  2724. if (NULL != pwszName)
  2725. {
  2726. LocalFree(pwszName);
  2727. }
  2728. return(hr);
  2729. }
  2730. HRESULT
  2731. myVerifyKRACertContext(
  2732. IN CERT_CONTEXT const *pCert,
  2733. IN DWORD dwFlags)
  2734. {
  2735. HRESULT hr;
  2736. WCHAR *pwszzAppPolicies = NULL;
  2737. WCHAR *pwszCrt;
  2738. hr = myVerifyCertContextEx(
  2739. pCert,
  2740. dwFlags,
  2741. 0, // cUsageOids
  2742. NULL, // apszUsageOids
  2743. HCCE_LOCAL_MACHINE, // hChainEngine
  2744. NULL, // pft
  2745. NULL, // hAdditionalStore
  2746. NULL, // ppwszMissingIssuer
  2747. NULL, // ppwszzIssuancePolicies
  2748. &pwszzAppPolicies);
  2749. _JumpIfError(hr, error, "myVerifyCertContextEx");
  2750. hr = CERT_E_WRONG_USAGE;
  2751. for(pwszCrt = pwszzAppPolicies;
  2752. pwszCrt && L'\0' != *pwszCrt;
  2753. pwszCrt = pwszCrt + wcslen(pwszzAppPolicies) + 1)
  2754. {
  2755. if(0==wcscmp(TEXT(szOID_KP_KEY_RECOVERY_AGENT), pwszCrt))
  2756. {
  2757. hr = S_OK;
  2758. break;
  2759. }
  2760. }
  2761. _JumpIfError(hr, error, "myVerifyKRACertContext");
  2762. error:
  2763. if(pwszzAppPolicies)
  2764. {
  2765. LocalFree(pwszzAppPolicies);
  2766. }
  2767. return(hr);
  2768. }