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 /*
62 MPDU 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 
68 RC4 encryption is performed as follows:
69 17
70 18  Key  fb 02 9e 30 31 32 33 34
71 Plaintext
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
76 Ciphertext
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
81 The plaintext consists of the MPDU data, followed by a 4-octet CRC-32
82 calculated over the MPDU data.
83 19  The expanded MPDU, after WEP encapsulation, is as follows:
84 20
85 21  IV  fb 02 9e 80
86 MPDU  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
91 ICV  2a 2c a8 f7
92 */
93 static const u_int8_t test1_key[] = {		/* TK (w/o IV) */
94 	0x30, 0x31, 0x32, 0x33, 0x34,
95 };
96 static 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 };
112 static 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 
138 struct 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 
153 static void
154 dumpdata(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 
167 static void
168 cmpfail(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 
181 struct 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 
187 static int
188 runtest(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;
281 bad:
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 
292 static	int tests = -1;
293 static	int debug = 0;
294 
295 static int
296 init_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 
332 static int
333 test_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 
345 static moduledata_t test_wep_mod = {
346 	"test_wep",
347 	test_wep_modevent,
348 	0
349 };
350 DECLARE_MODULE(test_wep, test_wep_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
351 MODULE_VERSION(test_wep, 1);
352 MODULE_DEPEND(test_wep, wlan, 1, 1, 1);
353