1219019Sgabor/*-
2219019Sgabor * Copyright (c) 2004 Sam Leffler, Errno Consulting
3219019Sgabor * All rights reserved.
4219019Sgabor *
5219019Sgabor * Redistribution and use in source and binary forms, with or without
6219019Sgabor * modification, are permitted provided that the following conditions
7219019Sgabor * are met:
8219019Sgabor * 1. Redistributions of source code must retain the above copyright
9219019Sgabor *    notice, this list of conditions and the following disclaimer.
10219019Sgabor * 2. Redistributions in binary form must reproduce the above copyright
11219019Sgabor *    notice, this list of conditions and the following disclaimer in the
12219019Sgabor *    documentation and/or other materials provided with the distribution.
13219019Sgabor * 3. The name of the author may not be used to endorse or promote products
14219019Sgabor *    derived from this software without specific prior written permission.
15219019Sgabor *
16219019Sgabor * Alternatively, this software may be distributed under the terms of the
17219019Sgabor * GNU General Public License ("GPL") version 2 as published by the Free
18219019Sgabor * Software Foundation.
19219019Sgabor *
20219019Sgabor * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21219019Sgabor * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22219019Sgabor * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23219019Sgabor * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24219019Sgabor * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25219019Sgabor * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26219019Sgabor * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27219019Sgabor * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28219019Sgabor * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29219019Sgabor * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30219019Sgabor *
31219019Sgabor * $FreeBSD$
32219019Sgabor */
33219019Sgabor
34219019Sgabor/*
35219019Sgabor * WEP test module.
36219019Sgabor *
37219019Sgabor * Test vectors come from section I.7.2 of P802.11i/D7.0, October 2003.
38219019Sgabor *
39219019Sgabor * To use this tester load the net80211 layer (either as a module or
40219019Sgabor * by statically configuring it into your kernel), then insmod this
41219019Sgabor * module.  It should automatically run all test cases and print
42219019Sgabor * information for each.  To run one or more tests you can specify a
43219019Sgabor * tests parameter to the module that is a bit mask of the set of tests
44219019Sgabor * you want; e.g. insmod wep_test tests=7 will run only test mpdu's
45219019Sgabor * 1, 2, and 3.
46219019Sgabor */
47219019Sgabor#include <sys/param.h>
48219019Sgabor#include <sys/kernel.h>
49219019Sgabor#include <sys/systm.h>
50219019Sgabor#include <sys/mbuf.h>
51219019Sgabor#include <sys/module.h>
52219019Sgabor
53219019Sgabor#include <sys/socket.h>
54219019Sgabor
55219019Sgabor#include <net/if.h>
56219019Sgabor#include <net/if_media.h>
57219019Sgabor
58219019Sgabor#include <net80211/ieee80211_var.h>
59219019Sgabor
60219019Sgabor/*
61219019SgaborMPDU data
62219019Sgabor aa aa 03 00 00 00 08 00 45 00 00 4e 66 1a 00 00 80 11 be 64 0a 00 01 22
63219019Sgabor 0a ff ff ff 00 89 00 89 00 3a 00 00 80 a6 01 10 00 01 00 00 00 00 00 00
64219019Sgabor 20 45 43 45 4a 45 48 45 43 46 43 45 50 46 45 45 49 45 46 46 43 43 41 43
65283908Stijl 41 43 41 43 41 43 41 41 41 00 00 20 00 01
66219019Sgabor
67219019SgaborRC4 encryption is performed as follows:
68219019Sgabor17
69219019Sgabor18  Key  fb 02 9e 30 31 32 33 34
70219019SgaborPlaintext
71219019Sgabor aa aa 03 00 00 00 08 00 45 00 00 4e 66 1a 00 00 80 11 be 64 0a 00 01
72219019Sgabor 22 0a ff ff ff 00 89 00 89 00 3a 00 00 80 a6 01 10 00 01 00 00 00 00
73219019Sgabor 00 00 20 45 43 45 4a 45 48 45 43 46 43 45 50 46 45 45 49 45 46 46 43
74219019Sgabor 43 41 43 41 43 41 43 41 43 41 41 41 00 00 20 00 01 1b d0 b6 04
75219019SgaborCiphertext
76219019Sgabor f6 9c 58 06 bd 6c e8 46 26 bc be fb 94 74 65 0a ad 1f 79 09 b0 f6 4d
77219019Sgabor 5f 58 a5 03 a2 58 b7 ed 22 eb 0e a6 49 30 d3 a0 56 a5 57 42 fc ce 14
78219019Sgabor 1d 48 5f 8a a8 36 de a1 8d f4 2c 53 80 80 5a d0 c6 1a 5d 6f 58 f4 10
79219019Sgabor 40 b2 4b 7d 1a 69 38 56 ed 0d 43 98 e7 ae e3 bf 0e 2a 2c a8 f7
80219019SgaborThe plaintext consists of the MPDU data, followed by a 4-octet CRC-32
81219019Sgaborcalculated over the MPDU data.
82219019Sgabor19  The expanded MPDU, after WEP encapsulation, is as follows:
83219019Sgabor20
84219019Sgabor21  IV  fb 02 9e 80
85219019SgaborMPDU  data
86219019Sgabor f6 9c 58 06 bd 6c e8 46 26 bc be fb 94 74 65 0a ad 1f 79 09 b0 f6 4d 5f 58 a5
87219019Sgabor 03 a2 58 b7 ed 22 eb 0e a6 49 30 d3 a0 56 a5 57 42 fc ce 14 1d 48 5f 8a a8 36
88219019Sgabor de a1 8d f4 2c 53 80 80 5a d0 c6 1a 5d 6f 58 f4 10 40 b2 4b 7d 1a 69 38 56 ed
89260264Sdim 0d 43 98 e7 ae e3 bf 0e
90219019SgaborICV  2a 2c a8 f7
91219019Sgabor*/
92219019Sgaborstatic const u_int8_t test1_key[] = {		/* TK (w/o IV) */
93219019Sgabor	0x30, 0x31, 0x32, 0x33, 0x34,
94219019Sgabor};
95219019Sgaborstatic const u_int8_t test1_plaintext[] = {	/* Plaintext MPDU */
96219019Sgabor	0x08, 0x48, 0xc3, 0x2c, 0x0f, 0xd2, 0xe1, 0x28,	/* 802.11 Header */
97219019Sgabor	0xa5, 0x7c, 0x50, 0x30, 0xf1, 0x84, 0x44, 0x08,
98219019Sgabor	0xab, 0xae, 0xa5, 0xb8, 0xfc, 0xba, 0x80, 0x33,
99219019Sgabor	0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00,	/* Plaintext data */
100219019Sgabor	0x45, 0x00, 0x00, 0x4e, 0x66, 0x1a, 0x00, 0x00,
101219019Sgabor	0x80, 0x11, 0xbe, 0x64, 0x0a, 0x00, 0x01, 0x22,
102219019Sgabor	0x0a, 0xff, 0xff, 0xff, 0x00, 0x89, 0x00, 0x89,
103219019Sgabor	0x00, 0x3a, 0x00, 0x00, 0x80, 0xa6, 0x01, 0x10,
104219019Sgabor	0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
105219019Sgabor	0x20, 0x45, 0x43, 0x45, 0x4a, 0x45, 0x48, 0x45,
106219019Sgabor	0x43, 0x46, 0x43, 0x45, 0x50, 0x46, 0x45, 0x45,
107260264Sdim	0x49, 0x45, 0x46, 0x46, 0x43, 0x43, 0x41, 0x43,
108219019Sgabor	0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x41,
109219019Sgabor	0x41, 0x00, 0x00, 0x20, 0x00, 0x01,
110219019Sgabor};
111219019Sgaborstatic const u_int8_t test1_encrypted[] = {	/* Encrypted MPDU */
112219019Sgabor	0x08, 0x48, 0xc3, 0x2c, 0x0f, 0xd2, 0xe1, 0x28,
113219019Sgabor	0xa5, 0x7c, 0x50, 0x30, 0xf1, 0x84, 0x44, 0x08,
114219019Sgabor	0xab, 0xae, 0xa5, 0xb8, 0xfc, 0xba, 0x80, 0x33,
115219019Sgabor	0xfb, 0x02, 0x9e, 0x80, 0xf6, 0x9c, 0x58, 0x06,
116219019Sgabor	0xbd, 0x6c, 0xe8, 0x46, 0x26, 0xbc, 0xbe, 0xfb,
117258496Stijl	0x94, 0x74, 0x65, 0x0a, 0xad, 0x1f, 0x79, 0x09,
118219019Sgabor	0xb0, 0xf6, 0x4d, 0x5f, 0x58, 0xa5, 0x03, 0xa2,
119258496Stijl	0x58, 0xb7, 0xed, 0x22, 0xeb, 0x0e, 0xa6, 0x49,
120219019Sgabor	0x30, 0xd3, 0xa0, 0x56, 0xa5, 0x57, 0x42, 0xfc,
121219019Sgabor	0xce, 0x14, 0x1d, 0x48, 0x5f, 0x8a, 0xa8, 0x36,
122219019Sgabor	0xde, 0xa1, 0x8d, 0xf4, 0x2c, 0x53, 0x80, 0x80,
123219019Sgabor	0x5a, 0xd0, 0xc6, 0x1a, 0x5d, 0x6f, 0x58, 0xf4,
124219019Sgabor	0x10, 0x40, 0xb2, 0x4b, 0x7d, 0x1a, 0x69, 0x38,
125219019Sgabor	0x56, 0xed, 0x0d, 0x43, 0x98, 0xe7, 0xae, 0xe3,
126219019Sgabor	0xbf, 0x0e, 0x2a, 0x2c, 0xa8, 0xf7,
127219019Sgabor};
128219019Sgabor
129219019Sgabor/* XXX fix byte order of iv */
130219019Sgabor#define	TEST(n,name,cipher,keyix,iv0,iv1,iv2,iv3) { \
131219019Sgabor	name, IEEE80211_CIPHER_##cipher,keyix, { iv2,iv1,iv0,iv3 }, \
132219019Sgabor	test##n##_key,   sizeof(test##n##_key), \
133219019Sgabor	test##n##_plaintext, sizeof(test##n##_plaintext), \
134219019Sgabor	test##n##_encrypted, sizeof(test##n##_encrypted) \
135219019Sgabor}
136219019Sgabor
137219019Sgaborstruct ciphertest {
138219019Sgabor	const char	*name;
139219019Sgabor	int		cipher;
140219019Sgabor	int		keyix;
141219019Sgabor	u_int8_t	iv[4];
142219019Sgabor	const u_int8_t	*key;
143219019Sgabor	size_t		key_len;
144219019Sgabor	const u_int8_t	*plaintext;
145219019Sgabor	size_t		plaintext_len;
146219019Sgabor	const u_int8_t	*encrypted;
147219019Sgabor	size_t		encrypted_len;
148219019Sgabor} weptests[] = {
149219019Sgabor	TEST(1, "WEP test mpdu 1", WEP, 2, 0xfb, 0x02, 0x9e, 0x80),
150219019Sgabor};
151219019Sgabor
152219019Sgaborstatic void
153282275Stijldumpdata(const char *tag, const void *p, size_t len)
154219019Sgabor{
155219019Sgabor	int i;
156282275Stijl
157219019Sgabor	printf("%s: 0x%p len %u", tag, p, len);
158219019Sgabor	for (i = 0; i < len; i++) {
159283908Stijl		if ((i % 16) == 0)
160219019Sgabor			printf("\n%03d:", i);
161219019Sgabor		printf(" %02x", ((const u_int8_t *)p)[i]);
162219019Sgabor	}
163219019Sgabor	printf("\n");
164219019Sgabor}
165219019Sgabor
166219019Sgaborstatic void
167219019Sgaborcmpfail(const void *gen, size_t genlen, const void *ref, size_t reflen)
168219019Sgabor{
169219019Sgabor	int i;
170219019Sgabor
171219019Sgabor	for (i = 0; i < genlen; i++)
172219019Sgabor		if (((const u_int8_t *)gen)[i] != ((const u_int8_t *)ref)[i]) {
173219019Sgabor			printf("first difference at byte %u\n", i);
174219019Sgabor			break;
175219019Sgabor		}
176219019Sgabor	dumpdata("Generated", gen, genlen);
177219019Sgabor	dumpdata("Reference", ref, reflen);
178219019Sgabor}
179219019Sgabor
180219019Sgaborstruct wep_ctx_hw {			/* for use with h/w support */
181219019Sgabor	struct ieee80211com *wc_ic;	/* for diagnostics */
182219019Sgabor	u_int32_t	wc_iv;		/* initial vector for crypto */
183219019Sgabor};
184219019Sgabor
185219019Sgaborstatic int
186219019Sgaborruntest(struct ieee80211com *ic, struct ciphertest *t)
187219019Sgabor{
188219019Sgabor	struct ieee80211_key key;
189219019Sgabor	struct mbuf *m = NULL;
190219019Sgabor	const struct ieee80211_cipher *cip;
191219019Sgabor	u_int8_t mac[IEEE80211_ADDR_LEN];
192219019Sgabor	struct wep_ctx_hw *ctx;
193219019Sgabor
194219019Sgabor	printf("%s: ", t->name);
195219019Sgabor
196219019Sgabor	/*
197219019Sgabor	 * Setup key.
198219019Sgabor	 */
199219019Sgabor	memset(&key, 0, sizeof(key));
200219019Sgabor	key.wk_flags = IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV;
201219019Sgabor	key.wk_cipher = &ieee80211_cipher_none;
202219019Sgabor	if (!ieee80211_crypto_newkey(ic, t->cipher,
203258496Stijl	    IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV, &key)) {
204258496Stijl		printf("FAIL: ieee80211_crypto_newkey failed\n");
205258496Stijl		goto bad;
206219019Sgabor	}
207219019Sgabor
208219019Sgabor	memcpy(key.wk_key, t->key, t->key_len);
209219019Sgabor	key.wk_keylen = t->key_len;
210219019Sgabor	if (!ieee80211_crypto_setkey(ic, &key, mac)) {
211219019Sgabor		printf("FAIL: ieee80211_crypto_setkey failed\n");
212219019Sgabor		goto bad;
213219019Sgabor	}
214219019Sgabor	cip = key.wk_cipher;
215219019Sgabor
216219019Sgabor	/*
217219019Sgabor	 * Craft frame from plaintext data.
218219019Sgabor	 */
219219019Sgabor	cip = key.wk_cipher;
220219019Sgabor	m = m_getcl(M_NOWAIT, MT_HEADER, M_PKTHDR);
221219019Sgabor	memcpy(mtod(m, void *), t->encrypted, t->encrypted_len);
222219019Sgabor	m->m_len = t->encrypted_len;
223219019Sgabor	m->m_pkthdr.len = m->m_len;
224219019Sgabor
225219019Sgabor	/*
226219019Sgabor	 * Decrypt frame.
227219019Sgabor	 */
228219019Sgabor	if (!cip->ic_decap(&key, m)) {
229219019Sgabor		printf("FAIL: wep decap failed\n");
230219019Sgabor		cmpfail(mtod(m, const void *), m->m_pkthdr.len,
231219019Sgabor			t->plaintext, t->plaintext_len);
232219019Sgabor		goto bad;
233219019Sgabor	}
234219019Sgabor	/*
235219019Sgabor	 * Verify: frame length, frame contents.
236219019Sgabor	 */
237219019Sgabor	if (m->m_pkthdr.len != t->plaintext_len) {
238219019Sgabor		printf("FAIL: decap botch; length mismatch\n");
239219019Sgabor		cmpfail(mtod(m, const void *), m->m_pkthdr.len,
240219019Sgabor			t->plaintext, t->plaintext_len);
241219019Sgabor		goto bad;
242282275Stijl	} else if (memcmp(mtod(m, const void *), t->plaintext, t->plaintext_len)) {
243219019Sgabor		printf("FAIL: decap botch; data does not compare\n");
244219019Sgabor		cmpfail(mtod(m, const void *), m->m_pkthdr.len,
245219019Sgabor			t->plaintext, t->plaintext_len);
246219019Sgabor		goto bad;
247219019Sgabor	}
248219019Sgabor
249219019Sgabor	/*
250219019Sgabor	 * Encrypt frame.
251219019Sgabor	 */
252219019Sgabor	ctx = (struct wep_ctx_hw *) key.wk_private;
253219019Sgabor	memcpy(&ctx->wc_iv, t->iv, sizeof(t->iv));	/* for encap/encrypt */
254219019Sgabor	if (!cip->ic_encap(&key, m, t->keyix<<6)) {
255283908Stijl		printf("FAIL: wep encap failed\n");
256283908Stijl		goto bad;
257283908Stijl	}
258283908Stijl	/*
259219019Sgabor	 * Verify: frame length, frame contents.
260283908Stijl	 */
261283908Stijl	if (m->m_pkthdr.len != t->encrypted_len) {
262283908Stijl		printf("FAIL: encap data length mismatch\n");
263283908Stijl		cmpfail(mtod(m, const void *), m->m_pkthdr.len,
264283908Stijl			t->encrypted, t->encrypted_len);
265283908Stijl		goto bad;
266283908Stijl	} else if (memcmp(mtod(m, const void *), t->encrypted, m->m_pkthdr.len)) {
267283908Stijl		printf("FAIL: encrypt data does not compare\n");
268258496Stijl		cmpfail(mtod(m, const void *), m->m_pkthdr.len,
269219019Sgabor			t->encrypted, t->encrypted_len);
270283908Stijl		dumpdata("Plaintext", t->plaintext, t->plaintext_len);
271219019Sgabor		goto bad;
272219019Sgabor	}
273219019Sgabor	m_freem(m);
274219019Sgabor	ieee80211_crypto_delkey(ic, &key);
275219019Sgabor	printf("PASS\n");
276283908Stijl	return 1;
277283908Stijlbad:
278283908Stijl	if (m != NULL)
279283908Stijl		m_freem(m);
280219019Sgabor	ieee80211_crypto_delkey(ic, &key);
281219019Sgabor	return 0;
282219019Sgabor}
283219019Sgabor
284219019Sgabor/*
285219019Sgabor * Module glue.
286219019Sgabor */
287219019Sgabor
288219019Sgaborstatic	int tests = -1;
289219019Sgaborstatic	int debug = 0;
290219019Sgabor
291219019Sgaborstatic int
292219019Sgaborinit_crypto_wep_test(void)
293219019Sgabor{
294219019Sgabor#define	N(a)	(sizeof(a)/sizeof(a[0]))
295219019Sgabor	struct ieee80211com ic;
296219019Sgabor	int i, pass, total;
297219019Sgabor
298219019Sgabor	memset(&ic, 0, sizeof(ic));
299219019Sgabor	if (debug)
300219019Sgabor		ic.ic_debug = IEEE80211_MSG_CRYPTO;
301219019Sgabor	ieee80211_crypto_attach(&ic);
302219019Sgabor	pass = 0;
303219019Sgabor	total = 0;
304219019Sgabor	for (i = 0; i < N(weptests); i++)
305219019Sgabor		if (tests & (1<<i)) {
306219019Sgabor			total++;
307219019Sgabor			pass += runtest(&ic, &weptests[i]);
308219019Sgabor		}
309219019Sgabor	printf("%u of %u 802.11i WEP test vectors passed\n", pass, total);
310219019Sgabor	ieee80211_crypto_detach(&ic);
311219019Sgabor	return (pass == total ? 0 : -1);
312219019Sgabor#undef N
313219019Sgabor}
314219019Sgabor
315219019Sgaborstatic int
316219019Sgabortest_wep_modevent(module_t mod, int type, void *unused)
317219019Sgabor{
318219019Sgabor	switch (type) {
319219019Sgabor	case MOD_LOAD:
320219019Sgabor		(void) init_crypto_wep_test();
321219019Sgabor		return 0;
322219019Sgabor	case MOD_UNLOAD:
323219019Sgabor		return 0;
324219019Sgabor	}
325219019Sgabor	return EINVAL;
326219019Sgabor}
327219019Sgabor
328219019Sgaborstatic moduledata_t test_wep_mod = {
329219019Sgabor	"test_wep",
330219019Sgabor	test_wep_modevent,
331219019Sgabor	0
332219019Sgabor};
333219019SgaborDECLARE_MODULE(test_wep, test_wep_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
334219019SgaborMODULE_VERSION(test_wep, 1);
335219019SgaborMODULE_DEPEND(test_wep, wlan, 1, 1, 1);
336219019Sgabor