PageRenderTime 65ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/security/nss/lib/pkcs12/p12e.c

https://bitbucket.org/mkato/mozilla-1.9.0-win64
C | 2075 lines | 1405 code | 286 blank | 384 comment | 262 complexity | e6a5f1cb55f68af0165730cca951d7f5 MD5 | raw file
Possible License(s): LGPL-3.0, MIT, BSD-3-Clause, MPL-2.0-no-copyleft-exception, GPL-2.0, LGPL-2.1

Large files files are truncated, but you can click here to view the full file

  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 "p12t.h"
  37. #include "p12.h"
  38. #include "plarena.h"
  39. #include "secitem.h"
  40. #include "secoid.h"
  41. #include "seccomon.h"
  42. #include "secport.h"
  43. #include "cert.h"
  44. #include "secpkcs7.h"
  45. #include "secasn1.h"
  46. #include "secerr.h"
  47. #include "pk11func.h"
  48. #include "p12plcy.h"
  49. #include "p12local.h"
  50. #include "prcpucfg.h"
  51. /*
  52. ** This PKCS12 file encoder uses numerous nested ASN.1 and PKCS7 encoder
  53. ** contexts. It can be difficult to keep straight. Here's a picture:
  54. **
  55. ** "outer" ASN.1 encoder. The output goes to the library caller's CB.
  56. ** "middle" PKCS7 encoder. Feeds the "outer" ASN.1 encoder.
  57. ** "middle" ASN1 encoder. Encodes the encrypted aSafes.
  58. ** Feeds the "middle" P7 encoder above.
  59. ** "inner" PKCS7 encoder. Encrypts the "authenticated Safes" (aSafes)
  60. ** Feeds the "middle" ASN.1 encoder above.
  61. ** "inner" ASN.1 encoder. Encodes the unencrypted aSafes.
  62. ** Feeds the "inner" P7 enocder above.
  63. **
  64. ** Buffering has been added at each point where the output of an ASN.1
  65. ** encoder feeds the input of a PKCS7 encoder.
  66. */
  67. /*********************************
  68. * Output buffer object, used to buffer output from ASN.1 encoder
  69. * before passing data on down to the next PKCS7 encoder.
  70. *********************************/
  71. #define PK12_OUTPUT_BUFFER_SIZE 8192
  72. struct sec_pkcs12OutputBufferStr {
  73. SEC_PKCS7EncoderContext * p7eCx;
  74. PK11Context * hmacCx;
  75. unsigned int numBytes;
  76. unsigned int bufBytes;
  77. char buf[PK12_OUTPUT_BUFFER_SIZE];
  78. };
  79. typedef struct sec_pkcs12OutputBufferStr sec_pkcs12OutputBuffer;
  80. /*********************************
  81. * Structures used in exporting the PKCS 12 blob
  82. *********************************/
  83. /* A SafeInfo is used for each ContentInfo which makes up the
  84. * sequence of safes in the AuthenticatedSafe portion of the
  85. * PFX structure.
  86. */
  87. struct SEC_PKCS12SafeInfoStr {
  88. PRArenaPool *arena;
  89. /* information for setting up password encryption */
  90. SECItem pwitem;
  91. SECOidTag algorithm;
  92. PK11SymKey *encryptionKey;
  93. /* how many items have been stored in this safe,
  94. * we will skip any safe which does not contain any
  95. * items
  96. */
  97. unsigned int itemCount;
  98. /* the content info for the safe */
  99. SEC_PKCS7ContentInfo *cinfo;
  100. sec_PKCS12SafeContents *safe;
  101. };
  102. /* An opaque structure which contains information needed for exporting
  103. * certificates and keys through PKCS 12.
  104. */
  105. struct SEC_PKCS12ExportContextStr {
  106. PRArenaPool *arena;
  107. PK11SlotInfo *slot;
  108. void *wincx;
  109. /* integrity information */
  110. PRBool integrityEnabled;
  111. PRBool pwdIntegrity;
  112. union {
  113. struct sec_PKCS12PasswordModeInfo pwdInfo;
  114. struct sec_PKCS12PublicKeyModeInfo pubkeyInfo;
  115. } integrityInfo;
  116. /* helper functions */
  117. /* retrieve the password call back */
  118. SECKEYGetPasswordKey pwfn;
  119. void *pwfnarg;
  120. /* safe contents bags */
  121. SEC_PKCS12SafeInfo **safeInfos;
  122. unsigned int safeInfoCount;
  123. /* the sequence of safes */
  124. sec_PKCS12AuthenticatedSafe authSafe;
  125. /* information needing deletion */
  126. CERTCertificate **certList;
  127. };
  128. /* structures for passing information to encoder callbacks when processing
  129. * data through the ASN1 engine.
  130. */
  131. struct sec_pkcs12_encoder_output {
  132. SEC_PKCS12EncoderOutputCallback outputfn;
  133. void *outputarg;
  134. };
  135. struct sec_pkcs12_hmac_and_output_info {
  136. void *arg;
  137. struct sec_pkcs12_encoder_output output;
  138. };
  139. /* An encoder context which is used for the actual encoding
  140. * portion of PKCS 12.
  141. */
  142. typedef struct sec_PKCS12EncoderContextStr {
  143. PRArenaPool *arena;
  144. SEC_PKCS12ExportContext *p12exp;
  145. PK11SymKey *encryptionKey;
  146. /* encoder information - this is set up based on whether
  147. * password based or public key pased privacy is being used
  148. */
  149. SEC_ASN1EncoderContext *outerA1ecx;
  150. union {
  151. struct sec_pkcs12_hmac_and_output_info hmacAndOutputInfo;
  152. struct sec_pkcs12_encoder_output encOutput;
  153. } output;
  154. /* structures for encoding of PFX and MAC */
  155. sec_PKCS12PFXItem pfx;
  156. sec_PKCS12MacData mac;
  157. /* authenticated safe encoding tracking information */
  158. SEC_PKCS7ContentInfo *aSafeCinfo;
  159. SEC_PKCS7EncoderContext *middleP7ecx;
  160. SEC_ASN1EncoderContext *middleA1ecx;
  161. unsigned int currentSafe;
  162. /* hmac context */
  163. PK11Context *hmacCx;
  164. /* output buffers */
  165. sec_pkcs12OutputBuffer middleBuf;
  166. sec_pkcs12OutputBuffer innerBuf;
  167. } sec_PKCS12EncoderContext;
  168. /*********************************
  169. * Export setup routines
  170. *********************************/
  171. /* SEC_PKCS12CreateExportContext
  172. * Creates an export context and sets the unicode and password retrieval
  173. * callbacks. This is the first call which must be made when exporting
  174. * a PKCS 12 blob.
  175. *
  176. * pwfn, pwfnarg - password retrieval callback and argument. these are
  177. * required for password-authentication mode.
  178. */
  179. SEC_PKCS12ExportContext *
  180. SEC_PKCS12CreateExportContext(SECKEYGetPasswordKey pwfn, void *pwfnarg,
  181. PK11SlotInfo *slot, void *wincx)
  182. {
  183. PRArenaPool *arena = NULL;
  184. SEC_PKCS12ExportContext *p12ctxt = NULL;
  185. /* allocate the arena and create the context */
  186. arena = PORT_NewArena(4096);
  187. if(!arena) {
  188. PORT_SetError(SEC_ERROR_NO_MEMORY);
  189. return NULL;
  190. }
  191. p12ctxt = (SEC_PKCS12ExportContext *)PORT_ArenaZAlloc(arena,
  192. sizeof(SEC_PKCS12ExportContext));
  193. if(!p12ctxt) {
  194. PORT_SetError(SEC_ERROR_NO_MEMORY);
  195. goto loser;
  196. }
  197. /* password callback for key retrieval */
  198. p12ctxt->pwfn = pwfn;
  199. p12ctxt->pwfnarg = pwfnarg;
  200. p12ctxt->integrityEnabled = PR_FALSE;
  201. p12ctxt->arena = arena;
  202. p12ctxt->wincx = wincx;
  203. p12ctxt->slot = (slot) ? PK11_ReferenceSlot(slot) : PK11_GetInternalSlot();
  204. return p12ctxt;
  205. loser:
  206. if(arena) {
  207. PORT_FreeArena(arena, PR_TRUE);
  208. }
  209. return NULL;
  210. }
  211. /*
  212. * Adding integrity mode
  213. */
  214. /* SEC_PKCS12AddPasswordIntegrity
  215. * Add password integrity to the exported data. If an integrity method
  216. * has already been set, then return an error.
  217. *
  218. * p12ctxt - the export context
  219. * pwitem - the password for integrity mode
  220. * integAlg - the integrity algorithm to use for authentication.
  221. */
  222. SECStatus
  223. SEC_PKCS12AddPasswordIntegrity(SEC_PKCS12ExportContext *p12ctxt,
  224. SECItem *pwitem, SECOidTag integAlg)
  225. {
  226. if(!p12ctxt || p12ctxt->integrityEnabled) {
  227. return SECFailure;
  228. }
  229. /* set up integrity information */
  230. p12ctxt->pwdIntegrity = PR_TRUE;
  231. p12ctxt->integrityInfo.pwdInfo.password =
  232. (SECItem*)PORT_ArenaZAlloc(p12ctxt->arena, sizeof(SECItem));
  233. if(!p12ctxt->integrityInfo.pwdInfo.password) {
  234. PORT_SetError(SEC_ERROR_NO_MEMORY);
  235. return SECFailure;
  236. }
  237. if(SECITEM_CopyItem(p12ctxt->arena,
  238. p12ctxt->integrityInfo.pwdInfo.password, pwitem)
  239. != SECSuccess) {
  240. PORT_SetError(SEC_ERROR_NO_MEMORY);
  241. return SECFailure;
  242. }
  243. p12ctxt->integrityInfo.pwdInfo.algorithm = integAlg;
  244. p12ctxt->integrityEnabled = PR_TRUE;
  245. return SECSuccess;
  246. }
  247. /* SEC_PKCS12AddPublicKeyIntegrity
  248. * Add public key integrity to the exported data. If an integrity method
  249. * has already been set, then return an error. The certificate must be
  250. * allowed to be used as a signing cert.
  251. *
  252. * p12ctxt - the export context
  253. * cert - signer certificate
  254. * certDb - the certificate database
  255. * algorithm - signing algorithm
  256. * keySize - size of the signing key (?)
  257. */
  258. SECStatus
  259. SEC_PKCS12AddPublicKeyIntegrity(SEC_PKCS12ExportContext *p12ctxt,
  260. CERTCertificate *cert, CERTCertDBHandle *certDb,
  261. SECOidTag algorithm, int keySize)
  262. {
  263. if(!p12ctxt) {
  264. return SECFailure;
  265. }
  266. p12ctxt->integrityInfo.pubkeyInfo.cert = cert;
  267. p12ctxt->integrityInfo.pubkeyInfo.certDb = certDb;
  268. p12ctxt->integrityInfo.pubkeyInfo.algorithm = algorithm;
  269. p12ctxt->integrityInfo.pubkeyInfo.keySize = keySize;
  270. p12ctxt->integrityEnabled = PR_TRUE;
  271. return SECSuccess;
  272. }
  273. /*
  274. * Adding safes - encrypted (password/public key) or unencrypted
  275. * Each of the safe creation routines return an opaque pointer which
  276. * are later passed into the routines for exporting certificates and
  277. * keys.
  278. */
  279. /* append the newly created safeInfo to list of safeInfos in the export
  280. * context.
  281. */
  282. static SECStatus
  283. sec_pkcs12_append_safe_info(SEC_PKCS12ExportContext *p12ctxt, SEC_PKCS12SafeInfo *info)
  284. {
  285. void *mark = NULL, *dummy1 = NULL, *dummy2 = NULL;
  286. if(!p12ctxt || !info) {
  287. return SECFailure;
  288. }
  289. mark = PORT_ArenaMark(p12ctxt->arena);
  290. /* if no safeInfos have been set, create the list, otherwise expand it. */
  291. if(!p12ctxt->safeInfoCount) {
  292. p12ctxt->safeInfos = (SEC_PKCS12SafeInfo **)PORT_ArenaZAlloc(p12ctxt->arena,
  293. 2 * sizeof(SEC_PKCS12SafeInfo *));
  294. dummy1 = p12ctxt->safeInfos;
  295. p12ctxt->authSafe.encodedSafes = (SECItem **)PORT_ArenaZAlloc(p12ctxt->arena,
  296. 2 * sizeof(SECItem *));
  297. dummy2 = p12ctxt->authSafe.encodedSafes;
  298. } else {
  299. dummy1 = PORT_ArenaGrow(p12ctxt->arena, p12ctxt->safeInfos,
  300. (p12ctxt->safeInfoCount + 1) * sizeof(SEC_PKCS12SafeInfo *),
  301. (p12ctxt->safeInfoCount + 2) * sizeof(SEC_PKCS12SafeInfo *));
  302. p12ctxt->safeInfos = (SEC_PKCS12SafeInfo **)dummy1;
  303. dummy2 = PORT_ArenaGrow(p12ctxt->arena, p12ctxt->authSafe.encodedSafes,
  304. (p12ctxt->authSafe.safeCount + 1) * sizeof(SECItem *),
  305. (p12ctxt->authSafe.safeCount + 2) * sizeof(SECItem *));
  306. p12ctxt->authSafe.encodedSafes = (SECItem**)dummy2;
  307. }
  308. if(!dummy1 || !dummy2) {
  309. PORT_SetError(SEC_ERROR_NO_MEMORY);
  310. goto loser;
  311. }
  312. /* append the new safeInfo and null terminate the list */
  313. p12ctxt->safeInfos[p12ctxt->safeInfoCount] = info;
  314. p12ctxt->safeInfos[++p12ctxt->safeInfoCount] = NULL;
  315. p12ctxt->authSafe.encodedSafes[p12ctxt->authSafe.safeCount] =
  316. (SECItem*)PORT_ArenaZAlloc(p12ctxt->arena, sizeof(SECItem));
  317. if(!p12ctxt->authSafe.encodedSafes[p12ctxt->authSafe.safeCount]) {
  318. PORT_SetError(SEC_ERROR_NO_MEMORY);
  319. goto loser;
  320. }
  321. p12ctxt->authSafe.encodedSafes[++p12ctxt->authSafe.safeCount] = NULL;
  322. PORT_ArenaUnmark(p12ctxt->arena, mark);
  323. return SECSuccess;
  324. loser:
  325. PORT_ArenaRelease(p12ctxt->arena, mark);
  326. return SECFailure;
  327. }
  328. /* SEC_PKCS12CreatePasswordPrivSafe
  329. * Create a password privacy safe to store exported information in.
  330. *
  331. * p12ctxt - export context
  332. * pwitem - password for encryption
  333. * privAlg - pbe algorithm through which encryption is done.
  334. */
  335. SEC_PKCS12SafeInfo *
  336. SEC_PKCS12CreatePasswordPrivSafe(SEC_PKCS12ExportContext *p12ctxt,
  337. SECItem *pwitem, SECOidTag privAlg)
  338. {
  339. SEC_PKCS12SafeInfo *safeInfo = NULL;
  340. void *mark = NULL;
  341. PK11SlotInfo *slot = NULL;
  342. SECAlgorithmID *algId;
  343. SECItem uniPwitem = {siBuffer, NULL, 0};
  344. if(!p12ctxt) {
  345. return NULL;
  346. }
  347. /* allocate the safe info */
  348. mark = PORT_ArenaMark(p12ctxt->arena);
  349. safeInfo = (SEC_PKCS12SafeInfo *)PORT_ArenaZAlloc(p12ctxt->arena,
  350. sizeof(SEC_PKCS12SafeInfo));
  351. if(!safeInfo) {
  352. PORT_SetError(SEC_ERROR_NO_MEMORY);
  353. PORT_ArenaRelease(p12ctxt->arena, mark);
  354. return NULL;
  355. }
  356. safeInfo->itemCount = 0;
  357. /* create the encrypted safe */
  358. safeInfo->cinfo = SEC_PKCS7CreateEncryptedData(privAlg, 0, p12ctxt->pwfn,
  359. p12ctxt->pwfnarg);
  360. if(!safeInfo->cinfo) {
  361. PORT_SetError(SEC_ERROR_NO_MEMORY);
  362. goto loser;
  363. }
  364. safeInfo->arena = p12ctxt->arena;
  365. /* convert the password to unicode */
  366. if(!sec_pkcs12_convert_item_to_unicode(NULL, &uniPwitem, pwitem,
  367. PR_TRUE, PR_TRUE, PR_TRUE)) {
  368. PORT_SetError(SEC_ERROR_NO_MEMORY);
  369. goto loser;
  370. }
  371. if(SECITEM_CopyItem(p12ctxt->arena, &safeInfo->pwitem, &uniPwitem) != SECSuccess) {
  372. PORT_SetError(SEC_ERROR_NO_MEMORY);
  373. goto loser;
  374. }
  375. /* generate the encryption key */
  376. slot = PK11_ReferenceSlot(p12ctxt->slot);
  377. if(!slot) {
  378. slot = PK11_GetInternalKeySlot();
  379. if(!slot) {
  380. PORT_SetError(SEC_ERROR_NO_MEMORY);
  381. goto loser;
  382. }
  383. }
  384. algId = SEC_PKCS7GetEncryptionAlgorithm(safeInfo->cinfo);
  385. safeInfo->encryptionKey = PK11_PBEKeyGen(slot, algId, &uniPwitem,
  386. PR_FALSE, p12ctxt->wincx);
  387. if(!safeInfo->encryptionKey) {
  388. goto loser;
  389. }
  390. safeInfo->arena = p12ctxt->arena;
  391. safeInfo->safe = NULL;
  392. if(sec_pkcs12_append_safe_info(p12ctxt, safeInfo) != SECSuccess) {
  393. goto loser;
  394. }
  395. if(uniPwitem.data) {
  396. SECITEM_ZfreeItem(&uniPwitem, PR_FALSE);
  397. }
  398. PORT_ArenaUnmark(p12ctxt->arena, mark);
  399. if (slot) {
  400. PK11_FreeSlot(slot);
  401. }
  402. return safeInfo;
  403. loser:
  404. if (slot) {
  405. PK11_FreeSlot(slot);
  406. }
  407. if(safeInfo->cinfo) {
  408. SEC_PKCS7DestroyContentInfo(safeInfo->cinfo);
  409. }
  410. if(uniPwitem.data) {
  411. SECITEM_ZfreeItem(&uniPwitem, PR_FALSE);
  412. }
  413. PORT_ArenaRelease(p12ctxt->arena, mark);
  414. return NULL;
  415. }
  416. /* SEC_PKCS12CreateUnencryptedSafe
  417. * Creates an unencrypted safe within the export context.
  418. *
  419. * p12ctxt - the export context
  420. */
  421. SEC_PKCS12SafeInfo *
  422. SEC_PKCS12CreateUnencryptedSafe(SEC_PKCS12ExportContext *p12ctxt)
  423. {
  424. SEC_PKCS12SafeInfo *safeInfo = NULL;
  425. void *mark = NULL;
  426. if(!p12ctxt) {
  427. return NULL;
  428. }
  429. /* create the safe info */
  430. mark = PORT_ArenaMark(p12ctxt->arena);
  431. safeInfo = (SEC_PKCS12SafeInfo *)PORT_ArenaZAlloc(p12ctxt->arena,
  432. sizeof(SEC_PKCS12SafeInfo));
  433. if(!safeInfo) {
  434. PORT_ArenaRelease(p12ctxt->arena, mark);
  435. PORT_SetError(SEC_ERROR_NO_MEMORY);
  436. return NULL;
  437. }
  438. safeInfo->itemCount = 0;
  439. /* create the safe content */
  440. safeInfo->cinfo = SEC_PKCS7CreateData();
  441. if(!safeInfo->cinfo) {
  442. PORT_SetError(SEC_ERROR_NO_MEMORY);
  443. goto loser;
  444. }
  445. if(sec_pkcs12_append_safe_info(p12ctxt, safeInfo) != SECSuccess) {
  446. goto loser;
  447. }
  448. PORT_ArenaUnmark(p12ctxt->arena, mark);
  449. return safeInfo;
  450. loser:
  451. if(safeInfo->cinfo) {
  452. SEC_PKCS7DestroyContentInfo(safeInfo->cinfo);
  453. }
  454. PORT_ArenaRelease(p12ctxt->arena, mark);
  455. return NULL;
  456. }
  457. /* SEC_PKCS12CreatePubKeyEncryptedSafe
  458. * Creates a safe which is protected by public key encryption.
  459. *
  460. * p12ctxt - the export context
  461. * certDb - the certificate database
  462. * signer - the signer's certificate
  463. * recipients - the list of recipient certificates.
  464. * algorithm - the encryption algorithm to use
  465. * keysize - the algorithms key size (?)
  466. */
  467. SEC_PKCS12SafeInfo *
  468. SEC_PKCS12CreatePubKeyEncryptedSafe(SEC_PKCS12ExportContext *p12ctxt,
  469. CERTCertDBHandle *certDb,
  470. CERTCertificate *signer,
  471. CERTCertificate **recipients,
  472. SECOidTag algorithm, int keysize)
  473. {
  474. SEC_PKCS12SafeInfo *safeInfo = NULL;
  475. void *mark = NULL;
  476. if(!p12ctxt || !signer || !recipients || !(*recipients)) {
  477. return NULL;
  478. }
  479. /* allocate the safeInfo */
  480. mark = PORT_ArenaMark(p12ctxt->arena);
  481. safeInfo = (SEC_PKCS12SafeInfo *)PORT_ArenaZAlloc(p12ctxt->arena,
  482. sizeof(SEC_PKCS12SafeInfo));
  483. if(!safeInfo) {
  484. PORT_ArenaRelease(p12ctxt->arena, mark);
  485. PORT_SetError(SEC_ERROR_NO_MEMORY);
  486. return NULL;
  487. }
  488. safeInfo->itemCount = 0;
  489. safeInfo->arena = p12ctxt->arena;
  490. /* create the enveloped content info using certUsageEmailSigner currently.
  491. * XXX We need to eventually use something other than certUsageEmailSigner
  492. */
  493. safeInfo->cinfo = SEC_PKCS7CreateEnvelopedData(signer, certUsageEmailSigner,
  494. certDb, algorithm, keysize,
  495. p12ctxt->pwfn, p12ctxt->pwfnarg);
  496. if(!safeInfo->cinfo) {
  497. PORT_SetError(SEC_ERROR_NO_MEMORY);
  498. goto loser;
  499. }
  500. /* add recipients */
  501. if(recipients) {
  502. unsigned int i = 0;
  503. while(recipients[i] != NULL) {
  504. SECStatus rv = SEC_PKCS7AddRecipient(safeInfo->cinfo, recipients[i],
  505. certUsageEmailRecipient, certDb);
  506. if(rv != SECSuccess) {
  507. goto loser;
  508. }
  509. i++;
  510. }
  511. }
  512. if(sec_pkcs12_append_safe_info(p12ctxt, safeInfo) != SECSuccess) {
  513. goto loser;
  514. }
  515. PORT_ArenaUnmark(p12ctxt->arena, mark);
  516. return safeInfo;
  517. loser:
  518. if(safeInfo->cinfo) {
  519. SEC_PKCS7DestroyContentInfo(safeInfo->cinfo);
  520. safeInfo->cinfo = NULL;
  521. }
  522. PORT_ArenaRelease(p12ctxt->arena, mark);
  523. return NULL;
  524. }
  525. /*********************************
  526. * Routines to handle the exporting of the keys and certificates
  527. *********************************/
  528. /* creates a safe contents which safeBags will be appended to */
  529. sec_PKCS12SafeContents *
  530. sec_PKCS12CreateSafeContents(PRArenaPool *arena)
  531. {
  532. sec_PKCS12SafeContents *safeContents;
  533. if(arena == NULL) {
  534. return NULL;
  535. }
  536. /* create the safe contents */
  537. safeContents = (sec_PKCS12SafeContents *)PORT_ArenaZAlloc(arena,
  538. sizeof(sec_PKCS12SafeContents));
  539. if(!safeContents) {
  540. PORT_SetError(SEC_ERROR_NO_MEMORY);
  541. goto loser;
  542. }
  543. /* set up the internal contents info */
  544. safeContents->safeBags = NULL;
  545. safeContents->arena = arena;
  546. safeContents->bagCount = 0;
  547. return safeContents;
  548. loser:
  549. return NULL;
  550. }
  551. /* appends a safe bag to a safeContents using the specified arena.
  552. */
  553. SECStatus
  554. sec_pkcs12_append_bag_to_safe_contents(PRArenaPool *arena,
  555. sec_PKCS12SafeContents *safeContents,
  556. sec_PKCS12SafeBag *safeBag)
  557. {
  558. void *mark = NULL, *dummy = NULL;
  559. if(!arena || !safeBag || !safeContents) {
  560. return SECFailure;
  561. }
  562. mark = PORT_ArenaMark(arena);
  563. if(!mark) {
  564. PORT_SetError(SEC_ERROR_NO_MEMORY);
  565. return SECFailure;
  566. }
  567. /* allocate space for the list, or reallocate to increase space */
  568. if(!safeContents->safeBags) {
  569. safeContents->safeBags = (sec_PKCS12SafeBag **)PORT_ArenaZAlloc(arena,
  570. (2 * sizeof(sec_PKCS12SafeBag *)));
  571. dummy = safeContents->safeBags;
  572. safeContents->bagCount = 0;
  573. } else {
  574. dummy = PORT_ArenaGrow(arena, safeContents->safeBags,
  575. (safeContents->bagCount + 1) * sizeof(sec_PKCS12SafeBag *),
  576. (safeContents->bagCount + 2) * sizeof(sec_PKCS12SafeBag *));
  577. safeContents->safeBags = (sec_PKCS12SafeBag **)dummy;
  578. }
  579. if(!dummy) {
  580. PORT_ArenaRelease(arena, mark);
  581. PORT_SetError(SEC_ERROR_NO_MEMORY);
  582. return SECFailure;
  583. }
  584. /* append the bag at the end and null terminate the list */
  585. safeContents->safeBags[safeContents->bagCount++] = safeBag;
  586. safeContents->safeBags[safeContents->bagCount] = NULL;
  587. PORT_ArenaUnmark(arena, mark);
  588. return SECSuccess;
  589. }
  590. /* appends a safeBag to a specific safeInfo.
  591. */
  592. SECStatus
  593. sec_pkcs12_append_bag(SEC_PKCS12ExportContext *p12ctxt,
  594. SEC_PKCS12SafeInfo *safeInfo, sec_PKCS12SafeBag *safeBag)
  595. {
  596. sec_PKCS12SafeContents *dest;
  597. SECStatus rv = SECFailure;
  598. if(!p12ctxt || !safeBag || !safeInfo) {
  599. return SECFailure;
  600. }
  601. if(!safeInfo->safe) {
  602. safeInfo->safe = sec_PKCS12CreateSafeContents(p12ctxt->arena);
  603. if(!safeInfo->safe) {
  604. return SECFailure;
  605. }
  606. }
  607. dest = safeInfo->safe;
  608. rv = sec_pkcs12_append_bag_to_safe_contents(p12ctxt->arena, dest, safeBag);
  609. if(rv == SECSuccess) {
  610. safeInfo->itemCount++;
  611. }
  612. return rv;
  613. }
  614. /* Creates a safeBag of the specified type, and if bagData is specified,
  615. * the contents are set. The contents could be set later by the calling
  616. * routine.
  617. */
  618. sec_PKCS12SafeBag *
  619. sec_PKCS12CreateSafeBag(SEC_PKCS12ExportContext *p12ctxt, SECOidTag bagType,
  620. void *bagData)
  621. {
  622. sec_PKCS12SafeBag *safeBag;
  623. PRBool setName = PR_TRUE;
  624. void *mark = NULL;
  625. SECStatus rv = SECSuccess;
  626. SECOidData *oidData = NULL;
  627. if(!p12ctxt) {
  628. return NULL;
  629. }
  630. mark = PORT_ArenaMark(p12ctxt->arena);
  631. if(!mark) {
  632. PORT_SetError(SEC_ERROR_NO_MEMORY);
  633. return NULL;
  634. }
  635. safeBag = (sec_PKCS12SafeBag *)PORT_ArenaZAlloc(p12ctxt->arena,
  636. sizeof(sec_PKCS12SafeBag));
  637. if(!safeBag) {
  638. PORT_ArenaRelease(p12ctxt->arena, mark);
  639. PORT_SetError(SEC_ERROR_NO_MEMORY);
  640. return NULL;
  641. }
  642. /* set the bags content based upon bag type */
  643. switch(bagType) {
  644. case SEC_OID_PKCS12_V1_KEY_BAG_ID:
  645. safeBag->safeBagContent.pkcs8KeyBag =
  646. (SECKEYPrivateKeyInfo *)bagData;
  647. break;
  648. case SEC_OID_PKCS12_V1_CERT_BAG_ID:
  649. safeBag->safeBagContent.certBag = (sec_PKCS12CertBag *)bagData;
  650. break;
  651. case SEC_OID_PKCS12_V1_CRL_BAG_ID:
  652. safeBag->safeBagContent.crlBag = (sec_PKCS12CRLBag *)bagData;
  653. break;
  654. case SEC_OID_PKCS12_V1_SECRET_BAG_ID:
  655. safeBag->safeBagContent.secretBag = (sec_PKCS12SecretBag *)bagData;
  656. break;
  657. case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:
  658. safeBag->safeBagContent.pkcs8ShroudedKeyBag =
  659. (SECKEYEncryptedPrivateKeyInfo *)bagData;
  660. break;
  661. case SEC_OID_PKCS12_V1_SAFE_CONTENTS_BAG_ID:
  662. safeBag->safeBagContent.safeContents =
  663. (sec_PKCS12SafeContents *)bagData;
  664. setName = PR_FALSE;
  665. break;
  666. default:
  667. goto loser;
  668. }
  669. oidData = SECOID_FindOIDByTag(bagType);
  670. if(oidData) {
  671. rv = SECITEM_CopyItem(p12ctxt->arena, &safeBag->safeBagType, &oidData->oid);
  672. if(rv != SECSuccess) {
  673. PORT_SetError(SEC_ERROR_NO_MEMORY);
  674. goto loser;
  675. }
  676. } else {
  677. goto loser;
  678. }
  679. safeBag->arena = p12ctxt->arena;
  680. PORT_ArenaUnmark(p12ctxt->arena, mark);
  681. return safeBag;
  682. loser:
  683. if(mark) {
  684. PORT_ArenaRelease(p12ctxt->arena, mark);
  685. }
  686. return NULL;
  687. }
  688. /* Creates a new certificate bag and returns a pointer to it. If an error
  689. * occurs NULL is returned.
  690. */
  691. sec_PKCS12CertBag *
  692. sec_PKCS12NewCertBag(PRArenaPool *arena, SECOidTag certType)
  693. {
  694. sec_PKCS12CertBag *certBag = NULL;
  695. SECOidData *bagType = NULL;
  696. SECStatus rv;
  697. void *mark = NULL;
  698. if(!arena) {
  699. return NULL;
  700. }
  701. mark = PORT_ArenaMark(arena);
  702. certBag = (sec_PKCS12CertBag *)PORT_ArenaZAlloc(arena,
  703. sizeof(sec_PKCS12CertBag));
  704. if(!certBag) {
  705. PORT_ArenaRelease(arena, mark);
  706. PORT_SetError(SEC_ERROR_NO_MEMORY);
  707. return NULL;
  708. }
  709. bagType = SECOID_FindOIDByTag(certType);
  710. if(!bagType) {
  711. PORT_SetError(SEC_ERROR_NO_MEMORY);
  712. goto loser;
  713. }
  714. rv = SECITEM_CopyItem(arena, &certBag->bagID, &bagType->oid);
  715. if(rv != SECSuccess) {
  716. PORT_SetError(SEC_ERROR_NO_MEMORY);
  717. goto loser;
  718. }
  719. PORT_ArenaUnmark(arena, mark);
  720. return certBag;
  721. loser:
  722. PORT_ArenaRelease(arena, mark);
  723. return NULL;
  724. }
  725. /* Creates a new CRL bag and returns a pointer to it. If an error
  726. * occurs NULL is returned.
  727. */
  728. sec_PKCS12CRLBag *
  729. sec_PKCS12NewCRLBag(PRArenaPool *arena, SECOidTag crlType)
  730. {
  731. sec_PKCS12CRLBag *crlBag = NULL;
  732. SECOidData *bagType = NULL;
  733. SECStatus rv;
  734. void *mark = NULL;
  735. if(!arena) {
  736. return NULL;
  737. }
  738. mark = PORT_ArenaMark(arena);
  739. crlBag = (sec_PKCS12CRLBag *)PORT_ArenaZAlloc(arena,
  740. sizeof(sec_PKCS12CRLBag));
  741. if(!crlBag) {
  742. PORT_ArenaRelease(arena, mark);
  743. PORT_SetError(SEC_ERROR_NO_MEMORY);
  744. return NULL;
  745. }
  746. bagType = SECOID_FindOIDByTag(crlType);
  747. if(!bagType) {
  748. PORT_SetError(SEC_ERROR_NO_MEMORY);
  749. goto loser;
  750. }
  751. rv = SECITEM_CopyItem(arena, &crlBag->bagID, &bagType->oid);
  752. if(rv != SECSuccess) {
  753. PORT_SetError(SEC_ERROR_NO_MEMORY);
  754. goto loser;
  755. }
  756. PORT_ArenaUnmark(arena, mark);
  757. return crlBag;
  758. loser:
  759. PORT_ArenaRelease(arena, mark);
  760. return NULL;
  761. }
  762. /* sec_PKCS12AddAttributeToBag
  763. * adds an attribute to a safeBag. currently, the only attributes supported
  764. * are those which are specified within PKCS 12.
  765. *
  766. * p12ctxt - the export context
  767. * safeBag - the safeBag to which attributes are appended
  768. * attrType - the attribute type
  769. * attrData - the attribute data
  770. */
  771. SECStatus
  772. sec_PKCS12AddAttributeToBag(SEC_PKCS12ExportContext *p12ctxt,
  773. sec_PKCS12SafeBag *safeBag, SECOidTag attrType,
  774. SECItem *attrData)
  775. {
  776. sec_PKCS12Attribute *attribute;
  777. void *mark = NULL, *dummy = NULL;
  778. SECOidData *oiddata = NULL;
  779. SECItem unicodeName = { siBuffer, NULL, 0};
  780. void *src = NULL;
  781. unsigned int nItems = 0;
  782. SECStatus rv;
  783. if(!safeBag || !p12ctxt) {
  784. return SECFailure;
  785. }
  786. mark = PORT_ArenaMark(safeBag->arena);
  787. /* allocate the attribute */
  788. attribute = (sec_PKCS12Attribute *)PORT_ArenaZAlloc(safeBag->arena,
  789. sizeof(sec_PKCS12Attribute));
  790. if(!attribute) {
  791. PORT_SetError(SEC_ERROR_NO_MEMORY);
  792. goto loser;
  793. }
  794. /* set up the attribute */
  795. oiddata = SECOID_FindOIDByTag(attrType);
  796. if(!oiddata) {
  797. PORT_SetError(SEC_ERROR_NO_MEMORY);
  798. goto loser;
  799. }
  800. if(SECITEM_CopyItem(p12ctxt->arena, &attribute->attrType, &oiddata->oid) !=
  801. SECSuccess) {
  802. PORT_SetError(SEC_ERROR_NO_MEMORY);
  803. goto loser;
  804. }
  805. nItems = 1;
  806. switch(attrType) {
  807. case SEC_OID_PKCS9_LOCAL_KEY_ID:
  808. {
  809. src = attrData;
  810. break;
  811. }
  812. case SEC_OID_PKCS9_FRIENDLY_NAME:
  813. {
  814. if(!sec_pkcs12_convert_item_to_unicode(p12ctxt->arena,
  815. &unicodeName, attrData, PR_FALSE,
  816. PR_FALSE, PR_TRUE)) {
  817. goto loser;
  818. }
  819. src = &unicodeName;
  820. break;
  821. }
  822. default:
  823. goto loser;
  824. }
  825. /* append the attribute to the attribute value list */
  826. attribute->attrValue = (SECItem **)PORT_ArenaZAlloc(p12ctxt->arena,
  827. ((nItems + 1) * sizeof(SECItem *)));
  828. if(!attribute->attrValue) {
  829. PORT_SetError(SEC_ERROR_NO_MEMORY);
  830. goto loser;
  831. }
  832. /* XXX this will need to be changed if attributes requiring more than
  833. * one element are ever used.
  834. */
  835. attribute->attrValue[0] = (SECItem *)PORT_ArenaZAlloc(p12ctxt->arena,
  836. sizeof(SECItem));
  837. if(!attribute->attrValue[0]) {
  838. PORT_SetError(SEC_ERROR_NO_MEMORY);
  839. goto loser;
  840. }
  841. attribute->attrValue[1] = NULL;
  842. rv = SECITEM_CopyItem(p12ctxt->arena, attribute->attrValue[0],
  843. (SECItem*)src);
  844. if(rv != SECSuccess) {
  845. PORT_SetError(SEC_ERROR_NO_MEMORY);
  846. goto loser;
  847. }
  848. /* append the attribute to the safeBag attributes */
  849. if(safeBag->nAttribs) {
  850. dummy = PORT_ArenaGrow(p12ctxt->arena, safeBag->attribs,
  851. ((safeBag->nAttribs + 1) * sizeof(sec_PKCS12Attribute *)),
  852. ((safeBag->nAttribs + 2) * sizeof(sec_PKCS12Attribute *)));
  853. safeBag->attribs = (sec_PKCS12Attribute **)dummy;
  854. } else {
  855. safeBag->attribs = (sec_PKCS12Attribute **)PORT_ArenaZAlloc(p12ctxt->arena,
  856. 2 * sizeof(sec_PKCS12Attribute *));
  857. dummy = safeBag->attribs;
  858. }
  859. if(!dummy) {
  860. goto loser;
  861. }
  862. safeBag->attribs[safeBag->nAttribs] = attribute;
  863. safeBag->attribs[++safeBag->nAttribs] = NULL;
  864. PORT_ArenaUnmark(p12ctxt->arena, mark);
  865. return SECSuccess;
  866. loser:
  867. if(mark) {
  868. PORT_ArenaRelease(p12ctxt->arena, mark);
  869. }
  870. return SECFailure;
  871. }
  872. /* SEC_PKCS12AddCert
  873. * Adds a certificate to the data being exported.
  874. *
  875. * p12ctxt - the export context
  876. * safe - the safeInfo to which the certificate is placed
  877. * nestedDest - if the cert is to be placed within a nested safeContents then,
  878. * this value is to be specified with the destination
  879. * cert - the cert to export
  880. * certDb - the certificate database handle
  881. * keyId - a unique identifier to associate a certificate/key pair
  882. * includeCertChain - PR_TRUE if the certificate chain is to be included.
  883. */
  884. SECStatus
  885. SEC_PKCS12AddCert(SEC_PKCS12ExportContext *p12ctxt, SEC_PKCS12SafeInfo *safe,
  886. void *nestedDest, CERTCertificate *cert,
  887. CERTCertDBHandle *certDb, SECItem *keyId,
  888. PRBool includeCertChain)
  889. {
  890. sec_PKCS12CertBag *certBag;
  891. sec_PKCS12SafeBag *safeBag;
  892. void *mark;
  893. SECStatus rv;
  894. SECItem nick = {siBuffer, NULL,0};
  895. if(!p12ctxt || !cert) {
  896. return SECFailure;
  897. }
  898. mark = PORT_ArenaMark(p12ctxt->arena);
  899. /* allocate the cert bag */
  900. certBag = sec_PKCS12NewCertBag(p12ctxt->arena,
  901. SEC_OID_PKCS9_X509_CERT);
  902. if(!certBag) {
  903. goto loser;
  904. }
  905. if(SECITEM_CopyItem(p12ctxt->arena, &certBag->value.x509Cert,
  906. &cert->derCert) != SECSuccess) {
  907. PORT_SetError(SEC_ERROR_NO_MEMORY);
  908. goto loser;
  909. }
  910. /* if the cert chain is to be included, we should only be exporting
  911. * the cert from our internal database.
  912. */
  913. if(includeCertChain) {
  914. CERTCertificateList *certList = CERT_CertChainFromCert(cert,
  915. certUsageSSLClient,
  916. PR_TRUE);
  917. unsigned int count = 0;
  918. if(!certList) {
  919. PORT_SetError(SEC_ERROR_NO_MEMORY);
  920. goto loser;
  921. }
  922. /* add cert chain */
  923. for(count = 0; count < (unsigned int)certList->len; count++) {
  924. if(SECITEM_CompareItem(&certList->certs[count], &cert->derCert)
  925. != SECEqual) {
  926. CERTCertificate *tempCert;
  927. /* decode the certificate */
  928. /* XXX
  929. * This was rather silly. The chain is constructed above
  930. * by finding all of the CERTCertificate's in the database.
  931. * Then the chain is put into a CERTCertificateList, which only
  932. * contains the DER. Finally, the DER was decoded, and the
  933. * decoded cert was sent recursively back to this function.
  934. * Beyond being inefficent, this causes data loss (specifically,
  935. * the nickname). Instead, for 3.4, we'll do a lookup by the
  936. * DER, which should return the cached entry.
  937. */
  938. tempCert = CERT_FindCertByDERCert(CERT_GetDefaultCertDB(),
  939. &certList->certs[count]);
  940. if(!tempCert) {
  941. CERT_DestroyCertificateList(certList);
  942. goto loser;
  943. }
  944. /* add the certificate */
  945. if(SEC_PKCS12AddCert(p12ctxt, safe, nestedDest, tempCert,
  946. certDb, NULL, PR_FALSE) != SECSuccess) {
  947. CERT_DestroyCertificate(tempCert);
  948. CERT_DestroyCertificateList(certList);
  949. goto loser;
  950. }
  951. CERT_DestroyCertificate(tempCert);
  952. }
  953. }
  954. CERT_DestroyCertificateList(certList);
  955. }
  956. /* if the certificate has a nickname, we will set the friendly name
  957. * to that.
  958. */
  959. if(cert->nickname) {
  960. if (cert->slot && !PK11_IsInternal(cert->slot)) {
  961. /*
  962. * The cert is coming off of an external token,
  963. * let's strip the token name from the nickname
  964. * and only add what comes after the colon as the
  965. * nickname. -javi
  966. */
  967. char *delimit;
  968. delimit = PORT_Strchr(cert->nickname,':');
  969. if (delimit == NULL) {
  970. nick.data = (unsigned char *)cert->nickname;
  971. nick.len = PORT_Strlen(cert->nickname);
  972. } else {
  973. delimit++;
  974. nick.data = (unsigned char *)PORT_ArenaStrdup(p12ctxt->arena,
  975. delimit);
  976. nick.len = PORT_Strlen(delimit);
  977. }
  978. } else {
  979. nick.data = (unsigned char *)cert->nickname;
  980. nick.len = PORT_Strlen(cert->nickname);
  981. }
  982. }
  983. safeBag = sec_PKCS12CreateSafeBag(p12ctxt, SEC_OID_PKCS12_V1_CERT_BAG_ID,
  984. certBag);
  985. if(!safeBag) {
  986. goto loser;
  987. }
  988. /* add the friendly name and keyId attributes, if necessary */
  989. if(nick.data) {
  990. if(sec_PKCS12AddAttributeToBag(p12ctxt, safeBag,
  991. SEC_OID_PKCS9_FRIENDLY_NAME, &nick)
  992. != SECSuccess) {
  993. goto loser;
  994. }
  995. }
  996. if(keyId) {
  997. if(sec_PKCS12AddAttributeToBag(p12ctxt, safeBag, SEC_OID_PKCS9_LOCAL_KEY_ID,
  998. keyId) != SECSuccess) {
  999. goto loser;
  1000. }
  1001. }
  1002. /* append the cert safeBag */
  1003. if(nestedDest) {
  1004. rv = sec_pkcs12_append_bag_to_safe_contents(p12ctxt->arena,
  1005. (sec_PKCS12SafeContents*)nestedDest,
  1006. safeBag);
  1007. } else {
  1008. rv = sec_pkcs12_append_bag(p12ctxt, safe, safeBag);
  1009. }
  1010. if(rv != SECSuccess) {
  1011. goto loser;
  1012. }
  1013. PORT_ArenaUnmark(p12ctxt->arena, mark);
  1014. return SECSuccess;
  1015. loser:
  1016. if(mark) {
  1017. PORT_ArenaRelease(p12ctxt->arena, mark);
  1018. }
  1019. return SECFailure;
  1020. }
  1021. /* SEC_PKCS12AddKeyForCert
  1022. * Extracts the key associated with a particular certificate and exports
  1023. * it.
  1024. *
  1025. * p12ctxt - the export context
  1026. * safe - the safeInfo to place the key in
  1027. * nestedDest - the nested safeContents to place a key
  1028. * cert - the certificate which the key belongs to
  1029. * shroudKey - encrypt the private key for export. This value should
  1030. * always be true. lower level code will not allow the export
  1031. * of unencrypted private keys.
  1032. * algorithm - the algorithm with which to encrypt the private key
  1033. * pwitem - the password to encrypt the private key with
  1034. * keyId - the keyID attribute
  1035. * nickName - the nickname attribute
  1036. */
  1037. SECStatus
  1038. SEC_PKCS12AddKeyForCert(SEC_PKCS12ExportContext *p12ctxt, SEC_PKCS12SafeInfo *safe,
  1039. void *nestedDest, CERTCertificate *cert,
  1040. PRBool shroudKey, SECOidTag algorithm, SECItem *pwitem,
  1041. SECItem *keyId, SECItem *nickName)
  1042. {
  1043. void *mark;
  1044. void *keyItem;
  1045. SECOidTag keyType;
  1046. SECStatus rv = SECFailure;
  1047. SECItem nickname = {siBuffer,NULL,0}, uniPwitem = {siBuffer, NULL, 0};
  1048. sec_PKCS12SafeBag *returnBag;
  1049. if(!p12ctxt || !cert || !safe) {
  1050. return SECFailure;
  1051. }
  1052. mark = PORT_ArenaMark(p12ctxt->arena);
  1053. /* retrieve the key based upon the type that it is and
  1054. * specify the type of safeBag to store the key in
  1055. */
  1056. if(!shroudKey) {
  1057. /* extract the key unencrypted. this will most likely go away */
  1058. SECKEYPrivateKeyInfo *pki = PK11_ExportPrivateKeyInfo(cert,
  1059. p12ctxt->wincx);
  1060. if(!pki) {
  1061. PORT_ArenaRelease(p12ctxt->arena, mark);
  1062. PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY);
  1063. return SECFailure;
  1064. }
  1065. keyItem = PORT_ArenaZAlloc(p12ctxt->arena, sizeof(SECKEYPrivateKeyInfo));
  1066. if(!keyItem) {
  1067. PORT_SetError(SEC_ERROR_NO_MEMORY);
  1068. goto loser;
  1069. }
  1070. rv = SECKEY_CopyPrivateKeyInfo(p12ctxt->arena,
  1071. (SECKEYPrivateKeyInfo *)keyItem, pki);
  1072. keyType = SEC_OID_PKCS12_V1_KEY_BAG_ID;
  1073. SECKEY_DestroyPrivateKeyInfo(pki, PR_TRUE);
  1074. } else {
  1075. /* extract the key encrypted */
  1076. SECKEYEncryptedPrivateKeyInfo *epki = NULL;
  1077. PK11SlotInfo *slot = NULL;
  1078. if(!sec_pkcs12_convert_item_to_unicode(p12ctxt->arena, &uniPwitem,
  1079. pwitem, PR_TRUE, PR_TRUE, PR_TRUE)) {
  1080. PORT_SetError(SEC_ERROR_NO_MEMORY);
  1081. goto loser;
  1082. }
  1083. /* we want to make sure to take the key out of the key slot */
  1084. if(PK11_IsInternal(p12ctxt->slot)) {
  1085. slot = PK11_GetInternalKeySlot();
  1086. } else {
  1087. slot = PK11_ReferenceSlot(p12ctxt->slot);
  1088. }
  1089. epki = PK11_ExportEncryptedPrivateKeyInfo(slot, algorithm,
  1090. &uniPwitem, cert, 1,
  1091. p12ctxt->wincx);
  1092. PK11_FreeSlot(slot);
  1093. if(!epki) {
  1094. PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY);
  1095. goto loser;
  1096. }
  1097. keyItem = PORT_ArenaZAlloc(p12ctxt->arena,
  1098. sizeof(SECKEYEncryptedPrivateKeyInfo));
  1099. if(!keyItem) {
  1100. PORT_SetError(SEC_ERROR_NO_MEMORY);
  1101. goto loser;
  1102. }
  1103. rv = SECKEY_CopyEncryptedPrivateKeyInfo(p12ctxt->arena,
  1104. (SECKEYEncryptedPrivateKeyInfo *)keyItem,
  1105. epki);
  1106. keyType = SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID;
  1107. SECKEY_DestroyEncryptedPrivateKeyInfo(epki, PR_TRUE);
  1108. }
  1109. if(rv != SECSuccess) {
  1110. goto loser;
  1111. }
  1112. /* if no nickname specified, let's see if the certificate has a
  1113. * nickname.
  1114. */
  1115. if(!nickName) {
  1116. if(cert->nickname) {
  1117. nickname.data = (unsigned char *)cert->nickname;
  1118. nickname.len = PORT_Strlen(cert->nickname);
  1119. nickName = &nickname;
  1120. }
  1121. }
  1122. /* create the safe bag and set any attributes */
  1123. returnBag = sec_PKCS12CreateSafeBag(p12ctxt, keyType, keyItem);
  1124. if(!returnBag) {
  1125. rv = SECFailure;
  1126. goto loser;
  1127. }
  1128. if(nickName) {
  1129. if(sec_PKCS12AddAttributeToBag(p12ctxt, returnBag,
  1130. SEC_OID_PKCS9_FRIENDLY_NAME, nickName)
  1131. != SECSuccess) {
  1132. goto loser;
  1133. }
  1134. }
  1135. if(keyId) {
  1136. if(sec_PKCS12AddAttributeToBag(p12ctxt, returnBag, SEC_OID_PKCS9_LOCAL_KEY_ID,
  1137. keyId) != SECSuccess) {
  1138. goto loser;
  1139. }
  1140. }
  1141. if(nestedDest) {
  1142. rv = sec_pkcs12_append_bag_to_safe_contents(p12ctxt->arena,
  1143. (sec_PKCS12SafeContents*)nestedDest,
  1144. returnBag);
  1145. } else {
  1146. rv = sec_pkcs12_append_bag(p12ctxt, safe, returnBag);
  1147. }
  1148. loser:
  1149. if (rv != SECSuccess) {
  1150. PORT_ArenaRelease(p12ctxt->arena, mark);
  1151. } else {
  1152. PORT_ArenaUnmark(p12ctxt->arena, mark);
  1153. }
  1154. return rv;
  1155. }
  1156. /* SEC_PKCS12AddCertOrChainAndKey
  1157. * Add a certificate and key pair to be exported.
  1158. *
  1159. * p12ctxt - the export context
  1160. * certSafe - the safeInfo where the cert is stored
  1161. * certNestedDest - the nested safeContents to store the cert
  1162. * keySafe - the safeInfo where the key is stored
  1163. * keyNestedDest - the nested safeContents to store the key
  1164. * shroudKey - extract the private key encrypted?
  1165. * pwitem - the password with which the key is encrypted
  1166. * algorithm - the algorithm with which the key is encrypted
  1167. * includeCertChain - also add certs from chain to bag.
  1168. */
  1169. SECStatus
  1170. SEC_PKCS12AddCertOrChainAndKey(SEC_PKCS12ExportContext *p12ctxt,
  1171. void *certSafe, void *certNestedDest,
  1172. CERTCertificate *cert, CERTCertDBHandle *certDb,
  1173. void *keySafe, void *keyNestedDest,
  1174. PRBool shroudKey, SECItem *pwitem,
  1175. SECOidTag algorithm, PRBool includeCertChain)
  1176. {
  1177. SECStatus rv = SECFailure;
  1178. SGNDigestInfo *digest = NULL;
  1179. void *mark = NULL;
  1180. if(!p12ctxt || !certSafe || !keySafe || !cert) {
  1181. return SECFailure;
  1182. }
  1183. mark = PORT_ArenaMark(p12ctxt->arena);
  1184. /* generate the thumbprint of the cert to use as a keyId */
  1185. digest = sec_pkcs12_compute_thumbprint(&cert->derCert);
  1186. if(!digest) {
  1187. PORT_ArenaRelease(p12ctxt->arena, mark);
  1188. return SECFailure;
  1189. }
  1190. /* add the certificate */
  1191. rv = SEC_PKCS12AddCert(p12ctxt, (SEC_PKCS12SafeInfo*)certSafe,
  1192. (SEC_PKCS12SafeInfo*)certNestedDest, cert, certDb,
  1193. &digest->digest, includeCertChain);
  1194. if(rv != SECSuccess) {
  1195. goto loser;
  1196. }
  1197. /* add the key */
  1198. rv = SEC_PKCS12AddKeyForCert(p12ctxt, (SEC_PKCS12SafeInfo*)keySafe,
  1199. keyNestedDest, cert,
  1200. shroudKey, algorithm, pwitem,
  1201. &digest->digest, NULL );
  1202. if(rv != SECSuccess) {
  1203. goto loser;
  1204. }
  1205. SGN_DestroyDigestInfo(digest);
  1206. PORT_ArenaUnmark(p12ctxt->arena, mark);
  1207. return SECSuccess;
  1208. loser:
  1209. SGN_DestroyDigestInfo(digest);
  1210. PORT_ArenaRelease(p12ctxt->arena, mark);
  1211. return SECFailure;
  1212. }
  1213. /* like SEC_PKCS12AddCertOrChainAndKey, but always adds cert chain */
  1214. SECStatus
  1215. SEC_PKCS12AddCertAndKey(SEC_PKCS12ExportContext *p12ctxt,
  1216. void *certSafe, void *certNestedDest,
  1217. CERTCertificate *cert, CERTCertDBHandle *certDb,
  1218. void *keySafe, void *keyNestedDest,
  1219. PRBool shroudKey, SECItem *pwItem, SECOidTag algorithm)
  1220. {
  1221. return SEC_PKCS12AddCertOrChainAndKey(p12ctxt, certSafe, certNestedDest,
  1222. cert, certDb, keySafe, keyNestedDest, shroudKey, pwItem,
  1223. algorithm, PR_TRUE);
  1224. }
  1225. /* SEC_PKCS12CreateNestedSafeContents
  1226. * Allows nesting of safe contents to be implemented. No limit imposed on
  1227. * depth.
  1228. *
  1229. * p12ctxt - the export context
  1230. * baseSafe - the base safeInfo
  1231. * nestedDest - a parent safeContents (?)
  1232. */
  1233. void *
  1234. SEC_PKCS12CreateNestedSafeContents(SEC_PKCS12ExportContext *p12ctxt,
  1235. void *baseSafe, void *nestedDest)
  1236. {
  1237. sec_PKCS12SafeContents *newSafe;
  1238. sec_PKCS12SafeBag *safeContentsBag;
  1239. void *mark;
  1240. SECStatus rv;
  1241. if(!p12ctxt || !baseSafe) {
  1242. return NULL;
  1243. }
  1244. mark = PORT_ArenaMark(p12ctxt->arena);
  1245. newSafe = sec_PKCS12CreateSafeContents(p12ctxt->arena);
  1246. if(!newSafe) {
  1247. PORT_ArenaRelease(p12ctxt->arena, mark);
  1248. PORT_SetError(SEC_ERROR_NO_MEMORY);
  1249. return NULL;
  1250. }
  1251. /* create the safeContents safeBag */
  1252. safeContentsBag = sec_PKCS12CreateSafeBag(p12ctxt,
  1253. SEC_OID_PKCS12_V1_SAFE_CONTENTS_BAG_ID,
  1254. newSafe);
  1255. if(!safeContentsBag) {
  1256. goto loser;
  1257. }
  1258. /* append the safeContents to the appropriate area */
  1259. if(nestedDest) {
  1260. rv = sec_pkcs12_append_bag_to_safe_contents(p12ctxt->arena,
  1261. (sec_PKCS12SafeContents*)nestedDest,
  1262. safeContentsBag);
  1263. } else {
  1264. rv = sec_pkcs12_append_bag(p12ctxt, (SEC_PKCS12SafeInfo*)baseSafe,
  1265. safeContentsBag);
  1266. }
  1267. if(rv != SECSuccess) {
  1268. goto loser;
  1269. }
  1270. PORT_ArenaUnmark(p12ctxt->arena, mark);
  1271. return newSafe;
  1272. loser:
  1273. PORT_ArenaRelease(p12ctxt->arena, mark);
  1274. return NULL;
  1275. }
  1276. /*********************************
  1277. * Encoding routines
  1278. *********************************/
  1279. /* set up the encoder context based on information in the export context
  1280. * and return the newly allocated enocoder context. A return of NULL
  1281. * indicates an error occurred.
  1282. */
  1283. sec_PKCS12EncoderContext *
  1284. sec_pkcs12_encoder_start_context(SEC_PKCS12ExportContext *p12exp)
  1285. {
  1286. sec_PKCS12EncoderContext *p12enc = NULL;
  1287. unsigned int i, nonEmptyCnt;
  1288. SECStatus rv;
  1289. SECItem ignore = {0};
  1290. void *mark;
  1291. if(!p12exp || !p12exp->safeInfos) {
  1292. return NULL;
  1293. }
  1294. /* check for any empty safes and skip them */
  1295. i = nonEmptyCnt = 0;
  1296. while(p12exp->safeInfos[i]) {
  1297. if(p12exp->safeInfos[i]->itemCount) {
  1298. nonEmptyCnt++;
  1299. }
  1300. i++;
  1301. }
  1302. if(nonEmptyCnt == 0) {
  1303. return NULL;
  1304. }
  1305. p12exp->authSafe.encodedSafes[nonEmptyCnt] = NULL;
  1306. /* allocate the encoder context */
  1307. mark = PORT_ArenaMark(p12exp->arena);
  1308. p12enc = PORT_ArenaZNew(p12exp->arena, sec_PKCS12EncoderContext);
  1309. if(!p12enc) {
  1310. PORT_SetError(SEC_ERROR_NO_MEMORY);
  1311. return NULL;
  1312. }
  1313. p12enc->arena = p12exp->arena;
  1314. p12enc->p12exp = p12exp;
  1315. /* set up the PFX version and information */
  1316. PORT_Memset(&p12enc->pfx, 0, sizeof(sec_PKCS12PFXItem));
  1317. if(!SEC_ASN1EncodeInteger(p12exp->arena, &(p12enc->pfx.version),
  1318. SEC_PKCS12_VERSION) ) {
  1319. PORT_SetError(SEC_ERROR_NO_MEMORY);
  1320. goto loser;
  1321. }
  1322. /* set up the authenticated safe content info based on the
  1323. * type of integrity being used. this should be changed to
  1324. * enforce integrity mode, but will not be implemented until
  1325. * it is confirmed that integrity must be in place
  1326. */
  1327. if(p12exp->integrityEnabled && !p12exp->pwdIntegrity) {
  1328. SECStatus rv;
  1329. /* create public key integrity mode */
  1330. p12enc->aSafeCinfo = SEC_PKCS7CreateSignedData(
  1331. p12exp->integrityInfo.pubkeyInfo.cert,
  1332. certUsageEmailSigner,
  1333. p12exp->integrityInfo.pubkeyInfo.certDb,
  1334. p12exp->integrityInfo.pubkeyInfo.algorithm,
  1335. NULL,
  1336. p12exp->pwfn,
  1337. p12exp->pwfnarg);
  1338. if(!p12enc->aSafeCinfo) {
  1339. goto loser;
  1340. }
  1341. if(SEC_PKCS7IncludeCertChain(p12enc->aSafeCinfo,NULL) != SECSuccess) {
  1342. goto loser;
  1343. }
  1344. rv = SEC_PKCS7AddSigningTime(p12enc->aSafeCinfo);
  1345. PORT_Assert(rv == SECSuccess);
  1346. } else {
  1347. p12enc->aSafeCinfo = SEC_PKCS7CreateData();
  1348. /* init password pased integrity mode */
  1349. if(p12exp->integrityEnabled) {
  1350. SECItem pwd = {siBuffer,NULL, 0};
  1351. SECItem *salt = sec_pkcs12_generate_salt();
  1352. PK11SymKey *symKey;
  1353. SECItem *params;
  1354. CK_MECHANISM_TYPE integrityMechType;
  1355. CK_MECHANISM_TYPE hmacMechType;
  1356. /* zero out macData and set values */
  1357. PORT_Memset(&p12enc->mac, 0, sizeof(sec_PKCS12MacData));
  1358. if(!salt) {
  1359. PORT_SetError(SEC_ERROR_NO_MEMORY);
  1360. goto loser;
  1361. }
  1362. if(SECITEM_CopyItem(p12exp->arena, &(p12enc->mac.macSalt), salt)
  1363. != SECSuccess) {
  1364. PORT_SetError(SEC_ERROR_NO_MEMORY);
  1365. goto loser;
  1366. }
  1367. /* generate HMAC key */
  1368. if(!sec_pkcs12_convert_item_to_unicode(NULL, &pwd,
  1369. p12exp->integrityInfo.pwdInfo.password, PR_TRUE,
  1370. PR_TRUE, PR_TRUE)) {
  1371. goto loser;
  1372. }
  1373. /*
  1374. * This code only works with PKCS #12 Mac using PKCS #5 v1
  1375. * PBA keygens. PKCS #5 v2 support will require a change to
  1376. * the PKCS #12 spec.
  1377. */
  1378. params = PK11_CreatePBEParams(salt, &pwd, 1);
  1379. SECITEM_ZfreeItem(salt, PR_TRUE);
  1380. SECITEM_ZfreeItem(&pwd, PR_FALSE);
  1381. /* get the PBA Mechanism to generate the key */
  1382. switch (p12exp->integrityInfo.pwdInfo.algorithm) {
  1383. case SEC_OID_SHA1:
  1384. integrityMechType = CKM_PBA_SHA1_WITH_SHA1_HMAC; break;
  1385. case SEC_OID_MD5:
  1386. integrityMechType = CKM_NETSCAPE_PBE_MD5_HMAC_KEY_GEN; break;
  1387. case SEC_OID_MD2:
  1388. integrityMechType = CKM_NETSCAPE_PBE_MD2_HMAC_KEY_GEN; break;
  1389. default:
  1390. goto loser;
  1391. }
  1392. /* generate the key */
  1393. symKey = PK11_KeyGen(NULL, integrityMechType, params, 20, NULL);
  1394. PK11_DestroyPBEParams(params);
  1395. if(!symKey) {
  1396. goto loser;
  1397. }
  1398. /* initialize HMAC */
  1399. /* Get the HMAC mechanism from the hash OID */
  1400. hmacMechType= sec_pkcs12_algtag_to_mech(
  1401. p12exp->integrityInfo.pwdInfo.algorithm);
  1402. p12enc->hmacCx = PK11_CreateContextBySymKey( hmacMechType,
  1403. CKA_SIGN, symKey, &ignore);
  1404. PK11_FreeSymKey(symKey);
  1405. if(!p12enc->hmacCx) {
  1406. PORT_SetError(SEC_ERROR_NO_MEMORY);
  1407. goto loser;
  1408. }
  1409. rv = PK11_DigestBegin(p12enc->hmacCx);
  1410. if (rv != SECSuccess)
  1411. goto loser;
  1412. }
  1413. }
  1414. if(!p12enc->aSafeCinfo) {
  1415. goto loser;
  1416. }
  1417. PORT_ArenaUnmark(p12exp->arena, mark);
  1418. return p12enc;
  1419. loser:
  1420. if(p12enc) {
  1421. if(p12enc->aSafeCinfo) {
  1422. SEC_PKCS7DestroyContentInfo(p12enc->aSafeCinfo);
  1423. }
  1424. if(p12enc->hmacCx) {
  1425. PK11_DestroyContext(p12enc->hmacCx, PR_TRUE);
  1426. }
  1427. }
  1428. if (p12exp->arena != NULL)
  1429. PORT_ArenaRelease(p12exp->arena, mark);
  1430. return NULL;
  1431. }
  1432. /* The outermost ASN.1 encoder calls this function for output.
  1433. ** This function calls back to the library caller's output routine,
  1434. ** which typically writes to a PKCS12 file.
  1435. */
  1436. static void
  1437. sec_P12A1OutputCB_Outer(void *arg, const char *buf, unsigned long len,
  1438. int depth, SEC_ASN1EncodingPart data_kind)
  1439. {
  1440. struct sec_pkcs12_encoder_output *output;
  1441. output = (struct sec_pkcs12_encoder_output*)arg;
  1442. (* output->outputfn)(output->outputarg, buf, len);
  1443. }
  1444. /* The "middle" and "inner" ASN.1 encoders call this function to output.
  1445. ** This function does HMACing, if appropriate, and then buffers the data.
  1446. ** The buffered data is eventually passed down to the underlying PKCS7 encoder.
  1447. */
  1448. static void
  1449. sec_P12A1OutputCB_HmacP7Update(void *arg, const char *buf,
  1450. unsigned long len,
  1451. int depth,
  1452. SEC_ASN1EncodingPart data_kind)
  1453. {
  1454. sec_pkcs12OutputBuffer * bufcx = (sec_pkcs12OutputBuffer *)arg;
  1455. if(!buf || !len)
  1456. return;
  1457. if (bufcx->hmacCx) {
  1458. PK11_DigestOp(bufcx->hmacCx, (unsigned char *)buf, len);
  1459. }
  1460. /* buffer */
  1461. if (bufcx->numBytes > 0) {
  1462. int toCopy;
  1463. if (len + bufcx->numBytes <= bufcx->bufBytes) {
  1464. memcpy(bufcx->buf + bufcx->numBytes, buf, len);
  1465. bufcx->numBytes += len;
  1466. if (bufcx->numBytes < bufcx->bufBytes)
  1467. return;
  1468. SEC_PKCS7EncoderUpdate(bufcx->p7eCx, bufcx->buf, bufcx->bufBytes);
  1469. bufcx->numBytes = 0;
  1470. return;
  1471. }
  1472. toCopy = bufcx->bufBytes - bufcx->numBytes;
  1473. memcpy(bufcx->buf + bufcx->numBytes, buf, toCopy);
  1474. SEC_PKCS7EncoderUpdate(bufcx->p7eCx, bufcx->buf, bufcx->bufBytes);
  1475. bufcx->numBytes = 0;
  1476. len -= toCopy;
  1477. buf += toCopy;
  1478. }
  1479. /* buffer is presently empty */
  1480. if (len >= bufcx->bufBytes) {
  1481. /* Just pass it through */
  1482. SEC_PKCS7EncoderUpdate(bufcx->p7eCx, buf, len);
  1483. } else {
  1484. /* copy it all into the buffer, and return */
  1485. memcpy(bufcx->buf, buf, len);
  1486. bufcx->numBytes = len;
  1487. }
  1488. }
  1489. void
  1490. sec_FlushPkcs12OutputBuffer( sec_pkcs12OutputBuffer * bufcx)
  1491. {
  1492. if (bufcx->numBytes > 0) {
  1493. SEC_PKCS7EncoderUpdate(bufcx->p7eCx, bufcx->buf, bufcx->numBytes);
  1494. bufcx->numBytes = 0;
  1495. }
  1496. }
  1497. /* Feeds the output of a PKCS7 encoder into the next outward ASN.1 encoder.
  1498. ** This function is used by both the inner and middle PCS7 encoders.
  1499. */
  1500. static void
  1501. sec_P12P7OutputCB_CallA1Update(void *arg, const char *buf, unsigned long len)
  1502. {
  1503. SEC_ASN1EncoderContext *cx = (SEC_ASN1EncoderContext*)arg;
  1504. if (!buf || !len)
  1505. return;
  1506. SEC_ASN1EncoderUpdate(cx, buf, len);
  1507. }
  1508. /* this function encodes content infos which are part of the
  1509. * sequence of content infos labeled AuthenticatedSafes
  1510. */
  1511. static SECStatus
  1512. sec_pkcs12_encoder_asafe_process(sec_PKCS12EncoderContext *p12ecx)
  1513. {
  1514. SEC_PKCS7EncoderContext *innerP7ecx;
  1515. SEC_PKCS7ContentInfo *cinfo;
  1516. PK11SymKey *bulkKey = NULL;
  1517. SEC_ASN1EncoderContext *innerA1ecx = NULL;
  1518. SECStatus rv = SECSuccess;
  1519. if(p12ecx->currentSafe < p12ecx->p12exp->authSafe.safeCount) {
  1520. SEC_PKCS12SafeInfo *safeInfo;
  1521. SECOidTag cinfoType;
  1522. safeInfo = p12ecx->p12exp->safeInfos[p12ecx->currentSafe];
  1523. /* skip empty safes */
  1524. if(safeInfo->itemCount == 0) {
  1525. return SECSuccess;
  1526. }
  1527. cinfo = safeInfo->cinfo;
  1528. cinfoType = SEC_PKCS7ContentType(cinfo);
  1529. /* determine the safe type and set the appropriate argument */
  1530. switch(cinfoType) {
  1531. case SEC_OID_PKCS7_DATA:
  1532. case SEC_OID_PKCS7_ENVELOPED_DATA:
  1533. break;
  1534. case SEC_OID_PKCS7_ENCRYPTED_DATA:
  1535. bulkKey = safeInfo->encryptionKey;
  1536. PK11_SetSymKeyUserData(bulkKey, &safeInfo->pwitem, NULL);
  1537. b

Large files files are truncated, but you can click here to view the full file