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: releng/10.3/tools/regression/net80211/wep/test_wep.c 269738 2014-08-08 19:39:40Z delphij $
32138578Ssam */
33138578Ssam
34138578Ssam/*
35138578Ssam * WEP test module.
36138578Ssam *
37138578Ssam * Test vectors come from section I.7.2 of P802.11i/D7.0, October 2003.
38138578Ssam *
39138578Ssam * To use this tester load the net80211 layer (either as a module or
40138578Ssam * by statically configuring it into your kernel), then insmod this
41138578Ssam * module.  It should automatically run all test cases and print
42138578Ssam * information for each.  To run one or more tests you can specify a
43138578Ssam * tests parameter to the module that is a bit mask of the set of tests
44138578Ssam * you want; e.g. insmod wep_test tests=7 will run only test mpdu's
45138578Ssam * 1, 2, and 3.
46138578Ssam */
47138578Ssam#include <sys/param.h>
48138578Ssam#include <sys/kernel.h>
49138578Ssam#include <sys/systm.h>
50138578Ssam#include <sys/mbuf.h>
51138578Ssam#include <sys/module.h>
52138578Ssam
53138578Ssam#include <sys/socket.h>
54138578Ssam
55138578Ssam#include <net/if.h>
56138578Ssam#include <net/if_media.h>
57138578Ssam
58138578Ssam#include <net80211/ieee80211_var.h>
59138578Ssam
60138578Ssam/*
61138578SsamMPDU data
62138578Ssam aa aa 03 00 00 00 08 00 45 00 00 4e 66 1a 00 00 80 11 be 64 0a 00 01 22
63138578Ssam 0a ff ff ff 00 89 00 89 00 3a 00 00 80 a6 01 10 00 01 00 00 00 00 00 00
64138578Ssam 20 45 43 45 4a 45 48 45 43 46 43 45 50 46 45 45 49 45 46 46 43 43 41 43
65138578Ssam 41 43 41 43 41 43 41 41 41 00 00 20 00 01
66138578Ssam
67138578SsamRC4 encryption is performed as follows:
68138578Ssam17
69138578Ssam18  Key  fb 02 9e 30 31 32 33 34
70138578SsamPlaintext
71138578Ssam aa aa 03 00 00 00 08 00 45 00 00 4e 66 1a 00 00 80 11 be 64 0a 00 01
72138578Ssam 22 0a ff ff ff 00 89 00 89 00 3a 00 00 80 a6 01 10 00 01 00 00 00 00
73138578Ssam 00 00 20 45 43 45 4a 45 48 45 43 46 43 45 50 46 45 45 49 45 46 46 43
74138578Ssam 43 41 43 41 43 41 43 41 43 41 41 41 00 00 20 00 01 1b d0 b6 04
75138578SsamCiphertext
76138578Ssam f6 9c 58 06 bd 6c e8 46 26 bc be fb 94 74 65 0a ad 1f 79 09 b0 f6 4d
77138578Ssam 5f 58 a5 03 a2 58 b7 ed 22 eb 0e a6 49 30 d3 a0 56 a5 57 42 fc ce 14
78138578Ssam 1d 48 5f 8a a8 36 de a1 8d f4 2c 53 80 80 5a d0 c6 1a 5d 6f 58 f4 10
79138578Ssam 40 b2 4b 7d 1a 69 38 56 ed 0d 43 98 e7 ae e3 bf 0e 2a 2c a8 f7
80138578SsamThe plaintext consists of the MPDU data, followed by a 4-octet CRC-32
81138578Ssamcalculated over the MPDU data.
82138578Ssam19  The expanded MPDU, after WEP encapsulation, is as follows:
83138578Ssam20
84138578Ssam21  IV  fb 02 9e 80
85138578SsamMPDU  data
86138578Ssam 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
87138578Ssam 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
88138578Ssam 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
89138578Ssam 0d 43 98 e7 ae e3 bf 0e
90138578SsamICV  2a 2c a8 f7
91138578Ssam*/
92138578Ssamstatic const u_int8_t test1_key[] = {		/* TK (w/o IV) */
93138578Ssam	0x30, 0x31, 0x32, 0x33, 0x34,
94138578Ssam};
95138578Ssamstatic const u_int8_t test1_plaintext[] = {	/* Plaintext MPDU */
96138578Ssam	0x08, 0x48, 0xc3, 0x2c, 0x0f, 0xd2, 0xe1, 0x28,	/* 802.11 Header */
97138578Ssam	0xa5, 0x7c, 0x50, 0x30, 0xf1, 0x84, 0x44, 0x08,
98138578Ssam	0xab, 0xae, 0xa5, 0xb8, 0xfc, 0xba, 0x80, 0x33,
99138578Ssam	0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00,	/* Plaintext data */
100138578Ssam	0x45, 0x00, 0x00, 0x4e, 0x66, 0x1a, 0x00, 0x00,
101138578Ssam	0x80, 0x11, 0xbe, 0x64, 0x0a, 0x00, 0x01, 0x22,
102138578Ssam	0x0a, 0xff, 0xff, 0xff, 0x00, 0x89, 0x00, 0x89,
103138578Ssam	0x00, 0x3a, 0x00, 0x00, 0x80, 0xa6, 0x01, 0x10,
104138578Ssam	0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
105138578Ssam	0x20, 0x45, 0x43, 0x45, 0x4a, 0x45, 0x48, 0x45,
106138578Ssam	0x43, 0x46, 0x43, 0x45, 0x50, 0x46, 0x45, 0x45,
107138578Ssam	0x49, 0x45, 0x46, 0x46, 0x43, 0x43, 0x41, 0x43,
108138578Ssam	0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x41,
109138578Ssam	0x41, 0x00, 0x00, 0x20, 0x00, 0x01,
110138578Ssam};
111138578Ssamstatic const u_int8_t test1_encrypted[] = {	/* Encrypted MPDU */
112138578Ssam	0x08, 0x48, 0xc3, 0x2c, 0x0f, 0xd2, 0xe1, 0x28,
113138578Ssam	0xa5, 0x7c, 0x50, 0x30, 0xf1, 0x84, 0x44, 0x08,
114138578Ssam	0xab, 0xae, 0xa5, 0xb8, 0xfc, 0xba, 0x80, 0x33,
115138578Ssam	0xfb, 0x02, 0x9e, 0x80, 0xf6, 0x9c, 0x58, 0x06,
116138578Ssam	0xbd, 0x6c, 0xe8, 0x46, 0x26, 0xbc, 0xbe, 0xfb,
117138578Ssam	0x94, 0x74, 0x65, 0x0a, 0xad, 0x1f, 0x79, 0x09,
118138578Ssam	0xb0, 0xf6, 0x4d, 0x5f, 0x58, 0xa5, 0x03, 0xa2,
119138578Ssam	0x58, 0xb7, 0xed, 0x22, 0xeb, 0x0e, 0xa6, 0x49,
120138578Ssam	0x30, 0xd3, 0xa0, 0x56, 0xa5, 0x57, 0x42, 0xfc,
121138578Ssam	0xce, 0x14, 0x1d, 0x48, 0x5f, 0x8a, 0xa8, 0x36,
122138578Ssam	0xde, 0xa1, 0x8d, 0xf4, 0x2c, 0x53, 0x80, 0x80,
123138578Ssam	0x5a, 0xd0, 0xc6, 0x1a, 0x5d, 0x6f, 0x58, 0xf4,
124138578Ssam	0x10, 0x40, 0xb2, 0x4b, 0x7d, 0x1a, 0x69, 0x38,
125138578Ssam	0x56, 0xed, 0x0d, 0x43, 0x98, 0xe7, 0xae, 0xe3,
126138578Ssam	0xbf, 0x0e, 0x2a, 0x2c, 0xa8, 0xf7,
127138578Ssam};
128138578Ssam
129138578Ssam/* XXX fix byte order of iv */
130138578Ssam#define	TEST(n,name,cipher,keyix,iv0,iv1,iv2,iv3) { \
131138578Ssam	name, IEEE80211_CIPHER_##cipher,keyix, { iv2,iv1,iv0,iv3 }, \
132138578Ssam	test##n##_key,   sizeof(test##n##_key), \
133138578Ssam	test##n##_plaintext, sizeof(test##n##_plaintext), \
134138578Ssam	test##n##_encrypted, sizeof(test##n##_encrypted) \
135138578Ssam}
136138578Ssam
137138578Ssamstruct ciphertest {
138138578Ssam	const char	*name;
139138578Ssam	int		cipher;
140138578Ssam	int		keyix;
141138578Ssam	u_int8_t	iv[4];
142138578Ssam	const u_int8_t	*key;
143138578Ssam	size_t		key_len;
144138578Ssam	const u_int8_t	*plaintext;
145138578Ssam	size_t		plaintext_len;
146138578Ssam	const u_int8_t	*encrypted;
147138578Ssam	size_t		encrypted_len;
148138578Ssam} weptests[] = {
149138578Ssam	TEST(1, "WEP test mpdu 1", WEP, 2, 0xfb, 0x02, 0x9e, 0x80),
150138578Ssam};
151138578Ssam
152138578Ssamstatic void
153138578Ssamdumpdata(const char *tag, const void *p, size_t len)
154138578Ssam{
155138578Ssam	int i;
156138578Ssam
157138578Ssam	printf("%s: 0x%p len %u", tag, p, len);
158138578Ssam	for (i = 0; i < len; i++) {
159138578Ssam		if ((i % 16) == 0)
160138578Ssam			printf("\n%03d:", i);
161138578Ssam		printf(" %02x", ((const u_int8_t *)p)[i]);
162138578Ssam	}
163138578Ssam	printf("\n");
164138578Ssam}
165138578Ssam
166138578Ssamstatic void
167138578Ssamcmpfail(const void *gen, size_t genlen, const void *ref, size_t reflen)
168138578Ssam{
169138578Ssam	int i;
170138578Ssam
171138578Ssam	for (i = 0; i < genlen; i++)
172138578Ssam		if (((const u_int8_t *)gen)[i] != ((const u_int8_t *)ref)[i]) {
173138578Ssam			printf("first difference at byte %u\n", i);
174138578Ssam			break;
175138578Ssam		}
176138578Ssam	dumpdata("Generated", gen, genlen);
177138578Ssam	dumpdata("Reference", ref, reflen);
178138578Ssam}
179138578Ssam
180138578Ssamstruct wep_ctx_hw {			/* for use with h/w support */
181138578Ssam	struct ieee80211com *wc_ic;	/* for diagnostics */
182138578Ssam	u_int32_t	wc_iv;		/* initial vector for crypto */
183138578Ssam};
184138578Ssam
185138578Ssamstatic int
186138578Ssamruntest(struct ieee80211com *ic, struct ciphertest *t)
187138578Ssam{
188138578Ssam	struct ieee80211_key key;
189138578Ssam	struct mbuf *m = NULL;
190138578Ssam	const struct ieee80211_cipher *cip;
191138578Ssam	u_int8_t mac[IEEE80211_ADDR_LEN];
192138578Ssam	struct wep_ctx_hw *ctx;
193138578Ssam
194138578Ssam	printf("%s: ", t->name);
195138578Ssam
196138578Ssam	/*
197138578Ssam	 * Setup key.
198138578Ssam	 */
199138578Ssam	memset(&key, 0, sizeof(key));
200138578Ssam	key.wk_flags = IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV;
201138578Ssam	key.wk_cipher = &ieee80211_cipher_none;
202145904Savatar	if (!ieee80211_crypto_newkey(ic, t->cipher,
203145904Savatar	    IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV, &key)) {
204138578Ssam		printf("FAIL: ieee80211_crypto_newkey failed\n");
205138578Ssam		goto bad;
206138578Ssam	}
207138578Ssam
208138578Ssam	memcpy(key.wk_key, t->key, t->key_len);
209138578Ssam	key.wk_keylen = t->key_len;
210138578Ssam	if (!ieee80211_crypto_setkey(ic, &key, mac)) {
211138578Ssam		printf("FAIL: ieee80211_crypto_setkey failed\n");
212138578Ssam		goto bad;
213138578Ssam	}
214138578Ssam	cip = key.wk_cipher;
215138578Ssam
216138578Ssam	/*
217138578Ssam	 * Craft frame from plaintext data.
218138578Ssam	 */
219138578Ssam	cip = key.wk_cipher;
220138578Ssam	m = m_getcl(M_NOWAIT, MT_HEADER, M_PKTHDR);
221138578Ssam	memcpy(mtod(m, void *), t->encrypted, t->encrypted_len);
222138578Ssam	m->m_len = t->encrypted_len;
223138578Ssam	m->m_pkthdr.len = m->m_len;
224138578Ssam
225138578Ssam	/*
226138578Ssam	 * Decrypt frame.
227138578Ssam	 */
228138578Ssam	if (!cip->ic_decap(&key, m)) {
229138578Ssam		printf("FAIL: wep decap failed\n");
230138578Ssam		cmpfail(mtod(m, const void *), m->m_pkthdr.len,
231138578Ssam			t->plaintext, t->plaintext_len);
232138578Ssam		goto bad;
233138578Ssam	}
234138578Ssam	/*
235138578Ssam	 * Verify: frame length, frame contents.
236138578Ssam	 */
237138578Ssam	if (m->m_pkthdr.len != t->plaintext_len) {
238138578Ssam		printf("FAIL: decap botch; length mismatch\n");
239138578Ssam		cmpfail(mtod(m, const void *), m->m_pkthdr.len,
240138578Ssam			t->plaintext, t->plaintext_len);
241138578Ssam		goto bad;
242138578Ssam	} else if (memcmp(mtod(m, const void *), t->plaintext, t->plaintext_len)) {
243138578Ssam		printf("FAIL: decap botch; data does not compare\n");
244138578Ssam		cmpfail(mtod(m, const void *), m->m_pkthdr.len,
245269738Sdelphij			t->plaintext, t->plaintext_len);
246138578Ssam		goto bad;
247138578Ssam	}
248138578Ssam
249138578Ssam	/*
250138578Ssam	 * Encrypt frame.
251138578Ssam	 */
252138578Ssam	ctx = (struct wep_ctx_hw *) key.wk_private;
253138578Ssam	memcpy(&ctx->wc_iv, t->iv, sizeof(t->iv));	/* for encap/encrypt */
254138578Ssam	if (!cip->ic_encap(&key, m, t->keyix<<6)) {
255138578Ssam		printf("FAIL: wep encap failed\n");
256138578Ssam		goto bad;
257138578Ssam	}
258138578Ssam	/*
259138578Ssam	 * Verify: frame length, frame contents.
260138578Ssam	 */
261138578Ssam	if (m->m_pkthdr.len != t->encrypted_len) {
262138578Ssam		printf("FAIL: encap data length mismatch\n");
263138578Ssam		cmpfail(mtod(m, const void *), m->m_pkthdr.len,
264138578Ssam			t->encrypted, t->encrypted_len);
265138578Ssam		goto bad;
266138578Ssam	} else if (memcmp(mtod(m, const void *), t->encrypted, m->m_pkthdr.len)) {
267138578Ssam		printf("FAIL: encrypt data does not compare\n");
268138578Ssam		cmpfail(mtod(m, const void *), m->m_pkthdr.len,
269138578Ssam			t->encrypted, t->encrypted_len);
270138578Ssam		dumpdata("Plaintext", t->plaintext, t->plaintext_len);
271138578Ssam		goto bad;
272138578Ssam	}
273138578Ssam	m_freem(m);
274138578Ssam	ieee80211_crypto_delkey(ic, &key);
275138578Ssam	printf("PASS\n");
276138578Ssam	return 1;
277138578Ssambad:
278138578Ssam	if (m != NULL)
279138578Ssam		m_freem(m);
280138578Ssam	ieee80211_crypto_delkey(ic, &key);
281138578Ssam	return 0;
282138578Ssam}
283138578Ssam
284138578Ssam/*
285138578Ssam * Module glue.
286138578Ssam */
287138578Ssam
288138578Ssamstatic	int tests = -1;
289138578Ssamstatic	int debug = 0;
290138578Ssam
291138578Ssamstatic int
292138578Ssaminit_crypto_wep_test(void)
293138578Ssam{
294138578Ssam#define	N(a)	(sizeof(a)/sizeof(a[0]))
295138578Ssam	struct ieee80211com ic;
296138578Ssam	int i, pass, total;
297138578Ssam
298138578Ssam	memset(&ic, 0, sizeof(ic));
299138578Ssam	if (debug)
300138578Ssam		ic.ic_debug = IEEE80211_MSG_CRYPTO;
301138578Ssam	ieee80211_crypto_attach(&ic);
302138578Ssam	pass = 0;
303138578Ssam	total = 0;
304138578Ssam	for (i = 0; i < N(weptests); i++)
305138578Ssam		if (tests & (1<<i)) {
306138578Ssam			total++;
307138578Ssam			pass += runtest(&ic, &weptests[i]);
308138578Ssam		}
309138578Ssam	printf("%u of %u 802.11i WEP test vectors passed\n", pass, total);
310138578Ssam	ieee80211_crypto_detach(&ic);
311138578Ssam	return (pass == total ? 0 : -1);
312138578Ssam#undef N
313138578Ssam}
314138578Ssam
315138578Ssamstatic int
316138578Ssamtest_wep_modevent(module_t mod, int type, void *unused)
317138578Ssam{
318138578Ssam	switch (type) {
319138578Ssam	case MOD_LOAD:
320138578Ssam		(void) init_crypto_wep_test();
321138578Ssam		return 0;
322138578Ssam	case MOD_UNLOAD:
323138578Ssam		return 0;
324138578Ssam	}
325138578Ssam	return EINVAL;
326138578Ssam}
327138578Ssam
328138578Ssamstatic moduledata_t test_wep_mod = {
329138578Ssam	"test_wep",
330138578Ssam	test_wep_modevent,
331241394Skevlo	0
332138578Ssam};
333138578SsamDECLARE_MODULE(test_wep, test_wep_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
334138578SsamMODULE_VERSION(test_wep, 1);
335138578SsamMODULE_DEPEND(test_wep, wlan, 1, 1, 1);
336