@@ -1152,3 +1152,130 @@ int test_wc_RsaDecrypt_BoundsCheck(void)
11521152 return EXPECT_RESULT ();
11531153} /* END test_wc_RsaDecryptBoundsCheck */
11541154
1155+ /*
1156+ * Test wc_RsaKeyToDer with an mp_int large enough to wrap size calculations.
1157+ */
1158+ int test_wc_RsaKeyToDer_SizeOverflow (void )
1159+ {
1160+ EXPECT_DECLS ;
1161+ #if !defined(NO_RSA ) && defined(USE_INTEGER_HEAP_MATH ) && \
1162+ defined(WOLFSSL_ASN_TEMPLATE ) && \
1163+ (defined(WOLFSSL_KEY_GEN ) || defined(WOLFSSL_KEY_TO_DER )) && \
1164+ !defined(_WIN32 )
1165+ #include <sys/mman.h>
1166+ RsaKey key ;
1167+ int i ;
1168+ int derRet ;
1169+ int crafted_used ;
1170+ int top_bits ;
1171+ mp_digit top_digit ;
1172+ mp_digit * crafted_dp = MAP_FAILED ;
1173+ size_t dp_bytes = 0 ;
1174+
1175+ int orig_used = 0 ;
1176+ int orig_alloc = 0 ;
1177+ int orig_sign = 0 ;
1178+ mp_digit * orig_dp = NULL ;
1179+
1180+ mp_int * fields [8 ];
1181+
1182+ XMEMSET (& key , 0 , sizeof (key ));
1183+
1184+ /* Find 'used' count that makes (used-1)*DIGIT_BIT + top_bits = -48
1185+ * as signed int, causing mp_unsigned_bin_size to return -6. */
1186+ {
1187+ unsigned int target = 0xFFFFFFD0u ; /* -48 as unsigned 32-bit */
1188+ int found = 0 ;
1189+
1190+ crafted_used = 0 ;
1191+ top_bits = 0 ;
1192+ top_digit = 0 ;
1193+
1194+ for (top_bits = 1 ; top_bits < DIGIT_BIT ; top_bits ++ ) {
1195+ unsigned int base = target - (unsigned int )top_bits ;
1196+ if (base % (unsigned int )DIGIT_BIT == 0 ) {
1197+ crafted_used = (int )(base / (unsigned int )DIGIT_BIT ) + 1 ;
1198+ top_digit = (mp_digit )1 << (top_bits - 1 );
1199+ found = 1 ;
1200+ break ;
1201+ }
1202+ }
1203+ if (!found ) {
1204+ return TEST_SKIPPED ;
1205+ }
1206+ }
1207+
1208+ dp_bytes = (size_t )crafted_used * sizeof (mp_digit );
1209+
1210+ ExpectIntEQ (wc_InitRsaKey (& key , HEAP_HINT ), 0 );
1211+
1212+ /* Set up dummy RSA private key fields. */
1213+ key .type = RSA_PRIVATE ;
1214+ fields [0 ] = & key .n ;
1215+ fields [1 ] = & key .e ;
1216+ fields [2 ] = & key .d ;
1217+ fields [3 ] = & key .p ;
1218+ fields [4 ] = & key .q ;
1219+ fields [5 ] = & key .dP ;
1220+ fields [6 ] = & key .dQ ;
1221+ fields [7 ] = & key .u ;
1222+
1223+ for (i = 0 ; i < 8 ; i ++ ) {
1224+ if (EXPECT_SUCCESS ()) {
1225+ ExpectIntEQ (mp_init (fields [i ]), 0 );
1226+ mp_set (fields [i ], 0x42 );
1227+ }
1228+ }
1229+
1230+ if (EXPECT_SUCCESS ()) {
1231+ orig_used = key .p .used ;
1232+ orig_alloc = key .p .alloc ;
1233+ orig_sign = key .p .sign ;
1234+ orig_dp = key .p .dp ;
1235+ }
1236+
1237+ /* Sparse mmap — only the page at dp[used-1] is faulted in. */
1238+ if (EXPECT_SUCCESS ()) {
1239+ crafted_dp = (mp_digit * )mmap (NULL , dp_bytes ,
1240+ PROT_READ | PROT_WRITE ,
1241+ MAP_PRIVATE | MAP_ANONYMOUS
1242+ #ifdef MAP_NORESERVE
1243+ | MAP_NORESERVE
1244+ #endif
1245+ , -1 , 0 );
1246+ }
1247+ if (crafted_dp == MAP_FAILED ) {
1248+ key .p .dp = orig_dp ;
1249+ key .p .used = orig_used ;
1250+ key .p .alloc = orig_alloc ;
1251+ key .p .sign = orig_sign ;
1252+ DoExpectIntEQ (wc_FreeRsaKey (& key ), 0 );
1253+ return TEST_SKIPPED ;
1254+ }
1255+
1256+ crafted_dp [crafted_used - 1 ] = top_digit ;
1257+
1258+ key .p .dp = crafted_dp ;
1259+ key .p .used = crafted_used ;
1260+ key .p .alloc = crafted_used ;
1261+ key .p .sign = 0 ; /* MP_ZPOS */
1262+
1263+ /* Should return an error, not a bogus small size. */
1264+ derRet = wc_RsaKeyToDer (& key , NULL , 0 );
1265+ ExpectIntLT (derRet , 0 );
1266+
1267+ /* Restore key.p before cleanup. */
1268+ key .p .dp = orig_dp ;
1269+ key .p .used = orig_used ;
1270+ key .p .alloc = orig_alloc ;
1271+ key .p .sign = orig_sign ;
1272+
1273+ if (crafted_dp != MAP_FAILED ) {
1274+ munmap (crafted_dp , dp_bytes );
1275+ }
1276+
1277+ DoExpectIntEQ (wc_FreeRsaKey (& key ), 0 );
1278+ #endif
1279+ return EXPECT_RESULT ();
1280+ } /* END test_wc_RsaKeyToDer_SizeOverflow */
1281+
0 commit comments