xref: /freebsd/crypto/openssl/test/keymgmt_internal_test.c (revision 67be1e195acfaec99ce4fffeb17111ce085755f7)
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 }
363