qcacmn: In crypto use QDF api to calculate MIC for OS derivatives

For WLAN_CRYPTO_OMAC1_OS_DERIVATIVE and
WLAN_CRYPTO_GCM_OS_DERIVATIVE set use QDF API to calculate MIC

Change-Id: I5971eb39414a292534981753805df6d9beb54be0
CRs-Fixed: 2664275
This commit is contained in:
Abhishek Singh
2020-04-13 11:41:53 +05:30
committed by nshrivas
parent e2d6e92a68
commit d96c0dbfbf
4 changed files with 168 additions and 13 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2018 The Linux Foundation. All rights reserved.
* Copyright (c) 2017-2018, 2020 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -47,6 +47,7 @@ extern "C" {
#define FIXED_PARAM_OFFSET_ASSOC_REQ 4
#define FIXED_PARAM_OFFSET_ASSOC_RSP 6
#define CMAC_TLEN 8 /* CMAC TLen = 64 bits (8 octets) */
#define AAD_LEN 20
#define IEEE80211_MMIE_GMAC_MICLEN 16
@@ -152,9 +153,21 @@ int qdf_aes_ctr(const uint8_t *key, unsigned int key_len, uint8_t *siv,
*
* Return: 0 if success else Error number
*/
int qdf_crypto_aes_gmac(uint8_t *key, uint16_t key_length,
uint8_t *iv, uint8_t *aad, uint8_t *data,
uint16_t data_len, uint8_t *mic);
int qdf_crypto_aes_gmac(const uint8_t *key, uint16_t key_length,
uint8_t *iv, const uint8_t *aad,
const uint8_t *data, uint16_t data_len, uint8_t *mic);
/**
* qdf_crypto_aes_128_cmac: This API calculates MIC for AES 128 CMAC
* @key: key used for operation
* @data: Pointer to data
* @len: Length of data
* @mic: Pointer to MIC
*
* Return: 0 if success else Error number
*/
int qdf_crypto_aes_128_cmac(const uint8_t *key, const uint8_t *data,
uint16_t len, uint8_t *mic);
#ifdef __cplusplus
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2019 The Linux Foundation. All rights reserved.
* Copyright (c) 2017-2020 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -95,6 +95,136 @@ void qdf_update_dbl(uint8_t *d)
d[AES_BLOCK_SIZE - 1] ^= 0x87;
}
static inline void xor_128(const uint8_t *a, const uint8_t *b, uint8_t *out)
{
uint8_t i;
for (i = 0; i < AES_BLOCK_SIZE; i++)
out[i] = a[i] ^ b[i];
}
static inline void leftshift_onebit(const uint8_t *input, uint8_t *output)
{
int i, overflow = 0;
for (i = (AES_BLOCK_SIZE - 1); i >= 0; i--) {
output[i] = input[i] << 1;
output[i] |= overflow;
overflow = (input[i] & 0x80) ? 1 : 0;
}
}
static void generate_subkey(struct crypto_cipher *tfm, uint8_t *k1, uint8_t *k2)
{
uint8_t l[AES_BLOCK_SIZE], tmp[AES_BLOCK_SIZE];
const uint8_t const_rb[AES_BLOCK_SIZE] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87
};
const uint8_t const_zero[AES_BLOCK_SIZE] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
crypto_cipher_encrypt_one(tfm, l, const_zero);
if ((l[0] & 0x80) == 0) { /* If MSB(l) = 0, then k1 = l << 1 */
leftshift_onebit(l, k1);
} else { /* Else k1 = ( l << 1 ) (+) Rb */
leftshift_onebit(l, tmp);
xor_128(tmp, const_rb, k1);
}
if ((k1[0] & 0x80) == 0) {
leftshift_onebit(k1, k2);
} else {
leftshift_onebit(k1, tmp);
xor_128(tmp, const_rb, k2);
}
}
static inline void padding(const uint8_t *lastb, uint8_t *pad, uint16_t length)
{
uint8_t j;
/* original last block */
for (j = 0; j < AES_BLOCK_SIZE; j++) {
if (j < length)
pad[j] = lastb[j];
else if (j == length)
pad[j] = 0x80;
else
pad[j] = 0x00;
}
}
int qdf_crypto_aes_128_cmac(const uint8_t *key, const uint8_t *data,
uint16_t len, uint8_t *mic)
{
uint8_t x[AES_BLOCK_SIZE], y[AES_BLOCK_SIZE];
uint8_t m_last[AES_BLOCK_SIZE], padded[AES_BLOCK_SIZE];
uint8_t k1[AES_KEYSIZE_128], k2[AES_KEYSIZE_128];
int cmp_blk;
int i, num_block = (len + 15) / AES_BLOCK_SIZE;
struct crypto_cipher *tfm;
int ret;
/*
* Calculate MIC and then copy
*/
tfm = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(tfm)) {
ret = PTR_ERR(tfm);
qdf_err("crypto_alloc_cipher failed (%d)", ret);
return ret;
}
ret = crypto_cipher_setkey(tfm, key, AES_KEYSIZE_128);
if (ret) {
qdf_err("crypto_cipher_setkey failed (%d)", ret);
crypto_free_cipher(tfm);
return ret;
}
generate_subkey(tfm, k1, k2);
if (num_block == 0) {
num_block = 1;
cmp_blk = 0;
} else {
cmp_blk = ((len % AES_BLOCK_SIZE) == 0) ? 1 : 0;
}
if (cmp_blk) {
/* Last block is complete block */
xor_128(&data[AES_BLOCK_SIZE * (num_block - 1)], k1, m_last);
} else {
/* Last block is not complete block */
padding(&data[AES_BLOCK_SIZE * (num_block - 1)], padded,
len % AES_BLOCK_SIZE);
xor_128(padded, k2, m_last);
}
for (i = 0; i < AES_BLOCK_SIZE; i++)
x[i] = 0;
for (i = 0; i < (num_block - 1); i++) {
/* y = Mi (+) x */
xor_128(x, &data[AES_BLOCK_SIZE * i], y);
/* x = AES-128(KEY, y) */
crypto_cipher_encrypt_one(tfm, x, y);
}
xor_128(x, m_last, y);
crypto_cipher_encrypt_one(tfm, x, y);
crypto_free_cipher(tfm);
memcpy(mic, x, CMAC_TLEN);
return 0;
}
/**
* set_desc_flags() - set flags variable in the shash_desc struct
* @desc: pointer to shash_desc struct
@@ -377,9 +507,9 @@ int qdf_aes_ctr(const uint8_t *key, unsigned int key_len, uint8_t *siv,
#endif
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
int qdf_crypto_aes_gmac(uint8_t *key, uint16_t key_length,
uint8_t *iv, uint8_t *aad, uint8_t *data,
uint16_t data_len, uint8_t *mic)
int qdf_crypto_aes_gmac(const uint8_t *key, uint16_t key_length,
uint8_t *iv, const uint8_t *aad,
const uint8_t *data, uint16_t data_len, uint8_t *mic)
{
struct crypto_aead *tfm;
int ret = 0;

View File

@@ -23,6 +23,7 @@
#define _WLAN_CRYPTO_GLOBAL_API_H_
#include "wlan_crypto_global_def.h"
#include <qdf_crypto.h>
/**
* wlan_crypto_set_vdev_param - called by ucfg to set crypto param
* @vdev: vdev
@@ -726,18 +727,22 @@ QDF_STATUS wlan_set_vdev_crypto_prarams_from_ie(struct wlan_objmgr_vdev *vdev,
uint16_t ie_len);
#ifdef WLAN_CRYPTO_GCM_OS_DERIVATIVE
static inline int wlan_crypto_aes_gmac(const uint8_t *key, size_t key_len,
const uint8_t *iv, size_t iv_len,
uint8_t *iv, size_t iv_len,
const uint8_t *aad, size_t aad_len,
uint8_t *tag)
{
return 0;
return qdf_crypto_aes_gmac(key, key_len, iv, aad,
aad + AAD_LEN,
aad_len - AAD_LEN -
IEEE80211_MMIE_GMAC_MICLEN,
tag);
}
#endif
#ifdef WLAN_CRYPTO_OMAC1_OS_DERIVATIVE
static inline int omac1_aes_128(const uint8_t *key, const uint8_t *data,
size_t data_len, uint8_t *mac)
{
return 0;
return qdf_crypto_aes_128_cmac(key, data, data_len, mac);
}
static inline int omac1_aes_256(const uint8_t *key, const uint8_t *data,

View File

@@ -2068,7 +2068,7 @@ bool wlan_crypto_is_mmie_valid(struct wlan_objmgr_vdev *vdev,
uint8_t *frm,
uint8_t *efrm){
struct wlan_crypto_mmie *mmie = NULL;
uint8_t *ipn, *aad, *buf, mic[16], nounce[12];
uint8_t *ipn, *aad, *buf, *mic, nounce[12];
struct wlan_crypto_key *key;
struct wlan_frame_hdr *hdr;
uint16_t mic_len, hdrlen, len;
@@ -2160,7 +2160,11 @@ bool wlan_crypto_is_mmie_valid(struct wlan_objmgr_vdev *vdev,
*/
qdf_mem_copy(buf + 20, frm + hdrlen, len - hdrlen);
qdf_mem_zero(buf + (len - hdrlen + 20 - mic_len), mic_len);
qdf_mem_zero(mic, 16);
mic = qdf_mem_malloc(mic_len);
if (!mic) {
qdf_mem_free(buf);
return false;
}
if (crypto_priv->igtk_key_type == WLAN_CRYPTO_CIPHER_AES_CMAC) {
ret = omac1_aes_128(key->keyval, buf,
len - hdrlen + aad_len, mic);
@@ -2181,16 +2185,19 @@ bool wlan_crypto_is_mmie_valid(struct wlan_objmgr_vdev *vdev,
qdf_mem_free(buf);
if (ret < 0) {
qdf_mem_free(mic);
crypto_err("genarate mmie failed");
return false;
}
if (qdf_mem_cmp(mic, mmie->mic, mic_len) != 0) {
qdf_mem_free(mic);
crypto_err("mmie mismatch");
/* MMIE MIC mismatch */
return false;
}
qdf_mem_free(mic);
/* Update the receive sequence number */
qdf_mem_copy(key->keyrsc, ipn, 6);
crypto_debug("mmie matched");