xref: /openssl/test/evp_pkey_dhkem_test.c (revision da1c088f)
1 /*
2  * Copyright 2022-2023 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/evp.h>
11 #include <openssl/core_names.h>
12 #include <openssl/param_build.h>
13 #include <openssl/proverr.h>
14 #include "internal/nelem.h"
15 #include "testutil.h"
16 
17 #define TEST_KEM_ENCAP       0
18 #define TEST_KEM_DECAP       1
19 #define TEST_KEM_ENCAP_DECAP 2
20 
21 #define TEST_TYPE_AUTH        0
22 #define TEST_TYPE_NOAUTH      1
23 #define TEST_TYPE_AUTH_NOAUTH 2
24 
25 #define TEST_KEYTYPE_P256         0
26 #define TEST_KEYTYPE_X25519       1
27 #define TEST_KEYTYPES_P256_X25519 2
28 
29 static OSSL_LIB_CTX *libctx = NULL;
30 static OSSL_PROVIDER *nullprov = NULL;
31 static OSSL_PROVIDER *libprov = NULL;
32 static OSSL_PARAM opparam[2];
33 static EVP_PKEY *rkey[TEST_KEYTYPES_P256_X25519] = { NULL, NULL };
34 static EVP_PKEY_CTX *rctx[TEST_KEYTYPES_P256_X25519] = { NULL, NULL };
35 
36 #include "dhkem_test.inc"
37 
38 /* Perform encapsulate KAT's */
test_dhkem_encapsulate(int tstid)39 static int test_dhkem_encapsulate(int tstid)
40 {
41     int ret = 0;
42     EVP_PKEY *rpub = NULL, *spriv = NULL;
43     const TEST_ENCAPDATA *t = &ec_encapdata[tstid];
44 
45     TEST_note("Test %s %s Decapsulate", t->curve,
46               t->spriv != NULL ? "Auth" : "");
47 
48     if (!TEST_ptr(rpub = new_raw_public_key(t->curve, t->rpub, t->rpublen)))
49         goto err;
50 
51     if (t->spriv != NULL) {
52         if (!TEST_ptr(spriv = new_raw_private_key(t->curve,
53                                                   t->spriv, t->sprivlen,
54                                                   t->spub, t->spublen)))
55             goto err;
56     }
57     ret = do_encap(t, rpub, spriv);
58 err:
59     EVP_PKEY_free(spriv);
60     EVP_PKEY_free(rpub);
61     return ret;
62 }
63 
64 /* Perform decapsulate KAT's */
test_dhkem_decapsulate(int tstid)65 static int test_dhkem_decapsulate(int tstid)
66 {
67     int ret = 0;
68     EVP_PKEY *rpriv = NULL, *spub = NULL;
69     const TEST_ENCAPDATA *t = &ec_encapdata[tstid];
70 
71     TEST_note("Test %s %s Decapsulate", t->curve, t->spub != NULL ? "Auth" : "");
72 
73     if (!TEST_ptr(rpriv = new_raw_private_key(t->curve, t->rpriv, t->rprivlen,
74                                               t->rpub, t->rpublen)))
75         goto err;
76     if (t->spub != NULL) {
77         if (!TEST_ptr(spub = new_raw_public_key(t->curve, t->spub, t->spublen)))
78             goto err;
79     }
80     ret = do_decap(t, rpriv, spub);
81 err:
82     EVP_PKEY_free(spub);
83     EVP_PKEY_free(rpriv);
84     return ret;
85 }
86 
87 /* Test that there are settables and they have correct data types */
test_settables(int tstid)88 static int test_settables(int tstid)
89 {
90     EVP_PKEY_CTX *ctx = rctx[tstid];
91     const OSSL_PARAM *settableparams;
92     const OSSL_PARAM *p;
93 
94     return TEST_int_eq(EVP_PKEY_encapsulate_init(ctx, NULL), 1)
95            && TEST_ptr(settableparams = EVP_PKEY_CTX_settable_params(ctx))
96            && TEST_ptr(p = OSSL_PARAM_locate_const(settableparams,
97                                                    OSSL_KEM_PARAM_OPERATION))
98            && TEST_uint_eq(p->data_type, OSSL_PARAM_UTF8_STRING)
99            && TEST_ptr(p = OSSL_PARAM_locate_const(settableparams,
100                                                    OSSL_KEM_PARAM_IKME))
101           && TEST_uint_eq(p->data_type, OSSL_PARAM_OCTET_STRING);
102 }
103 
104 /* Test initing multiple times passes */
test_init_multiple(int tstid)105 static int test_init_multiple(int tstid)
106 {
107     EVP_PKEY_CTX *ctx = rctx[tstid];
108 
109     return TEST_int_eq(EVP_PKEY_encapsulate_init(ctx, NULL), 1)
110            && TEST_int_eq(EVP_PKEY_encapsulate_init(ctx, NULL), 1)
111            && TEST_int_eq(EVP_PKEY_decapsulate_init(ctx, NULL), 1)
112            && TEST_int_eq(EVP_PKEY_decapsulate_init(ctx, NULL), 1);
113 }
114 
115 /* Fail is various bad inputs are passed to the derivekey (keygen) operation */
test_ec_dhkem_derivekey_fail(void)116 static int test_ec_dhkem_derivekey_fail(void)
117 {
118     int ret = 0;
119     EVP_PKEY *pkey = NULL;
120     OSSL_PARAM params[3];
121     EVP_PKEY_CTX *genctx = NULL;
122     const TEST_DERIVEKEY_DATA *t = &ec_derivekey_data[0];
123     BIGNUM *priv = NULL;
124 
125     /* Check non nist curve fails */
126     params[0] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME,
127                                                  "secp256k1", 0);
128     params[1] = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_DHKEM_IKM,
129                                                   (char *)t->ikm, t->ikmlen);
130     params[2] = OSSL_PARAM_construct_end();
131 
132     if (!TEST_ptr(genctx = EVP_PKEY_CTX_new_from_name(libctx, "EC", NULL))
133         || !TEST_int_eq(EVP_PKEY_keygen_init(genctx), 1)
134         || !TEST_int_eq(EVP_PKEY_CTX_set_params(genctx, params), 1)
135         || !TEST_int_eq(EVP_PKEY_generate(genctx, &pkey),0))
136         goto err;
137 
138     /* Fail if curve is not one of P-256, P-384 or P-521 */
139     params[0] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME,
140                                                  "P-224", 0);
141     params[1] = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_DHKEM_IKM,
142                                                   (char *)t->ikm, t->ikmlen);
143     params[2] = OSSL_PARAM_construct_end();
144     if (!TEST_int_eq(EVP_PKEY_keygen_init(genctx), 1)
145         || !TEST_int_eq(EVP_PKEY_CTX_set_params(genctx, params), 1)
146         || !TEST_int_eq(EVP_PKEY_generate(genctx, &pkey), 0))
147         goto err;
148 
149     /* Fail if ikm len is too small*/
150     params[0] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME,
151                                                  "P-256", 0);
152     params[1] = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_DHKEM_IKM,
153                                                   (char *)t->ikm, t->ikmlen - 1);
154     params[2] = OSSL_PARAM_construct_end();
155     if (!TEST_int_eq(EVP_PKEY_CTX_set_params(genctx, params), 1)
156         || !TEST_int_eq(EVP_PKEY_generate(genctx, &pkey), 0))
157         goto err;
158 
159     ret = 1;
160 err:
161     BN_free(priv);
162     EVP_PKEY_free(pkey);
163     EVP_PKEY_CTX_free(genctx);
164     return ret;
165 }
166 
167 /* Fail if the operation parameter is not set */
test_no_operation_set(int tstid)168 static int test_no_operation_set(int tstid)
169 {
170     EVP_PKEY_CTX *ctx = rctx[tstid];
171     const TEST_ENCAPDATA *t = &ec_encapdata[tstid];
172     size_t len = 0;
173 
174     return TEST_int_eq(EVP_PKEY_encapsulate_init(ctx, NULL), 1)
175            && TEST_int_eq(EVP_PKEY_encapsulate(ctx, NULL, &len, NULL, NULL), -2)
176            && TEST_int_eq(EVP_PKEY_decapsulate_init(ctx, NULL), 1)
177            && TEST_int_eq(EVP_PKEY_decapsulate(ctx, NULL, &len,
178                                                t->expected_enc,
179                                                t->expected_enclen), -2);
180 }
181 
182 /* Fail if the ikm is too small */
test_ikm_small(int tstid)183 static int test_ikm_small(int tstid)
184 {
185     unsigned char tmp[16] = { 0 };
186     unsigned char secret[256];
187     unsigned char enc[256];
188     size_t secretlen = sizeof(secret);
189     size_t enclen = sizeof(enc);
190     OSSL_PARAM params[3];
191     EVP_PKEY_CTX *ctx = rctx[tstid];
192 
193     params[0] = OSSL_PARAM_construct_utf8_string(OSSL_KEM_PARAM_OPERATION,
194                                                  OSSL_KEM_PARAM_OPERATION_DHKEM,
195                                                  0);
196     params[1] = OSSL_PARAM_construct_octet_string(OSSL_KEM_PARAM_IKME,
197                                                   tmp, sizeof(tmp));
198     params[2] = OSSL_PARAM_construct_end();
199 
200     return TEST_int_eq(EVP_PKEY_encapsulate_init(ctx, params), 1)
201            && TEST_int_eq(EVP_PKEY_encapsulate(ctx, enc, &enclen,
202                                                secret, &secretlen), 0);
203 }
204 
205 /* Fail if buffers lengths are too small to hold returned data */
test_input_size_small(int tstid)206 static int test_input_size_small(int tstid)
207 {
208     int ret = 0;
209     unsigned char sec[256];
210     unsigned char enc[256];
211     size_t seclen = sizeof(sec);
212     size_t enclen = sizeof(enc);
213     EVP_PKEY_CTX *ctx = rctx[tstid];
214 
215     if (!TEST_int_eq(EVP_PKEY_encapsulate_init(ctx, opparam), 1)
216         || !TEST_int_eq(EVP_PKEY_encapsulate(ctx, NULL, &enclen,
217                                              NULL, &seclen), 1))
218     goto err;
219 
220     /* buffer too small for enc */
221     enclen--;
222     if (!TEST_int_eq(EVP_PKEY_encapsulate(ctx, enc, &enclen, sec, &seclen),
223                      0))
224         goto err;
225     enclen++;
226     /* buffer too small for secret */
227     seclen--;
228     if (!TEST_int_eq(EVP_PKEY_encapsulate(ctx, enc, &enclen, sec, &seclen), 0))
229         goto err;
230     seclen++;
231     if (!TEST_int_eq(EVP_PKEY_decapsulate_init(ctx, opparam), 1))
232         goto err;
233      /* buffer too small for decapsulate secret */
234     seclen--;
235     if (!TEST_int_eq(EVP_PKEY_decapsulate(ctx, sec, &seclen, enc, enclen), 0))
236         goto err;
237     seclen++;
238      /* incorrect enclen passed to decap  */
239     enclen--;
240     ret = TEST_int_eq(EVP_PKEY_decapsulate(ctx, sec, &seclen, enc, enclen), 0);
241 err:
242     return ret;
243 }
244 
245 /* Fail if the auth key has a different curve */
test_ec_auth_key_curve_mismatch(void)246 static int test_ec_auth_key_curve_mismatch(void)
247 {
248     int ret = 0;
249     EVP_PKEY *auth = NULL;
250 
251     if (!TEST_ptr(auth = EVP_PKEY_Q_keygen(libctx, NULL, "EC", "P-521")))
252         return 0;
253 
254     ret = TEST_int_eq(EVP_PKEY_auth_encapsulate_init(rctx[0], auth, opparam), 0);
255     EVP_PKEY_free(auth);
256     return ret;
257 }
258 
259 /* Fail if the auth key has a different key type to the recipient */
test_auth_key_type_mismatch(int tstid)260 static int test_auth_key_type_mismatch(int tstid)
261 {
262     int id1 = tstid;
263     int id2 = !tstid;
264 
265     return TEST_int_eq(EVP_PKEY_auth_encapsulate_init(rctx[id1],
266                                                       rkey[id2], opparam), 0);
267 }
268 
test_ec_invalid_private_key(void)269 static int test_ec_invalid_private_key(void)
270 {
271     int ret = 0;
272     EVP_PKEY *priv = NULL;
273     EVP_PKEY_CTX *ctx = NULL;
274     const TEST_ENCAPDATA *t = &ec_encapdata[0];
275     static const unsigned char order[] = {
276         0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
277         0xFF, 0xFF, 0xFF, 0xFF, 0xBC, 0xE6, 0xFA, 0xAD, 0xA7, 0x17, 0x9E, 0x84,
278         0xF3, 0xB9, 0xCA, 0xC2, 0xFC, 0x63, 0x25, 0x51
279     };
280 
281     ret = TEST_ptr(priv = new_raw_private_key("P-256", order, sizeof(order),
282                                               t->rpub, t->rpublen))
283           && TEST_ptr(ctx = EVP_PKEY_CTX_new_from_pkey(libctx, priv, NULL))
284           && TEST_int_eq(EVP_PKEY_encapsulate_init(ctx, NULL), 0);
285     EVP_PKEY_free(priv);
286     EVP_PKEY_CTX_free(ctx);
287     return ret;
288 }
289 
test_ec_public_key_infinity(void)290 static int test_ec_public_key_infinity(void)
291 {
292     int ret = 0;
293     EVP_PKEY *key = NULL;
294     EVP_PKEY_CTX *keyctx = NULL;
295     unsigned char s[256];
296     unsigned char e[256];
297     size_t slen = sizeof(s);
298     size_t elen = sizeof(e);
299     unsigned char tmp[1] = { 0 }; /* The encoding for an EC point at infinity */
300     EVP_PKEY_CTX *ctx = rctx[0];
301     const TEST_ENCAPDATA *t = &ec_encapdata[0];
302 
303     ret = TEST_ptr(key = new_raw_private_key(t->curve, t->rpriv, t->rprivlen,
304                                                 tmp, sizeof(tmp)))
305           && TEST_ptr(keyctx = EVP_PKEY_CTX_new_from_pkey(libctx, key, NULL))
306           /* Fail if the recipient public key is invalid */
307           && TEST_int_eq(EVP_PKEY_encapsulate_init(keyctx, opparam), 1)
308           && TEST_int_eq(EVP_PKEY_encapsulate(keyctx, e, &elen, s, &slen), 0)
309           /* Fail the decap if the recipient public key is invalid */
310           && TEST_int_eq(EVP_PKEY_decapsulate_init(keyctx, opparam), 1)
311           && TEST_int_eq(EVP_PKEY_decapsulate(keyctx, s, &slen,
312                                               t->expected_enc,
313                                               t->expected_enclen), 0)
314           /* Fail if the auth key has a bad public key */
315           && TEST_int_eq(EVP_PKEY_auth_encapsulate_init(ctx, key, opparam), 1)
316           && TEST_int_eq(EVP_PKEY_encapsulate(ctx, e, &elen, s, &slen), 0);
317 
318     EVP_PKEY_free(key);
319     EVP_PKEY_CTX_free(keyctx);
320     return ret;
321 }
322 
323 /* Test incorrectly passing NULL values fail */
test_null_params(int tstid)324 static int test_null_params(int tstid)
325 {
326     EVP_PKEY_CTX *ctx = rctx[tstid];
327     const TEST_ENCAPDATA *t = &ec_encapdata[tstid];
328 
329     /* auth_encap/decap init must be passed a non NULL value */
330     return TEST_int_eq(EVP_PKEY_auth_encapsulate_init(ctx, NULL, opparam), 0)
331            && TEST_int_eq(EVP_PKEY_auth_decapsulate_init(ctx, NULL, opparam), 0)
332            /* Check decap fails if NULL params are passed */
333            && TEST_int_eq(EVP_PKEY_decapsulate_init(ctx, opparam), 1)
334            && TEST_int_eq(EVP_PKEY_decapsulate(ctx, NULL, NULL,
335                                                t->expected_enc,
336                                                t->expected_enclen), 0)
337            /* Check encap fails if NULL params are passed */
338            && TEST_int_eq(EVP_PKEY_encapsulate_init(ctx, opparam), 1)
339            && TEST_int_eq(EVP_PKEY_encapsulate(ctx, NULL, NULL,
340                                                NULL, NULL), 0);
341 }
342 
test_set_params(int tstid)343 static int test_set_params(int tstid)
344 {
345     int ret = 0;
346     EVP_PKEY_CTX *ctx = rctx[tstid];
347     OSSL_PARAM badparams[4];
348     int val = 1;
349 
350     /* wrong data type for operation param */
351     badparams[0] = OSSL_PARAM_construct_int(OSSL_KEM_PARAM_OPERATION, &val);
352     badparams[1] = OSSL_PARAM_construct_end();
353     if (!TEST_int_eq(EVP_PKEY_encapsulate_init(ctx, badparams), 0))
354         goto err;
355     /* unknown string used for the operation param */
356     badparams[0] = OSSL_PARAM_construct_utf8_string(OSSL_KEM_PARAM_OPERATION,
357                                                     "unknown_op", 0);
358     badparams[1] = OSSL_PARAM_construct_end();
359     if (!TEST_int_eq(EVP_PKEY_encapsulate_init(ctx, badparams), 0))
360         goto err;
361 
362     /* NULL string set for the operation param */
363     badparams[0] = OSSL_PARAM_construct_utf8_string(OSSL_KEM_PARAM_OPERATION,
364                                                     NULL, 0);
365     badparams[1] = OSSL_PARAM_construct_end();
366     if (!TEST_int_eq(EVP_PKEY_encapsulate_init(ctx, badparams), 0))
367         goto err;
368 
369     /* wrong data type for ikme param */
370     badparams[0] = OSSL_PARAM_construct_int(OSSL_KEM_PARAM_IKME, &val);
371     badparams[1] = OSSL_PARAM_construct_end();
372     if (!TEST_int_eq(EVP_PKEY_encapsulate_init(ctx, badparams), 0))
373         goto err;
374 
375     /* Setting the ikme to NULL is allowed */
376     badparams[0] = OSSL_PARAM_construct_octet_string(OSSL_KEM_PARAM_IKME, NULL, 0);
377     badparams[1] = OSSL_PARAM_construct_end();
378     if (!TEST_int_eq(EVP_PKEY_encapsulate_init(ctx, badparams), 1))
379         goto err;
380 
381     /* Test that unknown params are ignored */
382     badparams[0] = OSSL_PARAM_construct_int("unknownparam", &val);
383     badparams[1] = OSSL_PARAM_construct_end();
384     ret = TEST_int_eq(EVP_PKEY_encapsulate_init(ctx, badparams), 1);
385 err:
386     return ret;
387 }
388 
389 /*
390  * ECX keys autogen the public key if a private key is loaded,
391  * So this test passes for ECX, but fails for EC
392  */
test_nopublic(int tstid)393 static int test_nopublic(int tstid)
394 {
395     int ret = 0;
396     EVP_PKEY_CTX *ctx = NULL;
397     EVP_PKEY *priv = NULL;
398     int encap = ((tstid & 1) == 0);
399     int keytype = tstid >= TEST_KEM_ENCAP_DECAP;
400     const TEST_ENCAPDATA *t = &ec_encapdata[keytype];
401     int expected = (keytype == TEST_KEYTYPE_X25519);
402 
403     TEST_note("%s %s", t->curve, encap ? "Encap" : "Decap");
404     if (!TEST_ptr(priv = new_raw_private_key(t->curve, t->rpriv, t->rprivlen,
405                                              NULL, 0)))
406         goto err;
407     if (!TEST_ptr(ctx = EVP_PKEY_CTX_new_from_pkey(libctx, priv, NULL)))
408         goto err;
409 
410     if (encap) {
411         if (!TEST_int_eq(EVP_PKEY_encapsulate_init(ctx, opparam), expected))
412             goto err;
413     } else {
414         if (!TEST_int_eq(EVP_PKEY_decapsulate_init(ctx, opparam), expected))
415         goto err;
416     }
417     if (expected == 0
418         && !TEST_int_eq(ERR_GET_REASON(ERR_get_error()), PROV_R_NOT_A_PUBLIC_KEY))
419         goto err;
420     ret = 1;
421 err:
422     EVP_PKEY_free(priv);
423     EVP_PKEY_CTX_free(ctx);
424     return ret;
425 }
426 
427 /* Test that not setting the auth public key fails the auth encap/decap init */
test_noauthpublic(int tstid)428 static int test_noauthpublic(int tstid)
429 {
430     int ret = 0;
431     EVP_PKEY *auth = NULL;
432     int encap = ((tstid & 1) == 0);
433     int keytype = tstid >= TEST_KEM_ENCAP_DECAP;
434     const TEST_ENCAPDATA *t = &ec_encapdata[keytype];
435     EVP_PKEY_CTX *ctx = rctx[keytype];
436     int expected = (keytype == TEST_KEYTYPE_X25519);
437 
438     TEST_note("%s %s", t->curve, encap ? "Encap" : "Decap");
439     if (!TEST_ptr(auth = new_raw_private_key(t->curve, t->rpriv,
440                                              t->rprivlen, NULL, expected)))
441         goto err;
442 
443     if (encap) {
444         if (!TEST_int_eq(EVP_PKEY_auth_encapsulate_init(ctx, auth,
445                                                         opparam), expected))
446             goto err;
447     } else {
448         if (!TEST_int_eq(EVP_PKEY_auth_decapsulate_init(ctx, auth,
449                                                         opparam), expected))
450             goto err;
451     }
452     if (expected == 0
453         && !TEST_int_eq(ERR_GET_REASON(ERR_get_error()),
454                         PROV_R_NOT_A_PUBLIC_KEY))
455         goto err;
456     ret = 1;
457 err:
458     EVP_PKEY_free(auth);
459     return ret;
460 }
461 
462 /* EC specific tests */
463 
464 /* Perform EC DHKEM KATs */
test_ec_dhkem_derivekey(int tstid)465 static int test_ec_dhkem_derivekey(int tstid)
466 {
467     int ret = 0;
468     EVP_PKEY *pkey = NULL;
469     OSSL_PARAM params[3];
470     EVP_PKEY_CTX *genctx = NULL;
471     const TEST_DERIVEKEY_DATA *t = &ec_derivekey_data[tstid];
472     unsigned char pubkey[133];
473     unsigned char privkey[66];
474     size_t pubkeylen = 0, privkeylen = 0;
475     BIGNUM *priv = NULL;
476 
477     params[0] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME,
478                                                  (char *)t->curvename, 0);
479     params[1] = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_DHKEM_IKM,
480                                                   (char *)t->ikm, t->ikmlen);
481     params[2] = OSSL_PARAM_construct_end();
482 
483     ret = TEST_ptr(genctx = EVP_PKEY_CTX_new_from_name(libctx, "EC", NULL))
484           && TEST_int_eq(EVP_PKEY_keygen_init(genctx), 1)
485           && TEST_int_eq(EVP_PKEY_CTX_set_params(genctx, params), 1)
486           && TEST_int_eq(EVP_PKEY_generate(genctx, &pkey), 1)
487           && TEST_true(EVP_PKEY_get_octet_string_param(pkey,
488                            OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY,
489                            pubkey, sizeof(pubkey), &pubkeylen))
490           && TEST_true(EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PRIV_KEY,
491                                              &priv))
492           && TEST_int_gt(privkeylen = BN_bn2bin(priv, privkey), 0)
493           && TEST_int_le(privkeylen, sizeof(privkey))
494           && TEST_mem_eq(privkey, privkeylen, t->priv, t->privlen)
495           && TEST_mem_eq(pubkey, pubkeylen, t->pub, t->publen);
496 
497     BN_free(priv);
498     EVP_PKEY_free(pkey);
499     EVP_PKEY_CTX_free(genctx);
500     return ret;
501 }
502 
503 /*
504  * Test that encapsulation uses a random seed if the ikm is not specified,
505  * and verify that the shared secret matches the decapsulate result.
506  */
test_ec_noikme(int tstid)507 static int test_ec_noikme(int tstid)
508 {
509     int ret = 0, auth = 0;
510     EVP_PKEY_CTX *ctx = NULL;
511     EVP_PKEY *recip = NULL;
512     EVP_PKEY *sender_auth = NULL;
513     unsigned char sender_secret[256];
514     unsigned char recip_secret[256];
515     unsigned char sender_pub[256];
516     size_t sender_secretlen = sizeof(sender_secret);
517     size_t recip_secretlen = sizeof(recip_secret);
518     size_t sender_publen = sizeof(sender_pub);
519     const char *curve;
520     int sz = OSSL_NELEM(dhkem_supported_curves);
521     const char *op = OSSL_KEM_PARAM_OPERATION_DHKEM;
522 
523     if (tstid >= sz) {
524         auth = 1;
525         tstid -= sz;
526     }
527     curve = dhkem_supported_curves[tstid];
528     TEST_note("testing encap/decap of curve %s%s\n", curve,
529               auth ? " with auth" : "");
530 
531     if (curve[0] == 'X') {
532         if (!TEST_ptr(recip = EVP_PKEY_Q_keygen(libctx, NULL, curve))
533                 || (auth
534                     && !TEST_ptr(sender_auth = EVP_PKEY_Q_keygen(libctx, NULL,
535                                                                  curve))))
536             goto err;
537     } else {
538         if (!TEST_ptr(recip = EVP_PKEY_Q_keygen(libctx, NULL, "EC", curve))
539                 || (auth
540                     && !TEST_ptr(sender_auth = EVP_PKEY_Q_keygen(libctx, NULL,
541                                                                  "EC", curve))))
542             goto err;
543     }
544 
545     ret = TEST_ptr(ctx = EVP_PKEY_CTX_new_from_pkey(libctx, recip, NULL))
546           && (sender_auth == NULL
547               || TEST_int_eq(EVP_PKEY_auth_encapsulate_init(ctx, sender_auth,
548                                                             NULL), 1))
549           && (sender_auth != NULL
550               || TEST_int_eq(EVP_PKEY_encapsulate_init(ctx, NULL), 1))
551           && TEST_int_eq(EVP_PKEY_CTX_set_kem_op(ctx, op), 1)
552           && TEST_int_eq(EVP_PKEY_encapsulate(ctx, sender_pub, &sender_publen,
553                                               sender_secret, &sender_secretlen), 1)
554           && (sender_auth == NULL
555               || TEST_int_eq(EVP_PKEY_auth_decapsulate_init(ctx, sender_auth,
556                                                             NULL), 1))
557           && (sender_auth != NULL
558               || TEST_int_eq(EVP_PKEY_decapsulate_init(ctx, NULL), 1))
559           && TEST_int_eq(EVP_PKEY_CTX_set_kem_op(ctx, op), 1)
560           && TEST_int_eq(EVP_PKEY_decapsulate(ctx, recip_secret, &recip_secretlen,
561                                              sender_pub, sender_publen), 1)
562           && TEST_mem_eq(recip_secret, recip_secretlen,
563                          sender_secret, sender_secretlen);
564 err:
565     EVP_PKEY_CTX_free(ctx);
566     EVP_PKEY_free(sender_auth);
567     EVP_PKEY_free(recip);
568     return ret;
569 }
570 
571 /* Test encap/decap init fail if the curve is invalid */
do_ec_curve_failtest(const char * curve)572 static int do_ec_curve_failtest(const char *curve)
573 {
574     int ret;
575     EVP_PKEY *key = NULL;
576     EVP_PKEY_CTX *ctx = NULL;
577 
578     ret = TEST_ptr(key = EVP_PKEY_Q_keygen(libctx, NULL, "EC", curve))
579           && TEST_ptr(ctx = EVP_PKEY_CTX_new_from_pkey(libctx, key, NULL))
580           && TEST_int_eq(EVP_PKEY_encapsulate_init(ctx, NULL), -2)
581           && TEST_int_eq(EVP_PKEY_decapsulate_init(ctx, NULL), -2);
582     EVP_PKEY_free(key);
583     EVP_PKEY_CTX_free(ctx);
584     return ret;
585 }
586 
test_ec_curve_nonnist(void)587 static int test_ec_curve_nonnist(void)
588 {
589     return do_ec_curve_failtest("secp256k1");
590 }
591 
test_ec_curve_unsupported(void)592 static int test_ec_curve_unsupported(void)
593 {
594     return do_ec_curve_failtest("P-224");
595 }
596 
597 /* Test that passing a bad recipient public EC key fails during encap/decap */
test_ec_badpublic(int tstid)598 static int test_ec_badpublic(int tstid)
599 {
600     int ret = 0;
601     EVP_PKEY *recippriv = NULL;
602     EVP_PKEY_CTX *ctx = NULL;
603     unsigned char secret[256];
604     unsigned char pub[256];
605     size_t secretlen = sizeof(secret);
606     int encap = ((tstid & 1) == 0);
607     const TEST_ENCAPDATA *t = &ec_encapdata[0];
608 
609     TEST_note("%s %s", t->curve, encap ? "Encap" : "Decap");
610     /* Set the recipient public key to the point at infinity */
611     pub[0] = 0;
612     if (!TEST_ptr(recippriv = new_raw_private_key(t->curve, t->rpriv, t->rprivlen,
613                                                   pub, 1)))
614         goto err;
615 
616     if (!TEST_ptr(ctx = EVP_PKEY_CTX_new_from_pkey(libctx, recippriv, NULL)))
617         goto err;
618 
619     if (encap) {
620         unsigned char enc[256];
621         size_t enclen = sizeof(enc);
622 
623         if (!TEST_int_eq(EVP_PKEY_encapsulate_init(ctx, opparam), 1))
624             goto err;
625         if (!TEST_int_eq(EVP_PKEY_encapsulate(ctx, enc , &enclen,
626                                               secret, &secretlen), 0 ))
627             goto err;
628     } else {
629         if (!TEST_int_eq(EVP_PKEY_decapsulate_init(ctx, opparam), 1))
630             goto err;
631         if (!TEST_int_eq(EVP_PKEY_decapsulate(ctx, secret, &secretlen,
632                                               t->expected_enc,
633                                               t->expected_enclen),
634                          0))
635             goto err;
636     }
637     if (!TEST_int_eq(ERR_GET_REASON(ERR_get_error()), PROV_R_INVALID_KEY))
638         goto err;
639     ret = 1;
640 err:
641     EVP_PKEY_free(recippriv);
642     EVP_PKEY_CTX_free(ctx);
643     return ret;
644 }
645 
test_ec_badauth(int tstid)646 static int test_ec_badauth(int tstid)
647 {
648     int ret = 0;
649     EVP_PKEY *auth = NULL;
650     unsigned char enc[256];
651     unsigned char secret[256];
652     unsigned char pub[256];
653     size_t enclen = sizeof(enc);
654     size_t secretlen = sizeof(secret);
655     int encap = ((tstid & 1) == 0);
656     const TEST_ENCAPDATA *t = &ec_encapdata[TEST_KEYTYPE_P256];
657     EVP_PKEY_CTX *ctx = rctx[TEST_KEYTYPE_P256];
658 
659     TEST_note("%s %s", t->curve, encap ? "Encap" : "Decap");
660     /* Set the auth public key to the point at infinity */
661     pub[0] = 0;
662     if (!TEST_ptr(auth = new_raw_private_key(t->curve, t->rpriv, t->rprivlen,
663                                              pub, 1)))
664         goto err;
665     if (encap) {
666         if (!TEST_int_eq(EVP_PKEY_auth_encapsulate_init(ctx, auth,
667                                                         opparam), 1)
668             || !TEST_int_eq(EVP_PKEY_encapsulate(ctx, enc, &enclen,
669                                                  secret, &secretlen), 0))
670             goto err;
671     } else {
672         if (!TEST_int_eq(EVP_PKEY_auth_decapsulate_init(ctx, auth, opparam), 1)
673             || !TEST_int_eq(EVP_PKEY_decapsulate(ctx, secret, &secretlen,
674                                                  t->expected_enc,
675                                                  t->expected_enclen), 0))
676             goto err;
677     }
678     if (!TEST_int_eq(ERR_GET_REASON(ERR_get_error()), PROV_R_INVALID_KEY))
679         goto err;
680     ret = 1;
681 err:
682     EVP_PKEY_free(auth);
683     return ret;
684 }
685 
test_ec_invalid_decap_enc_buffer(void)686 static int test_ec_invalid_decap_enc_buffer(void)
687 {
688     const TEST_ENCAPDATA *t = &ec_encapdata[TEST_KEYTYPE_P256];
689     unsigned char enc[256];
690     unsigned char secret[256];
691     size_t secretlen = sizeof(secret);
692     EVP_PKEY_CTX *ctx = rctx[0];
693 
694     memcpy(enc, t->expected_enc, t->expected_enclen);
695     enc[0] = 0xFF;
696 
697     return TEST_int_eq(EVP_PKEY_decapsulate_init(ctx, opparam), 1)
698            && TEST_int_eq(EVP_PKEY_decapsulate(ctx, secret, &secretlen,
699                                                enc, t->expected_enclen), 0);
700 }
701 
702 #ifndef OPENSSL_NO_ECX
703 /* ECX specific tests */
704 
705 /* Perform ECX DHKEM KATs */
test_ecx_dhkem_derivekey(int tstid)706 static int test_ecx_dhkem_derivekey(int tstid)
707 {
708     int ret;
709     OSSL_PARAM params[2];
710     EVP_PKEY_CTX *genctx;
711     EVP_PKEY *pkey = NULL;
712     unsigned char pubkey[64];
713     unsigned char privkey[64];
714     unsigned char masked_priv[64];
715     size_t pubkeylen = 0, privkeylen = 0;
716     const TEST_DERIVEKEY_DATA *t = &ecx_derivekey_data[tstid];
717 
718     memcpy(masked_priv, t->priv, t->privlen);
719     if (OPENSSL_strcasecmp(t->curvename, "X25519") == 0) {
720         /*
721          * The RFC test vector seems incorrect since it is not in serialized form,
722          * So manually do the conversion here for now.
723          */
724         masked_priv[0] &= 248;
725         masked_priv[t->privlen - 1] &= 127;
726         masked_priv[t->privlen - 1] |= 64;
727     } else {
728         masked_priv[0] &= 252;
729         masked_priv[t->privlen - 1] |= 128;
730     }
731 
732     params[0] = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_DHKEM_IKM,
733                                                   (char *)t->ikm, t->ikmlen);
734     params[1] = OSSL_PARAM_construct_end();
735 
736     ret = TEST_ptr(genctx = EVP_PKEY_CTX_new_from_name(libctx, t->curvename, NULL))
737           && TEST_int_eq(EVP_PKEY_keygen_init(genctx), 1)
738           && TEST_int_eq(EVP_PKEY_CTX_set_params(genctx, params), 1)
739           && TEST_int_eq(EVP_PKEY_keygen(genctx, &pkey), 1)
740           && TEST_int_eq(EVP_PKEY_get_octet_string_param(pkey,
741                              OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY,
742                              pubkey, sizeof(pubkey), &pubkeylen), 1)
743           && TEST_int_eq(EVP_PKEY_get_octet_string_param(pkey,
744                              OSSL_PKEY_PARAM_PRIV_KEY,
745                              privkey, sizeof(privkey), &privkeylen), 1)
746           && TEST_mem_eq(t->pub, t->publen, pubkey, pubkeylen)
747           && TEST_mem_eq(masked_priv, t->privlen, privkey, privkeylen);
748 
749     EVP_PKEY_free(pkey);
750     EVP_PKEY_CTX_free(genctx);
751     return ret;
752 }
753 
754 /* Fail if the auth key has a different curve */
test_ecx_auth_key_curve_mismatch(void)755 static int test_ecx_auth_key_curve_mismatch(void)
756 {
757     int ret = 0;
758     EVP_PKEY *auth = NULL;
759 
760     if (!TEST_ptr(auth = EVP_PKEY_Q_keygen(libctx, NULL, "X448")))
761         return 0;
762 
763     ret = TEST_int_eq(EVP_PKEY_auth_encapsulate_init(rctx[TEST_KEYTYPE_X25519],
764                                                      auth, opparam), 0);
765     EVP_PKEY_free(auth);
766     return ret;
767 }
768 
769 /* Fail if ED448 is used for DHKEM */
test_ed_curve_unsupported(void)770 static int test_ed_curve_unsupported(void)
771 {
772     int ret;
773     EVP_PKEY *key = NULL;
774     EVP_PKEY_CTX *ctx = NULL;
775 
776     ret = TEST_ptr(key = EVP_PKEY_Q_keygen(libctx, NULL, "ED448"))
777           && TEST_ptr(ctx = EVP_PKEY_CTX_new_from_pkey(libctx, key, NULL))
778           && TEST_int_eq(EVP_PKEY_encapsulate_init(ctx, NULL), -2)
779           && TEST_int_eq(EVP_PKEY_decapsulate_init(ctx, NULL), -2);
780     EVP_PKEY_free(key);
781     EVP_PKEY_CTX_free(ctx);
782     return ret;
783 }
784 #endif
785 
setup_tests(void)786 int setup_tests(void)
787 {
788     const char *prov_name = "default";
789     char *config_file = NULL;
790     char *op = OSSL_KEM_PARAM_OPERATION_DHKEM;
791 
792     if (!test_get_libctx(&libctx, &nullprov, config_file, &libprov, prov_name))
793         return 0;
794     opparam[0] = OSSL_PARAM_construct_utf8_string(OSSL_KEM_PARAM_OPERATION,
795                                                   op, 0);
796     opparam[1] = OSSL_PARAM_construct_end();
797 
798     /* Create P256 and X25519 keys and ctxs */
799     if (!TEST_ptr(rkey[TEST_KEYTYPE_P256] = EVP_PKEY_Q_keygen(libctx, NULL,
800                                                               "EC", "P-256")))
801         goto err;
802 #ifndef OPENSSL_NO_ECX
803     if (!TEST_ptr(rkey[TEST_KEYTYPE_X25519] = EVP_PKEY_Q_keygen(libctx, NULL,
804                                                                 "X25519")))
805         goto err;
806 #endif
807     if (!TEST_ptr(rctx[TEST_KEYTYPE_P256] =
808                       EVP_PKEY_CTX_new_from_pkey(libctx,
809                                                  rkey[TEST_KEYTYPE_P256], NULL)))
810        goto err;
811 #ifndef OPENSSL_NO_ECX
812     if (!TEST_ptr(rctx[TEST_KEYTYPE_X25519] =
813                       EVP_PKEY_CTX_new_from_pkey(libctx,
814                                                  rkey[TEST_KEYTYPE_X25519], NULL)))
815        goto err;
816 #endif
817 
818     ADD_ALL_TESTS(test_dhkem_encapsulate, OSSL_NELEM(ec_encapdata));
819     ADD_ALL_TESTS(test_dhkem_decapsulate, OSSL_NELEM(ec_encapdata));
820 #ifndef OPENSSL_NO_ECX
821     ADD_ALL_TESTS(test_settables, TEST_KEYTYPES_P256_X25519);
822     ADD_ALL_TESTS(test_init_multiple, TEST_KEYTYPES_P256_X25519);
823 
824     ADD_ALL_TESTS(test_auth_key_type_mismatch, TEST_KEYTYPES_P256_X25519);
825     ADD_ALL_TESTS(test_no_operation_set, TEST_KEYTYPES_P256_X25519);
826     ADD_ALL_TESTS(test_ikm_small, TEST_KEYTYPES_P256_X25519);
827     ADD_ALL_TESTS(test_input_size_small, TEST_KEYTYPES_P256_X25519);
828     ADD_ALL_TESTS(test_null_params, TEST_KEYTYPES_P256_X25519);
829     ADD_ALL_TESTS(test_set_params, TEST_KEYTYPES_P256_X25519);
830     ADD_ALL_TESTS(test_nopublic,
831                   TEST_KEM_ENCAP_DECAP * TEST_KEYTYPES_P256_X25519);
832     ADD_ALL_TESTS(test_noauthpublic,
833                   TEST_KEM_ENCAP_DECAP * TEST_KEYTYPES_P256_X25519);
834 #else
835     ADD_ALL_TESTS(test_settables, TEST_KEYTYPE_P256);
836     ADD_ALL_TESTS(test_init_multiple, TEST_KEYTYPE_P256);
837 
838     ADD_ALL_TESTS(test_auth_key_type_mismatch, TEST_KEYTYPE_P256);
839     ADD_ALL_TESTS(test_no_operation_set, TEST_KEYTYPE_P256);
840     ADD_ALL_TESTS(test_ikm_small, TEST_KEYTYPE_P256);
841     ADD_ALL_TESTS(test_input_size_small, TEST_KEYTYPE_P256);
842     ADD_ALL_TESTS(test_null_params, TEST_KEYTYPE_P256);
843     ADD_ALL_TESTS(test_set_params, TEST_KEYTYPE_P256);
844     ADD_ALL_TESTS(test_nopublic,
845                   TEST_KEM_ENCAP_DECAP * TEST_KEYTYPE_P256);
846     ADD_ALL_TESTS(test_noauthpublic,
847                   TEST_KEM_ENCAP_DECAP * TEST_KEYTYPE_P256);
848 #endif
849     /* EC Specific tests */
850     ADD_ALL_TESTS(test_ec_dhkem_derivekey, OSSL_NELEM(ec_derivekey_data));
851     ADD_ALL_TESTS(test_ec_noikme,
852                   TEST_TYPE_AUTH_NOAUTH * OSSL_NELEM(dhkem_supported_curves));
853     ADD_TEST(test_ec_auth_key_curve_mismatch);
854     ADD_TEST(test_ec_invalid_private_key);
855     ADD_TEST(test_ec_dhkem_derivekey_fail);
856     ADD_TEST(test_ec_curve_nonnist);
857     ADD_TEST(test_ec_curve_unsupported);
858     ADD_TEST(test_ec_invalid_decap_enc_buffer);
859     ADD_TEST(test_ec_public_key_infinity);
860     ADD_ALL_TESTS(test_ec_badpublic, TEST_KEM_ENCAP_DECAP);
861     ADD_ALL_TESTS(test_ec_badauth, TEST_KEM_ENCAP_DECAP);
862 
863     /* ECX specific tests */
864 #ifndef OPENSSL_NO_ECX
865     ADD_ALL_TESTS(test_ecx_dhkem_derivekey, OSSL_NELEM(ecx_derivekey_data));
866     ADD_TEST(test_ecx_auth_key_curve_mismatch);
867     ADD_TEST(test_ed_curve_unsupported);
868 #endif
869     return 1;
870 err:
871     return 0;
872 }
873 
cleanup_tests(void)874 void cleanup_tests(void)
875 {
876     EVP_PKEY_free(rkey[1]);
877     EVP_PKEY_free(rkey[0]);
878     EVP_PKEY_CTX_free(rctx[1]);
879     EVP_PKEY_CTX_free(rctx[0]);
880     OSSL_PROVIDER_unload(libprov);
881     OSSL_LIB_CTX_free(libctx);
882     OSSL_PROVIDER_unload(nullprov);
883 }
884