1 /* packet-wireguard.c
2  * Routines for WireGuard dissection
3  * Copyright 2018, Peter Wu <peter@lekensteyn.nl>
4  *
5  * Wireshark - Network traffic analyzer
6  * By Gerald Combs <gerald@wireshark.org>
7  * Copyright 1998 Gerald Combs
8  *
9  * SPDX-License-Identifier: GPL-2.0-or-later
10  */
11 
12 /*
13  * Protocol details: https://www.wireguard.com/protocol/
14  */
15 
16 #include <config.h>
17 
18 #include <errno.h>
19 
20 #define WS_LOG_DOMAIN "packet-wireguard"
21 
22 #include <epan/packet.h>
23 #include <epan/expert.h>
24 #include <epan/prefs.h>
25 #include <epan/proto_data.h>
26 #include <epan/conversation.h>
27 #include <epan/uat.h>
28 #include <wsutil/file_util.h>
29 #include <wsutil/filesystem.h>
30 #include <wsutil/wsgcrypt.h>
31 #include <wsutil/curve25519.h>
32 #include <wsutil/wslog.h>
33 #include <epan/secrets.h>
34 #include <wiretap/secrets-types.h>
35 
36 #if GCRYPT_VERSION_NUMBER >= 0x010800 /* 1.8.0 */
37 /* Decryption requires Curve25519, ChaCha20-Poly1305 (1.7) and Blake2s (1.8). */
38 #define WG_DECRYPTION_SUPPORTED
39 #endif
40 
41 void proto_reg_handoff_wg(void);
42 void proto_register_wg(void);
43 
44 static int proto_wg = -1;
45 static int hf_wg_type = -1;
46 static int hf_wg_reserved = -1;
47 static int hf_wg_sender = -1;
48 static int hf_wg_ephemeral = -1;
49 static int hf_wg_encrypted_static = -1;
50 static int hf_wg_static = -1;
51 static int hf_wg_encrypted_timestamp = -1;
52 static int hf_wg_timestamp_tai64_label = -1;
53 static int hf_wg_timestamp_nanoseconds = -1;
54 static int hf_wg_timestamp_value = -1;
55 static int hf_wg_mac1 = -1;
56 static int hf_wg_mac2 = -1;
57 static int hf_wg_receiver = -1;
58 static int hf_wg_encrypted_empty = -1;
59 static int hf_wg_handshake_ok = -1;
60 static int hf_wg_nonce = -1;
61 static int hf_wg_encrypted_cookie = -1;
62 static int hf_wg_counter = -1;
63 static int hf_wg_encrypted_packet = -1;
64 static int hf_wg_stream = -1;
65 static int hf_wg_response_in = -1;
66 static int hf_wg_response_to = -1;
67 static int hf_wg_receiver_pubkey = -1;
68 static int hf_wg_receiver_pubkey_known_privkey = -1;
69 static int hf_wg_ephemeral_known_privkey = -1;
70 static int hf_wg_static_known_pubkey = -1;
71 static int hf_wg_static_known_privkey = -1;
72 
73 static gint ett_wg = -1;
74 static gint ett_timestamp = -1;
75 static gint ett_key_info = -1;
76 
77 static expert_field ei_wg_bad_packet_length = EI_INIT;
78 static expert_field ei_wg_keepalive  = EI_INIT;
79 static expert_field ei_wg_decryption_error = EI_INIT;
80 
81 #ifdef WG_DECRYPTION_SUPPORTED
82 static gboolean     pref_dissect_packet = TRUE;
83 static const char  *pref_keylog_file;
84 
85 static dissector_handle_t ip_handle;
86 #endif /* WG_DECRYPTION_SUPPORTED */
87 static dissector_handle_t wg_handle;
88 
89 
90 // Length of AEAD authentication tag
91 #define AUTH_TAG_LENGTH 16
92 
93 typedef enum {
94     WG_TYPE_HANDSHAKE_INITIATION = 1,
95     WG_TYPE_HANDSHAKE_RESPONSE = 2,
96     WG_TYPE_COOKIE_REPLY = 3,
97     WG_TYPE_TRANSPORT_DATA = 4
98 } wg_message_type;
99 
100 static const value_string wg_type_names[] = {
101     { 0x01, "Handshake Initiation" },
102     { 0x02, "Handshake Response" },
103     { 0x03, "Cookie Reply" },
104     { 0x04, "Transport Data" },
105     { 0x00, NULL }
106 };
107 
108 #ifdef WG_DECRYPTION_SUPPORTED
109 /* Decryption types. {{{ */
110 /*
111  * Most operations operate on 32 byte units (keys and hash output).
112  */
113 typedef struct {
114 #define WG_KEY_LEN  32
115     guchar data[WG_KEY_LEN];
116 } wg_qqword;
117 
118 /*
119  * Static key with the MAC1 key pre-computed and an optional private key.
120  */
121 typedef struct wg_skey {
122     wg_qqword   pub_key;
123     wg_qqword   mac1_key;
124     wg_qqword   priv_key;   /* Optional, set to all zeroes if missing. */
125 } wg_skey_t;
126 
127 /*
128  * Pre-shared key, needed while processing the handshake response message. At
129  * that point, ephemeral keys (from either the initiator or responder) should be
130  * known. Thus link the PSK to such ephemeral keys.
131  *
132  * Usually a "wg_ekey_t" contains an empty list (if there is no PSK, i.e. an
133  * all-zeroes PSK) or one item (if a PSK is configured). In the unlikely event
134  * that an ephemeral key is reused, support more than one PSK.
135  */
136 typedef struct wg_psk {
137     wg_qqword psk_data;
138     struct wg_psk *next;
139 } wg_psk_t;
140 
141 /*
142  * Ephemeral key.
143  */
144 typedef struct wg_ekey {
145     wg_qqword   pub_key;
146     wg_qqword   priv_key;   /* Optional, set to all zeroes if missing. */
147     wg_psk_t   *psk_list;   /* Optional, possible PSKs to try. */
148 } wg_ekey_t;
149 
150 /*
151  * Set of (long-term) static keys (for guessing the peer based on MAC1).
152  * Maps the public key to the "wg_skey_t" structure.
153  * Keys are populated from the UAT and key log file.
154  */
155 static GHashTable *wg_static_keys = NULL;
156 
157 /*
158  * Set of ephemeral keys (for decryption). Maps the public key to the
159  * "wg_ekey_t" structure. The private key MUST be available.
160  * Keys are populated from the key log file and wmem_file_scope allocated.
161  */
162 static wmem_map_t *wg_ephemeral_keys;
163 
164 /*
165  * Key log file handle. Opened on demand (when keys are actually looked up),
166  * closed when the capture file closes.
167  */
168 static FILE *wg_keylog_file;
169 
170 /*
171  * The most recently parsed ephemeral key. If a PSK is configured, the key log
172  * file must have a PSK line after other keys. If not, then it is assumed that
173  * the session does not use a PSK.
174  *
175  * This pointer is cleared when the key log file is reset (i.e. when the capture
176  * file closes).
177  */
178 static wg_ekey_t *wg_keylog_last_ekey;
179 
180 enum wg_psk_iter_state {
181     WG_PSK_ITER_STATE_ENTER = 0,
182     WG_PSK_ITER_STATE_INITIATOR,
183     WG_PSK_ITER_STATE_RESPONDER,
184     WG_PSK_ITER_STATE_EXIT
185 };
186 
187 /* See wg_psk_iter_next. */
188 typedef struct {
189     enum wg_psk_iter_state state;
190     wg_psk_t               *next_psk;
191 } wg_psk_iter_context;
192 
193 /* UAT adapter for populating wg_static_keys. */
194 enum { WG_KEY_UAT_PUBLIC, WG_KEY_UAT_PRIVATE };
195 static const value_string wg_key_uat_type_vals[] = {
196     { WG_KEY_UAT_PUBLIC, "Public" },
197     { WG_KEY_UAT_PRIVATE, "Private" },
198     { 0, NULL }
199 };
200 
201 typedef struct {
202     guint   key_type;   /* See "wg_key_uat_type_vals". */
203     char   *key;
204 } wg_key_uat_record_t;
205 
206 static wg_key_uat_record_t *wg_key_records;
207 static guint num_wg_key_records;
208 
209 /*
210  * Input keying material for key derivation/decryption during the handshake.
211  * For the Initiation message, Spub_r and either Spriv_r or Epriv_i must be set.
212  * For the Response message, Epriv_r + Spriv_r or Epriv_r + Epub_i.
213  *
214  * The static and ephemeral keys are reset upon UAT changes or are invalidated
215  * when the capture file closes.
216  */
217 typedef struct {
218     const wg_skey_t    *initiator_skey;     /* Spub_i based on Initiation.static (decrypted, null if decryption failed) */
219     const wg_skey_t    *responder_skey;     /* Spub_r based on Initiation.MAC1 (+Spriv_r if available) */
220     guint8              timestamp[12];      /* Initiation.timestamp (decrypted) */
221     gboolean            timestamp_ok : 1;   /* Whether the timestamp was successfully decrypted */
222     gboolean            empty_ok : 1;       /* Whether the empty field was successfully decrypted */
223 
224     /* The following fields are only valid on the initial pass. */
225     const wg_ekey_t    *initiator_ekey;     /* Epub_i matching Initiation.Ephemeral (+Epriv_i if available) */
226     const wg_ekey_t    *responder_ekey;     /* Epub_r matching Response.Ephemeral (+Epriv_r if available) */
227     wg_qqword           handshake_hash;     /* Handshake hash H_i */
228     wg_qqword           chaining_key;       /* Chaining key C_i */
229 
230     /* Transport ciphers. */
231     gcry_cipher_hd_t    initiator_recv_cipher;
232     gcry_cipher_hd_t    responder_recv_cipher;
233 } wg_handshake_state_t;
234 
235 /** Hash(CONSTRUCTION), initialized by wg_decrypt_init. */
236 static wg_qqword hash_of_construction;
237 /** Hash(Hash(CONSTRUCTION) || IDENTIFIER), initialized by wg_decrypt_init. */
238 static wg_qqword hash_of_c_identifier;
239 /* Decryption types. }}} */
240 #endif /* WG_DECRYPTION_SUPPORTED */
241 
242 /*
243  * Information required to process and link messages as required on the first
244  * sequential pass. After that it can be erased.
245  */
246 typedef struct {
247     address     initiator_address;
248     address     responder_address;
249     guint16     initiator_port;
250     guint16     responder_port;
251 } wg_initial_info_t;
252 
253 /*
254  * A "session" between two peer is identified by a "sender" id as independently
255  * chosen by each side. In case both peer IDs collide, the source IP and UDP
256  * port number could be used to distinguish sessions. As IDs can be recycled
257  * over time, lookups should use the most recent initiation (or response).
258  *
259  * XXX record timestamps (time since last message, for validating timers).
260  */
261 typedef struct {
262     guint32     stream;             /* Session identifier (akin to udp.stream). */
263     guint32     initiator_frame;
264     guint32     response_frame;     /* Responder or Cookie Reply message. */
265     wg_initial_info_t initial;      /* Valid only on the first pass. */
266 #ifdef WG_DECRYPTION_SUPPORTED
267     wg_handshake_state_t *hs;       /* Handshake state to enable decryption. */
268 #endif /* WG_DECRYPTION_SUPPORTED */
269 } wg_session_t;
270 
271 /* Per-packet state. */
272 typedef struct {
273     wg_session_t   *session;
274     gboolean        receiver_is_initiator;  /* Whether this transport data packet is sent to an Initiator. */
275 } wg_packet_info_t;
276 
277 /* Map from Sender/Receiver IDs to a list of session information. */
278 static wmem_map_t *sessions;
279 static guint32 wg_session_count;
280 
281 
282 #ifdef WG_DECRYPTION_SUPPORTED
283 /* Key conversion routines. {{{ */
284 /* Import external random data as private key. */
285 static void
set_private_key(wg_qqword * privkey,const wg_qqword * inkey)286 set_private_key(wg_qqword *privkey, const wg_qqword *inkey)
287 {
288     // The 254th bit of a Curve25519 secret will always be set in calculations,
289     // use this property to recognize whether a private key is set.
290     *privkey = *inkey;
291     privkey->data[31] |= 64;
292 }
293 
294 /* Whether a private key is initialized (see set_private_key). */
295 static inline gboolean
has_private_key(const wg_qqword * secret)296 has_private_key(const wg_qqword *secret)
297 {
298     return !!(secret->data[31] & 64);
299 }
300 
301 /**
302  * Compute the Curve25519 public key from a private key.
303  */
304 static void
priv_to_pub(wg_qqword * pub,const wg_qqword * priv)305 priv_to_pub(wg_qqword *pub, const wg_qqword *priv)
306 {
307     int r = crypto_scalarmult_curve25519_base(pub->data, priv->data);
308     /* The computation should always be possible. */
309     DISSECTOR_ASSERT(r == 0);
310 }
311 
312 static void
dh_x25519(wg_qqword * shared_secret,const wg_qqword * priv,const wg_qqword * pub)313 dh_x25519(wg_qqword *shared_secret, const wg_qqword *priv, const wg_qqword *pub)
314 {
315     /*
316      * If the point ("pub") is of small order, of if the result is all zeros, -1
317      * could be returned with Sodium. We are just interpreting the trace, so
318      * just ignore the condition for now.
319      */
320     (void)crypto_scalarmult_curve25519(shared_secret->data, priv->data, pub->data);
321 }
322 
323 /*
324  * Returns the string representation (base64) of a public key.
325  * The returned value is allocated with wmem_packet_scope.
326  */
327 static const char *
pubkey_to_string(const wg_qqword * pubkey)328 pubkey_to_string(const wg_qqword *pubkey)
329 {
330     gchar *str = g_base64_encode(pubkey->data, WG_KEY_LEN);
331     gchar *ret = wmem_strdup(wmem_packet_scope(), str);
332     g_free(str);
333     return ret;
334 }
335 
336 static gboolean
decode_base64_key(wg_qqword * out,const char * str)337 decode_base64_key(wg_qqword *out, const char *str)
338 {
339     gsize out_len;
340     gchar tmp[45];
341 
342     if (strlen(str) + 1 != sizeof(tmp)) {
343         return FALSE;
344     }
345     memcpy(tmp, str, sizeof(tmp));
346     g_base64_decode_inplace(tmp, &out_len);
347     if (out_len != WG_KEY_LEN) {
348         return FALSE;
349     }
350     memcpy(out->data, tmp, WG_KEY_LEN);
351     return TRUE;
352 }
353 /* Key conversion routines. }}} */
354 
355 static gboolean
wg_pubkey_equal(gconstpointer v1,gconstpointer v2)356 wg_pubkey_equal(gconstpointer v1, gconstpointer v2)
357 {
358     const wg_qqword *pubkey1 = (const wg_qqword *)v1;
359     const wg_qqword *pubkey2 = (const wg_qqword *)v2;
360     return !memcmp(pubkey1->data, pubkey2->data, WG_KEY_LEN);
361 }
362 
363 
364 /* Protocol-specific crypto routines. {{{ */
365 /**
366  * Computes MAC1. Caller must ensure that GCRY_MD_BLAKE2S_256 is available.
367  */
368 static void
wg_mac1_key(const wg_qqword * static_public,wg_qqword * mac_key_out)369 wg_mac1_key(const wg_qqword *static_public, wg_qqword *mac_key_out)
370 {
371     gcry_md_hd_t hd;
372     if (gcry_md_open(&hd, GCRY_MD_BLAKE2S_256, 0) == 0) {
373         const char wg_label_mac1[] = "mac1----";
374         gcry_md_write(hd, wg_label_mac1, strlen(wg_label_mac1));
375         gcry_md_write(hd, static_public->data, sizeof(wg_qqword));
376         memcpy(mac_key_out->data, gcry_md_read(hd, 0), sizeof(wg_qqword));
377         gcry_md_close(hd);
378         return;
379     }
380     // caller should have checked this.
381     DISSECTOR_ASSERT_NOT_REACHED();
382 }
383 
384 /*
385  * Verify that MAC(mac_key, data) matches "mac_output".
386  */
387 static gboolean
wg_mac_verify(const wg_qqword * mac_key,const guchar * data,guint data_len,const guint8 mac_output[16])388 wg_mac_verify(const wg_qqword *mac_key,
389               const guchar *data, guint data_len, const guint8 mac_output[16])
390 {
391     gboolean ok = FALSE;
392     gcry_md_hd_t hd;
393     if (gcry_md_open(&hd, GCRY_MD_BLAKE2S_128, 0) == 0) {
394         gcry_error_t r;
395         // not documented by Libgcrypt, but required for keyed blake2s
396         r = gcry_md_setkey(hd, mac_key->data, WG_KEY_LEN);
397         DISSECTOR_ASSERT(r == 0);
398         gcry_md_write(hd, data, data_len);
399         ok = memcmp(mac_output, gcry_md_read(hd, 0), 16) == 0;
400         gcry_md_close(hd);
401     } else {
402         // caller should have checked this.
403         DISSECTOR_ASSERT_NOT_REACHED();
404     }
405     return ok;
406 }
407 
408 /**
409  * Update the new chained hash value: h = Hash(h || data).
410  */
411 static void
wg_mix_hash(wg_qqword * h,const void * data,size_t data_len)412 wg_mix_hash(wg_qqword *h, const void *data, size_t data_len)
413 {
414     gcry_md_hd_t hd;
415     if (gcry_md_open(&hd, GCRY_MD_BLAKE2S_256, 0)) {
416         DISSECTOR_ASSERT_NOT_REACHED();
417     }
418     gcry_md_write(hd, h->data, sizeof(wg_qqword));
419     gcry_md_write(hd, data, data_len);
420     memcpy(h, gcry_md_read(hd, 0), sizeof(wg_qqword));
421     gcry_md_close(hd);
422 }
423 
424 /**
425  * Computes KDF_n(key, input) where n is the number of derived keys.
426  */
427 static void
wg_kdf(const wg_qqword * key,const guint8 * input,guint input_len,guint n,wg_qqword * out)428 wg_kdf(const wg_qqword *key, const guint8 *input, guint input_len, guint n, wg_qqword *out)
429 {
430     guint8          prk[32];    /* Blake2s_256 hash output. */
431     gcry_error_t    err;
432     err = hkdf_extract(GCRY_MD_BLAKE2S_256, key->data, sizeof(wg_qqword), input, input_len, prk);
433     DISSECTOR_ASSERT(err == 0);
434     err = hkdf_expand(GCRY_MD_BLAKE2S_256, prk, sizeof(prk), NULL, 0, out->data, 32 * n);
435     DISSECTOR_ASSERT(err == 0);
436 }
437 
438 /*
439  * Must be called before attempting decryption.
440  */
441 static gboolean
wg_decrypt_init(void)442 wg_decrypt_init(void)
443 {
444     if (gcry_md_test_algo(GCRY_MD_BLAKE2S_128) != 0 ||
445         gcry_md_test_algo(GCRY_MD_BLAKE2S_256) != 0 ||
446         gcry_cipher_test_algo(GCRY_CIPHER_CHACHA20) != 0) {
447         return FALSE;
448     }
449     static const char construction[] = "Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s";
450     gcry_md_hash_buffer(GCRY_MD_BLAKE2S_256, hash_of_construction.data, construction, strlen(construction));
451 
452     static const char wg_identifier[] = "WireGuard v1 zx2c4 Jason@zx2c4.com";
453     memcpy(&hash_of_c_identifier, hash_of_construction.data, sizeof(wg_qqword));
454     wg_mix_hash(&hash_of_c_identifier, wg_identifier, strlen(wg_identifier));
455     return TRUE;
456 }
457 
458 static gcry_cipher_hd_t
wg_create_cipher(const wg_qqword * key)459 wg_create_cipher(const wg_qqword *key)
460 {
461     gcry_cipher_hd_t    hd;
462     if (gcry_cipher_open(&hd, GCRY_CIPHER_CHACHA20, GCRY_CIPHER_MODE_POLY1305, 0)) {
463         return NULL;
464     }
465 
466     if (gcry_cipher_setkey(hd, key->data, sizeof(*key))) {
467         gcry_cipher_close(hd);
468         hd = NULL;
469     }
470     return hd;
471 }
472 
473 static gboolean
wg_handshake_state_destroy_cb(wmem_allocator_t * allocator _U_,wmem_cb_event_t event _U_,void * user_data)474 wg_handshake_state_destroy_cb(wmem_allocator_t *allocator _U_, wmem_cb_event_t event _U_, void *user_data)
475 {
476     wg_handshake_state_t *hs = (wg_handshake_state_t *)user_data;
477 
478     if (hs->initiator_recv_cipher) {
479         gcry_cipher_close(hs->initiator_recv_cipher);
480         hs->initiator_recv_cipher = NULL;
481     }
482     if (hs->responder_recv_cipher) {
483         gcry_cipher_close(hs->responder_recv_cipher);
484         hs->responder_recv_cipher = NULL;
485     }
486     return FALSE;
487 }
488 
489 /*
490  * Decrypt ciphertext using the ChaCha20-Poly1305 cipher. The auth tag must be
491  * included with the ciphertext.
492  */
493 static gboolean
wg_aead_decrypt(gcry_cipher_hd_t hd,guint64 counter,const guchar * ctext,guint ctext_len,const guchar * aad,guint aad_len,guchar * out,guint out_len)494 wg_aead_decrypt(gcry_cipher_hd_t hd, guint64 counter, const guchar *ctext, guint ctext_len, const guchar *aad, guint aad_len, guchar *out, guint out_len)
495 {
496     DISSECTOR_ASSERT(ctext_len >= AUTH_TAG_LENGTH);
497     ctext_len -= AUTH_TAG_LENGTH;
498     const guchar *auth_tag = ctext + ctext_len;
499 
500     counter = GUINT64_TO_LE(counter);
501     guchar nonce[12] = { 0 };
502     memcpy(nonce + 4, &counter, 8);
503 
504     return gcry_cipher_setiv(hd, nonce, sizeof(nonce)) == 0 &&
505         gcry_cipher_authenticate(hd, aad, aad_len) == 0 &&
506         gcry_cipher_decrypt(hd, out, out_len, ctext, ctext_len) == 0 &&
507         gcry_cipher_checktag(hd, auth_tag, AUTH_TAG_LENGTH) == 0;
508 }
509 
510 /**
511  * Decrypt ciphertext using the ChaCha20-Poly1305 cipher. The auth tag must be
512  * included with the ciphertext.
513  */
514 static gboolean
aead_decrypt(const wg_qqword * key,guint64 counter,const guchar * ctext,guint ctext_len,const guchar * aad,guint aad_len,guchar * out,guint out_len)515 aead_decrypt(const wg_qqword *key, guint64 counter, const guchar *ctext, guint ctext_len, const guchar *aad, guint aad_len, guchar *out, guint out_len)
516 {
517     DISSECTOR_ASSERT(ctext_len >= AUTH_TAG_LENGTH);
518 
519     gcry_cipher_hd_t hd = wg_create_cipher(key);
520     DISSECTOR_ASSERT(hd);
521     gboolean ok = wg_aead_decrypt(hd, counter, ctext, ctext_len, aad, aad_len, out, out_len);
522     gcry_cipher_close(hd);
523     return ok;
524 }
525 /* Protocol-specific crypto routines. }}} */
526 
527 /*
528  * Add a static public or private key to "wg_static_keys".
529  */
530 static void
wg_add_static_key(const wg_qqword * tmp_key,gboolean is_private)531 wg_add_static_key(const wg_qqword *tmp_key, gboolean is_private)
532 {
533     wg_skey_t *key = g_new0(wg_skey_t, 1);
534     if (is_private) {
535         set_private_key(&key->priv_key, tmp_key);
536         priv_to_pub(&key->pub_key, tmp_key);
537     } else {
538         key->pub_key = *tmp_key;
539     }
540 
541     // If a previous pubkey exists, skip adding the new key. Do add the
542     // secret if it has become known in meantime.
543     wg_skey_t *oldkey = (wg_skey_t *)g_hash_table_lookup(wg_static_keys, &key->pub_key);
544     if (oldkey) {
545         if (!has_private_key(&oldkey->priv_key) && is_private) {
546             oldkey->priv_key = key->priv_key;
547         }
548         g_free(key);
549         return;
550     }
551 
552     // New key, precompute the MAC1 label.
553     wg_mac1_key(&key->pub_key, &key->mac1_key);
554 
555     g_hash_table_insert(wg_static_keys, &key->pub_key, key);
556 }
557 
558 /**
559  * Stores the given ephemeral private key.
560  */
561 static wg_ekey_t *
wg_add_ephemeral_privkey(const wg_qqword * priv_key)562 wg_add_ephemeral_privkey(const wg_qqword *priv_key)
563 {
564     wg_qqword pub_key;
565     priv_to_pub(&pub_key, priv_key);
566     wg_ekey_t *key = (wg_ekey_t *)wmem_map_lookup(wg_ephemeral_keys, &pub_key);
567     if (!key) {
568         key = wmem_new0(wmem_file_scope(), wg_ekey_t);
569         key->pub_key = pub_key;
570         set_private_key(&key->priv_key, priv_key);
571         wmem_map_insert(wg_ephemeral_keys, &key->pub_key, key);
572     }
573     return key;
574 }
575 
576 /* PSK handling. {{{ */
577 static void
wg_add_psk(wg_ekey_t * ekey,const wg_qqword * psk)578 wg_add_psk(wg_ekey_t *ekey, const wg_qqword *psk)
579 {
580     wg_psk_t *psk_entry = wmem_new0(wmem_file_scope(), wg_psk_t);
581     psk_entry->psk_data = *psk;
582     psk_entry->next = ekey->psk_list;
583     ekey->psk_list = psk_entry;
584 }
585 
586 /*
587  * Retrieves the next PSK to try and returns TRUE if one is found or FALSE if
588  * there are no more to try.
589  */
590 static gboolean
wg_psk_iter_next(wg_psk_iter_context * psk_iter,const wg_handshake_state_t * hs,wg_qqword * psk_out)591 wg_psk_iter_next(wg_psk_iter_context *psk_iter, const wg_handshake_state_t *hs,
592                  wg_qqword *psk_out)
593 {
594     wg_psk_t *psk = psk_iter->next_psk;
595     while (!psk) {
596         /*
597          * Yield PSKs based on Epub_i, then those based on Epub_r, then yield an
598          * all-zeroes key and finally fail in the terminating state.
599          */
600         switch (psk_iter->state) {
601             case WG_PSK_ITER_STATE_ENTER:
602                 psk = hs->initiator_ekey->psk_list;
603                 psk_iter->state = WG_PSK_ITER_STATE_INITIATOR;
604                 break;
605             case WG_PSK_ITER_STATE_INITIATOR:
606                 psk = hs->responder_ekey->psk_list;
607                 psk_iter->state = WG_PSK_ITER_STATE_RESPONDER;
608                 break;
609             case WG_PSK_ITER_STATE_RESPONDER:
610                 memset(psk_out->data, 0, WG_KEY_LEN);
611                 psk_iter->state = WG_PSK_ITER_STATE_EXIT;
612                 return TRUE;
613             case WG_PSK_ITER_STATE_EXIT:
614                 return FALSE;
615         }
616     }
617 
618     *psk_out = psk->psk_data;
619     psk_iter->next_psk = psk->next;
620     return TRUE;
621 }
622 /* PSK handling. }}} */
623 
624 /* UAT and key configuration. {{{ */
625 
626 static void
wg_keylog_reset(void)627 wg_keylog_reset(void)
628 {
629     if (wg_keylog_file) {
630         fclose(wg_keylog_file);
631         wg_keylog_file = NULL;
632         wg_keylog_last_ekey = NULL;
633     }
634 }
635 
636 static void wg_keylog_process_lines(const void *data, guint datalen);
637 
638 static void
wg_keylog_read(void)639 wg_keylog_read(void)
640 {
641     if (!pref_keylog_file || !*pref_keylog_file) {
642         return;
643     }
644 
645     // Reopen file if it got deleted/overwritten.
646     if (wg_keylog_file && file_needs_reopen(ws_fileno(wg_keylog_file), pref_keylog_file)) {
647         ws_debug("Key log file got changed or deleted, trying to re-open.");
648         wg_keylog_reset();
649     }
650 
651     if (!wg_keylog_file) {
652         wg_keylog_file = ws_fopen(pref_keylog_file, "r");
653         if (!wg_keylog_file) {
654             ws_debug("Failed to open key log file %s: %s", pref_keylog_file, g_strerror(errno));
655             return;
656         }
657         ws_debug("Opened key log file %s", pref_keylog_file);
658     }
659 
660     /* File format: each line follows the format "<type>=<key>" (leading spaces
661      * and spaces around '=' as produced by extract-handshakes.sh are ignored).
662      * For available <type>s, see below. <key> is the base64-encoded key (44
663      * characters).
664      *
665      * Example:
666      *  LOCAL_STATIC_PRIVATE_KEY = AKeZaHwBxjiKLFnkY2unvEdOTtg4AL+M9dQXfopFVFk=
667      *  REMOTE_STATIC_PUBLIC_KEY = YDCttCs9e1J52/g9vEnwJJa+2x6RqaayAYMpSVQfGEY=
668      *  LOCAL_EPHEMERAL_PRIVATE_KEY = sLGLJSOQfyz7JNJ5ZDzFf3Uz1rkiCMMjbWerNYcPFFU=
669      *  PRESHARED_KEY = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
670      */
671 
672     for (;;) {
673         char buf[512];
674         if (!fgets(buf, sizeof(buf), wg_keylog_file)) {
675             if (feof(wg_keylog_file)) {
676                 clearerr(wg_keylog_file);
677             } else if (ferror(wg_keylog_file)) {
678                 ws_debug("Error while reading %s, closing it.", pref_keylog_file);
679                 wg_keylog_reset();
680             }
681             break;
682         }
683 
684         wg_keylog_process_lines((const guint8 *)buf, (guint)strlen(buf));
685     }
686 }
687 
688 static void
wg_keylog_process_lines(const void * data,guint datalen)689 wg_keylog_process_lines(const void *data, guint datalen)
690 {
691     const char *next_line = (const char *)data;
692     const char *line_end = next_line + datalen;
693     while (next_line && next_line < line_end) {
694         /* Note: line is NOT nul-terminated. */
695         const char *line = next_line;
696         next_line = (const char *)memchr(line, '\n', line_end - line);
697         gssize linelen;
698 
699         if (next_line) {
700             linelen = next_line - line;
701             next_line++;    /* drop LF */
702         } else {
703             linelen = (gssize)(line_end - line);
704         }
705         if (linelen > 0 && line[linelen - 1] == '\r') {
706             linelen--;      /* drop CR */
707         }
708 
709         ws_debug("Read WG key log line: %.*s", (int)linelen, line);
710 
711         /* Strip leading spaces. */
712         const char *p = line;
713         while (p < line_end && *p == ' ') {
714             ++p;
715         }
716         char key_type[sizeof("LOCAL_EPHEMERAL_PRIVATE_KEY")];
717         char key_value[45] = { 0 };
718         const char *p0 = p;
719         p = (const char *)memchr(p0, '=', line_end - p);
720         if (p && p0 != p) {
721             /* Extract "key-type" from "key-type = key-value" */
722             gsize key_type_len = p - p0;
723             while (key_type_len && p0[key_type_len - 1] == ' ') {
724                 --key_type_len;
725             }
726             if (key_type_len && key_type_len < sizeof(key_type)) {
727                 memcpy(key_type, p0, key_type_len);
728                 key_type[key_type_len] = '\0';
729 
730                 /* Skip '=' and any spaces. */
731                 p = p + 1;
732                 while (p < line_end && *p == ' ') {
733                     ++p;
734                 }
735                 gsize key_value_len = (line + linelen) - p;
736                 if (key_value_len && key_value_len < sizeof(key_value)) {
737                     memcpy(key_value, p, key_value_len);
738                 }
739             }
740         }
741 
742         wg_qqword key;
743         if (!key_value[0] || !decode_base64_key(&key, key_value)) {
744             ws_debug("Unrecognized key log line: %.*s", (int)linelen, line);
745             continue;
746         }
747 
748         if (!strcmp(key_type, "LOCAL_STATIC_PRIVATE_KEY")) {
749             wg_add_static_key(&key, TRUE);
750         } else if (!strcmp(key_type, "REMOTE_STATIC_PUBLIC_KEY")) {
751             wg_add_static_key(&key, FALSE);
752         } else if (!strcmp(key_type, "LOCAL_EPHEMERAL_PRIVATE_KEY")) {
753             wg_keylog_last_ekey = wg_add_ephemeral_privkey(&key);
754         } else if (!strcmp(key_type, "PRESHARED_KEY")) {
755             /* Link the PSK to the last ephemeral key. */
756             if (wg_keylog_last_ekey) {
757                 wg_add_psk(wg_keylog_last_ekey, &key);
758                 wg_keylog_last_ekey = NULL;
759             } else {
760                 ws_debug("Ignored PSK as no new ephemeral key was found");
761             }
762         } else {
763             ws_debug("Unrecognized key log line: %.*s", (int)linelen, line);
764         }
765     }
766 }
767 
768 static void*
wg_key_uat_record_copy_cb(void * dest,const void * source,size_t len _U_)769 wg_key_uat_record_copy_cb(void *dest, const void *source, size_t len _U_)
770 {
771     const wg_key_uat_record_t* o = (const wg_key_uat_record_t*)source;
772     wg_key_uat_record_t* d = (wg_key_uat_record_t*)dest;
773 
774     d->key_type = o->key_type;
775     d->key = g_strdup(o->key);
776 
777     return dest;
778 }
779 
780 static gboolean
wg_key_uat_record_update_cb(void * r,char ** error)781 wg_key_uat_record_update_cb(void *r, char **error)
782 {
783     wg_key_uat_record_t *rec = (wg_key_uat_record_t *)r;
784     wg_qqword key;
785 
786     /* Check for valid base64-encoding. */
787     if (!decode_base64_key(&key, rec->key)) {
788         *error = g_strdup("Invalid key");
789         return FALSE;
790     }
791 
792     return TRUE;
793 }
794 
795 static void
wg_key_uat_record_free_cb(void * r)796 wg_key_uat_record_free_cb(void *r)
797 {
798     wg_key_uat_record_t *rec = (wg_key_uat_record_t *)r;
799     g_free(rec->key);
800 }
801 
802 static void
wg_key_uat_apply(void)803 wg_key_uat_apply(void)
804 {
805     if (!wg_static_keys) {
806         // The first field of "wg_skey_t" is the pubkey (and the table key),
807         // its initial four bytes should be good enough as key hash.
808         wg_static_keys = g_hash_table_new_full(g_int_hash, wg_pubkey_equal, NULL, g_free);
809     } else {
810         g_hash_table_remove_all(wg_static_keys);
811     }
812 
813     // As static keys from the key log file also end up in "wg_static_keys",
814     // reset the file pointer such that it will be fully read later.
815     wg_keylog_reset();
816 
817     /* Convert base64-encoded strings to wg_skey_t and derive pubkey. */
818     for (guint i = 0; i < num_wg_key_records; i++) {
819         wg_key_uat_record_t *rec = &wg_key_records[i];
820         wg_qqword tmp_key;  /* Either public or private, not sure yet. */
821 
822         /* Populate public (and private) keys. */
823         gboolean decoded = decode_base64_key(&tmp_key, rec->key);
824         DISSECTOR_ASSERT(decoded);
825         wg_add_static_key(&tmp_key, rec->key_type == WG_KEY_UAT_PRIVATE);
826     }
827 }
828 
829 static void
wg_key_uat_reset(void)830 wg_key_uat_reset(void)
831 {
832     /* Erase keys when the UAT is unloaded. */
833     if (wg_static_keys != NULL) {
834         g_hash_table_destroy(wg_static_keys);
835         wg_static_keys = NULL;
836     }
837 }
838 
839 UAT_VS_DEF(wg_key_uat, key_type, wg_key_uat_record_t, guint, WG_KEY_UAT_PUBLIC, "Public")
UAT_CSTRING_CB_DEF(wg_key_uat,key,wg_key_uat_record_t)840 UAT_CSTRING_CB_DEF(wg_key_uat, key, wg_key_uat_record_t)
841 /* UAT and key configuration. }}} */
842 
843 /**
844  * Tries to decrypt the initiation message.
845  * Assumes responder_skey and initiator_ekey to be set.
846  */
847 static void
848 wg_process_initiation(tvbuff_t *tvb, wg_handshake_state_t *hs)
849 {
850     DISSECTOR_ASSERT(hs->responder_skey);
851     DISSECTOR_ASSERT(hs->initiator_ekey);
852     DISSECTOR_ASSERT(hs->initiator_skey == NULL);
853 
854     wg_qqword decrypted_static = {{ 0 }};
855     const gboolean has_Spriv_r = has_private_key(&hs->responder_skey->priv_key);
856     const gboolean has_Epriv_i = has_private_key(&hs->initiator_ekey->priv_key);
857 
858     // Either Spriv_r or Epriv_i + Spriv_i are needed. If the first two are not
859     // available, fail early. Spriv_i will be looked up later.
860     if (!has_Spriv_r && !has_Epriv_i) {
861         return;
862     }
863 
864     const wg_qqword *ephemeral = (const wg_qqword *)tvb_get_ptr(tvb, 8, WG_KEY_LEN);
865 #define WG_ENCRYPTED_STATIC_LENGTH      (32 + AUTH_TAG_LENGTH)
866     const guint8 *encrypted_static = (const guint8 *)tvb_get_ptr(tvb, 40, WG_ENCRYPTED_STATIC_LENGTH);
867 #define WG_ENCRYPTED_TIMESTAMP_LENGTH   (12 + AUTH_TAG_LENGTH)
868     const guint8 *encrypted_timestamp = (const guint8 *)tvb_get_ptr(tvb, 88, WG_ENCRYPTED_TIMESTAMP_LENGTH);
869 
870     wg_qqword c_and_k[2], h;
871     wg_qqword *c = &c_and_k[0], *k = &c_and_k[1];
872     // c = Hash(CONSTRUCTION)
873     memcpy(c->data, hash_of_construction.data, sizeof(wg_qqword));
874     // h = Hash(c || IDENTIFIER)
875     memcpy(h.data, hash_of_c_identifier.data, sizeof(wg_qqword));
876     // h = Hash(h || Spub_r)
877     wg_mix_hash(&h, hs->responder_skey->pub_key.data, sizeof(wg_qqword));
878     // c = KDF1(c, msg.ephemeral)
879     wg_kdf(c, ephemeral->data, WG_KEY_LEN, 1, c);
880     // h = Hash(h || msg.ephemeral)
881     wg_mix_hash(&h, ephemeral, WG_KEY_LEN);
882     //  dh1 = DH(Spriv_r, msg.ephemeral)    if kType = R
883     //  dh1 = DH(Epriv_i, Spub_r)           if kType = I
884     wg_qqword dh1 = {{ 0 }};
885     if (has_Spriv_r) {
886         dh_x25519(&dh1, &hs->responder_skey->priv_key, ephemeral);
887     } else {
888         dh_x25519(&dh1, &hs->initiator_ekey->priv_key, &hs->responder_skey->pub_key);
889     }
890     // (c, k) = KDF2(c, dh1)
891     wg_kdf(c, dh1.data, sizeof(dh1), 2, c_and_k);
892     // Spub_i = AEAD-Decrypt(k, 0, msg.static, h)
893     if (!aead_decrypt(k, 0, encrypted_static, WG_ENCRYPTED_STATIC_LENGTH, h.data, sizeof(wg_qqword), decrypted_static.data, sizeof(decrypted_static))) {
894         return;
895     }
896     // Save static public key to the context and lookup private key if possible.
897     wg_skey_t *skey_i = (wg_skey_t *)g_hash_table_lookup(wg_static_keys, &decrypted_static);
898     if (!skey_i) {
899         skey_i = wmem_new0(wmem_file_scope(), wg_skey_t);
900         skey_i->pub_key = decrypted_static;
901     }
902     hs->initiator_skey = skey_i;
903     // If Spriv_r is not available, then Epriv_i + Spriv_i must be available.
904     if (!has_Spriv_r && !has_private_key(&hs->initiator_skey->priv_key)) {
905         return;
906     }
907 
908     // h = Hash(h || msg.static)
909     wg_mix_hash(&h, encrypted_static, WG_ENCRYPTED_STATIC_LENGTH);
910     //  dh2 = DH(Spriv_r, Spub_i)           if kType = R
911     //  dh2 = DH(Spriv_i, Spub_r)           if kType = I
912     wg_qqword dh2 = {{ 0 }};
913     if (has_Spriv_r) {
914         dh_x25519(&dh2, &hs->responder_skey->priv_key, &hs->initiator_skey->pub_key);
915     } else {
916         dh_x25519(&dh2, &hs->initiator_skey->priv_key, &hs->responder_skey->pub_key);
917     }
918     // (c, k) = KDF2(c, dh2)
919     wg_kdf(c, dh2.data, sizeof(wg_qqword), 2, c_and_k);
920     // timestamp = AEAD-Decrypt(k, 0, msg.timestamp, h)
921     if (!aead_decrypt(k, 0, encrypted_timestamp, WG_ENCRYPTED_TIMESTAMP_LENGTH, h.data, sizeof(wg_qqword), hs->timestamp, sizeof(hs->timestamp))) {
922         return;
923     }
924     hs->timestamp_ok = TRUE;
925     // h = Hash(h || msg.timestamp)
926     wg_mix_hash(&h, encrypted_timestamp, WG_ENCRYPTED_TIMESTAMP_LENGTH);
927 
928     // save (h, k) context for responder message processing
929     hs->handshake_hash = h;
930     hs->chaining_key = *c;
931 }
932 
933 static void
wg_process_response(tvbuff_t * tvb,wg_handshake_state_t * hs)934 wg_process_response(tvbuff_t *tvb, wg_handshake_state_t *hs)
935 {
936     DISSECTOR_ASSERT(hs->initiator_ekey);
937     DISSECTOR_ASSERT(hs->initiator_skey);
938     DISSECTOR_ASSERT(hs->responder_ekey);
939     DISSECTOR_ASSERT(hs->responder_skey);
940     // XXX when multiple responses are linkable to a single handshake state,
941     // they should probably fork into a new state or be discarded when equal.
942     if (hs->initiator_recv_cipher || hs->responder_recv_cipher) {
943         ws_warning("%s FIXME multiple responses linked to a single session", G_STRFUNC);
944         return;
945     }
946     DISSECTOR_ASSERT(!hs->initiator_recv_cipher);
947     DISSECTOR_ASSERT(!hs->responder_recv_cipher);
948 
949     const gboolean has_Epriv_i = has_private_key(&hs->initiator_ekey->priv_key);
950     const gboolean has_Spriv_i = has_private_key(&hs->initiator_skey->priv_key);
951     const gboolean has_Epriv_r = has_private_key(&hs->responder_ekey->priv_key);
952 
953     // Either Epriv_i + Spriv_i or Epriv_r + Epub_i + Spub_i are required.
954     if (!(has_Epriv_i && has_Spriv_i) && !has_Epriv_r) {
955         return;
956     }
957 
958     const wg_qqword *ephemeral = (const wg_qqword *)tvb_get_ptr(tvb, 12, WG_KEY_LEN);
959     const guint8 *encrypted_empty = (const guint8 *)tvb_get_ptr(tvb, 44, AUTH_TAG_LENGTH);
960 
961     wg_qqword ctk[3], h;
962     wg_qqword *c = &ctk[0], *t = &ctk[1], *k = &ctk[2];
963     h = hs->handshake_hash;
964     *c = hs->chaining_key;
965 
966     // c = KDF1(c, msg.ephemeral)
967     wg_kdf(c, ephemeral->data, WG_KEY_LEN, 1, c);
968     // h = Hash(h || msg.ephemeral)
969     wg_mix_hash(&h, ephemeral, WG_KEY_LEN);
970     //  dh1 = DH(Epriv_i, msg.ephemeral)    if kType == I
971     //  dh1 = DH(Epriv_r, Epub_i)           if kType == R
972     wg_qqword dh1;
973     if (has_Epriv_i && has_Spriv_i) {
974         dh_x25519(&dh1, &hs->initiator_ekey->priv_key, ephemeral);
975     } else {
976         dh_x25519(&dh1, &hs->responder_ekey->priv_key, &hs->initiator_ekey->pub_key);
977     }
978     // c = KDF1(c, dh1)
979     wg_kdf(c, dh1.data, sizeof(dh1), 1, c);
980     //  dh2 = DH(Spriv_i, msg.ephemeral)    if kType == I
981     //  dh2 = DH(Epriv_r, Spub_i)           if kType == R
982     wg_qqword dh2;
983     if (has_Epriv_i && has_Spriv_i) {
984         dh_x25519(&dh2, &hs->initiator_skey->priv_key, ephemeral);
985     } else {
986         dh_x25519(&dh2, &hs->responder_ekey->priv_key, &hs->initiator_skey->pub_key);
987     }
988     // c = KDF1(c, dh2)
989     wg_kdf(c, dh2.data, sizeof(dh2), 1, c);
990     wg_qqword h_before_psk = h, c_before_psk = *c, psk;
991     wg_psk_iter_context psk_iter = { WG_PSK_ITER_STATE_ENTER, NULL };
992     while (wg_psk_iter_next(&psk_iter, hs, &psk)) {
993         // c, t, k = KDF3(c, PSK)
994         wg_kdf(c, psk.data, WG_KEY_LEN, 3, ctk);
995         // h = Hash(h || t)
996         wg_mix_hash(&h, t, sizeof(wg_qqword));
997         // empty = AEAD-Decrypt(k, 0, msg.empty, h)
998         if (!aead_decrypt(k, 0, encrypted_empty, AUTH_TAG_LENGTH, h.data, sizeof(wg_qqword), NULL, 0)) {
999             /* Possibly bad PSK, reset and try another. */
1000             h = h_before_psk;
1001             *c = c_before_psk;
1002             continue;
1003         }
1004         hs->empty_ok = TRUE;
1005         break;
1006     }
1007     if (!hs->empty_ok) {
1008         return;
1009     }
1010     // h = Hash(h || msg.empty)
1011     wg_mix_hash(&h, encrypted_empty, AUTH_TAG_LENGTH);
1012 
1013     // Calculate transport keys and create ciphers.
1014     // (Tsend_i = Trecv_r, Trecv_i = Tsend_r) = KDF2(C, "")
1015     wg_qqword transport_keys[2];
1016     wg_kdf(c, NULL, 0, 2, transport_keys);
1017 
1018     hs->initiator_recv_cipher = wg_create_cipher(&transport_keys[1]);
1019     hs->responder_recv_cipher = wg_create_cipher(&transport_keys[0]);
1020 }
1021 #endif /* WG_DECRYPTION_SUPPORTED */
1022 
1023 
1024 static void
wg_sessions_insert(guint32 id,wg_session_t * session)1025 wg_sessions_insert(guint32 id, wg_session_t *session)
1026 {
1027     wmem_list_t *list = (wmem_list_t *)wmem_map_lookup(sessions, GUINT_TO_POINTER(id));
1028     if (!list) {
1029         list = wmem_list_new(wmem_file_scope());
1030         wmem_map_insert(sessions, GUINT_TO_POINTER(id), list);
1031     }
1032     wmem_list_append(list, session);
1033 }
1034 
1035 static wg_session_t *
wg_session_new(void)1036 wg_session_new(void)
1037 {
1038     wg_session_t *session = wmem_new0(wmem_file_scope(), wg_session_t);
1039     session->stream = wg_session_count++;
1040     return session;
1041 }
1042 
1043 /* Updates the peer address based on the source address. */
1044 static void
wg_session_update_address(wg_session_t * session,packet_info * pinfo,gboolean sender_is_initiator)1045 wg_session_update_address(wg_session_t *session, packet_info *pinfo, gboolean sender_is_initiator)
1046 {
1047     DISSECTOR_ASSERT(!PINFO_FD_VISITED(pinfo));
1048 
1049     if (sender_is_initiator) {
1050         copy_address_wmem(wmem_file_scope(), &session->initial.initiator_address, &pinfo->src);
1051         session->initial.initiator_port = (guint16)pinfo->srcport;
1052     } else {
1053         copy_address_wmem(wmem_file_scope(), &session->initial.responder_address, &pinfo->src);
1054         session->initial.responder_port = (guint16)pinfo->srcport;
1055     }
1056 }
1057 
1058 /* Finds an initiation message based on the given Receiver ID that was not
1059  * previously associated with a responder message. Returns the session if a
1060  * matching initation message can be found or NULL otherwise.
1061  */
1062 static wg_session_t *
wg_sessions_lookup_initiation(packet_info * pinfo,guint32 receiver_id)1063 wg_sessions_lookup_initiation(packet_info *pinfo, guint32 receiver_id)
1064 {
1065     DISSECTOR_ASSERT(!PINFO_FD_VISITED(pinfo));
1066 
1067     /* Look for the initiation message matching this Receiver ID. */
1068     wmem_list_t *list = (wmem_list_t *)wmem_map_lookup(sessions, GUINT_TO_POINTER(receiver_id));
1069     if (!list) {
1070         return NULL;
1071     }
1072 
1073     /* Walk backwards to find the most recent message first. All packets are
1074      * guaranteed to arrive before this frame because this is the first pass. */
1075     for (wmem_list_frame_t *item = wmem_list_tail(list); item; item = wmem_list_frame_prev(item)) {
1076         wg_session_t *session = (wg_session_t *)wmem_list_frame_data(item);
1077         if (session->initial.initiator_port != pinfo->destport ||
1078             !addresses_equal(&session->initial.initiator_address, &pinfo->dst)) {
1079             /* Responder messages are expected to be sent to the initiator. */
1080             continue;
1081         }
1082         if (session->response_frame && session->response_frame != pinfo->num) {
1083             /* This session was linked elsewhere. */
1084             continue;
1085         }
1086 
1087         /* This assumes no malicious messages and no contrived sequences:
1088          * Any initiator or responder message is not duplicated nor are these
1089          * mutated. If this must be detected, the caller could decrypt or check
1090          * mac1 to distinguish valid messages.
1091          */
1092         return session;
1093     }
1094 
1095     return NULL;
1096 }
1097 
1098 /* Finds a session with a completed handshake that matches the Receiver ID. */
1099 static wg_session_t *
wg_sessions_lookup(packet_info * pinfo,guint32 receiver_id,gboolean * receiver_is_initiator)1100 wg_sessions_lookup(packet_info *pinfo, guint32 receiver_id, gboolean *receiver_is_initiator)
1101 {
1102     DISSECTOR_ASSERT(!PINFO_FD_VISITED(pinfo));
1103 
1104     wmem_list_t *list = (wmem_list_t *)wmem_map_lookup(sessions, GUINT_TO_POINTER(receiver_id));
1105     if (!list) {
1106         return NULL;
1107     }
1108 
1109     /* Walk backwards to find the most recent message first. */
1110     for (wmem_list_frame_t *item = wmem_list_tail(list); item; item = wmem_list_frame_prev(item)) {
1111         wg_session_t *session = (wg_session_t *)wmem_list_frame_data(item);
1112         if (!session->response_frame) {
1113             /* Ignore sessions that are not fully established. */
1114             continue;
1115         }
1116         if (session->initial.initiator_port == pinfo->destport &&
1117             addresses_equal(&session->initial.initiator_address, &pinfo->dst)) {
1118             *receiver_is_initiator = TRUE;
1119         } else if (session->initial.responder_port == pinfo->destport &&
1120                    addresses_equal(&session->initial.responder_address, &pinfo->dst)) {
1121             *receiver_is_initiator = FALSE;
1122         } else {
1123             /* Both peers do not match the destination, ignore. */
1124             continue;
1125         }
1126         return session;
1127     }
1128 
1129     return NULL;
1130 }
1131 
1132 #ifdef WG_DECRYPTION_SUPPORTED
1133 /*
1134  * Finds the static public key for the receiver of this message based on the
1135  * MAC1 value.
1136  * TODO on PINFO_FD_VISITED, reuse previously discovered keys from session?
1137  */
1138 static const wg_skey_t *
wg_mac1_key_probe(tvbuff_t * tvb,gboolean is_initiation)1139 wg_mac1_key_probe(tvbuff_t *tvb, gboolean is_initiation)
1140 {
1141     const int mac1_offset = is_initiation ? 116 : 60;
1142 
1143     // Shortcut: skip MAC1 validation if no pubkeys are configured.
1144     if (g_hash_table_size(wg_static_keys) == 0) {
1145         return NULL;
1146     }
1147 
1148     guint8 *mac1_msgdata = (guint8 *)tvb_memdup(wmem_packet_scope(), tvb, 0, mac1_offset);
1149     const guint8 *mac1_output = tvb_get_ptr(tvb, mac1_offset, 16);
1150 
1151     // MAC1 is computed over a message with three reserved bytes set to zero.
1152     mac1_msgdata[1] = mac1_msgdata[2] = mac1_msgdata[3] = 0;
1153 
1154     // Find public key that matches the 16-byte MAC1 field.
1155     GHashTableIter iter;
1156     gpointer value;
1157     g_hash_table_iter_init(&iter, wg_static_keys);
1158     while (g_hash_table_iter_next(&iter, NULL, &value)) {
1159         const wg_skey_t *skey = (wg_skey_t *)value;
1160         if (wg_mac_verify(&skey->mac1_key, mac1_msgdata, (guint)mac1_offset, mac1_output)) {
1161             return skey;
1162         }
1163     }
1164 
1165     return NULL;
1166 }
1167 
1168 /*
1169  * Builds the handshake decryption state when sufficient keying material is
1170  * available from the initiation message.
1171  */
1172 static wg_handshake_state_t *
wg_prepare_handshake_keys(const wg_skey_t * skey_r,tvbuff_t * tvb)1173 wg_prepare_handshake_keys(const wg_skey_t *skey_r, tvbuff_t *tvb)
1174 {
1175     wg_handshake_state_t *hs;
1176     gboolean has_r_keys = skey_r && has_private_key(&skey_r->priv_key);
1177     wg_ekey_t *ekey_i = (wg_ekey_t *)wmem_map_lookup(wg_ephemeral_keys, tvb_get_ptr(tvb, 8, WG_KEY_LEN));
1178 
1179     // If neither private keys are available, do not create a session.
1180     if (!has_r_keys && !ekey_i) {
1181         return NULL;
1182     }
1183 
1184     // Even if Spriv_r is available, store Epub_i for Response decryption.
1185     if (!ekey_i) {
1186         ekey_i = wmem_new0(wmem_file_scope(), wg_ekey_t);
1187         tvb_memcpy(tvb, ekey_i->pub_key.data, 8, WG_KEY_LEN);
1188     }
1189 
1190     hs = wmem_new0(wmem_file_scope(), wg_handshake_state_t);
1191     hs->responder_skey = skey_r;
1192     hs->initiator_ekey = ekey_i;
1193     wmem_register_callback(wmem_file_scope(), wg_handshake_state_destroy_cb, hs);
1194     return hs;
1195 }
1196 
1197 /*
1198  * Processes a Response message, storing additional keys in the state.
1199  */
1200 static void
wg_prepare_handshake_responder_keys(wg_handshake_state_t * hs,tvbuff_t * tvb)1201 wg_prepare_handshake_responder_keys(wg_handshake_state_t *hs, tvbuff_t *tvb)
1202 {
1203     wg_ekey_t *ekey_r = (wg_ekey_t *)wmem_map_lookup(wg_ephemeral_keys, tvb_get_ptr(tvb, 12, WG_KEY_LEN));
1204 
1205     // Response decryption needs Epriv_r (or Epub_r + additional secrets).
1206     if (!ekey_r) {
1207         ekey_r = wmem_new0(wmem_file_scope(), wg_ekey_t);
1208         tvb_memcpy(tvb, ekey_r->pub_key.data, 12, WG_KEY_LEN);
1209     }
1210 
1211     hs->responder_ekey = ekey_r;
1212 }
1213 
1214 /* Converts a TAI64 label to the seconds since the Unix epoch.
1215  * See https://cr.yp.to/libtai/tai64.html */
tai64n_to_unix(guint64 tai64_label,guint32 nanoseconds,nstime_t * nstime)1216 static gboolean tai64n_to_unix(guint64 tai64_label, guint32 nanoseconds, nstime_t *nstime)
1217 {
1218     const guint64 pow2_62 = 1ULL << 62;
1219     if (tai64_label < pow2_62 || tai64_label >= (1ULL << 63) || nanoseconds > 999999999) {
1220         // Seconds before 1970 and values larger than 2^63 (reserved) cannot
1221         // be represented. Nanoseconds must also be valid.
1222         return FALSE;
1223     }
1224 
1225     // TODO this can result in loss of precision
1226     nstime->secs = (time_t)(tai64_label - pow2_62);
1227     nstime->nsecs = (int)nanoseconds;
1228     return TRUE;
1229 }
1230 
1231 static void
wg_dissect_key_extra(proto_tree * tree,tvbuff_t * tvb,const wg_qqword * pubkey,gboolean is_ephemeral)1232 wg_dissect_key_extra(proto_tree *tree, tvbuff_t *tvb, const wg_qqword *pubkey, gboolean is_ephemeral)
1233 {
1234     guint32 has_private = FALSE;
1235     proto_item *ti;
1236 
1237     if (is_ephemeral) {
1238         wg_ekey_t *ekey = (wg_ekey_t *)wmem_map_lookup(wg_ephemeral_keys, pubkey->data);
1239         has_private = ekey && has_private_key(&ekey->priv_key);
1240     } else {
1241         wg_skey_t *skey = (wg_skey_t *)g_hash_table_lookup(wg_static_keys, pubkey->data);
1242         has_private = skey && has_private_key(&skey->priv_key);
1243         ti = proto_tree_add_boolean(tree, hf_wg_static_known_pubkey, tvb, 0, 0, !!skey);
1244         proto_item_set_generated(ti);
1245     }
1246 
1247     int hf_known_privkey = is_ephemeral ? hf_wg_ephemeral_known_privkey : hf_wg_static_known_privkey;
1248     ti = proto_tree_add_boolean(tree, hf_known_privkey, tvb, 0, 0, has_private);
1249     proto_item_set_generated(ti);
1250 }
1251 #endif /* WG_DECRYPTION_SUPPORTED */
1252 
1253 
1254 static void
wg_dissect_pubkey(proto_tree * tree,tvbuff_t * tvb,int offset,gboolean is_ephemeral)1255 wg_dissect_pubkey(proto_tree *tree, tvbuff_t *tvb, int offset, gboolean is_ephemeral)
1256 {
1257     const guint8 *pubkey = tvb_get_ptr(tvb, offset, 32);
1258     gchar *str = g_base64_encode(pubkey, 32);
1259     gchar *key_str = wmem_strdup(wmem_packet_scope(), str);
1260     g_free(str);
1261 
1262     int hf_id = is_ephemeral ? hf_wg_ephemeral : hf_wg_static;
1263 #ifdef WG_DECRYPTION_SUPPORTED
1264     proto_item *ti = proto_tree_add_string(tree, hf_id, tvb, offset, 32, key_str);
1265     proto_tree *key_tree = proto_item_add_subtree(ti, ett_key_info);
1266     wg_dissect_key_extra(key_tree, tvb, (const wg_qqword *)pubkey, is_ephemeral);
1267 #else
1268     proto_tree_add_string(tree, hf_id, tvb, offset, 32, key_str);
1269 #endif
1270 }
1271 
1272 #ifdef WG_DECRYPTION_SUPPORTED
1273 static void
wg_dissect_decrypted_static(tvbuff_t * tvb,packet_info * pinfo,proto_tree * wg_tree,wg_handshake_state_t * hs)1274 wg_dissect_decrypted_static(tvbuff_t *tvb, packet_info *pinfo, proto_tree *wg_tree, wg_handshake_state_t *hs)
1275 {
1276     tvbuff_t   *new_tvb;
1277 
1278     if (!hs || !hs->initiator_skey) {
1279         return;
1280     }
1281 
1282     new_tvb = tvb_new_child_real_data(tvb, hs->initiator_skey->pub_key.data, WG_KEY_LEN, WG_KEY_LEN);
1283     add_new_data_source(pinfo, new_tvb, "Decrypted Static");
1284     wg_dissect_pubkey(wg_tree, new_tvb, 0, FALSE);
1285 }
1286 
1287 static void
wg_dissect_decrypted_timestamp(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,wg_handshake_state_t * hs)1288 wg_dissect_decrypted_timestamp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, wg_handshake_state_t *hs)
1289 {
1290     guint64     tai64_label;
1291     guint32     nanoseconds;
1292     nstime_t    nstime;
1293     proto_item *ti;
1294     tvbuff_t   *new_tvb;
1295 
1296     if (!hs || !hs->timestamp_ok) {
1297         return;
1298     }
1299 
1300     new_tvb = tvb_new_child_real_data(tvb, hs->timestamp, sizeof(hs->timestamp), sizeof(hs->timestamp));
1301     add_new_data_source(pinfo, new_tvb, "Decrypted Timestamp");
1302 
1303     tai64_label = tvb_get_guint64(new_tvb, 0, ENC_BIG_ENDIAN);
1304     nanoseconds = tvb_get_guint32(new_tvb, 8, ENC_BIG_ENDIAN);
1305     if (tai64n_to_unix(tai64_label, nanoseconds, &nstime)) {
1306         ti = proto_tree_add_time(tree, hf_wg_timestamp_value, new_tvb, 0, 12, &nstime);
1307         tree = proto_item_add_subtree(ti, ett_timestamp);
1308     }
1309     proto_tree_add_item(tree, hf_wg_timestamp_tai64_label, new_tvb, 0, 8, ENC_BIG_ENDIAN);
1310     proto_tree_add_item(tree, hf_wg_timestamp_nanoseconds, new_tvb, 8, 4, ENC_BIG_ENDIAN);
1311 }
1312 
1313 static void
wg_dissect_decrypted_packet(tvbuff_t * tvb,packet_info * pinfo,proto_tree * wg_tree,wg_packet_info_t * wg_pinfo,guint64 counter,gint plain_length)1314 wg_dissect_decrypted_packet(tvbuff_t *tvb, packet_info *pinfo, proto_tree *wg_tree, wg_packet_info_t *wg_pinfo, guint64 counter, gint plain_length)
1315 {
1316     wg_handshake_state_t *hs = wg_pinfo->session->hs;
1317     gcry_cipher_hd_t cipher = wg_pinfo->receiver_is_initiator ? hs->initiator_recv_cipher : hs->responder_recv_cipher;
1318     if (!cipher) {
1319         return;
1320     }
1321 
1322     DISSECTOR_ASSERT(plain_length >= 0);
1323     const gint ctext_len = plain_length + AUTH_TAG_LENGTH;
1324     const guchar *ctext = tvb_get_ptr(tvb, 16, ctext_len);
1325     guchar *plain = (guchar *)wmem_alloc0(pinfo->pool, (guint)plain_length);
1326     if (!wg_aead_decrypt(cipher, counter, ctext, (guint)ctext_len, NULL, 0, plain, (guint)plain_length)) {
1327         proto_tree_add_expert(wg_tree, pinfo, &ei_wg_decryption_error, tvb, 16, ctext_len);
1328         return;
1329     }
1330     if (plain_length == 0) {
1331         return;
1332     }
1333 
1334     tvbuff_t *new_tvb = tvb_new_child_real_data(tvb, plain, (guint)plain_length, plain_length);
1335     add_new_data_source(pinfo, new_tvb, "Decrypted Packet");
1336 
1337     proto_tree *tree = proto_item_get_parent(wg_tree);
1338     if (!pref_dissect_packet) {
1339         // (IP packet not shown, preference "Dissect transport data" is disabled)
1340         call_data_dissector(new_tvb, pinfo, tree);
1341     } else {
1342         call_dissector(ip_handle, new_tvb, pinfo, tree);
1343     }
1344 }
1345 
1346 static void
wg_dissect_mac1_pubkey(proto_tree * tree,tvbuff_t * tvb,const wg_skey_t * skey)1347 wg_dissect_mac1_pubkey(proto_tree *tree, tvbuff_t *tvb, const wg_skey_t *skey)
1348 {
1349     proto_item *ti;
1350 
1351     if (!skey) {
1352         return;
1353     }
1354 
1355     ti = proto_tree_add_string(tree, hf_wg_receiver_pubkey, tvb, 0, 0, pubkey_to_string(&skey->pub_key));
1356     proto_item_set_generated(ti);
1357     proto_tree *key_tree = proto_item_add_subtree(ti, ett_key_info);
1358     ti = proto_tree_add_boolean(key_tree, hf_wg_receiver_pubkey_known_privkey, tvb, 0, 0, !!has_private_key(&skey->priv_key));
1359     proto_item_set_generated(ti);
1360 }
1361 #endif /* WG_DECRYPTION_SUPPORTED */
1362 
1363 static int
wg_dissect_handshake_initiation(tvbuff_t * tvb,packet_info * pinfo,proto_tree * wg_tree,wg_packet_info_t * wg_pinfo)1364 wg_dissect_handshake_initiation(tvbuff_t *tvb, packet_info *pinfo, proto_tree *wg_tree, wg_packet_info_t *wg_pinfo)
1365 {
1366     guint32 sender_id;
1367     proto_item *ti;
1368 
1369 #ifdef WG_DECRYPTION_SUPPORTED
1370     wg_keylog_read();
1371     const wg_skey_t *skey_r = wg_mac1_key_probe(tvb, TRUE);
1372     wg_handshake_state_t *hs = NULL;
1373 
1374     if (!PINFO_FD_VISITED(pinfo)) {
1375         if (skey_r) {
1376             hs = wg_prepare_handshake_keys(skey_r, tvb);
1377             if (hs) {
1378                 wg_process_initiation(tvb, hs);
1379             }
1380         }
1381     } else if (wg_pinfo && wg_pinfo->session) {
1382         hs = wg_pinfo->session->hs;
1383     }
1384 #endif /* WG_DECRYPTION_SUPPORTED */
1385 
1386     proto_tree_add_item_ret_uint(wg_tree, hf_wg_sender, tvb, 4, 4, ENC_LITTLE_ENDIAN, &sender_id);
1387     col_append_fstr(pinfo->cinfo, COL_INFO, ", sender=0x%08X", sender_id);
1388     wg_dissect_pubkey(wg_tree, tvb, 8, TRUE);
1389     proto_tree_add_item(wg_tree, hf_wg_encrypted_static, tvb, 40, 32 + AUTH_TAG_LENGTH, ENC_NA);
1390 #ifdef WG_DECRYPTION_SUPPORTED
1391     wg_dissect_decrypted_static(tvb, pinfo, wg_tree, hs);
1392 #endif /* WG_DECRYPTION_SUPPORTED */
1393     proto_tree_add_item(wg_tree, hf_wg_encrypted_timestamp, tvb, 88, 12 + AUTH_TAG_LENGTH, ENC_NA);
1394 #ifdef WG_DECRYPTION_SUPPORTED
1395     wg_dissect_decrypted_timestamp(tvb, pinfo, wg_tree, hs);
1396 #endif /* WG_DECRYPTION_SUPPORTED */
1397     proto_tree_add_item(wg_tree, hf_wg_mac1, tvb, 116, 16, ENC_NA);
1398 #ifdef WG_DECRYPTION_SUPPORTED
1399     wg_dissect_mac1_pubkey(wg_tree, tvb, skey_r);
1400 #endif /* WG_DECRYPTION_SUPPORTED */
1401     proto_tree_add_item(wg_tree, hf_wg_mac2, tvb, 132, 16, ENC_NA);
1402 
1403     if (!PINFO_FD_VISITED(pinfo)) {
1404         /* XXX should an initiation message with the same contents (except MAC2) be
1405          * considered part of the same "session"? */
1406         wg_session_t *session = wg_session_new();
1407         session->initiator_frame = pinfo->num;
1408         wg_session_update_address(session, pinfo, TRUE);
1409 #ifdef WG_DECRYPTION_SUPPORTED
1410         session->hs = hs;
1411 #endif /* WG_DECRYPTION_SUPPORTED */
1412         wg_sessions_insert(sender_id, session);
1413         wg_pinfo->session = session;
1414     }
1415     wg_session_t *session = wg_pinfo ? wg_pinfo->session : NULL;
1416     if (session) {
1417         ti = proto_tree_add_uint(wg_tree, hf_wg_stream, tvb, 0, 0, session->stream);
1418         proto_item_set_generated(ti);
1419     }
1420     if (session && session->response_frame) {
1421         ti = proto_tree_add_uint(wg_tree, hf_wg_response_in, tvb, 0, 0, session->response_frame);
1422         proto_item_set_generated(ti);
1423     }
1424 
1425     return 148;
1426 }
1427 
1428 static int
wg_dissect_handshake_response(tvbuff_t * tvb,packet_info * pinfo,proto_tree * wg_tree,wg_packet_info_t * wg_pinfo)1429 wg_dissect_handshake_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *wg_tree, wg_packet_info_t *wg_pinfo)
1430 {
1431     guint32 sender_id, receiver_id;
1432     proto_item *ti;
1433     wg_session_t *session;
1434 
1435 #ifdef WG_DECRYPTION_SUPPORTED
1436     wg_keylog_read();
1437     const wg_skey_t *skey_i = wg_mac1_key_probe(tvb, FALSE);
1438 #endif /* WG_DECRYPTION_SUPPORTED */
1439 
1440     proto_tree_add_item_ret_uint(wg_tree, hf_wg_sender, tvb, 4, 4, ENC_LITTLE_ENDIAN, &sender_id);
1441     col_append_fstr(pinfo->cinfo, COL_INFO, ", sender=0x%08X", sender_id);
1442     proto_tree_add_item_ret_uint(wg_tree, hf_wg_receiver, tvb, 8, 4, ENC_LITTLE_ENDIAN, &receiver_id);
1443     col_append_fstr(pinfo->cinfo, COL_INFO, ", receiver=0x%08X", receiver_id);
1444 
1445     if (!PINFO_FD_VISITED(pinfo)) {
1446         session = wg_sessions_lookup_initiation(pinfo, receiver_id);
1447 #ifdef WG_DECRYPTION_SUPPORTED
1448         if (session && session->hs) {
1449             wg_prepare_handshake_responder_keys(session->hs, tvb);
1450             wg_process_response(tvb, session->hs);
1451         }
1452 #endif /* WG_DECRYPTION_SUPPORTED */
1453     } else {
1454         session = wg_pinfo ? wg_pinfo->session : NULL;
1455     }
1456 
1457     wg_dissect_pubkey(wg_tree, tvb, 12, TRUE);
1458     proto_tree_add_item(wg_tree, hf_wg_encrypted_empty, tvb, 44, 16, ENC_NA);
1459 #ifdef WG_DECRYPTION_SUPPORTED
1460     if (session && session->hs) {
1461         ti = proto_tree_add_boolean(wg_tree, hf_wg_handshake_ok, tvb, 0, 0, !!session->hs->empty_ok);
1462         proto_item_set_generated(ti);
1463     }
1464 #endif /* WG_DECRYPTION_SUPPORTED */
1465     proto_tree_add_item(wg_tree, hf_wg_mac1, tvb, 60, 16, ENC_NA);
1466 #ifdef WG_DECRYPTION_SUPPORTED
1467     wg_dissect_mac1_pubkey(wg_tree, tvb, skey_i);
1468 #endif /* WG_DECRYPTION_SUPPORTED */
1469     proto_tree_add_item(wg_tree, hf_wg_mac2, tvb, 76, 16, ENC_NA);
1470 
1471     if (!PINFO_FD_VISITED(pinfo)) {
1472         /* XXX should probably check whether decryption succeeds before linking
1473          * and somehow mark that this response is related but not correct. */
1474         if (session) {
1475             session->response_frame = pinfo->num;
1476             wg_session_update_address(session, pinfo, FALSE);
1477             wg_sessions_insert(sender_id, session);
1478             wg_pinfo->session = session;
1479         }
1480     }
1481     if (session) {
1482         ti = proto_tree_add_uint(wg_tree, hf_wg_stream, tvb, 0, 0, session->stream);
1483         proto_item_set_generated(ti);
1484         ti = proto_tree_add_uint(wg_tree, hf_wg_response_to, tvb, 0, 0, session->initiator_frame);
1485         proto_item_set_generated(ti);
1486     }
1487 
1488     return 92;
1489 }
1490 
1491 static int
wg_dissect_handshake_cookie(tvbuff_t * tvb,packet_info * pinfo,proto_tree * wg_tree,wg_packet_info_t * wg_pinfo)1492 wg_dissect_handshake_cookie(tvbuff_t *tvb, packet_info *pinfo, proto_tree *wg_tree, wg_packet_info_t *wg_pinfo)
1493 {
1494     guint32 receiver_id;
1495     proto_item *ti;
1496 
1497     proto_tree_add_item_ret_uint(wg_tree, hf_wg_receiver, tvb, 4, 4, ENC_LITTLE_ENDIAN, &receiver_id);
1498     col_append_fstr(pinfo->cinfo, COL_INFO, ", receiver=0x%08X", receiver_id);
1499     proto_tree_add_item(wg_tree, hf_wg_nonce, tvb, 8, 24, ENC_NA);
1500     proto_tree_add_item(wg_tree, hf_wg_encrypted_cookie, tvb, 32, 16 + AUTH_TAG_LENGTH, ENC_NA);
1501 
1502     wg_session_t *session;
1503     if (!PINFO_FD_VISITED(pinfo)) {
1504         /* Check for Cookie Reply from Responder to Initiator. */
1505         session = wg_sessions_lookup_initiation(pinfo, receiver_id);
1506         if (session) {
1507             session->response_frame = pinfo->num;
1508             wg_session_update_address(session, pinfo, FALSE);
1509             wg_pinfo->session = session;
1510         }
1511         /* XXX check for cookie reply from Initiator to Responder */
1512     } else {
1513         session = wg_pinfo ? wg_pinfo->session : NULL;
1514     }
1515     if (session) {
1516         ti = proto_tree_add_uint(wg_tree, hf_wg_stream, tvb, 0, 0, session->stream);
1517         proto_item_set_generated(ti);
1518         /* XXX check for cookie reply from Initiator to Responder */
1519         ti = proto_tree_add_uint(wg_tree, hf_wg_response_to, tvb, 0, 0, session->initiator_frame);
1520         proto_item_set_generated(ti);
1521     }
1522 
1523     return 64;
1524 }
1525 
1526 static int
wg_dissect_data(tvbuff_t * tvb,packet_info * pinfo,proto_tree * wg_tree,wg_packet_info_t * wg_pinfo)1527 wg_dissect_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *wg_tree, wg_packet_info_t *wg_pinfo)
1528 {
1529     guint32 receiver_id;
1530     guint64 counter;
1531     proto_item *ti;
1532 
1533     proto_tree_add_item_ret_uint(wg_tree, hf_wg_receiver, tvb, 4, 4, ENC_LITTLE_ENDIAN, &receiver_id);
1534     col_append_fstr(pinfo->cinfo, COL_INFO, ", receiver=0x%08X", receiver_id);
1535     proto_tree_add_item_ret_uint64(wg_tree, hf_wg_counter, tvb, 8, 8, ENC_LITTLE_ENDIAN, &counter);
1536     col_append_fstr(pinfo->cinfo, COL_INFO, ", counter=%" G_GUINT64_FORMAT, counter);
1537 
1538     gint packet_length = tvb_captured_length_remaining(tvb, 16);
1539     if (packet_length < AUTH_TAG_LENGTH) {
1540         proto_tree_add_expert(wg_tree, pinfo, &ei_wg_bad_packet_length, tvb, 16, packet_length);
1541         return 16 + packet_length;
1542     } else if (packet_length != AUTH_TAG_LENGTH) {
1543         /* Keepalive messages are already marked, no need to append data length. */
1544         col_append_fstr(pinfo->cinfo, COL_INFO, ", datalen=%d", packet_length - AUTH_TAG_LENGTH);
1545     }
1546     ti = proto_tree_add_item(wg_tree, hf_wg_encrypted_packet, tvb, 16, packet_length, ENC_NA);
1547 
1548     if (packet_length == AUTH_TAG_LENGTH) {
1549         expert_add_info(pinfo, ti, &ei_wg_keepalive);
1550     }
1551 
1552     wg_session_t *session;
1553     if (!PINFO_FD_VISITED(pinfo)) {
1554         gboolean receiver_is_initiator;
1555         session = wg_sessions_lookup(pinfo, receiver_id, &receiver_is_initiator);
1556         if (session) {
1557             wg_session_update_address(session, pinfo, !receiver_is_initiator);
1558             wg_pinfo->session = session;
1559             wg_pinfo->receiver_is_initiator = receiver_is_initiator;
1560         }
1561     } else {
1562         session = wg_pinfo ? wg_pinfo->session : NULL;
1563     }
1564     if (session) {
1565         ti = proto_tree_add_uint(wg_tree, hf_wg_stream, tvb, 0, 0, session->stream);
1566         proto_item_set_generated(ti);
1567     }
1568 
1569 #ifdef WG_DECRYPTION_SUPPORTED
1570     if (session && session->hs) {
1571         wg_dissect_decrypted_packet(tvb, pinfo, wg_tree, wg_pinfo, counter, packet_length - AUTH_TAG_LENGTH);
1572     }
1573 #endif /* WG_DECRYPTION_SUPPORTED */
1574 
1575     return 16 + packet_length;
1576 }
1577 
1578 static gboolean
wg_is_valid_message_length(guint8 message_type,guint length)1579 wg_is_valid_message_length(guint8 message_type, guint length)
1580 {
1581     switch (message_type) {
1582     case WG_TYPE_HANDSHAKE_INITIATION:
1583         return length == 148;
1584     case WG_TYPE_HANDSHAKE_RESPONSE:
1585         return length == 92;
1586     case WG_TYPE_COOKIE_REPLY:
1587         return length == 64;
1588     case WG_TYPE_TRANSPORT_DATA:
1589         return length >= 32;
1590     default:
1591         return FALSE;
1592     }
1593 }
1594 
1595 static int
dissect_wg(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)1596 dissect_wg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
1597 {
1598     proto_item *ti;
1599     proto_tree *wg_tree;
1600     guint32     message_type;
1601     const char *message_type_str;
1602     wg_packet_info_t *wg_pinfo;
1603 
1604     message_type = tvb_get_guint8(tvb, 0);
1605     message_type_str = try_val_to_str(message_type, wg_type_names);
1606     if (!message_type_str)
1607         return 0;
1608 
1609     if (!wg_is_valid_message_length(message_type, tvb_reported_length(tvb))) {
1610         return 0;
1611     }
1612 
1613     /* Special case: zero-length data message is a Keepalive message. */
1614     if (message_type == WG_TYPE_TRANSPORT_DATA && tvb_reported_length(tvb) == 32) {
1615         message_type_str = "Keepalive";
1616     }
1617 
1618     col_set_str(pinfo->cinfo, COL_PROTOCOL, "WireGuard");
1619     col_set_str(pinfo->cinfo, COL_INFO, message_type_str);
1620 
1621     ti = proto_tree_add_item(tree, proto_wg, tvb, 0, -1, ENC_NA);
1622     wg_tree = proto_item_add_subtree(ti, ett_wg);
1623 
1624     proto_tree_add_item(wg_tree, hf_wg_type, tvb, 0, 1, ENC_NA);
1625     proto_tree_add_item(wg_tree, hf_wg_reserved, tvb, 1, 3, ENC_NA);
1626 
1627     if (!PINFO_FD_VISITED(pinfo)) {
1628         wg_pinfo = wmem_new0(wmem_file_scope(), wg_packet_info_t);
1629         p_add_proto_data(wmem_file_scope(), pinfo, proto_wg, 0, wg_pinfo);
1630     } else {
1631         /*
1632          * Note: this may be NULL if the heuristics dissector sets a
1633          * conversation dissector later in the stream, for example due to a new
1634          * Handshake Initiation message. Previous messages are potentially
1635          * Transport Data messages which might not be detected through
1636          * heuristics.
1637          */
1638         wg_pinfo = (wg_packet_info_t *)p_get_proto_data(wmem_file_scope(), pinfo, proto_wg, 0);
1639     }
1640 
1641     switch ((wg_message_type)message_type) {
1642     case WG_TYPE_HANDSHAKE_INITIATION:
1643         return wg_dissect_handshake_initiation(tvb, pinfo, wg_tree, wg_pinfo);
1644     case WG_TYPE_HANDSHAKE_RESPONSE:
1645         return wg_dissect_handshake_response(tvb, pinfo, wg_tree, wg_pinfo);
1646     case WG_TYPE_COOKIE_REPLY:
1647         return wg_dissect_handshake_cookie(tvb, pinfo, wg_tree, wg_pinfo);
1648     case WG_TYPE_TRANSPORT_DATA:
1649         return wg_dissect_data(tvb, pinfo, wg_tree, wg_pinfo);
1650     }
1651 
1652     DISSECTOR_ASSERT_NOT_REACHED();
1653 }
1654 
1655 static gboolean
dissect_wg_heur(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)1656 dissect_wg_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
1657 {
1658     /*
1659      * Heuristics to detect the WireGuard protocol:
1660      * - The first byte must be one of the valid four messages.
1661      * - The total packet length depends on the message type, and is fixed for
1662      *   three of them. The Data type has a minimum length however.
1663      * - The next three bytes are reserved and zero in the official protocol.
1664      *   Cloudflare's implementation however uses this field for load balancing
1665      *   purposes, so this condition is not checked here for most messages.
1666      *   It is checked for data messages to avoid false positives.
1667      */
1668     guint32     message_type;
1669     gboolean    reserved_is_zeroes;
1670 
1671     if (tvb_reported_length(tvb) < 4)
1672         return FALSE;
1673 
1674     message_type = tvb_get_guint8(tvb, 0);
1675     reserved_is_zeroes = tvb_get_ntoh24(tvb, 1) == 0;
1676 
1677     if (!wg_is_valid_message_length(message_type, tvb_reported_length(tvb))) {
1678         return FALSE;
1679     }
1680 
1681     switch (message_type) {
1682         case WG_TYPE_COOKIE_REPLY:
1683         case WG_TYPE_TRANSPORT_DATA:
1684             if (!reserved_is_zeroes)
1685                 return FALSE;
1686             break;
1687     }
1688 
1689     /*
1690      * Assuming that this is a new handshake, make sure that future messages are
1691      * directed to our dissector. This ensures that cookie replies and data
1692      * messages using non-zero reserved bytes are still properly recognized.
1693      * An edge case occurs when the address or port change. In that case, Data
1694      * messages using non-zero reserved bytes will not be recognized. The user
1695      * can use Decode As for this case.
1696      */
1697     if (message_type == WG_TYPE_HANDSHAKE_INITIATION) {
1698         conversation_t *conversation = find_or_create_conversation(pinfo);
1699         conversation_set_dissector(conversation, wg_handle);
1700     }
1701 
1702     dissect_wg(tvb, pinfo, tree, NULL);
1703     return TRUE;
1704 }
1705 
1706 static void
wg_init(void)1707 wg_init(void)
1708 {
1709     wg_session_count = 0;
1710 }
1711 
1712 void
proto_register_wg(void)1713 proto_register_wg(void)
1714 {
1715 #ifdef WG_DECRYPTION_SUPPORTED
1716     module_t        *wg_module;
1717 #endif /* WG_DECRYPTION_SUPPORTED */
1718     expert_module_t *expert_wg;
1719 
1720     static hf_register_info hf[] = {
1721         /* Initiation message */
1722         { &hf_wg_type,
1723           { "Type", "wg.type",
1724             FT_UINT8, BASE_DEC, VALS(wg_type_names), 0x0,
1725             NULL, HFILL }
1726         },
1727         { &hf_wg_reserved,
1728           { "Reserved", "wg.reserved",
1729             FT_BYTES, BASE_NONE, NULL, 0x0,
1730             NULL, HFILL }
1731         },
1732         { &hf_wg_sender,
1733           { "Sender", "wg.sender",
1734             FT_UINT32, BASE_HEX, NULL, 0x0,
1735             "Identifier as chosen by the sender", HFILL }
1736         },
1737         { &hf_wg_ephemeral,
1738           { "Ephemeral", "wg.ephemeral",
1739             FT_STRING, BASE_NONE, NULL, 0x0,
1740             "Ephemeral public key of sender", HFILL }
1741         },
1742         { &hf_wg_encrypted_static,
1743           { "Encrypted Static", "wg.encrypted_static",
1744             FT_NONE, BASE_NONE, NULL, 0x0,
1745             "Encrypted long-term static public key of sender", HFILL }
1746         },
1747         { &hf_wg_static,
1748           { "Static Public Key", "wg.static",
1749             FT_STRING, BASE_NONE, NULL, 0x0,
1750             "Long-term static public key of sender", HFILL }
1751         },
1752         { &hf_wg_encrypted_timestamp,
1753           { "Encrypted Timestamp", "wg.encrypted_timestamp",
1754             FT_NONE, BASE_NONE, NULL, 0x0,
1755             NULL, HFILL }
1756         },
1757         { &hf_wg_timestamp_tai64_label,
1758           { "TAI64 Label", "wg.timestamp.tai64_label",
1759             FT_UINT64, BASE_DEC, NULL, 0x0,
1760             NULL, HFILL }
1761         },
1762         { &hf_wg_timestamp_nanoseconds,
1763           { "Nanoseconds", "wg.timestamp.nanoseconds",
1764             FT_UINT32, BASE_DEC, NULL, 0x0,
1765             NULL, HFILL }
1766         },
1767         { &hf_wg_timestamp_value,
1768           { "Timestamp", "wg.timestamp.value",
1769             FT_ABSOLUTE_TIME, ABSOLUTE_TIME_UTC, NULL, 0x0,
1770             NULL, HFILL }
1771         },
1772         { &hf_wg_mac1,
1773           { "mac1", "wg.mac1",
1774             FT_BYTES, BASE_NONE, NULL, 0x0,
1775             NULL, HFILL }
1776         },
1777         { &hf_wg_mac2,
1778           { "mac2", "wg.mac2",
1779             FT_BYTES, BASE_NONE, NULL, 0x0,
1780             NULL, HFILL }
1781         },
1782 
1783         /* Response message */
1784         { &hf_wg_receiver,
1785           { "Receiver", "wg.receiver",
1786             FT_UINT32, BASE_HEX, NULL, 0x0,
1787             "Identifier as chosen by receiver", HFILL }
1788         },
1789         { &hf_wg_encrypted_empty,
1790           { "Encrypted Empty", "wg.encrypted_empty",
1791             FT_NONE, BASE_NONE, NULL, 0x0,
1792             "Authenticated encryption of an empty string", HFILL }
1793         },
1794         { &hf_wg_handshake_ok,
1795           { "Handshake decryption successful", "wg.handshake_ok",
1796             FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1797             "Whether decryption keys were successfully derived", HFILL }
1798         },
1799 
1800         /* Cookie message */
1801         { &hf_wg_nonce,
1802           { "Nonce", "wg.nonce",
1803             FT_BYTES, BASE_NONE, NULL, 0x0,
1804             NULL, HFILL }
1805         },
1806         { &hf_wg_encrypted_cookie,
1807           { "Encrypted Cookie", "wg.encrypted_cookie",
1808             FT_BYTES, BASE_NONE, NULL, 0x0,
1809             NULL, HFILL }
1810         },
1811         /* TODO decrypted cookie field. */
1812 
1813         /* Data message */
1814         { &hf_wg_counter,
1815           { "Counter", "wg.counter",
1816             FT_UINT64, BASE_DEC, NULL, 0x0,
1817             NULL, HFILL }
1818         },
1819         { &hf_wg_encrypted_packet,
1820           { "Encrypted Packet", "wg.encrypted_packet",
1821             FT_NONE, BASE_NONE, NULL, 0x0,
1822             NULL, HFILL }
1823         },
1824 
1825         /* Association tracking. */
1826         { &hf_wg_stream,
1827           { "Stream index", "wg.stream",
1828             FT_UINT32, BASE_DEC, NULL, 0x0,
1829             "Identifies a session in this capture file", HFILL }
1830         },
1831         { &hf_wg_response_in,
1832           { "Response in Frame", "wg.response_in",
1833             FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_RESPONSE), 0x0,
1834             "The response to this initiation message is in this frame", HFILL }
1835         },
1836         { &hf_wg_response_to,
1837           { "Response to Frame", "wg.response_to",
1838             FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_REQUEST), 0x0,
1839             "This is a response to the initiation message in this frame", HFILL }
1840         },
1841 
1842         /* Additional fields. */
1843         { &hf_wg_receiver_pubkey,
1844           { "Receiver Static Public Key", "wg.receiver_pubkey",
1845             FT_STRING, BASE_NONE, NULL, 0x0,
1846             "Public key of the receiver (matched based on MAC1)", HFILL }
1847         },
1848         { &hf_wg_receiver_pubkey_known_privkey,
1849           { "Has Private Key", "wg.receiver_pubkey.known_privkey",
1850             FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1851             "Whether the corresponding private key is known (configured via prefs)", HFILL }
1852         },
1853         { &hf_wg_ephemeral_known_privkey,
1854           { "Has Private Key", "wg.ephemeral.known_privkey",
1855             FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1856             "Whether the corresponding private key is known (configured via prefs)", HFILL }
1857         },
1858         { &hf_wg_static_known_pubkey,
1859           { "Known Public Key", "wg.static.known_pubkey",
1860             FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1861             "Whether this public key is known (configured via prefs)", HFILL }
1862         },
1863         { &hf_wg_static_known_privkey,
1864           { "Has Private Key", "wg.static.known_privkey",
1865             FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1866             "Whether the corresponding private key is known (configured via prefs)", HFILL }
1867         },
1868     };
1869 
1870     static gint *ett[] = {
1871         &ett_wg,
1872         &ett_timestamp,
1873         &ett_key_info,
1874     };
1875 
1876     static ei_register_info ei[] = {
1877         { &ei_wg_bad_packet_length,
1878           { "wg.bad_packet_length", PI_MALFORMED, PI_ERROR,
1879             "Packet length is too small", EXPFILL }
1880         },
1881         { &ei_wg_keepalive,
1882           { "wg.keepalive", PI_SEQUENCE, PI_CHAT,
1883             "This is a Keepalive message", EXPFILL }
1884         },
1885         { &ei_wg_decryption_error,
1886           { "wg.decryption_error", PI_DECRYPTION, PI_WARN,
1887             "Packet data decryption failed", EXPFILL }
1888         },
1889     };
1890 
1891 #ifdef WG_DECRYPTION_SUPPORTED
1892     /* UAT for header fields */
1893     static uat_field_t wg_key_uat_fields[] = {
1894         UAT_FLD_VS(wg_key_uat, key_type, "Key type", wg_key_uat_type_vals, "Public or Private"),
1895         UAT_FLD_CSTRING(wg_key_uat, key, "Key", "Base64-encoded key"),
1896         UAT_END_FIELDS
1897     };
1898 #endif /* WG_DECRYPTION_SUPPORTED */
1899 
1900     proto_wg = proto_register_protocol("WireGuard Protocol", "WireGuard", "wg");
1901 
1902     proto_register_field_array(proto_wg, hf, array_length(hf));
1903     proto_register_subtree_array(ett, array_length(ett));
1904 
1905     expert_wg = expert_register_protocol(proto_wg);
1906     expert_register_field_array(expert_wg, ei, array_length(ei));
1907 
1908     wg_handle = register_dissector("wg", dissect_wg, proto_wg);
1909 
1910 #ifdef WG_DECRYPTION_SUPPORTED
1911     wg_module = prefs_register_protocol(proto_wg, NULL);
1912 
1913     uat_t *wg_keys_uat = uat_new("WireGuard static keys",
1914             sizeof(wg_key_uat_record_t),
1915             "wg_keys",                      /* filename */
1916             TRUE,                           /* from_profile */
1917             &wg_key_records,                /* data_ptr */
1918             &num_wg_key_records,            /* numitems_ptr */
1919             UAT_AFFECTS_DISSECTION,         /* affects dissection of packets, but not set of named fields */
1920             NULL,                           /* Help section (currently a wiki page) */
1921             wg_key_uat_record_copy_cb,      /* copy_cb */
1922             wg_key_uat_record_update_cb,    /* update_cb */
1923             wg_key_uat_record_free_cb,      /* free_cb */
1924             wg_key_uat_apply,               /* post_update_cb */
1925             wg_key_uat_reset,               /* reset_cb */
1926             wg_key_uat_fields);
1927 
1928     prefs_register_uat_preference(wg_module, "keys",
1929             "WireGuard static keys",
1930             "A table of long-term static keys to enable WireGuard peer identification or partial decryption",
1931             wg_keys_uat);
1932 
1933     prefs_register_bool_preference(wg_module, "dissect_packet",
1934             "Dissect transport data",
1935             "Whether the IP dissector should dissect decrypted transport data.",
1936             &pref_dissect_packet);
1937 
1938     prefs_register_filename_preference(wg_module, "keylog_file", "Key log filename",
1939             "The path to the file which contains a list of secrets in the following format:\n"
1940             "\"<key-type> = <base64-encoded-key>\" (without quotes, leading spaces and spaces around '=' are ignored).\n"
1941             "<key-type> is one of: LOCAL_STATIC_PRIVATE_KEY, REMOTE_STATIC_PUBLIC_KEY, "
1942             "LOCAL_EPHEMERAL_PRIVATE_KEY or PRESHARED_KEY.",
1943             &pref_keylog_file, FALSE);
1944 
1945     if (!wg_decrypt_init()) {
1946         ws_warning("%s: decryption will not be possible due to lack of algorithms support", G_STRFUNC);
1947     }
1948 
1949     secrets_register_type(SECRETS_TYPE_WIREGUARD, wg_keylog_process_lines);
1950 
1951     wg_ephemeral_keys = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), g_int_hash, wg_pubkey_equal);
1952 #endif /* WG_DECRYPTION_SUPPORTED */
1953 
1954     register_init_routine(wg_init);
1955 #ifdef WG_DECRYPTION_SUPPORTED
1956     register_cleanup_routine(wg_keylog_reset);
1957 #endif /* WG_DECRYPTION_SUPPORTED */
1958     sessions = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), g_direct_hash, g_direct_equal);
1959 }
1960 
1961 void
proto_reg_handoff_wg(void)1962 proto_reg_handoff_wg(void)
1963 {
1964     dissector_add_uint_with_preference("udp.port", 0, wg_handle);
1965     heur_dissector_add("udp", dissect_wg_heur, "WireGuard", "wg", proto_wg, HEURISTIC_ENABLE);
1966 
1967 #ifdef WG_DECRYPTION_SUPPORTED
1968     ip_handle = find_dissector("ip");
1969 #endif /* WG_DECRYPTION_SUPPORTED */
1970 }
1971 
1972 /*
1973  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
1974  *
1975  * Local variables:
1976  * c-basic-offset: 4
1977  * tab-width: 8
1978  * indent-tabs-mode: nil
1979  * End:
1980  *
1981  * vi: set shiftwidth=4 tabstop=8 expandtab:
1982  * :indentSize=4:tabSize=8:noTabs=true:
1983  */
1984