1*e7be843bSPierre Pronchery /*
2*e7be843bSPierre Pronchery * Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved.
3*e7be843bSPierre Pronchery *
4*e7be843bSPierre Pronchery * Licensed under the Apache License 2.0 (the "License"). You may not use
5*e7be843bSPierre Pronchery * this file except in compliance with the License. You can obtain a copy
6*e7be843bSPierre Pronchery * in the file LICENSE in the source distribution or at
7*e7be843bSPierre Pronchery * https://www.openssl.org/source/license.html
8*e7be843bSPierre Pronchery */
9*e7be843bSPierre Pronchery
10*e7be843bSPierre Pronchery #include <openssl/provider.h>
11*e7be843bSPierre Pronchery #include <openssl/params.h>
12*e7be843bSPierre Pronchery #include <openssl/param_build.h>
13*e7be843bSPierre Pronchery #include <openssl/core_names.h>
14*e7be843bSPierre Pronchery #include <openssl/evp.h>
15*e7be843bSPierre Pronchery #include "testutil.h"
16*e7be843bSPierre Pronchery #include "fake_cipherprov.h"
17*e7be843bSPierre Pronchery
18*e7be843bSPierre Pronchery static OSSL_LIB_CTX *libctx = NULL;
19*e7be843bSPierre Pronchery static OSSL_PROVIDER *deflprov = NULL;
20*e7be843bSPierre Pronchery
21*e7be843bSPierre Pronchery #define KEY_SIZE 16
22*e7be843bSPierre Pronchery
23*e7be843bSPierre Pronchery static OSSL_CALLBACK ossl_pkey_todata_cb;
24*e7be843bSPierre Pronchery
ossl_pkey_todata_cb(const OSSL_PARAM params[],void * arg)25*e7be843bSPierre Pronchery static int ossl_pkey_todata_cb(const OSSL_PARAM params[], void *arg)
26*e7be843bSPierre Pronchery {
27*e7be843bSPierre Pronchery OSSL_PARAM **ret = arg;
28*e7be843bSPierre Pronchery
29*e7be843bSPierre Pronchery *ret = OSSL_PARAM_dup(params);
30*e7be843bSPierre Pronchery return 1;
31*e7be843bSPierre Pronchery }
32*e7be843bSPierre Pronchery
test_skey_cipher(void)33*e7be843bSPierre Pronchery static int test_skey_cipher(void)
34*e7be843bSPierre Pronchery {
35*e7be843bSPierre Pronchery int ret = 0;
36*e7be843bSPierre Pronchery OSSL_PROVIDER *fake_prov = NULL;
37*e7be843bSPierre Pronchery EVP_SKEY *key = NULL;
38*e7be843bSPierre Pronchery EVP_CIPHER *fake_cipher = NULL;
39*e7be843bSPierre Pronchery EVP_CIPHER_CTX *ctx = NULL;
40*e7be843bSPierre Pronchery const unsigned char import_key[KEY_SIZE] = {
41*e7be843bSPierre Pronchery 0x53, 0x4B, 0x45, 0x59, 0x53, 0x4B, 0x45, 0x59,
42*e7be843bSPierre Pronchery 0x53, 0x4B, 0x45, 0x59, 0x53, 0x4B, 0x45, 0x59,
43*e7be843bSPierre Pronchery };
44*e7be843bSPierre Pronchery OSSL_PARAM params[3];
45*e7be843bSPierre Pronchery OSSL_PARAM *export_params = NULL;
46*e7be843bSPierre Pronchery const unsigned char *export;
47*e7be843bSPierre Pronchery size_t export_len;
48*e7be843bSPierre Pronchery
49*e7be843bSPierre Pronchery if (!TEST_ptr(fake_prov = fake_cipher_start(libctx)))
50*e7be843bSPierre Pronchery return 0;
51*e7be843bSPierre Pronchery
52*e7be843bSPierre Pronchery /* Do a direct fetch to see it works */
53*e7be843bSPierre Pronchery fake_cipher = EVP_CIPHER_fetch(libctx, "fake_cipher", FAKE_CIPHER_FETCH_PROPS);
54*e7be843bSPierre Pronchery if (!TEST_ptr(fake_cipher))
55*e7be843bSPierre Pronchery goto end;
56*e7be843bSPierre Pronchery
57*e7be843bSPierre Pronchery /* Create EVP_SKEY */
58*e7be843bSPierre Pronchery params[0] = OSSL_PARAM_construct_utf8_string(FAKE_CIPHER_PARAM_KEY_NAME,
59*e7be843bSPierre Pronchery "fake key name", 0);
60*e7be843bSPierre Pronchery params[1] = OSSL_PARAM_construct_octet_string(OSSL_SKEY_PARAM_RAW_BYTES,
61*e7be843bSPierre Pronchery (void *)import_key, KEY_SIZE);
62*e7be843bSPierre Pronchery params[2] = OSSL_PARAM_construct_end();
63*e7be843bSPierre Pronchery key = EVP_SKEY_import(libctx, "fake_cipher", FAKE_CIPHER_FETCH_PROPS,
64*e7be843bSPierre Pronchery OSSL_SKEYMGMT_SELECT_ALL, params);
65*e7be843bSPierre Pronchery if (!TEST_ptr(key))
66*e7be843bSPierre Pronchery goto end;
67*e7be843bSPierre Pronchery
68*e7be843bSPierre Pronchery /* Init cipher */
69*e7be843bSPierre Pronchery if (!TEST_ptr(ctx = EVP_CIPHER_CTX_new())
70*e7be843bSPierre Pronchery || !TEST_int_gt(EVP_CipherInit_SKEY(ctx, fake_cipher, key, NULL, 0, 1, NULL), 0))
71*e7be843bSPierre Pronchery goto end;
72*e7be843bSPierre Pronchery
73*e7be843bSPierre Pronchery /* Export params */
74*e7be843bSPierre Pronchery if (!TEST_int_gt(EVP_SKEY_export(key, OSSL_SKEYMGMT_SELECT_SECRET_KEY,
75*e7be843bSPierre Pronchery ossl_pkey_todata_cb, &export_params), 0))
76*e7be843bSPierre Pronchery goto end;
77*e7be843bSPierre Pronchery
78*e7be843bSPierre Pronchery /* Export raw key */
79*e7be843bSPierre Pronchery if (!TEST_int_gt(EVP_SKEY_get0_raw_key(key, &export, &export_len), 0)
80*e7be843bSPierre Pronchery || !TEST_mem_eq(export, export_len, import_key, sizeof(import_key)))
81*e7be843bSPierre Pronchery goto end;
82*e7be843bSPierre Pronchery
83*e7be843bSPierre Pronchery ret = 1;
84*e7be843bSPierre Pronchery
85*e7be843bSPierre Pronchery end:
86*e7be843bSPierre Pronchery OSSL_PARAM_free(export_params);
87*e7be843bSPierre Pronchery EVP_SKEY_free(key);
88*e7be843bSPierre Pronchery EVP_CIPHER_free(fake_cipher);
89*e7be843bSPierre Pronchery EVP_CIPHER_CTX_free(ctx);
90*e7be843bSPierre Pronchery fake_cipher_finish(fake_prov);
91*e7be843bSPierre Pronchery
92*e7be843bSPierre Pronchery return ret;
93*e7be843bSPierre Pronchery }
94*e7be843bSPierre Pronchery
95*e7be843bSPierre Pronchery #define IV_SIZE 16
96*e7be843bSPierre Pronchery #define DATA_SIZE 32
test_aes_raw_skey(void)97*e7be843bSPierre Pronchery static int test_aes_raw_skey(void)
98*e7be843bSPierre Pronchery {
99*e7be843bSPierre Pronchery const unsigned char data[DATA_SIZE] = {
100*e7be843bSPierre Pronchery 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2,
101*e7be843bSPierre Pronchery 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2,
102*e7be843bSPierre Pronchery 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2,
103*e7be843bSPierre Pronchery 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2
104*e7be843bSPierre Pronchery };
105*e7be843bSPierre Pronchery unsigned char aes_key[KEY_SIZE], aes_iv[IV_SIZE];
106*e7be843bSPierre Pronchery unsigned char encrypted_skey[DATA_SIZE + IV_SIZE];
107*e7be843bSPierre Pronchery unsigned char encrypted_raw[DATA_SIZE + IV_SIZE];
108*e7be843bSPierre Pronchery int enc_len, fin_len;
109*e7be843bSPierre Pronchery const unsigned char *export_key = NULL;
110*e7be843bSPierre Pronchery size_t export_length;
111*e7be843bSPierre Pronchery EVP_CIPHER *aes_cbc = NULL;
112*e7be843bSPierre Pronchery EVP_CIPHER_CTX *ctx = NULL;
113*e7be843bSPierre Pronchery EVP_SKEY *skey = NULL;
114*e7be843bSPierre Pronchery OSSL_PARAM_BLD *tmpl = NULL;
115*e7be843bSPierre Pronchery OSSL_PARAM *params = NULL;
116*e7be843bSPierre Pronchery int ret = 0;
117*e7be843bSPierre Pronchery
118*e7be843bSPierre Pronchery deflprov = OSSL_PROVIDER_load(libctx, "default");
119*e7be843bSPierre Pronchery if (!TEST_ptr(deflprov))
120*e7be843bSPierre Pronchery return 0;
121*e7be843bSPierre Pronchery
122*e7be843bSPierre Pronchery memset(encrypted_skey, 0, sizeof(encrypted_skey));
123*e7be843bSPierre Pronchery memset(encrypted_raw, 0, sizeof(encrypted_raw));
124*e7be843bSPierre Pronchery memset(aes_key, 1, KEY_SIZE);
125*e7be843bSPierre Pronchery memset(aes_iv, 2, IV_SIZE);
126*e7be843bSPierre Pronchery
127*e7be843bSPierre Pronchery /* Do a direct fetch to see it works */
128*e7be843bSPierre Pronchery aes_cbc = EVP_CIPHER_fetch(libctx, "AES-128-CBC", "provider=default");
129*e7be843bSPierre Pronchery if (!TEST_ptr(aes_cbc))
130*e7be843bSPierre Pronchery goto end;
131*e7be843bSPierre Pronchery
132*e7be843bSPierre Pronchery /* Create EVP_SKEY */
133*e7be843bSPierre Pronchery skey = EVP_SKEY_import_raw_key(libctx, "AES-128", aes_key, KEY_SIZE, NULL);
134*e7be843bSPierre Pronchery if (!TEST_ptr(skey))
135*e7be843bSPierre Pronchery goto end;
136*e7be843bSPierre Pronchery
137*e7be843bSPierre Pronchery if (!TEST_int_gt(EVP_SKEY_get0_raw_key(skey, &export_key, &export_length), 0)
138*e7be843bSPierre Pronchery || !TEST_mem_eq(aes_key, KEY_SIZE, export_key, export_length))
139*e7be843bSPierre Pronchery goto end;
140*e7be843bSPierre Pronchery
141*e7be843bSPierre Pronchery enc_len = sizeof(encrypted_skey);
142*e7be843bSPierre Pronchery fin_len = 0;
143*e7be843bSPierre Pronchery if (!TEST_ptr(ctx = EVP_CIPHER_CTX_new())
144*e7be843bSPierre Pronchery || !TEST_int_gt(EVP_CipherInit_SKEY(ctx, aes_cbc, skey, aes_iv, IV_SIZE, 1, NULL), 0)
145*e7be843bSPierre Pronchery || !TEST_int_gt(EVP_CipherUpdate(ctx, encrypted_skey, &enc_len, data, DATA_SIZE), 0)
146*e7be843bSPierre Pronchery || !TEST_int_gt(EVP_CipherFinal(ctx, encrypted_skey + enc_len, &fin_len), 0))
147*e7be843bSPierre Pronchery goto end;
148*e7be843bSPierre Pronchery
149*e7be843bSPierre Pronchery EVP_CIPHER_CTX_free(ctx);
150*e7be843bSPierre Pronchery ctx = EVP_CIPHER_CTX_new();
151*e7be843bSPierre Pronchery
152*e7be843bSPierre Pronchery enc_len = sizeof(encrypted_raw);
153*e7be843bSPierre Pronchery fin_len = 0;
154*e7be843bSPierre Pronchery if (!TEST_int_gt(EVP_CipherInit_ex2(ctx, aes_cbc, aes_key, aes_iv, 1, NULL), 0)
155*e7be843bSPierre Pronchery || !TEST_int_gt(EVP_CipherUpdate(ctx, encrypted_raw, &enc_len, data, DATA_SIZE), 0)
156*e7be843bSPierre Pronchery || !TEST_int_gt(EVP_CipherFinal(ctx, encrypted_raw + enc_len, &fin_len), 0)
157*e7be843bSPierre Pronchery || !TEST_mem_eq(encrypted_skey, DATA_SIZE + IV_SIZE, encrypted_raw, DATA_SIZE + IV_SIZE))
158*e7be843bSPierre Pronchery goto end;
159*e7be843bSPierre Pronchery
160*e7be843bSPierre Pronchery ret = 1;
161*e7be843bSPierre Pronchery end:
162*e7be843bSPierre Pronchery OSSL_PARAM_free(params);
163*e7be843bSPierre Pronchery OSSL_PARAM_BLD_free(tmpl);
164*e7be843bSPierre Pronchery EVP_SKEY_free(skey);
165*e7be843bSPierre Pronchery EVP_CIPHER_free(aes_cbc);
166*e7be843bSPierre Pronchery EVP_CIPHER_CTX_free(ctx);
167*e7be843bSPierre Pronchery OSSL_PROVIDER_unload(deflprov);
168*e7be843bSPierre Pronchery return ret;
169*e7be843bSPierre Pronchery }
170*e7be843bSPierre Pronchery
171*e7be843bSPierre Pronchery #ifndef OPENSSL_NO_DES
172*e7be843bSPierre Pronchery /* DES is used to test a "skey-unware" cipher provider */
173*e7be843bSPierre Pronchery # define DES_KEY_SIZE 24
174*e7be843bSPierre Pronchery # define DES_IV_SIZE 8
test_des_raw_skey(void)175*e7be843bSPierre Pronchery static int test_des_raw_skey(void)
176*e7be843bSPierre Pronchery {
177*e7be843bSPierre Pronchery const unsigned char data[DATA_SIZE] = {
178*e7be843bSPierre Pronchery 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2,
179*e7be843bSPierre Pronchery 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2,
180*e7be843bSPierre Pronchery 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2,
181*e7be843bSPierre Pronchery 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2
182*e7be843bSPierre Pronchery };
183*e7be843bSPierre Pronchery unsigned char des_key[DES_KEY_SIZE], des_iv[DES_IV_SIZE];
184*e7be843bSPierre Pronchery unsigned char encrypted_skey[DATA_SIZE + DES_IV_SIZE];
185*e7be843bSPierre Pronchery unsigned char encrypted_raw[DATA_SIZE + DES_IV_SIZE];
186*e7be843bSPierre Pronchery int enc_len, fin_len;
187*e7be843bSPierre Pronchery const unsigned char *export_key = NULL;
188*e7be843bSPierre Pronchery size_t export_length;
189*e7be843bSPierre Pronchery EVP_CIPHER *des_cbc = NULL;
190*e7be843bSPierre Pronchery EVP_CIPHER_CTX *ctx = NULL;
191*e7be843bSPierre Pronchery EVP_SKEY *skey = NULL;
192*e7be843bSPierre Pronchery int ret = 0;
193*e7be843bSPierre Pronchery
194*e7be843bSPierre Pronchery deflprov = OSSL_PROVIDER_load(libctx, "default");
195*e7be843bSPierre Pronchery if (!TEST_ptr(deflprov))
196*e7be843bSPierre Pronchery return 0;
197*e7be843bSPierre Pronchery
198*e7be843bSPierre Pronchery memset(encrypted_skey, 0, sizeof(encrypted_skey));
199*e7be843bSPierre Pronchery memset(encrypted_raw, 0, sizeof(encrypted_raw));
200*e7be843bSPierre Pronchery memset(des_key, 1, DES_KEY_SIZE);
201*e7be843bSPierre Pronchery memset(des_iv, 2, DES_IV_SIZE);
202*e7be843bSPierre Pronchery
203*e7be843bSPierre Pronchery /* Do a direct fetch to see it works */
204*e7be843bSPierre Pronchery des_cbc = EVP_CIPHER_fetch(libctx, "DES-EDE3-CBC", "provider=default");
205*e7be843bSPierre Pronchery if (!TEST_ptr(des_cbc))
206*e7be843bSPierre Pronchery goto end;
207*e7be843bSPierre Pronchery
208*e7be843bSPierre Pronchery /* Create EVP_SKEY */
209*e7be843bSPierre Pronchery skey = EVP_SKEY_import_raw_key(libctx, "DES", des_key, sizeof(des_key),
210*e7be843bSPierre Pronchery NULL);
211*e7be843bSPierre Pronchery if (!TEST_ptr(skey))
212*e7be843bSPierre Pronchery goto end;
213*e7be843bSPierre Pronchery
214*e7be843bSPierre Pronchery if (!TEST_int_gt(EVP_SKEY_get0_raw_key(skey, &export_key, &export_length), 0)
215*e7be843bSPierre Pronchery || !TEST_mem_eq(des_key, DES_KEY_SIZE, export_key, export_length))
216*e7be843bSPierre Pronchery goto end;
217*e7be843bSPierre Pronchery
218*e7be843bSPierre Pronchery enc_len = sizeof(encrypted_skey);
219*e7be843bSPierre Pronchery fin_len = 0;
220*e7be843bSPierre Pronchery if (!TEST_ptr(ctx = EVP_CIPHER_CTX_new())
221*e7be843bSPierre Pronchery || !TEST_int_gt(EVP_CipherInit_SKEY(ctx, des_cbc, skey, des_iv, DES_IV_SIZE, 1, NULL), 0)
222*e7be843bSPierre Pronchery || !TEST_int_gt(EVP_CipherUpdate(ctx, encrypted_skey, &enc_len, data, DATA_SIZE), 0)
223*e7be843bSPierre Pronchery || !TEST_int_gt(EVP_CipherFinal(ctx, encrypted_skey + enc_len, &fin_len), 0))
224*e7be843bSPierre Pronchery goto end;
225*e7be843bSPierre Pronchery
226*e7be843bSPierre Pronchery EVP_CIPHER_CTX_free(ctx);
227*e7be843bSPierre Pronchery ctx = EVP_CIPHER_CTX_new();
228*e7be843bSPierre Pronchery
229*e7be843bSPierre Pronchery enc_len = sizeof(encrypted_raw);
230*e7be843bSPierre Pronchery fin_len = 0;
231*e7be843bSPierre Pronchery if (!TEST_int_gt(EVP_CipherInit_ex2(ctx, des_cbc, des_key, des_iv, 1, NULL), 0)
232*e7be843bSPierre Pronchery || !TEST_int_gt(EVP_CipherUpdate(ctx, encrypted_raw, &enc_len, data, DATA_SIZE), 0)
233*e7be843bSPierre Pronchery || !TEST_int_gt(EVP_CipherFinal(ctx, encrypted_raw + enc_len, &fin_len), 0)
234*e7be843bSPierre Pronchery || !TEST_mem_eq(encrypted_skey, DATA_SIZE + DES_IV_SIZE, encrypted_raw,
235*e7be843bSPierre Pronchery DATA_SIZE + DES_IV_SIZE))
236*e7be843bSPierre Pronchery goto end;
237*e7be843bSPierre Pronchery
238*e7be843bSPierre Pronchery ret = 1;
239*e7be843bSPierre Pronchery end:
240*e7be843bSPierre Pronchery EVP_SKEY_free(skey);
241*e7be843bSPierre Pronchery EVP_CIPHER_free(des_cbc);
242*e7be843bSPierre Pronchery EVP_CIPHER_CTX_free(ctx);
243*e7be843bSPierre Pronchery OSSL_PROVIDER_unload(deflprov);
244*e7be843bSPierre Pronchery return ret;
245*e7be843bSPierre Pronchery }
246*e7be843bSPierre Pronchery #endif
247*e7be843bSPierre Pronchery
setup_tests(void)248*e7be843bSPierre Pronchery int setup_tests(void)
249*e7be843bSPierre Pronchery {
250*e7be843bSPierre Pronchery libctx = OSSL_LIB_CTX_new();
251*e7be843bSPierre Pronchery if (libctx == NULL)
252*e7be843bSPierre Pronchery return 0;
253*e7be843bSPierre Pronchery
254*e7be843bSPierre Pronchery ADD_TEST(test_skey_cipher);
255*e7be843bSPierre Pronchery
256*e7be843bSPierre Pronchery ADD_TEST(test_aes_raw_skey);
257*e7be843bSPierre Pronchery #ifndef OPENSSL_NO_DES
258*e7be843bSPierre Pronchery ADD_TEST(test_des_raw_skey);
259*e7be843bSPierre Pronchery #endif
260*e7be843bSPierre Pronchery
261*e7be843bSPierre Pronchery return 1;
262*e7be843bSPierre Pronchery }
263*e7be843bSPierre Pronchery
cleanup_tests(void)264*e7be843bSPierre Pronchery void cleanup_tests(void)
265*e7be843bSPierre Pronchery {
266*e7be843bSPierre Pronchery OSSL_LIB_CTX_free(libctx);
267*e7be843bSPierre Pronchery }
268