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