Skip to content

Commit

Permalink
Corrected 4WH and GKH replay counters
Browse files Browse the repository at this point in the history
Added unused setting to authenticator send replay counter and
supplicant receive replay counter. This allows that authenticator
may use zero counter on send and supplicant can accept it.
  • Loading branch information
Mika Leppänen committed Mar 29, 2019
1 parent 45a76e1 commit 1c25c24
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 7 deletions.
23 changes: 17 additions & 6 deletions source/Security/protocols/fwh_sec_prot/supp_fwh_sec_prot.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ typedef struct {
uint64_t recv_replay_cnt; /**< received replay counter */
bool msg3_received : 1; /**< Valid Message 3 has been received */
bool msg3_retry_wait : 1; /**< Waiting for Message 3 retry */
bool recv_replay_cnt_set : 1; /**< received replay counter set */
} fwh_sec_prot_int_t;

static uint16_t supp_fwh_sec_prot_size(void);
Expand All @@ -97,7 +98,7 @@ static int8_t supp_fwh_sec_prot_ptk_generate(sec_prot_t *prot, sec_prot_keys_t *
static int8_t supp_fwh_sec_prot_mic_validate(sec_prot_t *prot);

static void supp_fwh_sec_prot_recv_replay_counter_store(sec_prot_t *prot);
static uint64_t supp_fwh_sec_prot_recv_replay_counter_get(sec_prot_t *prot);
static bool supp_fwh_sec_prot_recv_replay_cnt_compare(uint64_t received_counter, sec_prot_t *prot);
static void supp_fwh_sec_prot_anonce_store(sec_prot_t *prot);
static int8_t supp_fwh_sec_prot_anonce_validate(sec_prot_t *prot);
static void supp_fwh_sec_prot_security_replay_counter_update(sec_prot_t *prot);
Expand Down Expand Up @@ -141,6 +142,7 @@ static int8_t supp_fwh_sec_prot_init(sec_prot_t *prot)
data->msg3_received = false;
data->msg3_retry_wait = false;
data->recv_replay_cnt = 0;
data->recv_replay_cnt_set = false;

uint8_t eui64[8] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
sec_prot_lib_nonce_init(data->snonce, eui64, 1000);
Expand Down Expand Up @@ -213,8 +215,8 @@ static fwh_sec_prot_msg_e supp_fwh_sec_prot_message_get(sec_prot_t *prot, eapol_
* the four way handshake session (note: PMK replay counter is not updated for Message 1
* but session specific counter is)
*/
if (eapol_pdu->msg.key.replay_counter > sec_prot_keys_pmk_replay_cnt_get(prot->sec_keys) &&
eapol_pdu->msg.key.replay_counter > supp_fwh_sec_prot_recv_replay_counter_get(prot)) {
if (sec_prot_keys_pmk_replay_cnt_compare(eapol_pdu->msg.key.replay_counter, prot->sec_keys) &&
supp_fwh_sec_prot_recv_replay_cnt_compare(eapol_pdu->msg.key.replay_counter, prot)) {
msg = FWH_MESSAGE_1;
} else {
tr_error("4WH: invalid replay counter %"PRId64, eapol_pdu->msg.key.replay_counter);
Expand All @@ -223,7 +225,7 @@ static fwh_sec_prot_msg_e supp_fwh_sec_prot_message_get(sec_prot_t *prot, eapol_
// Message 3
case KEY_INFO_INSTALL | KEY_INFO_KEY_ACK | KEY_INFO_KEY_MIC | KEY_INFO_SECURED_KEY_FRAME:
// Must have valid replay counter
if (eapol_pdu->msg.key.replay_counter > sec_prot_keys_pmk_replay_cnt_get(prot->sec_keys)) {
if (sec_prot_keys_pmk_replay_cnt_compare(eapol_pdu->msg.key.replay_counter, prot->sec_keys)) {
if (eapol_pdu->msg.key.key_information.encrypted_key_data) {
// This should include the GTK KDE, Lifetime KDE and GTKL KDE.
// At least some of them should be present
Expand Down Expand Up @@ -489,12 +491,21 @@ static void supp_fwh_sec_prot_recv_replay_counter_store(sec_prot_t *prot)
{
fwh_sec_prot_int_t *data = fwh_sec_prot_get(prot);
data->recv_replay_cnt = data->recv_eapol_pdu.msg.key.replay_counter;
data->recv_replay_cnt_set = true;
}

static uint64_t supp_fwh_sec_prot_recv_replay_counter_get(sec_prot_t *prot)
static bool supp_fwh_sec_prot_recv_replay_cnt_compare(uint64_t received_counter, sec_prot_t *prot)
{
fwh_sec_prot_int_t *data = fwh_sec_prot_get(prot);
return data->recv_replay_cnt;
// If previous value is set must be greater
if (data->recv_replay_cnt_set && received_counter > data->recv_replay_cnt) {
return true;
} else if (!data->recv_replay_cnt_set && received_counter >= data->recv_replay_cnt) {
// Otherwise allows also same value e.g. zero
return true;
}

return false;
}

static void supp_fwh_sec_prot_anonce_store(sec_prot_t *prot)
Expand Down
2 changes: 1 addition & 1 deletion source/Security/protocols/gkh_sec_prot/supp_gkh_sec_prot.c
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ static gkh_sec_prot_msg_e supp_gkh_sec_prot_message_get(eapol_pdu_t *eapol_pdu,
switch (key_mask) {
case KEY_INFO_KEY_ACK | KEY_INFO_KEY_MIC | KEY_INFO_SECURED_KEY_FRAME:
// Must have valid replay counter
if (eapol_pdu->msg.key.replay_counter > sec_prot_keys_pmk_replay_cnt_get(sec_keys)) {
if (sec_prot_keys_pmk_replay_cnt_compare(eapol_pdu->msg.key.replay_counter, sec_keys)) {
if (eapol_pdu->msg.key.key_information.encrypted_key_data) {
// This should include the GTK KDE, Lifetime KDE and GTKL KDE.
msg = GKH_MESSAGE_1;
Expand Down
22 changes: 22 additions & 0 deletions source/Security/protocols/sec_prot_keys.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ void sec_prot_keys_init(sec_prot_keys_t *sec_keys, sec_prot_gtk_keys_t *gtks, co
sec_keys->gtk_set_index = -1;
sec_keys->pmk_set = false;
sec_keys->ptk_set = false;
sec_keys->pmk_key_replay_cnt_set = false;
sec_keys->updated = false;
sec_keys->ptk_eui_64_set = false;
sec_keys->pmk_mismatch = false;
Expand Down Expand Up @@ -100,6 +101,7 @@ void sec_prot_keys_pmk_write(sec_prot_keys_t *sec_keys, uint8_t *pmk)
{
memcpy(sec_keys->pmk, pmk, PMK_LEN);
sec_keys->pmk_key_replay_cnt = 0;
sec_keys->pmk_key_replay_cnt_set = false;
sec_keys->pmk_lifetime = PMK_LIFETIME_INSTALL;
sec_keys->pmk_set = true;
sec_keys->updated = true;
Expand All @@ -109,6 +111,7 @@ void sec_prot_keys_pmk_delete(sec_prot_keys_t *sec_keys)
{
memset(sec_keys->pmk, 0, PMK_LEN);
sec_keys->pmk_key_replay_cnt = 0;
sec_keys->pmk_key_replay_cnt_set = false;
sec_keys->pmk_lifetime = PMK_LIFETIME_INSTALL;
sec_keys->pmk_set = false;
sec_keys->updated = true;
Expand All @@ -130,14 +133,33 @@ uint64_t sec_prot_keys_pmk_replay_cnt_get(sec_prot_keys_t *sec_keys)

void sec_prot_keys_pmk_replay_cnt_set(sec_prot_keys_t *sec_keys, uint64_t counter)
{
sec_keys->pmk_key_replay_cnt_set = true;
sec_keys->pmk_key_replay_cnt = counter;
}

void sec_prot_keys_pmk_replay_cnt_increment(sec_prot_keys_t *sec_keys)
{
// Start from zero i.e. does not increment on first call
if (!sec_keys->pmk_key_replay_cnt_set) {
sec_keys->pmk_key_replay_cnt_set = true;
return;
}
sec_keys->pmk_key_replay_cnt++;
}

bool sec_prot_keys_pmk_replay_cnt_compare(uint64_t received_counter, sec_prot_keys_t *sec_keys)
{
// If previous value is set must be greater
if (sec_keys->pmk_key_replay_cnt_set && received_counter > sec_keys->pmk_key_replay_cnt) {
return true;
} else if (!sec_keys->pmk_key_replay_cnt_set && received_counter >= sec_keys->pmk_key_replay_cnt) {
// Otherwise allows also same value e.g. zero
return true;
}

return false;
}

void sec_prot_keys_pmk_mismatch_set(sec_prot_keys_t *sec_keys)
{
sec_keys->pmk_mismatch = true;
Expand Down
13 changes: 13 additions & 0 deletions source/Security/protocols/sec_prot_keys.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ typedef struct {
int8_t gtk_set_index; /**< Index of GTK to set */
bool pmk_set: 1; /**< Pairwise Master Key set */
bool ptk_set: 1; /**< Pairwise Transient Key set */
bool pmk_key_replay_cnt_set: 1; /**< Pairwise Master Key replay counter set */
bool updated: 1; /**< Keys has been updated */
bool ptk_eui_64_set: 1; /**< Remote EUI-64 used to derive PTK is set */
bool pmk_mismatch: 1; /**< Remote PMK mismatch reported */
Expand Down Expand Up @@ -207,6 +208,18 @@ void sec_prot_keys_pmk_replay_cnt_set(sec_prot_keys_t *sec_keys, uint64_t counte
*/
void sec_prot_keys_pmk_replay_cnt_increment(sec_prot_keys_t *sec_keys);

/**
* sec_prot_keys_pmk_replay_cnt_compare compares received replay counter value to PMK replay counter
*
* \param received_counter received replay counter
* \param sec_keys security keys
*
* \return TRUE received replay counter is valid
* \return FALSE received replay counter is not valid
*
*/
bool sec_prot_keys_pmk_replay_cnt_compare(uint64_t received_counter, sec_prot_keys_t *sec_keys);

/**
* sec_prot_keys_pmk_mismatch_set set PMK mismatch
*
Expand Down

0 comments on commit 1c25c24

Please sign in to comment.