LCOV - code coverage report
Current view: top level - plugins/wireguard - wireguard_cookie.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 133 139 95.7 %
Date: 2023-10-26 01:39:38 Functions: 16 16 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             : #include <stddef.h>
      19             : #include <openssl/rand.h>
      20             : #include <vlib/vlib.h>
      21             : 
      22             : #include <wireguard/wireguard_cookie.h>
      23             : #include <wireguard/wireguard_chachapoly.h>
      24             : #include <wireguard/wireguard.h>
      25             : 
      26             : static void cookie_precompute_key (uint8_t *,
      27             :                                    const uint8_t[COOKIE_INPUT_SIZE],
      28             :                                    const char *);
      29             : static void cookie_macs_mac1 (message_macs_t *, const void *, size_t,
      30             :                               const uint8_t[COOKIE_KEY_SIZE]);
      31             : static void cookie_macs_mac2 (message_macs_t *, const void *, size_t,
      32             :                               const uint8_t[COOKIE_COOKIE_SIZE]);
      33             : static void cookie_checker_make_cookie (vlib_main_t *vm, cookie_checker_t *,
      34             :                                         uint8_t[COOKIE_COOKIE_SIZE],
      35             :                                         ip46_address_t *ip, u16 udp_port);
      36             : 
      37             : static void ratelimit_init (ratelimit_t *, ratelimit_entry_t *);
      38             : static void ratelimit_deinit (ratelimit_t *);
      39             : static void ratelimit_gc (ratelimit_t *, bool);
      40             : static bool ratelimit_allow (ratelimit_t *, ip46_address_t *);
      41             : 
      42             : /* Public Functions */
      43             : void
      44         146 : cookie_maker_init (cookie_maker_t * cp, const uint8_t key[COOKIE_INPUT_SIZE])
      45             : {
      46         146 :   clib_memset (cp, 0, sizeof (*cp));
      47         146 :   cookie_precompute_key (cp->cp_mac1_key, key, COOKIE_MAC1_KEY_LABEL);
      48         146 :   cookie_precompute_key (cp->cp_cookie_key, key, COOKIE_COOKIE_KEY_LABEL);
      49         146 : }
      50             : 
      51             : void
      52          82 : cookie_checker_init (cookie_checker_t *cc, ratelimit_entry_t *pool)
      53             : {
      54          82 :   clib_memset (cc, 0, sizeof (*cc));
      55          82 :   ratelimit_init (&cc->cc_ratelimit_v4, pool);
      56          82 :   ratelimit_init (&cc->cc_ratelimit_v6, pool);
      57          82 : }
      58             : 
      59             : void
      60          82 : cookie_checker_update (cookie_checker_t * cc, uint8_t key[COOKIE_INPUT_SIZE])
      61             : {
      62          82 :   if (key)
      63             :     {
      64          82 :       cookie_precompute_key (cc->cc_mac1_key, key, COOKIE_MAC1_KEY_LABEL);
      65          82 :       cookie_precompute_key (cc->cc_cookie_key, key, COOKIE_COOKIE_KEY_LABEL);
      66             :     }
      67             :   else
      68             :     {
      69           0 :       clib_memset (cc->cc_mac1_key, 0, sizeof (cc->cc_mac1_key));
      70           0 :       clib_memset (cc->cc_cookie_key, 0, sizeof (cc->cc_cookie_key));
      71             :     }
      72          82 : }
      73             : 
      74             : void
      75          82 : cookie_checker_deinit (cookie_checker_t *cc)
      76             : {
      77          82 :   ratelimit_deinit (&cc->cc_ratelimit_v4);
      78          82 :   ratelimit_deinit (&cc->cc_ratelimit_v6);
      79          82 : }
      80             : 
      81             : void
      82          28 : cookie_checker_create_payload (vlib_main_t *vm, cookie_checker_t *cc,
      83             :                                message_macs_t *cm,
      84             :                                uint8_t nonce[COOKIE_NONCE_SIZE],
      85             :                                uint8_t ecookie[COOKIE_ENCRYPTED_SIZE],
      86             :                                ip46_address_t *ip, u16 udp_port)
      87             : {
      88             :   uint8_t cookie[COOKIE_COOKIE_SIZE];
      89             : 
      90          28 :   cookie_checker_make_cookie (vm, cc, cookie, ip, udp_port);
      91          28 :   RAND_bytes (nonce, COOKIE_NONCE_SIZE);
      92             : 
      93          28 :   wg_xchacha20poly1305_encrypt (vm, cookie, COOKIE_COOKIE_SIZE, ecookie,
      94          28 :                                 cm->mac1, COOKIE_MAC_SIZE, nonce,
      95          28 :                                 cc->cc_cookie_key);
      96             : 
      97          28 :   wg_secure_zero_memory (cookie, sizeof (cookie));
      98          28 : }
      99             : 
     100             : bool
     101          16 : cookie_maker_consume_payload (vlib_main_t *vm, cookie_maker_t *cp,
     102             :                               uint8_t nonce[COOKIE_NONCE_SIZE],
     103             :                               uint8_t ecookie[COOKIE_ENCRYPTED_SIZE])
     104             : {
     105             :   uint8_t cookie[COOKIE_COOKIE_SIZE];
     106             : 
     107          16 :   if (cp->cp_mac1_valid == 0)
     108             :     {
     109           0 :       return false;
     110             :     }
     111             : 
     112          16 :   if (!wg_xchacha20poly1305_decrypt (vm, ecookie, COOKIE_ENCRYPTED_SIZE,
     113          16 :                                      cookie, cp->cp_mac1_last, COOKIE_MAC_SIZE,
     114          16 :                                      nonce, cp->cp_cookie_key))
     115             :     {
     116           8 :       return false;
     117             :     }
     118             : 
     119           8 :   clib_memcpy (cp->cp_cookie, cookie, COOKIE_COOKIE_SIZE);
     120           8 :   cp->cp_birthdate = vlib_time_now (vm);
     121           8 :   cp->cp_mac1_valid = 0;
     122             : 
     123           8 :   return true;
     124             : }
     125             : 
     126             : void
     127         209 : cookie_maker_mac (cookie_maker_t * cp, message_macs_t * cm, void *buf,
     128             :                   size_t len)
     129             : {
     130         209 :   len = len - sizeof (message_macs_t);
     131         209 :   cookie_macs_mac1 (cm, buf, len, cp->cp_mac1_key);
     132             : 
     133         209 :   clib_memcpy (cp->cp_mac1_last, cm->mac1, COOKIE_MAC_SIZE);
     134         209 :   cp->cp_mac1_valid = 1;
     135             : 
     136         209 :   if (!wg_birthdate_has_expired (cp->cp_birthdate,
     137             :                                  COOKIE_SECRET_MAX_AGE -
     138             :                                  COOKIE_SECRET_LATENCY))
     139           8 :     cookie_macs_mac2 (cm, buf, len, cp->cp_cookie);
     140             :   else
     141         201 :     clib_memset (cm->mac2, 0, COOKIE_MAC_SIZE);
     142         209 : }
     143             : 
     144             : enum cookie_mac_state
     145         918 : cookie_checker_validate_macs (vlib_main_t *vm, cookie_checker_t *cc,
     146             :                               message_macs_t *cm, void *buf, size_t len,
     147             :                               bool busy, ip46_address_t *ip, u16 udp_port)
     148             : {
     149             :   message_macs_t our_cm;
     150             :   uint8_t cookie[COOKIE_COOKIE_SIZE];
     151             : 
     152         918 :   len = len - sizeof (message_macs_t);
     153         918 :   cookie_macs_mac1 (&our_cm, buf, len, cc->cc_mac1_key);
     154             : 
     155             :   /* If mac1 is invalid, we want to drop the packet */
     156         918 :   if (clib_memcmp (our_cm.mac1, cm->mac1, COOKIE_MAC_SIZE) != 0)
     157          14 :     return INVALID_MAC;
     158             : 
     159         904 :   if (!busy)
     160         774 :     return VALID_MAC_BUT_NO_COOKIE;
     161             : 
     162         130 :   cookie_checker_make_cookie (vm, cc, cookie, ip, udp_port);
     163         130 :   cookie_macs_mac2 (&our_cm, buf, len, cookie);
     164             : 
     165             :   /* If the mac2 is invalid, we want to send a cookie response */
     166         130 :   if (clib_memcmp (our_cm.mac2, cm->mac2, COOKIE_MAC_SIZE) != 0)
     167          28 :     return VALID_MAC_BUT_NO_COOKIE;
     168             : 
     169             :   /* If the mac2 is valid, we may want to rate limit the peer */
     170             :   ratelimit_t *rl;
     171         102 :   rl = ip46_address_is_ip4 (ip) ? &cc->cc_ratelimit_v4 : &cc->cc_ratelimit_v6;
     172             : 
     173         102 :   if (!ratelimit_allow (rl, ip))
     174          54 :     return VALID_MAC_WITH_COOKIE_BUT_RATELIMITED;
     175             : 
     176          48 :   return VALID_MAC_WITH_COOKIE;
     177             : }
     178             : 
     179             : /* Private functions */
     180             : static void
     181         456 : cookie_precompute_key (uint8_t * key, const uint8_t input[COOKIE_INPUT_SIZE],
     182             :                        const char *label)
     183             : {
     184             :   blake2s_state_t blake;
     185             : 
     186         456 :   blake2s_init (&blake, COOKIE_KEY_SIZE);
     187         456 :   blake2s_update (&blake, (const uint8_t *) label, strlen (label));
     188         456 :   blake2s_update (&blake, input, COOKIE_INPUT_SIZE);
     189         456 :   blake2s_final (&blake, key, COOKIE_KEY_SIZE);
     190         456 : }
     191             : 
     192             : static void
     193        1127 : cookie_macs_mac1 (message_macs_t * cm, const void *buf, size_t len,
     194             :                   const uint8_t key[COOKIE_KEY_SIZE])
     195             : {
     196             :   blake2s_state_t state;
     197        1127 :   blake2s_init_key (&state, COOKIE_MAC_SIZE, key, COOKIE_KEY_SIZE);
     198        1127 :   blake2s_update (&state, buf, len);
     199        1127 :   blake2s_final (&state, cm->mac1, COOKIE_MAC_SIZE);
     200             : 
     201        1127 : }
     202             : 
     203             : static void
     204         138 : cookie_macs_mac2 (message_macs_t * cm, const void *buf, size_t len,
     205             :                   const uint8_t key[COOKIE_COOKIE_SIZE])
     206             : {
     207             :   blake2s_state_t state;
     208         138 :   blake2s_init_key (&state, COOKIE_MAC_SIZE, key, COOKIE_COOKIE_SIZE);
     209         138 :   blake2s_update (&state, buf, len);
     210         138 :   blake2s_update (&state, cm->mac1, COOKIE_MAC_SIZE);
     211         138 :   blake2s_final (&state, cm->mac2, COOKIE_MAC_SIZE);
     212         138 : }
     213             : 
     214             : static void
     215         158 : cookie_checker_make_cookie (vlib_main_t *vm, cookie_checker_t *cc,
     216             :                             uint8_t cookie[COOKIE_COOKIE_SIZE],
     217             :                             ip46_address_t *ip, u16 udp_port)
     218             : {
     219             :   blake2s_state_t state;
     220             : 
     221         158 :   if (wg_birthdate_has_expired (cc->cc_secret_birthdate,
     222             :                                 COOKIE_SECRET_MAX_AGE))
     223             :     {
     224          16 :       cc->cc_secret_birthdate = vlib_time_now (vm);
     225          16 :       RAND_bytes (cc->cc_secret, COOKIE_SECRET_SIZE);
     226             :     }
     227             : 
     228         158 :   blake2s_init_key (&state, COOKIE_COOKIE_SIZE, cc->cc_secret,
     229             :                     COOKIE_SECRET_SIZE);
     230             : 
     231         158 :   if (ip46_address_is_ip4 (ip))
     232             :     {
     233         104 :       blake2s_update (&state, ip->ip4.as_u8, sizeof (ip4_address_t));
     234             :     }
     235             :   else
     236             :     {
     237          54 :       blake2s_update (&state, ip->ip6.as_u8, sizeof (ip6_address_t));
     238             :     }
     239         158 :   blake2s_update (&state, (u8 *) & udp_port, sizeof (u16));
     240         158 :   blake2s_final (&state, cookie, COOKIE_COOKIE_SIZE);
     241         158 : }
     242             : 
     243             : static void
     244         164 : ratelimit_init (ratelimit_t *rl, ratelimit_entry_t *pool)
     245             : {
     246         164 :   rl->rl_pool = pool;
     247         164 : }
     248             : 
     249             : static void
     250         164 : ratelimit_deinit (ratelimit_t *rl)
     251             : {
     252         164 :   ratelimit_gc (rl, /* force */ true);
     253         164 :   hash_free (rl->rl_table);
     254         164 : }
     255             : 
     256             : static void
     257         180 : ratelimit_gc (ratelimit_t *rl, bool force)
     258             : {
     259             :   u32 r_key;
     260             :   u32 r_idx;
     261             :   ratelimit_entry_t *r;
     262             : 
     263         180 :   if (force)
     264             :     {
     265             :       /* clang-format off */
     266        1076 :       hash_foreach (r_key, r_idx, rl->rl_table, {
     267             :         r = pool_elt_at_index (rl->rl_pool, r_idx);
     268             :         pool_put (rl->rl_pool, r);
     269             :       });
     270             :       /* clang-format on */
     271         164 :       return;
     272             :     }
     273             : 
     274          16 :   f64 now = vlib_time_now (vlib_get_main ());
     275             : 
     276          16 :   if ((rl->rl_last_gc + ELEMENT_TIMEOUT) < now)
     277             :     {
     278          14 :       u32 *r_key_to_del = NULL;
     279             :       u32 *pr_key;
     280             : 
     281          14 :       rl->rl_last_gc = now;
     282             : 
     283             :       /* clang-format off */
     284          14 :       hash_foreach (r_key, r_idx, rl->rl_table, {
     285             :         r = pool_elt_at_index (rl->rl_pool, r_idx);
     286             :         if ((r->r_last_time + ELEMENT_TIMEOUT) < now)
     287             :           {
     288             :             vec_add1 (r_key_to_del, r_key);
     289             :             pool_put (rl->rl_pool, r);
     290             :           }
     291             :       });
     292             :       /* clang-format on */
     293             : 
     294          14 :       vec_foreach (pr_key, r_key_to_del)
     295             :         {
     296           0 :           hash_unset (rl->rl_table, *pr_key);
     297             :         }
     298             : 
     299          14 :       vec_free (r_key_to_del);
     300             :     }
     301             : }
     302             : 
     303             : static bool
     304         102 : ratelimit_allow (ratelimit_t *rl, ip46_address_t *ip)
     305             : {
     306             :   u32 r_key;
     307             :   uword *p;
     308             :   u32 r_idx;
     309             :   ratelimit_entry_t *r;
     310         102 :   f64 now = vlib_time_now (vlib_get_main ());
     311             : 
     312         102 :   if (ip46_address_is_ip4 (ip))
     313             :     /* Use all 4 bytes of IPv4 address */
     314          68 :     r_key = ip->ip4.as_u32;
     315             :   else
     316             :     /* Use top 8 bytes (/64) of IPv6 address */
     317          34 :     r_key = ip->ip6.as_u32[0] ^ ip->ip6.as_u32[1];
     318             : 
     319             :   /* Check if there is already an entry for the IP address */
     320         102 :   p = hash_get (rl->rl_table, r_key);
     321         102 :   if (p)
     322             :     {
     323             :       u64 tokens;
     324             :       f64 diff;
     325             : 
     326          86 :       r_idx = p[0];
     327          86 :       r = pool_elt_at_index (rl->rl_pool, r_idx);
     328             : 
     329          86 :       diff = now - r->r_last_time;
     330          86 :       r->r_last_time = now;
     331             : 
     332          86 :       tokens = r->r_tokens + diff * NSEC_PER_SEC;
     333             : 
     334          86 :       if (tokens > TOKEN_MAX)
     335           0 :         tokens = TOKEN_MAX;
     336             : 
     337          86 :       if (tokens >= INITIATION_COST)
     338             :         {
     339          32 :           r->r_tokens = tokens - INITIATION_COST;
     340          32 :           return true;
     341             :         }
     342             : 
     343          54 :       r->r_tokens = tokens;
     344          54 :       return false;
     345             :     }
     346             : 
     347             :   /* No entry for the IP address */
     348          16 :   ratelimit_gc (rl, /* force */ false);
     349             : 
     350          16 :   if (hash_elts (rl->rl_table) >= RATELIMIT_SIZE_MAX)
     351           0 :     return false;
     352             : 
     353          16 :   pool_get (rl->rl_pool, r);
     354          16 :   r_idx = r - rl->rl_pool;
     355          16 :   hash_set (rl->rl_table, r_key, r_idx);
     356             : 
     357          16 :   r->r_last_time = now;
     358          16 :   r->r_tokens = TOKEN_MAX - INITIATION_COST;
     359             : 
     360          16 :   return true;
     361             : }
     362             : 
     363             : /*
     364             :  * fd.io coding-style-patch-verification: ON
     365             :  *
     366             :  * Local Variables:
     367             :  * eval: (c-set-style "gnu")
     368             :  * End:
     369             :  */

Generated by: LCOV version 1.14