wireguard: add processing of received cookie messages
[vpp.git] / src / plugins / wireguard / wireguard_noise.c
1 /*
2  * Copyright (c) 2020 Doc.ai and/or its affiliates.
3  * Copyright (c) 2015-2020 Jason A. Donenfeld <Jason@zx2c4.com>.
4  * Copyright (c) 2019-2020 Matt Dunwoodie <ncon@noconroy.net>.
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at:
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 #include <openssl/hmac.h>
19 #include <wireguard/wireguard.h>
20 #include <wireguard/wireguard_chachapoly.h>
21
22 /* This implements Noise_IKpsk2:
23  *
24  * <- s
25  * ******
26  * -> e, es, s, ss, {t}
27  * <- e, ee, se, psk, {}
28  */
29
30 noise_local_t *noise_local_pool;
31
32 /* Private functions */
33 static noise_keypair_t *noise_remote_keypair_allocate (noise_remote_t *);
34 static void noise_remote_keypair_free (vlib_main_t * vm, noise_remote_t *,
35                                        noise_keypair_t **);
36 static uint32_t noise_remote_handshake_index_get (noise_remote_t *);
37 static void noise_remote_handshake_index_drop (noise_remote_t *);
38
39 static uint64_t noise_counter_send (noise_counter_t *);
40 bool noise_counter_recv (noise_counter_t *, uint64_t);
41
42 static void noise_kdf (uint8_t *, uint8_t *, uint8_t *, const uint8_t *,
43                        size_t, size_t, size_t, size_t,
44                        const uint8_t[NOISE_HASH_LEN]);
45 static bool noise_mix_dh (uint8_t[NOISE_HASH_LEN],
46                           uint8_t[NOISE_SYMMETRIC_KEY_LEN],
47                           const uint8_t[NOISE_PUBLIC_KEY_LEN],
48                           const uint8_t[NOISE_PUBLIC_KEY_LEN]);
49 static bool noise_mix_ss (uint8_t ck[NOISE_HASH_LEN],
50                           uint8_t key[NOISE_SYMMETRIC_KEY_LEN],
51                           const uint8_t ss[NOISE_PUBLIC_KEY_LEN]);
52 static void noise_mix_hash (uint8_t[NOISE_HASH_LEN], const uint8_t *, size_t);
53 static void noise_mix_psk (uint8_t[NOISE_HASH_LEN],
54                            uint8_t[NOISE_HASH_LEN],
55                            uint8_t[NOISE_SYMMETRIC_KEY_LEN],
56                            const uint8_t[NOISE_SYMMETRIC_KEY_LEN]);
57 static void noise_param_init (uint8_t[NOISE_HASH_LEN],
58                               uint8_t[NOISE_HASH_LEN],
59                               const uint8_t[NOISE_PUBLIC_KEY_LEN]);
60
61 static void noise_msg_encrypt (vlib_main_t * vm, uint8_t *, uint8_t *, size_t,
62                                uint32_t key_idx, uint8_t[NOISE_HASH_LEN]);
63 static bool noise_msg_decrypt (vlib_main_t * vm, uint8_t *, uint8_t *, size_t,
64                                uint32_t key_idx, uint8_t[NOISE_HASH_LEN]);
65 static void noise_msg_ephemeral (uint8_t[NOISE_HASH_LEN],
66                                  uint8_t[NOISE_HASH_LEN],
67                                  const uint8_t src[NOISE_PUBLIC_KEY_LEN]);
68
69 static void noise_tai64n_now (uint8_t[NOISE_TIMESTAMP_LEN]);
70
71 /* Set/Get noise parameters */
72 void
73 noise_local_init (noise_local_t * l, struct noise_upcall *upcall)
74 {
75   clib_memset (l, 0, sizeof (*l));
76   l->l_upcall = *upcall;
77 }
78
79 bool
80 noise_local_set_private (noise_local_t * l,
81                          const uint8_t private[NOISE_PUBLIC_KEY_LEN])
82 {
83   clib_memcpy (l->l_private, private, NOISE_PUBLIC_KEY_LEN);
84
85   return curve25519_gen_public (l->l_public, private);
86 }
87
88 void
89 noise_remote_init (noise_remote_t * r, uint32_t peer_pool_idx,
90                    const uint8_t public[NOISE_PUBLIC_KEY_LEN],
91                    u32 noise_local_idx)
92 {
93   clib_memset (r, 0, sizeof (*r));
94   clib_memcpy (r->r_public, public, NOISE_PUBLIC_KEY_LEN);
95   clib_rwlock_init (&r->r_keypair_lock);
96   r->r_peer_idx = peer_pool_idx;
97   r->r_local_idx = noise_local_idx;
98   r->r_handshake.hs_state = HS_ZEROED;
99
100   noise_remote_precompute (r);
101 }
102
103 void
104 noise_remote_precompute (noise_remote_t * r)
105 {
106   noise_local_t *l = noise_local_get (r->r_local_idx);
107
108   if (!curve25519_gen_shared (r->r_ss, l->l_private, r->r_public))
109     clib_memset (r->r_ss, 0, NOISE_PUBLIC_KEY_LEN);
110
111   noise_remote_handshake_index_drop (r);
112   wg_secure_zero_memory (&r->r_handshake, sizeof (r->r_handshake));
113 }
114
115 /* Handshake functions */
116 bool
117 noise_create_initiation (vlib_main_t * vm, noise_remote_t * r,
118                          uint32_t * s_idx, uint8_t ue[NOISE_PUBLIC_KEY_LEN],
119                          uint8_t es[NOISE_PUBLIC_KEY_LEN + NOISE_AUTHTAG_LEN],
120                          uint8_t ets[NOISE_TIMESTAMP_LEN + NOISE_AUTHTAG_LEN])
121 {
122   noise_handshake_t *hs = &r->r_handshake;
123   noise_local_t *l = noise_local_get (r->r_local_idx);
124   uint8_t _key[NOISE_SYMMETRIC_KEY_LEN] = { 0 };
125   uint32_t key_idx;
126   uint8_t *key;
127   int ret = false;
128
129   key_idx =
130     vnet_crypto_key_add (vm, VNET_CRYPTO_ALG_CHACHA20_POLY1305, _key,
131                          NOISE_SYMMETRIC_KEY_LEN);
132   key = vnet_crypto_get_key (key_idx)->data;
133
134   noise_param_init (hs->hs_ck, hs->hs_hash, r->r_public);
135
136   /* e */
137   curve25519_gen_secret (hs->hs_e);
138   if (!curve25519_gen_public (ue, hs->hs_e))
139     goto error;
140   noise_msg_ephemeral (hs->hs_ck, hs->hs_hash, ue);
141
142   /* es */
143   if (!noise_mix_dh (hs->hs_ck, key, hs->hs_e, r->r_public))
144     goto error;
145
146   /* s */
147   noise_msg_encrypt (vm, es, l->l_public, NOISE_PUBLIC_KEY_LEN, key_idx,
148                      hs->hs_hash);
149
150   /* ss */
151   if (!noise_mix_ss (hs->hs_ck, key, r->r_ss))
152     goto error;
153
154   /* {t} */
155   noise_tai64n_now (ets);
156   noise_msg_encrypt (vm, ets, ets, NOISE_TIMESTAMP_LEN, key_idx, hs->hs_hash);
157   noise_remote_handshake_index_drop (r);
158   hs->hs_state = CREATED_INITIATION;
159   hs->hs_local_index = noise_remote_handshake_index_get (r);
160   *s_idx = hs->hs_local_index;
161   ret = true;
162 error:
163   wg_secure_zero_memory (key, NOISE_SYMMETRIC_KEY_LEN);
164   vnet_crypto_key_del (vm, key_idx);
165   return ret;
166 }
167
168 bool
169 noise_consume_initiation (vlib_main_t * vm, noise_local_t * l,
170                           noise_remote_t ** rp, uint32_t s_idx,
171                           uint8_t ue[NOISE_PUBLIC_KEY_LEN],
172                           uint8_t es[NOISE_PUBLIC_KEY_LEN +
173                                      NOISE_AUTHTAG_LEN],
174                           uint8_t ets[NOISE_TIMESTAMP_LEN +
175                                       NOISE_AUTHTAG_LEN])
176 {
177   noise_remote_t *r;
178   noise_handshake_t hs;
179   uint8_t _key[NOISE_SYMMETRIC_KEY_LEN] = { 0 };
180   uint8_t r_public[NOISE_PUBLIC_KEY_LEN] = { 0 };
181   uint8_t timestamp[NOISE_TIMESTAMP_LEN] = { 0 };
182   u32 key_idx;
183   uint8_t *key;
184   int ret = false;
185
186   key_idx =
187     vnet_crypto_key_add (vm, VNET_CRYPTO_ALG_CHACHA20_POLY1305, _key,
188                          NOISE_SYMMETRIC_KEY_LEN);
189   key = vnet_crypto_get_key (key_idx)->data;
190
191   noise_param_init (hs.hs_ck, hs.hs_hash, l->l_public);
192
193   /* e */
194   noise_msg_ephemeral (hs.hs_ck, hs.hs_hash, ue);
195
196   /* es */
197   if (!noise_mix_dh (hs.hs_ck, key, l->l_private, ue))
198     goto error;
199
200   /* s */
201
202   if (!noise_msg_decrypt (vm, r_public, es,
203                           NOISE_PUBLIC_KEY_LEN + NOISE_AUTHTAG_LEN, key_idx,
204                           hs.hs_hash))
205     goto error;
206
207   /* Lookup the remote we received from */
208   if ((r = l->l_upcall.u_remote_get (r_public)) == NULL)
209     goto error;
210
211   /* ss */
212   if (!noise_mix_ss (hs.hs_ck, key, r->r_ss))
213     goto error;
214
215   /* {t} */
216   if (!noise_msg_decrypt (vm, timestamp, ets,
217                           NOISE_TIMESTAMP_LEN + NOISE_AUTHTAG_LEN, key_idx,
218                           hs.hs_hash))
219     goto error;
220   ;
221
222   hs.hs_state = CONSUMED_INITIATION;
223   hs.hs_local_index = 0;
224   hs.hs_remote_index = s_idx;
225   clib_memcpy (hs.hs_e, ue, NOISE_PUBLIC_KEY_LEN);
226
227   /* Replay */
228   if (clib_memcmp (timestamp, r->r_timestamp, NOISE_TIMESTAMP_LEN) > 0)
229     clib_memcpy (r->r_timestamp, timestamp, NOISE_TIMESTAMP_LEN);
230   else
231     goto error;
232
233   /* Flood attack */
234   if (wg_birthdate_has_expired (r->r_last_init, REJECT_INTERVAL))
235     r->r_last_init = vlib_time_now (vm);
236   else
237     goto error;
238
239   /* Ok, we're happy to accept this initiation now */
240   noise_remote_handshake_index_drop (r);
241   r->r_handshake = hs;
242   *rp = r;
243   ret = true;
244
245 error:
246   wg_secure_zero_memory (key, NOISE_SYMMETRIC_KEY_LEN);
247   vnet_crypto_key_del (vm, key_idx);
248   wg_secure_zero_memory (&hs, sizeof (hs));
249   return ret;
250 }
251
252 bool
253 noise_create_response (vlib_main_t * vm, noise_remote_t * r, uint32_t * s_idx,
254                        uint32_t * r_idx, uint8_t ue[NOISE_PUBLIC_KEY_LEN],
255                        uint8_t en[0 + NOISE_AUTHTAG_LEN])
256 {
257   noise_handshake_t *hs = &r->r_handshake;
258   uint8_t _key[NOISE_SYMMETRIC_KEY_LEN] = { 0 };
259   uint8_t e[NOISE_PUBLIC_KEY_LEN] = { 0 };
260   uint32_t key_idx;
261   uint8_t *key;
262   int ret = false;
263
264   key_idx =
265     vnet_crypto_key_add (vm, VNET_CRYPTO_ALG_CHACHA20_POLY1305, _key,
266                          NOISE_SYMMETRIC_KEY_LEN);
267   key = vnet_crypto_get_key (key_idx)->data;
268
269   if (hs->hs_state != CONSUMED_INITIATION)
270     goto error;
271
272   /* e */
273   curve25519_gen_secret (e);
274   if (!curve25519_gen_public (ue, e))
275     goto error;
276   noise_msg_ephemeral (hs->hs_ck, hs->hs_hash, ue);
277
278   /* ee */
279   if (!noise_mix_dh (hs->hs_ck, NULL, e, hs->hs_e))
280     goto error;
281
282   /* se */
283   if (!noise_mix_dh (hs->hs_ck, NULL, e, r->r_public))
284     goto error;
285
286   /* psk */
287   noise_mix_psk (hs->hs_ck, hs->hs_hash, key, r->r_psk);
288
289   /* {} */
290   noise_msg_encrypt (vm, en, NULL, 0, key_idx, hs->hs_hash);
291
292
293   hs->hs_state = CREATED_RESPONSE;
294   hs->hs_local_index = noise_remote_handshake_index_get (r);
295   *r_idx = hs->hs_remote_index;
296   *s_idx = hs->hs_local_index;
297   ret = true;
298 error:
299   wg_secure_zero_memory (key, NOISE_SYMMETRIC_KEY_LEN);
300   vnet_crypto_key_del (vm, key_idx);
301   wg_secure_zero_memory (e, NOISE_PUBLIC_KEY_LEN);
302   return ret;
303 }
304
305 bool
306 noise_consume_response (vlib_main_t * vm, noise_remote_t * r, uint32_t s_idx,
307                         uint32_t r_idx, uint8_t ue[NOISE_PUBLIC_KEY_LEN],
308                         uint8_t en[0 + NOISE_AUTHTAG_LEN])
309 {
310   noise_local_t *l = noise_local_get (r->r_local_idx);
311   noise_handshake_t hs;
312   uint8_t _key[NOISE_SYMMETRIC_KEY_LEN] = { 0 };
313   uint8_t preshared_key[NOISE_PUBLIC_KEY_LEN] = { 0 };
314   uint32_t key_idx;
315   uint8_t *key;
316   int ret = false;
317
318   key_idx =
319     vnet_crypto_key_add (vm, VNET_CRYPTO_ALG_CHACHA20_POLY1305, _key,
320                          NOISE_SYMMETRIC_KEY_LEN);
321   key = vnet_crypto_get_key (key_idx)->data;
322
323   hs = r->r_handshake;
324   clib_memcpy (preshared_key, r->r_psk, NOISE_SYMMETRIC_KEY_LEN);
325
326   if (hs.hs_state != CREATED_INITIATION || hs.hs_local_index != r_idx)
327     goto error;
328
329   /* e */
330   noise_msg_ephemeral (hs.hs_ck, hs.hs_hash, ue);
331
332   /* ee */
333   if (!noise_mix_dh (hs.hs_ck, NULL, hs.hs_e, ue))
334     goto error;
335
336   /* se */
337   if (!noise_mix_dh (hs.hs_ck, NULL, l->l_private, ue))
338     goto error;
339
340   /* psk */
341   noise_mix_psk (hs.hs_ck, hs.hs_hash, key, preshared_key);
342
343   /* {} */
344
345   if (!noise_msg_decrypt
346       (vm, NULL, en, 0 + NOISE_AUTHTAG_LEN, key_idx, hs.hs_hash))
347     goto error;
348
349
350   hs.hs_remote_index = s_idx;
351
352   if (r->r_handshake.hs_state == hs.hs_state &&
353       r->r_handshake.hs_local_index == hs.hs_local_index)
354     {
355       r->r_handshake = hs;
356       r->r_handshake.hs_state = CONSUMED_RESPONSE;
357       ret = true;
358     }
359 error:
360   wg_secure_zero_memory (&hs, sizeof (hs));
361   wg_secure_zero_memory (key, NOISE_SYMMETRIC_KEY_LEN);
362   vnet_crypto_key_del (vm, key_idx);
363   return ret;
364 }
365
366 bool
367 noise_remote_begin_session (vlib_main_t * vm, noise_remote_t * r)
368 {
369   noise_handshake_t *hs = &r->r_handshake;
370   noise_keypair_t kp, *next, *current, *previous;
371
372   uint8_t key_send[NOISE_SYMMETRIC_KEY_LEN];
373   uint8_t key_recv[NOISE_SYMMETRIC_KEY_LEN];
374
375   /* We now derive the keypair from the handshake */
376   if (hs->hs_state == CONSUMED_RESPONSE)
377     {
378       kp.kp_is_initiator = 1;
379       noise_kdf (key_send, key_recv, NULL, NULL,
380                  NOISE_SYMMETRIC_KEY_LEN, NOISE_SYMMETRIC_KEY_LEN, 0, 0,
381                  hs->hs_ck);
382     }
383   else if (hs->hs_state == CREATED_RESPONSE)
384     {
385       kp.kp_is_initiator = 0;
386       noise_kdf (key_recv, key_send, NULL, NULL,
387                  NOISE_SYMMETRIC_KEY_LEN, NOISE_SYMMETRIC_KEY_LEN, 0, 0,
388                  hs->hs_ck);
389     }
390   else
391     {
392       return false;
393     }
394
395   kp.kp_valid = 1;
396   kp.kp_send_index = vnet_crypto_key_add (vm,
397                                           VNET_CRYPTO_ALG_CHACHA20_POLY1305,
398                                           key_send, NOISE_SYMMETRIC_KEY_LEN);
399   kp.kp_recv_index = vnet_crypto_key_add (vm,
400                                           VNET_CRYPTO_ALG_CHACHA20_POLY1305,
401                                           key_recv, NOISE_SYMMETRIC_KEY_LEN);
402   kp.kp_local_index = hs->hs_local_index;
403   kp.kp_remote_index = hs->hs_remote_index;
404   kp.kp_birthdate = vlib_time_now (vm);
405   clib_memset (&kp.kp_ctr, 0, sizeof (kp.kp_ctr));
406
407   /* Now we need to add_new_keypair */
408   clib_rwlock_writer_lock (&r->r_keypair_lock);
409   /* Activate barrier to synchronization keys between threads */
410   vlib_worker_thread_barrier_sync (vm);
411   next = r->r_next;
412   current = r->r_current;
413   previous = r->r_previous;
414
415   if (kp.kp_is_initiator)
416     {
417       if (next != NULL)
418         {
419           r->r_next = NULL;
420           r->r_previous = next;
421           noise_remote_keypair_free (vm, r, &current);
422         }
423       else
424         {
425           r->r_previous = current;
426         }
427
428       noise_remote_keypair_free (vm, r, &previous);
429
430       r->r_current = noise_remote_keypair_allocate (r);
431       *r->r_current = kp;
432     }
433   else
434     {
435       noise_remote_keypair_free (vm, r, &next);
436       r->r_previous = NULL;
437       noise_remote_keypair_free (vm, r, &previous);
438
439       r->r_next = noise_remote_keypair_allocate (r);
440       *r->r_next = kp;
441     }
442   vlib_worker_thread_barrier_release (vm);
443   clib_rwlock_writer_unlock (&r->r_keypair_lock);
444
445   wg_secure_zero_memory (&r->r_handshake, sizeof (r->r_handshake));
446
447   wg_secure_zero_memory (&kp, sizeof (kp));
448   return true;
449 }
450
451 void
452 noise_remote_clear (vlib_main_t * vm, noise_remote_t * r)
453 {
454   noise_remote_handshake_index_drop (r);
455   wg_secure_zero_memory (&r->r_handshake, sizeof (r->r_handshake));
456
457   clib_rwlock_writer_lock (&r->r_keypair_lock);
458   noise_remote_keypair_free (vm, r, &r->r_next);
459   noise_remote_keypair_free (vm, r, &r->r_current);
460   noise_remote_keypair_free (vm, r, &r->r_previous);
461   r->r_next = NULL;
462   r->r_current = NULL;
463   r->r_previous = NULL;
464   clib_rwlock_writer_unlock (&r->r_keypair_lock);
465 }
466
467 void
468 noise_remote_expire_current (noise_remote_t * r)
469 {
470   clib_rwlock_writer_lock (&r->r_keypair_lock);
471   if (r->r_next != NULL)
472     r->r_next->kp_valid = 0;
473   if (r->r_current != NULL)
474     r->r_current->kp_valid = 0;
475   clib_rwlock_writer_unlock (&r->r_keypair_lock);
476 }
477
478 bool
479 noise_remote_ready (noise_remote_t * r)
480 {
481   noise_keypair_t *kp;
482   int ret;
483
484   clib_rwlock_reader_lock (&r->r_keypair_lock);
485   if ((kp = r->r_current) == NULL ||
486       !kp->kp_valid ||
487       wg_birthdate_has_expired (kp->kp_birthdate, REJECT_AFTER_TIME) ||
488       kp->kp_ctr.c_recv >= REJECT_AFTER_MESSAGES ||
489       kp->kp_ctr.c_send >= REJECT_AFTER_MESSAGES)
490     ret = false;
491   else
492     ret = true;
493   clib_rwlock_reader_unlock (&r->r_keypair_lock);
494   return ret;
495 }
496
497 enum noise_state_crypt
498 noise_remote_encrypt (vlib_main_t * vm, noise_remote_t * r, uint32_t * r_idx,
499                       uint64_t * nonce, uint8_t * src, size_t srclen,
500                       uint8_t * dst)
501 {
502   noise_keypair_t *kp;
503   enum noise_state_crypt ret = SC_FAILED;
504
505   if ((kp = r->r_current) == NULL)
506     goto error;
507
508   /* We confirm that our values are within our tolerances. We want:
509    *  - a valid keypair
510    *  - our keypair to be less than REJECT_AFTER_TIME seconds old
511    *  - our receive counter to be less than REJECT_AFTER_MESSAGES
512    *  - our send counter to be less than REJECT_AFTER_MESSAGES
513    */
514   if (!kp->kp_valid ||
515       wg_birthdate_has_expired (kp->kp_birthdate, REJECT_AFTER_TIME) ||
516       kp->kp_ctr.c_recv >= REJECT_AFTER_MESSAGES ||
517       ((*nonce = noise_counter_send (&kp->kp_ctr)) > REJECT_AFTER_MESSAGES))
518     goto error;
519
520   /* We encrypt into the same buffer, so the caller must ensure that buf
521    * has NOISE_AUTHTAG_LEN bytes to store the MAC. The nonce and index
522    * are passed back out to the caller through the provided data pointer. */
523   *r_idx = kp->kp_remote_index;
524
525   wg_chacha20poly1305_calc (vm, src, srclen, dst, NULL, 0, *nonce,
526                             VNET_CRYPTO_OP_CHACHA20_POLY1305_ENC,
527                             kp->kp_send_index);
528
529   /* If our values are still within tolerances, but we are approaching
530    * the tolerances, we notify the caller with ESTALE that they should
531    * establish a new keypair. The current keypair can continue to be used
532    * until the tolerances are hit. We notify if:
533    *  - our send counter is valid and not less than REKEY_AFTER_MESSAGES
534    *  - we're the initiator and our keypair is older than
535    *    REKEY_AFTER_TIME seconds */
536   ret = SC_KEEP_KEY_FRESH;
537   if ((kp->kp_valid && *nonce >= REKEY_AFTER_MESSAGES) ||
538       (kp->kp_is_initiator &&
539        wg_birthdate_has_expired (kp->kp_birthdate, REKEY_AFTER_TIME)))
540     goto error;
541
542   ret = SC_OK;
543 error:
544   return ret;
545 }
546
547 /* Private functions - these should not be called outside this file under any
548  * circumstances. */
549 static noise_keypair_t *
550 noise_remote_keypair_allocate (noise_remote_t * r)
551 {
552   noise_keypair_t *kp;
553   kp = clib_mem_alloc (sizeof (*kp));
554   return kp;
555 }
556
557 static uint32_t
558 noise_remote_handshake_index_get (noise_remote_t * r)
559 {
560   noise_local_t *local = noise_local_get (r->r_local_idx);
561   struct noise_upcall *u = &local->l_upcall;
562   return u->u_index_set (r);
563 }
564
565 static void
566 noise_remote_handshake_index_drop (noise_remote_t * r)
567 {
568   noise_handshake_t *hs = &r->r_handshake;
569   noise_local_t *local = noise_local_get (r->r_local_idx);
570   struct noise_upcall *u = &local->l_upcall;
571   if (hs->hs_state != HS_ZEROED)
572     u->u_index_drop (hs->hs_local_index);
573 }
574
575 static void
576 noise_kdf (uint8_t * a, uint8_t * b, uint8_t * c, const uint8_t * x,
577            size_t a_len, size_t b_len, size_t c_len, size_t x_len,
578            const uint8_t ck[NOISE_HASH_LEN])
579 {
580   uint8_t out[BLAKE2S_HASH_SIZE + 1];
581   uint8_t sec[BLAKE2S_HASH_SIZE];
582
583   /* Extract entropy from "x" into sec */
584   u32 l = 0;
585   HMAC (EVP_blake2s256 (), ck, NOISE_HASH_LEN, x, x_len, sec, &l);
586   ASSERT (l == BLAKE2S_HASH_SIZE);
587   if (a == NULL || a_len == 0)
588     goto out;
589
590   /* Expand first key: key = sec, data = 0x1 */
591   out[0] = 1;
592   HMAC (EVP_blake2s256 (), sec, BLAKE2S_HASH_SIZE, out, 1, out, &l);
593   ASSERT (l == BLAKE2S_HASH_SIZE);
594   clib_memcpy (a, out, a_len);
595
596   if (b == NULL || b_len == 0)
597     goto out;
598
599   /* Expand second key: key = sec, data = "a" || 0x2 */
600   out[BLAKE2S_HASH_SIZE] = 2;
601   HMAC (EVP_blake2s256 (), sec, BLAKE2S_HASH_SIZE, out, BLAKE2S_HASH_SIZE + 1,
602         out, &l);
603   ASSERT (l == BLAKE2S_HASH_SIZE);
604   clib_memcpy (b, out, b_len);
605
606   if (c == NULL || c_len == 0)
607     goto out;
608
609   /* Expand third key: key = sec, data = "b" || 0x3 */
610   out[BLAKE2S_HASH_SIZE] = 3;
611   HMAC (EVP_blake2s256 (), sec, BLAKE2S_HASH_SIZE, out, BLAKE2S_HASH_SIZE + 1,
612         out, &l);
613   ASSERT (l == BLAKE2S_HASH_SIZE);
614
615   clib_memcpy (c, out, c_len);
616
617 out:
618   /* Clear sensitive data from stack */
619   wg_secure_zero_memory (sec, BLAKE2S_HASH_SIZE);
620   wg_secure_zero_memory (out, BLAKE2S_HASH_SIZE + 1);
621 }
622
623 static bool
624 noise_mix_dh (uint8_t ck[NOISE_HASH_LEN],
625               uint8_t key[NOISE_SYMMETRIC_KEY_LEN],
626               const uint8_t private[NOISE_PUBLIC_KEY_LEN],
627               const uint8_t public[NOISE_PUBLIC_KEY_LEN])
628 {
629   uint8_t dh[NOISE_PUBLIC_KEY_LEN];
630   if (!curve25519_gen_shared (dh, private, public))
631     return false;
632   noise_kdf (ck, key, NULL, dh,
633              NOISE_HASH_LEN, NOISE_SYMMETRIC_KEY_LEN, 0, NOISE_PUBLIC_KEY_LEN,
634              ck);
635   wg_secure_zero_memory (dh, NOISE_PUBLIC_KEY_LEN);
636   return true;
637 }
638
639 static bool
640 noise_mix_ss (uint8_t ck[NOISE_HASH_LEN],
641               uint8_t key[NOISE_SYMMETRIC_KEY_LEN],
642               const uint8_t ss[NOISE_PUBLIC_KEY_LEN])
643 {
644   static uint8_t null_point[NOISE_PUBLIC_KEY_LEN];
645   if (clib_memcmp (ss, null_point, NOISE_PUBLIC_KEY_LEN) == 0)
646     return false;
647   noise_kdf (ck, key, NULL, ss,
648              NOISE_HASH_LEN, NOISE_SYMMETRIC_KEY_LEN, 0, NOISE_PUBLIC_KEY_LEN,
649              ck);
650   return true;
651 }
652
653 static void
654 noise_mix_hash (uint8_t hash[NOISE_HASH_LEN], const uint8_t * src,
655                 size_t src_len)
656 {
657   blake2s_state_t blake;
658
659   blake2s_init (&blake, NOISE_HASH_LEN);
660   blake2s_update (&blake, hash, NOISE_HASH_LEN);
661   blake2s_update (&blake, src, src_len);
662   blake2s_final (&blake, hash, NOISE_HASH_LEN);
663 }
664
665 static void
666 noise_mix_psk (uint8_t ck[NOISE_HASH_LEN], uint8_t hash[NOISE_HASH_LEN],
667                uint8_t key[NOISE_SYMMETRIC_KEY_LEN],
668                const uint8_t psk[NOISE_SYMMETRIC_KEY_LEN])
669 {
670   uint8_t tmp[NOISE_HASH_LEN];
671
672   noise_kdf (ck, tmp, key, psk,
673              NOISE_HASH_LEN, NOISE_HASH_LEN, NOISE_SYMMETRIC_KEY_LEN,
674              NOISE_SYMMETRIC_KEY_LEN, ck);
675   noise_mix_hash (hash, tmp, NOISE_HASH_LEN);
676   wg_secure_zero_memory (tmp, NOISE_HASH_LEN);
677 }
678
679 static void
680 noise_param_init (uint8_t ck[NOISE_HASH_LEN], uint8_t hash[NOISE_HASH_LEN],
681                   const uint8_t s[NOISE_PUBLIC_KEY_LEN])
682 {
683   blake2s_state_t blake;
684
685   blake2s (ck, NOISE_HASH_LEN, (uint8_t *) NOISE_HANDSHAKE_NAME,
686            strlen (NOISE_HANDSHAKE_NAME), NULL, 0);
687
688   blake2s_init (&blake, NOISE_HASH_LEN);
689   blake2s_update (&blake, ck, NOISE_HASH_LEN);
690   blake2s_update (&blake, (uint8_t *) NOISE_IDENTIFIER_NAME,
691                   strlen (NOISE_IDENTIFIER_NAME));
692   blake2s_final (&blake, hash, NOISE_HASH_LEN);
693
694   noise_mix_hash (hash, s, NOISE_PUBLIC_KEY_LEN);
695 }
696
697 static void
698 noise_msg_encrypt (vlib_main_t * vm, uint8_t * dst, uint8_t * src,
699                    size_t src_len, uint32_t key_idx,
700                    uint8_t hash[NOISE_HASH_LEN])
701 {
702   /* Nonce always zero for Noise_IK */
703   wg_chacha20poly1305_calc (vm, src, src_len, dst, hash, NOISE_HASH_LEN, 0,
704                             VNET_CRYPTO_OP_CHACHA20_POLY1305_ENC, key_idx);
705   noise_mix_hash (hash, dst, src_len + NOISE_AUTHTAG_LEN);
706 }
707
708 static bool
709 noise_msg_decrypt (vlib_main_t * vm, uint8_t * dst, uint8_t * src,
710                    size_t src_len, uint32_t key_idx,
711                    uint8_t hash[NOISE_HASH_LEN])
712 {
713   /* Nonce always zero for Noise_IK */
714   if (!wg_chacha20poly1305_calc (vm, src, src_len, dst, hash, NOISE_HASH_LEN,
715                                  0, VNET_CRYPTO_OP_CHACHA20_POLY1305_DEC,
716                                  key_idx))
717     return false;
718   noise_mix_hash (hash, src, src_len);
719   return true;
720 }
721
722 static void
723 noise_msg_ephemeral (uint8_t ck[NOISE_HASH_LEN], uint8_t hash[NOISE_HASH_LEN],
724                      const uint8_t src[NOISE_PUBLIC_KEY_LEN])
725 {
726   noise_mix_hash (hash, src, NOISE_PUBLIC_KEY_LEN);
727   noise_kdf (ck, NULL, NULL, src, NOISE_HASH_LEN, 0, 0,
728              NOISE_PUBLIC_KEY_LEN, ck);
729 }
730
731 static void
732 noise_tai64n_now (uint8_t output[NOISE_TIMESTAMP_LEN])
733 {
734   uint32_t unix_sec;
735   uint32_t unix_nanosec;
736
737   uint64_t sec;
738   uint32_t nsec;
739
740   unix_time_now_nsec_fraction (&unix_sec, &unix_nanosec);
741
742   /* Round down the nsec counter to limit precise timing leak. */
743   unix_nanosec &= REJECT_INTERVAL_MASK;
744
745   /* https://cr.yp.to/libtai/tai64.html */
746   sec = htobe64 (0x400000000000000aULL + unix_sec);
747   nsec = htobe32 (unix_nanosec);
748
749   /* memcpy to output buffer, assuming output could be unaligned. */
750   clib_memcpy (output, &sec, sizeof (sec));
751   clib_memcpy (output + sizeof (sec), &nsec, sizeof (nsec));
752 }
753
754 /*
755  * fd.io coding-style-patch-verification: ON
756  *
757  * Local Variables:
758  * eval: (c-set-style "gnu")
759  * End:
760  */