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.

1423 lines
41 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1995 - 1999
  6. //
  7. // File: certhlpr.cpp
  8. //
  9. // Contents: import and export of private keys
  10. //
  11. // Functions: ImportExoprtDllMain
  12. // CryptImportPKCS8
  13. // CryptExportPKCS8
  14. //
  15. // History:
  16. //--------------------------------------------------------------------------
  17. #include "global.hxx"
  18. //#include "prvtkey.h"
  19. #include "impexppk.h"
  20. #include "pfxcrypt.h"
  21. // All the *pvInfo extra stuff needs to be aligned
  22. #define INFO_LEN_ALIGN(Len) ((Len + 7) & ~7)
  23. static BOOL WINAPI ExportRSAPrivateKeyInfo(
  24. HCRYPTPROV hCryptProv, // in
  25. DWORD dwKeySpec, // in
  26. LPSTR pszPrivateKeyObjId, // in
  27. DWORD dwFlags, // in
  28. void *pvAuxInfo, // in
  29. CRYPT_PRIVATE_KEY_INFO *pPrivateKeyInfo, // out
  30. DWORD *pcbPrivateKeyInfo // in, out
  31. );
  32. static BOOL WINAPI ImportRSAPrivateKeyInfo(
  33. HCRYPTPROV hCryptProv, // in
  34. CRYPT_PRIVATE_KEY_INFO *pPrivateKeyInfo, // in
  35. DWORD dwFlags, // in, optional
  36. void *pvAuxInfo // in, optional
  37. );
  38. static BOOL WINAPI ExportDSSPrivateKeyInfo(
  39. HCRYPTPROV hCryptProv, // in
  40. DWORD dwKeySpec, // in
  41. LPSTR pszPrivateKeyObjId, // in
  42. DWORD dwFlags, // in
  43. void *pvAuxInfo, // in
  44. CRYPT_PRIVATE_KEY_INFO *pPrivateKeyInfo, // out
  45. DWORD *pcbPrivateKeyInfo // in, out
  46. );
  47. static BOOL WINAPI ImportDSSPrivateKeyInfo(
  48. HCRYPTPROV hCryptProv, // in
  49. CRYPT_PRIVATE_KEY_INFO *pPrivateKeyInfo, // in
  50. DWORD dwFlags, // in, optional
  51. void *pvAuxInfo // in, optional
  52. );
  53. static HCRYPTOIDFUNCSET hExportPrivKeyFuncSet;
  54. static HCRYPTOIDFUNCSET hImportPrivKeyFuncSet;
  55. // Internal default OIDs
  56. #define DEFAULT_CSP_PRIVKEY1 ((LPCSTR) 1)
  57. #define DEFAULT_CSP_PRIVKEY2 ((LPCSTR) 2)
  58. static const CRYPT_OID_FUNC_ENTRY ExportPrivKeyFuncTable[] = {
  59. DEFAULT_CSP_PRIVKEY1, ExportRSAPrivateKeyInfo,
  60. szOID_RSA_RSA, ExportRSAPrivateKeyInfo,
  61. szOID_OIWSEC_dsa, ExportDSSPrivateKeyInfo,
  62. szOID_X957_DSA, ExportDSSPrivateKeyInfo
  63. };
  64. #define EXPORT_PRIV_KEY_FUNC_COUNT (sizeof(ExportPrivKeyFuncTable) / \
  65. sizeof(ExportPrivKeyFuncTable[0]))
  66. static const CRYPT_OID_FUNC_ENTRY ImportPrivKeyFuncTable[] = {
  67. szOID_RSA_RSA, ImportRSAPrivateKeyInfo,
  68. szOID_OIWSEC_dsa, ImportDSSPrivateKeyInfo,
  69. szOID_X957_DSA, ImportDSSPrivateKeyInfo
  70. };
  71. #define IMPORT_PRIV_KEY_FUNC_COUNT (sizeof(ImportPrivKeyFuncTable) / \
  72. sizeof(ImportPrivKeyFuncTable[0]))
  73. BOOL
  74. WINAPI
  75. ImportExportDllMain(
  76. HMODULE hInst,
  77. ULONG ul_reason_for_call,
  78. LPVOID lpReserved)
  79. {
  80. switch( ul_reason_for_call )
  81. {
  82. case DLL_PROCESS_ATTACH:
  83. // Private key function setup
  84. if (NULL == (hExportPrivKeyFuncSet = CryptInitOIDFunctionSet(
  85. CRYPT_OID_EXPORT_PRIVATE_KEY_INFO_FUNC,
  86. 0)))
  87. goto ErrorReturn;
  88. if (NULL == (hImportPrivKeyFuncSet = CryptInitOIDFunctionSet(
  89. CRYPT_OID_IMPORT_PRIVATE_KEY_INFO_FUNC,
  90. 0)))
  91. goto ErrorReturn;
  92. if (!CryptInstallOIDFunctionAddress(
  93. NULL, // hModule
  94. X509_ASN_ENCODING,
  95. CRYPT_OID_EXPORT_PRIVATE_KEY_INFO_FUNC,
  96. EXPORT_PRIV_KEY_FUNC_COUNT,
  97. ExportPrivKeyFuncTable,
  98. 0)) // dwFlags
  99. goto ErrorReturn;
  100. if (!CryptInstallOIDFunctionAddress(
  101. NULL, // hModule
  102. X509_ASN_ENCODING,
  103. CRYPT_OID_IMPORT_PRIVATE_KEY_INFO_FUNC,
  104. IMPORT_PRIV_KEY_FUNC_COUNT,
  105. ImportPrivKeyFuncTable,
  106. 0)) // dwFlags
  107. goto ErrorReturn;
  108. break;
  109. case DLL_PROCESS_DETACH:
  110. break;
  111. default:
  112. break;
  113. }
  114. return TRUE;
  115. ErrorReturn:
  116. return FALSE;
  117. }
  118. //+-------------------------------------------------------------------------
  119. // phCryptProv - a pointer to a HCRYPTPROV to put the handle of the provider
  120. // that received the imported keyset. if this is NON_NULL then
  121. // the caller is responsible for calling CryptReleaseContext().
  122. // pdwKeySpec - a pointer to a DWORD to receive the KeySpec of imported keyset
  123. // privateKeyAndParams - private key blob and corresponding parameters
  124. // dwFlags - The available flags are:
  125. // CRYPT_EXPORTABLE
  126. // this flag is used when importing private keys, for a full
  127. // explanation please see the documentation for CryptImportKey.
  128. // phCryptProv - filled in with the handle of the provider the key was
  129. // imported to, the caller is responsible for freeing it
  130. // pvAuxInfo - This parameter is reserved for future use and should be set
  131. // to NULL in the interim.
  132. //+-------------------------------------------------------------------------
  133. BOOL
  134. WINAPI
  135. CryptImportPKCS8(
  136. CRYPT_PKCS8_IMPORT_PARAMS sPrivateKeyAndParams, // in
  137. DWORD dwFlags, // in, optional
  138. HCRYPTPROV *phCryptProv, // out
  139. void *pvAuxInfo // in, optional
  140. )
  141. {
  142. BOOL fResult = TRUE;
  143. void *pvFuncAddr;
  144. HCRYPTOIDFUNCADDR hFuncAddr;
  145. CRYPT_PRIVATE_KEY_INFO *pPrivateKeyInfoStruct = NULL;
  146. DWORD cbPrivateKeyInfoStruct = 0;
  147. CRYPT_ENCRYPTED_PRIVATE_KEY_INFO *pEncryptedPrivateKeyInfoStruct = NULL;
  148. DWORD cbEncryptedPrivateKeyInfoStruct = 0;
  149. BYTE *pbEncodedPrivateKey = sPrivateKeyAndParams.PrivateKey.pbData;
  150. DWORD cbEncodedPrivateKey = sPrivateKeyAndParams.PrivateKey.cbData;
  151. BOOL bEncodedPrivateKeyAlloced = FALSE;
  152. HCRYPTPROV hCryptProv = NULL;
  153. // try to decode private key blob as a CRYPT_PRIVATE_KEY_INFO structure
  154. if (!CryptDecodeObject(X509_ASN_ENCODING,
  155. PKCS_PRIVATE_KEY_INFO,
  156. sPrivateKeyAndParams.PrivateKey.pbData,
  157. sPrivateKeyAndParams.PrivateKey.cbData,
  158. CRYPT_DECODE_NOCOPY_FLAG,
  159. NULL,
  160. &cbPrivateKeyInfoStruct)) {
  161. // that decode failed, so try to decode as CRYPT_ENCRYPTED_PRIVATE_KEY_INFO structure
  162. if (!CryptDecodeObject(X509_ASN_ENCODING,
  163. PKCS_ENCRYPTED_PRIVATE_KEY_INFO,
  164. sPrivateKeyAndParams.PrivateKey.pbData,
  165. sPrivateKeyAndParams.PrivateKey.cbData,
  166. CRYPT_DECODE_NOCOPY_FLAG,
  167. NULL,
  168. &cbEncryptedPrivateKeyInfoStruct))
  169. goto ErrorReturn;
  170. if (NULL == (pEncryptedPrivateKeyInfoStruct = (CRYPT_ENCRYPTED_PRIVATE_KEY_INFO *)
  171. SSAlloc(cbEncryptedPrivateKeyInfoStruct)))
  172. goto ErrorReturn;
  173. if (!CryptDecodeObject(X509_ASN_ENCODING,
  174. PKCS_ENCRYPTED_PRIVATE_KEY_INFO,
  175. sPrivateKeyAndParams.PrivateKey.pbData,
  176. sPrivateKeyAndParams.PrivateKey.cbData,
  177. CRYPT_DECODE_NOCOPY_FLAG,
  178. pEncryptedPrivateKeyInfoStruct,
  179. &cbEncryptedPrivateKeyInfoStruct))
  180. goto ErrorReturn;
  181. // call back the callee to decrypt the private key info
  182. pbEncodedPrivateKey = NULL;
  183. cbEncodedPrivateKey = 0;
  184. if (!sPrivateKeyAndParams.pDecryptPrivateKeyFunc(
  185. pEncryptedPrivateKeyInfoStruct->EncryptionAlgorithm,
  186. pEncryptedPrivateKeyInfoStruct->EncryptedPrivateKey,
  187. NULL,
  188. &cbEncodedPrivateKey,
  189. sPrivateKeyAndParams.pVoidDecryptFunc))
  190. goto ErrorReturn;
  191. if (NULL == (pbEncodedPrivateKey = (BYTE *)
  192. SSAlloc(cbEncodedPrivateKey)))
  193. goto ErrorReturn;
  194. bEncodedPrivateKeyAlloced = TRUE;
  195. if (!sPrivateKeyAndParams.pDecryptPrivateKeyFunc(
  196. pEncryptedPrivateKeyInfoStruct->EncryptionAlgorithm,
  197. pEncryptedPrivateKeyInfoStruct->EncryptedPrivateKey,
  198. pbEncodedPrivateKey,
  199. &cbEncodedPrivateKey,
  200. sPrivateKeyAndParams.pVoidDecryptFunc))
  201. goto ErrorReturn;
  202. // we are now back to square one with an encoded CRYPT_PRIVATE_KEY_INFO struct,
  203. // so get the size of that when it's decoded
  204. if (!CryptDecodeObject(X509_ASN_ENCODING,
  205. PKCS_PRIVATE_KEY_INFO,
  206. pbEncodedPrivateKey,
  207. cbEncodedPrivateKey,
  208. CRYPT_DECODE_NOCOPY_FLAG,
  209. NULL,
  210. &cbPrivateKeyInfoStruct))
  211. goto ErrorReturn;
  212. }
  213. if (NULL == (pPrivateKeyInfoStruct = (CRYPT_PRIVATE_KEY_INFO *)
  214. SSAlloc(cbPrivateKeyInfoStruct)))
  215. goto ErrorReturn;
  216. if (!CryptDecodeObject(X509_ASN_ENCODING,
  217. PKCS_PRIVATE_KEY_INFO,
  218. pbEncodedPrivateKey,
  219. cbEncodedPrivateKey,
  220. CRYPT_DECODE_NOCOPY_FLAG,
  221. pPrivateKeyInfoStruct,
  222. &cbPrivateKeyInfoStruct))
  223. goto ErrorReturn;
  224. // call the caller back to get the provider to import to, if the
  225. // call back is null then just use the default provider.
  226. if (sPrivateKeyAndParams.pResolvehCryptProvFunc != NULL) {
  227. if (!sPrivateKeyAndParams.pResolvehCryptProvFunc(
  228. pPrivateKeyInfoStruct,
  229. &hCryptProv,
  230. sPrivateKeyAndParams.pVoidResolveFunc)) {
  231. goto ErrorReturn;
  232. }
  233. }
  234. else {
  235. if (!CryptAcquireContext(
  236. &hCryptProv,
  237. NULL,
  238. NULL,
  239. PROV_RSA_FULL,
  240. CRYPT_NEWKEYSET)) {
  241. goto ErrorReturn;
  242. }
  243. }
  244. // resolve what supporting import function to call based on the algorithm
  245. // OID of the private key
  246. if (CryptGetOIDFunctionAddress(
  247. hImportPrivKeyFuncSet,
  248. X509_ASN_ENCODING,
  249. pPrivateKeyInfoStruct->Algorithm.pszObjId,
  250. 0, // dwFlags
  251. &pvFuncAddr,
  252. &hFuncAddr)) {
  253. fResult = ((PFN_IMPORT_PRIV_KEY_FUNC) pvFuncAddr)(
  254. hCryptProv,
  255. pPrivateKeyInfoStruct,
  256. dwFlags,
  257. pvAuxInfo
  258. );
  259. CryptFreeOIDFunctionAddress(hFuncAddr, 0);
  260. }
  261. else {
  262. SetLastError(ERROR_UNSUPPORTED_TYPE);
  263. goto ErrorReturn;
  264. }
  265. // check to see if the caller wants the hCryptProv
  266. if (phCryptProv) {
  267. *phCryptProv = hCryptProv;
  268. }
  269. else {
  270. HRESULT hr = GetLastError();
  271. CryptReleaseContext(hCryptProv, 0);
  272. SetLastError(hr);
  273. }
  274. goto CommonReturn;
  275. ErrorReturn:
  276. fResult = FALSE;
  277. if (hCryptProv)
  278. {
  279. HRESULT hr = GetLastError();
  280. CryptReleaseContext(hCryptProv, 0);
  281. SetLastError(hr);
  282. }
  283. CommonReturn:
  284. if (pPrivateKeyInfoStruct)
  285. SSFree(pPrivateKeyInfoStruct);
  286. if (pEncryptedPrivateKeyInfoStruct)
  287. SSFree(pEncryptedPrivateKeyInfoStruct);
  288. if (bEncodedPrivateKeyAlloced)
  289. SSFree(pbEncodedPrivateKey);
  290. return fResult;
  291. }
  292. ////////
  293. // old crusty API kept around for compat reasons
  294. BOOL
  295. WINAPI
  296. CryptExportPKCS8(
  297. HCRYPTPROV hCryptProv, // in
  298. DWORD dwKeySpec, // in
  299. LPSTR pszPrivateKeyObjId, // in
  300. DWORD dwFlags, // in
  301. void *pvAuxInfo, // in
  302. BYTE *pbPrivateKeyBlob, // out
  303. DWORD *pcbPrivateKeyBlob // in, out
  304. )
  305. {
  306. CRYPT_PKCS8_EXPORT_PARAMS sExportParams;
  307. ZeroMemory(&sExportParams, sizeof(sExportParams));
  308. // copy args to pkcs8_export struct
  309. sExportParams.hCryptProv = hCryptProv;
  310. sExportParams.dwKeySpec = dwKeySpec;
  311. sExportParams.pszPrivateKeyObjId = pszPrivateKeyObjId;
  312. // these are not available to non-Ex function
  313. sExportParams.pEncryptPrivateKeyFunc = NULL;
  314. sExportParams.pVoidEncryptFunc = NULL;
  315. return CryptExportPKCS8Ex(
  316. &sExportParams,
  317. dwFlags,
  318. pvAuxInfo,
  319. pbPrivateKeyBlob,
  320. pcbPrivateKeyBlob);
  321. }
  322. //+-------------------------------------------------------------------------
  323. // hCryptProv - specifies the provider to export from
  324. // dwKeySpec - Identifies the public key to use from the provider's container.
  325. // For example, AT_KEYEXCHANGE or AT_SIGNATURE.
  326. // pszPrivateKeyObjId - Specifies the private key algorithm. If an installable
  327. // function was not found for the pszPrivateKeyObjId, an
  328. // attempt is made to export the key as a RSA Public Key
  329. // (szOID_RSA_RSA).
  330. // dwFlags - The flag values. Current supported values are:
  331. // DELETE_KEYSET - (NOT CURRENTLY SUPPORTED!!!!)
  332. // will delete key after export
  333. // pvAuxInfo - This parameter is reserved for future use and should be set to
  334. // NULL in the interim.
  335. // pbPrivateKeyBlob - A pointer to the private key blob. It will be encoded
  336. // as a PKCS8 PrivateKeyInfo.
  337. // pcbPrivateKeyBlob - A pointer to a DWORD that contains the size, in bytes,
  338. // of the private key blob being exported.
  339. //+-------------------------------------------------------------------------
  340. BOOL
  341. WINAPI
  342. CryptExportPKCS8Ex(
  343. CRYPT_PKCS8_EXPORT_PARAMS* psExportParams, // in
  344. DWORD dwFlags, // in
  345. void *pvAuxInfo, // in
  346. BYTE *pbPrivateKeyBlob, // out
  347. DWORD *pcbPrivateKeyBlob // in, out
  348. )
  349. {
  350. BOOL fResult = TRUE;
  351. void *pvFuncAddr;
  352. HCRYPTOIDFUNCADDR hFuncAddr;
  353. CRYPT_PRIVATE_KEY_INFO *pPrivateKeyInfo = NULL;
  354. DWORD cbPrivateKeyInfo = 0;
  355. DWORD cbEncoded = 0;
  356. // optional; used during encrypted export
  357. PBYTE pbTmpKeyBlob = NULL;
  358. CRYPT_ENCRYPTED_PRIVATE_KEY_INFO sEncryptedKeyInfo; ZeroMemory(&sEncryptedKeyInfo, sizeof(sEncryptedKeyInfo));
  359. if (CryptGetOIDFunctionAddress(
  360. hExportPrivKeyFuncSet,
  361. X509_ASN_ENCODING,
  362. psExportParams->pszPrivateKeyObjId,
  363. 0, // dwFlags
  364. &pvFuncAddr,
  365. &hFuncAddr)) {
  366. if (!((PFN_EXPORT_PRIV_KEY_FUNC) pvFuncAddr)(
  367. psExportParams->hCryptProv,
  368. psExportParams->dwKeySpec,
  369. psExportParams->pszPrivateKeyObjId,
  370. dwFlags & ~GIVE_ME_DATA, // sizeit
  371. pvAuxInfo,
  372. NULL,
  373. &cbPrivateKeyInfo
  374. ))
  375. goto ErrorReturn;
  376. if (NULL == (pPrivateKeyInfo = (CRYPT_PRIVATE_KEY_INFO *)
  377. SSAlloc(cbPrivateKeyInfo)))
  378. goto ErrorReturn;
  379. if (!((PFN_EXPORT_PRIV_KEY_FUNC) pvFuncAddr)(
  380. psExportParams->hCryptProv,
  381. psExportParams->dwKeySpec,
  382. psExportParams->pszPrivateKeyObjId,
  383. dwFlags, // maybe real data...
  384. pvAuxInfo,
  385. pPrivateKeyInfo,
  386. &cbPrivateKeyInfo
  387. ))
  388. goto ErrorReturn;
  389. CryptFreeOIDFunctionAddress(hFuncAddr, 0);
  390. }
  391. else { // if (CryptGetOIDFunctionAddress())
  392. SetLastError(ERROR_UNSUPPORTED_TYPE);
  393. return FALSE;
  394. }
  395. // encode the private key info struct
  396. if (!CryptEncodeObject(
  397. X509_ASN_ENCODING,
  398. PKCS_PRIVATE_KEY_INFO,
  399. pPrivateKeyInfo,
  400. NULL,
  401. &cbEncoded))
  402. goto ErrorReturn;
  403. if (NULL == psExportParams->pEncryptPrivateKeyFunc)
  404. {
  405. // no encryption; this is output buffer
  406. // check to see if the caller specified a buffer and has enough space
  407. if ((pbPrivateKeyBlob != NULL) && (*pcbPrivateKeyBlob >= cbEncoded)) {
  408. if (!CryptEncodeObject(
  409. X509_ASN_ENCODING,
  410. PKCS_PRIVATE_KEY_INFO,
  411. pPrivateKeyInfo,
  412. pbPrivateKeyBlob,
  413. pcbPrivateKeyBlob))
  414. goto ErrorReturn;
  415. }
  416. else {
  417. *pcbPrivateKeyBlob = cbEncoded;
  418. if (pbPrivateKeyBlob != NULL) {
  419. SetLastError((DWORD) ERROR_MORE_DATA);
  420. goto ErrorReturn;
  421. }
  422. }
  423. }
  424. else
  425. {
  426. // we do want to encrypt!!
  427. // always encode: use tmp alloc
  428. pbTmpKeyBlob = (PBYTE)SSAlloc(cbEncoded);
  429. if (pbTmpKeyBlob == NULL)
  430. goto ErrorReturn;
  431. DWORD cbTmpKeyBlob = cbEncoded;
  432. // NOW add optional encryption and encode as ENCR_PRIV_KEY_INFO
  433. CRYPT_DATA_BLOB sClearTextKey = { cbTmpKeyBlob, pbTmpKeyBlob};
  434. // do inner encode
  435. if (!CryptEncodeObject(
  436. X509_ASN_ENCODING,
  437. PKCS_PRIVATE_KEY_INFO,
  438. pPrivateKeyInfo,
  439. pbTmpKeyBlob,
  440. &cbTmpKeyBlob))
  441. goto ErrorReturn;
  442. // exported the key; encoded as PRIVATE_KEY_INFO.
  443. if (!psExportParams->pEncryptPrivateKeyFunc(
  444. &sEncryptedKeyInfo.EncryptionAlgorithm, // out
  445. &sClearTextKey, // in
  446. NULL, // opt
  447. &sEncryptedKeyInfo.EncryptedPrivateKey.cbData, // out
  448. psExportParams->pVoidEncryptFunc))
  449. goto ErrorReturn;
  450. if (NULL == (sEncryptedKeyInfo.EncryptedPrivateKey.pbData = (BYTE*) SSAlloc(sEncryptedKeyInfo.EncryptedPrivateKey.cbData)))
  451. goto ErrorReturn;
  452. if (dwFlags & GIVE_ME_DATA)
  453. {
  454. if (!psExportParams->pEncryptPrivateKeyFunc(
  455. &sEncryptedKeyInfo.EncryptionAlgorithm, // out
  456. &sClearTextKey, // in
  457. sEncryptedKeyInfo.EncryptedPrivateKey.pbData, // opt
  458. &sEncryptedKeyInfo.EncryptedPrivateKey.cbData, // out
  459. psExportParams->pVoidEncryptFunc))
  460. goto ErrorReturn;
  461. }
  462. else
  463. {
  464. // fill in phony encr key
  465. FillMemory(sEncryptedKeyInfo.EncryptedPrivateKey.pbData, sEncryptedKeyInfo.EncryptedPrivateKey.cbData, 0x69);
  466. }
  467. // item is now encrypted; now encode
  468. // encode the private key info struct
  469. if (!CryptEncodeObject(
  470. X509_ASN_ENCODING,
  471. PKCS_ENCRYPTED_PRIVATE_KEY_INFO,
  472. &sEncryptedKeyInfo,
  473. NULL,
  474. &cbEncoded))
  475. goto ErrorReturn;
  476. // check to see if the caller specified a buffer and has enough space
  477. if ((pbPrivateKeyBlob != NULL) && (*pcbPrivateKeyBlob >= cbEncoded)) {
  478. if (!CryptEncodeObject(
  479. X509_ASN_ENCODING,
  480. PKCS_ENCRYPTED_PRIVATE_KEY_INFO,
  481. &sEncryptedKeyInfo,
  482. pbPrivateKeyBlob,
  483. pcbPrivateKeyBlob))
  484. goto ErrorReturn;
  485. }
  486. else {
  487. *pcbPrivateKeyBlob = cbEncoded;
  488. if (pbPrivateKeyBlob != NULL) {
  489. SetLastError((DWORD) ERROR_MORE_DATA);
  490. goto ErrorReturn;
  491. }
  492. }
  493. }
  494. goto CommonReturn;
  495. ErrorReturn:
  496. fResult = FALSE;
  497. CommonReturn:
  498. if (pPrivateKeyInfo)
  499. SSFree(pPrivateKeyInfo);
  500. if (pbTmpKeyBlob)
  501. SSFree(pbTmpKeyBlob);
  502. if (sEncryptedKeyInfo.EncryptedPrivateKey.pbData)
  503. SSFree(sEncryptedKeyInfo.EncryptedPrivateKey.pbData);
  504. if (sEncryptedKeyInfo.EncryptionAlgorithm.Parameters.pbData)
  505. SSFree(sEncryptedKeyInfo.EncryptionAlgorithm.Parameters.pbData);
  506. return fResult;
  507. }
  508. static LONG counter = 0;
  509. // hack function to create a mock RSA private key blob based only on size
  510. BYTE * AllocFakeRSAPrivateKey(DWORD cb)
  511. {
  512. BLOBHEADER *pBlobHeader;
  513. RSAPUBKEY *pKey;
  514. BYTE *pByte;
  515. DWORD dwJumpSize;
  516. pBlobHeader = (BLOBHEADER *) SSAlloc(cb);
  517. if (pBlobHeader == NULL)
  518. return NULL;
  519. memset(pBlobHeader, 0, cb);
  520. pBlobHeader->bType = PRIVATEKEYBLOB;
  521. pBlobHeader->bVersion = CUR_BLOB_VERSION;
  522. pBlobHeader->reserved = 0;
  523. pBlobHeader->aiKeyAlg = CALG_RSA_SIGN;
  524. pKey = (RSAPUBKEY *) (((BYTE*) pBlobHeader) + sizeof(BLOBHEADER));
  525. pKey->magic = 0x32415352;
  526. pKey->bitlen = ((cb - sizeof(BLOBHEADER) - sizeof(RSAPUBKEY)) / 9) * 2 * 8;
  527. pKey->pubexp = 65537;
  528. dwJumpSize = (cb - sizeof(BLOBHEADER) - sizeof(RSAPUBKEY)) / 9;
  529. pByte = ((BYTE *) pBlobHeader) + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY);
  530. // put some bogus data at the start of the key so
  531. // that we know will be unique for each key so that
  532. // they look different durring a comparison
  533. InterlockedIncrement(&counter);
  534. *((LONG *) pByte) = counter;
  535. // most significant byte of modulus
  536. pByte += (dwJumpSize * 2) - 1;
  537. *pByte = 0x80;
  538. // most significant byte of prime1
  539. pByte += dwJumpSize;
  540. *pByte = 0x80;
  541. // most significant byte of prime2
  542. pByte += dwJumpSize;
  543. *pByte = 0x80;
  544. // most significant byte of exponent1
  545. pByte += dwJumpSize;
  546. *pByte = 0x80;
  547. // most significant byte of exponent2
  548. pByte += dwJumpSize;
  549. *pByte = 0x80;
  550. // most significant byte of coefficient
  551. pByte += dwJumpSize;
  552. *pByte = 0x80;
  553. // most significant byte of privateExponent
  554. pByte += dwJumpSize * 2;
  555. *pByte = 0x80;
  556. return ((BYTE *)pBlobHeader);
  557. }
  558. static BOOL WINAPI ExportRSAPrivateKeyInfo(
  559. HCRYPTPROV hCryptProv, // in
  560. DWORD dwKeySpec, // in
  561. LPSTR pszPrivateKeyObjId, // in
  562. DWORD dwFlags, // in
  563. void *pvAuxInfo, // in
  564. CRYPT_PRIVATE_KEY_INFO *pPrivateKeyInfo, // out
  565. DWORD *pcbPrivateKeyInfo // in, out
  566. )
  567. {
  568. BOOL fResult = TRUE;
  569. HCRYPTKEY hCryptKey = NULL;
  570. BYTE *pKeyBlob = NULL;
  571. DWORD cbKeyBlob = 0;
  572. BYTE *pEncodedKeyBlob = NULL;
  573. DWORD cbEncodedKeyBlob = 0;
  574. BYTE *pKeyUsage = NULL;
  575. DWORD cbKeyUsage = 0;
  576. DWORD dwSize = 0;
  577. CRYPT_BIT_BLOB CryptBitBlob;
  578. BYTE KeyUsageByte = 0;
  579. BYTE *pbCurrentLocation = NULL;
  580. // get a handle to the keyset to export
  581. if (!CryptGetUserKey(
  582. hCryptProv,
  583. dwKeySpec,
  584. &hCryptKey))
  585. goto ErrorReturn;
  586. // export the key set to a CAPI blob
  587. if (!CryptExportKey(
  588. hCryptKey,
  589. 0,
  590. PRIVATEKEYBLOB,
  591. 0,
  592. NULL,
  593. &cbKeyBlob))
  594. goto ErrorReturn;
  595. // make sure the caller REALLY wants the key at this point
  596. if ((dwFlags & PFX_MODE) && !(dwFlags & GIVE_ME_DATA))
  597. {
  598. if (NULL == (pKeyBlob = AllocFakeRSAPrivateKey(cbKeyBlob)))
  599. goto ErrorReturn;
  600. }
  601. // if not in PFX export mode or we really want the key then just do normal processing
  602. else
  603. {
  604. if (NULL == (pKeyBlob = (BYTE *) SSAlloc(cbKeyBlob)))
  605. goto ErrorReturn;
  606. if (!CryptExportKey(
  607. hCryptKey,
  608. 0,
  609. PRIVATEKEYBLOB,
  610. 0,
  611. pKeyBlob,
  612. &cbKeyBlob))
  613. goto ErrorReturn;
  614. }
  615. // encode the key blob to a RSA private key
  616. if (!CryptEncodeObject(
  617. X509_ASN_ENCODING,
  618. PKCS_RSA_PRIVATE_KEY,
  619. pKeyBlob,
  620. NULL,
  621. &cbEncodedKeyBlob))
  622. goto ErrorReturn;
  623. if (NULL == (pEncodedKeyBlob = (BYTE *) SSAlloc(cbEncodedKeyBlob)))
  624. goto ErrorReturn;
  625. if (!CryptEncodeObject(
  626. X509_ASN_ENCODING,
  627. PKCS_RSA_PRIVATE_KEY,
  628. pKeyBlob,
  629. pEncodedKeyBlob,
  630. &cbEncodedKeyBlob))
  631. goto ErrorReturn;
  632. // encode the KEY_USAGE attribute
  633. CryptBitBlob.cbData = 1;
  634. CryptBitBlob.pbData = &KeyUsageByte;
  635. CryptBitBlob.cUnusedBits = 0;
  636. if (((BLOBHEADER *) pKeyBlob)->aiKeyAlg == CALG_RSA_SIGN)
  637. KeyUsageByte = CERT_DIGITAL_SIGNATURE_KEY_USAGE;
  638. else if (((BLOBHEADER *) pKeyBlob)->aiKeyAlg == CALG_RSA_KEYX)
  639. KeyUsageByte = CERT_DATA_ENCIPHERMENT_KEY_USAGE;
  640. else {
  641. goto ErrorReturn;
  642. }
  643. if (!CryptEncodeObject(
  644. X509_ASN_ENCODING,
  645. X509_BITS,
  646. (void *) &CryptBitBlob,
  647. NULL,
  648. &cbKeyUsage))
  649. goto ErrorReturn;
  650. if (NULL == (pKeyUsage = (BYTE *) SSAlloc(cbKeyUsage)))
  651. goto ErrorReturn;
  652. if (!CryptEncodeObject(
  653. X509_ASN_ENCODING,
  654. X509_BITS,
  655. (void *) &CryptBitBlob,
  656. pKeyUsage,
  657. &cbKeyUsage))
  658. goto ErrorReturn;
  659. // we can now calculate the size needed
  660. dwSize = sizeof(CRYPT_PRIVATE_KEY_INFO) + // main private key info struct
  661. INFO_LEN_ALIGN(sizeof(szOID_RSA_RSA)) + // size of the RSA algorithm identifier string
  662. INFO_LEN_ALIGN(cbEncodedKeyBlob) + // buffer that holds encoded RSA private key
  663. sizeof(CRYPT_ATTRIBUTES) + // struct for private key attributes
  664. sizeof(CRYPT_ATTRIBUTE) + // struct for the one attribute being set, KEY_USAGE
  665. INFO_LEN_ALIGN(sizeof(szOID_KEY_USAGE)) + // size of attribute OID for key usage
  666. sizeof(CRYPT_ATTR_BLOB) + // struct for values in attribute
  667. cbKeyUsage; // size of buffer for encoded attribute
  668. // check to see if the caller passed in a buffer, and enough space
  669. if (pPrivateKeyInfo == NULL)
  670. goto CommonReturn;
  671. else if (*pcbPrivateKeyInfo < dwSize) {
  672. SetLastError((DWORD) ERROR_MORE_DATA);
  673. goto ErrorReturn;
  674. }
  675. // everything is OK so copy all the information to the caller's buffer
  676. pbCurrentLocation = ((BYTE *) pPrivateKeyInfo) + sizeof(CRYPT_PRIVATE_KEY_INFO);
  677. pPrivateKeyInfo->Version = 0;
  678. pPrivateKeyInfo->Algorithm.pszObjId = (LPSTR) pbCurrentLocation;
  679. memcpy(pbCurrentLocation, szOID_RSA_RSA, sizeof(szOID_RSA_RSA));
  680. pbCurrentLocation += INFO_LEN_ALIGN(sizeof(szOID_RSA_RSA));
  681. pPrivateKeyInfo->Algorithm.Parameters.cbData = 0; // no parameters for RSA
  682. pPrivateKeyInfo->Algorithm.Parameters.pbData = NULL;// no parameters for RSA
  683. pPrivateKeyInfo->PrivateKey.cbData = cbEncodedKeyBlob;
  684. pPrivateKeyInfo->PrivateKey.pbData = pbCurrentLocation;
  685. memcpy(pbCurrentLocation, pEncodedKeyBlob, cbEncodedKeyBlob);
  686. pbCurrentLocation += INFO_LEN_ALIGN(cbEncodedKeyBlob);
  687. pPrivateKeyInfo->pAttributes = (PCRYPT_ATTRIBUTES) pbCurrentLocation;
  688. pbCurrentLocation += sizeof(CRYPT_ATTRIBUTES);
  689. pPrivateKeyInfo->pAttributes->cAttr = 1; // the only attribute right now is KEY_USAGE
  690. pPrivateKeyInfo->pAttributes->rgAttr = (PCRYPT_ATTRIBUTE) pbCurrentLocation;
  691. pbCurrentLocation += sizeof(CRYPT_ATTRIBUTE);
  692. pPrivateKeyInfo->pAttributes->rgAttr[0].pszObjId = (LPSTR) pbCurrentLocation;
  693. memcpy(pbCurrentLocation, szOID_KEY_USAGE, sizeof(szOID_KEY_USAGE));
  694. pbCurrentLocation += INFO_LEN_ALIGN(sizeof(szOID_KEY_USAGE));
  695. pPrivateKeyInfo->pAttributes->rgAttr[0].cValue = 1;
  696. pPrivateKeyInfo->pAttributes->rgAttr[0].rgValue = (PCRYPT_ATTR_BLOB) pbCurrentLocation;
  697. pbCurrentLocation += sizeof(CRYPT_ATTR_BLOB);
  698. pPrivateKeyInfo->pAttributes->rgAttr[0].rgValue[0].cbData = cbKeyUsage;
  699. pPrivateKeyInfo->pAttributes->rgAttr[0].rgValue[0].pbData = pbCurrentLocation;
  700. memcpy(pbCurrentLocation, pKeyUsage, cbKeyUsage);
  701. goto CommonReturn;
  702. ErrorReturn:
  703. fResult = FALSE;
  704. CommonReturn:
  705. *pcbPrivateKeyInfo = dwSize;
  706. if (hCryptKey)
  707. {
  708. DWORD dwErr = GetLastError();
  709. CryptDestroyKey(hCryptKey);
  710. SetLastError(dwErr);
  711. }
  712. if (pKeyBlob)
  713. SSFree(pKeyBlob);
  714. if (pEncodedKeyBlob)
  715. SSFree(pEncodedKeyBlob);
  716. if (pKeyUsage)
  717. SSFree(pKeyUsage);
  718. return fResult;
  719. }
  720. static DWORD ResolveKeySpec(
  721. PCRYPT_ATTRIBUTES pCryptAttributes)
  722. {
  723. DWORD i = 0;
  724. DWORD dwKeySpec = 0;
  725. DWORD cbAttribute = 0;
  726. CRYPT_BIT_BLOB *pAttribute = NULL;
  727. if (pCryptAttributes != NULL)
  728. while (i < pCryptAttributes->cAttr) {
  729. if (lstrcmp(pCryptAttributes->rgAttr[i].pszObjId, szOID_KEY_USAGE) == 0) {
  730. if (!CryptDecodeObject(
  731. X509_ASN_ENCODING,
  732. X509_BITS,
  733. pCryptAttributes->rgAttr[i].rgValue->pbData,
  734. pCryptAttributes->rgAttr[i].rgValue->cbData,
  735. 0,
  736. NULL,
  737. &cbAttribute
  738. )) {
  739. i++;
  740. continue;
  741. }
  742. if (NULL == (pAttribute = (CRYPT_BIT_BLOB *) SSAlloc(cbAttribute)))
  743. {
  744. i++;
  745. continue;
  746. }
  747. if (!CryptDecodeObject(
  748. X509_ASN_ENCODING,
  749. X509_BITS,
  750. pCryptAttributes->rgAttr[i].rgValue->pbData,
  751. pCryptAttributes->rgAttr[i].rgValue->cbData,
  752. 0,
  753. pAttribute,
  754. &cbAttribute
  755. )) {
  756. i++;
  757. SSFree(pAttribute);
  758. continue;
  759. }
  760. if ((pAttribute->pbData[0] & CERT_KEY_ENCIPHERMENT_KEY_USAGE) ||
  761. (pAttribute->pbData[0] & CERT_DATA_ENCIPHERMENT_KEY_USAGE)) {
  762. dwKeySpec = AT_KEYEXCHANGE;
  763. goto CommonReturn;
  764. }
  765. else if ((pAttribute->pbData[0] & CERT_DIGITAL_SIGNATURE_KEY_USAGE) ||
  766. (pAttribute->pbData[0] & CERT_KEY_CERT_SIGN_KEY_USAGE) ||
  767. (pAttribute->pbData[0] & CERT_CRL_SIGN_KEY_USAGE)) {
  768. dwKeySpec = AT_SIGNATURE;
  769. goto CommonReturn;
  770. }
  771. } // if (lstrcmp(pCryptAttributes->rgAttr[i].pszObjId, szOID_KEY_USAGE) == 0)
  772. i++;
  773. } // while (i < pCryptAttributes->cAttr)
  774. //ErrorReturn:
  775. CommonReturn:
  776. if (pAttribute)
  777. SSFree(pAttribute);
  778. return dwKeySpec;
  779. }
  780. static BOOL WINAPI ImportRSAPrivateKeyInfo(
  781. HCRYPTPROV hCryptProv, // in
  782. CRYPT_PRIVATE_KEY_INFO *pPrivateKeyInfo, // in
  783. DWORD dwFlags, // in, optional
  784. void *pvAuxInfo // in, optional
  785. )
  786. {
  787. BOOL fResult = TRUE;
  788. DWORD cbRSAPrivateKey = 0;
  789. BYTE *pbRSAPrivateKey = NULL;
  790. HCRYPTKEY hCryptKey = NULL;
  791. DWORD dwKeySpec = 0;
  792. // decode the rsa der-encoded keyblob into a CAPI type keyblob
  793. if (!CryptDecodeObject(X509_ASN_ENCODING,
  794. PKCS_RSA_PRIVATE_KEY,
  795. pPrivateKeyInfo->PrivateKey.pbData,
  796. pPrivateKeyInfo->PrivateKey.cbData,
  797. CRYPT_DECODE_NOCOPY_FLAG,
  798. NULL,
  799. &cbRSAPrivateKey))
  800. goto ErrorReturn;
  801. if (NULL == (pbRSAPrivateKey = (BYTE *) SSAlloc(cbRSAPrivateKey)))
  802. goto ErrorReturn;
  803. if (!CryptDecodeObject(X509_ASN_ENCODING,
  804. PKCS_RSA_PRIVATE_KEY,
  805. pPrivateKeyInfo->PrivateKey.pbData,
  806. pPrivateKeyInfo->PrivateKey.cbData,
  807. CRYPT_DECODE_NOCOPY_FLAG,
  808. pbRSAPrivateKey,
  809. &cbRSAPrivateKey))
  810. goto ErrorReturn;
  811. // figure out what keyspec to use and manually set the algid in the keyblob accordingly
  812. dwKeySpec = ResolveKeySpec(pPrivateKeyInfo->pAttributes);
  813. if ((dwKeySpec == AT_KEYEXCHANGE) || (dwKeySpec == 0))
  814. ((BLOBHEADER *) pbRSAPrivateKey)->aiKeyAlg = CALG_RSA_KEYX;
  815. else
  816. ((BLOBHEADER *) pbRSAPrivateKey)->aiKeyAlg = CALG_RSA_SIGN;
  817. // import this thing
  818. if (!CryptImportKey(hCryptProv,
  819. pbRSAPrivateKey,
  820. cbRSAPrivateKey,
  821. 0,
  822. dwFlags & (CRYPT_EXPORTABLE | CRYPT_USER_PROTECTED), // mask the flags that are used
  823. &hCryptKey)) // during the CryptImportKey
  824. goto ErrorReturn;
  825. goto CommonReturn;
  826. ErrorReturn:
  827. fResult = FALSE;
  828. CommonReturn:
  829. if (pbRSAPrivateKey)
  830. SSFree(pbRSAPrivateKey);
  831. if (hCryptKey)
  832. CryptDestroyKey(hCryptKey);
  833. return fResult;
  834. }
  835. #ifndef DSS2
  836. #define DSS2 ((DWORD)'D'+((DWORD)'S'<<8)+((DWORD)'S'<<16)+((DWORD)'2'<<24))
  837. #endif
  838. #ifndef DSS_Q_LEN
  839. #define DSS_Q_LEN 20
  840. #endif
  841. // hack function to create a mock RSA private key blob based only on size
  842. BYTE * AllocFakeDSSPrivateKey(DWORD cb)
  843. {
  844. BLOBHEADER *pBlobHeader;
  845. DSSPUBKEY *pCspPubKey = NULL;
  846. BYTE *pbKeyBlob;
  847. BYTE *pbKey;
  848. DWORD cbKey;
  849. DSSSEED *pCspSeed = NULL;
  850. pBlobHeader = (BLOBHEADER *) SSAlloc(cb);
  851. if (pBlobHeader == NULL)
  852. return NULL;
  853. memset(pBlobHeader, 0, cb);
  854. pbKeyBlob = (BYTE *) pBlobHeader;
  855. pCspPubKey = (DSSPUBKEY *) (pbKeyBlob + sizeof(BLOBHEADER));
  856. pbKey = pbKeyBlob + sizeof(BLOBHEADER) + sizeof(DSSPUBKEY);
  857. // BLOBHEADER
  858. pBlobHeader->bType = PRIVATEKEYBLOB;
  859. pBlobHeader->bVersion = CUR_BLOB_VERSION;
  860. pBlobHeader->reserved = 0;
  861. pBlobHeader->aiKeyAlg = CALG_DSS_SIGN;
  862. // DSSPUBKEY
  863. pCspPubKey->magic = DSS2;
  864. cbKey = (cb - sizeof(BLOBHEADER) - sizeof(DSSPUBKEY) - (2 * DSS_Q_LEN) - sizeof(DSSSEED)) / 2;
  865. pCspPubKey->bitlen = cbKey * 8;
  866. // put some bogus data at the start of the key so
  867. // that we know will be unique for each key so that
  868. // they look different durring a comparison
  869. InterlockedIncrement(&counter);
  870. // rgbP[cbKey]
  871. memset(pbKey, counter, cbKey);
  872. pbKey += cbKey;
  873. *(pbKey-1) = 0x80;
  874. // rgbQ[20]
  875. memset(pbKey, counter, DSS_Q_LEN);
  876. pbKey += DSS_Q_LEN;
  877. *(pbKey-1) = 0x80;
  878. // rgbG[cbKey]
  879. memset(pbKey, counter, cbKey);
  880. pbKey += cbKey;
  881. *(pbKey-1) = 0x80;
  882. // rgbX[20]
  883. memset(pbKey, counter, DSS_Q_LEN);
  884. pbKey += DSS_Q_LEN;
  885. *(pbKey-1) = 0x80;
  886. // DSSSEED: set counter to 0xFFFFFFFF to indicate not available
  887. pCspSeed = (DSSSEED *) pbKey;
  888. memset(&pCspSeed->counter, 0xFF, sizeof(pCspSeed->counter));
  889. return ((BYTE *)pBlobHeader);
  890. }
  891. static BOOL WINAPI ExportDSSPrivateKeyInfo(
  892. HCRYPTPROV hCryptProv, // in
  893. DWORD dwKeySpec, // in
  894. LPSTR pszPrivateKeyObjId, // in
  895. DWORD dwFlags, // in
  896. void *pvAuxInfo, // in
  897. CRYPT_PRIVATE_KEY_INFO *pPrivateKeyInfo, // out
  898. DWORD *pcbPrivateKeyInfo // in, out
  899. )
  900. {
  901. BOOL fResult = TRUE;
  902. HCRYPTKEY hCryptKey = NULL;
  903. BYTE *pbKeyBlob = NULL;
  904. DWORD cbKeyBlob = 0;
  905. BYTE *pbEncodedPrivateKeyBlob = NULL;
  906. DWORD cbEncodedPrivateKeyBlob = 0;
  907. BYTE *pbEncodedParameters = NULL;
  908. DWORD cbEncodedParameters = 0;
  909. CRYPT_INTEGER_BLOB PrivateKeyBlob;
  910. CERT_DSS_PARAMETERS DssParameters;
  911. DWORD cbKey;
  912. DSSPUBKEY *pCspPubKey = NULL;
  913. BYTE *pbBytes;
  914. DWORD dwSize = 0;
  915. BYTE *pbCurrentLocation;
  916. // get a handle to the keyset to export
  917. if (!CryptGetUserKey(
  918. hCryptProv,
  919. dwKeySpec,
  920. &hCryptKey))
  921. goto ErrorReturn;
  922. // export the key set to a CAPI blob
  923. if (!CryptExportKey(
  924. hCryptKey,
  925. 0,
  926. PRIVATEKEYBLOB,
  927. 0,
  928. NULL,
  929. &cbKeyBlob))
  930. goto ErrorReturn;
  931. // make sure the caller REALLY wants the key at this point
  932. if ((dwFlags & PFX_MODE) && !(dwFlags & GIVE_ME_DATA))
  933. {
  934. if (NULL == (pbKeyBlob = AllocFakeDSSPrivateKey(cbKeyBlob)))
  935. goto ErrorReturn;
  936. }
  937. // if not in PFX export mode or we really want the key then just do normal processing
  938. else
  939. {
  940. if (NULL == (pbKeyBlob = (BYTE *) SSAlloc(cbKeyBlob)))
  941. goto ErrorReturn;
  942. if (!CryptExportKey(
  943. hCryptKey,
  944. 0,
  945. PRIVATEKEYBLOB,
  946. 0,
  947. pbKeyBlob,
  948. &cbKeyBlob))
  949. goto ErrorReturn;
  950. }
  951. pCspPubKey = (DSSPUBKEY *) (pbKeyBlob + sizeof(BLOBHEADER));
  952. pbBytes = pbKeyBlob + sizeof(PUBLICKEYSTRUC) + sizeof(DSSPUBKEY);
  953. cbKey = pCspPubKey->bitlen / 8;
  954. // encode the DSS paramaters
  955. memset(&DssParameters, 0, sizeof(CERT_DSS_PARAMETERS));
  956. DssParameters.p.cbData = cbKey;
  957. DssParameters.p.pbData = pbBytes;
  958. pbBytes += cbKey;
  959. DssParameters.q.cbData = DSS_Q_LEN;
  960. DssParameters.q.pbData = pbBytes;
  961. pbBytes += DSS_Q_LEN;
  962. DssParameters.g.cbData = cbKey;
  963. DssParameters.g.pbData = pbBytes;
  964. pbBytes += cbKey;
  965. if (!CryptEncodeObject(
  966. X509_ASN_ENCODING,
  967. X509_DSS_PARAMETERS,
  968. &DssParameters,
  969. NULL,
  970. &cbEncodedParameters))
  971. goto ErrorReturn;
  972. if (NULL == (pbEncodedParameters = (BYTE *) SSAlloc(cbEncodedParameters)))
  973. goto ErrorReturn;
  974. if (!CryptEncodeObject(
  975. X509_ASN_ENCODING,
  976. X509_DSS_PARAMETERS,
  977. &DssParameters,
  978. pbEncodedParameters,
  979. &cbEncodedParameters))
  980. goto ErrorReturn;
  981. // encode the key DSS private key
  982. PrivateKeyBlob.cbData = DSS_Q_LEN;
  983. PrivateKeyBlob.pbData = pbBytes;
  984. if (!CryptEncodeObject(
  985. X509_ASN_ENCODING,
  986. X509_MULTI_BYTE_INTEGER,
  987. &PrivateKeyBlob,
  988. NULL,
  989. &cbEncodedPrivateKeyBlob))
  990. goto ErrorReturn;
  991. if (NULL == (pbEncodedPrivateKeyBlob = (BYTE *) SSAlloc(cbEncodedPrivateKeyBlob)))
  992. goto ErrorReturn;
  993. if (!CryptEncodeObject(
  994. X509_ASN_ENCODING,
  995. X509_MULTI_BYTE_INTEGER,
  996. &PrivateKeyBlob,
  997. pbEncodedPrivateKeyBlob,
  998. &cbEncodedPrivateKeyBlob))
  999. goto ErrorReturn;
  1000. // we can now calculate the size needed
  1001. dwSize = sizeof(CRYPT_PRIVATE_KEY_INFO) + // main private key info struct
  1002. sizeof(szOID_X957_DSA) + // size of the DSA algorithm identifier string
  1003. cbEncodedParameters + // size of the DSA parameters
  1004. cbEncodedPrivateKeyBlob; // buffer that holds encoded DSS private key
  1005. // check to see if the caller passed in a buffer, and enough space
  1006. if (pPrivateKeyInfo == NULL)
  1007. goto CommonReturn;
  1008. else if (*pcbPrivateKeyInfo < dwSize) {
  1009. SetLastError((DWORD) ERROR_MORE_DATA);
  1010. goto ErrorReturn;
  1011. }
  1012. // everything is OK so copy all the information to the caller's buffer
  1013. pbCurrentLocation = ((BYTE *) pPrivateKeyInfo) + sizeof(CRYPT_PRIVATE_KEY_INFO);
  1014. pPrivateKeyInfo->Version = 0;
  1015. pPrivateKeyInfo->Algorithm.pszObjId = (LPSTR) pbCurrentLocation;
  1016. memcpy(pbCurrentLocation, szOID_X957_DSA, sizeof(szOID_X957_DSA));
  1017. pbCurrentLocation += sizeof(szOID_X957_DSA);
  1018. pPrivateKeyInfo->Algorithm.Parameters.cbData = cbEncodedParameters;
  1019. pPrivateKeyInfo->Algorithm.Parameters.pbData = pbCurrentLocation;
  1020. memcpy(pbCurrentLocation, pbEncodedParameters, cbEncodedParameters);
  1021. pbCurrentLocation += cbEncodedParameters;
  1022. pPrivateKeyInfo->PrivateKey.cbData = cbEncodedPrivateKeyBlob;
  1023. pPrivateKeyInfo->PrivateKey.pbData = pbCurrentLocation;
  1024. memcpy(pbCurrentLocation, pbEncodedPrivateKeyBlob, cbEncodedPrivateKeyBlob);
  1025. pbCurrentLocation += cbEncodedPrivateKeyBlob;
  1026. pPrivateKeyInfo->pAttributes = NULL;
  1027. goto CommonReturn;
  1028. ErrorReturn:
  1029. fResult = FALSE;
  1030. CommonReturn:
  1031. *pcbPrivateKeyInfo = dwSize;
  1032. if (hCryptKey)
  1033. {
  1034. DWORD dwErr = GetLastError();
  1035. CryptDestroyKey(hCryptKey);
  1036. SetLastError(dwErr);
  1037. }
  1038. if (pbKeyBlob)
  1039. SSFree(pbKeyBlob);
  1040. if (pbEncodedParameters)
  1041. SSFree(pbEncodedParameters);
  1042. if (pbEncodedPrivateKeyBlob)
  1043. SSFree(pbEncodedPrivateKeyBlob);
  1044. return fResult;
  1045. }
  1046. static BOOL WINAPI ImportDSSPrivateKeyInfo(
  1047. HCRYPTPROV hCryptProv, // in
  1048. CRYPT_PRIVATE_KEY_INFO *pPrivateKeyInfo, // in
  1049. DWORD dwFlags, // in, optional
  1050. void *pvAuxInfo // in, optional
  1051. )
  1052. {
  1053. BOOL fResult = TRUE;
  1054. DWORD cbDSSPrivateKey = 0;
  1055. CRYPT_DATA_BLOB *pbDSSPrivateKey = NULL;
  1056. HCRYPTKEY hCryptKey = NULL;
  1057. DWORD dwKeySpec = 0;
  1058. DWORD cbParameters = 0;
  1059. PCERT_DSS_PARAMETERS pDssParameters = NULL;
  1060. BLOBHEADER *pPrivateKeyBlob = NULL;
  1061. DWORD cbPrivateKeyStruc = 0;
  1062. DSSPUBKEY *pCspPubKey = NULL;
  1063. DSSSEED *pCspSeed = NULL;
  1064. BYTE *pbKey = NULL;
  1065. BYTE *pbKeyBlob = NULL;
  1066. DWORD cb;
  1067. DWORD cbKey;
  1068. // decode the DSS private key
  1069. if (!CryptDecodeObject(X509_ASN_ENCODING,
  1070. X509_MULTI_BYTE_UINT,
  1071. pPrivateKeyInfo->PrivateKey.pbData,
  1072. pPrivateKeyInfo->PrivateKey.cbData,
  1073. CRYPT_DECODE_NOCOPY_FLAG,
  1074. NULL,
  1075. &cbDSSPrivateKey))
  1076. goto ErrorReturn;
  1077. if (NULL == (pbDSSPrivateKey = (CRYPT_DATA_BLOB *) SSAlloc(cbDSSPrivateKey)))
  1078. {
  1079. SetLastError(E_OUTOFMEMORY);
  1080. goto ErrorReturn;
  1081. }
  1082. if (!CryptDecodeObject(X509_ASN_ENCODING,
  1083. X509_MULTI_BYTE_UINT,
  1084. pPrivateKeyInfo->PrivateKey.pbData,
  1085. pPrivateKeyInfo->PrivateKey.cbData,
  1086. CRYPT_DECODE_NOCOPY_FLAG,
  1087. pbDSSPrivateKey,
  1088. &cbDSSPrivateKey))
  1089. goto ErrorReturn;
  1090. // decode the DSS parameters
  1091. if (!CryptDecodeObject(
  1092. X509_ASN_ENCODING,
  1093. X509_DSS_PARAMETERS,
  1094. pPrivateKeyInfo->Algorithm.Parameters.pbData,
  1095. pPrivateKeyInfo->Algorithm.Parameters.cbData,
  1096. 0,
  1097. NULL,
  1098. &cbParameters
  1099. ))
  1100. goto ErrorReturn;
  1101. if (NULL == (pDssParameters = (PCERT_DSS_PARAMETERS) SSAlloc(cbParameters)))
  1102. {
  1103. SetLastError(E_OUTOFMEMORY);
  1104. goto ErrorReturn;
  1105. }
  1106. if (!CryptDecodeObject(
  1107. X509_ASN_ENCODING,
  1108. X509_DSS_PARAMETERS,
  1109. pPrivateKeyInfo->Algorithm.Parameters.pbData,
  1110. pPrivateKeyInfo->Algorithm.Parameters.cbData,
  1111. 0,
  1112. pDssParameters,
  1113. &cbParameters
  1114. ))
  1115. goto ErrorReturn;
  1116. // The CAPI private key representation consists of the following sequence:
  1117. // - BLOBHEADER
  1118. // - DSSPUBKEY
  1119. // - rgbP[cbKey]
  1120. // - rgbQ[20]
  1121. // - rgbG[cbKey]
  1122. // - rgbX[20]
  1123. // - DSSSEED
  1124. cbKey = pDssParameters->p.cbData;
  1125. if (0 == cbKey)
  1126. goto ErrorInvalidKey;
  1127. cbPrivateKeyStruc = sizeof(BLOBHEADER) + sizeof(DSSPUBKEY) +
  1128. cbKey + DSS_Q_LEN + cbKey + DSS_Q_LEN + sizeof(DSSSEED);
  1129. if (NULL == (pPrivateKeyBlob = (BLOBHEADER *) SSAlloc(cbPrivateKeyStruc)))
  1130. {
  1131. SetLastError(E_OUTOFMEMORY);
  1132. goto ErrorReturn;
  1133. }
  1134. pbKeyBlob = (BYTE *) pPrivateKeyBlob;
  1135. pCspPubKey = (DSSPUBKEY *) (pbKeyBlob + sizeof(BLOBHEADER));
  1136. pbKey = pbKeyBlob + sizeof(BLOBHEADER) + sizeof(DSSPUBKEY);
  1137. // NOTE, the length of G can be less than the length of P.
  1138. // The CSP requires G to be padded out with 0x00 bytes if it
  1139. // is less and in little endian form
  1140. // BLOBHEADER
  1141. pPrivateKeyBlob->bType = PRIVATEKEYBLOB;
  1142. pPrivateKeyBlob->bVersion = CUR_BLOB_VERSION;
  1143. pPrivateKeyBlob->reserved = 0;
  1144. pPrivateKeyBlob->aiKeyAlg = CALG_DSS_SIGN;
  1145. // DSSPUBKEY
  1146. pCspPubKey->magic = DSS2;
  1147. pCspPubKey->bitlen = cbKey * 8;
  1148. // rgbP[cbKey]
  1149. memcpy(pbKey, pDssParameters->p.pbData, cbKey);
  1150. pbKey += cbKey;
  1151. // rgbQ[20]
  1152. cb = pDssParameters->q.cbData;
  1153. if (0 == cb || cb > DSS_Q_LEN)
  1154. goto ErrorInvalidKey;
  1155. memcpy(pbKey, pDssParameters->q.pbData, cb);
  1156. if (DSS_Q_LEN > cb)
  1157. memset(pbKey + cb, 0, DSS_Q_LEN - cb);
  1158. pbKey += DSS_Q_LEN;
  1159. // rgbG[cbKey]
  1160. cb = pDssParameters->g.cbData;
  1161. if (0 == cb || cb > cbKey)
  1162. goto ErrorInvalidKey;
  1163. memcpy(pbKey, pDssParameters->g.pbData, cb);
  1164. if (cbKey > cb)
  1165. memset(pbKey + cb, 0, cbKey - cb);
  1166. pbKey += cbKey;
  1167. // rgbX[20]
  1168. cb = pbDSSPrivateKey->cbData;
  1169. if (0 == cb || cb > DSS_Q_LEN)
  1170. goto ErrorInvalidKey;
  1171. memcpy(pbKey, pbDSSPrivateKey->pbData, cb);
  1172. if (DSS_Q_LEN > cb)
  1173. memset(pbKey + cb, 0, DSS_Q_LEN - cb);
  1174. pbKey += DSS_Q_LEN;
  1175. // DSSSEED: set counter to 0xFFFFFFFF to indicate not available
  1176. pCspSeed = (DSSSEED *) pbKey;
  1177. memset(&pCspSeed->counter, 0xFF, sizeof(pCspSeed->counter));
  1178. // import this thing
  1179. if (!CryptImportKey(hCryptProv,
  1180. (BYTE *)pPrivateKeyBlob,
  1181. cbPrivateKeyStruc,
  1182. 0,
  1183. dwFlags & (CRYPT_EXPORTABLE | CRYPT_USER_PROTECTED), // mask the flags that are used
  1184. &hCryptKey)) // during the CryptImportKey
  1185. {
  1186. DWORD dw = GetLastError();
  1187. goto ErrorReturn;
  1188. }
  1189. goto CommonReturn;
  1190. ErrorInvalidKey:
  1191. SetLastError(E_INVALIDARG);
  1192. ErrorReturn:
  1193. fResult = FALSE;
  1194. CommonReturn:
  1195. if (pbDSSPrivateKey)
  1196. SSFree(pbDSSPrivateKey);
  1197. if (pDssParameters)
  1198. SSFree(pDssParameters);
  1199. if (pPrivateKeyBlob)
  1200. SSFree(pPrivateKeyBlob);
  1201. if (hCryptKey)
  1202. CryptDestroyKey(hCryptKey);
  1203. return fResult;
  1204. }