1138578Ssam/*-
2138578Ssam * Copyright (c) 2004 Sam Leffler, Errno Consulting
3138578Ssam * All rights reserved.
4138578Ssam *
5138578Ssam * Redistribution and use in source and binary forms, with or without
6138578Ssam * modification, are permitted provided that the following conditions
7138578Ssam * are met:
8138578Ssam * 1. Redistributions of source code must retain the above copyright
9138578Ssam *    notice, this list of conditions and the following disclaimer.
10138578Ssam * 2. Redistributions in binary form must reproduce the above copyright
11138578Ssam *    notice, this list of conditions and the following disclaimer in the
12138578Ssam *    documentation and/or other materials provided with the distribution.
13138578Ssam * 3. The name of the author may not be used to endorse or promote products
14138578Ssam *    derived from this software without specific prior written permission.
15138578Ssam *
16138578Ssam * Alternatively, this software may be distributed under the terms of the
17138578Ssam * GNU General Public License ("GPL") version 2 as published by the Free
18138578Ssam * Software Foundation.
19138578Ssam *
20138578Ssam * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21138578Ssam * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22138578Ssam * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23138578Ssam * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24138578Ssam * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25138578Ssam * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26138578Ssam * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27138578Ssam * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28138578Ssam * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29138578Ssam * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30138578Ssam *
31138578Ssam * $FreeBSD$
32138578Ssam */
33138578Ssam
34138578Ssam/*
35138578Ssam * TKIP test module.
36138578Ssam */
37138578Ssam#include <sys/param.h>
38138578Ssam#include <sys/kernel.h>
39138578Ssam#include <sys/systm.h>
40138578Ssam#include <sys/mbuf.h>
41138578Ssam#include <sys/module.h>
42138578Ssam
43138578Ssam#include <sys/socket.h>
44138578Ssam
45138578Ssam#include <net/if.h>
46138578Ssam#include <net/if_media.h>
47138578Ssam
48138578Ssam#include <net80211/ieee80211_var.h>
49138578Ssam
50138578Ssam/*
51138578SsamKey	12 34 56 78 90 12 34 56 78 90 12 34 56 78 90 12
52138578Ssam	34 56 78 90 12 34 56 78 90 12 34 56 78 90 12 34
53138578SsamPN	0x000000000001
54138578SsamIV	00 20 01 20 00 00 00 00
55138578SsamPhase1	bb 58 07 1f 9e 93 b4 38 25 4b
56138578SsamPhase2	00 20 01 4c fe 67 be d2 7c 86 7b 1b f8 02 8b 1c
57138578Ssam*/
58138578Ssam
59138578Ssamstatic const u_int8_t test1_key[] = {
60138578Ssam	0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12,
61138578Ssam	0x34, 0x56, 0x78, 0x90, 0x12,
62138578Ssam
63138578Ssam	0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78,		/* TX MIC */
64138578Ssam	/*
65138578Ssam	 * NB: 11i test vector specifies a RX MIC key different
66138578Ssam	 *     from the TX key.  But this doesn't work to enmic,
67138578Ssam	 *     encrypt, then decrypt, demic.  So instead we use
68138578Ssam	 *     the same key for doing the MIC in each direction.
69138578Ssam	 *
70138578Ssam	 * XXX need additional vectors to test alternate MIC keys
71138578Ssam	 */
72138578Ssam#if 0
73138578Ssam	0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34,		/* 11i RX MIC */
74138578Ssam#else
75138578Ssam	0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78,		/* TX copy */
76138578Ssam#endif
77138578Ssam};
78138578Ssamstatic const u_int8_t test1_phase1[] = {
79138578Ssam	0xbb, 0x58, 0x07, 0x1f, 0x9e, 0x93, 0xb4, 0x38, 0x25, 0x4b
80138578Ssam};
81138578Ssamstatic const u_int8_t test1_phase2[] = {
82138578Ssam	0x00, 0x20, 0x01, 0x4c, 0xfe, 0x67, 0xbe, 0xd2, 0x7c, 0x86,
83138578Ssam	0x7b, 0x1b, 0xf8, 0x02, 0x8b, 0x1c,
84138578Ssam};
85138578Ssam
86138578Ssam/* Plaintext MPDU with MIC */
87138578Ssamstatic const u_int8_t test1_plaintext[] = {
88138578Ssam0x08,0x42,0x2c,0x00,0x02,0x03,0x04,0x05,0x06,0x08,0x02,0x03,0x04,0x05,0x06,0x07,
89138578Ssam0x02,0x03,0x04,0x05,0x06,0x07,0xd0,0x02,
90138578Ssam0xaa,0xaa,0x03,0x00,0x00,0x00,0x08,0x00,0x45,0x00,0x00,0x54,0x00,0x00,0x40,0x00,
91138578Ssam0x40,0x01,0xa5,0x55,0xc0,0xa8,0x0a,0x02,0xc0,0xa8,0x0a,0x01,0x08,0x00,0x3a,0xb0,
92138578Ssam0x00,0x00,0x00,0x00,0xcd,0x4c,0x05,0x00,0x00,0x00,0x00,0x00,0x08,0x09,0x0a,0x0b,
93138578Ssam0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,
94138578Ssam0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,
95138578Ssam0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
96138578Ssam/* MIC */ 0x68,0x81,0xa3,0xf3,0xd6,0x48,0xd0,0x3c
97138578Ssam};
98138578Ssam
99138578Ssam/* Encrypted MPDU with MIC and ICV */
100138578Ssamstatic const u_int8_t test1_encrypted[] = {
101138578Ssam0x08,0x42,0x2c,0x00,0x02,0x03,0x04,0x05,0x06,0x08,0x02,0x03,0x04,0x05,0x06,0x07,
102138578Ssam0x02,0x03,0x04,0x05,0x06,0x07,0xd0,0x02,0x00,0x20,0x01,0x20,0x00,0x00,0x00,0x00,
103138578Ssam0xc0,0x0e,0x14,0xfc,0xe7,0xcf,0xab,0xc7,0x75,0x47,0xe6,0x66,0xe5,0x7c,0x0d,0xac,
104138578Ssam0x70,0x4a,0x1e,0x35,0x8a,0x88,0xc1,0x1c,0x8e,0x2e,0x28,0x2e,0x38,0x01,0x02,0x7a,
105138578Ssam0x46,0x56,0x05,0x5e,0xe9,0x3e,0x9c,0x25,0x47,0x02,0xe9,0x73,0x58,0x05,0xdd,0xb5,
106138578Ssam0x76,0x9b,0xa7,0x3f,0x1e,0xbb,0x56,0xe8,0x44,0xef,0x91,0x22,0x85,0xd3,0xdd,0x6e,
107138578Ssam0x54,0x1e,0x82,0x38,0x73,0x55,0x8a,0xdb,0xa0,0x79,0x06,0x8a,0xbd,0x7f,0x7f,0x50,
108138578Ssam0x95,0x96,0x75,0xac,0xc4,0xb4,0xde,0x9a,0xa9,0x9c,0x05,0xf2,0x89,0xa7,0xc5,0x2f,
109138578Ssam0xee,0x5b,0xfc,0x14,0xf6,0xf8,0xe5,0xf8
110138578Ssam};
111138578Ssam
112138578Ssam#define	TEST(n,name,cipher,keyix,pn) { \
113138578Ssam	name, IEEE80211_CIPHER_##cipher,keyix, pn##LL, \
114138578Ssam	test##n##_key,   sizeof(test##n##_key), \
115138578Ssam	test##n##_phase1,   sizeof(test##n##_phase1), \
116138578Ssam	test##n##_phase2,   sizeof(test##n##_phase2), \
117138578Ssam	test##n##_plaintext, sizeof(test##n##_plaintext), \
118138578Ssam	test##n##_encrypted, sizeof(test##n##_encrypted) \
119138578Ssam}
120138578Ssam
121138578Ssamstruct ciphertest {
122138578Ssam	const char	*name;
123138578Ssam	int		cipher;
124138578Ssam	int		keyix;
125138578Ssam	u_int64_t	pn;
126138578Ssam	const u_int8_t	*key;
127138578Ssam	size_t		key_len;
128138578Ssam	const u_int8_t	*phase1;
129138578Ssam	size_t		phase1_len;
130138578Ssam	const u_int8_t	*phase2;
131138578Ssam	size_t		phase2_len;
132138578Ssam	const u_int8_t	*plaintext;
133138578Ssam	size_t		plaintext_len;
134138578Ssam	const u_int8_t	*encrypted;
135138578Ssam	size_t		encrypted_len;
136138578Ssam} tkiptests[] = {
137138578Ssam	TEST(1, "TKIP test mpdu 1", TKIP, 0, 0),
138138578Ssam};
139138578Ssam
140138578Ssamstruct tkip_ctx {
141138578Ssam	struct ieee80211com *tc_ic;	/* for diagnostics */
142138578Ssam
143138578Ssam	uint16_t tx_ttak[5];
144138578Ssam	int	tx_phase1_done;
145138578Ssam	uint8_t	tx_rc4key[16];
146138578Ssam
147138578Ssam	uint16_t rx_ttak[5];
148138578Ssam	int	rx_phase1_done;
149138578Ssam	uint8_t	rx_rc4key[16];
150138578Ssam	uint64_t rx_rsc;		/* held until MIC verified */
151138578Ssam};
152138578Ssam
153138578Ssamstatic void
154138578Ssamdumpdata(const char *tag, const void *p, size_t len)
155138578Ssam{
156138578Ssam	int i;
157138578Ssam
158138578Ssam	printf("%s: 0x%p len %u", tag, p, len);
159138578Ssam	for (i = 0; i < len; i++) {
160138578Ssam		if ((i % 16) == 0)
161138578Ssam			printf("\n%03d:", i);
162138578Ssam		printf(" %02x", ((const u_int8_t *)p)[i]);
163138578Ssam	}
164138578Ssam	printf("\n");
165138578Ssam}
166138578Ssam
167138578Ssamstatic void
168138578Ssamcmpfail(const void *gen, size_t genlen, const void *ref, size_t reflen)
169138578Ssam{
170138578Ssam	int i;
171138578Ssam
172138578Ssam	for (i = 0; i < genlen; i++)
173138578Ssam		if (((const u_int8_t *)gen)[i] != ((const u_int8_t *)ref)[i]) {
174138578Ssam			printf("first difference at byte %u\n", i);
175138578Ssam			break;
176138578Ssam		}
177138578Ssam	dumpdata("Generated", gen, genlen);
178138578Ssam	dumpdata("Reference", ref, reflen);
179138578Ssam}
180138578Ssam
181138578Ssamstatic int
182138578Ssamruntest(struct ieee80211com *ic, struct ciphertest *t)
183138578Ssam{
184138578Ssam	struct tkip_ctx *ctx;
185138578Ssam	struct ieee80211_key key;
186138578Ssam	struct mbuf *m = NULL;
187138578Ssam	const struct ieee80211_cipher *cip;
188138578Ssam	u_int8_t mac[IEEE80211_ADDR_LEN];
189138578Ssam	u_int len;
190138578Ssam
191138578Ssam	printf("%s: ", t->name);
192138578Ssam
193138578Ssam	/*
194138578Ssam	 * Setup key.
195138578Ssam	 */
196138578Ssam	memset(&key, 0, sizeof(key));
197138578Ssam	key.wk_flags = IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV;
198138578Ssam	key.wk_cipher = &ieee80211_cipher_none;
199145904Savatar	if (!ieee80211_crypto_newkey(ic, IEEE80211_CIPHER_TKIP,
200145904Savatar	    IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV, &key)) {
201138578Ssam		printf("FAIL: ieee80211_crypto_newkey failed\n");
202138578Ssam		goto bad;
203138578Ssam	}
204138578Ssam
205138578Ssam	memcpy(key.wk_key, t->key, t->key_len);
206138578Ssam	key.wk_keylen = 128/NBBY;
207138578Ssam	key.wk_keyrsc = 0;
208138578Ssam	key.wk_keytsc = t->pn;
209138578Ssam	if (!ieee80211_crypto_setkey(ic, &key, mac)) {
210138578Ssam		printf("FAIL: ieee80211_crypto_setkey failed\n");
211138578Ssam		goto bad;
212138578Ssam	}
213138578Ssam
214138578Ssam	/*
215138578Ssam	 * Craft frame from plaintext data.
216138578Ssam	 */
217138578Ssam	cip = key.wk_cipher;
218138578Ssam	m = m_getcl(M_NOWAIT, MT_HEADER, M_PKTHDR);
219138578Ssam	m->m_data += cip->ic_header;
220138578Ssam	len = t->plaintext_len - IEEE80211_WEP_MICLEN;
221138578Ssam	memcpy(mtod(m, void *), t->plaintext, len);
222138578Ssam	m->m_len = len;
223138578Ssam	m->m_pkthdr.len = m->m_len;
224138578Ssam
225138578Ssam	/*
226138578Ssam	 * Add MIC.
227138578Ssam	 */
228138578Ssam	if (!ieee80211_crypto_enmic(ic, &key, m)) {
229138578Ssam		printf("FAIL: tkip enmic failed\n");
230138578Ssam		goto bad;
231138578Ssam	}
232138578Ssam	/*
233138578Ssam	 * Verify: frame length, frame contents.
234138578Ssam	 */
235138578Ssam	if (m->m_pkthdr.len != t->plaintext_len) {
236138578Ssam		printf("FAIL: enmic botch; length mismatch\n");
237138578Ssam		cmpfail(mtod(m, const void *), m->m_pkthdr.len,
238138578Ssam			t->plaintext, t->plaintext_len);
239138578Ssam		goto bad;
240138578Ssam	}
241138578Ssam	if (memcmp(mtod(m, const void *), t->plaintext, t->plaintext_len)) {
242138578Ssam		printf("FAIL: enmic botch\n");
243138578Ssam		cmpfail(mtod(m, const void *), m->m_pkthdr.len,
244138578Ssam			t->plaintext, t->plaintext_len);
245138578Ssam		goto bad;
246138578Ssam	}
247138578Ssam	/*
248138578Ssam	 * Encrypt frame w/ MIC.
249138578Ssam	 */
250138578Ssam	if (!cip->ic_encap(&key, m, t->keyix<<6)) {
251138578Ssam		printf("FAIL: tkip encap failed\n");
252138578Ssam		goto bad;
253138578Ssam	}
254138578Ssam	/*
255138578Ssam	 * Verify: phase1, phase2, frame length, frame contents.
256138578Ssam	 */
257138578Ssam	ctx = key.wk_private;
258138578Ssam	if (memcmp(ctx->tx_ttak, t->phase1, t->phase1_len)) {
259138578Ssam		printf("FAIL: encrypt phase1 botch\n");
260138578Ssam		cmpfail(ctx->tx_ttak, sizeof(ctx->tx_ttak),
261138578Ssam			t->phase1, t->phase1_len);
262138578Ssam		goto bad;
263138578Ssam	} else if (memcmp(ctx->tx_rc4key, t->phase2, t->phase2_len)) {
264138578Ssam		printf("FAIL: encrypt phase2 botch\n");
265138578Ssam		cmpfail(ctx->tx_rc4key, sizeof(ctx->tx_rc4key),
266138578Ssam			t->phase2, t->phase2_len);
267138578Ssam		goto bad;
268138578Ssam	} else if (m->m_pkthdr.len != t->encrypted_len) {
269138578Ssam		printf("FAIL: encrypt data length mismatch\n");
270138578Ssam		cmpfail(mtod(m, const void *), m->m_pkthdr.len,
271138578Ssam			t->encrypted, t->encrypted_len);
272138578Ssam		goto bad;
273138578Ssam	} else if (memcmp(mtod(m, const void *), t->encrypted, m->m_pkthdr.len)) {
274138578Ssam		printf("FAIL: encrypt data does not compare\n");
275138578Ssam		cmpfail(mtod(m, const void *), m->m_pkthdr.len,
276138578Ssam			t->encrypted, t->encrypted_len);
277138578Ssam		dumpdata("Plaintext", t->plaintext, t->plaintext_len);
278138578Ssam		goto bad;
279138578Ssam	}
280138578Ssam
281138578Ssam	/*
282138578Ssam	 * Decrypt frame.
283138578Ssam	 */
284138578Ssam	if (!cip->ic_decap(&key, m)) {
285138578Ssam		printf("tkip decap failed\n");
286138578Ssam		/*
287138578Ssam		 * Check reason for failure: phase1, phase2, frame data (ICV).
288138578Ssam		 */
289138578Ssam		if (memcmp(ctx->rx_ttak, t->phase1, t->phase1_len)) {
290138578Ssam			printf("FAIL: decrypt phase1 botch\n");
291138578Ssam			cmpfail(ctx->rx_ttak, sizeof(ctx->rx_ttak),
292138578Ssam				t->phase1, t->phase1_len);
293138578Ssam		} else if (memcmp(ctx->rx_rc4key, t->phase2, t->phase2_len)) {
294138578Ssam			printf("FAIL: decrypt phase2 botch\n");
295138578Ssam			cmpfail(ctx->rx_rc4key, sizeof(ctx->rx_rc4key),
296138578Ssam				t->phase2, t->phase2_len);
297138578Ssam		} else {
298138578Ssam			printf("FAIL: decrypt data does not compare\n");
299138578Ssam			cmpfail(mtod(m, const void *), m->m_pkthdr.len,
300138578Ssam				t->plaintext, t->plaintext_len);
301138578Ssam		}
302138578Ssam		goto bad;
303138578Ssam	}
304138578Ssam	/*
305138578Ssam	 * Verify: frame length, frame contents.
306138578Ssam	 */
307138578Ssam	if (m->m_pkthdr.len != t->plaintext_len) {
308138578Ssam		printf("FAIL: decap botch; length mismatch\n");
309138578Ssam		cmpfail(mtod(m, const void *), m->m_pkthdr.len,
310138578Ssam			t->plaintext, t->plaintext_len);
311138578Ssam		goto bad;
312138578Ssam	}
313138578Ssam	if (memcmp(mtod(m, const void *), t->plaintext, t->plaintext_len)) {
314138578Ssam		printf("FAIL: decap botch; data does not compare\n");
315138578Ssam		cmpfail(mtod(m, const void *), m->m_pkthdr.len,
316138578Ssam			t->plaintext, t->plaintext_len);
317138578Ssam		goto bad;
318138578Ssam	}
319138578Ssam	/*
320138578Ssam	 * De-MIC decrypted frame.
321138578Ssam	 */
322138578Ssam	if (!ieee80211_crypto_demic(ic, &key, m)) {
323138578Ssam		printf("FAIL: tkip demic failed\n");
324138578Ssam		goto bad;
325138578Ssam	}
326138578Ssam	/* XXX check frame length and contents... */
327138578Ssam	printf("PASS\n");
328138578Ssam	return 1;
329138578Ssambad:
330138578Ssam	if (m != NULL)
331138578Ssam		m_freem(m);
332138578Ssam	ieee80211_crypto_delkey(ic, &key);
333138578Ssam	return 0;
334138578Ssam}
335138578Ssam
336138578Ssam/*
337138578Ssam * Module glue.
338138578Ssam */
339138578Ssam
340138578Ssamstatic	int debug = 0;
341138578Ssamstatic	int tests = -1;
342138578Ssam
343138578Ssamstatic int
344138578Ssaminit_crypto_tkip_test(void)
345138578Ssam{
346138578Ssam#define	N(a)	(sizeof(a)/sizeof(a[0]))
347138578Ssam	struct ieee80211com ic;
348138578Ssam	int i, pass, total;
349138578Ssam
350138578Ssam	memset(&ic, 0, sizeof(ic));
351138578Ssam	if (debug)
352138578Ssam		ic.ic_debug = IEEE80211_MSG_CRYPTO;
353138578Ssam	ieee80211_crypto_attach(&ic);
354138578Ssam
355138578Ssam	pass = 0;
356138578Ssam	total = 0;
357138578Ssam	for (i = 0; i < N(tkiptests); i++)
358138578Ssam		if (tests & (1<<i)) {
359138578Ssam			total++;
360138578Ssam			pass += runtest(&ic, &tkiptests[i]);
361138578Ssam		}
362138578Ssam	printf("%u of %u 802.11i TKIP test vectors passed\n", pass, total);
363138578Ssam	ieee80211_crypto_detach(&ic);
364138578Ssam	return (pass == total ? 0 : -1);
365138578Ssam#undef N
366138578Ssam}
367138578Ssam
368138578Ssamstatic int
369138578Ssamtest_tkip_modevent(module_t mod, int type, void *unused)
370138578Ssam{
371138578Ssam	switch (type) {
372138578Ssam	case MOD_LOAD:
373138578Ssam		(void) init_crypto_tkip_test();
374138578Ssam		return 0;
375138578Ssam	case MOD_UNLOAD:
376138578Ssam		return 0;
377138578Ssam	}
378138578Ssam	return EINVAL;
379138578Ssam}
380138578Ssam
381138578Ssamstatic moduledata_t test_tkip_mod = {
382138578Ssam	"test_tkip",
383138578Ssam	test_tkip_modevent,
384241394Skevlo	0
385138578Ssam};
386138578SsamDECLARE_MODULE(test_tkip, test_tkip_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
387138578SsamMODULE_VERSION(test_tkip, 1);
388138578SsamMODULE_DEPEND(test_tkip, wlan, 1, 1, 1);
389