@@ -1118,6 +1118,229 @@ int test_wc_PKCS7_EnvelopedData_KTRI_RSA_PSS(void)
11181118#endif
11191119
11201120
1121+ /*
1122+ * Bleichenbacher padding-oracle regression: wc_PKCS7_DecryptKtri must not
1123+ * return a distinguishable error when RSA PKCS#1 v1.5 unwrap of the
1124+ * encrypted CEK fails vs. when it succeeds with a wrong key. The
1125+ * mitigation substitutes a deterministic pseudo-random CEK on RSA failure
1126+ * so content decryption fails indistinguishably. This test corrupts the
1127+ * encryptedKey in a valid EnvelopedData and asserts the error matches
1128+ * content corruption rather than surfacing an RSA/recipient-level code.
1129+ * Runs for AES-128 and AES-256 because the fake CEK is a fixed 32 bytes:
1130+ * AES-128 (key size 16) exercises the path where the fake size differs
1131+ * from the real CEK size.
1132+ */
1133+ #if defined(HAVE_PKCS7 ) && !defined(NO_RSA ) && !defined(NO_SHA256 ) && \
1134+ !defined(NO_AES ) && defined(HAVE_AES_CBC ) && defined(WOLFSSL_AES_128 ) && \
1135+ defined(WOLFSSL_AES_256 ) && !defined(NO_HMAC ) && \
1136+ !defined(WOLFSSL_NO_MALLOC ) && \
1137+ (defined(USE_CERT_BUFFERS_2048 ) || defined(USE_CERT_BUFFERS_1024 ) || \
1138+ !defined(NO_FILESYSTEM ))
1139+ static int pkcs7_ktri_bad_pad_case (int encryptOID , byte * rsaCert ,
1140+ word32 rsaCertSz , byte * rsaPrivKey ,
1141+ word32 rsaPrivKeySz , byte * encrypted ,
1142+ word32 encryptedCap , byte * decoded ,
1143+ word32 decodedCap )
1144+ {
1145+ EXPECT_DECLS ;
1146+ PKCS7 * pkcs7 = NULL ;
1147+ byte data [] = "PKCS7 KTRI bad-RSA-padding regression payload." ;
1148+ int encryptedSz = 0 ;
1149+ int badKeyRet = 0 ;
1150+ int badContentRet = 0 ;
1151+ byte savedKeyByte = 0 ;
1152+ byte savedContentByte = 0 ;
1153+ word32 i ;
1154+ word32 encryptedKeyOff = 0 ;
1155+ static const byte rsaEncOid [] = {
1156+ 0x06 , 0x09 , 0x2A , 0x86 , 0x48 , 0x86 , 0xF7 , 0x0D ,
1157+ 0x01 , 0x01 , 0x01
1158+ };
1159+
1160+ ExpectNotNull (pkcs7 = wc_PKCS7_New (HEAP_HINT , testDevId ));
1161+ ExpectIntEQ (wc_PKCS7_InitWithCert (pkcs7 , rsaCert , rsaCertSz ), 0 );
1162+ if (pkcs7 != NULL ) {
1163+ pkcs7 -> content = data ;
1164+ pkcs7 -> contentSz = (word32 )sizeof (data );
1165+ pkcs7 -> contentOID = DATA ;
1166+ pkcs7 -> encryptOID = encryptOID ;
1167+ }
1168+ ExpectIntGT (encryptedSz = wc_PKCS7_EncodeEnvelopedData (pkcs7 ,
1169+ encrypted , encryptedCap ), 0 );
1170+ wc_PKCS7_Free (pkcs7 );
1171+ pkcs7 = NULL ;
1172+
1173+ /* Locate the KTRI encryptedKey OCTET STRING. After the rsaEncryption
1174+ * OID there are NULL algorithm parameters (05 00), then a 256-byte
1175+ * OCTET STRING (tag 04, long-form length 82 01 00 for RSA-2048). */
1176+ for (i = 0 ; (int )(i + sizeof (rsaEncOid )) < encryptedSz ; i ++ ) {
1177+ if (XMEMCMP (& encrypted [i ], rsaEncOid , sizeof (rsaEncOid )) == 0 ) {
1178+ word32 p = i + (word32 )sizeof (rsaEncOid );
1179+ if (p + 2 < (word32 )encryptedSz &&
1180+ encrypted [p ] == 0x05 && encrypted [p + 1 ] == 0x00 ) {
1181+ p += 2 ;
1182+ }
1183+ if (p + 4 < (word32 )encryptedSz && encrypted [p ] == 0x04 ) {
1184+ if (encrypted [p + 1 ] == 0x82 ) {
1185+ encryptedKeyOff = p + 4 ;
1186+ }
1187+ else if (encrypted [p + 1 ] == 0x81 ) {
1188+ encryptedKeyOff = p + 3 ;
1189+ }
1190+ else {
1191+ encryptedKeyOff = p + 2 ;
1192+ }
1193+ }
1194+ break ;
1195+ }
1196+ }
1197+ ExpectIntGT (encryptedKeyOff , 0 );
1198+ ExpectIntLT (encryptedKeyOff + 32 , (word32 )encryptedSz );
1199+
1200+ /* Case 1: corrupt a byte inside the RSA ciphertext, decode, restore. */
1201+ savedKeyByte = encrypted [encryptedKeyOff + 16 ];
1202+ encrypted [encryptedKeyOff + 16 ] ^= 0xA5 ;
1203+
1204+ ExpectNotNull (pkcs7 = wc_PKCS7_New (HEAP_HINT , testDevId ));
1205+ ExpectIntEQ (wc_PKCS7_InitWithCert (pkcs7 , rsaCert , rsaCertSz ), 0 );
1206+ if (pkcs7 != NULL ) {
1207+ pkcs7 -> privateKey = rsaPrivKey ;
1208+ pkcs7 -> privateKeySz = rsaPrivKeySz ;
1209+ }
1210+ badKeyRet = wc_PKCS7_DecodeEnvelopedData (pkcs7 , encrypted ,
1211+ (word32 )encryptedSz , decoded , decodedCap );
1212+ wc_PKCS7_Free (pkcs7 );
1213+ pkcs7 = NULL ;
1214+ encrypted [encryptedKeyOff + 16 ] = savedKeyByte ;
1215+
1216+ /* Case 2: corrupt a byte in the second-to-last AES ciphertext block.
1217+ * In CBC mode this deterministically XOR-flips the corresponding byte
1218+ * in the last plaintext block, invalidating the PKCS#7 padding
1219+ * (original pad byte 0x01 becomes 0x01^0xA5 = 0xA4 > blockSz).
1220+ * Corrupting the last ciphertext block directly would randomize the
1221+ * entire last plaintext block, giving ~1/256 chance of accidentally
1222+ * valid padding and intermittent test failures. */
1223+ savedContentByte = encrypted [encryptedSz - 17 ];
1224+ encrypted [encryptedSz - 17 ] ^= 0xA5 ;
1225+
1226+ ExpectNotNull (pkcs7 = wc_PKCS7_New (HEAP_HINT , testDevId ));
1227+ ExpectIntEQ (wc_PKCS7_InitWithCert (pkcs7 , rsaCert , rsaCertSz ), 0 );
1228+ if (pkcs7 != NULL ) {
1229+ pkcs7 -> privateKey = rsaPrivKey ;
1230+ pkcs7 -> privateKeySz = rsaPrivKeySz ;
1231+ }
1232+ badContentRet = wc_PKCS7_DecodeEnvelopedData (pkcs7 , encrypted ,
1233+ (word32 )encryptedSz , decoded , decodedCap );
1234+ wc_PKCS7_Free (pkcs7 );
1235+ pkcs7 = NULL ;
1236+ encrypted [encryptedSz - 17 ] = savedContentByte ;
1237+
1238+ /* Case 2 must always fail: the CBC-chain corruption deterministically
1239+ * invalidates the PKCS#7 padding. */
1240+ ExpectIntLT (badContentRet , 0 );
1241+ /* Bad-key must NOT leak as an RSA- or recipient-level error. */
1242+ ExpectIntNE (badKeyRet , WC_NO_ERR_TRACE (PKCS7_RECIP_E ));
1243+ ExpectIntNE (badKeyRet , WC_NO_ERR_TRACE (RSA_PAD_E ));
1244+ ExpectIntNE (badKeyRet , WC_NO_ERR_TRACE (RSA_BUFFER_E ));
1245+ ExpectIntNE (badKeyRet , WC_NO_ERR_TRACE (BAD_PADDING_E ));
1246+ /* Case 1 (bad RSA key) decrypts content with a random fake CEK,
1247+ * producing fully random plaintext. With ~1/256 probability the
1248+ * PKCS#7 padding accidentally looks valid, causing a positive
1249+ * garbage-length return instead of an error. This does not leak
1250+ * RSA key information, so it is acceptable. When both cases do
1251+ * fail, verify they fail at the same content-decryption layer. */
1252+ if (badKeyRet < 0 ) {
1253+ ExpectIntEQ (badKeyRet , badContentRet );
1254+ }
1255+
1256+ return EXPECT_RESULT ();
1257+ }
1258+
1259+ int test_wc_PKCS7_EnvelopedData_KTRI_BadRsaPad (void )
1260+ {
1261+ EXPECT_DECLS ;
1262+ byte encrypted [FOURK_BUF ];
1263+ byte decoded [FOURK_BUF ];
1264+ byte * rsaCert = NULL ;
1265+ byte * rsaPrivKey = NULL ;
1266+ word32 rsaCertSz = 0 ;
1267+ word32 rsaPrivKeySz = 0 ;
1268+ #if !defined(USE_CERT_BUFFERS_1024 ) && !defined(USE_CERT_BUFFERS_2048 ) && \
1269+ !defined(NO_FILESYSTEM )
1270+ XFILE f = XBADFILE ;
1271+ #endif
1272+
1273+ /* Load RSA cert and key */
1274+ #if defined(USE_CERT_BUFFERS_1024 )
1275+ rsaCertSz = (word32 )sizeof_client_cert_der_1024 ;
1276+ ExpectNotNull (rsaCert = (byte * )XMALLOC (rsaCertSz , HEAP_HINT ,
1277+ DYNAMIC_TYPE_TMP_BUFFER ));
1278+ if (rsaCert != NULL )
1279+ XMEMCPY (rsaCert , client_cert_der_1024 , rsaCertSz );
1280+ rsaPrivKeySz = (word32 )sizeof_client_key_der_1024 ;
1281+ ExpectNotNull (rsaPrivKey = (byte * )XMALLOC (rsaPrivKeySz , HEAP_HINT ,
1282+ DYNAMIC_TYPE_TMP_BUFFER ));
1283+ if (rsaPrivKey != NULL )
1284+ XMEMCPY (rsaPrivKey , client_key_der_1024 , rsaPrivKeySz );
1285+ #elif defined(USE_CERT_BUFFERS_2048 )
1286+ rsaCertSz = (word32 )sizeof_client_cert_der_2048 ;
1287+ ExpectNotNull (rsaCert = (byte * )XMALLOC (rsaCertSz , HEAP_HINT ,
1288+ DYNAMIC_TYPE_TMP_BUFFER ));
1289+ if (rsaCert != NULL )
1290+ XMEMCPY (rsaCert , client_cert_der_2048 , rsaCertSz );
1291+ rsaPrivKeySz = (word32 )sizeof_client_key_der_2048 ;
1292+ ExpectNotNull (rsaPrivKey = (byte * )XMALLOC (rsaPrivKeySz , HEAP_HINT ,
1293+ DYNAMIC_TYPE_TMP_BUFFER ));
1294+ if (rsaPrivKey != NULL )
1295+ XMEMCPY (rsaPrivKey , client_key_der_2048 , rsaPrivKeySz );
1296+ #elif !defined(NO_FILESYSTEM )
1297+ rsaCertSz = FOURK_BUF ;
1298+ ExpectNotNull (rsaCert = (byte * )XMALLOC (rsaCertSz , HEAP_HINT ,
1299+ DYNAMIC_TYPE_TMP_BUFFER ));
1300+ ExpectTrue ((f = XFOPEN ("./certs/client-cert.der" , "rb" )) != XBADFILE );
1301+ ExpectTrue ((rsaCertSz = (word32 )XFREAD (rsaCert , 1 , rsaCertSz , f )) > 0 );
1302+ if (f != XBADFILE ) {
1303+ XFCLOSE (f );
1304+ f = XBADFILE ;
1305+ }
1306+ rsaPrivKeySz = FOURK_BUF ;
1307+ ExpectNotNull (rsaPrivKey = (byte * )XMALLOC (rsaPrivKeySz , HEAP_HINT ,
1308+ DYNAMIC_TYPE_TMP_BUFFER ));
1309+ ExpectTrue ((f = XFOPEN ("./certs/client-key.der" , "rb" )) != XBADFILE );
1310+ ExpectTrue ((rsaPrivKeySz = (word32 )XFREAD (rsaPrivKey , 1 ,
1311+ rsaPrivKeySz , f )) > 0 );
1312+ if (f != XBADFILE )
1313+ XFCLOSE (f );
1314+ #endif
1315+
1316+ if (rsaCert == NULL || rsaPrivKey == NULL ) {
1317+ XFREE (rsaCert , HEAP_HINT , DYNAMIC_TYPE_TMP_BUFFER );
1318+ XFREE (rsaPrivKey , HEAP_HINT , DYNAMIC_TYPE_TMP_BUFFER );
1319+ return TEST_SKIPPED ;
1320+ }
1321+
1322+ /* AES-128: 32-byte fake CEK larger than real CEK size (16 bytes). */
1323+ ExpectIntEQ (pkcs7_ktri_bad_pad_case (AES128CBCb , rsaCert , rsaCertSz ,
1324+ rsaPrivKey , rsaPrivKeySz , encrypted , sizeof (encrypted ),
1325+ decoded , sizeof (decoded )), TEST_SUCCESS );
1326+ #ifdef WOLFSSL_AES_192
1327+ /* AES-192: fake CEK (32) vs real CEK (24) - another size mismatch. */
1328+ ExpectIntEQ (pkcs7_ktri_bad_pad_case (AES192CBCb , rsaCert , rsaCertSz ,
1329+ rsaPrivKey , rsaPrivKeySz , encrypted , sizeof (encrypted ),
1330+ decoded , sizeof (decoded )), TEST_SUCCESS );
1331+ #endif
1332+ /* AES-256: fake CEK size matches real CEK size (32 bytes). */
1333+ ExpectIntEQ (pkcs7_ktri_bad_pad_case (AES256CBCb , rsaCert , rsaCertSz ,
1334+ rsaPrivKey , rsaPrivKeySz , encrypted , sizeof (encrypted ),
1335+ decoded , sizeof (decoded )), TEST_SUCCESS );
1336+
1337+ XFREE (rsaCert , HEAP_HINT , DYNAMIC_TYPE_TMP_BUFFER );
1338+ XFREE (rsaPrivKey , HEAP_HINT , DYNAMIC_TYPE_TMP_BUFFER );
1339+ return EXPECT_RESULT ();
1340+ } /* END test_wc_PKCS7_EnvelopedData_KTRI_BadRsaPad */
1341+ #endif
1342+
1343+
11211344/*
11221345 * Testing wc_PKCS7_EncodeSignedData_ex() and wc_PKCS7_VerifySignedData_ex()
11231346 */
0 commit comments