Bug Summary

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