PageRenderTime 62ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

/security/nss/lib/pkcs12/p12exp.c

https://bitbucket.org/soko/mozilla-central
C | 1410 lines | 1047 code | 178 blank | 185 comment | 413 complexity | 7a80aab65d5cf42829d9b970698e49b1 MD5 | raw file
Possible License(s): GPL-2.0, JSON, 0BSD, LGPL-3.0, AGPL-1.0, MIT, MPL-2.0-no-copyleft-exception, BSD-3-Clause, LGPL-2.1, Apache-2.0
  1. /* ***** BEGIN LICENSE BLOCK *****
  2. * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  3. *
  4. * The contents of this file are subject to the Mozilla Public License Version
  5. * 1.1 (the "License"); you may not use this file except in compliance with
  6. * the License. You may obtain a copy of the License at
  7. * http://www.mozilla.org/MPL/
  8. *
  9. * Software distributed under the License is distributed on an "AS IS" basis,
  10. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11. * for the specific language governing rights and limitations under the
  12. * License.
  13. *
  14. * The Original Code is the Netscape security libraries.
  15. *
  16. * The Initial Developer of the Original Code is
  17. * Netscape Communications Corporation.
  18. * Portions created by the Initial Developer are Copyright (C) 1994-2000
  19. * the Initial Developer. All Rights Reserved.
  20. *
  21. * Contributor(s):
  22. *
  23. * Alternatively, the contents of this file may be used under the terms of
  24. * either the GNU General Public License Version 2 or later (the "GPL"), or
  25. * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  26. * in which case the provisions of the GPL or the LGPL are applicable instead
  27. * of those above. If you wish to allow use of your version of this file only
  28. * under the terms of either the GPL or the LGPL, and not to allow others to
  29. * use your version of this file under the terms of the MPL, indicate your
  30. * decision by deleting the provisions above and replace them with the notice
  31. * and other provisions required by the GPL or the LGPL. If you do not delete
  32. * the provisions above, a recipient may use your version of this file under
  33. * the terms of any one of the MPL, the GPL or the LGPL.
  34. *
  35. * ***** END LICENSE BLOCK ***** */
  36. #include "plarena.h"
  37. #include "secitem.h"
  38. #include "secoid.h"
  39. #include "seccomon.h"
  40. #include "secport.h"
  41. #include "cert.h"
  42. #include "pkcs12.h"
  43. #include "p12local.h"
  44. #include "secpkcs7.h"
  45. #include "secasn1.h"
  46. #include "secerr.h"
  47. #include "p12plcy.h"
  48. /* release the memory taken up by the list of nicknames */
  49. static void
  50. sec_pkcs12_destroy_nickname_list(SECItem **nicknames)
  51. {
  52. int i = 0;
  53. if(nicknames == NULL) {
  54. return;
  55. }
  56. while(nicknames[i] != NULL) {
  57. SECITEM_FreeItem(nicknames[i], PR_FALSE);
  58. i++;
  59. }
  60. PORT_Free(nicknames);
  61. }
  62. /* release the memory taken up by the list of certificates */
  63. static void
  64. sec_pkcs12_destroy_certificate_list(CERTCertificate **ref_certs)
  65. {
  66. int i = 0;
  67. if(ref_certs == NULL) {
  68. return;
  69. }
  70. while(ref_certs[i] != NULL) {
  71. CERT_DestroyCertificate(ref_certs[i]);
  72. i++;
  73. }
  74. }
  75. static void
  76. sec_pkcs12_destroy_cinfos_for_cert_bags(SEC_PKCS12CertAndCRLBag *certBag)
  77. {
  78. int j = 0;
  79. j = 0;
  80. while(certBag->certAndCRLs[j] != NULL) {
  81. SECOidTag certType = SECOID_FindOIDTag(&certBag->certAndCRLs[j]->BagID);
  82. if(certType == SEC_OID_PKCS12_X509_CERT_CRL_BAG) {
  83. SEC_PKCS12X509CertCRL *x509;
  84. x509 = certBag->certAndCRLs[j]->value.x509;
  85. SEC_PKCS7DestroyContentInfo(&x509->certOrCRL);
  86. }
  87. j++;
  88. }
  89. }
  90. /* destroy all content infos since they were not allocated in common
  91. * pool
  92. */
  93. static void
  94. sec_pkcs12_destroy_cert_content_infos(SEC_PKCS12SafeContents *safe,
  95. SEC_PKCS12Baggage *baggage)
  96. {
  97. int i, j;
  98. if((safe != NULL) && (safe->contents != NULL)) {
  99. i = 0;
  100. while(safe->contents[i] != NULL) {
  101. SECOidTag bagType = SECOID_FindOIDTag(&safe->contents[i]->safeBagType);
  102. if(bagType == SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID) {
  103. SEC_PKCS12CertAndCRLBag *certBag;
  104. certBag = safe->contents[i]->safeContent.certAndCRLBag;
  105. sec_pkcs12_destroy_cinfos_for_cert_bags(certBag);
  106. }
  107. i++;
  108. }
  109. }
  110. if((baggage != NULL) && (baggage->bags != NULL)) {
  111. i = 0;
  112. while(baggage->bags[i] != NULL) {
  113. if(baggage->bags[i]->unencSecrets != NULL) {
  114. j = 0;
  115. while(baggage->bags[i]->unencSecrets[j] != NULL) {
  116. SECOidTag bagType;
  117. bagType = SECOID_FindOIDTag(&baggage->bags[i]->unencSecrets[j]->safeBagType);
  118. if(bagType == SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID) {
  119. SEC_PKCS12CertAndCRLBag *certBag;
  120. certBag = baggage->bags[i]->unencSecrets[j]->safeContent.certAndCRLBag;
  121. sec_pkcs12_destroy_cinfos_for_cert_bags(certBag);
  122. }
  123. j++;
  124. }
  125. }
  126. i++;
  127. }
  128. }
  129. }
  130. /* convert the nickname list from a NULL termincated Char list
  131. * to a NULL terminated SECItem list
  132. */
  133. static SECItem **
  134. sec_pkcs12_convert_nickname_list(char **nicknames)
  135. {
  136. SECItem **nicks;
  137. int i, j;
  138. PRBool error = PR_FALSE;
  139. if(nicknames == NULL) {
  140. return NULL;
  141. }
  142. i = j = 0;
  143. while(nicknames[i] != NULL) {
  144. i++;
  145. }
  146. /* allocate the space and copy the data */
  147. nicks = (SECItem **)PORT_ZAlloc(sizeof(SECItem *) * (i + 1));
  148. if(nicks != NULL) {
  149. for(j = 0; ((j < i) && (error == PR_FALSE)); j++) {
  150. nicks[j] = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
  151. if(nicks[j] != NULL) {
  152. nicks[j]->data =
  153. (unsigned char *)PORT_ZAlloc(PORT_Strlen(nicknames[j])+1);
  154. if(nicks[j]->data != NULL) {
  155. nicks[j]->len = PORT_Strlen(nicknames[j]);
  156. PORT_Memcpy(nicks[j]->data, nicknames[j], nicks[j]->len);
  157. nicks[j]->data[nicks[j]->len] = 0;
  158. } else {
  159. error = PR_TRUE;
  160. }
  161. } else {
  162. error = PR_TRUE;
  163. }
  164. }
  165. }
  166. if(error == PR_TRUE) {
  167. for(i = 0; i < j; i++) {
  168. SECITEM_FreeItem(nicks[i], PR_TRUE);
  169. }
  170. PORT_Free(nicks);
  171. nicks = NULL;
  172. }
  173. return nicks;
  174. }
  175. /* package the certificate add_cert into PKCS12 structures,
  176. * retrieve the certificate chain for the cert and return
  177. * the packaged contents.
  178. * poolp -- common memory pool;
  179. * add_cert -- certificate to package up
  180. * nickname for the certificate
  181. * a return of NULL indicates an error
  182. */
  183. static SEC_PKCS12CertAndCRL *
  184. sec_pkcs12_get_cert(PRArenaPool *poolp,
  185. CERTCertificate *add_cert,
  186. SECItem *nickname)
  187. {
  188. SEC_PKCS12CertAndCRL *cert;
  189. SEC_PKCS7ContentInfo *cinfo;
  190. SGNDigestInfo *t_di;
  191. void *mark;
  192. SECStatus rv;
  193. if((poolp == NULL) || (add_cert == NULL) || (nickname == NULL)) {
  194. return NULL;
  195. }
  196. mark = PORT_ArenaMark(poolp);
  197. cert = sec_pkcs12_new_cert_crl(poolp, SEC_OID_PKCS12_X509_CERT_CRL_BAG);
  198. if(cert != NULL) {
  199. /* copy the nickname */
  200. rv = SECITEM_CopyItem(poolp, &cert->nickname, nickname);
  201. if(rv != SECSuccess) {
  202. PORT_SetError(SEC_ERROR_NO_MEMORY);
  203. cert = NULL;
  204. } else {
  205. /* package the certificate and cert chain into a NULL signer
  206. * PKCS 7 SignedData content Info and prepare it for encoding
  207. * since we cannot use DER_ANY_TEMPLATE
  208. */
  209. cinfo = SEC_PKCS7CreateCertsOnly(add_cert, PR_TRUE, NULL);
  210. rv = SEC_PKCS7PrepareForEncode(cinfo, NULL, NULL, NULL);
  211. /* thumbprint the certificate */
  212. if((cinfo != NULL) && (rv == SECSuccess))
  213. {
  214. PORT_Memcpy(&cert->value.x509->certOrCRL, cinfo, sizeof(*cinfo));
  215. t_di = sec_pkcs12_compute_thumbprint(&add_cert->derCert);
  216. if(t_di != NULL)
  217. {
  218. /* test */
  219. rv = SGN_CopyDigestInfo(poolp, &cert->value.x509->thumbprint,
  220. t_di);
  221. if(rv != SECSuccess) {
  222. cert = NULL;
  223. PORT_SetError(SEC_ERROR_NO_MEMORY);
  224. }
  225. SGN_DestroyDigestInfo(t_di);
  226. }
  227. else
  228. cert = NULL;
  229. }
  230. }
  231. }
  232. if (cert == NULL) {
  233. PORT_ArenaRelease(poolp, mark);
  234. } else {
  235. PORT_ArenaUnmark(poolp, mark);
  236. }
  237. return cert;
  238. }
  239. /* package the private key associated with the certificate and
  240. * return the appropriate PKCS 12 structure
  241. * poolp common memory pool
  242. * nickname key nickname
  243. * cert -- cert to look up
  244. * wincx -- window handle
  245. * an error is indicated by a return of NULL
  246. */
  247. static SEC_PKCS12PrivateKey *
  248. sec_pkcs12_get_private_key(PRArenaPool *poolp,
  249. SECItem *nickname,
  250. CERTCertificate *cert,
  251. void *wincx)
  252. {
  253. SECKEYPrivateKeyInfo *pki;
  254. SEC_PKCS12PrivateKey *pk;
  255. SECStatus rv;
  256. void *mark;
  257. if((poolp == NULL) || (nickname == NULL)) {
  258. return NULL;
  259. }
  260. mark = PORT_ArenaMark(poolp);
  261. /* retrieve key from the data base */
  262. pki = PK11_ExportPrivateKeyInfo(nickname, cert, wincx);
  263. if(pki == NULL) {
  264. PORT_ArenaRelease(poolp, mark);
  265. PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY);
  266. return NULL;
  267. }
  268. pk = (SEC_PKCS12PrivateKey *)PORT_ArenaZAlloc(poolp,
  269. sizeof(SEC_PKCS12PrivateKey));
  270. if(pk != NULL) {
  271. rv = sec_pkcs12_init_pvk_data(poolp, &pk->pvkData);
  272. if(rv == SECSuccess) {
  273. /* copy the key into poolp memory space */
  274. rv = SECKEY_CopyPrivateKeyInfo(poolp, &pk->pkcs8data, pki);
  275. if(rv == SECSuccess) {
  276. rv = SECITEM_CopyItem(poolp, &pk->pvkData.nickname, nickname);
  277. }
  278. }
  279. if(rv != SECSuccess) {
  280. PORT_SetError(SEC_ERROR_NO_MEMORY);
  281. pk = NULL;
  282. }
  283. } else {
  284. PORT_SetError(SEC_ERROR_NO_MEMORY);
  285. }
  286. /* destroy private key, zeroing out data */
  287. SECKEY_DestroyPrivateKeyInfo(pki, PR_TRUE);
  288. if (pk == NULL) {
  289. PORT_ArenaRelease(poolp, mark);
  290. } else {
  291. PORT_ArenaUnmark(poolp, mark);
  292. }
  293. return pk;
  294. }
  295. /* get a shrouded key item associated with a certificate
  296. * return the appropriate PKCS 12 structure
  297. * poolp common memory pool
  298. * nickname key nickname
  299. * cert -- cert to look up
  300. * wincx -- window handle
  301. * an error is indicated by a return of NULL
  302. */
  303. static SEC_PKCS12ESPVKItem *
  304. sec_pkcs12_get_shrouded_key(PRArenaPool *poolp,
  305. SECItem *nickname,
  306. CERTCertificate *cert,
  307. SECOidTag algorithm,
  308. SECItem *pwitem,
  309. PKCS12UnicodeConvertFunction unicodeFn,
  310. void *wincx)
  311. {
  312. SECKEYEncryptedPrivateKeyInfo *epki;
  313. SEC_PKCS12ESPVKItem *pk;
  314. void *mark;
  315. SECStatus rv;
  316. PK11SlotInfo *slot = NULL;
  317. PRBool swapUnicodeBytes = PR_FALSE;
  318. #ifdef IS_LITTLE_ENDIAN
  319. swapUnicodeBytes = PR_TRUE;
  320. #endif
  321. if((poolp == NULL) || (nickname == NULL))
  322. return NULL;
  323. mark = PORT_ArenaMark(poolp);
  324. /* use internal key slot */
  325. slot = PK11_GetInternalKeySlot();
  326. /* retrieve encrypted prviate key */
  327. epki = PK11_ExportEncryptedPrivateKeyInfo(slot, algorithm, pwitem,
  328. nickname, cert, 1, 0, NULL);
  329. PK11_FreeSlot(slot);
  330. if(epki == NULL) {
  331. PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY);
  332. PORT_ArenaRelease(poolp, mark);
  333. return NULL;
  334. }
  335. /* create a private key and store the data into the poolp memory space */
  336. pk = sec_pkcs12_create_espvk(poolp, SEC_OID_PKCS12_PKCS8_KEY_SHROUDING);
  337. if(pk != NULL) {
  338. rv = sec_pkcs12_init_pvk_data(poolp, &pk->espvkData);
  339. rv = SECITEM_CopyItem(poolp, &pk->espvkData.nickname, nickname);
  340. pk->espvkCipherText.pkcs8KeyShroud =
  341. (SECKEYEncryptedPrivateKeyInfo *)PORT_ArenaZAlloc(poolp,
  342. sizeof(SECKEYEncryptedPrivateKeyInfo));
  343. if((pk->espvkCipherText.pkcs8KeyShroud != NULL) && (rv == SECSuccess)) {
  344. rv = SECKEY_CopyEncryptedPrivateKeyInfo(poolp,
  345. pk->espvkCipherText.pkcs8KeyShroud, epki);
  346. if(rv == SECSuccess) {
  347. rv = (*unicodeFn)(poolp, &pk->espvkData.uniNickName, nickname,
  348. PR_TRUE, swapUnicodeBytes);
  349. }
  350. }
  351. if(rv != SECSuccess) {
  352. PORT_SetError(SEC_ERROR_NO_MEMORY);
  353. pk = NULL;
  354. }
  355. }
  356. SECKEY_DestroyEncryptedPrivateKeyInfo(epki, PR_TRUE);
  357. if(pk == NULL) {
  358. PORT_ArenaRelease(poolp, mark);
  359. } else {
  360. PORT_ArenaUnmark(poolp, mark);
  361. }
  362. return pk;
  363. }
  364. /* add a thumbprint to a private key associated certs list
  365. * pvk is the area where the list is stored
  366. * thumb is the thumbprint to copy
  367. * a return of SECFailure indicates an error
  368. */
  369. static SECStatus
  370. sec_pkcs12_add_thumbprint(SEC_PKCS12PVKSupportingData *pvk,
  371. SGNDigestInfo *thumb)
  372. {
  373. SGNDigestInfo **thumb_list = NULL;
  374. int nthumbs, size;
  375. void *mark, *dummy;
  376. SECStatus rv = SECFailure;
  377. if((pvk == NULL) || (thumb == NULL)) {
  378. return SECFailure;
  379. }
  380. mark = PORT_ArenaMark(pvk->poolp);
  381. thumb_list = pvk->assocCerts;
  382. nthumbs = pvk->nThumbs;
  383. /* allocate list space needed -- either growing or allocating
  384. * list must be NULL terminated
  385. */
  386. size = sizeof(SGNDigestInfo *);
  387. dummy = PORT_ArenaGrow(pvk->poolp, thumb_list, (size * (nthumbs + 1)),
  388. (size * (nthumbs + 2)));
  389. thumb_list = dummy;
  390. if(dummy != NULL) {
  391. thumb_list[nthumbs] = (SGNDigestInfo *)PORT_ArenaZAlloc(pvk->poolp,
  392. sizeof(SGNDigestInfo));
  393. if(thumb_list[nthumbs] != NULL) {
  394. SGN_CopyDigestInfo(pvk->poolp, thumb_list[nthumbs], thumb);
  395. nthumbs += 1;
  396. thumb_list[nthumbs] = 0;
  397. } else {
  398. dummy = NULL;
  399. }
  400. }
  401. if(dummy == NULL) {
  402. PORT_ArenaRelease(pvk->poolp, mark);
  403. return SECFailure;
  404. }
  405. pvk->assocCerts = thumb_list;
  406. pvk->nThumbs = nthumbs;
  407. PORT_ArenaUnmark(pvk->poolp, mark);
  408. return SECSuccess;
  409. }
  410. /* search the list of shrouded keys in the baggage for the desired
  411. * name. return a pointer to the item. a return of NULL indicates
  412. * that no match was present or that an error occurred.
  413. */
  414. static SEC_PKCS12ESPVKItem *
  415. sec_pkcs12_get_espvk_by_name(SEC_PKCS12Baggage *luggage,
  416. SECItem *name)
  417. {
  418. PRBool found = PR_FALSE;
  419. SEC_PKCS12ESPVKItem *espvk = NULL;
  420. int i, j;
  421. SECComparison rv = SECEqual;
  422. SECItem *t_name;
  423. SEC_PKCS12BaggageItem *bag;
  424. if((luggage == NULL) || (name == NULL)) {
  425. return NULL;
  426. }
  427. i = 0;
  428. while((found == PR_FALSE) && (i < luggage->luggage_size)) {
  429. j = 0;
  430. bag = luggage->bags[i];
  431. while((found == PR_FALSE) && (j < bag->nEspvks)) {
  432. espvk = bag->espvks[j];
  433. if(espvk->poolp == NULL) {
  434. espvk->poolp = luggage->poolp;
  435. }
  436. t_name = SECITEM_DupItem(&espvk->espvkData.nickname);
  437. if(t_name != NULL) {
  438. rv = SECITEM_CompareItem(name, t_name);
  439. if(rv == SECEqual) {
  440. found = PR_TRUE;
  441. }
  442. SECITEM_FreeItem(t_name, PR_TRUE);
  443. } else {
  444. PORT_SetError(SEC_ERROR_NO_MEMORY);
  445. return NULL;
  446. }
  447. j++;
  448. }
  449. i++;
  450. }
  451. if(found != PR_TRUE) {
  452. PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_LOCATE_OBJECT_BY_NAME);
  453. return NULL;
  454. }
  455. return espvk;
  456. }
  457. /* locates a certificate and copies the thumbprint to the
  458. * appropriate private key
  459. */
  460. static SECStatus
  461. sec_pkcs12_propagate_thumbprints(SECItem **nicknames,
  462. CERTCertificate **ref_certs,
  463. SEC_PKCS12SafeContents *safe,
  464. SEC_PKCS12Baggage *baggage)
  465. {
  466. SEC_PKCS12CertAndCRL *cert;
  467. SEC_PKCS12PrivateKey *key;
  468. SEC_PKCS12ESPVKItem *espvk;
  469. int i;
  470. PRBool error = PR_FALSE;
  471. SECStatus rv = SECFailure;
  472. if((nicknames == NULL) || (safe == NULL)) {
  473. return SECFailure;
  474. }
  475. i = 0;
  476. while((nicknames[i] != NULL) && (error == PR_FALSE)) {
  477. /* process all certs */
  478. cert = (SEC_PKCS12CertAndCRL *)sec_pkcs12_find_object(safe, baggage,
  479. SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID,
  480. nicknames[i], NULL);
  481. if(cert != NULL) {
  482. /* locate key and copy thumbprint */
  483. key = (SEC_PKCS12PrivateKey *)sec_pkcs12_find_object(safe, baggage,
  484. SEC_OID_PKCS12_KEY_BAG_ID,
  485. nicknames[i], NULL);
  486. if(key != NULL) {
  487. key->pvkData.poolp = key->poolp;
  488. rv = sec_pkcs12_add_thumbprint(&key->pvkData,
  489. &cert->value.x509->thumbprint);
  490. if(rv == SECFailure)
  491. error = PR_TRUE; /* XXX Set error? */
  492. }
  493. /* look in the baggage as well...*/
  494. if((baggage != NULL) && (error == PR_FALSE)) {
  495. espvk = sec_pkcs12_get_espvk_by_name(baggage, nicknames[i]);
  496. if(espvk != NULL) {
  497. espvk->espvkData.poolp = espvk->poolp;
  498. rv = sec_pkcs12_add_thumbprint(&espvk->espvkData,
  499. &cert->value.x509->thumbprint);
  500. if(rv == SECFailure)
  501. error = PR_TRUE; /* XXX Set error? */
  502. }
  503. }
  504. }
  505. i++;
  506. }
  507. if(error == PR_TRUE) {
  508. return SECFailure;
  509. }
  510. return SECSuccess;
  511. }
  512. /* append a safe bag to the end of the safe contents list */
  513. SECStatus
  514. sec_pkcs12_append_safe_bag(SEC_PKCS12SafeContents *safe,
  515. SEC_PKCS12SafeBag *bag)
  516. {
  517. int size;
  518. void *mark = NULL, *dummy = NULL;
  519. if((bag == NULL) || (safe == NULL))
  520. return SECFailure;
  521. mark = PORT_ArenaMark(safe->poolp);
  522. size = (safe->safe_size * sizeof(SEC_PKCS12SafeBag *));
  523. if(safe->safe_size > 0) {
  524. dummy = (SEC_PKCS12SafeBag **)PORT_ArenaGrow(safe->poolp,
  525. safe->contents,
  526. size,
  527. (size + sizeof(SEC_PKCS12SafeBag *)));
  528. safe->contents = dummy;
  529. } else {
  530. safe->contents = (SEC_PKCS12SafeBag **)PORT_ArenaZAlloc(safe->poolp,
  531. (2 * sizeof(SEC_PKCS12SafeBag *)));
  532. dummy = safe->contents;
  533. }
  534. if(dummy == NULL) {
  535. PORT_SetError(SEC_ERROR_NO_MEMORY);
  536. goto loser;
  537. }
  538. safe->contents[safe->safe_size] = bag;
  539. safe->safe_size++;
  540. safe->contents[safe->safe_size] = NULL;
  541. PORT_ArenaUnmark(safe->poolp, mark);
  542. return SECSuccess;
  543. loser:
  544. PORT_ArenaRelease(safe->poolp, mark);
  545. return SECFailure;
  546. }
  547. /* append a certificate onto the end of a cert bag */
  548. static SECStatus
  549. sec_pkcs12_append_cert_to_bag(PRArenaPool *arena,
  550. SEC_PKCS12SafeBag *safebag,
  551. CERTCertificate *cert,
  552. SECItem *nickname)
  553. {
  554. int size;
  555. void *dummy = NULL, *mark = NULL;
  556. SEC_PKCS12CertAndCRL *p12cert;
  557. SEC_PKCS12CertAndCRLBag *bag;
  558. if((arena == NULL) || (safebag == NULL) ||
  559. (cert == NULL) || (nickname == NULL)) {
  560. return SECFailure;
  561. }
  562. bag = safebag->safeContent.certAndCRLBag;
  563. if(bag == NULL) {
  564. return SECFailure;
  565. }
  566. mark = PORT_ArenaMark(arena);
  567. p12cert = sec_pkcs12_get_cert(arena, cert, nickname);
  568. if(p12cert == NULL) {
  569. PORT_ArenaRelease(bag->poolp, mark);
  570. return SECFailure;
  571. }
  572. size = bag->bag_size * sizeof(SEC_PKCS12CertAndCRL *);
  573. if(bag->bag_size > 0) {
  574. dummy = (SEC_PKCS12CertAndCRL **)PORT_ArenaGrow(bag->poolp,
  575. bag->certAndCRLs, size, size + sizeof(SEC_PKCS12CertAndCRL *));
  576. bag->certAndCRLs = dummy;
  577. } else {
  578. bag->certAndCRLs = (SEC_PKCS12CertAndCRL **)PORT_ArenaZAlloc(bag->poolp,
  579. (2 * sizeof(SEC_PKCS12CertAndCRL *)));
  580. dummy = bag->certAndCRLs;
  581. }
  582. if(dummy == NULL) {
  583. PORT_SetError(SEC_ERROR_NO_MEMORY);
  584. goto loser;
  585. }
  586. bag->certAndCRLs[bag->bag_size] = p12cert;
  587. bag->bag_size++;
  588. bag->certAndCRLs[bag->bag_size] = NULL;
  589. PORT_ArenaUnmark(bag->poolp, mark);
  590. return SECSuccess;
  591. loser:
  592. PORT_ArenaRelease(bag->poolp, mark);
  593. return SECFailure;
  594. }
  595. /* append a key onto the end of a list of keys in a key bag */
  596. SECStatus
  597. sec_pkcs12_append_key_to_bag(SEC_PKCS12SafeBag *safebag,
  598. SEC_PKCS12PrivateKey *pk)
  599. {
  600. void *mark, *dummy;
  601. SEC_PKCS12PrivateKeyBag *bag;
  602. int size;
  603. if((safebag == NULL) || (pk == NULL))
  604. return SECFailure;
  605. bag = safebag->safeContent.keyBag;
  606. if(bag == NULL) {
  607. return SECFailure;
  608. }
  609. mark = PORT_ArenaMark(bag->poolp);
  610. size = (bag->bag_size * sizeof(SEC_PKCS12PrivateKey *));
  611. if(bag->bag_size > 0) {
  612. dummy = (SEC_PKCS12PrivateKey **)PORT_ArenaGrow(bag->poolp,
  613. bag->privateKeys,
  614. size,
  615. size + sizeof(SEC_PKCS12PrivateKey *));
  616. bag->privateKeys = dummy;
  617. } else {
  618. bag->privateKeys = (SEC_PKCS12PrivateKey **)PORT_ArenaZAlloc(bag->poolp,
  619. (2 * sizeof(SEC_PKCS12PrivateKey *)));
  620. dummy = bag->privateKeys;
  621. }
  622. if(dummy == NULL) {
  623. PORT_SetError(SEC_ERROR_NO_MEMORY);
  624. goto loser;
  625. }
  626. bag->privateKeys[bag->bag_size] = pk;
  627. bag->bag_size++;
  628. bag->privateKeys[bag->bag_size] = NULL;
  629. PORT_ArenaUnmark(bag->poolp, mark);
  630. return SECSuccess;
  631. loser:
  632. /* XXX Free memory? */
  633. PORT_ArenaRelease(bag->poolp, mark);
  634. return SECFailure;
  635. }
  636. /* append a safe bag to the baggage area */
  637. static SECStatus
  638. sec_pkcs12_append_unshrouded_bag(SEC_PKCS12BaggageItem *bag,
  639. SEC_PKCS12SafeBag *u_bag)
  640. {
  641. int size;
  642. void *mark = NULL, *dummy = NULL;
  643. if((bag == NULL) || (u_bag == NULL))
  644. return SECFailure;
  645. mark = PORT_ArenaMark(bag->poolp);
  646. /* dump things into the first bag */
  647. size = (bag->nSecrets + 1) * sizeof(SEC_PKCS12SafeBag *);
  648. dummy = PORT_ArenaGrow(bag->poolp,
  649. bag->unencSecrets, size,
  650. size + sizeof(SEC_PKCS12SafeBag *));
  651. bag->unencSecrets = dummy;
  652. if(dummy == NULL) {
  653. PORT_SetError(SEC_ERROR_NO_MEMORY);
  654. goto loser;
  655. }
  656. bag->unencSecrets[bag->nSecrets] = u_bag;
  657. bag->nSecrets++;
  658. bag->unencSecrets[bag->nSecrets] = NULL;
  659. PORT_ArenaUnmark(bag->poolp, mark);
  660. return SECSuccess;
  661. loser:
  662. PORT_ArenaRelease(bag->poolp, mark);
  663. return SECFailure;
  664. }
  665. /* gather up all certificates and keys and package them up
  666. * in the safe, baggage, or both.
  667. * nicknames is the list of nicknames and corresponding certs in ref_certs
  668. * ref_certs a null terminated list of certificates
  669. * rSafe, rBaggage -- return areas for safe and baggage
  670. * shroud_keys -- store keys externally
  671. * pwitem -- password for computing integrity mac and encrypting contents
  672. * wincx -- window handle
  673. *
  674. * if a failure occurs, an error is set and SECFailure returned.
  675. */
  676. static SECStatus
  677. sec_pkcs12_package_certs_and_keys(SECItem **nicknames,
  678. CERTCertificate **ref_certs,
  679. PRBool unencryptedCerts,
  680. SEC_PKCS12SafeContents **rSafe,
  681. SEC_PKCS12Baggage **rBaggage,
  682. PRBool shroud_keys,
  683. SECOidTag shroud_alg,
  684. SECItem *pwitem,
  685. PKCS12UnicodeConvertFunction unicodeFn,
  686. void *wincx)
  687. {
  688. PRArenaPool *permArena;
  689. SEC_PKCS12SafeContents *safe = NULL;
  690. SEC_PKCS12Baggage *baggage = NULL;
  691. SECStatus rv = SECFailure;
  692. PRBool problem = PR_FALSE;
  693. SEC_PKCS12ESPVKItem *espvk = NULL;
  694. SEC_PKCS12PrivateKey *pk = NULL;
  695. CERTCertificate *add_cert = NULL;
  696. SEC_PKCS12SafeBag *certbag = NULL, *keybag = NULL;
  697. SEC_PKCS12BaggageItem *external_bag = NULL;
  698. int ncerts = 0, nkeys = 0;
  699. int i;
  700. if((nicknames == NULL) || (rSafe == NULL) || (rBaggage == NULL)) {
  701. return SECFailure;
  702. }
  703. *rBaggage = baggage;
  704. *rSafe = safe;
  705. permArena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
  706. if(permArena == NULL) {
  707. PORT_SetError(SEC_ERROR_NO_MEMORY);
  708. return SECFailure;
  709. }
  710. /* allocate structures */
  711. safe = sec_pkcs12_create_safe_contents(permArena);
  712. if(safe == NULL) {
  713. PORT_SetError(SEC_ERROR_NO_MEMORY);
  714. rv = SECFailure;
  715. goto loser;
  716. }
  717. certbag = sec_pkcs12_create_safe_bag(permArena,
  718. SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID);
  719. if(certbag == NULL) {
  720. rv = SECFailure;
  721. goto loser;
  722. }
  723. if(shroud_keys != PR_TRUE) {
  724. keybag = sec_pkcs12_create_safe_bag(permArena,
  725. SEC_OID_PKCS12_KEY_BAG_ID);
  726. if(keybag == NULL) {
  727. rv = SECFailure;
  728. goto loser;
  729. }
  730. }
  731. if((shroud_keys == PR_TRUE) || (unencryptedCerts == PR_TRUE)) {
  732. baggage = sec_pkcs12_create_baggage(permArena);
  733. if(baggage == NULL) {
  734. rv = SECFailure;
  735. goto loser;
  736. }
  737. external_bag = sec_pkcs12_create_external_bag(baggage);
  738. }
  739. /* package keys and certs */
  740. i = 0;
  741. while((nicknames[i] != NULL) && (problem == PR_FALSE)) {
  742. if(ref_certs[i] != NULL) {
  743. /* append cert to bag o certs */
  744. rv = sec_pkcs12_append_cert_to_bag(permArena, certbag,
  745. ref_certs[i],
  746. nicknames[i]);
  747. if(rv == SECFailure) {
  748. problem = PR_FALSE;
  749. } else {
  750. ncerts++;
  751. }
  752. if(rv == SECSuccess) {
  753. /* package up them keys */
  754. if(shroud_keys == PR_TRUE) {
  755. espvk = sec_pkcs12_get_shrouded_key(permArena,
  756. nicknames[i],
  757. ref_certs[i],
  758. shroud_alg,
  759. pwitem, unicodeFn,
  760. wincx);
  761. if(espvk != NULL) {
  762. rv = sec_pkcs12_append_shrouded_key(external_bag, espvk);
  763. SECITEM_CopyItem(permArena, &espvk->derCert,
  764. &ref_certs[i]->derCert);
  765. } else {
  766. rv = SECFailure;
  767. }
  768. } else {
  769. pk = sec_pkcs12_get_private_key(permArena, nicknames[i],
  770. ref_certs[i], wincx);
  771. if(pk != NULL) {
  772. rv = sec_pkcs12_append_key_to_bag(keybag, pk);
  773. SECITEM_CopyItem(permArena, &espvk->derCert,
  774. &ref_certs[i]->derCert);
  775. } else {
  776. rv = SECFailure;
  777. }
  778. }
  779. if(rv == SECFailure) {
  780. problem = PR_TRUE;
  781. } else {
  782. nkeys++;
  783. }
  784. }
  785. } else {
  786. /* handle only keys here ? */
  787. problem = PR_TRUE;
  788. }
  789. i++;
  790. }
  791. /* let success fall through */
  792. loser:
  793. if(problem == PR_FALSE) {
  794. /* if we have certs, we want to append the cert bag to the
  795. * appropriate area
  796. */
  797. if(ncerts > 0) {
  798. if(unencryptedCerts != PR_TRUE) {
  799. rv = sec_pkcs12_append_safe_bag(safe, certbag);
  800. } else {
  801. rv = sec_pkcs12_append_unshrouded_bag(external_bag, certbag);
  802. }
  803. } else {
  804. rv = SECSuccess;
  805. }
  806. /* append key bag, if they are stored in safe contents */
  807. if((rv == SECSuccess) && (shroud_keys == PR_FALSE) && (nkeys > 0)) {
  808. rv = sec_pkcs12_append_safe_bag(safe, keybag);
  809. }
  810. } else {
  811. rv = SECFailure;
  812. }
  813. /* if baggage not used, NULLify it */
  814. if((shroud_keys == PR_TRUE) || (unencryptedCerts == PR_TRUE)) {
  815. if(((unencryptedCerts == PR_TRUE) && (ncerts == 0)) &&
  816. ((shroud_keys == PR_TRUE) && (nkeys == 0)))
  817. baggage = NULL;
  818. } else {
  819. baggage = NULL;
  820. }
  821. if((problem == PR_TRUE) || (rv == SECFailure)) {
  822. PORT_FreeArena(permArena, PR_TRUE);
  823. rv = SECFailure;
  824. baggage = NULL;
  825. safe = NULL;
  826. }
  827. *rBaggage = baggage;
  828. *rSafe = safe;
  829. return rv;
  830. }
  831. /* DER encode the safe contents and return a SECItem. if an error
  832. * occurs, NULL is returned.
  833. */
  834. static SECItem *
  835. sec_pkcs12_encode_safe_contents(SEC_PKCS12SafeContents *safe)
  836. {
  837. SECItem *dsafe = NULL, *tsafe;
  838. void *dummy = NULL;
  839. PRArenaPool *arena;
  840. if(safe == NULL) {
  841. return NULL;
  842. }
  843. /* rv = sec_pkcs12_prepare_for_der_code_safe(safe, PR_TRUE);
  844. if(rv != SECSuccess) {
  845. PORT_SetError(SEC_ERROR_NO_MEMORY);
  846. return NULL;
  847. }*/
  848. arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
  849. if(arena == NULL) {
  850. PORT_SetError(SEC_ERROR_NO_MEMORY);
  851. return NULL;
  852. }
  853. tsafe = (SECItem *)PORT_ArenaZAlloc(arena, sizeof(SECItem));
  854. if(tsafe != NULL) {
  855. dummy = SEC_ASN1EncodeItem(arena, tsafe, safe,
  856. SEC_PKCS12SafeContentsTemplate);
  857. if(dummy != NULL) {
  858. dsafe = SECITEM_DupItem(tsafe);
  859. } else {
  860. PORT_SetError(SEC_ERROR_NO_MEMORY);
  861. }
  862. } else {
  863. PORT_SetError(SEC_ERROR_NO_MEMORY);
  864. }
  865. PORT_FreeArena(arena, PR_TRUE);
  866. return dsafe;
  867. }
  868. /* prepare the authenicated safe for encoding and encode it.
  869. * baggage is copied to the appropriate area, safe is encoded and
  870. * encrypted. the version and transport mode are set on the asafe.
  871. * the whole ball of wax is then der encoded and packaged up into
  872. * data content info
  873. * safe -- container of certs and keys, is encrypted.
  874. * baggage -- container of certs and keys, keys assumed to be encrypted by
  875. * another method, certs are in the clear
  876. * algorithm -- algorithm by which to encrypt safe
  877. * pwitem -- password for encryption
  878. * wincx - window handle
  879. *
  880. * return of NULL is an error condition.
  881. */
  882. static SEC_PKCS7ContentInfo *
  883. sec_pkcs12_get_auth_safe(SEC_PKCS12SafeContents *safe,
  884. SEC_PKCS12Baggage *baggage,
  885. SECOidTag algorithm,
  886. SECItem *pwitem,
  887. PKCS12UnicodeConvertFunction unicodeFn,
  888. void *wincx)
  889. {
  890. SECItem *src = NULL, *dest = NULL, *psalt = NULL;
  891. PRArenaPool *poolp;
  892. SEC_PKCS12AuthenticatedSafe *asafe;
  893. SEC_PKCS7ContentInfo *safe_cinfo = NULL;
  894. SEC_PKCS7ContentInfo *asafe_cinfo = NULL;
  895. void *dummy;
  896. SECStatus rv = SECSuccess;
  897. PRBool swapUnicodeBytes = PR_FALSE;
  898. #ifdef IS_LITTLE_ENDIAN
  899. swapUnicodeBytes = PR_TRUE;
  900. #endif
  901. if(((safe != NULL) && (pwitem == NULL)) && (baggage == NULL))
  902. return NULL;
  903. poolp = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
  904. if(poolp == NULL) {
  905. PORT_SetError(SEC_ERROR_NO_MEMORY);
  906. return NULL;
  907. }
  908. /* prepare authenticated safe for encode */
  909. asafe = sec_pkcs12_new_asafe(poolp);
  910. if(asafe != NULL) {
  911. /* set version */
  912. dummy = SEC_ASN1EncodeInteger(asafe->poolp, &asafe->version,
  913. SEC_PKCS12_PFX_VERSION);
  914. if(dummy == NULL) {
  915. PORT_SetError(SEC_ERROR_NO_MEMORY);
  916. rv = SECFailure;
  917. goto loser;
  918. }
  919. /* generate the privacy salt used to create virtual pwd */
  920. psalt = sec_pkcs12_generate_salt();
  921. if(psalt != NULL) {
  922. rv = SECITEM_CopyItem(asafe->poolp, &asafe->privacySalt,
  923. psalt);
  924. if(rv == SECSuccess) {
  925. asafe->privacySalt.len *= 8;
  926. }
  927. else {
  928. SECITEM_ZfreeItem(psalt, PR_TRUE);
  929. PORT_SetError(SEC_ERROR_NO_MEMORY);
  930. goto loser;
  931. }
  932. }
  933. if((psalt == NULL) || (rv == SECFailure)) {
  934. PORT_SetError(SEC_ERROR_NO_MEMORY);
  935. rv = SECFailure;
  936. goto loser;
  937. }
  938. /* package up safe contents */
  939. if(safe != NULL)
  940. {
  941. safe_cinfo = SEC_PKCS7CreateEncryptedData(algorithm, NULL, wincx);
  942. if((safe_cinfo != NULL) && (safe->safe_size > 0)) {
  943. /* encode the safe and encrypt the contents of the
  944. * content info
  945. */
  946. src = sec_pkcs12_encode_safe_contents(safe);
  947. if(src != NULL) {
  948. rv = SEC_PKCS7SetContent(safe_cinfo, (char *)src->data, src->len);
  949. SECITEM_ZfreeItem(src, PR_TRUE);
  950. if(rv == SECSuccess) {
  951. SECItem *vpwd;
  952. vpwd = sec_pkcs12_create_virtual_password(pwitem, psalt,
  953. unicodeFn, swapUnicodeBytes);
  954. if(vpwd != NULL) {
  955. rv = SEC_PKCS7EncryptContents(NULL, safe_cinfo,
  956. vpwd, wincx);
  957. SECITEM_ZfreeItem(vpwd, PR_TRUE);
  958. } else {
  959. rv = SECFailure;
  960. PORT_SetError(SEC_ERROR_NO_MEMORY);
  961. }
  962. } else {
  963. PORT_SetError(SEC_ERROR_NO_MEMORY);
  964. }
  965. } else {
  966. rv = SECFailure;
  967. }
  968. } else if(safe->safe_size > 0) {
  969. PORT_SetError(SEC_ERROR_NO_MEMORY);
  970. goto loser;
  971. } else {
  972. /* case where there is NULL content in the safe contents */
  973. rv = SEC_PKCS7SetContent(safe_cinfo, NULL, 0);
  974. if(rv != SECFailure) {
  975. PORT_SetError(SEC_ERROR_NO_MEMORY);
  976. }
  977. }
  978. if(rv != SECSuccess) {
  979. SEC_PKCS7DestroyContentInfo(safe_cinfo);
  980. safe_cinfo = NULL;
  981. goto loser;
  982. }
  983. asafe->safe = safe_cinfo;
  984. /*
  985. PORT_Memcpy(&asafe->safe, safe_cinfo, sizeof(*safe_cinfo));
  986. */
  987. }
  988. /* copy the baggage to the authenticated safe baggage if present */
  989. if(baggage != NULL) {
  990. PORT_Memcpy(&asafe->baggage, baggage, sizeof(*baggage));
  991. }
  992. /* encode authenticated safe and store it in a Data content info */
  993. dest = (SECItem *)PORT_ArenaZAlloc(poolp, sizeof(SECItem));
  994. if(dest != NULL) {
  995. dummy = SEC_ASN1EncodeItem(poolp, dest, asafe,
  996. SEC_PKCS12AuthenticatedSafeTemplate);
  997. if(dummy != NULL) {
  998. asafe_cinfo = SEC_PKCS7CreateData();
  999. if(asafe_cinfo != NULL) {
  1000. rv = SEC_PKCS7SetContent(asafe_cinfo,
  1001. (char *)dest->data,
  1002. dest->len);
  1003. if(rv != SECSuccess) {
  1004. PORT_SetError(SEC_ERROR_NO_MEMORY);
  1005. SEC_PKCS7DestroyContentInfo(asafe_cinfo);
  1006. asafe_cinfo = NULL;
  1007. }
  1008. }
  1009. } else {
  1010. PORT_SetError(SEC_ERROR_NO_MEMORY);
  1011. rv = SECFailure;
  1012. }
  1013. }
  1014. }
  1015. loser:
  1016. PORT_FreeArena(poolp, PR_TRUE);
  1017. if(safe_cinfo != NULL) {
  1018. SEC_PKCS7DestroyContentInfo(safe_cinfo);
  1019. }
  1020. if(psalt != NULL) {
  1021. SECITEM_ZfreeItem(psalt, PR_TRUE);
  1022. }
  1023. if(rv == SECFailure) {
  1024. return NULL;
  1025. }
  1026. return asafe_cinfo;
  1027. }
  1028. /* generates the PFX and computes the mac on the authenticated safe
  1029. * NULL implies an error
  1030. */
  1031. static SEC_PKCS12PFXItem *
  1032. sec_pkcs12_get_pfx(SEC_PKCS7ContentInfo *cinfo,
  1033. PRBool do_mac,
  1034. SECItem *pwitem, PKCS12UnicodeConvertFunction unicodeFn)
  1035. {
  1036. SECItem *dest = NULL, *mac = NULL, *salt = NULL, *key = NULL;
  1037. SEC_PKCS12PFXItem *pfx;
  1038. SECStatus rv = SECFailure;
  1039. SGNDigestInfo *di;
  1040. SECItem *vpwd;
  1041. PRBool swapUnicodeBytes = PR_FALSE;
  1042. #ifdef IS_LITTLE_ENDIAN
  1043. swapUnicodeBytes = PR_TRUE;
  1044. #endif
  1045. if((cinfo == NULL) || ((do_mac == PR_TRUE) && (pwitem == NULL))) {
  1046. return NULL;
  1047. }
  1048. /* allocate new pfx structure */
  1049. pfx = sec_pkcs12_new_pfx();
  1050. if(pfx == NULL) {
  1051. PORT_SetError(SEC_ERROR_NO_MEMORY);
  1052. return NULL;
  1053. }
  1054. PORT_Memcpy(&pfx->authSafe, cinfo, sizeof(*cinfo));
  1055. if(do_mac == PR_TRUE) {
  1056. /* salt for computing mac */
  1057. salt = sec_pkcs12_generate_salt();
  1058. if(salt != NULL) {
  1059. rv = SECITEM_CopyItem(pfx->poolp, &pfx->macData.macSalt, salt);
  1060. pfx->macData.macSalt.len *= 8;
  1061. vpwd = sec_pkcs12_create_virtual_password(pwitem, salt,
  1062. unicodeFn, swapUnicodeBytes);
  1063. if(vpwd == NULL) {
  1064. rv = SECFailure;
  1065. key = NULL;
  1066. } else {
  1067. key = sec_pkcs12_generate_key_from_password(SEC_OID_SHA1,
  1068. salt, vpwd);
  1069. SECITEM_ZfreeItem(vpwd, PR_TRUE);
  1070. }
  1071. if((key != NULL) && (rv == SECSuccess)) {
  1072. dest = SEC_PKCS7GetContent(cinfo);
  1073. if(dest != NULL) {
  1074. /* compute mac on data -- for password integrity mode */
  1075. mac = sec_pkcs12_generate_mac(key, dest, PR_FALSE);
  1076. if(mac != NULL) {
  1077. di = SGN_CreateDigestInfo(SEC_OID_SHA1,
  1078. mac->data, mac->len);
  1079. if(di != NULL) {
  1080. rv = SGN_CopyDigestInfo(pfx->poolp,
  1081. &pfx->macData.safeMac, di);
  1082. SGN_DestroyDigestInfo(di);
  1083. } else {
  1084. PORT_SetError(SEC_ERROR_NO_MEMORY);
  1085. }
  1086. SECITEM_ZfreeItem(mac, PR_TRUE);
  1087. }
  1088. } else {
  1089. rv = SECFailure;
  1090. }
  1091. } else {
  1092. PORT_SetError(SEC_ERROR_NO_MEMORY);
  1093. rv = SECFailure;
  1094. }
  1095. if(key != NULL) {
  1096. SECITEM_ZfreeItem(key, PR_TRUE);
  1097. }
  1098. SECITEM_ZfreeItem(salt, PR_TRUE);
  1099. }
  1100. }
  1101. if(rv == SECFailure) {
  1102. SEC_PKCS12DestroyPFX(pfx);
  1103. pfx = NULL;
  1104. }
  1105. return pfx;
  1106. }
  1107. /* der encode the pfx */
  1108. static SECItem *
  1109. sec_pkcs12_encode_pfx(SEC_PKCS12PFXItem *pfx)
  1110. {
  1111. SECItem *dest;
  1112. void *dummy;
  1113. if(pfx == NULL) {
  1114. return NULL;
  1115. }
  1116. dest = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
  1117. if(dest == NULL) {
  1118. PORT_SetError(SEC_ERROR_NO_MEMORY);
  1119. return NULL;
  1120. }
  1121. dummy = SEC_ASN1EncodeItem(NULL, dest, pfx, SEC_PKCS12PFXItemTemplate);
  1122. if(dummy == NULL) {
  1123. PORT_SetError(SEC_ERROR_NO_MEMORY);
  1124. SECITEM_ZfreeItem(dest, PR_TRUE);
  1125. dest = NULL;
  1126. }
  1127. return dest;
  1128. }
  1129. SECItem *
  1130. SEC_PKCS12GetPFX(char **nicknames,
  1131. CERTCertificate **ref_certs,
  1132. PRBool shroud_keys,
  1133. SEC_PKCS5GetPBEPassword pbef,
  1134. void *pbearg,
  1135. PKCS12UnicodeConvertFunction unicodeFn,
  1136. void *wincx)
  1137. {
  1138. SECItem **nicks = NULL;
  1139. SEC_PKCS12PFXItem *pfx = NULL;
  1140. SEC_PKCS12Baggage *baggage = NULL;
  1141. SEC_PKCS12SafeContents *safe = NULL;
  1142. SEC_PKCS7ContentInfo *cinfo = NULL;
  1143. SECStatus rv = SECFailure;
  1144. SECItem *dest = NULL, *pwitem = NULL;
  1145. PRBool problem = PR_FALSE;
  1146. PRBool unencryptedCerts;
  1147. SECOidTag shroud_alg, safe_alg;
  1148. /* how should we encrypt certs ? */
  1149. unencryptedCerts = !SEC_PKCS12IsEncryptionAllowed();
  1150. if(!unencryptedCerts) {
  1151. safe_alg = SEC_PKCS12GetPreferredEncryptionAlgorithm();
  1152. if(safe_alg == SEC_OID_UNKNOWN) {
  1153. safe_alg = SEC_PKCS12GetStrongestAllowedAlgorithm();
  1154. }
  1155. if(safe_alg == SEC_OID_UNKNOWN) {
  1156. unencryptedCerts = PR_TRUE;
  1157. /* for export where no encryption is allowed, we still need
  1158. * to encrypt the NULL contents per the spec. encrypted info
  1159. * is known plaintext, so it shouldn't be a problem.
  1160. */
  1161. safe_alg = SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC;
  1162. }
  1163. } else {
  1164. /* for export where no encryption is allowed, we still need
  1165. * to encrypt the NULL contents per the spec. encrypted info
  1166. * is known plaintext, so it shouldn't be a problem.
  1167. */
  1168. safe_alg = SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC;
  1169. }
  1170. /* keys are always stored with triple DES */
  1171. shroud_alg = SEC_OID_PKCS12_PBE_WITH_SHA1_AND_TRIPLE_DES_CBC;
  1172. /* check for FIPS, if so, do not encrypt certs */
  1173. if(PK11_IsFIPS() && !unencryptedCerts) {
  1174. unencryptedCerts = PR_TRUE;
  1175. }
  1176. if((nicknames == NULL) || (pbef == NULL) || (ref_certs == NULL)) {
  1177. problem = PR_TRUE;
  1178. goto loser;
  1179. }
  1180. /* get password */
  1181. pwitem = (*pbef)(pbearg);
  1182. if(pwitem == NULL) {
  1183. problem = PR_TRUE;
  1184. goto loser;
  1185. }
  1186. nicks = sec_pkcs12_convert_nickname_list(nicknames);
  1187. /* get safe and baggage */
  1188. rv = sec_pkcs12_package_certs_and_keys(nicks, ref_certs, unencryptedCerts,
  1189. &safe, &baggage, shroud_keys,
  1190. shroud_alg, pwitem, unicodeFn, wincx);
  1191. if(rv == SECFailure) {
  1192. problem = PR_TRUE;
  1193. }
  1194. if((safe != NULL) && (problem == PR_FALSE)) {
  1195. /* copy thumbprints */
  1196. rv = sec_pkcs12_propagate_thumbprints(nicks, ref_certs, safe, baggage);
  1197. /* package everything up into AuthenticatedSafe */
  1198. cinfo = sec_pkcs12_get_auth_safe(safe, baggage,
  1199. safe_alg, pwitem, unicodeFn, wincx);
  1200. sec_pkcs12_destroy_cert_content_infos(safe, baggage);
  1201. /* get the pfx and mac it */
  1202. if(cinfo != NULL) {
  1203. pfx = sec_pkcs12_get_pfx(cinfo, PR_TRUE, pwitem, unicodeFn);
  1204. if(pfx != NULL) {
  1205. dest = sec_pkcs12_encode_pfx(pfx);
  1206. SEC_PKCS12DestroyPFX(pfx);
  1207. }
  1208. SEC_PKCS7DestroyContentInfo(cinfo);
  1209. }
  1210. if(safe != NULL) {
  1211. PORT_FreeArena(safe->poolp, PR_TRUE);
  1212. }
  1213. } else {
  1214. if(safe != NULL) {
  1215. PORT_FreeArena(safe->poolp, PR_TRUE);
  1216. }
  1217. }
  1218. loser:
  1219. if(nicks != NULL) {
  1220. sec_pkcs12_destroy_nickname_list(nicks);
  1221. }
  1222. if(ref_certs != NULL) {
  1223. sec_pkcs12_destroy_certificate_list(ref_certs);
  1224. }
  1225. if(pwitem != NULL) {
  1226. SECITEM_ZfreeItem(pwitem, PR_TRUE);
  1227. }
  1228. if(problem == PR_TRUE) {
  1229. dest = NULL;
  1230. }
  1231. return dest;
  1232. }