diff --git a/qdf/inc/qdf_crypto.h b/qdf/inc/qdf_crypto.h index e418ce7796..2d599fde9a 100644 --- a/qdf/inc/qdf_crypto.h +++ b/qdf/inc/qdf_crypto.h @@ -54,6 +54,8 @@ extern "C" { #define IS_VALID_CTR_KEY_LEN(len) ((((len) == 16) || ((len) == 32) || \ ((len) == 48)) ? 1 : 0) +#define WLAN_MAX_PRF_INTERATIONS_COUNT 255 + /* Function declarations and documenation */ /** @@ -87,6 +89,34 @@ int qdf_get_hmac_hash(uint8_t *type, uint8_t *key, uint32_t keylen, uint8_t element_cnt, uint8_t *addr[], uint32_t *addr_len, int8_t *hash); +/** + * qdf_default_hmac_sha256_kdf()- This API calculates key data using default kdf + * defined in RFC4306. + * @secret: key which needs to be used in crypto + * @secret_len: key_len of secret + * @label: PRF label + * @optional_data: Data used for hash + * @optional_data_len: data length + * @key: key data output + * @keylen: key data length + * + * This API creates default KDF as defined in RFC4306 + * PRF+ (K,S) = T1 | T2 | T3 | T4 | ... + * T1 = PRF (K, S | 0x01) + * T2 = PRF (K, T1 | S | 0x02) + * T3 = PRF (K, T2 | S | 0x03) + * T4 = PRF (K, T3 | S | 0x04) + * + * for every iteration its creates 32 bit of hash + * + * Return: QDF_STATUS + */ +QDF_STATUS +qdf_default_hmac_sha256_kdf(uint8_t *secret, uint32_t secret_len, + uint8_t *label, uint8_t *optional_data, + uint32_t optional_data_len, uint8_t *key, + uint32_t keylen); + /** * qdf_get_keyed_hash: API to get hash using specific crypto and * scatterlist elements. diff --git a/qdf/linux/src/qdf_crypto.c b/qdf/linux/src/qdf_crypto.c index 62b28e717e..12d450fe66 100644 --- a/qdf/linux/src/qdf_crypto.c +++ b/qdf/linux/src/qdf_crypto.c @@ -78,6 +78,63 @@ int qdf_get_hmac_hash(uint8_t *type, uint8_t *key, src_len, element_cnt, hash); } +QDF_STATUS +qdf_default_hmac_sha256_kdf(uint8_t *secret, uint32_t secret_len, + uint8_t *label, uint8_t *optional_data, + uint32_t optional_data_len, uint8_t *key, + uint32_t keylen) +{ + uint8_t tmp_hash[SHA256_DIGEST_SIZE] = {0}; + uint8_t count = 1; + uint8_t *addr[4]; + uint32_t len[4]; + uint32_t current_position = 0, remaining_data = SHA256_DIGEST_SIZE; + + addr[0] = tmp_hash; + len[0] = SHA256_DIGEST_SIZE; + addr[1] = label; + len[1] = strlen(label) + 1; + addr[2] = optional_data; + len[2] = optional_data_len; + addr[3] = &count; + len[3] = 1; + + if (keylen == 0 || + (keylen > (WLAN_MAX_PRF_INTERATIONS_COUNT * SHA256_DIGEST_SIZE))) { + qdf_err("invalid key length %d", keylen); + return QDF_STATUS_E_FAILURE; + } + + /* Create T1 */ + if (qdf_get_hmac_hash(HMAC_SHA256_CRYPTO_TYPE, secret, secret_len, 3, + &addr[1], &len[1], tmp_hash) < 0) { + qdf_err("failed to get hmac hash"); + return QDF_STATUS_E_FAILURE; + } + + /* Update hash from tmp_hash */ + qdf_mem_copy(key + current_position, tmp_hash, remaining_data); + current_position += remaining_data; + + for (count = 2; current_position < keylen; count++) { + remaining_data = keylen - current_position; + if (remaining_data > SHA256_DIGEST_SIZE) + remaining_data = SHA256_DIGEST_SIZE; + + /* Create T-n */ + if (qdf_get_hmac_hash(HMAC_SHA256_CRYPTO_TYPE, secret, + secret_len, 4, addr, len, tmp_hash) < 0) { + qdf_err("failed to get hmac hash"); + return QDF_STATUS_E_FAILURE; + } + /* Update hash from tmp_hash */ + qdf_mem_copy(key + current_position, tmp_hash, remaining_data); + current_position += remaining_data; + } + + return QDF_STATUS_SUCCESS; +} + /* qdf_update_dbl from RFC 5297. Length of d is AES_BLOCK_SIZE (128 bits) */ void qdf_update_dbl(uint8_t *d) { diff --git a/umac/cmn_services/crypto/inc/wlan_crypto_global_api.h b/umac/cmn_services/crypto/inc/wlan_crypto_global_api.h index e265ae873b..58f1fed461 100644 --- a/umac/cmn_services/crypto/inc/wlan_crypto_global_api.h +++ b/umac/cmn_services/crypto/inc/wlan_crypto_global_api.h @@ -981,4 +981,24 @@ void wlan_crypto_set_sae_single_pmk_bss_cap(struct wlan_objmgr_vdev *vdev, } #endif +#ifdef WLAN_FEATURE_FILS_SK +/** + * lim_create_fils_rik()- This API create rik using rrk coming from + * supplicant. + * @rrk: input rrk + * @rrk_len: rrk length + * @rik: Created rik + * @rik_len: rik length to be filled + * + * rIK = KDF (K, S), where + * K = rRK and + * S = rIK Label + "\0" + cryptosuite + length + * The rIK Label is the 8-bit ASCII string: + * Re-authentication Integrity Key@ietf.org + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_crypto_create_fils_rik(uint8_t *rrk, uint8_t rrk_len, + uint8_t *rik, uint32_t *rik_len); +#endif /* WLAN_FEATURE_FILS_SK */ #endif /* end of _WLAN_CRYPTO_GLOBAL_API_H_ */ diff --git a/umac/cmn_services/crypto/inc/wlan_crypto_global_def.h b/umac/cmn_services/crypto/inc/wlan_crypto_global_def.h index 468e42b4dd..922ee620e1 100644 --- a/umac/cmn_services/crypto/inc/wlan_crypto_global_def.h +++ b/umac/cmn_services/crypto/inc/wlan_crypto_global_def.h @@ -75,6 +75,10 @@ #define WLAN_CRYPTO_WPI_SMS4_PADLEN (1) #define WLAN_CRYPTO_WPI_SMS4_MICLEN (16) +/* FILS definitions */ +#define WLAN_CRYPTO_FILS_OPTIONAL_DATA_LEN 3 +#define WLAN_CRYPTO_FILS_RIK_LABEL "Re-authentication Integrity Key@ietf.org" + /* key used for xmit */ #define WLAN_CRYPTO_KEY_XMIT (0x01) /* key used for recv */ @@ -217,6 +221,21 @@ enum wlan_crypto_key_type { #define IS_WEP_CIPHER(_c) ((_c == WLAN_CRYPTO_CIPHER_WEP) || \ (_c == WLAN_CRYPTO_CIPHER_WEP_40) || \ (_c == WLAN_CRYPTO_CIPHER_WEP_104)) + +/* + * enum fils_erp_cryptosuite: this enum defines the cryptosuites used + * to calculate auth tag and auth tag length as defined by RFC 6696 5.3.1 + * @HMAC_SHA256_64: sha256 with auth tag len as 64 bits + * @HMAC_SHA256_128: sha256 with auth tag len as 128 bits + * @HMAC_SHA256_256: sha256 with auth tag len as 256 bits + */ +enum fils_erp_cryptosuite { + INVALID_CRYPTO = 0, /* reserved */ + HMAC_SHA256_64, + HMAC_SHA256_128, + HMAC_SHA256_256, +}; + /** * struct wlan_crypto_pmksa - structure of crypto to contain pmkid * @bssid: bssid for which pmkid is saved diff --git a/umac/cmn_services/crypto/src/wlan_crypto_global_api.c b/umac/cmn_services/crypto/src/wlan_crypto_global_api.c index bf1b538d4e..b4a146a149 100644 --- a/umac/cmn_services/crypto/src/wlan_crypto_global_api.c +++ b/umac/cmn_services/crypto/src/wlan_crypto_global_api.c @@ -4486,5 +4486,38 @@ void wlan_crypto_set_sae_single_pmk_bss_cap(struct wlan_objmgr_vdev *vdev, } } #endif - #endif + +#ifdef WLAN_FEATURE_FILS_SK +QDF_STATUS wlan_crypto_create_fils_rik(uint8_t *rrk, uint8_t rrk_len, + uint8_t *rik, uint32_t *rik_len) +{ + uint8_t optional_data[WLAN_CRYPTO_FILS_OPTIONAL_DATA_LEN]; + uint8_t label[] = WLAN_CRYPTO_FILS_RIK_LABEL; + QDF_STATUS status; + + if (!rrk || !rik) { + crypto_err("FILS rrk/rik NULL"); + return QDF_STATUS_E_FAILURE; + } + + optional_data[0] = HMAC_SHA256_128; + /* basic validation */ + if (rrk_len <= 0) { + crypto_err("invalid r_rk length %d", rrk_len); + return QDF_STATUS_E_FAILURE; + } + + wlan_crypto_put_be16(&optional_data[1], rrk_len); + status = qdf_default_hmac_sha256_kdf(rrk, rrk_len, label, optional_data, + sizeof(optional_data), rik, + rrk_len); + if (QDF_IS_STATUS_ERROR(status)) { + crypto_err("failed to create rik"); + return status; + } + *rik_len = rrk_len; + + return QDF_STATUS_SUCCESS; +} +#endif /* WLAN_FEATURE_FILS_SK */