diff options
Diffstat (limited to 'tools/regression/net80211/tkip/test_tkip.c')
-rw-r--r-- | tools/regression/net80211/tkip/test_tkip.c | 387 |
1 files changed, 387 insertions, 0 deletions
diff --git a/tools/regression/net80211/tkip/test_tkip.c b/tools/regression/net80211/tkip/test_tkip.c new file mode 100644 index 0000000..8c7e655 --- /dev/null +++ b/tools/regression/net80211/tkip/test_tkip.c @@ -0,0 +1,387 @@ +/*- + * Copyright (c) 2004 Sam Leffler, Errno Consulting + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* + * TKIP test module. + */ +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/module.h> + +#include <sys/socket.h> + +#include <net/if.h> +#include <net/if_media.h> + +#include <net80211/ieee80211_var.h> + +/* +Key 12 34 56 78 90 12 34 56 78 90 12 34 56 78 90 12 + 34 56 78 90 12 34 56 78 90 12 34 56 78 90 12 34 +PN 0x000000000001 +IV 00 20 01 20 00 00 00 00 +Phase1 bb 58 07 1f 9e 93 b4 38 25 4b +Phase2 00 20 01 4c fe 67 be d2 7c 86 7b 1b f8 02 8b 1c +*/ + +static const u_int8_t test1_key[] = { + 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, + 0x34, 0x56, 0x78, 0x90, 0x12, + + 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, /* TX MIC */ + /* + * NB: 11i test vector specifies a RX MIC key different + * from the TX key. But this doesn't work to enmic, + * encrypt, then decrypt, demic. So instead we use + * the same key for doing the MIC in each direction. + * + * XXX need additional vectors to test alternate MIC keys + */ +#if 0 + 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, /* 11i RX MIC */ +#else + 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, /* TX copy */ +#endif +}; +static const u_int8_t test1_phase1[] = { + 0xbb, 0x58, 0x07, 0x1f, 0x9e, 0x93, 0xb4, 0x38, 0x25, 0x4b +}; +static const u_int8_t test1_phase2[] = { + 0x00, 0x20, 0x01, 0x4c, 0xfe, 0x67, 0xbe, 0xd2, 0x7c, 0x86, + 0x7b, 0x1b, 0xf8, 0x02, 0x8b, 0x1c, +}; + +/* Plaintext MPDU with MIC */ +static const u_int8_t test1_plaintext[] = { +0x08,0x42,0x2c,0x00,0x02,0x03,0x04,0x05,0x06,0x08,0x02,0x03,0x04,0x05,0x06,0x07, +0x02,0x03,0x04,0x05,0x06,0x07,0xd0,0x02, +0xaa,0xaa,0x03,0x00,0x00,0x00,0x08,0x00,0x45,0x00,0x00,0x54,0x00,0x00,0x40,0x00, +0x40,0x01,0xa5,0x55,0xc0,0xa8,0x0a,0x02,0xc0,0xa8,0x0a,0x01,0x08,0x00,0x3a,0xb0, +0x00,0x00,0x00,0x00,0xcd,0x4c,0x05,0x00,0x00,0x00,0x00,0x00,0x08,0x09,0x0a,0x0b, +0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b, +0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b, +0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37, +/* MIC */ 0x68,0x81,0xa3,0xf3,0xd6,0x48,0xd0,0x3c +}; + +/* Encrypted MPDU with MIC and ICV */ +static const u_int8_t test1_encrypted[] = { +0x08,0x42,0x2c,0x00,0x02,0x03,0x04,0x05,0x06,0x08,0x02,0x03,0x04,0x05,0x06,0x07, +0x02,0x03,0x04,0x05,0x06,0x07,0xd0,0x02,0x00,0x20,0x01,0x20,0x00,0x00,0x00,0x00, +0xc0,0x0e,0x14,0xfc,0xe7,0xcf,0xab,0xc7,0x75,0x47,0xe6,0x66,0xe5,0x7c,0x0d,0xac, +0x70,0x4a,0x1e,0x35,0x8a,0x88,0xc1,0x1c,0x8e,0x2e,0x28,0x2e,0x38,0x01,0x02,0x7a, +0x46,0x56,0x05,0x5e,0xe9,0x3e,0x9c,0x25,0x47,0x02,0xe9,0x73,0x58,0x05,0xdd,0xb5, +0x76,0x9b,0xa7,0x3f,0x1e,0xbb,0x56,0xe8,0x44,0xef,0x91,0x22,0x85,0xd3,0xdd,0x6e, +0x54,0x1e,0x82,0x38,0x73,0x55,0x8a,0xdb,0xa0,0x79,0x06,0x8a,0xbd,0x7f,0x7f,0x50, +0x95,0x96,0x75,0xac,0xc4,0xb4,0xde,0x9a,0xa9,0x9c,0x05,0xf2,0x89,0xa7,0xc5,0x2f, +0xee,0x5b,0xfc,0x14,0xf6,0xf8,0xe5,0xf8 +}; + +#define TEST(n,name,cipher,keyix,pn) { \ + name, IEEE80211_CIPHER_##cipher,keyix, pn##LL, \ + test##n##_key, sizeof(test##n##_key), \ + test##n##_phase1, sizeof(test##n##_phase1), \ + test##n##_phase2, sizeof(test##n##_phase2), \ + test##n##_plaintext, sizeof(test##n##_plaintext), \ + test##n##_encrypted, sizeof(test##n##_encrypted) \ +} + +struct ciphertest { + const char *name; + int cipher; + int keyix; + u_int64_t pn; + const u_int8_t *key; + size_t key_len; + const u_int8_t *phase1; + size_t phase1_len; + const u_int8_t *phase2; + size_t phase2_len; + const u_int8_t *plaintext; + size_t plaintext_len; + const u_int8_t *encrypted; + size_t encrypted_len; +} tkiptests[] = { + TEST(1, "TKIP test mpdu 1", TKIP, 0, 0), +}; + +struct tkip_ctx { + struct ieee80211com *tc_ic; /* for diagnostics */ + + uint16_t tx_ttak[5]; + int tx_phase1_done; + uint8_t tx_rc4key[16]; + + uint16_t rx_ttak[5]; + int rx_phase1_done; + uint8_t rx_rc4key[16]; + uint64_t rx_rsc; /* held until MIC verified */ +}; + +static void +dumpdata(const char *tag, const void *p, size_t len) +{ + int i; + + printf("%s: 0x%p len %u", tag, p, len); + for (i = 0; i < len; i++) { + if ((i % 16) == 0) + printf("\n%03d:", i); + printf(" %02x", ((const u_int8_t *)p)[i]); + } + printf("\n"); +} + +static void +cmpfail(const void *gen, size_t genlen, const void *ref, size_t reflen) +{ + int i; + + for (i = 0; i < genlen; i++) + if (((const u_int8_t *)gen)[i] != ((const u_int8_t *)ref)[i]) { + printf("first difference at byte %u\n", i); + break; + } + dumpdata("Generated", gen, genlen); + dumpdata("Reference", ref, reflen); +} + +static int +runtest(struct ieee80211com *ic, struct ciphertest *t) +{ + struct tkip_ctx *ctx; + struct ieee80211_key key; + struct mbuf *m = NULL; + const struct ieee80211_cipher *cip; + u_int8_t mac[IEEE80211_ADDR_LEN]; + u_int len; + + printf("%s: ", t->name); + + /* + * Setup key. + */ + memset(&key, 0, sizeof(key)); + key.wk_flags = IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV; + key.wk_cipher = &ieee80211_cipher_none; + if (!ieee80211_crypto_newkey(ic, IEEE80211_CIPHER_TKIP, &key)) { + printf("FAIL: ieee80211_crypto_newkey failed\n"); + goto bad; + } + + memcpy(key.wk_key, t->key, t->key_len); + key.wk_keylen = 128/NBBY; + key.wk_keyrsc = 0; + key.wk_keytsc = t->pn; + if (!ieee80211_crypto_setkey(ic, &key, mac)) { + printf("FAIL: ieee80211_crypto_setkey failed\n"); + goto bad; + } + + /* + * Craft frame from plaintext data. + */ + cip = key.wk_cipher; + m = m_getcl(M_NOWAIT, MT_HEADER, M_PKTHDR); + m->m_data += cip->ic_header; + len = t->plaintext_len - IEEE80211_WEP_MICLEN; + memcpy(mtod(m, void *), t->plaintext, len); + m->m_len = len; + m->m_pkthdr.len = m->m_len; + + /* + * Add MIC. + */ + if (!ieee80211_crypto_enmic(ic, &key, m)) { + printf("FAIL: tkip enmic failed\n"); + goto bad; + } + /* + * Verify: frame length, frame contents. + */ + if (m->m_pkthdr.len != t->plaintext_len) { + printf("FAIL: enmic botch; length mismatch\n"); + cmpfail(mtod(m, const void *), m->m_pkthdr.len, + t->plaintext, t->plaintext_len); + goto bad; + } + if (memcmp(mtod(m, const void *), t->plaintext, t->plaintext_len)) { + printf("FAIL: enmic botch\n"); + cmpfail(mtod(m, const void *), m->m_pkthdr.len, + t->plaintext, t->plaintext_len); + goto bad; + } + /* + * Encrypt frame w/ MIC. + */ + if (!cip->ic_encap(&key, m, t->keyix<<6)) { + printf("FAIL: tkip encap failed\n"); + goto bad; + } + /* + * Verify: phase1, phase2, frame length, frame contents. + */ + ctx = key.wk_private; + if (memcmp(ctx->tx_ttak, t->phase1, t->phase1_len)) { + printf("FAIL: encrypt phase1 botch\n"); + cmpfail(ctx->tx_ttak, sizeof(ctx->tx_ttak), + t->phase1, t->phase1_len); + goto bad; + } else if (memcmp(ctx->tx_rc4key, t->phase2, t->phase2_len)) { + printf("FAIL: encrypt phase2 botch\n"); + cmpfail(ctx->tx_rc4key, sizeof(ctx->tx_rc4key), + t->phase2, t->phase2_len); + goto bad; + } else if (m->m_pkthdr.len != t->encrypted_len) { + printf("FAIL: encrypt data length mismatch\n"); + cmpfail(mtod(m, const void *), m->m_pkthdr.len, + t->encrypted, t->encrypted_len); + goto bad; + } else if (memcmp(mtod(m, const void *), t->encrypted, m->m_pkthdr.len)) { + printf("FAIL: encrypt data does not compare\n"); + cmpfail(mtod(m, const void *), m->m_pkthdr.len, + t->encrypted, t->encrypted_len); + dumpdata("Plaintext", t->plaintext, t->plaintext_len); + goto bad; + } + + /* + * Decrypt frame. + */ + if (!cip->ic_decap(&key, m)) { + printf("tkip decap failed\n"); + /* + * Check reason for failure: phase1, phase2, frame data (ICV). + */ + if (memcmp(ctx->rx_ttak, t->phase1, t->phase1_len)) { + printf("FAIL: decrypt phase1 botch\n"); + cmpfail(ctx->rx_ttak, sizeof(ctx->rx_ttak), + t->phase1, t->phase1_len); + } else if (memcmp(ctx->rx_rc4key, t->phase2, t->phase2_len)) { + printf("FAIL: decrypt phase2 botch\n"); + cmpfail(ctx->rx_rc4key, sizeof(ctx->rx_rc4key), + t->phase2, t->phase2_len); + } else { + printf("FAIL: decrypt data does not compare\n"); + cmpfail(mtod(m, const void *), m->m_pkthdr.len, + t->plaintext, t->plaintext_len); + } + goto bad; + } + /* + * Verify: frame length, frame contents. + */ + if (m->m_pkthdr.len != t->plaintext_len) { + printf("FAIL: decap botch; length mismatch\n"); + cmpfail(mtod(m, const void *), m->m_pkthdr.len, + t->plaintext, t->plaintext_len); + goto bad; + } + if (memcmp(mtod(m, const void *), t->plaintext, t->plaintext_len)) { + printf("FAIL: decap botch; data does not compare\n"); + cmpfail(mtod(m, const void *), m->m_pkthdr.len, + t->plaintext, t->plaintext_len); + goto bad; + } + /* + * De-MIC decrypted frame. + */ + if (!ieee80211_crypto_demic(ic, &key, m)) { + printf("FAIL: tkip demic failed\n"); + goto bad; + } + /* XXX check frame length and contents... */ + printf("PASS\n"); + return 1; +bad: + if (m != NULL) + m_freem(m); + ieee80211_crypto_delkey(ic, &key); + return 0; +} + +/* + * Module glue. + */ + +static int debug = 0; +static int tests = -1; + +static int +init_crypto_tkip_test(void) +{ +#define N(a) (sizeof(a)/sizeof(a[0])) + struct ieee80211com ic; + int i, pass, total; + + memset(&ic, 0, sizeof(ic)); + if (debug) + ic.ic_debug = IEEE80211_MSG_CRYPTO; + ieee80211_crypto_attach(&ic); + + pass = 0; + total = 0; + for (i = 0; i < N(tkiptests); i++) + if (tests & (1<<i)) { + total++; + pass += runtest(&ic, &tkiptests[i]); + } + printf("%u of %u 802.11i TKIP test vectors passed\n", pass, total); + ieee80211_crypto_detach(&ic); + return (pass == total ? 0 : -1); +#undef N +} + +static int +test_tkip_modevent(module_t mod, int type, void *unused) +{ + switch (type) { + case MOD_LOAD: + (void) init_crypto_tkip_test(); + return 0; + case MOD_UNLOAD: + return 0; + } + return EINVAL; +} + +static moduledata_t test_tkip_mod = { + "test_tkip", + test_tkip_modevent, + 0 +}; +DECLARE_MODULE(test_tkip, test_tkip_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST); +MODULE_VERSION(test_tkip, 1); +MODULE_DEPEND(test_tkip, wlan, 1, 1, 1); |