mac80111: Add BIP-CMAC-256 cipher
This allows mac80211 to configure BIP-CMAC-256 to the driver and also use software-implementation within mac80211 when the driver does not support this with hardware accelaration. Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:

committed by
Johannes Berg

parent
2b2ba0db1c
commit
56c52da2d5
@@ -955,6 +955,48 @@ ieee80211_crypto_aes_cmac_encrypt(struct ieee80211_tx_data *tx)
|
||||
return TX_CONTINUE;
|
||||
}
|
||||
|
||||
ieee80211_tx_result
|
||||
ieee80211_crypto_aes_cmac_256_encrypt(struct ieee80211_tx_data *tx)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
struct ieee80211_tx_info *info;
|
||||
struct ieee80211_key *key = tx->key;
|
||||
struct ieee80211_mmie_16 *mmie;
|
||||
u8 aad[20];
|
||||
u64 pn64;
|
||||
|
||||
if (WARN_ON(skb_queue_len(&tx->skbs) != 1))
|
||||
return TX_DROP;
|
||||
|
||||
skb = skb_peek(&tx->skbs);
|
||||
|
||||
info = IEEE80211_SKB_CB(skb);
|
||||
|
||||
if (info->control.hw_key)
|
||||
return TX_CONTINUE;
|
||||
|
||||
if (WARN_ON(skb_tailroom(skb) < sizeof(*mmie)))
|
||||
return TX_DROP;
|
||||
|
||||
mmie = (struct ieee80211_mmie_16 *)skb_put(skb, sizeof(*mmie));
|
||||
mmie->element_id = WLAN_EID_MMIE;
|
||||
mmie->length = sizeof(*mmie) - 2;
|
||||
mmie->key_id = cpu_to_le16(key->conf.keyidx);
|
||||
|
||||
/* PN = PN + 1 */
|
||||
pn64 = atomic64_inc_return(&key->u.aes_cmac.tx_pn);
|
||||
|
||||
bip_ipn_set64(mmie->sequence_number, pn64);
|
||||
|
||||
bip_aad(skb, aad);
|
||||
|
||||
/* MIC = AES-256-CMAC(IGTK, AAD || Management Frame Body || MMIE, 128)
|
||||
*/
|
||||
ieee80211_aes_cmac_256(key->u.aes_cmac.tfm, aad,
|
||||
skb->data + 24, skb->len - 24, mmie->mic);
|
||||
|
||||
return TX_CONTINUE;
|
||||
}
|
||||
|
||||
ieee80211_rx_result
|
||||
ieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx)
|
||||
@@ -1006,6 +1048,56 @@ ieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx)
|
||||
return RX_CONTINUE;
|
||||
}
|
||||
|
||||
ieee80211_rx_result
|
||||
ieee80211_crypto_aes_cmac_256_decrypt(struct ieee80211_rx_data *rx)
|
||||
{
|
||||
struct sk_buff *skb = rx->skb;
|
||||
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
|
||||
struct ieee80211_key *key = rx->key;
|
||||
struct ieee80211_mmie_16 *mmie;
|
||||
u8 aad[20], mic[16], ipn[6];
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
|
||||
if (!ieee80211_is_mgmt(hdr->frame_control))
|
||||
return RX_CONTINUE;
|
||||
|
||||
/* management frames are already linear */
|
||||
|
||||
if (skb->len < 24 + sizeof(*mmie))
|
||||
return RX_DROP_UNUSABLE;
|
||||
|
||||
mmie = (struct ieee80211_mmie_16 *)
|
||||
(skb->data + skb->len - sizeof(*mmie));
|
||||
if (mmie->element_id != WLAN_EID_MMIE ||
|
||||
mmie->length != sizeof(*mmie) - 2)
|
||||
return RX_DROP_UNUSABLE; /* Invalid MMIE */
|
||||
|
||||
bip_ipn_swap(ipn, mmie->sequence_number);
|
||||
|
||||
if (memcmp(ipn, key->u.aes_cmac.rx_pn, 6) <= 0) {
|
||||
key->u.aes_cmac.replays++;
|
||||
return RX_DROP_UNUSABLE;
|
||||
}
|
||||
|
||||
if (!(status->flag & RX_FLAG_DECRYPTED)) {
|
||||
/* hardware didn't decrypt/verify MIC */
|
||||
bip_aad(skb, aad);
|
||||
ieee80211_aes_cmac_256(key->u.aes_cmac.tfm, aad,
|
||||
skb->data + 24, skb->len - 24, mic);
|
||||
if (memcmp(mic, mmie->mic, sizeof(mmie->mic)) != 0) {
|
||||
key->u.aes_cmac.icverrors++;
|
||||
return RX_DROP_UNUSABLE;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(key->u.aes_cmac.rx_pn, ipn, 6);
|
||||
|
||||
/* Remove MMIE */
|
||||
skb_trim(skb, skb->len - sizeof(*mmie));
|
||||
|
||||
return RX_CONTINUE;
|
||||
}
|
||||
|
||||
ieee80211_tx_result
|
||||
ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx)
|
||||
{
|
||||
|
Reference in New Issue
Block a user