#include <PBKDF2/HMACSHA1.h>
#include <PBKDF2/pbkdf2.h>
#include "AppleCSPSession.h"
#include "AppleCSPUtils.h"
#include "cspdebugging.h"
#include <Security/context.h>
#include <Security/utilities.h>
#include <DiffieHellman/DH_exchange.h>
#define PBKDF2_MIN_SALT 8
#define PBKDF2_MIN_ITER_CNT 1000
#define ALLOW_ZERO_PASSWORD 1
void AppleCSPSession::DeriveKey_PBKDF2(
const Context &context,
const CssmData &Param,
CSSM_DATA *keyData)
{
if(Param.Length != sizeof(CSSM_PKCS5_PBKDF2_PARAMS)) {
errorLog0("DeriveKey_PBKDF2: Param wrong size\n");
CssmError::throwMe(CSSMERR_CSP_INVALID_INPUT_POINTER);
}
const CSSM_PKCS5_PBKDF2_PARAMS *pbkdf2Params =
reinterpret_cast<const CSSM_PKCS5_PBKDF2_PARAMS *>(Param.Data);
if(pbkdf2Params == NULL) {
errorLog0("DeriveKey_PBKDF2: null Param.Data\n");
CssmError::throwMe(CSSMERR_CSP_INVALID_DATA);
}
uint32 passphraseLen = pbkdf2Params->Passphrase.Length;
uint8 *passphrase = pbkdf2Params->Passphrase.Data;
#if !ALLOW_ZERO_PASSWORD
if(passphrase == NULL) {
errorLog0("DeriveKey_PBKDF2: null Passphrase\n");
CssmError::throwMe(CSSMERR_CSP_INVALID_DATA);
}
if(passphraseLen == 0) {
errorLog0("DeriveKey_PBKDF2: zero length passphrase\n");
CssmError::throwMe(CSSMERR_CSP_INVALID_INPUT_POINTER);
}
#endif
if(pbkdf2Params->PseudoRandomFunction !=
CSSM_PKCS5_PBKDF2_PRF_HMAC_SHA1) {
errorLog0("DeriveKey_PBKDF2: invalid PRF\n");
CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM);
}
CssmData salt = context.get<CssmData>(CSSM_ATTRIBUTE_SALT,
CSSMERR_CSP_MISSING_ATTR_SALT);
if((salt.Data == NULL) || (salt.Length < PBKDF2_MIN_SALT)){
CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_SALT);
}
uint32 iterCount = context.getInt(CSSM_ATTRIBUTE_ITERATION_COUNT,
CSSMERR_CSP_MISSING_ATTR_ITERATION_COUNT);
if(iterCount < PBKDF2_MIN_ITER_CNT) {
CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_ITERATION_COUNT);
}
uint32 tempLen = salt.Length + 4;
if(tempLen < kSHA1DigestSize) {
tempLen = kSHA1DigestSize;
}
tempLen += (2 * kSHA1DigestSize);
CSSM_DATA tempData = {0, NULL};
setUpData(tempData, tempLen, privAllocator);
pbkdf2 (hmacsha1,
kSHA1DigestSize,
passphrase, passphraseLen,
salt.Data, salt.Length,
iterCount,
keyData->Data, keyData->Length,
tempData.Data);
freeData(&tempData, privAllocator, false);
}
void AppleCSPSession::DeriveKey(
CSSM_CC_HANDLE CCHandle,
const Context &context,
CssmData &Param,
uint32 KeyUsage,
uint32 KeyAttr,
const CssmData *KeyLabel,
const CSSM_RESOURCE_CONTROL_CONTEXT *CredAndAclEntry,
CssmKey &DerivedKey)
{
switch(context.algorithm()) {
case CSSM_ALGID_PKCS5_PBKDF2:
case CSSM_ALGID_DH:
break;
default:
CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM);
}
DerivedKey.KeyData.Data = NULL;
DerivedKey.KeyData.Length = 0;
cspKeyStorage keyStorage = cspParseKeyAttr(CKT_Session, KeyAttr);
cspValidateKeyUsageBits(CKT_Session, KeyUsage);
uint32 keyType = context.getInt(CSSM_ATTRIBUTE_KEY_TYPE,
CSSMERR_CSP_MISSING_ATTR_KEY_TYPE);
uint32 reqKeySize = context.getInt(
CSSM_ATTRIBUTE_KEY_LENGTH,
CSSMERR_CSP_MISSING_ATTR_KEY_LENGTH);
uint32 keySizeInBytes = (reqKeySize + 7) / 8;
SymmetricBinaryKey *binKey = NULL;
CSSM_DATA_PTR keyData = NULL;
switch(keyStorage) {
case CKS_None:
CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK);
case CKS_Ref:
binKey = new SymmetricBinaryKey(reqKeySize);
keyData = &binKey->mKeyData;
break;
case CKS_Data:
keyData = &DerivedKey.KeyData;
setUpData(*keyData, keySizeInBytes,
normAllocator);
break;
}
switch(context.algorithm()) {
case CSSM_ALGID_PKCS5_PBKDF2:
DeriveKey_PBKDF2(context,
Param,
keyData);
break;
case CSSM_ALGID_DH:
DeriveKey_DH(context,
Param,
keyData,
*this);
break;
default:
assert(0);
}
KeyAttr &= ~KEY_ATTR_RETURN_MASK;
CSSM_KEYHEADER &hdr = DerivedKey.KeyHeader;
setKeyHeader(hdr,
plugin.myGuid(),
keyType,
CSSM_KEYCLASS_SESSION_KEY,
KeyAttr,
KeyUsage);
hdr.LogicalKeySizeInBits = reqKeySize;
if(keyStorage == CKS_Ref) {
addRefKey(*binKey, DerivedKey);
}
else {
hdr.BlobType = CSSM_KEYBLOB_RAW;
hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING;
}
}