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>
46289762Savos#include <net/if_var.h>
47138578Ssam#include <net/if_media.h>
48138578Ssam
49138578Ssam#include <net80211/ieee80211_var.h>
50138578Ssam
51138578Ssam/*
52138578SsamKey	12 34 56 78 90 12 34 56 78 90 12 34 56 78 90 12
53138578Ssam	34 56 78 90 12 34 56 78 90 12 34 56 78 90 12 34
54138578SsamPN	0x000000000001
55138578SsamIV	00 20 01 20 00 00 00 00
56138578SsamPhase1	bb 58 07 1f 9e 93 b4 38 25 4b
57138578SsamPhase2	00 20 01 4c fe 67 be d2 7c 86 7b 1b f8 02 8b 1c
58138578Ssam*/
59138578Ssam
60138578Ssamstatic const u_int8_t test1_key[] = {
61138578Ssam	0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12,
62138578Ssam	0x34, 0x56, 0x78, 0x90, 0x12,
63138578Ssam
64138578Ssam	0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78,		/* TX MIC */
65138578Ssam	/*
66138578Ssam	 * NB: 11i test vector specifies a RX MIC key different
67138578Ssam	 *     from the TX key.  But this doesn't work to enmic,
68138578Ssam	 *     encrypt, then decrypt, demic.  So instead we use
69138578Ssam	 *     the same key for doing the MIC in each direction.
70138578Ssam	 *
71138578Ssam	 * XXX need additional vectors to test alternate MIC keys
72138578Ssam	 */
73138578Ssam#if 0
74138578Ssam	0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34,		/* 11i RX MIC */
75138578Ssam#else
76138578Ssam	0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78,		/* TX copy */
77138578Ssam#endif
78138578Ssam};
79138578Ssamstatic const u_int8_t test1_phase1[] = {
80138578Ssam	0xbb, 0x58, 0x07, 0x1f, 0x9e, 0x93, 0xb4, 0x38, 0x25, 0x4b
81138578Ssam};
82138578Ssamstatic const u_int8_t test1_phase2[] = {
83138578Ssam	0x00, 0x20, 0x01, 0x4c, 0xfe, 0x67, 0xbe, 0xd2, 0x7c, 0x86,
84138578Ssam	0x7b, 0x1b, 0xf8, 0x02, 0x8b, 0x1c,
85138578Ssam};
86138578Ssam
87138578Ssam/* Plaintext MPDU with MIC */
88138578Ssamstatic const u_int8_t test1_plaintext[] = {
89138578Ssam0x08,0x42,0x2c,0x00,0x02,0x03,0x04,0x05,0x06,0x08,0x02,0x03,0x04,0x05,0x06,0x07,
90138578Ssam0x02,0x03,0x04,0x05,0x06,0x07,0xd0,0x02,
91138578Ssam0xaa,0xaa,0x03,0x00,0x00,0x00,0x08,0x00,0x45,0x00,0x00,0x54,0x00,0x00,0x40,0x00,
92138578Ssam0x40,0x01,0xa5,0x55,0xc0,0xa8,0x0a,0x02,0xc0,0xa8,0x0a,0x01,0x08,0x00,0x3a,0xb0,
93138578Ssam0x00,0x00,0x00,0x00,0xcd,0x4c,0x05,0x00,0x00,0x00,0x00,0x00,0x08,0x09,0x0a,0x0b,
94138578Ssam0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,
95138578Ssam0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,
96138578Ssam0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
97138578Ssam/* MIC */ 0x68,0x81,0xa3,0xf3,0xd6,0x48,0xd0,0x3c
98138578Ssam};
99138578Ssam
100138578Ssam/* Encrypted MPDU with MIC and ICV */
101138578Ssamstatic const u_int8_t test1_encrypted[] = {
102138578Ssam0x08,0x42,0x2c,0x00,0x02,0x03,0x04,0x05,0x06,0x08,0x02,0x03,0x04,0x05,0x06,0x07,
103138578Ssam0x02,0x03,0x04,0x05,0x06,0x07,0xd0,0x02,0x00,0x20,0x01,0x20,0x00,0x00,0x00,0x00,
104138578Ssam0xc0,0x0e,0x14,0xfc,0xe7,0xcf,0xab,0xc7,0x75,0x47,0xe6,0x66,0xe5,0x7c,0x0d,0xac,
105138578Ssam0x70,0x4a,0x1e,0x35,0x8a,0x88,0xc1,0x1c,0x8e,0x2e,0x28,0x2e,0x38,0x01,0x02,0x7a,
106138578Ssam0x46,0x56,0x05,0x5e,0xe9,0x3e,0x9c,0x25,0x47,0x02,0xe9,0x73,0x58,0x05,0xdd,0xb5,
107138578Ssam0x76,0x9b,0xa7,0x3f,0x1e,0xbb,0x56,0xe8,0x44,0xef,0x91,0x22,0x85,0xd3,0xdd,0x6e,
108138578Ssam0x54,0x1e,0x82,0x38,0x73,0x55,0x8a,0xdb,0xa0,0x79,0x06,0x8a,0xbd,0x7f,0x7f,0x50,
109138578Ssam0x95,0x96,0x75,0xac,0xc4,0xb4,0xde,0x9a,0xa9,0x9c,0x05,0xf2,0x89,0xa7,0xc5,0x2f,
110138578Ssam0xee,0x5b,0xfc,0x14,0xf6,0xf8,0xe5,0xf8
111138578Ssam};
112138578Ssam
113138578Ssam#define	TEST(n,name,cipher,keyix,pn) { \
114138578Ssam	name, IEEE80211_CIPHER_##cipher,keyix, pn##LL, \
115138578Ssam	test##n##_key,   sizeof(test##n##_key), \
116138578Ssam	test##n##_phase1,   sizeof(test##n##_phase1), \
117138578Ssam	test##n##_phase2,   sizeof(test##n##_phase2), \
118138578Ssam	test##n##_plaintext, sizeof(test##n##_plaintext), \
119138578Ssam	test##n##_encrypted, sizeof(test##n##_encrypted) \
120138578Ssam}
121138578Ssam
122138578Ssamstruct ciphertest {
123138578Ssam	const char	*name;
124138578Ssam	int		cipher;
125138578Ssam	int		keyix;
126138578Ssam	u_int64_t	pn;
127138578Ssam	const u_int8_t	*key;
128138578Ssam	size_t		key_len;
129138578Ssam	const u_int8_t	*phase1;
130138578Ssam	size_t		phase1_len;
131138578Ssam	const u_int8_t	*phase2;
132138578Ssam	size_t		phase2_len;
133138578Ssam	const u_int8_t	*plaintext;
134138578Ssam	size_t		plaintext_len;
135138578Ssam	const u_int8_t	*encrypted;
136138578Ssam	size_t		encrypted_len;
137138578Ssam} tkiptests[] = {
138138578Ssam	TEST(1, "TKIP test mpdu 1", TKIP, 0, 0),
139138578Ssam};
140138578Ssam
141138578Ssamstruct tkip_ctx {
142138578Ssam	struct ieee80211com *tc_ic;	/* for diagnostics */
143138578Ssam
144138578Ssam	uint16_t tx_ttak[5];
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
182289762Savosruntest(struct ieee80211vap *vap, struct ciphertest *t)
183138578Ssam{
184138578Ssam	struct tkip_ctx *ctx;
185289762Savos	struct ieee80211_key *key = &vap->iv_nw_keys[t->keyix];
186138578Ssam	struct mbuf *m = NULL;
187138578Ssam	const struct ieee80211_cipher *cip;
188138578Ssam	u_int len;
189289762Savos	int hdrlen;
190138578Ssam
191138578Ssam	printf("%s: ", t->name);
192138578Ssam
193138578Ssam	/*
194138578Ssam	 * Setup key.
195138578Ssam	 */
196289762Savos	memset(key, 0, sizeof(*key));
197289762Savos	key->wk_flags = IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV;
198289762Savos	key->wk_cipher = &ieee80211_cipher_none;
199289762Savos	if (!ieee80211_crypto_newkey(vap, t->cipher,
200289762Savos	    IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV, key)) {
201138578Ssam		printf("FAIL: ieee80211_crypto_newkey failed\n");
202138578Ssam		goto bad;
203138578Ssam	}
204138578Ssam
205289762Savos	memcpy(key->wk_key, t->key, t->key_len);
206289762Savos	key->wk_keylen = 128/NBBY;
207289762Savos	memset(key->wk_keyrsc, 0, sizeof(key->wk_keyrsc));
208289762Savos	key->wk_keytsc = t->pn;
209289762Savos	if (!ieee80211_crypto_setkey(vap, key)) {
210138578Ssam		printf("FAIL: ieee80211_crypto_setkey failed\n");
211138578Ssam		goto bad;
212138578Ssam	}
213138578Ssam
214138578Ssam	/*
215138578Ssam	 * Craft frame from plaintext data.
216138578Ssam	 */
217289762Savos	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;
224289762Savos	hdrlen = ieee80211_anyhdrsize(mtod(m, void *));
225138578Ssam
226138578Ssam	/*
227138578Ssam	 * Add MIC.
228138578Ssam	 */
229289762Savos	if (!ieee80211_crypto_enmic(vap, key, m, 1)) {
230138578Ssam		printf("FAIL: tkip enmic failed\n");
231138578Ssam		goto bad;
232138578Ssam	}
233138578Ssam	/*
234138578Ssam	 * Verify: frame length, frame contents.
235138578Ssam	 */
236138578Ssam	if (m->m_pkthdr.len != t->plaintext_len) {
237138578Ssam		printf("FAIL: enmic botch; length mismatch\n");
238138578Ssam		cmpfail(mtod(m, const void *), m->m_pkthdr.len,
239138578Ssam			t->plaintext, t->plaintext_len);
240138578Ssam		goto bad;
241138578Ssam	}
242138578Ssam	if (memcmp(mtod(m, const void *), t->plaintext, t->plaintext_len)) {
243138578Ssam		printf("FAIL: enmic botch\n");
244138578Ssam		cmpfail(mtod(m, const void *), m->m_pkthdr.len,
245138578Ssam			t->plaintext, t->plaintext_len);
246138578Ssam		goto bad;
247138578Ssam	}
248138578Ssam	/*
249138578Ssam	 * Encrypt frame w/ MIC.
250138578Ssam	 */
251289762Savos	if (!cip->ic_encap(key, m)) {
252138578Ssam		printf("FAIL: tkip encap failed\n");
253138578Ssam		goto bad;
254138578Ssam	}
255138578Ssam	/*
256138578Ssam	 * Verify: phase1, phase2, frame length, frame contents.
257138578Ssam	 */
258289762Savos	ctx = key->wk_private;
259138578Ssam	if (memcmp(ctx->tx_ttak, t->phase1, t->phase1_len)) {
260138578Ssam		printf("FAIL: encrypt phase1 botch\n");
261138578Ssam		cmpfail(ctx->tx_ttak, sizeof(ctx->tx_ttak),
262138578Ssam			t->phase1, t->phase1_len);
263138578Ssam		goto bad;
264138578Ssam	} else if (memcmp(ctx->tx_rc4key, t->phase2, t->phase2_len)) {
265138578Ssam		printf("FAIL: encrypt phase2 botch\n");
266138578Ssam		cmpfail(ctx->tx_rc4key, sizeof(ctx->tx_rc4key),
267138578Ssam			t->phase2, t->phase2_len);
268138578Ssam		goto bad;
269138578Ssam	} else if (m->m_pkthdr.len != t->encrypted_len) {
270138578Ssam		printf("FAIL: encrypt data length mismatch\n");
271138578Ssam		cmpfail(mtod(m, const void *), m->m_pkthdr.len,
272138578Ssam			t->encrypted, t->encrypted_len);
273138578Ssam		goto bad;
274138578Ssam	} else if (memcmp(mtod(m, const void *), t->encrypted, m->m_pkthdr.len)) {
275138578Ssam		printf("FAIL: encrypt data does not compare\n");
276138578Ssam		cmpfail(mtod(m, const void *), m->m_pkthdr.len,
277138578Ssam			t->encrypted, t->encrypted_len);
278138578Ssam		dumpdata("Plaintext", t->plaintext, t->plaintext_len);
279138578Ssam		goto bad;
280138578Ssam	}
281138578Ssam
282138578Ssam	/*
283138578Ssam	 * Decrypt frame.
284138578Ssam	 */
285289762Savos	if (!cip->ic_decap(key, m, hdrlen)) {
286138578Ssam		printf("tkip decap failed\n");
287138578Ssam		/*
288138578Ssam		 * Check reason for failure: phase1, phase2, frame data (ICV).
289138578Ssam		 */
290138578Ssam		if (memcmp(ctx->rx_ttak, t->phase1, t->phase1_len)) {
291138578Ssam			printf("FAIL: decrypt phase1 botch\n");
292138578Ssam			cmpfail(ctx->rx_ttak, sizeof(ctx->rx_ttak),
293138578Ssam				t->phase1, t->phase1_len);
294138578Ssam		} else if (memcmp(ctx->rx_rc4key, t->phase2, t->phase2_len)) {
295138578Ssam			printf("FAIL: decrypt phase2 botch\n");
296138578Ssam			cmpfail(ctx->rx_rc4key, sizeof(ctx->rx_rc4key),
297138578Ssam				t->phase2, t->phase2_len);
298138578Ssam		} else {
299138578Ssam			printf("FAIL: decrypt data does not compare\n");
300138578Ssam			cmpfail(mtod(m, const void *), m->m_pkthdr.len,
301138578Ssam				t->plaintext, t->plaintext_len);
302138578Ssam		}
303138578Ssam		goto bad;
304138578Ssam	}
305138578Ssam	/*
306138578Ssam	 * Verify: frame length, frame contents.
307138578Ssam	 */
308138578Ssam	if (m->m_pkthdr.len != t->plaintext_len) {
309138578Ssam		printf("FAIL: decap botch; length mismatch\n");
310138578Ssam		cmpfail(mtod(m, const void *), m->m_pkthdr.len,
311138578Ssam			t->plaintext, t->plaintext_len);
312138578Ssam		goto bad;
313138578Ssam	}
314138578Ssam	if (memcmp(mtod(m, const void *), t->plaintext, t->plaintext_len)) {
315138578Ssam		printf("FAIL: decap botch; data does not compare\n");
316138578Ssam		cmpfail(mtod(m, const void *), m->m_pkthdr.len,
317138578Ssam			t->plaintext, t->plaintext_len);
318138578Ssam		goto bad;
319138578Ssam	}
320138578Ssam	/*
321138578Ssam	 * De-MIC decrypted frame.
322138578Ssam	 */
323289762Savos	if (!ieee80211_crypto_demic(vap, key, m, 1)) {
324138578Ssam		printf("FAIL: tkip demic failed\n");
325138578Ssam		goto bad;
326138578Ssam	}
327138578Ssam	/* XXX check frame length and contents... */
328289762Savos	m_freem(m);
329289762Savos	ieee80211_crypto_delkey(vap, key);
330138578Ssam	printf("PASS\n");
331138578Ssam	return 1;
332138578Ssambad:
333138578Ssam	if (m != NULL)
334138578Ssam		m_freem(m);
335289762Savos	ieee80211_crypto_delkey(vap, key);
336138578Ssam	return 0;
337138578Ssam}
338138578Ssam
339138578Ssam/*
340138578Ssam * Module glue.
341138578Ssam */
342138578Ssam
343138578Ssamstatic	int debug = 0;
344138578Ssamstatic	int tests = -1;
345138578Ssam
346138578Ssamstatic int
347138578Ssaminit_crypto_tkip_test(void)
348138578Ssam{
349138578Ssam	struct ieee80211com ic;
350289762Savos	struct ieee80211vap vap;
351289762Savos	struct ifnet ifp;
352138578Ssam	int i, pass, total;
353138578Ssam
354138578Ssam	memset(&ic, 0, sizeof(ic));
355289762Savos	memset(&vap, 0, sizeof(vap));
356289762Savos	memset(&ifp, 0, sizeof(ifp));
357289762Savos
358138578Ssam	ieee80211_crypto_attach(&ic);
359138578Ssam
360289762Savos	/* some minimal initialization */
361289762Savos	strncpy(ifp.if_xname, "test_ccmp", sizeof(ifp.if_xname));
362289762Savos	vap.iv_ic = &ic;
363289762Savos	vap.iv_ifp = &ifp;
364289762Savos	if (debug)
365289762Savos		vap.iv_debug = IEEE80211_MSG_CRYPTO;
366289762Savos	ieee80211_crypto_vattach(&vap);
367289762Savos
368138578Ssam	pass = 0;
369138578Ssam	total = 0;
370289762Savos	for (i = 0; i < nitems(tkiptests); i++)
371138578Ssam		if (tests & (1<<i)) {
372138578Ssam			total++;
373289762Savos			pass += runtest(&vap, &tkiptests[i]);
374138578Ssam		}
375138578Ssam	printf("%u of %u 802.11i TKIP test vectors passed\n", pass, total);
376289762Savos
377289762Savos	ieee80211_crypto_vdetach(&vap);
378138578Ssam	ieee80211_crypto_detach(&ic);
379289762Savos
380138578Ssam	return (pass == total ? 0 : -1);
381138578Ssam}
382138578Ssam
383138578Ssamstatic int
384138578Ssamtest_tkip_modevent(module_t mod, int type, void *unused)
385138578Ssam{
386138578Ssam	switch (type) {
387138578Ssam	case MOD_LOAD:
388138578Ssam		(void) init_crypto_tkip_test();
389138578Ssam		return 0;
390138578Ssam	case MOD_UNLOAD:
391138578Ssam		return 0;
392138578Ssam	}
393138578Ssam	return EINVAL;
394138578Ssam}
395138578Ssam
396138578Ssamstatic moduledata_t test_tkip_mod = {
397138578Ssam	"test_tkip",
398138578Ssam	test_tkip_modevent,
399241394Skevlo	0
400138578Ssam};
401138578SsamDECLARE_MODULE(test_tkip, test_tkip_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
402138578SsamMODULE_VERSION(test_tkip, 1);
403138578SsamMODULE_DEPEND(test_tkip, wlan, 1, 1, 1);
404