• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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