@@ -84,12 +84,14 @@
* Management frames.
*/
u8 rx_pn[IEEE80211_NUM_TIDS + 1][IEEE80211_CCMP_PN_LEN];
+ u8 rx_pn_old[IEEE80211_NUM_TIDS + 1][IEEE80211_CCMP_PN_LEN];
struct crypto_aead *tfm;
u32 replays; /* dot11RSNAStatsCCMPReplays */
} ccmp;
struct {
atomic64_t tx_pn;
u8 rx_pn[IEEE80211_CMAC_PN_LEN];
+ u8 rx_pn_old[IEEE80211_CMAC_PN_LEN];
struct crypto_cipher *tfm;
u32 replays; /* dot11RSNAStatsCMACReplays */
u32 icverrors; /* dot11RSNAStatsCMACICVErrors */
@@ -97,6 +99,7 @@
struct {
atomic64_t tx_pn;
u8 rx_pn[IEEE80211_GMAC_PN_LEN];
+ u8 rx_pn_old[IEEE80211_GMAC_PN_LEN];
struct crypto_aead *tfm;
u32 replays; /* dot11RSNAStatsCMACReplays */
u32 icverrors; /* dot11RSNAStatsCMACICVErrors */
@@ -109,12 +112,14 @@
* Management frames.
*/
u8 rx_pn[IEEE80211_NUM_TIDS + 1][IEEE80211_GCMP_PN_LEN];
+ u8 rx_pn_old[IEEE80211_NUM_TIDS + 1][IEEE80211_GCMP_PN_LEN];
struct crypto_aead *tfm;
u32 replays; /* dot11RSNAStatsGCMPReplays */
} gcmp;
struct {
/* generic cipher scheme */
u8 rx_pn[IEEE80211_NUM_TIDS + 1][MAX_PN_LEN];
+ u8 rx_pn_old[IEEE80211_NUM_TIDS + 1][MAX_PN_LEN];
} gen;
} u;
@@ -495,6 +495,7 @@
struct sk_buff *skb = rx->skb;
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
u8 pn[IEEE80211_CCMP_PN_LEN];
+ static u8 zero[IEEE80211_CCMP_PN_LEN];
int data_len;
int queue;
@@ -525,6 +526,31 @@
return RX_DROP_UNUSABLE;
}
+ /* HACK: try to work around race when replacing PSK with enabled hardware offload on AP or STA */
+ if (unlikely(memcmp(key->u.ccmp.rx_pn[queue], zero, IEEE80211_CCMP_PN_LEN) == 0 )) {
+
+ printk ("DDD - rx_pn is zero, virgin key detected! pl=%x\n", pn[IEEE80211_CCMP_PN_LEN-1]);
+ print_hex_dump_debug("cnt: ", DUMP_PREFIX_OFFSET, IEEE80211_CCMP_PN_LEN, 1, key->u.ccmp.rx_pn[queue], IEEE80211_CCMP_PN_LEN, false);
+ print_hex_dump_debug("pn : ", DUMP_PREFIX_OFFSET, IEEE80211_CCMP_PN_LEN, 1, pn, IEEE80211_CCMP_PN_LEN, false);
+
+ if ((memcmp(pn, zero, IEEE80211_CCMP_PN_LEN -1) == 0) && pn[IEEE80211_CCMP_PN_LEN-1] <= 10) {
+ /* pn is <=10 , we can start using the new counter */
+ printk ("DDD - set new pn\n");
+ memcpy(key->u.ccmp.rx_pn[queue], pn, IEEE80211_CCMP_PN_LEN);
+ } else if (memcmp(pn, key->u.ccmp.rx_pn_old[queue], IEEE80211_CCMP_PN_LEN) <= 0) {
+ printk ("DDD - attack!\n");
+ /* reply attack during rekey operation, guess it will really hard to do that... */
+ key->u.ccmp.replays++; /* we count it as an reply anyway...*/
+ return RX_DROP_UNUSABLE;
+ } else {
+ printk ("DDD - prevent poisening \n");
+ memcpy(key->u.ccmp.rx_pn_old[queue], pn, IEEE80211_CCMP_PN_LEN);
+ }
+ } else {
+
+ memcpy(key->u.ccmp.rx_pn[queue], pn, IEEE80211_CCMP_PN_LEN);
+ }
+
if (!(status->flag & RX_FLAG_DECRYPTED)) {
u8 aad[2 * AES_BLOCK_SIZE];
u8 b_0[AES_BLOCK_SIZE];
@@ -539,8 +565,6 @@
return RX_DROP_UNUSABLE;
}
- memcpy(key->u.ccmp.rx_pn[queue], pn, IEEE80211_CCMP_PN_LEN);
-
/* Remove CCMP header and MIC */
if (pskb_trim(skb, skb->len - mic_len))
return RX_DROP_UNUSABLE;