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

1826 lines
76 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1995 - 1999
  6. //
  7. // File: pfxhelp.cpp
  8. //
  9. // Contents: Support functions for PFX
  10. //
  11. // Functions: CertExportSafeContents
  12. // CertImportSafeContents
  13. //
  14. // History: 23-Feb-96 philh created
  15. //--------------------------------------------------------------------------
  16. #include "global.hxx"
  17. #include <dbgdef.h>
  18. #include "pfxhelp.h"
  19. #include "pfxpkcs.h"
  20. #include "pfxcmn.h"
  21. #include "pfxcrypt.h"
  22. // All the *pvInfo extra stuff needs to be aligned
  23. #define INFO_LEN_ALIGN(Len) ((Len + 7) & ~7)
  24. // remove when this is defined in wincrypt.h
  25. #ifndef PP_KEYSET_TYPE
  26. #define PP_KEYSET_TYPE 27
  27. #endif
  28. #define DISALLOWED_FLAG_MASK ~(CRYPT_EXPORTABLE | CRYPT_DELETEKEYSET)
  29. //+-------------------------------------------------------------------------
  30. // PFX helpe allocation and free functions
  31. //--------------------------------------------------------------------------
  32. static void *PFXHelpAlloc(
  33. IN size_t cbBytes
  34. )
  35. {
  36. void *pv;
  37. pv = malloc(cbBytes);
  38. if (pv == NULL)
  39. SetLastError((DWORD) E_OUTOFMEMORY);
  40. return pv;
  41. }
  42. static void *PFXHelpRealloc(
  43. IN void *pvOrg,
  44. IN size_t cbBytes
  45. )
  46. {
  47. void *pv;
  48. if (NULL == (pv = pvOrg ? realloc(pvOrg, cbBytes) : malloc(cbBytes)))
  49. SetLastError((DWORD) E_OUTOFMEMORY);
  50. return pv;
  51. }
  52. static void PFXHelpFree(
  53. IN void *pv
  54. )
  55. {
  56. if (pv)
  57. free(pv);
  58. }
  59. // this function will search an a SAFE_CONTENTS to see if any of the SAFE_BAGS have the
  60. // same private key as the one passed to the function. if it finds a matching private
  61. // key it will return a pointer the encoded keyID and return TRUE, it will return FALSE
  62. // otherwise. NOTE that if it returns a pointer to the encoded blob that the caller
  63. // is responsible for copying the data and must not free what is returned
  64. static BOOL WINAPI PrivateKeyAlreadyExists(
  65. BYTE *pPrivateKey,
  66. DWORD cbPrivateKey,
  67. SAFE_CONTENTS *pSafeContents,
  68. PCRYPT_DER_BLOB pEncodedKeyID
  69. )
  70. {
  71. BOOL bKeyFound = FALSE;
  72. DWORD i = 0;
  73. if (pSafeContents == NULL) {
  74. goto CommonReturn;
  75. }
  76. while ((!bKeyFound) && (i < pSafeContents->cSafeBags))
  77. {
  78. if ( ((strcmp(pSafeContents->pSafeBags[i].pszBagTypeOID, szOID_PKCS_12_KEY_BAG) == 0) ||
  79. (strcmp(pSafeContents->pSafeBags[i].pszBagTypeOID, szOID_PKCS_12_SHROUDEDKEY_BAG) == 0)) &&
  80. (cbPrivateKey == pSafeContents->pSafeBags[i].BagContents.cbData) &&
  81. (memcmp(pPrivateKey, pSafeContents->pSafeBags[i].BagContents.pbData, cbPrivateKey) == 0))
  82. {
  83. pEncodedKeyID->pbData = pSafeContents->pSafeBags[i].Attributes.rgAttr[0].rgValue[0].pbData;
  84. pEncodedKeyID->cbData = pSafeContents->pSafeBags[i].Attributes.rgAttr[0].rgValue[0].cbData;
  85. bKeyFound = TRUE;
  86. }
  87. else {
  88. i++;
  89. }
  90. }
  91. CommonReturn:
  92. return bKeyFound;
  93. }
  94. // this function will walk through a SAFE_CONTENTS structure and free all the space
  95. // associated with it
  96. static BOOL WINAPI FreeSafeContents(
  97. SAFE_CONTENTS *pSafeContents
  98. )
  99. {
  100. DWORD i,j,k;
  101. // loop for each SAFE_BAG
  102. for (i=0; i<pSafeContents->cSafeBags; i++) {
  103. if (pSafeContents->pSafeBags[i].BagContents.pbData)
  104. PFXHelpFree(pSafeContents->pSafeBags[i].BagContents.pbData);
  105. // loop for each attribute
  106. for (j=0; j<pSafeContents->pSafeBags[i].Attributes.cAttr; j++) {
  107. // l0op for each value
  108. for (k=0; k<pSafeContents->pSafeBags[i].Attributes.rgAttr[j].cValue; k++) {
  109. if (pSafeContents->pSafeBags[i].Attributes.rgAttr[j].rgValue[k].pbData)
  110. PFXHelpFree(pSafeContents->pSafeBags[i].Attributes.rgAttr[j].rgValue[k].pbData);
  111. }
  112. // free the value struct array
  113. if (pSafeContents->pSafeBags[i].Attributes.rgAttr[j].rgValue)
  114. PFXHelpFree(pSafeContents->pSafeBags[i].Attributes.rgAttr[j].rgValue);
  115. }
  116. // free the attribute struct array
  117. if (pSafeContents->pSafeBags[i].Attributes.rgAttr)
  118. PFXHelpFree(pSafeContents->pSafeBags[i].Attributes.rgAttr);
  119. }
  120. // finally, free the safe bag array
  121. if (pSafeContents->pSafeBags != NULL)
  122. {
  123. PFXHelpFree(pSafeContents->pSafeBags);
  124. }
  125. return TRUE;
  126. }
  127. #define SZ_NO_PROVIDER_NAME_KEY L"Software\\Microsoft\\Windows\\CurrentVersion\\PFX"
  128. #define SZ_NO_PROVIDER_NAME_VALUE L"NoProviderName"
  129. BOOL
  130. NoProviderNameRegValueSet()
  131. {
  132. HKEY hKey = NULL;
  133. BOOL fRet = FALSE;
  134. DWORD dwData;
  135. DWORD dwDataSize = sizeof(dwData);
  136. if (ERROR_SUCCESS != RegOpenKeyExU(
  137. HKEY_CURRENT_USER,
  138. SZ_NO_PROVIDER_NAME_KEY,
  139. 0,
  140. KEY_EXECUTE,
  141. &hKey))
  142. {
  143. goto Return;;
  144. }
  145. if (ERROR_SUCCESS == RegQueryValueExU(
  146. hKey,
  147. SZ_NO_PROVIDER_NAME_VALUE,
  148. NULL,
  149. NULL,
  150. (LPBYTE) &dwData,
  151. &dwDataSize))
  152. {
  153. fRet = (BOOL) dwData;
  154. }
  155. Return:
  156. if (hKey != NULL)
  157. RegCloseKey(hKey);
  158. return fRet;
  159. }
  160. //+-------------------------------------------------------------------------
  161. // hCertStore - handle to the cert store that contains the certs whose
  162. // corresponding private keys are to be exported
  163. // pSafeContents - pointer to a buffer to receive the SAFE_CONTENTS structure
  164. // and supporting data
  165. // pcbSafeContents - (in) specifies the length, in bytes, of the pSafeContents
  166. // buffer. (out) gets filled in with the number of bytes
  167. // used by the operation. If this is set to 0, the
  168. // required length of pSafeContents is filled in, and
  169. // pSafeContents is ignored.
  170. // dwFlags - the current available flags are:
  171. // EXPORT_PRIVATE_KEYS
  172. // if this flag is set then the private keys are exported as well
  173. // as the certificates
  174. // REPORT_NO_PRIVATE_KEY
  175. // if this flag is set and a certificate is encountered that has no
  176. // no associated private key, the function will return immediately
  177. // with ppCertContext filled in with a pointer to the cert context
  178. // in question. the caller is responsible for freeing the cert
  179. // context which is passed back.
  180. // REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY
  181. // if this flag is set and a certificate is encountered that has a
  182. // non-exportable private key, the function will return immediately
  183. // with ppCertContext filled in with a pointer to the cert context
  184. // in question. the caller is responsible for freeing the cert
  185. // context which is passed back.
  186. // ppCertContext - a pointer to a pointer to a cert context. this is used
  187. // if REPORT_NO_PRIVATE_KEY or REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY
  188. // flags are set. the caller is responsible for freeing the
  189. // cert context.
  190. // pvAuxInfo - reserved for future use, must be set to NULL
  191. //+-------------------------------------------------------------------------
  192. BOOL WINAPI CertExportSafeContents(
  193. HCERTSTORE hCertStore, // in
  194. SAFE_CONTENTS *pSafeContents, // out
  195. DWORD *pcbSafeContents, // in, out
  196. EXPORT_SAFE_CALLBACK_STRUCT *ExportSafeCallbackStruct, // in
  197. DWORD dwFlags, // in
  198. PCCERT_CONTEXT *ppCertContext, // out
  199. void *pvAuxInfo // in
  200. )
  201. {
  202. BOOL fResult = TRUE;
  203. PCCERT_CONTEXT pCertContext = NULL;
  204. DWORD dwKeySpec;
  205. DWORD dwBytesRequired = sizeof(SAFE_CONTENTS);
  206. SAFE_CONTENTS localSafeContents;
  207. BYTE *pCurrentBufferLocation = NULL;
  208. DWORD dwIDs = 1;
  209. DWORD i,j,k;
  210. // all these variables are used in the while loop that enumerates through
  211. // the cert contexts
  212. CRYPT_KEY_PROV_INFO *pCryptKeyProvInfo = NULL;
  213. DWORD cbCryptKeyProvInfo = 0;
  214. HCRYPTPROV hCryptProv = NULL;
  215. BYTE *pPrivateKey = NULL;
  216. DWORD cbPrivateKey = 0;
  217. void *pTempMemBlock = NULL;
  218. SAFE_BAG *pCurrentSafeBag = NULL;
  219. DWORD dwKeyID = 0;
  220. CRYPT_ATTR_BLOB keyID;
  221. CRYPT_DER_BLOB EncodedKeyID;
  222. CERT_NAME_VALUE wideFriendlyName;
  223. BYTE *pFriendlyName = NULL;
  224. DWORD cbFriendlyName = 0;
  225. DWORD dwFriendlyNameAttributeIndex = 0;
  226. BOOL fAddProviderName;
  227. LPWSTR pwszProviderName = NULL;
  228. DWORD cbProviderName = 0;
  229. localSafeContents.cSafeBags = 0;
  230. localSafeContents.pSafeBags = NULL;
  231. // validate input parameters
  232. if ((pcbSafeContents == NULL) ||
  233. (pvAuxInfo != NULL ||
  234. ((*pcbSafeContents != 0) && (pSafeContents == NULL)))) {
  235. SetLastError((DWORD)ERROR_INVALID_PARAMETER);
  236. goto ErrorReturn;
  237. }
  238. if ((dwFlags & REPORT_NO_PRIVATE_KEY) || (dwFlags & REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY)) {
  239. if (ppCertContext == NULL) {
  240. SetLastError((DWORD)ERROR_INVALID_PARAMETER);
  241. goto ErrorReturn;
  242. }
  243. *ppCertContext = NULL;
  244. }
  245. fAddProviderName = !NoProviderNameRegValueSet();
  246. // loop for each certificate context in the store and export the cert and
  247. // corresponding private key if one exists
  248. while (NULL != (pCertContext = CertEnumCertificatesInStore(hCertStore, pCertContext))) {
  249. // initialize all loop variables
  250. if (pCryptKeyProvInfo)
  251. PFXHelpFree(pCryptKeyProvInfo);
  252. pCryptKeyProvInfo = NULL;
  253. cbCryptKeyProvInfo = 0;
  254. if (hCryptProv)
  255. CryptReleaseContext(hCryptProv, 0);
  256. hCryptProv = NULL;
  257. if (pPrivateKey)
  258. PFXHelpFree(pPrivateKey);
  259. pPrivateKey = NULL;
  260. cbPrivateKey = 0;
  261. pTempMemBlock = NULL;
  262. pCurrentSafeBag = NULL;
  263. // keyID is the CRYPT_ATTR_BLOB that is always used to encode the key id
  264. // for certs and private keys. dwKeyID is the only thing that will need
  265. // to be set properly before calling CryptEncodeObject with keyID.
  266. keyID.pbData = (BYTE *) &dwKeyID;
  267. keyID.cbData = sizeof(DWORD);
  268. // initialize EncodedKeyID so when exporting the cert it can check to see if this
  269. // has been set
  270. EncodedKeyID.pbData = NULL;
  271. EncodedKeyID.cbData = 0;
  272. // if the EXPORT_PRIVATE_KEYS flag is set then
  273. // try to export the private key which corresponds to this certificate before
  274. // exporting the certificate so we know how to set the key ID on the certificate
  275. if (EXPORT_PRIVATE_KEYS & dwFlags)
  276. // get the provider info so we can export the private key
  277. if (CertGetCertificateContextProperty(
  278. pCertContext,
  279. CERT_KEY_PROV_INFO_PROP_ID,
  280. NULL,
  281. &cbCryptKeyProvInfo
  282. )) {
  283. if (NULL == (pCryptKeyProvInfo = (CRYPT_KEY_PROV_INFO *)
  284. PFXHelpAlloc(cbCryptKeyProvInfo))) {
  285. goto ErrorReturn;
  286. }
  287. if (CertGetCertificateContextProperty(
  288. pCertContext,
  289. CERT_KEY_PROV_INFO_PROP_ID,
  290. pCryptKeyProvInfo,
  291. &cbCryptKeyProvInfo
  292. )) {
  293. // acquire the HCRYPTPROV so we can export the private key in that puppy
  294. if (!CryptAcquireContextU(
  295. &hCryptProv,
  296. pCryptKeyProvInfo->pwszContainerName,
  297. pCryptKeyProvInfo->pwszProvName,
  298. pCryptKeyProvInfo->dwProvType,
  299. pCryptKeyProvInfo->dwFlags & (DISALLOWED_FLAG_MASK)) ) {
  300. goto ErrorReturn;
  301. }
  302. CRYPT_PKCS8_EXPORT_PARAMS sExportParams = { hCryptProv,
  303. pCryptKeyProvInfo->dwKeySpec,
  304. pCertContext->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId,
  305. //szOID_RSA_RSA, // FIX -what do I do here??, possibly look at the algorithm in the cert
  306. (ExportSafeCallbackStruct) ? ExportSafeCallbackStruct->pEncryptPrivateKeyFunc : NULL,
  307. (ExportSafeCallbackStruct) ? ExportSafeCallbackStruct->pVoidEncryptFunc : NULL};
  308. // do the actual export of the private key
  309. if (CryptExportPKCS8Ex(
  310. &sExportParams,
  311. PFX_MODE,
  312. NULL,
  313. NULL,
  314. &cbPrivateKey
  315. )) {
  316. if (NULL == (pPrivateKey = (BYTE *) PFXHelpAlloc(cbPrivateKey))) {
  317. goto ErrorReturn;
  318. }
  319. if (CryptExportPKCS8Ex(
  320. &sExportParams,
  321. (dwFlags & GIVE_ME_DATA) ? PFX_MODE | GIVE_ME_DATA : PFX_MODE,
  322. NULL,
  323. pPrivateKey,
  324. &cbPrivateKey
  325. )) {
  326. // search the array of key bags to see if the private key is already there
  327. // and take action accordingly. if the private key already exists, the
  328. // EncodedKeyID contains the encoded keyID attribute for exporting the
  329. // certificate so we don't need to do anything
  330. if (!PrivateKeyAlreadyExists(
  331. pPrivateKey,
  332. cbPrivateKey,
  333. &localSafeContents,
  334. &EncodedKeyID
  335. )) {
  336. // extend the length of the SAFE_BAGs array by one
  337. if (NULL == (pTempMemBlock = PFXHelpRealloc(
  338. localSafeContents.pSafeBags,
  339. sizeof(SAFE_BAG) *
  340. ++localSafeContents.cSafeBags))) {
  341. goto ErrorReturn;
  342. }
  343. localSafeContents.pSafeBags = (SAFE_BAG *) pTempMemBlock;
  344. pCurrentSafeBag =
  345. &localSafeContents.pSafeBags[localSafeContents.cSafeBags - 1];
  346. ZeroMemory(pCurrentSafeBag, sizeof(SAFE_BAG));
  347. dwBytesRequired += sizeof(SAFE_BAG);
  348. // set up the OID information for the bag type
  349. pCurrentSafeBag->pszBagTypeOID = (ExportSafeCallbackStruct->pEncryptPrivateKeyFunc) ? szOID_PKCS_12_SHROUDEDKEY_BAG : szOID_PKCS_12_KEY_BAG;
  350. dwBytesRequired += INFO_LEN_ALIGN(strlen(pCurrentSafeBag->pszBagTypeOID) + 1);
  351. // copy the pointer to the private key into the new safe bag
  352. // and NULL out the pPrivateKey pointer so the memory does not get freed
  353. pCurrentSafeBag->BagContents.pbData = pPrivateKey;
  354. pCurrentSafeBag->BagContents.cbData = cbPrivateKey;
  355. dwBytesRequired += INFO_LEN_ALIGN(cbPrivateKey);
  356. pPrivateKey = NULL;
  357. cbPrivateKey = 0;
  358. // set up the attributes array for the SAFE_BAG
  359. // FIX - for right now just do the
  360. // szOID_PKCS_12_LOCAL_KEY_ID,
  361. // szOID_PKCS_12_FRIENDLY_NAME_ATTR,
  362. // and szOID_PKCS_12_KEY_PROVIDER_NAME_ATTR. (if the NoProviderName reg value not set)
  363. // optional szOID_LOCAL_MACHINE_KEYSET if needed
  364. pCurrentSafeBag->Attributes.cAttr = fAddProviderName ? 3 : 2;
  365. if (pCryptKeyProvInfo->dwFlags & CRYPT_MACHINE_KEYSET)
  366. pCurrentSafeBag->Attributes.cAttr++;
  367. if (NULL == (pCurrentSafeBag->Attributes.rgAttr = (CRYPT_ATTRIBUTE *)
  368. PFXHelpAlloc(sizeof(CRYPT_ATTRIBUTE) * pCurrentSafeBag->Attributes.cAttr))) {
  369. goto ErrorReturn;
  370. }
  371. ZeroMemory(pCurrentSafeBag->Attributes.rgAttr, sizeof(CRYPT_ATTRIBUTE) * pCurrentSafeBag->Attributes.cAttr);
  372. dwBytesRequired += sizeof(CRYPT_ATTRIBUTE) * pCurrentSafeBag->Attributes.cAttr;
  373. // allocate space and do setup based on whether the szOID_LOCAL_MACHINE_KEYSET
  374. // attribute is needed
  375. if (pCryptKeyProvInfo->dwFlags & CRYPT_MACHINE_KEYSET)
  376. {
  377. // since there is nothing to do for the szOID_LOCAL_MACHINE_KEYSET
  378. // besides just setting the OID do it here and put it in the last
  379. // attribute
  380. pCurrentSafeBag->Attributes.rgAttr[pCurrentSafeBag->Attributes.cAttr-1].pszObjId =
  381. szOID_LOCAL_MACHINE_KEYSET;
  382. dwBytesRequired += INFO_LEN_ALIGN(strlen(szOID_LOCAL_MACHINE_KEYSET) + 1);
  383. pCurrentSafeBag->Attributes.rgAttr[pCurrentSafeBag->Attributes.cAttr-1].rgValue = NULL;
  384. pCurrentSafeBag->Attributes.rgAttr[pCurrentSafeBag->Attributes.cAttr-1].cValue = 0;
  385. }
  386. // set the OID in the szOID_PKCS_12_LOCAL_KEY_ID attribute
  387. pCurrentSafeBag->Attributes.rgAttr[0].pszObjId =
  388. szOID_PKCS_12_LOCAL_KEY_ID;
  389. dwBytesRequired += INFO_LEN_ALIGN(strlen(szOID_PKCS_12_LOCAL_KEY_ID) + 1);
  390. // allocate space for the single value inside the attribute
  391. if (NULL == (pCurrentSafeBag->Attributes.rgAttr[0].rgValue =
  392. (CRYPT_ATTR_BLOB *) PFXHelpAlloc(sizeof(CRYPT_ATTR_BLOB)))) {
  393. goto ErrorReturn;
  394. }
  395. ZeroMemory(pCurrentSafeBag->Attributes.rgAttr[0].rgValue, sizeof(CRYPT_ATTR_BLOB));
  396. dwBytesRequired += sizeof(CRYPT_ATTR_BLOB);
  397. pCurrentSafeBag->Attributes.rgAttr[0].cValue = 1;
  398. // set the key ID to the appropriate key ID
  399. dwKeyID = dwIDs++;
  400. // encode the keyID
  401. pCurrentSafeBag->Attributes.rgAttr[0].rgValue[0].pbData = NULL;
  402. pCurrentSafeBag->Attributes.rgAttr[0].rgValue[0].cbData = 0;
  403. if (!CryptEncodeObject(
  404. X509_ASN_ENCODING,
  405. X509_OCTET_STRING,
  406. &keyID,
  407. NULL,
  408. &pCurrentSafeBag->Attributes.rgAttr[0].rgValue[0].cbData)) {
  409. goto ErrorReturn;
  410. }
  411. if (NULL == (pCurrentSafeBag->Attributes.rgAttr[0].rgValue[0].pbData =
  412. (BYTE *) PFXHelpAlloc(pCurrentSafeBag->Attributes.rgAttr[0].rgValue[0].cbData))) {
  413. goto ErrorReturn;
  414. }
  415. dwBytesRequired += INFO_LEN_ALIGN(pCurrentSafeBag->Attributes.rgAttr[0].rgValue[0].cbData);
  416. if (!CryptEncodeObject(
  417. X509_ASN_ENCODING,
  418. X509_OCTET_STRING,
  419. &keyID,
  420. pCurrentSafeBag->Attributes.rgAttr[0].rgValue[0].pbData,
  421. &pCurrentSafeBag->Attributes.rgAttr[0].rgValue[0].cbData)) {
  422. goto ErrorReturn;
  423. }
  424. // set the fields in EncodedKeyID so that when the cert is exported
  425. // it can just copy the already encoded keyID to it's attributes
  426. EncodedKeyID.pbData = pCurrentSafeBag->Attributes.rgAttr[0].rgValue[0].pbData;
  427. EncodedKeyID.cbData = pCurrentSafeBag->Attributes.rgAttr[0].rgValue[0].cbData;
  428. // Friendly Name
  429. // set the OID in the szOID_PKCS_12_FRIENDLY_NAME_ATTR attribute
  430. pCurrentSafeBag->Attributes.rgAttr[1].pszObjId =
  431. szOID_PKCS_12_FRIENDLY_NAME_ATTR;
  432. dwBytesRequired += INFO_LEN_ALIGN(strlen(szOID_PKCS_12_FRIENDLY_NAME_ATTR) + 1);
  433. // allocate space for the single value inside the attribute
  434. if (NULL == (pCurrentSafeBag->Attributes.rgAttr[1].rgValue =
  435. (CRYPT_ATTR_BLOB *) PFXHelpAlloc(sizeof(CRYPT_ATTR_BLOB)))) {
  436. goto ErrorReturn;
  437. }
  438. ZeroMemory(pCurrentSafeBag->Attributes.rgAttr[1].rgValue, sizeof(CRYPT_ATTR_BLOB));
  439. dwBytesRequired += sizeof(CRYPT_ATTR_BLOB);
  440. pCurrentSafeBag->Attributes.rgAttr[1].cValue = 1;
  441. // encode the provider name so it can be used on import
  442. wideFriendlyName.dwValueType = CERT_RDN_BMP_STRING;
  443. wideFriendlyName.Value.pbData = (BYTE *) pCryptKeyProvInfo->pwszContainerName;
  444. wideFriendlyName.Value.cbData = 0;
  445. if (!CryptEncodeObject(
  446. X509_ASN_ENCODING,
  447. X509_UNICODE_ANY_STRING,
  448. (void *)&wideFriendlyName,
  449. NULL,
  450. &pCurrentSafeBag->Attributes.rgAttr[1].rgValue[0].cbData)) {
  451. goto ErrorReturn;
  452. }
  453. if (NULL == (pCurrentSafeBag->Attributes.rgAttr[1].rgValue[0].pbData =
  454. (BYTE *) PFXHelpAlloc(pCurrentSafeBag->Attributes.rgAttr[1].rgValue[0].cbData))) {
  455. goto ErrorReturn;
  456. }
  457. dwBytesRequired += INFO_LEN_ALIGN(pCurrentSafeBag->Attributes.rgAttr[1].rgValue[0].cbData);
  458. if (!CryptEncodeObject(
  459. X509_ASN_ENCODING,
  460. X509_UNICODE_ANY_STRING,
  461. (void *)&wideFriendlyName,
  462. pCurrentSafeBag->Attributes.rgAttr[1].rgValue[0].pbData,
  463. &pCurrentSafeBag->Attributes.rgAttr[1].rgValue[0].cbData)) {
  464. goto ErrorReturn;
  465. }
  466. // Provider Name
  467. if (fAddProviderName)
  468. {
  469. // set the OID in the szOID_PKCS_12_KEY_PROVIDER_NAME_ATTR attribute
  470. pCurrentSafeBag->Attributes.rgAttr[2].pszObjId =
  471. szOID_PKCS_12_KEY_PROVIDER_NAME_ATTR;
  472. dwBytesRequired += INFO_LEN_ALIGN(strlen(szOID_PKCS_12_KEY_PROVIDER_NAME_ATTR) + 1);
  473. // allocate space for the single value inside the attribute
  474. if (NULL == (pCurrentSafeBag->Attributes.rgAttr[2].rgValue =
  475. (CRYPT_ATTR_BLOB *) PFXHelpAlloc(sizeof(CRYPT_ATTR_BLOB)))) {
  476. goto ErrorReturn;
  477. }
  478. ZeroMemory(pCurrentSafeBag->Attributes.rgAttr[2].rgValue, sizeof(CRYPT_ATTR_BLOB));
  479. dwBytesRequired += sizeof(CRYPT_ATTR_BLOB);
  480. pCurrentSafeBag->Attributes.rgAttr[2].cValue = 1;
  481. // encode the provider name so it can be used on import
  482. //
  483. // if the provider name is NULL or the empty string, then use
  484. // the default provider name for the provider type
  485. //
  486. wideFriendlyName.dwValueType = CERT_RDN_BMP_STRING;
  487. wideFriendlyName.Value.cbData = 0;
  488. if ((pCryptKeyProvInfo->pwszProvName == NULL) ||
  489. (wcscmp(pCryptKeyProvInfo->pwszProvName, L"") == 0))
  490. {
  491. if (!CryptGetDefaultProviderW(
  492. pCryptKeyProvInfo->dwProvType,
  493. NULL,
  494. (pCryptKeyProvInfo->dwFlags & CRYPT_MACHINE_KEYSET) ?
  495. CRYPT_MACHINE_DEFAULT : CRYPT_USER_DEFAULT,
  496. NULL,
  497. &cbProviderName))
  498. {
  499. goto ErrorReturn;
  500. }
  501. if (NULL == (pwszProviderName = (LPWSTR) PFXHelpAlloc(cbProviderName)))
  502. {
  503. goto ErrorReturn;
  504. }
  505. if (!CryptGetDefaultProviderW(
  506. pCryptKeyProvInfo->dwProvType,
  507. NULL,
  508. (pCryptKeyProvInfo->dwFlags & CRYPT_MACHINE_KEYSET) ?
  509. CRYPT_MACHINE_DEFAULT : CRYPT_USER_DEFAULT,
  510. pwszProviderName,
  511. &cbProviderName))
  512. {
  513. goto ErrorReturn;
  514. }
  515. wideFriendlyName.Value.pbData = (BYTE *) pwszProviderName;
  516. }
  517. else
  518. {
  519. wideFriendlyName.Value.pbData = (BYTE *) pCryptKeyProvInfo->pwszProvName;
  520. }
  521. if (!CryptEncodeObject(
  522. X509_ASN_ENCODING,
  523. X509_UNICODE_ANY_STRING,
  524. (void *)&wideFriendlyName,
  525. NULL,
  526. &pCurrentSafeBag->Attributes.rgAttr[2].rgValue[0].cbData)) {
  527. goto ErrorReturn;
  528. }
  529. if (NULL == (pCurrentSafeBag->Attributes.rgAttr[2].rgValue[0].pbData =
  530. (BYTE *) PFXHelpAlloc(pCurrentSafeBag->Attributes.rgAttr[2].rgValue[0].cbData))) {
  531. goto ErrorReturn;
  532. }
  533. dwBytesRequired += INFO_LEN_ALIGN(pCurrentSafeBag->Attributes.rgAttr[2].rgValue[0].cbData);
  534. if (!CryptEncodeObject(
  535. X509_ASN_ENCODING,
  536. X509_UNICODE_ANY_STRING,
  537. (void *)&wideFriendlyName,
  538. pCurrentSafeBag->Attributes.rgAttr[2].rgValue[0].pbData,
  539. &pCurrentSafeBag->Attributes.rgAttr[2].rgValue[0].cbData)) {
  540. goto ErrorReturn;
  541. }
  542. }
  543. }
  544. } // if (CryptExportPKCS8Ex())
  545. else {
  546. // check to see if it is a non-exportable key error or no key error
  547. if (GetLastError() == NTE_BAD_KEY ||
  548. GetLastError() == NTE_BAD_KEY_STATE) {
  549. // the user has specified whether this is a fatal error or not
  550. if (dwFlags & REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY) {
  551. *ppCertContext = pCertContext;
  552. pCertContext = NULL;
  553. goto ErrorReturn;
  554. }
  555. }
  556. else if (GetLastError() == NTE_NO_KEY) {
  557. // the user has specified whether this is a fatal error or not
  558. if (dwFlags & REPORT_NO_PRIVATE_KEY) {
  559. *ppCertContext = pCertContext;
  560. pCertContext = NULL;
  561. goto ErrorReturn;
  562. }
  563. }
  564. else {
  565. // it isn't a non-exportable key error or no key error, so it is bad... bad...
  566. goto ErrorReturn;
  567. }
  568. }
  569. } // if (CryptExportPKCS8Ex())
  570. else {
  571. // check to see if it is a non-exportable key error or no key error
  572. if (GetLastError() == NTE_BAD_KEY ||
  573. GetLastError() == NTE_BAD_KEY_STATE) {
  574. // the user has specified whether this is a fatal error or not
  575. if (dwFlags & REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY) {
  576. *ppCertContext = pCertContext;
  577. pCertContext = NULL;
  578. goto ErrorReturn;
  579. }
  580. }
  581. else if (GetLastError() == NTE_NO_KEY) {
  582. // the user has specified whether this is a fatal error or not
  583. if (dwFlags & REPORT_NO_PRIVATE_KEY) {
  584. *ppCertContext = pCertContext;
  585. pCertContext = NULL;
  586. goto ErrorReturn;
  587. }
  588. }
  589. else {
  590. // it was not a non-exportable error,so go directly to ErrorReturn
  591. goto ErrorReturn;
  592. }
  593. }
  594. } // if (CertGetCertificateContextProperty())
  595. else {
  596. // if CertGetCertificateContextProperty failed then there is no corresponding
  597. // private key, the user has indicated via dwFlags whether this is fatal or not,
  598. // if it is fatal then return an error, otherwise just loop and get the next cert
  599. if (dwFlags & REPORT_NO_PRIVATE_KEY) {
  600. *ppCertContext = pCertContext;
  601. pCertContext = NULL;
  602. goto ErrorReturn;
  603. }
  604. }
  605. } // if (CertGetCertificateContextProperty())
  606. else {
  607. // if CertGetCertificateContextProperty failed then there is no corresponding
  608. // private key, the user has indicated via dwFlags whether this is fatal or not,
  609. // if it is fatal then return an error, otherwise just continue and export the cert
  610. if (dwFlags & REPORT_NO_PRIVATE_KEY) {
  611. *ppCertContext = pCertContext;
  612. pCertContext = NULL;
  613. goto ErrorReturn;
  614. }
  615. }
  616. // now export the current cert!!
  617. // extend the length of the SAFE_BAGs array by one
  618. if (NULL == (pTempMemBlock = PFXHelpRealloc(
  619. localSafeContents.pSafeBags,
  620. sizeof(SAFE_BAG) * ++localSafeContents.cSafeBags))) {
  621. goto ErrorReturn;
  622. }
  623. localSafeContents.pSafeBags = (SAFE_BAG *) pTempMemBlock;
  624. pCurrentSafeBag = &localSafeContents.pSafeBags[localSafeContents.cSafeBags - 1];
  625. ZeroMemory(pCurrentSafeBag, sizeof(SAFE_BAG));
  626. dwBytesRequired += sizeof(SAFE_BAG);
  627. // set up the OID information for the bag type
  628. pCurrentSafeBag->pszBagTypeOID = szOID_PKCS_12_CERT_BAG;
  629. dwBytesRequired += INFO_LEN_ALIGN(strlen(szOID_PKCS_12_CERT_BAG) + 1);
  630. // take the encoded cert and turn it into an encoded CertBag and place in the
  631. // BagContents
  632. pCurrentSafeBag->BagContents.cbData = 0;
  633. if (!MakeEncodedCertBag(
  634. pCertContext->pbCertEncoded,
  635. pCertContext->cbCertEncoded,
  636. NULL,
  637. &(pCurrentSafeBag->BagContents.cbData))) {
  638. goto ErrorReturn;
  639. }
  640. if (NULL == (pCurrentSafeBag->BagContents.pbData =
  641. (BYTE *) PFXHelpAlloc(pCurrentSafeBag->BagContents.cbData))) {
  642. goto ErrorReturn;
  643. }
  644. if (!MakeEncodedCertBag(
  645. pCertContext->pbCertEncoded,
  646. pCertContext->cbCertEncoded,
  647. pCurrentSafeBag->BagContents.pbData,
  648. &(pCurrentSafeBag->BagContents.cbData))) {
  649. goto ErrorReturn;
  650. }
  651. dwBytesRequired += INFO_LEN_ALIGN(pCurrentSafeBag->BagContents.cbData);
  652. // check to see how many attributes there will be, the possibilities right now
  653. // are FREINDLY_NAME and LOCAL_KEY_ID
  654. // try to get the friendly name property from the cert context
  655. if (!CertGetCertificateContextProperty(
  656. pCertContext,
  657. CERT_FRIENDLY_NAME_PROP_ID,
  658. NULL,
  659. &cbFriendlyName)) {
  660. // just set this to insure that it is 0 if we don't have a friendly name
  661. cbFriendlyName = 0;
  662. }
  663. // allocate space for the attributes array in the safe bag accordingly
  664. // if EncodedKeyID.pbData != NULL means there is a corresponding private
  665. // key, so the LOCAL_KEY_ID attribute needs to be set
  666. if ((cbFriendlyName != 0) && (EncodedKeyID.pbData != NULL)) {
  667. if (NULL == (pCurrentSafeBag->Attributes.rgAttr =
  668. (CRYPT_ATTRIBUTE *) PFXHelpAlloc(sizeof(CRYPT_ATTRIBUTE) * 2))) {
  669. goto ErrorReturn;
  670. }
  671. ZeroMemory(pCurrentSafeBag->Attributes.rgAttr, sizeof(CRYPT_ATTRIBUTE) * 2);
  672. dwBytesRequired += sizeof(CRYPT_ATTRIBUTE) * 2;
  673. pCurrentSafeBag->Attributes.cAttr = 2;
  674. }
  675. else if ((cbFriendlyName != 0) || (EncodedKeyID.pbData != NULL)) {
  676. if (NULL == (pCurrentSafeBag->Attributes.rgAttr =
  677. (CRYPT_ATTRIBUTE *) PFXHelpAlloc(sizeof(CRYPT_ATTRIBUTE)))) {
  678. goto ErrorReturn;
  679. }
  680. ZeroMemory(pCurrentSafeBag->Attributes.rgAttr, sizeof(CRYPT_ATTRIBUTE));
  681. dwBytesRequired += sizeof(CRYPT_ATTRIBUTE);
  682. pCurrentSafeBag->Attributes.cAttr = 1;
  683. }
  684. else {
  685. pCurrentSafeBag->Attributes.rgAttr = NULL;
  686. pCurrentSafeBag->Attributes.cAttr = 0;
  687. }
  688. // check to see if the cert has a corresponding private key, if so then set
  689. // up the first attribute to point to it.... if there is a private key then
  690. // LOCAL_KEY_ID will always be the 0th element in the attribute array
  691. if (EncodedKeyID.pbData != NULL) {
  692. // set the OID in the single attribute
  693. pCurrentSafeBag->Attributes.rgAttr[0].pszObjId = szOID_PKCS_12_LOCAL_KEY_ID;
  694. dwBytesRequired += INFO_LEN_ALIGN(strlen(szOID_PKCS_12_LOCAL_KEY_ID) + 1);
  695. // allocate space for the single value inside the single attribute
  696. if (NULL == (pCurrentSafeBag->Attributes.rgAttr[0].rgValue =
  697. (CRYPT_ATTR_BLOB *) PFXHelpAlloc(sizeof(CRYPT_ATTR_BLOB)))) {
  698. goto ErrorReturn;
  699. }
  700. ZeroMemory(pCurrentSafeBag->Attributes.rgAttr[0].rgValue, sizeof(CRYPT_ATTR_BLOB));
  701. dwBytesRequired += sizeof(CRYPT_ATTR_BLOB);
  702. pCurrentSafeBag->Attributes.rgAttr[0].cValue = 1;
  703. // copy the encoded keyID that was set up during export of private key
  704. if (NULL == (pCurrentSafeBag->Attributes.rgAttr[0].rgValue[0].pbData =
  705. (BYTE *) PFXHelpAlloc(EncodedKeyID.cbData))) {
  706. goto ErrorReturn;
  707. }
  708. pCurrentSafeBag->Attributes.rgAttr[0].rgValue[0].cbData = EncodedKeyID.cbData;
  709. dwBytesRequired += INFO_LEN_ALIGN(EncodedKeyID.cbData);
  710. memcpy(
  711. pCurrentSafeBag->Attributes.rgAttr[0].rgValue[0].pbData,
  712. EncodedKeyID.pbData,
  713. EncodedKeyID.cbData);
  714. } // if (EncodedKeyID.pbData != NULL)
  715. // check to see if this cert has a friendly name property, if so,
  716. // get it and put it in an attribute
  717. if (cbFriendlyName != 0) {
  718. if ((pFriendlyName = (BYTE *) PFXHelpAlloc(cbFriendlyName)) != NULL) {
  719. if (CertGetCertificateContextProperty(
  720. pCertContext,
  721. CERT_FRIENDLY_NAME_PROP_ID,
  722. pFriendlyName,
  723. &cbFriendlyName)) {
  724. // set the index of the attribute which will hold the FRIENDLY_NAME,
  725. // if there is a LOCAL_KEY_ID attribute then the index will be 1,
  726. // if there isn't then the index will be 0
  727. if (EncodedKeyID.pbData != NULL) {
  728. dwFriendlyNameAttributeIndex = 1;
  729. }
  730. else {
  731. dwFriendlyNameAttributeIndex = 0;
  732. }
  733. // set the OID in the szOID_PKCS_12_FRIENDLY_NAME_ATTR attribute
  734. pCurrentSafeBag->Attributes.rgAttr[dwFriendlyNameAttributeIndex].pszObjId =
  735. szOID_PKCS_12_FRIENDLY_NAME_ATTR;
  736. dwBytesRequired += INFO_LEN_ALIGN(strlen(szOID_PKCS_12_FRIENDLY_NAME_ATTR) + 1);
  737. // allocate space for the single value inside the attribute
  738. if (NULL == (pCurrentSafeBag->Attributes.rgAttr[dwFriendlyNameAttributeIndex].rgValue =
  739. (CRYPT_ATTR_BLOB *) PFXHelpAlloc(sizeof(CRYPT_ATTR_BLOB)))) {
  740. goto ErrorReturn;
  741. }
  742. ZeroMemory(pCurrentSafeBag->Attributes.rgAttr[dwFriendlyNameAttributeIndex].rgValue, sizeof(CRYPT_ATTR_BLOB));
  743. dwBytesRequired += sizeof(CRYPT_ATTR_BLOB);
  744. pCurrentSafeBag->Attributes.rgAttr[dwFriendlyNameAttributeIndex].cValue = 1;
  745. // encode the friendly name, reuse the containerName variable because its there
  746. wideFriendlyName.dwValueType = CERT_RDN_BMP_STRING;
  747. wideFriendlyName.Value.pbData = pFriendlyName;
  748. wideFriendlyName.Value.cbData = cbFriendlyName;
  749. if (!CryptEncodeObject(
  750. X509_ASN_ENCODING,
  751. X509_UNICODE_ANY_STRING,
  752. (void *)&wideFriendlyName,
  753. NULL,
  754. &pCurrentSafeBag->Attributes.rgAttr[dwFriendlyNameAttributeIndex].rgValue[0].cbData)) {
  755. goto ErrorReturn;
  756. }
  757. if (NULL == (pCurrentSafeBag->Attributes.rgAttr[dwFriendlyNameAttributeIndex].rgValue[0].pbData =
  758. (BYTE *) PFXHelpAlloc(pCurrentSafeBag->Attributes.rgAttr[dwFriendlyNameAttributeIndex].rgValue[0].cbData))) {
  759. goto ErrorReturn;
  760. }
  761. dwBytesRequired += INFO_LEN_ALIGN(pCurrentSafeBag->Attributes.rgAttr[dwFriendlyNameAttributeIndex].rgValue[0].cbData);
  762. if (!CryptEncodeObject(
  763. X509_ASN_ENCODING,
  764. X509_UNICODE_ANY_STRING,
  765. (void *)&wideFriendlyName,
  766. pCurrentSafeBag->Attributes.rgAttr[dwFriendlyNameAttributeIndex].rgValue[0].pbData,
  767. &pCurrentSafeBag->Attributes.rgAttr[dwFriendlyNameAttributeIndex].rgValue[0].cbData)) {
  768. goto ErrorReturn;
  769. }
  770. } // if (CertGetCertificateContextProperty(CERT_FRIENDLY_NAME_PROP_ID))
  771. } // if (PFXHelpAlloc())
  772. } // if (CertGetCertificateContextProperty(CERT_FRIENDLY_NAME_PROP_ID))
  773. } // while (NULL != (pCertContext = CertEnumCertificatesInStore(hCertStore, pCertContext)))
  774. // check to see if the caller passed in a buffer with encough enough space
  775. if (0 == *pcbSafeContents) {
  776. *pcbSafeContents = dwBytesRequired;
  777. goto CommonReturn;
  778. }
  779. else if (*pcbSafeContents < dwBytesRequired) {
  780. *pcbSafeContents = dwBytesRequired;
  781. SetLastError((DWORD) ERROR_MORE_DATA);
  782. goto ErrorReturn;
  783. }
  784. // copy the contents into the callers buffer
  785. // initialize the SAFE_CONTENTS structure that is at the head of the buffer
  786. ZeroMemory(pSafeContents, dwBytesRequired);
  787. pCurrentBufferLocation = ((BYTE *) pSafeContents) + sizeof(SAFE_CONTENTS);
  788. // initialize the callers SAFE_CONTENTS
  789. pSafeContents->cSafeBags = localSafeContents.cSafeBags;
  790. if (0 == localSafeContents.cSafeBags) {
  791. pSafeContents->pSafeBags = NULL;
  792. }
  793. else {
  794. pSafeContents->pSafeBags = (SAFE_BAG *) pCurrentBufferLocation;
  795. }
  796. pCurrentBufferLocation += localSafeContents.cSafeBags * sizeof(SAFE_BAG);
  797. // copy each safe bag in the array
  798. for (i=0; i<localSafeContents.cSafeBags; i++) {
  799. // copy the bag type
  800. pSafeContents->pSafeBags[i].pszBagTypeOID = (LPSTR) pCurrentBufferLocation;
  801. strcpy(pSafeContents->pSafeBags[i].pszBagTypeOID, localSafeContents.pSafeBags[i].pszBagTypeOID);
  802. pCurrentBufferLocation += INFO_LEN_ALIGN(strlen(pSafeContents->pSafeBags[i].pszBagTypeOID) + 1);
  803. // copy the bag contents
  804. pSafeContents->pSafeBags[i].BagContents.cbData = localSafeContents.pSafeBags[i].BagContents.cbData;
  805. pSafeContents->pSafeBags[i].BagContents.pbData = pCurrentBufferLocation;
  806. memcpy(
  807. pSafeContents->pSafeBags[i].BagContents.pbData,
  808. localSafeContents.pSafeBags[i].BagContents.pbData,
  809. pSafeContents->pSafeBags[i].BagContents.cbData);
  810. pCurrentBufferLocation += INFO_LEN_ALIGN(pSafeContents->pSafeBags[i].BagContents.cbData);
  811. // copy the attributes
  812. if (localSafeContents.pSafeBags[i].Attributes.cAttr > 0)
  813. {
  814. pSafeContents->pSafeBags[i].Attributes.cAttr = localSafeContents.pSafeBags[i].Attributes.cAttr;
  815. pSafeContents->pSafeBags[i].Attributes.rgAttr = (PCRYPT_ATTRIBUTE) pCurrentBufferLocation;
  816. pCurrentBufferLocation += pSafeContents->pSafeBags[i].Attributes.cAttr * sizeof(CRYPT_ATTRIBUTE);
  817. for (j=0; j<pSafeContents->pSafeBags[i].Attributes.cAttr; j++) {
  818. // copy the OID of the attribute
  819. pSafeContents->pSafeBags[i].Attributes.rgAttr[j].pszObjId =
  820. (LPSTR) pCurrentBufferLocation;
  821. strcpy(
  822. pSafeContents->pSafeBags[i].Attributes.rgAttr[j].pszObjId,
  823. localSafeContents.pSafeBags[i].Attributes.rgAttr[j].pszObjId);
  824. pCurrentBufferLocation +=
  825. INFO_LEN_ALIGN(strlen(pSafeContents->pSafeBags[i].Attributes.rgAttr[j].pszObjId) + 1);
  826. // copy value count
  827. pSafeContents->pSafeBags[i].Attributes.rgAttr[j].cValue =
  828. localSafeContents.pSafeBags[i].Attributes.rgAttr[j].cValue;
  829. // copy the values
  830. if (pSafeContents->pSafeBags[i].Attributes.rgAttr[j].cValue > 0) {
  831. // setup the array of values
  832. pSafeContents->pSafeBags[i].Attributes.rgAttr[j].rgValue =
  833. (PCRYPT_ATTR_BLOB) pCurrentBufferLocation;
  834. pCurrentBufferLocation +=
  835. pSafeContents->pSafeBags[i].Attributes.rgAttr[j].cValue * sizeof(CRYPT_ATTR_BLOB);
  836. // loop once for each value in the array
  837. for (k=0; k<pSafeContents->pSafeBags[i].Attributes.rgAttr[j].cValue; k++) {
  838. pSafeContents->pSafeBags[i].Attributes.rgAttr[j].rgValue[k].cbData =
  839. localSafeContents.pSafeBags[i].Attributes.rgAttr[j].rgValue[k].cbData;
  840. pSafeContents->pSafeBags[i].Attributes.rgAttr[j].rgValue[k].pbData =
  841. pCurrentBufferLocation;
  842. memcpy(
  843. pSafeContents->pSafeBags[i].Attributes.rgAttr[j].rgValue[k].pbData,
  844. localSafeContents.pSafeBags[i].Attributes.rgAttr[j].rgValue[k].pbData,
  845. pSafeContents->pSafeBags[i].Attributes.rgAttr[j].rgValue[k].cbData);
  846. pCurrentBufferLocation +=
  847. INFO_LEN_ALIGN(pSafeContents->pSafeBags[i].Attributes.rgAttr[j].rgValue[k].cbData);
  848. }
  849. }
  850. else {
  851. pSafeContents->pSafeBags[i].Attributes.rgAttr[j].rgValue = NULL;
  852. }
  853. }
  854. }
  855. else {
  856. pSafeContents->pSafeBags[i].Attributes.cAttr = 0;
  857. pSafeContents->pSafeBags[i].Attributes.rgAttr = NULL;
  858. }
  859. }
  860. goto CommonReturn;
  861. ErrorReturn:
  862. fResult = FALSE;
  863. CommonReturn:
  864. FreeSafeContents(&localSafeContents);
  865. if (pCertContext)
  866. CertFreeCertificateContext(pCertContext);
  867. if (pCryptKeyProvInfo)
  868. PFXHelpFree(pCryptKeyProvInfo);
  869. if (pPrivateKey)
  870. PFXHelpFree(pPrivateKey);
  871. if (pFriendlyName)
  872. PFXHelpFree(pFriendlyName);
  873. if (pwszProviderName)
  874. PFXHelpFree(pwszProviderName);
  875. if (hCryptProv)
  876. {
  877. HRESULT hr = GetLastError();
  878. CryptReleaseContext(hCryptProv, 0);
  879. SetLastError(hr);
  880. }
  881. return fResult;
  882. }
  883. static DWORD ResolveKeySpec(
  884. CRYPT_PRIVATE_KEY_INFO *pPrivateKeyInfo)
  885. {
  886. DWORD i = 0;
  887. DWORD dwKeySpec;
  888. DWORD cbAttribute = 0;
  889. CRYPT_BIT_BLOB *pAttribute = NULL;
  890. PCRYPT_ATTRIBUTES pCryptAttributes = pPrivateKeyInfo->pAttributes;
  891. // set the default keyspec
  892. if ((0 == strcmp(pPrivateKeyInfo->Algorithm.pszObjId, szOID_RSA_RSA)) ||
  893. (0 == strcmp(pPrivateKeyInfo->Algorithm.pszObjId, szOID_ANSI_X942_DH)))
  894. {
  895. dwKeySpec = AT_KEYEXCHANGE;
  896. }
  897. else
  898. {
  899. dwKeySpec = AT_SIGNATURE;
  900. }
  901. if (pCryptAttributes != NULL)
  902. while (i < pCryptAttributes->cAttr) {
  903. if (lstrcmp(pCryptAttributes->rgAttr[i].pszObjId, szOID_KEY_USAGE) == 0) {
  904. if (!CryptDecodeObject(
  905. X509_ASN_ENCODING,
  906. X509_BITS,
  907. pCryptAttributes->rgAttr[i].rgValue->pbData,
  908. pCryptAttributes->rgAttr[i].rgValue->cbData,
  909. 0,
  910. NULL,
  911. &cbAttribute
  912. )) {
  913. i++;
  914. continue;
  915. }
  916. if (NULL == (pAttribute = (CRYPT_BIT_BLOB *) PFXHelpAlloc(cbAttribute))) {
  917. i++;
  918. continue;
  919. }
  920. if (!CryptDecodeObject(
  921. X509_ASN_ENCODING,
  922. X509_BITS,
  923. pCryptAttributes->rgAttr[i].rgValue->pbData,
  924. pCryptAttributes->rgAttr[i].rgValue->cbData,
  925. 0,
  926. pAttribute,
  927. &cbAttribute
  928. )) {
  929. i++;
  930. PFXHelpFree(pAttribute);
  931. continue;
  932. }
  933. if ((pAttribute->pbData[0] & CERT_KEY_ENCIPHERMENT_KEY_USAGE) ||
  934. (pAttribute->pbData[0] & CERT_DATA_ENCIPHERMENT_KEY_USAGE)) {
  935. dwKeySpec = AT_KEYEXCHANGE;
  936. goto CommonReturn;
  937. }
  938. else if ((pAttribute->pbData[0] & CERT_DIGITAL_SIGNATURE_KEY_USAGE) ||
  939. (pAttribute->pbData[0] & CERT_KEY_CERT_SIGN_KEY_USAGE) ||
  940. (pAttribute->pbData[0] & CERT_CRL_SIGN_KEY_USAGE)) {
  941. dwKeySpec = AT_SIGNATURE;
  942. goto CommonReturn;
  943. }
  944. } // if (lstrcmp(pCryptAttributes->rgAttr[i].pszObjId, szOID_KEY_USAGE) == 0)
  945. i++;
  946. } // while (i < pCryptAttributes->cAttr)
  947. //ErrorReturn:
  948. CommonReturn:
  949. if (pAttribute)
  950. PFXHelpFree(pAttribute);
  951. return dwKeySpec;
  952. }
  953. typedef struct _HCRYPT_QUERY_FUNC_STATE {
  954. DWORD dwSafeBagIndex;
  955. PHCRYPTPROV_QUERY_FUNC phCryptQueryFunc;
  956. LPVOID pVoid;
  957. DWORD dwKeySpec;
  958. DWORD dwPFXImportFlags;
  959. } HCRYPT_QUERY_FUNC_STATE, *PHCRYPT_QUERY_FUNC_STATE;
  960. // this is the callback handler for resolving what HCRYPTPROV should
  961. // be used to import the key to, it is handed in to the ImportPKCS8
  962. // call, and will be called from that context.
  963. // this callback will just turn around and call the callback provided
  964. // when CertImportSafeContents was called.
  965. static BOOL CALLBACK ResolvehCryptFunc(
  966. CRYPT_PRIVATE_KEY_INFO *pPrivateKeyInfo,
  967. HCRYPTPROV *phCryptProv,
  968. LPVOID pVoidResolveFunc)
  969. {
  970. HCRYPT_QUERY_FUNC_STATE *pState = (HCRYPT_QUERY_FUNC_STATE *) pVoidResolveFunc;
  971. // set the dwKeySpec field in the HCRYPT_QUERY_FUNC_STATE structure
  972. // so that the CertImportSafeContents function can use it
  973. pState->dwKeySpec = ResolveKeySpec(pPrivateKeyInfo);
  974. return (pState->phCryptQueryFunc(
  975. pPrivateKeyInfo,
  976. pState->dwSafeBagIndex,
  977. phCryptProv,
  978. pState->pVoid,
  979. pState->dwPFXImportFlags));
  980. }
  981. // this function will seach through two arrays of attributes and find the KeyID
  982. // attributes and see if they match
  983. static BOOL WINAPI KeyIDsMatch(
  984. CRYPT_ATTRIBUTES *pAttr1,
  985. CRYPT_ATTRIBUTES *pAttr2
  986. )
  987. {
  988. BOOL bMatch = FALSE;
  989. BOOL bFound = FALSE;
  990. DWORD i = 0;
  991. DWORD j = 0;
  992. CRYPT_ATTR_BLOB *pDecodedAttr1 = NULL;
  993. DWORD cbDecodedAttr1 = 0;
  994. CRYPT_ATTR_BLOB *pDecodedAttr2 = NULL;
  995. DWORD cbDecodedAttr2 = 0;
  996. // search the first attribute array for a key id
  997. while ((i<pAttr1->cAttr) && (!bFound)) {
  998. if ((strcmp(pAttr1->rgAttr[i].pszObjId, szOID_PKCS_12_LOCAL_KEY_ID) == 0) &&
  999. (pAttr1->rgAttr[i].cValue != 0)){
  1000. bFound = TRUE;
  1001. }
  1002. else {
  1003. i++;
  1004. }
  1005. }
  1006. // check to see if a key id was found
  1007. if (!bFound)
  1008. goto CommonReturn;
  1009. // search the second attribute array for a key id
  1010. bFound = FALSE;
  1011. while ((j<pAttr2->cAttr) && (!bFound)) {
  1012. if ((strcmp(pAttr2->rgAttr[j].pszObjId, szOID_PKCS_12_LOCAL_KEY_ID) == 0) &&
  1013. (pAttr2->rgAttr[j].cValue != 0)) {
  1014. bFound = TRUE;
  1015. }
  1016. else {
  1017. j++;
  1018. }
  1019. }
  1020. // check to see if a key id was found
  1021. if (!bFound)
  1022. goto CommonReturn;
  1023. // decode the values
  1024. if (!CryptDecodeObject(
  1025. X509_ASN_ENCODING,
  1026. X509_OCTET_STRING,
  1027. pAttr1->rgAttr[i].rgValue[0].pbData,
  1028. pAttr1->rgAttr[i].rgValue[0].cbData,
  1029. 0,
  1030. NULL,
  1031. &cbDecodedAttr1
  1032. )) {
  1033. goto ErrorReturn;
  1034. }
  1035. if (NULL == (pDecodedAttr1 = (CRYPT_ATTR_BLOB *) PFXHelpAlloc(cbDecodedAttr1))) {
  1036. goto ErrorReturn;
  1037. }
  1038. if (!CryptDecodeObject(
  1039. X509_ASN_ENCODING,
  1040. X509_OCTET_STRING,
  1041. pAttr1->rgAttr[i].rgValue[0].pbData,
  1042. pAttr1->rgAttr[i].rgValue[0].cbData,
  1043. 0,
  1044. pDecodedAttr1,
  1045. &cbDecodedAttr1
  1046. )) {
  1047. goto ErrorReturn;
  1048. }
  1049. if (!CryptDecodeObject(
  1050. X509_ASN_ENCODING,
  1051. X509_OCTET_STRING,
  1052. pAttr2->rgAttr[j].rgValue[0].pbData,
  1053. pAttr2->rgAttr[j].rgValue[0].cbData,
  1054. 0,
  1055. NULL,
  1056. &cbDecodedAttr2
  1057. )) {
  1058. goto ErrorReturn;
  1059. }
  1060. if (NULL == (pDecodedAttr2 = (CRYPT_ATTR_BLOB *) PFXHelpAlloc(cbDecodedAttr2))) {
  1061. goto ErrorReturn;
  1062. }
  1063. if (!CryptDecodeObject(
  1064. X509_ASN_ENCODING,
  1065. X509_OCTET_STRING,
  1066. pAttr2->rgAttr[j].rgValue[0].pbData,
  1067. pAttr2->rgAttr[j].rgValue[0].cbData,
  1068. 0,
  1069. pDecodedAttr2,
  1070. &cbDecodedAttr2
  1071. )) {
  1072. goto ErrorReturn;
  1073. }
  1074. if ((pDecodedAttr1->cbData == pDecodedAttr2->cbData) &&
  1075. (memcmp(pDecodedAttr1->pbData, pDecodedAttr2->pbData, pDecodedAttr1->cbData) == 0)) {
  1076. bMatch = TRUE;
  1077. }
  1078. goto CommonReturn;
  1079. ErrorReturn:
  1080. bMatch = FALSE;
  1081. CommonReturn:
  1082. if (pDecodedAttr1)
  1083. PFXHelpFree(pDecodedAttr1);
  1084. if (pDecodedAttr2)
  1085. PFXHelpFree(pDecodedAttr2);
  1086. return bMatch;
  1087. }
  1088. // this function will search the attributes array and try to find a
  1089. // FRIENDLY_NAME attribute, if it does it will add it as a property
  1090. // to the given cert context
  1091. static
  1092. BOOL
  1093. WINAPI
  1094. AddFriendlyNameProperty(
  1095. PCCERT_CONTEXT pCertContext,
  1096. CRYPT_ATTRIBUTES *pAttr
  1097. )
  1098. {
  1099. BOOL fReturn = TRUE;
  1100. BOOL bFound = FALSE;
  1101. DWORD i = 0;
  1102. CERT_NAME_VALUE *pFriendlyName = NULL;
  1103. DWORD cbDecodedFriendlyName = 0;
  1104. CRYPT_DATA_BLOB friendlyNameDataBlob;
  1105. // search the attribute array for a FRIENDLY_NAME
  1106. while ((i<pAttr->cAttr) && (!bFound)) {
  1107. if ((strcmp(pAttr->rgAttr[i].pszObjId, szOID_PKCS_12_FRIENDLY_NAME_ATTR) == 0) &&
  1108. (pAttr->rgAttr[i].cValue != 0)){
  1109. bFound = TRUE;
  1110. // try to decode the FRIENDLY_NAME
  1111. if (!CryptDecodeObject(
  1112. X509_ASN_ENCODING,
  1113. X509_UNICODE_ANY_STRING,
  1114. pAttr->rgAttr[i].rgValue[0].pbData,
  1115. pAttr->rgAttr[i].rgValue[0].cbData,
  1116. 0,
  1117. NULL,
  1118. &cbDecodedFriendlyName
  1119. )) {
  1120. goto ErrorReturn;
  1121. }
  1122. if (NULL == (pFriendlyName = (CERT_NAME_VALUE *) PFXHelpAlloc(cbDecodedFriendlyName))) {
  1123. goto ErrorReturn;
  1124. }
  1125. if (!CryptDecodeObject(
  1126. X509_ASN_ENCODING,
  1127. X509_UNICODE_ANY_STRING,
  1128. pAttr->rgAttr[i].rgValue[0].pbData,
  1129. pAttr->rgAttr[i].rgValue[0].cbData,
  1130. 0,
  1131. pFriendlyName,
  1132. &cbDecodedFriendlyName
  1133. )) {
  1134. goto ErrorReturn;
  1135. }
  1136. friendlyNameDataBlob.pbData = pFriendlyName->Value.pbData;
  1137. friendlyNameDataBlob.cbData =
  1138. (wcslen((LPWSTR)friendlyNameDataBlob.pbData) + 1) * sizeof(WCHAR);
  1139. if (!CertSetCertificateContextProperty(
  1140. pCertContext,
  1141. CERT_FRIENDLY_NAME_PROP_ID,
  1142. 0,
  1143. &friendlyNameDataBlob)) {
  1144. goto ErrorReturn;
  1145. }
  1146. }
  1147. else {
  1148. i++;
  1149. }
  1150. }
  1151. goto CommonReturn;
  1152. ErrorReturn:
  1153. fReturn = FALSE;
  1154. CommonReturn:
  1155. if (pFriendlyName)
  1156. PFXHelpFree(pFriendlyName);
  1157. return fReturn;
  1158. }
  1159. static BOOL GetProvType(HCRYPTPROV hCryptProv, DWORD *pdwProvType)
  1160. {
  1161. BOOL fRet = TRUE;
  1162. HCRYPTKEY hCryptKey = NULL;
  1163. PUBLICKEYSTRUC *pKeyBlob = NULL;
  1164. DWORD cbKeyBlob = 0;
  1165. *pdwProvType = 0;
  1166. // get a handle to the keyset to export
  1167. if (!CryptGetUserKey(
  1168. hCryptProv,
  1169. AT_KEYEXCHANGE,
  1170. &hCryptKey))
  1171. if (!CryptGetUserKey(
  1172. hCryptProv,
  1173. AT_SIGNATURE,
  1174. &hCryptKey))
  1175. goto ErrorReturn;
  1176. // export the key set to a CAPI blob
  1177. if (!CryptExportKey(
  1178. hCryptKey,
  1179. 0,
  1180. PUBLICKEYBLOB,
  1181. 0,
  1182. NULL,
  1183. &cbKeyBlob))
  1184. goto ErrorReturn;
  1185. if (NULL == (pKeyBlob = (PUBLICKEYSTRUC *) SSAlloc(cbKeyBlob)))
  1186. goto ErrorReturn;
  1187. if (!CryptExportKey(
  1188. hCryptKey,
  1189. 0,
  1190. PUBLICKEYBLOB,
  1191. 0,
  1192. (BYTE *)pKeyBlob,
  1193. &cbKeyBlob))
  1194. goto ErrorReturn;
  1195. switch (pKeyBlob->aiKeyAlg)
  1196. {
  1197. case CALG_DSS_SIGN:
  1198. *pdwProvType = PROV_DSS_DH;
  1199. break;
  1200. case CALG_RSA_SIGN:
  1201. *pdwProvType = PROV_RSA_SIG;
  1202. break;
  1203. case CALG_RSA_KEYX:
  1204. *pdwProvType = PROV_RSA_FULL;
  1205. break;
  1206. default:
  1207. goto ErrorReturn;
  1208. }
  1209. goto CommonReturn;
  1210. ErrorReturn:
  1211. fRet = FALSE;
  1212. CommonReturn:
  1213. if (hCryptKey)
  1214. {
  1215. DWORD dwErr = GetLastError();
  1216. CryptDestroyKey(hCryptKey);
  1217. SetLastError(dwErr);
  1218. }
  1219. if (pKeyBlob)
  1220. SSFree(pKeyBlob);
  1221. return (fRet);
  1222. }
  1223. //+-------------------------------------------------------------------------
  1224. // hCertStore - handle of the cert store to import the safe contents to
  1225. // SafeContents - pointer to the safe contents to import to the store
  1226. // dwCertAddDisposition - used when importing certificate to the store.
  1227. // for a full explanation of the possible values
  1228. // and their meanings see documentation for
  1229. // CertAddEncodedCertificateToStore
  1230. // ImportSafeCallbackStruct - structure that contains pointers to functions
  1231. // which are callled to get a HCRYPTPROV for import
  1232. // and to decrypt the key if a EncryptPrivateKeyInfo
  1233. // is encountered during import
  1234. // dwFlags - The available flags are:
  1235. // CRYPT_EXPORTABLE
  1236. // this flag is used when importing private keys, for a full
  1237. // explanation please see the documentation for CryptImportKey.
  1238. // CRYPT_USER_PROTECTED
  1239. // this flag is used when importing private keys, for a full
  1240. // explanation please see the documentation for CryptImportKey.
  1241. // CRYPT_MACHINE_KEYSET
  1242. // this flag is used when calling CryptAcquireContext.
  1243. // pvAuxInfo - reserved for future use, must be set to NULL
  1244. //+-------------------------------------------------------------------------
  1245. BOOL WINAPI CertImportSafeContents(
  1246. HCERTSTORE hCertStore, // in
  1247. SAFE_CONTENTS *pSafeContents, // in
  1248. DWORD dwCertAddDisposition, // in
  1249. IMPORT_SAFE_CALLBACK_STRUCT *ImportSafeCallbackStruct, // in
  1250. DWORD dwFlags, // in
  1251. void *pvAuxInfo // in
  1252. )
  1253. {
  1254. BOOL fResult = TRUE;
  1255. DWORD i,j;
  1256. PCCERT_CONTEXT pCertContext = NULL;
  1257. BOOL *pAlreadyInserted = NULL;
  1258. HCRYPT_QUERY_FUNC_STATE stateStruct;
  1259. CRYPT_PKCS8_IMPORT_PARAMS PrivateKeyBlobAndParams;
  1260. HCRYPTPROV hCryptProv = NULL;
  1261. CRYPT_KEY_PROV_INFO cryptKeyProvInfo;
  1262. LPSTR pszContainerName = NULL;
  1263. DWORD cbContainerName = 0;
  1264. LPSTR pszProviderName = NULL;
  1265. DWORD cbProviderName = 0;
  1266. DWORD dwProvType;
  1267. DWORD cbProvType = sizeof(DWORD);
  1268. DWORD dwNumWideChars = 0;
  1269. BYTE *pbEncodedCert = NULL;
  1270. DWORD cbEncodedCert = 0;
  1271. DWORD dwKeySetType;
  1272. DWORD cbKeySetType = sizeof(DWORD);
  1273. ZeroMemory(&cryptKeyProvInfo, sizeof(CRYPT_KEY_PROV_INFO));
  1274. // validate parameters
  1275. if (pvAuxInfo != NULL) {
  1276. SetLastError((DWORD)ERROR_INVALID_PARAMETER);
  1277. goto ErrorReturn;
  1278. }
  1279. // set up the pAlreadyInserted array so that it has an entry for each safe
  1280. // bag and all entries are set to false. this is used so that the certificates
  1281. // can be imported at the same time their corresponding private keys are imported
  1282. if (NULL == (pAlreadyInserted = (BOOL *) PFXHelpAlloc(sizeof(BOOL) * pSafeContents->cSafeBags))) {
  1283. goto ErrorReturn;
  1284. }
  1285. else {
  1286. for (i=0; i<pSafeContents->cSafeBags; i++) {
  1287. pAlreadyInserted[i] = FALSE;
  1288. }
  1289. }
  1290. // loop for each safe bag and import it if it is a private key
  1291. for (i=0; i<pSafeContents->cSafeBags; i++) {
  1292. // check to see if it is a cert or a key
  1293. if ((strcmp(pSafeContents->pSafeBags[i].pszBagTypeOID, szOID_PKCS_12_KEY_BAG) == 0) ||
  1294. (strcmp(pSafeContents->pSafeBags[i].pszBagTypeOID, szOID_PKCS_12_SHROUDEDKEY_BAG) == 0)) {
  1295. // set up the stateStruct so when the hCryptQueryFunc is called when can make
  1296. // our callback
  1297. stateStruct.dwSafeBagIndex = i;
  1298. stateStruct.phCryptQueryFunc = ImportSafeCallbackStruct->phCryptProvQueryFunc;
  1299. stateStruct.pVoid = ImportSafeCallbackStruct->pVoidhCryptProvQuery;
  1300. stateStruct.dwPFXImportFlags = dwFlags;
  1301. // import the private key
  1302. PrivateKeyBlobAndParams.PrivateKey.pbData = pSafeContents->pSafeBags[i].BagContents.pbData;
  1303. PrivateKeyBlobAndParams.PrivateKey.cbData = pSafeContents->pSafeBags[i].BagContents.cbData;
  1304. PrivateKeyBlobAndParams.pResolvehCryptProvFunc = ResolvehCryptFunc;
  1305. PrivateKeyBlobAndParams.pVoidResolveFunc = (LPVOID) &stateStruct;
  1306. PrivateKeyBlobAndParams.pDecryptPrivateKeyFunc = ImportSafeCallbackStruct->pDecryptPrivateKeyFunc;
  1307. PrivateKeyBlobAndParams.pVoidDecryptFunc = ImportSafeCallbackStruct->pVoidDecryptFunc;
  1308. if (!CryptImportPKCS8(
  1309. PrivateKeyBlobAndParams,
  1310. dwFlags,
  1311. &hCryptProv,
  1312. NULL)) {
  1313. goto ErrorReturn;
  1314. }
  1315. pAlreadyInserted[i] = TRUE;
  1316. // now look at each safe bag and see if it contains a cert with a KeyID that
  1317. // matches the private key that we just imported
  1318. for (j=0; j<pSafeContents->cSafeBags; j++) {
  1319. if ((strcmp(pSafeContents->pSafeBags[j].pszBagTypeOID, szOID_PKCS_12_CERT_BAG) == 0) &&
  1320. (!pAlreadyInserted[j]) &&
  1321. (KeyIDsMatch(&pSafeContents->pSafeBags[i].Attributes, &pSafeContents->pSafeBags[j].Attributes))){
  1322. // extract the encoded cert from an encoded cert bag
  1323. pbEncodedCert = NULL;
  1324. cbEncodedCert = 0;
  1325. if (!GetEncodedCertFromEncodedCertBag(
  1326. pSafeContents->pSafeBags[j].BagContents.pbData,
  1327. pSafeContents->pSafeBags[j].BagContents.cbData,
  1328. NULL,
  1329. &cbEncodedCert)) {
  1330. goto ErrorReturn;
  1331. }
  1332. if (NULL == (pbEncodedCert = (BYTE *) PFXHelpAlloc(cbEncodedCert))) {
  1333. goto ErrorReturn;
  1334. }
  1335. if (!GetEncodedCertFromEncodedCertBag(
  1336. pSafeContents->pSafeBags[j].BagContents.pbData,
  1337. pSafeContents->pSafeBags[j].BagContents.cbData,
  1338. pbEncodedCert,
  1339. &cbEncodedCert)) {
  1340. PFXHelpFree(pbEncodedCert);
  1341. goto ErrorReturn;
  1342. }
  1343. // insert the X509 cert blob into the store
  1344. if (!CertAddEncodedCertificateToStore(
  1345. hCertStore,
  1346. X509_ASN_ENCODING,
  1347. pbEncodedCert,
  1348. cbEncodedCert,
  1349. dwCertAddDisposition,
  1350. &pCertContext)) {
  1351. PFXHelpFree(pbEncodedCert);
  1352. goto ErrorReturn;
  1353. }
  1354. // we don't need this anymore
  1355. PFXHelpFree(pbEncodedCert);
  1356. if (!AddFriendlyNameProperty(
  1357. pCertContext,
  1358. &pSafeContents->pSafeBags[j].Attributes)) {
  1359. goto ErrorReturn;
  1360. }
  1361. // get information needed to set up a connection between the
  1362. // certificate and private key
  1363. if (!CryptGetProvParam(
  1364. hCryptProv,
  1365. PP_CONTAINER,
  1366. NULL,
  1367. &cbContainerName,
  1368. 0))
  1369. goto ErrorReturn;
  1370. if (NULL == (pszContainerName =
  1371. (LPSTR) PFXHelpAlloc(cbContainerName)))
  1372. goto ErrorReturn;
  1373. if (!CryptGetProvParam(
  1374. hCryptProv,
  1375. PP_CONTAINER,
  1376. (BYTE *) pszContainerName,
  1377. &cbContainerName,
  1378. 0))
  1379. goto ErrorReturn;
  1380. if (!CryptGetProvParam(
  1381. hCryptProv,
  1382. PP_NAME,
  1383. NULL,
  1384. &cbProviderName,
  1385. 0))
  1386. goto ErrorReturn;
  1387. if (NULL == (pszProviderName =
  1388. (LPSTR) PFXHelpAlloc(cbProviderName)))
  1389. goto ErrorReturn;
  1390. if (!CryptGetProvParam(
  1391. hCryptProv,
  1392. PP_NAME,
  1393. (BYTE *) pszProviderName,
  1394. &cbProviderName,
  1395. 0))
  1396. goto ErrorReturn;
  1397. if (!CryptGetProvParam(
  1398. hCryptProv,
  1399. PP_PROVTYPE,
  1400. (BYTE *) &dwProvType,
  1401. &cbProvType,
  1402. 0)) {
  1403. // we couldn't get the information from the provider
  1404. // so try to figure it out ourselves
  1405. if (!GetProvType(hCryptProv, &dwProvType))
  1406. {
  1407. goto ErrorReturn;
  1408. }
  1409. }
  1410. // convert strings to wide chars
  1411. dwNumWideChars = MultiByteToWideChar(
  1412. CP_ACP,
  1413. 0,
  1414. pszContainerName,
  1415. -1,
  1416. NULL,
  1417. 0);
  1418. if (NULL == (cryptKeyProvInfo.pwszContainerName = (LPWSTR)
  1419. PFXHelpAlloc(dwNumWideChars * sizeof(WCHAR)))) {
  1420. goto ErrorReturn;
  1421. }
  1422. if (!MultiByteToWideChar(
  1423. CP_ACP,
  1424. 0,
  1425. pszContainerName,
  1426. -1,
  1427. cryptKeyProvInfo.pwszContainerName,
  1428. dwNumWideChars)) {
  1429. goto ErrorReturn;
  1430. }
  1431. dwNumWideChars = MultiByteToWideChar(
  1432. CP_ACP,
  1433. 0,
  1434. pszProviderName,
  1435. -1,
  1436. NULL,
  1437. 0);
  1438. if (NULL == (cryptKeyProvInfo.pwszProvName = (LPWSTR)
  1439. PFXHelpAlloc(dwNumWideChars * sizeof(WCHAR)))) {
  1440. goto ErrorReturn;
  1441. }
  1442. if (!MultiByteToWideChar(
  1443. CP_ACP,
  1444. 0,
  1445. pszProviderName,
  1446. -1,
  1447. cryptKeyProvInfo.pwszProvName,
  1448. dwNumWideChars)) {
  1449. goto ErrorReturn;
  1450. }
  1451. cryptKeyProvInfo.dwProvType = dwProvType;
  1452. if (CryptGetProvParam(
  1453. hCryptProv,
  1454. PP_KEYSET_TYPE,
  1455. (BYTE *) &dwKeySetType,
  1456. &cbKeySetType,
  1457. 0)) {
  1458. if (CRYPT_MACHINE_KEYSET == dwKeySetType)
  1459. {
  1460. cryptKeyProvInfo.dwFlags = CRYPT_MACHINE_KEYSET;
  1461. }
  1462. }
  1463. // the dwKeySpec field was set by the callback generated from the
  1464. // CryptImportPKCS8 call. the callback is currently used to because at
  1465. // the point the callback is made the private key has been decoded and
  1466. // the attributes are available, one of which is the key usage attribute.
  1467. // FIX - in the future we should be able to call CryptGetProvParam to get
  1468. // the dwKeySpec, right now that is not supported.
  1469. cryptKeyProvInfo.dwKeySpec = stateStruct.dwKeySpec;
  1470. // set up a property to point to the private key
  1471. if (!CertSetCertificateContextProperty(
  1472. pCertContext,
  1473. CERT_KEY_PROV_INFO_PROP_ID,
  1474. 0,
  1475. (void *) &cryptKeyProvInfo)) {
  1476. CertFreeCertificateContext(pCertContext);
  1477. goto ErrorReturn;
  1478. }
  1479. CertFreeCertificateContext(pCertContext);
  1480. pAlreadyInserted[j] = TRUE;
  1481. }
  1482. } // for (j=0; j<pSafeContents->cSafeBags; j++)
  1483. } // if (strcmp(pSafeContents->pSafeBags[i].pszBagTypeOID, szOID_PKCS_12_KEY_BAG) == 0)
  1484. } // for (i=0; i<pSafeContents->cSafeBags; i++)
  1485. // now loop for each safe bag again and import the certificates which didn't have private keys
  1486. for (i=0; i<pSafeContents->cSafeBags; i++) {
  1487. // if the certificate has not been inserted, then do it
  1488. if (!pAlreadyInserted[i]) {
  1489. // extract the encoded cert from an encoded cert bag
  1490. pbEncodedCert = NULL;
  1491. cbEncodedCert = 0;
  1492. if (!GetEncodedCertFromEncodedCertBag(
  1493. pSafeContents->pSafeBags[i].BagContents.pbData,
  1494. pSafeContents->pSafeBags[i].BagContents.cbData,
  1495. NULL,
  1496. &cbEncodedCert)) {
  1497. goto ErrorReturn;
  1498. }
  1499. if (NULL == (pbEncodedCert = (BYTE *) PFXHelpAlloc(cbEncodedCert))) {
  1500. goto ErrorReturn;
  1501. }
  1502. if (!GetEncodedCertFromEncodedCertBag(
  1503. pSafeContents->pSafeBags[i].BagContents.pbData,
  1504. pSafeContents->pSafeBags[i].BagContents.cbData,
  1505. pbEncodedCert,
  1506. &cbEncodedCert)) {
  1507. PFXHelpFree(pbEncodedCert);
  1508. goto ErrorReturn;
  1509. }
  1510. if (!CertAddEncodedCertificateToStore(
  1511. hCertStore,
  1512. X509_ASN_ENCODING,
  1513. pbEncodedCert,
  1514. cbEncodedCert,
  1515. dwCertAddDisposition,
  1516. &pCertContext)) {
  1517. PFXHelpFree(pbEncodedCert);
  1518. goto ErrorReturn;
  1519. }
  1520. // we don't need this anymore
  1521. PFXHelpFree(pbEncodedCert);
  1522. if (!AddFriendlyNameProperty(
  1523. pCertContext,
  1524. &pSafeContents->pSafeBags[i].Attributes)) {
  1525. goto ErrorReturn;
  1526. }
  1527. CertFreeCertificateContext(pCertContext);
  1528. }
  1529. }
  1530. goto CommonReturn;
  1531. ErrorReturn:
  1532. fResult = FALSE;
  1533. CommonReturn:
  1534. if (pAlreadyInserted)
  1535. PFXHelpFree(pAlreadyInserted);
  1536. if (pszContainerName)
  1537. PFXHelpFree(pszContainerName);
  1538. if (pszProviderName)
  1539. PFXHelpFree(pszProviderName);
  1540. if (cryptKeyProvInfo.pwszContainerName)
  1541. PFXHelpFree(cryptKeyProvInfo.pwszContainerName);
  1542. if (cryptKeyProvInfo.pwszProvName)
  1543. PFXHelpFree(cryptKeyProvInfo.pwszProvName);
  1544. if (hCryptProv)
  1545. {
  1546. HRESULT hr = GetLastError();
  1547. CryptReleaseContext(hCryptProv, 0);
  1548. SetLastError(hr);
  1549. }
  1550. return fResult;
  1551. }