/src/wireshark/epan/crypt/dot11decrypt_ccmp.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* dot11decrypt_ccmp.c |
2 | | * |
3 | | * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting |
4 | | * Copyright (c) 2006 CACE Technologies, Davis (California) |
5 | | * All rights reserved. |
6 | | * |
7 | | * SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only) |
8 | | */ |
9 | | |
10 | | /* |
11 | | * Note: This file was derived from the FreeBSD source code, RELENG 6, |
12 | | * sys/net80211/ieee80211_crypto_ccmp.c |
13 | | */ |
14 | | |
15 | | /****************************************************************************/ |
16 | | /* File includes */ |
17 | | #include "config.h" |
18 | | |
19 | | #include "dot11decrypt_debug.h" |
20 | | #include "dot11decrypt_system.h" |
21 | | #include "dot11decrypt_util.h" |
22 | | #include "dot11decrypt_int.h" |
23 | | |
24 | | #include <wsutil/wsgcrypt.h> |
25 | | |
26 | | /****************************************************************************/ |
27 | | /* Internal definitions */ |
28 | | |
29 | | /****************************************************************************/ |
30 | | /* Internal macros */ |
31 | | |
32 | | #define READ_6(b0, b1, b2, b3, b4, b5) \ |
33 | 0 | ((((uint64_t)((uint16_t)((b4 << 0) | (b5 << 8)))) << 32) | \ |
34 | 0 | ((uint32_t)((b0 << 0) | (b1 << 8) | (b2 << 16) | (b3 << 24)))) |
35 | | |
36 | | /****************************************************************************/ |
37 | | /* Internal function prototypes declarations */ |
38 | | |
39 | | /****************************************************************************/ |
40 | | /* Function definitions */ |
41 | | |
42 | | /* From IEEE 802.11 2016 Chapter 12.5.3.3.4 Construct CCM nonce */ |
43 | | /* Nonce: Flags | A2 | PN */ |
44 | | static void ccmp_construct_nonce( |
45 | | PDOT11DECRYPT_MAC_FRAME wh, |
46 | | uint64_t pn, |
47 | | uint8_t nonce[13]) |
48 | 0 | { |
49 | 0 | uint8_t mgmt = (DOT11DECRYPT_TYPE(wh->fc[0]) == DOT11DECRYPT_TYPE_MANAGEMENT); |
50 | |
|
51 | 0 | if (DOT11DECRYPT_IS_4ADDRESS(wh) && DOT11DECRYPT_IS_QOS_DATA(wh)) { |
52 | 0 | PDOT11DECRYPT_MAC_FRAME_ADDR4_QOS qwh4 = |
53 | 0 | (PDOT11DECRYPT_MAC_FRAME_ADDR4_QOS) wh; |
54 | 0 | nonce[0] = (uint8_t)(qwh4->qos[0] & 0x0f);/* just priority bits */ |
55 | 0 | } else if (DOT11DECRYPT_IS_QOS_DATA(wh)) { |
56 | 0 | PDOT11DECRYPT_MAC_FRAME_QOS qwh = |
57 | 0 | (PDOT11DECRYPT_MAC_FRAME_QOS) wh; |
58 | 0 | nonce[0] = (uint8_t)(qwh->qos[0] & 0x0f); /* just priority bits */ |
59 | 0 | } else { |
60 | 0 | nonce[0] = 0; |
61 | 0 | } |
62 | 0 | if (mgmt) { |
63 | 0 | nonce[0] |= 0x10; /* set MGMT flag */ |
64 | 0 | } |
65 | |
|
66 | 0 | DOT11DECRYPT_ADDR_COPY(nonce + 1, wh->addr2); |
67 | 0 | nonce[7] = (uint8_t)(pn >> 40); |
68 | 0 | nonce[8] = (uint8_t)(pn >> 32); |
69 | 0 | nonce[9] = (uint8_t)(pn >> 24); |
70 | 0 | nonce[10] = (uint8_t)(pn >> 16); |
71 | 0 | nonce[11] = (uint8_t)(pn >> 8); |
72 | 0 | nonce[12] = (uint8_t)(pn >> 0); |
73 | 0 | } |
74 | | |
75 | | int Dot11DecryptCcmpDecrypt( |
76 | | uint8_t *m, |
77 | | int mac_header_len, |
78 | | int len, |
79 | | uint8_t *TK1, |
80 | | int tk_len, |
81 | | int mic_len) |
82 | 0 | { |
83 | 0 | PDOT11DECRYPT_MAC_FRAME wh; |
84 | 0 | uint8_t aad[30]; /* Max aad_len. See Table 12-1 IEEE 802.11 2016 */ |
85 | 0 | uint8_t nonce[13]; |
86 | 0 | uint8_t mic[16]; /* Big enough for CCMP-256 */ |
87 | 0 | ssize_t data_len; |
88 | 0 | size_t aad_len; |
89 | 0 | int z = mac_header_len; |
90 | 0 | gcry_cipher_hd_t handle; |
91 | 0 | uint64_t pn; |
92 | 0 | uint8_t *ivp = m + z; |
93 | |
|
94 | 0 | wh = (PDOT11DECRYPT_MAC_FRAME )m; |
95 | 0 | data_len = len - (z + DOT11DECRYPT_CCMP_HEADER + mic_len); |
96 | 0 | if (data_len < 1) { |
97 | 0 | return 0; |
98 | 0 | } |
99 | | |
100 | 0 | memcpy(mic, m + len - mic_len, mic_len); |
101 | 0 | pn = READ_6(ivp[0], ivp[1], ivp[4], ivp[5], ivp[6], ivp[7]); |
102 | 0 | ccmp_construct_nonce(wh, pn, nonce); |
103 | 0 | dot11decrypt_construct_aad(wh, aad, &aad_len); |
104 | |
|
105 | 0 | if (gcry_cipher_open(&handle, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CCM, 0)) { |
106 | 0 | return 1; |
107 | 0 | } |
108 | 0 | if (gcry_cipher_setkey(handle, TK1, tk_len)) { |
109 | 0 | goto err_out; |
110 | 0 | } |
111 | 0 | if (gcry_cipher_setiv(handle, nonce, sizeof(nonce))) { |
112 | 0 | goto err_out; |
113 | 0 | } |
114 | | |
115 | 0 | uint64_t ccm_lengths[3]; |
116 | 0 | ccm_lengths[0] = data_len; |
117 | 0 | ccm_lengths[1] = aad_len; |
118 | 0 | ccm_lengths[2] = mic_len; |
119 | 0 | if (gcry_cipher_ctl(handle, GCRYCTL_SET_CCM_LENGTHS, ccm_lengths, sizeof(ccm_lengths))) { |
120 | 0 | goto err_out; |
121 | 0 | } |
122 | 0 | if (gcry_cipher_authenticate(handle, aad, aad_len)) { |
123 | 0 | goto err_out; |
124 | 0 | } |
125 | 0 | if (gcry_cipher_decrypt(handle, m + z + DOT11DECRYPT_CCMP_HEADER, data_len, NULL, 0)) { |
126 | 0 | goto err_out; |
127 | 0 | } |
128 | 0 | if (gcry_cipher_checktag(handle, mic, mic_len)) { |
129 | 0 | goto err_out; |
130 | 0 | } |
131 | | |
132 | | /* TODO replay check (IEEE 802.11i-2004, pg. 62) */ |
133 | | /* TODO PN must be incremental (IEEE 802.11i-2004, pg. 62) */ |
134 | | |
135 | 0 | gcry_cipher_close(handle); |
136 | 0 | return 0; |
137 | 0 | err_out: |
138 | 0 | gcry_cipher_close(handle); |
139 | 0 | return 1; |
140 | 0 | } |