Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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