blob: 9b25443f330cfc78425df7ca74a7d7986bb7e39d [file] [log] [blame]
/*
* Copyright (c) 2012-2013 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
* copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/*
* This file was originally distributed by Qualcomm Atheros, Inc.
* under proprietary terms before Copyright ownership was assigned
* to the Linux Foundation.
*/
/*
* $File: //depot/software/projects/feature_branches/gen5_phase1/os/linux/classic/ap/apps/ssm/auth8021x/ani8021xPrf.c $
*
* Contains definitions for routines to calculate the 802.11i PRF
* functions.
*
* Author: Mayank D. Upadhyay
* Date: 19-March-2003
* History:-
* Date Modified by Modification Information
* ------------------------------------------------------
*/
/*#include <assert.h>
#include <stdlib.h>
#include <aniSsmSha1.h>
*/
#include "vos_utils.h"
#include "vos_memory.h"
#include "bapRsn8021xPrf.h"
#include "bapRsnErrors.h"
//#include "ani8021xUtils.h"
#define AAG_PTK_PRF_ADD_PARAM 159
#define AAG_PTK_PRF_DIV_PARAM 160
#define AAG_PTK_PRF_CONST "Pairwise key expansion"
#define AAG_PTK_PRF_CONST_LEN 22
#define AAG_PTK_PRF_LM_POS 0
#define AAG_PTK_PRF_HM_POS 6
#define AAG_PTK_PRF_LN_POS 12
#define AAG_PTK_PRF_HN_POS (AAG_PTK_PRF_LN_POS + ANI_EAPOL_KEY_RSN_NONCE_SIZE)
#define AAG_PTK_PRF_TEXT_LEN (AAG_PTK_PRF_HN_POS + ANI_EAPOL_KEY_RSN_NONCE_SIZE)
#define AAG_GTK_PRF_CONST "Group key expansion"
#define AAG_GTK_PRF_CONST_LEN 19
#define AAG_GTK_PRF_MAC_POS 0
#define AAG_GTK_PRF_NONCE_POS 6
#define AAG_GTK_PRF_TEXT_LEN (AAG_GTK_PRF_NONCE_POS + ANI_EAPOL_KEY_RSN_NONCE_SIZE)
/**
* aagGetKeyMaterialLen
*
* Returns the number of bytes of the PTK that have to be provided to
* the MAC layer for a given cipher type.
*
* @param cipherType the cipher-type
*
* @return the number of bytes of key material for this cipher type,
* or 0 for invalid cipher types.
*/
int
aagGetKeyMaterialLen(eCsrEncryptionType cipherType)
{
switch (cipherType) {
case eCSR_ENCRYPT_TYPE_AES:
return AAG_RSN_KEY_MATERIAL_LEN_CCMP;
break;
default:
return 0;
break;
};
}
/**
* aagPtkPrf
*
* The PRF used for calculating the pairwise temporal key under IEEE
* 802.11i.
*
* @param result a fixed size array where the outputis stored. Should
* have enough place for the SHA-1 overflow.
* @param prfLen the number of BITS desired from the PRF result
* @param pmk the pairwise master-key
* @param authAddr the MAC address of the authenticator
* @param suppAddr the MAC address of the supplicant
* @param aNonce the nonce generated by the authenticator
* @param sNonce the nonce generated by the supplicant
*
* @return ANI_OK if the operation succeeds
*/
int
aagPtkPrf(v_U32_t cryptHandle,
v_U8_t result[AAG_PRF_MAX_OUTPUT_SIZE],
v_U32_t prfLen,
tAniPacket *pmk,
tAniMacAddr authAddr,
tAniMacAddr suppAddr,
v_U8_t aNonce[ANI_EAPOL_KEY_RSN_NONCE_SIZE],
v_U8_t sNonce[ANI_EAPOL_KEY_RSN_NONCE_SIZE])
{
v_U8_t *lowMac;
v_U8_t *highMac;
v_U8_t *lowNonce;
v_U8_t *highNonce;
v_U8_t *keyBytes;
int keyLen;
v_U8_t text[AAG_PTK_PRF_TEXT_LEN];
//Cannot use voss function here because vos_mem_compare doesn't tell whihc is larger
if (vos_mem_compare2(authAddr, suppAddr, sizeof(tAniMacAddr)) < 0) {
lowMac = authAddr;
highMac = suppAddr;
} else {
lowMac = suppAddr;
highMac = authAddr;
}
if (vos_mem_compare2(aNonce, sNonce, ANI_EAPOL_KEY_RSN_NONCE_SIZE) < 0) {
lowNonce = aNonce;
highNonce = sNonce;
} else {
lowNonce = sNonce;
highNonce = aNonce;
}
vos_mem_copy(text + AAG_PTK_PRF_LM_POS, lowMac, sizeof(tAniMacAddr));
vos_mem_copy(text + AAG_PTK_PRF_HM_POS, highMac, sizeof(tAniMacAddr));
vos_mem_copy(text + AAG_PTK_PRF_LN_POS, lowNonce, ANI_EAPOL_KEY_RSN_NONCE_SIZE);
vos_mem_copy(text + AAG_PTK_PRF_HN_POS, highNonce, ANI_EAPOL_KEY_RSN_NONCE_SIZE);
keyLen = aniAsfPacketGetBytes(pmk, &keyBytes);
if( !ANI_IS_STATUS_SUCCESS( keyLen ) )
{
return keyLen;
}
return aagPrf(cryptHandle,
result,
keyBytes, keyLen,
(v_U8_t *)AAG_PTK_PRF_CONST, AAG_PTK_PRF_CONST_LEN,
text, sizeof(text),
prfLen);
}
/**
* aagGtkPrf
*
* The PRF used for calculating the group temporal key under IEEE
* 802.11i.
*
* @param result a fixed size array where the outputis stored. Should
* have enough place for the SHA-1 overflow.
* @param prfLen the number of BITS desired from the PRF result
* @param gmk the group master-key
* @param authAddr the MAC address of the authenticator
* @param gNonce the nonce generated by the authenticator for this purpose
*
* @return ANI_OK if the operation succeeds
*/
int
aagGtkPrf(v_U32_t cryptHandle,
v_U8_t result[AAG_PRF_MAX_OUTPUT_SIZE],
v_U32_t prfLen,
v_U8_t gmk[AAG_RSN_GMK_SIZE],
tAniMacAddr authAddr,
v_U8_t gNonce[ANI_EAPOL_KEY_RSN_NONCE_SIZE])
{
v_U8_t text[AAG_GTK_PRF_TEXT_LEN];
vos_mem_copy(text + AAG_GTK_PRF_MAC_POS, authAddr, sizeof(tAniMacAddr));
vos_mem_copy(text + AAG_GTK_PRF_NONCE_POS, gNonce, ANI_EAPOL_KEY_RSN_NONCE_SIZE);
return aagPrf(cryptHandle,
result,
gmk, AAG_RSN_GMK_SIZE,
(v_U8_t *)AAG_GTK_PRF_CONST, AAG_GTK_PRF_CONST_LEN,
text, sizeof(text),
prfLen);
}
/**
* aagPrf
*
* The raw PRF function that is used in IEEE 802.11i.
*
* @param result a fixed size array where the outputis stored. Should
* have enough place for the SHA-1 overflow.
* @param key the key to use in the PRF
* @param keyLen the length of the key
* @param a the parameter A which is usually a unique label
* @param aLen the length of the parameter A
* @ param b the parameter B
* @param bLen the length of parameter B
* @param prfLen the number to BITS desired from the PRF result
*
* @return ANI_OK if the operation succeeds
*/
int
aagPrf(v_U32_t cryptHandle,
v_U8_t result[AAG_PRF_MAX_OUTPUT_SIZE],
v_U8_t *key, v_U8_t keyLen,
v_U8_t *a, v_U8_t aLen,
v_U8_t *b, v_U8_t bLen,
v_U32_t prfLen)
{
static v_U8_t y;
v_U8_t *hmacText = NULL;
v_U8_t *resultOffset = result;
int numLoops;
int loopCtrPos;
int i, retVal=0;
hmacText = vos_mem_malloc( aLen + bLen + 2 );
if( NULL == hmacText )
{
return ANI_E_NULL_VALUE;
}
vos_mem_copy(hmacText + 0, a, aLen);
hmacText[aLen] = y;
vos_mem_copy(hmacText + aLen + 1, b, bLen);
loopCtrPos = aLen + 1 + bLen;
numLoops = prfLen + AAG_PTK_PRF_ADD_PARAM;
numLoops /= AAG_PTK_PRF_DIV_PARAM;
for (i = 0; i < numLoops; i++)
{
VOS_ASSERT((resultOffset - result + VOS_DIGEST_SHA1_SIZE)
<= AAG_PRF_MAX_OUTPUT_SIZE);
hmacText[loopCtrPos] = i;
if( VOS_IS_STATUS_SUCCESS( vos_sha1_hmac_str(cryptHandle, hmacText, loopCtrPos + 1, key, keyLen, resultOffset) ) )
{
resultOffset += VOS_DIGEST_SHA1_SIZE;
retVal = ANI_OK;
}
else
{
retVal = ANI_ERROR;
}
}
vos_mem_free(hmacText);
return retVal;
}