#include "CACKeyHandle.h"
#include "CACRecord.h"
#include "CACToken.h"
#include <security_utilities/debugging.h>
#include <security_utilities/utilities.h>
#include <security_cdsa_utilities/cssmerrors.h>
#include <Security/cssmerr.h>
CACKeyHandle::CACKeyHandle(CACToken &cacToken,
const Tokend::MetaRecord &metaRecord, CACKeyRecord &cacKey) :
Tokend::KeyHandle(metaRecord, &cacKey),
mToken(cacToken),
mKey(cacKey)
{
}
CACKeyHandle::~CACKeyHandle()
{
}
void CACKeyHandle::getKeySize(CSSM_KEY_SIZE &keySize)
{
secdebug("crypto", "getKeySize");
keySize.LogicalKeySizeInBits = mKey.sizeInBits(); keySize.EffectiveKeySizeInBits = mKey.sizeInBits(); }
uint32 CACKeyHandle::getOutputSize(const Context &context, uint32 inputSize,
bool encrypting)
{
secdebug("crypto", "getOutputSize");
if (encrypting)
CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
return inputSize; }
static const unsigned char sha1sigheader[] =
{
0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14 };
static const unsigned char md5sigheader[] =
{
0x30, 0x20, 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05,
0x05, 0x00, 0x04, 0x10 };
void CACKeyHandle::generateSignature(const Context &context,
CSSM_ALGORITHMS signOnly, const CssmData &input, CssmData &signature)
{
secdebug("crypto", "generateSignature alg: %u signOnly: %u",
context.algorithm(), signOnly);
IFDUMPING("crypto", context.dump("signature context"));
if (context.type() != CSSM_ALGCLASS_SIGNATURE)
CssmError::throwMe(CSSMERR_CSP_INVALID_CONTEXT);
if (context.algorithm() != CSSM_ALGID_RSA)
CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM);
const unsigned char *header;
size_t headerLength;
if (signOnly == CSSM_ALGID_SHA1)
{
if (input.Length != 20)
CssmError::throwMe(CSSMERR_CSP_BLOCK_SIZE_MISMATCH);
header = sha1sigheader;
headerLength = sizeof(sha1sigheader);
}
else if (signOnly == CSSM_ALGID_MD5)
{
if (input.Length != 16)
CssmError::throwMe(CSSMERR_CSP_BLOCK_SIZE_MISMATCH);
header = md5sigheader;
headerLength = sizeof(md5sigheader);
}
else if (signOnly == CSSM_ALGID_NONE)
{
header = NULL;
headerLength = 0;
}
else
CssmError::throwMe(CSSMERR_CSP_INVALID_DIGEST_ALGORITHM);
size_t inputDataSize = headerLength + input.Length;
size_t keyLength = mKey.sizeInBits() / 8;
auto_array<unsigned char> inputData(keyLength);
unsigned char *to = inputData.get();
uint32 padding = CSSM_PADDING_PKCS1;
context.getInt(CSSM_ATTRIBUTE_PADDING, padding);
if (padding == CSSM_PADDING_PKCS1)
{
*(to++) = 0;
*(to++) = 1;
size_t padLength = keyLength - 3 - inputDataSize;
memset(to, 0xff, padLength);
to += padLength;
*(to++) = 0;
inputDataSize = keyLength;
}
else if (padding == CSSM_PADDING_NONE)
{
}
else
CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_PADDING);
if (headerLength)
{
memcpy(to, header, headerLength);
to += headerLength;
}
memcpy(to, input.Data, input.Length);
unsigned char *outputData =
reinterpret_cast<unsigned char *>(malloc(keyLength));
size_t outputLength = keyLength;
try
{
mKey.computeCrypt(mToken, true, inputData.get(), inputDataSize,
outputData, outputLength);
}
catch (...)
{
free(outputData);
throw;
}
signature.Data = outputData;
signature.Length = outputLength;
}
void CACKeyHandle::verifySignature(const Context &context,
CSSM_ALGORITHMS signOnly, const CssmData &input, const CssmData &signature)
{
secdebug("crypto", "verifySignature");
CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
}
void CACKeyHandle::generateMac(const Context &context,
const CssmData &input, CssmData &output)
{
secdebug("crypto", "generateMac");
CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
}
void CACKeyHandle::verifyMac(const Context &context,
const CssmData &input, const CssmData &compare)
{
secdebug("crypto", "verifyMac");
CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
}
void CACKeyHandle::encrypt(const Context &context,
const CssmData &clear, CssmData &cipher)
{
secdebug("crypto", "encrypt");
CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
}
void CACKeyHandle::decrypt(const Context &context,
const CssmData &cipher, CssmData &clear)
{
secdebug("crypto", "decrypt alg: %u", context.algorithm());
IFDUMPING("crypto", context.dump("decrypt context"));
if (context.type() != CSSM_ALGCLASS_ASYMMETRIC)
CssmError::throwMe(CSSMERR_CSP_INVALID_CONTEXT);
if (context.algorithm() != CSSM_ALGID_RSA)
CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM);
size_t keyLength = mKey.sizeInBits() / 8;
if (cipher.length() % keyLength != 0)
CssmError::throwMe(CSSMERR_CSP_INPUT_LENGTH_ERROR);
if (cipher.length() != keyLength)
CssmError::throwMe(CSSMERR_CSP_INPUT_LENGTH_ERROR);
auto_array<uint8> outputData(keyLength);
uint8 *output = outputData.get();
size_t outputLength = keyLength;
secdebug("crypto", "decrypt: card supports RSA_NOPAD");
mKey.computeCrypt(mToken, false, cipher.Data, cipher.Length, output,
outputLength);
if (outputLength != keyLength || *(output++) != 0 || *(output++) != 2)
CssmError::throwMe(CSSMERR_CSP_INVALID_DATA);
outputLength -= 2;
size_t padSize;
for (padSize = 0; padSize < outputLength; ++padSize)
if (*(output++) == 0) break;
if (padSize == outputLength || padSize < 8)
CssmError::throwMe(CSSMERR_CSP_INVALID_DATA);
outputLength -= padSize + 1;
clear.Data = reinterpret_cast<uint8 *>(malloc(outputLength));
memcpy(clear.Data, output, outputLength);
clear.Length = outputLength;
}
void CACKeyHandle::exportKey(const Context &context,
const AccessCredentials *cred, CssmKey &wrappedKey)
{
secdebug("crypto", "exportKey");
CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
}
CACKeyHandleFactory::~CACKeyHandleFactory()
{
}
Tokend::KeyHandle *CACKeyHandleFactory::keyHandle(
Tokend::TokenContext *tokenContext, const Tokend::MetaRecord &metaRecord,
Tokend::Record &record) const
{
CACKeyRecord &key = dynamic_cast<CACKeyRecord &>(record);
CACToken &cacToken = static_cast<CACToken &>(*tokenContext);
return new CACKeyHandle(cacToken, metaRecord, key);
}