1 /* Copyright (c) 2020, Google Inc.
2 *
3 * Permission to use, copy, modify, and/or distribute this software for any
4 * purpose with or without fee is hereby granted, provided that the above
5 * copyright notice and this permission notice appear in all copies.
6 *
7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
14
15 #include <assert.h>
16 #include <string.h>
17
18 #include <openssl/aead.h>
19 #include <openssl/bytestring.h>
20 #include <openssl/digest.h>
21 #include <openssl/err.h>
22 #include <openssl/evp.h>
23 #include <openssl/hkdf.h>
24 #include <openssl/sha.h>
25
26 #include "../internal.h"
27 #include "internal.h"
28
29
30 // This file implements draft-irtf-cfrg-hpke-07.
31
32 #define KEM_CONTEXT_LEN (2 * X25519_PUBLIC_VALUE_LEN)
33
34 // HPKE KEM scheme IDs.
35 #define HPKE_DHKEM_X25519_HKDF_SHA256 0x0020
36
37 // This is strlen("HPKE") + 3 * sizeof(uint16_t).
38 #define HPKE_SUITE_ID_LEN 10
39
40 #define HPKE_MODE_BASE 0
41 #define HPKE_MODE_PSK 1
42
43 static const char kHpkeRfcId[] = "HPKE-07";
44
add_label_string(CBB * cbb,const char * label)45 static int add_label_string(CBB *cbb, const char *label) {
46 return CBB_add_bytes(cbb, (const uint8_t *)label, strlen(label));
47 }
48
49 // The suite_id for the KEM is defined as concat("KEM", I2OSP(kem_id, 2)). Note
50 // that the suite_id used outside of the KEM also includes the kdf_id and
51 // aead_id.
52 static const uint8_t kX25519SuiteID[] = {
53 'K', 'E', 'M', HPKE_DHKEM_X25519_HKDF_SHA256 >> 8,
54 HPKE_DHKEM_X25519_HKDF_SHA256 & 0x00ff};
55
56 // The suite_id for non-KEM pieces of HPKE is defined as concat("HPKE",
57 // I2OSP(kem_id, 2), I2OSP(kdf_id, 2), I2OSP(aead_id, 2)).
hpke_build_suite_id(uint8_t out[HPKE_SUITE_ID_LEN],uint16_t kdf_id,uint16_t aead_id)58 static int hpke_build_suite_id(uint8_t out[HPKE_SUITE_ID_LEN], uint16_t kdf_id,
59 uint16_t aead_id) {
60 CBB cbb;
61 int ret = CBB_init_fixed(&cbb, out, HPKE_SUITE_ID_LEN) &&
62 add_label_string(&cbb, "HPKE") &&
63 CBB_add_u16(&cbb, HPKE_DHKEM_X25519_HKDF_SHA256) &&
64 CBB_add_u16(&cbb, kdf_id) &&
65 CBB_add_u16(&cbb, aead_id);
66 CBB_cleanup(&cbb);
67 return ret;
68 }
69
hpke_labeled_extract(const EVP_MD * hkdf_md,uint8_t * out_key,size_t * out_len,const uint8_t * salt,size_t salt_len,const uint8_t * suite_id,size_t suite_id_len,const char * label,const uint8_t * ikm,size_t ikm_len)70 static int hpke_labeled_extract(const EVP_MD *hkdf_md, uint8_t *out_key,
71 size_t *out_len, const uint8_t *salt,
72 size_t salt_len, const uint8_t *suite_id,
73 size_t suite_id_len, const char *label,
74 const uint8_t *ikm, size_t ikm_len) {
75 // labeledIKM = concat("RFCXXXX ", suite_id, label, IKM)
76 CBB labeled_ikm;
77 int ok = CBB_init(&labeled_ikm, 0) &&
78 add_label_string(&labeled_ikm, kHpkeRfcId) &&
79 CBB_add_bytes(&labeled_ikm, suite_id, suite_id_len) &&
80 add_label_string(&labeled_ikm, label) &&
81 CBB_add_bytes(&labeled_ikm, ikm, ikm_len) &&
82 HKDF_extract(out_key, out_len, hkdf_md, CBB_data(&labeled_ikm),
83 CBB_len(&labeled_ikm), salt, salt_len);
84 CBB_cleanup(&labeled_ikm);
85 return ok;
86 }
87
hpke_labeled_expand(const EVP_MD * hkdf_md,uint8_t * out_key,size_t out_len,const uint8_t * prk,size_t prk_len,const uint8_t * suite_id,size_t suite_id_len,const char * label,const uint8_t * info,size_t info_len)88 static int hpke_labeled_expand(const EVP_MD *hkdf_md, uint8_t *out_key,
89 size_t out_len, const uint8_t *prk,
90 size_t prk_len, const uint8_t *suite_id,
91 size_t suite_id_len, const char *label,
92 const uint8_t *info, size_t info_len) {
93 // labeledInfo = concat(I2OSP(L, 2), "RFCXXXX ", suite_id, label, info)
94 CBB labeled_info;
95 int ok = CBB_init(&labeled_info, 0) &&
96 CBB_add_u16(&labeled_info, out_len) &&
97 add_label_string(&labeled_info, kHpkeRfcId) &&
98 CBB_add_bytes(&labeled_info, suite_id, suite_id_len) &&
99 add_label_string(&labeled_info, label) &&
100 CBB_add_bytes(&labeled_info, info, info_len) &&
101 HKDF_expand(out_key, out_len, hkdf_md, prk, prk_len,
102 CBB_data(&labeled_info), CBB_len(&labeled_info));
103 CBB_cleanup(&labeled_info);
104 return ok;
105 }
106
hpke_extract_and_expand(const EVP_MD * hkdf_md,uint8_t * out_key,size_t out_len,const uint8_t dh[X25519_PUBLIC_VALUE_LEN],const uint8_t kem_context[KEM_CONTEXT_LEN])107 static int hpke_extract_and_expand(const EVP_MD *hkdf_md, uint8_t *out_key,
108 size_t out_len,
109 const uint8_t dh[X25519_PUBLIC_VALUE_LEN],
110 const uint8_t kem_context[KEM_CONTEXT_LEN]) {
111 uint8_t prk[EVP_MAX_MD_SIZE];
112 size_t prk_len;
113 static const char kEaePrkLabel[] = "eae_prk";
114 if (!hpke_labeled_extract(hkdf_md, prk, &prk_len, NULL, 0, kX25519SuiteID,
115 sizeof(kX25519SuiteID), kEaePrkLabel, dh,
116 X25519_PUBLIC_VALUE_LEN)) {
117 return 0;
118 }
119 static const char kPRKExpandLabel[] = "shared_secret";
120 if (!hpke_labeled_expand(hkdf_md, out_key, out_len, prk, prk_len,
121 kX25519SuiteID, sizeof(kX25519SuiteID),
122 kPRKExpandLabel, kem_context, KEM_CONTEXT_LEN)) {
123 return 0;
124 }
125 return 1;
126 }
127
EVP_HPKE_get_aead(uint16_t aead_id)128 const EVP_AEAD *EVP_HPKE_get_aead(uint16_t aead_id) {
129 switch (aead_id) {
130 case EVP_HPKE_AEAD_AES_GCM_128:
131 return EVP_aead_aes_128_gcm();
132 case EVP_HPKE_AEAD_AES_GCM_256:
133 return EVP_aead_aes_256_gcm();
134 case EVP_HPKE_AEAD_CHACHA20POLY1305:
135 return EVP_aead_chacha20_poly1305();
136 }
137 OPENSSL_PUT_ERROR(EVP, ERR_R_INTERNAL_ERROR);
138 return NULL;
139 }
140
EVP_HPKE_get_hkdf_md(uint16_t kdf_id)141 const EVP_MD *EVP_HPKE_get_hkdf_md(uint16_t kdf_id) {
142 switch (kdf_id) {
143 case EVP_HPKE_HKDF_SHA256:
144 return EVP_sha256();
145 case EVP_HPKE_HKDF_SHA384:
146 return EVP_sha384();
147 case EVP_HPKE_HKDF_SHA512:
148 return EVP_sha512();
149 }
150 OPENSSL_PUT_ERROR(EVP, ERR_R_INTERNAL_ERROR);
151 return NULL;
152 }
153
hpke_key_schedule(EVP_HPKE_CTX * hpke,uint8_t mode,const uint8_t * shared_secret,size_t shared_secret_len,const uint8_t * info,size_t info_len,const uint8_t * psk,size_t psk_len,const uint8_t * psk_id,size_t psk_id_len)154 static int hpke_key_schedule(EVP_HPKE_CTX *hpke, uint8_t mode,
155 const uint8_t *shared_secret,
156 size_t shared_secret_len, const uint8_t *info,
157 size_t info_len, const uint8_t *psk,
158 size_t psk_len, const uint8_t *psk_id,
159 size_t psk_id_len) {
160 // Verify the PSK inputs.
161 switch (mode) {
162 case HPKE_MODE_BASE:
163 // This is an internal error, unreachable from the caller.
164 assert(psk_len == 0 && psk_id_len == 0);
165 break;
166 case HPKE_MODE_PSK:
167 if (psk_len == 0 || psk_id_len == 0) {
168 OPENSSL_PUT_ERROR(EVP, EVP_R_EMPTY_PSK);
169 return 0;
170 }
171 break;
172 default:
173 return 0;
174 }
175
176 // Attempt to get an EVP_AEAD*.
177 const EVP_AEAD *aead = EVP_HPKE_get_aead(hpke->aead_id);
178 if (aead == NULL) {
179 return 0;
180 }
181
182 uint8_t suite_id[HPKE_SUITE_ID_LEN];
183 if (!hpke_build_suite_id(suite_id, hpke->kdf_id, hpke->aead_id)) {
184 return 0;
185 }
186
187 // psk_id_hash = LabeledExtract("", "psk_id_hash", psk_id)
188 static const char kPskIdHashLabel[] = "psk_id_hash";
189 uint8_t psk_id_hash[EVP_MAX_MD_SIZE];
190 size_t psk_id_hash_len;
191 if (!hpke_labeled_extract(hpke->hkdf_md, psk_id_hash, &psk_id_hash_len, NULL,
192 0, suite_id, sizeof(suite_id), kPskIdHashLabel,
193 psk_id, psk_id_len)) {
194 return 0;
195 }
196
197 // info_hash = LabeledExtract("", "info_hash", info)
198 static const char kInfoHashLabel[] = "info_hash";
199 uint8_t info_hash[EVP_MAX_MD_SIZE];
200 size_t info_hash_len;
201 if (!hpke_labeled_extract(hpke->hkdf_md, info_hash, &info_hash_len, NULL, 0,
202 suite_id, sizeof(suite_id), kInfoHashLabel, info,
203 info_len)) {
204 return 0;
205 }
206
207 // key_schedule_context = concat(mode, psk_id_hash, info_hash)
208 uint8_t context[sizeof(uint8_t) + 2 * EVP_MAX_MD_SIZE];
209 size_t context_len;
210 CBB context_cbb;
211 if (!CBB_init_fixed(&context_cbb, context, sizeof(context)) ||
212 !CBB_add_u8(&context_cbb, mode) ||
213 !CBB_add_bytes(&context_cbb, psk_id_hash, psk_id_hash_len) ||
214 !CBB_add_bytes(&context_cbb, info_hash, info_hash_len) ||
215 !CBB_finish(&context_cbb, NULL, &context_len)) {
216 return 0;
217 }
218
219 // secret = LabeledExtract(shared_secret, "secret", psk)
220 static const char kSecretExtractLabel[] = "secret";
221 uint8_t secret[EVP_MAX_MD_SIZE];
222 size_t secret_len;
223 if (!hpke_labeled_extract(hpke->hkdf_md, secret, &secret_len, shared_secret,
224 shared_secret_len, suite_id, sizeof(suite_id),
225 kSecretExtractLabel, psk, psk_len)) {
226 return 0;
227 }
228
229 // key = LabeledExpand(secret, "key", key_schedule_context, Nk)
230 static const char kKeyExpandLabel[] = "key";
231 uint8_t key[EVP_AEAD_MAX_KEY_LENGTH];
232 const size_t kKeyLen = EVP_AEAD_key_length(aead);
233 if (!hpke_labeled_expand(hpke->hkdf_md, key, kKeyLen, secret, secret_len,
234 suite_id, sizeof(suite_id), kKeyExpandLabel, context,
235 context_len)) {
236 return 0;
237 }
238
239 // Initialize the HPKE context's AEAD context, storing a copy of |key|.
240 if (!EVP_AEAD_CTX_init(&hpke->aead_ctx, aead, key, kKeyLen, 0, NULL)) {
241 return 0;
242 }
243
244 // base_nonce = LabeledExpand(secret, "base_nonce", key_schedule_context, Nn)
245 static const char kNonceExpandLabel[] = "base_nonce";
246 if (!hpke_labeled_expand(hpke->hkdf_md, hpke->base_nonce,
247 EVP_AEAD_nonce_length(aead), secret, secret_len,
248 suite_id, sizeof(suite_id), kNonceExpandLabel,
249 context, context_len)) {
250 return 0;
251 }
252
253 // exporter_secret = LabeledExpand(secret, "exp", key_schedule_context, Nh)
254 static const char kExporterSecretExpandLabel[] = "exp";
255 if (!hpke_labeled_expand(hpke->hkdf_md, hpke->exporter_secret,
256 EVP_MD_size(hpke->hkdf_md), secret, secret_len,
257 suite_id, sizeof(suite_id),
258 kExporterSecretExpandLabel, context, context_len)) {
259 return 0;
260 }
261
262 return 1;
263 }
264
265 // The number of bytes written to |out_shared_secret| is the size of the KEM's
266 // KDF (currently we only support SHA256).
hpke_encap(EVP_HPKE_CTX * hpke,uint8_t out_shared_secret[SHA256_DIGEST_LENGTH],const uint8_t public_key_r[X25519_PUBLIC_VALUE_LEN],const uint8_t ephemeral_private[X25519_PRIVATE_KEY_LEN],const uint8_t ephemeral_public[X25519_PUBLIC_VALUE_LEN])267 static int hpke_encap(EVP_HPKE_CTX *hpke,
268 uint8_t out_shared_secret[SHA256_DIGEST_LENGTH],
269 const uint8_t public_key_r[X25519_PUBLIC_VALUE_LEN],
270 const uint8_t ephemeral_private[X25519_PRIVATE_KEY_LEN],
271 const uint8_t ephemeral_public[X25519_PUBLIC_VALUE_LEN]) {
272 uint8_t dh[X25519_PUBLIC_VALUE_LEN];
273 if (!X25519(dh, ephemeral_private, public_key_r)) {
274 OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PEER_KEY);
275 return 0;
276 }
277
278 uint8_t kem_context[KEM_CONTEXT_LEN];
279 OPENSSL_memcpy(kem_context, ephemeral_public, X25519_PUBLIC_VALUE_LEN);
280 OPENSSL_memcpy(kem_context + X25519_PUBLIC_VALUE_LEN, public_key_r,
281 X25519_PUBLIC_VALUE_LEN);
282 if (!hpke_extract_and_expand(EVP_sha256(), out_shared_secret,
283 SHA256_DIGEST_LENGTH, dh, kem_context)) {
284 return 0;
285 }
286 return 1;
287 }
288
hpke_decap(const EVP_HPKE_CTX * hpke,uint8_t out_shared_secret[SHA256_DIGEST_LENGTH],const uint8_t enc[X25519_PUBLIC_VALUE_LEN],const uint8_t public_key_r[X25519_PUBLIC_VALUE_LEN],const uint8_t secret_key_r[X25519_PRIVATE_KEY_LEN])289 static int hpke_decap(const EVP_HPKE_CTX *hpke,
290 uint8_t out_shared_secret[SHA256_DIGEST_LENGTH],
291 const uint8_t enc[X25519_PUBLIC_VALUE_LEN],
292 const uint8_t public_key_r[X25519_PUBLIC_VALUE_LEN],
293 const uint8_t secret_key_r[X25519_PRIVATE_KEY_LEN]) {
294 uint8_t dh[X25519_PUBLIC_VALUE_LEN];
295 if (!X25519(dh, secret_key_r, enc)) {
296 OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PEER_KEY);
297 return 0;
298 }
299 uint8_t kem_context[KEM_CONTEXT_LEN];
300 OPENSSL_memcpy(kem_context, enc, X25519_PUBLIC_VALUE_LEN);
301 OPENSSL_memcpy(kem_context + X25519_PUBLIC_VALUE_LEN, public_key_r,
302 X25519_PUBLIC_VALUE_LEN);
303 if (!hpke_extract_and_expand(EVP_sha256(), out_shared_secret,
304 SHA256_DIGEST_LENGTH, dh, kem_context)) {
305 return 0;
306 }
307 return 1;
308 }
309
EVP_HPKE_CTX_init(EVP_HPKE_CTX * ctx)310 void EVP_HPKE_CTX_init(EVP_HPKE_CTX *ctx) {
311 OPENSSL_memset(ctx, 0, sizeof(EVP_HPKE_CTX));
312 EVP_AEAD_CTX_zero(&ctx->aead_ctx);
313 }
314
EVP_HPKE_CTX_cleanup(EVP_HPKE_CTX * ctx)315 void EVP_HPKE_CTX_cleanup(EVP_HPKE_CTX *ctx) {
316 EVP_AEAD_CTX_cleanup(&ctx->aead_ctx);
317 }
318
EVP_HPKE_CTX_setup_base_s_x25519(EVP_HPKE_CTX * hpke,uint8_t out_enc[X25519_PUBLIC_VALUE_LEN],uint16_t kdf_id,uint16_t aead_id,const uint8_t peer_public_value[X25519_PUBLIC_VALUE_LEN],const uint8_t * info,size_t info_len)319 int EVP_HPKE_CTX_setup_base_s_x25519(
320 EVP_HPKE_CTX *hpke, uint8_t out_enc[X25519_PUBLIC_VALUE_LEN],
321 uint16_t kdf_id, uint16_t aead_id,
322 const uint8_t peer_public_value[X25519_PUBLIC_VALUE_LEN],
323 const uint8_t *info, size_t info_len) {
324 // The GenerateKeyPair() step technically belongs in the KEM's Encap()
325 // function, but we've moved it up a layer to make it easier for tests to
326 // inject an ephemeral keypair.
327 uint8_t ephemeral_private[X25519_PRIVATE_KEY_LEN];
328 X25519_keypair(out_enc, ephemeral_private);
329 return EVP_HPKE_CTX_setup_base_s_x25519_for_test(
330 hpke, kdf_id, aead_id, peer_public_value, info, info_len,
331 ephemeral_private, out_enc);
332 }
333
EVP_HPKE_CTX_setup_base_s_x25519_for_test(EVP_HPKE_CTX * hpke,uint16_t kdf_id,uint16_t aead_id,const uint8_t peer_public_value[X25519_PUBLIC_VALUE_LEN],const uint8_t * info,size_t info_len,const uint8_t ephemeral_private[X25519_PRIVATE_KEY_LEN],const uint8_t ephemeral_public[X25519_PUBLIC_VALUE_LEN])334 int EVP_HPKE_CTX_setup_base_s_x25519_for_test(
335 EVP_HPKE_CTX *hpke, uint16_t kdf_id, uint16_t aead_id,
336 const uint8_t peer_public_value[X25519_PUBLIC_VALUE_LEN],
337 const uint8_t *info, size_t info_len,
338 const uint8_t ephemeral_private[X25519_PRIVATE_KEY_LEN],
339 const uint8_t ephemeral_public[X25519_PUBLIC_VALUE_LEN]) {
340 hpke->is_sender = 1;
341 hpke->kdf_id = kdf_id;
342 hpke->aead_id = aead_id;
343 hpke->hkdf_md = EVP_HPKE_get_hkdf_md(kdf_id);
344 if (hpke->hkdf_md == NULL) {
345 return 0;
346 }
347 uint8_t shared_secret[SHA256_DIGEST_LENGTH];
348 if (!hpke_encap(hpke, shared_secret, peer_public_value, ephemeral_private,
349 ephemeral_public) ||
350 !hpke_key_schedule(hpke, HPKE_MODE_BASE, shared_secret,
351 sizeof(shared_secret), info, info_len, NULL, 0, NULL,
352 0)) {
353 return 0;
354 }
355 return 1;
356 }
357
EVP_HPKE_CTX_setup_base_r_x25519(EVP_HPKE_CTX * hpke,uint16_t kdf_id,uint16_t aead_id,const uint8_t enc[X25519_PUBLIC_VALUE_LEN],const uint8_t public_key[X25519_PUBLIC_VALUE_LEN],const uint8_t private_key[X25519_PRIVATE_KEY_LEN],const uint8_t * info,size_t info_len)358 int EVP_HPKE_CTX_setup_base_r_x25519(
359 EVP_HPKE_CTX *hpke, uint16_t kdf_id, uint16_t aead_id,
360 const uint8_t enc[X25519_PUBLIC_VALUE_LEN],
361 const uint8_t public_key[X25519_PUBLIC_VALUE_LEN],
362 const uint8_t private_key[X25519_PRIVATE_KEY_LEN], const uint8_t *info,
363 size_t info_len) {
364 hpke->is_sender = 0;
365 hpke->kdf_id = kdf_id;
366 hpke->aead_id = aead_id;
367 hpke->hkdf_md = EVP_HPKE_get_hkdf_md(kdf_id);
368 if (hpke->hkdf_md == NULL) {
369 return 0;
370 }
371 uint8_t shared_secret[SHA256_DIGEST_LENGTH];
372 if (!hpke_decap(hpke, shared_secret, enc, public_key, private_key) ||
373 !hpke_key_schedule(hpke, HPKE_MODE_BASE, shared_secret,
374 sizeof(shared_secret), info, info_len, NULL, 0, NULL,
375 0)) {
376 return 0;
377 }
378 return 1;
379 }
380
EVP_HPKE_CTX_setup_psk_s_x25519(EVP_HPKE_CTX * hpke,uint8_t out_enc[X25519_PUBLIC_VALUE_LEN],uint16_t kdf_id,uint16_t aead_id,const uint8_t peer_public_value[X25519_PUBLIC_VALUE_LEN],const uint8_t * info,size_t info_len,const uint8_t * psk,size_t psk_len,const uint8_t * psk_id,size_t psk_id_len)381 int EVP_HPKE_CTX_setup_psk_s_x25519(
382 EVP_HPKE_CTX *hpke, uint8_t out_enc[X25519_PUBLIC_VALUE_LEN],
383 uint16_t kdf_id, uint16_t aead_id,
384 const uint8_t peer_public_value[X25519_PUBLIC_VALUE_LEN],
385 const uint8_t *info, size_t info_len, const uint8_t *psk, size_t psk_len,
386 const uint8_t *psk_id, size_t psk_id_len) {
387 // The GenerateKeyPair() step technically belongs in the KEM's Encap()
388 // function, but we've moved it up a layer to make it easier for tests to
389 // inject an ephemeral keypair.
390 uint8_t ephemeral_private[X25519_PRIVATE_KEY_LEN];
391 X25519_keypair(out_enc, ephemeral_private);
392 return EVP_HPKE_CTX_setup_psk_s_x25519_for_test(
393 hpke, kdf_id, aead_id, peer_public_value, info, info_len, psk, psk_len,
394 psk_id, psk_id_len, ephemeral_private, out_enc);
395 }
396
EVP_HPKE_CTX_setup_psk_s_x25519_for_test(EVP_HPKE_CTX * hpke,uint16_t kdf_id,uint16_t aead_id,const uint8_t peer_public_value[X25519_PUBLIC_VALUE_LEN],const uint8_t * info,size_t info_len,const uint8_t * psk,size_t psk_len,const uint8_t * psk_id,size_t psk_id_len,const uint8_t ephemeral_private[X25519_PRIVATE_KEY_LEN],const uint8_t ephemeral_public[X25519_PUBLIC_VALUE_LEN])397 int EVP_HPKE_CTX_setup_psk_s_x25519_for_test(
398 EVP_HPKE_CTX *hpke, uint16_t kdf_id, uint16_t aead_id,
399 const uint8_t peer_public_value[X25519_PUBLIC_VALUE_LEN],
400 const uint8_t *info, size_t info_len, const uint8_t *psk, size_t psk_len,
401 const uint8_t *psk_id, size_t psk_id_len,
402 const uint8_t ephemeral_private[X25519_PRIVATE_KEY_LEN],
403 const uint8_t ephemeral_public[X25519_PUBLIC_VALUE_LEN]) {
404 hpke->is_sender = 1;
405 hpke->kdf_id = kdf_id;
406 hpke->aead_id = aead_id;
407 hpke->hkdf_md = EVP_HPKE_get_hkdf_md(kdf_id);
408 if (hpke->hkdf_md == NULL) {
409 return 0;
410 }
411 uint8_t shared_secret[SHA256_DIGEST_LENGTH];
412 if (!hpke_encap(hpke, shared_secret, peer_public_value, ephemeral_private,
413 ephemeral_public) ||
414 !hpke_key_schedule(hpke, HPKE_MODE_PSK, shared_secret,
415 sizeof(shared_secret), info, info_len, psk, psk_len,
416 psk_id, psk_id_len)) {
417 return 0;
418 }
419 return 1;
420 }
421
EVP_HPKE_CTX_setup_psk_r_x25519(EVP_HPKE_CTX * hpke,uint16_t kdf_id,uint16_t aead_id,const uint8_t enc[X25519_PUBLIC_VALUE_LEN],const uint8_t public_key[X25519_PUBLIC_VALUE_LEN],const uint8_t private_key[X25519_PRIVATE_KEY_LEN],const uint8_t * info,size_t info_len,const uint8_t * psk,size_t psk_len,const uint8_t * psk_id,size_t psk_id_len)422 int EVP_HPKE_CTX_setup_psk_r_x25519(
423 EVP_HPKE_CTX *hpke, uint16_t kdf_id, uint16_t aead_id,
424 const uint8_t enc[X25519_PUBLIC_VALUE_LEN],
425 const uint8_t public_key[X25519_PUBLIC_VALUE_LEN],
426 const uint8_t private_key[X25519_PRIVATE_KEY_LEN], const uint8_t *info,
427 size_t info_len, const uint8_t *psk, size_t psk_len, const uint8_t *psk_id,
428 size_t psk_id_len) {
429 hpke->is_sender = 0;
430 hpke->kdf_id = kdf_id;
431 hpke->aead_id = aead_id;
432 hpke->hkdf_md = EVP_HPKE_get_hkdf_md(kdf_id);
433 if (hpke->hkdf_md == NULL) {
434 return 0;
435 }
436 uint8_t shared_secret[SHA256_DIGEST_LENGTH];
437 if (!hpke_decap(hpke, shared_secret, enc, public_key, private_key) ||
438 !hpke_key_schedule(hpke, HPKE_MODE_PSK, shared_secret,
439 sizeof(shared_secret), info, info_len, psk, psk_len,
440 psk_id, psk_id_len)) {
441 return 0;
442 }
443 return 1;
444 }
445
hpke_nonce(const EVP_HPKE_CTX * hpke,uint8_t * out_nonce,size_t nonce_len)446 static void hpke_nonce(const EVP_HPKE_CTX *hpke, uint8_t *out_nonce,
447 size_t nonce_len) {
448 assert(nonce_len >= 8);
449
450 // Write padded big-endian bytes of |hpke->seq| to |out_nonce|.
451 OPENSSL_memset(out_nonce, 0, nonce_len);
452 uint64_t seq_copy = hpke->seq;
453 for (size_t i = 0; i < 8; i++) {
454 out_nonce[nonce_len - i - 1] = seq_copy & 0xff;
455 seq_copy >>= 8;
456 }
457
458 // XOR the encoded sequence with the |hpke->base_nonce|.
459 for (size_t i = 0; i < nonce_len; i++) {
460 out_nonce[i] ^= hpke->base_nonce[i];
461 }
462 }
463
EVP_HPKE_CTX_max_overhead(const EVP_HPKE_CTX * hpke)464 size_t EVP_HPKE_CTX_max_overhead(const EVP_HPKE_CTX *hpke) {
465 assert(hpke->is_sender);
466 return EVP_AEAD_max_overhead(hpke->aead_ctx.aead);
467 }
468
EVP_HPKE_CTX_open(EVP_HPKE_CTX * hpke,uint8_t * out,size_t * out_len,size_t max_out_len,const uint8_t * in,size_t in_len,const uint8_t * ad,size_t ad_len)469 int EVP_HPKE_CTX_open(EVP_HPKE_CTX *hpke, uint8_t *out, size_t *out_len,
470 size_t max_out_len, const uint8_t *in, size_t in_len,
471 const uint8_t *ad, size_t ad_len) {
472 if (hpke->is_sender) {
473 OPENSSL_PUT_ERROR(EVP, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
474 return 0;
475 }
476 if (hpke->seq == UINT64_MAX) {
477 OPENSSL_PUT_ERROR(EVP, ERR_R_OVERFLOW);
478 return 0;
479 }
480
481 uint8_t nonce[EVP_AEAD_MAX_NONCE_LENGTH];
482 const size_t nonce_len = EVP_AEAD_nonce_length(hpke->aead_ctx.aead);
483 hpke_nonce(hpke, nonce, nonce_len);
484
485 if (!EVP_AEAD_CTX_open(&hpke->aead_ctx, out, out_len, max_out_len, nonce,
486 nonce_len, in, in_len, ad, ad_len)) {
487 return 0;
488 }
489 hpke->seq++;
490 return 1;
491 }
492
EVP_HPKE_CTX_seal(EVP_HPKE_CTX * hpke,uint8_t * out,size_t * out_len,size_t max_out_len,const uint8_t * in,size_t in_len,const uint8_t * ad,size_t ad_len)493 int EVP_HPKE_CTX_seal(EVP_HPKE_CTX *hpke, uint8_t *out, size_t *out_len,
494 size_t max_out_len, const uint8_t *in, size_t in_len,
495 const uint8_t *ad, size_t ad_len) {
496 if (!hpke->is_sender) {
497 OPENSSL_PUT_ERROR(EVP, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
498 return 0;
499 }
500 if (hpke->seq == UINT64_MAX) {
501 OPENSSL_PUT_ERROR(EVP, ERR_R_OVERFLOW);
502 return 0;
503 }
504
505 uint8_t nonce[EVP_AEAD_MAX_NONCE_LENGTH];
506 const size_t nonce_len = EVP_AEAD_nonce_length(hpke->aead_ctx.aead);
507 hpke_nonce(hpke, nonce, nonce_len);
508
509 if (!EVP_AEAD_CTX_seal(&hpke->aead_ctx, out, out_len, max_out_len, nonce,
510 nonce_len, in, in_len, ad, ad_len)) {
511 return 0;
512 }
513 hpke->seq++;
514 return 1;
515 }
516
EVP_HPKE_CTX_export(const EVP_HPKE_CTX * hpke,uint8_t * out,size_t secret_len,const uint8_t * context,size_t context_len)517 int EVP_HPKE_CTX_export(const EVP_HPKE_CTX *hpke, uint8_t *out,
518 size_t secret_len, const uint8_t *context,
519 size_t context_len) {
520 uint8_t suite_id[HPKE_SUITE_ID_LEN];
521 if (!hpke_build_suite_id(suite_id, hpke->kdf_id, hpke->aead_id)) {
522 return 0;
523 }
524 static const char kExportExpandLabel[] = "sec";
525 if (!hpke_labeled_expand(hpke->hkdf_md, out, secret_len,
526 hpke->exporter_secret, EVP_MD_size(hpke->hkdf_md),
527 suite_id, sizeof(suite_id), kExportExpandLabel,
528 context, context_len)) {
529 return 0;
530 }
531 return 1;
532 }
533