#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(session),
mSession(session)
{
certificateToSign = new CertificateToSign;
reset();
}
DecodedCert::DecodedCert(
AppleX509CLSession &session,
const CssmData &encodedCert)
: alloc(session),
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);
}
return CL_extractCSSMKey(*snaccKeyInfo, alloc, this);
}