@@ -191,6 +191,11 @@ static const char* wp_rsa_param_key[WP_RSA_PARAM_NUMS_CNT] = {
191191 OSSL_PKEY_PARAM_RSA_EXPONENT1 , OSSL_PKEY_PARAM_RSA_EXPONENT2 ,
192192 OSSL_PKEY_PARAM_RSA_COEFFICIENT1
193193};
194+ #define WP_RSA_PARAM_KEY_FACTOR_INDEX1 3
195+ #define WP_RSA_PARAM_KEY_FACTOR_INDEX2 4
196+ #define WP_RSA_PARAM_KEY_EXPONENT_INDEX1 5
197+ #define WP_RSA_PARAM_KEY_EXPONENT_INDEX2 6
198+ #define WP_RSA_PARAM_KEY_COEFFICIENT_INDEX 7
194199
195200/**
196201 * RSA PSS parameters.
@@ -1143,6 +1148,27 @@ static int wp_rsa_match(const wp_Rsa* rsa1, const wp_Rsa* rsa2, int selection)
11431148 return ok ;
11441149}
11451150
1151+ #define VALIDATE_PRIMES_SIZE 133
1152+ static const mp_digit validate_primes [VALIDATE_PRIMES_SIZE ] = {
1153+ 0x0002 , 0x0003 , 0x0005 , 0x0007 , 0x000B , 0x000D , 0x0011 , 0x0013 ,
1154+ 0x0017 , 0x001D , 0x001F , 0x0025 , 0x0029 , 0x002B , 0x002F , 0x0035 ,
1155+ 0x003B , 0x003D , 0x0043 , 0x0047 , 0x0049 , 0x004F , 0x0053 , 0x0059 ,
1156+ 0x0061 , 0x0065 , 0x0067 , 0x006B , 0x006D , 0x0071 , 0x007F , 0x0083 ,
1157+ 0x0089 , 0x008B , 0x0095 , 0x0097 , 0x009D , 0x00A3 , 0x00A7 , 0x00AD ,
1158+ 0x00B3 , 0x00B5 , 0x00BF , 0x00C1 , 0x00C5 , 0x00C7 , 0x00D3 , 0x00DF ,
1159+ 0x00E3 , 0x00E5 , 0x00E9 , 0x00EF , 0x00F1 , 0x00FB , 0x0101 , 0x0107 ,
1160+ 0x010D , 0x010F , 0x0115 , 0x0119 , 0x011B , 0x0125 , 0x0133 , 0x0137 ,
1161+ 0x0139 , 0x013D , 0x014B , 0x0151 , 0x015B , 0x015D , 0x0161 , 0x0167 ,
1162+ 0x016F , 0x0175 , 0x017B , 0x017F , 0x0185 , 0x018D , 0x0191 , 0x0199 ,
1163+ 0x01A3 , 0x01A5 , 0x01AF , 0x01B1 , 0x01B7 , 0x01BB , 0x01C1 , 0x01C9 ,
1164+ 0x01CD , 0x01CF , 0x01D3 , 0x01DF , 0x01E7 , 0x01EB , 0x01F3 , 0x01F7 ,
1165+ 0x01FD , 0x0209 , 0x020B , 0x021D , 0x0223 , 0x022D , 0x0233 , 0x0239 ,
1166+ 0x023B , 0x0241 , 0x024B , 0x0251 , 0x0257 , 0x0259 , 0x025F , 0x0265 ,
1167+ 0x0269 , 0x026B , 0x0277 , 0x0281 , 0x0283 , 0x0287 , 0x028D , 0x0293 ,
1168+ 0x0295 , 0x02A1 , 0x02A5 , 0x02AB , 0x02B3 , 0x02BD , 0x02C5 , 0x02CF ,
1169+ 0x02D7 , 0x02DD , 0x02E3 , 0x02E7 , 0x02EF ,
1170+ };
1171+
11461172/**
11471173 * Validate the RSA key.
11481174 *
@@ -1175,21 +1201,137 @@ static int wp_rsa_validate(const wp_Rsa* rsa, int selection, int checkType)
11751201 else
11761202#endif
11771203 if (checkPriv ) {
1178- if (mp_isone ( & rsa -> key . d ) || mp_iszero ((mp_int * )& rsa -> key .d ) ||
1204+ if (mp_iszero ((mp_int * )& rsa -> key .d ) ||
11791205 (mp_cmp ((mp_int * )& rsa -> key .d , (mp_int * )& rsa -> key .n ) != MP_LT )) {
11801206 ok = 0 ;
11811207 }
11821208 }
11831209 else if (checkPub ) {
1184- if (mp_iseven (& rsa -> key .e ) || mp_iszero ((mp_int * )& rsa -> key .e ) ||
1185- mp_isone (& rsa -> key .e )) {
1210+ int prime ;
1211+ mp_int res ;
1212+
1213+ if (mp_iszero ((mp_int * )& rsa -> key .e ) || mp_iszero ((mp_int * )& rsa -> key .n ) ||
1214+ mp_isone ((mp_int * )& rsa -> key .e ) || mp_isone ((mp_int * )& rsa -> key .n ) ||
1215+ mp_iseven ((mp_int * )& rsa -> key .e ) || mp_iseven ((mp_int * )& rsa -> key .n )) {
11861216 ok = 0 ;
11871217 }
1218+
1219+ if (ok && mp_init (& res ) != MP_OKAY ) {
1220+ ok = 0 ;
1221+ }
1222+ else if (ok ) {
1223+ for (prime = 0 ; prime < VALIDATE_PRIMES_SIZE ; prime ++ ) {
1224+ if (mp_set_int (& res , validate_primes [prime ]) != MP_OKAY ||
1225+ mp_mod ((mp_int * )& rsa -> key .n , & res , & res ) != MP_OKAY ||
1226+ mp_iszero (& res )) {
1227+ ok = 0 ;
1228+ break ;
1229+ }
1230+ }
1231+
1232+ mp_clear (& res );
1233+ }
1234+ }
1235+
1236+ WOLFPROV_LEAVE (WP_LOG_COMP_RSA , __FILE__ ":" WOLFPROV_STRINGIZE (__LINE__ ), ok );
1237+ return ok ;
1238+ }
1239+
1240+ /**
1241+ * Copy an unsigned value from an OSSL param into a provided RSA key parameter.
1242+ *
1243+ * @param [out] mp RSA key parameter.
1244+ * @param [in] param Parameter to copy value from.
1245+ * @return Size of mp in bits as unsigned integer on success.
1246+ * @return -1 on failure.
1247+ */
1248+ static int wp_rsa_import_store_unsigned (mp_int * mp , const OSSL_PARAM * param )
1249+ {
1250+ int ok ;
1251+ int bits = -1 ;
1252+
1253+ WOLFPROV_ENTER (WP_LOG_COMP_RSA , "wp_rsa_import_store_unsigned" );
1254+
1255+ #if OPENSSL_VERSION_NUMBER <= 0x30100080L
1256+ ok = param -> data != NULL && param -> data_type == OSSL_PARAM_UNSIGNED_INTEGER ;
1257+ #else
1258+ ok = param -> data != NULL && (param -> data_type == OSSL_PARAM_INTEGER ||
1259+ param -> data_type == OSSL_PARAM_UNSIGNED_INTEGER );
1260+ #endif /* OPENSSL_VERSION_NUMBER <= 3.1.8 */
1261+
1262+ if (ok && !wp_mp_read_unsigned_bin_le (mp , param -> data , param -> data_size )) {
1263+ WOLFPROV_MSG (WP_LOG_COMP_RSA ,
1264+ "Failed to read %s from parameters" , param -> key );
1265+ ok = 0 ;
1266+ }
1267+
1268+ if (ok ) {
1269+ bits = mp_count_bits (mp );
1270+ }
1271+
1272+ /* Negative values are accepted by OSSL, for now just set to 0.
1273+ * Note that bits of signed value (as unsigned) are returned */
1274+ if (ok && param -> data_type == OSSL_PARAM_INTEGER ) {
1275+ ok = mp_set (mp , 0 ) == MP_OKAY ;
1276+ bits -= 8 ;
11881277 }
11891278
11901279 WOLFPROV_LEAVE (WP_LOG_COMP_RSA , __FILE__ ":" WOLFPROV_STRINGIZE (__LINE__ ), ok );
1280+ return bits ;
1281+ }
1282+
1283+ /**
1284+ * Based on the index into wp_rsa_param_key, increment the appropriate counter.
1285+ *
1286+ * @param [in] index Index associated with wp_rsa_param_key.
1287+ * @param [out] primes Count of prime parameters.
1288+ * @param [out] exps Count of exponent parameters.
1289+ * @param [out] coeffs Count of coefficient parameters.
1290+ */
1291+ #if OPENSSL_VERSION_NUMBER < 0x30300000L
1292+ static void wp_rsa_import_increment_crt_counts (int index , int * primes ,
1293+ int * exps , int * coeffs )
1294+ {
1295+ if (index >= WP_RSA_PARAM_KEY_FACTOR_INDEX1 &&
1296+ index <= WP_RSA_PARAM_KEY_FACTOR_INDEX2 ) {
1297+ * primes += 1 ;
1298+ }
1299+ else if (index >= WP_RSA_PARAM_KEY_EXPONENT_INDEX1 &&
1300+ index <= WP_RSA_PARAM_KEY_EXPONENT_INDEX2 ) {
1301+ * exps += 1 ;
1302+ }
1303+ else if (index == WP_RSA_PARAM_KEY_COEFFICIENT_INDEX ) {
1304+ * coeffs += 1 ;
1305+ }
1306+ }
1307+
1308+ static int wp_rsa_import_verify_crt (int primes , int exps , int coeffs )
1309+ {
1310+ int ok = 1 ;
1311+
1312+ (void )exps ;
1313+ (void )coeffs ;
1314+
1315+ if (primes > 0 ) {
1316+ #if (OPENSSL_VERSION_NUMBER < 0x30100040L && OPENSSL_VERSION_NUMBER > 0x30000120L ) \
1317+ || (OPENSSL_VERSION_NUMBER < 0x300000C0L )
1318+ if (primes < 2 || primes != exps || primes != coeffs + 1 ) {
1319+ #else
1320+ if (primes < 2 ) {
1321+ #endif /* (Ver < 3.1.4 && Ver > 3.0.18) || (Ver < 3.0.12) */
1322+ WOLFPROV_MSG (WP_LOG_COMP_RSA ,
1323+ "RSA factors provided but CRT parameters incomplete" );
1324+ ok = 0 ;
1325+ }
1326+ /* TODO: multi-prime checks */
1327+ else if (primes > 2 ) {
1328+ ok = 0 ;
1329+ }
1330+ }
1331+
11911332 return ok ;
11921333}
1334+ #endif /* OPENSSL_VERSION_NUMBER < 3.3.0 */
11931335
11941336/**
11951337 * Import the key data into RSA key object from parameters.
@@ -1208,18 +1350,39 @@ static int wp_rsa_import_key_data(wp_Rsa* rsa, const OSSL_PARAM params[],
12081350 int cnt = 0 ;
12091351 mp_int * mp = NULL ;
12101352 const OSSL_PARAM * p = NULL ;
1353+ const OSSL_PARAM * n ;
1354+ const OSSL_PARAM * e ;
1355+ const OSSL_PARAM * d = NULL ;
1356+ int bits ;
1357+ int nbits ;
1358+ #if OPENSSL_VERSION_NUMBER < 0x30300000L
1359+ int primes = 0 ;
1360+ int exps = 0 ;
1361+ int coeffs = 0 ;
1362+ #endif /* OPENSSL_VERSION_NUMBER < 3.3.0 */
12111363
12121364 WOLFPROV_ENTER (WP_LOG_COMP_RSA , "wp_rsa_import_key_data" );
12131365
12141366 /* N and E params are the only ones required by OSSL, so match that.
12151367 * See ossl_rsa_fromdata() and RSA_set0_key() in OpenSSL. */
1216- if (OSSL_PARAM_locate_const (params , OSSL_PKEY_PARAM_RSA_N ) == NULL ||
1217- OSSL_PARAM_locate_const (params , OSSL_PKEY_PARAM_RSA_E ) == NULL ) {
1368+ if ((n = OSSL_PARAM_locate_const (params , OSSL_PKEY_PARAM_RSA_N )) == NULL ||
1369+ n -> data == NULL ||
1370+ (e = OSSL_PARAM_locate_const (params , OSSL_PKEY_PARAM_RSA_E )) == NULL ||
1371+ e -> data == NULL ) {
12181372 WOLFPROV_MSG (WP_LOG_COMP_RSA , "Param N or E is missing" );
12191373 ok = 0 ;
12201374 }
1375+ if (ok && priv ) {
1376+ d = OSSL_PARAM_locate_const (params , OSSL_PKEY_PARAM_RSA_D );
1377+ }
12211378
12221379 if (ok ) {
1380+ mp = & rsa -> key .n ;
1381+ nbits = wp_rsa_import_store_unsigned (mp , n );
1382+ ok = nbits != -1 ;
1383+ }
1384+
1385+ if (ok && d != NULL ) {
12231386 cnt = wp_params_count (params );
12241387 rsa -> key .type = priv ? RSA_PRIVATE : RSA_PUBLIC ;
12251388
@@ -1230,6 +1393,10 @@ static int wp_rsa_import_key_data(wp_Rsa* rsa, const OSSL_PARAM params[],
12301393 for (j = 0 ; j < (int )ARRAY_SIZE (wp_rsa_param_key ); j ++ ) {
12311394 if (XSTRNCMP (p -> key , wp_rsa_param_key [j ], XSTRLEN (p -> key )) == 0 ) {
12321395 index = j ;
1396+ #if OPENSSL_VERSION_NUMBER < 0x30300000L
1397+ wp_rsa_import_increment_crt_counts (index , & primes , & exps ,
1398+ & coeffs );
1399+ #endif /* OPENSSL_VERSION_NUMBER < 3.3.0 */
12331400 break ;
12341401 }
12351402 }
@@ -1241,15 +1408,33 @@ static int wp_rsa_import_key_data(wp_Rsa* rsa, const OSSL_PARAM params[],
12411408 }
12421409
12431410 /* Read the value into the rsa struct */
1244- if (ok ) {
1411+ if (ok && p != n ) {
12451412 mp = (mp_int * )(((byte * )& rsa -> key ) + wp_rsa_offset [index ]);
1246- if (!wp_mp_read_unsigned_bin_le (mp , p -> data , p -> data_size )) {
1247- WOLFPROV_MSG (WP_LOG_COMP_RSA ,
1248- "Failed to read %s from parameters" , p -> key );
1249- ok = 0 ;
1250- }
1413+ bits = wp_rsa_import_store_unsigned (mp , p );
1414+ #if OPENSSL_VERSION_NUMBER >= 0x30400000L
1415+ ok = bits != -1 && bits <= nbits ;
1416+ #else
1417+ ok = bits != -1 ;
1418+ #endif /* OPENSSL_VERSION_NUMBER >= 3.4.0 */
12511419 }
12521420 }
1421+
1422+ /* TODO: need to generate exponents and coefficients beforehand
1423+ * in newer versions, so skip check for now */
1424+ #if OPENSSL_VERSION_NUMBER < 0x30300000L
1425+ if (ok ) {
1426+ ok = wp_rsa_import_verify_crt (primes , exps , coeffs );
1427+ }
1428+ #endif /* OPENSSL_VERSION_NUMBER < 3.3.0 */
1429+ }
1430+ else if (ok && d == NULL ) {
1431+ mp = & rsa -> key .e ;
1432+ bits = wp_rsa_import_store_unsigned (mp , e );
1433+ #if OPENSSL_VERSION_NUMBER >= 0x30400000L
1434+ ok = bits != -1 && bits <= nbits ;
1435+ #else
1436+ ok = bits != -1 ;
1437+ #endif /* OPENSSL_VERSION_NUMBER >= 3.4.0 */
12531438 }
12541439
12551440 WOLFPROV_LEAVE (WP_LOG_COMP_RSA , __FILE__ ":" WOLFPROV_STRINGIZE (__LINE__ ), ok );
0 commit comments