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.

1236 lines
34 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 <windows.h>
  24. #include <assert.h>
  25. #include "wincrypt.h"
  26. #include "pvk.h"
  27. #include "unicode.h"
  28. #include <string.h>
  29. #include <memory.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. )
  138. {
  139. BOOL fResult;
  140. BYTE *pbAllocPassword = NULL;
  141. BYTE *pbPassword;
  142. DWORD cbPassword;
  143. HCRYPTHASH hHash = 0;
  144. HCRYPTKEY hEncryptKey = 0;
  145. BYTE rgbDefPw [] = { 0x43, 0x52, 0x41, 0x50 };
  146. DWORD cbDefPw = sizeof(rgbDefPw);
  147. if (fNoPassDlg) {
  148. pbPassword = rgbDefPw;
  149. cbPassword = cbDefPw;
  150. } else {
  151. if (IDOK != PvkDlgGetKeyPassword(
  152. PasswordType,
  153. hwndOwner,
  154. pwszKeyName,
  155. &pbAllocPassword,
  156. &cbPassword
  157. )) {
  158. SetLastError(PVK_HELPER_PASSWORD_CANCEL);
  159. goto ErrorReturn;
  160. }
  161. pbPassword = pbAllocPassword;
  162. }
  163. if (cbPassword) {
  164. if (!CryptCreateHash(hProv, CALG_SHA, 0, 0, &hHash))
  165. goto ErrorReturn;
  166. if (cbSalt) {
  167. if (!CryptHashData(hHash, pbSalt, cbSalt, 0))
  168. goto ErrorReturn;
  169. }
  170. if (!CryptHashData(hHash, pbPassword, cbPassword, 0))
  171. goto ErrorReturn;
  172. if (!CryptDeriveKey(hProv, Algid, hHash, 0, &hEncryptKey))
  173. goto ErrorReturn;
  174. }
  175. fResult = TRUE;
  176. goto CommonReturn;
  177. ErrorReturn:
  178. fResult = FALSE;
  179. if (hEncryptKey) {
  180. CryptDestroyKey(hEncryptKey);
  181. hEncryptKey = 0;
  182. }
  183. CommonReturn:
  184. if (pbAllocPassword)
  185. PvkFree(pbAllocPassword);
  186. if (hHash)
  187. CryptDestroyHash(hHash);
  188. *phEncryptKey = hEncryptKey;
  189. return fResult;
  190. }
  191. // Support backwards compatibility with Bob's storage file which contains
  192. // a snap shot of the keys as they are stored in the registry. Note, for
  193. // win95, the registry values are decrypted before being written to the file.
  194. static BOOL LoadBobKey(
  195. IN HCRYPTPROV hCryptProv,
  196. IN HANDLE hRead,
  197. IN PFNREAD pfnRead,
  198. IN DWORD cbBobKey,
  199. IN HWND hwndOwner,
  200. IN LPCWSTR pwszKeyName,
  201. IN DWORD dwFlags,
  202. IN OUT OPTIONAL DWORD *pdwKeySpec,
  203. IN PFILE_HDR pHdr // header has already been read
  204. );
  205. static BOOL LoadKey(
  206. IN HCRYPTPROV hCryptProv,
  207. IN HANDLE hRead,
  208. IN PFNREAD pfnRead,
  209. IN DWORD cbKeyData,
  210. IN HWND hwndOwner,
  211. IN LPCWSTR pwszKeyName,
  212. IN DWORD dwFlags,
  213. IN OUT OPTIONAL DWORD *pdwKeySpec
  214. )
  215. {
  216. BOOL fResult;
  217. FILE_HDR Hdr;
  218. HCRYPTKEY hDecryptKey = 0;
  219. HCRYPTKEY hKey = 0;
  220. BYTE *pbEncryptData = NULL;
  221. BYTE *pbPvk = NULL;
  222. DWORD cbPvk;
  223. // Read the file header and verify
  224. if (!pfnRead(hRead, &Hdr, sizeof(Hdr))) goto BadPvkFile;
  225. if (Hdr.dwMagic != PVK_MAGIC)
  226. // Try to load as Bob's storage file containing streams for the
  227. // private and public keys. Bob made a copy of the cryptography
  228. // registry key values.
  229. //
  230. // Note, Bob now has two different formats for storing the private
  231. // key information. See LoadBobKey for details.
  232. fResult = LoadBobKey(hCryptProv, hRead, pfnRead, cbKeyData, hwndOwner,
  233. pwszKeyName, dwFlags, pdwKeySpec, &Hdr);
  234. else {
  235. // Treat as a "normal" private key file
  236. cbPvk = Hdr.cbPvk;
  237. if (Hdr.dwVersion != PVK_FILE_VERSION_0 ||
  238. Hdr.cbEncryptData > MAX_PVK_FILE_LEN ||
  239. cbPvk == 0 || cbPvk > MAX_PVK_FILE_LEN)
  240. goto BadPvkFile;
  241. if (pdwKeySpec) {
  242. DWORD dwKeySpec = *pdwKeySpec;
  243. *pdwKeySpec = Hdr.dwKeySpec;
  244. if (dwKeySpec && dwKeySpec != Hdr.dwKeySpec) {
  245. SetLastError(PVK_HELPER_WRONG_KEY_TYPE);
  246. goto ErrorReturn;
  247. }
  248. }
  249. if (Hdr.cbEncryptData) {
  250. // Read the encrypt data
  251. if (NULL == (pbEncryptData = (BYTE *) PvkAlloc(Hdr.cbEncryptData)))
  252. goto ErrorReturn;
  253. if (!pfnRead(hRead, pbEncryptData, Hdr.cbEncryptData))
  254. goto BadPvkFile;
  255. }
  256. // Allocate and read the private key
  257. if (NULL == (pbPvk = (BYTE *) PvkAlloc(cbPvk)))
  258. goto ErrorReturn;
  259. if (!pfnRead(hRead, pbPvk, cbPvk))
  260. goto BadPvkFile;
  261. // Get symmetric key to decrypt the private key
  262. switch (Hdr.dwEncryptType) {
  263. case PVK_NO_ENCRYPT:
  264. break;
  265. case PVK_RC4_PASSWORD_ENCRYPT:
  266. if (!GetPasswordKey(hCryptProv, CALG_RC4,
  267. ENTER_PASSWORD, hwndOwner,
  268. pwszKeyName, FALSE, pbEncryptData, Hdr.cbEncryptData,
  269. &hDecryptKey))
  270. goto ErrorReturn;
  271. break;
  272. case PVK_RC2_CBC_PASSWORD_ENCRYPT:
  273. if (!GetPasswordKey(hCryptProv, CALG_RC2,
  274. ENTER_PASSWORD, hwndOwner,
  275. pwszKeyName, FALSE, pbEncryptData, Hdr.cbEncryptData,
  276. &hDecryptKey))
  277. goto ErrorReturn;
  278. break;
  279. default:
  280. goto BadPvkFile;
  281. }
  282. // Decrypt and import the private key
  283. if (!CryptImportKey(hCryptProv, pbPvk, cbPvk, hDecryptKey, dwFlags,
  284. &hKey))
  285. goto ErrorReturn;
  286. fResult = TRUE;
  287. }
  288. goto CommonReturn;
  289. BadPvkFile:
  290. SetLastError(PVK_HELPER_BAD_PVK_FILE);
  291. if (pdwKeySpec)
  292. *pdwKeySpec = 0;
  293. ErrorReturn:
  294. fResult = FALSE;
  295. CommonReturn:
  296. if (pbEncryptData)
  297. PvkFree(pbEncryptData);
  298. if (pbPvk)
  299. PvkFree(pbPvk);
  300. if (hDecryptKey)
  301. CryptDestroyKey(hDecryptKey);
  302. if (hKey)
  303. CryptDestroyKey(hKey);
  304. return fResult;
  305. }
  306. static BOOL SaveKey(
  307. IN HCRYPTPROV hCryptProv,
  308. IN HANDLE hWrite,
  309. IN PFNREAD pfnWrite,
  310. IN DWORD dwKeySpec, // either AT_SIGNATURE or AT_KEYEXCHANGE
  311. IN HWND hwndOwner,
  312. IN LPCWSTR pwszKeyName,
  313. IN DWORD dwFlags,
  314. IN BOOL fNoPassDlg
  315. )
  316. {
  317. BOOL fResult;
  318. FILE_HDR Hdr;
  319. HCRYPTKEY hEncryptKey = 0;
  320. HCRYPTKEY hKey = 0;
  321. BYTE *pbEncryptData = NULL; // Not allocated
  322. BYTE *pbPvk = NULL;
  323. DWORD cbPvk;
  324. BYTE rgbSalt[16];
  325. // Initialize the header record
  326. memset(&Hdr, 0, sizeof(Hdr));
  327. Hdr.dwMagic = PVK_MAGIC;
  328. Hdr.dwVersion = PVK_FILE_VERSION_0;
  329. Hdr.dwKeySpec = dwKeySpec;
  330. // Generate random salt
  331. if (!CryptGenRandom(hCryptProv, sizeof(rgbSalt), rgbSalt))
  332. goto ErrorReturn;
  333. // Get symmetric key to use to encrypt the private key
  334. #if 1
  335. if (!GetPasswordKey(hCryptProv, CALG_RC4,
  336. #else
  337. if (!GetPasswordKey(hCryptProv, CALG_RC2,
  338. #endif
  339. CREATE_PASSWORD, hwndOwner, pwszKeyName,
  340. fNoPassDlg, rgbSalt, sizeof(rgbSalt), &hEncryptKey))
  341. goto ErrorReturn;
  342. if (hEncryptKey) {
  343. #if 1
  344. Hdr.dwEncryptType = PVK_RC4_PASSWORD_ENCRYPT;
  345. #else
  346. Hdr.dwEncryptType = PVK_RC2_CBC_PASSWORD_ENCRYPT;
  347. #endif
  348. Hdr.cbEncryptData = sizeof(rgbSalt);
  349. pbEncryptData = rgbSalt;
  350. } else
  351. Hdr.dwEncryptType = PVK_NO_ENCRYPT;
  352. // Allocate, encrypt and export the private key
  353. if (!CryptGetUserKey(hCryptProv, dwKeySpec, &hKey))
  354. goto ErrorReturn;
  355. cbPvk = 0;
  356. if (!CryptExportKey(hKey, hEncryptKey, PRIVATEKEYBLOB, dwFlags, NULL,
  357. &cbPvk))
  358. goto ErrorReturn;
  359. if (NULL == (pbPvk = (BYTE *) PvkAlloc(cbPvk)))
  360. goto ErrorReturn;
  361. if (!CryptExportKey(hKey, hEncryptKey, PRIVATEKEYBLOB, dwFlags, pbPvk,
  362. &cbPvk))
  363. goto ErrorReturn;
  364. Hdr.cbPvk = cbPvk;
  365. // Write the header, optional encrypt data, and private key to the file
  366. if (!pfnWrite(hWrite, &Hdr, sizeof(Hdr)))
  367. goto ErrorReturn;
  368. if (Hdr.cbEncryptData) {
  369. if (!pfnWrite(hWrite, pbEncryptData, Hdr.cbEncryptData))
  370. goto ErrorReturn;
  371. }
  372. if (!pfnWrite(hWrite, pbPvk, cbPvk))
  373. goto ErrorReturn;
  374. fResult = TRUE;
  375. goto CommonReturn;
  376. ErrorReturn:
  377. fResult = FALSE;
  378. CommonReturn:
  379. if (pbPvk)
  380. PvkFree(pbPvk);
  381. if (hEncryptKey)
  382. CryptDestroyKey(hEncryptKey);
  383. if (hKey)
  384. CryptDestroyKey(hKey);
  385. return fResult;
  386. }
  387. //+-------------------------------------------------------------------------
  388. // Load the AT_SIGNATURE or AT_KEYEXCHANGE private key (and its public key)
  389. // from the file into the cryptographic provider.
  390. //
  391. // If the private key was password encrypted, then, the user is first
  392. // presented with a dialog box to enter the password.
  393. //
  394. // If pdwKeySpec is non-Null, then, if *pdwKeySpec is nonzero, verifies the
  395. // key type before loading. Sets LastError to PVK_HELPER_WRONG_KEY_TYPE for
  396. // a mismatch. *pdwKeySpec is updated with the key type.
  397. //
  398. // dwFlags is passed through to CryptImportKey.
  399. //--------------------------------------------------------------------------
  400. BOOL
  401. WINAPI
  402. PrivateKeyLoad(
  403. IN HCRYPTPROV hCryptProv,
  404. IN HANDLE hFile,
  405. IN HWND hwndOwner,
  406. IN LPCWSTR pwszKeyName,
  407. IN DWORD dwFlags,
  408. IN OUT OPTIONAL DWORD *pdwKeySpec
  409. )
  410. {
  411. return LoadKey(
  412. hCryptProv,
  413. hFile,
  414. ReadFromFile,
  415. GetFileSize(hFile, NULL),
  416. hwndOwner,
  417. pwszKeyName,
  418. dwFlags,
  419. pdwKeySpec
  420. );
  421. }
  422. //+-------------------------------------------------------------------------
  423. // Save the AT_SIGNATURE or AT_KEYEXCHANGE private key (and its public key)
  424. // to the specified file.
  425. //
  426. // The user is presented with a dialog box to enter an optional password to
  427. // encrypt the private key.
  428. //
  429. // dwFlags is passed through to CryptExportKey.
  430. //--------------------------------------------------------------------------
  431. BOOL
  432. WINAPI
  433. PrivateKeySave(
  434. IN HCRYPTPROV hCryptProv,
  435. IN HANDLE hFile,
  436. IN DWORD dwKeySpec, // either AT_SIGNATURE or AT_KEYEXCHANGE
  437. IN HWND hwndOwner,
  438. IN LPCWSTR pwszKeyName,
  439. IN DWORD dwFlags
  440. )
  441. {
  442. return SaveKey(
  443. hCryptProv,
  444. hFile,
  445. WriteToFile,
  446. dwKeySpec,
  447. hwndOwner,
  448. pwszKeyName,
  449. dwFlags,
  450. FALSE // fNoPassDlg
  451. );
  452. }
  453. //+-------------------------------------------------------------------------
  454. // Load the AT_SIGNATURE or AT_KEYEXCHANGE private key (and its public key)
  455. // from memory into the cryptographic provider.
  456. //
  457. // Except for the key being loaded from memory, identical to PrivateKeyLoad.
  458. //--------------------------------------------------------------------------
  459. BOOL
  460. WINAPI
  461. PrivateKeyLoadFromMemory(
  462. IN HCRYPTPROV hCryptProv,
  463. IN BYTE *pbData,
  464. IN DWORD cbData,
  465. IN HWND hwndOwner,
  466. IN LPCWSTR pwszKeyName,
  467. IN DWORD dwFlags,
  468. IN OUT OPTIONAL DWORD *pdwKeySpec
  469. )
  470. {
  471. MEMINFO MemInfo;
  472. MemInfo.pb = pbData;
  473. MemInfo.cb = cbData;
  474. MemInfo.cbSeek = 0;
  475. return LoadKey(
  476. hCryptProv,
  477. (HANDLE) &MemInfo,
  478. ReadFromMemory,
  479. cbData,
  480. hwndOwner,
  481. pwszKeyName,
  482. dwFlags,
  483. pdwKeySpec
  484. );
  485. }
  486. //+-------------------------------------------------------------------------
  487. // Save the AT_SIGNATURE or AT_KEYEXCHANGE private key (and its public key)
  488. // to memory.
  489. //
  490. // If pbData == NULL || *pcbData == 0, calculates the length and doesn't
  491. // return an error (also, the user isn't prompted for a password).
  492. //
  493. // Except for the key being saved to memory, identical to PrivateKeySave.
  494. //--------------------------------------------------------------------------
  495. BOOL
  496. WINAPI
  497. PrivateKeySaveToMemory(
  498. IN HCRYPTPROV hCryptProv,
  499. IN DWORD dwKeySpec, // either AT_SIGNATURE or AT_KEYEXCHANGE
  500. IN HWND hwndOwner,
  501. IN LPCWSTR pwszKeyName,
  502. IN DWORD dwFlags,
  503. OUT BYTE *pbData,
  504. IN OUT DWORD *pcbData
  505. )
  506. {
  507. BOOL fResult;
  508. MEMINFO MemInfo;
  509. MemInfo.pb = pbData;
  510. if (pbData == NULL)
  511. *pcbData = 0;
  512. MemInfo.cb = *pcbData;
  513. MemInfo.cbSeek = 0;
  514. if (fResult = SaveKey(
  515. hCryptProv,
  516. (HANDLE) &MemInfo,
  517. WriteToMemory,
  518. dwKeySpec,
  519. hwndOwner,
  520. pwszKeyName,
  521. dwFlags,
  522. *pcbData == 0 // fNoPassDlg
  523. )) {
  524. if (MemInfo.cbSeek > MemInfo.cb && *pcbData) {
  525. fResult = FALSE;
  526. SetLastError(ERROR_END_OF_MEDIA);
  527. }
  528. *pcbData = MemInfo.cbSeek;
  529. } else
  530. *pcbData = 0;
  531. return fResult;
  532. }
  533. //+-------------------------------------------------------------------------
  534. // Converts the bytes into WCHAR hex
  535. //
  536. // Needs (cb * 2 + 1) * sizeof(WCHAR) bytes of space in wsz
  537. //--------------------------------------------------------------------------
  538. static void BytesToWStr(ULONG cb, void* pv, LPWSTR wsz)
  539. {
  540. BYTE* pb = (BYTE*) pv;
  541. for (ULONG i = 0; i<cb; i++) {
  542. int b;
  543. b = (*pb & 0xF0) >> 4;
  544. *wsz++ = (b <= 9) ? b + L'0' : (b - 10) + L'A';
  545. b = *pb & 0x0F;
  546. *wsz++ = (b <= 9) ? b + L'0' : (b - 10) + L'A';
  547. pb++;
  548. }
  549. *wsz++ = 0;
  550. }
  551. #define UUID_WSTR_BYTES ((sizeof(UUID) * 2 + 1) * sizeof(WCHAR))
  552. static BOOL AcquireKeyContext(
  553. IN LPCWSTR pwszProvName,
  554. IN DWORD dwProvType,
  555. IN HANDLE hRead,
  556. IN PFNREAD pfnRead,
  557. IN DWORD cbKeyData,
  558. IN HWND hwndOwner,
  559. IN LPCWSTR pwszKeyName,
  560. IN OUT OPTIONAL DWORD *pdwKeySpec,
  561. OUT HCRYPTPROV *phCryptProv,
  562. OUT LPWSTR *ppwszTmpContainer
  563. )
  564. {
  565. BOOL fResult;
  566. HCRYPTPROV hProv = 0;
  567. UUID TmpContainerUuid;
  568. LPWSTR pwszTmpContainer = NULL;
  569. DWORD dwKeySpec;
  570. RPC_STATUS RpcStatus;
  571. // Create a temporary keyset to load the private key into
  572. RpcStatus = UuidCreate(&TmpContainerUuid);
  573. if (!(RPC_S_OK == RpcStatus || RPC_S_UUID_LOCAL_ONLY == RpcStatus)) {
  574. // Use stack randomness
  575. ;
  576. }
  577. if (NULL == (pwszTmpContainer = (LPWSTR) PvkAlloc(
  578. 6 * sizeof(WCHAR) + UUID_WSTR_BYTES)))
  579. goto ErrorReturn;
  580. wcscpy(pwszTmpContainer, L"TmpKey");
  581. BytesToWStr(sizeof(UUID), &TmpContainerUuid, pwszTmpContainer + 6);
  582. if (!CryptAcquireContextU(
  583. &hProv,
  584. pwszTmpContainer,
  585. pwszProvName,
  586. dwProvType,
  587. CRYPT_NEWKEYSET
  588. ))
  589. goto ErrorReturn;
  590. if (!LoadKey(
  591. hProv,
  592. hRead,
  593. pfnRead,
  594. cbKeyData,
  595. hwndOwner,
  596. pwszKeyName,
  597. 0, // dwFlags
  598. pdwKeySpec
  599. ))
  600. goto DeleteKeySetReturn;
  601. fResult = TRUE;
  602. goto CommonReturn;
  603. DeleteKeySetReturn:
  604. CryptReleaseContext(hProv, 0);
  605. CryptAcquireContextU(
  606. &hProv,
  607. pwszTmpContainer,
  608. pwszProvName,
  609. dwProvType,
  610. CRYPT_DELETEKEYSET
  611. );
  612. hProv = 0;
  613. ErrorReturn:
  614. if (hProv) {
  615. CryptReleaseContext(hProv, 0);
  616. hProv = 0;
  617. }
  618. if (pwszTmpContainer) {
  619. PvkFree(pwszTmpContainer);
  620. pwszTmpContainer = NULL;
  621. }
  622. fResult = FALSE;
  623. CommonReturn:
  624. *ppwszTmpContainer = pwszTmpContainer;
  625. *phCryptProv = hProv;
  626. return fResult;
  627. }
  628. //+-------------------------------------------------------------------------
  629. // Creates a temporary container in the provider and loads the private key
  630. // from the specified file.
  631. // For success, returns a handle to a cryptographic provider for the private
  632. // key and the name of the temporary container. PrivateKeyReleaseContext must
  633. // be called to release the hCryptProv and delete the temporary container.
  634. //
  635. // PrivateKeyLoad is called to load the private key into the temporary
  636. // container.
  637. //--------------------------------------------------------------------------
  638. BOOL
  639. WINAPI
  640. PrivateKeyAcquireContext(
  641. IN LPCWSTR pwszProvName,
  642. IN DWORD dwProvType,
  643. IN HANDLE hFile,
  644. IN HWND hwndOwner,
  645. IN LPCWSTR pwszKeyName,
  646. IN OUT OPTIONAL DWORD *pdwKeySpec,
  647. OUT HCRYPTPROV *phCryptProv,
  648. OUT LPWSTR *ppwszTmpContainer
  649. )
  650. {
  651. return AcquireKeyContext(
  652. pwszProvName,
  653. dwProvType,
  654. hFile,
  655. ReadFromFile,
  656. GetFileSize(hFile, NULL),
  657. hwndOwner,
  658. pwszKeyName,
  659. pdwKeySpec,
  660. phCryptProv,
  661. ppwszTmpContainer
  662. );
  663. }
  664. //+-------------------------------------------------------------------------
  665. // Creates a temporary container in the provider and loads the private key
  666. // from memory.
  667. // For success, returns a handle to a cryptographic provider for the private
  668. // key and the name of the temporary container. PrivateKeyReleaseContext must
  669. // be called to release the hCryptProv and delete the temporary container.
  670. //
  671. // PrivateKeyLoadFromMemory is called to load the private key into the
  672. // temporary container.
  673. //--------------------------------------------------------------------------
  674. BOOL
  675. WINAPI
  676. PrivateKeyAcquireContextFromMemory(
  677. IN LPCWSTR pwszProvName,
  678. IN DWORD dwProvType,
  679. IN BYTE *pbData,
  680. IN DWORD cbData,
  681. IN HWND hwndOwner,
  682. IN LPCWSTR pwszKeyName,
  683. IN OUT OPTIONAL DWORD *pdwKeySpec,
  684. OUT HCRYPTPROV *phCryptProv,
  685. OUT LPWSTR *ppwszTmpContainer
  686. )
  687. {
  688. MEMINFO MemInfo;
  689. MemInfo.pb = pbData;
  690. MemInfo.cb = cbData;
  691. MemInfo.cbSeek = 0;
  692. return AcquireKeyContext(
  693. pwszProvName,
  694. dwProvType,
  695. (HANDLE) &MemInfo,
  696. ReadFromMemory,
  697. cbData,
  698. hwndOwner,
  699. pwszKeyName,
  700. pdwKeySpec,
  701. phCryptProv,
  702. ppwszTmpContainer
  703. );
  704. }
  705. //+-------------------------------------------------------------------------
  706. // Releases the cryptographic provider and deletes the temporary container
  707. // created by PrivateKeyAcquireContext or PrivateKeyAcquireContextFromMemory.
  708. //--------------------------------------------------------------------------
  709. BOOL
  710. WINAPI
  711. PrivateKeyReleaseContext(
  712. IN HCRYPTPROV hCryptProv,
  713. IN LPCWSTR pwszProvName,
  714. IN DWORD dwProvType,
  715. IN LPWSTR pwszTmpContainer
  716. )
  717. {
  718. if (hCryptProv)
  719. CryptReleaseContext(hCryptProv, 0);
  720. if (pwszTmpContainer) {
  721. // Delete the temporary container for the private key from
  722. // the provider
  723. //
  724. // Note: for CRYPT_DELETEKEYSET, the returned hCryptProv is undefined
  725. // and must not be released.
  726. CryptAcquireContextU(
  727. &hCryptProv,
  728. pwszTmpContainer,
  729. pwszProvName,
  730. dwProvType,
  731. CRYPT_DELETEKEYSET
  732. );
  733. PvkFree(pwszTmpContainer);
  734. }
  735. return TRUE;
  736. }
  737. //+-------------------------------------------------------------------------
  738. // Functions supporting backwards compatibility with Bob's storage file
  739. // containing a snap shot of the keys as they are stored in the registry.
  740. // Note, for win95, the registry values are decrypted before being written to
  741. // the file.
  742. //--------------------------------------------------------------------------
  743. // Return the size of this stream; return 0 if an error
  744. static DWORD CbBobSize(IStream *pStm)
  745. {
  746. STATSTG stat;
  747. if (FAILED(pStm->Stat(&stat, STATFLAG_NONAME)))
  748. return 0;
  749. return stat.cbSize.LowPart;
  750. }
  751. // Allocate and read this value which has the indicated stream name from the
  752. // storage
  753. static BOOL LoadBobStream(
  754. IStorage *pStg,
  755. LPCWSTR pwszStm,
  756. BYTE **ppbValue,
  757. DWORD *pcbValue
  758. )
  759. {
  760. BOOL fResult;
  761. HRESULT hr;
  762. IStream *pStm = NULL;
  763. BYTE *pbValue = NULL;
  764. DWORD cbValue;
  765. DWORD cbRead;
  766. if (FAILED(hr = pStg->OpenStream(pwszStm, 0,
  767. STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStm)))
  768. goto HrError;
  769. if (0 == (cbValue = CbBobSize(pStm))) goto BadBobFile;
  770. if (NULL == (pbValue = (BYTE *) PvkAlloc(cbValue))) goto ErrorReturn;
  771. pStm->Read(pbValue, cbValue, &cbRead);
  772. if (cbRead != cbValue) goto BadBobFile;
  773. fResult = TRUE;
  774. goto CommonReturn;
  775. HrError:
  776. SetLastError((DWORD) hr);
  777. goto ErrorReturn;
  778. BadBobFile:
  779. SetLastError(PVK_HELPER_BAD_PVK_FILE);
  780. ErrorReturn:
  781. if (pbValue) {
  782. PvkFree(pbValue);
  783. pbValue = NULL;
  784. }
  785. cbValue = 0;
  786. fResult = FALSE;
  787. CommonReturn:
  788. if (pStm)
  789. pStm->Release();
  790. *ppbValue = pbValue;
  791. *pcbValue = cbValue;
  792. return fResult;
  793. }
  794. // New "Bob" format::
  795. //
  796. // Allocate and read either the Exported Signature or Exchange Private
  797. // key stream from the storage
  798. static BOOL LoadBobExportedPvk(
  799. IStorage *pStg,
  800. DWORD dwKeySpec,
  801. BYTE **ppbPvkValue,
  802. DWORD *pcbPvkValue
  803. )
  804. {
  805. BOOL fResult;
  806. LPCWSTR pwszPvk;
  807. switch (dwKeySpec) {
  808. case AT_SIGNATURE:
  809. pwszPvk = L"Exported Signature Private Key";
  810. break;
  811. case AT_KEYEXCHANGE:
  812. pwszPvk = L"Exported Exchange Private Key";
  813. break;
  814. default:
  815. SetLastError(PVK_HELPER_BAD_PARAMETER);
  816. goto ErrorReturn;
  817. }
  818. fResult = LoadBobStream(pStg, pwszPvk, ppbPvkValue, pcbPvkValue);
  819. if (fResult) goto CommonReturn;
  820. ErrorReturn:
  821. *ppbPvkValue = NULL;
  822. *pcbPvkValue = 0;
  823. fResult = FALSE;
  824. CommonReturn:
  825. return fResult;
  826. }
  827. // Old "Bob" format::
  828. //
  829. // Allocate and read either the Signature or Exchange Private
  830. // key streams from the storage
  831. static BOOL LoadBobOldPvk(
  832. IStorage *pStg,
  833. DWORD dwKeySpec,
  834. BYTE **ppbPvkValue,
  835. DWORD *pcbPvkValue
  836. )
  837. {
  838. BOOL fResult;
  839. LPCWSTR pwszPvk;
  840. switch (dwKeySpec) {
  841. case AT_SIGNATURE:
  842. pwszPvk = L"SPvk";
  843. break;
  844. case AT_KEYEXCHANGE:
  845. pwszPvk = L"EPvk";
  846. break;
  847. default:
  848. SetLastError(PVK_HELPER_BAD_PARAMETER);
  849. goto ErrorReturn;
  850. }
  851. fResult = LoadBobStream(pStg, pwszPvk, ppbPvkValue, pcbPvkValue);
  852. if (fResult) goto CommonReturn;
  853. ErrorReturn:
  854. *ppbPvkValue = NULL;
  855. *pcbPvkValue = 0;
  856. fResult = FALSE;
  857. CommonReturn:
  858. return fResult;
  859. }
  860. ///////////////////////////////////////////////////////////////////////////////////////
  861. //
  862. // Key header structures for private key construction
  863. //
  864. // These structs define the fixed data at the beginning of an RSA key.
  865. // They are followed by a variable length of data, sized by the stlen
  866. // field.
  867. //
  868. // For more info see Jeff Spellman in the crypto team or look in the
  869. // source to RsaBase.Dll
  870. //
  871. typedef struct {
  872. DWORD magic; /* Should always be RSA2 */
  873. DWORD keylen; // size of modulus buffer
  874. DWORD bitlen; // bit size of key
  875. DWORD datalen; // max number of bytes to be encoded
  876. DWORD pubexp; // public exponent
  877. } BSAFE_PRV_KEY, FAR *LPBSAFE_PRV_KEY;
  878. typedef struct {
  879. BYTE *modulus;
  880. BYTE *prvexp;
  881. BYTE *prime1;
  882. BYTE *prime2;
  883. BYTE *exp1;
  884. BYTE *exp2;
  885. BYTE *coef;
  886. BYTE *invmod;
  887. BYTE *invpr1;
  888. BYTE *invpr2;
  889. } BSAFE_KEY_PARTS, FAR *LPBSAFE_KEY_PARTS;
  890. typedef struct {
  891. DWORD magic; /* Should always be RSA2 */
  892. DWORD bitlen; // bit size of key
  893. DWORD pubexp; // public exponent
  894. } EXPORT_PRV_KEY, FAR *PEXPORT_PRV_KEY;
  895. ///////////////////////////////////////////////////////////////////////////////////////
  896. //
  897. // Take a raw exported unshrowded private key from the registry and turn it
  898. // into a private key export blob.
  899. //
  900. // This is based on the PreparePrivateKeyForExport routine from rsabase.dll
  901. //
  902. static BOOL ConstructPrivateKeyExportBlob(
  903. IN DWORD dwKeySpec,
  904. IN BSAFE_PRV_KEY * pPrvKey,
  905. IN DWORD PrvKeyLen,
  906. OUT PBYTE *ppbBlob,
  907. OUT DWORD *pcbBlob
  908. )
  909. {
  910. BOOL fResult;
  911. PEXPORT_PRV_KEY pExportKey;
  912. DWORD cbHalfModLen;
  913. PBYTE pbBlob = NULL;
  914. DWORD cbBlob;
  915. PBYTE pbIn;
  916. PBYTE pbOut;
  917. cbHalfModLen = pPrvKey->bitlen / 16;
  918. cbBlob = sizeof(EXPORT_PRV_KEY) + 9 * cbHalfModLen +
  919. sizeof(PUBLICKEYSTRUC);
  920. if (NULL == (pbBlob = (BYTE *) PvkAlloc(cbBlob))) {
  921. fResult = FALSE;
  922. cbBlob = 0;
  923. } else {
  924. BYTE* pb = pbBlob;
  925. PUBLICKEYSTRUC *pPubKeyStruc = (PUBLICKEYSTRUC *) pb;
  926. pPubKeyStruc->bType = PRIVATEKEYBLOB;
  927. pPubKeyStruc->bVersion = 2;
  928. pPubKeyStruc->reserved = 0;
  929. if (dwKeySpec == AT_KEYEXCHANGE)
  930. pPubKeyStruc->aiKeyAlg = CALG_RSA_KEYX;
  931. else if (dwKeySpec == AT_SIGNATURE)
  932. pPubKeyStruc->aiKeyAlg = CALG_RSA_SIGN;
  933. else
  934. pPubKeyStruc->aiKeyAlg = 0;
  935. pb = pbBlob + sizeof(PUBLICKEYSTRUC);
  936. // take most of the header info
  937. pExportKey = (PEXPORT_PRV_KEY)pb;
  938. pExportKey->magic = pPrvKey->magic;
  939. pExportKey->bitlen = pPrvKey->bitlen;
  940. pExportKey->pubexp = pPrvKey->pubexp;
  941. pbIn = (PBYTE)pPrvKey + sizeof(BSAFE_PRV_KEY);
  942. pbOut = pb + sizeof(EXPORT_PRV_KEY);
  943. // copy all the private key info
  944. memcpy(pbOut, pbIn, cbHalfModLen * 2);
  945. pbIn += (cbHalfModLen + sizeof(DWORD)) * 2;
  946. pbOut += cbHalfModLen * 2;
  947. memcpy(pbOut, pbIn, cbHalfModLen);
  948. pbIn += cbHalfModLen + sizeof(DWORD);
  949. pbOut += cbHalfModLen;
  950. memcpy(pbOut, pbIn, cbHalfModLen);
  951. pbIn += cbHalfModLen + sizeof(DWORD);
  952. pbOut += cbHalfModLen;
  953. memcpy(pbOut, pbIn, cbHalfModLen);
  954. pbIn += cbHalfModLen + sizeof(DWORD);
  955. pbOut += cbHalfModLen;
  956. memcpy(pbOut, pbIn, cbHalfModLen);
  957. pbIn += cbHalfModLen + sizeof(DWORD);
  958. pbOut += cbHalfModLen;
  959. memcpy(pbOut, pbIn, cbHalfModLen);
  960. pbIn += cbHalfModLen + sizeof(DWORD);
  961. pbOut += cbHalfModLen;
  962. memcpy(pbOut, pbIn, cbHalfModLen * 2);
  963. fResult = TRUE;
  964. }
  965. *ppbBlob = pbBlob;
  966. *pcbBlob = cbBlob;
  967. return fResult;
  968. }
  969. static BOOL LoadBobKey(
  970. IN HCRYPTPROV hCryptProv,
  971. IN HANDLE hRead,
  972. IN PFNREAD pfnRead,
  973. IN DWORD cbBobKey,
  974. IN HWND hwndOwner,
  975. IN LPCWSTR pwszKeyName,
  976. IN DWORD dwFlags,
  977. IN OUT OPTIONAL DWORD *pdwKeySpec,
  978. IN PFILE_HDR pHdr // header has already been read
  979. )
  980. {
  981. BOOL fResult;
  982. DWORD dwErr = 0;
  983. HRESULT hr;
  984. HGLOBAL hGlobal = NULL;
  985. BYTE *pbBobKey; // not allocated
  986. ILockBytes *pLkByt = NULL;
  987. IStorage *pStg = NULL;
  988. IStorage *pPrivStg = NULL;
  989. BYTE *pbPvkValue = NULL;
  990. DWORD cbPvkValue;
  991. DWORD dwKeySpec;
  992. BYTE *pbPvk = NULL;
  993. DWORD cbPvk;
  994. if (cbBobKey > MAX_BOB_FILE_LEN) goto BadBobFile;
  995. if (NULL == (hGlobal = GlobalAlloc(GMEM_MOVEABLE | GMEM_DISCARDABLE,
  996. cbBobKey)))
  997. goto ErrorReturn;
  998. if (NULL == (pbBobKey = (BYTE *) GlobalLock(hGlobal)))
  999. goto ErrorReturn;
  1000. memcpy(pbBobKey, (BYTE *) pHdr, sizeof(FILE_HDR));
  1001. if (cbBobKey > sizeof(FILE_HDR))
  1002. fResult = pfnRead(hRead, pbBobKey + sizeof(FILE_HDR),
  1003. cbBobKey - sizeof(FILE_HDR));
  1004. else
  1005. fResult = TRUE;
  1006. GlobalUnlock(hGlobal);
  1007. if (!fResult) goto ErrorReturn;
  1008. // FALSE => don't DeleteOnRelease
  1009. if (FAILED(hr = CreateILockBytesOnHGlobal(hGlobal, FALSE, &pLkByt)))
  1010. goto HrError;
  1011. if (FAILED(hr = StgOpenStorageOnILockBytes(
  1012. pLkByt,
  1013. NULL, // pStgPriority
  1014. STGM_DIRECT | STGM_READ | STGM_SHARE_DENY_WRITE,
  1015. NULL, // snbExclude
  1016. 0, // dwReserved
  1017. &pStg
  1018. ))) goto HrError;
  1019. if (FAILED(pStg->OpenStorage(
  1020. L"Plain Private Key",
  1021. 0,
  1022. STGM_READ | STGM_SHARE_EXCLUSIVE,
  1023. NULL,
  1024. 0,
  1025. &pPrivStg))) goto BadBobFile;
  1026. if (pdwKeySpec && *pdwKeySpec)
  1027. dwKeySpec = *pdwKeySpec;
  1028. else
  1029. dwKeySpec = AT_SIGNATURE;
  1030. // First, attempt to read the new format where the keys are stored in
  1031. // the private key export format
  1032. fResult = LoadBobExportedPvk(pPrivStg, dwKeySpec, &pbPvkValue,
  1033. &cbPvkValue);
  1034. if (!fResult && (pdwKeySpec == NULL || *pdwKeySpec == 0)) {
  1035. dwKeySpec = AT_KEYEXCHANGE;
  1036. fResult = LoadBobExportedPvk(pPrivStg, dwKeySpec,
  1037. &pbPvkValue, &cbPvkValue);
  1038. }
  1039. if (fResult)
  1040. fResult = PrivateKeyLoadFromMemory(
  1041. hCryptProv,
  1042. pbPvkValue,
  1043. cbPvkValue,
  1044. hwndOwner,
  1045. pwszKeyName,
  1046. dwFlags,
  1047. &dwKeySpec
  1048. );
  1049. else {
  1050. // Try "old" format
  1051. if (pdwKeySpec && *pdwKeySpec)
  1052. dwKeySpec = *pdwKeySpec;
  1053. else
  1054. dwKeySpec = AT_SIGNATURE;
  1055. fResult = LoadBobOldPvk(pPrivStg, dwKeySpec, &pbPvkValue, &cbPvkValue);
  1056. if (!fResult && (pdwKeySpec == NULL || *pdwKeySpec == 0)) {
  1057. dwKeySpec = AT_KEYEXCHANGE;
  1058. fResult = LoadBobOldPvk(pPrivStg, dwKeySpec,
  1059. &pbPvkValue, &cbPvkValue);
  1060. }
  1061. if (fResult) {
  1062. BYTE *pbExportPvk;
  1063. DWORD cbExportPvk;
  1064. // Convert Bob's old private key format to the new export private
  1065. // key format
  1066. if ((fResult = ConstructPrivateKeyExportBlob(
  1067. dwKeySpec,
  1068. (BSAFE_PRV_KEY *) pbPvkValue,
  1069. cbPvkValue,
  1070. &pbExportPvk,
  1071. &cbExportPvk
  1072. ))) {
  1073. HCRYPTKEY hKey = 0;
  1074. // Import the private key
  1075. fResult = CryptImportKey(hCryptProv, pbExportPvk, cbExportPvk,
  1076. 0, dwFlags, &hKey);
  1077. if (hKey)
  1078. CryptDestroyKey(hKey);
  1079. PvkFree(pbExportPvk);
  1080. }
  1081. }
  1082. }
  1083. if (fResult) goto CommonReturn;
  1084. goto ErrorReturn;
  1085. HrError:
  1086. SetLastError((DWORD) hr);
  1087. goto ErrorReturn;
  1088. BadBobFile:
  1089. SetLastError(PVK_HELPER_BAD_PVK_FILE);
  1090. ErrorReturn:
  1091. dwKeySpec = 0;
  1092. fResult = FALSE;
  1093. // One of the following Releases may clear it out
  1094. dwErr = GetLastError();
  1095. CommonReturn:
  1096. if (pbPvkValue)
  1097. PvkFree(pbPvkValue);
  1098. if (pPrivStg)
  1099. pPrivStg->Release();
  1100. if (pStg)
  1101. pStg->Release();
  1102. if (pLkByt)
  1103. pLkByt->Release();
  1104. if (hGlobal)
  1105. GlobalFree(hGlobal);
  1106. if (pdwKeySpec)
  1107. *pdwKeySpec = dwKeySpec;
  1108. if (dwErr)
  1109. SetLastError(dwErr);
  1110. return fResult;
  1111. }