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 2468 : noise_local_get (uint32_t locali)
135 : {
136 2468 : 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 : */
|