OLD | NEW |
| (Empty) |
1 /* This Source Code Form is subject to the terms of the Mozilla Public | |
2 * License, v. 2.0. If a copy of the MPL was not distributed with this | |
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | |
4 | |
5 #include "pkcs12.h" | |
6 #include "plarena.h" | |
7 #include "secpkcs7.h" | |
8 #include "p12local.h" | |
9 #include "secoid.h" | |
10 #include "secitem.h" | |
11 #include "secport.h" | |
12 #include "secasn1.h" | |
13 #include "secder.h" | |
14 #include "secerr.h" | |
15 #include "cert.h" | |
16 #include "certdb.h" | |
17 #include "p12plcy.h" | |
18 #include "p12.h" | |
19 #include "secpkcs5.h" | |
20 | |
21 /* PFX extraction and validation routines */ | |
22 | |
23 /* decode the DER encoded PFX item. if unable to decode, check to see if it | |
24 * is an older PFX item. If that fails, assume the file was not a valid | |
25 * pfx file. | |
26 * the returned pfx structure should be destroyed using SEC_PKCS12DestroyPFX | |
27 */ | |
28 static SEC_PKCS12PFXItem * | |
29 sec_pkcs12_decode_pfx(SECItem *der_pfx) | |
30 { | |
31 SEC_PKCS12PFXItem *pfx; | |
32 SECStatus rv; | |
33 | |
34 if(der_pfx == NULL) { | |
35 return NULL; | |
36 } | |
37 | |
38 /* allocate the space for a new PFX item */ | |
39 pfx = sec_pkcs12_new_pfx(); | |
40 if(pfx == NULL) { | |
41 return NULL; | |
42 } | |
43 | |
44 rv = SEC_ASN1DecodeItem(pfx->poolp, pfx, SEC_PKCS12PFXItemTemplate, | |
45 der_pfx); | |
46 | |
47 /* if a failure occurred, check for older version... | |
48 * we also get rid of the old pfx structure, because we don't | |
49 * know where it failed and what data in may contain | |
50 */ | |
51 if(rv != SECSuccess) { | |
52 SEC_PKCS12DestroyPFX(pfx); | |
53 pfx = sec_pkcs12_new_pfx(); | |
54 if(pfx == NULL) { | |
55 return NULL; | |
56 } | |
57 rv = SEC_ASN1DecodeItem(pfx->poolp, pfx, SEC_PKCS12PFXItemTemplate_OLD, | |
58 der_pfx); | |
59 if(rv != SECSuccess) { | |
60 PORT_SetError(SEC_ERROR_PKCS12_DECODING_PFX); | |
61 PORT_FreeArena(pfx->poolp, PR_TRUE); | |
62 return NULL; | |
63 } | |
64 pfx->old = PR_TRUE; | |
65 SGN_CopyDigestInfo(pfx->poolp, &pfx->macData.safeMac, &pfx->old_safeMac)
; | |
66 SECITEM_CopyItem(pfx->poolp, &pfx->macData.macSalt, &pfx->old_macSalt); | |
67 } else { | |
68 pfx->old = PR_FALSE; | |
69 } | |
70 | |
71 /* convert bit string from bits to bytes */ | |
72 pfx->macData.macSalt.len /= 8; | |
73 | |
74 return pfx; | |
75 } | |
76 | |
77 /* validate the integrity MAC used in the PFX. The MAC is generated | |
78 * per the PKCS 12 document. If the MAC is incorrect, it is most likely | |
79 * due to an invalid password. | |
80 * pwitem is the integrity password | |
81 * pfx is the decoded pfx item | |
82 */ | |
83 static PRBool | |
84 sec_pkcs12_check_pfx_mac(SEC_PKCS12PFXItem *pfx, | |
85 SECItem *pwitem) | |
86 { | |
87 SECItem *key = NULL, *mac = NULL, *data = NULL; | |
88 SECItem *vpwd = NULL; | |
89 SECOidTag algorithm; | |
90 PRBool ret = PR_FALSE; | |
91 | |
92 if(pfx == NULL) { | |
93 return PR_FALSE; | |
94 } | |
95 | |
96 algorithm = SECOID_GetAlgorithmTag(&pfx->macData.safeMac.digestAlgorithm); | |
97 switch(algorithm) { | |
98 /* only SHA1 hashing supported as a MACing algorithm */ | |
99 case SEC_OID_SHA1: | |
100 if(pfx->old == PR_FALSE) { | |
101 pfx->swapUnicode = PR_FALSE; | |
102 } | |
103 | |
104 recheckUnicodePassword: | |
105 vpwd = sec_pkcs12_create_virtual_password(pwitem, | |
106 &pfx->macData.macSalt, | |
107 pfx->swapUnicode); | |
108 if(vpwd == NULL) { | |
109 return PR_FALSE; | |
110 } | |
111 | |
112 key = sec_pkcs12_generate_key_from_password(algorithm, | |
113 &pfx->macData.macSalt, | |
114 (pfx->old ? pwitem : vpwd)); | |
115 /* free vpwd only for newer PFX */ | |
116 if(vpwd) { | |
117 SECITEM_ZfreeItem(vpwd, PR_TRUE); | |
118 } | |
119 if(key == NULL) { | |
120 return PR_FALSE; | |
121 } | |
122 | |
123 data = SEC_PKCS7GetContent(&pfx->authSafe); | |
124 if(data == NULL) { | |
125 break; | |
126 } | |
127 | |
128 /* check MAC */ | |
129 mac = sec_pkcs12_generate_mac(key, data, pfx->old); | |
130 ret = PR_TRUE; | |
131 if(mac) { | |
132 SECItem *safeMac = &pfx->macData.safeMac.digest; | |
133 if(SECITEM_CompareItem(mac, safeMac) != SECEqual) { | |
134 | |
135 /* if we encounter an invalid mac, lets invert the | |
136 * password in case of unicode changes | |
137 */ | |
138 if(((!pfx->old) && pfx->swapUnicode) || (pfx->old)){ | |
139 PORT_SetError(SEC_ERROR_PKCS12_INVALID_MAC); | |
140 ret = PR_FALSE; | |
141 } else { | |
142 SECITEM_ZfreeItem(mac, PR_TRUE); | |
143 pfx->swapUnicode = PR_TRUE; | |
144 goto recheckUnicodePassword; | |
145 } | |
146 } | |
147 SECITEM_ZfreeItem(mac, PR_TRUE); | |
148 } else { | |
149 ret = PR_FALSE; | |
150 } | |
151 break; | |
152 default: | |
153 PORT_SetError(SEC_ERROR_PKCS12_UNSUPPORTED_MAC_ALGORITHM); | |
154 ret = PR_FALSE; | |
155 break; | |
156 } | |
157 | |
158 /* let success fall through */ | |
159 if(key != NULL) | |
160 SECITEM_ZfreeItem(key, PR_TRUE); | |
161 | |
162 return ret; | |
163 } | |
164 | |
165 /* check the validity of the pfx structure. we currently only support | |
166 * password integrity mode, so we check the MAC. | |
167 */ | |
168 static PRBool | |
169 sec_pkcs12_validate_pfx(SEC_PKCS12PFXItem *pfx, | |
170 SECItem *pwitem) | |
171 { | |
172 SECOidTag contentType; | |
173 | |
174 contentType = SEC_PKCS7ContentType(&pfx->authSafe); | |
175 switch(contentType) | |
176 { | |
177 case SEC_OID_PKCS7_DATA: | |
178 return sec_pkcs12_check_pfx_mac(pfx, pwitem); | |
179 break; | |
180 case SEC_OID_PKCS7_SIGNED_DATA: | |
181 default: | |
182 PORT_SetError(SEC_ERROR_PKCS12_UNSUPPORTED_TRANSPORT_MODE); | |
183 break; | |
184 } | |
185 | |
186 return PR_FALSE; | |
187 } | |
188 | |
189 /* decode and return the valid PFX. if the PFX item is not valid, | |
190 * NULL is returned. | |
191 */ | |
192 static SEC_PKCS12PFXItem * | |
193 sec_pkcs12_get_pfx(SECItem *pfx_data, | |
194 SECItem *pwitem) | |
195 { | |
196 SEC_PKCS12PFXItem *pfx; | |
197 PRBool valid_pfx; | |
198 | |
199 if((pfx_data == NULL) || (pwitem == NULL)) { | |
200 return NULL; | |
201 } | |
202 | |
203 pfx = sec_pkcs12_decode_pfx(pfx_data); | |
204 if(pfx == NULL) { | |
205 return NULL; | |
206 } | |
207 | |
208 valid_pfx = sec_pkcs12_validate_pfx(pfx, pwitem); | |
209 if(valid_pfx != PR_TRUE) { | |
210 SEC_PKCS12DestroyPFX(pfx); | |
211 pfx = NULL; | |
212 } | |
213 | |
214 return pfx; | |
215 } | |
216 | |
217 /* authenticated safe decoding, validation, and access routines | |
218 */ | |
219 | |
220 /* convert dogbert beta 3 authenticated safe structure to a post | |
221 * beta three structure, so that we don't have to change more routines. | |
222 */ | |
223 static SECStatus | |
224 sec_pkcs12_convert_old_auth_safe(SEC_PKCS12AuthenticatedSafe *asafe) | |
225 { | |
226 SEC_PKCS12Baggage *baggage; | |
227 SEC_PKCS12BaggageItem *bag; | |
228 SECStatus rv = SECSuccess; | |
229 | |
230 if(asafe->old_baggage.espvks == NULL) { | |
231 /* XXX should the ASN1 engine produce a single NULL element list | |
232 * rather than setting the pointer to NULL? | |
233 * There is no need to return an error -- assume that the list | |
234 * was empty. | |
235 */ | |
236 return SECSuccess; | |
237 } | |
238 | |
239 baggage = sec_pkcs12_create_baggage(asafe->poolp); | |
240 if(!baggage) { | |
241 return SECFailure; | |
242 } | |
243 bag = sec_pkcs12_create_external_bag(baggage); | |
244 if(!bag) { | |
245 return SECFailure; | |
246 } | |
247 | |
248 PORT_Memcpy(&asafe->baggage, baggage, sizeof(SEC_PKCS12Baggage)); | |
249 | |
250 /* if there are shrouded keys, append them to the bag */ | |
251 rv = SECSuccess; | |
252 if(asafe->old_baggage.espvks[0] != NULL) { | |
253 int nEspvk = 0; | |
254 rv = SECSuccess; | |
255 while((asafe->old_baggage.espvks[nEspvk] != NULL) && | |
256 (rv == SECSuccess)) { | |
257 rv = sec_pkcs12_append_shrouded_key(bag, | |
258 asafe->old_baggage.espvks[nEspvk]); | |
259 nEspvk++; | |
260 } | |
261 } | |
262 | |
263 return rv; | |
264 } | |
265 | |
266 /* decodes the authenticated safe item. a return of NULL indicates | |
267 * an error. however, the error will have occurred either in memory | |
268 * allocation or in decoding the authenticated safe. | |
269 * | |
270 * if an old PFX item has been found, we want to convert the | |
271 * old authenticated safe to the new one. | |
272 */ | |
273 static SEC_PKCS12AuthenticatedSafe * | |
274 sec_pkcs12_decode_authenticated_safe(SEC_PKCS12PFXItem *pfx) | |
275 { | |
276 SECItem *der_asafe = NULL; | |
277 SEC_PKCS12AuthenticatedSafe *asafe = NULL; | |
278 SECStatus rv; | |
279 | |
280 if(pfx == NULL) { | |
281 return NULL; | |
282 } | |
283 | |
284 der_asafe = SEC_PKCS7GetContent(&pfx->authSafe); | |
285 if(der_asafe == NULL) { | |
286 /* XXX set error ? */ | |
287 goto loser; | |
288 } | |
289 | |
290 asafe = sec_pkcs12_new_asafe(pfx->poolp); | |
291 if(asafe == NULL) { | |
292 goto loser; | |
293 } | |
294 | |
295 if(pfx->old == PR_FALSE) { | |
296 rv = SEC_ASN1DecodeItem(pfx->poolp, asafe, | |
297 SEC_PKCS12AuthenticatedSafeTemplate, | |
298 der_asafe); | |
299 asafe->old = PR_FALSE; | |
300 asafe->swapUnicode = pfx->swapUnicode; | |
301 } else { | |
302 /* handle beta exported files */ | |
303 rv = SEC_ASN1DecodeItem(pfx->poolp, asafe, | |
304 SEC_PKCS12AuthenticatedSafeTemplate_OLD, | |
305 der_asafe); | |
306 asafe->safe = &(asafe->old_safe); | |
307 rv = sec_pkcs12_convert_old_auth_safe(asafe); | |
308 asafe->old = PR_TRUE; | |
309 } | |
310 | |
311 if(rv != SECSuccess) { | |
312 goto loser; | |
313 } | |
314 | |
315 asafe->poolp = pfx->poolp; | |
316 | |
317 return asafe; | |
318 | |
319 loser: | |
320 return NULL; | |
321 } | |
322 | |
323 /* validates the safe within the authenticated safe item. | |
324 * in order to be valid: | |
325 * 1. the privacy salt must be present | |
326 * 2. the encryption algorithm must be supported (including | |
327 * export policy) | |
328 * PR_FALSE indicates an error, PR_TRUE indicates a valid safe | |
329 */ | |
330 static PRBool | |
331 sec_pkcs12_validate_encrypted_safe(SEC_PKCS12AuthenticatedSafe *asafe) | |
332 { | |
333 PRBool valid = PR_FALSE; | |
334 SECAlgorithmID *algid; | |
335 | |
336 if(asafe == NULL) { | |
337 return PR_FALSE; | |
338 } | |
339 | |
340 /* if mode is password privacy, then privacySalt is assumed | |
341 * to be non-zero. | |
342 */ | |
343 if(asafe->privacySalt.len != 0) { | |
344 valid = PR_TRUE; | |
345 asafe->privacySalt.len /= 8; | |
346 } else { | |
347 PORT_SetError(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE); | |
348 return PR_FALSE; | |
349 } | |
350 | |
351 /* until spec changes, content will have between 2 and 8 bytes depending | |
352 * upon the algorithm used if certs are unencrypted... | |
353 * also want to support case where content is empty -- which we produce | |
354 */ | |
355 if(SEC_PKCS7IsContentEmpty(asafe->safe, 8) == PR_TRUE) { | |
356 asafe->emptySafe = PR_TRUE; | |
357 return PR_TRUE; | |
358 } | |
359 | |
360 asafe->emptySafe = PR_FALSE; | |
361 | |
362 /* make sure that a pbe algorithm is being used */ | |
363 algid = SEC_PKCS7GetEncryptionAlgorithm(asafe->safe); | |
364 if(algid != NULL) { | |
365 if(SEC_PKCS5IsAlgorithmPBEAlg(algid)) { | |
366 valid = SEC_PKCS12DecryptionAllowed(algid); | |
367 | |
368 if(valid == PR_FALSE) { | |
369 PORT_SetError(SEC_ERROR_BAD_EXPORT_ALGORITHM); | |
370 } | |
371 } else { | |
372 PORT_SetError(SEC_ERROR_PKCS12_UNSUPPORTED_PBE_ALGORITHM); | |
373 valid = PR_FALSE; | |
374 } | |
375 } else { | |
376 valid = PR_FALSE; | |
377 PORT_SetError(SEC_ERROR_PKCS12_UNSUPPORTED_PBE_ALGORITHM); | |
378 } | |
379 | |
380 return valid; | |
381 } | |
382 | |
383 /* validates authenticates safe: | |
384 * 1. checks that the version is supported | |
385 * 2. checks that only password privacy mode is used (currently) | |
386 * 3. further, makes sure safe has appropriate policies per above function | |
387 * PR_FALSE indicates failure. | |
388 */ | |
389 static PRBool | |
390 sec_pkcs12_validate_auth_safe(SEC_PKCS12AuthenticatedSafe *asafe) | |
391 { | |
392 PRBool valid = PR_TRUE; | |
393 SECOidTag safe_type; | |
394 int version; | |
395 | |
396 if(asafe == NULL) { | |
397 return PR_FALSE; | |
398 } | |
399 | |
400 /* check version, since it is default it may not be present. | |
401 * therefore, assume ok | |
402 */ | |
403 if((asafe->version.len > 0) && (asafe->old == PR_FALSE)) { | |
404 version = DER_GetInteger(&asafe->version); | |
405 if(version > SEC_PKCS12_PFX_VERSION) { | |
406 PORT_SetError(SEC_ERROR_PKCS12_UNSUPPORTED_VERSION); | |
407 return PR_FALSE; | |
408 } | |
409 } | |
410 | |
411 /* validate password mode is being used */ | |
412 safe_type = SEC_PKCS7ContentType(asafe->safe); | |
413 switch(safe_type) | |
414 { | |
415 case SEC_OID_PKCS7_ENCRYPTED_DATA: | |
416 valid = sec_pkcs12_validate_encrypted_safe(asafe); | |
417 break; | |
418 case SEC_OID_PKCS7_ENVELOPED_DATA: | |
419 default: | |
420 PORT_SetError(SEC_ERROR_PKCS12_UNSUPPORTED_TRANSPORT_MODE); | |
421 valid = PR_FALSE; | |
422 break; | |
423 } | |
424 | |
425 return valid; | |
426 } | |
427 | |
428 /* retrieves the authenticated safe item from the PFX item | |
429 * before returning the authenticated safe, the validity of the | |
430 * authenticated safe is checked and if valid, returned. | |
431 * a return of NULL indicates that an error occurred. | |
432 */ | |
433 static SEC_PKCS12AuthenticatedSafe * | |
434 sec_pkcs12_get_auth_safe(SEC_PKCS12PFXItem *pfx) | |
435 { | |
436 SEC_PKCS12AuthenticatedSafe *asafe; | |
437 PRBool valid_safe; | |
438 | |
439 if(pfx == NULL) { | |
440 return NULL; | |
441 } | |
442 | |
443 asafe = sec_pkcs12_decode_authenticated_safe(pfx); | |
444 if(asafe == NULL) { | |
445 return NULL; | |
446 } | |
447 | |
448 valid_safe = sec_pkcs12_validate_auth_safe(asafe); | |
449 if(valid_safe != PR_TRUE) { | |
450 asafe = NULL; | |
451 } else if(asafe) { | |
452 asafe->baggage.poolp = asafe->poolp; | |
453 } | |
454 | |
455 return asafe; | |
456 } | |
457 | |
458 /* decrypts the authenticated safe. | |
459 * a return of anything but SECSuccess indicates an error. the | |
460 * password is not known to be valid until the call to the | |
461 * function sec_pkcs12_get_safe_contents. If decoding the safe | |
462 * fails, it is assumed the password was incorrect and the error | |
463 * is set then. any failure here is assumed to be due to | |
464 * internal problems in SEC_PKCS7DecryptContents or below. | |
465 */ | |
466 static SECStatus | |
467 sec_pkcs12_decrypt_auth_safe(SEC_PKCS12AuthenticatedSafe *asafe, | |
468 SECItem *pwitem, | |
469 void *wincx) | |
470 { | |
471 SECStatus rv = SECFailure; | |
472 SECItem *vpwd = NULL; | |
473 | |
474 if((asafe == NULL) || (pwitem == NULL)) { | |
475 return SECFailure; | |
476 } | |
477 | |
478 if(asafe->old == PR_FALSE) { | |
479 vpwd = sec_pkcs12_create_virtual_password(pwitem, &asafe->privacySalt, | |
480 asafe->swapUnicode); | |
481 if(vpwd == NULL) { | |
482 return SECFailure; | |
483 } | |
484 } | |
485 | |
486 rv = SEC_PKCS7DecryptContents(asafe->poolp, asafe->safe, | |
487 (asafe->old ? pwitem : vpwd), wincx); | |
488 | |
489 if(asafe->old == PR_FALSE) { | |
490 SECITEM_ZfreeItem(vpwd, PR_TRUE); | |
491 } | |
492 | |
493 return rv; | |
494 } | |
495 | |
496 /* extract the safe from the authenticated safe. | |
497 * if we are unable to decode the safe, then it is likely that the | |
498 * safe has not been decrypted or the password used to decrypt | |
499 * the safe was invalid. we assume that the password was invalid and | |
500 * set an error accordingly. | |
501 * a return of NULL indicates that an error occurred. | |
502 */ | |
503 static SEC_PKCS12SafeContents * | |
504 sec_pkcs12_get_safe_contents(SEC_PKCS12AuthenticatedSafe *asafe) | |
505 { | |
506 SECItem *src = NULL; | |
507 SEC_PKCS12SafeContents *safe = NULL; | |
508 SECStatus rv = SECFailure; | |
509 | |
510 if(asafe == NULL) { | |
511 return NULL; | |
512 } | |
513 | |
514 safe = (SEC_PKCS12SafeContents *)PORT_ArenaZAlloc(asafe->poolp, | |
515 sizeof(SEC_PKCS12SafeContents)); | |
516 if(safe == NULL) { | |
517 return NULL; | |
518 } | |
519 safe->poolp = asafe->poolp; | |
520 safe->old = asafe->old; | |
521 safe->swapUnicode = asafe->swapUnicode; | |
522 | |
523 src = SEC_PKCS7GetContent(asafe->safe); | |
524 if(src != NULL) { | |
525 const SEC_ASN1Template *theTemplate; | |
526 if(asafe->old != PR_TRUE) { | |
527 theTemplate = SEC_PKCS12SafeContentsTemplate; | |
528 } else { | |
529 theTemplate = SEC_PKCS12SafeContentsTemplate_OLD; | |
530 } | |
531 | |
532 rv = SEC_ASN1DecodeItem(asafe->poolp, safe, theTemplate, src); | |
533 | |
534 /* if we could not decode the item, password was probably invalid */ | |
535 if(rv != SECSuccess) { | |
536 safe = NULL; | |
537 PORT_SetError(SEC_ERROR_PKCS12_PRIVACY_PASSWORD_INCORRECT); | |
538 } | |
539 } else { | |
540 PORT_SetError(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE); | |
541 rv = SECFailure; | |
542 } | |
543 | |
544 return safe; | |
545 } | |
546 | |
547 /* import PFX item | |
548 * der_pfx is the der encoded pfx structure | |
549 * pbef and pbearg are the integrity/encryption password call back | |
550 * ncCall is the nickname collision calllback | |
551 * slot is the destination token | |
552 * wincx window handler | |
553 * | |
554 * on error, error code set and SECFailure returned | |
555 */ | |
556 SECStatus | |
557 SEC_PKCS12PutPFX(SECItem *der_pfx, SECItem *pwitem, | |
558 SEC_PKCS12NicknameCollisionCallback ncCall, | |
559 PK11SlotInfo *slot, | |
560 void *wincx) | |
561 { | |
562 SEC_PKCS12PFXItem *pfx; | |
563 SEC_PKCS12AuthenticatedSafe *asafe; | |
564 SEC_PKCS12SafeContents *safe_contents = NULL; | |
565 SECStatus rv; | |
566 | |
567 if(!der_pfx || !pwitem || !slot) { | |
568 return SECFailure; | |
569 } | |
570 | |
571 /* decode and validate each section */ | |
572 rv = SECFailure; | |
573 | |
574 pfx = sec_pkcs12_get_pfx(der_pfx, pwitem); | |
575 if(pfx != NULL) { | |
576 asafe = sec_pkcs12_get_auth_safe(pfx); | |
577 if(asafe != NULL) { | |
578 | |
579 /* decrypt safe -- only if not empty */ | |
580 if(asafe->emptySafe != PR_TRUE) { | |
581 rv = sec_pkcs12_decrypt_auth_safe(asafe, pwitem, wincx); | |
582 if(rv == SECSuccess) { | |
583 safe_contents = sec_pkcs12_get_safe_contents(asafe); | |
584 if(safe_contents == NULL) { | |
585 rv = SECFailure; | |
586 } | |
587 } | |
588 } else { | |
589 safe_contents = sec_pkcs12_create_safe_contents(asafe->poolp); | |
590 if(safe_contents == NULL) { | |
591 rv = SECFailure; | |
592 } else { | |
593 safe_contents->swapUnicode = pfx->swapUnicode; | |
594 rv = SECSuccess; | |
595 } | |
596 } | |
597 | |
598 /* get safe contents and begin import */ | |
599 if(rv == SECSuccess) { | |
600 SEC_PKCS12DecoderContext *p12dcx; | |
601 | |
602 p12dcx = sec_PKCS12ConvertOldSafeToNew(pfx->poolp, slot, | |
603 pfx->swapUnicode, | |
604 pwitem, wincx, safe_contents, | |
605 &asafe->baggage); | |
606 if(!p12dcx) { | |
607 rv = SECFailure; | |
608 goto loser; | |
609 } | |
610 | |
611 if(SEC_PKCS12DecoderValidateBags(p12dcx, ncCall) | |
612 != SECSuccess) { | |
613 rv = SECFailure; | |
614 goto loser; | |
615 } | |
616 | |
617 rv = SEC_PKCS12DecoderImportBags(p12dcx); | |
618 } | |
619 | |
620 } | |
621 } | |
622 | |
623 loser: | |
624 | |
625 if(pfx) { | |
626 SEC_PKCS12DestroyPFX(pfx); | |
627 } | |
628 | |
629 return rv; | |
630 } | |
631 | |
632 PRBool | |
633 SEC_PKCS12ValidData(char *buf, int bufLen, long int totalLength) | |
634 { | |
635 int lengthLength; | |
636 | |
637 PRBool valid = PR_FALSE; | |
638 | |
639 if(buf == NULL) { | |
640 return PR_FALSE; | |
641 } | |
642 | |
643 /* check for constructed sequence identifier tag */ | |
644 if(*buf == (SEC_ASN1_CONSTRUCTED | SEC_ASN1_SEQUENCE)) { | |
645 totalLength--; /* header byte taken care of */ | |
646 buf++; | |
647 | |
648 lengthLength = (long int)SEC_ASN1LengthLength(totalLength - 1); | |
649 if(totalLength > 0x7f) { | |
650 lengthLength--; | |
651 *buf &= 0x7f; /* remove bit 8 indicator */ | |
652 if((*buf - (char)lengthLength) == 0) { | |
653 valid = PR_TRUE; | |
654 } | |
655 } else { | |
656 lengthLength--; | |
657 if((*buf - (char)lengthLength) == 0) { | |
658 valid = PR_TRUE; | |
659 } | |
660 } | |
661 } | |
662 | |
663 return valid; | |
664 } | |
OLD | NEW |