1 /*
2  * Copyright 2024-2025 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 #include <openssl/provider.h>
11 #include <openssl/params.h>
12 #include <openssl/param_build.h>
13 #include <openssl/core_names.h>
14 #include <openssl/evp.h>
15 #include "testutil.h"
16 #include "fake_cipherprov.h"
17 
18 static OSSL_LIB_CTX *libctx = NULL;
19 static OSSL_PROVIDER *deflprov = NULL;
20 
21 #define KEY_SIZE 16
22 
23 static OSSL_CALLBACK ossl_pkey_todata_cb;
24 
ossl_pkey_todata_cb(const OSSL_PARAM params[],void * arg)25 static int ossl_pkey_todata_cb(const OSSL_PARAM params[], void *arg)
26 {
27     OSSL_PARAM **ret = arg;
28 
29     *ret = OSSL_PARAM_dup(params);
30     return 1;
31 }
32 
test_skey_cipher(void)33 static int test_skey_cipher(void)
34 {
35     int ret = 0;
36     OSSL_PROVIDER *fake_prov = NULL;
37     EVP_SKEY *key = NULL;
38     EVP_CIPHER *fake_cipher = NULL;
39     EVP_CIPHER_CTX *ctx = NULL;
40     const unsigned char import_key[KEY_SIZE] = {
41         0x53, 0x4B, 0x45, 0x59, 0x53, 0x4B, 0x45, 0x59,
42         0x53, 0x4B, 0x45, 0x59, 0x53, 0x4B, 0x45, 0x59,
43     };
44     OSSL_PARAM params[3];
45     OSSL_PARAM *export_params = NULL;
46     const unsigned char *export;
47     size_t export_len;
48 
49     if (!TEST_ptr(fake_prov = fake_cipher_start(libctx)))
50         return 0;
51 
52     /* Do a direct fetch to see it works */
53     fake_cipher = EVP_CIPHER_fetch(libctx, "fake_cipher", FAKE_CIPHER_FETCH_PROPS);
54     if (!TEST_ptr(fake_cipher))
55         goto end;
56 
57     /* Create EVP_SKEY */
58     params[0] = OSSL_PARAM_construct_utf8_string(FAKE_CIPHER_PARAM_KEY_NAME,
59                                                  "fake key name", 0);
60     params[1] = OSSL_PARAM_construct_octet_string(OSSL_SKEY_PARAM_RAW_BYTES,
61                                                   (void *)import_key, KEY_SIZE);
62     params[2] = OSSL_PARAM_construct_end();
63     key = EVP_SKEY_import(libctx, "fake_cipher", FAKE_CIPHER_FETCH_PROPS,
64                           OSSL_SKEYMGMT_SELECT_ALL, params);
65     if (!TEST_ptr(key))
66         goto end;
67 
68     /* Init cipher */
69     if (!TEST_ptr(ctx = EVP_CIPHER_CTX_new())
70         || !TEST_int_gt(EVP_CipherInit_SKEY(ctx, fake_cipher, key, NULL, 0, 1, NULL), 0))
71         goto end;
72 
73     /* Export params */
74     if (!TEST_int_gt(EVP_SKEY_export(key, OSSL_SKEYMGMT_SELECT_SECRET_KEY,
75                                      ossl_pkey_todata_cb, &export_params), 0))
76         goto end;
77 
78     /* Export raw key */
79     if (!TEST_int_gt(EVP_SKEY_get0_raw_key(key, &export, &export_len), 0)
80         || !TEST_mem_eq(export, export_len, import_key, sizeof(import_key)))
81         goto end;
82 
83     ret = 1;
84 
85 end:
86     OSSL_PARAM_free(export_params);
87     EVP_SKEY_free(key);
88     EVP_CIPHER_free(fake_cipher);
89     EVP_CIPHER_CTX_free(ctx);
90     fake_cipher_finish(fake_prov);
91 
92     return ret;
93 }
94 
test_skey_skeymgmt(void)95 static int test_skey_skeymgmt(void)
96 {
97     int ret = 0;
98     EVP_SKEYMGMT *skeymgmt = NULL;
99     EVP_SKEY *key = NULL;
100     const unsigned char import_key[KEY_SIZE] = {
101         0x53, 0x4B, 0x45, 0x59, 0x53, 0x4B, 0x45, 0x59,
102         0x53, 0x4B, 0x45, 0x59, 0x53, 0x4B, 0x45, 0x59,
103     };
104     OSSL_PARAM params[2];
105     const OSSL_PARAM *imp_params;
106     const OSSL_PARAM *p;
107     OSSL_PARAM *exp_params = NULL;
108     const void *export_key = NULL;
109     size_t export_len;
110 
111     deflprov = OSSL_PROVIDER_load(libctx, "default");
112     if (!TEST_ptr(deflprov))
113         return 0;
114 
115     /* Fetch our SKYMGMT for Generic Secrets */
116     if (!TEST_ptr(skeymgmt = EVP_SKEYMGMT_fetch(libctx, OSSL_SKEY_TYPE_GENERIC,
117                                                 NULL)))
118         goto end;
119 
120     /* Check the parameter we need is available */
121     if (!TEST_ptr(imp_params = EVP_SKEYMGMT_get0_imp_settable_params(skeymgmt))
122         || !TEST_ptr(p = OSSL_PARAM_locate_const(imp_params,
123                                                  OSSL_SKEY_PARAM_RAW_BYTES)))
124         goto end;
125 
126     /* Import EVP_SKEY */
127     params[0] = OSSL_PARAM_construct_octet_string(OSSL_SKEY_PARAM_RAW_BYTES,
128                                                   (void *)import_key, KEY_SIZE);
129     params[1] = OSSL_PARAM_construct_end();
130 
131     if (!TEST_ptr(key = EVP_SKEY_import(libctx,
132                                         EVP_SKEYMGMT_get0_name(skeymgmt), NULL,
133                                         OSSL_SKEYMGMT_SELECT_ALL, params)))
134         goto end;
135 
136     /* Export EVP_SKEY */
137     if (!TEST_int_gt(EVP_SKEY_export(key, OSSL_SKEYMGMT_SELECT_SECRET_KEY,
138                                      ossl_pkey_todata_cb, &exp_params), 0)
139         || !TEST_ptr(p = OSSL_PARAM_locate_const(exp_params,
140                                                  OSSL_SKEY_PARAM_RAW_BYTES))
141         || !TEST_int_gt(OSSL_PARAM_get_octet_string_ptr(p, &export_key,
142                                                         &export_len), 0)
143         || !TEST_mem_eq(import_key, KEY_SIZE, export_key, export_len))
144         goto end;
145 
146     ret = 1;
147 end:
148     OSSL_PARAM_free(exp_params);
149     EVP_SKEYMGMT_free(skeymgmt);
150     EVP_SKEY_free(key);
151 
152     return ret;
153 }
154 
155 #define IV_SIZE 16
156 #define DATA_SIZE 32
test_aes_raw_skey(void)157 static int test_aes_raw_skey(void)
158 {
159     const unsigned char data[DATA_SIZE] = {
160         0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2,
161         0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2,
162         0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2,
163         0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2
164     };
165     unsigned char aes_key[KEY_SIZE], aes_iv[IV_SIZE];
166     unsigned char encrypted_skey[DATA_SIZE + IV_SIZE];
167     unsigned char encrypted_raw[DATA_SIZE + IV_SIZE];
168     int enc_len, fin_len;
169     const unsigned char *export_key = NULL;
170     size_t export_length;
171     EVP_CIPHER *aes_cbc = NULL;
172     EVP_CIPHER_CTX *ctx = NULL;
173     EVP_SKEY *skey = NULL;
174     OSSL_PARAM_BLD *tmpl = NULL;
175     OSSL_PARAM *params = NULL;
176     int ret = 0;
177 
178     deflprov = OSSL_PROVIDER_load(libctx, "default");
179     if (!TEST_ptr(deflprov))
180         return 0;
181 
182     memset(encrypted_skey, 0, sizeof(encrypted_skey));
183     memset(encrypted_raw,  0, sizeof(encrypted_raw));
184     memset(aes_key, 1, KEY_SIZE);
185     memset(aes_iv, 2, IV_SIZE);
186 
187     /* Do a direct fetch to see it works */
188     aes_cbc = EVP_CIPHER_fetch(libctx, "AES-128-CBC", "provider=default");
189     if (!TEST_ptr(aes_cbc))
190         goto end;
191 
192     /* Create EVP_SKEY */
193     skey = EVP_SKEY_import_raw_key(libctx, "AES-128", aes_key, KEY_SIZE, NULL);
194     if (!TEST_ptr(skey))
195         goto end;
196 
197     if (!TEST_int_gt(EVP_SKEY_get0_raw_key(skey, &export_key, &export_length), 0)
198         || !TEST_mem_eq(aes_key, KEY_SIZE, export_key, export_length))
199         goto end;
200 
201     enc_len = sizeof(encrypted_skey);
202     fin_len = 0;
203     if (!TEST_ptr(ctx = EVP_CIPHER_CTX_new())
204         || !TEST_int_gt(EVP_CipherInit_SKEY(ctx, aes_cbc, skey, aes_iv, IV_SIZE, 1, NULL), 0)
205         || !TEST_int_gt(EVP_CipherUpdate(ctx, encrypted_skey, &enc_len, data, DATA_SIZE), 0)
206         || !TEST_int_gt(EVP_CipherFinal(ctx, encrypted_skey + enc_len, &fin_len), 0))
207         goto end;
208 
209     EVP_CIPHER_CTX_free(ctx);
210     ctx = EVP_CIPHER_CTX_new();
211 
212     enc_len = sizeof(encrypted_raw);
213     fin_len = 0;
214     if (!TEST_int_gt(EVP_CipherInit_ex2(ctx, aes_cbc, aes_key, aes_iv, 1, NULL), 0)
215         || !TEST_int_gt(EVP_CipherUpdate(ctx, encrypted_raw, &enc_len, data, DATA_SIZE), 0)
216         || !TEST_int_gt(EVP_CipherFinal(ctx, encrypted_raw + enc_len, &fin_len), 0)
217         || !TEST_mem_eq(encrypted_skey, DATA_SIZE + IV_SIZE, encrypted_raw, DATA_SIZE + IV_SIZE))
218         goto end;
219 
220     ret = 1;
221 end:
222     OSSL_PARAM_free(params);
223     OSSL_PARAM_BLD_free(tmpl);
224     EVP_SKEY_free(skey);
225     EVP_CIPHER_free(aes_cbc);
226     EVP_CIPHER_CTX_free(ctx);
227     OSSL_PROVIDER_unload(deflprov);
228     return ret;
229 }
230 
231 #ifndef OPENSSL_NO_DES
232 /* DES is used to test a "skey-unware" cipher provider */
233 # define DES_KEY_SIZE 24
234 # define DES_IV_SIZE 8
test_des_raw_skey(void)235 static int test_des_raw_skey(void)
236 {
237     const unsigned char data[DATA_SIZE] = {
238         0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2,
239         0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2,
240         0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2,
241         0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2
242     };
243     unsigned char des_key[DES_KEY_SIZE], des_iv[DES_IV_SIZE];
244     unsigned char encrypted_skey[DATA_SIZE + DES_IV_SIZE];
245     unsigned char encrypted_raw[DATA_SIZE + DES_IV_SIZE];
246     int enc_len, fin_len;
247     const unsigned char *export_key = NULL;
248     size_t export_length;
249     EVP_CIPHER *des_cbc = NULL;
250     EVP_CIPHER_CTX *ctx = NULL;
251     EVP_SKEY *skey = NULL;
252     int ret = 0;
253 
254     deflprov = OSSL_PROVIDER_load(libctx, "default");
255     if (!TEST_ptr(deflprov))
256         return 0;
257 
258     memset(encrypted_skey, 0, sizeof(encrypted_skey));
259     memset(encrypted_raw,  0, sizeof(encrypted_raw));
260     memset(des_key, 1, DES_KEY_SIZE);
261     memset(des_iv, 2, DES_IV_SIZE);
262 
263     /* Do a direct fetch to see it works */
264     des_cbc = EVP_CIPHER_fetch(libctx, "DES-EDE3-CBC", "provider=default");
265     if (!TEST_ptr(des_cbc))
266         goto end;
267 
268     /* Create EVP_SKEY */
269     skey = EVP_SKEY_import_raw_key(libctx, "DES", des_key, sizeof(des_key),
270                                    NULL);
271     if (!TEST_ptr(skey))
272         goto end;
273 
274     if (!TEST_int_gt(EVP_SKEY_get0_raw_key(skey, &export_key, &export_length), 0)
275         || !TEST_mem_eq(des_key, DES_KEY_SIZE, export_key, export_length))
276         goto end;
277 
278     enc_len = sizeof(encrypted_skey);
279     fin_len = 0;
280     if (!TEST_ptr(ctx = EVP_CIPHER_CTX_new())
281         || !TEST_int_gt(EVP_CipherInit_SKEY(ctx, des_cbc, skey, des_iv, DES_IV_SIZE, 1, NULL), 0)
282         || !TEST_int_gt(EVP_CipherUpdate(ctx, encrypted_skey, &enc_len, data, DATA_SIZE), 0)
283         || !TEST_int_gt(EVP_CipherFinal(ctx, encrypted_skey + enc_len, &fin_len), 0))
284         goto end;
285 
286     EVP_CIPHER_CTX_free(ctx);
287     ctx = EVP_CIPHER_CTX_new();
288 
289     enc_len = sizeof(encrypted_raw);
290     fin_len = 0;
291     if (!TEST_int_gt(EVP_CipherInit_ex2(ctx, des_cbc, des_key, des_iv, 1, NULL), 0)
292         || !TEST_int_gt(EVP_CipherUpdate(ctx, encrypted_raw, &enc_len, data, DATA_SIZE), 0)
293         || !TEST_int_gt(EVP_CipherFinal(ctx, encrypted_raw + enc_len, &fin_len), 0)
294         || !TEST_mem_eq(encrypted_skey, DATA_SIZE + DES_IV_SIZE, encrypted_raw,
295                         DATA_SIZE + DES_IV_SIZE))
296         goto end;
297 
298     ret = 1;
299 end:
300     EVP_SKEY_free(skey);
301     EVP_CIPHER_free(des_cbc);
302     EVP_CIPHER_CTX_free(ctx);
303     OSSL_PROVIDER_unload(deflprov);
304     return ret;
305 }
306 #endif
307 
setup_tests(void)308 int setup_tests(void)
309 {
310     libctx = OSSL_LIB_CTX_new();
311     if (libctx == NULL)
312         return 0;
313 
314     ADD_TEST(test_skey_cipher);
315     ADD_TEST(test_skey_skeymgmt);
316 
317     ADD_TEST(test_aes_raw_skey);
318 #ifndef OPENSSL_NO_DES
319     ADD_TEST(test_des_raw_skey);
320 #endif
321 
322     return 1;
323 }
324 
cleanup_tests(void)325 void cleanup_tests(void)
326 {
327     OSSL_LIB_CTX_free(libctx);
328 }
329