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.

1010 lines
27 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1997 - 1999
  6. //
  7. // File: pfxmain.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. #include "global.hxx"
  11. #include <wincrypt.h>
  12. #include "pfxhelp.h"
  13. #include "pfxcmn.h"
  14. #include "pfxcrypt.h"
  15. #include "pfx.h"
  16. #include "impexppk.h"
  17. #include "encdecpk.h"
  18. #include <rpcdce.h>
  19. HINSTANCE g_hInst;
  20. BOOL
  21. WINAPI
  22. CryptPFXDllMain(
  23. HMODULE hInst,
  24. ULONG ul_reason_for_call,
  25. LPVOID lpReserved)
  26. {
  27. if (!ImportExportDllMain(hInst, ul_reason_for_call, lpReserved))
  28. {
  29. goto ImportExportError;
  30. }
  31. if (!EncodeDecodeDllMain(hInst, ul_reason_for_call, lpReserved))
  32. {
  33. goto EncodeDecodeError;
  34. }
  35. switch( ul_reason_for_call )
  36. {
  37. case DLL_PROCESS_ATTACH:
  38. g_hInst = hInst;
  39. if (!InitPFX())
  40. goto InitPFXError;
  41. if (!InitNSCP())
  42. goto InitNSCPError;
  43. break;
  44. case DLL_PROCESS_DETACH:
  45. TerminatePFX();
  46. TerminateNSCP();
  47. break;
  48. default:
  49. break;
  50. }
  51. return TRUE;
  52. InitNSCPError:
  53. TerminatePFX();
  54. InitPFXError:
  55. EncodeDecodeDllMain(hInst, DLL_PROCESS_DETACH, NULL);
  56. EncodeDecodeError:
  57. ImportExportDllMain(hInst, DLL_PROCESS_DETACH, NULL);
  58. ImportExportError:
  59. return FALSE;
  60. }
  61. BOOL FreeCryptSafeContents(
  62. SAFE_CONTENTS *pSafeContents
  63. )
  64. {
  65. DWORD i,j,k;
  66. // loop for each SAFE_BAG
  67. for (i=0; i<pSafeContents->cSafeBags; i++) {
  68. if (pSafeContents->pSafeBags[i].pszBagTypeOID)
  69. SSFree(pSafeContents->pSafeBags[i].pszBagTypeOID);
  70. if (pSafeContents->pSafeBags[i].BagContents.pbData)
  71. SSFree(pSafeContents->pSafeBags[i].BagContents.pbData);
  72. // loop for each attribute
  73. for (j=0; j<pSafeContents->pSafeBags[i].Attributes.cAttr; j++) {
  74. if (pSafeContents->pSafeBags[i].Attributes.rgAttr[j].pszObjId)
  75. SSFree(pSafeContents->pSafeBags[i].Attributes.rgAttr[j].pszObjId);
  76. // l0op for each value
  77. for (k=0; k<pSafeContents->pSafeBags[i].Attributes.rgAttr[j].cValue; k++) {
  78. if (pSafeContents->pSafeBags[i].Attributes.rgAttr[j].rgValue[k].pbData)
  79. SSFree(pSafeContents->pSafeBags[i].Attributes.rgAttr[j].rgValue[k].pbData);
  80. }
  81. // free the value struct array
  82. if (pSafeContents->pSafeBags[i].Attributes.rgAttr[j].rgValue)
  83. SSFree(pSafeContents->pSafeBags[i].Attributes.rgAttr[j].rgValue);
  84. }
  85. // free the attribute struct array
  86. if (pSafeContents->pSafeBags[i].Attributes.rgAttr)
  87. SSFree(pSafeContents->pSafeBags[i].Attributes.rgAttr);
  88. }
  89. if (pSafeContents->pSafeBags)
  90. SSFree(pSafeContents->pSafeBags);
  91. return TRUE;
  92. }
  93. BOOL CALLBACK
  94. Decrypt_Private_Key(
  95. CRYPT_ALGORITHM_IDENTIFIER Alg,
  96. CRYPT_DATA_BLOB EncrBlob,
  97. BYTE* pbClearText,
  98. DWORD* pcbClearText,
  99. LPVOID pVoidDecrypt)
  100. {
  101. BOOL fRet = TRUE;
  102. DWORD cbSalt = 0;
  103. BYTE *pbSalt = NULL;
  104. int iIterationCount;
  105. int iEncrType;
  106. BYTE *pbTempBuffer = NULL;
  107. DWORD cbTempBuffer = 0;
  108. if (0 == strcmp(Alg.pszObjId, szOID_PKCS_12_pbeWithSHA1And40BitRC2)) {
  109. iEncrType = RC2_40;
  110. }
  111. else if (0 == strcmp(Alg.pszObjId, szOID_PKCS_12_pbeWithSHA1And3KeyTripleDES)) {
  112. iEncrType = TripleDES;
  113. }
  114. else
  115. goto ErrorReturn;
  116. if (!GetSaltAndIterationCount(
  117. Alg.Parameters.pbData,
  118. Alg.Parameters.cbData,
  119. &pbSalt,
  120. &cbSalt,
  121. &iIterationCount)) {
  122. goto ErrorReturn;
  123. }
  124. // since the decode is done in-place, copy the buffer to decode into a temp buffer,
  125. // we need to use our temp buffer because the decrypt function may do a realloc
  126. // on the decode buffer
  127. if (NULL == (pbTempBuffer = (BYTE *) SSAlloc(EncrBlob.cbData)))
  128. goto ErrorReturn;
  129. memcpy(pbTempBuffer, EncrBlob.pbData, EncrBlob.cbData);
  130. cbTempBuffer = EncrBlob.cbData;
  131. if (!PFXPasswordDecryptData(
  132. iEncrType,
  133. (LPWSTR) pVoidDecrypt,
  134. iIterationCount,
  135. pbSalt,
  136. cbSalt,
  137. &pbTempBuffer,
  138. &cbTempBuffer))
  139. goto SetPFXDecryptError;
  140. // if pcbClearText is not 0 and there is not enough space then error out
  141. if ((0 != *pcbClearText) && (*pcbClearText < cbTempBuffer)){
  142. *pcbClearText = cbTempBuffer;
  143. goto Ret;
  144. }
  145. else if (0 != *pcbClearText) {
  146. memcpy(pbClearText, pbTempBuffer, cbTempBuffer);
  147. }
  148. *pcbClearText = cbTempBuffer;
  149. goto Ret;
  150. SetPFXDecryptError:
  151. SetLastError(NTE_FAIL);
  152. fRet = FALSE;
  153. goto Ret;
  154. ErrorReturn:
  155. fRet = FALSE;
  156. Ret:
  157. if (pbSalt)
  158. SSFree(pbSalt);
  159. if (pbTempBuffer)
  160. SSFree(pbTempBuffer);
  161. return fRet;
  162. }
  163. typedef struct _ENCRYPT_PRIVATE_PARAM_DATASTRUCT
  164. {
  165. HCRYPTPROV hVerifyProv;
  166. LPCWSTR szPwd;
  167. } ENCRYPT_PRIVATE_PARAM_DATASTRUCT, *PENCRYPT_PRIVATE_PARAM_DATASTRUCT;
  168. BOOL CALLBACK
  169. Encrypt_Private_Key(
  170. CRYPT_ALGORITHM_IDENTIFIER* pAlg,
  171. CRYPT_DATA_BLOB* pClearTextPrivateKey,
  172. BYTE* pbEncryptedKey,
  173. DWORD* pcbEncryptedKey,
  174. LPVOID pVoidEncrypt)
  175. {
  176. BOOL fRet = TRUE;
  177. DWORD cbSalt = 0;
  178. BYTE *pbSalt = NULL;
  179. int iIterationCount;
  180. int iEncrType;
  181. BYTE *pbTempBuffer = NULL;
  182. DWORD cbTempBuffer = 0;
  183. // crack param
  184. ENCRYPT_PRIVATE_PARAM_DATASTRUCT* pParam = (ENCRYPT_PRIVATE_PARAM_DATASTRUCT*)pVoidEncrypt;
  185. HCRYPTPROV hVerifyProv = pParam->hVerifyProv;
  186. LPCWSTR szPwd = pParam->szPwd;
  187. // use hardcoded params
  188. iEncrType = TripleDES;
  189. iIterationCount = PKCS12_ENCR_PWD_ITERATIONS;
  190. pbSalt = (BYTE *) SSAlloc(PBE_SALT_LENGTH);
  191. if (pbSalt == NULL)
  192. goto SetPFXAllocError;
  193. cbSalt = PBE_SALT_LENGTH;
  194. if (!CryptGenRandom(hVerifyProv, cbSalt, pbSalt))
  195. goto ErrorReturn;
  196. // out param
  197. pAlg->pszObjId = szOID_PKCS_12_pbeWithSHA1And3KeyTripleDES;
  198. if (!SetSaltAndIterationCount(
  199. &pAlg->Parameters.pbData,
  200. &pAlg->Parameters.cbData,
  201. pbSalt,
  202. cbSalt,
  203. iIterationCount)) {
  204. goto ErrorReturn;
  205. }
  206. // since the decode is done in-place, copy the buffer to decode into a temp buffer,
  207. // we need to use our temp buffer because the decrypt function may do a realloc
  208. // on the decode buffer
  209. if (NULL == (pbTempBuffer = (BYTE *) SSAlloc(pClearTextPrivateKey->cbData)))
  210. goto SetPFXAllocError;
  211. CopyMemory(pbTempBuffer, pClearTextPrivateKey->pbData, pClearTextPrivateKey->cbData);
  212. cbTempBuffer = pClearTextPrivateKey->cbData;
  213. if (!PFXPasswordEncryptData(
  214. iEncrType,
  215. szPwd,
  216. (pbEncryptedKey == NULL) ? 1 : iIterationCount, // don't bother iterating if we're just sizing
  217. pbSalt,
  218. cbSalt,
  219. &pbTempBuffer,
  220. &cbTempBuffer))
  221. goto SetPFXDecryptError;
  222. // if pcbEncryptedKey is not 0 and there is not enough space then error out
  223. if (pbEncryptedKey == NULL)
  224. {
  225. // just sizing; return cb
  226. *pcbEncryptedKey = cbTempBuffer;
  227. goto Ret;
  228. }
  229. else if (*pcbEncryptedKey < cbTempBuffer)
  230. {
  231. // buffer passed in too small
  232. *pcbEncryptedKey = cbTempBuffer;
  233. goto ErrorReturn;
  234. }
  235. else
  236. {
  237. // buffer sufficient
  238. memcpy(pbEncryptedKey, pbTempBuffer, cbTempBuffer);
  239. *pcbEncryptedKey = cbTempBuffer;
  240. }
  241. goto Ret;
  242. SetPFXDecryptError:
  243. SetLastError(NTE_FAIL);
  244. fRet = FALSE;
  245. goto Ret;
  246. SetPFXAllocError:
  247. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  248. fRet = FALSE;
  249. goto Ret;
  250. ErrorReturn:
  251. fRet = FALSE;
  252. Ret:
  253. if (pbSalt)
  254. SSFree(pbSalt);
  255. if (pbTempBuffer)
  256. SSFree(pbTempBuffer);
  257. return fRet;
  258. }
  259. BOOL
  260. GetNamedProviderType(
  261. LPCWSTR pwszProvName,
  262. DWORD *pdwProvType)
  263. {
  264. BOOL fResult = FALSE;
  265. LPWSTR pwszTempProvName;
  266. DWORD cbTempProvName;
  267. DWORD dwProvType;
  268. DWORD dwProvIndex;
  269. for (dwProvIndex = 0; TRUE; dwProvIndex++)
  270. {
  271. cbTempProvName = 0;
  272. dwProvType = 0;
  273. pwszTempProvName = NULL;
  274. if (!CryptEnumProvidersU(
  275. dwProvIndex,
  276. NULL, // pdwReserved
  277. 0, // dwFlags
  278. &dwProvType,
  279. NULL, // pwszProvName,
  280. &cbTempProvName
  281. ) || 0 == cbTempProvName)
  282. {
  283. if (ERROR_NO_MORE_ITEMS != GetLastError())
  284. {
  285. break;
  286. }
  287. }
  288. if (NULL == (pwszTempProvName = (LPWSTR) SSAlloc(
  289. (cbTempProvName + 1) * sizeof(WCHAR))))
  290. {
  291. break;
  292. }
  293. if (!CryptEnumProvidersU(
  294. dwProvIndex,
  295. NULL, // pdwReserved
  296. 0, // dwFlags
  297. &dwProvType,
  298. pwszTempProvName,
  299. &cbTempProvName
  300. ))
  301. {
  302. SSFree(pwszTempProvName);
  303. break;
  304. }
  305. if (0 == wcscmp(pwszTempProvName, pwszProvName))
  306. {
  307. *pdwProvType = dwProvType;
  308. fResult = TRUE;
  309. SSFree(pwszTempProvName);
  310. break;
  311. }
  312. SSFree(pwszTempProvName);
  313. }
  314. return fResult;
  315. }
  316. BOOL CALLBACK
  317. HCryptProv_Query_Func(
  318. CRYPT_PRIVATE_KEY_INFO *pPrivateKeyInfo,
  319. DWORD dwSafeBagIndex,
  320. HCRYPTPROV *phCryptProv,
  321. LPVOID pVoidhCryptProvQuery,
  322. DWORD dwPFXImportFlags
  323. )
  324. {
  325. DWORD dwErr = ERROR_SUCCESS;
  326. SAFE_CONTENTS *pSafeContents = (SAFE_CONTENTS *) pVoidhCryptProvQuery;
  327. DWORD i = 0;
  328. WCHAR szName[256];
  329. DWORD dwLocalMachineFlag = 0;
  330. GUID guidContainerName;
  331. DWORD cbProviderName = 0;
  332. CERT_NAME_VALUE *providerName = NULL;
  333. LPWSTR szSizeDeterminedProvider = NULL;
  334. DWORD dwKeyBitLen;
  335. DWORD dwProvType;
  336. RPC_STATUS rpcStatus;
  337. // UNDONE: support other than RSA or DSA keys
  338. if ((pPrivateKeyInfo->Algorithm.pszObjId) &&
  339. !( (0 == strcmp(pPrivateKeyInfo->Algorithm.pszObjId, szOID_RSA_RSA)) ||
  340. (0 == strcmp(pPrivateKeyInfo->Algorithm.pszObjId, szOID_ANSI_X942_DH)) ||
  341. (0 == strcmp(pPrivateKeyInfo->Algorithm.pszObjId, szOID_OIWSEC_dsa)) ||
  342. (0 == strcmp(pPrivateKeyInfo->Algorithm.pszObjId, szOID_X957_DSA))))
  343. {
  344. SetLastError(NTE_BAD_ALGID);
  345. goto ErrorReturn;
  346. }
  347. // generate a GUID as the containter name for the keyset being imported
  348. rpcStatus = UuidCreate(&guidContainerName);
  349. if ((rpcStatus != RPC_S_OK) && (rpcStatus != RPC_S_UUID_LOCAL_ONLY))
  350. {
  351. SetLastError(rpcStatus);
  352. goto ErrorReturn;
  353. }
  354. guid2wstr(&guidContainerName, &(szName[0]));
  355. // get the provider name
  356. while ((i<pSafeContents->pSafeBags[dwSafeBagIndex].Attributes.cAttr) &&
  357. (strcmp(pSafeContents->pSafeBags[dwSafeBagIndex].Attributes.rgAttr[i].pszObjId, szOID_PKCS_12_KEY_PROVIDER_NAME_ATTR) != 0)) {
  358. i++;
  359. }
  360. // check to see if a provider name was found
  361. if (i<pSafeContents->pSafeBags[dwSafeBagIndex].Attributes.cAttr)
  362. {
  363. // decode the provider name
  364. if (!CryptDecodeObject(
  365. X509_ASN_ENCODING,
  366. X509_UNICODE_ANY_STRING,
  367. pSafeContents->pSafeBags[dwSafeBagIndex].Attributes.rgAttr[i].rgValue[0].pbData,
  368. pSafeContents->pSafeBags[dwSafeBagIndex].Attributes.rgAttr[i].rgValue[0].cbData,
  369. 0,
  370. NULL,
  371. &cbProviderName)) {
  372. goto ErrorReturn;
  373. }
  374. if (NULL == (providerName = (CERT_NAME_VALUE *) SSAlloc(cbProviderName)))
  375. goto SetPFXAllocError;
  376. // decode the provider name
  377. if (!CryptDecodeObject(
  378. X509_ASN_ENCODING,
  379. X509_UNICODE_ANY_STRING,
  380. pSafeContents->pSafeBags[dwSafeBagIndex].Attributes.rgAttr[i].rgValue[0].pbData,
  381. pSafeContents->pSafeBags[dwSafeBagIndex].Attributes.rgAttr[i].rgValue[0].cbData,
  382. 0,
  383. (BYTE *) providerName,
  384. &cbProviderName)) {
  385. goto ErrorReturn;
  386. }
  387. }
  388. // check to see if the szOID_LOCAL_MACHINE_KEYSET OID is present
  389. i = 0;
  390. while ((i<pSafeContents->pSafeBags[dwSafeBagIndex].Attributes.cAttr) &&
  391. (strcmp(pSafeContents->pSafeBags[dwSafeBagIndex].Attributes.rgAttr[i].pszObjId, szOID_LOCAL_MACHINE_KEYSET) != 0)) {
  392. i++;
  393. }
  394. if (i<pSafeContents->pSafeBags[dwSafeBagIndex].Attributes.cAttr)
  395. {
  396. dwLocalMachineFlag = CRYPT_MACHINE_KEYSET;
  397. }
  398. // regardless of whether the CRYPT_MACHINE_KEYSET property was in the pfx blob,
  399. // if the caller specifies a preference of user or local machine honor that
  400. // preference ultimately
  401. if (dwPFXImportFlags & CRYPT_MACHINE_KEYSET)
  402. {
  403. dwLocalMachineFlag = CRYPT_MACHINE_KEYSET;
  404. }
  405. else if (dwPFXImportFlags & CRYPT_USER_KEYSET)
  406. {
  407. dwLocalMachineFlag = 0;
  408. }
  409. // still don't know where to put this: need keysize to determine
  410. if ((NULL == providerName) && (0 == strcmp(pPrivateKeyInfo->Algorithm.pszObjId, szOID_RSA_RSA)))
  411. {
  412. PBYTE pbRSAPrivateKey = NULL;
  413. DWORD cbRSAPrivateKey;
  414. // decode the rsa der-encoded keyblob into a CAPI type keyblob
  415. if (!CryptDecodeObject(X509_ASN_ENCODING,
  416. PKCS_RSA_PRIVATE_KEY,
  417. pPrivateKeyInfo->PrivateKey.pbData,
  418. pPrivateKeyInfo->PrivateKey.cbData,
  419. CRYPT_DECODE_NOCOPY_FLAG,
  420. NULL,
  421. &cbRSAPrivateKey))
  422. goto ErrorReturn;
  423. if (NULL == (pbRSAPrivateKey = (BYTE *) SSAlloc(cbRSAPrivateKey)))
  424. goto SetPFXAllocError;
  425. if (!CryptDecodeObject(X509_ASN_ENCODING,
  426. PKCS_RSA_PRIVATE_KEY,
  427. pPrivateKeyInfo->PrivateKey.pbData,
  428. pPrivateKeyInfo->PrivateKey.cbData,
  429. CRYPT_DECODE_NOCOPY_FLAG,
  430. pbRSAPrivateKey,
  431. &cbRSAPrivateKey))
  432. {
  433. if (pbRSAPrivateKey)
  434. SSFree(pbRSAPrivateKey);
  435. goto ErrorReturn;
  436. }
  437. dwKeyBitLen =
  438. ((RSAPUBKEY*) (pbRSAPrivateKey + sizeof(BLOBHEADER)) )->bitlen;
  439. szSizeDeterminedProvider = (dwKeyBitLen <= 1024) ? MS_DEF_PROV_W : MS_ENHANCED_PROV_W;
  440. ZeroMemory(pbRSAPrivateKey, cbRSAPrivateKey);
  441. SSFree(pbRSAPrivateKey);
  442. }
  443. if (0 == strcmp(pPrivateKeyInfo->Algorithm.pszObjId, szOID_RSA_RSA))
  444. {
  445. if ((providerName == NULL) || (!GetNamedProviderType((LPWSTR)providerName->Value.pbData, &dwProvType)))
  446. {
  447. dwProvType = PROV_RSA_FULL;
  448. }
  449. // if we have a prov name AND acq works, we're done
  450. // try prov name if given to us
  451. if (CryptAcquireContextU(
  452. phCryptProv,
  453. szName,
  454. (providerName != NULL) ? (LPWSTR)providerName->Value.pbData : szSizeDeterminedProvider,
  455. dwProvType,
  456. dwLocalMachineFlag | CRYPT_NEWKEYSET ))
  457. goto CommonReturn;
  458. // otherwise attempt default
  459. if (CryptAcquireContextU(
  460. phCryptProv,
  461. szName,
  462. NULL,
  463. PROV_RSA_FULL,
  464. dwLocalMachineFlag | CRYPT_NEWKEYSET ))
  465. goto CommonReturn;
  466. // Neither succeeded; fail
  467. }
  468. else
  469. {
  470. if ((providerName == NULL) || (!GetNamedProviderType((LPWSTR)providerName->Value.pbData, &dwProvType)))
  471. {
  472. dwProvType = PROV_DSS_DH;
  473. }
  474. if (CryptAcquireContextU(
  475. phCryptProv,
  476. szName,
  477. (providerName != NULL) ? (LPWSTR)providerName->Value.pbData : MS_DEF_DSS_DH_PROV_W,
  478. dwProvType,
  479. dwLocalMachineFlag | CRYPT_NEWKEYSET ))
  480. {
  481. goto CommonReturn;
  482. }
  483. else if (CryptAcquireContextU(
  484. phCryptProv,
  485. szName,
  486. NULL,
  487. PROV_DSS_DH,
  488. dwLocalMachineFlag | CRYPT_NEWKEYSET ))
  489. {
  490. goto CommonReturn;
  491. }
  492. // did not succeed, so fail
  493. }
  494. ErrorReturn:
  495. dwErr = GetLastError();
  496. goto CommonReturn;
  497. SetPFXAllocError:
  498. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  499. goto CommonReturn;
  500. CommonReturn:
  501. if (providerName)
  502. SSFree(providerName);
  503. return (ERROR_SUCCESS == dwErr);
  504. }
  505. IMPORT_SAFE_CALLBACK_STRUCT g_sImportCallbacks = {HCryptProv_Query_Func, NULL, Decrypt_Private_Key, NULL};
  506. //+-------------------------------------------------------------------------
  507. // PFXImportCertStore
  508. //
  509. // Import the PFX blob and return a store containing certificates
  510. //
  511. // if the password parameter is incorrect or any other problems decoding
  512. // the PFX blob are encountered, the function will return NULL and the
  513. // error code can be found from GetLastError().
  514. //
  515. // The dwFlags parameter may be set to:
  516. // CRYPT_EXPORTABLE - which would then specify that any imported keys should
  517. // be marked as exportable (see documentation on CryptImportKey)
  518. // CRYPT_USER_PROTECTED - (see documentation on CryptImportKey)
  519. // PKCS12_NO_DATA_COMMIT - will unpack the pfx blob but does not persist its contents.
  520. // In this case, returns BOOL indicating successful unpack.
  521. // CRYPT_MACHINE_KEYSET - used to force the private key to be stored in the
  522. // the local machine and not the current user.
  523. // CRYPT_USER_KEYSET - used to force the private key to be stored in the
  524. // the current user and not the local machine, even if
  525. // the pfx blob specifies that it should go into local machine.
  526. //--------------------------------------------------------------------------
  527. #define PKCS12_NO_DATA_COMMIT 0x10000000 // unpack but don't persist results
  528. HCERTSTORE
  529. WINAPI
  530. PFXImportCertStore(
  531. CRYPT_DATA_BLOB* pPFX,
  532. LPCWSTR szPassword,
  533. DWORD dwFlags)
  534. {
  535. BOOL fRet = FALSE;
  536. BOOL fDataCommit = TRUE;
  537. HPFX hPfx = NULL;
  538. HCERTSTORE hStore = NULL;
  539. SAFE_CONTENTS sContents; MAKEZERO(sContents);
  540. SAFE_CONTENTS *pSafeContents = NULL;
  541. LPCWSTR szOldNetscapeNull = L"";
  542. LPCWSTR szNetscapePassword = NULL;
  543. if (dwFlags &
  544. ~( CRYPT_EXPORTABLE | CRYPT_USER_PROTECTED | PKCS12_NO_DATA_COMMIT |
  545. CRYPT_MACHINE_KEYSET | CRYPT_USER_KEYSET))
  546. {
  547. SetLastError(ERROR_INVALID_PARAMETER);
  548. goto Ret;
  549. }
  550. if ((pPFX == NULL)) {
  551. SetLastError(ERROR_INVALID_PARAMETER);
  552. goto Ret;
  553. }
  554. // shall we commit the data we unpack?
  555. if (PKCS12_NO_DATA_COMMIT == (dwFlags & PKCS12_NO_DATA_COMMIT))
  556. {
  557. // no
  558. fDataCommit = FALSE;
  559. }
  560. else
  561. {
  562. // yes, open a store to populate
  563. hStore = CertOpenStore(
  564. CERT_STORE_PROV_MEMORY,
  565. 0,
  566. NULL,
  567. 0,
  568. NULL);
  569. }
  570. // try to import as real PKCS12
  571. if (NULL != (hPfx =
  572. PfxImportBlob (
  573. szPassword,
  574. pPFX->pbData,
  575. pPFX->cbData,
  576. dwFlags)) )
  577. {
  578. // break out if not saving data
  579. if (!fDataCommit)
  580. {
  581. fRet = TRUE;
  582. goto Ret;
  583. }
  584. // import all private keys and certs
  585. if (PfxGetKeysAndCerts(hPfx, &sContents))
  586. {
  587. g_sImportCallbacks.pVoidhCryptProvQuery = &sContents;
  588. g_sImportCallbacks.pVoidDecryptFunc = (void *) szPassword;
  589. if (!CertImportSafeContents(
  590. hStore,
  591. &sContents,
  592. CERT_STORE_ADD_ALWAYS,
  593. &g_sImportCallbacks,
  594. dwFlags,
  595. NULL))
  596. goto Ret;
  597. }
  598. }
  599. else
  600. {
  601. if (GetLastError() == CRYPT_E_BAD_ENCODE)
  602. {
  603. // that decode failed; try an old netscape version
  604. // if the password is NULL then use L"" because that is what
  605. // Netscape did in their old version, otherwise just use the password passed in
  606. if (szPassword == NULL)
  607. szNetscapePassword = szOldNetscapeNull;
  608. else
  609. szNetscapePassword = szPassword;
  610. if (NSCPImportBlob(
  611. szNetscapePassword,
  612. pPFX->pbData,
  613. pPFX->cbData,
  614. &pSafeContents))
  615. {
  616. // break out if not saving data
  617. if (!fDataCommit)
  618. {
  619. fRet = TRUE;
  620. goto Ret;
  621. }
  622. g_sImportCallbacks.pVoidhCryptProvQuery = pSafeContents;
  623. if (!CertImportSafeContents(
  624. hStore,
  625. pSafeContents,
  626. CERT_STORE_ADD_ALWAYS,
  627. &g_sImportCallbacks,
  628. dwFlags,
  629. NULL))
  630. goto Ret;
  631. SSFree(pSafeContents);
  632. }
  633. else // nscp import fail
  634. goto Ret;
  635. }
  636. else
  637. {
  638. // pfx import fail, not a decoding error
  639. goto Ret;
  640. }
  641. }
  642. fRet = TRUE;
  643. Ret:
  644. if (hPfx)
  645. PfxCloseHandle(hPfx);
  646. FreeCryptSafeContents(&sContents);
  647. if (!fRet)
  648. {
  649. if (hStore)
  650. {
  651. CertCloseStore(hStore, 0);
  652. hStore = NULL;
  653. }
  654. }
  655. if (fDataCommit)
  656. return hStore;
  657. else
  658. return (HCERTSTORE)(ULONG_PTR) fRet;
  659. }
  660. EXPORT_SAFE_CALLBACK_STRUCT g_sExportCallbacks = { Encrypt_Private_Key, NULL };
  661. //+-------------------------------------------------------------------------
  662. // PFXExportCertStoreEx
  663. //
  664. // Export the certificates and private keys referenced in the passed-in store
  665. //
  666. // This API encodes the blob under a stronger algorithm. The resulting
  667. // PKCS12 blobs are incompatible with the earlier APIs.
  668. //
  669. // The value passed in the password parameter will be used to encrypt and
  670. // verify the integrity of the PFX packet. If any problems encoding the store
  671. // are encountered, the function will return FALSE and the error code can
  672. // be found from GetLastError().
  673. //
  674. // The dwFlags parameter may be set to any combination of
  675. // EXPORT_PRIVATE_KEYS
  676. // REPORT_NO_PRIVATE_KEY
  677. // REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY
  678. // These flags are as documented in the CertExportSafeContents Crypt32 API
  679. //--------------------------------------------------------------------------
  680. BOOL
  681. WINAPI
  682. PFXExportCertStoreEx(
  683. HCERTSTORE hStore,
  684. CRYPT_DATA_BLOB* pPFX,
  685. LPCWSTR szPassword,
  686. void* pvReserved,
  687. DWORD dwFlags)
  688. {
  689. return
  690. PFXExportCertStore(
  691. hStore,
  692. pPFX,
  693. szPassword,
  694. (dwFlags | PKCS12_ENHANCED_STRENGTH_ENCODING) );
  695. }
  696. //+-------------------------------------------------------------------------
  697. // PFXExportCertStore
  698. //
  699. // Export the certificates and private keys referenced in the passed-in store
  700. //
  701. // This is an old API kept for compatibility with IE4 clients. New applications
  702. // should call PfxExportCertStoreEx for enhanced security.
  703. //
  704. // The value passed in the password parameter will be used to encrypt and
  705. // verify the integrity of the PFX packet. If any problems encoding the store
  706. // are encountered, the function will return FALSE and the error code can
  707. // be found from GetLastError().
  708. //
  709. // The dwFlags parameter may be set to any combination of
  710. // EXPORT_PRIVATE_KEYS
  711. // REPORT_NO_PRIVATE_KEY
  712. // REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY
  713. // PKCS12_ENHANCED_STRENGTH_ENCODING (used only by ExportCertStoreEx)
  714. // These flags are as documented in the CertExportSafeContents Crypt32 API
  715. //--------------------------------------------------------------------------
  716. BOOL
  717. WINAPI
  718. PFXExportCertStore(
  719. HCERTSTORE hStore,
  720. CRYPT_DATA_BLOB* pPFX,
  721. LPCWSTR szPassword,
  722. DWORD dwFlags)
  723. {
  724. BOOL fRet = FALSE;
  725. SAFE_CONTENTS* pContents = NULL;
  726. DWORD cbContents = 0;
  727. HPFX hPfx = NULL;
  728. HCRYPTPROV hCrypt = NULL;
  729. ENCRYPT_PRIVATE_PARAM_DATASTRUCT sParam;
  730. PCCERT_CONTEXT pBadCert = NULL;
  731. if (dwFlags &
  732. ~( EXPORT_PRIVATE_KEYS |
  733. REPORT_NO_PRIVATE_KEY |
  734. REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY |
  735. PKCS12_ENHANCED_STRENGTH_ENCODING ))
  736. {
  737. SetLastError(ERROR_INVALID_PARAMETER);
  738. goto Ret;
  739. }
  740. if ((hStore == NULL) ||
  741. (pPFX == NULL)) {
  742. SetLastError(ERROR_INVALID_PARAMETER);
  743. goto Ret;
  744. }
  745. // get HCRYPTPROV for rng
  746. if (!CryptAcquireContextA(&hCrypt, NULL, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
  747. goto Ret;
  748. sParam.hVerifyProv = hCrypt;
  749. sParam.szPwd = szPassword;
  750. g_sExportCallbacks.pVoidEncryptFunc = &sParam;
  751. if (!CertExportSafeContents(
  752. hStore,
  753. pContents,
  754. &cbContents,
  755. &g_sExportCallbacks,
  756. dwFlags | PFX_MODE,
  757. &pBadCert,
  758. NULL))
  759. goto Ret;
  760. pContents = (SAFE_CONTENTS*)SSAlloc(cbContents);
  761. if (pContents == NULL)
  762. goto Ret;
  763. if (!CertExportSafeContents(
  764. hStore,
  765. pContents,
  766. &cbContents,
  767. &g_sExportCallbacks,
  768. (pPFX->cbData != 0) ? dwFlags | PFX_MODE | GIVE_ME_DATA : dwFlags | PFX_MODE,
  769. &pBadCert,
  770. NULL))
  771. goto Ret;
  772. if (NULL == (hPfx = PfxExportCreate(szPassword)) )
  773. goto Ret;
  774. if (!PfxAddSafeBags(hPfx, pContents->pSafeBags, pContents->cSafeBags))
  775. goto Ret;
  776. // export
  777. if (!PfxExportBlob(
  778. hPfx,
  779. pPFX->pbData,
  780. &pPFX->cbData,
  781. dwFlags))
  782. goto Ret;
  783. fRet = TRUE;
  784. Ret:
  785. if (pBadCert != NULL)
  786. CertFreeCertificateContext(pBadCert);
  787. if (pContents)
  788. SSFree(pContents);
  789. if (hPfx)
  790. PfxCloseHandle(hPfx);
  791. if (hCrypt)
  792. {
  793. HRESULT hr = GetLastError();
  794. CryptReleaseContext(hCrypt, 0);
  795. SetLastError(hr);
  796. }
  797. return fRet;
  798. }
  799. //+-------------------------------------------------------------------------
  800. // IsPFXBlob
  801. //
  802. // This function will try to decode the outer layer of the blob as a pfx
  803. // blob, and if that works it will return TRUE, it will return FALSE otherwise
  804. //
  805. //--------------------------------------------------------------------------
  806. BOOL
  807. WINAPI
  808. PFXIsPFXBlob(
  809. CRYPT_DATA_BLOB* pPFX)
  810. {
  811. if (IsRealPFXBlob(pPFX))
  812. {
  813. return TRUE;
  814. }
  815. if (IsNetscapePFXBlob(pPFX))
  816. {
  817. return TRUE;
  818. }
  819. return FALSE;
  820. }
  821. //+-------------------------------------------------------------------------
  822. // VerifyPassword
  823. //
  824. // This function will attempt to decode the outer layer of the blob as a pfx
  825. // blob and decrypt with the given password. No data from the blob will be imported.
  826. // Return value is TRUE if password appears correct, FALSE otherwise.
  827. //
  828. //--------------------------------------------------------------------------
  829. BOOL
  830. WINAPI
  831. PFXVerifyPassword(
  832. CRYPT_DATA_BLOB* pPFX,
  833. LPCWSTR szPassword,
  834. DWORD dwFlags)
  835. {
  836. // uses overloaded ImportCertStore API
  837. HCERTSTORE h;
  838. h = PFXImportCertStore(
  839. pPFX,
  840. szPassword,
  841. PKCS12_NO_DATA_COMMIT);
  842. return (h==NULL) ? FALSE:TRUE;
  843. }