1 | /*
|
---|
2 | * Copyright 2019-2024 The OpenSSL Project Authors. All Rights Reserved.
|
---|
3 | *
|
---|
4 | * Licensed under the Apache License 2.0 (the "License"). You may not use
|
---|
5 | * this file except in compliance with the License. You can obtain a copy
|
---|
6 | * in the file LICENSE in the source distribution or at
|
---|
7 | * https://www.openssl.org/source/license.html
|
---|
8 | */
|
---|
9 |
|
---|
10 | /*
|
---|
11 | * RSA low level APIs are deprecated for public use, but still ok for
|
---|
12 | * internal use.
|
---|
13 | */
|
---|
14 | #include "internal/deprecated.h"
|
---|
15 |
|
---|
16 | #include <string.h>
|
---|
17 |
|
---|
18 | #include <openssl/bio.h>
|
---|
19 | #include <openssl/bn.h>
|
---|
20 | #include <openssl/rsa.h>
|
---|
21 | #include <openssl/evp.h>
|
---|
22 | #include <openssl/pem.h>
|
---|
23 | #include <openssl/provider.h>
|
---|
24 | #include <openssl/core_names.h>
|
---|
25 | #include "internal/core.h"
|
---|
26 | #include "internal/nelem.h"
|
---|
27 | #include "crypto/evp.h" /* For the internal API */
|
---|
28 | #include "testutil.h"
|
---|
29 |
|
---|
30 | typedef struct {
|
---|
31 | OSSL_LIB_CTX *ctx1;
|
---|
32 | OSSL_PROVIDER *prov1;
|
---|
33 | OSSL_LIB_CTX *ctx2;
|
---|
34 | OSSL_PROVIDER *prov2;
|
---|
35 | } FIXTURE;
|
---|
36 |
|
---|
37 | /* Collected arguments */
|
---|
38 | static const char *cert_filename = NULL;
|
---|
39 |
|
---|
40 | static void tear_down(FIXTURE *fixture)
|
---|
41 | {
|
---|
42 | if (fixture != NULL) {
|
---|
43 | OSSL_PROVIDER_unload(fixture->prov1);
|
---|
44 | OSSL_PROVIDER_unload(fixture->prov2);
|
---|
45 | OSSL_LIB_CTX_free(fixture->ctx1);
|
---|
46 | OSSL_LIB_CTX_free(fixture->ctx2);
|
---|
47 | OPENSSL_free(fixture);
|
---|
48 | }
|
---|
49 | }
|
---|
50 |
|
---|
51 | static FIXTURE *set_up(const char *testcase_name)
|
---|
52 | {
|
---|
53 | FIXTURE *fixture;
|
---|
54 |
|
---|
55 | if (!TEST_ptr(fixture = OPENSSL_zalloc(sizeof(*fixture)))
|
---|
56 | || !TEST_ptr(fixture->ctx1 = OSSL_LIB_CTX_new())
|
---|
57 | || !TEST_ptr(fixture->prov1 = OSSL_PROVIDER_load(fixture->ctx1,
|
---|
58 | "default"))
|
---|
59 | || !TEST_ptr(fixture->ctx2 = OSSL_LIB_CTX_new())
|
---|
60 | || !TEST_ptr(fixture->prov2 = OSSL_PROVIDER_load(fixture->ctx2,
|
---|
61 | "default"))) {
|
---|
62 | tear_down(fixture);
|
---|
63 | return NULL;
|
---|
64 | }
|
---|
65 | return fixture;
|
---|
66 | }
|
---|
67 |
|
---|
68 | /* Array indexes */
|
---|
69 | #define N 0
|
---|
70 | #define E 1
|
---|
71 | #define D 2
|
---|
72 | #define P 3
|
---|
73 | #define Q 4
|
---|
74 | #define F3 5 /* Extra factor */
|
---|
75 | #define DP 6
|
---|
76 | #define DQ 7
|
---|
77 | #define E3 8 /* Extra exponent */
|
---|
78 | #define QINV 9
|
---|
79 | #define C2 10 /* Extra coefficient */
|
---|
80 |
|
---|
81 | /*
|
---|
82 | * We have to do this because OSSL_PARAM_get_ulong() can't handle params
|
---|
83 | * holding data that isn't exactly sizeof(uint32_t) or sizeof(uint64_t),
|
---|
84 | * and because the other end deals with BIGNUM, the resulting param might
|
---|
85 | * be any size. In this particular test, we know that the expected data
|
---|
86 | * fits within an unsigned long, and we want to get the data in that form
|
---|
87 | * to make testing of values easier.
|
---|
88 | */
|
---|
89 | static int get_ulong_via_BN(const OSSL_PARAM *p, unsigned long *goal)
|
---|
90 | {
|
---|
91 | BIGNUM *n = NULL;
|
---|
92 | int ret = 1; /* Ever so hopeful */
|
---|
93 |
|
---|
94 | if (!TEST_true(OSSL_PARAM_get_BN(p, &n))
|
---|
95 | || !TEST_int_ge(BN_bn2nativepad(n, (unsigned char *)goal, sizeof(*goal)), 0))
|
---|
96 | ret = 0;
|
---|
97 | BN_free(n);
|
---|
98 | return ret;
|
---|
99 | }
|
---|
100 |
|
---|
101 | static int export_cb(const OSSL_PARAM *params, void *arg)
|
---|
102 | {
|
---|
103 | unsigned long *keydata = arg;
|
---|
104 | const OSSL_PARAM *p = NULL;
|
---|
105 |
|
---|
106 | if (keydata == NULL)
|
---|
107 | return 0;
|
---|
108 |
|
---|
109 | if (!TEST_ptr(p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_N))
|
---|
110 | || !TEST_true(get_ulong_via_BN(p, &keydata[N]))
|
---|
111 | || !TEST_ptr(p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_E))
|
---|
112 | || !TEST_true(get_ulong_via_BN(p, &keydata[E]))
|
---|
113 | || !TEST_ptr(p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_D))
|
---|
114 | || !TEST_true(get_ulong_via_BN(p, &keydata[D])))
|
---|
115 | return 0;
|
---|
116 |
|
---|
117 | if (!TEST_ptr(p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_FACTOR1))
|
---|
118 | || !TEST_true(get_ulong_via_BN(p, &keydata[P]))
|
---|
119 | || !TEST_ptr(p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_FACTOR2))
|
---|
120 | || !TEST_true(get_ulong_via_BN(p, &keydata[Q]))
|
---|
121 | || !TEST_ptr(p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_FACTOR3))
|
---|
122 | || !TEST_true(get_ulong_via_BN(p, &keydata[F3])))
|
---|
123 | return 0;
|
---|
124 |
|
---|
125 | if (!TEST_ptr(p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_EXPONENT1))
|
---|
126 | || !TEST_true(get_ulong_via_BN(p, &keydata[DP]))
|
---|
127 | || !TEST_ptr(p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_EXPONENT2))
|
---|
128 | || !TEST_true(get_ulong_via_BN(p, &keydata[DQ]))
|
---|
129 | || !TEST_ptr(p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_EXPONENT3))
|
---|
130 | || !TEST_true(get_ulong_via_BN(p, &keydata[E3])))
|
---|
131 | return 0;
|
---|
132 |
|
---|
133 | if (!TEST_ptr(p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_COEFFICIENT1))
|
---|
134 | || !TEST_true(get_ulong_via_BN(p, &keydata[QINV]))
|
---|
135 | || !TEST_ptr(p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_COEFFICIENT2))
|
---|
136 | || !TEST_true(get_ulong_via_BN(p, &keydata[C2])))
|
---|
137 | return 0;
|
---|
138 |
|
---|
139 | return 1;
|
---|
140 | }
|
---|
141 |
|
---|
142 | static int test_pass_rsa(FIXTURE *fixture)
|
---|
143 | {
|
---|
144 | size_t i;
|
---|
145 | int ret = 0;
|
---|
146 | RSA *rsa = NULL;
|
---|
147 | BIGNUM *bn1 = NULL, *bn2 = NULL, *bn3 = NULL;
|
---|
148 | EVP_PKEY *pk = NULL, *dup_pk = NULL;
|
---|
149 | EVP_KEYMGMT *km = NULL, *km1 = NULL, *km2 = NULL, *km3 = NULL;
|
---|
150 | void *provkey = NULL, *provkey2 = NULL;
|
---|
151 | BIGNUM *bn_primes[1] = { NULL };
|
---|
152 | BIGNUM *bn_exps[1] = { NULL };
|
---|
153 | BIGNUM *bn_coeffs[1] = { NULL };
|
---|
154 | /*
|
---|
155 | * 32-bit RSA key, extracted from this command,
|
---|
156 | * executed with OpenSSL 1.0.2:
|
---|
157 | * An extra factor was added just for testing purposes.
|
---|
158 | *
|
---|
159 | * openssl genrsa 32 | openssl rsa -text
|
---|
160 | */
|
---|
161 | static BN_ULONG expected[] = {
|
---|
162 | 0xbc747fc5, /* N */
|
---|
163 | 0x10001, /* E */
|
---|
164 | 0x7b133399, /* D */
|
---|
165 | 0xe963, /* P */
|
---|
166 | 0xceb7, /* Q */
|
---|
167 | 1, /* F3 */
|
---|
168 | 0x8599, /* DP */
|
---|
169 | 0xbd87, /* DQ */
|
---|
170 | 2, /* E3 */
|
---|
171 | 0xcc3b, /* QINV */
|
---|
172 | 3, /* C3 */
|
---|
173 | 0 /* Extra, should remain zero */
|
---|
174 | };
|
---|
175 | static unsigned long keydata[OSSL_NELEM(expected)] = { 0, };
|
---|
176 |
|
---|
177 | if (!TEST_ptr(rsa = RSA_new()))
|
---|
178 | goto err;
|
---|
179 |
|
---|
180 | if (!TEST_ptr(bn1 = BN_new())
|
---|
181 | || !TEST_true(BN_set_word(bn1, expected[N]))
|
---|
182 | || !TEST_ptr(bn2 = BN_new())
|
---|
183 | || !TEST_true(BN_set_word(bn2, expected[E]))
|
---|
184 | || !TEST_ptr(bn3 = BN_new())
|
---|
185 | || !TEST_true(BN_set_word(bn3, expected[D]))
|
---|
186 | || !TEST_true(RSA_set0_key(rsa, bn1, bn2, bn3)))
|
---|
187 | goto err;
|
---|
188 |
|
---|
189 | if (!TEST_ptr(bn1 = BN_new())
|
---|
190 | || !TEST_true(BN_set_word(bn1, expected[P]))
|
---|
191 | || !TEST_ptr(bn2 = BN_new())
|
---|
192 | || !TEST_true(BN_set_word(bn2, expected[Q]))
|
---|
193 | || !TEST_true(RSA_set0_factors(rsa, bn1, bn2)))
|
---|
194 | goto err;
|
---|
195 |
|
---|
196 | if (!TEST_ptr(bn1 = BN_new())
|
---|
197 | || !TEST_true(BN_set_word(bn1, expected[DP]))
|
---|
198 | || !TEST_ptr(bn2 = BN_new())
|
---|
199 | || !TEST_true(BN_set_word(bn2, expected[DQ]))
|
---|
200 | || !TEST_ptr(bn3 = BN_new())
|
---|
201 | || !TEST_true(BN_set_word(bn3, expected[QINV]))
|
---|
202 | || !TEST_true(RSA_set0_crt_params(rsa, bn1, bn2, bn3)))
|
---|
203 | goto err;
|
---|
204 | bn1 = bn2 = bn3 = NULL;
|
---|
205 |
|
---|
206 | if (!TEST_ptr(bn_primes[0] = BN_new())
|
---|
207 | || !TEST_true(BN_set_word(bn_primes[0], expected[F3]))
|
---|
208 | || !TEST_ptr(bn_exps[0] = BN_new())
|
---|
209 | || !TEST_true(BN_set_word(bn_exps[0], expected[E3]))
|
---|
210 | || !TEST_ptr(bn_coeffs[0] = BN_new())
|
---|
211 | || !TEST_true(BN_set_word(bn_coeffs[0], expected[C2]))
|
---|
212 | || !TEST_true(RSA_set0_multi_prime_params(rsa, bn_primes, bn_exps,
|
---|
213 | bn_coeffs, 1)))
|
---|
214 | goto err;
|
---|
215 |
|
---|
216 | if (!TEST_ptr(pk = EVP_PKEY_new())
|
---|
217 | || !TEST_true(EVP_PKEY_assign_RSA(pk, rsa)))
|
---|
218 | goto err;
|
---|
219 | rsa = NULL;
|
---|
220 |
|
---|
221 | if (!TEST_ptr(km1 = EVP_KEYMGMT_fetch(fixture->ctx1, "RSA", NULL))
|
---|
222 | || !TEST_ptr(km2 = EVP_KEYMGMT_fetch(fixture->ctx2, "RSA", NULL))
|
---|
223 | || !TEST_ptr(km3 = EVP_KEYMGMT_fetch(fixture->ctx1, "RSA-PSS", NULL))
|
---|
224 | || !TEST_ptr_ne(km1, km2))
|
---|
225 | goto err;
|
---|
226 |
|
---|
227 | for (;;) {
|
---|
228 | ret = 0;
|
---|
229 | km = km3;
|
---|
230 | /* Check that we can't export an RSA key into an RSA-PSS keymanager */
|
---|
231 | if (!TEST_ptr_null(provkey2 = evp_pkey_export_to_provider(pk, NULL,
|
---|
232 | &km,
|
---|
233 | NULL)))
|
---|
234 | goto err;
|
---|
235 |
|
---|
236 | if (!TEST_ptr(provkey = evp_pkey_export_to_provider(pk, NULL, &km1,
|
---|
237 | NULL))
|
---|
238 | || !TEST_true(evp_keymgmt_export(km2, provkey,
|
---|
239 | OSSL_KEYMGMT_SELECT_KEYPAIR,
|
---|
240 | &export_cb, keydata)))
|
---|
241 | goto err;
|
---|
242 |
|
---|
243 | /*
|
---|
244 | * At this point, the hope is that keydata will have all the numbers
|
---|
245 | * from the key.
|
---|
246 | */
|
---|
247 |
|
---|
248 | for (i = 0; i < OSSL_NELEM(expected); i++) {
|
---|
249 | int rv = TEST_int_eq(expected[i], keydata[i]);
|
---|
250 |
|
---|
251 | if (!rv)
|
---|
252 | TEST_info("i = %zu", i);
|
---|
253 | else
|
---|
254 | ret++;
|
---|
255 | }
|
---|
256 |
|
---|
257 | ret = (ret == OSSL_NELEM(expected));
|
---|
258 |
|
---|
259 | if (!ret || dup_pk != NULL)
|
---|
260 | break;
|
---|
261 |
|
---|
262 | if (!TEST_ptr(dup_pk = EVP_PKEY_dup(pk)))
|
---|
263 | goto err;
|
---|
264 |
|
---|
265 | ret = TEST_int_eq(EVP_PKEY_eq(pk, dup_pk), 1);
|
---|
266 | EVP_PKEY_free(pk);
|
---|
267 | pk = dup_pk;
|
---|
268 | if (!ret)
|
---|
269 | goto err;
|
---|
270 | }
|
---|
271 |
|
---|
272 | err:
|
---|
273 | RSA_free(rsa);
|
---|
274 | BN_free(bn1);
|
---|
275 | BN_free(bn2);
|
---|
276 | BN_free(bn3);
|
---|
277 | EVP_PKEY_free(pk);
|
---|
278 | EVP_KEYMGMT_free(km1);
|
---|
279 | EVP_KEYMGMT_free(km2);
|
---|
280 | EVP_KEYMGMT_free(km3);
|
---|
281 |
|
---|
282 | return ret;
|
---|
283 | }
|
---|
284 |
|
---|
285 | static int (*tests[])(FIXTURE *) = {
|
---|
286 | test_pass_rsa
|
---|
287 | };
|
---|
288 |
|
---|
289 | static int test_pass_key(int n)
|
---|
290 | {
|
---|
291 | SETUP_TEST_FIXTURE(FIXTURE, set_up);
|
---|
292 | EXECUTE_TEST(tests[n], tear_down);
|
---|
293 | return result;
|
---|
294 | }
|
---|
295 |
|
---|
296 | static int test_evp_pkey_export_to_provider(int n)
|
---|
297 | {
|
---|
298 | OSSL_LIB_CTX *libctx = NULL;
|
---|
299 | OSSL_PROVIDER *prov = NULL;
|
---|
300 | X509 *cert = NULL;
|
---|
301 | BIO *bio = NULL;
|
---|
302 | X509_PUBKEY *pubkey = NULL;
|
---|
303 | EVP_KEYMGMT *keymgmt = NULL;
|
---|
304 | EVP_PKEY *pkey = NULL;
|
---|
305 | void *keydata = NULL;
|
---|
306 | int ret = 0;
|
---|
307 |
|
---|
308 | if (!TEST_ptr(libctx = OSSL_LIB_CTX_new())
|
---|
309 | || !TEST_ptr(prov = OSSL_PROVIDER_load(libctx, "default")))
|
---|
310 | goto end;
|
---|
311 |
|
---|
312 | if ((bio = BIO_new_file(cert_filename, "r")) == NULL) {
|
---|
313 | TEST_error("Couldn't open '%s' for reading\n", cert_filename);
|
---|
314 | TEST_openssl_errors();
|
---|
315 | goto end;
|
---|
316 | }
|
---|
317 |
|
---|
318 | if ((cert = PEM_read_bio_X509(bio, NULL, NULL, NULL)) == NULL) {
|
---|
319 | TEST_error("'%s' doesn't appear to be a X.509 certificate in PEM format\n",
|
---|
320 | cert_filename);
|
---|
321 | TEST_openssl_errors();
|
---|
322 | goto end;
|
---|
323 | }
|
---|
324 |
|
---|
325 | pubkey = X509_get_X509_PUBKEY(cert);
|
---|
326 | pkey = X509_PUBKEY_get0(pubkey);
|
---|
327 |
|
---|
328 | if (n == 0) {
|
---|
329 | if (!TEST_ptr(keydata = evp_pkey_export_to_provider(pkey, NULL,
|
---|
330 | NULL, NULL)))
|
---|
331 | goto end;
|
---|
332 | } else if (n == 1) {
|
---|
333 | if (!TEST_ptr(keydata = evp_pkey_export_to_provider(pkey, NULL,
|
---|
334 | &keymgmt, NULL)))
|
---|
335 | goto end;
|
---|
336 | } else {
|
---|
337 | keymgmt = EVP_KEYMGMT_fetch(libctx, "RSA", NULL);
|
---|
338 |
|
---|
339 | if (!TEST_ptr(keydata = evp_pkey_export_to_provider(pkey, NULL,
|
---|
340 | &keymgmt, NULL)))
|
---|
341 | goto end;
|
---|
342 | }
|
---|
343 |
|
---|
344 | ret = 1;
|
---|
345 | end:
|
---|
346 | BIO_free(bio);
|
---|
347 | X509_free(cert);
|
---|
348 | EVP_KEYMGMT_free(keymgmt);
|
---|
349 | OSSL_PROVIDER_unload(prov);
|
---|
350 | OSSL_LIB_CTX_free(libctx);
|
---|
351 | return ret;
|
---|
352 | }
|
---|
353 |
|
---|
354 | int setup_tests(void)
|
---|
355 | {
|
---|
356 | if (!TEST_ptr(cert_filename = test_get_argument(0)))
|
---|
357 | return 0;
|
---|
358 |
|
---|
359 | ADD_ALL_TESTS(test_pass_key, 1);
|
---|
360 | ADD_ALL_TESTS(test_evp_pkey_export_to_provider, 3);
|
---|
361 | return 1;
|
---|
362 | }
|
---|