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