Skip to content

Commit

Permalink
Added protection to frames, mtk derivation.
Browse files Browse the repository at this point in the history
Stable and passes test-005-encryption
  • Loading branch information
Javier Cardona committed Apr 26, 2011
1 parent c3fc620 commit a42b16a
Show file tree
Hide file tree
Showing 10 changed files with 159 additions and 80 deletions.
129 changes: 103 additions & 26 deletions ampe.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@
static unsigned char *meshid[32];
static unsigned char meshid_len;
static struct ampe_config config;
static const unsigned char akm_suite_selector[4] = { 0x0, 0xf, 0xac, 0x8 };
static const unsigned char akm_suite_selector[4] = { 0x0, 0xf, 0xac, 0x8 }; /* SAE */
static const unsigned char pw_suite_selector[4] = { 0x0, 0xf, 0xac, 0x4 }; /* CCMP */

/* For debugging use */
static const char *mplstates[] = {
Expand Down Expand Up @@ -201,38 +202,48 @@ static void plink_timer(timerid id, void *data)
}
}

static void protect_frame(unsigned char *buf, struct candidate *cand, int *len)
void protect_frame(struct candidate *cand, unsigned char *buf, int len)
{
struct ieee80211_mgmt_frame *frame;
struct ieee80211_mgmt_frame *mgmt;
unsigned char output[32];
unsigned char counter[AES_BLOCK_SIZE];
unsigned char *ies;
unsigned short ies_len;
struct info_elems elems;

assert(len && cand && buf);

frame = (struct ieee80211_mgmt_frame *) buf;
/* Find mesh peering ie */
mgmt = (struct ieee80211_mgmt_frame *) buf;
ies = start_of_ies(mgmt, len, &ies_len);
parse_ies(ies, ies_len, &elems);
if (!elems.mesh_peering) {
sae_debug(AMPE_DEBUG_FSM, "protect frame: missing mesh peering ie\n");
return;
}

siv_init(&cand->sivctx, cand->aek, SIV_256);
siv_encrypt(&cand->sivctx, (unsigned char *) &frame->action, output,
*len - ((unsigned char*) &frame->action - buf),
siv_encrypt(&cand->sivctx, elems.mesh_peering, output,
elems.mesh_peering_len,
counter, 3,
"ONE", 3,
"TWO", 3,
"THREE", 5);
cand->my_mac, ETH_ALEN,
cand->peer_mac, ETH_ALEN,
&mgmt->action, len - 24);
}

static int plink_frame_tx(struct candidate *cand, enum
plink_action_code action, unsigned short reason)
{
unsigned char *buf;
struct ieee80211_mgmt_frame *mgmt;
unsigned char *plen;
unsigned char *ie_len;
int len;
struct mesh_peering_ie;
unsigned char *ies;

assert(cand);

/* XXX: calculate the right size */
len = 400;
len = 1000;
buf = calloc(1, len);
if (!buf)
return -1;
Expand All @@ -257,24 +268,27 @@ static int plink_frame_tx(struct candidate *cand, enum
memcpy((char *) ies, meshid, meshid_len);
ies += meshid_len;

/* Add mesh peering */
/* Add mesh peering: llid, plid, reason and pmk */
*ies++ = IEEE80211_EID_MESH_PEERING;
plen = ies++;
ie_len = ies++;
memcpy(ies, &cand->my_lid, 2);
ies += 2;
*plen = 2;
*ie_len = 2;
if (cand->peer_lid) {
memcpy(ies, &cand->peer_lid, 2);
ies += 2;
*plen += 2;
*ie_len += 2;
}
if (reason) {
memcpy(ies, &cand->reason, 2);
ies += 2;
*plen += 2;
*ie_len += 2;
}

/* TODO: Add PMK field to mesh peering element here */
/* Add chosen PMK */
memcpy(ies, cand->pmkid, sizeof(cand->pmkid));
ies += sizeof(cand->pmkid);
*ie_len += sizeof(cand->pmkid);

/* Add mesh config */
*ies++ = IEEE80211_EID_MESH_CONFIG;
Expand All @@ -283,11 +297,20 @@ static int plink_frame_tx(struct candidate *cand, enum
memset(ies, 0, 8);
ies += 8;

/* TODO: Add PMK field to mesh peering element here */
/* Add AMPE IE */
*ies++ = IEEE80211_EID_AMPE;
*ies++ = 68;
memcpy(ies, pw_suite_selector, 4);
ies += 4;
memcpy(ies, cand->my_nonce, 32);
ies += 32;
memcpy(ies, cand->peer_nonce, 32);
ies += 32;
/* TODO: Add key replay and GTK fields */

len = ies - buf;

protect_frame(buf, cand, &len);
protect_frame(cand, buf, len);

if (meshd_write_mgmt((char *)buf, len, cand->cookie) != len) {
sae_debug(SAE_DEBUG_ERR, "can't send an authentication "
Expand All @@ -297,6 +320,53 @@ static int plink_frame_tx(struct candidate *cand, enum
return 0;
}

static void derive_mtk(struct candidate *cand)
{
unsigned char context[84];
unsigned char *p;

p = context;
if (memcmp(cand->my_nonce, cand->peer_nonce, 32)) {
memcpy(p, cand->my_nonce, 32);
memcpy(p + 32, cand->peer_nonce, 32);
} else {
memcpy(p, cand->peer_nonce, 32);
memcpy(p + 32, cand->my_nonce, 32);
}
p += 64;

if (le16toh(cand->my_lid) < le16toh(cand->peer_lid)) {
memcpy(p, &cand->my_lid, 2);
memcpy(p + 2, &cand->peer_lid, 2);
} else {
memcpy(p, &cand->peer_lid, 2);
memcpy(p + 2, &cand->my_lid, 2);
}
p += 4;

memcpy(p, akm_suite_selector, sizeof(akm_suite_selector));
p += sizeof(akm_suite_selector);

if (memcmp(cand->my_mac, cand->peer_mac, ETH_ALEN) < 0) {
memcpy(p, cand->my_mac, ETH_ALEN);
memcpy(p + ETH_ALEN, cand->peer_mac, ETH_ALEN);
} else {
memcpy(p, cand->peer_mac, ETH_ALEN);
memcpy(p + ETH_ALEN, cand->my_mac, ETH_ALEN);
}
p += 12;

assert(p - context <= sizeof(context));

prf(cand->mtk, SHA256_DIGEST_LENGTH,
(unsigned char *)"Temporal Key Derivation", strlen("Temporal Key Derivation"),
context, sizeof(context),
cand->aek, SHA256_DIGEST_LENGTH * 8);

sae_hexdump(AMPE_DEBUG_KEYS, "aek: ", cand->aek, sizeof(cand->aek));
}


static void fsm_step(struct candidate *cand, enum plink_event event)
{
unsigned short reason = 0;
Expand Down Expand Up @@ -369,7 +439,10 @@ static void fsm_step(struct candidate *cand, enum plink_event event)
cand->link_state = PLINK_ESTAB;
//mesh_plink_inc_estab_count(sdata);
//ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
estab_peer_link(cand->peer_mac, cand->cookie);
derive_mtk(cand);
// TODO: for now give everyone the same all-zeros mgtk
memset(cand->mgtk, 0, sizeof(cand->mgtk));
estab_peer_link(cand->peer_mac, cand->mtk, sizeof(cand->mtk), cand->mgtk, sizeof(cand->mgtk), cand->cookie);
sae_debug(AMPE_DEBUG_FSM, "mesh plink with "
MACSTR " established\n", MAC2STR(cand->peer_mac));
break;
Expand All @@ -394,7 +467,9 @@ static void fsm_step(struct candidate *cand, enum plink_event event)
break;
case OPN_ACPT:
cand->link_state = PLINK_ESTAB;
estab_peer_link(cand->peer_mac, cand->cookie);
// TODO: for now give everyone the same all-zeros mgtk
memset(cand->mgtk, 0, sizeof(cand->mgtk));
estab_peer_link(cand->peer_mac, cand->mtk, sizeof(cand->mtk), cand->mgtk, sizeof(cand->mgtk), cand->cookie);
//TODO: update the number of available peer "slots" in mesh config
//mesh_plink_inc_estab_count(sdata);
//ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
Expand Down Expand Up @@ -496,6 +571,7 @@ int start_peer_link(unsigned char *peer_mac, unsigned char *me, void *cookie)
derive_aek(cand);

RAND_bytes((unsigned char *) &llid, 2);
RAND_bytes(cand->my_nonce, 32);
cand->cookie = cookie;
cand->my_lid = llid;
cand->peer_lid = 0;
Expand Down Expand Up @@ -566,10 +642,9 @@ int process_ampe_frame(struct ieee80211_mgmt_frame *mgmt, int len,
ftype = mgmt->action.action_code;
ie_len = elems.mesh_peering_len;

/* TODO: This hard coded lenghts need reviewing */
if ((ftype == PLINK_OPEN && ie_len != 2) ||
(ftype == PLINK_CONFIRM && ie_len != 4) ||
(ftype == PLINK_CLOSE && ie_len != 4 && ie_len != 6)) {
if ((ftype == PLINK_OPEN && ie_len != 18) ||
(ftype == PLINK_CONFIRM && ie_len != 20) ||
(ftype == PLINK_CLOSE && ie_len != 20 && ie_len != 22)) {
sae_debug(AMPE_DEBUG_FSM, "Mesh plink: incorrect plink ie length %d %d\n",
ftype, ie_len);
return 0;
Expand All @@ -592,6 +667,8 @@ int process_ampe_frame(struct ieee80211_mgmt_frame *mgmt, int len,
return 0;
}

/* The local nonce in the frame is the peer from the POV of this host. */
memcpy(cand->peer_nonce, elems.ampe->local_nonce, 32);
cand->cookie = cookie;

if (cand->link_state == PLINK_BLOCKED) {
Expand Down
2 changes: 1 addition & 1 deletion ampe.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,5 @@ int process_ampe_frame(struct ieee80211_mgmt_frame *frame, int len, unsigned cha
int start_peer_link(unsigned char *peer_mac, unsigned char *me, void *cookie);

/* and implements these: */
void estab_peer_link(unsigned char *peer, void *cookie);
void estab_peer_link(unsigned char *peer, unsigned char *mtk, int mtk_len, unsigned char *mgtk, int mgtk_len, void *cookie);
#endif
8 changes: 6 additions & 2 deletions common.c
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,9 @@ void sae_debug (int level, const char *fmt, ...)
}
}

void sae_hexdump(int level, const char *label, const char *start, int len)
void sae_hexdump(int level, const char *label, const unsigned char *start, int len)
{
const char *pos;
const unsigned char *pos;
int i;

if (sae_debug_mask & level) {
Expand Down Expand Up @@ -150,6 +150,10 @@ void parse_ies(unsigned char *start, int len, struct info_elems *elems)
elems->mesh_config = pos;
elems->mesh_config_len = elen;
break;
case IEEE80211_EID_AMPE:
elems->ampe = (struct ampe_ie *) pos;
elems->ampe_len = elen;
break;
default:
break;
}
Expand Down
6 changes: 5 additions & 1 deletion common.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,10 @@ int parse_buffer(char *, char **);
#define AMPE_DEBUG_CANDIDATES 0x20
#define MESHD_DEBUG 0x40
#define AMPE_DEBUG_FSM 0x80
#define AMPE_DEBUG_KEYS 0x100
extern unsigned int sae_debug_mask;
void sae_debug (int level, const char *fmt, ...);
void sae_hexdump(int level, const char *label, const char *start, int
void sae_hexdump(int level, const char *label, const unsigned char *start, int
len);

#ifndef u8
Expand All @@ -72,4 +73,7 @@ void sae_hexdump(int level, const char *label, const char *start, int
#ifndef u16
#define u16 unsigned short
#endif
#ifndef le32
#define le32 unsigned int
#endif
#endif /* _COMMON_H_ */
5 changes: 3 additions & 2 deletions config/sae.conf
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
debug=128
#debug=128
#debug=96
#debug=32
#
debug=256

password=thisisreallysecret
#
group=19 26 21 25 20
Expand Down
21 changes: 11 additions & 10 deletions ieee802_11.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,23 +144,21 @@ enum ieee_ie_ids {
IEEE80211_EID_MESH_CONFIG = 113,
IEEE80211_EID_MESH_ID = 114,
IEEE80211_EID_MESH_PEERING = 117,
IEEE80211_EID_AMPE = 139,
};

enum ieee_categories {
IEEE80211_CATEGORY_MESH_ACTION = 13,
IEEE80211_CATEGORY_SELF_PROTECTED = 15,
};

struct mesh_peering_ie {
unsigned char eid;
unsigned char len;
unsigned short llid;
union {
unsigned short plid;
unsigned short reason; /* may be in var[0] if plid is present */
};
unsigned char var[0];
};
struct ampe_ie {
unsigned char selected_pairwise_suite[4];
unsigned char local_nonce[32];
unsigned char peer_nonce[32];
unsigned char key_replay_cnt[8];
unsigned char gtk[0];
} __attribute__ ((packed));

struct info_elems {
unsigned char *rsn;
Expand All @@ -174,6 +172,9 @@ struct info_elems {

unsigned char *mesh_config;
unsigned char mesh_config_len;

struct ampe_ie *ampe;
unsigned char ampe_len;
};

void parse_ies(unsigned char *start, int len, struct info_elems *elems);
Expand Down
Loading

0 comments on commit a42b16a

Please sign in to comment.