/src/wireshark/epan/crypt/dot11decrypt.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* dot11decrypt.c |
2 | | * |
3 | | * Copyright (c) 2006 CACE Technologies, Davis (California) |
4 | | * All rights reserved. |
5 | | * |
6 | | * SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only) |
7 | | */ |
8 | | |
9 | | /****************************************************************************/ |
10 | | /* File includes */ |
11 | | |
12 | | #include "config.h" |
13 | | /* Keep this first after config.h so that WS_LOG_DOMAIN is set correctly. */ |
14 | | #include "dot11decrypt_debug.h" |
15 | | |
16 | | #include <stdint.h> |
17 | | #include <glib.h> |
18 | | |
19 | | #include <wsutil/wsgcrypt.h> |
20 | | #include <wsutil/crc32.h> |
21 | | #include <wsutil/pint.h> |
22 | | |
23 | | #include <epan/proto.h> /* for DISSECTOR_ASSERT. */ |
24 | | #include <epan/strutil.h> |
25 | | |
26 | | #include "dot11decrypt_util.h" |
27 | | #include "dot11decrypt_system.h" |
28 | | #include "dot11decrypt_int.h" |
29 | | |
30 | | #include "wep-wpadefs.h" |
31 | | |
32 | | |
33 | | /****************************************************************************/ |
34 | | static int Dot11DecryptGetKckLen(int akm, int dh_group); |
35 | | static int Dot11DecryptGetTkLen(int cipher); |
36 | | static int Dot11DecryptGetKekLen(int akm, int dh_group); |
37 | | static int Dot11DecryptGetPtkLen(int akm, int cipher, int dh_group); |
38 | | static int Dot11DecryptGetHashAlgoFromAkm(int akm, int dh_group); |
39 | | |
40 | | /****************************************************************************/ |
41 | | /* Constant definitions */ |
42 | | |
43 | | /* EAPOL definitions */ |
44 | | /** |
45 | | * Length of the EAPOL-Key key confirmation key (KCK) used to calculate |
46 | | * MIC over EAPOL frame and validate an EAPOL packet (128 bits) |
47 | | */ |
48 | | #define DOT11DECRYPT_WPA_KCK_LEN 16 |
49 | | /** |
50 | | *Offset of the Key MIC in the EAPOL packet body |
51 | | */ |
52 | 0 | #define DOT11DECRYPT_WPA_MICKEY_OFFSET 77 |
53 | | /** |
54 | | * Maximum length of the EAPOL packet (it depends on the maximum MAC |
55 | | * frame size) |
56 | | */ |
57 | | #define DOT11DECRYPT_WPA_MAX_EAPOL_LEN 4095 |
58 | | /** |
59 | | * EAPOL Key Descriptor Version 1, used for all EAPOL-Key frames to and |
60 | | * from a STA when neither the group nor pairwise ciphers are CCMP for |
61 | | * Key Descriptor 1. |
62 | | * @note |
63 | | * Defined in 802.11i-2004, page 78 |
64 | | */ |
65 | 0 | #define DOT11DECRYPT_WPA_KEY_VER_NOT_CCMP 1 |
66 | | /** |
67 | | * EAPOL Key Descriptor Version 2, used for all EAPOL-Key frames to and |
68 | | * from a STA when either the pairwise or the group cipher is AES-CCMP |
69 | | * for Key Descriptor 2. |
70 | | * /note |
71 | | * Defined in 802.11i-2004, page 78 |
72 | | */ |
73 | 0 | #define DOT11DECRYPT_WPA_KEY_VER_AES_CCMP 2 |
74 | | |
75 | | /** Define EAPOL Key Descriptor type values: use 254 for WPA and 2 for WPA2 **/ |
76 | 0 | #define DOT11DECRYPT_RSN_WPA_KEY_DESCRIPTOR 254 |
77 | 0 | #define DOT11DECRYPT_RSN_WPA2_KEY_DESCRIPTOR 2 |
78 | | |
79 | | /* PMK to PTK derive functions */ |
80 | 0 | #define DOT11DECRYPT_DERIVE_USING_PRF 0 |
81 | 0 | #define DOT11DECRYPT_DERIVE_USING_KDF 1 |
82 | | /****************************************************************************/ |
83 | | |
84 | | |
85 | | /****************************************************************************/ |
86 | | /* Macro definitions */ |
87 | | |
88 | | extern const uint32_t crc32_table[256]; |
89 | | #define CRC(crc, ch) (crc = (crc >> 8) ^ crc32_table[(crc ^ (ch)) & 0xff]) |
90 | | |
91 | 0 | #define KCK_OFFSET(akm) (0) |
92 | 0 | #define KEK_OFFSET(akm, dh_group) ((KCK_OFFSET(akm) + Dot11DecryptGetKckLen(akm, dh_group) / 8)) |
93 | 0 | #define TK_OFFSET(akm, dh_group) ((KEK_OFFSET(akm, dh_group) + Dot11DecryptGetKekLen(akm, dh_group) / 8)) |
94 | | |
95 | 0 | #define DOT11DECRYPT_GET_KCK(ptk, akm) (ptk + KCK_OFFSET(akm)) |
96 | 0 | #define DOT11DECRYPT_GET_KEK(ptk, akm, dh_group) (ptk + KEK_OFFSET(akm, dh_group)) |
97 | 0 | #define DOT11DECRYPT_GET_TK_TKIP(ptk) (ptk + 32) |
98 | 0 | #define DOT11DECRYPT_GET_TK(ptk, akm, dh_group) (ptk + TK_OFFSET(akm, dh_group)) |
99 | | |
100 | | #define DOT11DECRYPT_IEEE80211_OUI(oui) (pntoh24(oui) == 0x000fac) |
101 | | |
102 | | /****************************************************************************/ |
103 | | |
104 | | /****************************************************************************/ |
105 | | /* Type definitions */ |
106 | | |
107 | | /* Internal function prototype declarations */ |
108 | | |
109 | | #ifdef __cplusplus |
110 | | extern "C" { |
111 | | #endif |
112 | | |
113 | | /** |
114 | | * It is a step of the PBKDF2 (specifically the PKCS #5 v2.0) defined in |
115 | | * the RFC 2898 to derive a key (used as PMK in WPA) |
116 | | * @param ppbytes [IN] pointer to a password (sequence of between 8 and |
117 | | * 63 ASCII encoded characters) |
118 | | * @param ssid [IN] pointer to the SSID string encoded in max 32 ASCII |
119 | | * encoded characters |
120 | | * @param iterations [IN] times to hash the password (4096 for WPA) |
121 | | * @param count [IN] ??? |
122 | | * @param output [OUT] pointer to a preallocated buffer of |
123 | | * SHA1_DIGEST_LEN characters that will contain a part of the key |
124 | | */ |
125 | | static int Dot11DecryptRsnaPwd2PskStep( |
126 | | const uint8_t *ppbytes, |
127 | | const unsigned passLength, |
128 | | const char *ssid, |
129 | | const size_t ssidLength, |
130 | | const int iterations, |
131 | | const int count, |
132 | | unsigned char *output) |
133 | | ; |
134 | | |
135 | | /** |
136 | | * It calculates the passphrase-to-PSK mapping reccomanded for use with |
137 | | * RSNAs. This implementation uses the PBKDF2 method defined in the RFC |
138 | | * 2898. |
139 | | * @param userPwd [IN] pointer to the struct containing a password |
140 | | * (octet string between 8 and 63 octets) and optional SSID octet |
141 | | * string of up to 32 octets (both are usually ASCII but in fact |
142 | | * opaque and can be any encoding.) |
143 | | * @param output [OUT] calculated PSK (to use as PMK in WPA) |
144 | | * @note |
145 | | * Described in 802.11i-2004, page 165 |
146 | | */ |
147 | | static int Dot11DecryptRsnaPwd2Psk( |
148 | | const struct DOT11DECRYPT_KEY_ITEMDATA_PWD *userPwd, |
149 | | unsigned char *output) |
150 | | ; |
151 | | |
152 | | static int Dot11DecryptRsnaMng( |
153 | | unsigned char *decrypt_data, |
154 | | unsigned mac_header_len, |
155 | | unsigned *decrypt_len, |
156 | | PDOT11DECRYPT_KEY_ITEM key, |
157 | | DOT11DECRYPT_SEC_ASSOCIATION *sa) |
158 | | ; |
159 | | |
160 | | static int Dot11DecryptWepMng( |
161 | | PDOT11DECRYPT_CONTEXT ctx, |
162 | | unsigned char *decrypt_data, |
163 | | unsigned mac_header_len, |
164 | | unsigned *decrypt_len, |
165 | | PDOT11DECRYPT_KEY_ITEM key, |
166 | | DOT11DECRYPT_SEC_ASSOCIATION_ID *id) |
167 | | ; |
168 | | |
169 | | static int Dot11DecryptRsna4WHandshake( |
170 | | PDOT11DECRYPT_CONTEXT ctx, |
171 | | PDOT11DECRYPT_EAPOL_PARSED eapol_parsed, |
172 | | const uint8_t *eapol_raw, |
173 | | DOT11DECRYPT_SEC_ASSOCIATION_ID *id, |
174 | | const unsigned tot_len); |
175 | | |
176 | | /** |
177 | | * It checks whether the specified key is corrected or not. |
178 | | * @note |
179 | | * For a standard WEP key the length will be changed to the standard |
180 | | * length, and the type changed in a generic WEP key. |
181 | | * @param key [IN] pointer to the key to validate |
182 | | * @return |
183 | | * - true: the key contains valid fields and values |
184 | | * - false: the key has some invalid field or value |
185 | | */ |
186 | | static int Dot11DecryptValidateKey( |
187 | | PDOT11DECRYPT_KEY_ITEM key) |
188 | | ; |
189 | | |
190 | | static int Dot11DecryptRsnaMicCheck( |
191 | | PDOT11DECRYPT_EAPOL_PARSED eapol_parsed, |
192 | | unsigned char *eapol, |
193 | | unsigned short eapol_len, |
194 | | unsigned char *KCK, |
195 | | unsigned short key_ver, |
196 | | int akm) |
197 | | ; |
198 | | |
199 | | static int |
200 | | Dot11DecryptFtMicCheck( |
201 | | const PDOT11DECRYPT_ASSOC_PARSED assoc_parsed, |
202 | | const uint8_t *kck, |
203 | | size_t kck_len); |
204 | | |
205 | | static PDOT11DECRYPT_SEC_ASSOCIATION |
206 | | Dot11DecryptGetSa( |
207 | | PDOT11DECRYPT_CONTEXT ctx, |
208 | | const DOT11DECRYPT_SEC_ASSOCIATION_ID *id) |
209 | | ; |
210 | | |
211 | | static int Dot11DecryptGetSaAddress( |
212 | | const DOT11DECRYPT_MAC_FRAME_ADDR4 *frame, |
213 | | DOT11DECRYPT_SEC_ASSOCIATION_ID *id) |
214 | | ; |
215 | | |
216 | | static const unsigned char * Dot11DecryptGetStaAddress( |
217 | | const DOT11DECRYPT_MAC_FRAME_ADDR4 *frame) |
218 | | ; |
219 | | |
220 | | static const unsigned char * Dot11DecryptGetBssidAddress( |
221 | | const DOT11DECRYPT_MAC_FRAME_ADDR4 *frame) |
222 | | ; |
223 | | |
224 | | static uint8_t |
225 | | Dot11DecryptDerivePtk( |
226 | | const DOT11DECRYPT_SEC_ASSOCIATION *sa, |
227 | | const unsigned char *pmk, |
228 | | size_t pmk_len, |
229 | | const unsigned char snonce[32], |
230 | | int key_version, |
231 | | int akm, |
232 | | int cipher, |
233 | | uint8_t *ptk, size_t *ptk_len, |
234 | | int dh_group); |
235 | | |
236 | | static uint8_t |
237 | | Dot11DecryptFtDerivePtk( |
238 | | const PDOT11DECRYPT_CONTEXT ctx, |
239 | | const DOT11DECRYPT_SEC_ASSOCIATION *sa, |
240 | | const PDOT11DECRYPT_KEY_ITEM key, |
241 | | const uint8_t mdid[2], |
242 | | const uint8_t *snonce, |
243 | | const uint8_t *r0kh_id, size_t r0kh_id_len, |
244 | | const uint8_t *r1kh_id, size_t r1kh_id_len _U_, |
245 | | int akm, int cipher, |
246 | | uint8_t *ptk, size_t *ptk_len); |
247 | | |
248 | | /** |
249 | | * @param sa [IN/OUT] pointer to SA that will hold the key |
250 | | * @param data [IN] Frame |
251 | | * @param offset_rsne [IN] RSNE IE offset in the frame |
252 | | * @param offset_fte [IN] Fast BSS Transition IE offset in the frame |
253 | | * @param offset_timeout [IN] Timeout Interval IE offset in the frame |
254 | | * @param offset_link [IN] Link Identifier IE offset in the frame |
255 | | * @param action [IN] Tdls Action code (response or confirm) |
256 | | * |
257 | | * @return |
258 | | * DOT11DECRYPT_RET_SUCCESS if Key has been successfully derived (and MIC verified) |
259 | | * DOT11DECRYPT_RET_UNSUCCESS otherwise |
260 | | */ |
261 | | static int |
262 | | Dot11DecryptTDLSDeriveKey( |
263 | | PDOT11DECRYPT_SEC_ASSOCIATION sa, |
264 | | const uint8_t *data, |
265 | | unsigned offset_rsne, |
266 | | unsigned offset_fte, |
267 | | unsigned offset_timeout, |
268 | | unsigned offset_link, |
269 | | uint8_t action) |
270 | | ; |
271 | | #ifdef __cplusplus |
272 | | } |
273 | | #endif |
274 | | |
275 | | /****************************************************************************/ |
276 | | |
277 | | /****************************************************************************/ |
278 | | /* Exported function definitions */ |
279 | | |
280 | | #ifdef __cplusplus |
281 | | extern "C" { |
282 | | #endif |
283 | | |
284 | | const uint8_t broadcast_mac[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; |
285 | | |
286 | 0 | #define TKIP_GROUP_KEY_LEN 32 |
287 | 0 | #define CCMP_GROUP_KEY_LEN 16 |
288 | | |
289 | 0 | #define EAPOL_RSN_KEY_LEN 95 |
290 | | |
291 | | /* Minimum possible key data size (at least one GTK KDE with CCMP key) */ |
292 | 0 | #define GROUP_KEY_MIN_LEN 8 + CCMP_GROUP_KEY_LEN |
293 | | /* Minimum possible group key msg size (group key msg using CCMP as cipher)*/ |
294 | | #define GROUP_KEY_PAYLOAD_LEN_MIN \ |
295 | 0 | (EAPOL_RSN_KEY_LEN + GROUP_KEY_MIN_LEN) |
296 | | |
297 | | static void |
298 | | Dot11DecryptCopyKey(PDOT11DECRYPT_SEC_ASSOCIATION sa, PDOT11DECRYPT_KEY_ITEM key) |
299 | 0 | { |
300 | 0 | if (key!=NULL) { |
301 | 0 | if (sa->key!=NULL) |
302 | 0 | memcpy(key, sa->key, sizeof(DOT11DECRYPT_KEY_ITEM)); |
303 | 0 | else |
304 | 0 | memset(key, 0, sizeof(DOT11DECRYPT_KEY_ITEM)); |
305 | 0 | key->KeyData.Wpa.PtkLen = sa->wpa.ptk_len; |
306 | 0 | memcpy(key->KeyData.Wpa.Ptk, sa->wpa.ptk, sa->wpa.ptk_len); |
307 | 0 | key->KeyData.Wpa.Akm = sa->wpa.akm; |
308 | 0 | key->KeyData.Wpa.Cipher = sa->wpa.cipher; |
309 | 0 | if (sa->wpa.key_ver==DOT11DECRYPT_WPA_KEY_VER_NOT_CCMP) |
310 | 0 | key->KeyType=DOT11DECRYPT_KEY_TYPE_TKIP; |
311 | 0 | else if (sa->wpa.key_ver == 0 || sa->wpa.key_ver == 3 || |
312 | 0 | sa->wpa.key_ver == DOT11DECRYPT_WPA_KEY_VER_AES_CCMP) |
313 | 0 | { |
314 | 0 | switch (sa->wpa.cipher) { |
315 | 0 | case 1: |
316 | 0 | key->KeyType = DOT11DECRYPT_KEY_TYPE_WEP_40; |
317 | 0 | break; |
318 | 0 | case 2: |
319 | 0 | key->KeyType = DOT11DECRYPT_KEY_TYPE_TKIP; |
320 | 0 | break; |
321 | 0 | case 4: |
322 | 0 | key->KeyType = DOT11DECRYPT_KEY_TYPE_CCMP; |
323 | 0 | break; |
324 | 0 | case 5: |
325 | 0 | key->KeyType = DOT11DECRYPT_KEY_TYPE_WEP_104; |
326 | 0 | break; |
327 | 0 | case 8: |
328 | 0 | key->KeyType = DOT11DECRYPT_KEY_TYPE_GCMP; |
329 | 0 | break; |
330 | 0 | case 9: |
331 | 0 | key->KeyType = DOT11DECRYPT_KEY_TYPE_GCMP_256; |
332 | 0 | break; |
333 | 0 | case 10: |
334 | 0 | key->KeyType = DOT11DECRYPT_KEY_TYPE_CCMP_256; |
335 | 0 | break; |
336 | 0 | default: |
337 | 0 | key->KeyType = DOT11DECRYPT_KEY_TYPE_UNKNOWN; |
338 | 0 | break; |
339 | | /* NOT SUPPORTED YET |
340 | | case 3: Reserved |
341 | | case 6: BIP-CMAC-128 |
342 | | case 7: Group addressed traffic not allowed |
343 | | case 11: BIP-GMAC-128 |
344 | | case 12: BIP-GMAC-256 |
345 | | case 13: BIP-CMAC-256 */ |
346 | 0 | } |
347 | 0 | } |
348 | 0 | } |
349 | 0 | } |
350 | | |
351 | | static uint8_t* |
352 | | Dot11DecryptRc4KeyData(const uint8_t *decryption_key, unsigned decryption_key_len, |
353 | | const uint8_t *encrypted_keydata, unsigned encrypted_keydata_len) |
354 | 0 | { |
355 | 0 | gcry_cipher_hd_t rc4_handle; |
356 | 0 | uint8_t dummy[256] = { 0 }; |
357 | 0 | uint8_t *decrypted_key = NULL; |
358 | |
|
359 | 0 | if (gcry_cipher_open (&rc4_handle, GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM, 0)) { |
360 | 0 | return NULL; |
361 | 0 | } |
362 | 0 | if (gcry_cipher_setkey(rc4_handle, decryption_key, decryption_key_len)) { |
363 | 0 | gcry_cipher_close(rc4_handle); |
364 | 0 | return NULL; |
365 | 0 | } |
366 | 0 | decrypted_key = (uint8_t *)g_memdup2(encrypted_keydata, encrypted_keydata_len); |
367 | 0 | if (!decrypted_key) { |
368 | 0 | gcry_cipher_close(rc4_handle); |
369 | 0 | return NULL; |
370 | 0 | } |
371 | | |
372 | | /* Do dummy 256 iterations of the RC4 algorithm (per 802.11i, Draft 3.0, p. 97 line 6) */ |
373 | 0 | gcry_cipher_decrypt(rc4_handle, dummy, 256, NULL, 0); |
374 | 0 | gcry_cipher_decrypt(rc4_handle, decrypted_key, encrypted_keydata_len, NULL, 0); |
375 | 0 | gcry_cipher_close(rc4_handle); |
376 | 0 | return decrypted_key; |
377 | 0 | } |
378 | | |
379 | | static int |
380 | | AES_unwrap( |
381 | | const uint8_t *kek, |
382 | | uint16_t kek_len, |
383 | | const uint8_t *cipher_text, |
384 | | uint16_t cipher_len, |
385 | | uint8_t *output, |
386 | | uint16_t *output_len) |
387 | 0 | { |
388 | 0 | gcry_cipher_hd_t handle; |
389 | |
|
390 | 0 | if (kek == NULL || cipher_len < 16 || cipher_text == NULL) { |
391 | 0 | return 1; /* "should not happen" */ |
392 | 0 | } |
393 | 0 | if (gcry_cipher_open(&handle, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_AESWRAP, 0)) { |
394 | 0 | return 1; |
395 | 0 | } |
396 | 0 | if (gcry_cipher_setkey(handle, kek, kek_len)) { |
397 | 0 | gcry_cipher_close(handle); |
398 | 0 | return 1; |
399 | 0 | } |
400 | 0 | if (gcry_cipher_decrypt(handle, output, cipher_len - 8, cipher_text, cipher_len)) { |
401 | 0 | gcry_cipher_close(handle); |
402 | 0 | return 1; |
403 | 0 | } |
404 | 0 | *output_len = cipher_len - 8; |
405 | 0 | gcry_cipher_close(handle); |
406 | 0 | return 0; |
407 | 0 | } |
408 | | |
409 | | int |
410 | | Dot11DecryptDecryptKeyData(PDOT11DECRYPT_CONTEXT ctx, |
411 | | PDOT11DECRYPT_EAPOL_PARSED eapol_parsed, |
412 | | const unsigned char bssid[DOT11DECRYPT_MAC_LEN], |
413 | | const unsigned char sta[DOT11DECRYPT_MAC_LEN], |
414 | | unsigned char *decrypted_data, unsigned *decrypted_len, |
415 | | PDOT11DECRYPT_KEY_ITEM key) |
416 | 0 | { |
417 | 0 | uint8_t key_version; |
418 | 0 | const uint8_t *key_data; |
419 | 0 | uint16_t key_bytes_len = 0; /* Length of the total key data field */ |
420 | 0 | DOT11DECRYPT_SEC_ASSOCIATION_ID id; |
421 | 0 | PDOT11DECRYPT_SEC_ASSOCIATION sa; |
422 | | |
423 | | /* search for a cached Security Association for current BSSID and AP */ |
424 | 0 | memcpy(id.bssid, bssid, DOT11DECRYPT_MAC_LEN); |
425 | 0 | memcpy(id.sta, sta, DOT11DECRYPT_MAC_LEN); |
426 | 0 | sa = Dot11DecryptGetSa(ctx, &id); |
427 | 0 | if (sa == NULL || !sa->validKey) { |
428 | 0 | ws_debug("No valid SA for BSSID found"); |
429 | 0 | return DOT11DECRYPT_RET_UNSUCCESS; |
430 | 0 | } |
431 | | |
432 | | /* Decrypt GTK using KEK portion of PTK */ |
433 | 0 | uint8_t *decryption_key = DOT11DECRYPT_GET_KEK(sa->wpa.ptk, sa->wpa.akm, sa->wpa.dh_group); |
434 | 0 | unsigned decryption_key_len = Dot11DecryptGetKekLen(sa->wpa.akm, sa->wpa.dh_group) / 8; |
435 | | |
436 | | /* We skip verifying the MIC of the key. If we were implementing a WPA supplicant we'd want to verify, but for a sniffer it's not needed. */ |
437 | | |
438 | | /* Preparation for decrypting the group key - determine group key data length */ |
439 | | /* depending on whether the pairwise key is TKIP or AES encryption key */ |
440 | 0 | key_version = eapol_parsed->key_version; |
441 | 0 | if (key_version == DOT11DECRYPT_WPA_KEY_VER_NOT_CCMP){ |
442 | | /* TKIP */ |
443 | 0 | key_bytes_len = eapol_parsed->key_len; |
444 | 0 | }else if (key_version == DOT11DECRYPT_WPA_KEY_VER_AES_CCMP){ |
445 | | /* AES */ |
446 | 0 | key_bytes_len = eapol_parsed->key_data_len; |
447 | | |
448 | | /* AES keys must be at least 128 bits = 16 bytes. */ |
449 | 0 | if (key_bytes_len < 16) { |
450 | 0 | return DOT11DECRYPT_RET_UNSUCCESS; |
451 | 0 | } |
452 | 0 | } else { |
453 | | /* XXX Ideally group cipher suite type from EAPOL message 2 of 4 should be used to */ |
454 | | /* determine key size. As we currently have no way to do this lookup check that key */ |
455 | | /* is at least 16 bytes (IEEE802.11-2016 Table 12-4 Cipher suite key lengths) */ |
456 | 0 | key_bytes_len = eapol_parsed->key_data_len; |
457 | |
|
458 | 0 | if (key_bytes_len < 16) { |
459 | 0 | return DOT11DECRYPT_RET_UNSUCCESS; |
460 | 0 | } |
461 | 0 | } |
462 | | |
463 | 0 | if ((key_bytes_len < GROUP_KEY_MIN_LEN) || |
464 | 0 | (eapol_parsed->len < EAPOL_RSN_KEY_LEN) || |
465 | 0 | (key_bytes_len > eapol_parsed->len - EAPOL_RSN_KEY_LEN)) { |
466 | 0 | return DOT11DECRYPT_RET_UNSUCCESS; |
467 | 0 | } |
468 | | |
469 | | /* Encrypted key is in the information element field of the EAPOL key packet */ |
470 | 0 | key_data = eapol_parsed->key_data; |
471 | |
|
472 | 0 | DEBUG_DUMP("Encrypted Broadcast key", key_data, key_bytes_len, LOG_LEVEL_DEBUG); |
473 | 0 | DEBUG_DUMP("KeyIV", eapol_parsed->key_iv, 16, LOG_LEVEL_DEBUG); |
474 | 0 | DEBUG_DUMP("decryption_key", decryption_key, decryption_key_len, LOG_LEVEL_DEBUG); |
475 | | |
476 | | /* As we have no concept of the prior association request at this point, we need to deduce the */ |
477 | | /* group key cipher from the length of the key bytes. In WPA this is straightforward as the */ |
478 | | /* keybytes just contain the GTK, and the GTK is only in the group handshake, NOT the M3. */ |
479 | | /* In WPA2 its a little more tricky as the M3 keybytes contain an RSN_IE, but the group handshake */ |
480 | | /* does not. Also there are other (variable length) items in the keybytes which we need to account */ |
481 | | /* for to determine the true key length, and thus the group cipher. */ |
482 | |
|
483 | 0 | if (key_version == DOT11DECRYPT_WPA_KEY_VER_NOT_CCMP){ |
484 | | /* TKIP key */ |
485 | | /* Per 802.11i, Draft 3.0 spec, section 8.5.2, p. 97, line 4-8, */ |
486 | | /* group key is decrypted using RC4. Concatenate the IV with the 16 byte EK (PTK+16) to get the decryption key */ |
487 | 0 | uint8_t new_key[32]; |
488 | 0 | uint8_t *data; |
489 | | |
490 | | /* The WPA group key just contains the GTK bytes so deducing the type is straightforward */ |
491 | | /* Note - WPA M3 doesn't contain a group key so we'll only be here for the group handshake */ |
492 | 0 | sa->wpa.key_ver = (key_bytes_len >=TKIP_GROUP_KEY_LEN)?DOT11DECRYPT_WPA_KEY_VER_NOT_CCMP:DOT11DECRYPT_WPA_KEY_VER_AES_CCMP; |
493 | | |
494 | | /* Build the full decryption key based on the IV and part of the pairwise key */ |
495 | 0 | memcpy(new_key, eapol_parsed->key_iv, 16); |
496 | 0 | memcpy(new_key+16, decryption_key, 16); |
497 | 0 | DEBUG_DUMP("FullDecrKey", new_key, 32, LOG_LEVEL_DEBUG); |
498 | 0 | data = Dot11DecryptRc4KeyData(new_key, 32, key_data, key_bytes_len); |
499 | 0 | if (!data) { |
500 | 0 | return DOT11DECRYPT_RET_UNSUCCESS; |
501 | 0 | } |
502 | 0 | memcpy(decrypted_data, data, key_bytes_len); |
503 | 0 | g_free(data); |
504 | 0 | } else { |
505 | | /* Ideally AKM from EAPOL message 2 of 4 should be used to determine Key-wrap algorithm to use */ |
506 | | /* Though fortunately IEEE802.11-2016 Table 12-8 state that all AKMs use "NIST AES Key Wrap" */ |
507 | | /* algorithm so no AKM lookup is needed. */ |
508 | | |
509 | | /* Unwrap the key; the result is key_bytes_len in length */ |
510 | 0 | if (AES_unwrap(decryption_key, decryption_key_len, key_data, key_bytes_len, |
511 | 0 | decrypted_data, &key_bytes_len)) { |
512 | 0 | return DOT11DECRYPT_RET_UNSUCCESS; |
513 | 0 | } |
514 | 0 | } |
515 | | |
516 | 0 | Dot11DecryptCopyKey(sa, key); |
517 | 0 | *decrypted_len = key_bytes_len; |
518 | 0 | return DOT11DECRYPT_RET_SUCCESS; |
519 | 0 | } |
520 | | |
521 | | /** |
522 | | * @param ctx [IN] pointer to the current context |
523 | | * @param id [IN] id of the association (composed by BSSID and MAC of |
524 | | * the station) |
525 | | * @return a pointer of the requested SA. NULL if it doesn't exist. |
526 | | */ |
527 | | static PDOT11DECRYPT_SEC_ASSOCIATION |
528 | | Dot11DecryptGetSa( |
529 | | PDOT11DECRYPT_CONTEXT ctx, |
530 | | const DOT11DECRYPT_SEC_ASSOCIATION_ID *id) |
531 | 158 | { |
532 | 158 | return (DOT11DECRYPT_SEC_ASSOCIATION *)g_hash_table_lookup(ctx->sa_hash, id); |
533 | 158 | } |
534 | | |
535 | | static PDOT11DECRYPT_SEC_ASSOCIATION |
536 | | Dot11DecryptNewSa(const DOT11DECRYPT_SEC_ASSOCIATION_ID *id) |
537 | 0 | { |
538 | 0 | PDOT11DECRYPT_SEC_ASSOCIATION sa = g_new0(DOT11DECRYPT_SEC_ASSOCIATION, 1); |
539 | 0 | if (sa != NULL) { |
540 | 0 | sa->saId = *id; |
541 | 0 | } |
542 | 0 | return sa; |
543 | 0 | } |
544 | | |
545 | | static DOT11DECRYPT_SEC_ASSOCIATION * |
546 | | Dot11DecryptPrependSa( |
547 | | DOT11DECRYPT_SEC_ASSOCIATION *existing_sa, |
548 | | DOT11DECRYPT_SEC_ASSOCIATION *new_sa) |
549 | 0 | { |
550 | 0 | DOT11DECRYPT_SEC_ASSOCIATION tmp_sa; |
551 | | |
552 | | /* Add new SA first in list, but copy by value into existing record |
553 | | * so that sa_hash need not be updated with new value */ |
554 | 0 | tmp_sa = *existing_sa; |
555 | 0 | *existing_sa = *new_sa; |
556 | 0 | *new_sa = tmp_sa; |
557 | 0 | existing_sa->next = new_sa; |
558 | 0 | return existing_sa; |
559 | 0 | } |
560 | | |
561 | | /* Add SA, keep existing (if any). Return pointer to newly inserted (first) SA */ |
562 | | static PDOT11DECRYPT_SEC_ASSOCIATION |
563 | | Dot11DecryptAddSa( |
564 | | PDOT11DECRYPT_CONTEXT ctx, |
565 | | const DOT11DECRYPT_SEC_ASSOCIATION_ID *id, |
566 | | DOT11DECRYPT_SEC_ASSOCIATION *sa) |
567 | 0 | { |
568 | 0 | DOT11DECRYPT_SEC_ASSOCIATION *existing_sa = Dot11DecryptGetSa(ctx, id); |
569 | 0 | if (existing_sa != NULL) { |
570 | 0 | sa = Dot11DecryptPrependSa(existing_sa, sa); |
571 | 0 | } else { |
572 | 0 | void *key = g_memdup2(id, sizeof(DOT11DECRYPT_SEC_ASSOCIATION_ID)); |
573 | 0 | g_hash_table_insert(ctx->sa_hash, key, sa); |
574 | 0 | } |
575 | 0 | return sa; |
576 | 0 | } |
577 | | |
578 | | int |
579 | | Dot11DecryptGetKCK(const PDOT11DECRYPT_KEY_ITEM key, const uint8_t **kck) |
580 | 0 | { |
581 | 0 | if (!key || !kck) { |
582 | 0 | return 0; |
583 | 0 | } |
584 | 0 | *kck = DOT11DECRYPT_GET_KCK(key->KeyData.Wpa.Ptk, key->KeyData.Wpa.Akm); |
585 | 0 | return Dot11DecryptGetKckLen(key->KeyData.Wpa.Akm, key->KeyData.Wpa.DhGroup) / 8; |
586 | 0 | } |
587 | | |
588 | | int |
589 | | Dot11DecryptGetKEK(const PDOT11DECRYPT_KEY_ITEM key, const uint8_t **kek) |
590 | 0 | { |
591 | 0 | if (!key || !kek) { |
592 | 0 | return 0; |
593 | 0 | } |
594 | 0 | *kek = DOT11DECRYPT_GET_KEK(key->KeyData.Wpa.Ptk, key->KeyData.Wpa.Akm, key->KeyData.Wpa.DhGroup); |
595 | 0 | return Dot11DecryptGetKekLen(key->KeyData.Wpa.Akm, key->KeyData.Wpa.DhGroup) / 8; |
596 | 0 | } |
597 | | |
598 | | int |
599 | | Dot11DecryptGetTK(const PDOT11DECRYPT_KEY_ITEM key, const uint8_t **tk) |
600 | 0 | { |
601 | 0 | int len; |
602 | 0 | if (!key || !tk) { |
603 | 0 | return 0; |
604 | 0 | } |
605 | 0 | if (key->KeyType == DOT11DECRYPT_KEY_TYPE_TKIP) { |
606 | 0 | *tk = DOT11DECRYPT_GET_TK_TKIP(key->KeyData.Wpa.Ptk); |
607 | 0 | len = 16; |
608 | 0 | } else { |
609 | 0 | *tk = DOT11DECRYPT_GET_TK(key->KeyData.Wpa.Ptk, key->KeyData.Wpa.Akm, key->KeyData.Wpa.DhGroup); |
610 | 0 | len = Dot11DecryptGetTkLen(key->KeyData.Wpa.Cipher) / 8; |
611 | 0 | } |
612 | 0 | return len; |
613 | 0 | } |
614 | | |
615 | | int |
616 | | Dot11DecryptGetGTK(const PDOT11DECRYPT_KEY_ITEM key, const uint8_t **gtk) |
617 | 0 | { |
618 | 0 | int len; |
619 | 0 | if (!key || !gtk) { |
620 | 0 | return 0; |
621 | 0 | } |
622 | | |
623 | | /* GTK is stored in PTK at offset 32. See comment in Dot11DecryptCopyBroadcastKey */ |
624 | 0 | *gtk = key->KeyData.Wpa.Ptk + 32; |
625 | 0 | if (key->KeyType == DOT11DECRYPT_KEY_TYPE_TKIP) { |
626 | 0 | len = 16; |
627 | 0 | } else { |
628 | 0 | len = Dot11DecryptGetTkLen(key->KeyData.Wpa.Cipher) / 8; |
629 | 0 | } |
630 | 0 | return len; |
631 | 0 | } |
632 | | |
633 | | int Dot11DecryptScanTdlsForKeys( |
634 | | PDOT11DECRYPT_CONTEXT ctx, |
635 | | const uint8_t *data, |
636 | | const unsigned tot_len) |
637 | 51 | { |
638 | 51 | unsigned offset = 0; |
639 | 51 | unsigned tot_len_left = tot_len; |
640 | 51 | DOT11DECRYPT_SEC_ASSOCIATION_ID id; |
641 | 51 | PDOT11DECRYPT_SEC_ASSOCIATION sa; |
642 | 51 | const uint8_t *initiator, *responder; |
643 | 51 | uint8_t action; |
644 | 51 | unsigned status, offset_rsne = 0, offset_fte = 0, offset_link = 0, offset_timeout = 0; |
645 | 51 | ws_debug("Authentication: TDLS Action Frame"); |
646 | | |
647 | | /* TDLS payload contains a TDLS Action field (802.11-2016 9.6.13) */ |
648 | | |
649 | | /* check if the packet is a TDLS response or confirm */ |
650 | 51 | if (tot_len_left < 1) { |
651 | 0 | ws_debug("Not EAPOL-Key"); |
652 | 0 | return DOT11DECRYPT_RET_NO_VALID_HANDSHAKE; |
653 | 0 | } |
654 | 51 | action = data[offset]; |
655 | 51 | if (action != 1 && action != 2) { |
656 | 9 | ws_debug("Not Response nor confirm"); |
657 | 9 | return DOT11DECRYPT_RET_NO_VALID_HANDSHAKE; |
658 | 9 | } |
659 | 42 | offset++; |
660 | 42 | tot_len_left--; |
661 | | |
662 | | /* Check for SUCCESS (0) or SUCCESS_POWER_SAVE_MODE (85) Status Code */ |
663 | 42 | if (tot_len_left < 5) { |
664 | 0 | ws_debug("Not EAPOL-Key"); |
665 | 0 | return DOT11DECRYPT_RET_NO_VALID_HANDSHAKE; |
666 | 0 | } |
667 | 42 | status=pntoh16(data + offset); |
668 | 42 | if (status != 0 && status != 85) { |
669 | 4 | ws_debug("TDLS setup not successful"); |
670 | 4 | return DOT11DECRYPT_RET_NO_VALID_HANDSHAKE; |
671 | 4 | } |
672 | | |
673 | | /* skip Token + capabilities */ |
674 | 38 | offset += 5; |
675 | | |
676 | | /* search for RSN, Fast BSS Transition, Link Identifier and Timeout Interval IEs */ |
677 | | |
678 | 551 | while(offset < (tot_len - 2)) { |
679 | 546 | uint8_t element_id = data[offset]; |
680 | 546 | uint8_t length = data[offset + 1]; |
681 | 546 | unsigned min_length = length; |
682 | 546 | switch (element_id) { |
683 | 8 | case 48: /* RSN (802.11-2016 9.4.2.35) */ |
684 | 8 | offset_rsne = offset; |
685 | 8 | min_length = 1; |
686 | 8 | break; |
687 | 6 | case 55: /* FTE (802.11-2016 9.4.2.48) */ |
688 | 6 | offset_fte = offset; |
689 | | /* Plus variable length optional parameter(s) */ |
690 | 6 | min_length = 2 + 16 + 32 + 32; |
691 | 6 | break; |
692 | 3 | case 56: /* Timeout Interval (802.11-2016 9.4.2.49) */ |
693 | 3 | offset_timeout = offset; |
694 | 3 | min_length = 1 + 4; |
695 | 3 | break; |
696 | 1 | case 101: /* Link Identifier (802.11-2016 9.4.2.62) */ |
697 | 1 | offset_link = offset; |
698 | 1 | min_length = 6 + 6 + 6; |
699 | 1 | break; |
700 | 546 | } |
701 | | |
702 | 546 | if (length < min_length || tot_len < offset + 2 + length) { |
703 | 33 | ws_debug("Invalid length records in IEs"); |
704 | 33 | return DOT11DECRYPT_RET_NO_VALID_HANDSHAKE; |
705 | 33 | } |
706 | 513 | offset += 2 + length; |
707 | 513 | } |
708 | | |
709 | 5 | if (offset_rsne == 0 || offset_fte == 0 || |
710 | 5 | offset_timeout == 0 || offset_link == 0) |
711 | 5 | { |
712 | 5 | ws_debug("Cannot Find all necessary IEs"); |
713 | 5 | return DOT11DECRYPT_RET_NO_VALID_HANDSHAKE; |
714 | 5 | } |
715 | | |
716 | 0 | ws_debug("Found RSNE/Fast BSS/Timeout Interval/Link IEs"); |
717 | | |
718 | | /* Will create a Security Association between 2 STA. Need to get both MAC address */ |
719 | 0 | initiator = &data[offset_link + 8]; |
720 | 0 | responder = &data[offset_link + 14]; |
721 | |
|
722 | 0 | if (memcmp(initiator, responder, DOT11DECRYPT_MAC_LEN) < 0) { |
723 | 0 | memcpy(id.sta, initiator, DOT11DECRYPT_MAC_LEN); |
724 | 0 | memcpy(id.bssid, responder, DOT11DECRYPT_MAC_LEN); |
725 | 0 | } else { |
726 | 0 | memcpy(id.sta, responder, DOT11DECRYPT_MAC_LEN); |
727 | 0 | memcpy(id.bssid, initiator, DOT11DECRYPT_MAC_LEN); |
728 | 0 | } |
729 | | |
730 | | /* Check if already derived this key */ |
731 | 0 | sa = Dot11DecryptGetSa(ctx, &id); |
732 | 0 | PDOT11DECRYPT_SEC_ASSOCIATION iter_sa; |
733 | 0 | for (iter_sa = sa; iter_sa != NULL; iter_sa = iter_sa->next) { |
734 | 0 | if (iter_sa->validKey && |
735 | 0 | memcmp(iter_sa->wpa.nonce, data + offset_fte + 52, |
736 | 0 | DOT11DECRYPT_WPA_NONCE_LEN) == 0) |
737 | 0 | { |
738 | | /* Already have valid key for this SA, no need to redo key derivation */ |
739 | 0 | return DOT11DECRYPT_RET_SUCCESS_HANDSHAKE; |
740 | 0 | } |
741 | 0 | } |
742 | | /* We are opening a new session with the same two STA (previous sa will be kept if any) */ |
743 | 0 | sa = Dot11DecryptNewSa(&id); |
744 | 0 | if (sa == NULL) { |
745 | 0 | ws_warning("Failed to alloc new SA entry"); |
746 | 0 | return DOT11DECRYPT_RET_REQ_DATA; |
747 | 0 | } |
748 | 0 | if (Dot11DecryptTDLSDeriveKey(sa, data, offset_rsne, offset_fte, |
749 | 0 | offset_timeout, offset_link, action) == DOT11DECRYPT_RET_SUCCESS) { |
750 | 0 | Dot11DecryptAddSa(ctx, &id, sa); |
751 | 0 | return DOT11DECRYPT_RET_SUCCESS_HANDSHAKE; |
752 | 0 | } |
753 | 0 | g_free(sa); |
754 | 0 | return DOT11DECRYPT_RET_NO_VALID_HANDSHAKE; |
755 | 0 | } |
756 | | |
757 | | static int |
758 | | Dot11DecryptCopyBroadcastKey( |
759 | | PDOT11DECRYPT_CONTEXT ctx, |
760 | | const uint8_t *gtk, size_t gtk_len, |
761 | | const DOT11DECRYPT_SEC_ASSOCIATION_ID *id) |
762 | 0 | { |
763 | 0 | DOT11DECRYPT_SEC_ASSOCIATION_ID broadcast_id; |
764 | 0 | DOT11DECRYPT_SEC_ASSOCIATION *sa; |
765 | 0 | DOT11DECRYPT_SEC_ASSOCIATION *broadcast_sa; |
766 | |
|
767 | 0 | if (!gtk || gtk_len == 0) { |
768 | 0 | ws_debug("No broadcast key found"); |
769 | 0 | return DOT11DECRYPT_RET_NO_VALID_HANDSHAKE; |
770 | 0 | } |
771 | 0 | if (gtk_len > DOT11DECRYPT_WPA_PTK_MAX_LEN - 32) { |
772 | 0 | ws_debug("Broadcast key too large"); |
773 | 0 | return DOT11DECRYPT_RET_NO_VALID_HANDSHAKE; |
774 | 0 | } |
775 | | |
776 | 0 | sa = Dot11DecryptGetSa(ctx, id); |
777 | 0 | if (sa == NULL) { |
778 | 0 | ws_debug("No SA for BSSID found"); |
779 | 0 | return DOT11DECRYPT_RET_NO_VALID_HANDSHAKE; |
780 | 0 | } |
781 | | |
782 | | /* Broadcast SA for the current BSSID */ |
783 | 0 | memcpy(broadcast_id.bssid, id->bssid, DOT11DECRYPT_MAC_LEN); |
784 | 0 | memcpy(broadcast_id.sta, broadcast_mac, DOT11DECRYPT_MAC_LEN); |
785 | |
|
786 | 0 | broadcast_sa = Dot11DecryptNewSa(&broadcast_id); |
787 | 0 | if (broadcast_sa == NULL) { |
788 | 0 | ws_warning("Failed to alloc broadcast sa"); |
789 | 0 | return DOT11DECRYPT_RET_NO_VALID_HANDSHAKE; |
790 | 0 | } |
791 | | |
792 | | /* Retrieve AKMS / cipher etc from handshake message 2 */ |
793 | | |
794 | 0 | broadcast_sa->wpa.key_ver = sa->wpa.key_ver; |
795 | 0 | broadcast_sa->wpa.akm = sa->wpa.akm; |
796 | 0 | broadcast_sa->wpa.cipher = sa->wpa.tmp_group_cipher; |
797 | 0 | broadcast_sa->wpa.ptk_len = sa->wpa.ptk_len; |
798 | 0 | broadcast_sa->validKey = true; |
799 | 0 | DEBUG_DUMP("Broadcast key", gtk, gtk_len, LOG_LEVEL_DEBUG); |
800 | | |
801 | | /* Since this is a GTK and its size is only 32 bytes (vs. the 64 byte size of a PTK), |
802 | | * we fake it and put it in at a 32-byte offset so the Dot11DecryptRsnaMng() function |
803 | | * will extract the right piece of the GTK for decryption. (The first 16 bytes of the |
804 | | * GTK are used for decryption.) */ |
805 | 0 | memset(broadcast_sa->wpa.ptk, 0, sizeof(broadcast_sa->wpa.ptk)); |
806 | 0 | memcpy(broadcast_sa->wpa.ptk + 32, gtk, gtk_len); |
807 | 0 | Dot11DecryptAddSa(ctx, &broadcast_id, broadcast_sa); |
808 | 0 | return DOT11DECRYPT_RET_SUCCESS_HANDSHAKE; |
809 | 0 | } |
810 | | |
811 | | static int |
812 | | Dot11DecryptGroupHandshake( |
813 | | PDOT11DECRYPT_CONTEXT ctx, |
814 | | PDOT11DECRYPT_EAPOL_PARSED eapol_parsed, |
815 | | const DOT11DECRYPT_SEC_ASSOCIATION_ID *id, |
816 | | const unsigned tot_len) |
817 | 0 | { |
818 | |
|
819 | 0 | if (GROUP_KEY_PAYLOAD_LEN_MIN > tot_len) { |
820 | 0 | ws_debug("Message too short for Group Key"); |
821 | 0 | return DOT11DECRYPT_RET_NO_VALID_HANDSHAKE; |
822 | 0 | } |
823 | 0 | if (eapol_parsed->msg_type != DOT11DECRYPT_HS_MSG_TYPE_GHS_1){ |
824 | 0 | ws_warning("Not Group handshake message 1"); |
825 | 0 | return DOT11DECRYPT_RET_NO_VALID_HANDSHAKE; |
826 | 0 | } |
827 | 0 | return Dot11DecryptCopyBroadcastKey(ctx, eapol_parsed->gtk, eapol_parsed->gtk_len, id); |
828 | 0 | } |
829 | | |
830 | | int Dot11DecryptScanEapolForKeys( |
831 | | PDOT11DECRYPT_CONTEXT ctx, |
832 | | PDOT11DECRYPT_EAPOL_PARSED eapol_parsed, |
833 | | const uint8_t *eapol_raw, |
834 | | const unsigned tot_len, |
835 | | const unsigned char bssid[DOT11DECRYPT_MAC_LEN], |
836 | | const unsigned char sta[DOT11DECRYPT_MAC_LEN]) |
837 | 0 | { |
838 | 0 | DOT11DECRYPT_SEC_ASSOCIATION_ID id; |
839 | | |
840 | | /* Callers provide these guarantees, so let's make them explicit. */ |
841 | 0 | DISSECTOR_ASSERT(tot_len <= DOT11DECRYPT_EAPOL_MAX_LEN); |
842 | |
|
843 | 0 | ws_debug("Authentication: EAPOL packet"); |
844 | | |
845 | | /* check if the key descriptor type is valid (IEEE 802.1X-2004, pg. 27) */ |
846 | 0 | if (/*eapol_parsed->key_type != 0x1 &&*/ /* RC4 Key Descriptor Type (deprecated) */ |
847 | 0 | eapol_parsed->key_type != DOT11DECRYPT_RSN_WPA2_KEY_DESCRIPTOR && /* IEEE 802.11 Key Descriptor Type (WPA2) */ |
848 | 0 | eapol_parsed->key_type != DOT11DECRYPT_RSN_WPA_KEY_DESCRIPTOR) /* 254 = RSN_KEY_DESCRIPTOR - WPA, */ |
849 | 0 | { |
850 | 0 | ws_debug("Not valid key descriptor type"); |
851 | 0 | return DOT11DECRYPT_RET_NO_VALID_HANDSHAKE; |
852 | 0 | } |
853 | | |
854 | | /* search for a cached Security Association for current BSSID and AP */ |
855 | 0 | memcpy(id.bssid, bssid, DOT11DECRYPT_MAC_LEN); |
856 | 0 | memcpy(id.sta, sta, DOT11DECRYPT_MAC_LEN); |
857 | |
|
858 | 0 | switch (eapol_parsed->msg_type) { |
859 | 0 | case DOT11DECRYPT_HS_MSG_TYPE_4WHS_1: |
860 | 0 | case DOT11DECRYPT_HS_MSG_TYPE_4WHS_2: |
861 | 0 | case DOT11DECRYPT_HS_MSG_TYPE_4WHS_3: |
862 | 0 | case DOT11DECRYPT_HS_MSG_TYPE_4WHS_4: |
863 | 0 | return Dot11DecryptRsna4WHandshake(ctx, eapol_parsed, eapol_raw, |
864 | 0 | &id, tot_len); |
865 | 0 | case DOT11DECRYPT_HS_MSG_TYPE_GHS_1: |
866 | 0 | return Dot11DecryptGroupHandshake(ctx, eapol_parsed, &id, tot_len); |
867 | 0 | case DOT11DECRYPT_HS_MSG_TYPE_GHS_2: |
868 | 0 | break; |
869 | 0 | case DOT11DECRYPT_HS_MSG_TYPE_INVALID: |
870 | 0 | default: |
871 | 0 | ws_warning("Invalid message type"); |
872 | 0 | break; |
873 | 0 | } |
874 | 0 | return DOT11DECRYPT_RET_NO_VALID_HANDSHAKE; |
875 | 0 | } |
876 | | |
877 | | static int |
878 | | Dot11DecryptGetNbrOfTkKeys(PDOT11DECRYPT_CONTEXT ctx) |
879 | 62 | { |
880 | 62 | int nbr = 0; |
881 | 62 | for (size_t i = 0; i < ctx->keys_nr; i++) { |
882 | 0 | if (ctx->keys[i].KeyType == DOT11DECRYPT_KEY_TYPE_TK) { |
883 | 0 | nbr++; |
884 | 0 | } |
885 | 0 | } |
886 | 62 | return nbr; |
887 | 62 | } |
888 | | |
889 | | static int |
890 | | Dot11DecryptUsingUserTk( |
891 | | PDOT11DECRYPT_CONTEXT ctx, |
892 | | unsigned char *decrypt_data, |
893 | | unsigned mac_header_len, |
894 | | unsigned *decrypt_len, |
895 | | DOT11DECRYPT_SEC_ASSOCIATION_ID *id, |
896 | | DOT11DECRYPT_KEY_ITEM *used_key) |
897 | 0 | { |
898 | 0 | int ret = DOT11DECRYPT_RET_REQ_DATA; |
899 | 0 | DOT11DECRYPT_SEC_ASSOCIATION *sa = Dot11DecryptNewSa(id); |
900 | 0 | DOT11DECRYPT_KEY_ITEM *key; |
901 | 0 | if (sa == NULL) { |
902 | 0 | return ret; |
903 | 0 | } |
904 | | |
905 | 0 | sa->wpa.akm = 2; |
906 | 0 | sa->validKey = true; |
907 | | |
908 | | /* Try decrypt packet with all user TKs applicable ciphers */ |
909 | 0 | for (size_t key_index = 0; key_index < ctx->keys_nr; key_index++) { |
910 | 0 | key = &ctx->keys[key_index]; |
911 | 0 | if (key->KeyType != DOT11DECRYPT_KEY_TYPE_TK) { |
912 | 0 | continue; |
913 | 0 | } |
914 | 0 | int ciphers_to_try[4] = { 0 }; |
915 | 0 | switch (key->Tk.Len) { |
916 | 0 | case DOT11DECRYPT_WEP_40_KEY_LEN: |
917 | 0 | case DOT11DECRYPT_WEP_104_KEY_LEN: |
918 | | /* TBD implement */ |
919 | 0 | continue; |
920 | 0 | case 256 / 8: |
921 | 0 | ciphers_to_try[0] = 9; /* GCMP-256 */ |
922 | 0 | ciphers_to_try[1] = 10; /* CCMP-256 */ |
923 | 0 | break; |
924 | 0 | case 128 / 8: |
925 | 0 | ciphers_to_try[0] = 4; /* CCMP-128 */ |
926 | 0 | ciphers_to_try[1] = 8; /* GCMP-128 */ |
927 | 0 | ciphers_to_try[2] = 2; /* TKIP */ |
928 | 0 | break; |
929 | 0 | default: |
930 | 0 | continue; |
931 | 0 | } |
932 | | |
933 | 0 | sa->key = key; |
934 | |
|
935 | 0 | for (int i = 0; ciphers_to_try[i] != 0; i++) { |
936 | 0 | sa->wpa.cipher = ciphers_to_try[i]; |
937 | 0 | if (sa->wpa.cipher == DOT11DECRYPT_CIPHER_TKIP) { |
938 | 0 | sa->wpa.key_ver = 1; |
939 | 0 | memcpy(DOT11DECRYPT_GET_TK_TKIP(sa->wpa.ptk), |
940 | 0 | key->Tk.Tk, key->Tk.Len); |
941 | 0 | } else { |
942 | 0 | sa->wpa.key_ver = 2; |
943 | 0 | sa->wpa.akm = 2; |
944 | 0 | memcpy(DOT11DECRYPT_GET_TK(sa->wpa.ptk, sa->wpa.akm, sa->wpa.dh_group), |
945 | 0 | key->Tk.Tk, key->Tk.Len); |
946 | 0 | } |
947 | 0 | sa->wpa.ptk_len = Dot11DecryptGetPtkLen(sa->wpa.akm, sa->wpa.cipher, sa->wpa.dh_group) / 8; |
948 | 0 | ret = Dot11DecryptRsnaMng(decrypt_data, mac_header_len, decrypt_len, used_key, sa); |
949 | 0 | if (ret == DOT11DECRYPT_RET_SUCCESS) { |
950 | | /* Successfully decrypted using user TK. Add SA formed from user TK so that |
951 | | * subsequent frames can be decrypted much faster using normal code path |
952 | | * without trying each and every user TK entered. |
953 | | */ |
954 | 0 | Dot11DecryptAddSa(ctx, id, sa); |
955 | 0 | return ret; |
956 | 0 | } |
957 | 0 | } |
958 | 0 | } |
959 | 0 | g_free(sa); |
960 | 0 | return ret; |
961 | 0 | } |
962 | | |
963 | | int Dot11DecryptDecryptPacket( |
964 | | PDOT11DECRYPT_CONTEXT ctx, |
965 | | const uint8_t *data, |
966 | | const unsigned mac_header_len, |
967 | | const unsigned tot_len, |
968 | | unsigned char *decrypt_data, |
969 | | unsigned *decrypt_len, |
970 | | PDOT11DECRYPT_KEY_ITEM key) |
971 | 272 | { |
972 | 272 | DOT11DECRYPT_SEC_ASSOCIATION_ID id; |
973 | 272 | DISSECTOR_ASSERT(decrypt_data); |
974 | 272 | DISSECTOR_ASSERT(decrypt_len); |
975 | | |
976 | 272 | if (decrypt_len) { |
977 | 272 | *decrypt_len = 0; |
978 | 272 | } |
979 | 272 | if (ctx==NULL) { |
980 | 0 | ws_warning("NULL context"); |
981 | 0 | return DOT11DECRYPT_RET_REQ_DATA; |
982 | 0 | } |
983 | 272 | if (data==NULL || tot_len==0) { |
984 | 0 | ws_debug("NULL data or length=0"); |
985 | 0 | return DOT11DECRYPT_RET_REQ_DATA; |
986 | 0 | } |
987 | | |
988 | | /* check correct packet size, to avoid wrong elaboration of encryption algorithms */ |
989 | 272 | if (tot_len < (unsigned)(mac_header_len+DOT11DECRYPT_CRYPTED_DATA_MINLEN)) { |
990 | 111 | ws_debug("minimum length violated"); |
991 | 111 | return DOT11DECRYPT_RET_WRONG_DATA_SIZE; |
992 | 111 | } |
993 | | |
994 | | /* Assume that the decrypt_data field is no more than this size. */ |
995 | 161 | if (tot_len > DOT11DECRYPT_MAX_CAPLEN) { |
996 | 0 | ws_debug("length too large"); |
997 | 0 | return DOT11DECRYPT_RET_UNSUCCESS; |
998 | 0 | } |
999 | | |
1000 | | /* get STA/BSSID address */ |
1001 | 161 | if (Dot11DecryptGetSaAddress((const DOT11DECRYPT_MAC_FRAME_ADDR4 *)(data), &id) != DOT11DECRYPT_RET_SUCCESS) { |
1002 | 0 | ws_noisy("STA/BSSID not found"); |
1003 | 0 | return DOT11DECRYPT_RET_REQ_DATA; |
1004 | 0 | } |
1005 | | |
1006 | | /* check if data is encrypted (use the WEP bit in the Frame Control field) */ |
1007 | 161 | if (DOT11DECRYPT_WEP(data[1])==0) { |
1008 | 3 | return DOT11DECRYPT_RET_NO_DATA_ENCRYPTED; |
1009 | 3 | } |
1010 | 158 | PDOT11DECRYPT_SEC_ASSOCIATION sa; |
1011 | | |
1012 | | /* create new header and data to modify */ |
1013 | 158 | *decrypt_len = tot_len; |
1014 | 158 | memcpy(decrypt_data, data, *decrypt_len); |
1015 | | |
1016 | | /* encrypted data */ |
1017 | 158 | ws_noisy("Encrypted data"); |
1018 | | |
1019 | | /* check the Extension IV to distinguish between WEP encryption and WPA encryption */ |
1020 | | /* refer to IEEE 802.11i-2004, 8.2.1.2, pag.35 for WEP, */ |
1021 | | /* IEEE 802.11i-2004, 8.3.2.2, pag. 45 for TKIP, */ |
1022 | | /* IEEE 802.11i-2004, 8.3.3.2, pag. 57 for CCMP */ |
1023 | 158 | if (DOT11DECRYPT_EXTIV(data[mac_header_len + 3]) == 0) { |
1024 | 96 | ws_noisy("WEP encryption"); |
1025 | 96 | return Dot11DecryptWepMng(ctx, decrypt_data, mac_header_len, decrypt_len, key, &id); |
1026 | 96 | } else { |
1027 | 62 | ws_noisy("TKIP or CCMP encryption"); |
1028 | | |
1029 | | /* If the destination is a multicast address use the group key. This will not work if the AP is using |
1030 | | more than one group key simultaneously. I've not seen this in practice, however. |
1031 | | Usually an AP will rotate between the two key index values of 1 and 2 whenever |
1032 | | it needs to change the group key to be used. */ |
1033 | 62 | if (((const DOT11DECRYPT_MAC_FRAME_ADDR4 *)(data))->addr1[0] & 0x01) { |
1034 | 33 | ws_noisy("Broadcast/Multicast address. This is encrypted with a group key."); |
1035 | | |
1036 | | /* force STA address to broadcast MAC so we load the SA for the groupkey */ |
1037 | 33 | memcpy(id.sta, broadcast_mac, DOT11DECRYPT_MAC_LEN); |
1038 | 33 | } |
1039 | | /* search for a cached Security Association for current BSSID and STA/broadcast MAC */ |
1040 | 62 | int ret = DOT11DECRYPT_RET_REQ_DATA; |
1041 | 62 | sa = Dot11DecryptGetSa(ctx, &id); |
1042 | 62 | if (sa != NULL) { |
1043 | | /* Decrypt the packet using the appropriate SA */ |
1044 | 0 | ret = Dot11DecryptRsnaMng(decrypt_data, mac_header_len, decrypt_len, key, sa); |
1045 | 0 | } |
1046 | 62 | if (ret != DOT11DECRYPT_RET_SUCCESS && Dot11DecryptGetNbrOfTkKeys(ctx) > 0) { |
1047 | | /* Decryption with known SAs failed. Try decrypt with TK user entries */ |
1048 | 0 | ret = Dot11DecryptUsingUserTk(ctx, decrypt_data, mac_header_len, decrypt_len, &id, key); |
1049 | 0 | } |
1050 | 62 | return ret; |
1051 | 62 | } |
1052 | 0 | return DOT11DECRYPT_RET_UNSUCCESS; |
1053 | 158 | } |
1054 | | |
1055 | | int Dot11DecryptSetKeys( |
1056 | | PDOT11DECRYPT_CONTEXT ctx, |
1057 | | DOT11DECRYPT_KEY_ITEM keys[], |
1058 | | const size_t keys_nr) |
1059 | 28 | { |
1060 | 28 | int i; |
1061 | 28 | int success; |
1062 | | |
1063 | 28 | if (ctx==NULL || keys==NULL) { |
1064 | 0 | ws_warning("NULL context or NULL keys array"); |
1065 | 0 | return 0; |
1066 | 0 | } |
1067 | | |
1068 | 28 | if (keys_nr>DOT11DECRYPT_MAX_KEYS_NR) { |
1069 | 0 | ws_warning("Keys number greater than maximum"); |
1070 | 0 | return 0; |
1071 | 0 | } |
1072 | | |
1073 | | /* clean key and SA collections before setting new ones */ |
1074 | 28 | Dot11DecryptInitContext(ctx); |
1075 | | |
1076 | | /* check and insert keys */ |
1077 | 28 | for (i=0, success=0; i<(int)keys_nr; i++) { |
1078 | 0 | if (Dot11DecryptValidateKey(keys+i)==true) { |
1079 | 0 | if (keys[i].KeyType==DOT11DECRYPT_KEY_TYPE_WPA_PWD) { |
1080 | 0 | Dot11DecryptRsnaPwd2Psk(&keys[i].UserPwd, keys[i].KeyData.Wpa.Psk); |
1081 | 0 | keys[i].KeyData.Wpa.PskLen = DOT11DECRYPT_WPA_PWD_PSK_LEN; |
1082 | 0 | } |
1083 | 0 | memcpy(&ctx->keys[success], &keys[i], sizeof(keys[i])); |
1084 | 0 | success++; |
1085 | 0 | } |
1086 | 0 | } |
1087 | | |
1088 | 28 | ctx->keys_nr=success; |
1089 | 28 | return success; |
1090 | 28 | } |
1091 | | |
1092 | | static void |
1093 | | Dot11DecryptCleanKeys( |
1094 | | PDOT11DECRYPT_CONTEXT ctx) |
1095 | 28 | { |
1096 | 28 | if (ctx==NULL) { |
1097 | 0 | ws_warning("NULL context"); |
1098 | 0 | return; |
1099 | 0 | } |
1100 | | |
1101 | 28 | memset(ctx->keys, 0, sizeof(DOT11DECRYPT_KEY_ITEM) * DOT11DECRYPT_MAX_KEYS_NR); |
1102 | | |
1103 | 28 | ctx->keys_nr=0; |
1104 | 28 | ws_debug("Keys collection cleaned!"); |
1105 | 28 | } |
1106 | | |
1107 | | static void |
1108 | | Dot11DecryptCleanSA( |
1109 | | void * first_sa) |
1110 | 0 | { |
1111 | 0 | DOT11DECRYPT_SEC_ASSOCIATION *cur_sa = (DOT11DECRYPT_SEC_ASSOCIATION *)first_sa; |
1112 | 0 | while (cur_sa) { |
1113 | 0 | DOT11DECRYPT_SEC_ASSOCIATION *next_sa = cur_sa->next; |
1114 | 0 | g_free(cur_sa); |
1115 | 0 | cur_sa = next_sa; |
1116 | 0 | } |
1117 | 0 | } |
1118 | | |
1119 | | static void |
1120 | | Dot11DecryptCleanSecAssoc( |
1121 | | PDOT11DECRYPT_CONTEXT ctx) |
1122 | 28 | { |
1123 | 28 | if (ctx->sa_hash != NULL) { |
1124 | 14 | g_hash_table_destroy(ctx->sa_hash); |
1125 | 14 | ctx->sa_hash = NULL; |
1126 | 14 | } |
1127 | 28 | } |
1128 | | |
1129 | | /* |
1130 | | * XXX - This won't be reliable if a packet containing SSID "B" shows |
1131 | | * up in the middle of a 4-way handshake for SSID "A". |
1132 | | * We should probably use a small array or hash table to keep multiple |
1133 | | * SSIDs. |
1134 | | */ |
1135 | | int Dot11DecryptSetLastSSID( |
1136 | | PDOT11DECRYPT_CONTEXT ctx, |
1137 | | char *pkt_ssid, |
1138 | | size_t pkt_ssid_len) |
1139 | 2.72k | { |
1140 | 2.72k | if (!ctx || !pkt_ssid || pkt_ssid_len < 1 || pkt_ssid_len > WPA_SSID_MAX_SIZE) |
1141 | 2.35k | return DOT11DECRYPT_RET_UNSUCCESS; |
1142 | | |
1143 | 371 | memcpy(ctx->pkt_ssid, pkt_ssid, pkt_ssid_len); |
1144 | 371 | ctx->pkt_ssid_len = pkt_ssid_len; |
1145 | | |
1146 | 371 | return DOT11DECRYPT_RET_SUCCESS; |
1147 | 2.72k | } |
1148 | | |
1149 | | static unsigned |
1150 | | Dot11DecryptSaHash(const void *key) |
1151 | 158 | { |
1152 | 158 | GBytes *bytes = g_bytes_new_static(key, sizeof(DOT11DECRYPT_SEC_ASSOCIATION_ID)); |
1153 | 158 | unsigned hash = g_bytes_hash(bytes); |
1154 | 158 | g_bytes_unref(bytes); |
1155 | 158 | return hash; |
1156 | 158 | } |
1157 | | |
1158 | | static gboolean |
1159 | | Dot11DecryptIsSaIdEqual(const void *key1, const void *key2) |
1160 | 0 | { |
1161 | 0 | return memcmp(key1, key2, sizeof(DOT11DECRYPT_SEC_ASSOCIATION_ID)) == 0; |
1162 | 0 | } |
1163 | | |
1164 | | int Dot11DecryptInitContext( |
1165 | | PDOT11DECRYPT_CONTEXT ctx) |
1166 | 28 | { |
1167 | 28 | if (ctx==NULL) { |
1168 | 0 | ws_warning("NULL context"); |
1169 | 0 | return DOT11DECRYPT_RET_UNSUCCESS; |
1170 | 0 | } |
1171 | | |
1172 | 28 | Dot11DecryptCleanKeys(ctx); |
1173 | 28 | Dot11DecryptCleanSecAssoc(ctx); |
1174 | | |
1175 | 28 | ctx->pkt_ssid_len = 0; |
1176 | 28 | ctx->sa_hash = g_hash_table_new_full(Dot11DecryptSaHash, Dot11DecryptIsSaIdEqual, |
1177 | 28 | g_free, Dot11DecryptCleanSA); |
1178 | 28 | if (ctx->sa_hash == NULL) { |
1179 | 0 | return DOT11DECRYPT_RET_UNSUCCESS; |
1180 | 0 | } |
1181 | | |
1182 | 28 | ws_debug("Context initialized!"); |
1183 | 28 | return DOT11DECRYPT_RET_SUCCESS; |
1184 | 28 | } |
1185 | | |
1186 | | int Dot11DecryptDestroyContext( |
1187 | | PDOT11DECRYPT_CONTEXT ctx) |
1188 | 0 | { |
1189 | 0 | if (ctx==NULL) { |
1190 | 0 | ws_warning("NULL context"); |
1191 | 0 | return DOT11DECRYPT_RET_UNSUCCESS; |
1192 | 0 | } |
1193 | | |
1194 | 0 | Dot11DecryptCleanKeys(ctx); |
1195 | 0 | Dot11DecryptCleanSecAssoc(ctx); |
1196 | |
|
1197 | 0 | ws_debug("Context destroyed!"); |
1198 | 0 | return DOT11DECRYPT_RET_SUCCESS; |
1199 | 0 | } |
1200 | | |
1201 | | #ifdef __cplusplus |
1202 | | } |
1203 | | #endif |
1204 | | |
1205 | | /****************************************************************************/ |
1206 | | |
1207 | | /****************************************************************************/ |
1208 | | /* Internal function definitions */ |
1209 | | |
1210 | | #ifdef __cplusplus |
1211 | | extern "C" { |
1212 | | #endif |
1213 | | |
1214 | | static int |
1215 | | Dot11DecryptRsnaMng( |
1216 | | unsigned char *decrypt_data, |
1217 | | unsigned mac_header_len, |
1218 | | unsigned *decrypt_len, |
1219 | | PDOT11DECRYPT_KEY_ITEM key, |
1220 | | DOT11DECRYPT_SEC_ASSOCIATION *sa) |
1221 | 0 | { |
1222 | 0 | int ret = 1; |
1223 | 0 | unsigned char *try_data; |
1224 | 0 | unsigned try_data_len = *decrypt_len; |
1225 | |
|
1226 | 0 | if (*decrypt_len == 0) { |
1227 | 0 | ws_debug("Invalid decryption length"); |
1228 | 0 | return DOT11DECRYPT_RET_UNSUCCESS; |
1229 | 0 | } |
1230 | | |
1231 | | /* allocate a temp buffer for the decryption loop */ |
1232 | 0 | try_data=(unsigned char *)g_malloc(try_data_len); |
1233 | | |
1234 | | /* start of loop added by GCS */ |
1235 | 0 | for(/* sa */; sa != NULL ;sa=sa->next) { |
1236 | |
|
1237 | 0 | if (sa->validKey==false) { |
1238 | 0 | ws_noisy("Key not yet valid"); |
1239 | 0 | continue; |
1240 | 0 | } |
1241 | | |
1242 | | /* copy the encrypted data into a temp buffer */ |
1243 | 0 | memcpy(try_data, decrypt_data, *decrypt_len); |
1244 | | |
1245 | | /* Select decryption method based on EAPOL Key Descriptor Version and negotiated AKM |
1246 | | * with selected cipher suite. Refer to IEEE 802.11-2020: |
1247 | | * 12.7.2 EAPOL-Key frames |
1248 | | * 12.2.4 RSNA establishment |
1249 | | * 12.7 Keys and key distribution |
1250 | | * Table 9-149-Cipher suite selectors |
1251 | | */ |
1252 | |
|
1253 | 0 | if (sa->wpa.key_ver == 1 || sa->wpa.cipher == DOT11DECRYPT_CIPHER_TKIP) { |
1254 | | /* CCMP -> HMAC-MD5 is the EAPOL-Key MIC, RC4 is the EAPOL-Key encryption algorithm */ |
1255 | 0 | ws_noisy("TKIP"); |
1256 | 0 | DEBUG_DUMP("ptk", sa->wpa.ptk, 64, LOG_LEVEL_NOISY); |
1257 | 0 | DEBUG_DUMP("ptk portion used", DOT11DECRYPT_GET_TK_TKIP(sa->wpa.ptk), |
1258 | 0 | 16, LOG_LEVEL_NOISY); |
1259 | |
|
1260 | 0 | if (*decrypt_len < (unsigned)mac_header_len) { |
1261 | 0 | ws_debug("Invalid decryption length"); |
1262 | 0 | g_free(try_data); |
1263 | 0 | return DOT11DECRYPT_RET_UNSUCCESS; |
1264 | 0 | } |
1265 | 0 | if (*decrypt_len < DOT11DECRYPT_TKIP_MICLEN + DOT11DECRYPT_WEP_ICV) { |
1266 | 0 | ws_debug("Invalid decryption length"); |
1267 | 0 | g_free(try_data); |
1268 | 0 | return DOT11DECRYPT_RET_UNSUCCESS; |
1269 | 0 | } |
1270 | | |
1271 | 0 | ret = Dot11DecryptTkipDecrypt(try_data + mac_header_len, *decrypt_len - mac_header_len, |
1272 | 0 | try_data + DOT11DECRYPT_TA_OFFSET, |
1273 | 0 | DOT11DECRYPT_GET_TK_TKIP(sa->wpa.ptk)); |
1274 | 0 | if (ret) { |
1275 | 0 | ws_noisy("TKIP failed!"); |
1276 | 0 | continue; |
1277 | 0 | } |
1278 | | |
1279 | 0 | ws_noisy("TKIP DECRYPTED!!!"); |
1280 | | /* remove MIC and ICV from the end of packet */ |
1281 | 0 | *decrypt_len -= DOT11DECRYPT_TKIP_MICLEN + DOT11DECRYPT_WEP_ICV; |
1282 | 0 | break; |
1283 | 0 | } else if (sa->wpa.cipher == DOT11DECRYPT_CIPHER_GCMP || |
1284 | 0 | sa->wpa.cipher == DOT11DECRYPT_CIPHER_GCMP256) |
1285 | 0 | { |
1286 | 0 | ws_noisy("GCMP"); |
1287 | |
|
1288 | 0 | if (*decrypt_len < DOT11DECRYPT_GCMP_TRAILER) { |
1289 | 0 | ws_debug("Invalid decryption length"); |
1290 | 0 | g_free(try_data); |
1291 | 0 | return DOT11DECRYPT_RET_UNSUCCESS; |
1292 | 0 | } |
1293 | 0 | ret = Dot11DecryptGcmpDecrypt(try_data, mac_header_len, (int)*decrypt_len, |
1294 | 0 | DOT11DECRYPT_GET_TK(sa->wpa.ptk, sa->wpa.akm, sa->wpa.dh_group), |
1295 | 0 | Dot11DecryptGetTkLen(sa->wpa.cipher) / 8); |
1296 | 0 | if (ret) { |
1297 | 0 | continue; |
1298 | 0 | } |
1299 | 0 | ws_noisy("GCMP DECRYPTED!!!"); |
1300 | | /* remove MIC from the end of packet */ |
1301 | 0 | *decrypt_len -= DOT11DECRYPT_GCMP_TRAILER; |
1302 | 0 | break; |
1303 | 0 | } else { |
1304 | | /* AES-CCMP -> HMAC-SHA1-128 is the EAPOL-Key MIC, AES wep_key wrap is the EAPOL-Key encryption algorithm */ |
1305 | 0 | ws_noisy("CCMP"); |
1306 | |
|
1307 | 0 | unsigned trailer = sa->wpa.cipher != 10 ? DOT11DECRYPT_CCMP_TRAILER : DOT11DECRYPT_CCMP_256_TRAILER; |
1308 | 0 | if (*decrypt_len < trailer) { |
1309 | 0 | ws_debug("Invalid decryption length"); |
1310 | 0 | g_free(try_data); |
1311 | 0 | return DOT11DECRYPT_RET_UNSUCCESS; |
1312 | 0 | } |
1313 | | |
1314 | 0 | ret = Dot11DecryptCcmpDecrypt(try_data, mac_header_len, (int)*decrypt_len, |
1315 | 0 | DOT11DECRYPT_GET_TK(sa->wpa.ptk, sa->wpa.akm, sa->wpa.dh_group), |
1316 | 0 | Dot11DecryptGetTkLen(sa->wpa.cipher) / 8, |
1317 | 0 | trailer); |
1318 | 0 | if (ret) { |
1319 | 0 | continue; |
1320 | 0 | } |
1321 | 0 | ws_noisy("CCMP DECRYPTED!!!"); |
1322 | | /* remove MIC from the end of packet */ |
1323 | 0 | *decrypt_len -= trailer; |
1324 | 0 | break; |
1325 | 0 | } |
1326 | 0 | } |
1327 | | /* end of loop */ |
1328 | | |
1329 | | /* none of the keys worked */ |
1330 | 0 | if(sa == NULL) { |
1331 | 0 | g_free(try_data); |
1332 | 0 | return ret; |
1333 | 0 | } |
1334 | | |
1335 | 0 | if (*decrypt_len > try_data_len || *decrypt_len < 8) { |
1336 | 0 | ws_debug("Invalid decryption length"); |
1337 | 0 | g_free(try_data); |
1338 | 0 | return DOT11DECRYPT_RET_UNSUCCESS; |
1339 | 0 | } |
1340 | | |
1341 | | /* remove protection bit */ |
1342 | 0 | decrypt_data[1]&=0xBF; |
1343 | | |
1344 | | /* remove TKIP/CCMP header */ |
1345 | 0 | *decrypt_len-=8; |
1346 | |
|
1347 | 0 | if (*decrypt_len < mac_header_len) { |
1348 | 0 | ws_debug("Invalid decryption length < mac_header_len"); |
1349 | 0 | g_free(try_data); |
1350 | 0 | return DOT11DECRYPT_RET_UNSUCCESS; |
1351 | 0 | } |
1352 | | |
1353 | | /* copy the decrypted data into the decrypt buffer GCS*/ |
1354 | 0 | memcpy(decrypt_data + mac_header_len, try_data + mac_header_len + 8, |
1355 | 0 | *decrypt_len - mac_header_len); |
1356 | 0 | g_free(try_data); |
1357 | |
|
1358 | 0 | Dot11DecryptCopyKey(sa, key); |
1359 | 0 | return DOT11DECRYPT_RET_SUCCESS; |
1360 | 0 | } |
1361 | | |
1362 | | static int |
1363 | | Dot11DecryptWepMng( |
1364 | | PDOT11DECRYPT_CONTEXT ctx, |
1365 | | unsigned char *decrypt_data, |
1366 | | unsigned mac_header_len, |
1367 | | unsigned *decrypt_len, |
1368 | | PDOT11DECRYPT_KEY_ITEM key, |
1369 | | DOT11DECRYPT_SEC_ASSOCIATION_ID *id) |
1370 | 96 | { |
1371 | 96 | unsigned char wep_key[DOT11DECRYPT_WEP_KEY_MAXLEN+DOT11DECRYPT_WEP_IVLEN]; |
1372 | 96 | size_t keylen; |
1373 | 96 | int ret_value=1; |
1374 | 96 | int key_index; |
1375 | 96 | DOT11DECRYPT_KEY_ITEM *tmp_key; |
1376 | 96 | uint8_t useCache=false; |
1377 | 96 | unsigned char *try_data; |
1378 | 96 | DOT11DECRYPT_SEC_ASSOCIATION *sa; |
1379 | 96 | unsigned try_data_len = *decrypt_len; |
1380 | | |
1381 | 96 | try_data = (unsigned char *)g_malloc(try_data_len); |
1382 | | |
1383 | | /* get the Security Association structure for the STA and AP */ |
1384 | | |
1385 | | /* For WEP the sa is used only for caching. When no sa exists all user |
1386 | | * entered WEP keys are checked and on successful packet decryption an |
1387 | | * sa is formed caching the key used for decryption. |
1388 | | */ |
1389 | 96 | sa = Dot11DecryptGetSa(ctx, id); |
1390 | 96 | if (sa != NULL && sa->key != NULL) { |
1391 | 0 | useCache = true; |
1392 | 0 | } |
1393 | | |
1394 | 96 | for (key_index=0; key_index<(int)ctx->keys_nr; key_index++) { |
1395 | | /* use the cached one, or try all keys */ |
1396 | 0 | if (!useCache) { |
1397 | 0 | tmp_key=&ctx->keys[key_index]; |
1398 | 0 | } else { |
1399 | 0 | if (sa->key!=NULL && sa->key->KeyType==DOT11DECRYPT_KEY_TYPE_WEP) { |
1400 | 0 | ws_noisy("Try cached WEP key..."); |
1401 | 0 | tmp_key=sa->key; |
1402 | 0 | } else { |
1403 | 0 | ws_noisy("Cached key is not valid, try another WEP key..."); |
1404 | 0 | tmp_key=&ctx->keys[key_index]; |
1405 | 0 | } |
1406 | 0 | } |
1407 | | |
1408 | | /* obviously, try only WEP keys... */ |
1409 | 0 | if (tmp_key->KeyType==DOT11DECRYPT_KEY_TYPE_WEP) { |
1410 | 0 | ws_noisy("Try WEP key..."); |
1411 | |
|
1412 | 0 | memset(wep_key, 0, sizeof(wep_key)); |
1413 | 0 | memcpy(try_data, decrypt_data, *decrypt_len); |
1414 | | |
1415 | | /* Construct the WEP seed: copy the IV in first 3 bytes and then the WEP key (refer to 802-11i-2004, 8.2.1.4.3, pag. 36) */ |
1416 | 0 | memcpy(wep_key, try_data+mac_header_len, DOT11DECRYPT_WEP_IVLEN); |
1417 | 0 | keylen=tmp_key->KeyData.Wep.WepKeyLen; |
1418 | 0 | memcpy(wep_key+DOT11DECRYPT_WEP_IVLEN, tmp_key->KeyData.Wep.WepKey, keylen); |
1419 | |
|
1420 | 0 | ret_value=Dot11DecryptWepDecrypt(wep_key, |
1421 | 0 | keylen+DOT11DECRYPT_WEP_IVLEN, |
1422 | 0 | try_data + (mac_header_len+DOT11DECRYPT_WEP_IVLEN+DOT11DECRYPT_WEP_KIDLEN), |
1423 | 0 | *decrypt_len-(mac_header_len+DOT11DECRYPT_WEP_IVLEN+DOT11DECRYPT_WEP_KIDLEN+DOT11DECRYPT_CRC_LEN)); |
1424 | |
|
1425 | 0 | if (ret_value == DOT11DECRYPT_RET_SUCCESS) |
1426 | 0 | memcpy(decrypt_data, try_data, *decrypt_len); |
1427 | 0 | } |
1428 | |
|
1429 | 0 | if (!ret_value && tmp_key->KeyType==DOT11DECRYPT_KEY_TYPE_WEP) { |
1430 | | /* the tried key is the correct one, cache it in the Security Association */ |
1431 | | |
1432 | | /* Form an SA if one does not exist already */ |
1433 | 0 | if (sa == NULL) { |
1434 | 0 | sa = Dot11DecryptNewSa(id); |
1435 | 0 | if (sa == NULL) { |
1436 | 0 | ws_warning("Failed to alloc sa for WEP"); |
1437 | 0 | ret_value = DOT11DECRYPT_RET_UNSUCCESS; |
1438 | 0 | break; |
1439 | 0 | } |
1440 | 0 | sa = Dot11DecryptAddSa(ctx, id, sa); |
1441 | 0 | } |
1442 | 0 | sa->key=tmp_key; |
1443 | |
|
1444 | 0 | if (key!=NULL) { |
1445 | 0 | memcpy(key, sa->key, sizeof(DOT11DECRYPT_KEY_ITEM)); |
1446 | 0 | key->KeyType=DOT11DECRYPT_KEY_TYPE_WEP; |
1447 | 0 | } |
1448 | |
|
1449 | 0 | break; |
1450 | 0 | } else { |
1451 | | /* the cached key was not valid, try other keys */ |
1452 | |
|
1453 | 0 | if (useCache==true) { |
1454 | 0 | useCache=false; |
1455 | 0 | key_index--; |
1456 | 0 | } |
1457 | 0 | } |
1458 | 0 | } |
1459 | | |
1460 | 96 | g_free(try_data); |
1461 | 96 | if (ret_value) |
1462 | 96 | return DOT11DECRYPT_RET_UNSUCCESS; |
1463 | | |
1464 | 0 | ws_noisy("WEP DECRYPTED!!!"); |
1465 | | |
1466 | | /* remove ICV (4bytes) from the end of packet */ |
1467 | 0 | *decrypt_len-=4; |
1468 | |
|
1469 | 0 | if (*decrypt_len < 4) { |
1470 | 0 | ws_debug("Decryption length too short"); |
1471 | 0 | return DOT11DECRYPT_RET_UNSUCCESS; |
1472 | 0 | } |
1473 | | |
1474 | | /* remove protection bit */ |
1475 | 0 | decrypt_data[1]&=0xBF; |
1476 | | |
1477 | | /* remove IC header */ |
1478 | 0 | *decrypt_len-=4; |
1479 | 0 | memmove(decrypt_data + mac_header_len, |
1480 | 0 | decrypt_data + mac_header_len + DOT11DECRYPT_WEP_IVLEN + DOT11DECRYPT_WEP_KIDLEN, |
1481 | 0 | *decrypt_len - mac_header_len); |
1482 | |
|
1483 | 0 | return DOT11DECRYPT_RET_SUCCESS; |
1484 | 0 | } |
1485 | | |
1486 | | /* From IEEE 802.11-2016 Table 9-133—AKM suite selectors */ |
1487 | | static bool Dot11DecryptIsFtAkm(int akm) |
1488 | 782 | { |
1489 | 782 | switch (akm) { |
1490 | 0 | case 3: |
1491 | 0 | case 4: |
1492 | 0 | case 9: |
1493 | 0 | case 13: |
1494 | 0 | return true; |
1495 | 782 | } |
1496 | 782 | return false; |
1497 | 782 | } |
1498 | | |
1499 | | /* Get xxkey portion of MSK */ |
1500 | | /* From IEEE 802.11-2016 12.7.1.7.3 PMK-R0 */ |
1501 | | static const uint8_t * |
1502 | | Dot11DecryptGetXXKeyFromMSK(const uint8_t *msk, size_t msk_len, |
1503 | | int akm, size_t *xxkey_len) |
1504 | 0 | { |
1505 | 0 | if (!xxkey_len) { |
1506 | 0 | return NULL; |
1507 | 0 | } |
1508 | 0 | switch (akm) { |
1509 | 0 | case 3: |
1510 | 0 | if (msk_len < 64) { |
1511 | 0 | return NULL; |
1512 | 0 | } |
1513 | 0 | *xxkey_len = 32; |
1514 | 0 | return msk + 32; |
1515 | 0 | case 13: |
1516 | 0 | if (msk_len < 48) { |
1517 | 0 | return NULL; |
1518 | 0 | } |
1519 | 0 | *xxkey_len = 48; |
1520 | 0 | return msk; |
1521 | 0 | default: |
1522 | 0 | return NULL; |
1523 | 0 | } |
1524 | 0 | } |
1525 | | |
1526 | | /* From IEEE 802.11-2016 12.7.1.3 Pairwise key hierarchy */ |
1527 | | static void |
1528 | | Dot11DecryptDerivePmkFromMsk(const uint8_t *msk, uint8_t msk_len, int akm, |
1529 | | uint8_t *pmk, uint8_t *pmk_len) |
1530 | 0 | { |
1531 | 0 | if (!msk || !pmk || !pmk_len) { |
1532 | 0 | return; |
1533 | 0 | } |
1534 | | // When using AKM suite selector 00-0F-AC:12, the length of the PMK, PMK_bits, |
1535 | | // shall be 384 bits. With all other AKM suite selectors, the length of the PMK, |
1536 | | // PMK_bits, shall be 256 bits. |
1537 | 0 | if (akm == 12) { |
1538 | 0 | *pmk_len = 384 / 8; |
1539 | 0 | } else { |
1540 | 0 | *pmk_len = 256 / 8; |
1541 | 0 | } |
1542 | 0 | if ((uint8_t)(msk_len + *pmk_len) < msk_len) { |
1543 | 0 | *pmk_len = 0; |
1544 | 0 | return; |
1545 | 0 | } |
1546 | | // PMK = L(MSK, 0, PMK_bits). |
1547 | 0 | memcpy(pmk, msk, *pmk_len); |
1548 | 0 | } |
1549 | | |
1550 | | static bool |
1551 | | Dot11DecryptIsWpaKeyType(uint8_t key_type) |
1552 | 0 | { |
1553 | 0 | switch (key_type) { |
1554 | 0 | case DOT11DECRYPT_KEY_TYPE_WPA_PWD: |
1555 | 0 | case DOT11DECRYPT_KEY_TYPE_WPA_PSK: |
1556 | 0 | case DOT11DECRYPT_KEY_TYPE_WPA_PMK: |
1557 | 0 | case DOT11DECRYPT_KEY_TYPE_MSK: |
1558 | 0 | return true; |
1559 | 0 | } |
1560 | 0 | return false; |
1561 | 0 | } |
1562 | | |
1563 | | static bool |
1564 | | Dot11DecryptIsPwdWildcardSsid(const PDOT11DECRYPT_CONTEXT ctx, |
1565 | | const DOT11DECRYPT_KEY_ITEM *key_item) |
1566 | 0 | { |
1567 | 0 | if (!ctx || !key_item || key_item->KeyType != DOT11DECRYPT_KEY_TYPE_WPA_PWD) { |
1568 | 0 | return false; |
1569 | 0 | } |
1570 | 0 | if (key_item->UserPwd.SsidLen == 0 && ctx->pkt_ssid_len > 0 && |
1571 | 0 | ctx->pkt_ssid_len <= DOT11DECRYPT_WPA_SSID_MAX_LEN) { |
1572 | 0 | return true; |
1573 | 0 | } |
1574 | 0 | return false; |
1575 | 0 | } |
1576 | | |
1577 | | /* Refer to IEEE 802.11i-2004, 8.5.3, pag. 85 */ |
1578 | | static int |
1579 | | Dot11DecryptRsna4WHandshake( |
1580 | | PDOT11DECRYPT_CONTEXT ctx, |
1581 | | PDOT11DECRYPT_EAPOL_PARSED eapol_parsed, |
1582 | | const uint8_t *eapol_raw, |
1583 | | DOT11DECRYPT_SEC_ASSOCIATION_ID *id, |
1584 | | const unsigned tot_len) |
1585 | 0 | { |
1586 | 0 | DOT11DECRYPT_KEY_ITEM *tmp_key, *tmp_pkt_key, pkt_key; |
1587 | 0 | DOT11DECRYPT_SEC_ASSOCIATION *sa; |
1588 | 0 | int key_index; |
1589 | 0 | int ret = 1; |
1590 | 0 | unsigned char useCache=false; |
1591 | 0 | unsigned char eapol[DOT11DECRYPT_EAPOL_MAX_LEN]; |
1592 | |
|
1593 | 0 | if (eapol_parsed->len > DOT11DECRYPT_EAPOL_MAX_LEN || |
1594 | 0 | eapol_parsed->key_len > DOT11DECRYPT_EAPOL_MAX_LEN || |
1595 | 0 | eapol_parsed->key_data_len > DOT11DECRYPT_EAPOL_MAX_LEN) { |
1596 | 0 | ws_debug("Too large EAPOL frame and/or key data"); |
1597 | 0 | return DOT11DECRYPT_RET_NO_VALID_HANDSHAKE; |
1598 | 0 | } |
1599 | | |
1600 | | /* TODO timeouts? */ |
1601 | | |
1602 | | /* TODO consider key-index */ |
1603 | | |
1604 | | /* TODO consider Deauthentications */ |
1605 | | |
1606 | 0 | ws_debug("4-way handshake..."); |
1607 | | |
1608 | | /* manage 4-way handshake packets; this step completes the 802.1X authentication process (IEEE 802.11i-2004, pag. 85) */ |
1609 | | |
1610 | | /* message 1: Authenticator->Supplicant (Sec=0, Mic=0, Ack=1, Inst=0, Key=1(pairwise), KeyRSC=0, Nonce=ANonce, MIC=0) */ |
1611 | 0 | if (eapol_parsed->msg_type == DOT11DECRYPT_HS_MSG_TYPE_4WHS_1) { |
1612 | 0 | ws_debug("4-way handshake message 1"); |
1613 | | |
1614 | | /* On reception of Message 1, the Supplicant determines whether the Key Replay Counter field value has been */ |
1615 | | /* used before with the current PMKSA. If the Key Replay Counter field value is less than or equal to the current */ |
1616 | | /* local value, the Supplicant discards the message. */ |
1617 | | /* -> not checked, the Authenticator will be send another Message 1 (hopefully!) */ |
1618 | | |
1619 | | /* save ANonce (from authenticator) to derive the PTK with the SNonce (from the 2 message) */ |
1620 | 0 | if (!eapol_parsed->nonce) { |
1621 | 0 | ws_debug("ANonce missing"); |
1622 | 0 | return DOT11DECRYPT_RET_NO_VALID_HANDSHAKE; |
1623 | 0 | } |
1624 | | |
1625 | 0 | sa = Dot11DecryptGetSa(ctx, id); |
1626 | 0 | if (sa == NULL || sa->handshake >= 2) { |
1627 | | /* Either no SA exists or one exists but we're reauthenticating */ |
1628 | 0 | sa = Dot11DecryptNewSa(id); |
1629 | 0 | if (sa == NULL) { |
1630 | 0 | ws_warning("Failed to alloc broadcast sa"); |
1631 | 0 | return DOT11DECRYPT_RET_NO_VALID_HANDSHAKE; |
1632 | 0 | } |
1633 | 0 | sa = Dot11DecryptAddSa(ctx, id, sa); |
1634 | 0 | } |
1635 | 0 | memcpy(sa->wpa.nonce, eapol_parsed->nonce, 32); |
1636 | | |
1637 | | /* get the Key Descriptor Version (to select algorithm used in decryption -CCMP or TKIP-) */ |
1638 | 0 | sa->wpa.key_ver = eapol_parsed->key_version; |
1639 | 0 | sa->handshake=1; |
1640 | 0 | return DOT11DECRYPT_RET_SUCCESS_HANDSHAKE; |
1641 | 0 | } |
1642 | | |
1643 | | /* message 2|4: Supplicant->Authenticator (Sec=0|1, Mic=1, Ack=0, Inst=0, Key=1(pairwise), KeyRSC=0, Nonce=SNonce|0, MIC=MIC(KCK,EAPOL)) */ |
1644 | 0 | if (eapol_parsed->msg_type == DOT11DECRYPT_HS_MSG_TYPE_4WHS_2) { |
1645 | 0 | ws_debug("4-way handshake message 2"); |
1646 | | |
1647 | | /* On reception of Message 2, the Authenticator checks that the key replay counter corresponds to the */ |
1648 | | /* outstanding Message 1. If not, it silently discards the message. */ |
1649 | | /* If the calculated MIC does not match the MIC that the Supplicant included in the EAPOL-Key frame, */ |
1650 | | /* the Authenticator silently discards Message 2. */ |
1651 | | /* -> not checked; the Supplicant will send another message 2 (hopefully!) */ |
1652 | |
|
1653 | 0 | sa = Dot11DecryptGetSa(ctx, id); |
1654 | 0 | if (sa == NULL) { |
1655 | 0 | ws_debug("No SA for BSSID found"); |
1656 | 0 | return DOT11DECRYPT_RET_NO_VALID_HANDSHAKE; |
1657 | 0 | } |
1658 | 0 | if (!eapol_parsed->nonce) { |
1659 | 0 | ws_debug("SNonce missing"); |
1660 | 0 | return DOT11DECRYPT_RET_NO_VALID_HANDSHAKE; |
1661 | 0 | } |
1662 | 0 | if (sa->key != NULL) { |
1663 | 0 | useCache = true; |
1664 | 0 | } |
1665 | |
|
1666 | 0 | int akm = -1; |
1667 | 0 | int cipher = -1; |
1668 | 0 | int group_cipher = -1; |
1669 | 0 | int dh_group = -1; |
1670 | 0 | uint8_t ptk[DOT11DECRYPT_WPA_PTK_MAX_LEN]; |
1671 | 0 | size_t ptk_len = 0; |
1672 | | |
1673 | | /* now you can derive the PTK */ |
1674 | 0 | for (key_index=0; key_index<(int)ctx->keys_nr || useCache; key_index++) { |
1675 | | /* use the cached one, or try all keys */ |
1676 | 0 | if (useCache && Dot11DecryptIsWpaKeyType(sa->key->KeyType)) { |
1677 | 0 | ws_debug("Try cached WPA key..."); |
1678 | 0 | tmp_key = sa->key; |
1679 | | /* Step back loop counter as cached key is used instead */ |
1680 | 0 | key_index--; |
1681 | 0 | } else { |
1682 | 0 | ws_debug("Try WPA key..."); |
1683 | 0 | tmp_key = &ctx->keys[key_index]; |
1684 | 0 | } |
1685 | 0 | useCache = false; |
1686 | | |
1687 | | /* obviously, try only WPA keys... */ |
1688 | 0 | if (!Dot11DecryptIsWpaKeyType(tmp_key->KeyType)) { |
1689 | 0 | continue; |
1690 | 0 | } |
1691 | 0 | if (tmp_key->KeyType == DOT11DECRYPT_KEY_TYPE_WPA_PWD && |
1692 | 0 | Dot11DecryptIsPwdWildcardSsid(ctx, tmp_key)) |
1693 | 0 | { |
1694 | | /* We have a "wildcard" SSID. Use the one from the packet. */ |
1695 | 0 | memcpy(&pkt_key, tmp_key, sizeof(pkt_key)); |
1696 | 0 | memcpy(&pkt_key.UserPwd.Ssid, ctx->pkt_ssid, ctx->pkt_ssid_len); |
1697 | 0 | pkt_key.UserPwd.SsidLen = ctx->pkt_ssid_len; |
1698 | 0 | Dot11DecryptRsnaPwd2Psk(&pkt_key.UserPwd, pkt_key.KeyData.Wpa.Psk); |
1699 | 0 | tmp_pkt_key = &pkt_key; |
1700 | 0 | } else { |
1701 | 0 | tmp_pkt_key = tmp_key; |
1702 | 0 | } |
1703 | 0 | memcpy(eapol, eapol_raw, tot_len); |
1704 | | |
1705 | | /* From IEEE 802.11-2016 12.7.2 EAPOL-Key frames */ |
1706 | 0 | if (eapol_parsed->key_version == 0 || eapol_parsed->key_version == 3 || |
1707 | 0 | eapol_parsed->key_version == DOT11DECRYPT_WPA_KEY_VER_AES_CCMP) |
1708 | 0 | { |
1709 | | /* PTK derivation is based on Authentication Key Management Type */ |
1710 | 0 | akm = eapol_parsed->akm; |
1711 | 0 | cipher = eapol_parsed->cipher; |
1712 | 0 | group_cipher = eapol_parsed->group_cipher; |
1713 | 0 | dh_group = eapol_parsed->dh_group; |
1714 | 0 | } else if (eapol_parsed->key_version == DOT11DECRYPT_WPA_KEY_VER_NOT_CCMP) { |
1715 | | /* TKIP */ |
1716 | 0 | akm = 2; |
1717 | 0 | cipher = 2; |
1718 | 0 | group_cipher = 2; |
1719 | 0 | } else { |
1720 | 0 | ws_info("EAPOL key_version not supported"); |
1721 | 0 | return DOT11DECRYPT_RET_NO_VALID_HANDSHAKE; |
1722 | 0 | } |
1723 | | |
1724 | 0 | if (tmp_pkt_key->KeyType == DOT11DECRYPT_KEY_TYPE_MSK) { |
1725 | 0 | Dot11DecryptDerivePmkFromMsk(tmp_pkt_key->Msk.Msk, tmp_pkt_key->Msk.Len, akm, |
1726 | 0 | tmp_pkt_key->KeyData.Wpa.Psk, |
1727 | 0 | &tmp_pkt_key->KeyData.Wpa.PskLen); |
1728 | 0 | } |
1729 | |
|
1730 | 0 | if (Dot11DecryptIsFtAkm(akm)) { |
1731 | 0 | ret = Dot11DecryptFtDerivePtk(ctx, sa, tmp_pkt_key, |
1732 | 0 | eapol_parsed->mdid, |
1733 | 0 | eapol_parsed->nonce, |
1734 | 0 | eapol_parsed->fte.r0kh_id, |
1735 | 0 | eapol_parsed->fte.r0kh_id_len, |
1736 | 0 | eapol_parsed->fte.r1kh_id, |
1737 | 0 | eapol_parsed->fte.r1kh_id_len, |
1738 | 0 | akm, cipher, ptk, &ptk_len); |
1739 | 0 | } else { |
1740 | | /* derive the PTK from the BSSID, STA MAC, PMK, SNonce, ANonce */ |
1741 | 0 | ret = Dot11DecryptDerivePtk(sa, /* authenticator nonce, bssid, station mac */ |
1742 | 0 | tmp_pkt_key->KeyData.Wpa.Psk, /* PSK == PMK */ |
1743 | 0 | tmp_pkt_key->KeyData.Wpa.PskLen, |
1744 | 0 | eapol_parsed->nonce, /* supplicant nonce */ |
1745 | 0 | eapol_parsed->key_version, |
1746 | 0 | akm, cipher, ptk, &ptk_len, dh_group); |
1747 | 0 | } |
1748 | 0 | if (ret) { |
1749 | | /* Unsuccessful PTK derivation */ |
1750 | 0 | continue; |
1751 | 0 | } |
1752 | 0 | DEBUG_DUMP("TK", DOT11DECRYPT_GET_TK(ptk, akm, dh_group), Dot11DecryptGetTkLen(cipher) / 8, |
1753 | 0 | LOG_LEVEL_DEBUG); |
1754 | |
|
1755 | 0 | ret = Dot11DecryptRsnaMicCheck(eapol_parsed, |
1756 | 0 | eapol, /* eapol frame (header also) */ |
1757 | 0 | tot_len, /* eapol frame length */ |
1758 | 0 | DOT11DECRYPT_GET_KCK(ptk, akm), |
1759 | 0 | eapol_parsed->key_version, |
1760 | 0 | akm); |
1761 | | /* If the MIC is valid, the Authenticator checks that the RSN information element bit-wise matches */ |
1762 | | /* that from the (Re)Association Request message. */ |
1763 | | /* i) TODO If these are not exactly the same, the Authenticator uses MLME-DEAUTHENTICATE.request */ |
1764 | | /* primitive to terminate the association. */ |
1765 | | /* ii) If they do match bit-wise, the Authenticator constructs Message 3. */ |
1766 | |
|
1767 | 0 | if (ret == DOT11DECRYPT_RET_SUCCESS) { |
1768 | | /* the key is the correct one, cache it in the Security Association */ |
1769 | 0 | sa->key = tmp_key; |
1770 | 0 | break; |
1771 | 0 | } |
1772 | 0 | } |
1773 | | |
1774 | 0 | if (ret) { |
1775 | 0 | ws_debug("handshake step failed"); |
1776 | 0 | return DOT11DECRYPT_RET_NO_VALID_HANDSHAKE; |
1777 | 0 | } |
1778 | 0 | sa->wpa.key_ver = eapol_parsed->key_version; |
1779 | 0 | sa->wpa.akm = akm; |
1780 | 0 | sa->wpa.cipher = cipher; |
1781 | 0 | sa->wpa.tmp_group_cipher = group_cipher; |
1782 | 0 | sa->wpa.dh_group = dh_group; |
1783 | 0 | memcpy(sa->wpa.ptk, ptk, ptk_len); |
1784 | 0 | sa->wpa.ptk_len = (int)ptk_len; |
1785 | 0 | sa->handshake = 2; |
1786 | 0 | sa->validKey = true; /* we can use the key to decode, even if we have not captured the other eapol packets */ |
1787 | |
|
1788 | 0 | return DOT11DECRYPT_RET_SUCCESS_HANDSHAKE; |
1789 | 0 | } |
1790 | | |
1791 | | /* message 3: Authenticator->Supplicant (Sec=1, Mic=1, Ack=1, Inst=0/1, Key=1(pairwise), KeyRSC=???, Nonce=ANonce, MIC=1) */ |
1792 | 0 | if (eapol_parsed->msg_type == DOT11DECRYPT_HS_MSG_TYPE_4WHS_3) { |
1793 | 0 | ws_debug("4-way handshake message 3"); |
1794 | | |
1795 | | /* On reception of Message 3, the Supplicant silently discards the message if the Key Replay Counter field */ |
1796 | | /* value has already been used or if the ANonce value in Message 3 differs from the ANonce value in Message 1. */ |
1797 | | /* -> not checked, the Authenticator will send another message 3 (hopefully!) */ |
1798 | | |
1799 | | /* TODO check page 88 (RNS) */ |
1800 | | |
1801 | | /* If using WPA2 PSK, message 3 will contain an RSN for the group key (GTK KDE). |
1802 | | In order to properly support decrypting WPA2-PSK packets, we need to parse this to get the group key. */ |
1803 | 0 | if (eapol_parsed->key_type == DOT11DECRYPT_RSN_WPA2_KEY_DESCRIPTOR) { |
1804 | 0 | return Dot11DecryptCopyBroadcastKey(ctx, eapol_parsed->gtk, eapol_parsed->gtk_len, id); |
1805 | 0 | } |
1806 | 0 | } |
1807 | | |
1808 | | /* message 4 */ |
1809 | 0 | if (eapol_parsed->msg_type == DOT11DECRYPT_HS_MSG_TYPE_4WHS_4) { |
1810 | | /* TODO "Note that when the 4-Way Handshake is first used Message 4 is sent in the clear." */ |
1811 | | |
1812 | | /* TODO check MIC and Replay Counter */ |
1813 | | /* On reception of Message 4, the Authenticator verifies that the Key Replay Counter field value is one */ |
1814 | | /* that it used on this 4-Way Handshake; if it is not, it silently discards the message. */ |
1815 | | /* If the calculated MIC does not match the MIC that the Supplicant included in the EAPOL-Key frame, the */ |
1816 | | /* Authenticator silently discards Message 4. */ |
1817 | |
|
1818 | 0 | ws_debug("4-way handshake message 4"); |
1819 | 0 | return DOT11DECRYPT_RET_SUCCESS_HANDSHAKE; |
1820 | 0 | } |
1821 | 0 | return DOT11DECRYPT_RET_NO_VALID_HANDSHAKE; |
1822 | 0 | } |
1823 | | |
1824 | | /* Refer to IEEE 802.11-2016 Chapeter 13.8 FT authentication sequence */ |
1825 | | int |
1826 | | Dot11DecryptScanFtAssocForKeys( |
1827 | | const PDOT11DECRYPT_CONTEXT ctx, |
1828 | | const PDOT11DECRYPT_ASSOC_PARSED assoc_parsed, |
1829 | | uint8_t *decrypted_gtk, size_t *decrypted_len, |
1830 | | DOT11DECRYPT_KEY_ITEM* used_key) |
1831 | 782 | { |
1832 | 782 | DOT11DECRYPT_SEC_ASSOCIATION_ID id; |
1833 | | |
1834 | 782 | ws_debug("(Re)Association packet"); |
1835 | | |
1836 | 782 | if (!ctx || !assoc_parsed) { |
1837 | 0 | ws_warning("Invalid input parameters"); |
1838 | 0 | return DOT11DECRYPT_RET_NO_VALID_HANDSHAKE; |
1839 | 0 | } |
1840 | 782 | if (!Dot11DecryptIsFtAkm(assoc_parsed->akm)) { |
1841 | 782 | return DOT11DECRYPT_RET_NO_VALID_HANDSHAKE; |
1842 | 782 | } |
1843 | 0 | if (!assoc_parsed->fte.anonce || !assoc_parsed->fte.snonce) { |
1844 | 0 | ws_debug("ANonce or SNonce missing"); |
1845 | 0 | return DOT11DECRYPT_RET_NO_VALID_HANDSHAKE; |
1846 | 0 | } |
1847 | | |
1848 | 0 | switch (assoc_parsed->frame_subtype) { |
1849 | 0 | case DOT11DECRYPT_SUBTYPE_ASSOC_REQ: |
1850 | 0 | case DOT11DECRYPT_SUBTYPE_REASSOC_REQ: |
1851 | 0 | memcpy(id.sta, assoc_parsed->sa, DOT11DECRYPT_MAC_LEN); |
1852 | 0 | break; |
1853 | 0 | case DOT11DECRYPT_SUBTYPE_ASSOC_RESP: |
1854 | 0 | case DOT11DECRYPT_SUBTYPE_REASSOC_RESP: |
1855 | 0 | memcpy(id.sta, assoc_parsed->da, DOT11DECRYPT_MAC_LEN); |
1856 | 0 | break; |
1857 | 0 | default: |
1858 | 0 | ws_warning("Invalid frame subtype"); |
1859 | 0 | return DOT11DECRYPT_RET_UNSUCCESS; |
1860 | 0 | } |
1861 | 0 | memcpy(id.bssid, assoc_parsed->bssid, DOT11DECRYPT_MAC_LEN); |
1862 | |
|
1863 | 0 | DOT11DECRYPT_KEY_ITEM *tmp_key, *tmp_pkt_key, pkt_key; |
1864 | 0 | DOT11DECRYPT_SEC_ASSOCIATION *sa; |
1865 | 0 | size_t key_index; |
1866 | 0 | unsigned ret = 1; |
1867 | 0 | bool useCache = false; |
1868 | |
|
1869 | 0 | sa = Dot11DecryptNewSa(&id); |
1870 | 0 | if (sa == NULL) { |
1871 | 0 | ws_warning("Failed to alloc sa"); |
1872 | 0 | return DOT11DECRYPT_RET_NO_VALID_HANDSHAKE; |
1873 | 0 | } |
1874 | | |
1875 | 0 | memcpy(sa->wpa.nonce, assoc_parsed->fte.anonce, 32); |
1876 | |
|
1877 | 0 | if (sa->key != NULL) { |
1878 | 0 | useCache = true; |
1879 | 0 | } |
1880 | |
|
1881 | 0 | uint8_t ptk[DOT11DECRYPT_WPA_PTK_MAX_LEN]; |
1882 | 0 | size_t ptk_len; |
1883 | | |
1884 | | /* now you can derive the PTK */ |
1885 | 0 | for (key_index = 0; key_index < ctx->keys_nr || useCache; key_index++) { |
1886 | | /* use the cached one, or try all keys */ |
1887 | 0 | if (useCache && Dot11DecryptIsWpaKeyType(sa->key->KeyType)) { |
1888 | 0 | ws_debug("Try cached WPA key..."); |
1889 | 0 | tmp_key = sa->key; |
1890 | | /* Step back loop counter as cached key is used instead */ |
1891 | 0 | key_index--; |
1892 | 0 | } else { |
1893 | 0 | ws_debug("Try WPA key..."); |
1894 | 0 | tmp_key = &ctx->keys[key_index]; |
1895 | 0 | } |
1896 | 0 | useCache = false; |
1897 | | |
1898 | | /* Try only WPA keys... */ |
1899 | 0 | if (!Dot11DecryptIsWpaKeyType(tmp_key->KeyType)) { |
1900 | 0 | continue; |
1901 | 0 | } |
1902 | 0 | if (tmp_key->KeyType == DOT11DECRYPT_KEY_TYPE_WPA_PWD && |
1903 | 0 | Dot11DecryptIsPwdWildcardSsid(ctx, tmp_key)) |
1904 | 0 | { |
1905 | | /* We have a "wildcard" SSID. Use the one from the packet. */ |
1906 | 0 | memcpy(&pkt_key, tmp_key, sizeof(pkt_key)); |
1907 | 0 | memcpy(&pkt_key.UserPwd.Ssid, ctx->pkt_ssid, ctx->pkt_ssid_len); |
1908 | 0 | pkt_key.UserPwd.SsidLen = ctx->pkt_ssid_len; |
1909 | 0 | Dot11DecryptRsnaPwd2Psk(&pkt_key.UserPwd, pkt_key.KeyData.Wpa.Psk); |
1910 | 0 | tmp_pkt_key = &pkt_key; |
1911 | 0 | } else { |
1912 | 0 | tmp_pkt_key = tmp_key; |
1913 | 0 | } |
1914 | |
|
1915 | 0 | if (tmp_pkt_key->KeyType == DOT11DECRYPT_KEY_TYPE_MSK) { |
1916 | 0 | Dot11DecryptDerivePmkFromMsk(tmp_pkt_key->Msk.Msk, tmp_pkt_key->Msk.Len, |
1917 | 0 | assoc_parsed->akm, |
1918 | 0 | tmp_pkt_key->KeyData.Wpa.Psk, |
1919 | 0 | &tmp_pkt_key->KeyData.Wpa.PskLen); |
1920 | 0 | } |
1921 | |
|
1922 | 0 | ret = Dot11DecryptFtDerivePtk(ctx, sa, tmp_pkt_key, |
1923 | 0 | assoc_parsed->mdid, |
1924 | 0 | assoc_parsed->fte.snonce, |
1925 | 0 | assoc_parsed->fte.r0kh_id, |
1926 | 0 | assoc_parsed->fte.r0kh_id_len, |
1927 | 0 | assoc_parsed->fte.r1kh_id, |
1928 | 0 | assoc_parsed->fte.r1kh_id_len, |
1929 | 0 | assoc_parsed->akm, assoc_parsed->cipher, |
1930 | 0 | ptk, &ptk_len); |
1931 | 0 | if (ret != DOT11DECRYPT_RET_SUCCESS) { |
1932 | 0 | continue; |
1933 | 0 | } |
1934 | 0 | DEBUG_DUMP("TK", DOT11DECRYPT_GET_TK(ptk, assoc_parsed->akm, 0), |
1935 | 0 | Dot11DecryptGetTkLen(assoc_parsed->cipher) / 8, |
1936 | 0 | LOG_LEVEL_DEBUG); |
1937 | |
|
1938 | 0 | ret = Dot11DecryptFtMicCheck(assoc_parsed, |
1939 | 0 | DOT11DECRYPT_GET_KCK(ptk, assoc_parsed->akm), |
1940 | 0 | Dot11DecryptGetKckLen(assoc_parsed->akm, 0) / 8); |
1941 | 0 | if (ret == DOT11DECRYPT_RET_SUCCESS) { |
1942 | | /* the key is the correct one, cache it in the Security Association */ |
1943 | 0 | sa->key = tmp_key; |
1944 | 0 | break; |
1945 | 0 | } |
1946 | 0 | } |
1947 | |
|
1948 | 0 | if (ret) { |
1949 | 0 | ws_debug("handshake step failed"); |
1950 | 0 | g_free(sa); |
1951 | 0 | return DOT11DECRYPT_RET_NO_VALID_HANDSHAKE; |
1952 | 0 | } |
1953 | 0 | sa = Dot11DecryptAddSa(ctx, &id, sa); |
1954 | |
|
1955 | 0 | sa->wpa.key_ver = 0; /* Determine key type from akms and cipher*/ |
1956 | 0 | sa->wpa.akm = assoc_parsed->akm; |
1957 | 0 | sa->wpa.cipher = assoc_parsed->cipher; |
1958 | 0 | sa->wpa.tmp_group_cipher = assoc_parsed->group_cipher; |
1959 | 0 | memcpy(sa->wpa.ptk, ptk, ptk_len); |
1960 | 0 | sa->wpa.ptk_len = (int)ptk_len; |
1961 | 0 | sa->validKey = true; |
1962 | |
|
1963 | 0 | if (assoc_parsed->gtk && assoc_parsed->gtk_len - 8 <= DOT11DECRYPT_WPA_PTK_MAX_LEN - 32) { |
1964 | 0 | uint8_t decrypted_key[DOT11DECRYPT_WPA_PTK_MAX_LEN - 32]; |
1965 | 0 | uint16_t decrypted_key_len; |
1966 | 0 | if (AES_unwrap(DOT11DECRYPT_GET_KEK(sa->wpa.ptk, sa->wpa.akm, sa->wpa.dh_group), |
1967 | 0 | Dot11DecryptGetKekLen(sa->wpa.akm, sa->wpa.dh_group) / 8, |
1968 | 0 | assoc_parsed->gtk, assoc_parsed->gtk_len, |
1969 | 0 | decrypted_key, &decrypted_key_len)) { |
1970 | 0 | return DOT11DECRYPT_RET_UNSUCCESS; |
1971 | 0 | } |
1972 | 0 | if (decrypted_key_len != assoc_parsed->gtk_subelem_key_len) { |
1973 | 0 | ws_debug("Unexpected GTK length"); |
1974 | 0 | return DOT11DECRYPT_RET_UNSUCCESS; |
1975 | 0 | } |
1976 | 0 | Dot11DecryptCopyBroadcastKey(ctx, decrypted_key, decrypted_key_len, &id); |
1977 | 0 | *decrypted_len = decrypted_key_len; |
1978 | 0 | memcpy(decrypted_gtk, decrypted_key, decrypted_key_len); |
1979 | 0 | } |
1980 | 0 | Dot11DecryptCopyKey(sa, used_key); |
1981 | 0 | return DOT11DECRYPT_RET_SUCCESS_HANDSHAKE; |
1982 | 0 | } |
1983 | | |
1984 | | /* From IEEE 802.11-2016 Table 12-8 Integrity and key-wrap algorithms */ |
1985 | | static int |
1986 | | Dot11DecryptGetIntegrityAlgoFromAkm(int akm, int *algo, bool *hmac, int dh_group) |
1987 | 0 | { |
1988 | 0 | int res = 0; |
1989 | 0 | switch (akm) { |
1990 | 0 | case 1: |
1991 | 0 | case 2: |
1992 | 0 | *algo = GCRY_MD_SHA1; |
1993 | 0 | *hmac = true; |
1994 | 0 | break; |
1995 | 0 | case 3: |
1996 | 0 | case 4: |
1997 | 0 | case 5: |
1998 | 0 | case 6: |
1999 | 0 | case 7: |
2000 | 0 | case 8: |
2001 | 0 | case 9: |
2002 | 0 | case 10: |
2003 | 0 | *algo = GCRY_MAC_CMAC_AES; |
2004 | 0 | *hmac = false; |
2005 | 0 | break; |
2006 | 0 | case 11: |
2007 | 0 | *algo = GCRY_MD_SHA256; |
2008 | 0 | *hmac = true; |
2009 | 0 | break; |
2010 | 0 | case 12: |
2011 | 0 | case 13: |
2012 | 0 | *algo = GCRY_MD_SHA384; |
2013 | 0 | *hmac = true; |
2014 | 0 | break; |
2015 | 0 | case 18: |
2016 | 0 | case 24: |
2017 | 0 | case 25: |
2018 | 0 | if (dh_group == 20) |
2019 | 0 | *algo = GCRY_MD_SHA384; |
2020 | 0 | else if (dh_group == 21) |
2021 | 0 | *algo = GCRY_MD_SHA512; |
2022 | 0 | else |
2023 | 0 | *algo = GCRY_MD_SHA256; |
2024 | 0 | *hmac = TRUE; |
2025 | 0 | break; |
2026 | 0 | default: |
2027 | | /* Unknown / Not supported yet */ |
2028 | 0 | res = -1; |
2029 | 0 | break; |
2030 | 0 | } |
2031 | 0 | return res; |
2032 | 0 | } |
2033 | | |
2034 | | static int |
2035 | | Dot11DecryptRsnaMicCheck( |
2036 | | PDOT11DECRYPT_EAPOL_PARSED eapol_parsed, |
2037 | | unsigned char *eapol, |
2038 | | unsigned short eapol_len, |
2039 | | unsigned char *KCK, |
2040 | | unsigned short key_ver, |
2041 | | int akm) |
2042 | 0 | { |
2043 | 0 | uint8_t *mic = eapol_parsed->mic; |
2044 | 0 | uint16_t mic_len = eapol_parsed->mic_len; |
2045 | 0 | uint16_t kck_len = Dot11DecryptGetKckLen(akm, eapol_parsed->dh_group) / 8; |
2046 | | /* MIC 16 or 24 bytes, though HMAC-SHA256 / SHA384 algos need 32 / 48 bytes buffer */ |
2047 | 0 | unsigned char c_mic[48] = { 0 }; |
2048 | 0 | int algo = -1; |
2049 | 0 | bool hmac = true; |
2050 | |
|
2051 | 0 | if (!mic || mic_len > DOT11DECRYPT_WPA_MICKEY_MAX_LEN) { |
2052 | 0 | ws_debug("Not a valid mic"); |
2053 | 0 | return DOT11DECRYPT_RET_UNSUCCESS; |
2054 | 0 | } |
2055 | | |
2056 | | /* set to 0 the MIC in the EAPOL packet (to calculate the MIC) */ |
2057 | 0 | memset(eapol + DOT11DECRYPT_WPA_MICKEY_OFFSET + 4, 0, mic_len); |
2058 | |
|
2059 | 0 | if (key_ver==DOT11DECRYPT_WPA_KEY_VER_NOT_CCMP) { |
2060 | | /* use HMAC-MD5 for the EAPOL-Key MIC */ |
2061 | 0 | algo = GCRY_MD_MD5; |
2062 | 0 | hmac = true; |
2063 | 0 | } else if (key_ver==DOT11DECRYPT_WPA_KEY_VER_AES_CCMP) { |
2064 | | /* use HMAC-SHA1-128 for the EAPOL-Key MIC */ |
2065 | 0 | algo = GCRY_MD_SHA1; |
2066 | 0 | hmac = true; |
2067 | 0 | } else { |
2068 | | /* Mic check algorithm determined by AKM type */ |
2069 | 0 | if (Dot11DecryptGetIntegrityAlgoFromAkm(akm, &algo, &hmac, eapol_parsed->dh_group)) { |
2070 | 0 | ws_warning("Unknown Mic check algo"); |
2071 | 0 | return DOT11DECRYPT_RET_UNSUCCESS; |
2072 | 0 | }; |
2073 | 0 | } |
2074 | 0 | if (hmac) { |
2075 | 0 | if (ws_hmac_buffer(algo, c_mic, eapol, eapol_len, KCK, kck_len)) { |
2076 | 0 | ws_debug("HMAC_BUFFER"); |
2077 | 0 | return DOT11DECRYPT_RET_UNSUCCESS; |
2078 | 0 | } |
2079 | 0 | } else { |
2080 | 0 | if (ws_cmac_buffer(algo, c_mic, eapol, eapol_len, KCK, kck_len)) { |
2081 | 0 | ws_debug("HMAC_BUFFER"); |
2082 | 0 | return DOT11DECRYPT_RET_UNSUCCESS; |
2083 | 0 | } |
2084 | 0 | } |
2085 | | |
2086 | | /* compare calculated MIC with the Key MIC and return result (0 means success) */ |
2087 | 0 | DEBUG_DUMP("mic", mic, mic_len, LOG_LEVEL_DEBUG); |
2088 | 0 | DEBUG_DUMP("c_mic", c_mic, mic_len, LOG_LEVEL_DEBUG); |
2089 | 0 | return memcmp(mic, c_mic, mic_len); |
2090 | 0 | } |
2091 | | |
2092 | | /* IEEE 802.11-2020 Chapter 13.8.4 FT authentication sequence: contents of third message |
2093 | | * IEEE 802.11-2020 Chapter 13.8.5 FT authentication sequence: contents of fourth message |
2094 | | * The MIC shall be calculated on the concatenation of the following data, in the order given here: |
2095 | | * — |
2096 | | * — FTO’s MAC address (6 octets) |
2097 | | * — Target AP’s MAC address (6 octets) |
2098 | | * If third message: |
2099 | | * — Transaction sequence number (1 octet), which shall be set to the value 5 if this is a |
2100 | | * Reassociation Request frame and, otherwise, set to the value 3 |
2101 | | * If fourth message: |
2102 | | * — Transaction sequence number (1 octet), which shall be set to the value 6 if this is a |
2103 | | * Reassociation Response frame or, otherwise, set to the value 4 |
2104 | | * |
2105 | | * — RSNE |
2106 | | * — MDE |
2107 | | * — FTE, with the MIC field of the FTE set to 0 |
2108 | | * — Contents of the RIC-Response (if present) |
2109 | | * — RSNXE (if present) |
2110 | | */ |
2111 | | static int |
2112 | | Dot11DecryptFtMicCheck( |
2113 | | const PDOT11DECRYPT_ASSOC_PARSED assoc_parsed, |
2114 | | const uint8_t *kck, |
2115 | | size_t kck_len) |
2116 | 0 | { |
2117 | 0 | uint8_t *sta; |
2118 | 0 | uint8_t seq_num; |
2119 | 0 | uint8_t fte_len; |
2120 | 0 | uint16_t mic_len; |
2121 | 0 | uint8_t zeros[16] = { 0 }; |
2122 | 0 | gcry_mac_hd_t handle; |
2123 | |
|
2124 | 0 | fte_len = assoc_parsed->fte_tag[1] + 2; |
2125 | 0 | if (fte_len < 20) { |
2126 | 0 | ws_debug("FTE too short"); |
2127 | 0 | return DOT11DECRYPT_RET_UNSUCCESS; |
2128 | 0 | } |
2129 | | |
2130 | 0 | switch (assoc_parsed->frame_subtype) { |
2131 | 0 | case DOT11DECRYPT_SUBTYPE_ASSOC_REQ: |
2132 | 0 | sta = assoc_parsed->sa; |
2133 | 0 | seq_num = 3; |
2134 | 0 | break; |
2135 | 0 | case DOT11DECRYPT_SUBTYPE_ASSOC_RESP: |
2136 | 0 | sta = assoc_parsed->da; |
2137 | 0 | seq_num = 4; |
2138 | 0 | break; |
2139 | 0 | case DOT11DECRYPT_SUBTYPE_REASSOC_REQ: |
2140 | 0 | sta = assoc_parsed->sa; |
2141 | 0 | seq_num = 5; |
2142 | 0 | break; |
2143 | 0 | case DOT11DECRYPT_SUBTYPE_REASSOC_RESP: |
2144 | 0 | sta = assoc_parsed->da; |
2145 | 0 | seq_num = 6; |
2146 | 0 | break; |
2147 | 0 | default: |
2148 | 0 | return DOT11DECRYPT_RET_UNSUCCESS; |
2149 | 0 | } |
2150 | | |
2151 | 0 | if (gcry_mac_open(&handle, GCRY_MAC_CMAC_AES, 0, NULL)) { |
2152 | 0 | ws_warning("gcry_mac_open failed"); |
2153 | 0 | return DOT11DECRYPT_RET_UNSUCCESS; |
2154 | 0 | } |
2155 | 0 | if (gcry_mac_setkey(handle, kck, kck_len)) { |
2156 | 0 | ws_warning("gcry_mac_setkey failed"); |
2157 | 0 | gcry_mac_close(handle); |
2158 | 0 | return DOT11DECRYPT_RET_UNSUCCESS; |
2159 | 0 | } |
2160 | 0 | gcry_mac_write(handle, sta, DOT11DECRYPT_MAC_LEN); |
2161 | 0 | gcry_mac_write(handle, assoc_parsed->bssid, DOT11DECRYPT_MAC_LEN); |
2162 | |
|
2163 | 0 | gcry_mac_write(handle, &seq_num, 1); |
2164 | |
|
2165 | 0 | gcry_mac_write(handle, assoc_parsed->rsne_tag, assoc_parsed->rsne_tag[1] + 2); |
2166 | 0 | gcry_mac_write(handle, assoc_parsed->mde_tag, assoc_parsed->mde_tag[1] + 2); |
2167 | |
|
2168 | 0 | mic_len = assoc_parsed->fte.mic_len; |
2169 | 0 | gcry_mac_write(handle, assoc_parsed->fte_tag, 4); |
2170 | 0 | gcry_mac_write(handle, zeros, mic_len); /* MIC zeroed */ |
2171 | 0 | gcry_mac_write(handle, assoc_parsed->fte_tag + 4 + mic_len, fte_len - 4 - mic_len); |
2172 | |
|
2173 | 0 | if (assoc_parsed->rde_tag) { |
2174 | 0 | gcry_mac_write(handle, assoc_parsed->rde_tag, assoc_parsed->rde_tag[1] + 2); |
2175 | 0 | } |
2176 | 0 | if (assoc_parsed->rsnxe_tag) { |
2177 | 0 | gcry_mac_write(handle, assoc_parsed->rsnxe_tag, assoc_parsed->rsnxe_tag[1] + 2); |
2178 | 0 | } |
2179 | |
|
2180 | 0 | if (gcry_mac_verify(handle, assoc_parsed->fte.mic, mic_len) != 0) { |
2181 | 0 | DEBUG_DUMP("MIC", assoc_parsed->fte.mic, mic_len, LOG_LEVEL_DEBUG); |
2182 | 0 | ws_debug("MIC verification failed"); |
2183 | 0 | gcry_mac_close(handle); |
2184 | 0 | return DOT11DECRYPT_RET_UNSUCCESS; |
2185 | 0 | } |
2186 | 0 | DEBUG_DUMP("MIC", assoc_parsed->fte.mic, mic_len, LOG_LEVEL_DEBUG); |
2187 | 0 | gcry_mac_close(handle); |
2188 | 0 | return DOT11DECRYPT_RET_SUCCESS; |
2189 | 0 | } |
2190 | | |
2191 | | static int |
2192 | | Dot11DecryptValidateKey( |
2193 | | PDOT11DECRYPT_KEY_ITEM key) |
2194 | 0 | { |
2195 | 0 | size_t len; |
2196 | 0 | unsigned char ret=true; |
2197 | |
|
2198 | 0 | if (key==NULL) { |
2199 | 0 | ws_warning("NULL key"); |
2200 | 0 | return false; |
2201 | 0 | } |
2202 | | |
2203 | 0 | switch (key->KeyType) { |
2204 | 0 | case DOT11DECRYPT_KEY_TYPE_WEP: |
2205 | | /* check key size limits */ |
2206 | 0 | len=key->KeyData.Wep.WepKeyLen; |
2207 | 0 | if (len<DOT11DECRYPT_WEP_KEY_MINLEN || len>DOT11DECRYPT_WEP_KEY_MAXLEN) { |
2208 | 0 | ws_info("WEP key: key length not accepted"); |
2209 | 0 | ret=false; |
2210 | 0 | } |
2211 | 0 | break; |
2212 | | |
2213 | 0 | case DOT11DECRYPT_KEY_TYPE_WEP_40: |
2214 | | /* set the standard length and use a generic WEP key type */ |
2215 | 0 | key->KeyData.Wep.WepKeyLen=DOT11DECRYPT_WEP_40_KEY_LEN; |
2216 | 0 | key->KeyType=DOT11DECRYPT_KEY_TYPE_WEP; |
2217 | 0 | break; |
2218 | | |
2219 | 0 | case DOT11DECRYPT_KEY_TYPE_WEP_104: |
2220 | | /* set the standard length and use a generic WEP key type */ |
2221 | 0 | key->KeyData.Wep.WepKeyLen=DOT11DECRYPT_WEP_104_KEY_LEN; |
2222 | 0 | key->KeyType=DOT11DECRYPT_KEY_TYPE_WEP; |
2223 | 0 | break; |
2224 | | |
2225 | 0 | case DOT11DECRYPT_KEY_TYPE_WPA_PWD: |
2226 | | /* check passphrase and SSID size limits */ |
2227 | 0 | len=strlen(key->UserPwd.Passphrase); |
2228 | 0 | if (len<DOT11DECRYPT_WPA_PASSPHRASE_MIN_LEN || len>DOT11DECRYPT_WPA_PASSPHRASE_MAX_LEN) { |
2229 | 0 | ws_info("WPA-PWD key: passphrase length not accepted"); |
2230 | 0 | ret=false; |
2231 | 0 | } |
2232 | |
|
2233 | 0 | len=key->UserPwd.SsidLen; |
2234 | 0 | if (len>DOT11DECRYPT_WPA_SSID_MAX_LEN) { |
2235 | 0 | ws_info("WPA-PWD key: ssid length not accepted"); |
2236 | 0 | ret=false; |
2237 | 0 | } |
2238 | |
|
2239 | 0 | break; |
2240 | | |
2241 | 0 | case DOT11DECRYPT_KEY_TYPE_WPA_PSK: |
2242 | 0 | break; |
2243 | | |
2244 | 0 | case DOT11DECRYPT_KEY_TYPE_TK: |
2245 | 0 | break; |
2246 | | |
2247 | 0 | case DOT11DECRYPT_KEY_TYPE_MSK: |
2248 | 0 | break; |
2249 | | |
2250 | 0 | default: |
2251 | 0 | ret=false; |
2252 | 0 | } |
2253 | 0 | return ret; |
2254 | 0 | } |
2255 | | |
2256 | | static int |
2257 | | Dot11DecryptGetSaAddress( |
2258 | | const DOT11DECRYPT_MAC_FRAME_ADDR4 *frame, |
2259 | | DOT11DECRYPT_SEC_ASSOCIATION_ID *id) |
2260 | 161 | { |
2261 | 161 | if ((DOT11DECRYPT_TYPE(frame->fc[0])==DOT11DECRYPT_TYPE_DATA) && |
2262 | 161 | (DOT11DECRYPT_DS_BITS(frame->fc[1]) == 0) && |
2263 | 161 | (memcmp(frame->addr2, frame->addr3, DOT11DECRYPT_MAC_LEN) != 0) && |
2264 | 161 | (memcmp(frame->addr1, frame->addr3, DOT11DECRYPT_MAC_LEN) != 0)) { |
2265 | | /* DATA frame with fromDS=0 ToDS=0 and neither RA or SA is BSSID |
2266 | | => TDLS traffic. Use highest MAC address for bssid */ |
2267 | 16 | if (memcmp(frame->addr1, frame->addr2, DOT11DECRYPT_MAC_LEN) < 0) { |
2268 | 4 | memcpy(id->sta, frame->addr1, DOT11DECRYPT_MAC_LEN); |
2269 | 4 | memcpy(id->bssid, frame->addr2, DOT11DECRYPT_MAC_LEN); |
2270 | 12 | } else { |
2271 | 12 | memcpy(id->sta, frame->addr2, DOT11DECRYPT_MAC_LEN); |
2272 | 12 | memcpy(id->bssid, frame->addr1, DOT11DECRYPT_MAC_LEN); |
2273 | 12 | } |
2274 | 145 | } else { |
2275 | 145 | const unsigned char *addr; |
2276 | | |
2277 | | /* Normal Case: SA between STA and AP */ |
2278 | 145 | if ((addr = Dot11DecryptGetBssidAddress(frame)) != NULL) { |
2279 | 145 | memcpy(id->bssid, addr, DOT11DECRYPT_MAC_LEN); |
2280 | 145 | } else { |
2281 | 0 | return DOT11DECRYPT_RET_UNSUCCESS; |
2282 | 0 | } |
2283 | | |
2284 | 145 | if ((addr = Dot11DecryptGetStaAddress(frame)) != NULL) { |
2285 | 145 | memcpy(id->sta, addr, DOT11DECRYPT_MAC_LEN); |
2286 | 145 | } else { |
2287 | 0 | return DOT11DECRYPT_RET_UNSUCCESS; |
2288 | 0 | } |
2289 | 145 | } |
2290 | 161 | ws_noisy("BSSID_MAC: %02X.%02X.%02X.%02X.%02X.%02X\t", |
2291 | 161 | id->bssid[0],id->bssid[1],id->bssid[2],id->bssid[3],id->bssid[4],id->bssid[5]); |
2292 | 161 | ws_noisy("STA_MAC: %02X.%02X.%02X.%02X.%02X.%02X\t", |
2293 | 161 | id->sta[0],id->sta[1],id->sta[2],id->sta[3],id->sta[4],id->sta[5]); |
2294 | | |
2295 | 161 | return DOT11DECRYPT_RET_SUCCESS; |
2296 | 161 | } |
2297 | | |
2298 | | /* |
2299 | | * Dot11DecryptGetBssidAddress() and Dot11DecryptGetBssidAddress() are used for |
2300 | | * key caching. In each case, it's more important to return a value than |
2301 | | * to return a _correct_ value, so we fudge addresses in some cases, e.g. |
2302 | | * the BSSID in bridged connections. |
2303 | | * FromDS ToDS Sta BSSID |
2304 | | * 0 0 addr1/2 addr3 |
2305 | | * 0 1 addr2 addr1 |
2306 | | * 1 0 addr1 addr2 |
2307 | | * 1 1 addr2 addr1 |
2308 | | */ |
2309 | | |
2310 | | static const unsigned char * |
2311 | | Dot11DecryptGetStaAddress( |
2312 | | const DOT11DECRYPT_MAC_FRAME_ADDR4 *frame) |
2313 | 145 | { |
2314 | 145 | switch(DOT11DECRYPT_DS_BITS(frame->fc[1])) { /* Bit 1 = FromDS, bit 0 = ToDS */ |
2315 | 40 | case 0: |
2316 | 40 | if (memcmp(frame->addr2, frame->addr3, DOT11DECRYPT_MAC_LEN) == 0) |
2317 | 12 | return frame->addr1; |
2318 | 28 | else |
2319 | 28 | return frame->addr2; |
2320 | 36 | case 1: |
2321 | 36 | return frame->addr2; |
2322 | 13 | case 2: |
2323 | 13 | return frame->addr1; |
2324 | 56 | case 3: |
2325 | 56 | if (memcmp(frame->addr1, frame->addr2, DOT11DECRYPT_MAC_LEN) < 0) |
2326 | 22 | return frame->addr1; |
2327 | 34 | else |
2328 | 34 | return frame->addr2; |
2329 | | |
2330 | 0 | default: |
2331 | 0 | return NULL; |
2332 | 145 | } |
2333 | 145 | } |
2334 | | |
2335 | | static const unsigned char * |
2336 | | Dot11DecryptGetBssidAddress( |
2337 | | const DOT11DECRYPT_MAC_FRAME_ADDR4 *frame) |
2338 | 145 | { |
2339 | 145 | switch(DOT11DECRYPT_DS_BITS(frame->fc[1])) { /* Bit 1 = FromDS, bit 0 = ToDS */ |
2340 | 40 | case 0: |
2341 | 40 | return frame->addr3; |
2342 | 36 | case 1: |
2343 | 36 | return frame->addr1; |
2344 | 13 | case 2: |
2345 | 13 | return frame->addr2; |
2346 | 56 | case 3: |
2347 | 56 | if (memcmp(frame->addr1, frame->addr2, DOT11DECRYPT_MAC_LEN) > 0) |
2348 | 33 | return frame->addr1; |
2349 | 23 | else |
2350 | 23 | return frame->addr2; |
2351 | | |
2352 | 0 | default: |
2353 | 0 | return NULL; |
2354 | 145 | } |
2355 | 145 | } |
2356 | | |
2357 | | /* From IEEE 802.11-2016 Table 9-131 Cipher suite selectors and |
2358 | | * Table 12-4 Cipher suite key lengths */ |
2359 | | static int Dot11DecryptGetTkLen(int cipher) |
2360 | 0 | { |
2361 | 0 | switch (cipher) { |
2362 | 0 | case 1: return 40; /* WEP-40 */ |
2363 | 0 | case 2: return 256; /* TKIP */ |
2364 | 0 | case 3: return -1; /* Reserved */ |
2365 | 0 | case 4: return 128; /* CCMP-128 */ |
2366 | 0 | case 5: return 104; /* WEP-104 */ |
2367 | 0 | case 6: return 128; /* BIP-CMAC-128 */ |
2368 | 0 | case 7: return -1; /* Group addressed traffic not allowed */ |
2369 | 0 | case 8: return 128; /* GCMP-128 */ |
2370 | 0 | case 9: return 256; /* GCMP-256 */ |
2371 | 0 | case 10: return 256; /* CCMP-256 */ |
2372 | 0 | case 11: return 128; /* BIP-GMAC-128 */ |
2373 | 0 | case 12: return 256; /* BIP-GMAC-256 */ |
2374 | 0 | case 13: return 256; /* BIP-CMAC-256 */ |
2375 | 0 | default: |
2376 | 0 | ws_warning("Unknown cipher"); |
2377 | 0 | return -1; |
2378 | 0 | } |
2379 | 0 | } |
2380 | | |
2381 | | /* From IEEE 802.11-2016 Table 12-8 Integrity and key-wrap algorithms */ |
2382 | | static int Dot11DecryptGetKckLen(int akm, int dh_group) |
2383 | 0 | { |
2384 | 0 | switch (akm) { |
2385 | 0 | case 1: return 128; |
2386 | 0 | case 2: return 128; |
2387 | 0 | case 3: return 128; |
2388 | 0 | case 4: return 128; |
2389 | 0 | case 5: return 128; |
2390 | 0 | case 6: return 128; |
2391 | 0 | case 8: return 128; |
2392 | 0 | case 9: return 128; |
2393 | 0 | case 11: return 128; |
2394 | 0 | case 12: return 192; |
2395 | 0 | case 13: return 192; |
2396 | 0 | case 18: |
2397 | 0 | case 24: |
2398 | 0 | case 25: |
2399 | 0 | if (dh_group == 20) |
2400 | 0 | return 192; |
2401 | 0 | else if (dh_group == 21) |
2402 | 0 | return 256; |
2403 | 0 | else |
2404 | 0 | return 128; |
2405 | 0 | default: |
2406 | | /* Unknown / Not supported */ |
2407 | 0 | ws_warning("Unknown akm"); |
2408 | 0 | return -1; |
2409 | 0 | } |
2410 | 0 | } |
2411 | | |
2412 | | /* From IEEE 802.11-2016 Table 12-8 Integrity and key-wrap algorithms */ |
2413 | | static int Dot11DecryptGetKekLen(int akm, int dh_group) |
2414 | 0 | { |
2415 | 0 | switch (akm) { |
2416 | 0 | case 1: return 128; |
2417 | 0 | case 2: return 128; |
2418 | 0 | case 3: return 128; |
2419 | 0 | case 4: return 128; |
2420 | 0 | case 5: return 128; |
2421 | 0 | case 6: return 128; |
2422 | 0 | case 8: return 128; |
2423 | 0 | case 9: return 128; |
2424 | 0 | case 11: return 128; |
2425 | 0 | case 12: return 256; |
2426 | 0 | case 13: return 256; |
2427 | 0 | case 18: |
2428 | 0 | case 24: |
2429 | 0 | case 25: |
2430 | 0 | if (dh_group == 20 || dh_group == 21) |
2431 | 0 | return 256; |
2432 | 0 | else |
2433 | 0 | return 128; |
2434 | 0 | default: |
2435 | | /* Unknown / Not supported */ |
2436 | 0 | ws_warning("Unknown akm"); |
2437 | 0 | return -1; |
2438 | 0 | } |
2439 | 0 | } |
2440 | | |
2441 | | /* From IEEE 802.11-2016 9.4.2.25.3 AKM suites and |
2442 | | * Table 12-8 Integrity and key-wrap algorithms */ |
2443 | | static int Dot11DecryptGetPtkLen(int akm, int cipher, int dh_group) |
2444 | 0 | { |
2445 | 0 | int kck_len = Dot11DecryptGetKckLen(akm, dh_group); |
2446 | 0 | int kek_len = Dot11DecryptGetKekLen(akm, dh_group); |
2447 | 0 | int tk_len = Dot11DecryptGetTkLen(cipher); |
2448 | |
|
2449 | 0 | if (kck_len == -1 || kek_len == -1 || tk_len == -1) { |
2450 | 0 | ws_warning("Invalid PTK len"); |
2451 | 0 | return -1; |
2452 | 0 | } |
2453 | 0 | return kck_len + kek_len + tk_len; |
2454 | 0 | } |
2455 | | |
2456 | | /* From IEEE 802.11-2016 12.7.1.2 PRF and Table 9-133 AKM suite selectors */ |
2457 | | static int |
2458 | | Dot11DecryptGetDeriveFuncFromAkm(int akm) |
2459 | 0 | { |
2460 | 0 | int func = -1; |
2461 | 0 | switch (akm) { |
2462 | 0 | case 1: |
2463 | 0 | case 2: |
2464 | 0 | func = DOT11DECRYPT_DERIVE_USING_PRF; |
2465 | 0 | break; |
2466 | 0 | case 3: |
2467 | 0 | case 4: |
2468 | 0 | case 5: |
2469 | 0 | case 6: |
2470 | 0 | case 7: |
2471 | 0 | case 8: |
2472 | 0 | case 9: |
2473 | 0 | case 10: |
2474 | 0 | case 11: |
2475 | 0 | case 12: |
2476 | 0 | case 13: |
2477 | 0 | case 18: |
2478 | 0 | case 24: |
2479 | 0 | func = DOT11DECRYPT_DERIVE_USING_KDF; |
2480 | 0 | break; |
2481 | 0 | default: |
2482 | | /* Unknown / Not supported yet */ |
2483 | 0 | break; |
2484 | 0 | } |
2485 | 0 | return func; |
2486 | 0 | } |
2487 | | |
2488 | | /* From IEEE 802.11-2016 12.7.1.2 PRF and Table 9-133 AKM suite selectors */ |
2489 | | static int |
2490 | | Dot11DecryptGetHashAlgoFromAkm(int akm, int dh_group) |
2491 | 0 | { |
2492 | 0 | int algo = -1; |
2493 | 0 | switch (akm) { |
2494 | 0 | case 1: |
2495 | 0 | case 2: |
2496 | 0 | algo = GCRY_MD_SHA1; |
2497 | 0 | break; |
2498 | 0 | case 3: |
2499 | 0 | case 4: |
2500 | 0 | case 5: |
2501 | 0 | case 6: |
2502 | 0 | case 7: |
2503 | 0 | case 8: |
2504 | 0 | case 9: |
2505 | 0 | case 10: |
2506 | 0 | case 11: |
2507 | 0 | algo = GCRY_MD_SHA256; |
2508 | 0 | break; |
2509 | 0 | case 12: |
2510 | 0 | case 13: |
2511 | 0 | algo = GCRY_MD_SHA384; |
2512 | 0 | break; |
2513 | 0 | case 18: |
2514 | 0 | case 24: |
2515 | 0 | case 25: |
2516 | 0 | if (dh_group == 20) |
2517 | 0 | algo = GCRY_MD_SHA384; |
2518 | 0 | else if (dh_group == 21) |
2519 | 0 | algo = GCRY_MD_SHA512; |
2520 | 0 | else |
2521 | 0 | algo = GCRY_MD_SHA256; |
2522 | 0 | break; |
2523 | 0 | default: |
2524 | | /* Unknown / Not supported yet */ |
2525 | 0 | break; |
2526 | 0 | } |
2527 | 0 | return algo; |
2528 | 0 | } |
2529 | | |
2530 | | /* derive the PTK from the BSSID, STA MAC, PMK, SNonce, ANonce */ |
2531 | | /** From IEEE 802.11-2016 12.7.1.3 Pairwise key hierarchy: |
2532 | | * PRF-Length(PMK, "Pairwise key expansion", |
2533 | | * Min(AA, SPA) || Max(AA, SPA) || |
2534 | | * Min(ANonce, SNonce) || Max(ANonce, SNonce)) |
2535 | | */ |
2536 | | static uint8_t |
2537 | | Dot11DecryptDerivePtk( |
2538 | | const DOT11DECRYPT_SEC_ASSOCIATION *sa, |
2539 | | const unsigned char *pmk, |
2540 | | size_t pmk_len, |
2541 | | const unsigned char snonce[32], |
2542 | | int key_version, |
2543 | | int akm, |
2544 | | int cipher, |
2545 | | uint8_t *ptk, size_t *ptk_len, |
2546 | | int dh_group) |
2547 | 0 | { |
2548 | 0 | int algo = -1; |
2549 | 0 | int ptk_len_bits = -1; |
2550 | 0 | int derive_func; |
2551 | |
|
2552 | 0 | if (!sa || !pmk || !snonce || !ptk || !ptk_len) { |
2553 | 0 | ws_warning("Invalid input for PTK derivation"); |
2554 | 0 | return DOT11DECRYPT_RET_NO_VALID_HANDSHAKE; |
2555 | 0 | } |
2556 | | |
2557 | 0 | if (key_version == DOT11DECRYPT_WPA_KEY_VER_NOT_CCMP) { |
2558 | | /* TKIP */ |
2559 | 0 | ptk_len_bits = 512; |
2560 | 0 | derive_func = DOT11DECRYPT_DERIVE_USING_PRF; |
2561 | 0 | algo = GCRY_MD_SHA1; |
2562 | 0 | } else { |
2563 | | /* From IEEE 802.11-2016 Table 12-8 Integrity and key-wrap algorithms */ |
2564 | 0 | ptk_len_bits = Dot11DecryptGetPtkLen(akm, cipher, dh_group); |
2565 | 0 | algo = Dot11DecryptGetHashAlgoFromAkm(akm, dh_group); |
2566 | 0 | derive_func = Dot11DecryptGetDeriveFuncFromAkm(akm); |
2567 | 0 | ws_debug("ptk_len_bits: %d, algo: %d, cipher: %d", ptk_len_bits, algo, cipher); |
2568 | 0 | } |
2569 | |
|
2570 | 0 | if (ptk_len_bits == -1 || algo == -1) { |
2571 | 0 | return DOT11DECRYPT_RET_NO_VALID_HANDSHAKE; |
2572 | 0 | } |
2573 | 0 | *ptk_len = ptk_len_bits / 8; |
2574 | |
|
2575 | 0 | static const char *const label = "Pairwise key expansion"; |
2576 | 0 | uint8_t context[DOT11DECRYPT_MAC_LEN * 2 + 32 * 2]; |
2577 | 0 | int offset = 0; |
2578 | | |
2579 | | /* Min(AA, SPA) || Max(AA, SPA) */ |
2580 | 0 | if (memcmp(sa->saId.sta, sa->saId.bssid, DOT11DECRYPT_MAC_LEN) < 0) |
2581 | 0 | { |
2582 | 0 | memcpy(context + offset, sa->saId.sta, DOT11DECRYPT_MAC_LEN); |
2583 | 0 | offset += DOT11DECRYPT_MAC_LEN; |
2584 | 0 | memcpy(context + offset, sa->saId.bssid, DOT11DECRYPT_MAC_LEN); |
2585 | 0 | offset += DOT11DECRYPT_MAC_LEN; |
2586 | 0 | } |
2587 | 0 | else |
2588 | 0 | { |
2589 | 0 | memcpy(context + offset, sa->saId.bssid, DOT11DECRYPT_MAC_LEN); |
2590 | 0 | offset += DOT11DECRYPT_MAC_LEN; |
2591 | 0 | memcpy(context + offset, sa->saId.sta, DOT11DECRYPT_MAC_LEN); |
2592 | 0 | offset += DOT11DECRYPT_MAC_LEN; |
2593 | 0 | } |
2594 | | |
2595 | | /* Min(ANonce, SNonce) || Max(ANonce, SNonce) */ |
2596 | 0 | if (memcmp(snonce, sa->wpa.nonce, 32) < 0 ) |
2597 | 0 | { |
2598 | 0 | memcpy(context + offset, snonce, 32); |
2599 | 0 | offset += 32; |
2600 | 0 | memcpy(context + offset, sa->wpa.nonce, 32); |
2601 | 0 | offset += 32; |
2602 | 0 | } |
2603 | 0 | else |
2604 | 0 | { |
2605 | 0 | memcpy(context + offset, sa->wpa.nonce, 32); |
2606 | 0 | offset += 32; |
2607 | 0 | memcpy(context + offset, snonce, 32); |
2608 | 0 | offset += 32; |
2609 | 0 | } |
2610 | 0 | if (derive_func == DOT11DECRYPT_DERIVE_USING_PRF) { |
2611 | 0 | dot11decrypt_prf(pmk, pmk_len, label, context, offset, algo, |
2612 | 0 | ptk, *ptk_len); |
2613 | 0 | } else { |
2614 | 0 | dot11decrypt_kdf(pmk, pmk_len, label, context, offset, algo, |
2615 | 0 | ptk, *ptk_len); |
2616 | 0 | } |
2617 | 0 | DEBUG_DUMP("PTK", ptk, *ptk_len, LOG_LEVEL_DEBUG); |
2618 | 0 | return DOT11DECRYPT_RET_SUCCESS; |
2619 | 0 | } |
2620 | | |
2621 | | /** |
2622 | | * For Fast BSS Transition AKMS derive PTK from sa, selected key and various information in |
2623 | | * eapol key frame. |
2624 | | * From IEEE 802.11-2016 12.7.1.7.1 |
2625 | | */ |
2626 | | static uint8_t |
2627 | | Dot11DecryptFtDerivePtk( |
2628 | | const PDOT11DECRYPT_CONTEXT ctx, |
2629 | | const DOT11DECRYPT_SEC_ASSOCIATION *sa, |
2630 | | const PDOT11DECRYPT_KEY_ITEM key, |
2631 | | const uint8_t mdid[2], |
2632 | | const uint8_t *snonce, |
2633 | | const uint8_t *r0kh_id, size_t r0kh_id_len, |
2634 | | const uint8_t *r1kh_id, size_t r1kh_id_len _U_, |
2635 | | int akm, int cipher, |
2636 | | uint8_t *ptk, size_t *ptk_len) |
2637 | 0 | { |
2638 | 0 | int hash_algo = Dot11DecryptGetHashAlgoFromAkm(akm, 0); |
2639 | 0 | uint8_t pmk_r0[DOT11DECRYPT_WPA_PMK_MAX_LEN]; |
2640 | 0 | uint8_t pmk_r1[DOT11DECRYPT_WPA_PMK_MAX_LEN]; |
2641 | 0 | uint8_t pmk_r0_name[16] = {0}; |
2642 | 0 | uint8_t pmk_r1_name[16] = {0}; |
2643 | 0 | uint8_t ptk_name[16]; |
2644 | 0 | size_t pmk_r0_len = 0; |
2645 | 0 | size_t pmk_r1_len = 0; |
2646 | 0 | const uint8_t *xxkey = NULL; |
2647 | 0 | size_t xxkey_len; |
2648 | 0 | int ptk_len_bits; |
2649 | |
|
2650 | 0 | if (!sa || !key || !mdid || !snonce || !r0kh_id || !r1kh_id || !ptk || !ptk_len) { |
2651 | 0 | ws_warning("Invalid input for FT PTK derivation"); |
2652 | 0 | return DOT11DECRYPT_RET_NO_VALID_HANDSHAKE; |
2653 | 0 | } |
2654 | 0 | ptk_len_bits = Dot11DecryptGetPtkLen(akm, cipher, 0); |
2655 | 0 | if (ptk_len_bits == -1) { |
2656 | 0 | ws_warning("Invalid akm or cipher"); |
2657 | 0 | return DOT11DECRYPT_RET_NO_VALID_HANDSHAKE; |
2658 | 0 | } |
2659 | 0 | *ptk_len = ptk_len_bits / 8; |
2660 | |
|
2661 | 0 | if (key->KeyType == DOT11DECRYPT_KEY_TYPE_MSK) { |
2662 | 0 | xxkey = Dot11DecryptGetXXKeyFromMSK(key->Msk.Msk, |
2663 | 0 | key->Msk.Len, |
2664 | 0 | akm, |
2665 | 0 | &xxkey_len); |
2666 | 0 | } |
2667 | 0 | if (!xxkey && key->KeyData.Wpa.PskLen > 0) { |
2668 | 0 | xxkey = key->KeyData.Wpa.Psk; |
2669 | 0 | xxkey_len = key->KeyData.Wpa.PskLen; |
2670 | 0 | } |
2671 | 0 | if (!xxkey) { |
2672 | 0 | ws_debug("no xxkey. Skipping"); |
2673 | 0 | return DOT11DECRYPT_RET_NO_VALID_HANDSHAKE; |
2674 | 0 | } |
2675 | 0 | if (!dot11decrypt_derive_pmk_r0(xxkey, xxkey_len, |
2676 | 0 | ctx->pkt_ssid, ctx->pkt_ssid_len, |
2677 | 0 | mdid, |
2678 | 0 | r0kh_id, r0kh_id_len, |
2679 | 0 | sa->saId.sta, hash_algo, |
2680 | 0 | pmk_r0, &pmk_r0_len, pmk_r0_name)) { |
2681 | | /* This can fail for bad size or a bad SHA256 sum. */ |
2682 | 0 | return DOT11DECRYPT_RET_UNSUCCESS; |
2683 | 0 | } |
2684 | 0 | DEBUG_DUMP("PMK-R0", pmk_r0, pmk_r0_len, LOG_LEVEL_DEBUG); |
2685 | 0 | DEBUG_DUMP("PMKR0Name", pmk_r0_name, 16, LOG_LEVEL_DEBUG); |
2686 | |
|
2687 | 0 | if (!dot11decrypt_derive_pmk_r1(pmk_r0, pmk_r0_len, pmk_r0_name, |
2688 | 0 | r1kh_id, sa->saId.sta, hash_algo, |
2689 | 0 | pmk_r1, &pmk_r1_len, pmk_r1_name)) { |
2690 | 0 | return DOT11DECRYPT_RET_UNSUCCESS; |
2691 | 0 | } |
2692 | 0 | DEBUG_DUMP("PMK-R1", pmk_r1, pmk_r1_len, LOG_LEVEL_DEBUG); |
2693 | 0 | DEBUG_DUMP("PMKR1Name", pmk_r1_name, 16, LOG_LEVEL_DEBUG); |
2694 | |
|
2695 | 0 | if (!dot11decrypt_derive_ft_ptk(pmk_r1, pmk_r1_len, pmk_r1_name, |
2696 | 0 | snonce, sa->wpa.nonce, |
2697 | 0 | sa->saId.bssid, sa->saId.sta, hash_algo, |
2698 | 0 | ptk, *ptk_len, ptk_name)) { |
2699 | 0 | return DOT11DECRYPT_RET_UNSUCCESS; |
2700 | 0 | } |
2701 | 0 | DEBUG_DUMP("PTK", ptk, *ptk_len, LOG_LEVEL_DEBUG); |
2702 | 0 | return DOT11DECRYPT_RET_SUCCESS; |
2703 | 0 | } |
2704 | | |
2705 | 0 | #define MAX_SSID_LENGTH 32 /* maximum SSID length */ |
2706 | | |
2707 | | static int |
2708 | | Dot11DecryptRsnaPwd2PskStep( |
2709 | | const uint8_t *ppBytes, |
2710 | | const unsigned ppLength, |
2711 | | const char *ssid, |
2712 | | const size_t ssidLength, |
2713 | | const int iterations, |
2714 | | const int count, |
2715 | | unsigned char *output) |
2716 | 0 | { |
2717 | 0 | unsigned char digest[MAX_SSID_LENGTH+4] = { 0 }; /* SSID plus 4 bytes of count */ |
2718 | 0 | int i, j; |
2719 | |
|
2720 | 0 | if (ssidLength > MAX_SSID_LENGTH) { |
2721 | | /* This "should not happen" */ |
2722 | 0 | return DOT11DECRYPT_RET_UNSUCCESS; |
2723 | 0 | } |
2724 | | |
2725 | | /* U1 = PRF(P, S || int(i)) */ |
2726 | 0 | memcpy(digest, ssid, ssidLength); |
2727 | 0 | digest[ssidLength] = (unsigned char)((count>>24) & 0xff); |
2728 | 0 | digest[ssidLength+1] = (unsigned char)((count>>16) & 0xff); |
2729 | 0 | digest[ssidLength+2] = (unsigned char)((count>>8) & 0xff); |
2730 | 0 | digest[ssidLength+3] = (unsigned char)(count & 0xff); |
2731 | 0 | if (ws_hmac_buffer(GCRY_MD_SHA1, digest, digest, (uint32_t) ssidLength + 4, ppBytes, ppLength)) { |
2732 | 0 | return DOT11DECRYPT_RET_UNSUCCESS; |
2733 | 0 | } |
2734 | | |
2735 | | /* output = U1 */ |
2736 | 0 | memcpy(output, digest, 20); |
2737 | 0 | for (i = 1; i < iterations; i++) { |
2738 | | /* Un = PRF(P, Un-1) */ |
2739 | 0 | if (ws_hmac_buffer(GCRY_MD_SHA1, digest, digest, HASH_SHA1_LENGTH, ppBytes, ppLength)) { |
2740 | 0 | return DOT11DECRYPT_RET_UNSUCCESS; |
2741 | 0 | } |
2742 | | |
2743 | | /* output = output xor Un */ |
2744 | 0 | for (j = 0; j < 20; j++) { |
2745 | 0 | output[j] ^= digest[j]; |
2746 | 0 | } |
2747 | 0 | } |
2748 | | |
2749 | 0 | return DOT11DECRYPT_RET_SUCCESS; |
2750 | 0 | } |
2751 | | |
2752 | | static int |
2753 | | Dot11DecryptRsnaPwd2Psk( |
2754 | | const struct DOT11DECRYPT_KEY_ITEMDATA_PWD *userPwd, |
2755 | | unsigned char *output) |
2756 | 0 | { |
2757 | 0 | unsigned char m_output[40] = { 0 }; |
2758 | 0 | GByteArray *pp_ba = g_byte_array_new(); |
2759 | |
|
2760 | 0 | g_byte_array_append(pp_ba, userPwd->Passphrase, (unsigned)userPwd->PassphraseLen); |
2761 | |
|
2762 | 0 | Dot11DecryptRsnaPwd2PskStep(pp_ba->data, pp_ba->len, userPwd->Ssid, userPwd->SsidLen, 4096, 1, m_output); |
2763 | 0 | Dot11DecryptRsnaPwd2PskStep(pp_ba->data, pp_ba->len, userPwd->Ssid, userPwd->SsidLen, 4096, 2, &m_output[20]); |
2764 | |
|
2765 | 0 | memcpy(output, m_output, DOT11DECRYPT_WPA_PWD_PSK_LEN); |
2766 | 0 | g_byte_array_free(pp_ba, true); |
2767 | |
|
2768 | 0 | return 0; |
2769 | 0 | } |
2770 | | |
2771 | | /* |
2772 | | * Returns the decryption_key_t struct given a string describing the key. |
2773 | | * Returns NULL if the input_string cannot be parsed. |
2774 | | * XXX: Should return an error string explaining why parsing failed |
2775 | | */ |
2776 | | decryption_key_t* |
2777 | | parse_key_string(char* input_string, uint8_t key_type, char** error) |
2778 | 0 | { |
2779 | 0 | GByteArray *ssid_ba = NULL, *key_ba; |
2780 | |
|
2781 | 0 | char **tokens; |
2782 | 0 | unsigned n = 0; |
2783 | 0 | decryption_key_t *dk; |
2784 | |
|
2785 | 0 | if(input_string == NULL || (strcmp(input_string, "") == 0)) { |
2786 | 0 | if (error) { |
2787 | 0 | *error = g_strdup("Key cannot be empty"); |
2788 | 0 | } |
2789 | 0 | return NULL; |
2790 | 0 | } |
2791 | | |
2792 | | /* |
2793 | | * Parse the input_string. WEP and WPA will be just a string |
2794 | | * of hexadecimal characters (if key is wrong, null will be |
2795 | | * returned...). |
2796 | | * WPA-PWD should be in the form |
2797 | | * <key data>[:<ssid>] |
2798 | | * With WPA-PWD, we percent-decode the key data and ssid. |
2799 | | * The percent itself ("%25") and the colon ("%3a") must be |
2800 | | * percent-encoded, the latter so we can distinguish between the |
2801 | | * separator and a colon in the key or ssid. Percent-encoding |
2802 | | * for anything else is optional. (NUL is not allowed, either |
2803 | | * percent-encoded or not.) |
2804 | | */ |
2805 | | |
2806 | 0 | switch(key_type) |
2807 | 0 | { |
2808 | 0 | case DOT11DECRYPT_KEY_TYPE_WEP: |
2809 | 0 | case DOT11DECRYPT_KEY_TYPE_WEP_40: |
2810 | 0 | case DOT11DECRYPT_KEY_TYPE_WEP_104: |
2811 | |
|
2812 | 0 | key_ba = g_byte_array_new(); |
2813 | |
|
2814 | 0 | if (!hex_str_to_bytes(input_string, key_ba, false)) { |
2815 | 0 | if (error) { |
2816 | 0 | *error = g_strdup("WEP key must be a hexadecimal string"); |
2817 | 0 | } |
2818 | 0 | g_byte_array_free(key_ba, true); |
2819 | 0 | return NULL; |
2820 | 0 | } |
2821 | | |
2822 | 0 | if (key_ba->len > 0 && key_ba->len <= DOT11DECRYPT_WEP_KEY_MAXLEN) { |
2823 | | /* Key is correct! It was probably an 'old style' WEP key */ |
2824 | | /* Create the decryption_key_t structure, fill it and return it*/ |
2825 | 0 | dk = g_new(decryption_key_t, 1); |
2826 | |
|
2827 | 0 | dk->type = DOT11DECRYPT_KEY_TYPE_WEP; |
2828 | 0 | dk->key = key_ba; |
2829 | 0 | dk->bits = key_ba->len * 8; |
2830 | 0 | dk->ssid = NULL; |
2831 | |
|
2832 | 0 | return dk; |
2833 | 0 | } |
2834 | | |
2835 | 0 | if (error) { |
2836 | 0 | *error = ws_strdup_printf("WEP key entered is %u bytes, and must be no more than %u", key_ba->len, DOT11DECRYPT_WEP_KEY_MAXLEN); |
2837 | 0 | } |
2838 | | /* Key doesn't work */ |
2839 | 0 | g_byte_array_free(key_ba, true); |
2840 | 0 | return NULL; |
2841 | | |
2842 | 0 | case DOT11DECRYPT_KEY_TYPE_WPA_PWD: |
2843 | |
|
2844 | 0 | tokens = g_strsplit(input_string,":", 3); |
2845 | 0 | n = g_strv_length(tokens); |
2846 | |
|
2847 | 0 | if (n < 1 || n > 2) |
2848 | 0 | { |
2849 | | /* Require either one or two tokens; more, and the user |
2850 | | * may have meant a colon in the passphrase or SSID name |
2851 | | */ |
2852 | | /* Free the array of strings */ |
2853 | | /* XXX: Return why parsing failed (":" must be escaped) */ |
2854 | 0 | if (error) { |
2855 | 0 | *error = g_strdup("Only one ':' is allowed, as a separator between passphrase and SSID; others must be percent-encoded as \"%%3a\""); |
2856 | 0 | } |
2857 | 0 | g_strfreev(tokens); |
2858 | 0 | return NULL; |
2859 | 0 | } |
2860 | | |
2861 | | /* |
2862 | | * The first token is the key |
2863 | | */ |
2864 | 0 | key_ba = g_byte_array_new(); |
2865 | 0 | if (! uri_str_to_bytes(tokens[0], key_ba)) { |
2866 | | /* Failed parsing as percent-encoded */ |
2867 | 0 | if (error) { |
2868 | 0 | *error = g_strdup("WPA passphrase is treated as percent-encoded; use \"%%25\" for a literal \"%%\""); |
2869 | 0 | } |
2870 | 0 | g_byte_array_free(key_ba, true); |
2871 | 0 | g_strfreev(tokens); |
2872 | 0 | return NULL; |
2873 | 0 | } |
2874 | | |
2875 | | /* key length (after percent-decoding) should be between 8 and 63 |
2876 | | * octets (63 to distinguish from a PSK as 64 hex characters.) |
2877 | | * XXX: 802.11-2016 Annex J assumes that each character in the |
2878 | | * pass-phrase is ASCII printable ("has an encoding in the range |
2879 | | * 32 to 126"), though this (and the entire algorithm for that |
2880 | | * matter) is only considered a suggestion. |
2881 | | * It is possible to apply PBKDF2 to any octet string, e.g. UTF-8. |
2882 | | * (wpa_passphrase from wpa_supplicant will do so, for example.) |
2883 | | */ |
2884 | 0 | if( ((key_ba->len) > WPA_KEY_MAX_CHAR_SIZE) || ((key_ba->len) < WPA_KEY_MIN_CHAR_SIZE)) |
2885 | 0 | { |
2886 | 0 | if (error) { |
2887 | 0 | *error = ws_strdup_printf("WPA passphrase entered is %u characters after percent-decoding and must be between %u and %u", key_ba->len, WPA_KEY_MIN_CHAR_SIZE, WPA_KEY_MAX_CHAR_SIZE); |
2888 | 0 | } |
2889 | 0 | g_byte_array_free(key_ba, true); |
2890 | | |
2891 | | /* Free the array of strings */ |
2892 | 0 | g_strfreev(tokens); |
2893 | 0 | return NULL; |
2894 | 0 | } |
2895 | | |
2896 | 0 | ssid_ba = NULL; |
2897 | 0 | if (n >= 2) /* more than two tokens found, means that the user specified the ssid */ |
2898 | 0 | { |
2899 | 0 | ssid_ba = g_byte_array_new(); |
2900 | 0 | if (! uri_str_to_bytes(tokens[1], ssid_ba)) { |
2901 | 0 | if (error) { |
2902 | 0 | *error = g_strdup("WPA SSID is treated as percent-encoded; use \"%%25\" for a literal \"%%\"."); |
2903 | 0 | } |
2904 | 0 | g_byte_array_free(key_ba, true); |
2905 | 0 | g_byte_array_free(ssid_ba, true); |
2906 | | /* Free the array of strings */ |
2907 | 0 | g_strfreev(tokens); |
2908 | 0 | return NULL; |
2909 | 0 | } |
2910 | | |
2911 | 0 | if(ssid_ba->len > WPA_SSID_MAX_CHAR_SIZE) |
2912 | 0 | { |
2913 | 0 | if (error) { |
2914 | 0 | *error = ws_strdup_printf("WPA SSID entered is %u characters after percent-decoding and must be no more than %u", ssid_ba->len, WPA_SSID_MAX_CHAR_SIZE); |
2915 | 0 | } |
2916 | 0 | g_byte_array_free(key_ba, true); |
2917 | 0 | g_byte_array_free(ssid_ba, true); |
2918 | | |
2919 | | /* Free the array of strings */ |
2920 | 0 | g_strfreev(tokens); |
2921 | 0 | return NULL; |
2922 | 0 | } |
2923 | 0 | } |
2924 | | |
2925 | | /* Key was correct!!! Create the new decryption_key_t ... */ |
2926 | 0 | dk = g_new(decryption_key_t, 1); |
2927 | |
|
2928 | 0 | dk->type = DOT11DECRYPT_KEY_TYPE_WPA_PWD; |
2929 | 0 | dk->key = key_ba; |
2930 | 0 | dk->bits = 256; /* This is the length of the array pf bytes that will be generated using key+ssid ...*/ |
2931 | 0 | dk->ssid = ssid_ba; /* NULL if ssid_ba is NULL */ |
2932 | | |
2933 | | /* Free the array of strings */ |
2934 | 0 | g_strfreev(tokens); |
2935 | 0 | return dk; |
2936 | | |
2937 | 0 | case DOT11DECRYPT_KEY_TYPE_WPA_PSK: |
2938 | |
|
2939 | 0 | key_ba = g_byte_array_new(); |
2940 | 0 | if (!hex_str_to_bytes(input_string, key_ba, false)) { |
2941 | 0 | if (error) { |
2942 | 0 | *error = g_strdup("WPA PSK/PMK must be a hexadecimal string"); |
2943 | 0 | } |
2944 | 0 | g_byte_array_free(key_ba, true); |
2945 | 0 | return NULL; |
2946 | 0 | } |
2947 | | |
2948 | | /* Two tokens means that the user should have entered a WPA-BIN key ... */ |
2949 | 0 | if((key_ba->len != DOT11DECRYPT_WPA_PWD_PSK_LEN && |
2950 | 0 | key_ba->len != DOT11DECRYPT_WPA_PMK_MAX_LEN)) |
2951 | 0 | { |
2952 | 0 | if (error) { |
2953 | 0 | *error = ws_strdup_printf("WPA Pre-Master Key/Pairwise Master Key entered is %u bytes and must be %u or %u", key_ba->len, DOT11DECRYPT_WPA_PWD_PSK_LEN, DOT11DECRYPT_WPA_PMK_MAX_LEN); |
2954 | 0 | } |
2955 | 0 | g_byte_array_free(key_ba, true); |
2956 | 0 | return NULL; |
2957 | 0 | } |
2958 | | |
2959 | | /* Key was correct!!! Create the new decryption_key_t ... */ |
2960 | 0 | dk = g_new(decryption_key_t, 1); |
2961 | |
|
2962 | 0 | dk->type = DOT11DECRYPT_KEY_TYPE_WPA_PSK; |
2963 | 0 | dk->key = key_ba; |
2964 | 0 | dk->bits = (unsigned) dk->key->len * 8; |
2965 | 0 | dk->ssid = NULL; |
2966 | |
|
2967 | 0 | return dk; |
2968 | | |
2969 | 0 | case DOT11DECRYPT_KEY_TYPE_TK: |
2970 | 0 | { |
2971 | | /* From IEEE 802.11-2016 Table 12-4 Cipher suite key lengths */ |
2972 | 0 | static const uint8_t allowed_key_lengths[] = { |
2973 | | // TBD 40 / 8, /* WEP-40 */ |
2974 | | // TBD 104 / 8, /* WEP-104 */ |
2975 | 0 | 128 / 8, /* CCMP-128, GCMP-128 */ |
2976 | 0 | 256 / 8, /* TKIP, GCMP-256, CCMP-256 */ |
2977 | 0 | }; |
2978 | 0 | bool key_length_ok = false; |
2979 | |
|
2980 | 0 | key_ba = g_byte_array_new(); |
2981 | 0 | if (!hex_str_to_bytes(input_string, key_ba, false)) { |
2982 | 0 | if (error) { |
2983 | 0 | *error = g_strdup("Temporal Key must be a hexadecimal string"); |
2984 | 0 | } |
2985 | 0 | g_byte_array_free(key_ba, true); |
2986 | 0 | return NULL; |
2987 | 0 | } |
2988 | | |
2989 | 0 | for (size_t i = 0; i < sizeof(allowed_key_lengths); i++) { |
2990 | 0 | if (key_ba->len == allowed_key_lengths[i]) { |
2991 | 0 | key_length_ok = true; |
2992 | 0 | break; |
2993 | 0 | } |
2994 | 0 | } |
2995 | 0 | if (!key_length_ok) { |
2996 | 0 | if (error) { |
2997 | 0 | GString *err_string = g_string_new("Temporal Keys entered is "); |
2998 | 0 | g_string_append_printf(err_string, "%u bytes and must be ", key_ba->len); |
2999 | 0 | size_t i = 0; |
3000 | 0 | for (; i + 1 < sizeof(allowed_key_lengths); i++) { |
3001 | 0 | g_string_append_printf(err_string, "%u, ", allowed_key_lengths[i]); |
3002 | 0 | } |
3003 | 0 | g_string_append_printf(err_string, "or %u bytes.", allowed_key_lengths[i]); |
3004 | 0 | *error = g_string_free(err_string, FALSE); |
3005 | 0 | } |
3006 | 0 | g_byte_array_free(key_ba, true); |
3007 | 0 | return NULL; |
3008 | 0 | } |
3009 | 0 | dk = g_new(decryption_key_t, 1); |
3010 | 0 | dk->type = DOT11DECRYPT_KEY_TYPE_TK; |
3011 | 0 | dk->key = key_ba; |
3012 | 0 | dk->bits = (unsigned) dk->key->len * 8; |
3013 | 0 | dk->ssid = NULL; |
3014 | |
|
3015 | 0 | return dk; |
3016 | 0 | } |
3017 | 0 | case DOT11DECRYPT_KEY_TYPE_MSK: |
3018 | 0 | { |
3019 | 0 | key_ba = g_byte_array_new(); |
3020 | 0 | if (!hex_str_to_bytes(input_string, key_ba, false)) { |
3021 | 0 | if (error) { |
3022 | 0 | *error = g_strdup("Master Session Key must be a hexadecimal string"); |
3023 | 0 | } |
3024 | 0 | g_byte_array_free(key_ba, true); |
3025 | 0 | return NULL; |
3026 | 0 | } |
3027 | | |
3028 | 0 | if (key_ba->len < DOT11DECRYPT_MSK_MIN_LEN || |
3029 | 0 | key_ba->len > DOT11DECRYPT_MSK_MAX_LEN) |
3030 | 0 | { |
3031 | 0 | if (error) { |
3032 | 0 | *error = ws_strdup_printf("Master Session Key entered is %u bytes and must be between %u and %u", key_ba->len, DOT11DECRYPT_MSK_MIN_LEN, DOT11DECRYPT_MSK_MAX_LEN); |
3033 | 0 | } |
3034 | 0 | g_byte_array_free(key_ba, true); |
3035 | 0 | return NULL; |
3036 | 0 | } |
3037 | 0 | dk = g_new(decryption_key_t, 1); |
3038 | 0 | dk->type = DOT11DECRYPT_KEY_TYPE_MSK; |
3039 | 0 | dk->key = key_ba; |
3040 | 0 | dk->bits = (unsigned)dk->key->len * 8; |
3041 | 0 | dk->ssid = NULL; |
3042 | 0 | return dk; |
3043 | 0 | } |
3044 | 0 | } |
3045 | | |
3046 | | /* Type not supported */ |
3047 | 0 | if (error) { |
3048 | 0 | *error = g_strdup("Unknown key type not supported"); |
3049 | 0 | } |
3050 | 0 | return NULL; |
3051 | 0 | } |
3052 | | |
3053 | | void |
3054 | | free_key_string(decryption_key_t *dk) |
3055 | 0 | { |
3056 | 0 | if (dk->key) |
3057 | 0 | g_byte_array_free(dk->key, true); |
3058 | 0 | if (dk->ssid) |
3059 | 0 | g_byte_array_free(dk->ssid, true); |
3060 | 0 | g_free(dk); |
3061 | 0 | } |
3062 | | |
3063 | | static int |
3064 | | Dot11DecryptTDLSDeriveKey( |
3065 | | PDOT11DECRYPT_SEC_ASSOCIATION sa, |
3066 | | const uint8_t *data, |
3067 | | unsigned offset_rsne, |
3068 | | unsigned offset_fte, |
3069 | | unsigned offset_timeout, |
3070 | | unsigned offset_link, |
3071 | | uint8_t action) |
3072 | 0 | { |
3073 | |
|
3074 | 0 | gcry_md_hd_t sha256_handle; |
3075 | 0 | gcry_md_hd_t hmac_handle; |
3076 | 0 | const uint8_t *snonce, *anonce, *initiator, *responder, *bssid; |
3077 | 0 | uint8_t key_input[32]; |
3078 | 0 | uint8_t mic[16], seq_num = action + 1; |
3079 | 0 | uint8_t zeros[16] = { 0 }; |
3080 | 0 | gcry_mac_hd_t cmac_handle; |
3081 | 0 | size_t cmac_len = 16; |
3082 | 0 | size_t cmac_write_len; |
3083 | | |
3084 | | /* Get key input */ |
3085 | 0 | anonce = &data[offset_fte + 20]; |
3086 | 0 | snonce = &data[offset_fte + 52]; |
3087 | |
|
3088 | 0 | if (gcry_md_open (&sha256_handle, GCRY_MD_SHA256, 0)) { |
3089 | 0 | return DOT11DECRYPT_RET_UNSUCCESS; |
3090 | 0 | } |
3091 | 0 | if (memcmp(anonce, snonce, DOT11DECRYPT_WPA_NONCE_LEN) < 0) { |
3092 | 0 | gcry_md_write(sha256_handle, anonce, DOT11DECRYPT_WPA_NONCE_LEN); |
3093 | 0 | gcry_md_write(sha256_handle, snonce, DOT11DECRYPT_WPA_NONCE_LEN); |
3094 | 0 | } else { |
3095 | 0 | gcry_md_write(sha256_handle, snonce, DOT11DECRYPT_WPA_NONCE_LEN); |
3096 | 0 | gcry_md_write(sha256_handle, anonce, DOT11DECRYPT_WPA_NONCE_LEN); |
3097 | 0 | } |
3098 | 0 | memcpy(key_input, gcry_md_read(sha256_handle, 0), 32); |
3099 | 0 | gcry_md_close(sha256_handle); |
3100 | | |
3101 | | /* Derive key */ |
3102 | 0 | bssid = &data[offset_link + 2]; |
3103 | 0 | initiator = &data[offset_link + 8]; |
3104 | 0 | responder = &data[offset_link + 14]; |
3105 | 0 | if (gcry_md_open(&hmac_handle, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC)) { |
3106 | 0 | return DOT11DECRYPT_RET_UNSUCCESS; |
3107 | 0 | } |
3108 | 0 | if (gcry_md_setkey(hmac_handle, key_input, 32)) { |
3109 | 0 | gcry_md_close(hmac_handle); |
3110 | 0 | return DOT11DECRYPT_RET_UNSUCCESS; |
3111 | 0 | } |
3112 | 0 | gcry_md_putc(hmac_handle, 1); |
3113 | 0 | gcry_md_putc(hmac_handle, 0); |
3114 | 0 | gcry_md_write(hmac_handle, "TDLS PMK", 8); |
3115 | 0 | if (memcmp(initiator, responder, DOT11DECRYPT_MAC_LEN) < 0) { |
3116 | 0 | gcry_md_write(hmac_handle, initiator, DOT11DECRYPT_MAC_LEN); |
3117 | 0 | gcry_md_write(hmac_handle, responder, DOT11DECRYPT_MAC_LEN); |
3118 | 0 | } else { |
3119 | 0 | gcry_md_write(hmac_handle, responder, DOT11DECRYPT_MAC_LEN); |
3120 | 0 | gcry_md_write(hmac_handle, initiator, DOT11DECRYPT_MAC_LEN); |
3121 | 0 | } |
3122 | 0 | gcry_md_write(hmac_handle, bssid, DOT11DECRYPT_MAC_LEN); |
3123 | 0 | gcry_md_putc(hmac_handle, 0); |
3124 | 0 | gcry_md_putc(hmac_handle, 1); |
3125 | 0 | memcpy(key_input, gcry_md_read(hmac_handle, 0), 32); |
3126 | 0 | gcry_md_close(hmac_handle); |
3127 | | |
3128 | | /* Check MIC */ |
3129 | 0 | if (gcry_mac_open(&cmac_handle, GCRY_MAC_CMAC_AES, 0, NULL)) { |
3130 | 0 | return DOT11DECRYPT_RET_UNSUCCESS; |
3131 | 0 | } |
3132 | 0 | if (gcry_mac_setkey(cmac_handle, key_input, 16)) { |
3133 | 0 | gcry_mac_close(cmac_handle); |
3134 | 0 | return DOT11DECRYPT_RET_UNSUCCESS; |
3135 | 0 | } |
3136 | 0 | gcry_mac_write(cmac_handle, initiator, DOT11DECRYPT_MAC_LEN); |
3137 | 0 | gcry_mac_write(cmac_handle, responder, DOT11DECRYPT_MAC_LEN); |
3138 | 0 | gcry_mac_write(cmac_handle, &seq_num, 1); |
3139 | 0 | gcry_mac_write(cmac_handle, &data[offset_link], data[offset_link + 1] + 2); |
3140 | 0 | gcry_mac_write(cmac_handle, &data[offset_rsne], data[offset_rsne + 1] + 2); |
3141 | 0 | gcry_mac_write(cmac_handle, &data[offset_timeout], data[offset_timeout + 1] + 2); |
3142 | 0 | gcry_mac_write(cmac_handle, &data[offset_fte], 4); |
3143 | 0 | gcry_mac_write(cmac_handle, zeros, 16); |
3144 | 0 | cmac_write_len = data[offset_fte + 1] + 2; |
3145 | 0 | if (cmac_write_len < 20) { |
3146 | 0 | ws_warning("Bad MAC len"); |
3147 | 0 | gcry_mac_close(cmac_handle); |
3148 | 0 | return DOT11DECRYPT_RET_UNSUCCESS; |
3149 | 0 | } |
3150 | 0 | gcry_mac_write(cmac_handle, &data[offset_fte + 20], cmac_write_len - 20); |
3151 | 0 | if (gcry_mac_read(cmac_handle, mic, &cmac_len) != GPG_ERR_NO_ERROR) { |
3152 | 0 | ws_warning("MAC read error"); |
3153 | 0 | gcry_mac_close(cmac_handle); |
3154 | 0 | return DOT11DECRYPT_RET_UNSUCCESS; |
3155 | 0 | } |
3156 | 0 | if (memcmp(mic, &data[offset_fte + 4], 16)) { |
3157 | 0 | ws_debug("MIC verification failed"); |
3158 | 0 | gcry_mac_close(cmac_handle); |
3159 | 0 | return DOT11DECRYPT_RET_UNSUCCESS; |
3160 | 0 | } |
3161 | 0 | gcry_mac_close(cmac_handle); |
3162 | | /* TODO support other akm and ciphers? */ |
3163 | 0 | sa->wpa.akm = 2; |
3164 | 0 | sa->wpa.cipher = 4; |
3165 | 0 | sa->wpa.ptk_len = Dot11DecryptGetPtkLen(sa->wpa.akm, sa->wpa.cipher, sa->wpa.dh_group) / 8; |
3166 | 0 | memcpy(DOT11DECRYPT_GET_TK(sa->wpa.ptk, sa->wpa.akm, sa->wpa.dh_group), |
3167 | 0 | key_input + 16, Dot11DecryptGetTkLen(sa->wpa.cipher) / 8); |
3168 | 0 | memcpy(sa->wpa.nonce, snonce, DOT11DECRYPT_WPA_NONCE_LEN); |
3169 | 0 | sa->validKey = true; |
3170 | 0 | sa->wpa.key_ver = DOT11DECRYPT_WPA_KEY_VER_AES_CCMP; |
3171 | 0 | ws_debug("MIC verified"); |
3172 | 0 | return DOT11DECRYPT_RET_SUCCESS; |
3173 | 0 | } |
3174 | | |
3175 | | |
3176 | | #ifdef __cplusplus |
3177 | | } |
3178 | | #endif |
3179 | | |
3180 | | /****************************************************************************/ |
3181 | | |
3182 | | /* |
3183 | | * Editor modelines |
3184 | | * |
3185 | | * Local Variables: |
3186 | | * c-basic-offset: 4 |
3187 | | * tab-width: 8 |
3188 | | * indent-tabs-mode: nil |
3189 | | * End: |
3190 | | * |
3191 | | * ex: set shiftwidth=4 tabstop=8 expandtab: |
3192 | | * :indentSize=4:tabSize=8:noTabs=true: |
3193 | | */ |