@@ -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.
@@ -1074,6 +1079,27 @@ static int wp_rsa_match(const wp_Rsa* rsa1, const wp_Rsa* rsa2, int selection)
10741079 return ok ;
10751080}
10761081
1082+ #define VALIDATE_PRIMES_SIZE 133
1083+ static const mp_digit validate_primes [VALIDATE_PRIMES_SIZE ] = {
1084+ 0x0002 , 0x0003 , 0x0005 , 0x0007 , 0x000B , 0x000D , 0x0011 , 0x0013 ,
1085+ 0x0017 , 0x001D , 0x001F , 0x0025 , 0x0029 , 0x002B , 0x002F , 0x0035 ,
1086+ 0x003B , 0x003D , 0x0043 , 0x0047 , 0x0049 , 0x004F , 0x0053 , 0x0059 ,
1087+ 0x0061 , 0x0065 , 0x0067 , 0x006B , 0x006D , 0x0071 , 0x007F , 0x0083 ,
1088+ 0x0089 , 0x008B , 0x0095 , 0x0097 , 0x009D , 0x00A3 , 0x00A7 , 0x00AD ,
1089+ 0x00B3 , 0x00B5 , 0x00BF , 0x00C1 , 0x00C5 , 0x00C7 , 0x00D3 , 0x00DF ,
1090+ 0x00E3 , 0x00E5 , 0x00E9 , 0x00EF , 0x00F1 , 0x00FB , 0x0101 , 0x0107 ,
1091+ 0x010D , 0x010F , 0x0115 , 0x0119 , 0x011B , 0x0125 , 0x0133 , 0x0137 ,
1092+ 0x0139 , 0x013D , 0x014B , 0x0151 , 0x015B , 0x015D , 0x0161 , 0x0167 ,
1093+ 0x016F , 0x0175 , 0x017B , 0x017F , 0x0185 , 0x018D , 0x0191 , 0x0199 ,
1094+ 0x01A3 , 0x01A5 , 0x01AF , 0x01B1 , 0x01B7 , 0x01BB , 0x01C1 , 0x01C9 ,
1095+ 0x01CD , 0x01CF , 0x01D3 , 0x01DF , 0x01E7 , 0x01EB , 0x01F3 , 0x01F7 ,
1096+ 0x01FD , 0x0209 , 0x020B , 0x021D , 0x0223 , 0x022D , 0x0233 , 0x0239 ,
1097+ 0x023B , 0x0241 , 0x024B , 0x0251 , 0x0257 , 0x0259 , 0x025F , 0x0265 ,
1098+ 0x0269 , 0x026B , 0x0277 , 0x0281 , 0x0283 , 0x0287 , 0x028D , 0x0293 ,
1099+ 0x0295 , 0x02A1 , 0x02A5 , 0x02AB , 0x02B3 , 0x02BD , 0x02C5 , 0x02CF ,
1100+ 0x02D7 , 0x02DD , 0x02E3 , 0x02E7 , 0x02EF ,
1101+ };
1102+
10771103/**
10781104 * Validate the RSA key.
10791105 *
@@ -1106,21 +1132,137 @@ static int wp_rsa_validate(const wp_Rsa* rsa, int selection, int checkType)
11061132 else
11071133#endif
11081134 if (checkPriv ) {
1109- if (mp_isone ( & rsa -> key . d ) || mp_iszero ((mp_int * )& rsa -> key .d ) ||
1135+ if (mp_iszero ((mp_int * )& rsa -> key .d ) ||
11101136 (mp_cmp ((mp_int * )& rsa -> key .d , (mp_int * )& rsa -> key .n ) != MP_LT )) {
11111137 ok = 0 ;
11121138 }
11131139 }
11141140 else if (checkPub ) {
1115- if (mp_iseven (& rsa -> key .e ) || mp_iszero ((mp_int * )& rsa -> key .e ) ||
1116- mp_isone (& rsa -> key .e )) {
1141+ int prime ;
1142+ mp_int res ;
1143+
1144+ if (mp_iszero ((mp_int * )& rsa -> key .e ) || mp_iszero ((mp_int * )& rsa -> key .n ) ||
1145+ mp_isone ((mp_int * )& rsa -> key .e ) || mp_isone ((mp_int * )& rsa -> key .n ) ||
1146+ mp_iseven ((mp_int * )& rsa -> key .e ) || mp_iseven ((mp_int * )& rsa -> key .n )) {
11171147 ok = 0 ;
11181148 }
1149+
1150+ if (ok && mp_init (& res ) != MP_OKAY ) {
1151+ ok = 0 ;
1152+ }
1153+ else if (ok ) {
1154+ for (prime = 0 ; prime < VALIDATE_PRIMES_SIZE ; prime ++ ) {
1155+ if (mp_set_int (& res , validate_primes [prime ]) != MP_OKAY ||
1156+ mp_mod ((mp_int * )& rsa -> key .n , & res , & res ) != MP_OKAY ||
1157+ mp_iszero (& res )) {
1158+ ok = 0 ;
1159+ break ;
1160+ }
1161+ }
1162+
1163+ mp_clear (& res );
1164+ }
1165+ }
1166+
1167+ WOLFPROV_LEAVE (WP_LOG_COMP_RSA , __FILE__ ":" WOLFPROV_STRINGIZE (__LINE__ ), ok );
1168+ return ok ;
1169+ }
1170+
1171+ /**
1172+ * Copy an unsigned value from an OSSL param into a provided RSA key parameter.
1173+ *
1174+ * @param [out] mp RSA key parameter.
1175+ * @param [in] param Parameter to copy value from.
1176+ * @return Size of mp in bits as unsigned integer on success.
1177+ * @return -1 on failure.
1178+ */
1179+ static int wp_rsa_import_store_unsigned (mp_int * mp , const OSSL_PARAM * param )
1180+ {
1181+ int ok ;
1182+ int bits = -1 ;
1183+
1184+ WOLFPROV_ENTER (WP_LOG_COMP_RSA , "wp_rsa_import_store_unsigned" );
1185+
1186+ #if OPENSSL_VERSION_NUMBER <= 0x30100080L
1187+ ok = param -> data != NULL && param -> data_type == OSSL_PARAM_UNSIGNED_INTEGER ;
1188+ #else
1189+ ok = param -> data != NULL && (param -> data_type == OSSL_PARAM_INTEGER ||
1190+ param -> data_type == OSSL_PARAM_UNSIGNED_INTEGER );
1191+ #endif /* OPENSSL_VERSION_NUMBER <= 3.1.8 */
1192+
1193+ if (ok && !wp_mp_read_unsigned_bin_le (mp , param -> data , param -> data_size )) {
1194+ WOLFPROV_MSG (WP_LOG_COMP_RSA ,
1195+ "Failed to read %s from parameters" , param -> key );
1196+ ok = 0 ;
1197+ }
1198+
1199+ if (ok ) {
1200+ bits = mp_count_bits (mp );
1201+ }
1202+
1203+ /* Negative values are accepted by OSSL, for now just set to 0.
1204+ * Note that bits of signed value (as unsigned) are returned */
1205+ if (ok && param -> data_type == OSSL_PARAM_INTEGER ) {
1206+ ok = mp_set (mp , 0 ) == MP_OKAY ;
1207+ bits -= 8 ;
11191208 }
11201209
11211210 WOLFPROV_LEAVE (WP_LOG_COMP_RSA , __FILE__ ":" WOLFPROV_STRINGIZE (__LINE__ ), ok );
1211+ return bits ;
1212+ }
1213+
1214+ /**
1215+ * Based on the index into wp_rsa_param_key, increment the appropriate counter.
1216+ *
1217+ * @param [in] index Index associated with wp_rsa_param_key.
1218+ * @param [out] primes Count of prime parameters.
1219+ * @param [out] exps Count of exponent parameters.
1220+ * @param [out] coeffs Count of coefficient parameters.
1221+ */
1222+ #if OPENSSL_VERSION_NUMBER < 0x30300000L
1223+ static void wp_rsa_import_increment_crt_counts (int index , int * primes ,
1224+ int * exps , int * coeffs )
1225+ {
1226+ if (index >= WP_RSA_PARAM_KEY_FACTOR_INDEX1 &&
1227+ index <= WP_RSA_PARAM_KEY_FACTOR_INDEX2 ) {
1228+ * primes += 1 ;
1229+ }
1230+ else if (index >= WP_RSA_PARAM_KEY_EXPONENT_INDEX1 &&
1231+ index <= WP_RSA_PARAM_KEY_EXPONENT_INDEX2 ) {
1232+ * exps += 1 ;
1233+ }
1234+ else if (index == WP_RSA_PARAM_KEY_COEFFICIENT_INDEX ) {
1235+ * coeffs += 1 ;
1236+ }
1237+ }
1238+
1239+ static int wp_rsa_import_verify_crt (int primes , int exps , int coeffs )
1240+ {
1241+ int ok = 1 ;
1242+
1243+ (void )exps ;
1244+ (void )coeffs ;
1245+
1246+ if (primes > 0 ) {
1247+ #if (OPENSSL_VERSION_NUMBER < 0x30100040L && OPENSSL_VERSION_NUMBER > 0x30000120L ) \
1248+ || (OPENSSL_VERSION_NUMBER < 0x300000C0L )
1249+ if (primes < 2 || primes != exps || primes != coeffs + 1 ) {
1250+ #else
1251+ if (primes < 2 ) {
1252+ #endif /* (Ver < 3.1.4 && Ver > 3.0.18) || (Ver < 3.0.12) */
1253+ WOLFPROV_MSG (WP_LOG_COMP_RSA ,
1254+ "RSA factors provided but CRT parameters incomplete" );
1255+ ok = 0 ;
1256+ }
1257+ /* TODO: multi-prime checks */
1258+ else if (primes > 2 ) {
1259+ ok = 0 ;
1260+ }
1261+ }
1262+
11221263 return ok ;
11231264}
1265+ #endif /* OPENSSL_VERSION_NUMBER < 3.3.0 */
11241266
11251267/**
11261268 * Import the key data into RSA key object from parameters.
@@ -1139,18 +1281,39 @@ static int wp_rsa_import_key_data(wp_Rsa* rsa, const OSSL_PARAM params[],
11391281 int cnt = 0 ;
11401282 mp_int * mp = NULL ;
11411283 const OSSL_PARAM * p = NULL ;
1284+ const OSSL_PARAM * n ;
1285+ const OSSL_PARAM * e ;
1286+ const OSSL_PARAM * d = NULL ;
1287+ int bits ;
1288+ int nbits ;
1289+ #if OPENSSL_VERSION_NUMBER < 0x30300000L
1290+ int primes = 0 ;
1291+ int exps = 0 ;
1292+ int coeffs = 0 ;
1293+ #endif /* OPENSSL_VERSION_NUMBER < 3.3.0 */
11421294
11431295 WOLFPROV_ENTER (WP_LOG_COMP_RSA , "wp_rsa_import_key_data" );
11441296
11451297 /* N and E params are the only ones required by OSSL, so match that.
11461298 * See ossl_rsa_fromdata() and RSA_set0_key() in OpenSSL. */
1147- if (OSSL_PARAM_locate_const (params , OSSL_PKEY_PARAM_RSA_N ) == NULL ||
1148- OSSL_PARAM_locate_const (params , OSSL_PKEY_PARAM_RSA_E ) == NULL ) {
1299+ if ((n = OSSL_PARAM_locate_const (params , OSSL_PKEY_PARAM_RSA_N )) == NULL ||
1300+ n -> data == NULL ||
1301+ (e = OSSL_PARAM_locate_const (params , OSSL_PKEY_PARAM_RSA_E )) == NULL ||
1302+ e -> data == NULL ) {
11491303 WOLFPROV_MSG (WP_LOG_COMP_RSA , "Param N or E is missing" );
11501304 ok = 0 ;
11511305 }
1306+ if (ok && priv ) {
1307+ d = OSSL_PARAM_locate_const (params , OSSL_PKEY_PARAM_RSA_D );
1308+ }
11521309
11531310 if (ok ) {
1311+ mp = & rsa -> key .n ;
1312+ nbits = wp_rsa_import_store_unsigned (mp , n );
1313+ ok = nbits != -1 ;
1314+ }
1315+
1316+ if (ok && d != NULL ) {
11541317 cnt = wp_params_count (params );
11551318 rsa -> key .type = priv ? RSA_PRIVATE : RSA_PUBLIC ;
11561319
@@ -1160,7 +1323,11 @@ static int wp_rsa_import_key_data(wp_Rsa* rsa, const OSSL_PARAM params[],
11601323 index = -1 ;
11611324 for (j = 0 ; j < (int )ARRAY_SIZE (wp_rsa_param_key ); j ++ ) {
11621325 if (XSTRNCMP (p -> key , wp_rsa_param_key [j ], XSTRLEN (p -> key )) == 0 ) {
1163- index = j ;
1326+ index = j ;
1327+ #if OPENSSL_VERSION_NUMBER < 0x30300000L
1328+ wp_rsa_import_increment_crt_counts (index , & primes , & exps ,
1329+ & coeffs );
1330+ #endif /* OPENSSL_VERSION_NUMBER < 3.3.0 */
11641331 break ;
11651332 }
11661333 }
@@ -1172,15 +1339,33 @@ static int wp_rsa_import_key_data(wp_Rsa* rsa, const OSSL_PARAM params[],
11721339 }
11731340
11741341 /* Read the value into the rsa struct */
1175- if (ok ) {
1342+ if (ok && p != n ) {
11761343 mp = (mp_int * )(((byte * )& rsa -> key ) + wp_rsa_offset [index ]);
1177- if (!wp_mp_read_unsigned_bin_le (mp , p -> data , p -> data_size )) {
1178- WOLFPROV_MSG (WP_LOG_COMP_RSA ,
1179- "Failed to read %s from parameters" , p -> key );
1180- ok = 0 ;
1181- }
1344+ bits = wp_rsa_import_store_unsigned (mp , p );
1345+ #if OPENSSL_VERSION_NUMBER >= 0x30400000L
1346+ ok = bits != -1 && bits <= nbits ;
1347+ #else
1348+ ok = bits != -1 ;
1349+ #endif /* OPENSSL_VERSION_NUMBER >= 3.4.0 */
11821350 }
11831351 }
1352+
1353+ /* TODO: need to generate exponents and coefficients beforehand
1354+ * in newer versions, so skip check for now */
1355+ #if OPENSSL_VERSION_NUMBER < 0x30300000L
1356+ if (ok ) {
1357+ ok = wp_rsa_import_verify_crt (primes , exps , coeffs );
1358+ }
1359+ #endif /* OPENSSL_VERSION_NUMBER < 3.3.0 */
1360+ }
1361+ else if (ok && d == NULL ) {
1362+ mp = & rsa -> key .e ;
1363+ bits = wp_rsa_import_store_unsigned (mp , e );
1364+ #if OPENSSL_VERSION_NUMBER >= 0x30400000L
1365+ ok = bits != -1 && bits <= nbits ;
1366+ #else
1367+ ok = bits != -1 ;
1368+ #endif /* OPENSSL_VERSION_NUMBER >= 3.4.0 */
11841369 }
11851370
11861371 WOLFPROV_LEAVE (WP_LOG_COMP_RSA , __FILE__ ":" WOLFPROV_STRINGIZE (__LINE__ ), ok );
0 commit comments