#include "rootCerts.h"
#if TP_ROOT_CERT_ENABLE
#include "certGroupUtils.h"
#include "tpdebugging.h"
#include <Security/Trust.h>
#include <Security/TrustStore.h>
#include <Security/debugging.h>
#include <Security/oidscert.h>
ModuleNexus<TPRootStore> TPRootStore::tpGlobalRoots;
TPRootStore::~TPRootStore()
{
}
const tpRootCert *TPRootStore::rootCerts(
CSSM_CL_HANDLE clHand,
unsigned &numRootCerts)
{
StLock<Mutex> _(mLock);
if(mRootCerts) {
numRootCerts = mNumRootCerts;
return mRootCerts;
}
CssmAllocator &alloc(CssmAllocator::standard());
CertGroup roots;
tpRootCert *tpRoots = NULL; unsigned numTpRoots = 0;
try {
Security::KeychainCore::TrustStore &trustStore =
Security::KeychainCore::Trust::gStore();
trustStore.getCssmRootCertificates(roots);
if(roots.type() != CSSM_CERTGROUP_DATA) {
secdebug("tpAnchor", "Bad certGroup Type (%d)\n",
(int)roots.type());
return NULL;
}
numTpRoots = roots.count();
if(numTpRoots == 0) {
secdebug("tpAnchor", "empty certGroup\n");
return NULL;
}
tpRoots =
(tpRootCert *)alloc.malloc(numTpRoots * sizeof(tpRootCert));
memset(tpRoots, 0, numTpRoots * sizeof(tpRootCert));
for(uint32 certNum=0; certNum<numTpRoots; certNum++) {
tpRootCert *tpRoot = &tpRoots[certNum];
const CSSM_DATA *certData = &((roots.blobCerts())[certNum]);
CSSM_DATA *field;
CSSM_HANDLE ResultsHandle;
uint32 numFields;
CSSM_RETURN crtn;
crtn = CSSM_CL_CertGetFirstFieldValue(
clHand,
certData,
&CSSMOID_X509V1SubjectName,
&ResultsHandle,
&numFields,
&field);
if(crtn) {
secdebug("tpAnchor", "GetFirstFieldValue error on cert %u",
(unsigned)certNum);
continue;
}
CSSM_CL_CertAbortQuery(clHand, ResultsHandle);
tpCopyCssmData(alloc, field, &tpRoot->subjectName);
CSSM_CL_FreeFieldValue(clHand, &CSSMOID_X509V1SubjectName,
field);
CSSM_KEY_PTR key;
crtn = CSSM_CL_CertGetKeyInfo(clHand, certData, &key);
if(crtn) {
secdebug("tpAnchor", "CSSM_CL_CertGetKeyInfo error on cert %u",
(unsigned)certNum);
continue;
}
tpCopyCssmData(alloc, &key->KeyData, &tpRoot->publicKey);
tpRoot->keySize = key->KeyHeader.LogicalKeySizeInBits;
CSSM_API_MEMORY_FUNCS memFuncs;
crtn = CSSM_GetAPIMemoryFunctions(clHand, &memFuncs);
if(crtn) {
secdebug("tpAnchor", "CSSM_GetAPIMemoryFunctions error");
continue;
}
memFuncs.free_func(key->KeyData.Data, memFuncs.AllocRef);
memFuncs.free_func(key, memFuncs.AllocRef);
}
}
catch(...) {
return NULL;
}
mNumRootCerts = numTpRoots;
numRootCerts = mNumRootCerts;
mRootCerts = tpRoots;
return mRootCerts;
}
CSSM_BOOL tp_isKnownRootCert(
TPCertInfo *rootCert, CSSM_CL_HANDLE clHand)
{
const CSSM_DATA *subjectName = NULL;
CSSM_DATA_PTR publicKey = NULL;
unsigned dex;
CSSM_BOOL brtn = CSSM_FALSE;
CSSM_DATA_PTR valToFree = NULL;
const tpRootCert *roots;
unsigned numRoots;
roots = TPRootStore::tpGlobalRoots().rootCerts(clHand, numRoots);
subjectName = rootCert->subjectName();
publicKey = tp_CertGetPublicKey(rootCert, &valToFree);
if(publicKey == NULL) {
tpPolicyError("tp_isKnownRootCert: error retrieving public "
"key info!");
goto errOut;
}
for(dex=0; dex<numRoots; dex++) {
if(!tpCompareCssmData(subjectName,
&roots[dex].subjectName)) {
continue;
}
if(!tpCompareCssmData(publicKey,
&roots[dex].publicKey)) {
continue;
}
brtn = CSSM_TRUE;
break;
}
errOut:
tp_CertFreePublicKey(rootCert->clHand(), valToFree);
return brtn;
}
CSSM_BOOL tp_verifyWithKnownRoots(
CSSM_CL_HANDLE clHand,
CSSM_CSP_HANDLE cspHand,
TPCertInfo *certToVfy) {
CSSM_KEY rootKey; CSSM_CC_HANDLE ccHand; CSSM_RETURN crtn;
unsigned dex;
const tpRootCert *rootInfo;
CSSM_BOOL brtn = CSSM_FALSE;
CSSM_KEYHEADER *hdr = &rootKey.KeyHeader;
CSSM_X509_ALGORITHM_IDENTIFIER_PTR algId;
CSSM_DATA_PTR valToFree = NULL;
CSSM_ALGORITHMS sigAlg;
const tpRootCert *rootCerts = NULL;
unsigned numRootCerts = 0;
memset(&rootKey, 0, sizeof(CSSM_KEY));
algId = tp_CertGetAlgId(certToVfy, &valToFree);
if(algId == NULL) {
return CSSM_FALSE;
}
sigAlg = tpOidToAldId(&algId->algorithm, &hdr->AlgorithmId);
if(sigAlg == CSSM_ALGID_NONE) {
tpPolicyError("tp_verifyWithKnownRoots: unknown sig alg");
goto errOut;
}
hdr->BlobType = CSSM_KEYBLOB_RAW;
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_OCTET_STRING;
break;
default:
hdr->Format = CSSM_KEYBLOB_RAW_FORMAT_NONE;
}
hdr->KeyClass = CSSM_KEYCLASS_PUBLIC_KEY;
hdr->KeyAttr = CSSM_KEYATTR_MODIFIABLE | CSSM_KEYATTR_EXTRACTABLE;
hdr->KeyUsage = CSSM_KEYUSE_VERIFY;
rootCerts = TPRootStore::tpGlobalRoots().rootCerts(clHand, numRootCerts);
for(dex=0; dex<numRootCerts; dex++) {
rootInfo = &rootCerts[dex];
if(!tpCompareCssmData(&rootInfo->subjectName, certToVfy->issuerName())) {
continue;
}
rootKey.KeyData = rootInfo->publicKey;
hdr->LogicalKeySizeInBits = rootInfo->keySize;
crtn = CSSM_CSP_CreateSignatureContext(cspHand,
sigAlg,
NULL, &rootKey,
&ccHand);
if(crtn) {
tpPolicyError("tp_verifyWithKnownRoots: "
"CSSM_CSP_CreateSignatureContext err");
CssmError::throwMe(CSSMERR_TP_INTERNAL_ERROR);
}
crtn = CSSM_CL_CertVerify(clHand,
ccHand,
certToVfy->itemData(),
NULL, NULL, 0); CSSM_DeleteContext(ccHand);
if(crtn == CSSM_OK) {
brtn = CSSM_TRUE;
break;
}
}
errOut:
if(valToFree != NULL) {
tp_CertFreeAlgId(clHand, valToFree);
}
return brtn;
}
#endif