#include "SDContext.h"
#include "SDCSPSession.h"
#include "SDKey.h"
#include <security_utilities/debugging.h>
#define ssCryptDebug(args...) secdebug("ssCrypt", ## args)
using namespace SecurityServer;
SDContext::SDContext(SDCSPSession &session)
: mSession(session), mContext(NULL)
{
}
void SDContext::clearOutBuf()
{
if(mOutBuf.Data) {
mSession.free(mOutBuf.Data);
mOutBuf.clear();
}
}
void SDContext::copyOutBuf(CssmData &out)
{
if(out.length() < mOutBuf.length()) {
CssmError::throwMe(CSSMERR_CSP_OUTPUT_LENGTH_ERROR);
}
memmove(out.Data, mOutBuf.Data, mOutBuf.Length);
out.Length = mOutBuf.Length;
clearOutBuf();
}
void
SDContext::init(const Context &context,
bool ) {
mContext = &context;
clearOutBuf();
}
SecurityServer::ClientSession &
SDContext::clientSession()
{
return mSession.clientSession();
}
SDRandomContext::SDRandomContext(SDCSPSession &session) : SDContext(session) {}
void
SDRandomContext::init(const Context &context, bool encoding)
{
SDContext::init(context, encoding);
mOutSize = context.getInt(CSSM_ATTRIBUTE_OUTPUT_SIZE, CSSMERR_CSP_MISSING_ATTR_OUTPUT_SIZE);
#if 0
if (const CssmCryptoData *seed = context.get<CssmCryptoData>(CSSM_ATTRIBUTE_SEED)) {
const CssmData &seedValue = (*seed)();
clientSession().seedRandom(seedValue);
}
#endif
}
size_t
SDRandomContext::outputSize(bool final, size_t inSize)
{
return mOutSize;
}
void
SDRandomContext::final(CssmData &out)
{
clientSession().generateRandom(*mContext, out);
}
SDSignatureContext::SDSignatureContext(SDCSPSession &session)
: SDContext(session),
mKeyHandle(noKey),
mNullDigest(NULL),
mDigest(NULL)
{
}
SDSignatureContext::~SDSignatureContext()
{
delete mNullDigest;
delete mDigest;
}
void SDSignatureContext::init(const Context &context, bool signing)
{
SDContext::init(context, signing);
if((mNullDigest != NULL) || (mDigest != NULL)) {
if(mNullDigest != NULL) {
mNullDigest->digestInit();
}
return;
}
const CssmKey &keyInContext =
context.get<const CssmKey>(CSSM_ATTRIBUTE_KEY,
CSSMERR_CSP_MISSING_ATTR_KEY);
mKeyHandle = mSession.lookupKey(keyInContext).keyHandle();
switch(context.algorithm()) {
case CSSM_ALGID_SHA1WithDSA:
mDigestAlg = CSSM_ALGID_SHA1;
mSigAlg = CSSM_ALGID_DSA;
break;
case CSSM_ALGID_DSA: mDigestAlg = CSSM_ALGID_NONE;
mSigAlg = CSSM_ALGID_DSA;
break;
case CSSM_ALGID_SHA1WithRSA:
mDigestAlg = CSSM_ALGID_SHA1;
mSigAlg = CSSM_ALGID_RSA;
break;
case CSSM_ALGID_MD5WithRSA:
mDigestAlg = CSSM_ALGID_MD5;
mSigAlg = CSSM_ALGID_RSA;
break;
case CSSM_ALGID_MD2WithRSA:
mDigestAlg = CSSM_ALGID_MD2;
mSigAlg = CSSM_ALGID_RSA;
break;
case CSSM_ALGID_RSA: mDigestAlg = CSSM_ALGID_NONE;
mSigAlg = CSSM_ALGID_RSA;
break;
case CSSM_ALGID_FEE_SHA1:
mDigestAlg = CSSM_ALGID_SHA1;
mSigAlg = CSSM_ALGID_FEE;
break;
case CSSM_ALGID_FEE_MD5:
mDigestAlg = CSSM_ALGID_MD5;
mSigAlg = CSSM_ALGID_FEE;
break;
case CSSM_ALGID_FEE: mDigestAlg = CSSM_ALGID_NONE;
mSigAlg = CSSM_ALGID_FEE;
break;
case CSSM_ALGID_SHA1WithECDSA:
mDigestAlg = CSSM_ALGID_SHA1;
mSigAlg = CSSM_ALGID_ECDSA;
break;
case CSSM_ALGID_SHA224WithECDSA:
mDigestAlg = CSSM_ALGID_SHA224;
mSigAlg = CSSM_ALGID_ECDSA;
break;
case CSSM_ALGID_SHA256WithECDSA:
mDigestAlg = CSSM_ALGID_SHA256;
mSigAlg = CSSM_ALGID_ECDSA;
break;
case CSSM_ALGID_SHA384WithECDSA:
mDigestAlg = CSSM_ALGID_SHA384;
mSigAlg = CSSM_ALGID_ECDSA;
break;
case CSSM_ALGID_SHA512WithECDSA:
mDigestAlg = CSSM_ALGID_SHA512;
mSigAlg = CSSM_ALGID_ECDSA;
break;
case CSSM_ALGID_ECDSA: mDigestAlg = CSSM_ALGID_NONE;
mSigAlg = CSSM_ALGID_ECDSA;
break;
default:
CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM);
}
if(mDigestAlg == CSSM_ALGID_NONE) {
mNullDigest = new NullDigest();
}
else {
mDigest = new CssmClient::Digest(mSession.mRawCsp, mDigestAlg);
}
}
void SDSignatureContext::setDigestAlgorithm(CSSM_ALGORITHMS digestAlg)
{
mDigestAlg = digestAlg;
}
void SDSignatureContext::update(const CssmData &data)
{
assert(mOutBuf.Data == NULL);
if(mNullDigest) {
mNullDigest->digestUpdate(data.data(), data.length());
}
else {
mDigest->digest(data);
}
}
size_t SDSignatureContext::outputSize(bool final, size_t inSize)
{
if(!final) {
ssCryptDebug("===sig outputSize !final\n");
return 0;
}
if(!encoding()) {
ssCryptDebug("===sig outputSize final, !encoding\n");
return 0;
}
if(inSize == 0) {
clearOutBuf();
sign(mOutBuf);
ssCryptDebug("===sig outputSize(pre-op) %u", (unsigned)mOutBuf.Length);
return (size_t)mOutBuf.Length;
}
else {
uint32 outSize = clientSession().getOutputSize(*mContext,
mKeyHandle,
(uint32)inSize,
true);
ssCryptDebug("===sig outputSize(RPC) %u", (unsigned)outSize);
return (size_t)outSize;
}
}
void SDSignatureContext::sign(CssmData &sig)
{
Context tempContext = *mContext;
tempContext.AlgorithmType = mSigAlg;
if(mNullDigest) {
CssmData dData(const_cast<void *>(mNullDigest->digestPtr()),
mNullDigest->digestSizeInBytes());
clientSession().generateSignature(tempContext,
mKeyHandle,
dData,
sig,
mDigestAlg);
}
else {
CssmAutoData d (mDigest->allocator ());
d.set((*mDigest) ());
clientSession().generateSignature(tempContext,
mKeyHandle,
d,
sig,
mDigestAlg);
}
}
void SDSignatureContext::final(CssmData &sig)
{
if(mOutBuf.Data) {
ssCryptDebug("===final via pre-op and copy");
copyOutBuf(sig);
return;
}
ssCryptDebug("===final via RPC");
sign(sig);
}
void
SDSignatureContext::final(const CssmData &sig)
{
Context tempContext = *mContext;
tempContext.AlgorithmType = mSigAlg;
if(mNullDigest) {
CssmData dData(const_cast<void *>(mNullDigest->digestPtr()),
mNullDigest->digestSizeInBytes());
clientSession().verifySignature(tempContext,
mKeyHandle,
dData,
sig,
mDigestAlg);
}
else {
clientSession().verifySignature(tempContext,
mKeyHandle,
(*mDigest)(),
sig,
mDigestAlg);
}
}
SDCryptContext::SDCryptContext(SDCSPSession &session)
: SDContext(session), mKeyHandle(noKey)
{
}
SDCryptContext::~SDCryptContext()
{
}
void
SDCryptContext::init(const Context &context, bool encoding)
{
ssCryptDebug("===init");
SDContext::init(context, encoding);
mNullDigest.digestInit();
const CssmKey &keyInContext =
context.get<const CssmKey>(CSSM_ATTRIBUTE_KEY,
CSSMERR_CSP_MISSING_ATTR_KEY);
mKeyHandle = mSession.lookupKey(keyInContext).keyHandle();
}
size_t
SDCryptContext::inputSize(size_t outSize)
{
ssCryptDebug("===inputSize outSize=%u", (unsigned)outSize);
return UINT_MAX;
}
size_t
SDCryptContext::outputSize(bool final, size_t inSize)
{
ssCryptDebug("===outputSize final %d inSize=%u", final, (unsigned)inSize);
if(!final) {
return 0;
}
size_t inBufSize = mNullDigest.digestSizeInBytes();
if(inSize == 0) {
clearOutBuf();
if(inBufSize == 0) {
return 0;
}
const CssmData in(const_cast<void *>(mNullDigest.digestPtr()), inBufSize);
if (encoding()) {
clientSession().encrypt(*mContext, mKeyHandle, in, mOutBuf);
}
else {
clientSession().decrypt(*mContext, mKeyHandle, in, mOutBuf);
}
ssCryptDebug(" ===outSize(pre-op) %u", (unsigned)mOutBuf.Length);
return mOutBuf.Length;
}
else {
uint32 outSize = clientSession().getOutputSize(*mContext,
mKeyHandle,
(uint32)(inBufSize + inSize),
encoding());
ssCryptDebug(" ===outSize(RPC) %u", (unsigned)outSize);
return (size_t)outSize;
}
}
void
SDCryptContext::minimumProgress(size_t &in, size_t &out)
{
in = 1;
out = 0;
}
void
SDCryptContext::update(void *inp, size_t &inSize, void *outp, size_t &outSize)
{
ssCryptDebug("===update inSize=%u", (unsigned)inSize);
mNullDigest.digestUpdate(inp, inSize);
outSize = 0;
clearOutBuf();
}
void
SDCryptContext::final(CssmData &out)
{
if(mOutBuf.Data != NULL) {
ssCryptDebug("===final via pre-op and copy");
copyOutBuf(out);
return;
}
ssCryptDebug("===final via RPC");
size_t inSize = mNullDigest.digestSizeInBytes();
if(!inSize) return;
const CssmData in(const_cast<void *>(mNullDigest.digestPtr()), inSize);
IFDEBUG(size_t origOutSize = out.length());
if (encoding()) {
clientSession().encrypt(*mContext, mKeyHandle, in, out);
}
else {
clientSession().decrypt(*mContext, mKeyHandle, in, out);
}
assert(out.length() <= origOutSize);
mNullDigest.digestInit();
}
SDDigestContext::SDDigestContext(SDCSPSession &session)
: SDContext(session), mDigest(NULL)
{
}
SDDigestContext::~SDDigestContext()
{
delete mDigest;
}
void SDDigestContext::init(const Context &context, bool encoding)
{
CSSM_ALGORITHMS alg;
SDContext::init(context, encoding);
alg = context.algorithm();
mDigest = new CssmClient::Digest(mSession.mRawCsp, alg);
}
void SDDigestContext::update(const CssmData &data)
{
mDigest->digest(data);
}
void SDDigestContext::final(CssmData &out)
{
(*mDigest)(out);
}
size_t SDDigestContext::outputSize(bool final, size_t inSize)
{
if(!final) {
return 0;
}
else {
return (size_t)mDigest->getOutputSize((uint32)inSize);
}
}
SDMACContext::SDMACContext(SDCSPSession &session)
: SDContext(session), mKeyHandle(noKey)
{
}
void SDMACContext::init(const Context &context, bool encoding)
{
SDContext::init(context, encoding);
mNullDigest.digestInit();
const CssmKey &keyInContext =
context.get<const CssmKey>(CSSM_ATTRIBUTE_KEY,
CSSMERR_CSP_MISSING_ATTR_KEY);
mKeyHandle = mSession.lookupKey(keyInContext).keyHandle();
}
void SDMACContext::update(const CssmData &data)
{
mNullDigest.digestUpdate(data.data(), data.length());
}
size_t SDMACContext::outputSize(bool final, size_t inSize)
{
if(!final) {
ssCryptDebug("===mac outputSize !final\n");
return 0;
}
if(!encoding()) {
ssCryptDebug("===mac outputSize final, !encoding\n");
return 0;
}
if(inSize == 0) {
clearOutBuf();
genMac(mOutBuf);
ssCryptDebug("===mac outputSize(pre-op) %u", (unsigned)mOutBuf.Length);
return (size_t)mOutBuf.Length;
}
else {
uint32 outSize = clientSession().getOutputSize(*mContext,
mKeyHandle,
(uint32)(inSize + mNullDigest.digestSizeInBytes()),
true);
ssCryptDebug("===mac outputSize(RPC) %u", (unsigned)outSize);
return (size_t)outSize;
}
}
void SDMACContext::genMac(CssmData &mac)
{
CssmData allData(const_cast<void *>(mNullDigest.digestPtr()),
mNullDigest.digestSizeInBytes());
clientSession().generateMac(*mContext, mKeyHandle, allData, mac);
}
void SDMACContext::final(CssmData &mac)
{
genMac(mac);
}
void SDMACContext::final(const CssmData &mac)
{
CssmData allData(const_cast<void *>(mNullDigest.digestPtr()),
mNullDigest.digestSizeInBytes());
clientSession().verifyMac(*mContext, mKeyHandle, allData, mac);
}