1 /*
2 * Copyright 2024-2026 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, 0x53, 0x4B,
42 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),
76 0))
77 goto end;
78
79 /* Export raw key */
80 if (!TEST_int_gt(EVP_SKEY_get0_raw_key(key, &export, &export_len), 0)
81 || !TEST_mem_eq(export, export_len, import_key, sizeof(import_key)))
82 goto end;
83
84 ret = 1;
85
86 end:
87 OSSL_PARAM_free(export_params);
88 EVP_SKEY_free(key);
89 EVP_CIPHER_free(fake_cipher);
90 EVP_CIPHER_CTX_free(ctx);
91 fake_cipher_finish(fake_prov);
92
93 return ret;
94 }
95
96 #define IV_SIZE 16
97 #define DATA_SIZE 32
test_aes_raw_skey(void)98 static int test_aes_raw_skey(void)
99 {
100 const unsigned char data[DATA_SIZE] = {
101 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2,
102 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2,
103 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2,
104 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2
105 };
106 unsigned char aes_key[KEY_SIZE], aes_iv[IV_SIZE];
107 unsigned char encrypted_skey[DATA_SIZE + IV_SIZE];
108 unsigned char encrypted_raw[DATA_SIZE + IV_SIZE];
109 int enc_len, fin_len;
110 const unsigned char *export_key = NULL;
111 size_t export_length;
112 EVP_CIPHER *aes_cbc = NULL;
113 EVP_CIPHER_CTX *ctx = NULL;
114 EVP_SKEY *skey = NULL;
115 OSSL_PARAM_BLD *tmpl = NULL;
116 OSSL_PARAM *params = NULL;
117 int ret = 0;
118
119 deflprov = OSSL_PROVIDER_load(libctx, "default");
120 if (!TEST_ptr(deflprov))
121 return 0;
122
123 memset(encrypted_skey, 0, sizeof(encrypted_skey));
124 memset(encrypted_raw, 0, sizeof(encrypted_raw));
125 memset(aes_key, 1, KEY_SIZE);
126 memset(aes_iv, 2, IV_SIZE);
127
128 /* Do a direct fetch to see it works */
129 aes_cbc = EVP_CIPHER_fetch(libctx, "AES-128-CBC", "provider=default");
130 if (!TEST_ptr(aes_cbc))
131 goto end;
132
133 /* Create EVP_SKEY */
134 skey = EVP_SKEY_import_raw_key(libctx, "AES-128", aes_key, KEY_SIZE, NULL);
135 if (!TEST_ptr(skey))
136 goto end;
137
138 if (!TEST_int_gt(EVP_SKEY_get0_raw_key(skey, &export_key, &export_length), 0)
139 || !TEST_mem_eq(aes_key, KEY_SIZE, export_key, export_length))
140 goto end;
141
142 enc_len = sizeof(encrypted_skey);
143 fin_len = 0;
144 if (!TEST_ptr(ctx = EVP_CIPHER_CTX_new())
145 || !TEST_int_gt(EVP_CipherInit_SKEY(ctx, aes_cbc, skey, aes_iv, IV_SIZE, 1, NULL), 0)
146 || !TEST_int_gt(EVP_CipherUpdate(ctx, encrypted_skey, &enc_len, data, DATA_SIZE), 0)
147 || !TEST_int_gt(EVP_CipherFinal(ctx, encrypted_skey + enc_len, &fin_len), 0))
148 goto end;
149
150 EVP_CIPHER_CTX_free(ctx);
151 ctx = EVP_CIPHER_CTX_new();
152
153 enc_len = sizeof(encrypted_raw);
154 fin_len = 0;
155 if (!TEST_int_gt(EVP_CipherInit_ex2(ctx, aes_cbc, aes_key, aes_iv, 1, NULL), 0)
156 || !TEST_int_gt(EVP_CipherUpdate(ctx, encrypted_raw, &enc_len, data, DATA_SIZE), 0)
157 || !TEST_int_gt(EVP_CipherFinal(ctx, encrypted_raw + enc_len, &fin_len), 0)
158 || !TEST_mem_eq(encrypted_skey, DATA_SIZE + IV_SIZE, encrypted_raw, DATA_SIZE + IV_SIZE))
159 goto end;
160
161 ret = 1;
162 end:
163 OSSL_PARAM_free(params);
164 OSSL_PARAM_BLD_free(tmpl);
165 EVP_SKEY_free(skey);
166 EVP_CIPHER_free(aes_cbc);
167 EVP_CIPHER_CTX_free(ctx);
168 OSSL_PROVIDER_unload(deflprov);
169 return ret;
170 }
171
172 #ifndef OPENSSL_NO_DES
173 /* DES is used to test a "skey-unware" cipher provider */
174 #define DES_KEY_SIZE 24
175 #define DES_IV_SIZE 8
test_des_raw_skey(void)176 static int test_des_raw_skey(void)
177 {
178 const unsigned char data[DATA_SIZE] = {
179 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2,
180 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2,
181 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2,
182 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2
183 };
184 unsigned char des_key[DES_KEY_SIZE], des_iv[DES_IV_SIZE];
185 unsigned char encrypted_skey[DATA_SIZE + DES_IV_SIZE];
186 unsigned char encrypted_raw[DATA_SIZE + DES_IV_SIZE];
187 int enc_len, fin_len;
188 const unsigned char *export_key = NULL;
189 size_t export_length;
190 EVP_CIPHER *des_cbc = NULL;
191 EVP_CIPHER_CTX *ctx = NULL;
192 EVP_SKEY *skey = NULL;
193 int ret = 0;
194
195 deflprov = OSSL_PROVIDER_load(libctx, "default");
196 if (!TEST_ptr(deflprov))
197 return 0;
198
199 memset(encrypted_skey, 0, sizeof(encrypted_skey));
200 memset(encrypted_raw, 0, sizeof(encrypted_raw));
201 memset(des_key, 1, DES_KEY_SIZE);
202 memset(des_iv, 2, DES_IV_SIZE);
203
204 /* Do a direct fetch to see it works */
205 des_cbc = EVP_CIPHER_fetch(libctx, "DES-EDE3-CBC", "provider=default");
206 if (!TEST_ptr(des_cbc))
207 goto end;
208
209 /* Create EVP_SKEY */
210 skey = EVP_SKEY_import_raw_key(libctx, "DES", des_key, sizeof(des_key),
211 NULL);
212 if (!TEST_ptr(skey))
213 goto end;
214
215 if (!TEST_int_gt(EVP_SKEY_get0_raw_key(skey, &export_key, &export_length), 0)
216 || !TEST_mem_eq(des_key, DES_KEY_SIZE, export_key, export_length))
217 goto end;
218
219 enc_len = sizeof(encrypted_skey);
220 fin_len = 0;
221 if (!TEST_ptr(ctx = EVP_CIPHER_CTX_new())
222 || !TEST_int_gt(EVP_CipherInit_SKEY(ctx, des_cbc, skey, des_iv, DES_IV_SIZE, 1, NULL), 0)
223 || !TEST_int_gt(EVP_CipherUpdate(ctx, encrypted_skey, &enc_len, data, DATA_SIZE), 0)
224 || !TEST_int_gt(EVP_CipherFinal(ctx, encrypted_skey + enc_len, &fin_len), 0))
225 goto end;
226
227 EVP_CIPHER_CTX_free(ctx);
228 ctx = EVP_CIPHER_CTX_new();
229
230 enc_len = sizeof(encrypted_raw);
231 fin_len = 0;
232 if (!TEST_int_gt(EVP_CipherInit_ex2(ctx, des_cbc, des_key, des_iv, 1, NULL), 0)
233 || !TEST_int_gt(EVP_CipherUpdate(ctx, encrypted_raw, &enc_len, data, DATA_SIZE), 0)
234 || !TEST_int_gt(EVP_CipherFinal(ctx, encrypted_raw + enc_len, &fin_len), 0)
235 || !TEST_mem_eq(encrypted_skey, DATA_SIZE + DES_IV_SIZE, encrypted_raw,
236 DATA_SIZE + DES_IV_SIZE))
237 goto end;
238
239 ret = 1;
240 end:
241 EVP_SKEY_free(skey);
242 EVP_CIPHER_free(des_cbc);
243 EVP_CIPHER_CTX_free(ctx);
244 OSSL_PROVIDER_unload(deflprov);
245 return ret;
246 }
247 #endif
248
setup_tests(void)249 int setup_tests(void)
250 {
251 libctx = OSSL_LIB_CTX_new();
252 if (libctx == NULL)
253 return 0;
254
255 ADD_TEST(test_skey_cipher);
256
257 ADD_TEST(test_aes_raw_skey);
258 #ifndef OPENSSL_NO_DES
259 ADD_TEST(test_des_raw_skey);
260 #endif
261
262 return 1;
263 }
264
cleanup_tests(void)265 void cleanup_tests(void)
266 {
267 OSSL_LIB_CTX_free(libctx);
268 }
269