wpa.c 13.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14
/*
 * Copyright 2002-2004, Instant802 Networks, Inc.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */

#include <linux/netdevice.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/skbuff.h>
#include <linux/compiler.h>
#include <net/mac80211.h>
J
Johannes Berg 已提交
15

16 17 18 19 20 21 22 23 24 25 26
#include "ieee80211_i.h"
#include "michael.h"
#include "tkip.h"
#include "aes_ccm.h"
#include "wpa.h"

static int ieee80211_get_hdr_info(const struct sk_buff *skb, u8 **sa, u8 **da,
				  u8 *qos_tid, u8 **data, size_t *data_len)
{
	struct ieee80211_hdr *hdr;
	size_t hdrlen;
27
	__le16 fc;
28

29 30
	hdr = (struct ieee80211_hdr *)skb->data;
	fc = hdr->frame_control;
31

32 33 34 35
	hdrlen = ieee80211_hdrlen(fc);

	*sa = ieee80211_get_SA(hdr);
	*da = ieee80211_get_DA(hdr);
36 37 38 39

	*data = skb->data + hdrlen;
	*data_len = skb->len - hdrlen;

40 41 42
	if (ieee80211_is_data_qos(fc))
		*qos_tid = (*ieee80211_get_qos_ctl(hdr) & 0x0f) | 0x80;
	else
43 44 45 46 47 48
		*qos_tid = 0;

	return skb->len < hdrlen ? -1 : 0;
}


49
ieee80211_tx_result
50
ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx)
51 52 53 54 55 56 57
{
	u8 *data, *sa, *da, *key, *mic, qos_tid;
	size_t data_len;
	u16 fc;
	struct sk_buff *skb = tx->skb;
	int authenticator;
	int wpa_test = 0;
58
	int tail;
59 60 61

	fc = tx->fc;

62
	if (!tx->key || tx->key->conf.alg != ALG_TKIP || skb->len < 24 ||
63
	    !WLAN_FC_DATA_PRESENT(fc))
64
		return TX_CONTINUE;
65 66

	if (ieee80211_get_hdr_info(skb, &sa, &da, &qos_tid, &data, &data_len))
67
		return TX_DROP;
68

J
Johannes Berg 已提交
69
	if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) &&
70
	    !(tx->flags & IEEE80211_TX_FRAGMENTED) &&
71
	    !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) &&
72 73 74
	    !wpa_test) {
		/* hwaccel - with no need for preallocated room for Michael MIC
		 */
75
		return TX_CONTINUE;
76 77
	}

78 79 80 81 82 83 84
	tail = MICHAEL_MIC_LEN;
	if (!(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
		tail += TKIP_ICV_LEN;

	if (WARN_ON(skb_tailroom(skb) < tail ||
		    skb_headroom(skb) < TKIP_IV_LEN))
		return TX_DROP;
85 86 87 88 89 90

#if 0
	authenticator = fc & IEEE80211_FCTL_FROMDS; /* FIX */
#else
	authenticator = 1;
#endif
91 92
	key = &tx->key->conf.key[authenticator ? ALG_TKIP_TEMP_AUTH_TX_MIC_KEY :
				 ALG_TKIP_TEMP_AUTH_RX_MIC_KEY];
93 94 95
	mic = skb_put(skb, MICHAEL_MIC_LEN);
	michael_mic(key, da, sa, qos_tid & 0x0f, data, data_len, mic);

96
	return TX_CONTINUE;
97 98 99
}


100
ieee80211_rx_result
101
ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx)
102 103 104 105 106 107 108
{
	u8 *data, *sa, *da, *key = NULL, qos_tid;
	size_t data_len;
	u16 fc;
	u8 mic[MICHAEL_MIC_LEN];
	struct sk_buff *skb = rx->skb;
	int authenticator = 1, wpa_test = 0;
109
	DECLARE_MAC_BUF(mac);
110 111 112

	fc = rx->fc;

113 114 115
	/*
	 * No way to verify the MIC if the hardware stripped it
	 */
116
	if (rx->status->flag & RX_FLAG_MMIC_STRIPPED)
117
		return RX_CONTINUE;
118

119
	if (!rx->key || rx->key->conf.alg != ALG_TKIP ||
120
	    !(rx->fc & IEEE80211_FCTL_PROTECTED) || !WLAN_FC_DATA_PRESENT(fc))
121
		return RX_CONTINUE;
122 123 124

	if (ieee80211_get_hdr_info(skb, &sa, &da, &qos_tid, &data, &data_len)
	    || data_len < MICHAEL_MIC_LEN)
J
Johannes Berg 已提交
125
		return RX_DROP_UNUSABLE;
126 127 128 129 130 131 132 133

	data_len -= MICHAEL_MIC_LEN;

#if 0
	authenticator = fc & IEEE80211_FCTL_TODS; /* FIX */
#else
	authenticator = 1;
#endif
134 135
	key = &rx->key->conf.key[authenticator ? ALG_TKIP_TEMP_AUTH_RX_MIC_KEY :
				 ALG_TKIP_TEMP_AUTH_TX_MIC_KEY];
136 137
	michael_mic(key, da, sa, qos_tid & 0x0f, data, data_len, mic);
	if (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0 || wpa_test) {
138
		if (!(rx->flags & IEEE80211_RX_RA_MATCH))
J
Johannes Berg 已提交
139
			return RX_DROP_UNUSABLE;
140 141

		printk(KERN_DEBUG "%s: invalid Michael MIC in data frame from "
142
		       "%s\n", rx->dev->name, print_mac(mac, sa));
143

144
		mac80211_ev_michael_mic_failure(rx->dev, rx->key->conf.keyidx,
J
Johannes Berg 已提交
145
						(void *) skb->data);
J
Johannes Berg 已提交
146
		return RX_DROP_UNUSABLE;
147 148 149 150 151
	}

	/* remove Michael MIC from payload */
	skb_trim(skb, skb->len - MICHAEL_MIC_LEN);

152
	/* update IV in key information to be able to detect replays */
153 154
	rx->key->u.tkip.rx[rx->queue].iv32 = rx->tkip_iv32;
	rx->key->u.tkip.rx[rx->queue].iv16 = rx->tkip_iv16;
155

156
	return RX_CONTINUE;
157 158 159
}


160
static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
161 162 163
{
	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
	struct ieee80211_key *key = tx->key;
164
	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
165 166
	unsigned int hdrlen;
	int len, tail;
167 168
	u8 *pos;

169 170 171 172 173 174 175
	info->control.icv_len = TKIP_ICV_LEN;
	info->control.iv_len = TKIP_IV_LEN;

	if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) &&
	    !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) {
		/* hwaccel - with no need for preallocated room for IV/ICV */
		info->control.hw_key = &tx->key->conf;
176
		return 0;
177 178
	}

179
	hdrlen = ieee80211_hdrlen(hdr->frame_control);
180 181
	len = skb->len - hdrlen;

J
Johannes Berg 已提交
182
	if (tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)
183
		tail = 0;
J
Johannes Berg 已提交
184
	else
185 186 187 188 189
		tail = TKIP_ICV_LEN;

	if (WARN_ON(skb_tailroom(skb) < tail ||
		    skb_headroom(skb) < TKIP_IV_LEN))
		return -1;
190 191 192 193 194 195

	pos = skb_push(skb, TKIP_IV_LEN);
	memmove(pos, pos + TKIP_IV_LEN, hdrlen);
	pos += hdrlen;

	/* Increase IV for the frame */
196 197 198
	key->u.tkip.tx.iv16++;
	if (key->u.tkip.tx.iv16 == 0)
		key->u.tkip.tx.iv32++;
199

J
Johannes Berg 已提交
200
	if (tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) {
201
		/* hwaccel - with preallocated room for IV */
202
		ieee80211_tkip_add_iv(pos, key, key->u.tkip.tx.iv16);
203

204
		info->control.hw_key = &tx->key->conf;
205 206 207 208 209 210 211 212 213 214 215 216 217
		return 0;
	}

	/* Add room for ICV */
	skb_put(skb, TKIP_ICV_LEN);

	hdr = (struct ieee80211_hdr *) skb->data;
	ieee80211_tkip_encrypt_data(tx->local->wep_tx_tfm,
				    key, pos, len, hdr->addr2);
	return 0;
}


218
ieee80211_tx_result
219
ieee80211_crypto_tkip_encrypt(struct ieee80211_tx_data *tx)
220 221 222
{
	struct sk_buff *skb = tx->skb;

223
	ieee80211_tx_set_protected(tx);
224

225
	if (tkip_encrypt_skb(tx, skb) < 0)
226
		return TX_DROP;
227

228
	if (tx->extra_frag) {
229
		int i;
230
		for (i = 0; i < tx->num_extra_frag; i++) {
231
			if (tkip_encrypt_skb(tx, tx->extra_frag[i]) < 0)
232
				return TX_DROP;
233 234 235
		}
	}

236
	return TX_CONTINUE;
237 238 239
}


240
ieee80211_rx_result
241
ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx)
242 243 244 245 246
{
	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
	int hdrlen, res, hwaccel = 0, wpa_test = 0;
	struct ieee80211_key *key = rx->key;
	struct sk_buff *skb = rx->skb;
247
	DECLARE_MAC_BUF(mac);
248

249
	hdrlen = ieee80211_hdrlen(hdr->frame_control);
250

251
	if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)
252
		return RX_CONTINUE;
253 254

	if (!rx->sta || skb->len - hdrlen < 12)
J
Johannes Berg 已提交
255
		return RX_DROP_UNUSABLE;
256

257 258
	if (rx->status->flag & RX_FLAG_DECRYPTED) {
		if (rx->status->flag & RX_FLAG_IV_STRIPPED) {
259 260 261 262 263
			/*
			 * Hardware took care of all processing, including
			 * replay protection, and stripped the ICV/IV so
			 * we cannot do any checks here.
			 */
264
			return RX_CONTINUE;
265 266 267 268 269 270 271 272 273
		}

		/* let TKIP code verify IV, but skip decryption */
		hwaccel = 1;
	}

	res = ieee80211_tkip_decrypt_data(rx->local->wep_rx_tfm,
					  key, skb->data + hdrlen,
					  skb->len - hdrlen, rx->sta->addr,
274
					  hdr->addr1, hwaccel, rx->queue,
275 276
					  &rx->tkip_iv32,
					  &rx->tkip_iv16);
277
	if (res != TKIP_DECRYPT_OK || wpa_test) {
278 279 280 281 282 283
#ifdef CONFIG_MAC80211_DEBUG
		if (net_ratelimit())
			printk(KERN_DEBUG "%s: TKIP decrypt failed for RX "
			       "frame from %s (res=%d)\n", rx->dev->name,
			       print_mac(mac, rx->sta->addr), res);
#endif /* CONFIG_MAC80211_DEBUG */
J
Johannes Berg 已提交
284
		return RX_DROP_UNUSABLE;
285 286 287 288 289 290 291 292 293
	}

	/* Trim ICV */
	skb_trim(skb, skb->len - TKIP_ICV_LEN);

	/* Remove IV */
	memmove(skb->data + TKIP_IV_LEN, skb->data, hdrlen);
	skb_pull(skb, TKIP_IV_LEN);

294
	return RX_CONTINUE;
295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390
}


static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *b_0, u8 *aad,
				int encrypted)
{
	u16 fc;
	int a4_included, qos_included;
	u8 qos_tid, *fc_pos, *data, *sa, *da;
	int len_a;
	size_t data_len;
	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;

	fc_pos = (u8 *) &hdr->frame_control;
	fc = fc_pos[0] ^ (fc_pos[1] << 8);
	a4_included = (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
		(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS);

	ieee80211_get_hdr_info(skb, &sa, &da, &qos_tid, &data, &data_len);
	data_len -= CCMP_HDR_LEN + (encrypted ? CCMP_MIC_LEN : 0);
	if (qos_tid & 0x80) {
		qos_included = 1;
		qos_tid &= 0x0f;
	} else
		qos_included = 0;
	/* First block, b_0 */

	b_0[0] = 0x59; /* flags: Adata: 1, M: 011, L: 001 */
	/* Nonce: QoS Priority | A2 | PN */
	b_0[1] = qos_tid;
	memcpy(&b_0[2], hdr->addr2, 6);
	memcpy(&b_0[8], pn, CCMP_PN_LEN);
	/* l(m) */
	b_0[14] = (data_len >> 8) & 0xff;
	b_0[15] = data_len & 0xff;


	/* AAD (extra authenticate-only data) / masked 802.11 header
	 * FC | A1 | A2 | A3 | SC | [A4] | [QC] */

	len_a = a4_included ? 28 : 22;
	if (qos_included)
		len_a += 2;

	aad[0] = 0; /* (len_a >> 8) & 0xff; */
	aad[1] = len_a & 0xff;
	/* Mask FC: zero subtype b4 b5 b6 */
	aad[2] = fc_pos[0] & ~(BIT(4) | BIT(5) | BIT(6));
	/* Retry, PwrMgt, MoreData; set Protected */
	aad[3] = (fc_pos[1] & ~(BIT(3) | BIT(4) | BIT(5))) | BIT(6);
	memcpy(&aad[4], &hdr->addr1, 18);

	/* Mask Seq#, leave Frag# */
	aad[22] = *((u8 *) &hdr->seq_ctrl) & 0x0f;
	aad[23] = 0;
	if (a4_included) {
		memcpy(&aad[24], hdr->addr4, 6);
		aad[30] = 0;
		aad[31] = 0;
	} else
		memset(&aad[24], 0, 8);
	if (qos_included) {
		u8 *dpos = &aad[a4_included ? 30 : 24];

		/* Mask QoS Control field */
		dpos[0] = qos_tid;
		dpos[1] = 0;
	}
}


static inline void ccmp_pn2hdr(u8 *hdr, u8 *pn, int key_id)
{
	hdr[0] = pn[5];
	hdr[1] = pn[4];
	hdr[2] = 0;
	hdr[3] = 0x20 | (key_id << 6);
	hdr[4] = pn[3];
	hdr[5] = pn[2];
	hdr[6] = pn[1];
	hdr[7] = pn[0];
}


static inline int ccmp_hdr2pn(u8 *pn, u8 *hdr)
{
	pn[0] = hdr[7];
	pn[1] = hdr[6];
	pn[2] = hdr[5];
	pn[3] = hdr[4];
	pn[4] = hdr[1];
	pn[5] = hdr[0];
	return (hdr[3] >> 6) & 0x03;
}


391
static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
392 393 394
{
	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
	struct ieee80211_key *key = tx->key;
395
	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
396
	int hdrlen, len, tail;
397 398 399
	u8 *pos, *pn, *b_0, *aad, *scratch;
	int i;

400 401 402 403 404 405 406 407
	info->control.icv_len = CCMP_MIC_LEN;
	info->control.iv_len = CCMP_HDR_LEN;

	if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) &&
	    !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) {
		/* hwaccel - with no need for preallocated room for CCMP "
		 * header or MIC fields */
		info->control.hw_key = &tx->key->conf;
408
		return 0;
409 410
	}

411 412 413 414
	scratch = key->u.ccmp.tx_crypto_buf;
	b_0 = scratch + 3 * AES_BLOCK_LEN;
	aad = scratch + 4 * AES_BLOCK_LEN;

415
	hdrlen = ieee80211_hdrlen(hdr->frame_control);
416 417
	len = skb->len - hdrlen;

J
Johannes Berg 已提交
418
	if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)
419
		tail = 0;
J
Johannes Berg 已提交
420
	else
421 422 423 424 425
		tail = CCMP_MIC_LEN;

	if (WARN_ON(skb_tailroom(skb) < tail ||
		    skb_headroom(skb) < CCMP_HDR_LEN))
		return -1;
426 427 428 429 430 431 432 433 434 435 436 437 438 439 440

	pos = skb_push(skb, CCMP_HDR_LEN);
	memmove(pos, pos + CCMP_HDR_LEN, hdrlen);
	hdr = (struct ieee80211_hdr *) pos;
	pos += hdrlen;

	/* PN = PN + 1 */
	pn = key->u.ccmp.tx_pn;

	for (i = CCMP_PN_LEN - 1; i >= 0; i--) {
		pn[i]++;
		if (pn[i])
			break;
	}

441
	ccmp_pn2hdr(pos, pn, key->conf.keyidx);
442

J
Johannes Berg 已提交
443
	if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) {
444
		/* hwaccel - with preallocated room for CCMP header */
445
		info->control.hw_key = &tx->key->conf;
446 447 448 449 450 451 452 453 454 455 456 457
		return 0;
	}

	pos += CCMP_HDR_LEN;
	ccmp_special_blocks(skb, pn, b_0, aad, 0);
	ieee80211_aes_ccm_encrypt(key->u.ccmp.tfm, scratch, b_0, aad, pos, len,
				  pos, skb_put(skb, CCMP_MIC_LEN));

	return 0;
}


458
ieee80211_tx_result
459
ieee80211_crypto_ccmp_encrypt(struct ieee80211_tx_data *tx)
460 461 462
{
	struct sk_buff *skb = tx->skb;

463
	ieee80211_tx_set_protected(tx);
464

465
	if (ccmp_encrypt_skb(tx, skb) < 0)
466
		return TX_DROP;
467

468
	if (tx->extra_frag) {
469
		int i;
470
		for (i = 0; i < tx->num_extra_frag; i++) {
471
			if (ccmp_encrypt_skb(tx, tx->extra_frag[i]) < 0)
472
				return TX_DROP;
473 474 475
		}
	}

476
	return TX_CONTINUE;
477 478 479
}


480
ieee80211_rx_result
481
ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx)
482 483 484 485 486 487 488
{
	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
	int hdrlen;
	struct ieee80211_key *key = rx->key;
	struct sk_buff *skb = rx->skb;
	u8 pn[CCMP_PN_LEN];
	int data_len;
489
	DECLARE_MAC_BUF(mac);
490

491
	hdrlen = ieee80211_hdrlen(hdr->frame_control);
492

493
	if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)
494
		return RX_CONTINUE;
495 496 497

	data_len = skb->len - hdrlen - CCMP_HDR_LEN - CCMP_MIC_LEN;
	if (!rx->sta || data_len < 0)
J
Johannes Berg 已提交
498
		return RX_DROP_UNUSABLE;
499

500 501
	if ((rx->status->flag & RX_FLAG_DECRYPTED) &&
	    (rx->status->flag & RX_FLAG_IV_STRIPPED))
502
		return RX_CONTINUE;
503 504 505

	(void) ccmp_hdr2pn(pn, skb->data + hdrlen);

506
	if (memcmp(pn, key->u.ccmp.rx_pn[rx->queue], CCMP_PN_LEN) <= 0) {
507
#ifdef CONFIG_MAC80211_DEBUG
508
		u8 *ppn = key->u.ccmp.rx_pn[rx->queue];
509

510
		printk(KERN_DEBUG "%s: CCMP replay detected for RX frame from "
511
		       "%s (RX PN %02x%02x%02x%02x%02x%02x <= prev. PN "
512
		       "%02x%02x%02x%02x%02x%02x)\n", rx->dev->name,
513
		       print_mac(mac, rx->sta->addr),
514 515 516 517
		       pn[0], pn[1], pn[2], pn[3], pn[4], pn[5],
		       ppn[0], ppn[1], ppn[2], ppn[3], ppn[4], ppn[5]);
#endif /* CONFIG_MAC80211_DEBUG */
		key->u.ccmp.replays++;
J
Johannes Berg 已提交
518
		return RX_DROP_UNUSABLE;
519 520
	}

521
	if (!(rx->status->flag & RX_FLAG_DECRYPTED)) {
522
		/* hardware didn't decrypt/verify MIC */
523 524 525 526 527 528 529 530 531 532 533 534 535
		u8 *scratch, *b_0, *aad;

		scratch = key->u.ccmp.rx_crypto_buf;
		b_0 = scratch + 3 * AES_BLOCK_LEN;
		aad = scratch + 4 * AES_BLOCK_LEN;

		ccmp_special_blocks(skb, pn, b_0, aad, 1);

		if (ieee80211_aes_ccm_decrypt(
			    key->u.ccmp.tfm, scratch, b_0, aad,
			    skb->data + hdrlen + CCMP_HDR_LEN, data_len,
			    skb->data + skb->len - CCMP_MIC_LEN,
			    skb->data + hdrlen + CCMP_HDR_LEN)) {
536 537 538 539 540 541
#ifdef CONFIG_MAC80211_DEBUG
			if (net_ratelimit())
				printk(KERN_DEBUG "%s: CCMP decrypt failed "
				       "for RX frame from %s\n", rx->dev->name,
				       print_mac(mac, rx->sta->addr));
#endif /* CONFIG_MAC80211_DEBUG */
J
Johannes Berg 已提交
542
			return RX_DROP_UNUSABLE;
543 544 545
		}
	}

546
	memcpy(key->u.ccmp.rx_pn[rx->queue], pn, CCMP_PN_LEN);
547 548 549 550 551 552

	/* Remove CCMP header and MIC */
	skb_trim(skb, skb->len - CCMP_MIC_LEN);
	memmove(skb->data + CCMP_HDR_LEN, skb->data, hdrlen);
	skb_pull(skb, CCMP_HDR_LEN);

553
	return RX_CONTINUE;
554
}