xref: /dpdk/examples/fips_validation/fips_validation_rsa.c (revision 36128a67c27ecb83425a793b2eb837e0581692e7)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(C) 2022 Marvell.
3  */
4 
5 #include <string.h>
6 #include <time.h>
7 #include <stdio.h>
8 #include <sys/types.h>
9 #include <unistd.h>
10 
11 #ifdef USE_OPENSSL
12 #include <openssl/bn.h>
13 #include <openssl/rand.h>
14 #endif /* USE_OPENSSL */
15 
16 #include <rte_cryptodev.h>
17 #include <rte_malloc.h>
18 
19 #include "fips_validation.h"
20 
21 #define TESTTYPE_JSON_STR	"testType"
22 #define SIGTYPE_JSON_STR "sigType"
23 #define MOD_JSON_STR	"modulo"
24 #define HASH_JSON_STR	"hashAlg"
25 #define SALT_JSON_STR	"saltLen"
26 #define E_JSON_STR	"e"
27 #define N_JSON_STR	"n"
28 
29 #define SEED_JSON_STR	"seed"
30 #define MSG_JSON_STR	"message"
31 #define SIG_JSON_STR	"signature"
32 
33 #ifdef USE_JANSSON
34 struct {
35 	uint8_t type;
36 	const char *desc;
37 } rsa_test_types[] = {
38 		{RSA_AFT, "AFT"},
39 		{RSA_GDT, "GDT"},
40 		{RSA_KAT, "KAT"},
41 };
42 
43 struct {
44 	enum rte_crypto_auth_algorithm auth;
45 	const char *desc;
46 } rsa_auth_algs[] = {
47 		{RTE_CRYPTO_AUTH_SHA1, "SHA-1"},
48 		{RTE_CRYPTO_AUTH_SHA224, "SHA2-224"},
49 		{RTE_CRYPTO_AUTH_SHA256, "SHA2-256"},
50 		{RTE_CRYPTO_AUTH_SHA384, "SHA2-384"},
51 		{RTE_CRYPTO_AUTH_SHA512, "SHA2-512"},
52 };
53 
54 struct {
55 	enum rte_crypto_rsa_padding_type padding;
56 	const char *desc;
57 } rsa_padding_types[] = {
58 		{RTE_CRYPTO_RSA_PADDING_NONE, "none"},
59 		{RTE_CRYPTO_RSA_PADDING_PKCS1_5, "pkcs1v1.5"},
60 		{RTE_CRYPTO_RSA_PADDING_OAEP, "oaep"},
61 		{RTE_CRYPTO_RSA_PADDING_PSS, "pss"},
62 };
63 
64 #ifdef USE_OPENSSL
65 static int
66 prepare_vec_rsa(void)
67 {
68 	BIGNUM *p = NULL, *q = NULL, *n = NULL, *d = NULL, *e = NULL;
69 	BIGNUM *dp = NULL, *dq = NULL, *qinv = NULL;
70 	BIGNUM *r0, *r1, *r2, *r3, *r4;
71 	BIGNUM *m = NULL, *r = NULL;
72 	int bits, ret = -1, i;
73 	char modbuf[8], *buf;
74 	BN_CTX *ctx = NULL;
75 	unsigned long pid;
76 
77 	/* Seed PRNG */
78 	if (vec.rsa.seed.val) {
79 		writeback_hex_str("", info.one_line_text, &vec.rsa.seed);
80 		RAND_seed((char *)info.one_line_text, strlen(info.one_line_text));
81 	} else {
82 		pid = getpid();
83 		RAND_seed(&pid, sizeof(pid));
84 	}
85 
86 	if (!RAND_status())
87 		return -1;
88 
89 	/* Check if e is known already */
90 	if (vec.rsa.e.val) {
91 		writeback_hex_str("", info.one_line_text, &vec.rsa.e);
92 		ret = BN_hex2bn(&e, info.one_line_text);
93 		if ((uint32_t)ret != strlen(info.one_line_text))
94 			goto err;
95 	}
96 
97 	/* BN context initialization */
98 	ctx = BN_CTX_new();
99 	if (!ctx)
100 		goto err;
101 
102 	BN_CTX_start(ctx);
103 	r0 = BN_CTX_get(ctx);
104 	r1 = BN_CTX_get(ctx);
105 	r2 = BN_CTX_get(ctx);
106 	r3 = BN_CTX_get(ctx);
107 	r4 = BN_CTX_get(ctx);
108 	if (!r4)
109 		goto err;
110 
111 	/* Calculate bit length for prime numbers */
112 	m = BN_new();
113 	if (!m)
114 		goto err;
115 
116 	snprintf(modbuf, sizeof(modbuf), "%d", info.interim_info.rsa_data.modulo);
117 	if (!BN_dec2bn(&m, modbuf))
118 		goto err;
119 
120 	r = BN_new();
121 	if (!r)
122 		goto err;
123 
124 	if (!BN_rshift1(r, m))
125 		goto err;
126 
127 	buf = BN_bn2dec(r);
128 	bits = atoi(buf);
129 
130 	p = BN_new();
131 	if (!p)
132 		goto err;
133 
134 	q = BN_new();
135 	if (!q)
136 		goto err;
137 
138 	n = BN_new();
139 	if (!n)
140 		goto err;
141 
142 	d = BN_new();
143 	if (!d)
144 		goto err;
145 
146 	/* Generate p and q suitably for RSA */
147 	for (i = 0; i < 10; i++) {
148 		uint8_t j = 0;
149 
150 		if (!BN_generate_prime_ex(p, bits, 0, NULL, NULL, NULL))
151 			goto err;
152 
153 		do {
154 			RAND_add(&j, sizeof(j), 1);
155 			if (!BN_generate_prime_ex(q, bits, 0, NULL, NULL, NULL))
156 				goto err;
157 
158 		} while ((BN_cmp(p, q) == 0) && (j++ < 100));
159 
160 		if (j >= 100) {
161 			RTE_LOG(ERR, USER1, "Error: insufficient %d retries to generate q", j);
162 			goto err;
163 		}
164 
165 		/* pq */
166 		if (!BN_mul(n, p, q, ctx))
167 			goto err;
168 
169 		/* p-1 */
170 		if (!BN_sub(r1, p, BN_value_one()))
171 			goto err;
172 
173 		/* q-1 */
174 		if (!BN_sub(r2, q, BN_value_one()))
175 			goto err;
176 
177 		/* (p-1 * q-1) */
178 		if (!BN_mul(r0, r1, r2, ctx))
179 			goto err;
180 
181 		/* gcd(p-1, q-1)*/
182 		if (!BN_gcd(r3, r1, r2, ctx))
183 			goto err;
184 
185 		/* lcm(p-1, q-1) */
186 		if (!BN_div(r4, r, r0, r3, ctx))
187 			goto err;
188 
189 		/* check if div and rem are non-zero */
190 		if (!r4 || !r)
191 			goto err;
192 
193 		/* 0 < e < lcm */
194 		if (!e) {
195 			int k = 0;
196 
197 			e = BN_new();
198 			do {
199 				RAND_add(&k, sizeof(k), 1);
200 				if (!BN_rand(e, 32, 1, 1))
201 					goto err;
202 
203 				if (!BN_gcd(r3, e, r4, ctx))
204 					goto err;
205 
206 				if (BN_is_one(r3))
207 					break;
208 			} while (k++ < 10);
209 
210 			if (k >= 10) {
211 				RTE_LOG(ERR, USER1, "Error: insufficient %d retries to generate e",
212 					k);
213 				goto err;
214 			}
215 		}
216 
217 		/* (de) mod lcm == 1 */
218 		if (!BN_mod_inverse(d, e, r4, ctx))
219 			goto err;
220 
221 		if (!BN_gcd(r3, r1, e, ctx))
222 			goto err;
223 
224 		if (!BN_gcd(r4, r2, e, ctx))
225 			goto err;
226 
227 		/* check if gcd(p-1, e) and gcd(q-1, e) are 1 */
228 		if (BN_is_one(r3) && BN_is_one(r4))
229 			break;
230 	}
231 
232 	if (i >= 10) {
233 		RTE_LOG(ERR, USER1, "Error: insufficient %d retries to generate p and q", i);
234 		goto err;
235 	}
236 
237 	/* d mod (p-1) */
238 	dp = BN_new();
239 	if (!dp)
240 		goto err;
241 
242 	if (!BN_mod(dp, d, r1, ctx))
243 		goto err;
244 
245 	/* d mod (q-1) */
246 	dq = BN_new();
247 	if (!dq)
248 		goto err;
249 
250 	if (!BN_mod(dq, d, r2, ctx))
251 		goto err;
252 
253 	/* modinv of q and p */
254 	qinv = BN_new();
255 	if (!qinv)
256 		goto err;
257 
258 	if (!BN_mod_inverse(qinv, q, p, ctx))
259 		goto err;
260 
261 	parse_uint8_hex_str("", BN_bn2hex(e), &vec.rsa.e);
262 	parse_uint8_hex_str("", BN_bn2hex(p), &vec.rsa.p);
263 	parse_uint8_hex_str("", BN_bn2hex(q), &vec.rsa.q);
264 	parse_uint8_hex_str("", BN_bn2hex(n), &vec.rsa.n);
265 	parse_uint8_hex_str("", BN_bn2hex(d), &vec.rsa.d);
266 	parse_uint8_hex_str("", BN_bn2hex(dp), &vec.rsa.dp);
267 	parse_uint8_hex_str("", BN_bn2hex(dq), &vec.rsa.dq);
268 	parse_uint8_hex_str("", BN_bn2hex(qinv), &vec.rsa.qinv);
269 
270 	ret = 0;
271 err:
272 	BN_CTX_end(ctx);
273 	BN_CTX_free(ctx);
274 	BN_free(m);
275 	BN_free(r);
276 	BN_free(p);
277 	BN_free(q);
278 	BN_free(n);
279 	BN_free(d);
280 	BN_free(e);
281 	return ret;
282 }
283 #else
284 static int
285 prepare_vec_rsa(void)
286 {
287 	/*
288 	 * Generate RSA values.
289 	 */
290 	return -ENOTSUP;
291 }
292 #endif /* USE_OPENSSL */
293 
294 static int
295 parse_test_rsa_json_interim_writeback(struct fips_val *val)
296 {
297 	RTE_SET_USED(val);
298 
299 	if (info.op == FIPS_TEST_ASYM_SIGGEN) {
300 		json_t *obj;
301 
302 		/* For siggen tests, RSA values can be created soon after
303 		 * the test group data are parsed.
304 		 */
305 		if (vec.rsa.e.val) {
306 			rte_free(vec.rsa.e.val);
307 			vec.rsa.e.val = NULL;
308 		}
309 
310 		if (prepare_vec_rsa() < 0)
311 			return -1;
312 
313 		writeback_hex_str("", info.one_line_text, &vec.rsa.n);
314 		obj = json_string(info.one_line_text);
315 		json_object_set_new(json_info.json_write_group, "n", obj);
316 
317 		writeback_hex_str("", info.one_line_text, &vec.rsa.e);
318 		obj = json_string(info.one_line_text);
319 		json_object_set_new(json_info.json_write_group, "e", obj);
320 	}
321 
322 	return 0;
323 }
324 
325 static int
326 parse_test_rsa_json_writeback(struct fips_val *val)
327 {
328 	json_t *tcId;
329 
330 	RTE_SET_USED(val);
331 
332 	tcId = json_object_get(json_info.json_test_case, "tcId");
333 
334 	json_info.json_write_case = json_object();
335 	json_object_set(json_info.json_write_case, "tcId", tcId);
336 
337 	if (info.op == FIPS_TEST_ASYM_KEYGEN) {
338 		json_t *obj;
339 
340 		writeback_hex_str("", info.one_line_text, &vec.rsa.seed);
341 		obj = json_string(info.one_line_text);
342 		json_object_set_new(json_info.json_write_case, "seed", obj);
343 
344 		writeback_hex_str("", info.one_line_text, &vec.rsa.n);
345 		obj = json_string(info.one_line_text);
346 		json_object_set_new(json_info.json_write_case, "n", obj);
347 
348 		writeback_hex_str("", info.one_line_text, &vec.rsa.e);
349 		obj = json_string(info.one_line_text);
350 		json_object_set_new(json_info.json_write_case, "e", obj);
351 
352 		writeback_hex_str("", info.one_line_text, &vec.rsa.p);
353 		obj = json_string(info.one_line_text);
354 		json_object_set_new(json_info.json_write_case, "p", obj);
355 
356 		writeback_hex_str("", info.one_line_text, &vec.rsa.q);
357 		obj = json_string(info.one_line_text);
358 		json_object_set_new(json_info.json_write_case, "q", obj);
359 
360 		writeback_hex_str("", info.one_line_text, &vec.rsa.d);
361 		obj = json_string(info.one_line_text);
362 		json_object_set_new(json_info.json_write_case, "d", obj);
363 	} else if (info.op == FIPS_TEST_ASYM_SIGGEN) {
364 		json_t *obj;
365 
366 		writeback_hex_str("", info.one_line_text, &vec.rsa.signature);
367 		obj = json_string(info.one_line_text);
368 		json_object_set_new(json_info.json_write_case, "signature", obj);
369 	} else if (info.op == FIPS_TEST_ASYM_SIGVER) {
370 		if (vec.status == RTE_CRYPTO_OP_STATUS_SUCCESS)
371 			json_object_set_new(json_info.json_write_case, "testPassed", json_true());
372 		else
373 			json_object_set_new(json_info.json_write_case, "testPassed", json_false());
374 	}
375 
376 	return 0;
377 }
378 
379 static int
380 parse_interim_str(const char *key, char *src, struct fips_val *val)
381 {
382 	uint32_t i;
383 
384 	RTE_SET_USED(val);
385 
386 	if (strcmp(key, SIGTYPE_JSON_STR) == 0) {
387 		for (i = 0; i < RTE_DIM(rsa_padding_types); i++)
388 			if (strstr(src, rsa_padding_types[i].desc)) {
389 				info.interim_info.rsa_data.padding = rsa_padding_types[i].padding;
390 				break;
391 			}
392 
393 		if (i >= RTE_DIM(rsa_padding_types))
394 			return -EINVAL;
395 
396 	}  else if (strcmp(key, MOD_JSON_STR) == 0) {
397 		info.interim_info.rsa_data.modulo = atoi(src);
398 	} else if (strcmp(key, HASH_JSON_STR) == 0) {
399 		for (i = 0; i < RTE_DIM(rsa_auth_algs); i++)
400 			if (strstr(src, rsa_auth_algs[i].desc)) {
401 				info.interim_info.rsa_data.auth = rsa_auth_algs[i].auth;
402 				break;
403 			}
404 
405 		if (i >= RTE_DIM(rsa_auth_algs))
406 			return -EINVAL;
407 
408 	}  else if (strcmp(key, SALT_JSON_STR) == 0) {
409 		info.interim_info.rsa_data.saltlen = atoi(src);
410 	} else if (strcmp(key, TESTTYPE_JSON_STR) == 0) {
411 		for (i = 0; i < RTE_DIM(rsa_test_types); i++)
412 			if (strstr(src, rsa_test_types[i].desc)) {
413 				info.parse_writeback = parse_test_rsa_json_writeback;
414 				break;
415 			}
416 
417 		if (!info.parse_writeback || i >= RTE_DIM(rsa_test_types))
418 			return -EINVAL;
419 
420 	} else {
421 		return -EINVAL;
422 	}
423 
424 	return 0;
425 }
426 
427 static int
428 parse_keygen_e_str(const char *key, char *src, struct fips_val *val)
429 {
430 	parse_uint8_hex_str(key, src, val);
431 
432 	/* For keygen tests, key "e" can be the end of input data
433 	 * to generate RSA values.
434 	 */
435 	return prepare_vec_rsa();
436 }
437 
438 struct fips_test_callback rsa_keygen_interim_json_vectors[] = {
439 		{MOD_JSON_STR, parse_interim_str, NULL},
440 		{HASH_JSON_STR, parse_interim_str, NULL},
441 		{TESTTYPE_JSON_STR, parse_interim_str, NULL},
442 		{NULL, NULL, NULL} /**< end pointer */
443 };
444 
445 struct fips_test_callback rsa_siggen_interim_json_vectors[] = {
446 		{SIGTYPE_JSON_STR, parse_interim_str, NULL},
447 		{MOD_JSON_STR, parse_interim_str, NULL},
448 		{HASH_JSON_STR, parse_interim_str, NULL},
449 		{SALT_JSON_STR, parse_interim_str, NULL},
450 		{TESTTYPE_JSON_STR, parse_interim_str, NULL},
451 		{NULL, NULL, NULL} /**< end pointer */
452 };
453 
454 struct fips_test_callback rsa_sigver_interim_json_vectors[] = {
455 		{SIGTYPE_JSON_STR, parse_interim_str, NULL},
456 		{MOD_JSON_STR, parse_interim_str, NULL},
457 		{HASH_JSON_STR, parse_interim_str, NULL},
458 		{SALT_JSON_STR, parse_interim_str, NULL},
459 		{N_JSON_STR, parse_uint8_hex_str, &vec.rsa.n},
460 		{E_JSON_STR, parse_uint8_hex_str, &vec.rsa.e},
461 		{TESTTYPE_JSON_STR, parse_interim_str, NULL},
462 		{NULL, NULL, NULL} /**< end pointer */
463 };
464 
465 struct fips_test_callback rsa_keygen_json_vectors[] = {
466 		{SEED_JSON_STR, parse_uint8_hex_str, &vec.rsa.seed},
467 		{E_JSON_STR, parse_keygen_e_str, &vec.rsa.e},
468 		{NULL, NULL, NULL} /**< end pointer */
469 };
470 
471 struct fips_test_callback rsa_siggen_json_vectors[] = {
472 		{MSG_JSON_STR, parse_uint8_hex_str, &vec.pt},
473 		{NULL, NULL, NULL} /**< end pointer */
474 };
475 
476 struct fips_test_callback rsa_sigver_json_vectors[] = {
477 		{MSG_JSON_STR, parse_uint8_hex_str, &vec.pt},
478 		{SIG_JSON_STR, parse_uint8_hex_str, &vec.rsa.signature},
479 		{NULL, NULL, NULL} /**< end pointer */
480 };
481 
482 int
483 parse_test_rsa_json_init(void)
484 {
485 	json_t *keyfmt_obj = json_object_get(json_info.json_vector_set, "keyFormat");
486 	json_t *mode_obj = json_object_get(json_info.json_vector_set, "mode");
487 	const char *keyfmt_str = json_string_value(keyfmt_obj);
488 	const char *mode_str = json_string_value(mode_obj);
489 
490 	info.callbacks = NULL;
491 	info.parse_writeback = NULL;
492 	info.interim_callbacks = NULL;
493 	info.parse_interim_writeback = NULL;
494 
495 	if (strcmp(mode_str, "keyGen") == 0) {
496 		info.op = FIPS_TEST_ASYM_KEYGEN;
497 		info.callbacks = rsa_keygen_json_vectors;
498 		info.interim_callbacks = rsa_keygen_interim_json_vectors;
499 	} else if (strcmp(mode_str, "sigGen") == 0) {
500 		info.op = FIPS_TEST_ASYM_SIGGEN;
501 		info.callbacks = rsa_siggen_json_vectors;
502 		info.interim_callbacks = rsa_siggen_interim_json_vectors;
503 		info.parse_interim_writeback = parse_test_rsa_json_interim_writeback;
504 	} else if (strcmp(mode_str, "sigVer") == 0) {
505 		info.op = FIPS_TEST_ASYM_SIGVER;
506 		info.callbacks = rsa_sigver_json_vectors;
507 		info.interim_callbacks = rsa_sigver_interim_json_vectors;
508 	} else {
509 		return -EINVAL;
510 	}
511 
512 	info.interim_info.rsa_data.privkey = RTE_RSA_KEY_TYPE_QT;
513 	if (keyfmt_str != NULL && strcmp(keyfmt_str, "standard") == 0)
514 		info.interim_info.rsa_data.privkey = RTE_RSA_KEY_TYPE_EXP;
515 
516 	return 0;
517 }
518 
519 #endif /* USE_JANSSON */
520