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