Bug Summary

File:s/lib/pkcs12/p12d.c
Warning:line 2233, column 9
Value stored to 'setNickname' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

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