security/nss/lib/pkcs12/p12dec.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial