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