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 "nssrenam.h"
6 #include "nss.h"
7 #include "p12t.h"
8 #include "p12.h"
9 #include "plarena.h"
10 #include "secitem.h"
11 #include "secoid.h"
12 #include "seccomon.h"
13 #include "secport.h"
14 #include "cert.h"
15 #include "secpkcs7.h"
16 #include "secasn1.h"
17 #include "secerr.h"
18 #include "pk11func.h"
19 #include "p12plcy.h"
20 #include "p12local.h"
21 #include "secder.h"
22 #include "secport.h"
23 
24 #include "certdb.h"
25 
26 #include "prcpucfg.h"
27 
28 /* This belongs in secport.h */
29 #define PORT_ArenaGrowArray(poolp, oldptr, type, oldnum, newnum) \
30     (type *)PORT_ArenaGrow((poolp), (oldptr),                    \
31                            (oldnum) * sizeof(type), (newnum) * sizeof(type))
32 
33 typedef struct sec_PKCS12SafeContentsContextStr sec_PKCS12SafeContentsContext;
34 
35 /* Opaque structure for decoding SafeContents.  These are used
36  * for each authenticated safe as well as any nested safe contents.
37  */
38 struct sec_PKCS12SafeContentsContextStr {
39     /* the parent decoder context */
40     SEC_PKCS12DecoderContext *p12dcx;
41 
42     /* memory arena to allocate space from */
43     PLArenaPool *arena;
44 
45     /* decoder context and destination for decoding safe contents */
46     SEC_ASN1DecoderContext *safeContentsA1Dcx;
47     sec_PKCS12SafeContents safeContents;
48 
49     /* information for decoding safe bags within the safe contents.
50      * these variables are updated for each safe bag decoded.
51      */
52     SEC_ASN1DecoderContext *currentSafeBagA1Dcx;
53     sec_PKCS12SafeBag *currentSafeBag;
54     PRBool skipCurrentSafeBag;
55 
56     /* if the safe contents is nested, the parent is pointed to here. */
57     sec_PKCS12SafeContentsContext *nestedSafeContentsCtx;
58 };
59 
60 /* opaque decoder context structure.  information for decoding a pkcs 12
61  * PDU are stored here as well as decoding pointers for intermediary
62  * structures which are part of the PKCS 12 PDU.  Upon a successful
63  * decode, the safe bags containing certificates and keys encountered.
64  */
65 struct SEC_PKCS12DecoderContextStr {
66     PLArenaPool *arena;
67     PK11SlotInfo *slot;
68     void *wincx;
69     PRBool error;
70     int errorValue;
71 
72     /* password */
73     SECItem *pwitem;
74 
75     /* used for decoding the PFX structure */
76     SEC_ASN1DecoderContext *pfxA1Dcx;
77     sec_PKCS12PFXItem pfx;
78 
79     /* safe bags found during decoding */
80     sec_PKCS12SafeBag **safeBags;
81     unsigned int safeBagCount;
82 
83     /* state variables for decoding authenticated safes. */
84     SEC_PKCS7DecoderContext *currentASafeP7Dcx;
85     SEC_ASN1DecoderContext *aSafeA1Dcx;
86     SEC_PKCS7DecoderContext *aSafeP7Dcx;
87     SEC_PKCS7ContentInfo *aSafeCinfo;
88     sec_PKCS12AuthenticatedSafe authSafe;
89     sec_PKCS12SafeContents safeContents;
90 
91     /* safe contents info */
92     unsigned int safeContentsCnt;
93     sec_PKCS12SafeContentsContext **safeContentsList;
94 
95     /* HMAC info */
96     sec_PKCS12MacData macData;
97 
98     /* routines for reading back the data to be hmac'd */
99     /* They are called as follows.
100      *
101      * Stage 1: decode the aSafes cinfo into a buffer in dArg,
102      * which p12d.c sometimes refers to as the "temp file".
103      * This occurs during SEC_PKCS12DecoderUpdate calls.
104      *
105      * dOpen(dArg, PR_FALSE)
106      * dWrite(dArg, buf, len)
107      * ...
108      * dWrite(dArg, buf, len)
109      * dClose(dArg, PR_FALSE)
110      *
111      * Stage 2: verify MAC
112      * This occurs SEC_PKCS12DecoderVerify.
113      *
114      * dOpen(dArg, PR_TRUE)
115      * dRead(dArg, buf, IN_BUF_LEN)
116      * ...
117      * dRead(dArg, buf, IN_BUF_LEN)
118      * dClose(dArg, PR_TRUE)
119      */
120     digestOpenFn dOpen;
121     digestCloseFn dClose;
122     digestIOFn dRead, dWrite;
123     void *dArg;
124     PRBool dIsOpen; /* is the temp file created? */
125 
126     /* helper functions */
127     SECKEYGetPasswordKey pwfn;
128     void *pwfnarg;
129     PRBool swapUnicodeBytes;
130     PRBool forceUnicode;
131 
132     /* import information */
133     PRBool bagsVerified;
134 
135     /* buffer management for the default callbacks implementation */
136     void *buffer;       /* storage area */
137     PRInt32 filesize;   /* actual data size */
138     PRInt32 allocated;  /* total buffer size allocated */
139     PRInt32 currentpos; /* position counter */
140     SECPKCS12TargetTokenCAs tokenCAs;
141     sec_PKCS12SafeBag **keyList; /* used by ...IterateNext() */
142     unsigned int iteration;
143     SEC_PKCS12DecoderItem decitem;
144 };
145 
146 /* forward declarations of functions that are used when decoding
147  * safeContents bags which are nested and when decoding the
148  * authenticatedSafes.
149  */
150 static SECStatus
151 sec_pkcs12_decoder_begin_nested_safe_contents(sec_PKCS12SafeContentsContext
152                                                   *safeContentsCtx);
153 static SECStatus
154 sec_pkcs12_decoder_finish_nested_safe_contents(sec_PKCS12SafeContentsContext
155                                                    *safeContentsCtx);
156 
157 /* make sure that the PFX version being decoded is a version
158  * which we support.
159  */
160 static PRBool
sec_pkcs12_proper_version(sec_PKCS12PFXItem * pfx)161 sec_pkcs12_proper_version(sec_PKCS12PFXItem *pfx)
162 {
163     /* if no version, assume it is not supported */
164     if (pfx->version.len == 0) {
165         return PR_FALSE;
166     }
167 
168     if (DER_GetInteger(&pfx->version) > SEC_PKCS12_VERSION) {
169         return PR_FALSE;
170     }
171 
172     return PR_TRUE;
173 }
174 
175 /* retrieve the key for decrypting the safe contents */
176 static PK11SymKey *
sec_pkcs12_decoder_get_decrypt_key(void * arg,SECAlgorithmID * algid)177 sec_pkcs12_decoder_get_decrypt_key(void *arg, SECAlgorithmID *algid)
178 {
179     SEC_PKCS12DecoderContext *p12dcx = (SEC_PKCS12DecoderContext *)arg;
180     PK11SlotInfo *slot;
181     PK11SymKey *bulkKey;
182     SECItem pwitem = { 0 };
183     SECOidTag algorithm;
184 
185     if (!p12dcx) {
186         return NULL;
187     }
188 
189     /* if no slot specified, use the internal key slot */
190     if (p12dcx->slot) {
191         slot = PK11_ReferenceSlot(p12dcx->slot);
192     } else {
193         slot = PK11_GetInternalKeySlot();
194     }
195 
196     algorithm = SECOID_GetAlgorithmTag(algid);
197 
198     if (p12dcx->forceUnicode) {
199         if (SECITEM_CopyItem(NULL, &pwitem, p12dcx->pwitem) != SECSuccess) {
200             PK11_FreeSlot(slot);
201             return NULL;
202         }
203     } else {
204         if (!sec_pkcs12_decode_password(NULL, &pwitem, algorithm, p12dcx->pwitem)) {
205             PK11_FreeSlot(slot);
206             return NULL;
207         }
208     }
209 
210     bulkKey = PK11_PBEKeyGen(slot, algid, &pwitem, PR_FALSE, p12dcx->wincx);
211     /* some tokens can't generate PBE keys on their own, generate the
212      * key in the internal slot, and let the Import code deal with it,
213      * (if the slot can't generate PBEs, then we need to use the internal
214      * slot anyway to unwrap). */
215     if (!bulkKey && !PK11_IsInternal(slot)) {
216         PK11_FreeSlot(slot);
217         slot = PK11_GetInternalKeySlot();
218         bulkKey = PK11_PBEKeyGen(slot, algid, &pwitem, PR_FALSE, p12dcx->wincx);
219     }
220     PK11_FreeSlot(slot);
221 
222     /* set the password data on the key */
223     if (bulkKey) {
224         PK11_SetSymKeyUserData(bulkKey, p12dcx->pwitem, NULL);
225     }
226 
227     if (pwitem.data) {
228         SECITEM_ZfreeItem(&pwitem, PR_FALSE);
229     }
230 
231     return bulkKey;
232 }
233 
234 /* XXX this needs to be modified to handle enveloped data.  most
235  * likely, it should mirror the routines for SMIME in that regard.
236  */
237 static PRBool
sec_pkcs12_decoder_decryption_allowed(SECAlgorithmID * algid,PK11SymKey * bulkkey)238 sec_pkcs12_decoder_decryption_allowed(SECAlgorithmID *algid,
239                                       PK11SymKey *bulkkey)
240 {
241     PRBool decryptionAllowed = SEC_PKCS12DecryptionAllowed(algid);
242 
243     if (!decryptionAllowed) {
244         return PR_FALSE;
245     }
246 
247     return PR_TRUE;
248 }
249 
250 /* when we encounter a new safe bag during the decoding, we need
251  * to allocate space for the bag to be decoded to and set the
252  * state variables appropriately.  all of the safe bags are allocated
253  * in a buffer in the outer SEC_PKCS12DecoderContext, however,
254  * a pointer to the safeBag is also used in the sec_PKCS12SafeContentsContext
255  * for the current bag.
256  */
257 static SECStatus
sec_pkcs12_decoder_init_new_safe_bag(sec_PKCS12SafeContentsContext * safeContentsCtx)258 sec_pkcs12_decoder_init_new_safe_bag(sec_PKCS12SafeContentsContext
259                                          *safeContentsCtx)
260 {
261     void *mark = NULL;
262     SEC_PKCS12DecoderContext *p12dcx;
263 
264     /* make sure that the structures are defined, and there has
265      * not been an error in the decoding
266      */
267     if (!safeContentsCtx || !safeContentsCtx->p12dcx || safeContentsCtx->p12dcx->error) {
268         return SECFailure;
269     }
270 
271     p12dcx = safeContentsCtx->p12dcx;
272     mark = PORT_ArenaMark(p12dcx->arena);
273 
274     /* allocate a new safe bag, if bags already exist, grow the
275      * list of bags, otherwise allocate a new list.  the list is
276      * NULL terminated.
277      */
278     p12dcx->safeBags = (!p12dcx->safeBagCount)
279                            ? PORT_ArenaZNewArray(p12dcx->arena, sec_PKCS12SafeBag *, 2)
280                            : PORT_ArenaGrowArray(p12dcx->arena, p12dcx->safeBags,
281                                                  sec_PKCS12SafeBag *, p12dcx->safeBagCount + 1,
282                                                  p12dcx->safeBagCount + 2);
283 
284     if (!p12dcx->safeBags) {
285         p12dcx->errorValue = PORT_GetError();
286         goto loser;
287     }
288 
289     /* append the bag to the end of the list and update the reference
290      * in the safeContentsCtx.
291      */
292     p12dcx->safeBags[p12dcx->safeBagCount] =
293         safeContentsCtx->currentSafeBag =
294             PORT_ArenaZNew(p12dcx->arena, sec_PKCS12SafeBag);
295     if (!safeContentsCtx->currentSafeBag) {
296         p12dcx->errorValue = PORT_GetError();
297         goto loser;
298     }
299     p12dcx->safeBags[++p12dcx->safeBagCount] = NULL;
300 
301     safeContentsCtx->currentSafeBag->slot = safeContentsCtx->p12dcx->slot;
302     safeContentsCtx->currentSafeBag->pwitem = safeContentsCtx->p12dcx->pwitem;
303     safeContentsCtx->currentSafeBag->swapUnicodeBytes =
304         safeContentsCtx->p12dcx->swapUnicodeBytes;
305     safeContentsCtx->currentSafeBag->arena = safeContentsCtx->p12dcx->arena;
306     safeContentsCtx->currentSafeBag->tokenCAs =
307         safeContentsCtx->p12dcx->tokenCAs;
308 
309     PORT_ArenaUnmark(p12dcx->arena, mark);
310     return SECSuccess;
311 
312 loser:
313 
314     /* if an error occurred, release the memory and set the error flag
315      * the only possible errors triggered by this function are memory
316      * related.
317      */
318     if (mark) {
319         PORT_ArenaRelease(p12dcx->arena, mark);
320     }
321 
322     p12dcx->error = PR_TRUE;
323     return SECFailure;
324 }
325 
326 /* A wrapper for updating the ASN1 context in which a safeBag is
327  * being decoded.  This function is called as a callback from
328  * secasn1d when decoding SafeContents structures.
329  */
330 static void
sec_pkcs12_decoder_safe_bag_update(void * arg,const char * data,unsigned long len,int depth,SEC_ASN1EncodingPart data_kind)331 sec_pkcs12_decoder_safe_bag_update(void *arg, const char *data,
332                                    unsigned long len, int depth,
333                                    SEC_ASN1EncodingPart data_kind)
334 {
335     sec_PKCS12SafeContentsContext *safeContentsCtx =
336         (sec_PKCS12SafeContentsContext *)arg;
337     SEC_PKCS12DecoderContext *p12dcx;
338     SECStatus rv;
339 
340     /* make sure that we are not skipping the current safeBag,
341      * and that there are no errors.  If so, just return rather
342      * than continuing to process.
343      */
344     if (!safeContentsCtx || !safeContentsCtx->p12dcx ||
345         safeContentsCtx->p12dcx->error || safeContentsCtx->skipCurrentSafeBag) {
346         return;
347     }
348     p12dcx = safeContentsCtx->p12dcx;
349 
350     rv = SEC_ASN1DecoderUpdate(safeContentsCtx->currentSafeBagA1Dcx, data, len);
351     if (rv != SECSuccess) {
352         p12dcx->errorValue = PORT_GetError();
353         goto loser;
354     }
355 
356     return;
357 
358 loser:
359     /* set the error, and finish the decoder context.  because there
360      * is not a way of returning an error message, it may be worth
361      * while to do a check higher up and finish any decoding contexts
362      * that are still open.
363      */
364     p12dcx->error = PR_TRUE;
365     SEC_ASN1DecoderFinish(safeContentsCtx->currentSafeBagA1Dcx);
366     safeContentsCtx->currentSafeBagA1Dcx = NULL;
367     return;
368 }
369 
370 /* notify function for decoding safeBags.  This function is
371  * used to filter safeBag types which are not supported,
372  * initiate the decoding of nested safe contents, and decode
373  * safeBags in general.  this function is set when the decoder
374  * context for the safeBag is first created.
375  */
376 static void
sec_pkcs12_decoder_safe_bag_notify(void * arg,PRBool before,void * dest,int real_depth)377 sec_pkcs12_decoder_safe_bag_notify(void *arg, PRBool before,
378                                    void *dest, int real_depth)
379 {
380     sec_PKCS12SafeContentsContext *safeContentsCtx =
381         (sec_PKCS12SafeContentsContext *)arg;
382     SEC_PKCS12DecoderContext *p12dcx;
383     sec_PKCS12SafeBag *bag;
384     PRBool after;
385 
386     /* if an error is encountered, return */
387     if (!safeContentsCtx || !safeContentsCtx->p12dcx ||
388         safeContentsCtx->p12dcx->error) {
389         return;
390     }
391     p12dcx = safeContentsCtx->p12dcx;
392 
393     /* to make things more readable */
394     if (before)
395         after = PR_FALSE;
396     else
397         after = PR_TRUE;
398 
399     /* have we determined the safeBagType yet? */
400     bag = safeContentsCtx->currentSafeBag;
401     if (bag->bagTypeTag == NULL) {
402         if (after && (dest == &(bag->safeBagType))) {
403             bag->bagTypeTag = SECOID_FindOID(&(bag->safeBagType));
404             if (bag->bagTypeTag == NULL) {
405                 p12dcx->error = PR_TRUE;
406                 p12dcx->errorValue = SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE;
407             }
408         }
409         return;
410     }
411 
412     /* process the safeBag depending on it's type.  those
413      * which we do not support, are ignored.  we start a decoding
414      * context for a nested safeContents.
415      */
416     switch (bag->bagTypeTag->offset) {
417         case SEC_OID_PKCS12_V1_KEY_BAG_ID:
418         case SEC_OID_PKCS12_V1_CERT_BAG_ID:
419         case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:
420             break;
421         case SEC_OID_PKCS12_V1_SAFE_CONTENTS_BAG_ID:
422             /* if we are just starting to decode the safeContents, initialize
423              * a new safeContentsCtx to process it.
424              */
425             if (before && (dest == &(bag->safeBagContent))) {
426                 sec_pkcs12_decoder_begin_nested_safe_contents(safeContentsCtx);
427             } else if (after && (dest == &(bag->safeBagContent))) {
428                 /* clean up the nested decoding */
429                 sec_pkcs12_decoder_finish_nested_safe_contents(safeContentsCtx);
430             }
431             break;
432         case SEC_OID_PKCS12_V1_CRL_BAG_ID:
433         case SEC_OID_PKCS12_V1_SECRET_BAG_ID:
434         default:
435             /* skip any safe bag types we don't understand or handle */
436             safeContentsCtx->skipCurrentSafeBag = PR_TRUE;
437             break;
438     }
439 
440     return;
441 }
442 
443 /* notify function for decoding safe contents.  each entry in the
444  * safe contents is a safeBag which needs to be allocated and
445  * the decoding context initialized at the beginning and then
446  * the context needs to be closed and finished at the end.
447  *
448  * this function is set when the safeContents decode context is
449  * initialized.
450  */
451 static void
sec_pkcs12_decoder_safe_contents_notify(void * arg,PRBool before,void * dest,int real_depth)452 sec_pkcs12_decoder_safe_contents_notify(void *arg, PRBool before,
453                                         void *dest, int real_depth)
454 {
455     sec_PKCS12SafeContentsContext *safeContentsCtx =
456         (sec_PKCS12SafeContentsContext *)arg;
457     SEC_PKCS12DecoderContext *p12dcx;
458     SECStatus rv;
459 
460     /* if there is an error we don't want to continue processing,
461      * just return and keep going.
462      */
463     if (!safeContentsCtx || !safeContentsCtx->p12dcx ||
464         safeContentsCtx->p12dcx->error) {
465         return;
466     }
467     p12dcx = safeContentsCtx->p12dcx;
468 
469     /* if we are done with the current safeBag, then we need to
470      * finish the context and set the state variables appropriately.
471      */
472     if (!before) {
473         SEC_ASN1DecoderClearFilterProc(safeContentsCtx->safeContentsA1Dcx);
474         SEC_ASN1DecoderFinish(safeContentsCtx->currentSafeBagA1Dcx);
475         safeContentsCtx->currentSafeBagA1Dcx = NULL;
476         safeContentsCtx->skipCurrentSafeBag = PR_FALSE;
477     } else {
478         /* we are starting a new safe bag.  we need to allocate space
479          * for the bag and initialize the decoding context.
480          */
481         rv = sec_pkcs12_decoder_init_new_safe_bag(safeContentsCtx);
482         if (rv != SECSuccess) {
483             goto loser;
484         }
485 
486         /* set up the decoder context */
487         safeContentsCtx->currentSafeBagA1Dcx =
488             SEC_ASN1DecoderStart(p12dcx->arena,
489                                  safeContentsCtx->currentSafeBag,
490                                  sec_PKCS12SafeBagTemplate);
491         if (!safeContentsCtx->currentSafeBagA1Dcx) {
492             p12dcx->errorValue = PORT_GetError();
493             goto loser;
494         }
495 
496         /* set the notify and filter procs so that the safe bag
497          * data gets sent to the proper location when decoding.
498          */
499         SEC_ASN1DecoderSetNotifyProc(safeContentsCtx->currentSafeBagA1Dcx,
500                                      sec_pkcs12_decoder_safe_bag_notify,
501                                      safeContentsCtx);
502         SEC_ASN1DecoderSetFilterProc(safeContentsCtx->safeContentsA1Dcx,
503                                      sec_pkcs12_decoder_safe_bag_update,
504                                      safeContentsCtx, PR_TRUE);
505     }
506 
507     return;
508 
509 loser:
510     /* in the event of an error, we want to close the decoding
511      * context and clear the filter and notify procedures.
512      */
513     p12dcx->error = PR_TRUE;
514 
515     if (safeContentsCtx->currentSafeBagA1Dcx) {
516         SEC_ASN1DecoderFinish(safeContentsCtx->currentSafeBagA1Dcx);
517         safeContentsCtx->currentSafeBagA1Dcx = NULL;
518     }
519 
520     SEC_ASN1DecoderClearNotifyProc(safeContentsCtx->safeContentsA1Dcx);
521     SEC_ASN1DecoderClearFilterProc(safeContentsCtx->safeContentsA1Dcx);
522 
523     return;
524 }
525 
526 /* initialize the safeContents for decoding.  this routine
527  * is used for authenticatedSafes as well as nested safeContents.
528  */
529 static sec_PKCS12SafeContentsContext *
sec_pkcs12_decoder_safe_contents_init_decode(SEC_PKCS12DecoderContext * p12dcx,PRBool nestedSafe)530 sec_pkcs12_decoder_safe_contents_init_decode(SEC_PKCS12DecoderContext *p12dcx,
531                                              PRBool nestedSafe)
532 {
533     sec_PKCS12SafeContentsContext *safeContentsCtx = NULL;
534     const SEC_ASN1Template *theTemplate;
535 
536     if (!p12dcx || p12dcx->error) {
537         return NULL;
538     }
539 
540     /* allocate a new safeContents list or grow the existing list and
541      * append the new safeContents onto the end.
542      */
543     p12dcx->safeContentsList = (!p12dcx->safeContentsCnt)
544                                    ? PORT_ArenaZNewArray(p12dcx->arena, sec_PKCS12SafeContentsContext *, 2)
545                                    : PORT_ArenaGrowArray(p12dcx->arena, p12dcx->safeContentsList,
546                                                          sec_PKCS12SafeContentsContext *,
547                                                          1 + p12dcx->safeContentsCnt,
548                                                          2 + p12dcx->safeContentsCnt);
549 
550     if (!p12dcx->safeContentsList) {
551         p12dcx->errorValue = PORT_GetError();
552         goto loser;
553     }
554 
555     p12dcx->safeContentsList[p12dcx->safeContentsCnt] = safeContentsCtx =
556         PORT_ArenaZNew(p12dcx->arena, sec_PKCS12SafeContentsContext);
557     if (!p12dcx->safeContentsList[p12dcx->safeContentsCnt]) {
558         p12dcx->errorValue = PORT_GetError();
559         goto loser;
560     }
561     p12dcx->safeContentsList[++p12dcx->safeContentsCnt] = NULL;
562 
563     /* set up the state variables */
564     safeContentsCtx->p12dcx = p12dcx;
565     safeContentsCtx->arena = p12dcx->arena;
566 
567     /* begin the decoding -- the template is based on whether we are
568      * decoding a nested safeContents or not.
569      */
570     if (nestedSafe == PR_TRUE) {
571         theTemplate = sec_PKCS12NestedSafeContentsDecodeTemplate;
572     } else {
573         theTemplate = sec_PKCS12SafeContentsDecodeTemplate;
574     }
575 
576     /* start the decoder context */
577     safeContentsCtx->safeContentsA1Dcx = SEC_ASN1DecoderStart(p12dcx->arena,
578                                                               &safeContentsCtx->safeContents,
579                                                               theTemplate);
580 
581     if (!safeContentsCtx->safeContentsA1Dcx) {
582         p12dcx->errorValue = PORT_GetError();
583         goto loser;
584     }
585 
586     /* set the safeContents notify procedure to look for
587      * and start the decode of safeBags.
588      */
589     SEC_ASN1DecoderSetNotifyProc(safeContentsCtx->safeContentsA1Dcx,
590                                  sec_pkcs12_decoder_safe_contents_notify,
591                                  safeContentsCtx);
592 
593     return safeContentsCtx;
594 
595 loser:
596     /* in the case of an error, we want to finish the decoder
597      * context and set the error flag.
598      */
599     if (safeContentsCtx && safeContentsCtx->safeContentsA1Dcx) {
600         SEC_ASN1DecoderFinish(safeContentsCtx->safeContentsA1Dcx);
601         safeContentsCtx->safeContentsA1Dcx = NULL;
602     }
603 
604     p12dcx->error = PR_TRUE;
605 
606     return NULL;
607 }
608 
609 /* wrapper for updating safeContents.  this is set as the filter of
610  * safeBag when there is a nested safeContents.
611  */
612 static void
sec_pkcs12_decoder_nested_safe_contents_update(void * arg,const char * buf,unsigned long len,int depth,SEC_ASN1EncodingPart data_kind)613 sec_pkcs12_decoder_nested_safe_contents_update(void *arg, const char *buf,
614                                                unsigned long len, int depth,
615                                                SEC_ASN1EncodingPart data_kind)
616 {
617     sec_PKCS12SafeContentsContext *safeContentsCtx =
618         (sec_PKCS12SafeContentsContext *)arg;
619     SEC_PKCS12DecoderContext *p12dcx;
620     SECStatus rv;
621 
622     /* check for an error */
623     if (!safeContentsCtx || !safeContentsCtx->p12dcx ||
624         safeContentsCtx->p12dcx->error || !safeContentsCtx->safeContentsA1Dcx) {
625         return;
626     }
627 
628     /* no need to update if no data sent in */
629     if (!len || !buf) {
630         return;
631     }
632 
633     /* update the decoding context */
634     p12dcx = safeContentsCtx->p12dcx;
635     rv = SEC_ASN1DecoderUpdate(safeContentsCtx->safeContentsA1Dcx, buf, len);
636     if (rv != SECSuccess) {
637         p12dcx->errorValue = PORT_GetError();
638         goto loser;
639     }
640 
641     return;
642 
643 loser:
644     /* handle any errors.  If a decoding context is open, close it. */
645     p12dcx->error = PR_TRUE;
646     if (safeContentsCtx->safeContentsA1Dcx) {
647         SEC_ASN1DecoderFinish(safeContentsCtx->safeContentsA1Dcx);
648         safeContentsCtx->safeContentsA1Dcx = NULL;
649     }
650 }
651 
652 /* whenever a new safeContentsSafeBag is encountered, we need
653  * to init a safeContentsContext.
654  */
655 static SECStatus
sec_pkcs12_decoder_begin_nested_safe_contents(sec_PKCS12SafeContentsContext * safeContentsCtx)656 sec_pkcs12_decoder_begin_nested_safe_contents(sec_PKCS12SafeContentsContext
657                                                   *safeContentsCtx)
658 {
659     /* check for an error */
660     if (!safeContentsCtx || !safeContentsCtx->p12dcx ||
661         safeContentsCtx->p12dcx->error) {
662         return SECFailure;
663     }
664 
665     safeContentsCtx->nestedSafeContentsCtx =
666         sec_pkcs12_decoder_safe_contents_init_decode(safeContentsCtx->p12dcx,
667                                                      PR_TRUE);
668     if (!safeContentsCtx->nestedSafeContentsCtx) {
669         return SECFailure;
670     }
671 
672     /* set up new filter proc */
673     SEC_ASN1DecoderSetNotifyProc(
674         safeContentsCtx->nestedSafeContentsCtx->safeContentsA1Dcx,
675         sec_pkcs12_decoder_safe_contents_notify,
676         safeContentsCtx->nestedSafeContentsCtx);
677 
678     SEC_ASN1DecoderSetFilterProc(safeContentsCtx->currentSafeBagA1Dcx,
679                                  sec_pkcs12_decoder_nested_safe_contents_update,
680                                  safeContentsCtx->nestedSafeContentsCtx,
681                                  PR_TRUE);
682 
683     return SECSuccess;
684 }
685 
686 /* when the safeContents is done decoding, we need to reset the
687  * proper filter and notify procs and close the decoding context
688  */
689 static SECStatus
sec_pkcs12_decoder_finish_nested_safe_contents(sec_PKCS12SafeContentsContext * safeContentsCtx)690 sec_pkcs12_decoder_finish_nested_safe_contents(sec_PKCS12SafeContentsContext
691                                                    *safeContentsCtx)
692 {
693     /* check for error */
694     if (!safeContentsCtx || !safeContentsCtx->p12dcx ||
695         safeContentsCtx->p12dcx->error) {
696         return SECFailure;
697     }
698 
699     /* clean up */
700     SEC_ASN1DecoderClearFilterProc(safeContentsCtx->currentSafeBagA1Dcx);
701     SEC_ASN1DecoderClearNotifyProc(
702         safeContentsCtx->nestedSafeContentsCtx->safeContentsA1Dcx);
703     SEC_ASN1DecoderFinish(
704         safeContentsCtx->nestedSafeContentsCtx->safeContentsA1Dcx);
705     safeContentsCtx->nestedSafeContentsCtx->safeContentsA1Dcx = NULL;
706     safeContentsCtx->nestedSafeContentsCtx = NULL;
707 
708     return SECSuccess;
709 }
710 
711 /* wrapper for updating safeContents.  This is used when decoding
712  * the nested safeContents and any authenticatedSafes.
713  */
714 static void
sec_pkcs12_decoder_safe_contents_callback(void * arg,const char * buf,unsigned long len)715 sec_pkcs12_decoder_safe_contents_callback(void *arg, const char *buf,
716                                           unsigned long len)
717 {
718     SECStatus rv;
719     sec_PKCS12SafeContentsContext *safeContentsCtx =
720         (sec_PKCS12SafeContentsContext *)arg;
721     SEC_PKCS12DecoderContext *p12dcx;
722 
723     /* check for error */
724     if (!safeContentsCtx || !safeContentsCtx->p12dcx ||
725         safeContentsCtx->p12dcx->error || !safeContentsCtx->safeContentsA1Dcx) {
726         return;
727     }
728     p12dcx = safeContentsCtx->p12dcx;
729 
730     /* update the decoder */
731     rv = SEC_ASN1DecoderUpdate(safeContentsCtx->safeContentsA1Dcx, buf, len);
732     if (rv != SECSuccess) {
733         /* if we fail while trying to decode a 'safe', it's probably because
734          * we didn't have the correct password. */
735         PORT_SetError(SEC_ERROR_BAD_PASSWORD);
736         p12dcx->errorValue = SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE;
737         SEC_PKCS7DecoderAbort(p12dcx->currentASafeP7Dcx, SEC_ERROR_BAD_PASSWORD);
738         goto loser;
739     }
740 
741     return;
742 
743 loser:
744     /* set the error and finish the context */
745     p12dcx->error = PR_TRUE;
746     if (safeContentsCtx->safeContentsA1Dcx) {
747         SEC_ASN1DecoderFinish(safeContentsCtx->safeContentsA1Dcx);
748         safeContentsCtx->safeContentsA1Dcx = NULL;
749     }
750 
751     return;
752 }
753 
754 /* this is a wrapper for the ASN1 decoder to call SEC_PKCS7DecoderUpdate
755  */
756 static void
sec_pkcs12_decoder_wrap_p7_update(void * arg,const char * data,unsigned long len,int depth,SEC_ASN1EncodingPart data_kind)757 sec_pkcs12_decoder_wrap_p7_update(void *arg, const char *data,
758                                   unsigned long len, int depth,
759                                   SEC_ASN1EncodingPart data_kind)
760 {
761     SEC_PKCS7DecoderContext *p7dcx = (SEC_PKCS7DecoderContext *)arg;
762 
763     SEC_PKCS7DecoderUpdate(p7dcx, data, len);
764 }
765 
766 /* notify function for decoding aSafes.  at the beginning,
767  * of an authenticatedSafe, we start a decode of a safeContents.
768  * at the end, we clean up the safeContents decoder context and
769  * reset state variables
770  */
771 static void
sec_pkcs12_decoder_asafes_notify(void * arg,PRBool before,void * dest,int real_depth)772 sec_pkcs12_decoder_asafes_notify(void *arg, PRBool before, void *dest,
773                                  int real_depth)
774 {
775     SEC_PKCS12DecoderContext *p12dcx;
776     sec_PKCS12SafeContentsContext *safeContentsCtx;
777 
778     /* make sure no error occurred. */
779     p12dcx = (SEC_PKCS12DecoderContext *)arg;
780     if (!p12dcx || p12dcx->error) {
781         return;
782     }
783 
784     if (before) {
785 
786         /* init a new safeContentsContext */
787         safeContentsCtx = sec_pkcs12_decoder_safe_contents_init_decode(p12dcx,
788                                                                        PR_FALSE);
789         if (!safeContentsCtx) {
790             goto loser;
791         }
792 
793         /* initiate the PKCS7ContentInfo decode */
794         p12dcx->currentASafeP7Dcx = SEC_PKCS7DecoderStart(
795             sec_pkcs12_decoder_safe_contents_callback,
796             safeContentsCtx,
797             p12dcx->pwfn, p12dcx->pwfnarg,
798             sec_pkcs12_decoder_get_decrypt_key, p12dcx,
799             sec_pkcs12_decoder_decryption_allowed);
800         if (!p12dcx->currentASafeP7Dcx) {
801             p12dcx->errorValue = PORT_GetError();
802             goto loser;
803         }
804         SEC_ASN1DecoderSetFilterProc(p12dcx->aSafeA1Dcx,
805                                      sec_pkcs12_decoder_wrap_p7_update,
806                                      p12dcx->currentASafeP7Dcx, PR_TRUE);
807     }
808 
809     if (!before) {
810         /* if one is being decoded, finish the decode */
811         if (p12dcx->currentASafeP7Dcx != NULL) {
812             SEC_PKCS7ContentInfo *cinfo;
813             unsigned int cnt = p12dcx->safeContentsCnt - 1;
814             safeContentsCtx = p12dcx->safeContentsList[cnt];
815             if (safeContentsCtx->safeContentsA1Dcx) {
816                 SEC_ASN1DecoderClearFilterProc(p12dcx->aSafeA1Dcx);
817                 SEC_ASN1DecoderFinish(safeContentsCtx->safeContentsA1Dcx);
818                 safeContentsCtx->safeContentsA1Dcx = NULL;
819             }
820             cinfo = SEC_PKCS7DecoderFinish(p12dcx->currentASafeP7Dcx);
821             p12dcx->currentASafeP7Dcx = NULL;
822             if (!cinfo) {
823                 p12dcx->errorValue = PORT_GetError();
824                 goto loser;
825             }
826             SEC_PKCS7DestroyContentInfo(cinfo); /* don't leak it */
827         }
828     }
829 
830     return;
831 
832 loser:
833     /* set the error flag */
834     p12dcx->error = PR_TRUE;
835     return;
836 }
837 
838 /* wrapper for updating asafes decoding context.  this function
839  * writes data being decoded to disk, so that a mac can be computed
840  * later.
841  */
842 static void
sec_pkcs12_decoder_asafes_callback(void * arg,const char * buf,unsigned long len)843 sec_pkcs12_decoder_asafes_callback(void *arg, const char *buf,
844                                    unsigned long len)
845 {
846     SEC_PKCS12DecoderContext *p12dcx = (SEC_PKCS12DecoderContext *)arg;
847     SECStatus rv;
848 
849     if (!p12dcx || p12dcx->error) {
850         return;
851     }
852 
853     /* update the context */
854     rv = SEC_ASN1DecoderUpdate(p12dcx->aSafeA1Dcx, buf, len);
855     if (rv != SECSuccess) {
856         p12dcx->errorValue = PORT_GetError();
857         p12dcx->error = PR_TRUE;
858         goto loser;
859     }
860 
861     /* if we are writing to a file, write out the new information */
862     if (p12dcx->dWrite) {
863         unsigned long writeLen = (*p12dcx->dWrite)(p12dcx->dArg,
864                                                    (unsigned char *)buf, len);
865         if (writeLen != len) {
866             p12dcx->errorValue = PORT_GetError();
867             goto loser;
868         }
869     }
870 
871     return;
872 
873 loser:
874     /* set the error flag */
875     p12dcx->error = PR_TRUE;
876     SEC_ASN1DecoderFinish(p12dcx->aSafeA1Dcx);
877     p12dcx->aSafeA1Dcx = NULL;
878 
879     return;
880 }
881 
882 /* start the decode of an authenticatedSafe contentInfo.
883  */
884 static SECStatus
sec_pkcs12_decode_start_asafes_cinfo(SEC_PKCS12DecoderContext * p12dcx)885 sec_pkcs12_decode_start_asafes_cinfo(SEC_PKCS12DecoderContext *p12dcx)
886 {
887     if (!p12dcx || p12dcx->error) {
888         return SECFailure;
889     }
890 
891     /* start the decode context */
892     p12dcx->aSafeA1Dcx = SEC_ASN1DecoderStart(p12dcx->arena,
893                                               &p12dcx->authSafe,
894                                               sec_PKCS12AuthenticatedSafeTemplate);
895     if (!p12dcx->aSafeA1Dcx) {
896         p12dcx->errorValue = PORT_GetError();
897         goto loser;
898     }
899 
900     /* set the notify function */
901     SEC_ASN1DecoderSetNotifyProc(p12dcx->aSafeA1Dcx,
902                                  sec_pkcs12_decoder_asafes_notify, p12dcx);
903 
904     /* begin the authSafe decoder context */
905     p12dcx->aSafeP7Dcx = SEC_PKCS7DecoderStart(
906         sec_pkcs12_decoder_asafes_callback, p12dcx,
907         p12dcx->pwfn, p12dcx->pwfnarg, NULL, NULL, NULL);
908     if (!p12dcx->aSafeP7Dcx) {
909         p12dcx->errorValue = PORT_GetError();
910         goto loser;
911     }
912 
913     /* open the temp file for writing, if the digest functions were set */
914     if (p12dcx->dOpen && (*p12dcx->dOpen)(p12dcx->dArg, PR_FALSE) != SECSuccess) {
915         p12dcx->errorValue = PORT_GetError();
916         goto loser;
917     }
918     /* dOpen(dArg, PR_FALSE) creates the temp file */
919     p12dcx->dIsOpen = PR_TRUE;
920 
921     return SECSuccess;
922 
923 loser:
924     p12dcx->error = PR_TRUE;
925 
926     if (p12dcx->aSafeA1Dcx) {
927         SEC_ASN1DecoderFinish(p12dcx->aSafeA1Dcx);
928         p12dcx->aSafeA1Dcx = NULL;
929     }
930 
931     if (p12dcx->aSafeP7Dcx) {
932         SEC_PKCS7DecoderFinish(p12dcx->aSafeP7Dcx);
933         p12dcx->aSafeP7Dcx = NULL;
934     }
935 
936     return SECFailure;
937 }
938 
939 /* wrapper for updating the safeContents.  this function is used as
940  * a filter for the pfx when decoding the authenticated safes
941  */
942 static void
sec_pkcs12_decode_asafes_cinfo_update(void * arg,const char * buf,unsigned long len,int depth,SEC_ASN1EncodingPart data_kind)943 sec_pkcs12_decode_asafes_cinfo_update(void *arg, const char *buf,
944                                       unsigned long len, int depth,
945                                       SEC_ASN1EncodingPart data_kind)
946 {
947     SEC_PKCS12DecoderContext *p12dcx;
948     SECStatus rv;
949 
950     p12dcx = (SEC_PKCS12DecoderContext *)arg;
951     if (!p12dcx || p12dcx->error) {
952         return;
953     }
954 
955     /* update the safeContents decoder */
956     rv = SEC_PKCS7DecoderUpdate(p12dcx->aSafeP7Dcx, buf, len);
957     if (rv != SECSuccess) {
958         p12dcx->errorValue = SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE;
959         goto loser;
960     }
961 
962     return;
963 
964 loser:
965 
966     /* did we find an error?  if so, close the context and set the
967      * error flag.
968      */
969     SEC_PKCS7DecoderFinish(p12dcx->aSafeP7Dcx);
970     p12dcx->aSafeP7Dcx = NULL;
971     p12dcx->error = PR_TRUE;
972 }
973 
974 /* notify procedure used while decoding the pfx.  When we encounter
975  * the authSafes, we want to trigger the decoding of authSafes as well
976  * as when we encounter the macData, trigger the decoding of it.  we do
977  * this because we we are streaming the decoder and not decoding in place.
978  * the pfx which is the destination, only has the version decoded into it.
979  */
980 static void
sec_pkcs12_decoder_pfx_notify_proc(void * arg,PRBool before,void * dest,int real_depth)981 sec_pkcs12_decoder_pfx_notify_proc(void *arg, PRBool before, void *dest,
982                                    int real_depth)
983 {
984     SECStatus rv;
985     SEC_PKCS12DecoderContext *p12dcx = (SEC_PKCS12DecoderContext *)arg;
986 
987     /* if an error occurs, clear the notifyProc and the filterProc
988      * and continue.
989      */
990     if (p12dcx->error) {
991         SEC_ASN1DecoderClearNotifyProc(p12dcx->pfxA1Dcx);
992         SEC_ASN1DecoderClearFilterProc(p12dcx->pfxA1Dcx);
993         return;
994     }
995 
996     if (before && (dest == &p12dcx->pfx.encodedAuthSafe)) {
997 
998         /* we want to make sure this is a version we support */
999         if (!sec_pkcs12_proper_version(&p12dcx->pfx)) {
1000             p12dcx->errorValue = SEC_ERROR_PKCS12_UNSUPPORTED_VERSION;
1001             goto loser;
1002         }
1003 
1004         /* start the decode of the aSafes cinfo... */
1005         rv = sec_pkcs12_decode_start_asafes_cinfo(p12dcx);
1006         if (rv != SECSuccess) {
1007             goto loser;
1008         }
1009 
1010         /* set the filter proc to update the authenticated safes. */
1011         SEC_ASN1DecoderSetFilterProc(p12dcx->pfxA1Dcx,
1012                                      sec_pkcs12_decode_asafes_cinfo_update,
1013                                      p12dcx, PR_TRUE);
1014     }
1015 
1016     if (!before && (dest == &p12dcx->pfx.encodedAuthSafe)) {
1017 
1018         /* we are done decoding the authenticatedSafes, so we need to
1019          * finish the decoderContext and clear the filter proc
1020          * and close the hmac callback, if present
1021          */
1022         p12dcx->aSafeCinfo = SEC_PKCS7DecoderFinish(p12dcx->aSafeP7Dcx);
1023         p12dcx->aSafeP7Dcx = NULL;
1024         if (!p12dcx->aSafeCinfo) {
1025             p12dcx->errorValue = PORT_GetError();
1026             goto loser;
1027         }
1028         SEC_ASN1DecoderClearFilterProc(p12dcx->pfxA1Dcx);
1029         if (p12dcx->dClose && ((*p12dcx->dClose)(p12dcx->dArg, PR_FALSE) != SECSuccess)) {
1030             p12dcx->errorValue = PORT_GetError();
1031             goto loser;
1032         }
1033     }
1034 
1035     return;
1036 
1037 loser:
1038     p12dcx->error = PR_TRUE;
1039 }
1040 
1041 /*  default implementations of the open/close/read/write functions for
1042     SEC_PKCS12DecoderStart
1043 */
1044 
1045 #define DEFAULT_TEMP_SIZE 4096
1046 
1047 static SECStatus
p12u_DigestOpen(void * arg,PRBool readData)1048 p12u_DigestOpen(void *arg, PRBool readData)
1049 {
1050     SEC_PKCS12DecoderContext *p12cxt = arg;
1051 
1052     p12cxt->currentpos = 0;
1053 
1054     if (PR_FALSE == readData) {
1055         /* allocate an initial buffer */
1056         p12cxt->filesize = 0;
1057         p12cxt->allocated = DEFAULT_TEMP_SIZE;
1058         p12cxt->buffer = PORT_Alloc(DEFAULT_TEMP_SIZE);
1059         PR_ASSERT(p12cxt->buffer);
1060     } else {
1061         PR_ASSERT(p12cxt->buffer);
1062         if (!p12cxt->buffer) {
1063             return SECFailure; /* no data to read */
1064         }
1065     }
1066 
1067     return SECSuccess;
1068 }
1069 
1070 static SECStatus
p12u_DigestClose(void * arg,PRBool removeFile)1071 p12u_DigestClose(void *arg, PRBool removeFile)
1072 {
1073     SEC_PKCS12DecoderContext *p12cxt = arg;
1074 
1075     PR_ASSERT(p12cxt);
1076     if (!p12cxt) {
1077         return SECFailure;
1078     }
1079     p12cxt->currentpos = 0;
1080 
1081     if (PR_TRUE == removeFile) {
1082         PR_ASSERT(p12cxt->buffer);
1083         if (!p12cxt->buffer) {
1084             return SECFailure;
1085         }
1086         if (p12cxt->buffer) {
1087             PORT_Free(p12cxt->buffer);
1088             p12cxt->buffer = NULL;
1089             p12cxt->allocated = 0;
1090             p12cxt->filesize = 0;
1091         }
1092     }
1093 
1094     return SECSuccess;
1095 }
1096 
1097 static int
p12u_DigestRead(void * arg,unsigned char * buf,unsigned long len)1098 p12u_DigestRead(void *arg, unsigned char *buf, unsigned long len)
1099 {
1100     int toread = len;
1101     SEC_PKCS12DecoderContext *p12cxt = arg;
1102 
1103     if (!buf || len == 0 || !p12cxt->buffer) {
1104         PORT_SetError(SEC_ERROR_INVALID_ARGS);
1105         return -1;
1106     }
1107 
1108     if ((p12cxt->filesize - p12cxt->currentpos) < (long)len) {
1109         /* trying to read past the end of the buffer */
1110         toread = p12cxt->filesize - p12cxt->currentpos;
1111     }
1112     memcpy(buf, (char *)p12cxt->buffer + p12cxt->currentpos, toread);
1113     p12cxt->currentpos += toread;
1114     return toread;
1115 }
1116 
1117 static int
p12u_DigestWrite(void * arg,unsigned char * buf,unsigned long len)1118 p12u_DigestWrite(void *arg, unsigned char *buf, unsigned long len)
1119 {
1120     SEC_PKCS12DecoderContext *p12cxt = arg;
1121 
1122     if (!buf || len == 0) {
1123         return -1;
1124     }
1125 
1126     if (p12cxt->currentpos + (long)len > p12cxt->filesize) {
1127         p12cxt->filesize = p12cxt->currentpos + len;
1128     } else {
1129         p12cxt->filesize += len;
1130     }
1131     if (p12cxt->filesize > p12cxt->allocated) {
1132         void *newbuffer;
1133         size_t newsize = p12cxt->filesize + DEFAULT_TEMP_SIZE;
1134         newbuffer = PORT_Realloc(p12cxt->buffer, newsize);
1135         if (NULL == newbuffer) {
1136             return -1; /* can't extend the buffer */
1137         }
1138         p12cxt->buffer = newbuffer;
1139         p12cxt->allocated = newsize;
1140     }
1141     PR_ASSERT(p12cxt->buffer);
1142     memcpy((char *)p12cxt->buffer + p12cxt->currentpos, buf, len);
1143     p12cxt->currentpos += len;
1144     return len;
1145 }
1146 
1147 /* SEC_PKCS12DecoderStart
1148  *      Creates a decoder context for decoding a PKCS 12 PDU objct.
1149  *      This function sets up the initial decoding context for the
1150  *      PFX and sets the needed state variables.
1151  *
1152  *      pwitem - the password for the hMac and any encoded safes.
1153  *               this should be changed to take a callback which retrieves
1154  *               the password.  it may be possible for different safes to
1155  *               have different passwords.  also, the password is already
1156  *               in unicode.  it should probably be converted down below via
1157  *               a unicode conversion callback.
1158  *      slot - the slot to import the dataa into should multiple slots
1159  *               be supported based on key type and cert type?
1160  *      dOpen, dClose, dRead, dWrite - digest routines for writing data
1161  *               to a file so it could be read back and the hmac recomputed
1162  *               and verified.  doesn't seem to be a way for both encoding
1163  *               and decoding to be single pass, thus the need for these
1164  *               routines.
1165  *      dArg - the argument for dOpen, etc.
1166  *
1167  *      if NULL == dOpen == dClose == dRead == dWrite == dArg, then default
1168  *      implementations using a memory buffer are used
1169  *
1170  *      This function returns the decoder context, if it was successful.
1171  *      Otherwise, null is returned.
1172  */
1173 SEC_PKCS12DecoderContext *
SEC_PKCS12DecoderStart(SECItem * pwitem,PK11SlotInfo * slot,void * wincx,digestOpenFn dOpen,digestCloseFn dClose,digestIOFn dRead,digestIOFn dWrite,void * dArg)1174 SEC_PKCS12DecoderStart(SECItem *pwitem, PK11SlotInfo *slot, void *wincx,
1175                        digestOpenFn dOpen, digestCloseFn dClose,
1176                        digestIOFn dRead, digestIOFn dWrite, void *dArg)
1177 {
1178     SEC_PKCS12DecoderContext *p12dcx;
1179     PLArenaPool *arena;
1180     PRInt32 forceUnicode = PR_FALSE;
1181     SECStatus rv;
1182 
1183     arena = PORT_NewArena(2048); /* different size? */
1184     if (!arena) {
1185         return NULL; /* error is already set */
1186     }
1187 
1188     /* allocate the decoder context and set the state variables */
1189     p12dcx = PORT_ArenaZNew(arena, SEC_PKCS12DecoderContext);
1190     if (!p12dcx) {
1191         goto loser; /* error is already set */
1192     }
1193 
1194     if (!dOpen && !dClose && !dRead && !dWrite && !dArg) {
1195         /* use default implementations */
1196         dOpen = p12u_DigestOpen;
1197         dClose = p12u_DigestClose;
1198         dRead = p12u_DigestRead;
1199         dWrite = p12u_DigestWrite;
1200         dArg = (void *)p12dcx;
1201     }
1202 
1203     p12dcx->arena = arena;
1204     p12dcx->pwitem = pwitem;
1205     p12dcx->slot = (slot ? PK11_ReferenceSlot(slot)
1206                          : PK11_GetInternalKeySlot());
1207     p12dcx->wincx = wincx;
1208     p12dcx->tokenCAs = SECPKCS12TargetTokenNoCAs;
1209 #ifdef IS_LITTLE_ENDIAN
1210     p12dcx->swapUnicodeBytes = PR_TRUE;
1211 #else
1212     p12dcx->swapUnicodeBytes = PR_FALSE;
1213 #endif
1214     rv = NSS_OptionGet(__NSS_PKCS12_DECODE_FORCE_UNICODE, &forceUnicode);
1215     if (rv != SECSuccess) {
1216         goto loser;
1217     }
1218     p12dcx->forceUnicode = forceUnicode;
1219     p12dcx->errorValue = 0;
1220     p12dcx->error = PR_FALSE;
1221 
1222     /* start the decoding of the PFX and set the notify proc
1223      * for the PFX item.
1224      */
1225     p12dcx->pfxA1Dcx = SEC_ASN1DecoderStart(p12dcx->arena, &p12dcx->pfx,
1226                                             sec_PKCS12PFXItemTemplate);
1227     if (!p12dcx->pfxA1Dcx) {
1228         PK11_FreeSlot(p12dcx->slot);
1229         goto loser;
1230     }
1231 
1232     SEC_ASN1DecoderSetNotifyProc(p12dcx->pfxA1Dcx,
1233                                  sec_pkcs12_decoder_pfx_notify_proc,
1234                                  p12dcx);
1235 
1236     /* set up digest functions */
1237     p12dcx->dOpen = dOpen;
1238     p12dcx->dWrite = dWrite;
1239     p12dcx->dClose = dClose;
1240     p12dcx->dRead = dRead;
1241     p12dcx->dArg = dArg;
1242     p12dcx->dIsOpen = PR_FALSE;
1243 
1244     p12dcx->keyList = NULL;
1245     p12dcx->decitem.type = 0;
1246     p12dcx->decitem.der = NULL;
1247     p12dcx->decitem.hasKey = PR_FALSE;
1248     p12dcx->decitem.friendlyName = NULL;
1249     p12dcx->iteration = 0;
1250 
1251     return p12dcx;
1252 
1253 loser:
1254     PORT_FreeArena(arena, PR_TRUE);
1255     return NULL;
1256 }
1257 
1258 SECStatus
SEC_PKCS12DecoderSetTargetTokenCAs(SEC_PKCS12DecoderContext * p12dcx,SECPKCS12TargetTokenCAs tokenCAs)1259 SEC_PKCS12DecoderSetTargetTokenCAs(SEC_PKCS12DecoderContext *p12dcx,
1260                                    SECPKCS12TargetTokenCAs tokenCAs)
1261 {
1262     if (!p12dcx || p12dcx->error) {
1263         return SECFailure;
1264     }
1265     p12dcx->tokenCAs = tokenCAs;
1266     return SECSuccess;
1267 }
1268 
1269 /* SEC_PKCS12DecoderUpdate
1270  *      Streaming update sending more data to the decoder.  If
1271  *      an error occurs, SECFailure is returned.
1272  *
1273  *      p12dcx - the decoder context
1274  *      data, len - the data buffer and length of data to send to
1275  *              the update functions.
1276  */
1277 SECStatus
SEC_PKCS12DecoderUpdate(SEC_PKCS12DecoderContext * p12dcx,unsigned char * data,unsigned long len)1278 SEC_PKCS12DecoderUpdate(SEC_PKCS12DecoderContext *p12dcx,
1279                         unsigned char *data, unsigned long len)
1280 {
1281     SECStatus rv;
1282 
1283     if (!p12dcx || p12dcx->error) {
1284         PORT_SetError(SEC_ERROR_INVALID_ARGS);
1285         return SECFailure;
1286     }
1287 
1288     /* update the PFX decoder context */
1289     rv = SEC_ASN1DecoderUpdate(p12dcx->pfxA1Dcx, (const char *)data, len);
1290     if (rv != SECSuccess) {
1291         p12dcx->errorValue = SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE;
1292         goto loser;
1293     }
1294 
1295     return SECSuccess;
1296 
1297 loser:
1298 
1299     p12dcx->error = PR_TRUE;
1300     return SECFailure;
1301 }
1302 
1303 /* This should be a nice sized buffer for reading in data (potentially large
1304 ** amounts) to be MACed.  It should be MUCH larger than HASH_LENGTH_MAX.
1305 */
1306 #define IN_BUF_LEN 1024
1307 #ifdef DEBUG
1308 static const char bufferEnd[] = { "BufferEnd" };
1309 #endif
1310 #define FUDGE 128 /* must be as large as bufferEnd or more. */
1311 
1312 /* verify the hmac by reading the data from the temporary file
1313  * using the routines specified when the decodingContext was
1314  * created and return SECSuccess if the hmac matches.
1315  */
1316 static SECStatus
sec_pkcs12_decoder_verify_mac(SEC_PKCS12DecoderContext * p12dcx)1317 sec_pkcs12_decoder_verify_mac(SEC_PKCS12DecoderContext *p12dcx)
1318 {
1319     PK11Context *pk11cx = NULL;
1320     PK11SymKey *symKey = NULL;
1321     SECItem *params = NULL;
1322     unsigned char *buf;
1323     SECStatus rv = SECFailure;
1324     SECStatus lrv;
1325     unsigned int bufLen;
1326     int iteration;
1327     int bytesRead;
1328     SECOidTag algtag;
1329     SECItem hmacRes;
1330     SECItem ignore = { 0 };
1331     CK_MECHANISM_TYPE integrityMech;
1332 
1333     if (!p12dcx || p12dcx->error) {
1334         PORT_SetError(SEC_ERROR_INVALID_ARGS);
1335         return SECFailure;
1336     }
1337     buf = (unsigned char *)PORT_Alloc(IN_BUF_LEN + FUDGE);
1338     if (!buf)
1339         return SECFailure; /* error code has been set. */
1340 
1341 #ifdef DEBUG
1342     memcpy(buf + IN_BUF_LEN, bufferEnd, sizeof bufferEnd);
1343 #endif
1344 
1345     /* generate hmac key */
1346     if (p12dcx->macData.iter.data) {
1347         iteration = (int)DER_GetInteger(&p12dcx->macData.iter);
1348     } else {
1349         iteration = 1;
1350     }
1351 
1352     params = PK11_CreatePBEParams(&p12dcx->macData.macSalt, p12dcx->pwitem,
1353                                   iteration);
1354 
1355     algtag = SECOID_GetAlgorithmTag(&p12dcx->macData.safeMac.digestAlgorithm);
1356     integrityMech = sec_pkcs12_algtag_to_keygen_mech(algtag);
1357     if (integrityMech == CKM_INVALID_MECHANISM) {
1358         goto loser;
1359     }
1360     symKey = PK11_KeyGen(NULL, integrityMech, params, 0, NULL);
1361     PK11_DestroyPBEParams(params);
1362     params = NULL;
1363     if (!symKey)
1364         goto loser;
1365     /* init hmac */
1366     pk11cx = PK11_CreateContextBySymKey(sec_pkcs12_algtag_to_mech(algtag),
1367                                         CKA_SIGN, symKey, &ignore);
1368     if (!pk11cx) {
1369         goto loser;
1370     }
1371     lrv = PK11_DigestBegin(pk11cx);
1372     if (lrv == SECFailure) {
1373         goto loser;
1374     }
1375 
1376     /* try to open the data for readback */
1377     if (p12dcx->dOpen && ((*p12dcx->dOpen)(p12dcx->dArg, PR_TRUE) != SECSuccess)) {
1378         goto loser;
1379     }
1380 
1381     /* read the data back IN_BUF_LEN bytes at a time and recompute
1382      * the hmac.  if fewer bytes are read than are requested, it is
1383      * assumed that the end of file has been reached. if bytesRead
1384      * is returned as -1, then an error occurred reading from the
1385      * file.
1386      */
1387     do {
1388         bytesRead = (*p12dcx->dRead)(p12dcx->dArg, buf, IN_BUF_LEN);
1389         if (bytesRead < 0) {
1390             PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_READ);
1391             goto loser;
1392         }
1393         PORT_Assert(bytesRead <= IN_BUF_LEN);
1394         PORT_Assert(!memcmp(buf + IN_BUF_LEN, bufferEnd, sizeof bufferEnd));
1395 
1396         if (bytesRead > IN_BUF_LEN) {
1397             /* dRead callback overflowed buffer. */
1398             PORT_SetError(SEC_ERROR_INPUT_LEN);
1399             goto loser;
1400         }
1401 
1402         if (bytesRead) {
1403             lrv = PK11_DigestOp(pk11cx, buf, bytesRead);
1404             if (lrv == SECFailure) {
1405                 goto loser;
1406             }
1407         }
1408     } while (bytesRead == IN_BUF_LEN);
1409 
1410     /* finish the hmac context */
1411     lrv = PK11_DigestFinal(pk11cx, buf, &bufLen, IN_BUF_LEN);
1412     if (lrv == SECFailure) {
1413         goto loser;
1414     }
1415 
1416     hmacRes.data = buf;
1417     hmacRes.len = bufLen;
1418 
1419     /* is the hmac computed the same as the hmac which was decoded? */
1420     rv = SECSuccess;
1421     if (SECITEM_CompareItem(&hmacRes, &p12dcx->macData.safeMac.digest) != SECEqual) {
1422         PORT_SetError(SEC_ERROR_PKCS12_INVALID_MAC);
1423         rv = SECFailure;
1424     }
1425 
1426 loser:
1427     /* close the file and remove it */
1428     if (p12dcx->dClose) {
1429         (*p12dcx->dClose)(p12dcx->dArg, PR_TRUE);
1430         p12dcx->dIsOpen = PR_FALSE;
1431     }
1432 
1433     if (pk11cx) {
1434         PK11_DestroyContext(pk11cx, PR_TRUE);
1435     }
1436     if (params) {
1437         PK11_DestroyPBEParams(params);
1438     }
1439     if (symKey) {
1440         PK11_FreeSymKey(symKey);
1441     }
1442     PORT_ZFree(buf, IN_BUF_LEN + FUDGE);
1443 
1444     return rv;
1445 }
1446 
1447 /* SEC_PKCS12DecoderVerify
1448  *      Verify the macData or the signature of the decoded PKCS 12 PDU.
1449  *      If the signature or the macData do not match, SECFailure is
1450  *      returned.
1451  *
1452  *      p12dcx - the decoder context
1453  */
1454 SECStatus
SEC_PKCS12DecoderVerify(SEC_PKCS12DecoderContext * p12dcx)1455 SEC_PKCS12DecoderVerify(SEC_PKCS12DecoderContext *p12dcx)
1456 {
1457     SECStatus rv = SECSuccess;
1458 
1459     /* make sure that no errors have occurred... */
1460     if (!p12dcx) {
1461         PORT_SetError(SEC_ERROR_INVALID_ARGS);
1462         return SECFailure;
1463     }
1464     if (p12dcx->error) {
1465         /* error code is already set! PORT_SetError(p12dcx->errorValue); */
1466         return SECFailure;
1467     }
1468 
1469     rv = SEC_ASN1DecoderFinish(p12dcx->pfxA1Dcx);
1470     p12dcx->pfxA1Dcx = NULL;
1471     if (rv != SECSuccess) {
1472         return rv;
1473     }
1474 
1475     /* check the signature or the mac depending on the type of
1476      * integrity used.
1477      */
1478     if (p12dcx->pfx.encodedMacData.len) {
1479         rv = SEC_ASN1DecodeItem(p12dcx->arena, &p12dcx->macData,
1480                                 sec_PKCS12MacDataTemplate,
1481                                 &p12dcx->pfx.encodedMacData);
1482         if (rv == SECSuccess) {
1483             return sec_pkcs12_decoder_verify_mac(p12dcx);
1484         }
1485         return rv;
1486     }
1487     if (SEC_PKCS7VerifySignature(p12dcx->aSafeCinfo, certUsageEmailSigner,
1488                                  PR_FALSE)) {
1489         return SECSuccess;
1490     }
1491     PORT_SetError(SEC_ERROR_PKCS12_INVALID_MAC);
1492     return SECFailure;
1493 }
1494 
1495 /* SEC_PKCS12DecoderFinish
1496  *      Free any open ASN1 or PKCS7 decoder contexts and then
1497  *      free the arena pool which everything should be allocated
1498  *      from.  This function should be called upon completion of
1499  *      decoding and installing of a pfx pdu.  This should be
1500  *      called even if an error occurs.
1501  *
1502  *      p12dcx - the decoder context
1503  */
1504 void
SEC_PKCS12DecoderFinish(SEC_PKCS12DecoderContext * p12dcx)1505 SEC_PKCS12DecoderFinish(SEC_PKCS12DecoderContext *p12dcx)
1506 {
1507     unsigned int i;
1508 
1509     if (!p12dcx) {
1510         PORT_SetError(SEC_ERROR_INVALID_ARGS);
1511         return;
1512     }
1513 
1514     if (p12dcx->pfxA1Dcx) {
1515         SEC_ASN1DecoderFinish(p12dcx->pfxA1Dcx);
1516         p12dcx->pfxA1Dcx = NULL;
1517     }
1518 
1519     if (p12dcx->aSafeA1Dcx) {
1520         SEC_ASN1DecoderFinish(p12dcx->aSafeA1Dcx);
1521         p12dcx->aSafeA1Dcx = NULL;
1522     }
1523 
1524     /* cleanup any old ASN1 decoder contexts */
1525     for (i = 0; i < p12dcx->safeContentsCnt; ++i) {
1526         sec_PKCS12SafeContentsContext *safeContentsCtx, *nested;
1527         safeContentsCtx = p12dcx->safeContentsList[i];
1528         if (safeContentsCtx) {
1529             nested = safeContentsCtx->nestedSafeContentsCtx;
1530             while (nested) {
1531                 if (nested->safeContentsA1Dcx) {
1532                     SEC_ASN1DecoderFinish(nested->safeContentsA1Dcx);
1533                     nested->safeContentsA1Dcx = NULL;
1534                 }
1535                 nested = nested->nestedSafeContentsCtx;
1536             }
1537             if (safeContentsCtx->safeContentsA1Dcx) {
1538                 SEC_ASN1DecoderFinish(safeContentsCtx->safeContentsA1Dcx);
1539                 safeContentsCtx->safeContentsA1Dcx = NULL;
1540             }
1541         }
1542     }
1543 
1544     if (p12dcx->currentASafeP7Dcx &&
1545         p12dcx->currentASafeP7Dcx != p12dcx->aSafeP7Dcx) {
1546         SEC_PKCS7ContentInfo *cinfo;
1547         cinfo = SEC_PKCS7DecoderFinish(p12dcx->currentASafeP7Dcx);
1548         if (cinfo) {
1549             SEC_PKCS7DestroyContentInfo(cinfo); /* don't leak it */
1550         }
1551     }
1552     p12dcx->currentASafeP7Dcx = NULL;
1553 
1554     if (p12dcx->aSafeP7Dcx) {
1555         SEC_PKCS7ContentInfo *cinfo;
1556         cinfo = SEC_PKCS7DecoderFinish(p12dcx->aSafeP7Dcx);
1557         if (cinfo) {
1558             SEC_PKCS7DestroyContentInfo(cinfo);
1559         }
1560         p12dcx->aSafeP7Dcx = NULL;
1561     }
1562 
1563     if (p12dcx->aSafeCinfo) {
1564         SEC_PKCS7DestroyContentInfo(p12dcx->aSafeCinfo);
1565         p12dcx->aSafeCinfo = NULL;
1566     }
1567 
1568     if (p12dcx->decitem.type != 0 && p12dcx->decitem.der != NULL) {
1569         SECITEM_FreeItem(p12dcx->decitem.der, PR_TRUE);
1570     }
1571     if (p12dcx->decitem.friendlyName != NULL) {
1572         SECITEM_FreeItem(p12dcx->decitem.friendlyName, PR_TRUE);
1573     }
1574 
1575     if (p12dcx->slot) {
1576         PK11_FreeSlot(p12dcx->slot);
1577         p12dcx->slot = NULL;
1578     }
1579 
1580     if (p12dcx->dIsOpen && p12dcx->dClose) {
1581         (*p12dcx->dClose)(p12dcx->dArg, PR_TRUE);
1582         p12dcx->dIsOpen = PR_FALSE;
1583     }
1584 
1585     if (p12dcx->arena) {
1586         PORT_FreeArena(p12dcx->arena, PR_TRUE);
1587     }
1588 }
1589 
1590 static SECStatus
sec_pkcs12_decoder_set_attribute_value(sec_PKCS12SafeBag * bag,SECOidTag attributeType,SECItem * attrValue)1591 sec_pkcs12_decoder_set_attribute_value(sec_PKCS12SafeBag *bag,
1592                                        SECOidTag attributeType,
1593                                        SECItem *attrValue)
1594 {
1595     int i = 0;
1596     SECOidData *oid;
1597 
1598     if (!bag || !attrValue) {
1599         PORT_SetError(SEC_ERROR_INVALID_ARGS);
1600         return SECFailure;
1601     }
1602 
1603     oid = SECOID_FindOIDByTag(attributeType);
1604     if (!oid) {
1605         return SECFailure;
1606     }
1607 
1608     if (!bag->attribs) {
1609         bag->attribs =
1610             PORT_ArenaZNewArray(bag->arena, sec_PKCS12Attribute *, 2);
1611     } else {
1612         while (bag->attribs[i])
1613             i++;
1614         bag->attribs = PORT_ArenaGrowArray(bag->arena, bag->attribs,
1615                                            sec_PKCS12Attribute *, i + 1, i + 2);
1616     }
1617 
1618     if (!bag->attribs) {
1619         return SECFailure;
1620     }
1621 
1622     bag->attribs[i] = PORT_ArenaZNew(bag->arena, sec_PKCS12Attribute);
1623     if (!bag->attribs[i]) {
1624         return SECFailure;
1625     }
1626 
1627     bag->attribs[i]->attrValue = PORT_ArenaZNewArray(bag->arena, SECItem *, 2);
1628     if (!bag->attribs[i]->attrValue) {
1629         return SECFailure;
1630     }
1631 
1632     bag->attribs[i + 1] = NULL;
1633     bag->attribs[i]->attrValue[0] = attrValue;
1634     bag->attribs[i]->attrValue[1] = NULL;
1635 
1636     return SECITEM_CopyItem(bag->arena, &bag->attribs[i]->attrType, &oid->oid);
1637 }
1638 
1639 static SECItem *
sec_pkcs12_get_attribute_value(sec_PKCS12SafeBag * bag,SECOidTag attributeType)1640 sec_pkcs12_get_attribute_value(sec_PKCS12SafeBag *bag,
1641                                SECOidTag attributeType)
1642 {
1643     int i;
1644 
1645     if (!bag->attribs) {
1646         PORT_SetError(SEC_ERROR_INVALID_ARGS);
1647         return NULL;
1648     }
1649 
1650     for (i = 0; bag->attribs[i] != NULL; i++) {
1651         if (SECOID_FindOIDTag(&bag->attribs[i]->attrType) == attributeType) {
1652             return bag->attribs[i]->attrValue[0];
1653         }
1654     }
1655     return NULL;
1656 }
1657 
1658 /* For now, this function will merely remove any ":"
1659  * in the nickname which the PK11 functions may have
1660  * placed there.  This will keep dual certs from appearing
1661  * twice under "Your" certificates when imported onto smart
1662  * cards.  Once with the name "Slot:Cert" and another with
1663  * the nickname "Slot:Slot:Cert"
1664  */
1665 static void
sec_pkcs12_sanitize_nickname(PK11SlotInfo * slot,SECItem * nick)1666 sec_pkcs12_sanitize_nickname(PK11SlotInfo *slot, SECItem *nick)
1667 {
1668     char *nickname;
1669     char *delimit;
1670     int delimitlen;
1671 
1672     nickname = (char *)nick->data;
1673     if ((delimit = PORT_Strchr(nickname, ':')) != NULL) {
1674         char *slotName;
1675         int slotNameLen;
1676 
1677         slotNameLen = delimit - nickname;
1678         slotName = PORT_NewArray(char, (slotNameLen + 1));
1679         PORT_Assert(slotName);
1680         if (slotName == NULL) {
1681             /* What else can we do?*/
1682             return;
1683         }
1684         PORT_Memcpy(slotName, nickname, slotNameLen);
1685         slotName[slotNameLen] = '\0';
1686         if (PORT_Strcmp(PK11_GetTokenName(slot), slotName) == 0) {
1687             delimitlen = PORT_Strlen(delimit + 1);
1688             PORT_Memmove(nickname, delimit + 1, delimitlen + 1);
1689             nick->len = delimitlen;
1690         }
1691         PORT_Free(slotName);
1692     }
1693 }
1694 
1695 static SECItem *
sec_pkcs12_get_nickname(sec_PKCS12SafeBag * bag)1696 sec_pkcs12_get_nickname(sec_PKCS12SafeBag *bag)
1697 {
1698     SECItem *src, *dest;
1699 
1700     if (!bag) {
1701         PORT_SetError(SEC_ERROR_INVALID_ARGS);
1702         return NULL;
1703     }
1704 
1705     src = sec_pkcs12_get_attribute_value(bag, SEC_OID_PKCS9_FRIENDLY_NAME);
1706 
1707     /* The return value src is 16-bit Unicode characters, in big-endian format.
1708      * Check if it is NULL or empty name.
1709      */
1710     if (!src || !src->data || src->len < 2 || (!src->data[0] && !src->data[1])) {
1711         return NULL;
1712     }
1713 
1714     dest = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
1715     if (!dest) {
1716         goto loser;
1717     }
1718     if (!sec_pkcs12_convert_item_to_unicode(NULL, dest, src, PR_FALSE,
1719                                             PR_FALSE, PR_FALSE)) {
1720         goto loser;
1721     }
1722 
1723     sec_pkcs12_sanitize_nickname(bag->slot, dest);
1724 
1725     return dest;
1726 
1727 loser:
1728     if (dest) {
1729         SECITEM_ZfreeItem(dest, PR_TRUE);
1730     }
1731 
1732     bag->problem = PR_TRUE;
1733     bag->error = PORT_GetError();
1734     return NULL;
1735 }
1736 
1737 static SECStatus
sec_pkcs12_set_nickname(sec_PKCS12SafeBag * bag,SECItem * name)1738 sec_pkcs12_set_nickname(sec_PKCS12SafeBag *bag, SECItem *name)
1739 {
1740     sec_PKCS12Attribute *attr = NULL;
1741     SECOidData *oid = SECOID_FindOIDByTag(SEC_OID_PKCS9_FRIENDLY_NAME);
1742 
1743     if (!bag || !bag->arena || !name) {
1744         PORT_SetError(SEC_ERROR_INVALID_ARGS);
1745         return SECFailure;
1746     }
1747 
1748     if (!bag->attribs) {
1749         if (!oid) {
1750             goto loser;
1751         }
1752 
1753         bag->attribs =
1754             PORT_ArenaZNewArray(bag->arena, sec_PKCS12Attribute *, 2);
1755         if (!bag->attribs) {
1756             goto loser;
1757         }
1758         bag->attribs[0] = PORT_ArenaZNew(bag->arena, sec_PKCS12Attribute);
1759         if (!bag->attribs[0]) {
1760             goto loser;
1761         }
1762         bag->attribs[1] = NULL;
1763 
1764         attr = bag->attribs[0];
1765         if (SECITEM_CopyItem(bag->arena, &attr->attrType, &oid->oid) != SECSuccess) {
1766             goto loser;
1767         }
1768     } else {
1769         int i;
1770         for (i = 0; bag->attribs[i]; i++) {
1771             if (SECOID_FindOIDTag(&bag->attribs[i]->attrType) == SEC_OID_PKCS9_FRIENDLY_NAME) {
1772                 attr = bag->attribs[i];
1773                 break;
1774             }
1775         }
1776         if (!attr) {
1777             if (!oid) {
1778                 goto loser;
1779             }
1780             bag->attribs = PORT_ArenaGrowArray(bag->arena, bag->attribs,
1781                                                sec_PKCS12Attribute *, i + 1, i + 2);
1782             if (!bag->attribs) {
1783                 goto loser;
1784             }
1785             bag->attribs[i] = PORT_ArenaZNew(bag->arena, sec_PKCS12Attribute);
1786             if (!bag->attribs[i]) {
1787                 goto loser;
1788             }
1789             bag->attribs[i + 1] = NULL;
1790             attr = bag->attribs[i];
1791             if (SECITEM_CopyItem(bag->arena, &attr->attrType, &oid->oid) != SECSuccess) {
1792                 goto loser;
1793             }
1794         }
1795     }
1796 
1797     PORT_Assert(attr);
1798     if (!attr->attrValue) {
1799         attr->attrValue = PORT_ArenaZNewArray(bag->arena, SECItem *, 2);
1800         if (!attr->attrValue) {
1801             goto loser;
1802         }
1803         attr->attrValue[0] = PORT_ArenaZNew(bag->arena, SECItem);
1804         if (!attr->attrValue[0]) {
1805             goto loser;
1806         }
1807         attr->attrValue[1] = NULL;
1808     }
1809 
1810     name->len = PORT_Strlen((char *)name->data);
1811     if (!sec_pkcs12_convert_item_to_unicode(bag->arena, attr->attrValue[0],
1812                                             name, PR_FALSE, PR_FALSE, PR_TRUE)) {
1813         goto loser;
1814     }
1815 
1816     return SECSuccess;
1817 
1818 loser:
1819     bag->problem = PR_TRUE;
1820     bag->error = PORT_GetError();
1821     return SECFailure;
1822 }
1823 
1824 static SECStatus
sec_pkcs12_get_key_info(sec_PKCS12SafeBag * key)1825 sec_pkcs12_get_key_info(sec_PKCS12SafeBag *key)
1826 {
1827     int i = 0;
1828     SECKEYPrivateKeyInfo *pki = NULL;
1829 
1830     if (!key) {
1831         PORT_SetError(SEC_ERROR_INVALID_ARGS);
1832         return SECFailure;
1833     }
1834 
1835     /* if the bag does *not* contain an unencrypted PrivateKeyInfo
1836      * then we cannot convert the attributes.  We are propagating
1837      * attributes within the PrivateKeyInfo to the SafeBag level.
1838      */
1839     if (SECOID_FindOIDTag(&(key->safeBagType)) !=
1840         SEC_OID_PKCS12_V1_KEY_BAG_ID) {
1841         return SECSuccess;
1842     }
1843 
1844     pki = key->safeBagContent.pkcs8KeyBag;
1845 
1846     if (!pki || !pki->attributes) {
1847         return SECSuccess;
1848     }
1849 
1850     while (pki->attributes[i]) {
1851         SECOidTag tag = SECOID_FindOIDTag(&pki->attributes[i]->attrType);
1852 
1853         if (tag == SEC_OID_PKCS9_LOCAL_KEY_ID ||
1854             tag == SEC_OID_PKCS9_FRIENDLY_NAME) {
1855             SECItem *attrValue = sec_pkcs12_get_attribute_value(key, tag);
1856             if (!attrValue) {
1857                 if (sec_pkcs12_decoder_set_attribute_value(key, tag,
1858                                                            pki->attributes[i]->attrValue[0]) != SECSuccess) {
1859                     key->problem = PR_TRUE;
1860                     key->error = PORT_GetError();
1861                     return SECFailure;
1862                 }
1863             }
1864         }
1865         i++;
1866     }
1867 
1868     return SECSuccess;
1869 }
1870 
1871 /* retrieve the nickname for the certificate bag.  first look
1872  * in the cert bag, otherwise get it from the key.
1873  */
1874 static SECItem *
sec_pkcs12_get_nickname_for_cert(sec_PKCS12SafeBag * cert,sec_PKCS12SafeBag * key)1875 sec_pkcs12_get_nickname_for_cert(sec_PKCS12SafeBag *cert,
1876                                  sec_PKCS12SafeBag *key)
1877 {
1878     SECItem *nickname;
1879 
1880     if (!cert) {
1881         PORT_SetError(SEC_ERROR_INVALID_ARGS);
1882         return NULL;
1883     }
1884 
1885     nickname = sec_pkcs12_get_nickname(cert);
1886     if (nickname) {
1887         return nickname;
1888     }
1889 
1890     if (key) {
1891         nickname = sec_pkcs12_get_nickname(key);
1892 
1893         if (nickname && sec_pkcs12_set_nickname(cert, nickname) != SECSuccess) {
1894             SECITEM_ZfreeItem(nickname, PR_TRUE);
1895             return NULL;
1896         }
1897     }
1898 
1899     return nickname;
1900 }
1901 
1902 /* set the nickname for the certificate */
1903 static SECStatus
sec_pkcs12_set_nickname_for_cert(sec_PKCS12SafeBag * cert,sec_PKCS12SafeBag * key,SECItem * nickname)1904 sec_pkcs12_set_nickname_for_cert(sec_PKCS12SafeBag *cert,
1905                                  sec_PKCS12SafeBag *key,
1906                                  SECItem *nickname)
1907 {
1908     if (!nickname || !cert) {
1909         PORT_SetError(SEC_ERROR_INVALID_ARGS);
1910         return SECFailure;
1911     }
1912 
1913     if (sec_pkcs12_set_nickname(cert, nickname) != SECSuccess) {
1914         return SECFailure;
1915     }
1916 
1917     if (key) {
1918         if (sec_pkcs12_set_nickname(key, nickname) != SECSuccess) {
1919             cert->problem = PR_TRUE;
1920             cert->error = key->error;
1921             return SECFailure;
1922         }
1923     }
1924 
1925     return SECSuccess;
1926 }
1927 
1928 /* retrieve the DER cert from the cert bag */
1929 static SECItem *
sec_pkcs12_get_der_cert(sec_PKCS12SafeBag * cert)1930 sec_pkcs12_get_der_cert(sec_PKCS12SafeBag *cert)
1931 {
1932     if (!cert) {
1933         PORT_SetError(SEC_ERROR_INVALID_ARGS);
1934         return NULL;
1935     }
1936 
1937     if (SECOID_FindOIDTag(&cert->safeBagType) != SEC_OID_PKCS12_V1_CERT_BAG_ID) {
1938         return NULL;
1939     }
1940 
1941     /* only support X509 certs not SDSI */
1942     if (SECOID_FindOIDTag(&cert->safeBagContent.certBag->bagID) != SEC_OID_PKCS9_X509_CERT) {
1943         return NULL;
1944     }
1945 
1946     return SECITEM_DupItem(&(cert->safeBagContent.certBag->value.x509Cert));
1947 }
1948 
1949 struct certNickInfo {
1950     PLArenaPool *arena;
1951     unsigned int nNicks;
1952     SECItem **nickList;
1953     unsigned int error;
1954 };
1955 
1956 /* callback for traversing certificates to gather the nicknames
1957  * used in a particular traversal.  for instance, when using
1958  * CERT_TraversePermCertsForSubject, gather the nicknames and
1959  * store them in the certNickInfo for a particular DN.
1960  *
1961  * this handles the case where multiple nicknames are allowed
1962  * for the same dn, which is not currently allowed, but may be
1963  * in the future.
1964  */
1965 static SECStatus
gatherNicknames(CERTCertificate * cert,void * arg)1966 gatherNicknames(CERTCertificate *cert, void *arg)
1967 {
1968     struct certNickInfo *nickArg = (struct certNickInfo *)arg;
1969     SECItem tempNick;
1970     unsigned int i;
1971 
1972     if (!cert || !nickArg || nickArg->error) {
1973         PORT_SetError(SEC_ERROR_INVALID_ARGS);
1974         return SECFailure;
1975     }
1976 
1977     if (!cert->nickname) {
1978         return SECSuccess;
1979     }
1980 
1981     tempNick.data = (unsigned char *)cert->nickname;
1982     tempNick.len = PORT_Strlen(cert->nickname) + 1;
1983     tempNick.type = siAsciiString;
1984 
1985     /* do we already have the nickname in the list? */
1986     if (nickArg->nNicks > 0) {
1987 
1988         /* nicknames have been encountered, but there is no list -- bad */
1989         if (!nickArg->nickList) {
1990             nickArg->error = SEC_ERROR_INVALID_ARGS;
1991             PORT_SetError(SEC_ERROR_INVALID_ARGS);
1992             return SECFailure;
1993         }
1994 
1995         for (i = 0; i < nickArg->nNicks; i++) {
1996             if (SECITEM_CompareItem(nickArg->nickList[i], &tempNick) == SECEqual) {
1997                 return SECSuccess;
1998             }
1999         }
2000     }
2001 
2002     /* add the nickname to the list */
2003     nickArg->nickList = (nickArg->nNicks == 0)
2004                             ? PORT_ArenaZNewArray(nickArg->arena, SECItem *, 2)
2005                             : PORT_ArenaGrowArray(nickArg->arena, nickArg->nickList, SECItem *,
2006                                                   nickArg->nNicks + 1, nickArg->nNicks + 2);
2007 
2008     if (!nickArg->nickList) {
2009         nickArg->error = SEC_ERROR_NO_MEMORY;
2010         return SECFailure;
2011     }
2012 
2013     nickArg->nickList[nickArg->nNicks] =
2014         PORT_ArenaZNew(nickArg->arena, SECItem);
2015     if (!nickArg->nickList[nickArg->nNicks]) {
2016         nickArg->error = PORT_GetError();
2017         return SECFailure;
2018     }
2019 
2020     if (SECITEM_CopyItem(nickArg->arena, nickArg->nickList[nickArg->nNicks],
2021                          &tempNick) != SECSuccess) {
2022         nickArg->error = PORT_GetError();
2023         return SECFailure;
2024     }
2025 
2026     nickArg->nNicks++;
2027 
2028     return SECSuccess;
2029 }
2030 
2031 /* traverses the certs in the data base or in the token for the
2032  * DN to see if any certs currently have a nickname set.
2033  * If so, return it.
2034  */
2035 static SECItem *
sec_pkcs12_get_existing_nick_for_dn(sec_PKCS12SafeBag * cert)2036 sec_pkcs12_get_existing_nick_for_dn(sec_PKCS12SafeBag *cert)
2037 {
2038     struct certNickInfo *nickArg = NULL;
2039     SECItem *derCert, *returnDn = NULL;
2040     PLArenaPool *arena = NULL;
2041     CERTCertificate *tempCert;
2042 
2043     if (!cert) {
2044         PORT_SetError(SEC_ERROR_INVALID_ARGS);
2045         return NULL;
2046     }
2047 
2048     derCert = sec_pkcs12_get_der_cert(cert);
2049     if (!derCert) {
2050         return NULL;
2051     }
2052 
2053     tempCert = CERT_DecodeDERCertificate(derCert, PR_FALSE, NULL);
2054     if (!tempCert) {
2055         returnDn = NULL;
2056         goto loser;
2057     }
2058 
2059     arena = PORT_NewArena(1024);
2060     if (!arena) {
2061         returnDn = NULL;
2062         goto loser;
2063     }
2064     nickArg = PORT_ArenaZNew(arena, struct certNickInfo);
2065     if (!nickArg) {
2066         returnDn = NULL;
2067         goto loser;
2068     }
2069     nickArg->error = 0;
2070     nickArg->nNicks = 0;
2071     nickArg->nickList = NULL;
2072     nickArg->arena = arena;
2073 
2074     /* if the token is local, first traverse the cert database
2075      * then traverse the token.
2076      */
2077     if (PK11_TraverseCertsForSubjectInSlot(tempCert, cert->slot, gatherNicknames,
2078                                            (void *)nickArg) != SECSuccess) {
2079         returnDn = NULL;
2080         goto loser;
2081     }
2082 
2083     if (nickArg->error) {
2084         /* XXX do we want to set the error? */
2085         returnDn = NULL;
2086         goto loser;
2087     }
2088 
2089     if (nickArg->nNicks == 0) {
2090         returnDn = NULL;
2091         goto loser;
2092     }
2093 
2094     /* set it to the first name, for now.  handle multiple names? */
2095     returnDn = SECITEM_DupItem(nickArg->nickList[0]);
2096 
2097 loser:
2098     if (arena) {
2099         PORT_FreeArena(arena, PR_TRUE);
2100     }
2101 
2102     if (tempCert) {
2103         CERT_DestroyCertificate(tempCert);
2104     }
2105 
2106     if (derCert) {
2107         SECITEM_FreeItem(derCert, PR_TRUE);
2108     }
2109 
2110     return (returnDn);
2111 }
2112 
2113 /* counts certificates found for a given traversal function */
2114 static SECStatus
countCertificate(CERTCertificate * cert,void * arg)2115 countCertificate(CERTCertificate *cert, void *arg)
2116 {
2117     unsigned int *nCerts = (unsigned int *)arg;
2118 
2119     if (!cert || !arg) {
2120         PORT_SetError(SEC_ERROR_INVALID_ARGS);
2121         return SECFailure;
2122     }
2123 
2124     (*nCerts)++;
2125     return SECSuccess;
2126 }
2127 
2128 static PRBool
sec_pkcs12_certs_for_nickname_exist(SECItem * nickname,PK11SlotInfo * slot)2129 sec_pkcs12_certs_for_nickname_exist(SECItem *nickname, PK11SlotInfo *slot)
2130 {
2131     unsigned int nCerts = 0;
2132 
2133     if (!nickname || !slot) {
2134         PORT_SetError(SEC_ERROR_INVALID_ARGS);
2135         return PR_TRUE;
2136     }
2137 
2138     /* we want to check the local database first if we are importing to it */
2139     PK11_TraverseCertsForNicknameInSlot(nickname, slot, countCertificate,
2140                                         (void *)&nCerts);
2141     return (PRBool)(nCerts != 0);
2142 }
2143 
2144 /* validate cert nickname such that there is a one-to-one relation
2145  * between nicknames and dn's.  we want to enforce the case that the
2146  * nickname is non-NULL and that there is only one nickname per DN.
2147  *
2148  * if there is a problem with a nickname or the nickname is not present,
2149  * the user will be prompted for it.
2150  */
2151 static void
sec_pkcs12_validate_cert_nickname(sec_PKCS12SafeBag * cert,sec_PKCS12SafeBag * key,SEC_PKCS12NicknameCollisionCallback nicknameCb,CERTCertificate * leafCert)2152 sec_pkcs12_validate_cert_nickname(sec_PKCS12SafeBag *cert,
2153                                   sec_PKCS12SafeBag *key,
2154                                   SEC_PKCS12NicknameCollisionCallback nicknameCb,
2155                                   CERTCertificate *leafCert)
2156 {
2157     SECItem *certNickname, *existingDNNick;
2158     PRBool setNickname = PR_FALSE, cancel = PR_FALSE;
2159     SECItem *newNickname = NULL;
2160 
2161     if (!cert || !cert->hasKey) {
2162         PORT_SetError(SEC_ERROR_INVALID_ARGS);
2163         return;
2164     }
2165 
2166     if (!nicknameCb) {
2167         cert->problem = PR_TRUE;
2168         cert->error = SEC_ERROR_INVALID_ARGS;
2169         PORT_SetError(SEC_ERROR_INVALID_ARGS);
2170         return;
2171     }
2172 
2173     if (cert->hasKey && !key) {
2174         cert->problem = PR_TRUE;
2175         cert->error = SEC_ERROR_INVALID_ARGS;
2176         PORT_SetError(SEC_ERROR_INVALID_ARGS);
2177         return;
2178     }
2179 
2180     certNickname = sec_pkcs12_get_nickname_for_cert(cert, key);
2181     existingDNNick = sec_pkcs12_get_existing_nick_for_dn(cert);
2182 
2183     /* nickname is already used w/ this dn, so it is safe to return */
2184     if (certNickname && existingDNNick &&
2185         SECITEM_CompareItem(certNickname, existingDNNick) == SECEqual) {
2186         goto loser;
2187     }
2188 
2189     /* nickname not set in pkcs 12 bags, but a nick is already used for
2190      * this dn.  set the nicks in the p12 bags and finish.
2191      */
2192     if (existingDNNick) {
2193         sec_pkcs12_set_nickname_for_cert(cert, key, existingDNNick);
2194         goto loser;
2195     }
2196 
2197     /* at this point, we have a certificate for which the DN is not located
2198      * on the token.  the nickname specified may or may not be NULL.  if it
2199      * is not null, we need to make sure that there are no other certificates
2200      * with this nickname in the token for it to be valid.  this imposes a
2201      * one to one relationship between DN and nickname.
2202      *
2203      * if the nickname is null, we need the user to enter a nickname for
2204      * the certificate.
2205      *
2206      * once we have a nickname, we make sure that the nickname is unique
2207      * for the DN.  if it is not, the user is reprompted to enter a new
2208      * nickname.
2209      *
2210      * in order to exit this loop, the nickname entered is either unique
2211      * or the user hits cancel and the certificate is not imported.
2212      */
2213     setNickname = PR_FALSE;
2214     while (1) {
2215         /* we will use the nickname so long as no other certs have the
2216          * same nickname.  and the nickname is not NULL.
2217          */
2218         if (certNickname && certNickname->data &&
2219             !sec_pkcs12_certs_for_nickname_exist(certNickname, cert->slot)) {
2220             if (setNickname) {
2221                 sec_pkcs12_set_nickname_for_cert(cert, key, certNickname);
2222             }
2223             break;
2224         }
2225 
2226         setNickname = PR_FALSE;
2227         newNickname = (*nicknameCb)(certNickname, &cancel, leafCert);
2228         if (cancel) {
2229             cert->problem = PR_TRUE;
2230             cert->error = SEC_ERROR_USER_CANCELLED;
2231             break;
2232         }
2233 
2234         if (!newNickname) {
2235             cert->problem = PR_TRUE;
2236             cert->error = PORT_GetError();
2237             break;
2238         }
2239 
2240         /* at this point we have a new nickname, if we have an existing
2241          * certNickname, we need to free it and assign the new nickname
2242          * to it to avoid a memory leak.  happy?
2243          */
2244         if (certNickname) {
2245             SECITEM_ZfreeItem(certNickname, PR_TRUE);
2246             certNickname = NULL;
2247         }
2248 
2249         certNickname = newNickname;
2250         setNickname = PR_TRUE;
2251         /* go back and recheck the new nickname */
2252     }
2253 
2254 loser:
2255     if (certNickname) {
2256         SECITEM_ZfreeItem(certNickname, PR_TRUE);
2257     }
2258 
2259     if (existingDNNick) {
2260         SECITEM_ZfreeItem(existingDNNick, PR_TRUE);
2261     }
2262 }
2263 
2264 static void
sec_pkcs12_validate_cert(sec_PKCS12SafeBag * cert,sec_PKCS12SafeBag * key,SEC_PKCS12NicknameCollisionCallback nicknameCb)2265 sec_pkcs12_validate_cert(sec_PKCS12SafeBag *cert,
2266                          sec_PKCS12SafeBag *key,
2267                          SEC_PKCS12NicknameCollisionCallback nicknameCb)
2268 {
2269     CERTCertificate *leafCert;
2270 
2271     if (!cert) {
2272         PORT_SetError(SEC_ERROR_INVALID_ARGS);
2273         return;
2274     }
2275 
2276     cert->validated = PR_TRUE;
2277 
2278     if (!nicknameCb) {
2279         cert->noInstall = PR_TRUE;
2280         cert->problem = PR_TRUE;
2281         cert->error = SEC_ERROR_INVALID_ARGS;
2282         PORT_SetError(SEC_ERROR_INVALID_ARGS);
2283         return;
2284     }
2285 
2286     if (!cert->safeBagContent.certBag) {
2287         cert->noInstall = PR_TRUE;
2288         cert->problem = PR_TRUE;
2289         cert->error = SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE;
2290         return;
2291     }
2292 
2293     cert->noInstall = PR_FALSE;
2294     cert->unused = PR_FALSE;
2295     cert->problem = PR_FALSE;
2296     cert->error = 0;
2297 
2298     leafCert = CERT_DecodeDERCertificate(
2299         &cert->safeBagContent.certBag->value.x509Cert, PR_FALSE, NULL);
2300     if (!leafCert) {
2301         cert->noInstall = PR_TRUE;
2302         cert->problem = PR_TRUE;
2303         cert->error = PORT_GetError();
2304         return;
2305     }
2306 
2307     sec_pkcs12_validate_cert_nickname(cert, key, nicknameCb, leafCert);
2308 
2309     CERT_DestroyCertificate(leafCert);
2310 }
2311 
2312 static void
sec_pkcs12_validate_key_by_cert(sec_PKCS12SafeBag * cert,sec_PKCS12SafeBag * key,void * wincx)2313 sec_pkcs12_validate_key_by_cert(sec_PKCS12SafeBag *cert, sec_PKCS12SafeBag *key,
2314                                 void *wincx)
2315 {
2316     CERTCertificate *leafCert;
2317     SECKEYPrivateKey *privk;
2318 
2319     if (!key) {
2320         PORT_SetError(SEC_ERROR_INVALID_ARGS);
2321         return;
2322     }
2323 
2324     key->validated = PR_TRUE;
2325 
2326     if (!cert) {
2327         key->problem = PR_TRUE;
2328         key->noInstall = PR_TRUE;
2329         key->error = SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY;
2330         return;
2331     }
2332 
2333     leafCert = CERT_DecodeDERCertificate(
2334         &(cert->safeBagContent.certBag->value.x509Cert), PR_FALSE, NULL);
2335     if (!leafCert) {
2336         key->problem = PR_TRUE;
2337         key->noInstall = PR_TRUE;
2338         key->error = PORT_GetError();
2339         return;
2340     }
2341 
2342     privk = PK11_FindPrivateKeyFromCert(key->slot, leafCert, wincx);
2343     if (!privk) {
2344         privk = PK11_FindKeyByDERCert(key->slot, leafCert, wincx);
2345     }
2346 
2347     if (privk) {
2348         SECKEY_DestroyPrivateKey(privk);
2349         key->noInstall = PR_TRUE;
2350     }
2351 
2352     CERT_DestroyCertificate(leafCert);
2353 }
2354 
2355 static SECStatus
sec_pkcs12_add_cert(sec_PKCS12SafeBag * cert,PRBool keyExists,void * wincx)2356 sec_pkcs12_add_cert(sec_PKCS12SafeBag *cert, PRBool keyExists, void *wincx)
2357 {
2358     SECItem *derCert, *nickName;
2359     char *nickData = NULL;
2360     PRBool isIntermediateCA;
2361     SECStatus rv;
2362 
2363     if (!cert) {
2364         PORT_SetError(SEC_ERROR_INVALID_ARGS);
2365         return SECFailure;
2366     }
2367 
2368     if (cert->problem || cert->noInstall || cert->installed) {
2369         return SECSuccess;
2370     }
2371 
2372     derCert = &cert->safeBagContent.certBag->value.x509Cert;
2373 
2374     PORT_Assert(!cert->problem && !cert->noInstall);
2375 
2376     nickName = sec_pkcs12_get_nickname(cert);
2377     if (nickName) {
2378         nickData = (char *)nickName->data;
2379     }
2380 
2381     isIntermediateCA = CERT_IsCADERCert(derCert, NULL) &&
2382                        !CERT_IsRootDERCert(derCert);
2383 
2384     if (keyExists) {
2385         CERTCertificate *newCert;
2386 
2387         newCert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
2388                                           derCert, NULL, PR_FALSE, PR_FALSE);
2389         if (!newCert) {
2390             if (nickName)
2391                 SECITEM_ZfreeItem(nickName, PR_TRUE);
2392             cert->error = PORT_GetError();
2393             cert->problem = PR_TRUE;
2394             return SECFailure;
2395         }
2396 
2397         rv = PK11_ImportCertForKeyToSlot(cert->slot, newCert, nickData,
2398                                          PR_TRUE, wincx);
2399         CERT_DestroyCertificate(newCert);
2400     } else if ((cert->tokenCAs == SECPKCS12TargetTokenNoCAs) ||
2401                ((cert->tokenCAs == SECPKCS12TargetTokenIntermediateCAs) &&
2402                 !isIntermediateCA)) {
2403         SECItem *certList[2];
2404         certList[0] = derCert;
2405         certList[1] = NULL;
2406 
2407         rv = CERT_ImportCerts(CERT_GetDefaultCertDB(), certUsageUserCertImport,
2408                               1, certList, NULL, PR_TRUE, PR_FALSE, nickData);
2409     } else {
2410         rv = PK11_ImportDERCert(cert->slot, derCert, CK_INVALID_HANDLE,
2411                                 nickData, PR_FALSE);
2412     }
2413     if (rv) {
2414         cert->problem = 1;
2415         cert->error = PORT_GetError();
2416     }
2417     cert->installed = PR_TRUE;
2418     if (nickName)
2419         SECITEM_ZfreeItem(nickName, PR_TRUE);
2420     return rv;
2421 }
2422 
2423 static SECItem *
2424 sec_pkcs12_get_public_value_and_type(SECKEYPublicKey *pubKey, KeyType *type);
2425 
2426 static SECStatus
sec_pkcs12_add_key(sec_PKCS12SafeBag * key,SECKEYPublicKey * pubKey,unsigned int keyUsage,SECItem * nickName,PRBool forceUnicode,void * wincx)2427 sec_pkcs12_add_key(sec_PKCS12SafeBag *key, SECKEYPublicKey *pubKey,
2428                    unsigned int keyUsage,
2429                    SECItem *nickName, PRBool forceUnicode, void *wincx)
2430 {
2431     SECStatus rv;
2432     SECItem *publicValue = NULL;
2433     KeyType keyType;
2434 
2435     /* We should always have values for "key" and "pubKey"
2436        so they can be dereferenced later. */
2437     if (!key || !pubKey) {
2438         PORT_SetError(SEC_ERROR_INVALID_ARGS);
2439         return SECFailure;
2440     }
2441 
2442     if (key->problem || key->noInstall) {
2443         return SECSuccess;
2444     }
2445 
2446     /* get the value and type from the public key */
2447     publicValue = sec_pkcs12_get_public_value_and_type(pubKey, &keyType);
2448     if (!publicValue) {
2449         key->error = SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY;
2450         key->problem = PR_TRUE;
2451         return SECFailure;
2452     }
2453 
2454     switch (SECOID_FindOIDTag(&key->safeBagType)) {
2455         case SEC_OID_PKCS12_V1_KEY_BAG_ID:
2456             rv = PK11_ImportPrivateKeyInfo(key->slot,
2457                                            key->safeBagContent.pkcs8KeyBag,
2458                                            nickName, publicValue, PR_TRUE, PR_TRUE,
2459                                            keyUsage, wincx);
2460             break;
2461         case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID: {
2462             SECItem pwitem = { 0 };
2463             SECAlgorithmID *algid =
2464                 &key->safeBagContent.pkcs8ShroudedKeyBag->algorithm;
2465             SECOidTag algorithm = SECOID_GetAlgorithmTag(algid);
2466 
2467             if (forceUnicode) {
2468                 if (SECITEM_CopyItem(NULL, &pwitem, key->pwitem) != SECSuccess) {
2469                     key->error = SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY;
2470                     key->problem = PR_TRUE;
2471                     return SECFailure;
2472                 }
2473             } else {
2474                 if (!sec_pkcs12_decode_password(NULL, &pwitem, algorithm,
2475                                                 key->pwitem)) {
2476                     key->error = SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY;
2477                     key->problem = PR_TRUE;
2478                     return SECFailure;
2479                 }
2480             }
2481 
2482             rv = PK11_ImportEncryptedPrivateKeyInfo(key->slot,
2483                                                     key->safeBagContent.pkcs8ShroudedKeyBag,
2484                                                     &pwitem, nickName, publicValue,
2485                                                     PR_TRUE, PR_TRUE, keyType, keyUsage,
2486                                                     wincx);
2487             if (pwitem.data) {
2488                 SECITEM_ZfreeItem(&pwitem, PR_FALSE);
2489             }
2490             break;
2491         }
2492         default:
2493             key->error = SEC_ERROR_PKCS12_UNSUPPORTED_VERSION;
2494             key->problem = PR_TRUE;
2495             if (nickName) {
2496                 SECITEM_ZfreeItem(nickName, PR_TRUE);
2497             }
2498             return SECFailure;
2499     }
2500 
2501     if (rv != SECSuccess) {
2502         key->error = SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY;
2503         key->problem = PR_TRUE;
2504     } else {
2505         /* try to import the public key. Failure to do so is not fatal,
2506          * not all tokens can store the public key */
2507         if (pubKey) {
2508             PK11_ImportPublicKey(key->slot, pubKey, PR_TRUE);
2509         }
2510         key->installed = PR_TRUE;
2511     }
2512 
2513     return rv;
2514 }
2515 
2516 /*
2517  * The correctness of the code in this file ABSOLUTELY REQUIRES
2518  * that ALL BAGs share a single common arena.
2519  *
2520  * This function allocates the bag list from the arena of whatever bag
2521  * happens to be passed to it.  Each time a new bag is handed to it,
2522  * it grows (resizes) the arena of the bag that was handed to it.
2523  * If the bags have different arenas, it will grow the wrong arena.
2524  *
2525  * Worse, if the bags had separate arenas, then while destroying the bags
2526  * in a bag list, when the bag whose arena contained the bag list was
2527  * destroyed, the baglist itself would be destroyed, making it difficult
2528  * or impossible to continue to destroy the bags in the destroyed list.
2529  */
2530 static SECStatus
sec_pkcs12_add_item_to_bag_list(sec_PKCS12SafeBag *** bagList,sec_PKCS12SafeBag * bag)2531 sec_pkcs12_add_item_to_bag_list(sec_PKCS12SafeBag ***bagList,
2532                                 sec_PKCS12SafeBag *bag)
2533 {
2534     sec_PKCS12SafeBag **newBagList = NULL;
2535     int i = 0;
2536 
2537     if (!bagList || !bag) {
2538         PORT_SetError(SEC_ERROR_INVALID_ARGS);
2539         return SECFailure;
2540     }
2541 
2542     if (!(*bagList)) {
2543         newBagList = PORT_ArenaZNewArray(bag->arena, sec_PKCS12SafeBag *, 2);
2544     } else {
2545         while ((*bagList)[i])
2546             i++;
2547         newBagList = PORT_ArenaGrowArray(bag->arena, *bagList,
2548                                          sec_PKCS12SafeBag *, i + 1, i + 2);
2549     }
2550 
2551     if (!newBagList) {
2552         PORT_SetError(SEC_ERROR_NO_MEMORY);
2553         return SECFailure;
2554     }
2555 
2556     newBagList[i] = bag;
2557     newBagList[i + 1] = NULL;
2558     *bagList = newBagList;
2559 
2560     return SECSuccess;
2561 }
2562 
2563 static sec_PKCS12SafeBag **
sec_pkcs12_find_certs_for_key(sec_PKCS12SafeBag ** safeBags,sec_PKCS12SafeBag * key)2564 sec_pkcs12_find_certs_for_key(sec_PKCS12SafeBag **safeBags,
2565                               sec_PKCS12SafeBag *key)
2566 {
2567     sec_PKCS12SafeBag **certList = NULL;
2568     SECItem *keyId;
2569     int i;
2570 
2571     if (!safeBags || !safeBags[0]) {
2572         PORT_SetError(SEC_ERROR_INVALID_ARGS);
2573         return NULL;
2574     }
2575 
2576     keyId = sec_pkcs12_get_attribute_value(key, SEC_OID_PKCS9_LOCAL_KEY_ID);
2577     if (!keyId) {
2578         return NULL;
2579     }
2580 
2581     for (i = 0; safeBags[i]; i++) {
2582         if (SECOID_FindOIDTag(&(safeBags[i]->safeBagType)) == SEC_OID_PKCS12_V1_CERT_BAG_ID) {
2583             SECItem *certKeyId = sec_pkcs12_get_attribute_value(safeBags[i],
2584                                                                 SEC_OID_PKCS9_LOCAL_KEY_ID);
2585 
2586             if (certKeyId && (SECITEM_CompareItem(certKeyId, keyId) == SECEqual)) {
2587                 if (sec_pkcs12_add_item_to_bag_list(&certList, safeBags[i]) != SECSuccess) {
2588                     /* This would leak the partial list of safeBags,
2589                      * but that list is allocated from the arena of
2590                      * one of the safebags, and will be destroyed when
2591                      * that arena is destroyed.  So this is not a real leak.
2592                      */
2593                     return NULL;
2594                 }
2595             }
2596         }
2597     }
2598 
2599     return certList;
2600 }
2601 
2602 CERTCertList *
SEC_PKCS12DecoderGetCerts(SEC_PKCS12DecoderContext * p12dcx)2603 SEC_PKCS12DecoderGetCerts(SEC_PKCS12DecoderContext *p12dcx)
2604 {
2605     CERTCertList *certList = NULL;
2606     sec_PKCS12SafeBag **safeBags;
2607     int i;
2608 
2609     if (!p12dcx || !p12dcx->safeBags || !p12dcx->safeBags[0]) {
2610         PORT_SetError(SEC_ERROR_INVALID_ARGS);
2611         return NULL;
2612     }
2613 
2614     safeBags = p12dcx->safeBags;
2615     certList = CERT_NewCertList();
2616 
2617     if (certList == NULL) {
2618         return NULL;
2619     }
2620 
2621     for (i = 0; safeBags[i]; i++) {
2622         if (SECOID_FindOIDTag(&(safeBags[i]->safeBagType)) == SEC_OID_PKCS12_V1_CERT_BAG_ID) {
2623             SECItem *derCert = sec_pkcs12_get_der_cert(safeBags[i]);
2624             CERTCertificate *tempCert = NULL;
2625 
2626             if (derCert == NULL)
2627                 continue;
2628             tempCert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
2629                                                derCert, NULL,
2630                                                PR_FALSE, PR_TRUE);
2631 
2632             if (tempCert) {
2633                 CERT_AddCertToListTail(certList, tempCert);
2634             }
2635             SECITEM_FreeItem(derCert, PR_TRUE);
2636         }
2637         /* fixed an infinite loop here, by ensuring that i gets incremented
2638          * if derCert is NULL above.
2639          */
2640     }
2641 
2642     return certList;
2643 }
2644 static sec_PKCS12SafeBag **
sec_pkcs12_get_key_bags(sec_PKCS12SafeBag ** safeBags)2645 sec_pkcs12_get_key_bags(sec_PKCS12SafeBag **safeBags)
2646 {
2647     int i;
2648     sec_PKCS12SafeBag **keyList = NULL;
2649     SECOidTag bagType;
2650 
2651     if (!safeBags || !safeBags[0]) {
2652         PORT_SetError(SEC_ERROR_INVALID_ARGS);
2653         return NULL;
2654     }
2655 
2656     for (i = 0; safeBags[i]; i++) {
2657         bagType = SECOID_FindOIDTag(&(safeBags[i]->safeBagType));
2658         switch (bagType) {
2659             case SEC_OID_PKCS12_V1_KEY_BAG_ID:
2660             case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:
2661                 if (sec_pkcs12_add_item_to_bag_list(&keyList, safeBags[i]) != SECSuccess) {
2662                     /* This would leak, except that keyList is allocated
2663                      * from the arena shared by all the safeBags.
2664                      */
2665                     return NULL;
2666                 }
2667                 break;
2668             default:
2669                 break;
2670         }
2671     }
2672 
2673     return keyList;
2674 }
2675 
2676 /* This function takes two passes over the bags, validating them
2677  * The two passes are intended to mirror exactly the two passes in
2678  * sec_pkcs12_install_bags.  But they don't. :(
2679  */
2680 static SECStatus
sec_pkcs12_validate_bags(sec_PKCS12SafeBag ** safeBags,SEC_PKCS12NicknameCollisionCallback nicknameCb,void * wincx)2681 sec_pkcs12_validate_bags(sec_PKCS12SafeBag **safeBags,
2682                          SEC_PKCS12NicknameCollisionCallback nicknameCb,
2683                          void *wincx)
2684 {
2685     sec_PKCS12SafeBag **keyList;
2686     int i;
2687 
2688     if (!safeBags || !nicknameCb) {
2689         PORT_SetError(SEC_ERROR_INVALID_ARGS);
2690         return SECFailure;
2691     }
2692 
2693     if (!safeBags[0]) {
2694         return SECSuccess;
2695     }
2696 
2697     /* First pass.  Find all the key bags.
2698      * Find the matching cert(s) for each key.
2699      */
2700     keyList = sec_pkcs12_get_key_bags(safeBags);
2701     if (keyList) {
2702         for (i = 0; keyList[i]; ++i) {
2703             sec_PKCS12SafeBag *key = keyList[i];
2704             sec_PKCS12SafeBag **certList =
2705                 sec_pkcs12_find_certs_for_key(safeBags, key);
2706 
2707             if (certList) {
2708                 int j;
2709 
2710                 if (SECOID_FindOIDTag(&(key->safeBagType)) ==
2711                     SEC_OID_PKCS12_V1_KEY_BAG_ID) {
2712                     /* if it is an unencrypted private key then make sure
2713                      * the attributes are propageted to the appropriate
2714                      * level
2715                      */
2716                     if (sec_pkcs12_get_key_info(key) != SECSuccess) {
2717                         return SECFailure;
2718                     }
2719                 }
2720 
2721                 sec_pkcs12_validate_key_by_cert(certList[0], key, wincx);
2722                 for (j = 0; certList[j]; ++j) {
2723                     sec_PKCS12SafeBag *cert = certList[j];
2724                     cert->hasKey = PR_TRUE;
2725                     if (key->problem) {
2726                         cert->problem = PR_TRUE;
2727                         cert->error = key->error;
2728                         continue;
2729                     }
2730                     sec_pkcs12_validate_cert(cert, key, nicknameCb);
2731                     if (cert->problem) {
2732                         key->problem = cert->problem;
2733                         key->error = cert->error;
2734                     }
2735                 }
2736             }
2737         }
2738     }
2739 
2740     /* Now take a second pass over the safebags and mark for installation any
2741      * certs that were neither installed nor disqualified by the first pass.
2742      */
2743     for (i = 0; safeBags[i]; ++i) {
2744         sec_PKCS12SafeBag *bag = safeBags[i];
2745 
2746         if (!bag->validated) {
2747             SECOidTag bagType = SECOID_FindOIDTag(&bag->safeBagType);
2748 
2749             switch (bagType) {
2750                 case SEC_OID_PKCS12_V1_CERT_BAG_ID:
2751                     sec_pkcs12_validate_cert(bag, NULL, nicknameCb);
2752                     break;
2753                 case SEC_OID_PKCS12_V1_KEY_BAG_ID:
2754                 case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:
2755                     bag->noInstall = PR_TRUE;
2756                     bag->problem = PR_TRUE;
2757                     bag->error = SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY;
2758                     break;
2759                 default:
2760                     bag->noInstall = PR_TRUE;
2761             }
2762         }
2763     }
2764 
2765     return SECSuccess;
2766 }
2767 
2768 SECStatus
SEC_PKCS12DecoderValidateBags(SEC_PKCS12DecoderContext * p12dcx,SEC_PKCS12NicknameCollisionCallback nicknameCb)2769 SEC_PKCS12DecoderValidateBags(SEC_PKCS12DecoderContext *p12dcx,
2770                               SEC_PKCS12NicknameCollisionCallback nicknameCb)
2771 {
2772     SECStatus rv;
2773     int i, noInstallCnt, probCnt, bagCnt, errorVal = 0;
2774     if (!p12dcx || p12dcx->error || !p12dcx->safeBags) {
2775         PORT_SetError(SEC_ERROR_INVALID_ARGS);
2776         return SECFailure;
2777     }
2778 
2779     rv = sec_pkcs12_validate_bags(p12dcx->safeBags, nicknameCb, p12dcx->wincx);
2780     if (rv == SECSuccess) {
2781         p12dcx->bagsVerified = PR_TRUE;
2782     }
2783 
2784     noInstallCnt = probCnt = bagCnt = 0;
2785     i = 0;
2786     while (p12dcx->safeBags[i]) {
2787         bagCnt++;
2788         if (p12dcx->safeBags[i]->noInstall)
2789             noInstallCnt++;
2790         if (p12dcx->safeBags[i]->problem) {
2791             probCnt++;
2792             errorVal = p12dcx->safeBags[i]->error;
2793         }
2794         i++;
2795     }
2796 
2797     /* formerly was erroneous code here that assumed that if all bags
2798      * failed to import, then the problem was duplicated data;
2799      * that is, it assume that the problem must be that the file had
2800      * previously been successfully imported.  But importing a
2801      * previously imported file causes NO ERRORS at all, and this
2802      * false assumption caused real errors to be hidden behind false
2803      * errors about duplicated data.
2804      */
2805 
2806     if (probCnt) {
2807         PORT_SetError(errorVal);
2808         return SECFailure;
2809     }
2810 
2811     return rv;
2812 }
2813 
2814 SECStatus
SEC_PKCS12DecoderRenameCertNicknames(SEC_PKCS12DecoderContext * p12dcx,SEC_PKCS12NicknameRenameCallback nicknameCb,void * arg)2815 SEC_PKCS12DecoderRenameCertNicknames(SEC_PKCS12DecoderContext *p12dcx,
2816                                      SEC_PKCS12NicknameRenameCallback nicknameCb,
2817                                      void *arg)
2818 {
2819     int i;
2820     sec_PKCS12SafeBag *safeBag;
2821     CERTCertificate *cert;
2822     SECStatus srv;
2823 
2824     if (!p12dcx || p12dcx->error || !p12dcx->safeBags || !nicknameCb) {
2825         PORT_SetError(SEC_ERROR_INVALID_ARGS);
2826         return SECFailure;
2827     }
2828 
2829     for (i = 0; (safeBag = p12dcx->safeBags[i]); i++) {
2830         SECItem *newNickname = NULL;
2831         SECItem *defaultNickname = NULL;
2832         SECStatus rename_rv;
2833 
2834         if (SECOID_FindOIDTag(&(safeBag->safeBagType)) !=
2835             SEC_OID_PKCS12_V1_CERT_BAG_ID) {
2836             continue;
2837         }
2838 
2839         cert = CERT_DecodeDERCertificate(
2840             &safeBag->safeBagContent.certBag->value.x509Cert,
2841             PR_FALSE, NULL);
2842         if (!cert) {
2843             return SECFailure;
2844         }
2845 
2846         defaultNickname = sec_pkcs12_get_nickname(safeBag);
2847         rename_rv = (*nicknameCb)(cert, defaultNickname, &newNickname, arg);
2848 
2849         CERT_DestroyCertificate(cert);
2850 
2851         if (defaultNickname) {
2852             SECITEM_ZfreeItem(defaultNickname, PR_TRUE);
2853             defaultNickname = NULL;
2854         }
2855 
2856         if (rename_rv != SECSuccess) {
2857             return rename_rv;
2858         }
2859 
2860         if (newNickname) {
2861             srv = sec_pkcs12_set_nickname(safeBag, newNickname);
2862             SECITEM_ZfreeItem(newNickname, PR_TRUE);
2863             newNickname = NULL;
2864             if (srv != SECSuccess) {
2865                 return SECFailure;
2866             }
2867         }
2868     }
2869 
2870     return SECSuccess;
2871 }
2872 
2873 static SECKEYPublicKey *
sec_pkcs12_get_public_key_and_usage(sec_PKCS12SafeBag * certBag,unsigned int * usage)2874 sec_pkcs12_get_public_key_and_usage(sec_PKCS12SafeBag *certBag,
2875                                     unsigned int *usage)
2876 {
2877     SECKEYPublicKey *pubKey = NULL;
2878     CERTCertificate *cert = NULL;
2879 
2880     if (!certBag || !usage) {
2881         PORT_SetError(SEC_ERROR_INVALID_ARGS);
2882         return NULL;
2883     }
2884 
2885     *usage = 0;
2886 
2887     cert = CERT_DecodeDERCertificate(
2888         &certBag->safeBagContent.certBag->value.x509Cert, PR_FALSE, NULL);
2889     if (!cert) {
2890         return NULL;
2891     }
2892 
2893     *usage = cert->keyUsage;
2894     pubKey = CERT_ExtractPublicKey(cert);
2895     CERT_DestroyCertificate(cert);
2896     return pubKey;
2897 }
2898 
2899 static SECItem *
sec_pkcs12_get_public_value_and_type(SECKEYPublicKey * pubKey,KeyType * type)2900 sec_pkcs12_get_public_value_and_type(SECKEYPublicKey *pubKey,
2901                                      KeyType *type)
2902 {
2903     SECItem *pubValue = NULL;
2904 
2905     if (!type || !pubKey) {
2906         PORT_SetError(SEC_ERROR_INVALID_ARGS);
2907         return NULL;
2908     }
2909 
2910     *type = pubKey->keyType;
2911     switch (pubKey->keyType) {
2912         case dsaKey:
2913             pubValue = &pubKey->u.dsa.publicValue;
2914             break;
2915         case dhKey:
2916             pubValue = &pubKey->u.dh.publicValue;
2917             break;
2918         case rsaKey:
2919             pubValue = &pubKey->u.rsa.modulus;
2920             break;
2921         case ecKey:
2922             pubValue = &pubKey->u.ec.publicValue;
2923             break;
2924         default:
2925             pubValue = NULL;
2926     }
2927 
2928     return pubValue;
2929 }
2930 
2931 /* This function takes two passes over the bags, installing them in the
2932  * desired slot.  The two passes are intended to mirror exactly the
2933  * two passes in sec_pkcs12_validate_bags.
2934  */
2935 static SECStatus
sec_pkcs12_install_bags(sec_PKCS12SafeBag ** safeBags,PRBool forceUnicode,void * wincx)2936 sec_pkcs12_install_bags(sec_PKCS12SafeBag **safeBags, PRBool forceUnicode,
2937                         void *wincx)
2938 {
2939     sec_PKCS12SafeBag **keyList;
2940     int i;
2941     int failedKeys = 0;
2942 
2943     if (!safeBags) {
2944         PORT_SetError(SEC_ERROR_INVALID_ARGS);
2945         return SECFailure;
2946     }
2947 
2948     if (!safeBags[0]) {
2949         return SECSuccess;
2950     }
2951 
2952     /* First pass.  Find all the key bags.
2953      * Try to install them, and any certs associated with them.
2954      */
2955     keyList = sec_pkcs12_get_key_bags(safeBags);
2956     if (keyList) {
2957         for (i = 0; keyList[i]; i++) {
2958             SECStatus rv;
2959             SECKEYPublicKey *pubKey = NULL;
2960             SECItem *nickName = NULL;
2961             sec_PKCS12SafeBag *key = keyList[i];
2962             sec_PKCS12SafeBag **certList;
2963             unsigned int keyUsage;
2964 
2965             if (key->problem) {
2966                 ++failedKeys;
2967                 continue;
2968             }
2969 
2970             certList = sec_pkcs12_find_certs_for_key(safeBags, key);
2971             if (certList && certList[0]) {
2972                 pubKey = sec_pkcs12_get_public_key_and_usage(certList[0],
2973                                                              &keyUsage);
2974                 /* use the cert's nickname, if it has one, else use the
2975                  * key's nickname, else fail.
2976                  */
2977                 nickName = sec_pkcs12_get_nickname_for_cert(certList[0], key);
2978             } else {
2979                 nickName = sec_pkcs12_get_nickname(key);
2980             }
2981             if (!nickName) {
2982                 key->error = SEC_ERROR_BAD_NICKNAME;
2983                 key->problem = PR_TRUE;
2984                 rv = SECFailure;
2985             } else if (!pubKey) {
2986                 key->error = SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY;
2987                 key->problem = PR_TRUE;
2988                 rv = SECFailure;
2989             } else {
2990                 rv = sec_pkcs12_add_key(key, pubKey, keyUsage, nickName,
2991                                         forceUnicode, wincx);
2992             }
2993             if (pubKey) {
2994                 SECKEY_DestroyPublicKey(pubKey);
2995                 pubKey = NULL;
2996             }
2997             if (nickName) {
2998                 SECITEM_FreeItem(nickName, PR_TRUE);
2999                 nickName = NULL;
3000             }
3001             if (rv != SECSuccess) {
3002                 PORT_SetError(key->error);
3003                 ++failedKeys;
3004             }
3005 
3006             if (certList) {
3007                 int j;
3008 
3009                 for (j = 0; certList[j]; j++) {
3010                     sec_PKCS12SafeBag *cert = certList[j];
3011                     SECStatus certRv;
3012 
3013                     if (!cert)
3014                         continue;
3015                     if (rv != SECSuccess) {
3016                         cert->problem = key->problem;
3017                         cert->error = key->error;
3018                         cert->noInstall = PR_TRUE;
3019                         continue;
3020                     }
3021 
3022                     certRv = sec_pkcs12_add_cert(cert, cert->hasKey, wincx);
3023                     if (certRv != SECSuccess) {
3024                         key->problem = cert->problem;
3025                         key->error = cert->error;
3026                         PORT_SetError(cert->error);
3027                         return SECFailure;
3028                     }
3029                 }
3030             }
3031         }
3032     }
3033     if (failedKeys)
3034         return SECFailure;
3035 
3036     /* Now take a second pass over the safebags and install any certs
3037      * that were neither installed nor disqualified by the first pass.
3038      */
3039     for (i = 0; safeBags[i]; i++) {
3040         sec_PKCS12SafeBag *bag = safeBags[i];
3041 
3042         if (!bag->installed && !bag->problem && !bag->noInstall) {
3043             SECStatus rv;
3044             SECOidTag bagType = SECOID_FindOIDTag(&(bag->safeBagType));
3045 
3046             switch (bagType) {
3047                 case SEC_OID_PKCS12_V1_CERT_BAG_ID:
3048                     rv = sec_pkcs12_add_cert(bag, bag->hasKey, wincx);
3049                     if (rv != SECSuccess) {
3050                         PORT_SetError(bag->error);
3051                         return SECFailure;
3052                     }
3053                     break;
3054                 case SEC_OID_PKCS12_V1_KEY_BAG_ID:
3055                 case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:
3056                 default:
3057                     break;
3058             }
3059         }
3060     }
3061 
3062     return SECSuccess;
3063 }
3064 
3065 SECStatus
SEC_PKCS12DecoderImportBags(SEC_PKCS12DecoderContext * p12dcx)3066 SEC_PKCS12DecoderImportBags(SEC_PKCS12DecoderContext *p12dcx)
3067 {
3068     PRBool forceUnicode = PR_FALSE;
3069     SECStatus rv;
3070 
3071     if (!p12dcx || p12dcx->error) {
3072         PORT_SetError(SEC_ERROR_INVALID_ARGS);
3073         return SECFailure;
3074     }
3075 
3076     if (!p12dcx->bagsVerified) {
3077         return SECFailure;
3078     }
3079 
3080     /* We need to check the option here as well as in
3081      * SEC_PKCS12DecoderStart, because different PBE's could be used
3082      * for PKCS #7 and PKCS #8 */
3083     rv = NSS_OptionGet(__NSS_PKCS12_DECODE_FORCE_UNICODE, &forceUnicode);
3084     if (rv != SECSuccess) {
3085         return SECFailure;
3086     }
3087 
3088     return sec_pkcs12_install_bags(p12dcx->safeBags, forceUnicode,
3089                                    p12dcx->wincx);
3090 }
3091 
3092 PRBool
sec_pkcs12_bagHasKey(SEC_PKCS12DecoderContext * p12dcx,sec_PKCS12SafeBag * bag)3093 sec_pkcs12_bagHasKey(SEC_PKCS12DecoderContext *p12dcx, sec_PKCS12SafeBag *bag)
3094 {
3095     int i;
3096     SECItem *keyId;
3097     SECItem *certKeyId;
3098 
3099     certKeyId = sec_pkcs12_get_attribute_value(bag, SEC_OID_PKCS9_LOCAL_KEY_ID);
3100     if (certKeyId == NULL) {
3101         return PR_FALSE;
3102     }
3103 
3104     for (i = 0; p12dcx->keyList && p12dcx->keyList[i]; i++) {
3105         keyId = sec_pkcs12_get_attribute_value(p12dcx->keyList[i],
3106                                                SEC_OID_PKCS9_LOCAL_KEY_ID);
3107         if (!keyId) {
3108             continue;
3109         }
3110         if (SECITEM_CompareItem(certKeyId, keyId) == SECEqual) {
3111             return PR_TRUE;
3112         }
3113     }
3114     return PR_FALSE;
3115 }
3116 
3117 SECItem *
sec_pkcs12_get_friendlyName(sec_PKCS12SafeBag * bag)3118 sec_pkcs12_get_friendlyName(sec_PKCS12SafeBag *bag)
3119 {
3120     SECItem *friendlyName;
3121     SECItem *tempnm;
3122 
3123     tempnm = sec_pkcs12_get_attribute_value(bag, SEC_OID_PKCS9_FRIENDLY_NAME);
3124     friendlyName = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
3125     if (friendlyName) {
3126         if (!sec_pkcs12_convert_item_to_unicode(NULL, friendlyName,
3127                                                 tempnm, PR_TRUE, PR_FALSE, PR_FALSE)) {
3128             SECITEM_FreeItem(friendlyName, PR_TRUE);
3129             friendlyName = NULL;
3130         }
3131     }
3132     return friendlyName;
3133 }
3134 
3135 /* Following two functions provide access to selected portions of the safe bags.
3136  * Iteration is implemented per decoder context and may be accessed after
3137  * SEC_PKCS12DecoderVerify() returns success.
3138  * When ...DecoderIterateNext() returns SUCCESS a decoder item has been returned
3139  * where item.type is always set; item.friendlyName is set if it is non-null;
3140  * item.der, item.hasKey are set only for SEC_OID_PKCS12_V1_CERT_BAG_ID items.
3141  * ...DecoderIterateNext() returns FAILURE when the list is exhausted or when
3142  * arguments are invalid; PORT_GetError() is 0 at end-of-list.
3143  * Caller has read-only access to decoder items. Any SECItems generated are
3144  * owned by the decoder context and are freed by ...DecoderFinish().
3145  */
3146 SECStatus
SEC_PKCS12DecoderIterateInit(SEC_PKCS12DecoderContext * p12dcx)3147 SEC_PKCS12DecoderIterateInit(SEC_PKCS12DecoderContext *p12dcx)
3148 {
3149     if (!p12dcx || p12dcx->error) {
3150         PORT_SetError(SEC_ERROR_INVALID_ARGS);
3151         return SECFailure;
3152     }
3153 
3154     p12dcx->iteration = 0;
3155     return SECSuccess;
3156 }
3157 
3158 SECStatus
SEC_PKCS12DecoderIterateNext(SEC_PKCS12DecoderContext * p12dcx,const SEC_PKCS12DecoderItem ** ipp)3159 SEC_PKCS12DecoderIterateNext(SEC_PKCS12DecoderContext *p12dcx,
3160                              const SEC_PKCS12DecoderItem **ipp)
3161 {
3162     sec_PKCS12SafeBag *bag;
3163 
3164     if (!p12dcx || p12dcx->error) {
3165         PORT_SetError(SEC_ERROR_INVALID_ARGS);
3166         return SECFailure;
3167     }
3168 
3169     if (p12dcx->decitem.type != 0 && p12dcx->decitem.der != NULL) {
3170         SECITEM_FreeItem(p12dcx->decitem.der, PR_TRUE);
3171     }
3172     if (p12dcx->decitem.shroudAlg != NULL) {
3173         SECOID_DestroyAlgorithmID(p12dcx->decitem.shroudAlg, PR_TRUE);
3174     }
3175     if (p12dcx->decitem.friendlyName != NULL) {
3176         SECITEM_FreeItem(p12dcx->decitem.friendlyName, PR_TRUE);
3177     }
3178     p12dcx->decitem.type = 0;
3179     p12dcx->decitem.der = NULL;
3180     p12dcx->decitem.shroudAlg = NULL;
3181     p12dcx->decitem.friendlyName = NULL;
3182     p12dcx->decitem.hasKey = PR_FALSE;
3183     *ipp = NULL;
3184     if (p12dcx->keyList == NULL) {
3185         p12dcx->keyList = sec_pkcs12_get_key_bags(p12dcx->safeBags);
3186     }
3187 
3188     for (; p12dcx->iteration < p12dcx->safeBagCount; p12dcx->iteration++) {
3189         bag = p12dcx->safeBags[p12dcx->iteration];
3190         if (bag == NULL || bag->problem) {
3191             continue;
3192         }
3193         p12dcx->decitem.type = SECOID_FindOIDTag(&(bag->safeBagType));
3194         switch (p12dcx->decitem.type) {
3195             case SEC_OID_PKCS12_V1_CERT_BAG_ID:
3196                 p12dcx->decitem.der = sec_pkcs12_get_der_cert(bag);
3197                 p12dcx->decitem.friendlyName = sec_pkcs12_get_friendlyName(bag);
3198                 p12dcx->decitem.hasKey = sec_pkcs12_bagHasKey(p12dcx, bag);
3199                 break;
3200             case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:
3201                 p12dcx->decitem.shroudAlg = PORT_ZNew(SECAlgorithmID);
3202                 if (p12dcx->decitem.shroudAlg) {
3203                     SECOID_CopyAlgorithmID(NULL, p12dcx->decitem.shroudAlg,
3204                                            &bag->safeBagContent.pkcs8ShroudedKeyBag->algorithm);
3205                 }
3206             /* fall through */
3207             case SEC_OID_PKCS12_V1_KEY_BAG_ID:
3208                 p12dcx->decitem.friendlyName = sec_pkcs12_get_friendlyName(bag);
3209                 break;
3210             default:
3211                 /* return these even though we don't expect them */
3212                 break;
3213             case SEC_OID_UNKNOWN:
3214                 /* ignore these */
3215                 continue;
3216         }
3217         *ipp = &p12dcx->decitem;
3218         p12dcx->iteration++;
3219         break; /* end for() */
3220     }
3221 
3222     PORT_SetError(0); /* end-of-list is SECFailure with no PORT error */
3223     return ((p12dcx->decitem.type == 0) ? SECFailure : SECSuccess);
3224 }
3225 
3226 static SECStatus
sec_pkcs12_decoder_append_bag_to_context(SEC_PKCS12DecoderContext * p12dcx,sec_PKCS12SafeBag * bag)3227 sec_pkcs12_decoder_append_bag_to_context(SEC_PKCS12DecoderContext *p12dcx,
3228                                          sec_PKCS12SafeBag *bag)
3229 {
3230     if (!p12dcx || p12dcx->error) {
3231         PORT_SetError(SEC_ERROR_INVALID_ARGS);
3232         return SECFailure;
3233     }
3234 
3235     p12dcx->safeBags = !p12dcx->safeBagCount
3236                            ? PORT_ArenaZNewArray(p12dcx->arena, sec_PKCS12SafeBag *, 2)
3237                            : PORT_ArenaGrowArray(p12dcx->arena, p12dcx->safeBags,
3238                                                  sec_PKCS12SafeBag *, p12dcx->safeBagCount + 1,
3239                                                  p12dcx->safeBagCount + 2);
3240 
3241     if (!p12dcx->safeBags) {
3242         PORT_SetError(SEC_ERROR_NO_MEMORY);
3243         return SECFailure;
3244     }
3245 
3246     p12dcx->safeBags[p12dcx->safeBagCount] = bag;
3247     p12dcx->safeBags[p12dcx->safeBagCount + 1] = NULL;
3248     p12dcx->safeBagCount++;
3249 
3250     return SECSuccess;
3251 }
3252 
3253 static sec_PKCS12SafeBag *
sec_pkcs12_decoder_convert_old_key(SEC_PKCS12DecoderContext * p12dcx,void * key,PRBool isEspvk)3254 sec_pkcs12_decoder_convert_old_key(SEC_PKCS12DecoderContext *p12dcx,
3255                                    void *key, PRBool isEspvk)
3256 {
3257     sec_PKCS12SafeBag *keyBag;
3258     SECOidData *oid;
3259     SECOidTag keyTag;
3260     SECItem *keyID, *nickName, *newNickName;
3261 
3262     if (!p12dcx || p12dcx->error || !key) {
3263         PORT_SetError(SEC_ERROR_INVALID_ARGS);
3264         return NULL;
3265     }
3266 
3267     newNickName = PORT_ArenaZNew(p12dcx->arena, SECItem);
3268     keyBag = PORT_ArenaZNew(p12dcx->arena, sec_PKCS12SafeBag);
3269     if (!keyBag || !newNickName) {
3270         return NULL;
3271     }
3272 
3273     keyBag->swapUnicodeBytes = p12dcx->swapUnicodeBytes;
3274     keyBag->slot = p12dcx->slot;
3275     keyBag->arena = p12dcx->arena;
3276     keyBag->pwitem = p12dcx->pwitem;
3277     keyBag->tokenCAs = p12dcx->tokenCAs;
3278     keyBag->oldBagType = PR_TRUE;
3279 
3280     keyTag = (isEspvk) ? SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID : SEC_OID_PKCS12_V1_KEY_BAG_ID;
3281     oid = SECOID_FindOIDByTag(keyTag);
3282     if (!oid) {
3283         return NULL;
3284     }
3285 
3286     if (SECITEM_CopyItem(p12dcx->arena, &keyBag->safeBagType, &oid->oid) != SECSuccess) {
3287         return NULL;
3288     }
3289 
3290     if (isEspvk) {
3291         SEC_PKCS12ESPVKItem *espvk = (SEC_PKCS12ESPVKItem *)key;
3292         keyBag->safeBagContent.pkcs8ShroudedKeyBag =
3293             espvk->espvkCipherText.pkcs8KeyShroud;
3294         nickName = &(espvk->espvkData.uniNickName);
3295         if (!espvk->espvkData.assocCerts || !espvk->espvkData.assocCerts[0]) {
3296             PORT_SetError(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE);
3297             return NULL;
3298         }
3299         keyID = &espvk->espvkData.assocCerts[0]->digest;
3300     } else {
3301         SEC_PKCS12PrivateKey *pk = (SEC_PKCS12PrivateKey *)key;
3302         keyBag->safeBagContent.pkcs8KeyBag = &pk->pkcs8data;
3303         nickName = &(pk->pvkData.uniNickName);
3304         if (!pk->pvkData.assocCerts || !pk->pvkData.assocCerts[0]) {
3305             PORT_SetError(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE);
3306             return NULL;
3307         }
3308         keyID = &pk->pvkData.assocCerts[0]->digest;
3309     }
3310 
3311     if (nickName->len) {
3312         if (nickName->len >= 2) {
3313             if (nickName->data[0] && nickName->data[1]) {
3314                 if (!sec_pkcs12_convert_item_to_unicode(p12dcx->arena, newNickName,
3315                                                         nickName, PR_FALSE, PR_FALSE, PR_TRUE)) {
3316                     return NULL;
3317                 }
3318                 nickName = newNickName;
3319             } else if (nickName->data[0] && !nickName->data[1]) {
3320                 unsigned int j = 0;
3321                 unsigned char t;
3322                 for (j = 0; j < nickName->len; j += 2) {
3323                     t = nickName->data[j + 1];
3324                     nickName->data[j + 1] = nickName->data[j];
3325                     nickName->data[j] = t;
3326                 }
3327             }
3328         } else {
3329             if (!sec_pkcs12_convert_item_to_unicode(p12dcx->arena, newNickName,
3330                                                     nickName, PR_FALSE, PR_FALSE, PR_TRUE)) {
3331                 return NULL;
3332             }
3333             nickName = newNickName;
3334         }
3335     }
3336 
3337     if (sec_pkcs12_decoder_set_attribute_value(keyBag,
3338                                                SEC_OID_PKCS9_FRIENDLY_NAME,
3339                                                nickName) != SECSuccess) {
3340         return NULL;
3341     }
3342 
3343     if (sec_pkcs12_decoder_set_attribute_value(keyBag, SEC_OID_PKCS9_LOCAL_KEY_ID,
3344                                                keyID) != SECSuccess) {
3345         return NULL;
3346     }
3347 
3348     return keyBag;
3349 }
3350 
3351 static sec_PKCS12SafeBag *
sec_pkcs12_decoder_create_cert(SEC_PKCS12DecoderContext * p12dcx,SECItem * derCert)3352 sec_pkcs12_decoder_create_cert(SEC_PKCS12DecoderContext *p12dcx,
3353                                SECItem *derCert)
3354 {
3355     sec_PKCS12SafeBag *certBag;
3356     SECOidData *oid;
3357     SGNDigestInfo *digest;
3358     SECItem *keyId;
3359     SECStatus rv;
3360 
3361     if (!p12dcx || p12dcx->error || !derCert) {
3362         PORT_SetError(SEC_ERROR_INVALID_ARGS);
3363         return NULL;
3364     }
3365 
3366     keyId = PORT_ArenaZNew(p12dcx->arena, SECItem);
3367     if (!keyId) {
3368         return NULL;
3369     }
3370 
3371     digest = sec_pkcs12_compute_thumbprint(derCert);
3372     if (!digest) {
3373         return NULL;
3374     }
3375 
3376     rv = SECITEM_CopyItem(p12dcx->arena, keyId, &digest->digest);
3377     SGN_DestroyDigestInfo(digest);
3378     if (rv != SECSuccess) {
3379         PORT_SetError(SEC_ERROR_NO_MEMORY);
3380         return NULL;
3381     }
3382 
3383     oid = SECOID_FindOIDByTag(SEC_OID_PKCS12_V1_CERT_BAG_ID);
3384     certBag = PORT_ArenaZNew(p12dcx->arena, sec_PKCS12SafeBag);
3385     if (!certBag || !oid || (SECITEM_CopyItem(p12dcx->arena,
3386                                               &certBag->safeBagType, &oid->oid) != SECSuccess)) {
3387         return NULL;
3388     }
3389 
3390     certBag->slot = p12dcx->slot;
3391     certBag->pwitem = p12dcx->pwitem;
3392     certBag->swapUnicodeBytes = p12dcx->swapUnicodeBytes;
3393     certBag->arena = p12dcx->arena;
3394     certBag->tokenCAs = p12dcx->tokenCAs;
3395 
3396     oid = SECOID_FindOIDByTag(SEC_OID_PKCS9_X509_CERT);
3397     certBag->safeBagContent.certBag =
3398         PORT_ArenaZNew(p12dcx->arena, sec_PKCS12CertBag);
3399     if (!certBag->safeBagContent.certBag || !oid ||
3400         (SECITEM_CopyItem(p12dcx->arena,
3401                           &certBag->safeBagContent.certBag->bagID,
3402                           &oid->oid) != SECSuccess)) {
3403         return NULL;
3404     }
3405 
3406     if (SECITEM_CopyItem(p12dcx->arena,
3407                          &(certBag->safeBagContent.certBag->value.x509Cert),
3408                          derCert) != SECSuccess) {
3409         return NULL;
3410     }
3411 
3412     if (sec_pkcs12_decoder_set_attribute_value(certBag, SEC_OID_PKCS9_LOCAL_KEY_ID,
3413                                                keyId) != SECSuccess) {
3414         return NULL;
3415     }
3416 
3417     return certBag;
3418 }
3419 
3420 static sec_PKCS12SafeBag **
sec_pkcs12_decoder_convert_old_cert(SEC_PKCS12DecoderContext * p12dcx,SEC_PKCS12CertAndCRL * oldCert)3421 sec_pkcs12_decoder_convert_old_cert(SEC_PKCS12DecoderContext *p12dcx,
3422                                     SEC_PKCS12CertAndCRL *oldCert)
3423 {
3424     sec_PKCS12SafeBag **certList;
3425     SECItem **derCertList;
3426     int i, j;
3427 
3428     if (!p12dcx || p12dcx->error || !oldCert) {
3429         PORT_SetError(SEC_ERROR_INVALID_ARGS);
3430         return NULL;
3431     }
3432 
3433     derCertList = SEC_PKCS7GetCertificateList(&oldCert->value.x509->certOrCRL);
3434     if (!derCertList) {
3435         return NULL;
3436     }
3437 
3438     i = 0;
3439     while (derCertList[i])
3440         i++;
3441 
3442     certList = PORT_ArenaZNewArray(p12dcx->arena, sec_PKCS12SafeBag *, (i + 1));
3443     if (!certList) {
3444         return NULL;
3445     }
3446 
3447     for (j = 0; j < i; j++) {
3448         certList[j] = sec_pkcs12_decoder_create_cert(p12dcx, derCertList[j]);
3449         if (!certList[j]) {
3450             return NULL;
3451         }
3452     }
3453 
3454     return certList;
3455 }
3456 
3457 static SECStatus
sec_pkcs12_decoder_convert_old_key_and_certs(SEC_PKCS12DecoderContext * p12dcx,void * oldKey,PRBool isEspvk,SEC_PKCS12SafeContents * safe,SEC_PKCS12Baggage * baggage)3458 sec_pkcs12_decoder_convert_old_key_and_certs(SEC_PKCS12DecoderContext *p12dcx,
3459                                              void *oldKey, PRBool isEspvk,
3460                                              SEC_PKCS12SafeContents *safe,
3461                                              SEC_PKCS12Baggage *baggage)
3462 {
3463     sec_PKCS12SafeBag *key, **certList;
3464     SEC_PKCS12CertAndCRL *oldCert;
3465     SEC_PKCS12PVKSupportingData *pvkData;
3466     int i;
3467     SECItem *keyName;
3468 
3469     if (!p12dcx || !oldKey) {
3470         return SECFailure;
3471     }
3472 
3473     if (isEspvk) {
3474         pvkData = &((SEC_PKCS12ESPVKItem *)(oldKey))->espvkData;
3475     } else {
3476         pvkData = &((SEC_PKCS12PrivateKey *)(oldKey))->pvkData;
3477     }
3478 
3479     if (!pvkData->assocCerts || !pvkData->assocCerts[0]) {
3480         PORT_SetError(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE);
3481         return SECFailure;
3482     }
3483 
3484     oldCert = (SEC_PKCS12CertAndCRL *)sec_pkcs12_find_object(safe, baggage,
3485                                                              SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID, NULL,
3486                                                              pvkData->assocCerts[0]);
3487     if (!oldCert) {
3488         PORT_SetError(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE);
3489         return SECFailure;
3490     }
3491 
3492     key = sec_pkcs12_decoder_convert_old_key(p12dcx, oldKey, isEspvk);
3493     certList = sec_pkcs12_decoder_convert_old_cert(p12dcx, oldCert);
3494     if (!key || !certList) {
3495         return SECFailure;
3496     }
3497 
3498     if (sec_pkcs12_decoder_append_bag_to_context(p12dcx, key) != SECSuccess) {
3499         return SECFailure;
3500     }
3501 
3502     keyName = sec_pkcs12_get_nickname(key);
3503     if (!keyName) {
3504         return SECFailure;
3505     }
3506 
3507     i = 0;
3508     while (certList[i]) {
3509         if (sec_pkcs12_decoder_append_bag_to_context(p12dcx, certList[i]) != SECSuccess) {
3510             return SECFailure;
3511         }
3512         i++;
3513     }
3514 
3515     certList = sec_pkcs12_find_certs_for_key(p12dcx->safeBags, key);
3516     if (!certList) {
3517         return SECFailure;
3518     }
3519 
3520     i = 0;
3521     while (certList[i] != 0) {
3522         if (sec_pkcs12_set_nickname(certList[i], keyName) != SECSuccess) {
3523             return SECFailure;
3524         }
3525         i++;
3526     }
3527 
3528     return SECSuccess;
3529 }
3530 
3531 static SECStatus
sec_pkcs12_decoder_convert_old_safe_to_bags(SEC_PKCS12DecoderContext * p12dcx,SEC_PKCS12SafeContents * safe,SEC_PKCS12Baggage * baggage)3532 sec_pkcs12_decoder_convert_old_safe_to_bags(SEC_PKCS12DecoderContext *p12dcx,
3533                                             SEC_PKCS12SafeContents *safe,
3534                                             SEC_PKCS12Baggage *baggage)
3535 {
3536     SECStatus rv;
3537 
3538     if (!p12dcx || p12dcx->error) {
3539         PORT_SetError(SEC_ERROR_INVALID_ARGS);
3540         return SECFailure;
3541     }
3542 
3543     if (safe && safe->contents) {
3544         int i = 0;
3545         while (safe->contents[i] != NULL) {
3546             if (SECOID_FindOIDTag(&safe->contents[i]->safeBagType) == SEC_OID_PKCS12_KEY_BAG_ID) {
3547                 int j = 0;
3548                 SEC_PKCS12PrivateKeyBag *privBag =
3549                     safe->contents[i]->safeContent.keyBag;
3550 
3551                 while (privBag->privateKeys[j] != NULL) {
3552                     SEC_PKCS12PrivateKey *pk = privBag->privateKeys[j];
3553                     rv = sec_pkcs12_decoder_convert_old_key_and_certs(p12dcx, pk,
3554                                                                       PR_FALSE, safe, baggage);
3555                     if (rv != SECSuccess) {
3556                         goto loser;
3557                     }
3558                     j++;
3559                 }
3560             }
3561             i++;
3562         }
3563     }
3564 
3565     if (baggage && baggage->bags) {
3566         int i = 0;
3567         while (baggage->bags[i] != NULL) {
3568             SEC_PKCS12BaggageItem *bag = baggage->bags[i];
3569             int j = 0;
3570 
3571             if (!bag->espvks) {
3572                 i++;
3573                 continue;
3574             }
3575 
3576             while (bag->espvks[j] != NULL) {
3577                 SEC_PKCS12ESPVKItem *espvk = bag->espvks[j];
3578                 rv = sec_pkcs12_decoder_convert_old_key_and_certs(p12dcx, espvk,
3579                                                                   PR_TRUE, safe, baggage);
3580                 if (rv != SECSuccess) {
3581                     goto loser;
3582                 }
3583                 j++;
3584             }
3585             i++;
3586         }
3587     }
3588 
3589     return SECSuccess;
3590 
3591 loser:
3592     return SECFailure;
3593 }
3594 
3595 SEC_PKCS12DecoderContext *
sec_PKCS12ConvertOldSafeToNew(PLArenaPool * arena,PK11SlotInfo * slot,PRBool swapUnicode,SECItem * pwitem,void * wincx,SEC_PKCS12SafeContents * safe,SEC_PKCS12Baggage * baggage)3596 sec_PKCS12ConvertOldSafeToNew(PLArenaPool *arena, PK11SlotInfo *slot,
3597                               PRBool swapUnicode, SECItem *pwitem,
3598                               void *wincx, SEC_PKCS12SafeContents *safe,
3599                               SEC_PKCS12Baggage *baggage)
3600 {
3601     SEC_PKCS12DecoderContext *p12dcx;
3602 
3603     if (!arena || !slot || !pwitem) {
3604         PORT_SetError(SEC_ERROR_INVALID_ARGS);
3605         return NULL;
3606     }
3607 
3608     if (!safe && !baggage) {
3609         PORT_SetError(SEC_ERROR_INVALID_ARGS);
3610         return NULL;
3611     }
3612 
3613     p12dcx = PORT_ArenaZNew(arena, SEC_PKCS12DecoderContext);
3614     if (!p12dcx) {
3615         return NULL;
3616     }
3617 
3618     p12dcx->arena = arena;
3619     p12dcx->slot = PK11_ReferenceSlot(slot);
3620     p12dcx->wincx = wincx;
3621     p12dcx->error = PR_FALSE;
3622     p12dcx->swapUnicodeBytes = swapUnicode;
3623     p12dcx->pwitem = pwitem;
3624     p12dcx->tokenCAs = SECPKCS12TargetTokenNoCAs;
3625 
3626     if (sec_pkcs12_decoder_convert_old_safe_to_bags(p12dcx, safe, baggage) != SECSuccess) {
3627         p12dcx->error = PR_TRUE;
3628         return NULL;
3629     }
3630 
3631     return p12dcx;
3632 }
3633