|
165 | 165 | #include <sys/uio.h> |
166 | 166 | #endif |
167 | 167 |
|
| 168 | +#ifdef HAVE_DILITHIUM |
| 169 | + #include <wolfssl/wolfcrypt/dilithium.h> |
| 170 | +#endif |
| 171 | +#if defined(WOLFSSL_HAVE_MLKEM) |
| 172 | + #include <wolfssl/wolfcrypt/mlkem.h> |
| 173 | +#endif |
| 174 | +#if defined(HAVE_PKCS7) |
| 175 | + #include <wolfssl/wolfcrypt/pkcs7.h> |
| 176 | +#endif |
| 177 | +#if !defined(NO_BIG_INT) |
| 178 | + #include <wolfssl/wolfcrypt/sp_int.h> |
| 179 | +#endif |
| 180 | + |
168 | 181 | /* include misc.c here regardless of NO_INLINE, because misc.c implementations |
169 | 182 | * have default (hidden) visibility, and in the absence of visibility, it's |
170 | 183 | * benign to mask out the library implementation. |
@@ -34758,6 +34771,47 @@ static int test_DhAgree_rejects_p_minus_1(void) |
34758 | 34771 | return EXPECT_RESULT(); |
34759 | 34772 | } |
34760 | 34773 |
|
| 34774 | + |
| 34775 | +/* ML-DSA HashML-DSA verify must reject hashLen > WC_MAX_DIGEST_SIZE */ |
| 34776 | +static int test_mldsa_verify_hash(void) |
| 34777 | +{ |
| 34778 | + EXPECT_DECLS; |
| 34779 | +#if defined(HAVE_DILITHIUM) && defined(WOLFSSL_WC_DILITHIUM) && \ |
| 34780 | + !defined(WOLFSSL_DILITHIUM_NO_MAKE_KEY) && \ |
| 34781 | + !defined(WOLFSSL_DILITHIUM_NO_VERIFY) |
| 34782 | + dilithium_key key; |
| 34783 | + WC_RNG rng; |
| 34784 | + int res = 0; |
| 34785 | + byte sig[4000]; |
| 34786 | + byte hash[4096]; /* larger than WC_MAX_DIGEST_SIZE */ |
| 34787 | + |
| 34788 | + XMEMSET(&key, 0, sizeof(key)); |
| 34789 | + XMEMSET(&rng, 0, sizeof(rng)); |
| 34790 | + XMEMSET(sig, 0x41, sizeof(sig)); |
| 34791 | + XMEMSET(hash, 'A', sizeof(hash)); |
| 34792 | + |
| 34793 | + ExpectIntEQ(wc_InitRng(&rng), 0); |
| 34794 | + ExpectIntEQ(wc_dilithium_init(&key), 0); |
| 34795 | +#ifndef WOLFSSL_NO_ML_DSA_65 |
| 34796 | + ExpectIntEQ(wc_dilithium_set_level(&key, WC_ML_DSA_65), 0); |
| 34797 | +#elif !defined(WOLFSSL_NO_ML_DSA_44) |
| 34798 | + ExpectIntEQ(wc_dilithium_set_level(&key, WC_ML_DSA_44), 0); |
| 34799 | +#else |
| 34800 | + ExpectIntEQ(wc_dilithium_set_level(&key, WC_ML_DSA_87), 0); |
| 34801 | +#endif |
| 34802 | + ExpectIntEQ(wc_dilithium_make_key(&key, &rng), 0); |
| 34803 | + |
| 34804 | + /* hashLen=4096 must be rejected, not overflow the stack */ |
| 34805 | + ExpectIntEQ(wc_dilithium_verify_ctx_hash(sig, sizeof(sig), NULL, 0, |
| 34806 | + WC_HASH_TYPE_SHA256, hash, sizeof(hash), &res, &key), |
| 34807 | + WC_NO_ERR_TRACE(BAD_LENGTH_E)); |
| 34808 | + |
| 34809 | + wc_dilithium_free(&key); |
| 34810 | + DoExpectIntEQ(wc_FreeRng(&rng), 0); |
| 34811 | +#endif |
| 34812 | + return EXPECT_RESULT(); |
| 34813 | +} |
| 34814 | + |
34761 | 34815 | /* Test: Ed448 must reject identity public key (0,1) */ |
34762 | 34816 | static int test_ed448_rejects_identity_key(void) |
34763 | 34817 | { |
@@ -34936,6 +34990,133 @@ static int test_pkcs7_ori_oversized_oid(void) |
34936 | 34990 | return EXPECT_RESULT(); |
34937 | 34991 | } |
34938 | 34992 |
|
| 34993 | +/* Dilithium verify_ctx_msg must reject absurdly large msgLen */ |
| 34994 | +static int test_dilithium_hash(void) |
| 34995 | +{ |
| 34996 | + EXPECT_DECLS; |
| 34997 | +#if defined(HAVE_DILITHIUM) && defined(WOLFSSL_WC_DILITHIUM) && \ |
| 34998 | + !defined(WOLFSSL_DILITHIUM_NO_MAKE_KEY) && \ |
| 34999 | + !defined(WOLFSSL_DILITHIUM_NO_VERIFY) |
| 35000 | + dilithium_key key; |
| 35001 | + WC_RNG rng; |
| 35002 | + int res = 0; |
| 35003 | + byte sig[4000]; |
| 35004 | + byte msg[64]; |
| 35005 | + |
| 35006 | + XMEMSET(&key, 0, sizeof(key)); |
| 35007 | + XMEMSET(&rng, 0, sizeof(rng)); |
| 35008 | + XMEMSET(sig, 0, sizeof(sig)); |
| 35009 | + XMEMSET(msg, 'A', sizeof(msg)); |
| 35010 | + |
| 35011 | + ExpectIntEQ(wc_InitRng(&rng), 0); |
| 35012 | + ExpectIntEQ(wc_dilithium_init(&key), 0); |
| 35013 | +#ifndef WOLFSSL_NO_ML_DSA_65 |
| 35014 | + ExpectIntEQ(wc_dilithium_set_level(&key, WC_ML_DSA_65), 0); |
| 35015 | +#elif !defined(WOLFSSL_NO_ML_DSA_44) |
| 35016 | + ExpectIntEQ(wc_dilithium_set_level(&key, WC_ML_DSA_44), 0); |
| 35017 | +#else |
| 35018 | + ExpectIntEQ(wc_dilithium_set_level(&key, WC_ML_DSA_87), 0); |
| 35019 | +#endif |
| 35020 | + ExpectIntEQ(wc_dilithium_make_key(&key, &rng), 0); |
| 35021 | + |
| 35022 | + ExpectIntEQ(wc_dilithium_verify_ctx_msg(sig, sizeof(sig), NULL, 0, |
| 35023 | + msg, 0xFFFFFFC0, &res, &key), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); |
| 35024 | + |
| 35025 | + wc_dilithium_free(&key); |
| 35026 | + DoExpectIntEQ(wc_FreeRng(&rng), 0); |
| 35027 | +#endif |
| 35028 | + return EXPECT_RESULT(); |
| 35029 | +} |
| 35030 | + |
| 35031 | +/* PKCS7 CBC must validate all padding bytes */ |
| 35032 | +static int test_pkcs7_padding(void) |
| 35033 | +{ |
| 35034 | + EXPECT_DECLS; |
| 35035 | +#if defined(HAVE_PKCS7) && !defined(NO_AES) && defined(HAVE_AES_CBC) && \ |
| 35036 | + defined(WOLFSSL_AES_256) && !defined(NO_PKCS7_ENCRYPTED_DATA) |
| 35037 | + PKCS7 pkcs7; |
| 35038 | + byte key[32]; |
| 35039 | + byte plaintext[27]; /* 27 bytes -> padded to 32 -> padding = 05 05 05 05 05 */ |
| 35040 | + byte encoded[4096]; |
| 35041 | + byte output[256]; |
| 35042 | + byte modified[4096]; |
| 35043 | + int encodedSz = 0; |
| 35044 | + int outSz; |
| 35045 | + int ctOff = -1; |
| 35046 | + int ctLen = 0; |
| 35047 | + int i; |
| 35048 | + |
| 35049 | + XMEMSET(key, 0xAA, sizeof(key)); |
| 35050 | + XMEMSET(plaintext, 'X', sizeof(plaintext)); |
| 35051 | + |
| 35052 | + /* Encode EncryptedData */ |
| 35053 | + XMEMSET(&pkcs7, 0, sizeof(pkcs7)); |
| 35054 | + ExpectIntEQ(wc_PKCS7_Init(&pkcs7, NULL, 0), 0); |
| 35055 | + pkcs7.content = plaintext; |
| 35056 | + pkcs7.contentSz = sizeof(plaintext); |
| 35057 | + pkcs7.contentOID = DATA; |
| 35058 | + pkcs7.encryptOID = AES256CBCb; |
| 35059 | + pkcs7.encryptionKey = key; |
| 35060 | + pkcs7.encryptionKeySz = sizeof(key); |
| 35061 | + |
| 35062 | + ExpectIntGT(encodedSz = wc_PKCS7_EncodeEncryptedData(&pkcs7, encoded, |
| 35063 | + sizeof(encoded)), 0); |
| 35064 | + |
| 35065 | + /* Verify normal decrypt works */ |
| 35066 | + ExpectIntEQ(outSz = wc_PKCS7_DecodeEncryptedData(&pkcs7, encoded, |
| 35067 | + (word32)encodedSz, output, sizeof(output)), (int)sizeof(plaintext)); |
| 35068 | + wc_PKCS7_Free(&pkcs7); |
| 35069 | + |
| 35070 | + /* Find ciphertext block in encoded DER */ |
| 35071 | + if (EXPECT_SUCCESS()) { |
| 35072 | + for (i = encodedSz - 10; i > 10; i--) { |
| 35073 | + if (encoded[i] == 0x04 || encoded[i] == 0x80) { |
| 35074 | + int len, lbytes; |
| 35075 | + |
| 35076 | + if (encoded[i+1] < 0x80) { |
| 35077 | + len = encoded[i+1]; lbytes = 1; |
| 35078 | + } |
| 35079 | + else if (encoded[i+1] == 0x81) { |
| 35080 | + len = encoded[i+2]; lbytes = 2; |
| 35081 | + } |
| 35082 | + else { |
| 35083 | + continue; |
| 35084 | + } |
| 35085 | + if (len > 0 && len % 16 == 0 && |
| 35086 | + i + 1 + lbytes + len <= encodedSz) { |
| 35087 | + ctOff = i + 1 + lbytes; |
| 35088 | + ctLen = len; |
| 35089 | + break; |
| 35090 | + } |
| 35091 | + } |
| 35092 | + } |
| 35093 | + } |
| 35094 | + ExpectIntGT(ctOff, 0); |
| 35095 | + ExpectIntGE(ctLen, 32); |
| 35096 | + |
| 35097 | + /* Corrupt an interior padding byte via CBC bit-flip */ |
| 35098 | + if (EXPECT_SUCCESS()) { |
| 35099 | + XMEMCPY(modified, encoded, (size_t)encodedSz); |
| 35100 | + /* Flip byte in penultimate block to corrupt interior padding */ |
| 35101 | + modified[ctOff + ctLen - 32 + 11] ^= 0x42; |
| 35102 | + |
| 35103 | + /* Decrypt modified ciphertext - must fail, not succeed */ |
| 35104 | + XMEMSET(&pkcs7, 0, sizeof(pkcs7)); |
| 35105 | + ExpectIntEQ(wc_PKCS7_Init(&pkcs7, NULL, 0), 0); |
| 35106 | + pkcs7.encryptionKey = key; |
| 35107 | + pkcs7.encryptionKeySz = sizeof(key); |
| 35108 | + |
| 35109 | + outSz = wc_PKCS7_DecodeEncryptedData(&pkcs7, modified, |
| 35110 | + (word32)encodedSz, output, sizeof(output)); |
| 35111 | + /* Must return an error - if it returns plaintext size, padding |
| 35112 | + * oracle vulnerability exists */ |
| 35113 | + ExpectIntLT(outSz, 0); |
| 35114 | + wc_PKCS7_Free(&pkcs7); |
| 35115 | + } |
| 35116 | +#endif |
| 35117 | + return EXPECT_RESULT(); |
| 35118 | +} |
| 35119 | + |
34939 | 35120 | TEST_CASE testCases[] = { |
34940 | 35121 | TEST_DECL(test_fileAccess), |
34941 | 35122 |
|
@@ -35754,11 +35935,14 @@ TEST_CASE testCases[] = { |
35754 | 35935 | TEST_DECL(test_ed448_rejects_identity_key), |
35755 | 35936 | TEST_DECL(test_pkcs7_decode_encrypted_outputsz), |
35756 | 35937 | TEST_DECL(test_pkcs7_ori_oversized_oid), |
| 35938 | + TEST_DECL(test_pkcs7_padding), |
35757 | 35939 |
|
35758 | 35940 | #if defined(WOLFSSL_SNIFFER) && defined(WOLFSSL_SNIFFER_CHAIN_INPUT) |
35759 | 35941 | TEST_DECL(test_sniffer_chain_input_overflow), |
35760 | 35942 | #endif |
35761 | 35943 |
|
| 35944 | + TEST_DECL(test_mldsa_verify_hash), |
| 35945 | + TEST_DECL(test_dilithium_hash), |
35762 | 35946 | /* This test needs to stay at the end to clean up any caches allocated. */ |
35763 | 35947 | TEST_DECL(test_wolfSSL_Cleanup) |
35764 | 35948 | }; |
|
0 commit comments