wlantest: Add support for CCMP protection for injected frames

This commit is contained in:
Jouni Malinen 2010-11-19 16:09:19 +02:00 committed by Jouni Malinen
parent f6b25ca5b4
commit 571ab37b86
4 changed files with 267 additions and 2 deletions

View file

@ -222,3 +222,127 @@ void ccmp_get_pn(u8 *pn, const u8 *data)
pn[4] = data[1]; /* PN1 */
pn[5] = data[0]; /* PN0 */
}
u8 * ccmp_encrypt(const u8 *tk, u8 *frame, size_t len, size_t hdrlen, u8 *qos,
u8 *pn, int keyid, size_t *encrypted_len)
{
u8 aad[2 + 30], nonce[13];
size_t aad_len;
u8 b[AES_BLOCK_SIZE], x[AES_BLOCK_SIZE], a[AES_BLOCK_SIZE];
void *aes;
u8 *crypt, *pos, *ppos, *mpos;
size_t plen, last;
struct ieee80211_hdr *hdr;
int i;
if (len < hdrlen || hdrlen < 24)
return NULL;
plen = len - hdrlen;
last = plen % AES_BLOCK_SIZE;
crypt = os_malloc(hdrlen + 8 + plen + 8);
if (crypt == NULL)
return NULL;
os_memcpy(crypt, frame, hdrlen);
hdr = (struct ieee80211_hdr *) crypt;
hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP);
pos = crypt + hdrlen;
*pos++ = pn[5]; /* PN0 */
*pos++ = pn[4]; /* PN1 */
*pos++ = 0x20 | (keyid << 6);
*pos++ = pn[3]; /* PN2 */
*pos++ = pn[2]; /* PN3 */
*pos++ = pn[1]; /* PN4 */
*pos++ = pn[0]; /* PN5 */
aes = aes_encrypt_init(tk, 16);
if (aes == NULL) {
os_free(crypt);
return NULL;
}
os_memset(aad, 0, sizeof(aad));
ccmp_aad_nonce(hdr, crypt + hdrlen, &aad[2], &aad_len, nonce);
WPA_PUT_BE16(aad, aad_len);
wpa_hexdump(MSG_EXCESSIVE, "CCMP AAD", &aad[2], aad_len);
wpa_hexdump(MSG_EXCESSIVE, "CCMP nonce", nonce, 13);
/* Authentication */
/* B_0: Flags | Nonce N | l(m) */
b[0] = 0x40 /* Adata */ | (3 /* M' */ << 3) | 1 /* L' */;
os_memcpy(&b[1], nonce, 13);
WPA_PUT_BE16(&b[14], plen);
wpa_hexdump(MSG_EXCESSIVE, "CCMP B_0", b, AES_BLOCK_SIZE);
aes_encrypt(aes, b, x); /* X_1 = E(K, B_0) */
wpa_hexdump(MSG_EXCESSIVE, "CCMP B_1", aad, AES_BLOCK_SIZE);
xor_aes_block(aad, x);
aes_encrypt(aes, aad, x); /* X_2 = E(K, X_1 XOR B_1) */
wpa_hexdump(MSG_EXCESSIVE, "CCMP B_2", &aad[AES_BLOCK_SIZE],
AES_BLOCK_SIZE);
xor_aes_block(&aad[AES_BLOCK_SIZE], x);
aes_encrypt(aes, &aad[AES_BLOCK_SIZE], x); /* X_3 = E(K, X_2 XOR B_2)
*/
ppos = frame + hdrlen;
for (i = 0; i < plen / AES_BLOCK_SIZE; i++) {
/* X_i+1 = E(K, X_i XOR B_i) */
xor_aes_block(x, ppos);
ppos += AES_BLOCK_SIZE;
aes_encrypt(aes, x, x);
}
if (last) {
/* XOR zero-padded last block */
for (i = 0; i < last; i++)
x[i] ^= *ppos++;
aes_encrypt(aes, x, x);
}
/* Encryption */
/* CCM: M=8 L=2, Adata=1, M' = (M-2)/2 = 3, L' = L-1 = 1 */
/* A_i = Flags | Nonce N | Counter i */
a[0] = 0x01; /* Flags = L' */
os_memcpy(&a[1], nonce, 13);
ppos = crypt + hdrlen + 8;
/* crypt = msg XOR (S_1 | S_2 | ... | S_n) */
mpos = frame + hdrlen;
for (i = 1; i <= plen / AES_BLOCK_SIZE; i++) {
WPA_PUT_BE16(&a[14], i);
/* S_i = E(K, A_i) */
aes_encrypt(aes, a, ppos);
xor_aes_block(ppos, mpos);
ppos += AES_BLOCK_SIZE;
mpos += AES_BLOCK_SIZE;
}
if (last) {
WPA_PUT_BE16(&a[14], i);
aes_encrypt(aes, a, ppos);
/* XOR zero-padded last block */
for (i = 0; i < last; i++)
*ppos++ ^= *mpos++;
}
wpa_hexdump(MSG_EXCESSIVE, "CCMP T", x, 8);
/* U = T XOR S_0; S_0 = E(K, A_0) */
WPA_PUT_BE16(&a[14], 0);
aes_encrypt(aes, a, b);
for (i = 0; i < 8; i++)
ppos[i] = x[i] ^ b[i];
wpa_hexdump(MSG_EXCESSIVE, "CCMP U", ppos, 8);
wpa_hexdump(MSG_EXCESSIVE, "CCMP encrypted", crypt + hdrlen + 8, plen);
aes_encrypt_deinit(aes);
*encrypted_len = hdrlen + 8 + plen + 8;
return crypt;
}

View file

@ -15,6 +15,8 @@
#include "utils/includes.h"
#include "utils/common.h"
#include "common/defs.h"
#include "common/ieee802_11_defs.h"
#include "wlantest.h"
@ -58,11 +60,99 @@ static int inject_frame(int s, const void *data, size_t len)
}
static int is_robust_mgmt(u8 *frame, size_t len)
{
struct ieee80211_mgmt *mgmt;
u16 fc, stype;
if (len < 24)
return 0;
mgmt = (struct ieee80211_mgmt *) frame;
fc = le_to_host16(mgmt->frame_control);
if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT)
return 0;
stype = WLAN_FC_GET_STYPE(fc);
if (stype == WLAN_FC_STYPE_DEAUTH || stype == WLAN_FC_STYPE_DISASSOC)
return 1;
if (stype == WLAN_FC_STYPE_ACTION) {
if (len < 25)
return 0;
if (mgmt->u.action.category != WLAN_ACTION_PUBLIC)
return 1;
}
return 0;
}
static int wlantest_inject_prot(struct wlantest *wt, struct wlantest_bss *bss,
struct wlantest_sta *sta, u8 *frame,
size_t len, int incorrect_key)
{
u8 *crypt;
size_t crypt_len;
int ret;
u8 dummy[64];
u8 *pn;
struct ieee80211_hdr *hdr;
u16 fc;
int tid = 0;
u8 *qos = NULL;
int hdrlen;
if (sta == NULL)
return -1; /* TODO: add support for group Data and BIP */
if (!sta->ptk_set)
return -1;
hdr = (struct ieee80211_hdr *) frame;
hdrlen = 24;
fc = le_to_host16(hdr->frame_control);
if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT)
tid = 16;
else if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_DATA) {
if ((fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) ==
(WLAN_FC_TODS | WLAN_FC_FROMDS))
hdrlen += ETH_ALEN;
if (WLAN_FC_GET_STYPE(fc) & 0x08) {
qos = frame + hdrlen;
hdrlen += 2;
tid = qos[0] & 0x0f;
}
}
if (os_memcmp(hdr->addr2, bss->bssid, ETH_ALEN) == 0)
pn = sta->rsc_fromds[tid];
else
pn = sta->rsc_tods[tid];
inc_byte_array(pn, 6);
os_memset(dummy, 0x11, sizeof(dummy));
if (sta->pairwise_cipher == WPA_CIPHER_TKIP)
crypt = tkip_encrypt(incorrect_key ? dummy : sta->ptk.tk1,
frame, len, hdrlen, qos, pn, 0,
&crypt_len);
else
crypt = ccmp_encrypt(incorrect_key ? dummy : sta->ptk.tk1,
frame, len, hdrlen, qos, pn, 0,
&crypt_len);
if (crypt == NULL)
return -1;
ret = inject_frame(wt->monitor_sock, crypt, crypt_len);
os_free(crypt);
return (ret < 0) ? -1 : 0;
}
int wlantest_inject(struct wlantest *wt, struct wlantest_bss *bss,
struct wlantest_sta *sta, u8 *frame, size_t len,
enum wlantest_inject_protection prot)
{
int ret;
struct ieee80211_hdr *hdr;
u16 fc;
int protectable, protect = 0;
wpa_hexdump(MSG_DEBUG, "Inject frame", frame, len);
if (wt->monitor_sock < 0) {
@ -71,9 +161,48 @@ int wlantest_inject(struct wlantest *wt, struct wlantest_bss *bss,
return -1;
}
/* TODO: encrypt if needed */
if (prot != WLANTEST_INJECT_UNPROTECTED)
hdr = (struct ieee80211_hdr *) frame;
fc = le_to_host16(hdr->frame_control);
protectable = WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_DATA ||
is_robust_mgmt(frame, len);
if (prot == WLANTEST_INJECT_PROTECTED ||
prot == WLANTEST_INJECT_INCORRECT_KEY) {
if (!sta) {
wpa_printf(MSG_INFO, "Broadcast protection not yet "
"implemented");
return -1;
}
if (sta && !sta->ptk_set) {
wpa_printf(MSG_INFO, "No PTK known for the STA " MACSTR
" to encrypt the injected frame",
MAC2STR(sta->addr));
return -1;
}
protect = 1;
} else if (protectable && prot != WLANTEST_INJECT_UNPROTECTED) {
if (sta && sta->ptk_set)
protect = 1;
else if (!sta) {
if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_DATA &&
(bss->gtk_len[1] || bss->gtk_len[2]))
protect = 1;
if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
(bss->igtk_set[4] || bss->igtk_set[5]))
protect = 1;
}
}
if ((prot == WLANTEST_INJECT_PROTECTED ||
prot == WLANTEST_INJECT_INCORRECT_KEY) && !protect) {
wpa_printf(MSG_INFO, "Cannot protect injected frame");
return -1;
}
if (protect)
return wlantest_inject_prot(
wt, bss, sta, frame, len,
prot == WLANTEST_INJECT_INCORRECT_KEY);
ret = inject_frame(wt->monitor_sock, frame, len);
return (ret < 0) ? -1 : 0;

View file

@ -403,3 +403,11 @@ void tkip_get_pn(u8 *pn, const u8 *data)
pn[4] = data[0]; /* PN1 */
pn[5] = data[2]; /* PN0 */
}
u8 * tkip_encrypt(const u8 *tk, u8 *frame, size_t len, size_t hdrlen, u8 *qos,
u8 *pn, int keyid, size_t *encrypted_len)
{
/* TODO */
return NULL;
}

View file

@ -161,10 +161,14 @@ void sta_update_assoc(struct wlantest_sta *sta,
u8 * ccmp_decrypt(const u8 *tk, const struct ieee80211_hdr *hdr,
const u8 *data, size_t data_len, size_t *decrypted_len);
u8 * ccmp_encrypt(const u8 *tk, u8 *frame, size_t len, size_t hdrlen, u8 *qos,
u8 *pn, int keyid, size_t *encrypted_len);
void ccmp_get_pn(u8 *pn, const u8 *data);
u8 * tkip_decrypt(const u8 *tk, const struct ieee80211_hdr *hdr,
const u8 *data, size_t data_len, size_t *decrypted_len);
u8 * tkip_encrypt(const u8 *tk, u8 *frame, size_t len, size_t hdrlen, u8 *qos,
u8 *pn, int keyid, size_t *encrypted_len);
void tkip_get_pn(u8 *pn, const u8 *data);
int ctrl_init(struct wlantest *wt);