1 /*
2  * CTR with CBC-MAC Protocol (CCMP)
3  * Copyright (c) 2010-2012, Jouni Malinen <j@w1.fi>
4  *
5  * This software may be distributed under the terms of the BSD license.
6  * See README for more details.
7  */
8 
9 #include "utils/includes.h"
10 
11 #include "utils/common.h"
12 #include "common/ieee802_11_defs.h"
13 #include "crypto/aes.h"
14 #include "crypto/aes_wrap.h"
15 #include "wlantest.h"
16 
17 
ccmp_aad_nonce(const struct ieee80211_hdr * hdr,const u8 * data,u8 * aad,size_t * aad_len,u8 * nonce)18 static void ccmp_aad_nonce(const struct ieee80211_hdr *hdr, const u8 *data,
19 			   u8 *aad, size_t *aad_len, u8 *nonce)
20 {
21 	u16 fc, stype, seq;
22 	int qos = 0, addr4 = 0;
23 	u8 *pos;
24 
25 	nonce[0] = 0;
26 
27 	fc = le_to_host16(hdr->frame_control);
28 	stype = WLAN_FC_GET_STYPE(fc);
29 	if ((fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) ==
30 	    (WLAN_FC_TODS | WLAN_FC_FROMDS))
31 		addr4 = 1;
32 
33 	if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_DATA) {
34 		fc &= ~0x0070; /* Mask subtype bits */
35 		if (stype & 0x08) {
36 			const u8 *qc;
37 			qos = 1;
38 			fc &= ~WLAN_FC_HTC;
39 			qc = (const u8 *) (hdr + 1);
40 			if (addr4)
41 				qc += ETH_ALEN;
42 			nonce[0] = qc[0] & 0x0f;
43 		}
44 	} else if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT)
45 		nonce[0] |= 0x10; /* Management */
46 
47 	fc &= ~(WLAN_FC_RETRY | WLAN_FC_PWRMGT | WLAN_FC_MOREDATA);
48 	fc |= WLAN_FC_ISWEP;
49 	WPA_PUT_LE16(aad, fc);
50 	pos = aad + 2;
51 	os_memcpy(pos, hdr->addr1, 3 * ETH_ALEN);
52 	pos += 3 * ETH_ALEN;
53 	seq = le_to_host16(hdr->seq_ctrl);
54 	seq &= ~0xfff0; /* Mask Seq#; do not modify Frag# */
55 	WPA_PUT_LE16(pos, seq);
56 	pos += 2;
57 
58 	os_memcpy(pos, hdr + 1, addr4 * ETH_ALEN + qos * 2);
59 	pos += addr4 * ETH_ALEN;
60 	if (qos) {
61 		pos[0] &= ~0x70;
62 		if (1 /* FIX: either device has SPP A-MSDU Capab = 0 */)
63 			pos[0] &= ~0x80;
64 		pos++;
65 		*pos++ = 0x00;
66 	}
67 
68 	*aad_len = pos - aad;
69 
70 	os_memcpy(nonce + 1, hdr->addr2, ETH_ALEN);
71 	nonce[7] = data[7]; /* PN5 */
72 	nonce[8] = data[6]; /* PN4 */
73 	nonce[9] = data[5]; /* PN3 */
74 	nonce[10] = data[4]; /* PN2 */
75 	nonce[11] = data[1]; /* PN1 */
76 	nonce[12] = data[0]; /* PN0 */
77 }
78 
79 
ccmp_aad_nonce_pv1(const u8 * hdr,const u8 * a1,const u8 * a2,const u8 * a3,const u8 * pn,u8 * aad,size_t * aad_len,u8 * nonce)80 static void ccmp_aad_nonce_pv1(const u8 *hdr, const u8 *a1, const u8 *a2,
81 			       const u8 *a3, const u8 *pn,
82 			       u8 *aad, size_t *aad_len, u8 *nonce)
83 {
84 	u16 fc, type;
85 	u8 *pos;
86 
87 	nonce[0] = BIT(5); /* PV1 */
88 	/* TODO: Priority for QMF; 0 is used for Data frames */
89 
90 	fc = WPA_GET_LE16(hdr);
91 	type = (fc & (BIT(2) | BIT(3) | BIT(4))) >> 2;
92 
93 	if (type == 1)
94 		nonce[0] |= 0x10; /* Management */
95 
96 	fc &= ~(BIT(10) | BIT(11) | BIT(13) | BIT(14) | BIT(15));
97 	fc |= BIT(12);
98 	WPA_PUT_LE16(aad, fc);
99 	pos = aad + 2;
100 	if (type == 0 || type == 3) {
101 		const u8 *sc;
102 
103 		os_memcpy(pos, a1, ETH_ALEN);
104 		pos += ETH_ALEN;
105 		os_memcpy(pos, a2, ETH_ALEN);
106 		pos += ETH_ALEN;
107 
108 		if (type == 0) {
109 			/* Either A1 or A2 contains SID */
110 			sc = hdr + 2 + 2 + ETH_ALEN;
111 		} else {
112 			/* Both A1 and A2 contain full addresses */
113 			sc = hdr + 2 + 2 * ETH_ALEN;
114 		}
115 		/* SC with Sequence Number subfield (bits 4-15 of the Sequence
116 		 * Control field) masked to 0. */
117 		*pos++ = *sc & 0x0f;
118 		*pos++ = 0;
119 
120 		if (a3) {
121 			os_memcpy(pos, a3, ETH_ALEN);
122 			pos += ETH_ALEN;
123 		}
124 	}
125 
126 	*aad_len = pos - aad;
127 
128 	os_memcpy(nonce + 1, a2, ETH_ALEN);
129 	nonce[7] = pn[5]; /* PN5 */
130 	nonce[8] = pn[4]; /* PN4 */
131 	nonce[9] = pn[3]; /* PN3 */
132 	nonce[10] = pn[2]; /* PN2 */
133 	nonce[11] = pn[1]; /* PN1 */
134 	nonce[12] = pn[0]; /* PN0 */
135 }
136 
137 
ccmp_decrypt(const u8 * tk,const struct ieee80211_hdr * hdr,const u8 * data,size_t data_len,size_t * decrypted_len)138 u8 * ccmp_decrypt(const u8 *tk, const struct ieee80211_hdr *hdr,
139 		  const u8 *data, size_t data_len, size_t *decrypted_len)
140 {
141 	u8 aad[30], nonce[13];
142 	size_t aad_len;
143 	size_t mlen;
144 	u8 *plain;
145 
146 	if (data_len < 8 + 8)
147 		return NULL;
148 
149 	plain = os_malloc(data_len + AES_BLOCK_SIZE);
150 	if (plain == NULL)
151 		return NULL;
152 
153 	mlen = data_len - 8 - 8;
154 
155 	os_memset(aad, 0, sizeof(aad));
156 	ccmp_aad_nonce(hdr, data, aad, &aad_len, nonce);
157 	wpa_hexdump(MSG_EXCESSIVE, "CCMP AAD", aad, aad_len);
158 	wpa_hexdump(MSG_EXCESSIVE, "CCMP nonce", nonce, 13);
159 
160 	if (aes_ccm_ad(tk, 16, nonce, 8, data + 8, mlen, aad, aad_len,
161 		       data + 8 + mlen, plain) < 0) {
162 		u16 seq_ctrl = le_to_host16(hdr->seq_ctrl);
163 		wpa_printf(MSG_INFO, "Invalid CCMP MIC in frame: A1=" MACSTR
164 			   " A2=" MACSTR " A3=" MACSTR " seq=%u frag=%u",
165 			   MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
166 			   MAC2STR(hdr->addr3),
167 			   WLAN_GET_SEQ_SEQ(seq_ctrl),
168 			   WLAN_GET_SEQ_FRAG(seq_ctrl));
169 		os_free(plain);
170 		return NULL;
171 	}
172 	wpa_hexdump(MSG_EXCESSIVE, "CCMP decrypted", plain, mlen);
173 
174 	*decrypted_len = mlen;
175 	return plain;
176 }
177 
178 
ccmp_get_pn(u8 * pn,const u8 * data)179 void ccmp_get_pn(u8 *pn, const u8 *data)
180 {
181 	pn[0] = data[7]; /* PN5 */
182 	pn[1] = data[6]; /* PN4 */
183 	pn[2] = data[5]; /* PN3 */
184 	pn[3] = data[4]; /* PN2 */
185 	pn[4] = data[1]; /* PN1 */
186 	pn[5] = data[0]; /* PN0 */
187 }
188 
189 
ccmp_encrypt(const u8 * tk,u8 * frame,size_t len,size_t hdrlen,u8 * qos,u8 * pn,int keyid,size_t * encrypted_len)190 u8 * ccmp_encrypt(const u8 *tk, u8 *frame, size_t len, size_t hdrlen, u8 *qos,
191 		  u8 *pn, int keyid, size_t *encrypted_len)
192 {
193 	u8 aad[30], nonce[13];
194 	size_t aad_len, plen;
195 	u8 *crypt, *pos;
196 	struct ieee80211_hdr *hdr;
197 
198 	if (len < hdrlen || hdrlen < 24)
199 		return NULL;
200 	plen = len - hdrlen;
201 
202 	crypt = os_malloc(hdrlen + 8 + plen + 8 + AES_BLOCK_SIZE);
203 	if (crypt == NULL)
204 		return NULL;
205 
206 	os_memcpy(crypt, frame, hdrlen);
207 	hdr = (struct ieee80211_hdr *) crypt;
208 	hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP);
209 	pos = crypt + hdrlen;
210 	*pos++ = pn[5]; /* PN0 */
211 	*pos++ = pn[4]; /* PN1 */
212 	*pos++ = 0x00; /* Rsvd */
213 	*pos++ = 0x20 | (keyid << 6);
214 	*pos++ = pn[3]; /* PN2 */
215 	*pos++ = pn[2]; /* PN3 */
216 	*pos++ = pn[1]; /* PN4 */
217 	*pos++ = pn[0]; /* PN5 */
218 
219 	os_memset(aad, 0, sizeof(aad));
220 	ccmp_aad_nonce(hdr, crypt + hdrlen, aad, &aad_len, nonce);
221 	wpa_hexdump(MSG_EXCESSIVE, "CCMP AAD", aad, aad_len);
222 	wpa_hexdump(MSG_EXCESSIVE, "CCMP nonce", nonce, 13);
223 
224 	if (aes_ccm_ae(tk, 16, nonce, 8, frame + hdrlen, plen, aad, aad_len,
225 		       pos, pos + plen) < 0) {
226 		os_free(crypt);
227 		return NULL;
228 	}
229 
230 	wpa_hexdump(MSG_EXCESSIVE, "CCMP encrypted", crypt + hdrlen + 8, plen);
231 
232 	*encrypted_len = hdrlen + 8 + plen + 8;
233 
234 	return crypt;
235 }
236 
237 
ccmp_encrypt_pv1(const u8 * tk,const u8 * a1,const u8 * a2,const u8 * a3,const u8 * frame,size_t len,size_t hdrlen,const u8 * pn,int keyid,size_t * encrypted_len)238 u8 * ccmp_encrypt_pv1(const u8 *tk, const u8 *a1, const u8 *a2, const u8 *a3,
239 		      const u8 *frame, size_t len,
240 		      size_t hdrlen, const u8 *pn, int keyid,
241 		      size_t *encrypted_len)
242 {
243 	u8 aad[24], nonce[13];
244 	size_t aad_len, plen;
245 	u8 *crypt, *pos;
246 	struct ieee80211_hdr *hdr;
247 
248 	if (len < hdrlen || hdrlen < 12)
249 		return NULL;
250 	plen = len - hdrlen;
251 
252 	crypt = os_malloc(hdrlen + plen + 8 + AES_BLOCK_SIZE);
253 	if (crypt == NULL)
254 		return NULL;
255 
256 	os_memcpy(crypt, frame, hdrlen);
257 	hdr = (struct ieee80211_hdr *) crypt;
258 	hdr->frame_control |= host_to_le16(BIT(12)); /* Protected Frame */
259 	pos = crypt + hdrlen;
260 
261 	os_memset(aad, 0, sizeof(aad));
262 	ccmp_aad_nonce_pv1(crypt, a1, a2, a3, pn, aad, &aad_len, nonce);
263 	wpa_hexdump(MSG_EXCESSIVE, "CCMP AAD", aad, aad_len);
264 	wpa_hexdump(MSG_EXCESSIVE, "CCMP nonce", nonce, sizeof(nonce));
265 
266 	if (aes_ccm_ae(tk, 16, nonce, 8, frame + hdrlen, plen, aad, aad_len,
267 		       pos, pos + plen) < 0) {
268 		os_free(crypt);
269 		return NULL;
270 	}
271 
272 	wpa_hexdump(MSG_EXCESSIVE, "CCMP encrypted", crypt + hdrlen, plen);
273 
274 	*encrypted_len = hdrlen + plen + 8;
275 
276 	return crypt;
277 }
278 
279 
ccmp_256_decrypt(const u8 * tk,const struct ieee80211_hdr * hdr,const u8 * data,size_t data_len,size_t * decrypted_len)280 u8 * ccmp_256_decrypt(const u8 *tk, const struct ieee80211_hdr *hdr,
281 		      const u8 *data, size_t data_len, size_t *decrypted_len)
282 {
283 	u8 aad[30], nonce[13];
284 	size_t aad_len;
285 	size_t mlen;
286 	u8 *plain;
287 
288 	if (data_len < 8 + 16)
289 		return NULL;
290 
291 	plain = os_malloc(data_len + AES_BLOCK_SIZE);
292 	if (plain == NULL)
293 		return NULL;
294 
295 	mlen = data_len - 8 - 16;
296 
297 	os_memset(aad, 0, sizeof(aad));
298 	ccmp_aad_nonce(hdr, data, aad, &aad_len, nonce);
299 	wpa_hexdump(MSG_EXCESSIVE, "CCMP-256 AAD", aad, aad_len);
300 	wpa_hexdump(MSG_EXCESSIVE, "CCMP-256 nonce", nonce, 13);
301 
302 	if (aes_ccm_ad(tk, 32, nonce, 16, data + 8, mlen, aad, aad_len,
303 		       data + 8 + mlen, plain) < 0) {
304 		u16 seq_ctrl = le_to_host16(hdr->seq_ctrl);
305 		wpa_printf(MSG_INFO, "Invalid CCMP-256 MIC in frame: A1=" MACSTR
306 			   " A2=" MACSTR " A3=" MACSTR " seq=%u frag=%u",
307 			   MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
308 			   MAC2STR(hdr->addr3),
309 			   WLAN_GET_SEQ_SEQ(seq_ctrl),
310 			   WLAN_GET_SEQ_FRAG(seq_ctrl));
311 		os_free(plain);
312 		return NULL;
313 	}
314 	wpa_hexdump(MSG_EXCESSIVE, "CCMP-256 decrypted", plain, mlen);
315 
316 	*decrypted_len = mlen;
317 	return plain;
318 }
319 
320 
ccmp_256_encrypt(const u8 * tk,u8 * frame,size_t len,size_t hdrlen,u8 * qos,u8 * pn,int keyid,size_t * encrypted_len)321 u8 * ccmp_256_encrypt(const u8 *tk, u8 *frame, size_t len, size_t hdrlen,
322 		      u8 *qos, u8 *pn, int keyid, size_t *encrypted_len)
323 {
324 	u8 aad[30], nonce[13];
325 	size_t aad_len, plen;
326 	u8 *crypt, *pos;
327 	struct ieee80211_hdr *hdr;
328 
329 	if (len < hdrlen || hdrlen < 24)
330 		return NULL;
331 	plen = len - hdrlen;
332 
333 	crypt = os_malloc(hdrlen + 8 + plen + 16 + AES_BLOCK_SIZE);
334 	if (crypt == NULL)
335 		return NULL;
336 
337 	os_memcpy(crypt, frame, hdrlen);
338 	hdr = (struct ieee80211_hdr *) crypt;
339 	hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP);
340 	pos = crypt + hdrlen;
341 	*pos++ = pn[5]; /* PN0 */
342 	*pos++ = pn[4]; /* PN1 */
343 	*pos++ = 0x00; /* Rsvd */
344 	*pos++ = 0x20 | (keyid << 6);
345 	*pos++ = pn[3]; /* PN2 */
346 	*pos++ = pn[2]; /* PN3 */
347 	*pos++ = pn[1]; /* PN4 */
348 	*pos++ = pn[0]; /* PN5 */
349 
350 	os_memset(aad, 0, sizeof(aad));
351 	ccmp_aad_nonce(hdr, crypt + hdrlen, aad, &aad_len, nonce);
352 	wpa_hexdump(MSG_EXCESSIVE, "CCMP-256 AAD", aad, aad_len);
353 	wpa_hexdump(MSG_EXCESSIVE, "CCMP-256 nonce", nonce, 13);
354 
355 	if (aes_ccm_ae(tk, 32, nonce, 16, frame + hdrlen, plen, aad, aad_len,
356 		       pos, pos + plen) < 0) {
357 		os_free(crypt);
358 		return NULL;
359 	}
360 
361 	wpa_hexdump(MSG_EXCESSIVE, "CCMP-256 encrypted", crypt + hdrlen + 8,
362 		    plen);
363 
364 	*encrypted_len = hdrlen + 8 + plen + 16;
365 
366 	return crypt;
367 }
368