#include "SSContext.h"
#include "SSCSPSession.h"
#include "SSKey.h"
#include <Security/debugging.h>
#define ssCryptDebug(args...) secdebug("ssCrypt", ## args)
using namespace SecurityServer;
SSContext::SSContext(SSCSPSession &session)
: mSession(session), mContext(NULL)
{
}
void SSContext::clearOutBuf()
{
if(mOutBuf.Data) {
mSession.free(mOutBuf.Data);
mOutBuf.clear();
}
}
void SSContext::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
SSContext::init(const Context &context,
bool ) {
mContext = &context;
clearOutBuf();
}
SecurityServer::ClientSession &
SSContext::clientSession()
{
return mSession.clientSession();
}
SSRandomContext::SSRandomContext(SSCSPSession &session) : SSContext(session) {}
void
SSRandomContext::init(const Context &context, bool encoding)
{
SSContext::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
SSRandomContext::outputSize(bool final, size_t inSize)
{
return mOutSize;
}
void
SSRandomContext::final(CssmData &out)
{
clientSession().generateRandom(out);
}
SSSignatureContext::SSSignatureContext(SSCSPSession &session)
: SSContext(session),
mKeyHandle(noKey),
mNullDigest(NULL),
mDigest(NULL)
{
}
SSSignatureContext::~SSSignatureContext()
{
delete mNullDigest;
delete mDigest;
}
void SSSignatureContext::init(const Context &context, bool signing)
{
SSContext::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_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 SSSignatureContext::setDigestAlgorithm(CSSM_ALGORITHMS digestAlg)
{
mDigestAlg = digestAlg;
}
void SSSignatureContext::update(const CssmData &data)
{
assert(mOutBuf.Data == NULL);
if(mNullDigest) {
mNullDigest->digestUpdate(data.data(), data.length());
}
else {
mDigest->digest(data);
}
}
size_t SSSignatureContext::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,
inSize,
true);
ssCryptDebug("===sig outputSize(RPC) %u", (unsigned)outSize);
return (size_t)outSize;
}
}
void SSSignatureContext::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 SSSignatureContext::final(CssmData &sig)
{
if(mOutBuf.Data) {
ssCryptDebug("===final via pre-op and copy");
copyOutBuf(sig);
return;
}
ssCryptDebug("===final via RPC");
sign(sig);
}
void
SSSignatureContext::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);
}
}
SSCryptContext::SSCryptContext(SSCSPSession &session)
: SSContext(session), mKeyHandle(noKey)
{
}
SSCryptContext::~SSCryptContext()
{
}
void
SSCryptContext::init(const Context &context, bool encoding)
{
ssCryptDebug("===init");
SSContext::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
SSCryptContext::inputSize(size_t outSize)
{
ssCryptDebug("===inputSize outSize=%u", (unsigned)outSize);
return UINT_MAX;
}
size_t
SSCryptContext::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,
inBufSize + inSize,
encoding());
ssCryptDebug(" ===outSize(RPC) %u", (unsigned)outSize);
return (size_t)outSize;
}
}
void
SSCryptContext::minimumProgress(size_t &in, size_t &out)
{
in = 1;
out = 0;
}
void
SSCryptContext::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
SSCryptContext::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(unsigned origOutSize = out.length());
if (encoding()) {
clientSession().encrypt(*mContext, mKeyHandle, in, out);
}
else {
clientSession().decrypt(*mContext, mKeyHandle, in, out);
}
assert(out.length() <= origOutSize);
mNullDigest.digestInit();
}
SSDigestContext::SSDigestContext(SSCSPSession &session)
: SSContext(session), mDigest(NULL)
{
}
SSDigestContext::~SSDigestContext()
{
delete mDigest;
}
void SSDigestContext::init(const Context &context, bool encoding)
{
CSSM_ALGORITHMS alg;
SSContext::init(context, encoding);
alg = context.algorithm();
mDigest = new CssmClient::Digest(mSession.mRawCsp, alg);
}
void SSDigestContext::update(const CssmData &data)
{
mDigest->digest(data);
}
void SSDigestContext::final(CssmData &out)
{
(*mDigest)(out);
}
size_t SSDigestContext::outputSize(bool final, size_t inSize)
{
if(!final) {
return 0;
}
else {
return (size_t)mDigest->getOutputSize(inSize);
}
}
SSMACContext::SSMACContext(SSCSPSession &session)
: SSContext(session), mKeyHandle(noKey)
{
}
void SSMACContext::init(const Context &context, bool encoding)
{
SSContext::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 SSMACContext::update(const CssmData &data)
{
mNullDigest.digestUpdate(data.data(), data.length());
}
size_t SSMACContext::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,
inSize + mNullDigest.digestSizeInBytes(),
true);
ssCryptDebug("===mac outputSize(RPC) %u", (unsigned)outSize);
return (size_t)outSize;
}
}
void SSMACContext::genMac(CssmData &mac)
{
CssmData allData(const_cast<void *>(mNullDigest.digestPtr()),
mNullDigest.digestSizeInBytes());
clientSession().generateMac(*mContext, mKeyHandle, allData, mac);
}
void SSMACContext::final(CssmData &mac)
{
genMac(mac);
}
void SSMACContext::final(const CssmData &mac)
{
CssmData allData(const_cast<void *>(mNullDigest.digestPtr()),
mNullDigest.digestSizeInBytes());
clientSession().verifyMac(*mContext, mKeyHandle, allData, mac);
}