2 * Copyright 2022 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,
128 if (!TEST_true(OSSL_HPKE_CTX_set1_ikme(sealctx, base->ikmE, base->ikmElen)))
130 if (base->mode == OSSL_HPKE_MODE_AUTH
131 || base->mode == OSSL_HPKE_MODE_PSKAUTH) {
132 if (!TEST_true(base->ikmAuth != NULL && base->ikmAuthlen > 0))
134 if (!TEST_true(OSSL_HPKE_keygen(base->suite,
135 authpub, &authpublen, &authpriv,
136 base->ikmAuth, base->ikmAuthlen,
139 if (!TEST_true(OSSL_HPKE_CTX_set1_authpriv(sealctx, authpriv)))
142 if (!TEST_true(OSSL_HPKE_keygen(base->suite, rpub, &rpublen, &privR,
143 base->ikmR, base->ikmRlen, libctx, propq)))
145 if (!TEST_true(cmpkey(privR, base->expected_pkRm, base->expected_pkRmlen)))
147 if (base->mode == OSSL_HPKE_MODE_PSK
148 || base->mode == OSSL_HPKE_MODE_PSKAUTH) {
149 if (!TEST_true(OSSL_HPKE_CTX_set1_psk(sealctx, base->pskid,
150 base->psk, base->psklen)))
153 if (!TEST_true(OSSL_HPKE_encap(sealctx, enc, &enclen,
155 base->ksinfo, base->ksinfolen)))
157 if (!TEST_true(cmpkey(privE, enc, enclen)))
159 for (i = 0; i < aeadsz; ++i) {
161 memset(ct, 0, ctlen);
162 if (!TEST_true(OSSL_HPKE_seal(sealctx, ct, &ctlen,
163 aead[i].aad, aead[i].aadlen,
164 aead[i].pt, aead[i].ptlen)))
166 if (!TEST_mem_eq(ct, ctlen, aead[i].expected_ct,
167 aead[i].expected_ctlen))
169 if (!TEST_true(OSSL_HPKE_CTX_get_seq(sealctx, &lastseq)))
171 if (lastseq != (uint64_t)(i + 1))
174 if (!TEST_ptr(openctx = OSSL_HPKE_CTX_new(base->mode, base->suite,
177 if (base->mode == OSSL_HPKE_MODE_PSK
178 || base->mode == OSSL_HPKE_MODE_PSKAUTH) {
179 if (!TEST_true(base->pskid != NULL && base->psk != NULL
180 && base->psklen > 0))
182 if (!TEST_true(OSSL_HPKE_CTX_set1_psk(openctx, base->pskid,
183 base->psk, base->psklen)))
186 if (base->mode == OSSL_HPKE_MODE_AUTH
187 || base->mode == OSSL_HPKE_MODE_PSKAUTH) {
188 if (!TEST_true(OSSL_HPKE_CTX_set1_authpub(openctx,
189 authpub, authpublen)))
192 if (!TEST_true(OSSL_HPKE_decap(openctx, enc, enclen, privR,
193 base->ksinfo, base->ksinfolen)))
195 for (i = 0; i < aeadsz; ++i) {
196 ptoutlen = sizeof(ptout);
197 memset(ptout, 0, ptoutlen);
198 if (!TEST_true(OSSL_HPKE_open(openctx, ptout, &ptoutlen,
199 aead[i].aad, aead[i].aadlen,
201 aead[i].expected_ctlen)))
203 if (!TEST_mem_eq(aead[i].pt, aead[i].ptlen, ptout, ptoutlen))
205 /* check the sequence is being incremented as expected */
206 if (!TEST_true(OSSL_HPKE_CTX_get_seq(openctx, &lastseq)))
208 if (lastseq != (uint64_t)(i + 1))
211 /* check exporters */
212 for (i = 0; i < exportsz; ++i) {
213 size_t len = export[i].expected_secretlen;
214 unsigned char eval[OSSL_HPKE_TSTSIZE];
216 if (len > sizeof(eval))
218 /* export with too long label should fail */
219 if (!TEST_false(OSSL_HPKE_export(sealctx, eval, len,
220 export[i].context, -1)))
222 /* good export call */
223 if (!TEST_true(OSSL_HPKE_export(sealctx, eval, len,
225 export[i].contextlen)))
227 if (!TEST_mem_eq(eval, len, export[i].expected_secret,
228 export[i].expected_secretlen))
231 /* check seal fails if export only mode */
234 if (!TEST_false(OSSL_HPKE_seal(sealctx, ct, &ctlen,
235 NULL, 0, ptout, ptoutlen)))
241 OSSL_HPKE_CTX_free(sealctx);
242 OSSL_HPKE_CTX_free(openctx);
243 EVP_PKEY_free(privE);
244 EVP_PKEY_free(privR);
245 EVP_PKEY_free(authpriv);
249 static const unsigned char pt[] = {
250 0x42, 0x65, 0x61, 0x75, 0x74, 0x79, 0x20, 0x69,
251 0x73, 0x20, 0x74, 0x72, 0x75, 0x74, 0x68, 0x2c,
252 0x20, 0x74, 0x72, 0x75, 0x74, 0x68, 0x20, 0x62,
253 0x65, 0x61, 0x75, 0x74, 0x79
255 static const unsigned char ksinfo[] = {
256 0x4f, 0x64, 0x65, 0x20, 0x6f, 0x6e, 0x20, 0x61,
257 0x20, 0x47, 0x72, 0x65, 0x63, 0x69, 0x61, 0x6e,
258 0x20, 0x55, 0x72, 0x6e
261 * static const char *pskid = "Ennyn Durin aran Moria";
263 static const unsigned char pskid[] = {
264 0x45, 0x6e, 0x6e, 0x79, 0x6e, 0x20, 0x44, 0x75,
265 0x72, 0x69, 0x6e, 0x20, 0x61, 0x72, 0x61, 0x6e,
266 0x20, 0x4d, 0x6f, 0x72, 0x69, 0x61, 0x00
268 static const unsigned char psk[] = {
269 0x02, 0x47, 0xfd, 0x33, 0xb9, 0x13, 0x76, 0x0f,
270 0xa1, 0xfa, 0x51, 0xe1, 0x89, 0x2d, 0x9f, 0x30,
271 0x7f, 0xbe, 0x65, 0xeb, 0x17, 0x1e, 0x81, 0x32,
272 0xc2, 0xaf, 0x18, 0x55, 0x5a, 0x73, 0x8b, 0x82
275 /* these need to be "outside" the function below to keep check-ansi CI happy */
276 static const unsigned char first_ikme[] = {
277 0x78, 0x62, 0x8c, 0x35, 0x4e, 0x46, 0xf3, 0xe1,
278 0x69, 0xbd, 0x23, 0x1b, 0xe7, 0xb2, 0xff, 0x1c,
279 0x77, 0xaa, 0x30, 0x24, 0x60, 0xa2, 0x6d, 0xbf,
280 0xa1, 0x55, 0x15, 0x68, 0x4c, 0x00, 0x13, 0x0b
282 static const unsigned char first_ikmr[] = {
283 0xd4, 0xa0, 0x9d, 0x09, 0xf5, 0x75, 0xfe, 0xf4,
284 0x25, 0x90, 0x5d, 0x2a, 0xb3, 0x96, 0xc1, 0x44,
285 0x91, 0x41, 0x46, 0x3f, 0x69, 0x8f, 0x8e, 0xfd,
286 0xb7, 0xac, 0xcf, 0xaf, 0xf8, 0x99, 0x50, 0x98
288 static const unsigned char first_ikmepub[] = {
289 0x0a, 0xd0, 0x95, 0x0d, 0x9f, 0xb9, 0x58, 0x8e,
290 0x59, 0x69, 0x0b, 0x74, 0xf1, 0x23, 0x7e, 0xcd,
291 0xf1, 0xd7, 0x75, 0xcd, 0x60, 0xbe, 0x2e, 0xca,
292 0x57, 0xaf, 0x5a, 0x4b, 0x04, 0x71, 0xc9, 0x1b,
294 static const unsigned char first_ikmrpub[] = {
295 0x9f, 0xed, 0x7e, 0x8c, 0x17, 0x38, 0x75, 0x60,
296 0xe9, 0x2c, 0xc6, 0x46, 0x2a, 0x68, 0x04, 0x96,
297 0x57, 0x24, 0x6a, 0x09, 0xbf, 0xa8, 0xad, 0xe7,
298 0xae, 0xfe, 0x58, 0x96, 0x72, 0x01, 0x63, 0x66
300 static const unsigned char first_ikmrpriv[] = {
301 0xc5, 0xeb, 0x01, 0xeb, 0x45, 0x7f, 0xe6, 0xc6,
302 0xf5, 0x75, 0x77, 0xc5, 0x41, 0x3b, 0x93, 0x15,
303 0x50, 0xa1, 0x62, 0xc7, 0x1a, 0x03, 0xac, 0x8d,
304 0x19, 0x6b, 0xab, 0xbd, 0x4e, 0x5c, 0xe0, 0xfd
306 static const unsigned char first_expected_shared_secret[] = {
307 0x72, 0x76, 0x99, 0xf0, 0x09, 0xff, 0xe3, 0xc0,
308 0x76, 0x31, 0x50, 0x19, 0xc6, 0x96, 0x48, 0x36,
309 0x6b, 0x69, 0x17, 0x14, 0x39, 0xbd, 0x7d, 0xd0,
310 0x80, 0x77, 0x43, 0xbd, 0xe7, 0x69, 0x86, 0xcd
312 static const unsigned char first_aad0[] = {
313 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x2d, 0x30
315 static const unsigned char first_ct0[] = {
316 0xe5, 0x2c, 0x6f, 0xed, 0x7f, 0x75, 0x8d, 0x0c,
317 0xf7, 0x14, 0x56, 0x89, 0xf2, 0x1b, 0xc1, 0xbe,
318 0x6e, 0xc9, 0xea, 0x09, 0x7f, 0xef, 0x4e, 0x95,
319 0x94, 0x40, 0x01, 0x2f, 0x4f, 0xeb, 0x73, 0xfb,
320 0x61, 0x1b, 0x94, 0x61, 0x99, 0xe6, 0x81, 0xf4,
321 0xcf, 0xc3, 0x4d, 0xb8, 0xea
323 static const unsigned char first_aad1[] = {
324 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x2d, 0x31
326 static const unsigned char first_ct1[] = {
327 0x49, 0xf3, 0xb1, 0x9b, 0x28, 0xa9, 0xea, 0x9f,
328 0x43, 0xe8, 0xc7, 0x12, 0x04, 0xc0, 0x0d, 0x4a,
329 0x49, 0x0e, 0xe7, 0xf6, 0x13, 0x87, 0xb6, 0x71,
330 0x9d, 0xb7, 0x65, 0xe9, 0x48, 0x12, 0x3b, 0x45,
331 0xb6, 0x16, 0x33, 0xef, 0x05, 0x9b, 0xa2, 0x2c,
332 0xd6, 0x24, 0x37, 0xc8, 0xba
334 static const unsigned char first_aad2[] = {
335 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x2d, 0x32
337 static const unsigned char first_ct2[] = {
338 0x25, 0x7c, 0xa6, 0xa0, 0x84, 0x73, 0xdc, 0x85,
339 0x1f, 0xde, 0x45, 0xaf, 0xd5, 0x98, 0xcc, 0x83,
340 0xe3, 0x26, 0xdd, 0xd0, 0xab, 0xe1, 0xef, 0x23,
341 0xba, 0xa3, 0xba, 0xa4, 0xdd, 0x8c, 0xde, 0x99,
342 0xfc, 0xe2, 0xc1, 0xe8, 0xce, 0x68, 0x7b, 0x0b,
343 0x47, 0xea, 0xd1, 0xad, 0xc9
345 static const unsigned char first_export1[] = {
346 0xdf, 0xf1, 0x7a, 0xf3, 0x54, 0xc8, 0xb4, 0x16,
347 0x73, 0x56, 0x7d, 0xb6, 0x25, 0x9f, 0xd6, 0x02,
348 0x99, 0x67, 0xb4, 0xe1, 0xaa, 0xd1, 0x30, 0x23,
349 0xc2, 0xae, 0x5d, 0xf8, 0xf4, 0xf4, 0x3b, 0xf6
351 static const unsigned char first_context2[] = { 0x00 };
352 static const unsigned char first_export2[] = {
353 0x6a, 0x84, 0x72, 0x61, 0xd8, 0x20, 0x7f, 0xe5,
354 0x96, 0xbe, 0xfb, 0x52, 0x92, 0x84, 0x63, 0x88,
355 0x1a, 0xb4, 0x93, 0xda, 0x34, 0x5b, 0x10, 0xe1,
356 0xdc, 0xc6, 0x45, 0xe3, 0xb9, 0x4e, 0x2d, 0x95
358 static const unsigned char first_context3[] = {
359 0x54, 0x65, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x74,
362 static const unsigned char first_export3[] = {
363 0x8a, 0xff, 0x52, 0xb4, 0x5a, 0x1b, 0xe3, 0xa7,
364 0x34, 0xbc, 0x7a, 0x41, 0xe2, 0x0b, 0x4e, 0x05,
365 0x5a, 0xd4, 0xc4, 0xd2, 0x21, 0x04, 0xb0, 0xc2,
366 0x02, 0x85, 0xa7, 0xc4, 0x30, 0x24, 0x01, 0xcd
369 static int x25519kdfsha256_hkdfsha256_aes128gcm_psk_test(void)
371 const TEST_BASEDATA pskdata = {
372 /* "X25519", NULL, "SHA256", "SHA256", "AES-128-GCM", */
375 OSSL_HPKE_KEM_ID_X25519,
376 OSSL_HPKE_KDF_ID_HKDF_SHA256,
377 OSSL_HPKE_AEAD_ID_AES_GCM_128
379 first_ikme, sizeof(first_ikme),
380 first_ikmepub, sizeof(first_ikmepub),
381 first_ikmr, sizeof(first_ikmr),
382 first_ikmrpub, sizeof(first_ikmrpub),
383 first_ikmrpriv, sizeof(first_ikmrpriv),
384 first_expected_shared_secret, sizeof(first_expected_shared_secret),
385 ksinfo, sizeof(ksinfo),
386 NULL, 0, /* No Auth */
387 psk, sizeof(psk), (char *) pskid
389 const TEST_AEADDATA aeaddata[] = {
393 first_aad0, sizeof(first_aad0),
394 first_ct0, sizeof(first_ct0)
399 first_aad1, sizeof(first_aad1),
400 first_ct1, sizeof(first_ct1)
405 first_aad2, sizeof(first_aad2),
406 first_ct2, sizeof(first_ct2)
409 const TEST_EXPORTDATA exportdata[] = {
410 { NULL, 0, first_export1, sizeof(first_export1) },
411 { first_context2, sizeof(first_context2),
412 first_export2, sizeof(first_export2) },
413 { first_context3, sizeof(first_context3),
414 first_export3, sizeof(first_export3) },
416 return do_testhpke(&pskdata, aeaddata, OSSL_NELEM(aeaddata),
417 exportdata, OSSL_NELEM(exportdata));
420 static const unsigned char second_ikme[] = {
421 0x72, 0x68, 0x60, 0x0d, 0x40, 0x3f, 0xce, 0x43,
422 0x15, 0x61, 0xae, 0xf5, 0x83, 0xee, 0x16, 0x13,
423 0x52, 0x7c, 0xff, 0x65, 0x5c, 0x13, 0x43, 0xf2,
424 0x98, 0x12, 0xe6, 0x67, 0x06, 0xdf, 0x32, 0x34
426 static const unsigned char second_ikmepub[] = {
427 0x37, 0xfd, 0xa3, 0x56, 0x7b, 0xdb, 0xd6, 0x28,
428 0xe8, 0x86, 0x68, 0xc3, 0xc8, 0xd7, 0xe9, 0x7d,
429 0x1d, 0x12, 0x53, 0xb6, 0xd4, 0xea, 0x6d, 0x44,
430 0xc1, 0x50, 0xf7, 0x41, 0xf1, 0xbf, 0x44, 0x31,
432 static const unsigned char second_ikmr[] = {
433 0x6d, 0xb9, 0xdf, 0x30, 0xaa, 0x07, 0xdd, 0x42,
434 0xee, 0x5e, 0x81, 0x81, 0xaf, 0xdb, 0x97, 0x7e,
435 0x53, 0x8f, 0x5e, 0x1f, 0xec, 0x8a, 0x06, 0x22,
436 0x3f, 0x33, 0xf7, 0x01, 0x3e, 0x52, 0x50, 0x37
438 static const unsigned char second_ikmrpub[] = {
439 0x39, 0x48, 0xcf, 0xe0, 0xad, 0x1d, 0xdb, 0x69,
440 0x5d, 0x78, 0x0e, 0x59, 0x07, 0x71, 0x95, 0xda,
441 0x6c, 0x56, 0x50, 0x6b, 0x02, 0x73, 0x29, 0x79,
442 0x4a, 0xb0, 0x2b, 0xca, 0x80, 0x81, 0x5c, 0x4d
444 static const unsigned char second_ikmrpriv[] = {
445 0x46, 0x12, 0xc5, 0x50, 0x26, 0x3f, 0xc8, 0xad,
446 0x58, 0x37, 0x5d, 0xf3, 0xf5, 0x57, 0xaa, 0xc5,
447 0x31, 0xd2, 0x68, 0x50, 0x90, 0x3e, 0x55, 0xa9,
448 0xf2, 0x3f, 0x21, 0xd8, 0x53, 0x4e, 0x8a, 0xc8
450 static const unsigned char second_expected_shared_secret[] = {
451 0xfe, 0x0e, 0x18, 0xc9, 0xf0, 0x24, 0xce, 0x43,
452 0x79, 0x9a, 0xe3, 0x93, 0xc7, 0xe8, 0xfe, 0x8f,
453 0xce, 0x9d, 0x21, 0x88, 0x75, 0xe8, 0x22, 0x7b,
454 0x01, 0x87, 0xc0, 0x4e, 0x7d, 0x2e, 0xa1, 0xfc
456 static const unsigned char second_aead0[] = {
457 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x2d, 0x30
459 static const unsigned char second_ct0[] = {
460 0xf9, 0x38, 0x55, 0x8b, 0x5d, 0x72, 0xf1, 0xa2,
461 0x38, 0x10, 0xb4, 0xbe, 0x2a, 0xb4, 0xf8, 0x43,
462 0x31, 0xac, 0xc0, 0x2f, 0xc9, 0x7b, 0xab, 0xc5,
463 0x3a, 0x52, 0xae, 0x82, 0x18, 0xa3, 0x55, 0xa9,
464 0x6d, 0x87, 0x70, 0xac, 0x83, 0xd0, 0x7b, 0xea,
465 0x87, 0xe1, 0x3c, 0x51, 0x2a
467 static const unsigned char second_aead1[] = {
468 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x2d, 0x31
470 static const unsigned char second_ct1[] = {
471 0xaf, 0x2d, 0x7e, 0x9a, 0xc9, 0xae, 0x7e, 0x27,
472 0x0f, 0x46, 0xba, 0x1f, 0x97, 0x5b, 0xe5, 0x3c,
473 0x09, 0xf8, 0xd8, 0x75, 0xbd, 0xc8, 0x53, 0x54,
474 0x58, 0xc2, 0x49, 0x4e, 0x8a, 0x6e, 0xab, 0x25,
475 0x1c, 0x03, 0xd0, 0xc2, 0x2a, 0x56, 0xb8, 0xca,
476 0x42, 0xc2, 0x06, 0x3b, 0x84
478 static const unsigned char second_export1[] = {
479 0x38, 0x53, 0xfe, 0x2b, 0x40, 0x35, 0x19, 0x5a,
480 0x57, 0x3f, 0xfc, 0x53, 0x85, 0x6e, 0x77, 0x05,
481 0x8e, 0x15, 0xd9, 0xea, 0x06, 0x4d, 0xe3, 0xe5,
482 0x9f, 0x49, 0x61, 0xd0, 0x09, 0x52, 0x50, 0xee
484 static const unsigned char second_context2[] = { 0x00 };
485 static const unsigned char second_export2[] = {
486 0x2e, 0x8f, 0x0b, 0x54, 0x67, 0x3c, 0x70, 0x29,
487 0x64, 0x9d, 0x4e, 0xb9, 0xd5, 0xe3, 0x3b, 0xf1,
488 0x87, 0x2c, 0xf7, 0x6d, 0x62, 0x3f, 0xf1, 0x64,
489 0xac, 0x18, 0x5d, 0xa9, 0xe8, 0x8c, 0x21, 0xa5
491 static const unsigned char second_context3[] = {
492 0x54, 0x65, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x74,
495 static const unsigned char second_export3[] = {
496 0xe9, 0xe4, 0x30, 0x65, 0x10, 0x2c, 0x38, 0x36,
497 0x40, 0x1b, 0xed, 0x8c, 0x3c, 0x3c, 0x75, 0xae,
498 0x46, 0xbe, 0x16, 0x39, 0x86, 0x93, 0x91, 0xd6,
499 0x2c, 0x61, 0xf1, 0xec, 0x7a, 0xf5, 0x49, 0x31
502 static int x25519kdfsha256_hkdfsha256_aes128gcm_base_test(void)
504 const TEST_BASEDATA basedata = {
507 OSSL_HPKE_KEM_ID_X25519,
508 OSSL_HPKE_KDF_ID_HKDF_SHA256,
509 OSSL_HPKE_AEAD_ID_AES_GCM_128
511 second_ikme, sizeof(second_ikme),
512 second_ikmepub, sizeof(second_ikmepub),
513 second_ikmr, sizeof(second_ikmr),
514 second_ikmrpub, sizeof(second_ikmrpub),
515 second_ikmrpriv, sizeof(second_ikmrpriv),
516 second_expected_shared_secret, sizeof(second_expected_shared_secret),
517 ksinfo, sizeof(ksinfo),
518 NULL, 0, /* no auth ikm */
519 NULL, 0, NULL /* no psk */
521 const TEST_AEADDATA aeaddata[] = {
525 second_aead0, sizeof(second_aead0),
526 second_ct0, sizeof(second_ct0)
531 second_aead1, sizeof(second_aead1),
532 second_ct1, sizeof(second_ct1)
535 const TEST_EXPORTDATA exportdata[] = {
536 { NULL, 0, second_export1, sizeof(second_export1) },
537 { second_context2, sizeof(second_context2),
538 second_export2, sizeof(second_export2) },
539 { second_context3, sizeof(second_context3),
540 second_export3, sizeof(second_export3) },
542 return do_testhpke(&basedata, aeaddata, OSSL_NELEM(aeaddata),
543 exportdata, OSSL_NELEM(exportdata));
546 static const unsigned char third_ikme[] = {
547 0x42, 0x70, 0xe5, 0x4f, 0xfd, 0x08, 0xd7, 0x9d,
548 0x59, 0x28, 0x02, 0x0a, 0xf4, 0x68, 0x6d, 0x8f,
549 0x6b, 0x7d, 0x35, 0xdb, 0xe4, 0x70, 0x26, 0x5f,
550 0x1f, 0x5a, 0xa2, 0x28, 0x16, 0xce, 0x86, 0x0e
552 static const unsigned char third_ikmepub[] = {
553 0x04, 0xa9, 0x27, 0x19, 0xc6, 0x19, 0x5d, 0x50,
554 0x85, 0x10, 0x4f, 0x46, 0x9a, 0x8b, 0x98, 0x14,
555 0xd5, 0x83, 0x8f, 0xf7, 0x2b, 0x60, 0x50, 0x1e,
556 0x2c, 0x44, 0x66, 0xe5, 0xe6, 0x7b, 0x32, 0x5a,
557 0xc9, 0x85, 0x36, 0xd7, 0xb6, 0x1a, 0x1a, 0xf4,
558 0xb7, 0x8e, 0x5b, 0x7f, 0x95, 0x1c, 0x09, 0x00,
559 0xbe, 0x86, 0x3c, 0x40, 0x3c, 0xe6, 0x5c, 0x9b,
560 0xfc, 0xb9, 0x38, 0x26, 0x57, 0x22, 0x2d, 0x18,
563 static const unsigned char third_ikmr[] = {
564 0x66, 0x8b, 0x37, 0x17, 0x1f, 0x10, 0x72, 0xf3,
565 0xcf, 0x12, 0xea, 0x8a, 0x23, 0x6a, 0x45, 0xdf,
566 0x23, 0xfc, 0x13, 0xb8, 0x2a, 0xf3, 0x60, 0x9a,
567 0xd1, 0xe3, 0x54, 0xf6, 0xef, 0x81, 0x75, 0x50
569 static const unsigned char third_ikmrpub[] = {
570 0x04, 0xfe, 0x8c, 0x19, 0xce, 0x09, 0x05, 0x19,
571 0x1e, 0xbc, 0x29, 0x8a, 0x92, 0x45, 0x79, 0x25,
572 0x31, 0xf2, 0x6f, 0x0c, 0xec, 0xe2, 0x46, 0x06,
573 0x39, 0xe8, 0xbc, 0x39, 0xcb, 0x7f, 0x70, 0x6a,
574 0x82, 0x6a, 0x77, 0x9b, 0x4c, 0xf9, 0x69, 0xb8,
575 0xa0, 0xe5, 0x39, 0xc7, 0xf6, 0x2f, 0xb3, 0xd3,
576 0x0a, 0xd6, 0xaa, 0x8f, 0x80, 0xe3, 0x0f, 0x1d,
577 0x12, 0x8a, 0xaf, 0xd6, 0x8a, 0x2c, 0xe7, 0x2e,
580 static const unsigned char third_ikmrpriv[] = {
581 0xf3, 0xce, 0x7f, 0xda, 0xe5, 0x7e, 0x1a, 0x31,
582 0x0d, 0x87, 0xf1, 0xeb, 0xbd, 0xe6, 0xf3, 0x28,
583 0xbe, 0x0a, 0x99, 0xcd, 0xbc, 0xad, 0xf4, 0xd6,
584 0x58, 0x9c, 0xf2, 0x9d, 0xe4, 0xb8, 0xff, 0xd2
586 static const unsigned char third_expected_shared_secret[] = {
587 0xc0, 0xd2, 0x6a, 0xea, 0xb5, 0x36, 0x60, 0x9a,
588 0x57, 0x2b, 0x07, 0x69, 0x5d, 0x93, 0x3b, 0x58,
589 0x9d, 0xcf, 0x36, 0x3f, 0xf9, 0xd9, 0x3c, 0x93,
590 0xad, 0xea, 0x53, 0x7a, 0xea, 0xbb, 0x8c, 0xb8
592 static const unsigned char third_aead0[] = {
593 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x2d, 0x30
595 static const unsigned char third_ct0[] = {
596 0x5a, 0xd5, 0x90, 0xbb, 0x8b, 0xaa, 0x57, 0x7f,
597 0x86, 0x19, 0xdb, 0x35, 0xa3, 0x63, 0x11, 0x22,
598 0x6a, 0x89, 0x6e, 0x73, 0x42, 0xa6, 0xd8, 0x36,
599 0xd8, 0xb7, 0xbc, 0xd2, 0xf2, 0x0b, 0x6c, 0x7f,
600 0x90, 0x76, 0xac, 0x23, 0x2e, 0x3a, 0xb2, 0x52,
601 0x3f, 0x39, 0x51, 0x34, 0x34
603 static const unsigned char third_aead1[] = {
604 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x2d, 0x31
606 static const unsigned char third_ct1[] = {
607 0xfa, 0x6f, 0x03, 0x7b, 0x47, 0xfc, 0x21, 0x82,
608 0x6b, 0x61, 0x01, 0x72, 0xca, 0x96, 0x37, 0xe8,
609 0x2d, 0x6e, 0x58, 0x01, 0xeb, 0x31, 0xcb, 0xd3,
610 0x74, 0x82, 0x71, 0xaf, 0xfd, 0x4e, 0xcb, 0x06,
611 0x64, 0x6e, 0x03, 0x29, 0xcb, 0xdf, 0x3c, 0x3c,
612 0xd6, 0x55, 0xb2, 0x8e, 0x82
614 static const unsigned char third_export1[] = {
615 0x5e, 0x9b, 0xc3, 0xd2, 0x36, 0xe1, 0x91, 0x1d,
616 0x95, 0xe6, 0x5b, 0x57, 0x6a, 0x8a, 0x86, 0xd4,
617 0x78, 0xfb, 0x82, 0x7e, 0x8b, 0xdf, 0xe7, 0x7b,
618 0x74, 0x1b, 0x28, 0x98, 0x90, 0x49, 0x0d, 0x4d
620 static const unsigned char third_context2[] = { 0x00 };
621 static const unsigned char third_export2[] = {
622 0x6c, 0xff, 0x87, 0x65, 0x89, 0x31, 0xbd, 0xa8,
623 0x3d, 0xc8, 0x57, 0xe6, 0x35, 0x3e, 0xfe, 0x49,
624 0x87, 0xa2, 0x01, 0xb8, 0x49, 0x65, 0x8d, 0x9b,
625 0x04, 0x7a, 0xab, 0x4c, 0xf2, 0x16, 0xe7, 0x96
627 static const unsigned char third_context3[] = {
628 0x54, 0x65, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x74,
631 static const unsigned char third_export3[] = {
632 0xd8, 0xf1, 0xea, 0x79, 0x42, 0xad, 0xbb, 0xa7,
633 0x41, 0x2c, 0x6d, 0x43, 0x1c, 0x62, 0xd0, 0x13,
634 0x71, 0xea, 0x47, 0x6b, 0x82, 0x3e, 0xb6, 0x97,
635 0xe1, 0xf6, 0xe6, 0xca, 0xe1, 0xda, 0xb8, 0x5a
638 static int P256kdfsha256_hkdfsha256_aes128gcm_base_test(void)
640 const TEST_BASEDATA basedata = {
643 OSSL_HPKE_KEM_ID_P256,
644 OSSL_HPKE_KDF_ID_HKDF_SHA256,
645 OSSL_HPKE_AEAD_ID_AES_GCM_128
647 third_ikme, sizeof(third_ikme),
648 third_ikmepub, sizeof(third_ikmepub),
649 third_ikmr, sizeof(third_ikmr),
650 third_ikmrpub, sizeof(third_ikmrpub),
651 third_ikmrpriv, sizeof(third_ikmrpriv),
652 third_expected_shared_secret, sizeof(third_expected_shared_secret),
653 ksinfo, sizeof(ksinfo),
654 NULL, 0, /* no auth */
655 NULL, 0, NULL /* PSK stuff */
657 const TEST_AEADDATA aeaddata[] = {
661 third_aead0, sizeof(third_aead0),
662 third_ct0, sizeof(third_ct0)
667 third_aead1, sizeof(third_aead1),
668 third_ct1, sizeof(third_ct1)
671 const TEST_EXPORTDATA exportdata[] = {
672 { NULL, 0, third_export1, sizeof(third_export1) },
673 { third_context2, sizeof(third_context2),
674 third_export2, sizeof(third_export2) },
675 { third_context3, sizeof(third_context3),
676 third_export3, sizeof(third_export3) },
678 return do_testhpke(&basedata, aeaddata, OSSL_NELEM(aeaddata),
679 exportdata, OSSL_NELEM(exportdata));
682 static const unsigned char fourth_ikme[] = {
683 0x55, 0xbc, 0x24, 0x5e, 0xe4, 0xef, 0xda, 0x25,
684 0xd3, 0x8f, 0x2d, 0x54, 0xd5, 0xbb, 0x66, 0x65,
685 0x29, 0x1b, 0x99, 0xf8, 0x10, 0x8a, 0x8c, 0x4b,
686 0x68, 0x6c, 0x2b, 0x14, 0x89, 0x3e, 0xa5, 0xd9
688 static const unsigned char fourth_ikmepub[] = {
689 0xe5, 0xe8, 0xf9, 0xbf, 0xff, 0x6c, 0x2f, 0x29,
690 0x79, 0x1f, 0xc3, 0x51, 0xd2, 0xc2, 0x5c, 0xe1,
691 0x29, 0x9a, 0xa5, 0xea, 0xca, 0x78, 0xa7, 0x57,
692 0xc0, 0xb4, 0xfb, 0x4b, 0xcd, 0x83, 0x09, 0x18
694 static const unsigned char fourth_ikmr[] = {
695 0x68, 0x3a, 0xe0, 0xda, 0x1d, 0x22, 0x18, 0x1e,
696 0x74, 0xed, 0x2e, 0x50, 0x3e, 0xbf, 0x82, 0x84,
697 0x0d, 0xeb, 0x1d, 0x5e, 0x87, 0x2c, 0xad, 0xe2,
698 0x0f, 0x4b, 0x45, 0x8d, 0x99, 0x78, 0x3e, 0x31
700 static const unsigned char fourth_ikmrpub[] = {
701 0x19, 0x41, 0x41, 0xca, 0x6c, 0x3c, 0x3b, 0xeb,
702 0x47, 0x92, 0xcd, 0x97, 0xba, 0x0e, 0xa1, 0xfa,
703 0xff, 0x09, 0xd9, 0x84, 0x35, 0x01, 0x23, 0x45,
704 0x76, 0x6e, 0xe3, 0x3a, 0xae, 0x2d, 0x76, 0x64
706 static const unsigned char fourth_ikmrpriv[] = {
707 0x33, 0xd1, 0x96, 0xc8, 0x30, 0xa1, 0x2f, 0x9a,
708 0xc6, 0x5d, 0x6e, 0x56, 0x5a, 0x59, 0x0d, 0x80,
709 0xf0, 0x4e, 0xe9, 0xb1, 0x9c, 0x83, 0xc8, 0x7f,
710 0x2c, 0x17, 0x0d, 0x97, 0x2a, 0x81, 0x28, 0x48
712 static const unsigned char fourth_expected_shared_secret[] = {
713 0xe8, 0x17, 0x16, 0xce, 0x8f, 0x73, 0x14, 0x1d,
714 0x4f, 0x25, 0xee, 0x90, 0x98, 0xef, 0xc9, 0x68,
715 0xc9, 0x1e, 0x5b, 0x8c, 0xe5, 0x2f, 0xff, 0xf5,
716 0x9d, 0x64, 0x03, 0x9e, 0x82, 0x91, 0x8b, 0x66
718 static const unsigned char fourth_export1[] = {
719 0x7a, 0x36, 0x22, 0x1b, 0xd5, 0x6d, 0x50, 0xfb,
720 0x51, 0xee, 0x65, 0xed, 0xfd, 0x98, 0xd0, 0x6a,
721 0x23, 0xc4, 0xdc, 0x87, 0x08, 0x5a, 0xa5, 0x86,
722 0x6c, 0xb7, 0x08, 0x72, 0x44, 0xbd, 0x2a, 0x36
724 static const unsigned char fourth_context2[] = { 0x00 };
725 static const unsigned char fourth_export2[] = {
726 0xd5, 0x53, 0x5b, 0x87, 0x09, 0x9c, 0x6c, 0x3c,
727 0xe8, 0x0d, 0xc1, 0x12, 0xa2, 0x67, 0x1c, 0x6e,
728 0xc8, 0xe8, 0x11, 0xa2, 0xf2, 0x84, 0xf9, 0x48,
729 0xce, 0xc6, 0xdd, 0x17, 0x08, 0xee, 0x33, 0xf0
731 static const unsigned char fourth_context3[] = {
732 0x54, 0x65, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x74,
735 static const unsigned char fourth_export3[] = {
736 0xff, 0xaa, 0xbc, 0x85, 0xa7, 0x76, 0x13, 0x6c,
737 0xa0, 0xc3, 0x78, 0xe5, 0xd0, 0x84, 0xc9, 0x14,
738 0x0a, 0xb5, 0x52, 0xb7, 0x8f, 0x03, 0x9d, 0x2e,
739 0x87, 0x75, 0xf2, 0x6e, 0xff, 0xf4, 0xc7, 0x0e
742 static int export_only_test(void)
744 /* based on RFC9180 A.7 */
745 const TEST_BASEDATA basedata = {
748 OSSL_HPKE_KEM_ID_X25519,
749 OSSL_HPKE_KDF_ID_HKDF_SHA256,
750 OSSL_HPKE_AEAD_ID_EXPORTONLY
752 fourth_ikme, sizeof(fourth_ikme),
753 fourth_ikmepub, sizeof(fourth_ikmepub),
754 fourth_ikmr, sizeof(fourth_ikmr),
755 fourth_ikmrpub, sizeof(fourth_ikmrpub),
756 fourth_ikmrpriv, sizeof(fourth_ikmrpriv),
757 fourth_expected_shared_secret, sizeof(fourth_expected_shared_secret),
758 ksinfo, sizeof(ksinfo),
759 NULL, 0, /* no auth */
760 NULL, 0, NULL /* PSK stuff */
762 const TEST_EXPORTDATA exportdata[] = {
763 { NULL, 0, fourth_export1, sizeof(fourth_export1) },
764 { fourth_context2, sizeof(fourth_context2),
765 fourth_export2, sizeof(fourth_export2) },
766 { fourth_context3, sizeof(fourth_context3),
767 fourth_export3, sizeof(fourth_export3) },
769 return do_testhpke(&basedata, NULL, 0,
770 exportdata, OSSL_NELEM(exportdata));
774 * Randomly toss a coin
776 #define COIN_IS_HEADS (test_random() % 2)
778 /* tables of HPKE modes and suite values */
779 static int hpke_mode_list[] = {
783 OSSL_HPKE_MODE_PSKAUTH
785 static uint16_t hpke_kem_list[] = {
786 OSSL_HPKE_KEM_ID_P256,
787 OSSL_HPKE_KEM_ID_P384,
788 OSSL_HPKE_KEM_ID_P521,
789 OSSL_HPKE_KEM_ID_X25519,
790 OSSL_HPKE_KEM_ID_X448
792 static uint16_t hpke_kdf_list[] = {
793 OSSL_HPKE_KDF_ID_HKDF_SHA256,
794 OSSL_HPKE_KDF_ID_HKDF_SHA384,
795 OSSL_HPKE_KDF_ID_HKDF_SHA512
797 static uint16_t hpke_aead_list[] = {
798 OSSL_HPKE_AEAD_ID_AES_GCM_128,
799 OSSL_HPKE_AEAD_ID_AES_GCM_256,
800 OSSL_HPKE_AEAD_ID_CHACHA_POLY1305
804 * Strings that can be used with names or IANA codepoints.
805 * Note that the initial entries from these lists should
806 * match the lists above, i.e. kem_str_list[0] and
807 * hpke_kem_list[0] should refer to the same KEM. We use
808 * that for verbose output via TEST_note() below.
809 * Subsequent entries are only used for tests of
810 * OSSL_HPKE_str2suite()
812 static const char *mode_str_list[] = {
813 "base", "psk", "auth", "pskauth"
815 static const char *kem_str_list[] = {
816 "P-256", "P-384", "P-521", "x25519", "x448",
817 "0x10", "0x11", "0x12", "0x20", "0x21",
818 "16", "17", "18", "32", "33"
820 static const char *kdf_str_list[] = {
821 "hkdf-sha256", "hkdf-sha384", "hkdf-sha512",
822 "0x1", "0x01", "0x2", "0x02", "0x3", "0x03",
825 static const char *aead_str_list[] = {
826 "aes-128-gcm", "aes-256-gcm", "chacha20-poly1305", "exporter",
827 "0x1", "0x01", "0x2", "0x02", "0x3", "0x03",
831 /* table of bogus strings that better not work */
832 static const char *bogus_suite_strs[] = {
835 "bogus,33,3,1,bogus",
843 /* in reverse order */
844 "aes-256-gcm,hkdf-sha512,x25519",
845 /* surplus separators */
849 /* embedded NUL chars */
851 "0x10,\0""0x01,0x02",
854 "0x10,0x01,\0""0x02",
855 /* embedded whitespace */
856 " aes-256-gcm,hkdf-sha512,x25519",
857 "aes-256-gcm, hkdf-sha512,x25519",
858 "aes-256-gcm ,hkdf-sha512,x25519",
859 "aes-256-gcm,hkdf-sha512, x25519",
860 "aes-256-gcm,hkdf-sha512 ,x25519",
861 "aes-256-gcm,hkdf-sha512,x25519 ",
862 /* good value followed by extra stuff */
865 "0x10,0x01,0x01,0x02",
866 "0x10,0x01,0x01,blah",
867 "0x10,0x01,0x01 0x02",
868 /* too few but good tokens */
879 * @brief round-trips, generating keys, encrypt and decrypt
881 * This iterates over all mode and ciphersuite options trying
882 * a key gen, encrypt and decrypt for each. The aad, info, and
883 * seq inputs are randomly set or omitted each time. EVP and
884 * non-EVP key generation are randomly selected.
886 * @return 1 for success, other otherwise
888 static int test_hpke_modes_suites(void)
890 int overallresult = 1;
891 size_t mind = 0; /* index into hpke_mode_list */
892 size_t kemind = 0; /* index into hpke_kem_list */
893 size_t kdfind = 0; /* index into hpke_kdf_list */
894 size_t aeadind = 0; /* index into hpke_aead_list */
896 /* iterate over the different modes */
897 for (mind = 0; mind < OSSL_NELEM(hpke_mode_list); mind++) {
898 int hpke_mode = hpke_mode_list[mind];
899 size_t aadlen = OSSL_HPKE_TSTSIZE;
900 unsigned char aad[OSSL_HPKE_TSTSIZE];
901 unsigned char *aadp = NULL;
903 unsigned char info[32];
904 unsigned char *infop = NULL;
905 unsigned char lpsk[32];
906 unsigned char *pskp = NULL;
910 EVP_PKEY *privp = NULL;
911 OSSL_HPKE_SUITE hpke_suite = OSSL_HPKE_SUITE_DEFAULT;
912 size_t plainlen = OSSL_HPKE_TSTSIZE;
913 unsigned char plain[OSSL_HPKE_TSTSIZE];
914 uint64_t startseq = 0;
915 OSSL_HPKE_CTX *rctx = NULL;
916 OSSL_HPKE_CTX *ctx = NULL;
918 memset(plain, 0x00, OSSL_HPKE_TSTSIZE);
919 strcpy((char *)plain, "a message not in a bottle");
920 plainlen = strlen((char *)plain);
922 * Randomly try with/without info, aad, seq. Given mode and suite
923 * combos, and this being run even a few times, we'll exercise many
924 * code paths fairly quickly. We don't really care what the values
925 * are but it'll be easier to debug if they're known, so we set 'em.
929 memset(aad, 'a', aadlen);
935 memset(info, 'i', infolen);
939 if (hpke_mode == OSSL_HPKE_MODE_PSK
940 || hpke_mode == OSSL_HPKE_MODE_PSKAUTH) {
942 memset(lpsk, 'P', psklen);
944 memset(lpskid, 'I', psklen - 1);
945 lpskid[psklen - 1] = '\0';
949 for (kemind = 0; /* iterate over the kems, kdfs and aeads */
950 overallresult == 1 && kemind < OSSL_NELEM(hpke_kem_list);
952 uint16_t kem_id = hpke_kem_list[kemind];
953 size_t authpublen = OSSL_HPKE_TSTSIZE;
954 unsigned char authpub[OSSL_HPKE_TSTSIZE];
955 unsigned char *authpubp = NULL;
956 EVP_PKEY *authpriv = NULL;
958 hpke_suite.kem_id = kem_id;
959 if (hpke_mode == OSSL_HPKE_MODE_AUTH
960 || hpke_mode == OSSL_HPKE_MODE_PSKAUTH) {
961 if (TEST_true(OSSL_HPKE_keygen(hpke_suite, authpub, &authpublen,
963 testctx, NULL)) != 1) {
971 overallresult == 1 && kdfind < OSSL_NELEM(hpke_kdf_list);
973 uint16_t kdf_id = hpke_kdf_list[kdfind];
975 hpke_suite.kdf_id = kdf_id;
978 && aeadind < OSSL_NELEM(hpke_aead_list);
980 uint16_t aead_id = hpke_aead_list[aeadind];
981 size_t publen = OSSL_HPKE_TSTSIZE;
982 unsigned char pub[OSSL_HPKE_TSTSIZE];
983 size_t senderpublen = OSSL_HPKE_TSTSIZE;
984 unsigned char senderpub[OSSL_HPKE_TSTSIZE];
985 size_t cipherlen = OSSL_HPKE_TSTSIZE;
986 unsigned char cipher[OSSL_HPKE_TSTSIZE];
987 size_t clearlen = OSSL_HPKE_TSTSIZE;
988 unsigned char clear[OSSL_HPKE_TSTSIZE];
990 hpke_suite.aead_id = aead_id;
991 if (!TEST_true(OSSL_HPKE_keygen(hpke_suite,
992 pub, &publen, &privp,
993 NULL, 0, testctx, NULL)))
995 if (!TEST_ptr(ctx = OSSL_HPKE_CTX_new(hpke_mode, hpke_suite,
998 if (hpke_mode == OSSL_HPKE_MODE_PSK
999 || hpke_mode == OSSL_HPKE_MODE_PSKAUTH) {
1000 if (!TEST_true(OSSL_HPKE_CTX_set1_psk(ctx, pskidp,
1004 if (hpke_mode == OSSL_HPKE_MODE_AUTH
1005 || hpke_mode == OSSL_HPKE_MODE_PSKAUTH) {
1006 if (!TEST_true(OSSL_HPKE_CTX_set1_authpriv(ctx,
1010 if (COIN_IS_HEADS) {
1011 if (!TEST_int_eq(1, RAND_bytes_ex(testctx,
1012 (unsigned char *) &startseq,
1013 sizeof(startseq), 0))
1014 || !TEST_true(OSSL_HPKE_CTX_set_seq(ctx, startseq)))
1019 if (!TEST_true(OSSL_HPKE_encap(ctx, senderpub,
1024 /* throw in a call with a too-short cipherlen */
1026 if (!TEST_false(OSSL_HPKE_seal(ctx, cipher, &cipherlen,
1030 /* fix back real cipherlen */
1031 cipherlen = OSSL_HPKE_TSTSIZE;
1032 if (!TEST_true(OSSL_HPKE_seal(ctx, cipher, &cipherlen,
1036 OSSL_HPKE_CTX_free(ctx);
1037 memset(clear, 0, clearlen);
1038 if (!TEST_ptr(rctx = OSSL_HPKE_CTX_new(hpke_mode,
1042 if (hpke_mode == OSSL_HPKE_MODE_PSK
1043 || hpke_mode == OSSL_HPKE_MODE_PSKAUTH) {
1044 if (!TEST_true(OSSL_HPKE_CTX_set1_psk(rctx, pskidp,
1048 if (hpke_mode == OSSL_HPKE_MODE_AUTH
1049 || hpke_mode == OSSL_HPKE_MODE_PSKAUTH) {
1050 /* check a borked p256 key */
1051 if (hpke_suite.kem_id == OSSL_HPKE_KEM_ID_P256) {
1052 /* set to fail decode of authpub this time */
1053 if (!TEST_false(OSSL_HPKE_CTX_set1_authpub(rctx,
1059 if (!TEST_true(OSSL_HPKE_CTX_set1_authpub(rctx,
1064 if (startseq != 0) {
1065 if (!TEST_true(OSSL_HPKE_CTX_set_seq(rctx, startseq)))
1068 if (!TEST_true(OSSL_HPKE_decap(rctx, senderpub,
1069 senderpublen, privp,
1072 /* throw in a call with a too-short clearlen */
1074 if (!TEST_false(OSSL_HPKE_open(rctx, clear, &clearlen,
1075 aadp, aadlen, cipher,
1078 /* fix up real clearlen again */
1079 clearlen = OSSL_HPKE_TSTSIZE;
1080 if (!TEST_true(OSSL_HPKE_open(rctx, clear, &clearlen,
1081 aadp, aadlen, cipher,
1084 OSSL_HPKE_CTX_free(rctx);
1085 EVP_PKEY_free(privp);
1088 if (!TEST_mem_eq(clear, clearlen, plain, plainlen)) {
1091 if (verbose || overallresult != 1) {
1092 const char *res = NULL;
1094 res = (overallresult == 1 ? "worked" : "failed");
1095 TEST_note("HPKE %s for mode: %s/0x%02x, "\
1096 "kem: %s/0x%02x, kdf: %s/0x%02x, "\
1097 "aead: %s/0x%02x", res,
1098 mode_str_list[mind], (int) mind,
1099 kem_str_list[kemind], kem_id,
1100 kdf_str_list[kdfind], kdf_id,
1101 aead_str_list[aeadind], aead_id);
1105 EVP_PKEY_free(authpriv);
1108 return overallresult;
1112 * @brief check roundtrip for export
1113 * @return 1 for success, other otherwise
1115 static int test_hpke_export(void)
1118 EVP_PKEY *privp = NULL;
1119 unsigned char pub[OSSL_HPKE_TSTSIZE];
1120 size_t publen = sizeof(pub);
1121 int hpke_mode = OSSL_HPKE_MODE_BASE;
1122 OSSL_HPKE_SUITE hpke_suite = OSSL_HPKE_SUITE_DEFAULT;
1123 OSSL_HPKE_CTX *ctx = NULL;
1124 OSSL_HPKE_CTX *rctx = NULL;
1125 unsigned char exp[32];
1126 unsigned char exp2[32];
1127 unsigned char rexp[32];
1128 unsigned char rexp2[32];
1129 unsigned char plain[] = "quick brown fox";
1130 size_t plainlen = sizeof(plain);
1131 unsigned char enc[OSSL_HPKE_TSTSIZE];
1132 size_t enclen = sizeof(enc);
1133 unsigned char cipher[OSSL_HPKE_TSTSIZE];
1134 size_t cipherlen = sizeof(cipher);
1135 unsigned char clear[OSSL_HPKE_TSTSIZE];
1136 size_t clearlen = sizeof(clear);
1139 if (!TEST_true(OSSL_HPKE_keygen(hpke_suite, pub, &publen, &privp,
1140 NULL, 0, testctx, NULL)))
1142 if (!TEST_ptr(ctx = OSSL_HPKE_CTX_new(hpke_mode, hpke_suite,
1145 /* a few error cases 1st */
1146 if (!TEST_false(OSSL_HPKE_export(NULL, exp, sizeof(exp),
1147 (unsigned char *)estr, strlen(estr))))
1149 /* ctx before encap should fail too */
1150 if (!TEST_false(OSSL_HPKE_export(ctx, exp, sizeof(exp),
1151 (unsigned char *)estr, strlen(estr))))
1153 if (!TEST_true(OSSL_HPKE_encap(ctx, enc, &enclen, pub, publen, NULL, 0)))
1155 if (!TEST_true(OSSL_HPKE_seal(ctx, cipher, &cipherlen, NULL, 0,
1159 if (!TEST_true(OSSL_HPKE_export(ctx, exp, sizeof(exp),
1160 (unsigned char *)estr, strlen(estr))))
1162 /* check a 2nd call with same input gives same output */
1163 if (!TEST_true(OSSL_HPKE_export(ctx, exp2, sizeof(exp2),
1164 (unsigned char *)estr, strlen(estr))))
1166 if (!TEST_mem_eq(exp, sizeof(exp), exp2, sizeof(exp2)))
1168 if (!TEST_ptr(rctx = OSSL_HPKE_CTX_new(hpke_mode, hpke_suite,
1171 if (!TEST_true(OSSL_HPKE_decap(rctx, enc, enclen, privp, NULL, 0)))
1173 if (!TEST_true(OSSL_HPKE_open(rctx, clear, &clearlen, NULL, 0,
1174 cipher, cipherlen)))
1176 if (!TEST_true(OSSL_HPKE_export(rctx, rexp, sizeof(rexp),
1177 (unsigned char *)estr, strlen(estr))))
1179 /* check a 2nd call with same input gives same output */
1180 if (!TEST_true(OSSL_HPKE_export(rctx, rexp2, sizeof(rexp2),
1181 (unsigned char *)estr, strlen(estr))))
1183 if (!TEST_mem_eq(rexp, sizeof(rexp), rexp2, sizeof(rexp2)))
1185 if (!TEST_mem_eq(exp, sizeof(exp), rexp, sizeof(rexp)))
1189 OSSL_HPKE_CTX_free(ctx);
1190 OSSL_HPKE_CTX_free(rctx);
1191 EVP_PKEY_free(privp);
1196 * @brief Check mapping from strings to HPKE suites
1197 * @return 1 for success, other otherwise
1199 static int test_hpke_suite_strs(void)
1201 int overallresult = 1;
1207 OSSL_HPKE_SUITE stirred;
1210 for (kemind = 0; kemind != OSSL_NELEM(kem_str_list); kemind++) {
1211 for (kdfind = 0; kdfind != OSSL_NELEM(kdf_str_list); kdfind++) {
1212 for (aeadind = 0; aeadind != OSSL_NELEM(aead_str_list); aeadind++) {
1213 snprintf(sstr, 128, "%s,%s,%s", kem_str_list[kemind],
1214 kdf_str_list[kdfind], aead_str_list[aeadind]);
1215 if (TEST_true(OSSL_HPKE_str2suite(sstr, &stirred)) != 1) {
1217 TEST_note("Unexpected str2suite fail for :%s",
1218 bogus_suite_strs[sind]);
1224 for (sind = 0; sind != OSSL_NELEM(bogus_suite_strs); sind++) {
1225 if (TEST_false(OSSL_HPKE_str2suite(bogus_suite_strs[sind],
1228 TEST_note("OSSL_HPKE_str2suite didn't fail for bogus[%d]:%s",
1229 sind, bogus_suite_strs[sind]);
1233 /* check a few errors */
1234 if (!TEST_false(OSSL_HPKE_str2suite("", &stirred)))
1236 if (!TEST_false(OSSL_HPKE_str2suite(NULL, &stirred)))
1238 if (!TEST_false(OSSL_HPKE_str2suite("", NULL)))
1240 memset(giant, 'A', sizeof(giant) - 1);
1241 giant[sizeof(giant) - 1] = '\0';
1242 if (!TEST_false(OSSL_HPKE_str2suite(giant, &stirred)))
1245 return overallresult;
1249 * @brief try the various GREASEy APIs
1250 * @return 1 for success, other otherwise
1252 static int test_hpke_grease(void)
1254 int overallresult = 1;
1255 OSSL_HPKE_SUITE g_suite;
1256 unsigned char g_pub[OSSL_HPKE_TSTSIZE];
1257 size_t g_pub_len = OSSL_HPKE_TSTSIZE;
1258 unsigned char g_cipher[OSSL_HPKE_TSTSIZE];
1259 size_t g_cipher_len = 266;
1260 size_t clearlen = 128;
1261 size_t expanded = 0;
1265 memset(&g_suite, 0, sizeof(OSSL_HPKE_SUITE));
1267 /* check too short for public value */
1269 if (TEST_false(OSSL_HPKE_get_grease_value(testctx, NULL, NULL, &g_suite,
1271 g_cipher, g_cipher_len)) != 1) {
1275 g_pub_len = OSSL_HPKE_TSTSIZE;
1276 if (TEST_true(OSSL_HPKE_get_grease_value(testctx, NULL, NULL, &g_suite,
1278 g_cipher, g_cipher_len)) != 1) {
1282 expanded = OSSL_HPKE_get_ciphertext_size(g_suite, clearlen);
1283 if (!TEST_size_t_gt(expanded, clearlen)) {
1286 enclen = OSSL_HPKE_get_public_encap_size(g_suite);
1287 if (!TEST_size_t_ne(enclen, 0))
1289 /* not really GREASE but we'll check ikmelen thing */
1290 ikmelen = OSSL_HPKE_get_recommended_ikmelen(g_suite);
1291 if (!TEST_size_t_ne(ikmelen, 0))
1294 return overallresult;
1298 * Make a set of calls with odd parameters
1300 static int test_hpke_oddcalls(void)
1303 EVP_PKEY *privp = NULL;
1304 unsigned char pub[OSSL_HPKE_TSTSIZE];
1305 size_t publen = sizeof(pub);
1306 int hpke_mode = OSSL_HPKE_MODE_BASE;
1307 int bad_mode = 0xbad;
1308 OSSL_HPKE_SUITE hpke_suite = OSSL_HPKE_SUITE_DEFAULT;
1309 OSSL_HPKE_SUITE bad_suite = { 0xbad, 0xbad, 0xbad };
1310 OSSL_HPKE_CTX *ctx = NULL;
1311 OSSL_HPKE_CTX *rctx = NULL;
1312 unsigned char plain[] = "quick brown fox";
1313 size_t plainlen = sizeof(plain);
1314 unsigned char enc[OSSL_HPKE_TSTSIZE];
1315 size_t enclen = sizeof(enc);
1316 unsigned char cipher[OSSL_HPKE_TSTSIZE];
1317 size_t cipherlen = sizeof(cipher);
1318 unsigned char clear[OSSL_HPKE_TSTSIZE];
1319 size_t clearlen = sizeof(clear);
1320 unsigned char fake_ikm[OSSL_HPKE_TSTSIZE];
1321 char *badpropq = "yeah, this won't work";
1323 char giant_pskid[OSSL_HPKE_MAX_PARMLEN + 10];
1324 unsigned char info[OSSL_HPKE_TSTSIZE];
1326 /* many of the calls below are designed to get better test coverage */
1328 /* NULL ctx calls */
1329 OSSL_HPKE_CTX_free(NULL);
1330 if (!TEST_false(OSSL_HPKE_CTX_set_seq(NULL, 1)))
1332 if (!TEST_false(OSSL_HPKE_CTX_get_seq(NULL, &lseq)))
1334 if (!TEST_false(OSSL_HPKE_CTX_set1_authpub(NULL, pub, publen)))
1336 if (!TEST_false(OSSL_HPKE_CTX_set1_authpriv(NULL, privp)))
1338 if (!TEST_false(OSSL_HPKE_CTX_set1_ikme(NULL, NULL, 0)))
1340 if (!TEST_false(OSSL_HPKE_CTX_set1_psk(NULL, NULL, NULL, 0)))
1343 /* make/break ctx */
1344 if (!TEST_ptr(ctx = OSSL_HPKE_CTX_new(hpke_mode, hpke_suite,
1347 OSSL_HPKE_CTX_free(ctx);
1350 /* bad suite calls */
1351 hpke_suite.aead_id = 0xbad;
1352 if (!TEST_false(OSSL_HPKE_suite_check(hpke_suite)))
1354 hpke_suite.aead_id = OSSL_HPKE_AEAD_ID_AES_GCM_128;
1355 if (!TEST_false(OSSL_HPKE_suite_check(bad_suite)))
1357 if (!TEST_false(OSSL_HPKE_get_recommended_ikmelen(bad_suite)))
1359 if (!TEST_false(OSSL_HPKE_get_public_encap_size(bad_suite)))
1361 if (!TEST_false(OSSL_HPKE_get_ciphertext_size(bad_suite, 0)))
1363 if (!TEST_false(OSSL_HPKE_keygen(bad_suite, pub, &publen, &privp,
1364 NULL, 0, testctx, badpropq)))
1366 if (!TEST_false(OSSL_HPKE_keygen(bad_suite, pub, &publen, &privp,
1367 NULL, 0, testctx, NULL)))
1370 /* dodgy keygen calls */
1372 if (!TEST_false(OSSL_HPKE_keygen(hpke_suite, NULL, &publen, &privp,
1373 NULL, 0, testctx, NULL)))
1375 /* ikmlen but NULL ikm */
1376 if (!TEST_false(OSSL_HPKE_keygen(hpke_suite, pub, &publen, &privp,
1377 NULL, 80, testctx, NULL)))
1379 /* zero ikmlen but ikm */
1380 if (!TEST_false(OSSL_HPKE_keygen(hpke_suite, pub, &publen, &privp,
1381 fake_ikm, 0, testctx, NULL)))
1384 if (!TEST_false(OSSL_HPKE_keygen(hpke_suite, pub, &publen, &privp,
1385 fake_ikm, -1, testctx, NULL)))
1389 if (!TEST_false(OSSL_HPKE_keygen(hpke_suite, pub, &publen, &privp,
1390 NULL, 0, testctx, NULL)))
1392 publen = sizeof(pub);
1394 /* encap/decap with NULLs */
1395 if (!TEST_false(OSSL_HPKE_encap(NULL, NULL, NULL, NULL, 0, NULL, 0)))
1397 if (!TEST_false(OSSL_HPKE_decap(NULL, NULL, 0, NULL, NULL, 0)))
1401 * run through a sender/recipient set of calls but with
1402 * failing calls interspersed whenever possible
1405 if (!TEST_true(OSSL_HPKE_keygen(hpke_suite, pub, &publen, &privp,
1406 NULL, 0, testctx, NULL)))
1409 /* a psk context with no psk => encap fail */
1410 if (!TEST_ptr(ctx = OSSL_HPKE_CTX_new(OSSL_HPKE_MODE_PSK, hpke_suite,
1413 /* set bad length psk */
1414 if (!TEST_false(OSSL_HPKE_CTX_set1_psk(ctx, "foo",
1415 (unsigned char *)"bar", -1)))
1417 /* set bad length pskid */
1418 memset(giant_pskid, 'A', sizeof(giant_pskid) - 1);
1419 giant_pskid[sizeof(giant_pskid) - 1] = '\0';
1420 if (!TEST_false(OSSL_HPKE_CTX_set1_psk(ctx, giant_pskid,
1421 (unsigned char *)"bar", 3)))
1423 /* still no psk really set so encap fails */
1424 if (!TEST_false(OSSL_HPKE_encap(ctx, enc, &enclen, pub, publen, NULL, 0)))
1426 OSSL_HPKE_CTX_free(ctx);
1429 if (!TEST_ptr_null(ctx = OSSL_HPKE_CTX_new(hpke_mode, bad_suite,
1433 if (!TEST_ptr_null(ctx = OSSL_HPKE_CTX_new(bad_mode, hpke_suite,
1437 if (!TEST_ptr(ctx = OSSL_HPKE_CTX_new(hpke_mode, hpke_suite,
1441 if (!TEST_false(OSSL_HPKE_CTX_set1_ikme(ctx, fake_ikm, -1)))
1443 /* zero length ikm */
1444 if (!TEST_false(OSSL_HPKE_CTX_set1_ikme(ctx, fake_ikm, 0)))
1447 if (!TEST_false(OSSL_HPKE_CTX_set1_authpub(ctx, NULL, 0)))
1449 /* NULL auth priv */
1450 if (!TEST_false(OSSL_HPKE_CTX_set1_authpriv(ctx, NULL)))
1452 /* priv good, but mode is bad */
1453 if (!TEST_false(OSSL_HPKE_CTX_set1_authpriv(ctx, privp)))
1455 /* bad mode for psk */
1456 if (!TEST_false(OSSL_HPKE_CTX_set1_psk(ctx, "foo",
1457 (unsigned char *)"bar", 3)))
1459 /* seal before encap */
1460 if (!TEST_false(OSSL_HPKE_seal(ctx, cipher, &cipherlen, NULL, 0,
1463 /* encap with dodgy public */
1464 if (!TEST_false(OSSL_HPKE_encap(ctx, enc, &enclen, pub, 1, NULL, 0)))
1466 /* encap with too big info */
1467 if (!TEST_false(OSSL_HPKE_encap(ctx, enc, &enclen, pub, 1, info, -1)))
1470 if (!TEST_true(OSSL_HPKE_encap(ctx, enc, &enclen, pub, publen, NULL, 0)))
1472 /* second encap fail */
1473 if (!TEST_false(OSSL_HPKE_encap(ctx, enc, &enclen, pub, publen, NULL, 0)))
1476 /* should fail for no plaintext */
1477 if (!TEST_false(OSSL_HPKE_seal(ctx, cipher, &cipherlen, NULL, 0,
1480 /* the sequence ought not have been incremented, so good to start over */
1481 plainlen = sizeof(plain);
1482 /* seq wrap around test */
1483 if (!TEST_true(OSSL_HPKE_CTX_set_seq(ctx, -1)))
1485 if (!TEST_false(OSSL_HPKE_seal(ctx, cipher, &cipherlen, NULL, 0,
1489 if (!TEST_true(OSSL_HPKE_CTX_set_seq(ctx, 0)))
1492 if (!TEST_true(OSSL_HPKE_seal(ctx, cipher, &cipherlen, NULL, 0,
1497 /* decap fail with psk mode but no psk set */
1498 if (!TEST_ptr(rctx = OSSL_HPKE_CTX_new(OSSL_HPKE_MODE_PSK, hpke_suite,
1501 if (!TEST_false(OSSL_HPKE_decap(rctx, enc, enclen, privp, NULL, 0)))
1503 /* done with PSK mode */
1504 OSSL_HPKE_CTX_free(rctx);
1506 /* back good calls for base mode */
1507 if (!TEST_ptr(rctx = OSSL_HPKE_CTX_new(hpke_mode, hpke_suite,
1510 /* open before decap */
1511 if (!TEST_false(OSSL_HPKE_open(rctx, clear, &clearlen, NULL, 0,
1512 cipher, cipherlen)))
1514 /* decap with info too long */
1515 if (!TEST_false(OSSL_HPKE_decap(rctx, enc, enclen, privp, info, -1)))
1518 if (!TEST_true(OSSL_HPKE_decap(rctx, enc, enclen, privp, NULL, 0)))
1520 /* second decap fail */
1521 if (!TEST_false(OSSL_HPKE_decap(rctx, enc, enclen, privp, NULL, 0)))
1523 /* no space for recovered clear */
1525 if (!TEST_false(OSSL_HPKE_open(rctx, clear, &clearlen, NULL, 0,
1526 cipher, cipherlen)))
1528 clearlen = OSSL_HPKE_TSTSIZE;
1529 /* seq wrap around test */
1530 if (!TEST_true(OSSL_HPKE_CTX_set_seq(rctx, -1)))
1532 if (!TEST_false(OSSL_HPKE_open(rctx, clear, &clearlen, NULL, 0,
1533 cipher, cipherlen)))
1535 if (!TEST_true(OSSL_HPKE_CTX_set_seq(rctx, 0)))
1537 if (!TEST_true(OSSL_HPKE_open(rctx, clear, &clearlen, NULL, 0,
1538 cipher, cipherlen)))
1540 if (!TEST_mem_eq(plain, plainlen, clear, clearlen))
1544 OSSL_HPKE_CTX_free(ctx);
1545 OSSL_HPKE_CTX_free(rctx);
1546 EVP_PKEY_free(privp);
1550 /* from RFC 9180 Appendix A.1.1 */
1551 static const unsigned char ikm25519[] = {
1552 0x72, 0x68, 0x60, 0x0d, 0x40, 0x3f, 0xce, 0x43,
1553 0x15, 0x61, 0xae, 0xf5, 0x83, 0xee, 0x16, 0x13,
1554 0x52, 0x7c, 0xff, 0x65, 0x5c, 0x13, 0x43, 0xf2,
1555 0x98, 0x12, 0xe6, 0x67, 0x06, 0xdf, 0x32, 0x34
1557 static const unsigned char pub25519[] = {
1558 0x37, 0xfd, 0xa3, 0x56, 0x7b, 0xdb, 0xd6, 0x28,
1559 0xe8, 0x86, 0x68, 0xc3, 0xc8, 0xd7, 0xe9, 0x7d,
1560 0x1d, 0x12, 0x53, 0xb6, 0xd4, 0xea, 0x6d, 0x44,
1561 0xc1, 0x50, 0xf7, 0x41, 0xf1, 0xbf, 0x44, 0x31
1564 /* from RFC9180 Appendix A.3.1 */
1565 static const unsigned char ikmp256[] = {
1566 0x42, 0x70, 0xe5, 0x4f, 0xfd, 0x08, 0xd7, 0x9d,
1567 0x59, 0x28, 0x02, 0x0a, 0xf4, 0x68, 0x6d, 0x8f,
1568 0x6b, 0x7d, 0x35, 0xdb, 0xe4, 0x70, 0x26, 0x5f,
1569 0x1f, 0x5a, 0xa2, 0x28, 0x16, 0xce, 0x86, 0x0e
1571 static const unsigned char pubp256[] = {
1572 0x04, 0xa9, 0x27, 0x19, 0xc6, 0x19, 0x5d, 0x50,
1573 0x85, 0x10, 0x4f, 0x46, 0x9a, 0x8b, 0x98, 0x14,
1574 0xd5, 0x83, 0x8f, 0xf7, 0x2b, 0x60, 0x50, 0x1e,
1575 0x2c, 0x44, 0x66, 0xe5, 0xe6, 0x7b, 0x32, 0x5a,
1576 0xc9, 0x85, 0x36, 0xd7, 0xb6, 0x1a, 0x1a, 0xf4,
1577 0xb7, 0x8e, 0x5b, 0x7f, 0x95, 0x1c, 0x09, 0x00,
1578 0xbe, 0x86, 0x3c, 0x40, 0x3c, 0xe6, 0x5c, 0x9b,
1579 0xfc, 0xb9, 0x38, 0x26, 0x57, 0x22, 0x2d, 0x18,
1584 * A test vector that exercises the counter iteration
1585 * for p256. This was contributed by Ilari L. on the
1586 * CFRG list, see the mail archive:
1587 * https://mailarchive.ietf.org/arch/msg/cfrg/4zwl_y5YN6OU9oeWZOMHNOlOa2w/
1589 static const unsigned char ikmiter[] = {
1590 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1591 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1592 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1593 0x00, 0x00, 0x00, 0x03, 0x01, 0x38, 0xb5, 0xec
1595 static const unsigned char pubiter[] = {
1596 0x04, 0x7d, 0x0c, 0x87, 0xff, 0xd5, 0xd1, 0x45,
1597 0x54, 0xa7, 0x51, 0xdf, 0xa3, 0x99, 0x26, 0xa9,
1598 0xe3, 0x0e, 0x7c, 0x3c, 0x65, 0x62, 0x4f, 0x4b,
1599 0x5f, 0xb3, 0xad, 0x7a, 0xa4, 0xda, 0xc2, 0x4a,
1600 0xd8, 0xf5, 0xbe, 0xd0, 0xe8, 0x6e, 0xb8, 0x84,
1601 0x1c, 0xe4, 0x89, 0x2e, 0x0f, 0xc3, 0x87, 0xbb,
1602 0xdb, 0xfe, 0x16, 0x0d, 0x58, 0x9c, 0x89, 0x2d,
1603 0xd4, 0xb1, 0x46, 0x4a, 0xc3, 0x51, 0xc5, 0x6f,
1607 /* from RFC9180 Appendix A.6.1 */
1608 static const unsigned char ikmp521[] = {
1609 0x7f, 0x06, 0xab, 0x82, 0x15, 0x10, 0x5f, 0xc4,
1610 0x6a, 0xce, 0xeb, 0x2e, 0x3d, 0xc5, 0x02, 0x8b,
1611 0x44, 0x36, 0x4f, 0x96, 0x04, 0x26, 0xeb, 0x0d,
1612 0x8e, 0x40, 0x26, 0xc2, 0xf8, 0xb5, 0xd7, 0xe7,
1613 0xa9, 0x86, 0x68, 0x8f, 0x15, 0x91, 0xab, 0xf5,
1614 0xab, 0x75, 0x3c, 0x35, 0x7a, 0x5d, 0x6f, 0x04,
1615 0x40, 0x41, 0x4b, 0x4e, 0xd4, 0xed, 0xe7, 0x13,
1616 0x17, 0x77, 0x2a, 0xc9, 0x8d, 0x92, 0x39, 0xf7,
1619 static const unsigned char pubp521[] = {
1620 0x04, 0x01, 0x38, 0xb3, 0x85, 0xca, 0x16, 0xbb,
1621 0x0d, 0x5f, 0xa0, 0xc0, 0x66, 0x5f, 0xbb, 0xd7,
1622 0xe6, 0x9e, 0x3e, 0xe2, 0x9f, 0x63, 0x99, 0x1d,
1623 0x3e, 0x9b, 0x5f, 0xa7, 0x40, 0xaa, 0xb8, 0x90,
1624 0x0a, 0xae, 0xed, 0x46, 0xed, 0x73, 0xa4, 0x90,
1625 0x55, 0x75, 0x84, 0x25, 0xa0, 0xce, 0x36, 0x50,
1626 0x7c, 0x54, 0xb2, 0x9c, 0xc5, 0xb8, 0x5a, 0x5c,
1627 0xee, 0x6b, 0xae, 0x0c, 0xf1, 0xc2, 0x1f, 0x27,
1628 0x31, 0xec, 0xe2, 0x01, 0x3d, 0xc3, 0xfb, 0x7c,
1629 0x8d, 0x21, 0x65, 0x4b, 0xb1, 0x61, 0xb4, 0x63,
1630 0x96, 0x2c, 0xa1, 0x9e, 0x8c, 0x65, 0x4f, 0xf2,
1631 0x4c, 0x94, 0xdd, 0x28, 0x98, 0xde, 0x12, 0x05,
1632 0x1f, 0x1e, 0xd0, 0x69, 0x22, 0x37, 0xfb, 0x02,
1633 0xb2, 0xf8, 0xd1, 0xdc, 0x1c, 0x73, 0xe9, 0xb3,
1634 0x66, 0xb5, 0x29, 0xeb, 0x43, 0x6e, 0x98, 0xa9,
1635 0x96, 0xee, 0x52, 0x2a, 0xef, 0x86, 0x3d, 0xd5,
1636 0x73, 0x9d, 0x2f, 0x29, 0xb0
1639 static int test_hpke_random_suites(void)
1641 OSSL_HPKE_SUITE def_suite = OSSL_HPKE_SUITE_DEFAULT;
1642 OSSL_HPKE_SUITE suite = OSSL_HPKE_SUITE_DEFAULT;
1643 OSSL_HPKE_SUITE suite2 = { 0xff01, 0xff02, 0xff03 };
1644 unsigned char enc[200];
1645 size_t enclen = sizeof(enc);
1646 unsigned char ct[500];
1647 size_t ctlen = sizeof(ct);
1649 /* test with NULL/0 inputs */
1650 if (!TEST_false(OSSL_HPKE_get_grease_value(testctx, NULL, NULL, NULL,
1651 NULL, NULL, NULL, 0)))
1654 if (!TEST_false(OSSL_HPKE_get_grease_value(testctx, NULL, &def_suite,
1655 &suite2, enc, &enclen,
1659 enclen = sizeof(enc); /* reset, 'cause get_grease() will have set */
1660 /* test with a should-be-good suite */
1661 if (!TEST_true(OSSL_HPKE_get_grease_value(testctx, NULL, &def_suite,
1662 &suite2, enc, &enclen,
1665 /* no suggested suite */
1666 enclen = sizeof(enc); /* reset, 'cause get_grease() will have set */
1667 if (!TEST_true(OSSL_HPKE_get_grease_value(testctx, NULL, NULL, &suite2,
1668 enc, &enclen, ct, ctlen)))
1670 /* suggested suite with P-521, just to be sure we hit long values */
1671 enclen = sizeof(enc); /* reset, 'cause get_grease() will have set */
1672 suite.kem_id = OSSL_HPKE_KEM_ID_P521;
1673 if (!TEST_true(OSSL_HPKE_get_grease_value(testctx, NULL, &suite, &suite2,
1674 enc, &enclen, ct, ctlen)))
1676 enclen = sizeof(enc);
1677 ctlen = 2; /* too-short cttext (can't fit an aead tag) */
1678 if (!TEST_false(OSSL_HPKE_get_grease_value(testctx, NULL, NULL, &suite2,
1679 enc, &enclen, ct, ctlen)))
1683 enclen = sizeof(enc);
1685 suite.kem_id = OSSL_HPKE_KEM_ID_X25519; /* back to default */
1686 suite.aead_id = 0x1234; /* bad aead */
1687 if (!TEST_false(OSSL_HPKE_get_grease_value(testctx, NULL, &suite, &suite2,
1688 enc, &enclen, ct, ctlen)))
1690 enclen = sizeof(enc);
1691 suite.aead_id = def_suite.aead_id; /* good aead */
1692 suite.kdf_id = 0x3451; /* bad kdf */
1693 if (!TEST_false(OSSL_HPKE_get_grease_value(testctx, NULL, &suite, &suite2,
1694 enc, &enclen, ct, ctlen)))
1696 enclen = sizeof(enc);
1697 suite.kdf_id = def_suite.kdf_id; /* good kdf */
1698 suite.kem_id = 0x4517; /* bad kem */
1699 if (!TEST_false(OSSL_HPKE_get_grease_value(testctx, NULL, &suite, &suite2,
1700 enc, &enclen, ct, ctlen)))
1706 * @brief generate a key pair from initial key material (ikm) and check public
1707 * @param kem_id the KEM to use (RFC9180 code point)
1708 * @ikm is the initial key material buffer
1709 * @ikmlen is the length of ikm
1710 * @pub is the public key buffer
1711 * @publen is the length of the public key
1712 * @return 1 for good, other otherwise
1714 * This calls OSSL_HPKE_keygen specifying only the IKM, then
1715 * compares the key pair values with the already-known values
1718 static int test_hpke_one_ikm_gen(uint16_t kem_id,
1719 const unsigned char *ikm, size_t ikmlen,
1720 const unsigned char *pub, size_t publen)
1722 OSSL_HPKE_SUITE hpke_suite = OSSL_HPKE_SUITE_DEFAULT;
1723 unsigned char lpub[OSSL_HPKE_TSTSIZE];
1724 size_t lpublen = OSSL_HPKE_TSTSIZE;
1725 EVP_PKEY *sk = NULL;
1727 hpke_suite.kem_id = kem_id;
1728 if (!TEST_true(OSSL_HPKE_keygen(hpke_suite, lpub, &lpublen, &sk,
1729 ikm, ikmlen, testctx, NULL)))
1734 if (!TEST_mem_eq(pub, publen, lpub, lpublen))
1740 * @brief test some uses of IKM produce the expected public keys
1742 static int test_hpke_ikms(void)
1746 res = test_hpke_one_ikm_gen(OSSL_HPKE_KEM_ID_X25519,
1747 ikm25519, sizeof(ikm25519),
1748 pub25519, sizeof(pub25519));
1752 res = test_hpke_one_ikm_gen(OSSL_HPKE_KEM_ID_P521,
1753 ikmp521, sizeof(ikmp521),
1754 pubp521, sizeof(pubp521));
1758 res = test_hpke_one_ikm_gen(OSSL_HPKE_KEM_ID_P256,
1759 ikmp256, sizeof(ikmp256),
1760 pubp256, sizeof(pubp256));
1764 res = test_hpke_one_ikm_gen(OSSL_HPKE_KEM_ID_P256,
1765 ikmiter, sizeof(ikmiter),
1766 pubiter, sizeof(pubiter));
1774 * Test that use of a compressed format auth public key works
1775 * We'll do a typical round-trip for auth mode but provide the
1776 * auth public key in compressed form. That should work.
1778 static int test_hpke_compressed(void)
1781 EVP_PKEY *privp = NULL;
1782 unsigned char pub[OSSL_HPKE_TSTSIZE];
1783 size_t publen = sizeof(pub);
1784 EVP_PKEY *authpriv = NULL;
1785 unsigned char authpub[OSSL_HPKE_TSTSIZE];
1786 size_t authpublen = sizeof(authpub);
1787 int hpke_mode = OSSL_HPKE_MODE_AUTH;
1788 OSSL_HPKE_SUITE hpke_suite = OSSL_HPKE_SUITE_DEFAULT;
1789 OSSL_HPKE_CTX *ctx = NULL;
1790 OSSL_HPKE_CTX *rctx = NULL;
1791 unsigned char plain[] = "quick brown fox";
1792 size_t plainlen = sizeof(plain);
1793 unsigned char enc[OSSL_HPKE_TSTSIZE];
1794 size_t enclen = sizeof(enc);
1795 unsigned char cipher[OSSL_HPKE_TSTSIZE];
1796 size_t cipherlen = sizeof(cipher);
1797 unsigned char clear[OSSL_HPKE_TSTSIZE];
1798 size_t clearlen = sizeof(clear);
1800 hpke_suite.kem_id = OSSL_HPKE_KEM_ID_P256;
1802 /* generate auth key pair */
1803 if (!TEST_true(OSSL_HPKE_keygen(hpke_suite, authpub, &authpublen, &authpriv,
1804 NULL, 0, testctx, NULL)))
1806 /* now get the compressed form public key */
1807 if (!TEST_true(EVP_PKEY_set_utf8_string_param(authpriv,
1808 OSSL_PKEY_PARAM_EC_POINT_CONVERSION_FORMAT,
1809 OSSL_PKEY_EC_POINT_CONVERSION_FORMAT_COMPRESSED)))
1811 if (!TEST_true(EVP_PKEY_get_octet_string_param(authpriv,
1812 OSSL_PKEY_PARAM_PUB_KEY,
1818 /* sender side as usual */
1819 if (!TEST_true(OSSL_HPKE_keygen(hpke_suite, pub, &publen, &privp,
1820 NULL, 0, testctx, NULL)))
1822 if (!TEST_ptr(ctx = OSSL_HPKE_CTX_new(hpke_mode, hpke_suite,
1825 if (!TEST_true(OSSL_HPKE_CTX_set1_authpriv(ctx, authpriv)))
1827 if (!TEST_true(OSSL_HPKE_encap(ctx, enc, &enclen, pub, publen, NULL, 0)))
1829 if (!TEST_true(OSSL_HPKE_seal(ctx, cipher, &cipherlen, NULL, 0,
1833 /* receiver side providing compressed form of auth public */
1834 if (!TEST_ptr(rctx = OSSL_HPKE_CTX_new(hpke_mode, hpke_suite,
1837 if (!TEST_true(OSSL_HPKE_CTX_set1_authpub(rctx, authpub, authpublen)))
1839 if (!TEST_true(OSSL_HPKE_decap(rctx, enc, enclen, privp, NULL, 0)))
1841 if (!TEST_true(OSSL_HPKE_open(rctx, clear, &clearlen, NULL, 0,
1842 cipher, cipherlen)))
1847 EVP_PKEY_free(privp);
1848 EVP_PKEY_free(authpriv);
1849 OSSL_HPKE_CTX_free(ctx);
1850 OSSL_HPKE_CTX_free(rctx);
1854 typedef enum OPTION_choice {
1861 const OPTIONS *test_get_options(void)
1863 static const OPTIONS test_options[] = {
1864 OPT_TEST_OPTIONS_DEFAULT_USAGE,
1865 { "v", OPT_VERBOSE, '-', "Enable verbose mode" },
1866 { OPT_HELP_STR, 1, '-', "Run HPKE tests\n" },
1869 return test_options;
1872 int setup_tests(void)
1876 while ((o = opt_next()) != OPT_EOF) {
1879 verbose = 1; /* Print progress dots */
1881 case OPT_TEST_CASES:
1888 if (!test_get_libctx(&testctx, &nullprov, NULL, &deflprov, "default"))
1890 ADD_TEST(x25519kdfsha256_hkdfsha256_aes128gcm_base_test);
1891 ADD_TEST(x25519kdfsha256_hkdfsha256_aes128gcm_psk_test);
1892 ADD_TEST(P256kdfsha256_hkdfsha256_aes128gcm_base_test);
1893 ADD_TEST(export_only_test);
1894 ADD_TEST(test_hpke_export);
1895 ADD_TEST(test_hpke_modes_suites);
1896 ADD_TEST(test_hpke_suite_strs);
1897 ADD_TEST(test_hpke_grease);
1898 ADD_TEST(test_hpke_ikms);
1899 ADD_TEST(test_hpke_random_suites);
1900 ADD_TEST(test_hpke_oddcalls);
1901 ADD_TEST(test_hpke_compressed);
1905 void cleanup_tests(void)
1907 OSSL_PROVIDER_unload(deflprov);
1908 OSSL_PROVIDER_unload(nullprov);
1909 OSSL_LIB_CTX_free(testctx);