#include "DecodedCert.h"
#include "SnaccUtils.h"
#include "cldebugging.h"
#include "AppleX509CLSession.h"
#include "CSPAttacher.h"
#include <Security/cdsaUtils.h>
#include <Security/cssmapple.h>
DecodedCert::DecodedCert(
AppleX509CLSession &session)
: alloc(CssmAllocator::standard()),
mSession(session)
{
certificateToSign = new CertificateToSign;
reset();
}
DecodedCert::DecodedCert(
AppleX509CLSession &session,
const CssmData &encodedCert)
: alloc(CssmAllocator::standard()),
mSession(session)
{
reset();
SC_decodeAsnObj(encodedCert, *this);
decodeExtensions();
mState = CS_DecodedCert;
}
DecodedCert::~DecodedCert()
{
unsigned dex;
for(dex=0; dex<mNumExtensions; dex++) {
DecodedExten *exten = &mExtensions[dex];
delete exten->extnId;
delete exten->snaccObj;
}
alloc.free(mExtensions);
reset();
}
void DecodedCert::decodeTbs(
const CssmData &encodedTbs)
{
CASSERT(mState == CS_Empty);
CASSERT(certificateToSign != NULL);
try {
SC_decodeAsnObj(encodedTbs, *certificateToSign);
}
catch (...) {
errorLog0("decodeTbs: tbs.BDec failure\n");
delete certificateToSign;
certificateToSign = new CertificateToSign;
}
decodeExtensions();
mState = CS_DecodedTBS;
}
#define MAX_TEMPLATE_SIZE (8 * 1024)
void DecodedCert::encodeTbs(
CssmOwnedData &encodedTbs)
{
encodeExtensions();
CASSERT(mState == CS_Building);
if(certificateToSign == NULL) {
errorLog0("DecodedCert::encodeTbs: no TBS\n");
CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR);
}
if((certificateToSign->signature == NULL) ||
(certificateToSign->issuer == NULL) ||
(certificateToSign->validity == NULL) ||
(certificateToSign->subject == NULL) ||
(certificateToSign->subjectPublicKeyInfo == NULL)) {
errorLog0("DecodedCert::encodeTbs: incomplete TBS\n");
CssmError::throwMe(CSSMERR_CL_NO_FIELD_VALUES);
}
SC_encodeAsnObj(*certificateToSign, encodedTbs, MAX_TEMPLATE_SIZE);
}
CSSM_KEYUSE DecodedCert::inferKeyUsage() const
{
CSSM_KEYUSE keyUse = 0;
DecodedExten *decodedExten;
uint32 numFields;
decodedExten = findDecodedExt(id_ce_keyUsage, false, 0, numFields);
if(decodedExten) {
KeyUsage *ku = dynamic_cast<KeyUsage *>(decodedExten->snaccObj);
if(ku == NULL) {
errorLog0("inferKeyUsage: dynamic_cast failure(1)\n");
CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR);
}
if(ku->GetBit(KeyUsage::digitalSignature)) {
keyUse |= CSSM_KEYUSE_VERIFY;
}
if(ku->GetBit(KeyUsage::nonRepudiation)) {
keyUse |= CSSM_KEYUSE_VERIFY;
}
if(ku->GetBit(KeyUsage::keyEncipherment)) {
keyUse |= CSSM_KEYUSE_WRAP;
}
if(ku->GetBit(KeyUsage::keyAgreement)) {
keyUse |= CSSM_KEYUSE_DERIVE;
}
if(ku->GetBit(KeyUsage::keyCertSign)) {
keyUse |= CSSM_KEYUSE_VERIFY;
}
if(ku->GetBit(KeyUsage::cRLSign)) {
keyUse |= CSSM_KEYUSE_VERIFY;
}
if(ku->GetBit(KeyUsage::dataEncipherment)) {
keyUse |= CSSM_KEYUSE_ENCRYPT;
}
}
decodedExten = findDecodedExt(id_ce_extKeyUsage, false, 0, numFields);
if(decodedExten) {
ExtKeyUsageSyntax *eku =
dynamic_cast<ExtKeyUsageSyntax *>(decodedExten->snaccObj);
if(eku == NULL) {
errorLog0("inferKeyUsage: dynamic_cast failure(2)\n");
CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR);
}
unsigned numOids = eku->Count();
eku->SetCurrToFirst();
unsigned oidDex;
for(oidDex=0; oidDex<numOids; oidDex++) {
KeyPurposeId *purp = eku->Curr();
if(*purp == id_kp_codeSigning) {
keyUse |= CSSM_KEYUSE_VERIFY;
}
eku->GoNext();
}
}
if(keyUse == 0) {
keyUse = CSSM_KEYUSE_ANY;
}
return keyUse;
}
CSSM_KEY_PTR DecodedCert::extractCSSMKey(
CssmAllocator &alloc) const
{
CASSERT(certificateToSign != NULL);
SubjectPublicKeyInfo *snaccKeyInfo = certificateToSign->subjectPublicKeyInfo;
if((snaccKeyInfo == NULL) ||
(snaccKeyInfo->algorithm == NULL)) {
CssmError::throwMe(CSSMERR_CL_NO_FIELD_VALUES);
}
CSSM_KEY_PTR cssmKey = (CSSM_KEY_PTR) alloc.malloc(sizeof(CSSM_KEY));
memset(cssmKey, 0, sizeof(CSSM_KEY));
CSSM_KEYHEADER &hdr = cssmKey->KeyHeader;
CssmRemoteData keyData(alloc, cssmKey->KeyData);
try {
hdr.HeaderVersion = CSSM_KEYHEADER_VERSION;
hdr.BlobType = CSSM_KEYBLOB_RAW;
hdr.AlgorithmId = CL_snaccOidToCssmAlg(snaccKeyInfo->algorithm->algorithm);
switch(hdr.AlgorithmId) {
case CSSM_ALGID_RSA:
hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_PKCS1;
break;
case CSSM_ALGID_DSA:
hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_FIPS186;
break;
case CSSM_ALGID_FEE:
hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_NONE;
break;
default:
hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_NONE;
}
hdr.KeyClass = CSSM_KEYCLASS_PUBLIC_KEY;
hdr.KeyUsage = inferKeyUsage();
hdr.WrapAlgorithmId = CSSM_ALGID_NONE;
hdr.WrapMode = CSSM_ALGMODE_NONE;
SC_asnBitsToCssmData(snaccKeyInfo->subjectPublicKey, keyData);
keyData.release();
CSSM_CSP_HANDLE cspHand = getGlobalCspHand(true);
CSSM_KEY_SIZE keySize;
CSSM_RETURN crtn;
crtn = CSSM_QueryKeySizeInBits(cspHand, NULL, cssmKey, &keySize);
if(crtn) {
CssmError::throwMe(crtn);
}
cssmKey->KeyHeader.LogicalKeySizeInBits =
keySize.LogicalKeySizeInBits;
}
catch (...) {
alloc.free(cssmKey);
throw;
}
return cssmKey;
}
void DecodedCert::freeCSSMKey(
CSSM_KEY_PTR cssmKey,
CssmAllocator &alloc,
bool freeTop)
{
if(cssmKey == NULL) {
return;
}
alloc.free(cssmKey->KeyData.Data);
memset(cssmKey, 0, sizeof(CSSM_KEY));
if(freeTop) {
alloc.free(cssmKey);
}
}