@@ -1118,6 +1118,219 @@ 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 the last byte of the content, decode, restore. */
1217+ savedContentByte = encrypted [encryptedSz - 1 ];
1218+ encrypted [encryptedSz - 1 ] ^= 0xA5 ;
1219+
1220+ ExpectNotNull (pkcs7 = wc_PKCS7_New (HEAP_HINT , testDevId ));
1221+ ExpectIntEQ (wc_PKCS7_InitWithCert (pkcs7 , rsaCert , rsaCertSz ), 0 );
1222+ if (pkcs7 != NULL ) {
1223+ pkcs7 -> privateKey = rsaPrivKey ;
1224+ pkcs7 -> privateKeySz = rsaPrivKeySz ;
1225+ }
1226+ badContentRet = wc_PKCS7_DecodeEnvelopedData (pkcs7 , encrypted ,
1227+ (word32 )encryptedSz , decoded , decodedCap );
1228+ wc_PKCS7_Free (pkcs7 );
1229+ pkcs7 = NULL ;
1230+ encrypted [encryptedSz - 1 ] = savedContentByte ;
1231+
1232+ /* Both must fail. */
1233+ ExpectIntLT (badKeyRet , 0 );
1234+ ExpectIntLT (badContentRet , 0 );
1235+ /* Bad-key must NOT leak as an RSA- or recipient-level error. */
1236+ ExpectIntNE (badKeyRet , WC_NO_ERR_TRACE (PKCS7_RECIP_E ));
1237+ ExpectIntNE (badKeyRet , WC_NO_ERR_TRACE (RSA_PAD_E ));
1238+ ExpectIntNE (badKeyRet , WC_NO_ERR_TRACE (RSA_BUFFER_E ));
1239+ ExpectIntNE (badKeyRet , WC_NO_ERR_TRACE (BAD_PADDING_E ));
1240+ /* Both corruption paths should fail at the same content layer.
1241+ * Note: this validates error-code indistinguishability only, not
1242+ * timing indistinguishability, which would require statistical
1243+ * measurement of execution time. */
1244+ ExpectIntEQ (badKeyRet , badContentRet );
1245+
1246+ return EXPECT_RESULT ();
1247+ }
1248+
1249+ int test_wc_PKCS7_EnvelopedData_KTRI_BadRsaPad (void )
1250+ {
1251+ EXPECT_DECLS ;
1252+ byte encrypted [FOURK_BUF ];
1253+ byte decoded [FOURK_BUF ];
1254+ byte * rsaCert = NULL ;
1255+ byte * rsaPrivKey = NULL ;
1256+ word32 rsaCertSz = 0 ;
1257+ word32 rsaPrivKeySz = 0 ;
1258+ #if !defined(USE_CERT_BUFFERS_1024 ) && !defined(USE_CERT_BUFFERS_2048 ) && \
1259+ !defined(NO_FILESYSTEM )
1260+ XFILE f = XBADFILE ;
1261+ #endif
1262+
1263+ /* Load RSA cert and key */
1264+ #if defined(USE_CERT_BUFFERS_1024 )
1265+ rsaCertSz = (word32 )sizeof_client_cert_der_1024 ;
1266+ ExpectNotNull (rsaCert = (byte * )XMALLOC (rsaCertSz , HEAP_HINT ,
1267+ DYNAMIC_TYPE_TMP_BUFFER ));
1268+ if (rsaCert != NULL )
1269+ XMEMCPY (rsaCert , client_cert_der_1024 , rsaCertSz );
1270+ rsaPrivKeySz = (word32 )sizeof_client_key_der_1024 ;
1271+ ExpectNotNull (rsaPrivKey = (byte * )XMALLOC (rsaPrivKeySz , HEAP_HINT ,
1272+ DYNAMIC_TYPE_TMP_BUFFER ));
1273+ if (rsaPrivKey != NULL )
1274+ XMEMCPY (rsaPrivKey , client_key_der_1024 , rsaPrivKeySz );
1275+ #elif defined(USE_CERT_BUFFERS_2048 )
1276+ rsaCertSz = (word32 )sizeof_client_cert_der_2048 ;
1277+ ExpectNotNull (rsaCert = (byte * )XMALLOC (rsaCertSz , HEAP_HINT ,
1278+ DYNAMIC_TYPE_TMP_BUFFER ));
1279+ if (rsaCert != NULL )
1280+ XMEMCPY (rsaCert , client_cert_der_2048 , rsaCertSz );
1281+ rsaPrivKeySz = (word32 )sizeof_client_key_der_2048 ;
1282+ ExpectNotNull (rsaPrivKey = (byte * )XMALLOC (rsaPrivKeySz , HEAP_HINT ,
1283+ DYNAMIC_TYPE_TMP_BUFFER ));
1284+ if (rsaPrivKey != NULL )
1285+ XMEMCPY (rsaPrivKey , client_key_der_2048 , rsaPrivKeySz );
1286+ #elif !defined(NO_FILESYSTEM )
1287+ rsaCertSz = FOURK_BUF ;
1288+ ExpectNotNull (rsaCert = (byte * )XMALLOC (rsaCertSz , HEAP_HINT ,
1289+ DYNAMIC_TYPE_TMP_BUFFER ));
1290+ ExpectTrue ((f = XFOPEN ("./certs/client-cert.der" , "rb" )) != XBADFILE );
1291+ ExpectTrue ((rsaCertSz = (word32 )XFREAD (rsaCert , 1 , rsaCertSz , f )) > 0 );
1292+ if (f != XBADFILE ) {
1293+ XFCLOSE (f );
1294+ f = XBADFILE ;
1295+ }
1296+ rsaPrivKeySz = FOURK_BUF ;
1297+ ExpectNotNull (rsaPrivKey = (byte * )XMALLOC (rsaPrivKeySz , HEAP_HINT ,
1298+ DYNAMIC_TYPE_TMP_BUFFER ));
1299+ ExpectTrue ((f = XFOPEN ("./certs/client-key.der" , "rb" )) != XBADFILE );
1300+ ExpectTrue ((rsaPrivKeySz = (word32 )XFREAD (rsaPrivKey , 1 ,
1301+ rsaPrivKeySz , f )) > 0 );
1302+ if (f != XBADFILE )
1303+ XFCLOSE (f );
1304+ #endif
1305+
1306+ if (rsaCert == NULL || rsaPrivKey == NULL ) {
1307+ XFREE (rsaCert , HEAP_HINT , DYNAMIC_TYPE_TMP_BUFFER );
1308+ XFREE (rsaPrivKey , HEAP_HINT , DYNAMIC_TYPE_TMP_BUFFER );
1309+ return TEST_SKIPPED ;
1310+ }
1311+
1312+ /* AES-128: 32-byte fake CEK larger than real CEK size (16 bytes). */
1313+ ExpectIntEQ (pkcs7_ktri_bad_pad_case (AES128CBCb , rsaCert , rsaCertSz ,
1314+ rsaPrivKey , rsaPrivKeySz , encrypted , sizeof (encrypted ),
1315+ decoded , sizeof (decoded )), TEST_SUCCESS );
1316+ #ifdef WOLFSSL_AES_192
1317+ /* AES-192: fake CEK (32) vs real CEK (24) - another size mismatch. */
1318+ ExpectIntEQ (pkcs7_ktri_bad_pad_case (AES192CBCb , rsaCert , rsaCertSz ,
1319+ rsaPrivKey , rsaPrivKeySz , encrypted , sizeof (encrypted ),
1320+ decoded , sizeof (decoded )), TEST_SUCCESS );
1321+ #endif
1322+ /* AES-256: fake CEK size matches real CEK size (32 bytes). */
1323+ ExpectIntEQ (pkcs7_ktri_bad_pad_case (AES256CBCb , rsaCert , rsaCertSz ,
1324+ rsaPrivKey , rsaPrivKeySz , encrypted , sizeof (encrypted ),
1325+ decoded , sizeof (decoded )), TEST_SUCCESS );
1326+
1327+ XFREE (rsaCert , HEAP_HINT , DYNAMIC_TYPE_TMP_BUFFER );
1328+ XFREE (rsaPrivKey , HEAP_HINT , DYNAMIC_TYPE_TMP_BUFFER );
1329+ return EXPECT_RESULT ();
1330+ } /* END test_wc_PKCS7_EnvelopedData_KTRI_BadRsaPad */
1331+ #endif
1332+
1333+
11211334/*
11221335 * Testing wc_PKCS7_EncodeSignedData_ex() and wc_PKCS7_VerifySignedData_ex()
11231336 */
0 commit comments