2 * Copyright 2022-2023 The OpenSSL Project Authors. All Rights Reserved.
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
10 #include <openssl/evp.h>
11 #include <openssl/core_names.h>
12 #include <openssl/rand.h>
13 #include <openssl/hpke.h>
16 /* a size to use for stack buffers */
17 #define OSSL_HPKE_TSTSIZE 512
19 static OSSL_LIB_CTX *testctx = NULL;
20 static OSSL_PROVIDER *nullprov = NULL;
21 static OSSL_PROVIDER *deflprov = NULL;
22 static char *testpropq = "provider=default";
23 static int verbose = 0;
27 OSSL_HPKE_SUITE suite;
28 const unsigned char *ikmE;
30 const unsigned char *expected_pkEm;
31 size_t expected_pkEmlen;
32 const unsigned char *ikmR;
34 const unsigned char *expected_pkRm;
35 size_t expected_pkRmlen;
36 const unsigned char *expected_skRm;
37 size_t expected_skRmlen;
38 const unsigned char *expected_secret;
39 size_t expected_secretlen;
40 const unsigned char *ksinfo;
42 const unsigned char *ikmAuth;
44 const unsigned char *psk;
46 const char *pskid; /* want terminating NUL here */
52 const unsigned char *pt;
54 const unsigned char *aad;
56 const unsigned char *expected_ct;
57 size_t expected_ctlen;
62 const unsigned char *context;
64 const unsigned char *expected_secret;
65 size_t expected_secretlen;
69 * @brief Test that an EVP_PKEY encoded public key matches the supplied buffer
70 * @param pkey is the EVP_PKEY we want to check
71 * @param pub is the expected public key buffer
72 * @param publen is the length of the above
73 * @return 1 for good, 0 for bad
75 static int cmpkey(const EVP_PKEY *pkey,
76 const unsigned char *pub, size_t publen)
78 unsigned char pubbuf[256];
82 if (!TEST_true(publen <= sizeof(pubbuf)))
84 erv = EVP_PKEY_get_octet_string_param(pkey,
85 OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY,
86 pubbuf, sizeof(pubbuf), &pubbuflen);
89 if (pub != NULL && !TEST_mem_eq(pubbuf, pubbuflen, pub, publen))
94 static int do_testhpke(const TEST_BASEDATA *base,
95 const TEST_AEADDATA *aead, size_t aeadsz,
96 const TEST_EXPORTDATA *export, size_t exportsz)
98 OSSL_LIB_CTX *libctx = testctx;
99 const char *propq = testpropq;
100 OSSL_HPKE_CTX *sealctx = NULL, *openctx = NULL;
101 unsigned char ct[256];
102 unsigned char enc[256];
103 unsigned char ptout[256];
104 size_t ptoutlen = sizeof(ptout);
105 size_t enclen = sizeof(enc);
106 size_t ctlen = sizeof(ct);
107 unsigned char pub[OSSL_HPKE_TSTSIZE];
108 size_t publen = sizeof(pub);
109 EVP_PKEY *privE = NULL;
110 unsigned char authpub[OSSL_HPKE_TSTSIZE];
111 size_t authpublen = sizeof(authpub);
112 EVP_PKEY *authpriv = NULL;
113 unsigned char rpub[OSSL_HPKE_TSTSIZE];
114 size_t rpublen = sizeof(pub);
115 EVP_PKEY *privR = NULL;
118 uint64_t lastseq = 0;
120 if (!TEST_true(OSSL_HPKE_keygen(base->suite, pub, &publen, &privE,
121 base->ikmE, base->ikmElen, libctx, propq)))
123 if (!TEST_true(cmpkey(privE, base->expected_pkEm, base->expected_pkEmlen)))
125 if (!TEST_ptr(sealctx = OSSL_HPKE_CTX_new(base->mode, base->suite,
126 OSSL_HPKE_ROLE_SENDER,
129 if (!TEST_true(OSSL_HPKE_CTX_set1_ikme(sealctx, base->ikmE, base->ikmElen)))
131 if (base->mode == OSSL_HPKE_MODE_AUTH
132 || base->mode == OSSL_HPKE_MODE_PSKAUTH) {
133 if (!TEST_true(base->ikmAuth != NULL && base->ikmAuthlen > 0))
135 if (!TEST_true(OSSL_HPKE_keygen(base->suite,
136 authpub, &authpublen, &authpriv,
137 base->ikmAuth, base->ikmAuthlen,
140 if (!TEST_true(OSSL_HPKE_CTX_set1_authpriv(sealctx, authpriv)))
143 if (!TEST_true(OSSL_HPKE_keygen(base->suite, rpub, &rpublen, &privR,
144 base->ikmR, base->ikmRlen, libctx, propq)))
146 if (!TEST_true(cmpkey(privR, base->expected_pkRm, base->expected_pkRmlen)))
148 if (base->mode == OSSL_HPKE_MODE_PSK
149 || base->mode == OSSL_HPKE_MODE_PSKAUTH) {
150 if (!TEST_true(OSSL_HPKE_CTX_set1_psk(sealctx, base->pskid,
151 base->psk, base->psklen)))
154 if (!TEST_true(OSSL_HPKE_encap(sealctx, enc, &enclen,
156 base->ksinfo, base->ksinfolen)))
158 if (!TEST_true(cmpkey(privE, enc, enclen)))
160 for (i = 0; i < aeadsz; ++i) {
162 memset(ct, 0, ctlen);
163 if (!TEST_true(OSSL_HPKE_seal(sealctx, ct, &ctlen,
164 aead[i].aad, aead[i].aadlen,
165 aead[i].pt, aead[i].ptlen)))
167 if (!TEST_mem_eq(ct, ctlen, aead[i].expected_ct,
168 aead[i].expected_ctlen))
170 if (!TEST_true(OSSL_HPKE_CTX_get_seq(sealctx, &lastseq)))
172 if (lastseq != (uint64_t)(i + 1))
175 if (!TEST_ptr(openctx = OSSL_HPKE_CTX_new(base->mode, base->suite,
176 OSSL_HPKE_ROLE_RECEIVER,
179 if (base->mode == OSSL_HPKE_MODE_PSK
180 || base->mode == OSSL_HPKE_MODE_PSKAUTH) {
181 if (!TEST_true(base->pskid != NULL && base->psk != NULL
182 && base->psklen > 0))
184 if (!TEST_true(OSSL_HPKE_CTX_set1_psk(openctx, base->pskid,
185 base->psk, base->psklen)))
188 if (base->mode == OSSL_HPKE_MODE_AUTH
189 || base->mode == OSSL_HPKE_MODE_PSKAUTH) {
190 if (!TEST_true(OSSL_HPKE_CTX_set1_authpub(openctx,
191 authpub, authpublen)))
194 if (!TEST_true(OSSL_HPKE_decap(openctx, enc, enclen, privR,
195 base->ksinfo, base->ksinfolen)))
197 for (i = 0; i < aeadsz; ++i) {
198 ptoutlen = sizeof(ptout);
199 memset(ptout, 0, ptoutlen);
200 if (!TEST_true(OSSL_HPKE_open(openctx, ptout, &ptoutlen,
201 aead[i].aad, aead[i].aadlen,
203 aead[i].expected_ctlen)))
205 if (!TEST_mem_eq(aead[i].pt, aead[i].ptlen, ptout, ptoutlen))
207 /* check the sequence is being incremented as expected */
208 if (!TEST_true(OSSL_HPKE_CTX_get_seq(openctx, &lastseq)))
210 if (lastseq != (uint64_t)(i + 1))
213 /* check exporters */
214 for (i = 0; i < exportsz; ++i) {
215 size_t len = export[i].expected_secretlen;
216 unsigned char eval[OSSL_HPKE_TSTSIZE];
218 if (len > sizeof(eval))
220 /* export with too long label should fail */
221 if (!TEST_false(OSSL_HPKE_export(sealctx, eval, len,
222 export[i].context, -1)))
224 /* good export call */
225 if (!TEST_true(OSSL_HPKE_export(sealctx, eval, len,
227 export[i].contextlen)))
229 if (!TEST_mem_eq(eval, len, export[i].expected_secret,
230 export[i].expected_secretlen))
233 /* check seal fails if export only mode */
236 if (!TEST_false(OSSL_HPKE_seal(sealctx, ct, &ctlen,
237 NULL, 0, ptout, ptoutlen)))
243 OSSL_HPKE_CTX_free(sealctx);
244 OSSL_HPKE_CTX_free(openctx);
245 EVP_PKEY_free(privE);
246 EVP_PKEY_free(privR);
247 EVP_PKEY_free(authpriv);
251 static const unsigned char pt[] = {
252 0x42, 0x65, 0x61, 0x75, 0x74, 0x79, 0x20, 0x69,
253 0x73, 0x20, 0x74, 0x72, 0x75, 0x74, 0x68, 0x2c,
254 0x20, 0x74, 0x72, 0x75, 0x74, 0x68, 0x20, 0x62,
255 0x65, 0x61, 0x75, 0x74, 0x79
257 static const unsigned char ksinfo[] = {
258 0x4f, 0x64, 0x65, 0x20, 0x6f, 0x6e, 0x20, 0x61,
259 0x20, 0x47, 0x72, 0x65, 0x63, 0x69, 0x61, 0x6e,
260 0x20, 0x55, 0x72, 0x6e
262 #ifndef OPENSSL_NO_ECX
264 * static const char *pskid = "Ennyn Durin aran Moria";
266 static const unsigned char pskid[] = {
267 0x45, 0x6e, 0x6e, 0x79, 0x6e, 0x20, 0x44, 0x75,
268 0x72, 0x69, 0x6e, 0x20, 0x61, 0x72, 0x61, 0x6e,
269 0x20, 0x4d, 0x6f, 0x72, 0x69, 0x61, 0x00
271 static const unsigned char psk[] = {
272 0x02, 0x47, 0xfd, 0x33, 0xb9, 0x13, 0x76, 0x0f,
273 0xa1, 0xfa, 0x51, 0xe1, 0x89, 0x2d, 0x9f, 0x30,
274 0x7f, 0xbe, 0x65, 0xeb, 0x17, 0x1e, 0x81, 0x32,
275 0xc2, 0xaf, 0x18, 0x55, 0x5a, 0x73, 0x8b, 0x82
278 /* these need to be "outside" the function below to keep check-ansi CI happy */
279 static const unsigned char first_ikme[] = {
280 0x78, 0x62, 0x8c, 0x35, 0x4e, 0x46, 0xf3, 0xe1,
281 0x69, 0xbd, 0x23, 0x1b, 0xe7, 0xb2, 0xff, 0x1c,
282 0x77, 0xaa, 0x30, 0x24, 0x60, 0xa2, 0x6d, 0xbf,
283 0xa1, 0x55, 0x15, 0x68, 0x4c, 0x00, 0x13, 0x0b
285 static const unsigned char first_ikmr[] = {
286 0xd4, 0xa0, 0x9d, 0x09, 0xf5, 0x75, 0xfe, 0xf4,
287 0x25, 0x90, 0x5d, 0x2a, 0xb3, 0x96, 0xc1, 0x44,
288 0x91, 0x41, 0x46, 0x3f, 0x69, 0x8f, 0x8e, 0xfd,
289 0xb7, 0xac, 0xcf, 0xaf, 0xf8, 0x99, 0x50, 0x98
291 static const unsigned char first_ikmepub[] = {
292 0x0a, 0xd0, 0x95, 0x0d, 0x9f, 0xb9, 0x58, 0x8e,
293 0x59, 0x69, 0x0b, 0x74, 0xf1, 0x23, 0x7e, 0xcd,
294 0xf1, 0xd7, 0x75, 0xcd, 0x60, 0xbe, 0x2e, 0xca,
295 0x57, 0xaf, 0x5a, 0x4b, 0x04, 0x71, 0xc9, 0x1b,
297 static const unsigned char first_ikmrpub[] = {
298 0x9f, 0xed, 0x7e, 0x8c, 0x17, 0x38, 0x75, 0x60,
299 0xe9, 0x2c, 0xc6, 0x46, 0x2a, 0x68, 0x04, 0x96,
300 0x57, 0x24, 0x6a, 0x09, 0xbf, 0xa8, 0xad, 0xe7,
301 0xae, 0xfe, 0x58, 0x96, 0x72, 0x01, 0x63, 0x66
303 static const unsigned char first_ikmrpriv[] = {
304 0xc5, 0xeb, 0x01, 0xeb, 0x45, 0x7f, 0xe6, 0xc6,
305 0xf5, 0x75, 0x77, 0xc5, 0x41, 0x3b, 0x93, 0x15,
306 0x50, 0xa1, 0x62, 0xc7, 0x1a, 0x03, 0xac, 0x8d,
307 0x19, 0x6b, 0xab, 0xbd, 0x4e, 0x5c, 0xe0, 0xfd
309 static const unsigned char first_expected_shared_secret[] = {
310 0x72, 0x76, 0x99, 0xf0, 0x09, 0xff, 0xe3, 0xc0,
311 0x76, 0x31, 0x50, 0x19, 0xc6, 0x96, 0x48, 0x36,
312 0x6b, 0x69, 0x17, 0x14, 0x39, 0xbd, 0x7d, 0xd0,
313 0x80, 0x77, 0x43, 0xbd, 0xe7, 0x69, 0x86, 0xcd
315 static const unsigned char first_aad0[] = {
316 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x2d, 0x30
318 static const unsigned char first_ct0[] = {
319 0xe5, 0x2c, 0x6f, 0xed, 0x7f, 0x75, 0x8d, 0x0c,
320 0xf7, 0x14, 0x56, 0x89, 0xf2, 0x1b, 0xc1, 0xbe,
321 0x6e, 0xc9, 0xea, 0x09, 0x7f, 0xef, 0x4e, 0x95,
322 0x94, 0x40, 0x01, 0x2f, 0x4f, 0xeb, 0x73, 0xfb,
323 0x61, 0x1b, 0x94, 0x61, 0x99, 0xe6, 0x81, 0xf4,
324 0xcf, 0xc3, 0x4d, 0xb8, 0xea
326 static const unsigned char first_aad1[] = {
327 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x2d, 0x31
329 static const unsigned char first_ct1[] = {
330 0x49, 0xf3, 0xb1, 0x9b, 0x28, 0xa9, 0xea, 0x9f,
331 0x43, 0xe8, 0xc7, 0x12, 0x04, 0xc0, 0x0d, 0x4a,
332 0x49, 0x0e, 0xe7, 0xf6, 0x13, 0x87, 0xb6, 0x71,
333 0x9d, 0xb7, 0x65, 0xe9, 0x48, 0x12, 0x3b, 0x45,
334 0xb6, 0x16, 0x33, 0xef, 0x05, 0x9b, 0xa2, 0x2c,
335 0xd6, 0x24, 0x37, 0xc8, 0xba
337 static const unsigned char first_aad2[] = {
338 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x2d, 0x32
340 static const unsigned char first_ct2[] = {
341 0x25, 0x7c, 0xa6, 0xa0, 0x84, 0x73, 0xdc, 0x85,
342 0x1f, 0xde, 0x45, 0xaf, 0xd5, 0x98, 0xcc, 0x83,
343 0xe3, 0x26, 0xdd, 0xd0, 0xab, 0xe1, 0xef, 0x23,
344 0xba, 0xa3, 0xba, 0xa4, 0xdd, 0x8c, 0xde, 0x99,
345 0xfc, 0xe2, 0xc1, 0xe8, 0xce, 0x68, 0x7b, 0x0b,
346 0x47, 0xea, 0xd1, 0xad, 0xc9
348 static const unsigned char first_export1[] = {
349 0xdf, 0xf1, 0x7a, 0xf3, 0x54, 0xc8, 0xb4, 0x16,
350 0x73, 0x56, 0x7d, 0xb6, 0x25, 0x9f, 0xd6, 0x02,
351 0x99, 0x67, 0xb4, 0xe1, 0xaa, 0xd1, 0x30, 0x23,
352 0xc2, 0xae, 0x5d, 0xf8, 0xf4, 0xf4, 0x3b, 0xf6
354 static const unsigned char first_context2[] = { 0x00 };
355 static const unsigned char first_export2[] = {
356 0x6a, 0x84, 0x72, 0x61, 0xd8, 0x20, 0x7f, 0xe5,
357 0x96, 0xbe, 0xfb, 0x52, 0x92, 0x84, 0x63, 0x88,
358 0x1a, 0xb4, 0x93, 0xda, 0x34, 0x5b, 0x10, 0xe1,
359 0xdc, 0xc6, 0x45, 0xe3, 0xb9, 0x4e, 0x2d, 0x95
361 static const unsigned char first_context3[] = {
362 0x54, 0x65, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x74,
365 static const unsigned char first_export3[] = {
366 0x8a, 0xff, 0x52, 0xb4, 0x5a, 0x1b, 0xe3, 0xa7,
367 0x34, 0xbc, 0x7a, 0x41, 0xe2, 0x0b, 0x4e, 0x05,
368 0x5a, 0xd4, 0xc4, 0xd2, 0x21, 0x04, 0xb0, 0xc2,
369 0x02, 0x85, 0xa7, 0xc4, 0x30, 0x24, 0x01, 0xcd
372 static int x25519kdfsha256_hkdfsha256_aes128gcm_psk_test(void)
374 const TEST_BASEDATA pskdata = {
375 /* "X25519", NULL, "SHA256", "SHA256", "AES-128-GCM", */
378 OSSL_HPKE_KEM_ID_X25519,
379 OSSL_HPKE_KDF_ID_HKDF_SHA256,
380 OSSL_HPKE_AEAD_ID_AES_GCM_128
382 first_ikme, sizeof(first_ikme),
383 first_ikmepub, sizeof(first_ikmepub),
384 first_ikmr, sizeof(first_ikmr),
385 first_ikmrpub, sizeof(first_ikmrpub),
386 first_ikmrpriv, sizeof(first_ikmrpriv),
387 first_expected_shared_secret, sizeof(first_expected_shared_secret),
388 ksinfo, sizeof(ksinfo),
389 NULL, 0, /* No Auth */
390 psk, sizeof(psk), (char *) pskid
392 const TEST_AEADDATA aeaddata[] = {
396 first_aad0, sizeof(first_aad0),
397 first_ct0, sizeof(first_ct0)
402 first_aad1, sizeof(first_aad1),
403 first_ct1, sizeof(first_ct1)
408 first_aad2, sizeof(first_aad2),
409 first_ct2, sizeof(first_ct2)
412 const TEST_EXPORTDATA exportdata[] = {
413 { NULL, 0, first_export1, sizeof(first_export1) },
414 { first_context2, sizeof(first_context2),
415 first_export2, sizeof(first_export2) },
416 { first_context3, sizeof(first_context3),
417 first_export3, sizeof(first_export3) },
419 return do_testhpke(&pskdata, aeaddata, OSSL_NELEM(aeaddata),
420 exportdata, OSSL_NELEM(exportdata));
423 static const unsigned char second_ikme[] = {
424 0x72, 0x68, 0x60, 0x0d, 0x40, 0x3f, 0xce, 0x43,
425 0x15, 0x61, 0xae, 0xf5, 0x83, 0xee, 0x16, 0x13,
426 0x52, 0x7c, 0xff, 0x65, 0x5c, 0x13, 0x43, 0xf2,
427 0x98, 0x12, 0xe6, 0x67, 0x06, 0xdf, 0x32, 0x34
429 static const unsigned char second_ikmepub[] = {
430 0x37, 0xfd, 0xa3, 0x56, 0x7b, 0xdb, 0xd6, 0x28,
431 0xe8, 0x86, 0x68, 0xc3, 0xc8, 0xd7, 0xe9, 0x7d,
432 0x1d, 0x12, 0x53, 0xb6, 0xd4, 0xea, 0x6d, 0x44,
433 0xc1, 0x50, 0xf7, 0x41, 0xf1, 0xbf, 0x44, 0x31,
435 static const unsigned char second_ikmr[] = {
436 0x6d, 0xb9, 0xdf, 0x30, 0xaa, 0x07, 0xdd, 0x42,
437 0xee, 0x5e, 0x81, 0x81, 0xaf, 0xdb, 0x97, 0x7e,
438 0x53, 0x8f, 0x5e, 0x1f, 0xec, 0x8a, 0x06, 0x22,
439 0x3f, 0x33, 0xf7, 0x01, 0x3e, 0x52, 0x50, 0x37
441 static const unsigned char second_ikmrpub[] = {
442 0x39, 0x48, 0xcf, 0xe0, 0xad, 0x1d, 0xdb, 0x69,
443 0x5d, 0x78, 0x0e, 0x59, 0x07, 0x71, 0x95, 0xda,
444 0x6c, 0x56, 0x50, 0x6b, 0x02, 0x73, 0x29, 0x79,
445 0x4a, 0xb0, 0x2b, 0xca, 0x80, 0x81, 0x5c, 0x4d
447 static const unsigned char second_ikmrpriv[] = {
448 0x46, 0x12, 0xc5, 0x50, 0x26, 0x3f, 0xc8, 0xad,
449 0x58, 0x37, 0x5d, 0xf3, 0xf5, 0x57, 0xaa, 0xc5,
450 0x31, 0xd2, 0x68, 0x50, 0x90, 0x3e, 0x55, 0xa9,
451 0xf2, 0x3f, 0x21, 0xd8, 0x53, 0x4e, 0x8a, 0xc8
453 static const unsigned char second_expected_shared_secret[] = {
454 0xfe, 0x0e, 0x18, 0xc9, 0xf0, 0x24, 0xce, 0x43,
455 0x79, 0x9a, 0xe3, 0x93, 0xc7, 0xe8, 0xfe, 0x8f,
456 0xce, 0x9d, 0x21, 0x88, 0x75, 0xe8, 0x22, 0x7b,
457 0x01, 0x87, 0xc0, 0x4e, 0x7d, 0x2e, 0xa1, 0xfc
459 static const unsigned char second_aead0[] = {
460 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x2d, 0x30
462 static const unsigned char second_ct0[] = {
463 0xf9, 0x38, 0x55, 0x8b, 0x5d, 0x72, 0xf1, 0xa2,
464 0x38, 0x10, 0xb4, 0xbe, 0x2a, 0xb4, 0xf8, 0x43,
465 0x31, 0xac, 0xc0, 0x2f, 0xc9, 0x7b, 0xab, 0xc5,
466 0x3a, 0x52, 0xae, 0x82, 0x18, 0xa3, 0x55, 0xa9,
467 0x6d, 0x87, 0x70, 0xac, 0x83, 0xd0, 0x7b, 0xea,
468 0x87, 0xe1, 0x3c, 0x51, 0x2a
470 static const unsigned char second_aead1[] = {
471 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x2d, 0x31
473 static const unsigned char second_ct1[] = {
474 0xaf, 0x2d, 0x7e, 0x9a, 0xc9, 0xae, 0x7e, 0x27,
475 0x0f, 0x46, 0xba, 0x1f, 0x97, 0x5b, 0xe5, 0x3c,
476 0x09, 0xf8, 0xd8, 0x75, 0xbd, 0xc8, 0x53, 0x54,
477 0x58, 0xc2, 0x49, 0x4e, 0x8a, 0x6e, 0xab, 0x25,
478 0x1c, 0x03, 0xd0, 0xc2, 0x2a, 0x56, 0xb8, 0xca,
479 0x42, 0xc2, 0x06, 0x3b, 0x84
481 static const unsigned char second_export1[] = {
482 0x38, 0x53, 0xfe, 0x2b, 0x40, 0x35, 0x19, 0x5a,
483 0x57, 0x3f, 0xfc, 0x53, 0x85, 0x6e, 0x77, 0x05,
484 0x8e, 0x15, 0xd9, 0xea, 0x06, 0x4d, 0xe3, 0xe5,
485 0x9f, 0x49, 0x61, 0xd0, 0x09, 0x52, 0x50, 0xee
487 static const unsigned char second_context2[] = { 0x00 };
488 static const unsigned char second_export2[] = {
489 0x2e, 0x8f, 0x0b, 0x54, 0x67, 0x3c, 0x70, 0x29,
490 0x64, 0x9d, 0x4e, 0xb9, 0xd5, 0xe3, 0x3b, 0xf1,
491 0x87, 0x2c, 0xf7, 0x6d, 0x62, 0x3f, 0xf1, 0x64,
492 0xac, 0x18, 0x5d, 0xa9, 0xe8, 0x8c, 0x21, 0xa5
494 static const unsigned char second_context3[] = {
495 0x54, 0x65, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x74,
498 static const unsigned char second_export3[] = {
499 0xe9, 0xe4, 0x30, 0x65, 0x10, 0x2c, 0x38, 0x36,
500 0x40, 0x1b, 0xed, 0x8c, 0x3c, 0x3c, 0x75, 0xae,
501 0x46, 0xbe, 0x16, 0x39, 0x86, 0x93, 0x91, 0xd6,
502 0x2c, 0x61, 0xf1, 0xec, 0x7a, 0xf5, 0x49, 0x31
505 static int x25519kdfsha256_hkdfsha256_aes128gcm_base_test(void)
507 const TEST_BASEDATA basedata = {
510 OSSL_HPKE_KEM_ID_X25519,
511 OSSL_HPKE_KDF_ID_HKDF_SHA256,
512 OSSL_HPKE_AEAD_ID_AES_GCM_128
514 second_ikme, sizeof(second_ikme),
515 second_ikmepub, sizeof(second_ikmepub),
516 second_ikmr, sizeof(second_ikmr),
517 second_ikmrpub, sizeof(second_ikmrpub),
518 second_ikmrpriv, sizeof(second_ikmrpriv),
519 second_expected_shared_secret, sizeof(second_expected_shared_secret),
520 ksinfo, sizeof(ksinfo),
521 NULL, 0, /* no auth ikm */
522 NULL, 0, NULL /* no psk */
524 const TEST_AEADDATA aeaddata[] = {
528 second_aead0, sizeof(second_aead0),
529 second_ct0, sizeof(second_ct0)
534 second_aead1, sizeof(second_aead1),
535 second_ct1, sizeof(second_ct1)
538 const TEST_EXPORTDATA exportdata[] = {
539 { NULL, 0, second_export1, sizeof(second_export1) },
540 { second_context2, sizeof(second_context2),
541 second_export2, sizeof(second_export2) },
542 { second_context3, sizeof(second_context3),
543 second_export3, sizeof(second_export3) },
545 return do_testhpke(&basedata, aeaddata, OSSL_NELEM(aeaddata),
546 exportdata, OSSL_NELEM(exportdata));
550 static const unsigned char third_ikme[] = {
551 0x42, 0x70, 0xe5, 0x4f, 0xfd, 0x08, 0xd7, 0x9d,
552 0x59, 0x28, 0x02, 0x0a, 0xf4, 0x68, 0x6d, 0x8f,
553 0x6b, 0x7d, 0x35, 0xdb, 0xe4, 0x70, 0x26, 0x5f,
554 0x1f, 0x5a, 0xa2, 0x28, 0x16, 0xce, 0x86, 0x0e
556 static const unsigned char third_ikmepub[] = {
557 0x04, 0xa9, 0x27, 0x19, 0xc6, 0x19, 0x5d, 0x50,
558 0x85, 0x10, 0x4f, 0x46, 0x9a, 0x8b, 0x98, 0x14,
559 0xd5, 0x83, 0x8f, 0xf7, 0x2b, 0x60, 0x50, 0x1e,
560 0x2c, 0x44, 0x66, 0xe5, 0xe6, 0x7b, 0x32, 0x5a,
561 0xc9, 0x85, 0x36, 0xd7, 0xb6, 0x1a, 0x1a, 0xf4,
562 0xb7, 0x8e, 0x5b, 0x7f, 0x95, 0x1c, 0x09, 0x00,
563 0xbe, 0x86, 0x3c, 0x40, 0x3c, 0xe6, 0x5c, 0x9b,
564 0xfc, 0xb9, 0x38, 0x26, 0x57, 0x22, 0x2d, 0x18,
567 static const unsigned char third_ikmr[] = {
568 0x66, 0x8b, 0x37, 0x17, 0x1f, 0x10, 0x72, 0xf3,
569 0xcf, 0x12, 0xea, 0x8a, 0x23, 0x6a, 0x45, 0xdf,
570 0x23, 0xfc, 0x13, 0xb8, 0x2a, 0xf3, 0x60, 0x9a,
571 0xd1, 0xe3, 0x54, 0xf6, 0xef, 0x81, 0x75, 0x50
573 static const unsigned char third_ikmrpub[] = {
574 0x04, 0xfe, 0x8c, 0x19, 0xce, 0x09, 0x05, 0x19,
575 0x1e, 0xbc, 0x29, 0x8a, 0x92, 0x45, 0x79, 0x25,
576 0x31, 0xf2, 0x6f, 0x0c, 0xec, 0xe2, 0x46, 0x06,
577 0x39, 0xe8, 0xbc, 0x39, 0xcb, 0x7f, 0x70, 0x6a,
578 0x82, 0x6a, 0x77, 0x9b, 0x4c, 0xf9, 0x69, 0xb8,
579 0xa0, 0xe5, 0x39, 0xc7, 0xf6, 0x2f, 0xb3, 0xd3,
580 0x0a, 0xd6, 0xaa, 0x8f, 0x80, 0xe3, 0x0f, 0x1d,
581 0x12, 0x8a, 0xaf, 0xd6, 0x8a, 0x2c, 0xe7, 0x2e,
584 static const unsigned char third_ikmrpriv[] = {
585 0xf3, 0xce, 0x7f, 0xda, 0xe5, 0x7e, 0x1a, 0x31,
586 0x0d, 0x87, 0xf1, 0xeb, 0xbd, 0xe6, 0xf3, 0x28,
587 0xbe, 0x0a, 0x99, 0xcd, 0xbc, 0xad, 0xf4, 0xd6,
588 0x58, 0x9c, 0xf2, 0x9d, 0xe4, 0xb8, 0xff, 0xd2
590 static const unsigned char third_expected_shared_secret[] = {
591 0xc0, 0xd2, 0x6a, 0xea, 0xb5, 0x36, 0x60, 0x9a,
592 0x57, 0x2b, 0x07, 0x69, 0x5d, 0x93, 0x3b, 0x58,
593 0x9d, 0xcf, 0x36, 0x3f, 0xf9, 0xd9, 0x3c, 0x93,
594 0xad, 0xea, 0x53, 0x7a, 0xea, 0xbb, 0x8c, 0xb8
596 static const unsigned char third_aead0[] = {
597 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x2d, 0x30
599 static const unsigned char third_ct0[] = {
600 0x5a, 0xd5, 0x90, 0xbb, 0x8b, 0xaa, 0x57, 0x7f,
601 0x86, 0x19, 0xdb, 0x35, 0xa3, 0x63, 0x11, 0x22,
602 0x6a, 0x89, 0x6e, 0x73, 0x42, 0xa6, 0xd8, 0x36,
603 0xd8, 0xb7, 0xbc, 0xd2, 0xf2, 0x0b, 0x6c, 0x7f,
604 0x90, 0x76, 0xac, 0x23, 0x2e, 0x3a, 0xb2, 0x52,
605 0x3f, 0x39, 0x51, 0x34, 0x34
607 static const unsigned char third_aead1[] = {
608 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x2d, 0x31
610 static const unsigned char third_ct1[] = {
611 0xfa, 0x6f, 0x03, 0x7b, 0x47, 0xfc, 0x21, 0x82,
612 0x6b, 0x61, 0x01, 0x72, 0xca, 0x96, 0x37, 0xe8,
613 0x2d, 0x6e, 0x58, 0x01, 0xeb, 0x31, 0xcb, 0xd3,
614 0x74, 0x82, 0x71, 0xaf, 0xfd, 0x4e, 0xcb, 0x06,
615 0x64, 0x6e, 0x03, 0x29, 0xcb, 0xdf, 0x3c, 0x3c,
616 0xd6, 0x55, 0xb2, 0x8e, 0x82
618 static const unsigned char third_export1[] = {
619 0x5e, 0x9b, 0xc3, 0xd2, 0x36, 0xe1, 0x91, 0x1d,
620 0x95, 0xe6, 0x5b, 0x57, 0x6a, 0x8a, 0x86, 0xd4,
621 0x78, 0xfb, 0x82, 0x7e, 0x8b, 0xdf, 0xe7, 0x7b,
622 0x74, 0x1b, 0x28, 0x98, 0x90, 0x49, 0x0d, 0x4d
624 static const unsigned char third_context2[] = { 0x00 };
625 static const unsigned char third_export2[] = {
626 0x6c, 0xff, 0x87, 0x65, 0x89, 0x31, 0xbd, 0xa8,
627 0x3d, 0xc8, 0x57, 0xe6, 0x35, 0x3e, 0xfe, 0x49,
628 0x87, 0xa2, 0x01, 0xb8, 0x49, 0x65, 0x8d, 0x9b,
629 0x04, 0x7a, 0xab, 0x4c, 0xf2, 0x16, 0xe7, 0x96
631 static const unsigned char third_context3[] = {
632 0x54, 0x65, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x74,
635 static const unsigned char third_export3[] = {
636 0xd8, 0xf1, 0xea, 0x79, 0x42, 0xad, 0xbb, 0xa7,
637 0x41, 0x2c, 0x6d, 0x43, 0x1c, 0x62, 0xd0, 0x13,
638 0x71, 0xea, 0x47, 0x6b, 0x82, 0x3e, 0xb6, 0x97,
639 0xe1, 0xf6, 0xe6, 0xca, 0xe1, 0xda, 0xb8, 0x5a
642 static int P256kdfsha256_hkdfsha256_aes128gcm_base_test(void)
644 const TEST_BASEDATA basedata = {
647 OSSL_HPKE_KEM_ID_P256,
648 OSSL_HPKE_KDF_ID_HKDF_SHA256,
649 OSSL_HPKE_AEAD_ID_AES_GCM_128
651 third_ikme, sizeof(third_ikme),
652 third_ikmepub, sizeof(third_ikmepub),
653 third_ikmr, sizeof(third_ikmr),
654 third_ikmrpub, sizeof(third_ikmrpub),
655 third_ikmrpriv, sizeof(third_ikmrpriv),
656 third_expected_shared_secret, sizeof(third_expected_shared_secret),
657 ksinfo, sizeof(ksinfo),
658 NULL, 0, /* no auth */
659 NULL, 0, NULL /* PSK stuff */
661 const TEST_AEADDATA aeaddata[] = {
665 third_aead0, sizeof(third_aead0),
666 third_ct0, sizeof(third_ct0)
671 third_aead1, sizeof(third_aead1),
672 third_ct1, sizeof(third_ct1)
675 const TEST_EXPORTDATA exportdata[] = {
676 { NULL, 0, third_export1, sizeof(third_export1) },
677 { third_context2, sizeof(third_context2),
678 third_export2, sizeof(third_export2) },
679 { third_context3, sizeof(third_context3),
680 third_export3, sizeof(third_export3) },
682 return do_testhpke(&basedata, aeaddata, OSSL_NELEM(aeaddata),
683 exportdata, OSSL_NELEM(exportdata));
686 #ifndef OPENSSL_NO_ECX
687 static const unsigned char fourth_ikme[] = {
688 0x55, 0xbc, 0x24, 0x5e, 0xe4, 0xef, 0xda, 0x25,
689 0xd3, 0x8f, 0x2d, 0x54, 0xd5, 0xbb, 0x66, 0x65,
690 0x29, 0x1b, 0x99, 0xf8, 0x10, 0x8a, 0x8c, 0x4b,
691 0x68, 0x6c, 0x2b, 0x14, 0x89, 0x3e, 0xa5, 0xd9
693 static const unsigned char fourth_ikmepub[] = {
694 0xe5, 0xe8, 0xf9, 0xbf, 0xff, 0x6c, 0x2f, 0x29,
695 0x79, 0x1f, 0xc3, 0x51, 0xd2, 0xc2, 0x5c, 0xe1,
696 0x29, 0x9a, 0xa5, 0xea, 0xca, 0x78, 0xa7, 0x57,
697 0xc0, 0xb4, 0xfb, 0x4b, 0xcd, 0x83, 0x09, 0x18
699 static const unsigned char fourth_ikmr[] = {
700 0x68, 0x3a, 0xe0, 0xda, 0x1d, 0x22, 0x18, 0x1e,
701 0x74, 0xed, 0x2e, 0x50, 0x3e, 0xbf, 0x82, 0x84,
702 0x0d, 0xeb, 0x1d, 0x5e, 0x87, 0x2c, 0xad, 0xe2,
703 0x0f, 0x4b, 0x45, 0x8d, 0x99, 0x78, 0x3e, 0x31
705 static const unsigned char fourth_ikmrpub[] = {
706 0x19, 0x41, 0x41, 0xca, 0x6c, 0x3c, 0x3b, 0xeb,
707 0x47, 0x92, 0xcd, 0x97, 0xba, 0x0e, 0xa1, 0xfa,
708 0xff, 0x09, 0xd9, 0x84, 0x35, 0x01, 0x23, 0x45,
709 0x76, 0x6e, 0xe3, 0x3a, 0xae, 0x2d, 0x76, 0x64
711 static const unsigned char fourth_ikmrpriv[] = {
712 0x33, 0xd1, 0x96, 0xc8, 0x30, 0xa1, 0x2f, 0x9a,
713 0xc6, 0x5d, 0x6e, 0x56, 0x5a, 0x59, 0x0d, 0x80,
714 0xf0, 0x4e, 0xe9, 0xb1, 0x9c, 0x83, 0xc8, 0x7f,
715 0x2c, 0x17, 0x0d, 0x97, 0x2a, 0x81, 0x28, 0x48
717 static const unsigned char fourth_expected_shared_secret[] = {
718 0xe8, 0x17, 0x16, 0xce, 0x8f, 0x73, 0x14, 0x1d,
719 0x4f, 0x25, 0xee, 0x90, 0x98, 0xef, 0xc9, 0x68,
720 0xc9, 0x1e, 0x5b, 0x8c, 0xe5, 0x2f, 0xff, 0xf5,
721 0x9d, 0x64, 0x03, 0x9e, 0x82, 0x91, 0x8b, 0x66
723 static const unsigned char fourth_export1[] = {
724 0x7a, 0x36, 0x22, 0x1b, 0xd5, 0x6d, 0x50, 0xfb,
725 0x51, 0xee, 0x65, 0xed, 0xfd, 0x98, 0xd0, 0x6a,
726 0x23, 0xc4, 0xdc, 0x87, 0x08, 0x5a, 0xa5, 0x86,
727 0x6c, 0xb7, 0x08, 0x72, 0x44, 0xbd, 0x2a, 0x36
729 static const unsigned char fourth_context2[] = { 0x00 };
730 static const unsigned char fourth_export2[] = {
731 0xd5, 0x53, 0x5b, 0x87, 0x09, 0x9c, 0x6c, 0x3c,
732 0xe8, 0x0d, 0xc1, 0x12, 0xa2, 0x67, 0x1c, 0x6e,
733 0xc8, 0xe8, 0x11, 0xa2, 0xf2, 0x84, 0xf9, 0x48,
734 0xce, 0xc6, 0xdd, 0x17, 0x08, 0xee, 0x33, 0xf0
736 static const unsigned char fourth_context3[] = {
737 0x54, 0x65, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x74,
740 static const unsigned char fourth_export3[] = {
741 0xff, 0xaa, 0xbc, 0x85, 0xa7, 0x76, 0x13, 0x6c,
742 0xa0, 0xc3, 0x78, 0xe5, 0xd0, 0x84, 0xc9, 0x14,
743 0x0a, 0xb5, 0x52, 0xb7, 0x8f, 0x03, 0x9d, 0x2e,
744 0x87, 0x75, 0xf2, 0x6e, 0xff, 0xf4, 0xc7, 0x0e
747 static int export_only_test(void)
749 /* based on RFC9180 A.7 */
750 const TEST_BASEDATA basedata = {
753 OSSL_HPKE_KEM_ID_X25519,
754 OSSL_HPKE_KDF_ID_HKDF_SHA256,
755 OSSL_HPKE_AEAD_ID_EXPORTONLY
757 fourth_ikme, sizeof(fourth_ikme),
758 fourth_ikmepub, sizeof(fourth_ikmepub),
759 fourth_ikmr, sizeof(fourth_ikmr),
760 fourth_ikmrpub, sizeof(fourth_ikmrpub),
761 fourth_ikmrpriv, sizeof(fourth_ikmrpriv),
762 fourth_expected_shared_secret, sizeof(fourth_expected_shared_secret),
763 ksinfo, sizeof(ksinfo),
764 NULL, 0, /* no auth */
765 NULL, 0, NULL /* PSK stuff */
767 const TEST_EXPORTDATA exportdata[] = {
768 { NULL, 0, fourth_export1, sizeof(fourth_export1) },
769 { fourth_context2, sizeof(fourth_context2),
770 fourth_export2, sizeof(fourth_export2) },
771 { fourth_context3, sizeof(fourth_context3),
772 fourth_export3, sizeof(fourth_export3) },
774 return do_testhpke(&basedata, NULL, 0,
775 exportdata, OSSL_NELEM(exportdata));
780 * Randomly toss a coin
782 #define COIN_IS_HEADS (test_random() % 2)
784 /* tables of HPKE modes and suite values */
785 static int hpke_mode_list[] = {
789 OSSL_HPKE_MODE_PSKAUTH
791 static uint16_t hpke_kem_list[] = {
792 OSSL_HPKE_KEM_ID_P256,
793 OSSL_HPKE_KEM_ID_P384,
794 OSSL_HPKE_KEM_ID_P521,
795 #ifndef OPENSSL_NO_ECX
796 OSSL_HPKE_KEM_ID_X25519,
797 OSSL_HPKE_KEM_ID_X448
800 static uint16_t hpke_kdf_list[] = {
801 OSSL_HPKE_KDF_ID_HKDF_SHA256,
802 OSSL_HPKE_KDF_ID_HKDF_SHA384,
803 OSSL_HPKE_KDF_ID_HKDF_SHA512
805 static uint16_t hpke_aead_list[] = {
806 OSSL_HPKE_AEAD_ID_AES_GCM_128,
807 OSSL_HPKE_AEAD_ID_AES_GCM_256,
808 #if !defined(OPENSSL_NO_CHACHA) && !defined(OPENSSL_NO_POLY1305)
809 OSSL_HPKE_AEAD_ID_CHACHA_POLY1305
814 * Strings that can be used with names or IANA codepoints.
815 * Note that the initial entries from these lists should
816 * match the lists above, i.e. kem_str_list[0] and
817 * hpke_kem_list[0] should refer to the same KEM. We use
818 * that for verbose output via TEST_note() below.
819 * Subsequent entries are only used for tests of
820 * OSSL_HPKE_str2suite()
822 static const char *mode_str_list[] = {
823 "base", "psk", "auth", "pskauth"
825 static const char *kem_str_list[] = {
826 #ifndef OPENSSL_NO_ECX
827 "P-256", "P-384", "P-521", "x25519", "x448",
828 "0x10", "0x11", "0x12", "0x20", "0x21",
829 "16", "17", "18", "32", "33"
831 "P-256", "P-384", "P-521",
832 "0x10", "0x11", "0x12",
836 static const char *kdf_str_list[] = {
837 "hkdf-sha256", "hkdf-sha384", "hkdf-sha512",
838 "0x1", "0x01", "0x2", "0x02", "0x3", "0x03",
841 static const char *aead_str_list[] = {
842 "aes-128-gcm", "aes-256-gcm", "chacha20-poly1305", "exporter",
843 "0x1", "0x01", "0x2", "0x02", "0x3", "0x03",
847 /* table of bogus strings that better not work */
848 static const char *bogus_suite_strs[] = {
851 "bogus,33,3,1,bogus",
859 /* in reverse order */
860 "aes-256-gcm,hkdf-sha512,x25519",
861 /* surplus separators */
865 /* embedded NUL chars */
867 "0x10,\0""0x01,0x02",
870 "0x10,0x01,\0""0x02",
871 /* embedded whitespace */
872 " aes-256-gcm,hkdf-sha512,x25519",
873 "aes-256-gcm, hkdf-sha512,x25519",
874 "aes-256-gcm ,hkdf-sha512,x25519",
875 "aes-256-gcm,hkdf-sha512, x25519",
876 "aes-256-gcm,hkdf-sha512 ,x25519",
877 "aes-256-gcm,hkdf-sha512,x25519 ",
878 /* good value followed by extra stuff */
881 "0x10,0x01,0x01,0x02",
882 "0x10,0x01,0x01,blah",
883 "0x10,0x01,0x01 0x02",
884 /* too few but good tokens */
895 * @brief round-trips, generating keys, encrypt and decrypt
897 * This iterates over all mode and ciphersuite options trying
898 * a key gen, encrypt and decrypt for each. The aad, info, and
899 * seq inputs are randomly set or omitted each time. EVP and
900 * non-EVP key generation are randomly selected.
902 * @return 1 for success, other otherwise
904 static int test_hpke_modes_suites(void)
906 int overallresult = 1;
907 size_t mind = 0; /* index into hpke_mode_list */
908 size_t kemind = 0; /* index into hpke_kem_list */
909 size_t kdfind = 0; /* index into hpke_kdf_list */
910 size_t aeadind = 0; /* index into hpke_aead_list */
912 /* iterate over the different modes */
913 for (mind = 0; mind < OSSL_NELEM(hpke_mode_list); mind++) {
914 int hpke_mode = hpke_mode_list[mind];
915 size_t aadlen = OSSL_HPKE_TSTSIZE;
916 unsigned char aad[OSSL_HPKE_TSTSIZE];
917 unsigned char *aadp = NULL;
919 unsigned char info[32];
920 unsigned char *infop = NULL;
921 unsigned char lpsk[32];
922 unsigned char *pskp = NULL;
926 EVP_PKEY *privp = NULL;
927 OSSL_HPKE_SUITE hpke_suite = OSSL_HPKE_SUITE_DEFAULT;
928 size_t plainlen = OSSL_HPKE_TSTSIZE;
929 unsigned char plain[OSSL_HPKE_TSTSIZE];
930 OSSL_HPKE_CTX *rctx = NULL;
931 OSSL_HPKE_CTX *ctx = NULL;
933 memset(plain, 0x00, OSSL_HPKE_TSTSIZE);
934 strcpy((char *)plain, "a message not in a bottle");
935 plainlen = strlen((char *)plain);
937 * Randomly try with/without info, aad, seq. Given mode and suite
938 * combos, and this being run even a few times, we'll exercise many
939 * code paths fairly quickly. We don't really care what the values
940 * are but it'll be easier to debug if they're known, so we set 'em.
944 memset(aad, 'a', aadlen);
950 memset(info, 'i', infolen);
954 if (hpke_mode == OSSL_HPKE_MODE_PSK
955 || hpke_mode == OSSL_HPKE_MODE_PSKAUTH) {
957 memset(lpsk, 'P', psklen);
959 memset(lpskid, 'I', psklen - 1);
960 lpskid[psklen - 1] = '\0';
964 for (kemind = 0; /* iterate over the kems, kdfs and aeads */
965 overallresult == 1 && kemind < OSSL_NELEM(hpke_kem_list);
967 uint16_t kem_id = hpke_kem_list[kemind];
968 size_t authpublen = OSSL_HPKE_TSTSIZE;
969 unsigned char authpub[OSSL_HPKE_TSTSIZE];
970 unsigned char *authpubp = NULL;
971 EVP_PKEY *authpriv = NULL;
973 hpke_suite.kem_id = kem_id;
974 if (hpke_mode == OSSL_HPKE_MODE_AUTH
975 || hpke_mode == OSSL_HPKE_MODE_PSKAUTH) {
976 if (TEST_true(OSSL_HPKE_keygen(hpke_suite, authpub, &authpublen,
978 testctx, NULL)) != 1) {
986 overallresult == 1 && kdfind < OSSL_NELEM(hpke_kdf_list);
988 uint16_t kdf_id = hpke_kdf_list[kdfind];
990 hpke_suite.kdf_id = kdf_id;
993 && aeadind < OSSL_NELEM(hpke_aead_list);
995 uint16_t aead_id = hpke_aead_list[aeadind];
996 size_t publen = OSSL_HPKE_TSTSIZE;
997 unsigned char pub[OSSL_HPKE_TSTSIZE];
998 size_t senderpublen = OSSL_HPKE_TSTSIZE;
999 unsigned char senderpub[OSSL_HPKE_TSTSIZE];
1000 size_t cipherlen = OSSL_HPKE_TSTSIZE;
1001 unsigned char cipher[OSSL_HPKE_TSTSIZE];
1002 size_t clearlen = OSSL_HPKE_TSTSIZE;
1003 unsigned char clear[OSSL_HPKE_TSTSIZE];
1005 hpke_suite.aead_id = aead_id;
1006 if (!TEST_true(OSSL_HPKE_keygen(hpke_suite,
1007 pub, &publen, &privp,
1008 NULL, 0, testctx, NULL)))
1010 if (!TEST_ptr(ctx = OSSL_HPKE_CTX_new(hpke_mode, hpke_suite,
1011 OSSL_HPKE_ROLE_SENDER,
1014 if (hpke_mode == OSSL_HPKE_MODE_PSK
1015 || hpke_mode == OSSL_HPKE_MODE_PSKAUTH) {
1016 if (!TEST_true(OSSL_HPKE_CTX_set1_psk(ctx, pskidp,
1020 if (hpke_mode == OSSL_HPKE_MODE_AUTH
1021 || hpke_mode == OSSL_HPKE_MODE_PSKAUTH) {
1022 if (!TEST_true(OSSL_HPKE_CTX_set1_authpriv(ctx,
1026 if (!TEST_true(OSSL_HPKE_encap(ctx, senderpub,
1031 /* throw in a call with a too-short cipherlen */
1033 if (!TEST_false(OSSL_HPKE_seal(ctx, cipher, &cipherlen,
1037 /* fix back real cipherlen */
1038 cipherlen = OSSL_HPKE_TSTSIZE;
1039 if (!TEST_true(OSSL_HPKE_seal(ctx, cipher, &cipherlen,
1043 OSSL_HPKE_CTX_free(ctx);
1044 memset(clear, 0, clearlen);
1045 rctx = OSSL_HPKE_CTX_new(hpke_mode, hpke_suite,
1046 OSSL_HPKE_ROLE_RECEIVER,
1048 if (!TEST_ptr(rctx))
1050 if (hpke_mode == OSSL_HPKE_MODE_PSK
1051 || hpke_mode == OSSL_HPKE_MODE_PSKAUTH) {
1052 if (!TEST_true(OSSL_HPKE_CTX_set1_psk(rctx, pskidp,
1056 if (hpke_mode == OSSL_HPKE_MODE_AUTH
1057 || hpke_mode == OSSL_HPKE_MODE_PSKAUTH) {
1058 /* check a borked p256 key */
1059 if (hpke_suite.kem_id == OSSL_HPKE_KEM_ID_P256) {
1060 /* set to fail decode of authpub this time */
1061 if (!TEST_false(OSSL_HPKE_CTX_set1_authpub(rctx,
1067 if (!TEST_true(OSSL_HPKE_CTX_set1_authpub(rctx,
1072 if (!TEST_true(OSSL_HPKE_decap(rctx, senderpub,
1073 senderpublen, privp,
1076 /* throw in a call with a too-short clearlen */
1078 if (!TEST_false(OSSL_HPKE_open(rctx, clear, &clearlen,
1079 aadp, aadlen, cipher,
1082 /* fix up real clearlen again */
1083 clearlen = OSSL_HPKE_TSTSIZE;
1084 if (!TEST_true(OSSL_HPKE_open(rctx, clear, &clearlen,
1085 aadp, aadlen, cipher,
1088 OSSL_HPKE_CTX_free(rctx);
1089 EVP_PKEY_free(privp);
1092 if (!TEST_mem_eq(clear, clearlen, plain, plainlen)) {
1095 if (verbose || overallresult != 1) {
1096 const char *res = NULL;
1098 res = (overallresult == 1 ? "worked" : "failed");
1099 TEST_note("HPKE %s for mode: %s/0x%02x, "\
1100 "kem: %s/0x%02x, kdf: %s/0x%02x, "\
1101 "aead: %s/0x%02x", res,
1102 mode_str_list[mind], (int) mind,
1103 kem_str_list[kemind], kem_id,
1104 kdf_str_list[kdfind], kdf_id,
1105 aead_str_list[aeadind], aead_id);
1109 EVP_PKEY_free(authpriv);
1112 return overallresult;
1116 * @brief check roundtrip for export
1117 * @return 1 for success, other otherwise
1119 static int test_hpke_export(void)
1122 EVP_PKEY *privp = NULL;
1123 unsigned char pub[OSSL_HPKE_TSTSIZE];
1124 size_t publen = sizeof(pub);
1125 int hpke_mode = OSSL_HPKE_MODE_BASE;
1126 OSSL_HPKE_SUITE hpke_suite = OSSL_HPKE_SUITE_DEFAULT;
1127 OSSL_HPKE_CTX *ctx = NULL;
1128 OSSL_HPKE_CTX *rctx = NULL;
1129 unsigned char exp[32];
1130 unsigned char exp2[32];
1131 unsigned char rexp[32];
1132 unsigned char rexp2[32];
1133 unsigned char plain[] = "quick brown fox";
1134 size_t plainlen = sizeof(plain);
1135 unsigned char enc[OSSL_HPKE_TSTSIZE];
1136 size_t enclen = sizeof(enc);
1137 unsigned char cipher[OSSL_HPKE_TSTSIZE];
1138 size_t cipherlen = sizeof(cipher);
1139 unsigned char clear[OSSL_HPKE_TSTSIZE];
1140 size_t clearlen = sizeof(clear);
1143 if (!TEST_true(OSSL_HPKE_keygen(hpke_suite, pub, &publen, &privp,
1144 NULL, 0, testctx, NULL)))
1146 if (!TEST_ptr(ctx = OSSL_HPKE_CTX_new(hpke_mode, hpke_suite,
1147 OSSL_HPKE_ROLE_SENDER,
1150 /* a few error cases 1st */
1151 if (!TEST_false(OSSL_HPKE_export(NULL, exp, sizeof(exp),
1152 (unsigned char *)estr, strlen(estr))))
1154 /* ctx before encap should fail too */
1155 if (!TEST_false(OSSL_HPKE_export(ctx, exp, sizeof(exp),
1156 (unsigned char *)estr, strlen(estr))))
1158 if (!TEST_true(OSSL_HPKE_encap(ctx, enc, &enclen, pub, publen, NULL, 0)))
1160 if (!TEST_true(OSSL_HPKE_seal(ctx, cipher, &cipherlen, NULL, 0,
1164 if (!TEST_true(OSSL_HPKE_export(ctx, exp, sizeof(exp),
1165 (unsigned char *)estr, strlen(estr))))
1167 /* check a 2nd call with same input gives same output */
1168 if (!TEST_true(OSSL_HPKE_export(ctx, exp2, sizeof(exp2),
1169 (unsigned char *)estr, strlen(estr))))
1171 if (!TEST_mem_eq(exp, sizeof(exp), exp2, sizeof(exp2)))
1173 if (!TEST_ptr(rctx = OSSL_HPKE_CTX_new(hpke_mode, hpke_suite,
1174 OSSL_HPKE_ROLE_RECEIVER,
1177 if (!TEST_true(OSSL_HPKE_decap(rctx, enc, enclen, privp, NULL, 0)))
1179 if (!TEST_true(OSSL_HPKE_open(rctx, clear, &clearlen, NULL, 0,
1180 cipher, cipherlen)))
1182 if (!TEST_true(OSSL_HPKE_export(rctx, rexp, sizeof(rexp),
1183 (unsigned char *)estr, strlen(estr))))
1185 /* check a 2nd call with same input gives same output */
1186 if (!TEST_true(OSSL_HPKE_export(rctx, rexp2, sizeof(rexp2),
1187 (unsigned char *)estr, strlen(estr))))
1189 if (!TEST_mem_eq(rexp, sizeof(rexp), rexp2, sizeof(rexp2)))
1191 if (!TEST_mem_eq(exp, sizeof(exp), rexp, sizeof(rexp)))
1195 OSSL_HPKE_CTX_free(ctx);
1196 OSSL_HPKE_CTX_free(rctx);
1197 EVP_PKEY_free(privp);
1202 * @brief Check mapping from strings to HPKE suites
1203 * @return 1 for success, other otherwise
1205 static int test_hpke_suite_strs(void)
1207 int overallresult = 1;
1213 OSSL_HPKE_SUITE stirred;
1216 for (kemind = 0; kemind != OSSL_NELEM(kem_str_list); kemind++) {
1217 for (kdfind = 0; kdfind != OSSL_NELEM(kdf_str_list); kdfind++) {
1218 for (aeadind = 0; aeadind != OSSL_NELEM(aead_str_list); aeadind++) {
1219 BIO_snprintf(sstr, 128, "%s,%s,%s", kem_str_list[kemind],
1220 kdf_str_list[kdfind], aead_str_list[aeadind]);
1221 if (TEST_true(OSSL_HPKE_str2suite(sstr, &stirred)) != 1) {
1223 TEST_note("Unexpected str2suite fail for :%s",
1224 bogus_suite_strs[sind]);
1230 for (sind = 0; sind != OSSL_NELEM(bogus_suite_strs); sind++) {
1231 if (TEST_false(OSSL_HPKE_str2suite(bogus_suite_strs[sind],
1234 TEST_note("OSSL_HPKE_str2suite didn't fail for bogus[%d]:%s",
1235 sind, bogus_suite_strs[sind]);
1239 /* check a few errors */
1240 if (!TEST_false(OSSL_HPKE_str2suite("", &stirred)))
1242 if (!TEST_false(OSSL_HPKE_str2suite(NULL, &stirred)))
1244 if (!TEST_false(OSSL_HPKE_str2suite("", NULL)))
1246 memset(giant, 'A', sizeof(giant) - 1);
1247 giant[sizeof(giant) - 1] = '\0';
1248 if (!TEST_false(OSSL_HPKE_str2suite(giant, &stirred)))
1251 return overallresult;
1255 * @brief try the various GREASEy APIs
1256 * @return 1 for success, other otherwise
1258 static int test_hpke_grease(void)
1260 int overallresult = 1;
1261 OSSL_HPKE_SUITE g_suite;
1262 unsigned char g_pub[OSSL_HPKE_TSTSIZE];
1263 size_t g_pub_len = OSSL_HPKE_TSTSIZE;
1264 unsigned char g_cipher[OSSL_HPKE_TSTSIZE];
1265 size_t g_cipher_len = 266;
1266 size_t clearlen = 128;
1267 size_t expanded = 0;
1271 memset(&g_suite, 0, sizeof(OSSL_HPKE_SUITE));
1273 /* check too short for public value */
1275 if (TEST_false(OSSL_HPKE_get_grease_value(NULL, &g_suite,
1277 g_cipher, g_cipher_len,
1278 testctx, NULL)) != 1) {
1282 g_pub_len = OSSL_HPKE_TSTSIZE;
1283 if (TEST_true(OSSL_HPKE_get_grease_value(NULL, &g_suite,
1285 g_cipher, g_cipher_len,
1286 testctx, NULL)) != 1) {
1290 expanded = OSSL_HPKE_get_ciphertext_size(g_suite, clearlen);
1291 if (!TEST_size_t_gt(expanded, clearlen)) {
1294 enclen = OSSL_HPKE_get_public_encap_size(g_suite);
1295 if (!TEST_size_t_ne(enclen, 0))
1297 /* not really GREASE but we'll check ikmelen thing */
1298 ikmelen = OSSL_HPKE_get_recommended_ikmelen(g_suite);
1299 if (!TEST_size_t_ne(ikmelen, 0))
1302 return overallresult;
1306 * Make a set of calls with odd parameters
1308 static int test_hpke_oddcalls(void)
1311 EVP_PKEY *privp = NULL;
1312 unsigned char pub[OSSL_HPKE_TSTSIZE];
1313 size_t publen = sizeof(pub);
1314 int hpke_mode = OSSL_HPKE_MODE_BASE;
1315 int bad_mode = 0xbad;
1316 OSSL_HPKE_SUITE hpke_suite = OSSL_HPKE_SUITE_DEFAULT;
1317 OSSL_HPKE_SUITE bad_suite = { 0xbad, 0xbad, 0xbad };
1318 OSSL_HPKE_CTX *ctx = NULL;
1319 OSSL_HPKE_CTX *rctx = NULL;
1320 unsigned char plain[] = "quick brown fox";
1321 size_t plainlen = sizeof(plain);
1322 unsigned char enc[OSSL_HPKE_TSTSIZE], smallenc[10];
1323 size_t enclen = sizeof(enc), smallenclen = sizeof(smallenc);
1324 unsigned char cipher[OSSL_HPKE_TSTSIZE];
1325 size_t cipherlen = sizeof(cipher);
1326 unsigned char clear[OSSL_HPKE_TSTSIZE];
1327 size_t clearlen = sizeof(clear);
1328 unsigned char fake_ikm[OSSL_HPKE_TSTSIZE];
1329 char *badpropq = "yeah, this won't work";
1331 char giant_pskid[OSSL_HPKE_MAX_PARMLEN + 10];
1332 unsigned char info[OSSL_HPKE_TSTSIZE];
1334 /* many of the calls below are designed to get better test coverage */
1336 /* NULL ctx calls */
1337 OSSL_HPKE_CTX_free(NULL);
1338 if (!TEST_false(OSSL_HPKE_CTX_set_seq(NULL, 1)))
1340 if (!TEST_false(OSSL_HPKE_CTX_get_seq(NULL, &lseq)))
1342 if (!TEST_false(OSSL_HPKE_CTX_set1_authpub(NULL, pub, publen)))
1344 if (!TEST_false(OSSL_HPKE_CTX_set1_authpriv(NULL, privp)))
1346 if (!TEST_false(OSSL_HPKE_CTX_set1_ikme(NULL, NULL, 0)))
1348 if (!TEST_false(OSSL_HPKE_CTX_set1_psk(NULL, NULL, NULL, 0)))
1351 /* bad suite calls */
1352 hpke_suite.aead_id = 0xbad;
1353 if (!TEST_false(OSSL_HPKE_suite_check(hpke_suite)))
1355 hpke_suite.aead_id = OSSL_HPKE_AEAD_ID_AES_GCM_128;
1356 if (!TEST_false(OSSL_HPKE_suite_check(bad_suite)))
1358 if (!TEST_false(OSSL_HPKE_get_recommended_ikmelen(bad_suite)))
1360 if (!TEST_false(OSSL_HPKE_get_public_encap_size(bad_suite)))
1362 if (!TEST_false(OSSL_HPKE_get_ciphertext_size(bad_suite, 0)))
1364 if (!TEST_false(OSSL_HPKE_keygen(bad_suite, pub, &publen, &privp,
1365 NULL, 0, testctx, badpropq)))
1367 if (!TEST_false(OSSL_HPKE_keygen(bad_suite, pub, &publen, &privp,
1368 NULL, 0, testctx, NULL)))
1371 /* dodgy keygen calls */
1373 if (!TEST_false(OSSL_HPKE_keygen(hpke_suite, NULL, &publen, &privp,
1374 NULL, 0, testctx, NULL)))
1376 /* ikmlen but NULL ikm */
1377 if (!TEST_false(OSSL_HPKE_keygen(hpke_suite, pub, &publen, &privp,
1378 NULL, 80, testctx, NULL)))
1380 /* zero ikmlen but ikm */
1381 if (!TEST_false(OSSL_HPKE_keygen(hpke_suite, pub, &publen, &privp,
1382 fake_ikm, 0, testctx, NULL)))
1385 if (!TEST_false(OSSL_HPKE_keygen(hpke_suite, pub, &publen, &privp,
1386 fake_ikm, -1, testctx, NULL)))
1390 if (!TEST_false(OSSL_HPKE_keygen(hpke_suite, pub, &publen, &privp,
1391 NULL, 0, testctx, NULL)))
1393 publen = sizeof(pub);
1395 /* encap/decap with NULLs */
1396 if (!TEST_false(OSSL_HPKE_encap(NULL, NULL, NULL, NULL, 0, NULL, 0)))
1398 if (!TEST_false(OSSL_HPKE_decap(NULL, NULL, 0, NULL, NULL, 0)))
1402 * run through a sender/recipient set of calls but with
1403 * failing calls interspersed whenever possible
1406 if (!TEST_true(OSSL_HPKE_keygen(hpke_suite, pub, &publen, &privp,
1407 NULL, 0, testctx, NULL)))
1410 /* a psk context with no psk => encap fail */
1411 if (!TEST_ptr(ctx = OSSL_HPKE_CTX_new(OSSL_HPKE_MODE_PSK, hpke_suite,
1412 OSSL_HPKE_ROLE_SENDER,
1415 /* set bad length psk */
1416 if (!TEST_false(OSSL_HPKE_CTX_set1_psk(ctx, "foo",
1417 (unsigned char *)"bar", -1)))
1419 /* set bad length pskid */
1420 memset(giant_pskid, 'A', sizeof(giant_pskid) - 1);
1421 giant_pskid[sizeof(giant_pskid) - 1] = '\0';
1422 if (!TEST_false(OSSL_HPKE_CTX_set1_psk(ctx, giant_pskid,
1423 (unsigned char *)"bar", 3)))
1425 /* still no psk really set so encap fails */
1426 if (!TEST_false(OSSL_HPKE_encap(ctx, enc, &enclen, pub, publen, NULL, 0)))
1428 OSSL_HPKE_CTX_free(ctx);
1431 if (!TEST_ptr_null(ctx = OSSL_HPKE_CTX_new(hpke_mode, bad_suite,
1432 OSSL_HPKE_ROLE_SENDER,
1436 if (!TEST_ptr_null(ctx = OSSL_HPKE_CTX_new(bad_mode, hpke_suite,
1437 OSSL_HPKE_ROLE_SENDER,
1441 if (!TEST_ptr(ctx = OSSL_HPKE_CTX_new(hpke_mode, hpke_suite,
1442 OSSL_HPKE_ROLE_SENDER,
1446 if (!TEST_false(OSSL_HPKE_CTX_set1_ikme(ctx, fake_ikm, -1)))
1448 /* zero length ikm */
1449 if (!TEST_false(OSSL_HPKE_CTX_set1_ikme(ctx, fake_ikm, 0)))
1452 if (!TEST_false(OSSL_HPKE_CTX_set1_authpub(ctx, NULL, 0)))
1454 /* NULL auth priv */
1455 if (!TEST_false(OSSL_HPKE_CTX_set1_authpriv(ctx, NULL)))
1457 /* priv good, but mode is bad */
1458 if (!TEST_false(OSSL_HPKE_CTX_set1_authpriv(ctx, privp)))
1460 /* bad mode for psk */
1461 if (!TEST_false(OSSL_HPKE_CTX_set1_psk(ctx, "foo",
1462 (unsigned char *)"bar", 3)))
1464 /* seal before encap */
1465 if (!TEST_false(OSSL_HPKE_seal(ctx, cipher, &cipherlen, NULL, 0,
1468 /* encap with dodgy public */
1469 if (!TEST_false(OSSL_HPKE_encap(ctx, enc, &enclen, pub, 1, NULL, 0)))
1471 /* encap with too big info */
1472 if (!TEST_false(OSSL_HPKE_encap(ctx, enc, &enclen, pub, 1, info, -1)))
1474 /* encap with NULL info & non-zero infolen */
1475 if (!TEST_false(OSSL_HPKE_encap(ctx, enc, &enclen, pub, 1, NULL, 1)))
1477 /* encap with non-NULL info & zero infolen */
1478 if (!TEST_false(OSSL_HPKE_encap(ctx, enc, &enclen, pub, 1, info, 0)))
1480 /* encap with too small enc */
1481 if (!TEST_false(OSSL_HPKE_encap(ctx, smallenc, &smallenclen, pub, 1, NULL, 0)))
1484 if (!TEST_true(OSSL_HPKE_encap(ctx, enc, &enclen, pub, publen, NULL, 0)))
1486 /* second encap fail */
1487 if (!TEST_false(OSSL_HPKE_encap(ctx, enc, &enclen, pub, publen, NULL, 0)))
1490 /* should fail for no plaintext */
1491 if (!TEST_false(OSSL_HPKE_seal(ctx, cipher, &cipherlen, NULL, 0,
1494 plainlen = sizeof(plain);
1496 if (!TEST_true(OSSL_HPKE_seal(ctx, cipher, &cipherlen, NULL, 0,
1501 /* decap fail with psk mode but no psk set */
1502 if (!TEST_ptr(rctx = OSSL_HPKE_CTX_new(OSSL_HPKE_MODE_PSK, hpke_suite,
1503 OSSL_HPKE_ROLE_RECEIVER,
1506 if (!TEST_false(OSSL_HPKE_decap(rctx, enc, enclen, privp, NULL, 0)))
1508 /* done with PSK mode */
1509 OSSL_HPKE_CTX_free(rctx);
1511 /* back good calls for base mode */
1512 if (!TEST_ptr(rctx = OSSL_HPKE_CTX_new(hpke_mode, hpke_suite,
1513 OSSL_HPKE_ROLE_RECEIVER,
1516 /* open before decap */
1517 if (!TEST_false(OSSL_HPKE_open(rctx, clear, &clearlen, NULL, 0,
1518 cipher, cipherlen)))
1520 /* decap with info too long */
1521 if (!TEST_false(OSSL_HPKE_decap(rctx, enc, enclen, privp, info, -1)))
1524 if (!TEST_true(OSSL_HPKE_decap(rctx, enc, enclen, privp, NULL, 0)))
1526 /* second decap fail */
1527 if (!TEST_false(OSSL_HPKE_decap(rctx, enc, enclen, privp, NULL, 0)))
1529 /* no space for recovered clear */
1531 if (!TEST_false(OSSL_HPKE_open(rctx, clear, &clearlen, NULL, 0,
1532 cipher, cipherlen)))
1534 clearlen = OSSL_HPKE_TSTSIZE;
1535 /* seq wrap around test */
1536 if (!TEST_true(OSSL_HPKE_CTX_set_seq(rctx, -1)))
1538 if (!TEST_false(OSSL_HPKE_open(rctx, clear, &clearlen, NULL, 0,
1539 cipher, cipherlen)))
1541 if (!TEST_true(OSSL_HPKE_CTX_set_seq(rctx, 0)))
1543 if (!TEST_true(OSSL_HPKE_open(rctx, clear, &clearlen, NULL, 0,
1544 cipher, cipherlen)))
1546 if (!TEST_mem_eq(plain, plainlen, clear, clearlen))
1550 OSSL_HPKE_CTX_free(ctx);
1551 OSSL_HPKE_CTX_free(rctx);
1552 EVP_PKEY_free(privp);
1556 #ifndef OPENSSL_NO_ECX
1557 /* from RFC 9180 Appendix A.1.1 */
1558 static const unsigned char ikm25519[] = {
1559 0x72, 0x68, 0x60, 0x0d, 0x40, 0x3f, 0xce, 0x43,
1560 0x15, 0x61, 0xae, 0xf5, 0x83, 0xee, 0x16, 0x13,
1561 0x52, 0x7c, 0xff, 0x65, 0x5c, 0x13, 0x43, 0xf2,
1562 0x98, 0x12, 0xe6, 0x67, 0x06, 0xdf, 0x32, 0x34
1564 static const unsigned char pub25519[] = {
1565 0x37, 0xfd, 0xa3, 0x56, 0x7b, 0xdb, 0xd6, 0x28,
1566 0xe8, 0x86, 0x68, 0xc3, 0xc8, 0xd7, 0xe9, 0x7d,
1567 0x1d, 0x12, 0x53, 0xb6, 0xd4, 0xea, 0x6d, 0x44,
1568 0xc1, 0x50, 0xf7, 0x41, 0xf1, 0xbf, 0x44, 0x31
1572 /* from RFC9180 Appendix A.3.1 */
1573 static const unsigned char ikmp256[] = {
1574 0x42, 0x70, 0xe5, 0x4f, 0xfd, 0x08, 0xd7, 0x9d,
1575 0x59, 0x28, 0x02, 0x0a, 0xf4, 0x68, 0x6d, 0x8f,
1576 0x6b, 0x7d, 0x35, 0xdb, 0xe4, 0x70, 0x26, 0x5f,
1577 0x1f, 0x5a, 0xa2, 0x28, 0x16, 0xce, 0x86, 0x0e
1579 static const unsigned char pubp256[] = {
1580 0x04, 0xa9, 0x27, 0x19, 0xc6, 0x19, 0x5d, 0x50,
1581 0x85, 0x10, 0x4f, 0x46, 0x9a, 0x8b, 0x98, 0x14,
1582 0xd5, 0x83, 0x8f, 0xf7, 0x2b, 0x60, 0x50, 0x1e,
1583 0x2c, 0x44, 0x66, 0xe5, 0xe6, 0x7b, 0x32, 0x5a,
1584 0xc9, 0x85, 0x36, 0xd7, 0xb6, 0x1a, 0x1a, 0xf4,
1585 0xb7, 0x8e, 0x5b, 0x7f, 0x95, 0x1c, 0x09, 0x00,
1586 0xbe, 0x86, 0x3c, 0x40, 0x3c, 0xe6, 0x5c, 0x9b,
1587 0xfc, 0xb9, 0x38, 0x26, 0x57, 0x22, 0x2d, 0x18,
1592 * A test vector that exercises the counter iteration
1593 * for p256. This was contributed by Ilari L. on the
1594 * CFRG list, see the mail archive:
1595 * https://mailarchive.ietf.org/arch/msg/cfrg/4zwl_y5YN6OU9oeWZOMHNOlOa2w/
1597 static const unsigned char ikmiter[] = {
1598 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1599 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1600 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1601 0x00, 0x00, 0x00, 0x03, 0x01, 0x38, 0xb5, 0xec
1603 static const unsigned char pubiter[] = {
1604 0x04, 0x7d, 0x0c, 0x87, 0xff, 0xd5, 0xd1, 0x45,
1605 0x54, 0xa7, 0x51, 0xdf, 0xa3, 0x99, 0x26, 0xa9,
1606 0xe3, 0x0e, 0x7c, 0x3c, 0x65, 0x62, 0x4f, 0x4b,
1607 0x5f, 0xb3, 0xad, 0x7a, 0xa4, 0xda, 0xc2, 0x4a,
1608 0xd8, 0xf5, 0xbe, 0xd0, 0xe8, 0x6e, 0xb8, 0x84,
1609 0x1c, 0xe4, 0x89, 0x2e, 0x0f, 0xc3, 0x87, 0xbb,
1610 0xdb, 0xfe, 0x16, 0x0d, 0x58, 0x9c, 0x89, 0x2d,
1611 0xd4, 0xb1, 0x46, 0x4a, 0xc3, 0x51, 0xc5, 0x6f,
1615 /* from RFC9180 Appendix A.6.1 */
1616 static const unsigned char ikmp521[] = {
1617 0x7f, 0x06, 0xab, 0x82, 0x15, 0x10, 0x5f, 0xc4,
1618 0x6a, 0xce, 0xeb, 0x2e, 0x3d, 0xc5, 0x02, 0x8b,
1619 0x44, 0x36, 0x4f, 0x96, 0x04, 0x26, 0xeb, 0x0d,
1620 0x8e, 0x40, 0x26, 0xc2, 0xf8, 0xb5, 0xd7, 0xe7,
1621 0xa9, 0x86, 0x68, 0x8f, 0x15, 0x91, 0xab, 0xf5,
1622 0xab, 0x75, 0x3c, 0x35, 0x7a, 0x5d, 0x6f, 0x04,
1623 0x40, 0x41, 0x4b, 0x4e, 0xd4, 0xed, 0xe7, 0x13,
1624 0x17, 0x77, 0x2a, 0xc9, 0x8d, 0x92, 0x39, 0xf7,
1627 static const unsigned char pubp521[] = {
1628 0x04, 0x01, 0x38, 0xb3, 0x85, 0xca, 0x16, 0xbb,
1629 0x0d, 0x5f, 0xa0, 0xc0, 0x66, 0x5f, 0xbb, 0xd7,
1630 0xe6, 0x9e, 0x3e, 0xe2, 0x9f, 0x63, 0x99, 0x1d,
1631 0x3e, 0x9b, 0x5f, 0xa7, 0x40, 0xaa, 0xb8, 0x90,
1632 0x0a, 0xae, 0xed, 0x46, 0xed, 0x73, 0xa4, 0x90,
1633 0x55, 0x75, 0x84, 0x25, 0xa0, 0xce, 0x36, 0x50,
1634 0x7c, 0x54, 0xb2, 0x9c, 0xc5, 0xb8, 0x5a, 0x5c,
1635 0xee, 0x6b, 0xae, 0x0c, 0xf1, 0xc2, 0x1f, 0x27,
1636 0x31, 0xec, 0xe2, 0x01, 0x3d, 0xc3, 0xfb, 0x7c,
1637 0x8d, 0x21, 0x65, 0x4b, 0xb1, 0x61, 0xb4, 0x63,
1638 0x96, 0x2c, 0xa1, 0x9e, 0x8c, 0x65, 0x4f, 0xf2,
1639 0x4c, 0x94, 0xdd, 0x28, 0x98, 0xde, 0x12, 0x05,
1640 0x1f, 0x1e, 0xd0, 0x69, 0x22, 0x37, 0xfb, 0x02,
1641 0xb2, 0xf8, 0xd1, 0xdc, 0x1c, 0x73, 0xe9, 0xb3,
1642 0x66, 0xb5, 0x29, 0xeb, 0x43, 0x6e, 0x98, 0xa9,
1643 0x96, 0xee, 0x52, 0x2a, 0xef, 0x86, 0x3d, 0xd5,
1644 0x73, 0x9d, 0x2f, 0x29, 0xb0
1647 static int test_hpke_random_suites(void)
1649 OSSL_HPKE_SUITE def_suite = OSSL_HPKE_SUITE_DEFAULT;
1650 OSSL_HPKE_SUITE suite = OSSL_HPKE_SUITE_DEFAULT;
1651 OSSL_HPKE_SUITE suite2 = { 0xff01, 0xff02, 0xff03 };
1652 unsigned char enc[200];
1653 size_t enclen = sizeof(enc);
1654 unsigned char ct[500];
1655 size_t ctlen = sizeof(ct);
1657 /* test with NULL/0 inputs */
1658 if (!TEST_false(OSSL_HPKE_get_grease_value(NULL, NULL,
1659 NULL, NULL, NULL, 0,
1663 if (!TEST_false(OSSL_HPKE_get_grease_value(&def_suite, &suite2,
1664 enc, &enclen, ct, ctlen,
1668 enclen = sizeof(enc); /* reset, 'cause get_grease() will have set */
1669 /* test with a should-be-good suite */
1670 if (!TEST_true(OSSL_HPKE_get_grease_value(&def_suite, &suite2,
1671 enc, &enclen, ct, ctlen,
1674 /* no suggested suite */
1675 enclen = sizeof(enc); /* reset, 'cause get_grease() will have set */
1676 if (!TEST_true(OSSL_HPKE_get_grease_value(NULL, &suite2,
1681 /* suggested suite with P-521, just to be sure we hit long values */
1682 enclen = sizeof(enc); /* reset, 'cause get_grease() will have set */
1683 suite.kem_id = OSSL_HPKE_KEM_ID_P521;
1684 if (!TEST_true(OSSL_HPKE_get_grease_value(&suite, &suite2,
1685 enc, &enclen, ct, ctlen,
1688 enclen = sizeof(enc);
1689 ctlen = 2; /* too-short cttext (can't fit an aead tag) */
1690 if (!TEST_false(OSSL_HPKE_get_grease_value(NULL, &suite2,
1691 enc, &enclen, ct, ctlen,
1696 enclen = sizeof(enc);
1698 suite.kem_id = OSSL_HPKE_KEM_ID_X25519; /* back to default */
1699 suite.aead_id = 0x1234; /* bad aead */
1700 if (!TEST_false(OSSL_HPKE_get_grease_value(&suite, &suite2,
1701 enc, &enclen, ct, ctlen,
1704 enclen = sizeof(enc);
1705 suite.aead_id = def_suite.aead_id; /* good aead */
1706 suite.kdf_id = 0x3451; /* bad kdf */
1707 if (!TEST_false(OSSL_HPKE_get_grease_value(&suite, &suite2,
1708 enc, &enclen, ct, ctlen,
1711 enclen = sizeof(enc);
1712 suite.kdf_id = def_suite.kdf_id; /* good kdf */
1713 suite.kem_id = 0x4517; /* bad kem */
1714 if (!TEST_false(OSSL_HPKE_get_grease_value(&suite, &suite2,
1715 enc, &enclen, ct, ctlen,
1722 * @brief generate a key pair from initial key material (ikm) and check public
1723 * @param kem_id the KEM to use (RFC9180 code point)
1724 * @ikm is the initial key material buffer
1725 * @ikmlen is the length of ikm
1726 * @pub is the public key buffer
1727 * @publen is the length of the public key
1728 * @return 1 for good, other otherwise
1730 * This calls OSSL_HPKE_keygen specifying only the IKM, then
1731 * compares the key pair values with the already-known values
1734 static int test_hpke_one_ikm_gen(uint16_t kem_id,
1735 const unsigned char *ikm, size_t ikmlen,
1736 const unsigned char *pub, size_t publen)
1738 OSSL_HPKE_SUITE hpke_suite = OSSL_HPKE_SUITE_DEFAULT;
1739 unsigned char lpub[OSSL_HPKE_TSTSIZE];
1740 size_t lpublen = OSSL_HPKE_TSTSIZE;
1741 EVP_PKEY *sk = NULL;
1743 hpke_suite.kem_id = kem_id;
1744 if (!TEST_true(OSSL_HPKE_keygen(hpke_suite, lpub, &lpublen, &sk,
1745 ikm, ikmlen, testctx, NULL)))
1750 if (!TEST_mem_eq(pub, publen, lpub, lpublen))
1756 * @brief test some uses of IKM produce the expected public keys
1758 static int test_hpke_ikms(void)
1762 #ifndef OPENSSL_NO_ECX
1763 res = test_hpke_one_ikm_gen(OSSL_HPKE_KEM_ID_X25519,
1764 ikm25519, sizeof(ikm25519),
1765 pub25519, sizeof(pub25519));
1770 res = test_hpke_one_ikm_gen(OSSL_HPKE_KEM_ID_P521,
1771 ikmp521, sizeof(ikmp521),
1772 pubp521, sizeof(pubp521));
1776 res = test_hpke_one_ikm_gen(OSSL_HPKE_KEM_ID_P256,
1777 ikmp256, sizeof(ikmp256),
1778 pubp256, sizeof(pubp256));
1782 res = test_hpke_one_ikm_gen(OSSL_HPKE_KEM_ID_P256,
1783 ikmiter, sizeof(ikmiter),
1784 pubiter, sizeof(pubiter));
1792 * Test that use of a compressed format auth public key works
1793 * We'll do a typical round-trip for auth mode but provide the
1794 * auth public key in compressed form. That should work.
1796 static int test_hpke_compressed(void)
1799 EVP_PKEY *privp = NULL;
1800 unsigned char pub[OSSL_HPKE_TSTSIZE];
1801 size_t publen = sizeof(pub);
1802 EVP_PKEY *authpriv = NULL;
1803 unsigned char authpub[OSSL_HPKE_TSTSIZE];
1804 size_t authpublen = sizeof(authpub);
1805 int hpke_mode = OSSL_HPKE_MODE_AUTH;
1806 OSSL_HPKE_SUITE hpke_suite = OSSL_HPKE_SUITE_DEFAULT;
1807 OSSL_HPKE_CTX *ctx = NULL;
1808 OSSL_HPKE_CTX *rctx = NULL;
1809 unsigned char plain[] = "quick brown fox";
1810 size_t plainlen = sizeof(plain);
1811 unsigned char enc[OSSL_HPKE_TSTSIZE];
1812 size_t enclen = sizeof(enc);
1813 unsigned char cipher[OSSL_HPKE_TSTSIZE];
1814 size_t cipherlen = sizeof(cipher);
1815 unsigned char clear[OSSL_HPKE_TSTSIZE];
1816 size_t clearlen = sizeof(clear);
1818 hpke_suite.kem_id = OSSL_HPKE_KEM_ID_P256;
1820 /* generate auth key pair */
1821 if (!TEST_true(OSSL_HPKE_keygen(hpke_suite, authpub, &authpublen, &authpriv,
1822 NULL, 0, testctx, NULL)))
1824 /* now get the compressed form public key */
1825 if (!TEST_true(EVP_PKEY_set_utf8_string_param(authpriv,
1826 OSSL_PKEY_PARAM_EC_POINT_CONVERSION_FORMAT,
1827 OSSL_PKEY_EC_POINT_CONVERSION_FORMAT_COMPRESSED)))
1829 if (!TEST_true(EVP_PKEY_get_octet_string_param(authpriv,
1830 OSSL_PKEY_PARAM_PUB_KEY,
1836 /* sender side as usual */
1837 if (!TEST_true(OSSL_HPKE_keygen(hpke_suite, pub, &publen, &privp,
1838 NULL, 0, testctx, NULL)))
1840 if (!TEST_ptr(ctx = OSSL_HPKE_CTX_new(hpke_mode, hpke_suite,
1841 OSSL_HPKE_ROLE_SENDER,
1844 if (!TEST_true(OSSL_HPKE_CTX_set1_authpriv(ctx, authpriv)))
1846 if (!TEST_true(OSSL_HPKE_encap(ctx, enc, &enclen, pub, publen, NULL, 0)))
1848 if (!TEST_true(OSSL_HPKE_seal(ctx, cipher, &cipherlen, NULL, 0,
1852 /* receiver side providing compressed form of auth public */
1853 if (!TEST_ptr(rctx = OSSL_HPKE_CTX_new(hpke_mode, hpke_suite,
1854 OSSL_HPKE_ROLE_RECEIVER,
1857 if (!TEST_true(OSSL_HPKE_CTX_set1_authpub(rctx, authpub, authpublen)))
1859 if (!TEST_true(OSSL_HPKE_decap(rctx, enc, enclen, privp, NULL, 0)))
1861 if (!TEST_true(OSSL_HPKE_open(rctx, clear, &clearlen, NULL, 0,
1862 cipher, cipherlen)))
1867 EVP_PKEY_free(privp);
1868 EVP_PKEY_free(authpriv);
1869 OSSL_HPKE_CTX_free(ctx);
1870 OSSL_HPKE_CTX_free(rctx);
1875 * Test that nonce reuse calls are prevented as we expect
1877 static int test_hpke_noncereuse(void)
1880 EVP_PKEY *privp = NULL;
1881 unsigned char pub[OSSL_HPKE_TSTSIZE];
1882 size_t publen = sizeof(pub);
1883 int hpke_mode = OSSL_HPKE_MODE_BASE;
1884 OSSL_HPKE_SUITE hpke_suite = OSSL_HPKE_SUITE_DEFAULT;
1885 OSSL_HPKE_CTX *ctx = NULL;
1886 OSSL_HPKE_CTX *rctx = NULL;
1887 unsigned char plain[] = "quick brown fox";
1888 size_t plainlen = sizeof(plain);
1889 unsigned char enc[OSSL_HPKE_TSTSIZE];
1890 size_t enclen = sizeof(enc);
1891 unsigned char cipher[OSSL_HPKE_TSTSIZE];
1892 size_t cipherlen = sizeof(cipher);
1893 unsigned char clear[OSSL_HPKE_TSTSIZE];
1894 size_t clearlen = sizeof(clear);
1895 uint64_t seq = 0xbad1dea;
1897 /* sender side is not allowed set seq once some crypto done */
1898 if (!TEST_true(OSSL_HPKE_keygen(hpke_suite, pub, &publen, &privp,
1899 NULL, 0, testctx, NULL)))
1901 if (!TEST_ptr(ctx = OSSL_HPKE_CTX_new(hpke_mode, hpke_suite,
1902 OSSL_HPKE_ROLE_SENDER,
1905 /* set seq will fail before any crypto done */
1906 if (!TEST_false(OSSL_HPKE_CTX_set_seq(ctx, seq)))
1908 if (!TEST_true(OSSL_HPKE_encap(ctx, enc, &enclen, pub, publen, NULL, 0)))
1910 /* set seq will also fail after some crypto done */
1911 if (!TEST_false(OSSL_HPKE_CTX_set_seq(ctx, seq + 1)))
1913 if (!TEST_true(OSSL_HPKE_seal(ctx, cipher, &cipherlen, NULL, 0,
1917 /* receiver side is allowed control seq */
1918 if (!TEST_ptr(rctx = OSSL_HPKE_CTX_new(hpke_mode, hpke_suite,
1919 OSSL_HPKE_ROLE_RECEIVER,
1922 /* set seq will work before any crypto done */
1923 if (!TEST_true(OSSL_HPKE_CTX_set_seq(rctx, seq)))
1925 if (!TEST_true(OSSL_HPKE_decap(rctx, enc, enclen, privp, NULL, 0)))
1927 /* set seq will work for receivers even after crypto done */
1928 if (!TEST_true(OSSL_HPKE_CTX_set_seq(rctx, seq)))
1930 /* but that value isn't good so decap will fail */
1931 if (!TEST_false(OSSL_HPKE_open(rctx, clear, &clearlen, NULL, 0,
1932 cipher, cipherlen)))
1934 /* reset seq to correct value and _open() should work */
1935 if (!TEST_true(OSSL_HPKE_CTX_set_seq(rctx, 0)))
1937 if (!TEST_true(OSSL_HPKE_open(rctx, clear, &clearlen, NULL, 0,
1938 cipher, cipherlen)))
1943 EVP_PKEY_free(privp);
1944 OSSL_HPKE_CTX_free(ctx);
1945 OSSL_HPKE_CTX_free(rctx);
1949 typedef enum OPTION_choice {
1956 const OPTIONS *test_get_options(void)
1958 static const OPTIONS test_options[] = {
1959 OPT_TEST_OPTIONS_DEFAULT_USAGE,
1960 { "v", OPT_VERBOSE, '-', "Enable verbose mode" },
1961 { OPT_HELP_STR, 1, '-', "Run HPKE tests\n" },
1964 return test_options;
1967 int setup_tests(void)
1971 while ((o = opt_next()) != OPT_EOF) {
1974 verbose = 1; /* Print progress dots */
1976 case OPT_TEST_CASES:
1983 if (!test_get_libctx(&testctx, &nullprov, NULL, &deflprov, "default"))
1985 #ifndef OPENSSL_NO_ECX
1986 ADD_TEST(export_only_test);
1987 ADD_TEST(x25519kdfsha256_hkdfsha256_aes128gcm_base_test);
1988 ADD_TEST(x25519kdfsha256_hkdfsha256_aes128gcm_psk_test);
1990 ADD_TEST(P256kdfsha256_hkdfsha256_aes128gcm_base_test);
1991 ADD_TEST(test_hpke_export);
1992 ADD_TEST(test_hpke_modes_suites);
1993 ADD_TEST(test_hpke_suite_strs);
1994 ADD_TEST(test_hpke_grease);
1995 ADD_TEST(test_hpke_ikms);
1996 ADD_TEST(test_hpke_random_suites);
1997 ADD_TEST(test_hpke_oddcalls);
1998 ADD_TEST(test_hpke_compressed);
1999 ADD_TEST(test_hpke_noncereuse);
2003 void cleanup_tests(void)
2005 OSSL_PROVIDER_unload(deflprov);
2006 OSSL_PROVIDER_unload(nullprov);
2007 OSSL_LIB_CTX_free(testctx);