#include <Security/cssmtype.h>
#include <Security/cssmapi.h>
#include "tpPolicies.h"
#include <Security/oidsattr.h>
#include <Security/cssmerr.h>
#include "tpdebugging.h"
#include "rootCerts.h"
#include "certGroupUtils.h"
#include <Security/x509defs.h>
#include <Security/oidscert.h>
#include <Security/certextensions.h>
#include <Security/cssmapple.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
typedef struct {
CSSM_BOOL present;
CSSM_BOOL critical;
CE_Data *extnData; CSSM_DATA *valToFree; } iSignExtenInfo;
typedef struct {
iSignExtenInfo authorityId;
iSignExtenInfo subjectId;
iSignExtenInfo keyUsage;
iSignExtenInfo extendKeyUsage;
iSignExtenInfo basicConstraints;
iSignExtenInfo netscapeCertType;
CSSM_BOOL foundUnknownCritical;
} iSignCertInfo;
static CSSM_RETURN tpSetupExtension(
CssmAllocator &alloc,
CSSM_DATA *extnData,
iSignExtenInfo *extnInfo) {
if(extnData->Length != sizeof(CSSM_X509_EXTENSION)) {
errorLog0("tpSetupExtension: malformed CSSM_FIELD\n");
return CSSMERR_TP_UNKNOWN_FORMAT;
}
CSSM_X509_EXTENSION *cssmExt = (CSSM_X509_EXTENSION *)extnData->Data;
extnInfo->present = CSSM_TRUE;
extnInfo->critical = cssmExt->critical;
extnInfo->extnData = (CE_Data *)cssmExt->value.parsedValue;
extnInfo->valToFree = extnData;
return CSSM_OK;
}
static CSSM_RETURN iSignFetchExtension(
CssmAllocator &alloc,
TPCertInfo *tpCert,
const CSSM_OID *fieldOid, iSignExtenInfo *extnInfo) {
CSSM_DATA_PTR fieldValue; CSSM_RETURN crtn;
crtn = tpCert->fetchField(fieldOid, &fieldValue);
switch(crtn) {
case CSSM_OK:
break;
case CSSMERR_CL_NO_FIELD_VALUES:
return CSSM_OK;
default:
return crtn;
}
return tpSetupExtension(alloc,
fieldValue,
extnInfo);
}
static CSSM_RETURN iSignSearchUnknownExtensions(
TPCertInfo *tpCert,
iSignCertInfo *certInfo)
{
CSSM_RETURN crtn;
CSSM_DATA_PTR fieldValue = NULL;
CSSM_HANDLE searchHand = CSSM_INVALID_HANDLE;
uint32 numFields = 0;
crtn = CSSM_CL_CertGetFirstCachedFieldValue(tpCert->clHand(),
tpCert->cacheHand(),
&CSSMOID_X509V3CertificateExtensionCStruct,
&searchHand,
&numFields,
&fieldValue);
switch(crtn) {
case CSSM_OK:
break;
case CSSMERR_CL_NO_FIELD_VALUES:
return CSSM_OK;
default:
return crtn;
}
if(fieldValue->Length != sizeof(CSSM_X509_EXTENSION)) {
errorLog0("iSignSearchUnknownExtensions: malformed CSSM_FIELD\n");
return CSSMERR_TP_UNKNOWN_FORMAT;
}
CSSM_X509_EXTENSION *cssmExt = (CSSM_X509_EXTENSION *)fieldValue->Data;
if(cssmExt->critical) {
certInfo->foundUnknownCritical = CSSM_TRUE;
goto fini;
}
CSSM_CL_FreeFieldValue(tpCert->clHand(),
&CSSMOID_X509V3CertificateExtensionCStruct,
fieldValue);
fieldValue = NULL;
for(unsigned i=1; i<numFields; i++) {
crtn = CSSM_CL_CertGetNextCachedFieldValue(tpCert->clHand(),
searchHand,
&fieldValue);
if(crtn) {
errorLog0("searchUnknownExtensions: GetNextCachedFieldValue error\n");
break;
}
if(fieldValue->Length != sizeof(CSSM_X509_EXTENSION)) {
errorLog0("iSignSearchUnknownExtensions: malformed CSSM_FIELD\n");
crtn = CSSMERR_TP_UNKNOWN_FORMAT;
break;
}
CSSM_X509_EXTENSION *cssmExt = (CSSM_X509_EXTENSION *)fieldValue->Data;
if(cssmExt->critical) {
certInfo->foundUnknownCritical = CSSM_TRUE;
break;
}
CSSM_CL_FreeFieldValue(tpCert->clHand(),
&CSSMOID_X509V3CertificateExtensionCStruct,
fieldValue);
fieldValue = NULL;
}
fini:
if(fieldValue) {
CSSM_CL_FreeFieldValue(tpCert->clHand(),
&CSSMOID_X509V3CertificateExtensionCStruct,
fieldValue);
}
if(searchHand != CSSM_INVALID_HANDLE) {
CSSM_CL_CertAbortQuery(tpCert->clHand(), searchHand);
}
return crtn;
}
static CSSM_RETURN iSignGetCertInfo(
CssmAllocator &alloc,
TPCertInfo *tpCert,
iSignCertInfo *certInfo)
{
CSSM_RETURN crtn;
crtn = iSignFetchExtension(alloc,
tpCert,
&CSSMOID_AuthorityKeyIdentifier,
&certInfo->authorityId);
if(crtn) {
return crtn;
}
crtn = iSignFetchExtension(alloc,
tpCert,
&CSSMOID_SubjectKeyIdentifier,
&certInfo->subjectId);
if(crtn) {
return crtn;
}
crtn = iSignFetchExtension(alloc,
tpCert,
&CSSMOID_KeyUsage,
&certInfo->keyUsage);
if(crtn) {
return crtn;
}
crtn = iSignFetchExtension(alloc,
tpCert,
&CSSMOID_ExtendedKeyUsage,
&certInfo->extendKeyUsage);
if(crtn) {
return crtn;
}
crtn = iSignFetchExtension(alloc,
tpCert,
&CSSMOID_BasicConstraints,
&certInfo->basicConstraints);
if(crtn) {
return crtn;
}
crtn = iSignFetchExtension(alloc,
tpCert,
&CSSMOID_NetscapeCertType,
&certInfo->netscapeCertType);
if(crtn) {
return crtn;
}
return iSignSearchUnknownExtensions(tpCert, certInfo);
}
static void iSignFreeCertInfo(
CSSM_CL_HANDLE clHand,
iSignCertInfo *certInfo)
{
if(certInfo->authorityId.present) {
CSSM_CL_FreeFieldValue(clHand, &CSSMOID_AuthorityKeyIdentifier,
certInfo->authorityId.valToFree);
}
if(certInfo->subjectId.present) {
CSSM_CL_FreeFieldValue(clHand, &CSSMOID_SubjectKeyIdentifier,
certInfo->subjectId.valToFree);
}
if(certInfo->keyUsage.present) {
CSSM_CL_FreeFieldValue(clHand, &CSSMOID_KeyUsage,
certInfo->keyUsage.valToFree);
}
if(certInfo->extendKeyUsage.present) {
CSSM_CL_FreeFieldValue(clHand, &CSSMOID_ExtendedKeyUsage,
certInfo->extendKeyUsage.valToFree);
}
if(certInfo->basicConstraints.present) {
CSSM_CL_FreeFieldValue(clHand, &CSSMOID_BasicConstraints,
certInfo->basicConstraints.valToFree);
}
if(certInfo->netscapeCertType.present) {
CSSM_CL_FreeFieldValue(clHand, &CSSMOID_NetscapeCertType,
certInfo->netscapeCertType.valToFree);
}
}
#if TP_ROOT_CERT_ENABLE
static CSSM_BOOL tp_isKnownRootCert(
TPCertInfo *rootCert, const tpRootCert *knownRoots,
unsigned numKnownRoots)
{
const CSSM_DATA *subjectName = NULL;
CSSM_DATA_PTR publicKey = NULL;
unsigned dex;
CSSM_BOOL brtn = CSSM_FALSE;
CSSM_DATA_PTR valToFree = NULL;
subjectName = rootCert->subjectName();
publicKey = tp_CertGetPublicKey(rootCert, &valToFree);
if(publicKey == NULL) {
errorLog0("tp_isKnownRootCert: error retrieving public key info!\n");
goto errOut;
}
for(dex=0; dex<numKnownRoots; dex++) {
if(!tpCompareCssmData(subjectName,
&knownRoots[dex].subjectName)) {
continue;
}
if(!tpCompareCssmData(publicKey,
&knownRoots[dex].publicKey)) {
continue;
}
#if ENABLE_APPLE_DEBUG_ROOT
if( dex == (knownRoots - 1) ){
brtn = CSSM_FALSE;
break;
}
#endif
brtn = CSSM_TRUE;
break;
}
errOut:
tp_CertFreePublicKey(rootCert->clHand(), valToFree);
return brtn;
}
static CSSM_BOOL tp_isIsignRootCert(
CSSM_CL_HANDLE clHand,
TPCertInfo *rootCert) {
const tpRootCert *roots;
unsigned numRoots;
roots = TPRootStore::tpGlobalRoots().rootCerts(clHand, numRoots);
return tp_isKnownRootCert(rootCert, roots, numRoots);
}
static CSSM_BOOL tp_isSslRootCert(
CSSM_CL_HANDLE clHand,
TPCertInfo *rootCert) {
const tpRootCert *roots;
unsigned numRoots;
roots = TPRootStore::tpGlobalRoots().rootCerts(clHand, numRoots);
return tp_isKnownRootCert(rootCert, roots, numRoots);
}
CSSM_BOOL tp_verifyWithSslRoots(
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) {
errorLog0("tp_verifyWithSslRoots: unknown sig alg\n");
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(!tpIsSameName(&rootInfo->subjectName, certToVfy->issuerName())) {
continue;
}
rootKey.KeyData = rootInfo->publicKey;
hdr->LogicalKeySizeInBits = rootInfo->keySize;
crtn = CSSM_CSP_CreateSignatureContext(cspHand,
sigAlg,
NULL, &rootKey,
&ccHand);
if(crtn) {
errorLog0("tp_verifyWithSslRoots: CSSM_CSP_CreateSignatureContext err\n");
CssmError::throwMe(CSSMERR_TP_INTERNAL_ERROR);
}
crtn = CSSM_CL_CertVerify(clHand,
ccHand,
certToVfy->certData(),
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
static CSSM_BOOL tpCompareCommonName(
TPCertInfo &cert,
const char *hostName,
uint32 hostNameLen)
{
char *commonName = NULL; uint32 commonNameLen = 0;
CSSM_DATA_PTR subjNameData = NULL;
CSSM_RETURN crtn;
CSSM_BOOL ourRtn = CSSM_FALSE;
crtn = cert.fetchField(&CSSMOID_X509V1SubjectNameCStruct, &subjNameData);
if(crtn) {
errorLog0("tp_verifySslOpts: error retrieving subject name");
return CSSM_FALSE;
}
CSSM_X509_NAME_PTR x509name = (CSSM_X509_NAME_PTR)subjNameData->Data;
if((x509name == NULL) || (subjNameData->Length != sizeof(CSSM_X509_NAME))) {
errorLog0("tp_verifySslOpts: malformed CSSM_X509_NAME");
cert.freeField(&CSSMOID_X509V1SubjectNameCStruct, subjNameData);
return CSSM_FALSE;
}
CSSM_X509_TYPE_VALUE_PAIR *ptvp;
CSSM_X509_RDN_PTR rdnp;
unsigned rdnDex;
unsigned pairDex;
for(rdnDex=0; rdnDex<x509name->numberOfRDNs; rdnDex++) {
rdnp = &x509name->RelativeDistinguishedName[rdnDex];
for(pairDex=0; pairDex<rdnp->numberOfPairs; pairDex++) {
ptvp = &rdnp->AttributeTypeAndValue[pairDex];
if(tpCompareOids(&ptvp->type, &CSSMOID_CommonName)) {
commonName = (char *)ptvp->value.Data;
commonNameLen = ptvp->value.Length;
ourRtn = tpCompareHostNames(hostName, hostNameLen,
commonName, commonNameLen);
if(ourRtn) {
break;
}
}
}
if(ourRtn) {
break;
}
}
cert.freeField(&CSSMOID_X509V1SubjectNameCStruct, subjNameData);
return ourRtn;
}
static CSSM_BOOL tpCompIpAddrStr(
const char *str,
unsigned strLen,
const CSSM_DATA *numeric)
{
const char *cp = str;
const char *nextDot;
char buf[100];
if((numeric == NULL) || (numeric->Length == 0) || (str == NULL)) {
return CSSM_FALSE;
}
if(cp[strLen - 1] == '\0') {
strLen--;
}
for(unsigned dex=0; dex<numeric->Length; dex++) {
const char *lastChar = cp + strLen;
nextDot = cp + 1;
for( ; nextDot<lastChar; nextDot++) {
if(*nextDot == '.') {
break;
}
}
if(nextDot == lastChar) {
if(dex != (numeric->Length - 1)) {
return CSSM_FALSE;
}
}
else if(dex == (numeric->Length - 1)) {
return CSSM_FALSE;
}
unsigned digLen = nextDot - cp;
if(digLen >= sizeof(buf)) {
return CSSM_FALSE;
}
memmove(buf, cp, digLen);
buf[digLen] = '\0';
digLen++;
cp += digLen;
strLen -= digLen;
int digVal = atoi(buf);
if(digVal != numeric->Data[dex]) {
return CSSM_FALSE;
}
}
return CSSM_TRUE;
}
static CSSM_BOOL tpCompareSubjectAltName(
TPCertInfo &cert,
const char *hostName,
uint32 hostNameLen,
bool &dnsNameFound) {
CSSM_DATA_PTR subjAltNameData = NULL;
CSSM_RETURN crtn;
CSSM_BOOL ourRtn = CSSM_FALSE;
dnsNameFound = false;
crtn = cert.fetchField(&CSSMOID_SubjectAltName, &subjAltNameData);
if(crtn) {
return CSSM_FALSE;
}
CSSM_X509_EXTENSION_PTR exten =
(CSSM_X509_EXTENSION_PTR)subjAltNameData->Data;
if((exten == NULL) ||
(subjAltNameData->Length != sizeof(CSSM_X509_EXTENSION)) ||
(exten->format != CSSM_X509_DATAFORMAT_PARSED) ||
(exten->value.parsedValue == NULL)) {
errorLog0("tpCompareSubjectAltName: malformed CSSM_X509_EXTENSION");
cert.freeField(&CSSMOID_SubjectAltName, subjAltNameData);
return CSSM_FALSE;
}
CE_GeneralNames *names = (CE_GeneralNames *)exten->value.parsedValue;
char *serverName;
unsigned serverNameLen;
for(unsigned dex=0; dex<names->numNames; dex++) {
CE_GeneralName *name = &names->generalName[dex];
switch(name->nameType) {
case GNT_IPAddress:
ourRtn = tpCompIpAddrStr(hostName, hostNameLen, &name->name);
break;
case GNT_DNSName:
if(name->berEncoded) {
errorLog0("tpCompareSubjectAltName: malformed "
"CE_GeneralName (1)\n");
break;
}
serverName = (char *)name->name.Data;
if(serverName == NULL) {
errorLog0("tpCompareSubjectAltName: malformed "
"CE_GeneralName (2)\n");
break;
}
serverNameLen = name->name.Length;
ourRtn = tpCompareHostNames(hostName, hostNameLen,
serverName, serverNameLen);
dnsNameFound = true;
break;
default:
break;
}
if(ourRtn) {
break;
}
}
cert.freeField(&CSSMOID_SubjectAltName, subjAltNameData);
return ourRtn;
}
static CSSM_BOOL tpIsNumeric(
const char *hostName,
unsigned hostNameLen)
{
if(hostName[hostNameLen - 1] == '\0') {
hostNameLen--;
}
for(unsigned i=0; i<hostNameLen; i++) {
char c = *hostName++;
if(isdigit(c)) {
continue;
}
if(c != '.') {
return CSSM_FALSE;
}
}
return CSSM_TRUE;
}
static CSSM_RETURN tp_verifySslOpts(
TPCertGroup &certGroup,
const CSSM_APPLE_TP_SSL_OPTIONS *sslOpts)
{
if(sslOpts == NULL) {
return CSSM_OK;
}
unsigned hostNameLen = sslOpts->ServerNameLen;
if(hostNameLen == 0) {
return CSSM_OK;
}
if(sslOpts->ServerName == NULL) {
return CSSMERR_TP_INVALID_POINTER;
}
char *hostName = (char *)certGroup.alloc().malloc(hostNameLen);
memmove(hostName, sslOpts->ServerName, hostNameLen);
tpToLower(hostName, hostNameLen);
TPCertInfo *leaf = certGroup.certAtIndex(0);
assert(leaf != NULL);
CSSM_BOOL match = CSSM_FALSE;
bool dnsNameFound = false;
match = tpCompareSubjectAltName(*leaf, hostName, hostNameLen,
dnsNameFound);
if(!match && !dnsNameFound && !tpIsNumeric(hostName, hostNameLen)) {
match = tpCompareCommonName(*leaf, hostName, hostNameLen);
}
certGroup.alloc().free(hostName);
if(match) {
return CSSM_OK;
}
else {
leaf->addStatusCode(CSSMERR_APPLETP_HOSTNAME_MISMATCH);
return CSSMERR_TP_VERIFY_ACTION_FAILED;
}
}
#define BASIC_CONSTRAINTS_MUST_BE_CRITICAL 0
#define EXTENDED_KEY_USAGE_REQUIRED_FOR_LEAF 0
#define SUBJECT_ALT_NAME_REQUIRED_FOR_LEAF 0
#define KEY_USAGE_REQUIRED_FOR_ROOT 0
CSSM_RETURN tp_policyVerify(
TPPolicy policy,
CssmAllocator &alloc,
CSSM_CL_HANDLE clHand,
CSSM_CSP_HANDLE cspHand,
TPCertGroup *certGroup,
CSSM_BOOL verifiedToRoot, const CSSM_APPLE_TP_ACTION_DATA *actionData,
const CSSM_APPLE_TP_SSL_OPTIONS *sslOpts,
void *policyOpts) {
iSignCertInfo *certInfo = NULL;
uint32 numCerts;
iSignCertInfo *thisCertInfo;
uint16 expUsage;
uint16 actUsage;
unsigned certDex;
CSSM_BOOL cA = CSSM_FALSE; CSSM_BOOL isLeaf; CSSM_BOOL isRoot; CE_ExtendedKeyUsage *extendUsage;
CE_AuthorityKeyID *authorityId;
CSSM_RETURN outErr = CSSM_OK; CSSM_BOOL policyFail = CSSM_FALSE;
if(policy == kTPDefault) {
return CSSM_OK;
}
if(certGroup == NULL) {
return CSSMERR_TP_INVALID_CERTGROUP;
}
numCerts = certGroup->numCerts();
if(numCerts == 0) {
return CSSMERR_TP_INVALID_CERTGROUP;
}
if(policy == kTPiSign) {
if(!verifiedToRoot) {
return CSSMERR_TP_INVALID_CERTGROUP;
}
if(numCerts <= 1) {
return CSSMERR_TP_INVALID_CERTGROUP;
}
}
certInfo = (iSignCertInfo *)tpCalloc(alloc, numCerts, sizeof(iSignCertInfo));
for(certDex=0; certDex<numCerts; certDex++) {
if(iSignGetCertInfo(alloc,
certGroup->certAtIndex(certDex),
&certInfo[certDex])) {
(certGroup->certAtIndex(certDex))->addStatusCode(
CSSMERR_TP_INVALID_CERTIFICATE);
outErr = CSSMERR_TP_INVALID_CERTIFICATE;
goto errOut;
}
}
for(certDex=0; certDex<numCerts; certDex++) {
thisCertInfo = &certInfo[certDex];
TPCertInfo *thisTpCertInfo = certGroup->certAtIndex(certDex);
if(thisCertInfo->foundUnknownCritical) {
errorLog0("tp_policyVerify: critical flag in unknown extension\n");
thisTpCertInfo->addStatusCode(CSSMERR_APPLETP_UNKNOWN_CRITICAL_EXTEN);
policyFail = CSSM_TRUE;
}
isLeaf = (certDex == 0) ? CSSM_TRUE : CSSM_FALSE;
isRoot = (certDex == (numCerts - 1)) ? CSSM_TRUE : CSSM_FALSE;
if(!thisCertInfo->basicConstraints.present) {
if(isLeaf) {
cA = CSSM_FALSE;
}
else if(isRoot) {
cA = CSSM_TRUE;
}
else {
switch(policy) {
case kTPx509Basic:
case kTP_SSL:
cA = CSSM_FALSE;
break;
case kTPiSign:
errorLog0("tp_policyVerify: no basicConstraints\n");
policyFail = CSSM_TRUE;
thisTpCertInfo->addStatusCode(
CSSMERR_APPLETP_NO_BASIC_CONSTRAINTS);
break;
default:
break;
}
}
}
else {
#if BASIC_CONSTRAINTS_MUST_BE_CRITICAL
if(!thisCertInfo->basicConstraints.critical) {
errorLog0("tp_policyVerify: basicConstraints marked not critical\n");
policyFail = CSSM_TRUE;
thisTpCertInfo->addStatusCode(CSSMERR_TP_VERIFY_ACTION_FAILED);
}
#endif
const CE_BasicConstraints *bcp =
&thisCertInfo->basicConstraints.extnData->basicConstraints;
cA = bcp->cA;
if(!isLeaf && cA && bcp->pathLenConstraintPresent) {
if(certDex > (bcp->pathLenConstraint + 1)) {
errorLog0("tp_policyVerify: pathLenConstraint exceeded\n");
policyFail = CSSM_TRUE;
thisTpCertInfo->addStatusCode(
CSSMERR_APPLETP_PATH_LEN_CONSTRAINT);
}
}
}
if(isLeaf) {
if(cA && !isRoot) {
errorLog0("tp_policyVerify: cA true for leaf\n");
policyFail = CSSM_TRUE;
thisTpCertInfo->addStatusCode(CSSMERR_APPLETP_INVALID_CA);
}
} else if(!cA) {
errorLog0("tp_policyVerify: cA false for non-leaf\n");
policyFail = CSSM_TRUE;
thisTpCertInfo->addStatusCode(CSSMERR_APPLETP_INVALID_CA);
}
if((policy == kTPiSign) && thisCertInfo->authorityId.present) {
if(isRoot) {
errorLog0("tp_policyVerify: authorityId in root\n");
policyFail = CSSM_TRUE;
thisTpCertInfo->addStatusCode(CSSMERR_APPLETP_INVALID_AUTHORITY_ID);
}
if(thisCertInfo->authorityId.critical) {
errorLog0("tp_policyVerify: authorityId marked critical\n");
policyFail = CSSM_TRUE;
thisTpCertInfo->addStatusCode(CSSMERR_APPLETP_INVALID_AUTHORITY_ID);
}
}
if(thisCertInfo->subjectId.present) {
if((policy == kTPiSign) && thisCertInfo->subjectId.critical) {
errorLog0("tp_policyVerify: subjectId marked critical\n");
policyFail = CSSM_TRUE;
thisTpCertInfo->addStatusCode(CSSMERR_APPLETP_INVALID_SUBJECT_ID);
}
}
if(thisCertInfo->keyUsage.present) {
if(isLeaf) {
if(policy == kTPiSign) {
expUsage = CE_KU_DigitalSignature;
}
else {
expUsage = thisCertInfo->keyUsage.extnData->keyUsage;
}
}
else {
expUsage = CE_KU_KeyCertSign;
}
actUsage = thisCertInfo->keyUsage.extnData->keyUsage;
if(!(actUsage & expUsage)) {
errorLog2("tp_policyVerify: bad keyUsage (leaf %s; usage 0x%x)\n",
(certDex == 0) ? "TRUE" : "FALSE", actUsage);
policyFail = CSSM_TRUE;
thisTpCertInfo->addStatusCode(CSSMERR_APPLETP_INVALID_KEY_USAGE);
}
}
else if(policy == kTPiSign) {
if(isLeaf && thisCertInfo->netscapeCertType.present) {
CE_NetscapeCertType ct =
thisCertInfo->netscapeCertType.extnData->netscapeCertType;
if(!(ct & CE_NCT_ObjSign)) {
errorLog0("tp_policyVerify: netscape-cert-type, !ObjectSign\n");
policyFail = CSSM_TRUE;
thisTpCertInfo->addStatusCode(CSSMERR_APPLETP_INVALID_KEY_USAGE);
}
}
else if(!isRoot) {
errorLog0("tp_policyVerify: !isRoot, no keyUsage, !(leaf and netscapeCertType)\n");
policyFail = CSSM_TRUE;
thisTpCertInfo->addStatusCode(CSSMERR_APPLETP_INVALID_KEY_USAGE);
}
}
}
if((policy == kTPiSign) && certInfo[0].extendKeyUsage.present) {
extendUsage = &certInfo[0].extendKeyUsage.extnData->extendedKeyUsage;
if(extendUsage->numPurposes != 1) {
errorLog1("tp_policyVerify: bad extendUsage->numPurposes (%d)\n",
(int)extendUsage->numPurposes);
policyFail = CSSM_TRUE;
(certGroup->certAtIndex(0))->addStatusCode(
CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE);
}
if(!tpCompareOids(extendUsage->purposes,
&CSSMOID_ExtendedUseCodeSigning)) {
errorLog0("tp_policyVerify: bad extendKeyUsage\n");
policyFail = CSSM_TRUE;
(certGroup->certAtIndex(0))->addStatusCode(
CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE);
}
}
for(certDex=0; certDex<(numCerts-1); certDex++) {
if(!certInfo[certDex].authorityId.present ||
!certInfo[certDex+1].subjectId.present) {
continue;
}
authorityId = &certInfo[certDex].authorityId.extnData->authorityKeyID;
if(!authorityId->keyIdentifierPresent) {
continue;
}
if(!tpCompareCssmData(&authorityId->keyIdentifier,
&certInfo[certDex+1].subjectId.extnData->subjectKeyID)) {
errorLog0("tp_policyVerify: bad key ID linkage\n");
policyFail = CSSM_TRUE;
(certGroup->certAtIndex(certDex))->addStatusCode(
CSSMERR_APPLETP_INVALID_ID_LINKAGE);
}
}
if(policy == kTP_SSL) {
CSSM_RETURN cerr = tp_verifySslOpts(*certGroup, sslOpts);
if(cerr) {
policyFail = CSSM_TRUE;
}
}
#if TP_ROOT_CERT_ENABLE
if((outErr == CSSM_OK) && (actionData != NULL) &&
(actionData->ActionFlags & 0x80000000)) { TPCertInfo *lastCert = certGroup->lastCert();
if(policy == kTPiSign) {
bool brtn = tp_isIsignRootCert(clHand, lastCert);
if(!brtn) {
policyFail = CSSM_TRUE;
}
}
else if(verifiedToRoot && (policy == kTP_SSL)) {
bool brtn = tp_isSslRootCert(clHand, lastCert);
if(!brtn) {
outErr = CSSMERR_TP_INVALID_ANCHOR_CERT;
}
}
}
#endif
if(policyFail && (outErr == CSSM_OK)) {
outErr = CSSMERR_TP_VERIFY_ACTION_FAILED;
}
errOut:
for(certDex=0; certDex<numCerts; certDex++) {
thisCertInfo = &certInfo[certDex];
iSignFreeCertInfo(clHand, thisCertInfo);
}
tpFree(alloc, certInfo);
return outErr;
}