Skip to content

Commit 9c304bd

Browse files
committed
PKCS12: check mismatch between hash algo and hash size
ZD#21457 (27)
1 parent 5ad6097 commit 9c304bd

3 files changed

Lines changed: 140 additions & 0 deletions

File tree

tests/api/test_pkcs12.c

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include <wolfcrypt/src/misc.c>
2929
#endif
3030

31+
#include <wolfssl/wolfcrypt/hmac.h>
3132
#include <wolfssl/wolfcrypt/pkcs12.h>
3233
#include <wolfssl/wolfcrypt/pwdbased.h>
3334
#include <wolfssl/wolfcrypt/types.h>
@@ -465,6 +466,137 @@ int test_wc_PKCS12_encrypted_content_bounds(void)
465466
return EXPECT_RESULT();
466467
}
467468

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];
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+
468600
int test_wc_PKCS12_PBKDF(void)
469601
{
470602
EXPECT_DECLS;

tests/api/test_pkcs12.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ int test_wc_PKCS12_create(void);
2929
int test_wc_d2i_PKCS12_bad_mac_salt(void);
3030
int test_wc_d2i_PKCS12_oid_underflow(void);
3131
int test_wc_PKCS12_encrypted_content_bounds(void);
32+
int test_wc_PKCS12_truncated_mac_bypass(void);
3233
int test_wc_PKCS12_PBKDF(void);
3334
int test_wc_PKCS12_PBKDF_ex(void);
3435
int test_wc_PKCS12_PBKDF_ex_sha1(void);
@@ -44,6 +45,7 @@ int test_wc_PKCS12_PBKDF_ex_sha512_256(void);
4445
TEST_DECL_GROUP("pkcs12", test_wc_d2i_PKCS12_bad_mac_salt), \
4546
TEST_DECL_GROUP("pkcs12", test_wc_d2i_PKCS12_oid_underflow), \
4647
TEST_DECL_GROUP("pkcs12", test_wc_PKCS12_encrypted_content_bounds), \
48+
TEST_DECL_GROUP("pkcs12", test_wc_PKCS12_truncated_mac_bypass), \
4749
TEST_DECL_GROUP("pkcs12", test_wc_PKCS12_PBKDF), \
4850
TEST_DECL_GROUP("pkcs12", test_wc_PKCS12_PBKDF_ex), \
4951
TEST_DECL_GROUP("pkcs12", test_wc_PKCS12_PBKDF_ex_sha1), \

wolfcrypt/src/pkcs12.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -633,6 +633,12 @@ static int wc_PKCS12_verify(WC_PKCS12* pkcs12, byte* data, word32 dataSz,
633633
return ret;
634634
}
635635

636+
if ((word32)ret != mac->digestSz) {
637+
WOLFSSL_MSG("PKCS12 MAC digest size mismatch");
638+
ForceZero(digest, sizeof(digest));
639+
return MAC_CMP_FAILED_E;
640+
}
641+
636642
#ifdef WOLFSSL_DEBUG_PKCS12
637643
{
638644
byte* p;

0 commit comments

Comments
 (0)