|
28 | 28 | #include <wolfcrypt/src/misc.c> |
29 | 29 | #endif |
30 | 30 |
|
| 31 | +#include <wolfssl/wolfcrypt/hmac.h> |
31 | 32 | #include <wolfssl/wolfcrypt/pkcs12.h> |
32 | 33 | #include <wolfssl/wolfcrypt/pwdbased.h> |
33 | 34 | #include <wolfssl/wolfcrypt/types.h> |
@@ -465,6 +466,137 @@ int test_wc_PKCS12_encrypted_content_bounds(void) |
465 | 466 | return EXPECT_RESULT(); |
466 | 467 | } |
467 | 468 |
|
| 469 | +/* Test that a crafted PKCS12 with a MAC OCTET STRING shorter than the |
| 470 | + * algorithm's native digest size is rejected, rather than allowing the |
| 471 | + * integrity check to be truncated to a brute-forceable length. */ |
| 472 | +int test_wc_PKCS12_truncated_mac_bypass(void) |
| 473 | +{ |
| 474 | + EXPECT_DECLS; |
| 475 | +#if !defined(NO_ASN) && !defined(NO_PWDBASED) && defined(HAVE_PKCS12) \ |
| 476 | + && !defined(NO_HMAC) && !defined(NO_SHA256) |
| 477 | + static const byte authSafe[] = { 0x30, 0x00 }; /* empty SEQUENCE OF CI */ |
| 478 | + static const char password[] = "wolfSSL test"; |
| 479 | + static const byte salt[8] = { |
| 480 | + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 |
| 481 | + }; |
| 482 | + const int iter = 1; |
| 483 | + const word32 pwLen = (word32)(sizeof(password) - 1); |
| 484 | + |
| 485 | + byte unicodePw[2 * sizeof(password) + 2]; |
| 486 | + int unicodePwLen = 0; |
| 487 | + byte macKey[WC_SHA256_DIGEST_SIZE]; |
| 488 | + byte fullMac[WC_SHA256_DIGEST_SIZE] = {0}; |
| 489 | + Hmac hmac; |
| 490 | + int hmacInited = 0; |
| 491 | + word32 i; |
| 492 | + |
| 493 | + WC_PKCS12* pkcs12 = NULL; |
| 494 | + byte pfx[64]; |
| 495 | + word32 pfxLen = 0; |
| 496 | + |
| 497 | + /* BMPString-style password (UTF-16BE) with trailing 0x00 0x00, matching |
| 498 | + * the unicode conversion done internally by wc_PKCS12_create_mac. */ |
| 499 | + for (i = 0; i < pwLen; i++) { |
| 500 | + unicodePw[unicodePwLen++] = 0x00; |
| 501 | + unicodePw[unicodePwLen++] = (byte)password[i]; |
| 502 | + } |
| 503 | + unicodePw[unicodePwLen++] = 0x00; |
| 504 | + unicodePw[unicodePwLen++] = 0x00; |
| 505 | + |
| 506 | + /* Derive the MAC key the same way wc_PKCS12_create_mac does: |
| 507 | + * PKCS12-PBKDF SHA-256, id=3 (MAC key), kLen=32. */ |
| 508 | + ExpectIntEQ(wc_PKCS12_PBKDF_ex(macKey, unicodePw, unicodePwLen, |
| 509 | + salt, (int)sizeof(salt), |
| 510 | + iter, WC_SHA256_DIGEST_SIZE, |
| 511 | + WC_SHA256, 3 /* id = MAC */, NULL), |
| 512 | + 0); |
| 513 | + |
| 514 | + /* Compute the genuine HMAC-SHA256 over the authSafe content. */ |
| 515 | + ExpectIntEQ(wc_HmacInit(&hmac, NULL, INVALID_DEVID), 0); |
| 516 | + if (EXPECT_SUCCESS()) |
| 517 | + hmacInited = 1; |
| 518 | + ExpectIntEQ(wc_HmacSetKey(&hmac, WC_SHA256, macKey, sizeof(macKey)), 0); |
| 519 | + ExpectIntEQ(wc_HmacUpdate(&hmac, authSafe, (word32)sizeof(authSafe)), 0); |
| 520 | + ExpectIntEQ(wc_HmacFinal(&hmac, fullMac), 0); |
| 521 | + if (hmacInited) |
| 522 | + wc_HmacFree(&hmac); |
| 523 | + |
| 524 | + /* |
| 525 | + * Build a 59-byte PFX with a 1-byte truncated digest equal to fullMac[0]: |
| 526 | + * |
| 527 | + * 30 39 PFX SEQUENCE (57) |
| 528 | + * 02 01 03 version = 3 |
| 529 | + * 30 11 AuthSafe ContentInfo (17) |
| 530 | + * 06 09 2A 86 48 86 F7 0D 01 07 01 OID 1.2.840.113549.1.7.1 (data) |
| 531 | + * A0 04 [0] EXPLICIT (4) |
| 532 | + * 04 02 OCTET STRING (2) |
| 533 | + * 30 00 authSafe = empty SEQUENCE |
| 534 | + * 30 21 MacData (33) |
| 535 | + * 30 12 DigestInfo (18) |
| 536 | + * 30 0d AlgorithmIdentifier (13) |
| 537 | + * 06 09 60 86 48 01 65 03 04 02 01 OID SHA-256 |
| 538 | + * 05 00 NULL |
| 539 | + * 04 01 XX OCTET STRING (1) |
| 540 | + * 04 08 01 02 03 04 05 06 07 08 salt |
| 541 | + * 02 01 01 iterations = 1 |
| 542 | + */ |
| 543 | + pfx[pfxLen++] = 0x30; pfx[pfxLen++] = 0x39; |
| 544 | + pfx[pfxLen++] = 0x02; pfx[pfxLen++] = 0x01; pfx[pfxLen++] = 0x03; |
| 545 | + pfx[pfxLen++] = 0x30; pfx[pfxLen++] = 0x11; |
| 546 | + pfx[pfxLen++] = 0x06; pfx[pfxLen++] = 0x09; |
| 547 | + pfx[pfxLen++] = 0x2A; pfx[pfxLen++] = 0x86; pfx[pfxLen++] = 0x48; |
| 548 | + pfx[pfxLen++] = 0x86; pfx[pfxLen++] = 0xF7; pfx[pfxLen++] = 0x0D; |
| 549 | + pfx[pfxLen++] = 0x01; pfx[pfxLen++] = 0x07; pfx[pfxLen++] = 0x01; |
| 550 | + pfx[pfxLen++] = 0xA0; pfx[pfxLen++] = 0x04; |
| 551 | + pfx[pfxLen++] = 0x04; pfx[pfxLen++] = 0x02; |
| 552 | + pfx[pfxLen++] = 0x30; pfx[pfxLen++] = 0x00; |
| 553 | + pfx[pfxLen++] = 0x30; pfx[pfxLen++] = 0x21; |
| 554 | + pfx[pfxLen++] = 0x30; pfx[pfxLen++] = 0x12; |
| 555 | + pfx[pfxLen++] = 0x30; pfx[pfxLen++] = 0x0D; |
| 556 | + pfx[pfxLen++] = 0x06; pfx[pfxLen++] = 0x09; |
| 557 | + pfx[pfxLen++] = 0x60; pfx[pfxLen++] = 0x86; pfx[pfxLen++] = 0x48; |
| 558 | + pfx[pfxLen++] = 0x01; pfx[pfxLen++] = 0x65; pfx[pfxLen++] = 0x03; |
| 559 | + pfx[pfxLen++] = 0x04; pfx[pfxLen++] = 0x02; pfx[pfxLen++] = 0x01; |
| 560 | + pfx[pfxLen++] = 0x05; pfx[pfxLen++] = 0x00; |
| 561 | + pfx[pfxLen++] = 0x04; pfx[pfxLen++] = 0x01; |
| 562 | + pfx[pfxLen++] = fullMac[0]; |
| 563 | + pfx[pfxLen++] = 0x04; pfx[pfxLen++] = 0x08; |
| 564 | + pfx[pfxLen++] = 0x01; pfx[pfxLen++] = 0x02; pfx[pfxLen++] = 0x03; |
| 565 | + pfx[pfxLen++] = 0x04; pfx[pfxLen++] = 0x05; pfx[pfxLen++] = 0x06; |
| 566 | + pfx[pfxLen++] = 0x07; pfx[pfxLen++] = 0x08; |
| 567 | + pfx[pfxLen++] = 0x02; pfx[pfxLen++] = 0x01; pfx[pfxLen++] = 0x01; |
| 568 | + |
| 569 | + { |
| 570 | + byte* parsedPkey = NULL; |
| 571 | + word32 parsedPkeySz = 0; |
| 572 | + byte* parsedCert = NULL; |
| 573 | + word32 parsedCertSz = 0; |
| 574 | + int d2iRet; |
| 575 | + |
| 576 | + ExpectNotNull(pkcs12 = wc_PKCS12_new()); |
| 577 | + |
| 578 | + /* Accept rejection at either parse time (wc_d2i_PKCS12) or |
| 579 | + * verify time (wc_PKCS12_parse); the test fails only if both |
| 580 | + * succeed. */ |
| 581 | + d2iRet = wc_d2i_PKCS12(pfx, pfxLen, pkcs12); |
| 582 | + if (d2iRet == 0) { |
| 583 | + ExpectIntNE(wc_PKCS12_parse(pkcs12, password, |
| 584 | + &parsedPkey, &parsedPkeySz, |
| 585 | + &parsedCert, &parsedCertSz, NULL), |
| 586 | + 0); |
| 587 | + } |
| 588 | + else { |
| 589 | + ExpectIntNE(d2iRet, 0); |
| 590 | + } |
| 591 | + |
| 592 | + XFREE(parsedPkey, NULL, DYNAMIC_TYPE_PUBLIC_KEY); |
| 593 | + XFREE(parsedCert, NULL, DYNAMIC_TYPE_PKCS); |
| 594 | + wc_PKCS12_free(pkcs12); |
| 595 | + } |
| 596 | +#endif |
| 597 | + return EXPECT_RESULT(); |
| 598 | +} |
| 599 | + |
468 | 600 | int test_wc_PKCS12_PBKDF(void) |
469 | 601 | { |
470 | 602 | EXPECT_DECLS; |
|
0 commit comments