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