LCOV - code coverage report
Current view: top level - plugins/wireguard - wireguard_noise.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 286 332 86.1 %
Date: 2023-07-05 22:20:52 Functions: 24 26 92.3 %

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

Generated by: LCOV version 1.14