Add encryption/decryption support for PMF

1. Add CCMP, AES crypto modules for unicast protected Mgmt frames
2. Add support for computing SHA256 MIC on Bcast Mgmt frames
3. Add support for storing iGTK during 4-way handshake.
4. Provide APIs to MLME for utilizing the SW crypto modules
This commit is contained in:
Nachiket Kukade 2020-04-29 18:29:39 +05:30
parent 1b7f3fee5c
commit 5c5ae96be2
12 changed files with 881 additions and 7 deletions

View file

@ -315,6 +315,47 @@ typedef void * (*esp_aes_decrypt_init_t)(const unsigned char *key, unsigned int
*/
typedef void (*esp_aes_decrypt_deinit_t)(void *ctx);
/**
* @brief One-Key CBC MAC (OMAC1) hash with AES-128 for MIC computation
*
* @key: 128-bit key for the hash operation
* @data: Data buffer for which a MIC is computed
* @data_len: Length of data buffer in bytes
* @mic: Buffer for MIC (128 bits, i.e., 16 bytes)
* Returns: 0 on success, -1 on failure
*/
typedef int (*esp_omac1_aes_128_t)(const uint8_t *key, const uint8_t *data, size_t data_len,
uint8_t *mic);
/**
* @brief Decrypt data using CCMP (Counter Mode CBC-MAC Protocol OR
* Counter Mode Cipher Block Chaining Message Authentication
* Code Protocol) which is used in IEEE 802.11i RSN standard.
* @tk: 128-bit Temporal Key for obtained during 4-way handshake
* @hdr: Pointer to IEEE802.11 frame headeri needed for AAD
* @data: Pointer to encrypted data buffer
* @data_len: Encrypted data length in bytes
* @decrypted_len: Length of decrypted data
* Returns: Pointer to decrypted data on success, NULL on failure
*/
typedef uint8_t * (*esp_ccmp_decrypt_t)(const uint8_t *tk, const uint8_t *ieee80211_hdr,
const uint8_t *data, size_t data_len, size_t *decrypted_len);
/**
* @brief Encrypt data using CCMP (Counter Mode CBC-MAC Protocol OR
* Counter Mode Cipher Block Chaining Message Authentication
* Code Protocol) which is used in IEEE 802.11i RSN standard.
* @tk: 128-bit Temporal Key for obtained during 4-way handshake
* @frame: Pointer to IEEE802.11 frame including header
* @len: Length of the frame including header
* @hdrlen: Length of the header
* @pn: Packet Number counter
* @keyid: Key ID to be mentioned in CCMP Vector
* @encrypted_len: Length of the encrypted frame including header
*/
typedef uint8_t * (*esp_ccmp_encrypt_t)(const uint8_t *tk, uint8_t *frame, size_t len, size_t hdrlen,
uint8_t *pn, int keyid, size_t *encrypted_len);
/**
* @brief The crypto callback function structure used when do station security connect.
* The structure can be set as software crypto or the crypto optimized by ESP32
@ -342,6 +383,9 @@ typedef struct {
esp_aes_decrypt_t aes_decrypt;
esp_aes_decrypt_init_t aes_decrypt_init;
esp_aes_decrypt_deinit_t aes_decrypt_deinit;
esp_omac1_aes_128_t omac1_aes_128;
esp_ccmp_decrypt_t ccmp_decrypt;
esp_ccmp_encrypt_t ccmp_encrypt;
}wpa_crypto_funcs_t;
/**

View file

@ -5,13 +5,16 @@ set(srcs "port/os_xtensa.c"
"src/ap/wpa_auth_ie.c"
"src/common/wpa_common.c"
"src/crypto/aes-cbc.c"
"src/crypto/aes-ccm.c"
"src/crypto/aes-internal-dec.c"
"src/crypto/aes-internal-enc.c"
"src/crypto/aes-internal.c"
"src/crypto/aes-omac1.c"
"src/crypto/aes-unwrap.c"
"src/crypto/aes-wrap.c"
"src/crypto/sha256-tlsprf.c"
"src/crypto/bignum.c"
"src/crypto/ccmp.c"
"src/crypto/crypto_mbedtls.c"
"src/crypto/crypto_ops.c"
"src/crypto/crypto_internal-cipher.c"

View file

@ -22,6 +22,7 @@
#include "crypto/sha1.h"
#include "crypto/sha256.h"
#include "crypto/md5.h"
#include "crypto/aes.h"
#define MD5_MAC_LEN 16
@ -388,6 +389,10 @@ int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len,
return -1;
memcpy(mic, hash, MD5_MAC_LEN);
break;
#ifdef CONFIG_IEEE80211W
case WPA_KEY_INFO_TYPE_AES_128_CMAC:
return omac1_aes_128(key, buf, len, mic);
#endif
default:
return -1;
}

View file

@ -0,0 +1,215 @@
/*
* Counter with CBC-MAC (CCM) with AES
*
* Copyright (c) 2010-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifdef CONFIG_IEEE80211W
#include "utils/includes.h"
#include "utils/common.h"
#include "aes.h"
#include "aes_wrap.h"
static void xor_aes_block(u8 *dst, const u8 *src)
{
u32 *d = (u32 *) dst;
u32 *s = (u32 *) src;
*d++ ^= *s++;
*d++ ^= *s++;
*d++ ^= *s++;
*d++ ^= *s++;
}
static void aes_ccm_auth_start(void *aes, size_t M, size_t L, const u8 *nonce,
const u8 *aad, size_t aad_len, size_t plain_len,
u8 *x)
{
u8 aad_buf[2 * AES_BLOCK_SIZE];
u8 b[AES_BLOCK_SIZE];
/* Authentication */
/* B_0: Flags | Nonce N | l(m) */
b[0] = aad_len ? 0x40 : 0 /* Adata */;
b[0] |= (((M - 2) / 2) /* M' */ << 3);
b[0] |= (L - 1) /* L' */;
os_memcpy(&b[1], nonce, 15 - L);
WPA_PUT_BE16(&b[AES_BLOCK_SIZE - L], plain_len);
wpa_hexdump_key(MSG_DEBUG, "CCM B_0", b, AES_BLOCK_SIZE);
aes_encrypt(aes, b, x); /* X_1 = E(K, B_0) */
if (!aad_len)
return;
WPA_PUT_BE16(aad_buf, aad_len);
os_memcpy(aad_buf + 2, aad, aad_len);
os_memset(aad_buf + 2 + aad_len, 0, sizeof(aad_buf) - 2 - aad_len);
xor_aes_block(aad_buf, x);
aes_encrypt(aes, aad_buf, x); /* X_2 = E(K, X_1 XOR B_1) */
if (aad_len > AES_BLOCK_SIZE - 2) {
xor_aes_block(&aad_buf[AES_BLOCK_SIZE], x);
/* X_3 = E(K, X_2 XOR B_2) */
aes_encrypt(aes, &aad_buf[AES_BLOCK_SIZE], x);
}
}
static void aes_ccm_auth(void *aes, const u8 *data, size_t len, u8 *x)
{
size_t last = len % AES_BLOCK_SIZE;
size_t i;
for (i = 0; i < len / AES_BLOCK_SIZE; i++) {
/* X_i+1 = E(K, X_i XOR B_i) */
xor_aes_block(x, data);
data += AES_BLOCK_SIZE;
aes_encrypt(aes, x, x);
}
if (last) {
/* XOR zero-padded last block */
for (i = 0; i < last; i++)
x[i] ^= *data++;
aes_encrypt(aes, x, x);
}
}
static void aes_ccm_encr_start(size_t L, const u8 *nonce, u8 *a)
{
/* A_i = Flags | Nonce N | Counter i */
a[0] = L - 1; /* Flags = L' */
os_memcpy(&a[1], nonce, 15 - L);
}
static void aes_ccm_encr(void *aes, size_t L, const u8 *in, size_t len, u8 *out,
u8 *a)
{
size_t last = len % AES_BLOCK_SIZE;
size_t i;
/* crypt = msg XOR (S_1 | S_2 | ... | S_n) */
for (i = 1; i <= len / AES_BLOCK_SIZE; i++) {
WPA_PUT_BE16(&a[AES_BLOCK_SIZE - 2], i);
/* S_i = E(K, A_i) */
aes_encrypt(aes, a, out);
xor_aes_block(out, in);
out += AES_BLOCK_SIZE;
in += AES_BLOCK_SIZE;
}
if (last) {
WPA_PUT_BE16(&a[AES_BLOCK_SIZE - 2], i);
aes_encrypt(aes, a, out);
/* XOR zero-padded last block */
for (i = 0; i < last; i++)
*out++ ^= *in++;
}
}
static void aes_ccm_encr_auth(void *aes, size_t M, u8 *x, u8 *a, u8 *auth)
{
size_t i;
u8 tmp[AES_BLOCK_SIZE];
wpa_hexdump_key(MSG_DEBUG, "CCM T", x, M);
/* U = T XOR S_0; S_0 = E(K, A_0) */
WPA_PUT_BE16(&a[AES_BLOCK_SIZE - 2], 0);
aes_encrypt(aes, a, tmp);
for (i = 0; i < M; i++)
auth[i] = x[i] ^ tmp[i];
wpa_hexdump_key(MSG_DEBUG, "CCM U", auth, M);
}
static void aes_ccm_decr_auth(void *aes, size_t M, u8 *a, const u8 *auth, u8 *t)
{
size_t i;
u8 tmp[AES_BLOCK_SIZE];
wpa_hexdump_key(MSG_DEBUG, "CCM U", auth, M);
/* U = T XOR S_0; S_0 = E(K, A_0) */
WPA_PUT_BE16(&a[AES_BLOCK_SIZE - 2], 0);
aes_encrypt(aes, a, tmp);
for (i = 0; i < M; i++)
t[i] = auth[i] ^ tmp[i];
wpa_hexdump_key(MSG_DEBUG, "CCM T", t, M);
}
/* AES-CCM with fixed L=2 and aad_len <= 30 assumption */
int aes_ccm_ae(const u8 *key, size_t key_len, const u8 *nonce,
size_t M, const u8 *plain, size_t plain_len,
const u8 *aad, size_t aad_len, u8 *crypt, u8 *auth)
{
const size_t L = 2;
void *aes;
u8 x[AES_BLOCK_SIZE], a[AES_BLOCK_SIZE];
if (aad_len > 30 || M > AES_BLOCK_SIZE)
return -1;
aes = aes_encrypt_init(key, key_len);
if (aes == NULL)
return -1;
aes_ccm_auth_start(aes, M, L, nonce, aad, aad_len, plain_len, x);
aes_ccm_auth(aes, plain, plain_len, x);
/* Encryption */
aes_ccm_encr_start(L, nonce, a);
aes_ccm_encr(aes, L, plain, plain_len, crypt, a);
aes_ccm_encr_auth(aes, M, x, a, auth);
aes_encrypt_deinit(aes);
return 0;
}
/* AES-CCM with fixed L=2 and aad_len <= 30 assumption */
int aes_ccm_ad(const u8 *key, size_t key_len, const u8 *nonce,
size_t M, const u8 *crypt, size_t crypt_len,
const u8 *aad, size_t aad_len, const u8 *auth, u8 *plain)
{
const size_t L = 2;
void *aes;
u8 x[AES_BLOCK_SIZE], a[AES_BLOCK_SIZE];
u8 t[AES_BLOCK_SIZE];
if (aad_len > 30 || M > AES_BLOCK_SIZE)
return -1;
aes = aes_encrypt_init(key, key_len);
if (aes == NULL)
return -1;
/* Decryption */
aes_ccm_encr_start(L, nonce, a);
aes_ccm_decr_auth(aes, M, a, auth, t);
/* plaintext = msg XOR (S_1 | S_2 | ... | S_n) */
aes_ccm_encr(aes, L, crypt, crypt_len, plain, a);
aes_ccm_auth_start(aes, M, L, nonce, aad, aad_len, crypt_len, x);
aes_ccm_auth(aes, plain, crypt_len, x);
aes_encrypt_deinit(aes);
if (os_memcmp(x, t, M) != 0) {
wpa_printf(MSG_DEBUG, "CCM: Auth mismatch");
return -1;
}
return 0;
}
#endif /* CONFIG_IEEE80211W */

View file

@ -0,0 +1,169 @@
/*
* One-key CBC MAC (OMAC1) hash with AES
*
* Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "utils/common.h"
#include "crypto/aes.h"
#include "crypto/aes_wrap.h"
static void gf_mulx(u8 *pad)
{
int i, carry;
carry = pad[0] & 0x80;
for (i = 0; i < AES_BLOCK_SIZE - 1; i++)
pad[i] = (pad[i] << 1) | (pad[i + 1] >> 7);
pad[AES_BLOCK_SIZE - 1] <<= 1;
if (carry)
pad[AES_BLOCK_SIZE - 1] ^= 0x87;
}
/**
* omac1_aes_vector - One-Key CBC MAC (OMAC1) hash with AES
* @key: Key for the hash operation
* @key_len: Key length in octets
* @num_elem: Number of elements in the data vector
* @addr: Pointers to the data areas
* @len: Lengths of the data blocks
* @mac: Buffer for MAC (128 bits, i.e., 16 bytes)
* Returns: 0 on success, -1 on failure
*
* This is a mode for using block cipher (AES in this case) for authentication.
* OMAC1 was standardized with the name CMAC by NIST in a Special Publication
* (SP) 800-38B.
*/
int omac1_aes_vector(const u8 *key, size_t key_len, size_t num_elem,
const u8 *addr[], const size_t *len, u8 *mac)
{
void *ctx;
u8 cbc[AES_BLOCK_SIZE], pad[AES_BLOCK_SIZE];
const u8 *pos, *end;
size_t i, e, left, total_len;
ctx = aes_encrypt_init(key, key_len);
if (ctx == NULL)
return -1;
os_memset(cbc, 0, AES_BLOCK_SIZE);
total_len = 0;
for (e = 0; e < num_elem; e++)
total_len += len[e];
left = total_len;
e = 0;
pos = addr[0];
end = pos + len[0];
while (left >= AES_BLOCK_SIZE) {
for (i = 0; i < AES_BLOCK_SIZE; i++) {
cbc[i] ^= *pos++;
if (pos >= end) {
/*
* Stop if there are no more bytes to process
* since there are no more entries in the array.
*/
if (i + 1 == AES_BLOCK_SIZE &&
left == AES_BLOCK_SIZE)
break;
e++;
pos = addr[e];
end = pos + len[e];
}
}
if (left > AES_BLOCK_SIZE)
aes_encrypt(ctx, cbc, cbc);
left -= AES_BLOCK_SIZE;
}
os_memset(pad, 0, AES_BLOCK_SIZE);
aes_encrypt(ctx, pad, pad);
gf_mulx(pad);
if (left || total_len == 0) {
for (i = 0; i < left; i++) {
cbc[i] ^= *pos++;
if (pos >= end) {
/*
* Stop if there are no more bytes to process
* since there are no more entries in the array.
*/
if (i + 1 == left)
break;
e++;
pos = addr[e];
end = pos + len[e];
}
}
cbc[left] ^= 0x80;
gf_mulx(pad);
}
for (i = 0; i < AES_BLOCK_SIZE; i++)
pad[i] ^= cbc[i];
aes_encrypt(ctx, pad, mac);
aes_encrypt_deinit(ctx);
return 0;
}
/**
* omac1_aes_128_vector - One-Key CBC MAC (OMAC1) hash with AES-128
* @key: 128-bit key for the hash operation
* @num_elem: Number of elements in the data vector
* @addr: Pointers to the data areas
* @len: Lengths of the data blocks
* @mac: Buffer for MAC (128 bits, i.e., 16 bytes)
* Returns: 0 on success, -1 on failure
*
* This is a mode for using block cipher (AES in this case) for authentication.
* OMAC1 was standardized with the name CMAC by NIST in a Special Publication
* (SP) 800-38B.
*/
int omac1_aes_128_vector(const u8 *key, size_t num_elem,
const u8 *addr[], const size_t *len, u8 *mac)
{
return omac1_aes_vector(key, 16, num_elem, addr, len, mac);
}
/**
* omac1_aes_128 - One-Key CBC MAC (OMAC1) hash with AES-128 (aka AES-CMAC)
* @key: 128-bit key for the hash operation
* @data: Data buffer for which a MAC is determined
* @data_len: Length of data buffer in bytes
* @mac: Buffer for MAC (128 bits, i.e., 16 bytes)
* Returns: 0 on success, -1 on failure
*
* This is a mode for using block cipher (AES in this case) for authentication.
* OMAC1 was standardized with the name CMAC by NIST in a Special Publication
* (SP) 800-38B.
*/
int omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
{
return omac1_aes_128_vector(key, 1, &data, &data_len, mac);
}
/**
* omac1_aes_256 - One-Key CBC MAC (OMAC1) hash with AES-256 (aka AES-CMAC)
* @key: 256-bit key for the hash operation
* @data: Data buffer for which a MAC is determined
* @data_len: Length of data buffer in bytes
* @mac: Buffer for MAC (128 bits, i.e., 16 bytes)
* Returns: 0 on success, -1 on failure
*
* This is a mode for using block cipher (AES in this case) for authentication.
* OMAC1 was standardized with the name CMAC by NIST in a Special Publication
* (SP) 800-38B.
*/
int omac1_aes_256(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
{
return omac1_aes_vector(key, 32, 1, &data, &data_len, mac);
}

View file

@ -24,4 +24,13 @@ void * aes_decrypt_init(const u8 *key, size_t len);
void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain);
void aes_decrypt_deinit(void *ctx);
int omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac);
int aes_ccm_ae(const u8 *key, size_t key_len, const u8 *nonce,
size_t M, const u8 *plain, size_t plain_len,
const u8 *aad, size_t aad_len, u8 *crypt, u8 *auth);
int aes_ccm_ad(const u8 *key, size_t key_len, const u8 *nonce,
size_t M, const u8 *crypt, size_t crypt_len,
const u8 *aad, size_t aad_len, const u8 *auth,
u8 *plain);
#endif /* AES_H */

View file

@ -0,0 +1,354 @@
/*
* CTR with CBC-MAC Protocol (CCMP)
* Copyright (c) 2010-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifdef CONFIG_IEEE80211W
#include "utils/includes.h"
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
#include "aes.h"
#include "aes_wrap.h"
static void ccmp_aad_nonce(const struct ieee80211_hdr *hdr, const u8 *data,
u8 *aad, size_t *aad_len, u8 *nonce)
{
u16 fc, stype, seq;
int qos = 0, addr4 = 0;
u8 *pos;
nonce[0] = 0;
fc = le_to_host16(hdr->frame_control);
stype = WLAN_FC_GET_STYPE(fc);
if ((fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) ==
(WLAN_FC_TODS | WLAN_FC_FROMDS))
addr4 = 1;
if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_DATA) {
fc &= ~0x0070; /* Mask subtype bits */
if (stype & 0x08) {
const u8 *qc;
qos = 1;
fc &= ~WLAN_FC_ORDER;
qc = (const u8 *) (hdr + 1);
if (addr4)
qc += ETH_ALEN;
nonce[0] = qc[0] & 0x0f;
}
} else if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT)
nonce[0] |= 0x10; /* Management */
fc &= ~(WLAN_FC_RETRY | WLAN_FC_PWRMGT | WLAN_FC_MOREDATA);
fc |= WLAN_FC_ISWEP;
WPA_PUT_LE16(aad, fc);
pos = aad + 2;
os_memcpy(pos, hdr->addr1, 3 * ETH_ALEN);
pos += 3 * ETH_ALEN;
seq = le_to_host16(hdr->seq_ctrl);
seq &= ~0xfff0; /* Mask Seq#; do not modify Frag# */
WPA_PUT_LE16(pos, seq);
pos += 2;
os_memcpy(pos, hdr + 1, addr4 * ETH_ALEN + qos * 2);
pos += addr4 * ETH_ALEN;
if (qos) {
pos[0] &= ~0x70;
if (1 /* FIX: either device has SPP A-MSDU Capab = 0 */)
pos[0] &= ~0x80;
pos++;
*pos++ = 0x00;
}
*aad_len = pos - aad;
os_memcpy(nonce + 1, hdr->addr2, ETH_ALEN);
nonce[7] = data[7]; /* PN5 */
nonce[8] = data[6]; /* PN4 */
nonce[9] = data[5]; /* PN3 */
nonce[10] = data[4]; /* PN2 */
nonce[11] = data[1]; /* PN1 */
nonce[12] = data[0]; /* PN0 */
}
static void ccmp_aad_nonce_pv1(const u8 *hdr, const u8 *a1, const u8 *a2,
const u8 *a3, const u8 *pn,
u8 *aad, size_t *aad_len, u8 *nonce)
{
u16 fc, type;
u8 *pos;
nonce[0] = BIT(5); /* PV1 */
/* TODO: Priority for QMF; 0 is used for Data frames */
fc = WPA_GET_LE16(hdr);
type = (fc & (BIT(2) | BIT(3) | BIT(4))) >> 2;
if (type == 1)
nonce[0] |= 0x10; /* Management */
fc &= ~(BIT(10) | BIT(11) | BIT(13) | BIT(14) | BIT(15));
fc |= BIT(12);
WPA_PUT_LE16(aad, fc);
pos = aad + 2;
if (type == 0 || type == 3) {
const u8 *sc;
os_memcpy(pos, a1, ETH_ALEN);
pos += ETH_ALEN;
os_memcpy(pos, a2, ETH_ALEN);
pos += ETH_ALEN;
if (type == 0) {
/* Either A1 or A2 contains SID */
sc = hdr + 2 + 2 + ETH_ALEN;
} else {
/* Both A1 and A2 contain full addresses */
sc = hdr + 2 + 2 * ETH_ALEN;
}
/* SC with Sequence Number subfield (bits 4-15 of the Sequence
* Control field) masked to 0. */
*pos++ = *sc & 0x0f;
*pos++ = 0;
if (a3) {
os_memcpy(pos, a3, ETH_ALEN);
pos += ETH_ALEN;
}
}
*aad_len = pos - aad;
os_memcpy(nonce + 1, a2, ETH_ALEN);
nonce[7] = pn[5]; /* PN5 */
nonce[8] = pn[4]; /* PN4 */
nonce[9] = pn[3]; /* PN3 */
nonce[10] = pn[2]; /* PN2 */
nonce[11] = pn[1]; /* PN1 */
nonce[12] = pn[0]; /* PN0 */
}
u8 * ccmp_decrypt(const u8 *tk, const u8 *hdr, const u8 *data,
size_t data_len, size_t *decrypted_len)
{
u8 aad[30], nonce[13];
size_t aad_len;
size_t mlen;
u8 *plain;
if (data_len < 8 + 8)
return NULL;
plain = os_malloc(data_len + AES_BLOCK_SIZE);
if (plain == NULL)
return NULL;
mlen = data_len - 8 - 8;
os_memset(aad, 0, sizeof(aad));
ccmp_aad_nonce((const struct ieee80211_hdr *)hdr, data, aad, &aad_len, nonce);
//wpa_hexdump(MSG_DEBUG, "CCMP AAD", aad, aad_len);
//wpa_hexdump(MSG_DEBUG, "CCMP nonce", nonce, 13);
if (aes_ccm_ad(tk, 16, nonce, 8, data + 8, mlen, aad, aad_len,
data + 8 + mlen, plain) < 0) {
os_free(plain);
return NULL;
}
//wpa_hexdump(MSG_DEBUG, "CCMP decrypted", plain, mlen);
*decrypted_len = mlen;
return plain;
}
void ccmp_get_pn(u8 *pn, const u8 *data)
{
pn[0] = data[7]; /* PN5 */
pn[1] = data[6]; /* PN4 */
pn[2] = data[5]; /* PN3 */
pn[3] = data[4]; /* PN2 */
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 *pn, int keyid, size_t *encrypted_len)
{
u8 aad[30], nonce[13];
size_t aad_len, plen;
u8 *crypt, *pos;
struct ieee80211_hdr *hdr;
if (len < hdrlen || hdrlen < 24)
return NULL;
plen = len - hdrlen;
crypt = os_malloc(hdrlen + 8 + plen + 8 + AES_BLOCK_SIZE);
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++ = 0x00; /* Rsvd */
*pos++ = 0x20 | (keyid << 6);
*pos++ = pn[3]; /* PN2 */
*pos++ = pn[2]; /* PN3 */
*pos++ = pn[1]; /* PN4 */
*pos++ = pn[0]; /* PN5 */
os_memset(aad, 0, sizeof(aad));
ccmp_aad_nonce(hdr, crypt + hdrlen, aad, &aad_len, nonce);
wpa_hexdump(MSG_DEBUG, "CCMP AAD", aad, aad_len);
wpa_hexdump(MSG_DEBUG, "CCMP nonce", nonce, 13);
if (aes_ccm_ae(tk, 16, nonce, 8, frame + hdrlen, plen, aad, aad_len,
pos, pos + plen) < 0) {
os_free(crypt);
return NULL;
}
wpa_hexdump(MSG_DEBUG, "CCMP encrypted", crypt + hdrlen + 8, plen);
*encrypted_len = hdrlen + 8 + plen + 8;
return crypt;
}
u8 * ccmp_encrypt_pv1(const u8 *tk, const u8 *a1, const u8 *a2, const u8 *a3,
const u8 *frame, size_t len,
size_t hdrlen, const u8 *pn, int keyid,
size_t *encrypted_len)
{
u8 aad[24], nonce[13];
size_t aad_len, plen;
u8 *crypt, *pos;
struct ieee80211_hdr *hdr;
if (len < hdrlen || hdrlen < 12)
return NULL;
plen = len - hdrlen;
crypt = os_malloc(hdrlen + plen + 8 + AES_BLOCK_SIZE);
if (crypt == NULL)
return NULL;
os_memcpy(crypt, frame, hdrlen);
hdr = (struct ieee80211_hdr *) crypt;
hdr->frame_control |= host_to_le16(BIT(12)); /* Protected Frame */
pos = crypt + hdrlen;
os_memset(aad, 0, sizeof(aad));
ccmp_aad_nonce_pv1(crypt, a1, a2, a3, pn, aad, &aad_len, nonce);
wpa_hexdump(MSG_DEBUG, "CCMP AAD", aad, aad_len);
wpa_hexdump(MSG_DEBUG, "CCMP nonce", nonce, sizeof(nonce));
if (aes_ccm_ae(tk, 16, nonce, 8, frame + hdrlen, plen, aad, aad_len,
pos, pos + plen) < 0) {
os_free(crypt);
return NULL;
}
wpa_hexdump(MSG_DEBUG, "CCMP encrypted", crypt + hdrlen, plen);
*encrypted_len = hdrlen + plen + 8;
return crypt;
}
u8 * ccmp_256_decrypt(const u8 *tk, const u8 *hdr, const u8 *data,
size_t data_len, size_t *decrypted_len)
{
u8 aad[30], nonce[13];
size_t aad_len;
size_t mlen;
u8 *plain;
if (data_len < 8 + 16)
return NULL;
plain = os_malloc(data_len + AES_BLOCK_SIZE);
if (plain == NULL)
return NULL;
mlen = data_len - 8 - 16;
os_memset(aad, 0, sizeof(aad));
ccmp_aad_nonce((const struct ieee80211_hdr *)hdr, data, aad, &aad_len, nonce);
wpa_hexdump(MSG_DEBUG, "CCMP-256 AAD", aad, aad_len);
wpa_hexdump(MSG_DEBUG, "CCMP-256 nonce", nonce, 13);
if (aes_ccm_ad(tk, 32, nonce, 16, data + 8, mlen, aad, aad_len,
data + 8 + mlen, plain) < 0) {
os_free(plain);
return NULL;
}
wpa_hexdump(MSG_DEBUG, "CCMP-256 decrypted", plain, mlen);
*decrypted_len = mlen;
return plain;
}
u8 * ccmp_256_encrypt(const u8 *tk, u8 *frame, size_t len, size_t hdrlen,
u8 *pn, int keyid, size_t *encrypted_len)
{
u8 aad[30], nonce[13];
size_t aad_len, plen;
u8 *crypt, *pos;
struct ieee80211_hdr *hdr;
if (len < hdrlen || hdrlen < 24)
return NULL;
plen = len - hdrlen;
crypt = os_malloc(hdrlen + 8 + plen + 16 + AES_BLOCK_SIZE);
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++ = 0x00; /* Rsvd */
*pos++ = 0x20 | (keyid << 6);
*pos++ = pn[3]; /* PN2 */
*pos++ = pn[2]; /* PN3 */
*pos++ = pn[1]; /* PN4 */
*pos++ = pn[0]; /* PN5 */
os_memset(aad, 0, sizeof(aad));
ccmp_aad_nonce(hdr, crypt + hdrlen, aad, &aad_len, nonce);
wpa_hexdump(MSG_DEBUG, "CCMP-256 AAD", aad, aad_len);
wpa_hexdump(MSG_DEBUG, "CCMP-256 nonce", nonce, 13);
if (aes_ccm_ae(tk, 32, nonce, 16, frame + hdrlen, plen, aad, aad_len,
pos, pos + plen) < 0) {
os_free(crypt);
return NULL;
}
wpa_hexdump(MSG_DEBUG, "CCMP-256 encrypted", crypt + hdrlen + 8,
plen);
*encrypted_len = hdrlen + 8 + plen + 16;
return crypt;
}
#endif /* CONFIG_IEEE80211W */

View file

@ -0,0 +1,28 @@
/*
* wlantest - IEEE 802.11 protocol monitoring and testing tool
* Copyright (c) 2010-2013, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifdef CONFIG_IEEE80211W
#ifndef CCMP_H
#define CCMP_H
u8 * ccmp_decrypt(const u8 *tk, const u8 *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 *pn, int keyid, size_t *encrypted_len);
u8 * ccmp_encrypt_pv1(const u8 *tk, const u8 *a1, const u8 *a2, const u8 *a3,
const u8 *frame, size_t len,
size_t hdrlen, const u8 *pn, int keyid,
size_t *encrypted_len);
void ccmp_get_pn(u8 *pn, const u8 *data);
u8 * ccmp_256_decrypt(const u8 *tk, const u8 *hdr, const u8 *data,
size_t data_len, size_t *decrypted_len);
u8 * ccmp_256_encrypt(const u8 *tk, u8 *frame, size_t len, size_t hdrlen,
u8 *pn, int keyid, size_t *encrypted_len);
#endif /* CCMP_H */
#endif /* CONFIG_IEEE80211W */

View file

@ -20,6 +20,7 @@
#include "sha1.h"
#include "aes.h"
#include "esp_wpa.h"
#include "ccmp.h"
/*
* This structure is used to set the cyrpto callback function for station to connect when in security mode.
@ -48,7 +49,10 @@ const wpa_crypto_funcs_t g_wifi_default_wpa_crypto_funcs = {
.aes_encrypt_deinit = (esp_aes_encrypt_deinit_t)aes_encrypt_deinit,
.aes_decrypt = (esp_aes_decrypt_t)aes_decrypt,
.aes_decrypt_init = (esp_aes_decrypt_init_t)aes_decrypt_init,
.aes_decrypt_deinit = (esp_aes_decrypt_deinit_t)aes_decrypt_deinit
.aes_decrypt_deinit = (esp_aes_decrypt_deinit_t)aes_decrypt_deinit,
.omac1_aes_128 = (esp_omac1_aes_128_t)omac1_aes_128,
.ccmp_decrypt = (esp_ccmp_decrypt_t)ccmp_decrypt,
.ccmp_encrypt = (esp_ccmp_encrypt_t)ccmp_encrypt
};
const mesh_crypto_funcs_t g_wifi_default_mesh_crypto_funcs = {

View file

@ -164,6 +164,13 @@ typedef struct {
uint32_t arg_size;
} wifi_ipc_config_t;
#define WPA_IGTK_LEN 16
typedef struct {
uint8_t keyid[2];
uint8_t pn[6];
uint8_t igtk[WPA_IGTK_LEN];
} wifi_wpa_igtk_t;
uint8_t *esp_wifi_ap_get_prof_pmk_internal(void);
struct wifi_ssid *esp_wifi_ap_get_prof_ap_ssid_internal(void);
uint8_t esp_wifi_ap_get_prof_authmode_internal(void);
@ -221,5 +228,6 @@ uint8_t *esp_wifi_sta_get_ap_info_prof_pmk_internal(void);
esp_err_t esp_wifi_set_wps_start_flag_internal(bool start);
uint16_t esp_wifi_sta_pmf_enabled(void);
wifi_cipher_type_t esp_wifi_sta_get_mgmt_group_cipher(void);
int esp_wifi_set_igtk_internal(uint8_t if_index, const wifi_wpa_igtk_t *igtk);
#endif /* _ESP_WIFI_DRIVER_H_ */

View file

@ -27,6 +27,7 @@
#include "crypto/crypto.h"
#include "crypto/sha1.h"
#include "crypto/aes_wrap.h"
#include "crypto/ccmp.h"
/**
* eapol_sm_notify_eap_success - Notification of external EAP success trigger
@ -681,7 +682,7 @@ int wpa_supplicant_install_ptk(struct wpa_sm *sm)
#endif
return -1;
}
if (sm->wpa_ptk_rekey) {
eloop_cancel_timeout(wpa_sm_rekey_ptk, sm, NULL);
eloop_register_timeout(sm->wpa_ptk_rekey, 0, wpa_sm_rekey_ptk,
@ -991,7 +992,29 @@ void wpa_report_ie_mismatch(struct wpa_sm *sm, const u8 *src_addr,
int ieee80211w_set_keys(struct wpa_sm *sm,
struct wpa_eapol_ie_parse *ie)
{
#ifdef CONFIG_IEEE80211W
if (sm->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) {
return -1;
}
if (ie->igtk) {
const wifi_wpa_igtk_t *igtk;
uint16_t keyidx;
if (ie->igtk_len != sizeof(*igtk)) {
return -1;
}
igtk = (const wifi_wpa_igtk_t*)ie->igtk;
keyidx = WPA_GET_LE16(igtk->keyid);
if (keyidx > 4095) {
return -1;
}
return esp_wifi_set_igtk_internal(ESP_IF_WIFI_STA, igtk);
}
return 0;
#else
return 0;
#endif
}
int wpa_supplicant_validate_ie(struct wpa_sm *sm,
@ -2319,10 +2342,10 @@ bool wpa_sta_in_4way_handshake(void)
return false;
}
bool wpa_sta_is_cur_pmksa_set(void) {
struct wpa_sm *sm = &gWpaSm;
return (pmksa_cache_get_current(sm) != NULL);
}
#endif // ESP_SUPPLICANT

View file

@ -231,14 +231,16 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
/* PMKID */
os_memcpy(pos, sm->cur_pmksa->pmkid, PMKID_LEN);
pos += PMKID_LEN;
} else {
/* 0 PMKID Count */
WPA_PUT_LE16(pos, 0);
pos += 2;
}
#ifdef CONFIG_IEEE80211W
if (mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) {
if (!sm->cur_pmksa) {
/* 0 PMKID Count */
WPA_PUT_LE16(pos, 0);
pos += 2;
}
/* Management Group Cipher Suite */
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC);
pos += RSN_SELECTOR_LEN;
@ -329,6 +331,16 @@ static int wpa_parse_generic(const u8 *pos, const u8 *end,
pos, pos[1] + 2);
return 0;
}
#ifdef CONFIG_IEEE80211W
if (pos[1] > RSN_SELECTOR_LEN + 2 &&
RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) {
ie->igtk = pos + 2 + RSN_SELECTOR_LEN;
ie->igtk_len = pos[1] - RSN_SELECTOR_LEN;
wpa_hexdump(MSG_DEBUG, "WPA: IGTK in EAPOL-Key",
pos, pos[1] + 2);
return 0;
}
#endif
return 0;
}