1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5 #include "p12t.h"
6 #include "p12.h"
7 #include "plarena.h"
8 #include "secitem.h"
9 #include "secoid.h"
10 #include "seccomon.h"
11 #include "secport.h"
12 #include "cert.h"
13 #include "secpkcs5.h"
14 #include "secpkcs7.h"
15 #include "secasn1.h"
16 #include "secerr.h"
17 #include "sechash.h"
18 #include "pk11func.h"
19 #include "p12plcy.h"
20 #include "p12local.h"
21 #include "prcpucfg.h"
22
23 extern const int NSS_PBE_DEFAULT_ITERATION_COUNT; /* defined in p7create.c */
24
25 /*
26 ** This PKCS12 file encoder uses numerous nested ASN.1 and PKCS7 encoder
27 ** contexts. It can be difficult to keep straight. Here's a picture:
28 **
29 ** "outer" ASN.1 encoder. The output goes to the library caller's CB.
30 ** "middle" PKCS7 encoder. Feeds the "outer" ASN.1 encoder.
31 ** "middle" ASN1 encoder. Encodes the encrypted aSafes.
32 ** Feeds the "middle" P7 encoder above.
33 ** "inner" PKCS7 encoder. Encrypts the "authenticated Safes" (aSafes)
34 ** Feeds the "middle" ASN.1 encoder above.
35 ** "inner" ASN.1 encoder. Encodes the unencrypted aSafes.
36 ** Feeds the "inner" P7 enocder above.
37 **
38 ** Buffering has been added at each point where the output of an ASN.1
39 ** encoder feeds the input of a PKCS7 encoder.
40 */
41
42 /*********************************
43 * Output buffer object, used to buffer output from ASN.1 encoder
44 * before passing data on down to the next PKCS7 encoder.
45 *********************************/
46
47 #define PK12_OUTPUT_BUFFER_SIZE 8192
48
49 struct sec_pkcs12OutputBufferStr {
50 SEC_PKCS7EncoderContext *p7eCx;
51 PK11Context *hmacCx;
52 unsigned int numBytes;
53 unsigned int bufBytes;
54 char buf[PK12_OUTPUT_BUFFER_SIZE];
55 };
56 typedef struct sec_pkcs12OutputBufferStr sec_pkcs12OutputBuffer;
57
58 /*********************************
59 * Structures used in exporting the PKCS 12 blob
60 *********************************/
61
62 /* A SafeInfo is used for each ContentInfo which makes up the
63 * sequence of safes in the AuthenticatedSafe portion of the
64 * PFX structure.
65 */
66 struct SEC_PKCS12SafeInfoStr {
67 PLArenaPool *arena;
68
69 /* information for setting up password encryption */
70 SECItem pwitem;
71 SECOidTag algorithm;
72 PK11SymKey *encryptionKey;
73
74 /* how many items have been stored in this safe,
75 * we will skip any safe which does not contain any
76 * items
77 */
78 unsigned int itemCount;
79
80 /* the content info for the safe */
81 SEC_PKCS7ContentInfo *cinfo;
82
83 sec_PKCS12SafeContents *safe;
84 };
85
86 /* An opaque structure which contains information needed for exporting
87 * certificates and keys through PKCS 12.
88 */
89 struct SEC_PKCS12ExportContextStr {
90 PLArenaPool *arena;
91 PK11SlotInfo *slot;
92 void *wincx;
93
94 /* integrity information */
95 PRBool integrityEnabled;
96 PRBool pwdIntegrity;
97 union {
98 struct sec_PKCS12PasswordModeInfo pwdInfo;
99 struct sec_PKCS12PublicKeyModeInfo pubkeyInfo;
100 } integrityInfo;
101
102 /* helper functions */
103 /* retrieve the password call back */
104 SECKEYGetPasswordKey pwfn;
105 void *pwfnarg;
106
107 /* safe contents bags */
108 SEC_PKCS12SafeInfo **safeInfos;
109 unsigned int safeInfoCount;
110
111 /* the sequence of safes */
112 sec_PKCS12AuthenticatedSafe authSafe;
113
114 /* information needing deletion */
115 CERTCertificate **certList;
116 };
117
118 /* structures for passing information to encoder callbacks when processing
119 * data through the ASN1 engine.
120 */
121 struct sec_pkcs12_encoder_output {
122 SEC_PKCS12EncoderOutputCallback outputfn;
123 void *outputarg;
124 };
125
126 struct sec_pkcs12_hmac_and_output_info {
127 void *arg;
128 struct sec_pkcs12_encoder_output output;
129 };
130
131 /* An encoder context which is used for the actual encoding
132 * portion of PKCS 12.
133 */
134 typedef struct sec_PKCS12EncoderContextStr {
135 PLArenaPool *arena;
136 SEC_PKCS12ExportContext *p12exp;
137
138 /* encoder information - this is set up based on whether
139 * password based or public key pased privacy is being used
140 */
141 SEC_ASN1EncoderContext *outerA1ecx;
142 union {
143 struct sec_pkcs12_hmac_and_output_info hmacAndOutputInfo;
144 struct sec_pkcs12_encoder_output encOutput;
145 } output;
146
147 /* structures for encoding of PFX and MAC */
148 sec_PKCS12PFXItem pfx;
149 sec_PKCS12MacData mac;
150
151 /* authenticated safe encoding tracking information */
152 SEC_PKCS7ContentInfo *aSafeCinfo;
153 SEC_PKCS7EncoderContext *middleP7ecx;
154 SEC_ASN1EncoderContext *middleA1ecx;
155 unsigned int currentSafe;
156
157 /* hmac context */
158 PK11Context *hmacCx;
159
160 /* output buffers */
161 sec_pkcs12OutputBuffer middleBuf;
162 sec_pkcs12OutputBuffer innerBuf;
163
164 } sec_PKCS12EncoderContext;
165
166 /*********************************
167 * Export setup routines
168 *********************************/
169
170 /* SEC_PKCS12CreateExportContext
171 * Creates an export context and sets the unicode and password retrieval
172 * callbacks. This is the first call which must be made when exporting
173 * a PKCS 12 blob.
174 *
175 * pwfn, pwfnarg - password retrieval callback and argument. these are
176 * required for password-authentication mode.
177 */
178 SEC_PKCS12ExportContext *
SEC_PKCS12CreateExportContext(SECKEYGetPasswordKey pwfn,void * pwfnarg,PK11SlotInfo * slot,void * wincx)179 SEC_PKCS12CreateExportContext(SECKEYGetPasswordKey pwfn, void *pwfnarg,
180 PK11SlotInfo *slot, void *wincx)
181 {
182 PLArenaPool *arena = NULL;
183 SEC_PKCS12ExportContext *p12ctxt = NULL;
184
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
192 p12ctxt = (SEC_PKCS12ExportContext *)PORT_ArenaZAlloc(arena,
193 sizeof(SEC_PKCS12ExportContext));
194 if (!p12ctxt) {
195 PORT_SetError(SEC_ERROR_NO_MEMORY);
196 goto loser;
197 }
198
199 /* password callback for key retrieval */
200 p12ctxt->pwfn = pwfn;
201 p12ctxt->pwfnarg = pwfnarg;
202
203 p12ctxt->integrityEnabled = PR_FALSE;
204 p12ctxt->arena = arena;
205 p12ctxt->wincx = wincx;
206 p12ctxt->slot = (slot) ? PK11_ReferenceSlot(slot) : PK11_GetInternalSlot();
207
208 return p12ctxt;
209
210 loser:
211 if (arena) {
212 PORT_FreeArena(arena, PR_TRUE);
213 }
214
215 return NULL;
216 }
217
218 /*
219 * Adding integrity mode
220 */
221
222 /* SEC_PKCS12AddPasswordIntegrity
223 * Add password integrity to the exported data. If an integrity method
224 * has already been set, then return an error.
225 *
226 * p12ctxt - the export context
227 * pwitem - the password for integrity mode
228 * integAlg - the integrity algorithm to use for authentication.
229 */
230 SECStatus
SEC_PKCS12AddPasswordIntegrity(SEC_PKCS12ExportContext * p12ctxt,SECItem * pwitem,SECOidTag integAlg)231 SEC_PKCS12AddPasswordIntegrity(SEC_PKCS12ExportContext *p12ctxt,
232 SECItem *pwitem, SECOidTag integAlg)
233 {
234 if (!p12ctxt || p12ctxt->integrityEnabled) {
235 return SECFailure;
236 }
237
238 /* set up integrity information */
239 p12ctxt->pwdIntegrity = PR_TRUE;
240 p12ctxt->integrityInfo.pwdInfo.password =
241 (SECItem *)PORT_ArenaZAlloc(p12ctxt->arena, sizeof(SECItem));
242 if (!p12ctxt->integrityInfo.pwdInfo.password) {
243 PORT_SetError(SEC_ERROR_NO_MEMORY);
244 return SECFailure;
245 }
246 if (SECITEM_CopyItem(p12ctxt->arena,
247 p12ctxt->integrityInfo.pwdInfo.password, pwitem) != SECSuccess) {
248 PORT_SetError(SEC_ERROR_NO_MEMORY);
249 return SECFailure;
250 }
251 p12ctxt->integrityInfo.pwdInfo.algorithm = integAlg;
252 p12ctxt->integrityEnabled = PR_TRUE;
253
254 return SECSuccess;
255 }
256
257 /* SEC_PKCS12AddPublicKeyIntegrity
258 * Add public key integrity to the exported data. If an integrity method
259 * has already been set, then return an error. The certificate must be
260 * allowed to be used as a signing cert.
261 *
262 * p12ctxt - the export context
263 * cert - signer certificate
264 * certDb - the certificate database
265 * algorithm - signing algorithm
266 * keySize - size of the signing key (?)
267 */
268 SECStatus
SEC_PKCS12AddPublicKeyIntegrity(SEC_PKCS12ExportContext * p12ctxt,CERTCertificate * cert,CERTCertDBHandle * certDb,SECOidTag algorithm,int keySize)269 SEC_PKCS12AddPublicKeyIntegrity(SEC_PKCS12ExportContext *p12ctxt,
270 CERTCertificate *cert, CERTCertDBHandle *certDb,
271 SECOidTag algorithm, int keySize)
272 {
273 if (!p12ctxt) {
274 return SECFailure;
275 }
276
277 p12ctxt->integrityInfo.pubkeyInfo.cert = cert;
278 p12ctxt->integrityInfo.pubkeyInfo.certDb = certDb;
279 p12ctxt->integrityInfo.pubkeyInfo.algorithm = algorithm;
280 p12ctxt->integrityInfo.pubkeyInfo.keySize = keySize;
281 p12ctxt->integrityEnabled = PR_TRUE;
282
283 return SECSuccess;
284 }
285
286 /*
287 * Adding safes - encrypted (password/public key) or unencrypted
288 * Each of the safe creation routines return an opaque pointer which
289 * are later passed into the routines for exporting certificates and
290 * keys.
291 */
292
293 /* append the newly created safeInfo to list of safeInfos in the export
294 * context.
295 */
296 static SECStatus
sec_pkcs12_append_safe_info(SEC_PKCS12ExportContext * p12ctxt,SEC_PKCS12SafeInfo * info)297 sec_pkcs12_append_safe_info(SEC_PKCS12ExportContext *p12ctxt, SEC_PKCS12SafeInfo *info)
298 {
299 void *mark = NULL, *dummy1 = NULL, *dummy2 = NULL;
300
301 if (!p12ctxt || !info) {
302 return SECFailure;
303 }
304
305 mark = PORT_ArenaMark(p12ctxt->arena);
306
307 /* if no safeInfos have been set, create the list, otherwise expand it. */
308 if (!p12ctxt->safeInfoCount) {
309 p12ctxt->safeInfos = (SEC_PKCS12SafeInfo **)PORT_ArenaZAlloc(p12ctxt->arena,
310 2 * sizeof(SEC_PKCS12SafeInfo *));
311 dummy1 = p12ctxt->safeInfos;
312 p12ctxt->authSafe.encodedSafes = (SECItem **)PORT_ArenaZAlloc(p12ctxt->arena,
313 2 * sizeof(SECItem *));
314 dummy2 = p12ctxt->authSafe.encodedSafes;
315 } else {
316 dummy1 = PORT_ArenaGrow(p12ctxt->arena, p12ctxt->safeInfos,
317 (p12ctxt->safeInfoCount + 1) * sizeof(SEC_PKCS12SafeInfo *),
318 (p12ctxt->safeInfoCount + 2) * sizeof(SEC_PKCS12SafeInfo *));
319 p12ctxt->safeInfos = (SEC_PKCS12SafeInfo **)dummy1;
320 dummy2 = PORT_ArenaGrow(p12ctxt->arena, p12ctxt->authSafe.encodedSafes,
321 (p12ctxt->authSafe.safeCount + 1) * sizeof(SECItem *),
322 (p12ctxt->authSafe.safeCount + 2) * sizeof(SECItem *));
323 p12ctxt->authSafe.encodedSafes = (SECItem **)dummy2;
324 }
325 if (!dummy1 || !dummy2) {
326 PORT_SetError(SEC_ERROR_NO_MEMORY);
327 goto loser;
328 }
329
330 /* append the new safeInfo and null terminate the list */
331 p12ctxt->safeInfos[p12ctxt->safeInfoCount] = info;
332 p12ctxt->safeInfos[++p12ctxt->safeInfoCount] = NULL;
333 p12ctxt->authSafe.encodedSafes[p12ctxt->authSafe.safeCount] =
334 (SECItem *)PORT_ArenaZAlloc(p12ctxt->arena, sizeof(SECItem));
335 if (!p12ctxt->authSafe.encodedSafes[p12ctxt->authSafe.safeCount]) {
336 PORT_SetError(SEC_ERROR_NO_MEMORY);
337 goto loser;
338 }
339 p12ctxt->authSafe.encodedSafes[++p12ctxt->authSafe.safeCount] = NULL;
340
341 PORT_ArenaUnmark(p12ctxt->arena, mark);
342 return SECSuccess;
343
344 loser:
345 PORT_ArenaRelease(p12ctxt->arena, mark);
346 return SECFailure;
347 }
348
349 /* SEC_PKCS12CreatePasswordPrivSafe
350 * Create a password privacy safe to store exported information in.
351 *
352 * p12ctxt - export context
353 * pwitem - password for encryption
354 * privAlg - pbe algorithm through which encryption is done.
355 */
356 SEC_PKCS12SafeInfo *
SEC_PKCS12CreatePasswordPrivSafe(SEC_PKCS12ExportContext * p12ctxt,SECItem * pwitem,SECOidTag privAlg)357 SEC_PKCS12CreatePasswordPrivSafe(SEC_PKCS12ExportContext *p12ctxt,
358 SECItem *pwitem, SECOidTag privAlg)
359 {
360 SEC_PKCS12SafeInfo *safeInfo = NULL;
361 void *mark = NULL;
362 PK11SlotInfo *slot = NULL;
363 SECAlgorithmID *algId;
364 SECItem uniPwitem = { siBuffer, NULL, 0 };
365
366 if (!p12ctxt) {
367 return NULL;
368 }
369
370 /* allocate the safe info */
371 mark = PORT_ArenaMark(p12ctxt->arena);
372 safeInfo = (SEC_PKCS12SafeInfo *)PORT_ArenaZAlloc(p12ctxt->arena,
373 sizeof(SEC_PKCS12SafeInfo));
374 if (!safeInfo) {
375 PORT_SetError(SEC_ERROR_NO_MEMORY);
376 PORT_ArenaRelease(p12ctxt->arena, mark);
377 return NULL;
378 }
379
380 safeInfo->itemCount = 0;
381
382 /* create the encrypted safe */
383 if (!SEC_PKCS5IsAlgorithmPBEAlgTag(privAlg)) {
384 SECOidTag prfAlg = SEC_OID_UNKNOWN;
385 /* if we have password integrity set, use that to set the integrity
386 * hash algorithm to set our password PRF. If we haven't set it, just
387 * let the low level code pick it */
388 if (p12ctxt->integrityEnabled && p12ctxt->pwdIntegrity) {
389 prfAlg = HASH_GetHMACOidTagByHashOidTag(
390 p12ctxt->integrityInfo.pwdInfo.algorithm);
391 }
392 safeInfo->cinfo = SEC_PKCS7CreateEncryptedDataWithPBEV2(SEC_OID_PKCS5_PBES2,
393 privAlg,
394 prfAlg,
395 0,
396 p12ctxt->pwfn,
397 p12ctxt->pwfnarg);
398 } else {
399 safeInfo->cinfo = SEC_PKCS7CreateEncryptedData(privAlg, 0, p12ctxt->pwfn,
400 p12ctxt->pwfnarg);
401 }
402 if (!safeInfo->cinfo) {
403 PORT_SetError(SEC_ERROR_NO_MEMORY);
404 goto loser;
405 }
406 safeInfo->arena = p12ctxt->arena;
407
408 if (!sec_pkcs12_encode_password(NULL, &uniPwitem, privAlg, pwitem)) {
409 PORT_SetError(SEC_ERROR_NO_MEMORY);
410 goto loser;
411 }
412 if (SECITEM_CopyItem(p12ctxt->arena, &safeInfo->pwitem, &uniPwitem) != SECSuccess) {
413 PORT_SetError(SEC_ERROR_NO_MEMORY);
414 goto loser;
415 }
416
417 /* generate the encryption key */
418 slot = PK11_ReferenceSlot(p12ctxt->slot);
419 if (!slot) {
420 slot = PK11_GetInternalKeySlot();
421 if (!slot) {
422 PORT_SetError(SEC_ERROR_NO_MEMORY);
423 goto loser;
424 }
425 }
426
427 algId = SEC_PKCS7GetEncryptionAlgorithm(safeInfo->cinfo);
428 safeInfo->encryptionKey = PK11_PBEKeyGen(slot, algId, &uniPwitem,
429 PR_FALSE, p12ctxt->wincx);
430 if (!safeInfo->encryptionKey) {
431 goto loser;
432 }
433
434 safeInfo->arena = p12ctxt->arena;
435 safeInfo->safe = NULL;
436 if (sec_pkcs12_append_safe_info(p12ctxt, safeInfo) != SECSuccess) {
437 goto loser;
438 }
439
440 if (uniPwitem.data) {
441 SECITEM_ZfreeItem(&uniPwitem, PR_FALSE);
442 }
443 PORT_ArenaUnmark(p12ctxt->arena, mark);
444
445 if (slot) {
446 PK11_FreeSlot(slot);
447 }
448 return safeInfo;
449
450 loser:
451 if (slot) {
452 PK11_FreeSlot(slot);
453 }
454 if (safeInfo->cinfo) {
455 SEC_PKCS7DestroyContentInfo(safeInfo->cinfo);
456 }
457
458 if (uniPwitem.data) {
459 SECITEM_ZfreeItem(&uniPwitem, PR_FALSE);
460 }
461
462 PORT_ArenaRelease(p12ctxt->arena, mark);
463 return NULL;
464 }
465
466 /* SEC_PKCS12CreateUnencryptedSafe
467 * Creates an unencrypted safe within the export context.
468 *
469 * p12ctxt - the export context
470 */
471 SEC_PKCS12SafeInfo *
SEC_PKCS12CreateUnencryptedSafe(SEC_PKCS12ExportContext * p12ctxt)472 SEC_PKCS12CreateUnencryptedSafe(SEC_PKCS12ExportContext *p12ctxt)
473 {
474 SEC_PKCS12SafeInfo *safeInfo = NULL;
475 void *mark = NULL;
476
477 if (!p12ctxt) {
478 return NULL;
479 }
480
481 /* create the safe info */
482 mark = PORT_ArenaMark(p12ctxt->arena);
483 safeInfo = (SEC_PKCS12SafeInfo *)PORT_ArenaZAlloc(p12ctxt->arena,
484 sizeof(SEC_PKCS12SafeInfo));
485 if (!safeInfo) {
486 PORT_ArenaRelease(p12ctxt->arena, mark);
487 PORT_SetError(SEC_ERROR_NO_MEMORY);
488 return NULL;
489 }
490
491 safeInfo->itemCount = 0;
492
493 /* create the safe content */
494 safeInfo->cinfo = SEC_PKCS7CreateData();
495 if (!safeInfo->cinfo) {
496 PORT_SetError(SEC_ERROR_NO_MEMORY);
497 goto loser;
498 }
499
500 if (sec_pkcs12_append_safe_info(p12ctxt, safeInfo) != SECSuccess) {
501 goto loser;
502 }
503
504 PORT_ArenaUnmark(p12ctxt->arena, mark);
505 return safeInfo;
506
507 loser:
508 if (safeInfo->cinfo) {
509 SEC_PKCS7DestroyContentInfo(safeInfo->cinfo);
510 }
511
512 PORT_ArenaRelease(p12ctxt->arena, mark);
513 return NULL;
514 }
515
516 /* SEC_PKCS12CreatePubKeyEncryptedSafe
517 * Creates a safe which is protected by public key encryption.
518 *
519 * p12ctxt - the export context
520 * certDb - the certificate database
521 * signer - the signer's certificate
522 * recipients - the list of recipient certificates.
523 * algorithm - the encryption algorithm to use
524 * keysize - the algorithms key size (?)
525 */
526 SEC_PKCS12SafeInfo *
SEC_PKCS12CreatePubKeyEncryptedSafe(SEC_PKCS12ExportContext * p12ctxt,CERTCertDBHandle * certDb,CERTCertificate * signer,CERTCertificate ** recipients,SECOidTag algorithm,int keysize)527 SEC_PKCS12CreatePubKeyEncryptedSafe(SEC_PKCS12ExportContext *p12ctxt,
528 CERTCertDBHandle *certDb,
529 CERTCertificate *signer,
530 CERTCertificate **recipients,
531 SECOidTag algorithm, int keysize)
532 {
533 SEC_PKCS12SafeInfo *safeInfo = NULL;
534 void *mark = NULL;
535
536 if (!p12ctxt || !signer || !recipients || !(*recipients)) {
537 return NULL;
538 }
539
540 /* allocate the safeInfo */
541 mark = PORT_ArenaMark(p12ctxt->arena);
542 safeInfo = (SEC_PKCS12SafeInfo *)PORT_ArenaZAlloc(p12ctxt->arena,
543 sizeof(SEC_PKCS12SafeInfo));
544 if (!safeInfo) {
545 PORT_ArenaRelease(p12ctxt->arena, mark);
546 PORT_SetError(SEC_ERROR_NO_MEMORY);
547 return NULL;
548 }
549
550 safeInfo->itemCount = 0;
551 safeInfo->arena = p12ctxt->arena;
552
553 /* create the enveloped content info using certUsageEmailSigner currently.
554 * XXX We need to eventually use something other than certUsageEmailSigner
555 */
556 safeInfo->cinfo = SEC_PKCS7CreateEnvelopedData(signer, certUsageEmailSigner,
557 certDb, algorithm, keysize,
558 p12ctxt->pwfn, p12ctxt->pwfnarg);
559 if (!safeInfo->cinfo) {
560 PORT_SetError(SEC_ERROR_NO_MEMORY);
561 goto loser;
562 }
563
564 /* add recipients */
565 if (recipients) {
566 unsigned int i = 0;
567 while (recipients[i] != NULL) {
568 SECStatus rv = SEC_PKCS7AddRecipient(safeInfo->cinfo, recipients[i],
569 certUsageEmailRecipient, certDb);
570 if (rv != SECSuccess) {
571 goto loser;
572 }
573 i++;
574 }
575 }
576
577 if (sec_pkcs12_append_safe_info(p12ctxt, safeInfo) != SECSuccess) {
578 goto loser;
579 }
580
581 PORT_ArenaUnmark(p12ctxt->arena, mark);
582 return safeInfo;
583
584 loser:
585 if (safeInfo->cinfo) {
586 SEC_PKCS7DestroyContentInfo(safeInfo->cinfo);
587 safeInfo->cinfo = NULL;
588 }
589
590 PORT_ArenaRelease(p12ctxt->arena, mark);
591 return NULL;
592 }
593
594 /*********************************
595 * Routines to handle the exporting of the keys and certificates
596 *********************************/
597
598 /* creates a safe contents which safeBags will be appended to */
599 sec_PKCS12SafeContents *
sec_PKCS12CreateSafeContents(PLArenaPool * arena)600 sec_PKCS12CreateSafeContents(PLArenaPool *arena)
601 {
602 sec_PKCS12SafeContents *safeContents;
603
604 if (arena == NULL) {
605 return NULL;
606 }
607
608 /* create the safe contents */
609 safeContents = (sec_PKCS12SafeContents *)PORT_ArenaZAlloc(arena,
610 sizeof(sec_PKCS12SafeContents));
611 if (!safeContents) {
612 PORT_SetError(SEC_ERROR_NO_MEMORY);
613 goto loser;
614 }
615
616 /* set up the internal contents info */
617 safeContents->safeBags = NULL;
618 safeContents->arena = arena;
619 safeContents->bagCount = 0;
620
621 return safeContents;
622
623 loser:
624 return NULL;
625 }
626
627 /* appends a safe bag to a safeContents using the specified arena.
628 */
629 SECStatus
sec_pkcs12_append_bag_to_safe_contents(PLArenaPool * arena,sec_PKCS12SafeContents * safeContents,sec_PKCS12SafeBag * safeBag)630 sec_pkcs12_append_bag_to_safe_contents(PLArenaPool *arena,
631 sec_PKCS12SafeContents *safeContents,
632 sec_PKCS12SafeBag *safeBag)
633 {
634 void *mark = NULL, *dummy = NULL;
635
636 if (!arena || !safeBag || !safeContents) {
637 return SECFailure;
638 }
639
640 mark = PORT_ArenaMark(arena);
641 if (!mark) {
642 PORT_SetError(SEC_ERROR_NO_MEMORY);
643 return SECFailure;
644 }
645
646 /* allocate space for the list, or reallocate to increase space */
647 if (!safeContents->safeBags) {
648 safeContents->safeBags = (sec_PKCS12SafeBag **)PORT_ArenaZAlloc(arena,
649 (2 * sizeof(sec_PKCS12SafeBag *)));
650 dummy = safeContents->safeBags;
651 safeContents->bagCount = 0;
652 } else {
653 dummy = PORT_ArenaGrow(arena, safeContents->safeBags,
654 (safeContents->bagCount + 1) * sizeof(sec_PKCS12SafeBag *),
655 (safeContents->bagCount + 2) * sizeof(sec_PKCS12SafeBag *));
656 safeContents->safeBags = (sec_PKCS12SafeBag **)dummy;
657 }
658
659 if (!dummy) {
660 PORT_ArenaRelease(arena, mark);
661 PORT_SetError(SEC_ERROR_NO_MEMORY);
662 return SECFailure;
663 }
664
665 /* append the bag at the end and null terminate the list */
666 safeContents->safeBags[safeContents->bagCount++] = safeBag;
667 safeContents->safeBags[safeContents->bagCount] = NULL;
668
669 PORT_ArenaUnmark(arena, mark);
670
671 return SECSuccess;
672 }
673
674 /* appends a safeBag to a specific safeInfo.
675 */
676 SECStatus
sec_pkcs12_append_bag(SEC_PKCS12ExportContext * p12ctxt,SEC_PKCS12SafeInfo * safeInfo,sec_PKCS12SafeBag * safeBag)677 sec_pkcs12_append_bag(SEC_PKCS12ExportContext *p12ctxt,
678 SEC_PKCS12SafeInfo *safeInfo, sec_PKCS12SafeBag *safeBag)
679 {
680 sec_PKCS12SafeContents *dest;
681 SECStatus rv = SECFailure;
682
683 if (!p12ctxt || !safeBag || !safeInfo) {
684 return SECFailure;
685 }
686
687 if (!safeInfo->safe) {
688 safeInfo->safe = sec_PKCS12CreateSafeContents(p12ctxt->arena);
689 if (!safeInfo->safe) {
690 return SECFailure;
691 }
692 }
693
694 dest = safeInfo->safe;
695 rv = sec_pkcs12_append_bag_to_safe_contents(p12ctxt->arena, dest, safeBag);
696 if (rv == SECSuccess) {
697 safeInfo->itemCount++;
698 }
699
700 return rv;
701 }
702
703 /* Creates a safeBag of the specified type, and if bagData is specified,
704 * the contents are set. The contents could be set later by the calling
705 * routine.
706 */
707 sec_PKCS12SafeBag *
sec_PKCS12CreateSafeBag(SEC_PKCS12ExportContext * p12ctxt,SECOidTag bagType,void * bagData)708 sec_PKCS12CreateSafeBag(SEC_PKCS12ExportContext *p12ctxt, SECOidTag bagType,
709 void *bagData)
710 {
711 sec_PKCS12SafeBag *safeBag;
712 void *mark = NULL;
713 SECStatus rv = SECSuccess;
714 SECOidData *oidData = NULL;
715
716 if (!p12ctxt) {
717 return NULL;
718 }
719
720 mark = PORT_ArenaMark(p12ctxt->arena);
721 if (!mark) {
722 PORT_SetError(SEC_ERROR_NO_MEMORY);
723 return NULL;
724 }
725
726 safeBag = (sec_PKCS12SafeBag *)PORT_ArenaZAlloc(p12ctxt->arena,
727 sizeof(sec_PKCS12SafeBag));
728 if (!safeBag) {
729 PORT_ArenaRelease(p12ctxt->arena, mark);
730 PORT_SetError(SEC_ERROR_NO_MEMORY);
731 return NULL;
732 }
733
734 /* set the bags content based upon bag type */
735 switch (bagType) {
736 case SEC_OID_PKCS12_V1_KEY_BAG_ID:
737 safeBag->safeBagContent.pkcs8KeyBag =
738 (SECKEYPrivateKeyInfo *)bagData;
739 break;
740 case SEC_OID_PKCS12_V1_CERT_BAG_ID:
741 safeBag->safeBagContent.certBag = (sec_PKCS12CertBag *)bagData;
742 break;
743 case SEC_OID_PKCS12_V1_CRL_BAG_ID:
744 safeBag->safeBagContent.crlBag = (sec_PKCS12CRLBag *)bagData;
745 break;
746 case SEC_OID_PKCS12_V1_SECRET_BAG_ID:
747 safeBag->safeBagContent.secretBag = (sec_PKCS12SecretBag *)bagData;
748 break;
749 case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:
750 safeBag->safeBagContent.pkcs8ShroudedKeyBag =
751 (SECKEYEncryptedPrivateKeyInfo *)bagData;
752 break;
753 case SEC_OID_PKCS12_V1_SAFE_CONTENTS_BAG_ID:
754 safeBag->safeBagContent.safeContents =
755 (sec_PKCS12SafeContents *)bagData;
756 break;
757 default:
758 goto loser;
759 }
760
761 oidData = SECOID_FindOIDByTag(bagType);
762 if (oidData) {
763 rv = SECITEM_CopyItem(p12ctxt->arena, &safeBag->safeBagType, &oidData->oid);
764 if (rv != SECSuccess) {
765 PORT_SetError(SEC_ERROR_NO_MEMORY);
766 goto loser;
767 }
768 } else {
769 goto loser;
770 }
771
772 safeBag->arena = p12ctxt->arena;
773 PORT_ArenaUnmark(p12ctxt->arena, mark);
774
775 return safeBag;
776
777 loser:
778 if (mark) {
779 PORT_ArenaRelease(p12ctxt->arena, mark);
780 }
781
782 return NULL;
783 }
784
785 /* Creates a new certificate bag and returns a pointer to it. If an error
786 * occurs NULL is returned.
787 */
788 sec_PKCS12CertBag *
sec_PKCS12NewCertBag(PLArenaPool * arena,SECOidTag certType)789 sec_PKCS12NewCertBag(PLArenaPool *arena, SECOidTag certType)
790 {
791 sec_PKCS12CertBag *certBag = NULL;
792 SECOidData *bagType = NULL;
793 SECStatus rv;
794 void *mark = NULL;
795
796 if (!arena) {
797 return NULL;
798 }
799
800 mark = PORT_ArenaMark(arena);
801 certBag = (sec_PKCS12CertBag *)PORT_ArenaZAlloc(arena,
802 sizeof(sec_PKCS12CertBag));
803 if (!certBag) {
804 PORT_ArenaRelease(arena, mark);
805 PORT_SetError(SEC_ERROR_NO_MEMORY);
806 return NULL;
807 }
808
809 bagType = SECOID_FindOIDByTag(certType);
810 if (!bagType) {
811 PORT_SetError(SEC_ERROR_NO_MEMORY);
812 goto loser;
813 }
814
815 rv = SECITEM_CopyItem(arena, &certBag->bagID, &bagType->oid);
816 if (rv != SECSuccess) {
817 PORT_SetError(SEC_ERROR_NO_MEMORY);
818 goto loser;
819 }
820
821 PORT_ArenaUnmark(arena, mark);
822 return certBag;
823
824 loser:
825 PORT_ArenaRelease(arena, mark);
826 return NULL;
827 }
828
829 /* Creates a new CRL bag and returns a pointer to it. If an error
830 * occurs NULL is returned.
831 */
832 sec_PKCS12CRLBag *
sec_PKCS12NewCRLBag(PLArenaPool * arena,SECOidTag crlType)833 sec_PKCS12NewCRLBag(PLArenaPool *arena, SECOidTag crlType)
834 {
835 sec_PKCS12CRLBag *crlBag = NULL;
836 SECOidData *bagType = NULL;
837 SECStatus rv;
838 void *mark = NULL;
839
840 if (!arena) {
841 return NULL;
842 }
843
844 mark = PORT_ArenaMark(arena);
845 crlBag = (sec_PKCS12CRLBag *)PORT_ArenaZAlloc(arena,
846 sizeof(sec_PKCS12CRLBag));
847 if (!crlBag) {
848 PORT_ArenaRelease(arena, mark);
849 PORT_SetError(SEC_ERROR_NO_MEMORY);
850 return NULL;
851 }
852
853 bagType = SECOID_FindOIDByTag(crlType);
854 if (!bagType) {
855 PORT_SetError(SEC_ERROR_NO_MEMORY);
856 goto loser;
857 }
858
859 rv = SECITEM_CopyItem(arena, &crlBag->bagID, &bagType->oid);
860 if (rv != SECSuccess) {
861 PORT_SetError(SEC_ERROR_NO_MEMORY);
862 goto loser;
863 }
864
865 PORT_ArenaUnmark(arena, mark);
866 return crlBag;
867
868 loser:
869 PORT_ArenaRelease(arena, mark);
870 return NULL;
871 }
872
873 /* sec_PKCS12AddAttributeToBag
874 * adds an attribute to a safeBag. currently, the only attributes supported
875 * are those which are specified within PKCS 12.
876 *
877 * p12ctxt - the export context
878 * safeBag - the safeBag to which attributes are appended
879 * attrType - the attribute type
880 * attrData - the attribute data
881 */
882 SECStatus
sec_PKCS12AddAttributeToBag(SEC_PKCS12ExportContext * p12ctxt,sec_PKCS12SafeBag * safeBag,SECOidTag attrType,SECItem * attrData)883 sec_PKCS12AddAttributeToBag(SEC_PKCS12ExportContext *p12ctxt,
884 sec_PKCS12SafeBag *safeBag, SECOidTag attrType,
885 SECItem *attrData)
886 {
887 sec_PKCS12Attribute *attribute;
888 void *mark = NULL, *dummy = NULL;
889 SECOidData *oiddata = NULL;
890 SECItem unicodeName = { siBuffer, NULL, 0 };
891 void *src = NULL;
892 unsigned int nItems = 0;
893 SECStatus rv;
894
895 PORT_Assert(p12ctxt->arena == safeBag->arena);
896 if (!safeBag || !p12ctxt || p12ctxt->arena != safeBag->arena) {
897 PORT_SetError(SEC_ERROR_INVALID_ARGS);
898 return SECFailure;
899 }
900
901 mark = PORT_ArenaMark(safeBag->arena);
902
903 /* allocate the attribute */
904 attribute = (sec_PKCS12Attribute *)PORT_ArenaZAlloc(safeBag->arena,
905 sizeof(sec_PKCS12Attribute));
906 if (!attribute) {
907 PORT_SetError(SEC_ERROR_NO_MEMORY);
908 goto loser;
909 }
910
911 /* set up the attribute */
912 oiddata = SECOID_FindOIDByTag(attrType);
913 if (!oiddata) {
914 PORT_SetError(SEC_ERROR_NO_MEMORY);
915 goto loser;
916 }
917 if (SECITEM_CopyItem(p12ctxt->arena, &attribute->attrType, &oiddata->oid) !=
918 SECSuccess) {
919 PORT_SetError(SEC_ERROR_NO_MEMORY);
920 goto loser;
921 }
922
923 nItems = 1;
924 switch (attrType) {
925 case SEC_OID_PKCS9_LOCAL_KEY_ID: {
926 src = attrData;
927 break;
928 }
929 case SEC_OID_PKCS9_FRIENDLY_NAME: {
930 if (!sec_pkcs12_convert_item_to_unicode(p12ctxt->arena,
931 &unicodeName, attrData, PR_FALSE,
932 PR_FALSE, PR_TRUE)) {
933 goto loser;
934 }
935 src = &unicodeName;
936 break;
937 }
938 default:
939 goto loser;
940 }
941
942 /* append the attribute to the attribute value list */
943 attribute->attrValue = (SECItem **)PORT_ArenaZAlloc(p12ctxt->arena,
944 ((nItems + 1) * sizeof(SECItem *)));
945 if (!attribute->attrValue) {
946 PORT_SetError(SEC_ERROR_NO_MEMORY);
947 goto loser;
948 }
949
950 /* XXX this will need to be changed if attributes requiring more than
951 * one element are ever used.
952 */
953 attribute->attrValue[0] = (SECItem *)PORT_ArenaZAlloc(p12ctxt->arena,
954 sizeof(SECItem));
955 if (!attribute->attrValue[0]) {
956 PORT_SetError(SEC_ERROR_NO_MEMORY);
957 goto loser;
958 }
959 attribute->attrValue[1] = NULL;
960
961 rv = SECITEM_CopyItem(p12ctxt->arena, attribute->attrValue[0],
962 (SECItem *)src);
963 if (rv != SECSuccess) {
964 PORT_SetError(SEC_ERROR_NO_MEMORY);
965 goto loser;
966 }
967
968 /* append the attribute to the safeBag attributes */
969 if (safeBag->nAttribs) {
970 dummy = PORT_ArenaGrow(p12ctxt->arena, safeBag->attribs,
971 ((safeBag->nAttribs + 1) * sizeof(sec_PKCS12Attribute *)),
972 ((safeBag->nAttribs + 2) * sizeof(sec_PKCS12Attribute *)));
973 safeBag->attribs = (sec_PKCS12Attribute **)dummy;
974 } else {
975 safeBag->attribs = (sec_PKCS12Attribute **)PORT_ArenaZAlloc(p12ctxt->arena,
976 2 * sizeof(sec_PKCS12Attribute *));
977 dummy = safeBag->attribs;
978 }
979 if (!dummy) {
980 goto loser;
981 }
982
983 safeBag->attribs[safeBag->nAttribs] = attribute;
984 safeBag->attribs[++safeBag->nAttribs] = NULL;
985
986 PORT_ArenaUnmark(p12ctxt->arena, mark);
987 return SECSuccess;
988
989 loser:
990 if (mark) {
991 PORT_ArenaRelease(p12ctxt->arena, mark);
992 }
993
994 return SECFailure;
995 }
996
997 /* SEC_PKCS12AddCert
998 * Adds a certificate to the data being exported.
999 *
1000 * p12ctxt - the export context
1001 * safe - the safeInfo to which the certificate is placed
1002 * nestedDest - if the cert is to be placed within a nested safeContents then,
1003 * this value is to be specified with the destination
1004 * cert - the cert to export
1005 * certDb - the certificate database handle
1006 * keyId - a unique identifier to associate a certificate/key pair
1007 * includeCertChain - PR_TRUE if the certificate chain is to be included.
1008 */
1009 SECStatus
SEC_PKCS12AddCert(SEC_PKCS12ExportContext * p12ctxt,SEC_PKCS12SafeInfo * safe,void * nestedDest,CERTCertificate * cert,CERTCertDBHandle * certDb,SECItem * keyId,PRBool includeCertChain)1010 SEC_PKCS12AddCert(SEC_PKCS12ExportContext *p12ctxt, SEC_PKCS12SafeInfo *safe,
1011 void *nestedDest, CERTCertificate *cert,
1012 CERTCertDBHandle *certDb, SECItem *keyId,
1013 PRBool includeCertChain)
1014 {
1015 sec_PKCS12CertBag *certBag;
1016 sec_PKCS12SafeBag *safeBag;
1017 void *mark;
1018 SECStatus rv;
1019 SECItem nick = { siBuffer, NULL, 0 };
1020
1021 if (!p12ctxt || !cert) {
1022 return SECFailure;
1023 }
1024 mark = PORT_ArenaMark(p12ctxt->arena);
1025
1026 /* allocate the cert bag */
1027 certBag = sec_PKCS12NewCertBag(p12ctxt->arena,
1028 SEC_OID_PKCS9_X509_CERT);
1029 if (!certBag) {
1030 goto loser;
1031 }
1032
1033 if (SECITEM_CopyItem(p12ctxt->arena, &certBag->value.x509Cert,
1034 &cert->derCert) != SECSuccess) {
1035 PORT_SetError(SEC_ERROR_NO_MEMORY);
1036 goto loser;
1037 }
1038
1039 /* if the cert chain is to be included, we should only be exporting
1040 * the cert from our internal database.
1041 */
1042 if (includeCertChain) {
1043 CERTCertificateList *certList = CERT_CertChainFromCert(cert,
1044 certUsageSSLClient,
1045 PR_TRUE);
1046 unsigned int count = 0;
1047 if (!certList) {
1048 PORT_SetError(SEC_ERROR_NO_MEMORY);
1049 goto loser;
1050 }
1051
1052 /* add cert chain */
1053 for (count = 0; count < (unsigned int)certList->len; count++) {
1054 if (SECITEM_CompareItem(&certList->certs[count], &cert->derCert) != SECEqual) {
1055 CERTCertificate *tempCert;
1056
1057 /* decode the certificate */
1058 /* XXX
1059 * This was rather silly. The chain is constructed above
1060 * by finding all of the CERTCertificate's in the database.
1061 * Then the chain is put into a CERTCertificateList, which only
1062 * contains the DER. Finally, the DER was decoded, and the
1063 * decoded cert was sent recursively back to this function.
1064 * Beyond being inefficent, this causes data loss (specifically,
1065 * the nickname). Instead, for 3.4, we'll do a lookup by the
1066 * DER, which should return the cached entry.
1067 */
1068 tempCert = CERT_FindCertByDERCert(CERT_GetDefaultCertDB(),
1069 &certList->certs[count]);
1070 if (!tempCert) {
1071 CERT_DestroyCertificateList(certList);
1072 goto loser;
1073 }
1074
1075 /* add the certificate */
1076 if (SEC_PKCS12AddCert(p12ctxt, safe, nestedDest, tempCert,
1077 certDb, NULL, PR_FALSE) != SECSuccess) {
1078 CERT_DestroyCertificate(tempCert);
1079 CERT_DestroyCertificateList(certList);
1080 goto loser;
1081 }
1082 CERT_DestroyCertificate(tempCert);
1083 }
1084 }
1085 CERT_DestroyCertificateList(certList);
1086 }
1087
1088 /* if the certificate has a nickname, we will set the friendly name
1089 * to that.
1090 */
1091 if (cert->nickname) {
1092 if (cert->slot && !PK11_IsInternal(cert->slot)) {
1093 /*
1094 * The cert is coming off of an external token,
1095 * let's strip the token name from the nickname
1096 * and only add what comes after the colon as the
1097 * nickname. -javi
1098 */
1099 char *delimit;
1100
1101 delimit = PORT_Strchr(cert->nickname, ':');
1102 if (delimit == NULL) {
1103 nick.data = (unsigned char *)cert->nickname;
1104 nick.len = PORT_Strlen(cert->nickname);
1105 } else {
1106 delimit++;
1107 nick.data = (unsigned char *)PORT_ArenaStrdup(p12ctxt->arena,
1108 delimit);
1109 nick.len = PORT_Strlen(delimit);
1110 }
1111 } else {
1112 nick.data = (unsigned char *)cert->nickname;
1113 nick.len = PORT_Strlen(cert->nickname);
1114 }
1115 }
1116
1117 safeBag = sec_PKCS12CreateSafeBag(p12ctxt, SEC_OID_PKCS12_V1_CERT_BAG_ID,
1118 certBag);
1119 if (!safeBag) {
1120 goto loser;
1121 }
1122
1123 /* add the friendly name and keyId attributes, if necessary */
1124 if (nick.data) {
1125 if (sec_PKCS12AddAttributeToBag(p12ctxt, safeBag,
1126 SEC_OID_PKCS9_FRIENDLY_NAME, &nick) != SECSuccess) {
1127 goto loser;
1128 }
1129 }
1130
1131 if (keyId) {
1132 if (sec_PKCS12AddAttributeToBag(p12ctxt, safeBag, SEC_OID_PKCS9_LOCAL_KEY_ID,
1133 keyId) != SECSuccess) {
1134 goto loser;
1135 }
1136 }
1137
1138 /* append the cert safeBag */
1139 if (nestedDest) {
1140 rv = sec_pkcs12_append_bag_to_safe_contents(p12ctxt->arena,
1141 (sec_PKCS12SafeContents *)nestedDest,
1142 safeBag);
1143 } else {
1144 rv = sec_pkcs12_append_bag(p12ctxt, safe, safeBag);
1145 }
1146
1147 if (rv != SECSuccess) {
1148 goto loser;
1149 }
1150
1151 PORT_ArenaUnmark(p12ctxt->arena, mark);
1152 return SECSuccess;
1153
1154 loser:
1155 if (mark) {
1156 PORT_ArenaRelease(p12ctxt->arena, mark);
1157 }
1158
1159 return SECFailure;
1160 }
1161
1162 /* SEC_PKCS12AddKeyForCert
1163 * Extracts the key associated with a particular certificate and exports
1164 * it.
1165 *
1166 * p12ctxt - the export context
1167 * safe - the safeInfo to place the key in
1168 * nestedDest - the nested safeContents to place a key
1169 * cert - the certificate which the key belongs to
1170 * shroudKey - encrypt the private key for export. This value should
1171 * always be true. lower level code will not allow the export
1172 * of unencrypted private keys.
1173 * algorithm - the algorithm with which to encrypt the private key
1174 * pwitem - the password to encrypt the private key with
1175 * keyId - the keyID attribute
1176 * nickName - the nickname attribute
1177 */
1178 SECStatus
SEC_PKCS12AddKeyForCert(SEC_PKCS12ExportContext * p12ctxt,SEC_PKCS12SafeInfo * safe,void * nestedDest,CERTCertificate * cert,PRBool shroudKey,SECOidTag algorithm,SECItem * pwitem,SECItem * keyId,SECItem * nickName)1179 SEC_PKCS12AddKeyForCert(SEC_PKCS12ExportContext *p12ctxt, SEC_PKCS12SafeInfo *safe,
1180 void *nestedDest, CERTCertificate *cert,
1181 PRBool shroudKey, SECOidTag algorithm, SECItem *pwitem,
1182 SECItem *keyId, SECItem *nickName)
1183 {
1184 void *mark;
1185 void *keyItem;
1186 SECOidTag keyType;
1187 SECStatus rv = SECFailure;
1188 SECItem nickname = { siBuffer, NULL, 0 }, uniPwitem = { siBuffer, NULL, 0 };
1189 sec_PKCS12SafeBag *returnBag;
1190
1191 if (!p12ctxt || !cert || !safe) {
1192 return SECFailure;
1193 }
1194
1195 mark = PORT_ArenaMark(p12ctxt->arena);
1196
1197 /* retrieve the key based upon the type that it is and
1198 * specify the type of safeBag to store the key in
1199 */
1200 if (!shroudKey) {
1201
1202 /* extract the key unencrypted. this will most likely go away */
1203 SECKEYPrivateKeyInfo *pki = PK11_ExportPrivateKeyInfo(cert,
1204 p12ctxt->wincx);
1205 if (!pki) {
1206 PORT_ArenaRelease(p12ctxt->arena, mark);
1207 PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY);
1208 return SECFailure;
1209 }
1210 keyItem = PORT_ArenaZAlloc(p12ctxt->arena, sizeof(SECKEYPrivateKeyInfo));
1211 if (!keyItem) {
1212 PORT_SetError(SEC_ERROR_NO_MEMORY);
1213 goto loser;
1214 }
1215 rv = SECKEY_CopyPrivateKeyInfo(p12ctxt->arena,
1216 (SECKEYPrivateKeyInfo *)keyItem, pki);
1217 keyType = SEC_OID_PKCS12_V1_KEY_BAG_ID;
1218 SECKEY_DestroyPrivateKeyInfo(pki, PR_TRUE);
1219 } else {
1220
1221 /* extract the key encrypted */
1222 SECKEYEncryptedPrivateKeyInfo *epki = NULL;
1223 PK11SlotInfo *slot = NULL;
1224 SECOidTag prfAlg = SEC_OID_UNKNOWN;
1225
1226 if (!sec_pkcs12_encode_password(p12ctxt->arena, &uniPwitem, algorithm,
1227 pwitem)) {
1228 PORT_SetError(SEC_ERROR_NO_MEMORY);
1229 goto loser;
1230 }
1231
1232 /* if we have password integrity set, use that to set the integrity
1233 * hash algorithm to set our password PRF. If we haven't set it, just
1234 * let the low level code pick it */
1235 if (p12ctxt->integrityEnabled && p12ctxt->pwdIntegrity) {
1236 prfAlg = HASH_GetHMACOidTagByHashOidTag(
1237 p12ctxt->integrityInfo.pwdInfo.algorithm);
1238 }
1239
1240 /* we want to make sure to take the key out of the key slot */
1241 if (PK11_IsInternal(p12ctxt->slot)) {
1242 slot = PK11_GetInternalKeySlot();
1243 } else {
1244 slot = PK11_ReferenceSlot(p12ctxt->slot);
1245 }
1246
1247 /* passing algorithm as the pbe will force the PBE code to
1248 * automatically handle the selection between using the algorithm
1249 * as a the pbe algorithm, or using the algorithm as a cipher
1250 * and building a pkcs5 pbe */
1251 epki = PK11_ExportEncryptedPrivateKeyInfoV2(slot, algorithm,
1252 SEC_OID_UNKNOWN, prfAlg,
1253 &uniPwitem, cert,
1254 NSS_PBE_DEFAULT_ITERATION_COUNT,
1255 p12ctxt->wincx);
1256 PK11_FreeSlot(slot);
1257 if (!epki) {
1258 PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY);
1259 goto loser;
1260 }
1261
1262 keyItem = PORT_ArenaZAlloc(p12ctxt->arena,
1263 sizeof(SECKEYEncryptedPrivateKeyInfo));
1264 if (!keyItem) {
1265 PORT_SetError(SEC_ERROR_NO_MEMORY);
1266 goto loser;
1267 }
1268 rv = SECKEY_CopyEncryptedPrivateKeyInfo(p12ctxt->arena,
1269 (SECKEYEncryptedPrivateKeyInfo *)keyItem,
1270 epki);
1271 keyType = SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID;
1272 SECKEY_DestroyEncryptedPrivateKeyInfo(epki, PR_TRUE);
1273 }
1274
1275 if (rv != SECSuccess) {
1276 goto loser;
1277 }
1278
1279 /* if no nickname specified, let's see if the certificate has a
1280 * nickname.
1281 */
1282 if (!nickName) {
1283 if (cert->nickname) {
1284 nickname.data = (unsigned char *)cert->nickname;
1285 nickname.len = PORT_Strlen(cert->nickname);
1286 nickName = &nickname;
1287 }
1288 }
1289
1290 /* create the safe bag and set any attributes */
1291 returnBag = sec_PKCS12CreateSafeBag(p12ctxt, keyType, keyItem);
1292 if (!returnBag) {
1293 rv = SECFailure;
1294 goto loser;
1295 }
1296
1297 if (nickName) {
1298 if (sec_PKCS12AddAttributeToBag(p12ctxt, returnBag,
1299 SEC_OID_PKCS9_FRIENDLY_NAME, nickName) != SECSuccess) {
1300 goto loser;
1301 }
1302 }
1303
1304 if (keyId) {
1305 if (sec_PKCS12AddAttributeToBag(p12ctxt, returnBag, SEC_OID_PKCS9_LOCAL_KEY_ID,
1306 keyId) != SECSuccess) {
1307 goto loser;
1308 }
1309 }
1310
1311 if (nestedDest) {
1312 rv = sec_pkcs12_append_bag_to_safe_contents(p12ctxt->arena,
1313 (sec_PKCS12SafeContents *)nestedDest,
1314 returnBag);
1315 } else {
1316 rv = sec_pkcs12_append_bag(p12ctxt, safe, returnBag);
1317 }
1318
1319 loser:
1320
1321 if (rv != SECSuccess) {
1322 PORT_ArenaRelease(p12ctxt->arena, mark);
1323 } else {
1324 PORT_ArenaUnmark(p12ctxt->arena, mark);
1325 }
1326
1327 return rv;
1328 }
1329
1330 /* SEC_PKCS12AddCertOrChainAndKey
1331 * Add a certificate and key pair to be exported.
1332 *
1333 * p12ctxt - the export context
1334 * certSafe - the safeInfo where the cert is stored
1335 * certNestedDest - the nested safeContents to store the cert
1336 * keySafe - the safeInfo where the key is stored
1337 * keyNestedDest - the nested safeContents to store the key
1338 * shroudKey - extract the private key encrypted?
1339 * pwitem - the password with which the key is encrypted
1340 * algorithm - the algorithm with which the key is encrypted
1341 * includeCertChain - also add certs from chain to bag.
1342 */
1343 SECStatus
SEC_PKCS12AddCertOrChainAndKey(SEC_PKCS12ExportContext * p12ctxt,void * certSafe,void * certNestedDest,CERTCertificate * cert,CERTCertDBHandle * certDb,void * keySafe,void * keyNestedDest,PRBool shroudKey,SECItem * pwitem,SECOidTag algorithm,PRBool includeCertChain)1344 SEC_PKCS12AddCertOrChainAndKey(SEC_PKCS12ExportContext *p12ctxt,
1345 void *certSafe, void *certNestedDest,
1346 CERTCertificate *cert, CERTCertDBHandle *certDb,
1347 void *keySafe, void *keyNestedDest,
1348 PRBool shroudKey, SECItem *pwitem,
1349 SECOidTag algorithm, PRBool includeCertChain)
1350 {
1351 SECStatus rv = SECFailure;
1352 SGNDigestInfo *digest = NULL;
1353 void *mark = NULL;
1354
1355 if (!p12ctxt || !certSafe || !keySafe || !cert) {
1356 return SECFailure;
1357 }
1358
1359 mark = PORT_ArenaMark(p12ctxt->arena);
1360
1361 /* generate the thumbprint of the cert to use as a keyId */
1362 digest = sec_pkcs12_compute_thumbprint(&cert->derCert);
1363 if (!digest) {
1364 PORT_ArenaRelease(p12ctxt->arena, mark);
1365 return SECFailure;
1366 }
1367
1368 /* add the certificate */
1369 rv = SEC_PKCS12AddCert(p12ctxt, (SEC_PKCS12SafeInfo *)certSafe,
1370 (SEC_PKCS12SafeInfo *)certNestedDest, cert, certDb,
1371 &digest->digest, includeCertChain);
1372 if (rv != SECSuccess) {
1373 goto loser;
1374 }
1375
1376 /* add the key */
1377 rv = SEC_PKCS12AddKeyForCert(p12ctxt, (SEC_PKCS12SafeInfo *)keySafe,
1378 keyNestedDest, cert,
1379 shroudKey, algorithm, pwitem,
1380 &digest->digest, NULL);
1381 if (rv != SECSuccess) {
1382 goto loser;
1383 }
1384
1385 SGN_DestroyDigestInfo(digest);
1386
1387 PORT_ArenaUnmark(p12ctxt->arena, mark);
1388 return SECSuccess;
1389
1390 loser:
1391 SGN_DestroyDigestInfo(digest);
1392 PORT_ArenaRelease(p12ctxt->arena, mark);
1393
1394 return SECFailure;
1395 }
1396
1397 /* like SEC_PKCS12AddCertOrChainAndKey, but always adds cert chain */
1398 SECStatus
SEC_PKCS12AddCertAndKey(SEC_PKCS12ExportContext * p12ctxt,void * certSafe,void * certNestedDest,CERTCertificate * cert,CERTCertDBHandle * certDb,void * keySafe,void * keyNestedDest,PRBool shroudKey,SECItem * pwItem,SECOidTag algorithm)1399 SEC_PKCS12AddCertAndKey(SEC_PKCS12ExportContext *p12ctxt,
1400 void *certSafe, void *certNestedDest,
1401 CERTCertificate *cert, CERTCertDBHandle *certDb,
1402 void *keySafe, void *keyNestedDest,
1403 PRBool shroudKey, SECItem *pwItem, SECOidTag algorithm)
1404 {
1405 return SEC_PKCS12AddCertOrChainAndKey(p12ctxt, certSafe, certNestedDest,
1406 cert, certDb, keySafe, keyNestedDest, shroudKey, pwItem,
1407 algorithm, PR_TRUE);
1408 }
1409
1410 /* SEC_PKCS12CreateNestedSafeContents
1411 * Allows nesting of safe contents to be implemented. No limit imposed on
1412 * depth.
1413 *
1414 * p12ctxt - the export context
1415 * baseSafe - the base safeInfo
1416 * nestedDest - a parent safeContents (?)
1417 */
1418 void *
SEC_PKCS12CreateNestedSafeContents(SEC_PKCS12ExportContext * p12ctxt,void * baseSafe,void * nestedDest)1419 SEC_PKCS12CreateNestedSafeContents(SEC_PKCS12ExportContext *p12ctxt,
1420 void *baseSafe, void *nestedDest)
1421 {
1422 sec_PKCS12SafeContents *newSafe;
1423 sec_PKCS12SafeBag *safeContentsBag;
1424 void *mark;
1425 SECStatus rv;
1426
1427 if (!p12ctxt || !baseSafe) {
1428 return NULL;
1429 }
1430
1431 mark = PORT_ArenaMark(p12ctxt->arena);
1432
1433 newSafe = sec_PKCS12CreateSafeContents(p12ctxt->arena);
1434 if (!newSafe) {
1435 PORT_ArenaRelease(p12ctxt->arena, mark);
1436 PORT_SetError(SEC_ERROR_NO_MEMORY);
1437 return NULL;
1438 }
1439
1440 /* create the safeContents safeBag */
1441 safeContentsBag = sec_PKCS12CreateSafeBag(p12ctxt,
1442 SEC_OID_PKCS12_V1_SAFE_CONTENTS_BAG_ID,
1443 newSafe);
1444 if (!safeContentsBag) {
1445 goto loser;
1446 }
1447
1448 /* append the safeContents to the appropriate area */
1449 if (nestedDest) {
1450 rv = sec_pkcs12_append_bag_to_safe_contents(p12ctxt->arena,
1451 (sec_PKCS12SafeContents *)nestedDest,
1452 safeContentsBag);
1453 } else {
1454 rv = sec_pkcs12_append_bag(p12ctxt, (SEC_PKCS12SafeInfo *)baseSafe,
1455 safeContentsBag);
1456 }
1457 if (rv != SECSuccess) {
1458 goto loser;
1459 }
1460
1461 PORT_ArenaUnmark(p12ctxt->arena, mark);
1462 return newSafe;
1463
1464 loser:
1465 PORT_ArenaRelease(p12ctxt->arena, mark);
1466 return NULL;
1467 }
1468
1469 /*********************************
1470 * Encoding routines
1471 *********************************/
1472
1473 /* Clean up the resources allocated by a sec_PKCS12EncoderContext. */
1474 static void
sec_pkcs12_encoder_destroy_context(sec_PKCS12EncoderContext * p12enc)1475 sec_pkcs12_encoder_destroy_context(sec_PKCS12EncoderContext *p12enc)
1476 {
1477 if (p12enc) {
1478 if (p12enc->outerA1ecx) {
1479 SEC_ASN1EncoderFinish(p12enc->outerA1ecx);
1480 p12enc->outerA1ecx = NULL;
1481 }
1482 if (p12enc->aSafeCinfo) {
1483 SEC_PKCS7DestroyContentInfo(p12enc->aSafeCinfo);
1484 p12enc->aSafeCinfo = NULL;
1485 }
1486 if (p12enc->middleP7ecx) {
1487 SEC_PKCS7EncoderFinish(p12enc->middleP7ecx, p12enc->p12exp->pwfn,
1488 p12enc->p12exp->pwfnarg);
1489 p12enc->middleP7ecx = NULL;
1490 }
1491 if (p12enc->middleA1ecx) {
1492 SEC_ASN1EncoderFinish(p12enc->middleA1ecx);
1493 p12enc->middleA1ecx = NULL;
1494 }
1495 if (p12enc->hmacCx) {
1496 PK11_DestroyContext(p12enc->hmacCx, PR_TRUE);
1497 p12enc->hmacCx = NULL;
1498 }
1499 }
1500 }
1501
1502 /* set up the encoder context based on information in the export context
1503 * and return the newly allocated enocoder context. A return of NULL
1504 * indicates an error occurred.
1505 */
1506 static sec_PKCS12EncoderContext *
sec_pkcs12_encoder_start_context(SEC_PKCS12ExportContext * p12exp)1507 sec_pkcs12_encoder_start_context(SEC_PKCS12ExportContext *p12exp)
1508 {
1509 sec_PKCS12EncoderContext *p12enc = NULL;
1510 unsigned int i, nonEmptyCnt;
1511 SECStatus rv;
1512 SECItem ignore = { 0 };
1513 void *mark;
1514 SECItem *salt = NULL;
1515 SECItem *params = NULL;
1516
1517 if (!p12exp || !p12exp->safeInfos) {
1518 return NULL;
1519 }
1520
1521 /* check for any empty safes and skip them */
1522 i = nonEmptyCnt = 0;
1523 while (p12exp->safeInfos[i]) {
1524 if (p12exp->safeInfos[i]->itemCount) {
1525 nonEmptyCnt++;
1526 }
1527 i++;
1528 }
1529 if (nonEmptyCnt == 0) {
1530 return NULL;
1531 }
1532 p12exp->authSafe.encodedSafes[nonEmptyCnt] = NULL;
1533
1534 /* allocate the encoder context */
1535 mark = PORT_ArenaMark(p12exp->arena);
1536 p12enc = PORT_ArenaZNew(p12exp->arena, sec_PKCS12EncoderContext);
1537 if (!p12enc) {
1538 PORT_SetError(SEC_ERROR_NO_MEMORY);
1539 return NULL;
1540 }
1541
1542 p12enc->arena = p12exp->arena;
1543 p12enc->p12exp = p12exp;
1544
1545 /* set up the PFX version and information */
1546 PORT_Memset(&p12enc->pfx, 0, sizeof(sec_PKCS12PFXItem));
1547 if (!SEC_ASN1EncodeInteger(p12exp->arena, &(p12enc->pfx.version),
1548 SEC_PKCS12_VERSION)) {
1549 PORT_SetError(SEC_ERROR_NO_MEMORY);
1550 goto loser;
1551 }
1552
1553 /* set up the authenticated safe content info based on the
1554 * type of integrity being used. this should be changed to
1555 * enforce integrity mode, but will not be implemented until
1556 * it is confirmed that integrity must be in place
1557 */
1558 if (p12exp->integrityEnabled && !p12exp->pwdIntegrity) {
1559 /* create public key integrity mode */
1560 p12enc->aSafeCinfo = SEC_PKCS7CreateSignedData(
1561 p12exp->integrityInfo.pubkeyInfo.cert,
1562 certUsageEmailSigner,
1563 p12exp->integrityInfo.pubkeyInfo.certDb,
1564 p12exp->integrityInfo.pubkeyInfo.algorithm,
1565 NULL,
1566 p12exp->pwfn,
1567 p12exp->pwfnarg);
1568 if (!p12enc->aSafeCinfo) {
1569 goto loser;
1570 }
1571 if (SEC_PKCS7IncludeCertChain(p12enc->aSafeCinfo, NULL) != SECSuccess) {
1572 goto loser;
1573 }
1574 PORT_CheckSuccess(SEC_PKCS7AddSigningTime(p12enc->aSafeCinfo));
1575 } else {
1576 p12enc->aSafeCinfo = SEC_PKCS7CreateData();
1577
1578 /* init password pased integrity mode */
1579 if (p12exp->integrityEnabled) {
1580 SECItem pwd = { siBuffer, NULL, 0 };
1581 PK11SymKey *symKey;
1582 CK_MECHANISM_TYPE integrityMechType;
1583 CK_MECHANISM_TYPE hmacMechType;
1584 salt = sec_pkcs12_generate_salt();
1585
1586 /* zero out macData and set values */
1587 PORT_Memset(&p12enc->mac, 0, sizeof(sec_PKCS12MacData));
1588
1589 if (!salt) {
1590 PORT_SetError(SEC_ERROR_NO_MEMORY);
1591 goto loser;
1592 }
1593 if (SECITEM_CopyItem(p12exp->arena, &(p12enc->mac.macSalt), salt) != SECSuccess) {
1594 PORT_SetError(SEC_ERROR_NO_MEMORY);
1595 goto loser;
1596 }
1597 if (!SEC_ASN1EncodeInteger(p12exp->arena, &(p12enc->mac.iter),
1598 NSS_PBE_DEFAULT_ITERATION_COUNT)) {
1599 goto loser;
1600 }
1601
1602 /* generate HMAC key */
1603 if (!sec_pkcs12_convert_item_to_unicode(NULL, &pwd,
1604 p12exp->integrityInfo.pwdInfo.password, PR_TRUE,
1605 PR_TRUE, PR_TRUE)) {
1606 goto loser;
1607 }
1608 /*
1609 * This code only works with PKCS #12 Mac using PKCS #5 v1
1610 * PBA keygens. PKCS #5 v2 support will require a change to
1611 * the PKCS #12 spec.
1612 */
1613 params = PK11_CreatePBEParams(salt, &pwd,
1614 NSS_PBE_DEFAULT_ITERATION_COUNT);
1615 SECITEM_ZfreeItem(salt, PR_TRUE);
1616 salt = NULL;
1617 SECITEM_ZfreeItem(&pwd, PR_FALSE);
1618
1619 /* get the PBA Mechanism to generate the key */
1620 integrityMechType = sec_pkcs12_algtag_to_keygen_mech(
1621 p12exp->integrityInfo.pwdInfo.algorithm);
1622 if (integrityMechType == CKM_INVALID_MECHANISM) {
1623 goto loser;
1624 }
1625
1626 /* generate the key */
1627 symKey = PK11_KeyGen(NULL, integrityMechType, params, 20, NULL);
1628 PK11_DestroyPBEParams(params);
1629 if (!symKey) {
1630 goto loser;
1631 }
1632
1633 /* initialize HMAC */
1634 /* Get the HMAC mechanism from the hash OID */
1635 hmacMechType = sec_pkcs12_algtag_to_mech(
1636 p12exp->integrityInfo.pwdInfo.algorithm);
1637
1638 p12enc->hmacCx = PK11_CreateContextBySymKey(hmacMechType,
1639 CKA_SIGN, symKey, &ignore);
1640
1641 PK11_FreeSymKey(symKey);
1642 if (!p12enc->hmacCx) {
1643 PORT_SetError(SEC_ERROR_NO_MEMORY);
1644 goto loser;
1645 }
1646 rv = PK11_DigestBegin(p12enc->hmacCx);
1647 if (rv != SECSuccess)
1648 goto loser;
1649 }
1650 }
1651
1652 if (!p12enc->aSafeCinfo) {
1653 goto loser;
1654 }
1655
1656 PORT_ArenaUnmark(p12exp->arena, mark);
1657
1658 return p12enc;
1659
1660 loser:
1661 sec_pkcs12_encoder_destroy_context(p12enc);
1662 if (p12exp->arena != NULL)
1663 PORT_ArenaRelease(p12exp->arena, mark);
1664 if (salt) {
1665 SECITEM_ZfreeItem(salt, PR_TRUE);
1666 }
1667 if (params) {
1668 PK11_DestroyPBEParams(params);
1669 }
1670
1671 return NULL;
1672 }
1673
1674 /* The outermost ASN.1 encoder calls this function for output.
1675 ** This function calls back to the library caller's output routine,
1676 ** which typically writes to a PKCS12 file.
1677 */
1678 static void
sec_P12A1OutputCB_Outer(void * arg,const char * buf,unsigned long len,int depth,SEC_ASN1EncodingPart data_kind)1679 sec_P12A1OutputCB_Outer(void *arg, const char *buf, unsigned long len,
1680 int depth, SEC_ASN1EncodingPart data_kind)
1681 {
1682 struct sec_pkcs12_encoder_output *output;
1683
1684 output = (struct sec_pkcs12_encoder_output *)arg;
1685 (*output->outputfn)(output->outputarg, buf, len);
1686 }
1687
1688 /* The "middle" and "inner" ASN.1 encoders call this function to output.
1689 ** This function does HMACing, if appropriate, and then buffers the data.
1690 ** The buffered data is eventually passed down to the underlying PKCS7 encoder.
1691 */
1692 static void
sec_P12A1OutputCB_HmacP7Update(void * arg,const char * buf,unsigned long len,int depth,SEC_ASN1EncodingPart data_kind)1693 sec_P12A1OutputCB_HmacP7Update(void *arg, const char *buf,
1694 unsigned long len,
1695 int depth,
1696 SEC_ASN1EncodingPart data_kind)
1697 {
1698 sec_pkcs12OutputBuffer *bufcx = (sec_pkcs12OutputBuffer *)arg;
1699
1700 if (!buf || !len)
1701 return;
1702
1703 if (bufcx->hmacCx) {
1704 PK11_DigestOp(bufcx->hmacCx, (unsigned char *)buf, len);
1705 }
1706
1707 /* buffer */
1708 if (bufcx->numBytes > 0) {
1709 int toCopy;
1710 if (len + bufcx->numBytes <= bufcx->bufBytes) {
1711 memcpy(bufcx->buf + bufcx->numBytes, buf, len);
1712 bufcx->numBytes += len;
1713 if (bufcx->numBytes < bufcx->bufBytes)
1714 return;
1715 SEC_PKCS7EncoderUpdate(bufcx->p7eCx, bufcx->buf, bufcx->bufBytes);
1716 bufcx->numBytes = 0;
1717 return;
1718 }
1719 toCopy = bufcx->bufBytes - bufcx->numBytes;
1720 memcpy(bufcx->buf + bufcx->numBytes, buf, toCopy);
1721 SEC_PKCS7EncoderUpdate(bufcx->p7eCx, bufcx->buf, bufcx->bufBytes);
1722 bufcx->numBytes = 0;
1723 len -= toCopy;
1724 buf += toCopy;
1725 }
1726 /* buffer is presently empty */
1727 if (len >= bufcx->bufBytes) {
1728 /* Just pass it through */
1729 SEC_PKCS7EncoderUpdate(bufcx->p7eCx, buf, len);
1730 } else {
1731 /* copy it all into the buffer, and return */
1732 memcpy(bufcx->buf, buf, len);
1733 bufcx->numBytes = len;
1734 }
1735 }
1736
1737 void
sec_FlushPkcs12OutputBuffer(sec_pkcs12OutputBuffer * bufcx)1738 sec_FlushPkcs12OutputBuffer(sec_pkcs12OutputBuffer *bufcx)
1739 {
1740 if (bufcx->numBytes > 0) {
1741 SEC_PKCS7EncoderUpdate(bufcx->p7eCx, bufcx->buf, bufcx->numBytes);
1742 bufcx->numBytes = 0;
1743 }
1744 }
1745
1746 /* Feeds the output of a PKCS7 encoder into the next outward ASN.1 encoder.
1747 ** This function is used by both the inner and middle PCS7 encoders.
1748 */
1749 static void
sec_P12P7OutputCB_CallA1Update(void * arg,const char * buf,unsigned long len)1750 sec_P12P7OutputCB_CallA1Update(void *arg, const char *buf, unsigned long len)
1751 {
1752 SEC_ASN1EncoderContext *cx = (SEC_ASN1EncoderContext *)arg;
1753
1754 if (!buf || !len)
1755 return;
1756
1757 SEC_ASN1EncoderUpdate(cx, buf, len);
1758 }
1759
1760 /* this function encodes content infos which are part of the
1761 * sequence of content infos labeled AuthenticatedSafes
1762 */
1763 static SECStatus
sec_pkcs12_encoder_asafe_process(sec_PKCS12EncoderContext * p12ecx)1764 sec_pkcs12_encoder_asafe_process(sec_PKCS12EncoderContext *p12ecx)
1765 {
1766 SEC_PKCS7EncoderContext *innerP7ecx;
1767 SEC_PKCS7ContentInfo *cinfo;
1768 PK11SymKey *bulkKey = NULL;
1769 SEC_ASN1EncoderContext *innerA1ecx = NULL;
1770 SECStatus rv = SECSuccess;
1771
1772 if (p12ecx->currentSafe < p12ecx->p12exp->authSafe.safeCount) {
1773 SEC_PKCS12SafeInfo *safeInfo;
1774 SECOidTag cinfoType;
1775
1776 safeInfo = p12ecx->p12exp->safeInfos[p12ecx->currentSafe];
1777
1778 /* skip empty safes */
1779 if (safeInfo->itemCount == 0) {
1780 return SECSuccess;
1781 }
1782
1783 cinfo = safeInfo->cinfo;
1784 cinfoType = SEC_PKCS7ContentType(cinfo);
1785
1786 /* determine the safe type and set the appropriate argument */
1787 switch (cinfoType) {
1788 case SEC_OID_PKCS7_DATA:
1789 case SEC_OID_PKCS7_ENVELOPED_DATA:
1790 break;
1791 case SEC_OID_PKCS7_ENCRYPTED_DATA:
1792 bulkKey = safeInfo->encryptionKey;
1793 PK11_SetSymKeyUserData(bulkKey, &safeInfo->pwitem, NULL);
1794 break;
1795 default:
1796 return SECFailure;
1797 }
1798
1799 /* start the PKCS7 encoder */
1800 innerP7ecx = SEC_PKCS7EncoderStart(cinfo,
1801 sec_P12P7OutputCB_CallA1Update,
1802 p12ecx->middleA1ecx, bulkKey);
1803 if (!innerP7ecx) {
1804 goto loser;
1805 }
1806
1807 /* encode safe contents */
1808 p12ecx->innerBuf.p7eCx = innerP7ecx;
1809 p12ecx->innerBuf.hmacCx = NULL;
1810 p12ecx->innerBuf.numBytes = 0;
1811 p12ecx->innerBuf.bufBytes = sizeof p12ecx->innerBuf.buf;
1812
1813 innerA1ecx = SEC_ASN1EncoderStart(safeInfo->safe,
1814 sec_PKCS12SafeContentsTemplate,
1815 sec_P12A1OutputCB_HmacP7Update,
1816 &p12ecx->innerBuf);
1817 if (!innerA1ecx) {
1818 goto loser;
1819 }
1820 rv = SEC_ASN1EncoderUpdate(innerA1ecx, NULL, 0);
1821 SEC_ASN1EncoderFinish(innerA1ecx);
1822 sec_FlushPkcs12OutputBuffer(&p12ecx->innerBuf);
1823 innerA1ecx = NULL;
1824 if (rv != SECSuccess) {
1825 goto loser;
1826 }
1827
1828 /* finish up safe content info */
1829 rv = SEC_PKCS7EncoderFinish(innerP7ecx, p12ecx->p12exp->pwfn,
1830 p12ecx->p12exp->pwfnarg);
1831 }
1832 memset(&p12ecx->innerBuf, 0, sizeof p12ecx->innerBuf);
1833 return SECSuccess;
1834
1835 loser:
1836 if (innerP7ecx) {
1837 SEC_PKCS7EncoderFinish(innerP7ecx, p12ecx->p12exp->pwfn,
1838 p12ecx->p12exp->pwfnarg);
1839 }
1840
1841 if (innerA1ecx) {
1842 SEC_ASN1EncoderFinish(innerA1ecx);
1843 }
1844 memset(&p12ecx->innerBuf, 0, sizeof p12ecx->innerBuf);
1845 return SECFailure;
1846 }
1847
1848 /* finish the HMAC and encode the macData so that it can be
1849 * encoded.
1850 */
1851 static SECStatus
sec_Pkcs12FinishMac(sec_PKCS12EncoderContext * p12ecx)1852 sec_Pkcs12FinishMac(sec_PKCS12EncoderContext *p12ecx)
1853 {
1854 unsigned char hmacData[HASH_LENGTH_MAX];
1855 unsigned int hmacLen;
1856 SECStatus rv;
1857 SGNDigestInfo *di = NULL;
1858 void *dummy;
1859
1860 if (!p12ecx) {
1861 return SECFailure;
1862 }
1863
1864 /* make sure we are using password integrity mode */
1865 if (!p12ecx->p12exp->integrityEnabled) {
1866 return SECSuccess;
1867 }
1868
1869 if (!p12ecx->p12exp->pwdIntegrity) {
1870 return SECSuccess;
1871 }
1872
1873 /* finish the hmac */
1874
1875 rv = PK11_DigestFinal(p12ecx->hmacCx, hmacData, &hmacLen, HASH_LENGTH_MAX);
1876
1877 if (rv != SECSuccess) {
1878 PORT_SetError(SEC_ERROR_NO_MEMORY);
1879 goto loser;
1880 }
1881
1882 /* create the digest info */
1883 di = SGN_CreateDigestInfo(p12ecx->p12exp->integrityInfo.pwdInfo.algorithm,
1884 hmacData, hmacLen);
1885 if (!di) {
1886 PORT_SetError(SEC_ERROR_NO_MEMORY);
1887 rv = SECFailure;
1888 goto loser;
1889 }
1890
1891 rv = SGN_CopyDigestInfo(p12ecx->arena, &p12ecx->mac.safeMac, di);
1892 if (rv != SECSuccess) {
1893 PORT_SetError(SEC_ERROR_NO_MEMORY);
1894 goto loser;
1895 }
1896
1897 /* encode the mac data */
1898 dummy = SEC_ASN1EncodeItem(p12ecx->arena, &p12ecx->pfx.encodedMacData,
1899 &p12ecx->mac, sec_PKCS12MacDataTemplate);
1900 if (!dummy) {
1901 PORT_SetError(SEC_ERROR_NO_MEMORY);
1902 rv = SECFailure;
1903 }
1904
1905 loser:
1906 if (di) {
1907 SGN_DestroyDigestInfo(di);
1908 }
1909 PK11_DestroyContext(p12ecx->hmacCx, PR_TRUE);
1910 p12ecx->hmacCx = NULL;
1911 PORT_Memset(hmacData, 0, hmacLen);
1912
1913 return rv;
1914 }
1915
1916 /* pfx notify function for ASN1 encoder.
1917 * We want to stop encoding once we reach the authenticated safe.
1918 * At that point, the encoder will be updated via streaming
1919 * as the authenticated safe is encoded.
1920 */
1921 static void
sec_pkcs12_encoder_pfx_notify(void * arg,PRBool before,void * dest,int real_depth)1922 sec_pkcs12_encoder_pfx_notify(void *arg, PRBool before, void *dest, int real_depth)
1923 {
1924 sec_PKCS12EncoderContext *p12ecx;
1925
1926 if (!before) {
1927 return;
1928 }
1929
1930 /* look for authenticated safe */
1931 p12ecx = (sec_PKCS12EncoderContext *)arg;
1932 if (dest != &p12ecx->pfx.encodedAuthSafe) {
1933 return;
1934 }
1935
1936 SEC_ASN1EncoderSetTakeFromBuf(p12ecx->outerA1ecx);
1937 SEC_ASN1EncoderSetStreaming(p12ecx->outerA1ecx);
1938 SEC_ASN1EncoderClearNotifyProc(p12ecx->outerA1ecx);
1939 }
1940
1941 /* SEC_PKCS12Encode
1942 * Encodes the PFX item and returns it to the output function, via
1943 * callback. the output function must be capable of multiple updates.
1944 *
1945 * p12exp - the export context
1946 * output - the output function callback, will be called more than once,
1947 * must be able to accept streaming data.
1948 * outputarg - argument for the output callback.
1949 */
1950 SECStatus
SEC_PKCS12Encode(SEC_PKCS12ExportContext * p12exp,SEC_PKCS12EncoderOutputCallback output,void * outputarg)1951 SEC_PKCS12Encode(SEC_PKCS12ExportContext *p12exp,
1952 SEC_PKCS12EncoderOutputCallback output, void *outputarg)
1953 {
1954 sec_PKCS12EncoderContext *p12enc;
1955 struct sec_pkcs12_encoder_output outInfo;
1956 SECStatus rv;
1957
1958 if (!p12exp || !output) {
1959 return SECFailure;
1960 }
1961
1962 /* get the encoder context */
1963 p12enc = sec_pkcs12_encoder_start_context(p12exp);
1964 if (!p12enc) {
1965 return SECFailure;
1966 }
1967
1968 outInfo.outputfn = output;
1969 outInfo.outputarg = outputarg;
1970
1971 /* set up PFX encoder, the "outer" encoder. Set it for streaming */
1972 p12enc->outerA1ecx = SEC_ASN1EncoderStart(&p12enc->pfx,
1973 sec_PKCS12PFXItemTemplate,
1974 sec_P12A1OutputCB_Outer,
1975 &outInfo);
1976 if (!p12enc->outerA1ecx) {
1977 PORT_SetError(SEC_ERROR_NO_MEMORY);
1978 rv = SECFailure;
1979 goto loser;
1980 }
1981 SEC_ASN1EncoderSetStreaming(p12enc->outerA1ecx);
1982 SEC_ASN1EncoderSetNotifyProc(p12enc->outerA1ecx,
1983 sec_pkcs12_encoder_pfx_notify, p12enc);
1984 rv = SEC_ASN1EncoderUpdate(p12enc->outerA1ecx, NULL, 0);
1985 if (rv != SECSuccess) {
1986 rv = SECFailure;
1987 goto loser;
1988 }
1989
1990 /* set up asafe cinfo - the output of the encoder feeds the PFX encoder */
1991 p12enc->middleP7ecx = SEC_PKCS7EncoderStart(p12enc->aSafeCinfo,
1992 sec_P12P7OutputCB_CallA1Update,
1993 p12enc->outerA1ecx, NULL);
1994 if (!p12enc->middleP7ecx) {
1995 rv = SECFailure;
1996 goto loser;
1997 }
1998
1999 /* encode asafe */
2000 p12enc->middleBuf.p7eCx = p12enc->middleP7ecx;
2001 p12enc->middleBuf.hmacCx = NULL;
2002 p12enc->middleBuf.numBytes = 0;
2003 p12enc->middleBuf.bufBytes = sizeof p12enc->middleBuf.buf;
2004
2005 /* Setup the "inner ASN.1 encoder for Authenticated Safes. */
2006 if (p12enc->p12exp->integrityEnabled &&
2007 p12enc->p12exp->pwdIntegrity) {
2008 p12enc->middleBuf.hmacCx = p12enc->hmacCx;
2009 }
2010 p12enc->middleA1ecx = SEC_ASN1EncoderStart(&p12enc->p12exp->authSafe,
2011 sec_PKCS12AuthenticatedSafeTemplate,
2012 sec_P12A1OutputCB_HmacP7Update,
2013 &p12enc->middleBuf);
2014 if (!p12enc->middleA1ecx) {
2015 rv = SECFailure;
2016 goto loser;
2017 }
2018 SEC_ASN1EncoderSetStreaming(p12enc->middleA1ecx);
2019 SEC_ASN1EncoderSetTakeFromBuf(p12enc->middleA1ecx);
2020
2021 /* encode each of the safes */
2022 while (p12enc->currentSafe != p12enc->p12exp->safeInfoCount) {
2023 sec_pkcs12_encoder_asafe_process(p12enc);
2024 p12enc->currentSafe++;
2025 }
2026 SEC_ASN1EncoderClearTakeFromBuf(p12enc->middleA1ecx);
2027 SEC_ASN1EncoderClearStreaming(p12enc->middleA1ecx);
2028 SEC_ASN1EncoderUpdate(p12enc->middleA1ecx, NULL, 0);
2029 SEC_ASN1EncoderFinish(p12enc->middleA1ecx);
2030 p12enc->middleA1ecx = NULL;
2031
2032 sec_FlushPkcs12OutputBuffer(&p12enc->middleBuf);
2033
2034 /* finish the encoding of the authenticated safes */
2035 rv = SEC_PKCS7EncoderFinish(p12enc->middleP7ecx, p12exp->pwfn,
2036 p12exp->pwfnarg);
2037 p12enc->middleP7ecx = NULL;
2038 if (rv != SECSuccess) {
2039 goto loser;
2040 }
2041
2042 SEC_ASN1EncoderClearTakeFromBuf(p12enc->outerA1ecx);
2043 SEC_ASN1EncoderClearStreaming(p12enc->outerA1ecx);
2044
2045 /* update the mac, if necessary */
2046 rv = sec_Pkcs12FinishMac(p12enc);
2047 if (rv != SECSuccess) {
2048 goto loser;
2049 }
2050
2051 /* finish encoding the pfx */
2052 rv = SEC_ASN1EncoderUpdate(p12enc->outerA1ecx, NULL, 0);
2053
2054 SEC_ASN1EncoderFinish(p12enc->outerA1ecx);
2055 p12enc->outerA1ecx = NULL;
2056
2057 loser:
2058 sec_pkcs12_encoder_destroy_context(p12enc);
2059 return rv;
2060 }
2061
2062 void
SEC_PKCS12DestroyExportContext(SEC_PKCS12ExportContext * p12ecx)2063 SEC_PKCS12DestroyExportContext(SEC_PKCS12ExportContext *p12ecx)
2064 {
2065 int i = 0;
2066
2067 if (!p12ecx) {
2068 return;
2069 }
2070
2071 if (p12ecx->safeInfos) {
2072 i = 0;
2073 while (p12ecx->safeInfos[i] != NULL) {
2074 if (p12ecx->safeInfos[i]->encryptionKey) {
2075 PK11_FreeSymKey(p12ecx->safeInfos[i]->encryptionKey);
2076 }
2077 if (p12ecx->safeInfos[i]->cinfo) {
2078 SEC_PKCS7DestroyContentInfo(p12ecx->safeInfos[i]->cinfo);
2079 }
2080 i++;
2081 }
2082 }
2083
2084 PK11_FreeSlot(p12ecx->slot);
2085
2086 PORT_FreeArena(p12ecx->arena, PR_TRUE);
2087 }
2088