#include "DecodedCert.h"
#include "clNssUtils.h"
#include "cldebugging.h"
#include "AppleX509CLSession.h"
#include "CSPAttacher.h"
#include <Security/cssmapple.h>
#include <Security/oidscert.h>
DecodedCert::DecodedCert(
AppleX509CLSession &session)
: DecodedItem(session)
{
memset(&mCert, 0, sizeof(mCert));
}
DecodedCert::DecodedCert(
AppleX509CLSession &session,
const CssmData &encodedCert)
: DecodedItem(session)
{
memset(&mCert, 0, sizeof(mCert));
PRErrorCode prtn = mCoder.decode(encodedCert.data(), encodedCert.length(),
kSecAsn1SignedCertTemplate, &mCert);
if(prtn) {
CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
}
mDecodedExtensions.decodeFromNss(mCert.tbs.extensions);
mState = IS_DecodedAll;
}
DecodedCert::~DecodedCert()
{
}
void DecodedCert::decodeTbs(
const CssmData &encodedTbs)
{
assert(mState == IS_Empty);
memset(&mCert, 0, sizeof(mCert));
PRErrorCode prtn = mCoder.decode(encodedTbs.data(), encodedTbs.length(),
kSecAsn1TBSCertificateTemplate, &mCert.tbs);
if(prtn) {
CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
}
mDecodedExtensions.decodeFromNss(mCert.tbs.extensions);
mState = IS_DecodedTBS;
}
void DecodedCert::encodeExtensions()
{
NSS_TBSCertificate &tbs = mCert.tbs;
assert(mState == IS_Building);
assert(tbs.extensions == NULL);
if(mDecodedExtensions.numExtensions() == 0) {
return;
}
mDecodedExtensions.encodeToNss(tbs.extensions);
}
#define MAX_TEMPLATE_SIZE (8 * 1024)
void DecodedCert::encodeTbs(
CssmOwnedData &encodedTbs)
{
encodeExtensions();
assert(mState == IS_Building);
NSS_TBSCertificate &tbs = mCert.tbs;
if((tbs.signature.algorithm.Data == NULL) ||
(tbs.issuer.rdns == NULL) ||
(tbs.subject.rdns == NULL) ||
(tbs.subjectPublicKeyInfo.subjectPublicKey.Data == NULL)) {
clErrorLog("DecodedCert::encodeTbs: incomplete TBS");
CssmError::throwMe(CSSMERR_CL_NO_FIELD_VALUES);
}
PRErrorCode prtn;
prtn = SecNssEncodeItemOdata(&tbs, kSecAsn1TBSCertificateTemplate,
encodedTbs);
if(prtn) {
CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR);
}
}
CSSM_KEYUSE DecodedCert::inferKeyUsage() const
{
CSSM_KEYUSE keyUse = 0;
const DecodedExten *decodedExten;
uint32 numFields;
decodedExten = DecodedItem::findDecodedExt(CSSMOID_KeyUsage, false,
0, numFields);
if(decodedExten) {
CSSM_DATA *ku = (CSSM_DATA *)decodedExten->nssObj();
assert(ku != NULL);
CE_KeyUsage kuse = clBitStringToKeyUsage(*ku);
if(kuse & CE_KU_DigitalSignature) {
keyUse |= CSSM_KEYUSE_VERIFY;
}
if(kuse & CE_KU_NonRepudiation) {
keyUse |= CSSM_KEYUSE_VERIFY;
}
if(kuse & CE_KU_KeyEncipherment) {
keyUse |= CSSM_KEYUSE_WRAP;
}
if(kuse & CE_KU_KeyAgreement) {
keyUse |= CSSM_KEYUSE_DERIVE;
}
if(kuse & CE_KU_KeyCertSign) {
keyUse |= CSSM_KEYUSE_VERIFY;
}
if(kuse & CE_KU_CRLSign) {
keyUse |= CSSM_KEYUSE_VERIFY;
}
if(kuse & CE_KU_DataEncipherment) {
keyUse |= CSSM_KEYUSE_ENCRYPT;
}
}
decodedExten = DecodedItem::findDecodedExt(CSSMOID_ExtendedKeyUsage,
false, 0, numFields);
if(decodedExten) {
NSS_ExtKeyUsage *euse = (NSS_ExtKeyUsage *)decodedExten->nssObj();
assert(euse != NULL);
unsigned numUses = clNssArraySize((const void **)euse->purposes);
for(unsigned dex=0; dex<numUses; dex++) {
const CSSM_OID *thisUse = euse->purposes[dex];
if(clCompareCssmData(thisUse, &CSSMOID_ExtendedKeyUsageAny)) {
keyUse = CSSM_KEYUSE_ANY;
break;
}
else if(clCompareCssmData(thisUse, &CSSMOID_ServerAuth)) {
keyUse |= (CSSM_KEYUSE_VERIFY | CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DERIVE);
}
else if(clCompareCssmData(thisUse, &CSSMOID_ClientAuth)) {
keyUse |= (CSSM_KEYUSE_VERIFY | CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DERIVE);
}
else if(clCompareCssmData(thisUse, &CSSMOID_ExtendedUseCodeSigning)) {
keyUse |= CSSM_KEYUSE_VERIFY;
}
else if(clCompareCssmData(thisUse, &CSSMOID_EmailProtection)) {
keyUse |=
(CSSM_KEYUSE_VERIFY | CSSM_KEYUSE_WRAP | CSSM_KEYUSE_DERIVE);
}
else if(clCompareCssmData(thisUse, &CSSMOID_TimeStamping)) {
keyUse |= CSSM_KEYUSE_VERIFY;
}
else if(clCompareCssmData(thisUse, &CSSMOID_OCSPSigning)) {
keyUse |= CSSM_KEYUSE_VERIFY;
}
else if(clCompareCssmData(thisUse, &CSSMOID_APPLE_EKU_SYSTEM_IDENTITY)) {
keyUse |=
(CSSM_KEYUSE_VERIFY | CSSM_KEYUSE_WRAP | CSSM_KEYUSE_ENCRYPT);
}
else if(clCompareCssmData(thisUse, &CSSMOID_KERBv5_PKINIT_KP_CLIENT_AUTH)) {
keyUse |= (CSSM_KEYUSE_VERIFY | CSSM_KEYUSE_WRAP);
}
else if(clCompareCssmData(thisUse, &CSSMOID_KERBv5_PKINIT_KP_KDC)) {
keyUse |= CSSM_KEYUSE_VERIFY;
}
}
}
decodedExten = DecodedItem::findDecodedExt(CSSMOID_NetscapeCertType,
false, 0, numFields);
if(decodedExten) {
CSSM_DATA *nctData = (CSSM_DATA *)decodedExten->nssObj();
if((nctData != NULL) && (nctData->Length > 0)) {
CE_NetscapeCertType nct = ((uint16)nctData->Data[0]) << 8;
if(nctData->Length > 1) {
nct |= nctData->Data[1];
}
if(nct & (CE_NCT_SSL_Client | CE_NCT_SSL_Server | CE_NCT_SMIME | CE_NCT_ObjSign |
CE_NCT_SSL_CA | CE_NCT_SMIME_CA | CE_NCT_ObjSignCA)) {
keyUse |= CSSM_KEYUSE_VERIFY;
}
}
}
if(keyUse == 0) {
keyUse = CSSM_KEYUSE_ANY;
}
return keyUse;
}
CSSM_KEY_PTR DecodedCert::extractCSSMKey(
Allocator &alloc) const
{
const CSSM_X509_SUBJECT_PUBLIC_KEY_INFO &keyInfo =
mCert.tbs.subjectPublicKeyInfo;
return CL_extractCSSMKeyNSS(keyInfo, alloc, this);
}