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.

1663 lines
43 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1995 - 1999
  6. //
  7. // File: pvkhlpr.cpp
  8. //
  9. // Contents: Private Key Helper APIs
  10. //
  11. // Functions: PrivateKeyLoad
  12. // PrivateKeySave
  13. // PrivateKeyLoadFromMemory
  14. // PrivateKeySaveToMemory
  15. // PrivateKeyAcquireContextFromMemory
  16. // PrivateKeyReleaseContext
  17. //
  18. // Note: Base CSP also exports/imports the public key with the
  19. // private key.
  20. //
  21. // History: 10-May-96 philh created
  22. //--------------------------------------------------------------------------
  23. #include "global.hxx"
  24. #include <assert.h>
  25. #include <string.h>
  26. #include <memory.h>
  27. #include <objbase.h>
  28. #include "pvk.h"
  29. #include "unicode.h"
  30. //+-------------------------------------------------------------------------
  31. // Private Key file definitions
  32. //
  33. // The file consists of the FILE_HDR followed by cbEncryptData optional
  34. // bytes used to encrypt the private key and then the private key.
  35. // The private key is encrypted according to dwEncryptType.
  36. //
  37. // The public key is included with the private key.
  38. //--------------------------------------------------------------------------
  39. typedef struct _FILE_HDR {
  40. DWORD dwMagic;
  41. DWORD dwVersion;
  42. DWORD dwKeySpec;
  43. DWORD dwEncryptType;
  44. DWORD cbEncryptData;
  45. DWORD cbPvk;
  46. } FILE_HDR, *PFILE_HDR;
  47. #define PVK_FILE_VERSION_0 0
  48. #define PVK_MAGIC 0xb0b5f11e
  49. // Private key encrypt types
  50. #define PVK_NO_ENCRYPT 0
  51. #define PVK_RC4_PASSWORD_ENCRYPT 1
  52. #define PVK_RC2_CBC_PASSWORD_ENCRYPT 2
  53. #define MAX_PVK_FILE_LEN 4096
  54. #define MAX_BOB_FILE_LEN (4096*4)
  55. typedef BOOL (* PFNWRITE)(HANDLE h, void * p, DWORD cb);
  56. typedef BOOL (* PFNREAD)(HANDLE h, void * p, DWORD cb);
  57. //+-------------------------------------------------------------------------
  58. // Private key helper allocation and free functions
  59. //--------------------------------------------------------------------------
  60. void *PvkAlloc(
  61. IN size_t cbBytes
  62. )
  63. {
  64. void *pv;
  65. pv = malloc(cbBytes);
  66. if (pv == NULL)
  67. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  68. return pv;
  69. }
  70. void PvkFree(
  71. IN void *pv
  72. )
  73. {
  74. free(pv);
  75. }
  76. //+-------------------------------------------------------------------------
  77. // Read & Write to file function
  78. //--------------------------------------------------------------------------
  79. static BOOL WriteToFile(HANDLE h, void * p, DWORD cb) {
  80. DWORD cbBytesWritten;
  81. return(WriteFile(h, p, cb, &cbBytesWritten, NULL));
  82. }
  83. static BOOL ReadFromFile(
  84. IN HANDLE h,
  85. IN void * p,
  86. IN DWORD cb
  87. )
  88. {
  89. DWORD cbBytesRead;
  90. return(ReadFile(h, p, cb, &cbBytesRead, NULL) && cbBytesRead == cb);
  91. }
  92. //+-------------------------------------------------------------------------
  93. // Read & Write to memory fucntion
  94. //--------------------------------------------------------------------------
  95. typedef struct _MEMINFO {
  96. BYTE * pb;
  97. DWORD cb;
  98. DWORD cbSeek;
  99. } MEMINFO, * PMEMINFO;
  100. static BOOL WriteToMemory(HANDLE h, void * p, DWORD cb) {
  101. PMEMINFO pMemInfo = (PMEMINFO) h;
  102. // See if we have room. The caller will detect an error after the final
  103. // write
  104. if(pMemInfo->cbSeek + cb <= pMemInfo->cb)
  105. // copy the bytes
  106. memcpy(&pMemInfo->pb[pMemInfo->cbSeek], p, cb);
  107. pMemInfo->cbSeek += cb;
  108. return(TRUE);
  109. }
  110. static BOOL ReadFromMemory(
  111. IN HANDLE h,
  112. IN void * p,
  113. IN DWORD cb
  114. )
  115. {
  116. PMEMINFO pMemInfo = (PMEMINFO) h;
  117. if (pMemInfo->cbSeek + cb <= pMemInfo->cb) {
  118. // copy the bytes
  119. memcpy(p, &pMemInfo->pb[pMemInfo->cbSeek], cb);
  120. pMemInfo->cbSeek += cb;
  121. return TRUE;
  122. } else {
  123. SetLastError(ERROR_END_OF_MEDIA);
  124. return FALSE;
  125. }
  126. }
  127. static BOOL GetPasswordKey(
  128. IN HCRYPTPROV hProv,
  129. IN ALG_ID Algid,
  130. IN PASSWORD_TYPE PasswordType,
  131. IN HWND hwndOwner,
  132. IN LPCWSTR pwszKeyName,
  133. IN BOOL fNoPassDlg,
  134. IN BYTE *pbSalt,
  135. IN DWORD cbSalt,
  136. OUT HCRYPTKEY *phEncryptKey,
  137. OUT OPTIONAL HCRYPTKEY *ph40EncryptKey = NULL,
  138. OUT OPTIONAL HCRYPTKEY *ph128EncryptKey = NULL
  139. )
  140. {
  141. BOOL fResult;
  142. BYTE *pbAllocPassword = NULL;
  143. BYTE *pbPassword;
  144. DWORD cbPassword;
  145. HCRYPTHASH hHash = 0;
  146. HCRYPTKEY hEncryptKey = 0;
  147. BYTE rgbDefPw [] = { 0x43, 0x52, 0x41, 0x50 };
  148. DWORD cbDefPw = sizeof(rgbDefPw);
  149. if (ph40EncryptKey)
  150. *ph40EncryptKey = 0;
  151. if (ph128EncryptKey)
  152. *ph128EncryptKey = 0;
  153. if (fNoPassDlg) {
  154. pbPassword = rgbDefPw;
  155. cbPassword = cbDefPw;
  156. } else {
  157. if (IDOK != PvkDlgGetKeyPassword(
  158. PasswordType,
  159. hwndOwner,
  160. pwszKeyName,
  161. &pbAllocPassword,
  162. &cbPassword
  163. )) {
  164. SetLastError(PVK_HELPER_PASSWORD_CANCEL);
  165. goto ErrorReturn;
  166. }
  167. pbPassword = pbAllocPassword;
  168. }
  169. if (cbPassword) {
  170. if (!CryptCreateHash(hProv, CALG_SHA, 0, 0, &hHash))
  171. goto ErrorReturn;
  172. if (cbSalt) {
  173. if (!CryptHashData(hHash, pbSalt, cbSalt, 0))
  174. goto ErrorReturn;
  175. }
  176. if (!CryptHashData(hHash, pbPassword, cbPassword, 0))
  177. goto ErrorReturn;
  178. if (!CryptDeriveKey(hProv, Algid, hHash, 0, &hEncryptKey))
  179. goto ErrorReturn;
  180. if (ph40EncryptKey) {
  181. if (!CryptDeriveKey(hProv, Algid, hHash,
  182. 40 << 16, // dwFlags, dwBitLen in upper WORD
  183. ph40EncryptKey)) {
  184. *ph40EncryptKey = NULL;
  185. }
  186. }
  187. if (ph128EncryptKey) {
  188. if (!CryptDeriveKey(hProv, Algid, hHash,
  189. 128 << 16, // dwFlags, dwBitLen in upper WORD
  190. ph128EncryptKey)) {
  191. *ph128EncryptKey = NULL;
  192. }
  193. }
  194. }
  195. fResult = TRUE;
  196. goto CommonReturn;
  197. ErrorReturn:
  198. fResult = FALSE;
  199. if (hEncryptKey) {
  200. CryptDestroyKey(hEncryptKey);
  201. hEncryptKey = 0;
  202. }
  203. CommonReturn:
  204. if (pbAllocPassword)
  205. PvkFree(pbAllocPassword);
  206. if (hHash)
  207. CryptDestroyHash(hHash);
  208. *phEncryptKey = hEncryptKey;
  209. return fResult;
  210. }
  211. // Support backwards compatibility with Bob's storage file which contains
  212. // a snap shot of the keys as they are stored in the registry. Note, for
  213. // win95, the registry values are decrypted before being written to the file.
  214. static BOOL LoadBobKey(
  215. IN HCRYPTPROV hCryptProv,
  216. IN HANDLE hRead,
  217. IN PFNREAD pfnRead,
  218. IN DWORD cbBobKey,
  219. IN HWND hwndOwner,
  220. IN LPCWSTR pwszKeyName,
  221. IN DWORD dwFlags,
  222. IN OUT OPTIONAL DWORD *pdwKeySpec,
  223. IN PFILE_HDR pHdr // header has already been read
  224. );
  225. static BOOL LoadKeyW(
  226. IN HCRYPTPROV hCryptProv,
  227. IN HANDLE hRead,
  228. IN PFNREAD pfnRead,
  229. IN DWORD cbKeyData,
  230. IN HWND hwndOwner,
  231. IN LPCWSTR pwszKeyName,
  232. IN DWORD dwFlags,
  233. IN OUT OPTIONAL DWORD *pdwKeySpec
  234. )
  235. {
  236. BOOL fResult;
  237. FILE_HDR Hdr;
  238. HCRYPTKEY hDecryptKey = 0;
  239. HCRYPTKEY h40DecryptKey = 0;
  240. HCRYPTKEY h128DecryptKey = 0;
  241. HCRYPTKEY hKey = 0;
  242. BYTE *pbEncryptData = NULL;
  243. BYTE *pbPvk = NULL;
  244. DWORD cbPvk;
  245. // Read the file header and verify
  246. if (!pfnRead(hRead, &Hdr, sizeof(Hdr))) goto BadPvkFile;
  247. if (Hdr.dwMagic != PVK_MAGIC)
  248. // Try to load as Bob's storage file containing streams for the
  249. // private and public keys. Bob made a copy of the cryptography
  250. // registry key values.
  251. //
  252. // Note, Bob now has two different formats for storing the private
  253. // key information. See LoadBobKey for details.
  254. fResult = LoadBobKey(hCryptProv, hRead, pfnRead, cbKeyData, hwndOwner,
  255. pwszKeyName, dwFlags, pdwKeySpec, &Hdr);
  256. else {
  257. // Treat as a "normal" private key file
  258. cbPvk = Hdr.cbPvk;
  259. if (Hdr.dwVersion != PVK_FILE_VERSION_0 ||
  260. Hdr.cbEncryptData > MAX_PVK_FILE_LEN ||
  261. cbPvk == 0 || cbPvk > MAX_PVK_FILE_LEN)
  262. goto BadPvkFile;
  263. if (pdwKeySpec) {
  264. DWORD dwKeySpec = *pdwKeySpec;
  265. *pdwKeySpec = Hdr.dwKeySpec;
  266. if (dwKeySpec && dwKeySpec != Hdr.dwKeySpec) {
  267. SetLastError(PVK_HELPER_WRONG_KEY_TYPE);
  268. goto ErrorReturn;
  269. }
  270. }
  271. if (Hdr.cbEncryptData) {
  272. // Read the encrypt data
  273. if (NULL == (pbEncryptData = (BYTE *) PvkAlloc(Hdr.cbEncryptData)))
  274. goto ErrorReturn;
  275. if (!pfnRead(hRead, pbEncryptData, Hdr.cbEncryptData))
  276. goto BadPvkFile;
  277. }
  278. // Allocate and read the private key
  279. if (NULL == (pbPvk = (BYTE *) PvkAlloc(cbPvk)))
  280. goto ErrorReturn;
  281. if (!pfnRead(hRead, pbPvk, cbPvk))
  282. goto BadPvkFile;
  283. // Get symmetric key to decrypt the private key
  284. switch (Hdr.dwEncryptType) {
  285. case PVK_NO_ENCRYPT:
  286. break;
  287. case PVK_RC4_PASSWORD_ENCRYPT:
  288. if (!GetPasswordKey(hCryptProv, CALG_RC4,
  289. ENTER_PASSWORD, hwndOwner,
  290. pwszKeyName, FALSE, pbEncryptData, Hdr.cbEncryptData,
  291. &hDecryptKey, &h40DecryptKey, &h128DecryptKey))
  292. goto ErrorReturn;
  293. break;
  294. case PVK_RC2_CBC_PASSWORD_ENCRYPT:
  295. if (!GetPasswordKey(hCryptProv, CALG_RC2,
  296. ENTER_PASSWORD, hwndOwner,
  297. pwszKeyName, FALSE, pbEncryptData, Hdr.cbEncryptData,
  298. &hDecryptKey, &h40DecryptKey, &h128DecryptKey))
  299. goto ErrorReturn;
  300. break;
  301. default:
  302. goto BadPvkFile;
  303. }
  304. // Decrypt and import the private key
  305. hKey = 0;
  306. fResult = CryptImportKey(hCryptProv, pbPvk, cbPvk, hDecryptKey, dwFlags,
  307. &hKey);
  308. if (!fResult && h40DecryptKey) {
  309. hKey = 0;
  310. fResult = CryptImportKey(hCryptProv, pbPvk, cbPvk,
  311. h40DecryptKey, dwFlags, &hKey);
  312. }
  313. if (!fResult && h128DecryptKey) {
  314. hKey = 0;
  315. fResult = CryptImportKey(hCryptProv, pbPvk, cbPvk,
  316. h128DecryptKey, dwFlags, &hKey);
  317. }
  318. }
  319. goto CommonReturn;
  320. BadPvkFile:
  321. SetLastError(PVK_HELPER_BAD_PVK_FILE);
  322. if (pdwKeySpec)
  323. *pdwKeySpec = 0;
  324. ErrorReturn:
  325. fResult = FALSE;
  326. CommonReturn:
  327. if (pbEncryptData)
  328. PvkFree(pbEncryptData);
  329. if (pbPvk)
  330. PvkFree(pbPvk);
  331. if (hDecryptKey)
  332. CryptDestroyKey(hDecryptKey);
  333. if (h40DecryptKey)
  334. CryptDestroyKey(h40DecryptKey);
  335. if (h128DecryptKey)
  336. CryptDestroyKey(h128DecryptKey);
  337. if (hKey)
  338. CryptDestroyKey(hKey);
  339. return fResult;
  340. }
  341. static BOOL LoadKeyA(
  342. IN HCRYPTPROV hCryptProv,
  343. IN HANDLE hRead,
  344. IN PFNREAD pfnRead,
  345. IN DWORD cbKeyData,
  346. IN HWND hwndOwner,
  347. IN LPCTSTR pszKeyName,
  348. IN DWORD dwFlags,
  349. IN OUT OPTIONAL DWORD *pdwKeySpec
  350. )
  351. {
  352. WIDEN(pszKeyName, pwszKeyName);
  353. // LPWSTR pwszKeyName = MkWStr((char*) pszKeyName);
  354. BOOL fResult = LoadKeyW(hCryptProv,
  355. hRead,
  356. pfnRead,
  357. cbKeyData,
  358. hwndOwner,
  359. pwszKeyName,
  360. dwFlags,
  361. pdwKeySpec);
  362. return fResult;
  363. }
  364. static BOOL SaveKeyW(
  365. IN HCRYPTPROV hCryptProv,
  366. IN HANDLE hWrite,
  367. IN PFNREAD pfnWrite,
  368. IN DWORD dwKeySpec, // either AT_SIGNATURE or AT_KEYEXCHANGE
  369. IN HWND hwndOwner,
  370. IN LPCWSTR pwszKeyName,
  371. IN DWORD dwFlags,
  372. IN BOOL fNoPassDlg
  373. )
  374. {
  375. BOOL fResult;
  376. FILE_HDR Hdr;
  377. HCRYPTKEY hEncryptKey = 0;
  378. HCRYPTKEY hKey = 0;
  379. BYTE *pbEncryptData = NULL; // Not allocated
  380. BYTE *pbPvk = NULL;
  381. DWORD cbPvk;
  382. BYTE rgbSalt[16];
  383. // Initialize the header record
  384. memset(&Hdr, 0, sizeof(Hdr));
  385. Hdr.dwMagic = PVK_MAGIC;
  386. Hdr.dwVersion = PVK_FILE_VERSION_0;
  387. Hdr.dwKeySpec = dwKeySpec;
  388. // Generate random salt
  389. if (!CryptGenRandom(hCryptProv, sizeof(rgbSalt), rgbSalt))
  390. goto ErrorReturn;
  391. // Get symmetric key to use to encrypt the private key
  392. #if 1
  393. if (!GetPasswordKey(hCryptProv, CALG_RC4,
  394. #else
  395. if (!GetPasswordKey(hCryptProv, CALG_RC2,
  396. #endif
  397. CREATE_PASSWORD, hwndOwner, pwszKeyName,
  398. fNoPassDlg, rgbSalt, sizeof(rgbSalt), &hEncryptKey))
  399. goto ErrorReturn;
  400. if (hEncryptKey) {
  401. #if 1
  402. Hdr.dwEncryptType = PVK_RC4_PASSWORD_ENCRYPT;
  403. #else
  404. Hdr.dwEncryptType = PVK_RC2_CBC_PASSWORD_ENCRYPT;
  405. #endif
  406. Hdr.cbEncryptData = sizeof(rgbSalt);
  407. pbEncryptData = rgbSalt;
  408. } else
  409. Hdr.dwEncryptType = PVK_NO_ENCRYPT;
  410. // Allocate, encrypt and export the private key
  411. if (!CryptGetUserKey(hCryptProv, dwKeySpec, &hKey))
  412. goto ErrorReturn;
  413. cbPvk = 0;
  414. if (!CryptExportKey(hKey, hEncryptKey, PRIVATEKEYBLOB, dwFlags, NULL,
  415. &cbPvk))
  416. goto ErrorReturn;
  417. if (NULL == (pbPvk = (BYTE *) PvkAlloc(cbPvk)))
  418. goto ErrorReturn;
  419. if (!CryptExportKey(hKey, hEncryptKey, PRIVATEKEYBLOB, dwFlags, pbPvk,
  420. &cbPvk))
  421. goto ErrorReturn;
  422. Hdr.cbPvk = cbPvk;
  423. // Write the header, optional encrypt data, and private key to the file
  424. if (!pfnWrite(hWrite, &Hdr, sizeof(Hdr)))
  425. goto ErrorReturn;
  426. if (Hdr.cbEncryptData) {
  427. if (!pfnWrite(hWrite, pbEncryptData, Hdr.cbEncryptData))
  428. goto ErrorReturn;
  429. }
  430. if (!pfnWrite(hWrite, pbPvk, cbPvk))
  431. goto ErrorReturn;
  432. fResult = TRUE;
  433. goto CommonReturn;
  434. ErrorReturn:
  435. fResult = FALSE;
  436. CommonReturn:
  437. if (pbPvk)
  438. PvkFree(pbPvk);
  439. if (hEncryptKey)
  440. CryptDestroyKey(hEncryptKey);
  441. if (hKey)
  442. CryptDestroyKey(hKey);
  443. return fResult;
  444. }
  445. static BOOL SaveKeyA(
  446. IN HCRYPTPROV hCryptProv,
  447. IN HANDLE hWrite,
  448. IN PFNREAD pfnWrite,
  449. IN DWORD dwKeySpec, // either AT_SIGNATURE or AT_KEYEXCHANGE
  450. IN HWND hwndOwner,
  451. IN LPCTSTR pszKeyName,
  452. IN DWORD dwFlags,
  453. IN BOOL fNoPassDlg
  454. )
  455. {
  456. WIDEN(pszKeyName, pwszKeyName);
  457. // LPWSTR pwszKeyName = MkWStr((char*) pszKeyName);
  458. BOOL fResult = SaveKeyW(hCryptProv,
  459. hWrite,
  460. pfnWrite,
  461. dwKeySpec,
  462. hwndOwner,
  463. pwszKeyName,
  464. dwFlags,
  465. fNoPassDlg);
  466. return fResult;
  467. }
  468. //+-------------------------------------------------------------------------
  469. // Load the AT_SIGNATURE or AT_KEYEXCHANGE private key (and its public key)
  470. // from the file into the cryptographic provider.
  471. //
  472. // If the private key was password encrypted, then, the user is first
  473. // presented with a dialog box to enter the password.
  474. //
  475. // If pdwKeySpec is non-Null, then, if *pdwKeySpec is nonzero, verifies the
  476. // key type before loading. Sets LastError to PVK_HELPER_WRONG_KEY_TYPE for
  477. // a mismatch. *pdwKeySpec is updated with the key type.
  478. //
  479. // dwFlags is passed through to CryptImportKey.
  480. //--------------------------------------------------------------------------
  481. BOOL
  482. WINAPI
  483. PvkPrivateKeyLoad(
  484. IN HCRYPTPROV hCryptProv,
  485. IN HANDLE hFile,
  486. IN HWND hwndOwner,
  487. IN LPCWSTR pwszKeyName,
  488. IN DWORD dwFlags,
  489. IN OUT OPTIONAL DWORD *pdwKeySpec
  490. )
  491. {
  492. return LoadKeyW(
  493. hCryptProv,
  494. hFile,
  495. ReadFromFile,
  496. GetFileSize(hFile, NULL),
  497. hwndOwner,
  498. pwszKeyName,
  499. dwFlags,
  500. pdwKeySpec
  501. );
  502. }
  503. BOOL
  504. WINAPI
  505. PvkPrivateKeyLoadA(
  506. IN HCRYPTPROV hCryptProv,
  507. IN HANDLE hFile,
  508. IN HWND hwndOwner,
  509. IN LPCTSTR pszKeyName,
  510. IN DWORD dwFlags,
  511. IN OUT OPTIONAL DWORD *pdwKeySpec
  512. )
  513. {
  514. return LoadKeyA(
  515. hCryptProv,
  516. hFile,
  517. ReadFromFile,
  518. GetFileSize(hFile, NULL),
  519. hwndOwner,
  520. pszKeyName,
  521. dwFlags,
  522. pdwKeySpec
  523. );
  524. }
  525. //+-------------------------------------------------------------------------
  526. // Save the AT_SIGNATURE or AT_KEYEXCHANGE private key (and its public key)
  527. // to the specified file.
  528. //
  529. // The user is presented with a dialog box to enter an optional password to
  530. // encrypt the private key.
  531. //
  532. // dwFlags is passed through to CryptExportKey.
  533. //--------------------------------------------------------------------------
  534. BOOL
  535. WINAPI
  536. PvkPrivateKeySave(
  537. IN HCRYPTPROV hCryptProv,
  538. IN HANDLE hFile,
  539. IN DWORD dwKeySpec, // either AT_SIGNATURE or AT_KEYEXCHANGE
  540. IN HWND hwndOwner,
  541. IN LPCWSTR pwszKeyName,
  542. IN DWORD dwFlags
  543. )
  544. {
  545. return SaveKeyW(
  546. hCryptProv,
  547. hFile,
  548. WriteToFile,
  549. dwKeySpec,
  550. hwndOwner,
  551. pwszKeyName,
  552. dwFlags,
  553. FALSE // fNoPassDlg
  554. );
  555. }
  556. BOOL
  557. WINAPI
  558. PvkPrivateKeySaveA(
  559. IN HCRYPTPROV hCryptProv,
  560. IN HANDLE hFile,
  561. IN DWORD dwKeySpec, // either AT_SIGNATURE or AT_KEYEXCHANGE
  562. IN HWND hwndOwner,
  563. IN LPCTSTR pszKeyName,
  564. IN DWORD dwFlags
  565. )
  566. {
  567. return SaveKeyA(
  568. hCryptProv,
  569. hFile,
  570. WriteToFile,
  571. dwKeySpec,
  572. hwndOwner,
  573. pszKeyName,
  574. dwFlags,
  575. FALSE // fNoPassDlg
  576. );
  577. }
  578. //+-------------------------------------------------------------------------
  579. // Load the AT_SIGNATURE or AT_KEYEXCHANGE private key (and its public key)
  580. // from memory into the cryptographic provider.
  581. //
  582. // Except for the key being loaded from memory, identical to PrivateKeyLoad.
  583. //--------------------------------------------------------------------------
  584. BOOL
  585. WINAPI
  586. PvkPrivateKeyLoadFromMemory(
  587. IN HCRYPTPROV hCryptProv,
  588. IN BYTE *pbData,
  589. IN DWORD cbData,
  590. IN HWND hwndOwner,
  591. IN LPCWSTR pwszKeyName,
  592. IN DWORD dwFlags,
  593. IN OUT OPTIONAL DWORD *pdwKeySpec
  594. )
  595. {
  596. MEMINFO MemInfo;
  597. MemInfo.pb = pbData;
  598. MemInfo.cb = cbData;
  599. MemInfo.cbSeek = 0;
  600. return LoadKeyW(
  601. hCryptProv,
  602. (HANDLE) &MemInfo,
  603. ReadFromMemory,
  604. cbData,
  605. hwndOwner,
  606. pwszKeyName,
  607. dwFlags,
  608. pdwKeySpec
  609. );
  610. }
  611. BOOL
  612. WINAPI
  613. PvkPrivateKeyLoadFromMemoryA(
  614. IN HCRYPTPROV hCryptProv,
  615. IN BYTE *pbData,
  616. IN DWORD cbData,
  617. IN HWND hwndOwner,
  618. IN LPCTSTR pszKeyName,
  619. IN DWORD dwFlags,
  620. IN OUT OPTIONAL DWORD *pdwKeySpec
  621. )
  622. {
  623. MEMINFO MemInfo;
  624. MemInfo.pb = pbData;
  625. MemInfo.cb = cbData;
  626. MemInfo.cbSeek = 0;
  627. return LoadKeyA(
  628. hCryptProv,
  629. (HANDLE) &MemInfo,
  630. ReadFromMemory,
  631. cbData,
  632. hwndOwner,
  633. pszKeyName,
  634. dwFlags,
  635. pdwKeySpec
  636. );
  637. }
  638. //+-------------------------------------------------------------------------
  639. // Save the AT_SIGNATURE or AT_KEYEXCHANGE private key (and its public key)
  640. // to memory.
  641. //
  642. // If pbData == NULL || *pcbData == 0, calculates the length and doesn't
  643. // return an error (also, the user isn't prompted for a password).
  644. //
  645. // Except for the key being saved to memory, identical to PrivateKeySave.
  646. //--------------------------------------------------------------------------
  647. BOOL
  648. WINAPI
  649. PvkPrivateKeySaveToMemory(
  650. IN HCRYPTPROV hCryptProv,
  651. IN DWORD dwKeySpec, // either AT_SIGNATURE or AT_KEYEXCHANGE
  652. IN HWND hwndOwner,
  653. IN LPCWSTR pwszKeyName,
  654. IN DWORD dwFlags,
  655. OUT BYTE *pbData,
  656. IN OUT DWORD *pcbData
  657. )
  658. {
  659. BOOL fResult;
  660. MEMINFO MemInfo;
  661. MemInfo.pb = pbData;
  662. if (pbData == NULL)
  663. *pcbData = 0;
  664. MemInfo.cb = *pcbData;
  665. MemInfo.cbSeek = 0;
  666. if (fResult = SaveKeyW(
  667. hCryptProv,
  668. (HANDLE) &MemInfo,
  669. WriteToMemory,
  670. dwKeySpec,
  671. hwndOwner,
  672. pwszKeyName,
  673. dwFlags,
  674. *pcbData == 0 // fNoPassDlg
  675. )) {
  676. if (MemInfo.cbSeek > MemInfo.cb && *pcbData) {
  677. fResult = FALSE;
  678. SetLastError(ERROR_END_OF_MEDIA);
  679. }
  680. *pcbData = MemInfo.cbSeek;
  681. } else
  682. *pcbData = 0;
  683. return fResult;
  684. }
  685. BOOL
  686. WINAPI
  687. PvkPrivateKeySaveToMemoryA(
  688. IN HCRYPTPROV hCryptProv,
  689. IN DWORD dwKeySpec, // either AT_SIGNATURE or AT_KEYEXCHANGE
  690. IN HWND hwndOwner,
  691. IN LPCTSTR pszKeyName,
  692. IN DWORD dwFlags,
  693. OUT BYTE *pbData,
  694. IN OUT DWORD *pcbData
  695. )
  696. {
  697. BOOL fResult;
  698. MEMINFO MemInfo;
  699. MemInfo.pb = pbData;
  700. if (pbData == NULL)
  701. *pcbData = 0;
  702. MemInfo.cb = *pcbData;
  703. MemInfo.cbSeek = 0;
  704. if (fResult = SaveKeyA(
  705. hCryptProv,
  706. (HANDLE) &MemInfo,
  707. WriteToMemory,
  708. dwKeySpec,
  709. hwndOwner,
  710. pszKeyName,
  711. dwFlags,
  712. *pcbData == 0 // fNoPassDlg
  713. )) {
  714. if (MemInfo.cbSeek > MemInfo.cb && *pcbData) {
  715. fResult = FALSE;
  716. SetLastError(ERROR_END_OF_MEDIA);
  717. }
  718. *pcbData = MemInfo.cbSeek;
  719. } else
  720. *pcbData = 0;
  721. return fResult;
  722. }
  723. //+-------------------------------------------------------------------------
  724. // Converts the bytes into WCHAR hex
  725. //
  726. // Needs (cb * 2 + 1) * sizeof(WCHAR) bytes of space in wsz
  727. //--------------------------------------------------------------------------
  728. static void BytesToWStr(ULONG cb, void* pv, LPWSTR wsz)
  729. {
  730. BYTE* pb = (BYTE*) pv;
  731. for (ULONG i = 0; i<cb; i++) {
  732. int b;
  733. b = (*pb & 0xF0) >> 4;
  734. *wsz++ = (b <= 9) ? b + L'0' : (b - 10) + L'A';
  735. b = *pb & 0x0F;
  736. *wsz++ = (b <= 9) ? b + L'0' : (b - 10) + L'A';
  737. pb++;
  738. }
  739. *wsz++ = 0;
  740. }
  741. #define UUID_WSTR_BYTES ((sizeof(UUID) * 2 + 1) * sizeof(WCHAR))
  742. //+-------------------------------------------------------------------------
  743. // Converts the bytes into CHAR hex
  744. //
  745. // Needs (cb * 2 + 1) * sizeof(CHAR) bytes of space in sz
  746. //--------------------------------------------------------------------------
  747. static void BytesToStr(ULONG cb, void* pv, LPTSTR sz)
  748. {
  749. BYTE* pb = (BYTE*) pv;
  750. for (ULONG i = 0; i<cb; i++) {
  751. int b;
  752. b = (*pb & 0xF0) >> 4;
  753. *sz++ = (b <= 9) ? b + '0' : (b - 10) + 'A';
  754. b = *pb & 0x0F;
  755. *sz++ = (b <= 9) ? b + '0' : (b - 10) + 'A';
  756. pb++;
  757. }
  758. *sz++ = 0;
  759. }
  760. #define UUID_STR_BYTES ((sizeof(UUID) * 2 + 1) * sizeof(CHAR))
  761. static BOOL AcquireKeyContextW(
  762. IN LPCWSTR pwszProvName,
  763. IN DWORD dwProvType,
  764. IN HANDLE hRead,
  765. IN PFNREAD pfnRead,
  766. IN DWORD cbKeyData,
  767. IN HWND hwndOwner,
  768. IN LPCWSTR pwszKeyName,
  769. IN OUT OPTIONAL DWORD *pdwKeySpec,
  770. OUT HCRYPTPROV *phCryptProv,
  771. OUT LPWSTR *ppwszTmpContainer
  772. )
  773. {
  774. BOOL fResult;
  775. HCRYPTPROV hProv = 0;
  776. UUID TmpContainerUuid;
  777. LPWSTR pwszTmpContainer = NULL;
  778. // Create a temporary keyset to load the private key into
  779. // UuidCreate(&TmpContainerUuid);
  780. if (CoCreateGuid((GUID *)&TmpContainerUuid) != S_OK)
  781. {
  782. goto ErrorReturn;
  783. }
  784. if (NULL == (pwszTmpContainer = (LPWSTR) PvkAlloc(
  785. 6 * sizeof(WCHAR) + UUID_WSTR_BYTES)))
  786. goto ErrorReturn;
  787. wcscpy(pwszTmpContainer, L"TmpKey");
  788. BytesToWStr(sizeof(UUID), &TmpContainerUuid, pwszTmpContainer + 6);
  789. if (!CryptAcquireContextU(
  790. &hProv,
  791. pwszTmpContainer,
  792. pwszProvName,
  793. dwProvType,
  794. CRYPT_NEWKEYSET
  795. ))
  796. goto ErrorReturn;
  797. if (!LoadKeyW(
  798. hProv,
  799. hRead,
  800. pfnRead,
  801. cbKeyData,
  802. hwndOwner,
  803. pwszKeyName,
  804. 0, // dwFlags
  805. pdwKeySpec
  806. ))
  807. goto DeleteKeySetReturn;
  808. fResult = TRUE;
  809. goto CommonReturn;
  810. DeleteKeySetReturn:
  811. CryptReleaseContext(hProv, 0);
  812. CryptAcquireContextU(
  813. &hProv,
  814. pwszTmpContainer,
  815. pwszProvName,
  816. dwProvType,
  817. CRYPT_DELETEKEYSET
  818. );
  819. hProv = 0;
  820. ErrorReturn:
  821. if (hProv) {
  822. CryptReleaseContext(hProv, 0);
  823. hProv = 0;
  824. }
  825. if (pwszTmpContainer) {
  826. PvkFree(pwszTmpContainer);
  827. pwszTmpContainer = NULL;
  828. }
  829. fResult = FALSE;
  830. CommonReturn:
  831. *ppwszTmpContainer = pwszTmpContainer;
  832. *phCryptProv = hProv;
  833. return fResult;
  834. }
  835. static BOOL AcquireKeyContextA(
  836. IN LPCTSTR pszProvName,
  837. IN DWORD dwProvType,
  838. IN HANDLE hRead,
  839. IN PFNREAD pfnRead,
  840. IN DWORD cbKeyData,
  841. IN HWND hwndOwner,
  842. IN LPCTSTR pszKeyName,
  843. IN OUT OPTIONAL DWORD *pdwKeySpec,
  844. OUT HCRYPTPROV *phCryptProv,
  845. OUT LPTSTR *ppszTmpContainer
  846. )
  847. {
  848. DWORD hr;
  849. BOOL fResult;
  850. HCRYPTPROV hProv = 0;
  851. UUID TmpContainerUuid;
  852. LPTSTR pszTmpContainer = NULL;
  853. // Create a temporary keyset to load the private key into
  854. if (CoCreateGuid((GUID *)&TmpContainerUuid) != S_OK)
  855. {
  856. goto ErrorReturn;
  857. }
  858. if (NULL == (pszTmpContainer = (LPTSTR) PvkAlloc(
  859. 6 * sizeof(CHAR) + UUID_STR_BYTES)))
  860. goto ErrorReturn;
  861. strcpy(pszTmpContainer, "TmpKey");
  862. BytesToStr(sizeof(UUID), &TmpContainerUuid, pszTmpContainer + 6);
  863. if (!CryptAcquireContext(
  864. &hProv,
  865. pszTmpContainer,
  866. pszProvName,
  867. dwProvType,
  868. CRYPT_NEWKEYSET
  869. ))
  870. goto ErrorReturn;
  871. if (!LoadKeyA(
  872. hProv,
  873. hRead,
  874. pfnRead,
  875. cbKeyData,
  876. hwndOwner,
  877. pszKeyName,
  878. 0, // dwFlags
  879. pdwKeySpec
  880. ))
  881. goto DeleteKeySetReturn;
  882. fResult = TRUE;
  883. goto CommonReturn;
  884. DeleteKeySetReturn:
  885. CryptReleaseContext(hProv, 0);
  886. CryptAcquireContext(
  887. &hProv,
  888. pszTmpContainer,
  889. pszProvName,
  890. dwProvType,
  891. CRYPT_DELETEKEYSET
  892. );
  893. hProv = 0;
  894. ErrorReturn:
  895. hr = GetLastError();
  896. if (hProv) {
  897. CryptReleaseContext(hProv, 0);
  898. hProv = 0;
  899. }
  900. if (pszTmpContainer) {
  901. PvkFree(pszTmpContainer);
  902. pszTmpContainer = NULL;
  903. }
  904. fResult = FALSE;
  905. CommonReturn:
  906. *ppszTmpContainer = pszTmpContainer;
  907. *phCryptProv = hProv;
  908. return fResult;
  909. }
  910. //+-------------------------------------------------------------------------
  911. // Creates a temporary container in the provider and loads the private key
  912. // from the specified file.
  913. // For success, returns a handle to a cryptographic provider for the private
  914. // key and the name of the temporary container. PrivateKeyReleaseContext must
  915. // be called to release the hCryptProv and delete the temporary container.
  916. //
  917. // PrivateKeyLoad is called to load the private key into the temporary
  918. // container.
  919. //--------------------------------------------------------------------------
  920. BOOL
  921. WINAPI
  922. PvkPrivateKeyAcquireContext(
  923. IN LPCWSTR pwszProvName,
  924. IN DWORD dwProvType,
  925. IN HANDLE hFile,
  926. IN HWND hwndOwner,
  927. IN LPCWSTR pwszKeyName,
  928. IN OUT OPTIONAL DWORD *pdwKeySpec,
  929. OUT HCRYPTPROV *phCryptProv,
  930. OUT LPWSTR *ppwszTmpContainer
  931. )
  932. {
  933. HRESULT hr = S_OK;
  934. if(FAILED(hr))
  935. return FALSE;
  936. BOOL fhr = AcquireKeyContextW(
  937. pwszProvName,
  938. dwProvType,
  939. hFile,
  940. ReadFromFile,
  941. GetFileSize(hFile, NULL),
  942. hwndOwner,
  943. pwszKeyName,
  944. pdwKeySpec,
  945. phCryptProv,
  946. ppwszTmpContainer
  947. );
  948. return fhr;
  949. }
  950. BOOL
  951. WINAPI
  952. PvkPrivateKeyAcquireContextA(
  953. IN LPCTSTR pszProvName,
  954. IN DWORD dwProvType,
  955. IN HANDLE hFile,
  956. IN HWND hwndOwner,
  957. IN LPCTSTR pszKeyName,
  958. IN OUT OPTIONAL DWORD *pdwKeySpec,
  959. OUT HCRYPTPROV *phCryptProv,
  960. OUT LPTSTR *ppszTmpContainer
  961. )
  962. {
  963. HRESULT hr = S_OK;
  964. if(FAILED(hr))
  965. return FALSE;
  966. BOOL fhr = AcquireKeyContextA(
  967. pszProvName,
  968. dwProvType,
  969. hFile,
  970. ReadFromFile,
  971. GetFileSize(hFile, NULL),
  972. hwndOwner,
  973. pszKeyName,
  974. pdwKeySpec,
  975. phCryptProv,
  976. ppszTmpContainer
  977. );
  978. return fhr;
  979. }
  980. //+-------------------------------------------------------------------------
  981. // Creates a temporary container in the provider and loads the private key
  982. // from memory.
  983. // For success, returns a handle to a cryptographic provider for the private
  984. // key and the name of the temporary container. PrivateKeyReleaseContext must
  985. // be called to release the hCryptProv and delete the temporary container.
  986. //
  987. // PrivateKeyLoadFromMemory is called to load the private key into the
  988. // temporary container.
  989. //--------------------------------------------------------------------------
  990. BOOL
  991. WINAPI
  992. PvkPrivateKeyAcquireContextFromMemory(
  993. IN LPCWSTR pwszProvName,
  994. IN DWORD dwProvType,
  995. IN BYTE *pbData,
  996. IN DWORD cbData,
  997. IN HWND hwndOwner,
  998. IN LPCWSTR pwszKeyName,
  999. IN OUT OPTIONAL DWORD *pdwKeySpec,
  1000. OUT HCRYPTPROV *phCryptProv,
  1001. OUT LPWSTR *ppwszTmpContainer
  1002. )
  1003. {
  1004. HRESULT hr = S_OK;
  1005. if(FAILED(hr))
  1006. return FALSE;
  1007. MEMINFO MemInfo;
  1008. MemInfo.pb = pbData;
  1009. MemInfo.cb = cbData;
  1010. MemInfo.cbSeek = 0;
  1011. BOOL fhr = AcquireKeyContextW(
  1012. pwszProvName,
  1013. dwProvType,
  1014. (HANDLE) &MemInfo,
  1015. ReadFromMemory,
  1016. cbData,
  1017. hwndOwner,
  1018. pwszKeyName,
  1019. pdwKeySpec,
  1020. phCryptProv,
  1021. ppwszTmpContainer
  1022. );
  1023. return fhr;
  1024. }
  1025. BOOL
  1026. WINAPI
  1027. PvkPrivateKeyAcquireContextFromMemoryA(
  1028. IN LPCTSTR pszProvName,
  1029. IN DWORD dwProvType,
  1030. IN BYTE *pbData,
  1031. IN DWORD cbData,
  1032. IN HWND hwndOwner,
  1033. IN LPCTSTR pszKeyName,
  1034. IN OUT OPTIONAL DWORD *pdwKeySpec,
  1035. OUT HCRYPTPROV *phCryptProv,
  1036. OUT LPTSTR *ppszTmpContainer
  1037. )
  1038. {
  1039. HRESULT hr = S_OK;
  1040. if(FAILED(hr))
  1041. return FALSE;
  1042. MEMINFO MemInfo;
  1043. MemInfo.pb = pbData;
  1044. MemInfo.cb = cbData;
  1045. MemInfo.cbSeek = 0;
  1046. BOOL fhr = AcquireKeyContextA(
  1047. pszProvName,
  1048. dwProvType,
  1049. (HANDLE) &MemInfo,
  1050. ReadFromMemory,
  1051. cbData,
  1052. hwndOwner,
  1053. pszKeyName,
  1054. pdwKeySpec,
  1055. phCryptProv,
  1056. ppszTmpContainer
  1057. );
  1058. return fhr;
  1059. }
  1060. //+-------------------------------------------------------------------------
  1061. // Releases the cryptographic provider and deletes the temporary container
  1062. // created by PrivateKeyAcquireContext or PrivateKeyAcquireContextFromMemory.
  1063. //--------------------------------------------------------------------------
  1064. BOOL
  1065. WINAPI
  1066. PvkPrivateKeyReleaseContext(
  1067. IN HCRYPTPROV hCryptProv,
  1068. IN LPCWSTR pwszProvName,
  1069. IN DWORD dwProvType,
  1070. IN LPWSTR pwszTmpContainer
  1071. )
  1072. {
  1073. HRESULT hr = S_OK;
  1074. if(FAILED(hr))
  1075. return FALSE;
  1076. if (hCryptProv)
  1077. CryptReleaseContext(hCryptProv, 0);
  1078. if (pwszTmpContainer) {
  1079. // Delete the temporary container for the private key from
  1080. // the provider
  1081. //
  1082. // Note: for CRYPT_DELETEKEYSET, the returned hCryptProv is undefined
  1083. // and must not be released.
  1084. CryptAcquireContextU(
  1085. &hCryptProv,
  1086. pwszTmpContainer,
  1087. pwszProvName,
  1088. dwProvType,
  1089. CRYPT_DELETEKEYSET
  1090. );
  1091. PvkFree(pwszTmpContainer);
  1092. }
  1093. return TRUE;
  1094. }
  1095. BOOL
  1096. WINAPI
  1097. PvkPrivateKeyReleaseContextA(
  1098. IN HCRYPTPROV hCryptProv,
  1099. IN LPCTSTR pszProvName,
  1100. IN DWORD dwProvType,
  1101. IN LPTSTR pszTmpContainer
  1102. )
  1103. {
  1104. HRESULT hr = S_OK;
  1105. if(FAILED(hr))
  1106. return FALSE;
  1107. if (hCryptProv)
  1108. CryptReleaseContext(hCryptProv, 0);
  1109. if (pszTmpContainer) {
  1110. // Delete the temporary container for the private key from
  1111. // the provider
  1112. //
  1113. // Note: for CRYPT_DELETEKEYSET, the returned hCryptProv is undefined
  1114. // and must not be released.
  1115. CryptAcquireContext(
  1116. &hCryptProv,
  1117. pszTmpContainer,
  1118. pszProvName,
  1119. dwProvType,
  1120. CRYPT_DELETEKEYSET
  1121. );
  1122. PvkFree(pszTmpContainer);
  1123. }
  1124. return TRUE;
  1125. }
  1126. //+-------------------------------------------------------------------------
  1127. // Functions supporting backwards compatibility with Bob's storage file
  1128. // containing a snap shot of the keys as they are stored in the registry.
  1129. // Note, for win95, the registry values are decrypted before being written to
  1130. // the file.
  1131. //--------------------------------------------------------------------------
  1132. // Return the size of this stream; return 0 if an error
  1133. static DWORD CbBobSize(IStream *pStm)
  1134. {
  1135. STATSTG stat;
  1136. if (FAILED(pStm->Stat(&stat, STATFLAG_NONAME)))
  1137. return 0;
  1138. return stat.cbSize.LowPart;
  1139. }
  1140. // Allocate and read this value which has the indicated stream name from the
  1141. // storage
  1142. static BOOL LoadBobStream(
  1143. IStorage *pStg,
  1144. LPCWSTR pwszStm,
  1145. BYTE **ppbValue,
  1146. DWORD *pcbValue
  1147. )
  1148. {
  1149. BOOL fResult;
  1150. HRESULT hr;
  1151. IStream *pStm = NULL;
  1152. BYTE *pbValue = NULL;
  1153. DWORD cbValue;
  1154. DWORD cbRead;
  1155. if (FAILED(hr = pStg->OpenStream(pwszStm, 0,
  1156. STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStm)))
  1157. goto HrError;
  1158. if (0 == (cbValue = CbBobSize(pStm))) goto BadBobFile;
  1159. if (NULL == (pbValue = (BYTE *) PvkAlloc(cbValue))) goto ErrorReturn;
  1160. pStm->Read(pbValue, cbValue, &cbRead);
  1161. if (cbRead != cbValue) goto BadBobFile;
  1162. fResult = TRUE;
  1163. goto CommonReturn;
  1164. HrError:
  1165. SetLastError((DWORD) hr);
  1166. goto ErrorReturn;
  1167. BadBobFile:
  1168. SetLastError(PVK_HELPER_BAD_PVK_FILE);
  1169. ErrorReturn:
  1170. if (pbValue) {
  1171. PvkFree(pbValue);
  1172. pbValue = NULL;
  1173. }
  1174. cbValue = 0;
  1175. fResult = FALSE;
  1176. CommonReturn:
  1177. if (pStm)
  1178. pStm->Release();
  1179. *ppbValue = pbValue;
  1180. *pcbValue = cbValue;
  1181. return fResult;
  1182. }
  1183. // New "Bob" format::
  1184. //
  1185. // Allocate and read either the Exported Signature or Exchange Private
  1186. // key stream from the storage
  1187. static BOOL LoadBobExportedPvk(
  1188. IStorage *pStg,
  1189. DWORD dwKeySpec,
  1190. BYTE **ppbPvkValue,
  1191. DWORD *pcbPvkValue
  1192. )
  1193. {
  1194. BOOL fResult;
  1195. LPCWSTR pwszPvk;
  1196. switch (dwKeySpec) {
  1197. case AT_SIGNATURE:
  1198. pwszPvk = L"Exported Signature Private Key";
  1199. break;
  1200. case AT_KEYEXCHANGE:
  1201. pwszPvk = L"Exported Exchange Private Key";
  1202. break;
  1203. default:
  1204. SetLastError(PVK_HELPER_BAD_PARAMETER);
  1205. goto ErrorReturn;
  1206. }
  1207. fResult = LoadBobStream(pStg, pwszPvk, ppbPvkValue, pcbPvkValue);
  1208. if (fResult) goto CommonReturn;
  1209. ErrorReturn:
  1210. *ppbPvkValue = NULL;
  1211. *pcbPvkValue = 0;
  1212. fResult = FALSE;
  1213. CommonReturn:
  1214. return fResult;
  1215. }
  1216. // Old "Bob" format::
  1217. //
  1218. // Allocate and read either the Signature or Exchange Private
  1219. // key streams from the storage
  1220. static BOOL LoadBobOldPvk(
  1221. IStorage *pStg,
  1222. DWORD dwKeySpec,
  1223. BYTE **ppbPvkValue,
  1224. DWORD *pcbPvkValue
  1225. )
  1226. {
  1227. BOOL fResult;
  1228. LPCWSTR pwszPvk;
  1229. switch (dwKeySpec) {
  1230. case AT_SIGNATURE:
  1231. pwszPvk = L"SPvk";
  1232. break;
  1233. case AT_KEYEXCHANGE:
  1234. pwszPvk = L"EPvk";
  1235. break;
  1236. default:
  1237. SetLastError(PVK_HELPER_BAD_PARAMETER);
  1238. goto ErrorReturn;
  1239. }
  1240. fResult = LoadBobStream(pStg, pwszPvk, ppbPvkValue, pcbPvkValue);
  1241. if (fResult) goto CommonReturn;
  1242. ErrorReturn:
  1243. *ppbPvkValue = NULL;
  1244. *pcbPvkValue = 0;
  1245. fResult = FALSE;
  1246. CommonReturn:
  1247. return fResult;
  1248. }
  1249. ///////////////////////////////////////////////////////////////////////////////////////
  1250. //
  1251. // Key header structures for private key construction
  1252. //
  1253. // These structs define the fixed data at the beginning of an RSA key.
  1254. // They are followed by a variable length of data, sized by the stlen
  1255. // field.
  1256. //
  1257. // For more info see Jeff Spellman in the crypto team or look in the
  1258. // source to RsaBase.Dll
  1259. //
  1260. typedef struct {
  1261. DWORD magic; /* Should always be RSA2 */
  1262. DWORD keylen; // size of modulus buffer
  1263. DWORD bitlen; // bit size of key
  1264. DWORD datalen; // max number of bytes to be encoded
  1265. DWORD pubexp; // public exponent
  1266. } BSAFE_PRV_KEY, FAR *LPBSAFE_PRV_KEY;
  1267. typedef struct {
  1268. BYTE *modulus;
  1269. BYTE *prvexp;
  1270. BYTE *prime1;
  1271. BYTE *prime2;
  1272. BYTE *exp1;
  1273. BYTE *exp2;
  1274. BYTE *coef;
  1275. BYTE *invmod;
  1276. BYTE *invpr1;
  1277. BYTE *invpr2;
  1278. } BSAFE_KEY_PARTS, FAR *LPBSAFE_KEY_PARTS;
  1279. typedef struct {
  1280. DWORD magic; /* Should always be RSA2 */
  1281. DWORD bitlen; // bit size of key
  1282. DWORD pubexp; // public exponent
  1283. } EXPORT_PRV_KEY, FAR *PEXPORT_PRV_KEY;
  1284. ///////////////////////////////////////////////////////////////////////////////////////
  1285. //
  1286. // Take a raw exported unshrowded private key from the registry and turn it
  1287. // into a private key export blob.
  1288. //
  1289. // This is based on the PreparePrivateKeyForExport routine from rsabase.dll
  1290. //
  1291. static BOOL ConstructPrivateKeyExportBlob(
  1292. IN DWORD dwKeySpec,
  1293. IN BSAFE_PRV_KEY * pPrvKey,
  1294. IN DWORD PrvKeyLen,
  1295. OUT PBYTE *ppbBlob,
  1296. OUT DWORD *pcbBlob
  1297. )
  1298. {
  1299. BOOL fResult;
  1300. PEXPORT_PRV_KEY pExportKey;
  1301. DWORD cbHalfModLen;
  1302. PBYTE pbBlob = NULL;
  1303. DWORD cbBlob;
  1304. PBYTE pbIn;
  1305. PBYTE pbOut;
  1306. cbHalfModLen = pPrvKey->bitlen / 16;
  1307. cbBlob = sizeof(EXPORT_PRV_KEY) + 9 * cbHalfModLen +
  1308. sizeof(PUBLICKEYSTRUC);
  1309. if (NULL == (pbBlob = (BYTE *) PvkAlloc(cbBlob))) {
  1310. fResult = FALSE;
  1311. cbBlob = 0;
  1312. } else {
  1313. BYTE* pb = pbBlob;
  1314. PUBLICKEYSTRUC *pPubKeyStruc = (PUBLICKEYSTRUC *) pb;
  1315. pPubKeyStruc->bType = PRIVATEKEYBLOB;
  1316. pPubKeyStruc->bVersion = 2;
  1317. pPubKeyStruc->reserved = 0;
  1318. if (dwKeySpec == AT_KEYEXCHANGE)
  1319. pPubKeyStruc->aiKeyAlg = CALG_RSA_KEYX;
  1320. else if (dwKeySpec == AT_SIGNATURE)
  1321. pPubKeyStruc->aiKeyAlg = CALG_RSA_SIGN;
  1322. else
  1323. pPubKeyStruc->aiKeyAlg = 0;
  1324. pb = pbBlob + sizeof(PUBLICKEYSTRUC);
  1325. // take most of the header info
  1326. pExportKey = (PEXPORT_PRV_KEY)pb;
  1327. pExportKey->magic = pPrvKey->magic;
  1328. pExportKey->bitlen = pPrvKey->bitlen;
  1329. pExportKey->pubexp = pPrvKey->pubexp;
  1330. pbIn = (PBYTE)pPrvKey + sizeof(BSAFE_PRV_KEY);
  1331. pbOut = pb + sizeof(EXPORT_PRV_KEY);
  1332. // copy all the private key info
  1333. memcpy(pbOut, pbIn, cbHalfModLen * 2);
  1334. pbIn += (cbHalfModLen + sizeof(DWORD)) * 2;
  1335. pbOut += cbHalfModLen * 2;
  1336. memcpy(pbOut, pbIn, cbHalfModLen);
  1337. pbIn += cbHalfModLen + sizeof(DWORD);
  1338. pbOut += cbHalfModLen;
  1339. memcpy(pbOut, pbIn, cbHalfModLen);
  1340. pbIn += cbHalfModLen + sizeof(DWORD);
  1341. pbOut += cbHalfModLen;
  1342. memcpy(pbOut, pbIn, cbHalfModLen);
  1343. pbIn += cbHalfModLen + sizeof(DWORD);
  1344. pbOut += cbHalfModLen;
  1345. memcpy(pbOut, pbIn, cbHalfModLen);
  1346. pbIn += cbHalfModLen + sizeof(DWORD);
  1347. pbOut += cbHalfModLen;
  1348. memcpy(pbOut, pbIn, cbHalfModLen);
  1349. pbIn += cbHalfModLen + sizeof(DWORD);
  1350. pbOut += cbHalfModLen;
  1351. memcpy(pbOut, pbIn, cbHalfModLen * 2);
  1352. fResult = TRUE;
  1353. }
  1354. *ppbBlob = pbBlob;
  1355. *pcbBlob = cbBlob;
  1356. return fResult;
  1357. }
  1358. static BOOL LoadBobKey(
  1359. IN HCRYPTPROV hCryptProv,
  1360. IN HANDLE hRead,
  1361. IN PFNREAD pfnRead,
  1362. IN DWORD cbBobKey,
  1363. IN HWND hwndOwner,
  1364. IN LPCWSTR pwszKeyName,
  1365. IN DWORD dwFlags,
  1366. IN OUT OPTIONAL DWORD *pdwKeySpec,
  1367. IN PFILE_HDR pHdr // header has already been read
  1368. )
  1369. {
  1370. BOOL fResult;
  1371. DWORD dwErr = 0;
  1372. HRESULT hr;
  1373. HGLOBAL hGlobal = NULL;
  1374. BYTE *pbBobKey; // not allocated
  1375. ILockBytes *pLkByt = NULL;
  1376. IStorage *pStg = NULL;
  1377. IStorage *pPrivStg = NULL;
  1378. BYTE *pbPvkValue = NULL;
  1379. DWORD cbPvkValue;
  1380. DWORD dwKeySpec;
  1381. BYTE *pbPvk = NULL;
  1382. DWORD cbPvk;
  1383. if (cbBobKey > MAX_BOB_FILE_LEN) goto BadBobFile;
  1384. if (NULL == (hGlobal = GlobalAlloc(GMEM_MOVEABLE | GMEM_DISCARDABLE,
  1385. cbBobKey)))
  1386. goto ErrorReturn;
  1387. if (NULL == (pbBobKey = (BYTE *) GlobalLock(hGlobal)))
  1388. goto ErrorReturn;
  1389. memcpy(pbBobKey, (BYTE *) pHdr, sizeof(FILE_HDR));
  1390. if (cbBobKey > sizeof(FILE_HDR))
  1391. fResult = pfnRead(hRead, pbBobKey + sizeof(FILE_HDR),
  1392. cbBobKey - sizeof(FILE_HDR));
  1393. else
  1394. fResult = TRUE;
  1395. GlobalUnlock(hGlobal);
  1396. if (!fResult) goto ErrorReturn;
  1397. // FALSE => don't DeleteOnRelease
  1398. if (FAILED(hr = CreateILockBytesOnHGlobal(hGlobal, FALSE, &pLkByt)))
  1399. goto HrError;
  1400. if (FAILED(hr = StgOpenStorageOnILockBytes(
  1401. pLkByt,
  1402. NULL, // pStgPriority
  1403. STGM_DIRECT | STGM_READ | STGM_SHARE_DENY_WRITE,
  1404. NULL, // snbExclude
  1405. 0, // dwReserved
  1406. &pStg
  1407. ))) goto HrError;
  1408. if (FAILED(pStg->OpenStorage(
  1409. L"Plain Private Key",
  1410. 0,
  1411. STGM_READ | STGM_SHARE_EXCLUSIVE,
  1412. NULL,
  1413. 0,
  1414. &pPrivStg))) goto BadBobFile;
  1415. if (pdwKeySpec && *pdwKeySpec)
  1416. dwKeySpec = *pdwKeySpec;
  1417. else
  1418. dwKeySpec = AT_SIGNATURE;
  1419. // First, attempt to read the new format where the keys are stored in
  1420. // the private key export format
  1421. fResult = LoadBobExportedPvk(pPrivStg, dwKeySpec, &pbPvkValue,
  1422. &cbPvkValue);
  1423. if (!fResult && (pdwKeySpec == NULL || *pdwKeySpec == 0)) {
  1424. dwKeySpec = AT_KEYEXCHANGE;
  1425. fResult = LoadBobExportedPvk(pPrivStg, dwKeySpec,
  1426. &pbPvkValue, &cbPvkValue);
  1427. }
  1428. if (fResult)
  1429. fResult = PvkPrivateKeyLoadFromMemory(
  1430. hCryptProv,
  1431. pbPvkValue,
  1432. cbPvkValue,
  1433. hwndOwner,
  1434. pwszKeyName,
  1435. dwFlags,
  1436. &dwKeySpec
  1437. );
  1438. else {
  1439. // Try "old" format
  1440. if (pdwKeySpec && *pdwKeySpec)
  1441. dwKeySpec = *pdwKeySpec;
  1442. else
  1443. dwKeySpec = AT_SIGNATURE;
  1444. fResult = LoadBobOldPvk(pPrivStg, dwKeySpec, &pbPvkValue, &cbPvkValue);
  1445. if (!fResult && (pdwKeySpec == NULL || *pdwKeySpec == 0)) {
  1446. dwKeySpec = AT_KEYEXCHANGE;
  1447. fResult = LoadBobOldPvk(pPrivStg, dwKeySpec,
  1448. &pbPvkValue, &cbPvkValue);
  1449. }
  1450. if (fResult) {
  1451. BYTE *pbExportPvk;
  1452. DWORD cbExportPvk;
  1453. // Convert Bob's old private key format to the new export private
  1454. // key format
  1455. if ((fResult = ConstructPrivateKeyExportBlob(
  1456. dwKeySpec,
  1457. (BSAFE_PRV_KEY *) pbPvkValue,
  1458. cbPvkValue,
  1459. &pbExportPvk,
  1460. &cbExportPvk
  1461. ))) {
  1462. HCRYPTKEY hKey = 0;
  1463. // Import the private key
  1464. fResult = CryptImportKey(hCryptProv, pbExportPvk, cbExportPvk,
  1465. 0, dwFlags, &hKey);
  1466. if (hKey)
  1467. CryptDestroyKey(hKey);
  1468. PvkFree(pbExportPvk);
  1469. }
  1470. }
  1471. }
  1472. if (fResult) goto CommonReturn;
  1473. goto ErrorReturn;
  1474. HrError:
  1475. SetLastError((DWORD) hr);
  1476. goto ErrorReturn;
  1477. BadBobFile:
  1478. SetLastError(PVK_HELPER_BAD_PVK_FILE);
  1479. ErrorReturn:
  1480. dwKeySpec = 0;
  1481. fResult = FALSE;
  1482. // One of the following Releases may clear it out
  1483. dwErr = GetLastError();
  1484. CommonReturn:
  1485. if (pbPvkValue)
  1486. PvkFree(pbPvkValue);
  1487. if (pPrivStg)
  1488. pPrivStg->Release();
  1489. if (pStg)
  1490. pStg->Release();
  1491. if (pLkByt)
  1492. pLkByt->Release();
  1493. if (hGlobal)
  1494. GlobalFree(hGlobal);
  1495. if (pdwKeySpec)
  1496. *pdwKeySpec = dwKeySpec;
  1497. if (dwErr)
  1498. SetLastError(dwErr);
  1499. return fResult;
  1500. }