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