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