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 #include "dot11decrypt_system.h"
19 #include "dot11decrypt_util.h"
20 #include "dot11decrypt_int.h"
21 
22 #include "dot11decrypt_debug.h"
23 #include <glib.h>
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 	((((UINT64)((UINT16)((b4 << 0) | (b5 << 8)))) << 32) | \
34 	    ((UINT32)((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 */
ccmp_construct_nonce(PDOT11DECRYPT_MAC_FRAME wh,guint64 pn,guint8 nonce[13])44 static void ccmp_construct_nonce(
45 	PDOT11DECRYPT_MAC_FRAME wh,
46 	guint64 pn,
47 	guint8 nonce[13])
48 {
49 	guint8 mgmt = (DOT11DECRYPT_TYPE(wh->fc[0]) == DOT11DECRYPT_TYPE_MANAGEMENT);
50 
51 	if (DOT11DECRYPT_IS_4ADDRESS(wh) && DOT11DECRYPT_IS_QOS_DATA(wh)) {
52 		PDOT11DECRYPT_MAC_FRAME_ADDR4_QOS qwh4 =
53 			(PDOT11DECRYPT_MAC_FRAME_ADDR4_QOS) wh;
54 		nonce[0] = (UINT8)(qwh4->qos[0] & 0x0f);/* just priority bits */
55 	} else if (DOT11DECRYPT_IS_QOS_DATA(wh)) {
56 		PDOT11DECRYPT_MAC_FRAME_QOS qwh =
57 			(PDOT11DECRYPT_MAC_FRAME_QOS) wh;
58 			nonce[0] = (UINT8)(qwh->qos[0] & 0x0f); /* just priority bits */
59 	} else {
60 		nonce[0] = 0;
61 	}
62 	if (mgmt) {
63 		nonce[0] |= 0x10; /* set MGMT flag */
64 	}
65 
66 	DOT11DECRYPT_ADDR_COPY(nonce + 1, wh->addr2);
67 	nonce[7] = (UINT8)(pn >> 40);
68 	nonce[8] = (UINT8)(pn >> 32);
69 	nonce[9] = (UINT8)(pn >> 24);
70 	nonce[10] = (UINT8)(pn >> 16);
71 	nonce[11] = (UINT8)(pn >> 8);
72 	nonce[12] = (UINT8)(pn >> 0);
73 }
74 
Dot11DecryptCcmpDecrypt(guint8 * m,int mac_header_len,int len,guint8 * TK1,int tk_len,int mic_len)75 int Dot11DecryptCcmpDecrypt(
76 	guint8 *m,
77 	int mac_header_len,
78 	int len,
79 	guint8 *TK1,
80 	int tk_len,
81 	int mic_len)
82 {
83 	PDOT11DECRYPT_MAC_FRAME wh;
84 	guint8 aad[30]; /* Max aad_len. See Table 12-1 IEEE 802.11 2016 */
85 	guint8 nonce[13];
86 	guint8 mic[16]; /* Big enough for CCMP-256 */
87 	ssize_t data_len;
88 	size_t aad_len;
89 	int z = mac_header_len;
90 	gcry_cipher_hd_t handle;
91 	guint64 pn;
92 	guint8 *ivp = m + z;
93 
94 	wh = (PDOT11DECRYPT_MAC_FRAME )m;
95 	data_len = len - (z + DOT11DECRYPT_CCMP_HEADER + mic_len);
96 	if (data_len < 1) {
97 		return 0;
98 	}
99 
100 	memcpy(mic, m + len - mic_len, mic_len);
101 	pn = READ_6(ivp[0], ivp[1], ivp[4], ivp[5], ivp[6], ivp[7]);
102 	ccmp_construct_nonce(wh, pn, nonce);
103 	dot11decrypt_construct_aad(wh, aad, &aad_len);
104 
105 	if (gcry_cipher_open(&handle, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CCM, 0)) {
106 		return 1;
107 	}
108 	if (gcry_cipher_setkey(handle, TK1, tk_len)) {
109 		goto err_out;
110 	}
111 	if (gcry_cipher_setiv(handle, nonce, sizeof(nonce))) {
112 		goto err_out;
113 	}
114 
115 	guint64 ccm_lengths[3];
116 	ccm_lengths[0] = data_len;
117 	ccm_lengths[1] = aad_len;
118 	ccm_lengths[2] = mic_len;
119 	if (gcry_cipher_ctl(handle, GCRYCTL_SET_CCM_LENGTHS, ccm_lengths, sizeof(ccm_lengths))) {
120 		goto err_out;
121 	}
122 	if (gcry_cipher_authenticate(handle, aad, aad_len)) {
123 		goto err_out;
124 	}
125 	if (gcry_cipher_decrypt(handle, m + z + DOT11DECRYPT_CCMP_HEADER, data_len, NULL, 0)) {
126 		goto err_out;
127 	}
128 	if (gcry_cipher_checktag(handle, mic, mic_len)) {
129 		goto err_out;
130 	}
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 	gcry_cipher_close(handle);
136 	return 0;
137 err_out:
138 	gcry_cipher_close(handle);
139 	return 1;
140 }
141