1/*-
2 * Copyright (c) 2004 Sam Leffler, Errno Consulting
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 *    derived from this software without specific prior written permission.
15 *
16 * Alternatively, this software may be distributed under the terms of the
17 * GNU General Public License ("GPL") version 2 as published by the Free
18 * Software Foundation.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 *
31 * $FreeBSD$
32 */
33
34/*
35 * WEP test module.
36 *
37 * Test vectors come from section I.7.2 of P802.11i/D7.0, October 2003.
38 *
39 * To use this tester load the net80211 layer (either as a module or
40 * by statically configuring it into your kernel), then insmod this
41 * module.  It should automatically run all test cases and print
42 * information for each.  To run one or more tests you can specify a
43 * tests parameter to the module that is a bit mask of the set of tests
44 * you want; e.g. insmod wep_test tests=7 will run only test mpdu's
45 * 1, 2, and 3.
46 */
47#include <sys/param.h>
48#include <sys/kernel.h>
49#include <sys/systm.h>
50#include <sys/mbuf.h>
51#include <sys/module.h>
52
53#include <sys/socket.h>
54
55#include <net/if.h>
56#include <net/if_var.h>
57#include <net/if_media.h>
58
59#include <net80211/ieee80211_var.h>
60
61/*
62MPDU data
63 aa aa 03 00 00 00 08 00 45 00 00 4e 66 1a 00 00 80 11 be 64 0a 00 01 22
64 0a ff ff ff 00 89 00 89 00 3a 00 00 80 a6 01 10 00 01 00 00 00 00 00 00
65 20 45 43 45 4a 45 48 45 43 46 43 45 50 46 45 45 49 45 46 46 43 43 41 43
66 41 43 41 43 41 43 41 41 41 00 00 20 00 01
67
68RC4 encryption is performed as follows:
6917
7018  Key  fb 02 9e 30 31 32 33 34
71Plaintext
72 aa aa 03 00 00 00 08 00 45 00 00 4e 66 1a 00 00 80 11 be 64 0a 00 01
73 22 0a ff ff ff 00 89 00 89 00 3a 00 00 80 a6 01 10 00 01 00 00 00 00
74 00 00 20 45 43 45 4a 45 48 45 43 46 43 45 50 46 45 45 49 45 46 46 43
75 43 41 43 41 43 41 43 41 43 41 41 41 00 00 20 00 01 1b d0 b6 04
76Ciphertext
77 f6 9c 58 06 bd 6c e8 46 26 bc be fb 94 74 65 0a ad 1f 79 09 b0 f6 4d
78 5f 58 a5 03 a2 58 b7 ed 22 eb 0e a6 49 30 d3 a0 56 a5 57 42 fc ce 14
79 1d 48 5f 8a a8 36 de a1 8d f4 2c 53 80 80 5a d0 c6 1a 5d 6f 58 f4 10
80 40 b2 4b 7d 1a 69 38 56 ed 0d 43 98 e7 ae e3 bf 0e 2a 2c a8 f7
81The plaintext consists of the MPDU data, followed by a 4-octet CRC-32
82calculated over the MPDU data.
8319  The expanded MPDU, after WEP encapsulation, is as follows:
8420
8521  IV  fb 02 9e 80
86MPDU  data
87 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
88 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
89 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
90 0d 43 98 e7 ae e3 bf 0e
91ICV  2a 2c a8 f7
92*/
93static const u_int8_t test1_key[] = {		/* TK (w/o IV) */
94	0x30, 0x31, 0x32, 0x33, 0x34,
95};
96static const u_int8_t test1_plaintext[] = {	/* Plaintext MPDU */
97	0x08, 0x48, 0xc3, 0x2c, 0x0f, 0xd2, 0xe1, 0x28,	/* 802.11 Header */
98	0xa5, 0x7c, 0x50, 0x30, 0xf1, 0x84, 0x44, 0x08,
99	0xab, 0xae, 0xa5, 0xb8, 0xfc, 0xba, 0x80, 0x33,
100	0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00,	/* Plaintext data */
101	0x45, 0x00, 0x00, 0x4e, 0x66, 0x1a, 0x00, 0x00,
102	0x80, 0x11, 0xbe, 0x64, 0x0a, 0x00, 0x01, 0x22,
103	0x0a, 0xff, 0xff, 0xff, 0x00, 0x89, 0x00, 0x89,
104	0x00, 0x3a, 0x00, 0x00, 0x80, 0xa6, 0x01, 0x10,
105	0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
106	0x20, 0x45, 0x43, 0x45, 0x4a, 0x45, 0x48, 0x45,
107	0x43, 0x46, 0x43, 0x45, 0x50, 0x46, 0x45, 0x45,
108	0x49, 0x45, 0x46, 0x46, 0x43, 0x43, 0x41, 0x43,
109	0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x41,
110	0x41, 0x00, 0x00, 0x20, 0x00, 0x01,
111};
112static const u_int8_t test1_encrypted[] = {	/* Encrypted MPDU */
113	0x08, 0x48, 0xc3, 0x2c, 0x0f, 0xd2, 0xe1, 0x28,
114	0xa5, 0x7c, 0x50, 0x30, 0xf1, 0x84, 0x44, 0x08,
115	0xab, 0xae, 0xa5, 0xb8, 0xfc, 0xba, 0x80, 0x33,
116	0xfb, 0x02, 0x9e, 0x80, 0xf6, 0x9c, 0x58, 0x06,
117	0xbd, 0x6c, 0xe8, 0x46, 0x26, 0xbc, 0xbe, 0xfb,
118	0x94, 0x74, 0x65, 0x0a, 0xad, 0x1f, 0x79, 0x09,
119	0xb0, 0xf6, 0x4d, 0x5f, 0x58, 0xa5, 0x03, 0xa2,
120	0x58, 0xb7, 0xed, 0x22, 0xeb, 0x0e, 0xa6, 0x49,
121	0x30, 0xd3, 0xa0, 0x56, 0xa5, 0x57, 0x42, 0xfc,
122	0xce, 0x14, 0x1d, 0x48, 0x5f, 0x8a, 0xa8, 0x36,
123	0xde, 0xa1, 0x8d, 0xf4, 0x2c, 0x53, 0x80, 0x80,
124	0x5a, 0xd0, 0xc6, 0x1a, 0x5d, 0x6f, 0x58, 0xf4,
125	0x10, 0x40, 0xb2, 0x4b, 0x7d, 0x1a, 0x69, 0x38,
126	0x56, 0xed, 0x0d, 0x43, 0x98, 0xe7, 0xae, 0xe3,
127	0xbf, 0x0e, 0x2a, 0x2c, 0xa8, 0xf7,
128};
129
130/* XXX fix byte order of iv */
131#define	TEST(n,name,cipher,keyix,iv0,iv1,iv2,iv3) { \
132	name, IEEE80211_CIPHER_##cipher,keyix, { iv2,iv1,iv0,iv3 }, \
133	test##n##_key,   sizeof(test##n##_key), \
134	test##n##_plaintext, sizeof(test##n##_plaintext), \
135	test##n##_encrypted, sizeof(test##n##_encrypted) \
136}
137
138struct ciphertest {
139	const char	*name;
140	int		cipher;
141	int		keyix;
142	u_int8_t	iv[4];
143	const u_int8_t	*key;
144	size_t		key_len;
145	const u_int8_t	*plaintext;
146	size_t		plaintext_len;
147	const u_int8_t	*encrypted;
148	size_t		encrypted_len;
149} weptests[] = {
150	TEST(1, "WEP test mpdu 1", WEP, 2, 0xfb, 0x02, 0x9e, 0x80),
151};
152
153static void
154dumpdata(const char *tag, const void *p, size_t len)
155{
156	int i;
157
158	printf("%s: 0x%p len %u", tag, p, len);
159	for (i = 0; i < len; i++) {
160		if ((i % 16) == 0)
161			printf("\n%03d:", i);
162		printf(" %02x", ((const u_int8_t *)p)[i]);
163	}
164	printf("\n");
165}
166
167static void
168cmpfail(const void *gen, size_t genlen, const void *ref, size_t reflen)
169{
170	int i;
171
172	for (i = 0; i < genlen; i++)
173		if (((const u_int8_t *)gen)[i] != ((const u_int8_t *)ref)[i]) {
174			printf("first difference at byte %u\n", i);
175			break;
176		}
177	dumpdata("Generated", gen, genlen);
178	dumpdata("Reference", ref, reflen);
179}
180
181struct wep_ctx_hw {			/* for use with h/w support */
182	struct ieee80211vap *wc_vap;	/* for diagnostics+statistics */
183	struct ieee80211com *wc_ic;
184	uint32_t        wc_iv;		/* initial vector for crypto */
185};
186
187static int
188runtest(struct ieee80211vap *vap, struct ciphertest *t)
189{
190	struct ieee80211_key *key = &vap->iv_nw_keys[t->keyix];
191	struct mbuf *m = NULL;
192	const struct ieee80211_cipher *cip;
193	struct wep_ctx_hw *ctx;
194	int hdrlen;
195
196	printf("%s: ", t->name);
197
198	/*
199	 * Setup key.
200	 */
201	memset(key, 0, sizeof(*key));
202	key->wk_flags = IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV;
203	key->wk_cipher = &ieee80211_cipher_none;
204	if (!ieee80211_crypto_newkey(vap, t->cipher,
205	    IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV, key)) {
206		printf("FAIL: ieee80211_crypto_newkey failed\n");
207		goto bad;
208	}
209
210	memcpy(key->wk_key, t->key, t->key_len);
211	key->wk_keylen = t->key_len;
212	if (!ieee80211_crypto_setkey(vap, key)) {
213		printf("FAIL: ieee80211_crypto_setkey failed\n");
214		goto bad;
215	}
216
217	/*
218	 * Craft frame from plaintext data.
219	 */
220	cip = key->wk_cipher;
221	m = m_getcl(M_NOWAIT, MT_HEADER, M_PKTHDR);
222	memcpy(mtod(m, void *), t->encrypted, t->encrypted_len);
223	m->m_len = t->encrypted_len;
224	m->m_pkthdr.len = m->m_len;
225	hdrlen = ieee80211_anyhdrsize(mtod(m, void *));
226
227	/*
228	 * Decrypt frame.
229	 */
230	if (!cip->ic_decap(key, m, hdrlen)) {
231		printf("FAIL: wep decap failed\n");
232		cmpfail(mtod(m, const void *), m->m_pkthdr.len,
233			t->plaintext, t->plaintext_len);
234		goto bad;
235	}
236	/*
237	 * Verify: frame length, frame contents.
238	 */
239	if (m->m_pkthdr.len != t->plaintext_len) {
240		printf("FAIL: decap botch; length mismatch\n");
241		cmpfail(mtod(m, const void *), m->m_pkthdr.len,
242			t->plaintext, t->plaintext_len);
243		goto bad;
244	} else if (memcmp(mtod(m, const void *), t->plaintext, t->plaintext_len)) {
245		printf("FAIL: decap botch; data does not compare\n");
246		cmpfail(mtod(m, const void *), m->m_pkthdr.len,
247			t->plaintext, t->plaintext_len);
248		goto bad;
249	}
250
251	/*
252	 * Encrypt frame.
253	 */
254	ctx = (struct wep_ctx_hw *) key->wk_private;
255	ctx->wc_vap = vap;
256	ctx->wc_ic = vap->iv_ic;
257	memcpy(&ctx->wc_iv, t->iv, sizeof(t->iv));	/* for encap/encrypt */
258	if (!cip->ic_encap(key, m)) {
259		printf("FAIL: wep encap failed\n");
260		goto bad;
261	}
262	/*
263	 * Verify: frame length, frame contents.
264	 */
265	if (m->m_pkthdr.len != t->encrypted_len) {
266		printf("FAIL: encap data length mismatch\n");
267		cmpfail(mtod(m, const void *), m->m_pkthdr.len,
268			t->encrypted, t->encrypted_len);
269		goto bad;
270	} else if (memcmp(mtod(m, const void *), t->encrypted, m->m_pkthdr.len)) {
271		printf("FAIL: encrypt data does not compare\n");
272		cmpfail(mtod(m, const void *), m->m_pkthdr.len,
273			t->encrypted, t->encrypted_len);
274		dumpdata("Plaintext", t->plaintext, t->plaintext_len);
275		goto bad;
276	}
277	m_freem(m);
278	ieee80211_crypto_delkey(vap, key);
279	printf("PASS\n");
280	return 1;
281bad:
282	if (m != NULL)
283		m_freem(m);
284	ieee80211_crypto_delkey(vap, key);
285	return 0;
286}
287
288/*
289 * Module glue.
290 */
291
292static	int tests = -1;
293static	int debug = 0;
294
295static int
296init_crypto_wep_test(void)
297{
298	struct ieee80211com ic;
299	struct ieee80211vap vap;
300	struct ifnet ifp;
301	int i, pass, total;
302
303	memset(&ic, 0, sizeof(ic));
304	memset(&vap, 0, sizeof(vap));
305	memset(&ifp, 0, sizeof(ifp));
306
307	ieee80211_crypto_attach(&ic);
308
309	/* some minimal initialization */
310	strncpy(ifp.if_xname, "test_ccmp", sizeof(ifp.if_xname));
311	vap.iv_ic = &ic;
312	vap.iv_ifp = &ifp;
313	if (debug)
314		vap.iv_debug = IEEE80211_MSG_CRYPTO;
315	ieee80211_crypto_vattach(&vap);
316
317	pass = 0;
318	total = 0;
319	for (i = 0; i < nitems(weptests); i++)
320		if (tests & (1<<i)) {
321			total++;
322			pass += runtest(&vap, &weptests[i]);
323		}
324	printf("%u of %u 802.11i WEP test vectors passed\n", pass, total);
325
326	ieee80211_crypto_vdetach(&vap);
327	ieee80211_crypto_detach(&ic);
328
329	return (pass == total ? 0 : -1);
330}
331
332static int
333test_wep_modevent(module_t mod, int type, void *unused)
334{
335	switch (type) {
336	case MOD_LOAD:
337		(void) init_crypto_wep_test();
338		return 0;
339	case MOD_UNLOAD:
340		return 0;
341	}
342	return EINVAL;
343}
344
345static moduledata_t test_wep_mod = {
346	"test_wep",
347	test_wep_modevent,
348	0
349};
350DECLARE_MODULE(test_wep, test_wep_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
351MODULE_VERSION(test_wep, 1);
352MODULE_DEPEND(test_wep, wlan, 1, 1, 1);
353