Skip to content

Commit 1c25c24

Browse files
author
Mika Leppänen
committed
Corrected 4WH and GKH replay counters
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.
1 parent 45a76e1 commit 1c25c24

File tree

4 files changed

+53
-7
lines changed

4 files changed

+53
-7
lines changed

source/Security/protocols/fwh_sec_prot/supp_fwh_sec_prot.c

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ typedef struct {
7979
uint64_t recv_replay_cnt; /**< received replay counter */
8080
bool msg3_received : 1; /**< Valid Message 3 has been received */
8181
bool msg3_retry_wait : 1; /**< Waiting for Message 3 retry */
82+
bool recv_replay_cnt_set : 1; /**< received replay counter set */
8283
} fwh_sec_prot_int_t;
8384

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

99100
static void supp_fwh_sec_prot_recv_replay_counter_store(sec_prot_t *prot);
100-
static uint64_t supp_fwh_sec_prot_recv_replay_counter_get(sec_prot_t *prot);
101+
static bool supp_fwh_sec_prot_recv_replay_cnt_compare(uint64_t received_counter, sec_prot_t *prot);
101102
static void supp_fwh_sec_prot_anonce_store(sec_prot_t *prot);
102103
static int8_t supp_fwh_sec_prot_anonce_validate(sec_prot_t *prot);
103104
static void supp_fwh_sec_prot_security_replay_counter_update(sec_prot_t *prot);
@@ -141,6 +142,7 @@ static int8_t supp_fwh_sec_prot_init(sec_prot_t *prot)
141142
data->msg3_received = false;
142143
data->msg3_retry_wait = false;
143144
data->recv_replay_cnt = 0;
145+
data->recv_replay_cnt_set = false;
144146

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

494-
static uint64_t supp_fwh_sec_prot_recv_replay_counter_get(sec_prot_t *prot)
497+
static bool supp_fwh_sec_prot_recv_replay_cnt_compare(uint64_t received_counter, sec_prot_t *prot)
495498
{
496499
fwh_sec_prot_int_t *data = fwh_sec_prot_get(prot);
497-
return data->recv_replay_cnt;
500+
// If previous value is set must be greater
501+
if (data->recv_replay_cnt_set && received_counter > data->recv_replay_cnt) {
502+
return true;
503+
} else if (!data->recv_replay_cnt_set && received_counter >= data->recv_replay_cnt) {
504+
// Otherwise allows also same value e.g. zero
505+
return true;
506+
}
507+
508+
return false;
498509
}
499510

500511
static void supp_fwh_sec_prot_anonce_store(sec_prot_t *prot)

source/Security/protocols/gkh_sec_prot/supp_gkh_sec_prot.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ static gkh_sec_prot_msg_e supp_gkh_sec_prot_message_get(eapol_pdu_t *eapol_pdu,
177177
switch (key_mask) {
178178
case KEY_INFO_KEY_ACK | KEY_INFO_KEY_MIC | KEY_INFO_SECURED_KEY_FRAME:
179179
// Must have valid replay counter
180-
if (eapol_pdu->msg.key.replay_counter > sec_prot_keys_pmk_replay_cnt_get(sec_keys)) {
180+
if (sec_prot_keys_pmk_replay_cnt_compare(eapol_pdu->msg.key.replay_counter, sec_keys)) {
181181
if (eapol_pdu->msg.key.key_information.encrypted_key_data) {
182182
// This should include the GTK KDE, Lifetime KDE and GTKL KDE.
183183
msg = GKH_MESSAGE_1;

source/Security/protocols/sec_prot_keys.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ void sec_prot_keys_init(sec_prot_keys_t *sec_keys, sec_prot_gtk_keys_t *gtks, co
6262
sec_keys->gtk_set_index = -1;
6363
sec_keys->pmk_set = false;
6464
sec_keys->ptk_set = false;
65+
sec_keys->pmk_key_replay_cnt_set = false;
6566
sec_keys->updated = false;
6667
sec_keys->ptk_eui_64_set = false;
6768
sec_keys->pmk_mismatch = false;
@@ -100,6 +101,7 @@ void sec_prot_keys_pmk_write(sec_prot_keys_t *sec_keys, uint8_t *pmk)
100101
{
101102
memcpy(sec_keys->pmk, pmk, PMK_LEN);
102103
sec_keys->pmk_key_replay_cnt = 0;
104+
sec_keys->pmk_key_replay_cnt_set = false;
103105
sec_keys->pmk_lifetime = PMK_LIFETIME_INSTALL;
104106
sec_keys->pmk_set = true;
105107
sec_keys->updated = true;
@@ -109,6 +111,7 @@ void sec_prot_keys_pmk_delete(sec_prot_keys_t *sec_keys)
109111
{
110112
memset(sec_keys->pmk, 0, PMK_LEN);
111113
sec_keys->pmk_key_replay_cnt = 0;
114+
sec_keys->pmk_key_replay_cnt_set = false;
112115
sec_keys->pmk_lifetime = PMK_LIFETIME_INSTALL;
113116
sec_keys->pmk_set = false;
114117
sec_keys->updated = true;
@@ -130,14 +133,33 @@ uint64_t sec_prot_keys_pmk_replay_cnt_get(sec_prot_keys_t *sec_keys)
130133

131134
void sec_prot_keys_pmk_replay_cnt_set(sec_prot_keys_t *sec_keys, uint64_t counter)
132135
{
136+
sec_keys->pmk_key_replay_cnt_set = true;
133137
sec_keys->pmk_key_replay_cnt = counter;
134138
}
135139

136140
void sec_prot_keys_pmk_replay_cnt_increment(sec_prot_keys_t *sec_keys)
137141
{
142+
// Start from zero i.e. does not increment on first call
143+
if (!sec_keys->pmk_key_replay_cnt_set) {
144+
sec_keys->pmk_key_replay_cnt_set = true;
145+
return;
146+
}
138147
sec_keys->pmk_key_replay_cnt++;
139148
}
140149

150+
bool sec_prot_keys_pmk_replay_cnt_compare(uint64_t received_counter, sec_prot_keys_t *sec_keys)
151+
{
152+
// If previous value is set must be greater
153+
if (sec_keys->pmk_key_replay_cnt_set && received_counter > sec_keys->pmk_key_replay_cnt) {
154+
return true;
155+
} else if (!sec_keys->pmk_key_replay_cnt_set && received_counter >= sec_keys->pmk_key_replay_cnt) {
156+
// Otherwise allows also same value e.g. zero
157+
return true;
158+
}
159+
160+
return false;
161+
}
162+
141163
void sec_prot_keys_pmk_mismatch_set(sec_prot_keys_t *sec_keys)
142164
{
143165
sec_keys->pmk_mismatch = true;

source/Security/protocols/sec_prot_keys.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ typedef struct {
8585
int8_t gtk_set_index; /**< Index of GTK to set */
8686
bool pmk_set: 1; /**< Pairwise Master Key set */
8787
bool ptk_set: 1; /**< Pairwise Transient Key set */
88+
bool pmk_key_replay_cnt_set: 1; /**< Pairwise Master Key replay counter set */
8889
bool updated: 1; /**< Keys has been updated */
8990
bool ptk_eui_64_set: 1; /**< Remote EUI-64 used to derive PTK is set */
9091
bool pmk_mismatch: 1; /**< Remote PMK mismatch reported */
@@ -207,6 +208,18 @@ void sec_prot_keys_pmk_replay_cnt_set(sec_prot_keys_t *sec_keys, uint64_t counte
207208
*/
208209
void sec_prot_keys_pmk_replay_cnt_increment(sec_prot_keys_t *sec_keys);
209210

211+
/**
212+
* sec_prot_keys_pmk_replay_cnt_compare compares received replay counter value to PMK replay counter
213+
*
214+
* \param received_counter received replay counter
215+
* \param sec_keys security keys
216+
*
217+
* \return TRUE received replay counter is valid
218+
* \return FALSE received replay counter is not valid
219+
*
220+
*/
221+
bool sec_prot_keys_pmk_replay_cnt_compare(uint64_t received_counter, sec_prot_keys_t *sec_keys);
222+
210223
/**
211224
* sec_prot_keys_pmk_mismatch_set set PMK mismatch
212225
*

0 commit comments

Comments
 (0)