Skip to content

Commit b518965

Browse files
rsa key validation test and additions to rsa fromdata test
updated rsa_key_import / validate to survive new tests
1 parent 4eeea87 commit b518965

File tree

4 files changed

+530
-11
lines changed

4 files changed

+530
-11
lines changed

src/wp_rsa_kmgmt.c

Lines changed: 196 additions & 11 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.
@@ -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

Comments
 (0)