Skip to content

Commit 982f4fd

Browse files
rsa key validation test and additions to rsa fromdata test
updated rsa_key_import / validate to survive new tests
1 parent 44d52b7 commit 982f4fd

File tree

4 files changed

+536
-17
lines changed

4 files changed

+536
-17
lines changed

src/wp_rsa_kmgmt.c

Lines changed: 197 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)