1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/pkcs12/p12dec.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,664 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#include "pkcs12.h" 1.9 +#include "plarena.h" 1.10 +#include "secpkcs7.h" 1.11 +#include "p12local.h" 1.12 +#include "secoid.h" 1.13 +#include "secitem.h" 1.14 +#include "secport.h" 1.15 +#include "secasn1.h" 1.16 +#include "secder.h" 1.17 +#include "secerr.h" 1.18 +#include "cert.h" 1.19 +#include "certdb.h" 1.20 +#include "p12plcy.h" 1.21 +#include "p12.h" 1.22 +#include "secpkcs5.h" 1.23 + 1.24 +/* PFX extraction and validation routines */ 1.25 + 1.26 +/* decode the DER encoded PFX item. if unable to decode, check to see if it 1.27 + * is an older PFX item. If that fails, assume the file was not a valid 1.28 + * pfx file. 1.29 + * the returned pfx structure should be destroyed using SEC_PKCS12DestroyPFX 1.30 + */ 1.31 +static SEC_PKCS12PFXItem * 1.32 +sec_pkcs12_decode_pfx(SECItem *der_pfx) 1.33 +{ 1.34 + SEC_PKCS12PFXItem *pfx; 1.35 + SECStatus rv; 1.36 + 1.37 + if(der_pfx == NULL) { 1.38 + return NULL; 1.39 + } 1.40 + 1.41 + /* allocate the space for a new PFX item */ 1.42 + pfx = sec_pkcs12_new_pfx(); 1.43 + if(pfx == NULL) { 1.44 + return NULL; 1.45 + } 1.46 + 1.47 + rv = SEC_ASN1DecodeItem(pfx->poolp, pfx, SEC_PKCS12PFXItemTemplate, 1.48 + der_pfx); 1.49 + 1.50 + /* if a failure occurred, check for older version... 1.51 + * we also get rid of the old pfx structure, because we don't 1.52 + * know where it failed and what data in may contain 1.53 + */ 1.54 + if(rv != SECSuccess) { 1.55 + SEC_PKCS12DestroyPFX(pfx); 1.56 + pfx = sec_pkcs12_new_pfx(); 1.57 + if(pfx == NULL) { 1.58 + return NULL; 1.59 + } 1.60 + rv = SEC_ASN1DecodeItem(pfx->poolp, pfx, SEC_PKCS12PFXItemTemplate_OLD, 1.61 + der_pfx); 1.62 + if(rv != SECSuccess) { 1.63 + PORT_SetError(SEC_ERROR_PKCS12_DECODING_PFX); 1.64 + PORT_FreeArena(pfx->poolp, PR_TRUE); 1.65 + return NULL; 1.66 + } 1.67 + pfx->old = PR_TRUE; 1.68 + SGN_CopyDigestInfo(pfx->poolp, &pfx->macData.safeMac, &pfx->old_safeMac); 1.69 + SECITEM_CopyItem(pfx->poolp, &pfx->macData.macSalt, &pfx->old_macSalt); 1.70 + } else { 1.71 + pfx->old = PR_FALSE; 1.72 + } 1.73 + 1.74 + /* convert bit string from bits to bytes */ 1.75 + pfx->macData.macSalt.len /= 8; 1.76 + 1.77 + return pfx; 1.78 +} 1.79 + 1.80 +/* validate the integrity MAC used in the PFX. The MAC is generated 1.81 + * per the PKCS 12 document. If the MAC is incorrect, it is most likely 1.82 + * due to an invalid password. 1.83 + * pwitem is the integrity password 1.84 + * pfx is the decoded pfx item 1.85 + */ 1.86 +static PRBool 1.87 +sec_pkcs12_check_pfx_mac(SEC_PKCS12PFXItem *pfx, 1.88 + SECItem *pwitem) 1.89 +{ 1.90 + SECItem *key = NULL, *mac = NULL, *data = NULL; 1.91 + SECItem *vpwd = NULL; 1.92 + SECOidTag algorithm; 1.93 + PRBool ret = PR_FALSE; 1.94 + 1.95 + if(pfx == NULL) { 1.96 + return PR_FALSE; 1.97 + } 1.98 + 1.99 + algorithm = SECOID_GetAlgorithmTag(&pfx->macData.safeMac.digestAlgorithm); 1.100 + switch(algorithm) { 1.101 + /* only SHA1 hashing supported as a MACing algorithm */ 1.102 + case SEC_OID_SHA1: 1.103 + if(pfx->old == PR_FALSE) { 1.104 + pfx->swapUnicode = PR_FALSE; 1.105 + } 1.106 + 1.107 +recheckUnicodePassword: 1.108 + vpwd = sec_pkcs12_create_virtual_password(pwitem, 1.109 + &pfx->macData.macSalt, 1.110 + pfx->swapUnicode); 1.111 + if(vpwd == NULL) { 1.112 + return PR_FALSE; 1.113 + } 1.114 + 1.115 + key = sec_pkcs12_generate_key_from_password(algorithm, 1.116 + &pfx->macData.macSalt, 1.117 + (pfx->old ? pwitem : vpwd)); 1.118 + /* free vpwd only for newer PFX */ 1.119 + if(vpwd) { 1.120 + SECITEM_ZfreeItem(vpwd, PR_TRUE); 1.121 + } 1.122 + if(key == NULL) { 1.123 + return PR_FALSE; 1.124 + } 1.125 + 1.126 + data = SEC_PKCS7GetContent(&pfx->authSafe); 1.127 + if(data == NULL) { 1.128 + break; 1.129 + } 1.130 + 1.131 + /* check MAC */ 1.132 + mac = sec_pkcs12_generate_mac(key, data, pfx->old); 1.133 + ret = PR_TRUE; 1.134 + if(mac) { 1.135 + SECItem *safeMac = &pfx->macData.safeMac.digest; 1.136 + if(SECITEM_CompareItem(mac, safeMac) != SECEqual) { 1.137 + 1.138 + /* if we encounter an invalid mac, lets invert the 1.139 + * password in case of unicode changes 1.140 + */ 1.141 + if(((!pfx->old) && pfx->swapUnicode) || (pfx->old)){ 1.142 + PORT_SetError(SEC_ERROR_PKCS12_INVALID_MAC); 1.143 + ret = PR_FALSE; 1.144 + } else { 1.145 + SECITEM_ZfreeItem(mac, PR_TRUE); 1.146 + pfx->swapUnicode = PR_TRUE; 1.147 + goto recheckUnicodePassword; 1.148 + } 1.149 + } 1.150 + SECITEM_ZfreeItem(mac, PR_TRUE); 1.151 + } else { 1.152 + ret = PR_FALSE; 1.153 + } 1.154 + break; 1.155 + default: 1.156 + PORT_SetError(SEC_ERROR_PKCS12_UNSUPPORTED_MAC_ALGORITHM); 1.157 + ret = PR_FALSE; 1.158 + break; 1.159 + } 1.160 + 1.161 + /* let success fall through */ 1.162 + if(key != NULL) 1.163 + SECITEM_ZfreeItem(key, PR_TRUE); 1.164 + 1.165 + return ret; 1.166 +} 1.167 + 1.168 +/* check the validity of the pfx structure. we currently only support 1.169 + * password integrity mode, so we check the MAC. 1.170 + */ 1.171 +static PRBool 1.172 +sec_pkcs12_validate_pfx(SEC_PKCS12PFXItem *pfx, 1.173 + SECItem *pwitem) 1.174 +{ 1.175 + SECOidTag contentType; 1.176 + 1.177 + contentType = SEC_PKCS7ContentType(&pfx->authSafe); 1.178 + switch(contentType) 1.179 + { 1.180 + case SEC_OID_PKCS7_DATA: 1.181 + return sec_pkcs12_check_pfx_mac(pfx, pwitem); 1.182 + break; 1.183 + case SEC_OID_PKCS7_SIGNED_DATA: 1.184 + default: 1.185 + PORT_SetError(SEC_ERROR_PKCS12_UNSUPPORTED_TRANSPORT_MODE); 1.186 + break; 1.187 + } 1.188 + 1.189 + return PR_FALSE; 1.190 +} 1.191 + 1.192 +/* decode and return the valid PFX. if the PFX item is not valid, 1.193 + * NULL is returned. 1.194 + */ 1.195 +static SEC_PKCS12PFXItem * 1.196 +sec_pkcs12_get_pfx(SECItem *pfx_data, 1.197 + SECItem *pwitem) 1.198 +{ 1.199 + SEC_PKCS12PFXItem *pfx; 1.200 + PRBool valid_pfx; 1.201 + 1.202 + if((pfx_data == NULL) || (pwitem == NULL)) { 1.203 + return NULL; 1.204 + } 1.205 + 1.206 + pfx = sec_pkcs12_decode_pfx(pfx_data); 1.207 + if(pfx == NULL) { 1.208 + return NULL; 1.209 + } 1.210 + 1.211 + valid_pfx = sec_pkcs12_validate_pfx(pfx, pwitem); 1.212 + if(valid_pfx != PR_TRUE) { 1.213 + SEC_PKCS12DestroyPFX(pfx); 1.214 + pfx = NULL; 1.215 + } 1.216 + 1.217 + return pfx; 1.218 +} 1.219 + 1.220 +/* authenticated safe decoding, validation, and access routines 1.221 + */ 1.222 + 1.223 +/* convert dogbert beta 3 authenticated safe structure to a post 1.224 + * beta three structure, so that we don't have to change more routines. 1.225 + */ 1.226 +static SECStatus 1.227 +sec_pkcs12_convert_old_auth_safe(SEC_PKCS12AuthenticatedSafe *asafe) 1.228 +{ 1.229 + SEC_PKCS12Baggage *baggage; 1.230 + SEC_PKCS12BaggageItem *bag; 1.231 + SECStatus rv = SECSuccess; 1.232 + 1.233 + if(asafe->old_baggage.espvks == NULL) { 1.234 + /* XXX should the ASN1 engine produce a single NULL element list 1.235 + * rather than setting the pointer to NULL? 1.236 + * There is no need to return an error -- assume that the list 1.237 + * was empty. 1.238 + */ 1.239 + return SECSuccess; 1.240 + } 1.241 + 1.242 + baggage = sec_pkcs12_create_baggage(asafe->poolp); 1.243 + if(!baggage) { 1.244 + return SECFailure; 1.245 + } 1.246 + bag = sec_pkcs12_create_external_bag(baggage); 1.247 + if(!bag) { 1.248 + return SECFailure; 1.249 + } 1.250 + 1.251 + PORT_Memcpy(&asafe->baggage, baggage, sizeof(SEC_PKCS12Baggage)); 1.252 + 1.253 + /* if there are shrouded keys, append them to the bag */ 1.254 + rv = SECSuccess; 1.255 + if(asafe->old_baggage.espvks[0] != NULL) { 1.256 + int nEspvk = 0; 1.257 + rv = SECSuccess; 1.258 + while((asafe->old_baggage.espvks[nEspvk] != NULL) && 1.259 + (rv == SECSuccess)) { 1.260 + rv = sec_pkcs12_append_shrouded_key(bag, 1.261 + asafe->old_baggage.espvks[nEspvk]); 1.262 + nEspvk++; 1.263 + } 1.264 + } 1.265 + 1.266 + return rv; 1.267 +} 1.268 + 1.269 +/* decodes the authenticated safe item. a return of NULL indicates 1.270 + * an error. however, the error will have occurred either in memory 1.271 + * allocation or in decoding the authenticated safe. 1.272 + * 1.273 + * if an old PFX item has been found, we want to convert the 1.274 + * old authenticated safe to the new one. 1.275 + */ 1.276 +static SEC_PKCS12AuthenticatedSafe * 1.277 +sec_pkcs12_decode_authenticated_safe(SEC_PKCS12PFXItem *pfx) 1.278 +{ 1.279 + SECItem *der_asafe = NULL; 1.280 + SEC_PKCS12AuthenticatedSafe *asafe = NULL; 1.281 + SECStatus rv; 1.282 + 1.283 + if(pfx == NULL) { 1.284 + return NULL; 1.285 + } 1.286 + 1.287 + der_asafe = SEC_PKCS7GetContent(&pfx->authSafe); 1.288 + if(der_asafe == NULL) { 1.289 + /* XXX set error ? */ 1.290 + goto loser; 1.291 + } 1.292 + 1.293 + asafe = sec_pkcs12_new_asafe(pfx->poolp); 1.294 + if(asafe == NULL) { 1.295 + goto loser; 1.296 + } 1.297 + 1.298 + if(pfx->old == PR_FALSE) { 1.299 + rv = SEC_ASN1DecodeItem(pfx->poolp, asafe, 1.300 + SEC_PKCS12AuthenticatedSafeTemplate, 1.301 + der_asafe); 1.302 + asafe->old = PR_FALSE; 1.303 + asafe->swapUnicode = pfx->swapUnicode; 1.304 + } else { 1.305 + /* handle beta exported files */ 1.306 + rv = SEC_ASN1DecodeItem(pfx->poolp, asafe, 1.307 + SEC_PKCS12AuthenticatedSafeTemplate_OLD, 1.308 + der_asafe); 1.309 + asafe->safe = &(asafe->old_safe); 1.310 + rv = sec_pkcs12_convert_old_auth_safe(asafe); 1.311 + asafe->old = PR_TRUE; 1.312 + } 1.313 + 1.314 + if(rv != SECSuccess) { 1.315 + goto loser; 1.316 + } 1.317 + 1.318 + asafe->poolp = pfx->poolp; 1.319 + 1.320 + return asafe; 1.321 + 1.322 +loser: 1.323 + return NULL; 1.324 +} 1.325 + 1.326 +/* validates the safe within the authenticated safe item. 1.327 + * in order to be valid: 1.328 + * 1. the privacy salt must be present 1.329 + * 2. the encryption algorithm must be supported (including 1.330 + * export policy) 1.331 + * PR_FALSE indicates an error, PR_TRUE indicates a valid safe 1.332 + */ 1.333 +static PRBool 1.334 +sec_pkcs12_validate_encrypted_safe(SEC_PKCS12AuthenticatedSafe *asafe) 1.335 +{ 1.336 + PRBool valid = PR_FALSE; 1.337 + SECAlgorithmID *algid; 1.338 + 1.339 + if(asafe == NULL) { 1.340 + return PR_FALSE; 1.341 + } 1.342 + 1.343 + /* if mode is password privacy, then privacySalt is assumed 1.344 + * to be non-zero. 1.345 + */ 1.346 + if(asafe->privacySalt.len != 0) { 1.347 + valid = PR_TRUE; 1.348 + asafe->privacySalt.len /= 8; 1.349 + } else { 1.350 + PORT_SetError(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE); 1.351 + return PR_FALSE; 1.352 + } 1.353 + 1.354 + /* until spec changes, content will have between 2 and 8 bytes depending 1.355 + * upon the algorithm used if certs are unencrypted... 1.356 + * also want to support case where content is empty -- which we produce 1.357 + */ 1.358 + if(SEC_PKCS7IsContentEmpty(asafe->safe, 8) == PR_TRUE) { 1.359 + asafe->emptySafe = PR_TRUE; 1.360 + return PR_TRUE; 1.361 + } 1.362 + 1.363 + asafe->emptySafe = PR_FALSE; 1.364 + 1.365 + /* make sure that a pbe algorithm is being used */ 1.366 + algid = SEC_PKCS7GetEncryptionAlgorithm(asafe->safe); 1.367 + if(algid != NULL) { 1.368 + if(SEC_PKCS5IsAlgorithmPBEAlg(algid)) { 1.369 + valid = SEC_PKCS12DecryptionAllowed(algid); 1.370 + 1.371 + if(valid == PR_FALSE) { 1.372 + PORT_SetError(SEC_ERROR_BAD_EXPORT_ALGORITHM); 1.373 + } 1.374 + } else { 1.375 + PORT_SetError(SEC_ERROR_PKCS12_UNSUPPORTED_PBE_ALGORITHM); 1.376 + valid = PR_FALSE; 1.377 + } 1.378 + } else { 1.379 + valid = PR_FALSE; 1.380 + PORT_SetError(SEC_ERROR_PKCS12_UNSUPPORTED_PBE_ALGORITHM); 1.381 + } 1.382 + 1.383 + return valid; 1.384 +} 1.385 + 1.386 +/* validates authenticates safe: 1.387 + * 1. checks that the version is supported 1.388 + * 2. checks that only password privacy mode is used (currently) 1.389 + * 3. further, makes sure safe has appropriate policies per above function 1.390 + * PR_FALSE indicates failure. 1.391 + */ 1.392 +static PRBool 1.393 +sec_pkcs12_validate_auth_safe(SEC_PKCS12AuthenticatedSafe *asafe) 1.394 +{ 1.395 + PRBool valid = PR_TRUE; 1.396 + SECOidTag safe_type; 1.397 + int version; 1.398 + 1.399 + if(asafe == NULL) { 1.400 + return PR_FALSE; 1.401 + } 1.402 + 1.403 + /* check version, since it is default it may not be present. 1.404 + * therefore, assume ok 1.405 + */ 1.406 + if((asafe->version.len > 0) && (asafe->old == PR_FALSE)) { 1.407 + version = DER_GetInteger(&asafe->version); 1.408 + if(version > SEC_PKCS12_PFX_VERSION) { 1.409 + PORT_SetError(SEC_ERROR_PKCS12_UNSUPPORTED_VERSION); 1.410 + return PR_FALSE; 1.411 + } 1.412 + } 1.413 + 1.414 + /* validate password mode is being used */ 1.415 + safe_type = SEC_PKCS7ContentType(asafe->safe); 1.416 + switch(safe_type) 1.417 + { 1.418 + case SEC_OID_PKCS7_ENCRYPTED_DATA: 1.419 + valid = sec_pkcs12_validate_encrypted_safe(asafe); 1.420 + break; 1.421 + case SEC_OID_PKCS7_ENVELOPED_DATA: 1.422 + default: 1.423 + PORT_SetError(SEC_ERROR_PKCS12_UNSUPPORTED_TRANSPORT_MODE); 1.424 + valid = PR_FALSE; 1.425 + break; 1.426 + } 1.427 + 1.428 + return valid; 1.429 +} 1.430 + 1.431 +/* retrieves the authenticated safe item from the PFX item 1.432 + * before returning the authenticated safe, the validity of the 1.433 + * authenticated safe is checked and if valid, returned. 1.434 + * a return of NULL indicates that an error occurred. 1.435 + */ 1.436 +static SEC_PKCS12AuthenticatedSafe * 1.437 +sec_pkcs12_get_auth_safe(SEC_PKCS12PFXItem *pfx) 1.438 +{ 1.439 + SEC_PKCS12AuthenticatedSafe *asafe; 1.440 + PRBool valid_safe; 1.441 + 1.442 + if(pfx == NULL) { 1.443 + return NULL; 1.444 + } 1.445 + 1.446 + asafe = sec_pkcs12_decode_authenticated_safe(pfx); 1.447 + if(asafe == NULL) { 1.448 + return NULL; 1.449 + } 1.450 + 1.451 + valid_safe = sec_pkcs12_validate_auth_safe(asafe); 1.452 + if(valid_safe != PR_TRUE) { 1.453 + asafe = NULL; 1.454 + } else if(asafe) { 1.455 + asafe->baggage.poolp = asafe->poolp; 1.456 + } 1.457 + 1.458 + return asafe; 1.459 +} 1.460 + 1.461 +/* decrypts the authenticated safe. 1.462 + * a return of anything but SECSuccess indicates an error. the 1.463 + * password is not known to be valid until the call to the 1.464 + * function sec_pkcs12_get_safe_contents. If decoding the safe 1.465 + * fails, it is assumed the password was incorrect and the error 1.466 + * is set then. any failure here is assumed to be due to 1.467 + * internal problems in SEC_PKCS7DecryptContents or below. 1.468 + */ 1.469 +static SECStatus 1.470 +sec_pkcs12_decrypt_auth_safe(SEC_PKCS12AuthenticatedSafe *asafe, 1.471 + SECItem *pwitem, 1.472 + void *wincx) 1.473 +{ 1.474 + SECStatus rv = SECFailure; 1.475 + SECItem *vpwd = NULL; 1.476 + 1.477 + if((asafe == NULL) || (pwitem == NULL)) { 1.478 + return SECFailure; 1.479 + } 1.480 + 1.481 + if(asafe->old == PR_FALSE) { 1.482 + vpwd = sec_pkcs12_create_virtual_password(pwitem, &asafe->privacySalt, 1.483 + asafe->swapUnicode); 1.484 + if(vpwd == NULL) { 1.485 + return SECFailure; 1.486 + } 1.487 + } 1.488 + 1.489 + rv = SEC_PKCS7DecryptContents(asafe->poolp, asafe->safe, 1.490 + (asafe->old ? pwitem : vpwd), wincx); 1.491 + 1.492 + if(asafe->old == PR_FALSE) { 1.493 + SECITEM_ZfreeItem(vpwd, PR_TRUE); 1.494 + } 1.495 + 1.496 + return rv; 1.497 +} 1.498 + 1.499 +/* extract the safe from the authenticated safe. 1.500 + * if we are unable to decode the safe, then it is likely that the 1.501 + * safe has not been decrypted or the password used to decrypt 1.502 + * the safe was invalid. we assume that the password was invalid and 1.503 + * set an error accordingly. 1.504 + * a return of NULL indicates that an error occurred. 1.505 + */ 1.506 +static SEC_PKCS12SafeContents * 1.507 +sec_pkcs12_get_safe_contents(SEC_PKCS12AuthenticatedSafe *asafe) 1.508 +{ 1.509 + SECItem *src = NULL; 1.510 + SEC_PKCS12SafeContents *safe = NULL; 1.511 + SECStatus rv = SECFailure; 1.512 + 1.513 + if(asafe == NULL) { 1.514 + return NULL; 1.515 + } 1.516 + 1.517 + safe = (SEC_PKCS12SafeContents *)PORT_ArenaZAlloc(asafe->poolp, 1.518 + sizeof(SEC_PKCS12SafeContents)); 1.519 + if(safe == NULL) { 1.520 + return NULL; 1.521 + } 1.522 + safe->poolp = asafe->poolp; 1.523 + safe->old = asafe->old; 1.524 + safe->swapUnicode = asafe->swapUnicode; 1.525 + 1.526 + src = SEC_PKCS7GetContent(asafe->safe); 1.527 + if(src != NULL) { 1.528 + const SEC_ASN1Template *theTemplate; 1.529 + if(asafe->old != PR_TRUE) { 1.530 + theTemplate = SEC_PKCS12SafeContentsTemplate; 1.531 + } else { 1.532 + theTemplate = SEC_PKCS12SafeContentsTemplate_OLD; 1.533 + } 1.534 + 1.535 + rv = SEC_ASN1DecodeItem(asafe->poolp, safe, theTemplate, src); 1.536 + 1.537 + /* if we could not decode the item, password was probably invalid */ 1.538 + if(rv != SECSuccess) { 1.539 + safe = NULL; 1.540 + PORT_SetError(SEC_ERROR_PKCS12_PRIVACY_PASSWORD_INCORRECT); 1.541 + } 1.542 + } else { 1.543 + PORT_SetError(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE); 1.544 + rv = SECFailure; 1.545 + } 1.546 + 1.547 + return safe; 1.548 +} 1.549 + 1.550 +/* import PFX item 1.551 + * der_pfx is the der encoded pfx structure 1.552 + * pbef and pbearg are the integrity/encryption password call back 1.553 + * ncCall is the nickname collision calllback 1.554 + * slot is the destination token 1.555 + * wincx window handler 1.556 + * 1.557 + * on error, error code set and SECFailure returned 1.558 + */ 1.559 +SECStatus 1.560 +SEC_PKCS12PutPFX(SECItem *der_pfx, SECItem *pwitem, 1.561 + SEC_PKCS12NicknameCollisionCallback ncCall, 1.562 + PK11SlotInfo *slot, 1.563 + void *wincx) 1.564 +{ 1.565 + SEC_PKCS12PFXItem *pfx; 1.566 + SEC_PKCS12AuthenticatedSafe *asafe; 1.567 + SEC_PKCS12SafeContents *safe_contents = NULL; 1.568 + SECStatus rv; 1.569 + 1.570 + if(!der_pfx || !pwitem || !slot) { 1.571 + return SECFailure; 1.572 + } 1.573 + 1.574 + /* decode and validate each section */ 1.575 + rv = SECFailure; 1.576 + 1.577 + pfx = sec_pkcs12_get_pfx(der_pfx, pwitem); 1.578 + if(pfx != NULL) { 1.579 + asafe = sec_pkcs12_get_auth_safe(pfx); 1.580 + if(asafe != NULL) { 1.581 + 1.582 + /* decrypt safe -- only if not empty */ 1.583 + if(asafe->emptySafe != PR_TRUE) { 1.584 + rv = sec_pkcs12_decrypt_auth_safe(asafe, pwitem, wincx); 1.585 + if(rv == SECSuccess) { 1.586 + safe_contents = sec_pkcs12_get_safe_contents(asafe); 1.587 + if(safe_contents == NULL) { 1.588 + rv = SECFailure; 1.589 + } 1.590 + } 1.591 + } else { 1.592 + safe_contents = sec_pkcs12_create_safe_contents(asafe->poolp); 1.593 + if(safe_contents == NULL) { 1.594 + rv = SECFailure; 1.595 + } else { 1.596 + safe_contents->swapUnicode = pfx->swapUnicode; 1.597 + rv = SECSuccess; 1.598 + } 1.599 + } 1.600 + 1.601 + /* get safe contents and begin import */ 1.602 + if(rv == SECSuccess) { 1.603 + SEC_PKCS12DecoderContext *p12dcx; 1.604 + 1.605 + p12dcx = sec_PKCS12ConvertOldSafeToNew(pfx->poolp, slot, 1.606 + pfx->swapUnicode, 1.607 + pwitem, wincx, safe_contents, 1.608 + &asafe->baggage); 1.609 + if(!p12dcx) { 1.610 + rv = SECFailure; 1.611 + goto loser; 1.612 + } 1.613 + 1.614 + if(SEC_PKCS12DecoderValidateBags(p12dcx, ncCall) 1.615 + != SECSuccess) { 1.616 + rv = SECFailure; 1.617 + goto loser; 1.618 + } 1.619 + 1.620 + rv = SEC_PKCS12DecoderImportBags(p12dcx); 1.621 + } 1.622 + 1.623 + } 1.624 + } 1.625 + 1.626 +loser: 1.627 + 1.628 + if(pfx) { 1.629 + SEC_PKCS12DestroyPFX(pfx); 1.630 + } 1.631 + 1.632 + return rv; 1.633 +} 1.634 + 1.635 +PRBool 1.636 +SEC_PKCS12ValidData(char *buf, int bufLen, long int totalLength) 1.637 +{ 1.638 + int lengthLength; 1.639 + 1.640 + PRBool valid = PR_FALSE; 1.641 + 1.642 + if(buf == NULL) { 1.643 + return PR_FALSE; 1.644 + } 1.645 + 1.646 + /* check for constructed sequence identifier tag */ 1.647 + if(*buf == (SEC_ASN1_CONSTRUCTED | SEC_ASN1_SEQUENCE)) { 1.648 + totalLength--; /* header byte taken care of */ 1.649 + buf++; 1.650 + 1.651 + lengthLength = (long int)SEC_ASN1LengthLength(totalLength - 1); 1.652 + if(totalLength > 0x7f) { 1.653 + lengthLength--; 1.654 + *buf &= 0x7f; /* remove bit 8 indicator */ 1.655 + if((*buf - (char)lengthLength) == 0) { 1.656 + valid = PR_TRUE; 1.657 + } 1.658 + } else { 1.659 + lengthLength--; 1.660 + if((*buf - (char)lengthLength) == 0) { 1.661 + valid = PR_TRUE; 1.662 + } 1.663 + } 1.664 + } 1.665 + 1.666 + return valid; 1.667 +}