LCOV - code coverage report
Current view: top level - plugins/wireguard - wireguard_noise.h (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 38 43 88.4 %
Date: 2023-07-05 22:20:52 Functions: 5 5 100.0 %

          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             : #ifndef __included_wg_noise_h__
      19             : #define __included_wg_noise_h__
      20             : 
      21             : #include <vlib/vlib.h>
      22             : #include <vnet/crypto/crypto.h>
      23             : #include <wireguard/blake/blake2s.h>
      24             : #include <wireguard/wireguard_key.h>
      25             : 
      26             : #define NOISE_PUBLIC_KEY_LEN    CURVE25519_KEY_SIZE
      27             : #define NOISE_SYMMETRIC_KEY_LEN   32    // CHACHA20POLY1305_KEY_SIZE
      28             : #define NOISE_TIMESTAMP_LEN     (sizeof(uint64_t) + sizeof(uint32_t))
      29             : #define NOISE_AUTHTAG_LEN       16      //CHACHA20POLY1305_AUTHTAG_SIZE
      30             : #define NOISE_HASH_LEN          BLAKE2S_HASH_SIZE
      31             : 
      32             : /* Protocol string constants */
      33             : #define NOISE_HANDSHAKE_NAME    "Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s"
      34             : #define NOISE_IDENTIFIER_NAME   "WireGuard v1 zx2c4 Jason@zx2c4.com"
      35             : 
      36             : /* Constants for the counter */
      37             : #define COUNTER_BITS_TOTAL      8192
      38             : #define COUNTER_BITS            (sizeof(unsigned long) * 8)
      39             : #define COUNTER_NUM             (COUNTER_BITS_TOTAL / COUNTER_BITS)
      40             : #define COUNTER_WINDOW_SIZE     (COUNTER_BITS_TOTAL - COUNTER_BITS)
      41             : 
      42             : /* Constants for the keypair */
      43             : #define REKEY_AFTER_MESSAGES    (1ull << 60)
      44             : #define REJECT_AFTER_MESSAGES   (UINT64_MAX - COUNTER_WINDOW_SIZE - 1)
      45             : #define REKEY_AFTER_TIME        120
      46             : #define REKEY_AFTER_TIME_RECV   165
      47             : #define REJECT_AFTER_TIME       180
      48             : #define REJECT_INTERVAL         (0.02)  /* fifty times per sec */
      49             : /* 24 = floor(log2(REJECT_INTERVAL)) */
      50             : #define REJECT_INTERVAL_MASK    (~((1ull<<24)-1))
      51             : 
      52             : enum noise_state_crypt
      53             : {
      54             :   SC_OK = 0,
      55             :   SC_CONN_RESET,
      56             :   SC_KEEP_KEY_FRESH,
      57             :   SC_FAILED,
      58             : };
      59             : 
      60             : enum noise_state_hs
      61             : {
      62             :   HS_ZEROED = 0,
      63             :   CREATED_INITIATION,
      64             :   CONSUMED_INITIATION,
      65             :   CREATED_RESPONSE,
      66             :   CONSUMED_RESPONSE,
      67             : };
      68             : 
      69             : typedef struct noise_handshake
      70             : {
      71             :   enum noise_state_hs hs_state;
      72             :   uint32_t hs_local_index;
      73             :   uint32_t hs_remote_index;
      74             :   uint8_t hs_e[NOISE_PUBLIC_KEY_LEN];
      75             :   uint8_t hs_hash[NOISE_HASH_LEN];
      76             :   uint8_t hs_ck[NOISE_HASH_LEN];
      77             : } noise_handshake_t;
      78             : 
      79             : typedef struct noise_counter
      80             : {
      81             :   uint64_t c_send;
      82             :   uint64_t c_recv;
      83             :   unsigned long c_backtrack[COUNTER_NUM];
      84             : } noise_counter_t;
      85             : 
      86             : typedef struct noise_keypair
      87             : {
      88             :   int kp_valid;
      89             :   int kp_is_initiator;
      90             :   uint32_t kp_local_index;
      91             :   uint32_t kp_remote_index;
      92             :   vnet_crypto_key_index_t kp_send_index;
      93             :   vnet_crypto_key_index_t kp_recv_index;
      94             :   f64 kp_birthdate;
      95             :   noise_counter_t kp_ctr;
      96             : } noise_keypair_t;
      97             : 
      98             : typedef struct noise_local noise_local_t;
      99             : typedef struct noise_remote
     100             : {
     101             :   uint32_t r_peer_idx;
     102             :   uint8_t r_public[NOISE_PUBLIC_KEY_LEN];
     103             :   uint32_t r_local_idx;
     104             :   uint8_t r_ss[NOISE_PUBLIC_KEY_LEN];
     105             : 
     106             :   noise_handshake_t r_handshake;
     107             :   uint8_t r_psk[NOISE_SYMMETRIC_KEY_LEN];
     108             :   uint8_t r_timestamp[NOISE_TIMESTAMP_LEN];
     109             :   f64 r_last_init;
     110             : 
     111             :   clib_rwlock_t r_keypair_lock;
     112             :   noise_keypair_t *r_next, *r_current, *r_previous;
     113             : } noise_remote_t;
     114             : 
     115             : typedef struct noise_local
     116             : {
     117             :   uint8_t l_public[NOISE_PUBLIC_KEY_LEN];
     118             :   uint8_t l_private[NOISE_PUBLIC_KEY_LEN];
     119             : 
     120             :   struct noise_upcall
     121             :   {
     122             :     void *u_arg;
     123             :     noise_remote_t *(*u_remote_get) (const uint8_t[NOISE_PUBLIC_KEY_LEN]);
     124             :     uint32_t (*u_index_set) (vlib_main_t *, noise_remote_t *);
     125             :     void (*u_index_drop) (vlib_main_t *, uint32_t);
     126             :   } l_upcall;
     127             : } noise_local_t;
     128             : 
     129             : /* pool of noise_local */
     130             : extern noise_local_t *noise_local_pool;
     131             : 
     132             : /* Set/Get noise parameters */
     133             : static_always_inline noise_local_t *
     134        2483 : noise_local_get (uint32_t locali)
     135             : {
     136        2483 :   return (pool_elt_at_index (noise_local_pool, locali));
     137             : }
     138             : 
     139             : static_always_inline uint64_t
     140        3410 : noise_counter_send (noise_counter_t *ctr)
     141             : {
     142             :   uint64_t ret;
     143        3410 :   ret = ctr->c_send++;
     144        3410 :   return ret;
     145             : }
     146             : 
     147             : void noise_local_init (noise_local_t *, struct noise_upcall *);
     148             : bool noise_local_set_private (noise_local_t *,
     149             :                               const uint8_t[NOISE_PUBLIC_KEY_LEN]);
     150             : 
     151             : void noise_remote_init (vlib_main_t *, noise_remote_t *, uint32_t,
     152             :                         const uint8_t[NOISE_PUBLIC_KEY_LEN], uint32_t);
     153             : 
     154             : /* Should be called anytime noise_local_set_private is called */
     155             : void noise_remote_precompute (vlib_main_t *, noise_remote_t *);
     156             : 
     157             : /* Cryptographic functions */
     158             : bool noise_create_initiation (vlib_main_t * vm, noise_remote_t *,
     159             :                               uint32_t * s_idx,
     160             :                               uint8_t ue[NOISE_PUBLIC_KEY_LEN],
     161             :                               uint8_t es[NOISE_PUBLIC_KEY_LEN +
     162             :                                          NOISE_AUTHTAG_LEN],
     163             :                               uint8_t ets[NOISE_TIMESTAMP_LEN +
     164             :                                           NOISE_AUTHTAG_LEN]);
     165             : 
     166             : bool noise_consume_initiation (vlib_main_t * vm, noise_local_t *,
     167             :                                noise_remote_t **,
     168             :                                uint32_t s_idx,
     169             :                                uint8_t ue[NOISE_PUBLIC_KEY_LEN],
     170             :                                uint8_t es[NOISE_PUBLIC_KEY_LEN +
     171             :                                           NOISE_AUTHTAG_LEN],
     172             :                                uint8_t ets[NOISE_TIMESTAMP_LEN +
     173             :                                            NOISE_AUTHTAG_LEN]);
     174             : 
     175             : bool noise_create_response (vlib_main_t * vm, noise_remote_t *,
     176             :                             uint32_t * s_idx,
     177             :                             uint32_t * r_idx,
     178             :                             uint8_t ue[NOISE_PUBLIC_KEY_LEN],
     179             :                             uint8_t en[0 + NOISE_AUTHTAG_LEN]);
     180             : 
     181             : bool noise_consume_response (vlib_main_t * vm, noise_remote_t *,
     182             :                              uint32_t s_idx,
     183             :                              uint32_t r_idx,
     184             :                              uint8_t ue[NOISE_PUBLIC_KEY_LEN],
     185             :                              uint8_t en[0 + NOISE_AUTHTAG_LEN]);
     186             : 
     187             : bool noise_remote_begin_session (vlib_main_t * vm, noise_remote_t * r);
     188             : void noise_remote_clear (vlib_main_t * vm, noise_remote_t * r);
     189             : void noise_remote_expire_current (noise_remote_t * r);
     190             : 
     191             : bool noise_remote_ready (noise_remote_t *);
     192             : 
     193             : enum noise_state_crypt
     194             : noise_remote_encrypt (vlib_main_t * vm, noise_remote_t *,
     195             :                       uint32_t * r_idx,
     196             :                       uint64_t * nonce,
     197             :                       uint8_t * src, size_t srclen, uint8_t * dst);
     198             : 
     199             : static_always_inline noise_keypair_t *
     200        7264 : wg_get_active_keypair (noise_remote_t *r, uint32_t r_idx)
     201             : {
     202        7264 :   if (r->r_current != NULL && r->r_current->kp_local_index == r_idx)
     203             :     {
     204        7243 :       return r->r_current;
     205             :     }
     206          21 :   else if (r->r_previous != NULL && r->r_previous->kp_local_index == r_idx)
     207             :     {
     208           0 :       return r->r_previous;
     209             :     }
     210          21 :   else if (r->r_next != NULL && r->r_next->kp_local_index == r_idx)
     211             :     {
     212          21 :       return r->r_next;
     213             :     }
     214             :   else
     215             :     {
     216           0 :       return NULL;
     217             :     }
     218             : }
     219             : 
     220             : inline bool
     221        3632 : noise_counter_recv (noise_counter_t *ctr, uint64_t recv)
     222             : {
     223             :   uint64_t i, top, index_recv, index_ctr;
     224             :   unsigned long bit;
     225        3632 :   bool ret = false;
     226             : 
     227             :   /* Check that the recv counter is valid */
     228        3632 :   if (ctr->c_recv >= REJECT_AFTER_MESSAGES || recv >= REJECT_AFTER_MESSAGES)
     229           0 :     goto error;
     230             : 
     231             :   /* If the packet is out of the window, invalid */
     232        3632 :   if (recv + COUNTER_WINDOW_SIZE < ctr->c_recv)
     233           0 :     goto error;
     234             : 
     235             :   /* If the new counter is ahead of the current counter, we'll need to
     236             :    * zero out the bitmap that has previously been used */
     237        3632 :   index_recv = recv / COUNTER_BITS;
     238        3632 :   index_ctr = ctr->c_recv / COUNTER_BITS;
     239             : 
     240        3632 :   if (recv > ctr->c_recv)
     241             :     {
     242        3591 :       top = clib_min (index_recv - index_ctr, COUNTER_NUM);
     243        3634 :       for (i = 1; i <= top; i++)
     244          43 :         ctr->c_backtrack[(i + index_ctr) & (COUNTER_NUM - 1)] = 0;
     245        3591 :       ctr->c_recv = recv;
     246             :     }
     247             : 
     248        3632 :   index_recv %= COUNTER_NUM;
     249        3632 :   bit = 1ul << (recv % COUNTER_BITS);
     250             : 
     251        3632 :   if (ctr->c_backtrack[index_recv] & bit)
     252           0 :     goto error;
     253             : 
     254        3632 :   ctr->c_backtrack[index_recv] |= bit;
     255             : 
     256        3632 :   ret = true;
     257        3632 : error:
     258        3632 :   return ret;
     259             : }
     260             : 
     261             : static_always_inline void
     262         624 : noise_remote_keypair_free (vlib_main_t *vm, noise_remote_t *r,
     263             :                            noise_keypair_t **kp)
     264             : {
     265         624 :   noise_local_t *local = noise_local_get (r->r_local_idx);
     266         624 :   struct noise_upcall *u = &local->l_upcall;
     267         624 :   if (*kp)
     268             :     {
     269          94 :       u->u_index_drop (vm, (*kp)->kp_local_index);
     270          94 :       vnet_crypto_key_del (vm, (*kp)->kp_send_index);
     271          94 :       vnet_crypto_key_del (vm, (*kp)->kp_recv_index);
     272          94 :       clib_mem_free (*kp);
     273             :     }
     274         624 : }
     275             : 
     276             : #endif /* __included_wg_noise_h__ */
     277             : 
     278             : /*
     279             :  * fd.io coding-style-patch-verification: ON
     280             :  *
     281             :  * Local Variables:
     282             :  * eval: (c-set-style "gnu")
     283             :  * End:
     284             :  */

Generated by: LCOV version 1.14