Bug Summary

File:root/firefox-clang/security/nss/lib/pkcs12/p12d.c
Warning:line 2215, column 9
Value stored to 'setNickname' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

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