]> git.saurik.com Git - apple/security.git/blobdiff - AppleX509TP/tpPolicies.cpp
Security-222.tar.gz
[apple/security.git] / AppleX509TP / tpPolicies.cpp
diff --git a/AppleX509TP/tpPolicies.cpp b/AppleX509TP/tpPolicies.cpp
deleted file mode 100644 (file)
index a2c8a6f..0000000
+++ /dev/null
@@ -1,1344 +0,0 @@
-/*
- * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
- * 
- * The contents of this file constitute Original Code as defined in and are
- * subject to the Apple Public Source License Version 1.2 (the 'License').
- * You may not use this file except in compliance with the License. Please obtain
- * a copy of the License at http://www.apple.com/publicsource and read it before
- * using this file.
- * 
- * This Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
- * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
- * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
- * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
- * specific language governing rights and limitations under the License.
- */
-
-
-/*
-       policies.cpp - TP module policy implementation
-
-       Created 10/9/2000 by Doug Mitchell. 
-*/
-
-#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>
-
-
-/* 
- * Our private per-extension info. One of these per (understood) extension per
- * cert. 
- */
-typedef struct {
-       CSSM_BOOL               present;
-       CSSM_BOOL               critical;
-       CE_Data         *extnData;              // mallocd by CL
-       CSSM_DATA               *valToFree;             // the data we pass to freeField()
-} iSignExtenInfo;
-
-/*
- * Struct to keep track of info pertinent to one cert.
- */
-typedef struct {
-
-       /* extensions we're interested in */
-       iSignExtenInfo          authorityId;
-       iSignExtenInfo          subjectId;
-       iSignExtenInfo          keyUsage;
-       iSignExtenInfo          extendKeyUsage;
-       iSignExtenInfo          basicConstraints;
-       iSignExtenInfo          netscapeCertType;
-       iSignExtenInfo          subjectAltName;
-                               
-       /* flag indicating presence of a critical extension we don't understand */
-       CSSM_BOOL                       foundUnknownCritical;
-       
-} iSignCertInfo;
-
-/*
- * Setup a single iSignExtenInfo. Called once per known extension
- * per cert. 
- */
-static CSSM_RETURN tpSetupExtension(
-       CssmAllocator           &alloc, 
-       CSSM_DATA                       *extnData,
-       iSignExtenInfo          *extnInfo)              // which component of certInfo
-{
-       if(extnData->Length != sizeof(CSSM_X509_EXTENSION)) {
-               tpPolicyError("tpSetupExtension: malformed CSSM_FIELD");
-               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;
-}
-
-/*
- * Fetch a known extension, set up associated iSignExtenInfo if present.
- */
-static CSSM_RETURN iSignFetchExtension(
-       CssmAllocator           &alloc, 
-       TPCertInfo                      *tpCert,
-       const CSSM_OID          *fieldOid,              // which extension to fetch
-       iSignExtenInfo          *extnInfo)              // where the info goes
-{
-       CSSM_DATA_PTR   fieldValue;                     // mallocd by CL
-       CSSM_RETURN             crtn;
-       
-       crtn = tpCert->fetchField(fieldOid, &fieldValue);
-       switch(crtn) {
-               case CSSM_OK:
-                       break;
-               case CSSMERR_CL_NO_FIELD_VALUES:
-                       /* field not present, OK */
-                       return CSSM_OK;
-               default:
-                       return crtn;
-       }
-       return tpSetupExtension(alloc,
-                       fieldValue,
-                       extnInfo);
-}
-
-/*
- * Search for al unknown extensions. If we find one which is flagged critical, 
- * flag certInfo->foundUnknownCritical. Only returns error on gross errors.  
- */
-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:
-                       /* found one, proceed */
-                       break;
-               case CSSMERR_CL_NO_FIELD_VALUES:
-                       /* no unknown extensions present, OK */
-                       return CSSM_OK;
-               default:
-                       return crtn;
-       }
-       
-       if(fieldValue->Length != sizeof(CSSM_X509_EXTENSION)) {
-               tpPolicyError("iSignSearchUnknownExtensions: malformed CSSM_FIELD");
-               return CSSMERR_TP_UNKNOWN_FORMAT;
-       }
-       CSSM_X509_EXTENSION *cssmExt = (CSSM_X509_EXTENSION *)fieldValue->Data;
-       if(cssmExt->critical) {
-               /* BRRZAPP! Found an unknown extension marked critical */
-               certInfo->foundUnknownCritical = CSSM_TRUE;
-               goto fini;
-       }
-       CSSM_CL_FreeFieldValue(tpCert->clHand(), 
-               &CSSMOID_X509V3CertificateExtensionCStruct, 
-               fieldValue);
-       fieldValue = NULL;
-       
-       /* process remaining unknown extensions */
-       for(unsigned i=1; i<numFields; i++) {
-               crtn = CSSM_CL_CertGetNextCachedFieldValue(tpCert->clHand(),
-                       searchHand,
-                       &fieldValue);
-               if(crtn) {
-                       /* should never happen */
-                       tpPolicyError("searchUnknownExtensions: GetNextCachedFieldValue"
-                               "error");
-                       break;
-               }
-               if(fieldValue->Length != sizeof(CSSM_X509_EXTENSION)) {
-                       tpPolicyError("iSignSearchUnknownExtensions: "
-                               "malformed CSSM_FIELD");
-                       crtn = CSSMERR_TP_UNKNOWN_FORMAT;
-                       break;
-               }
-               CSSM_X509_EXTENSION *cssmExt = (CSSM_X509_EXTENSION *)fieldValue->Data;
-               if(cssmExt->critical) {
-                       /* BRRZAPP! Found an unknown extension marked critical */
-                       certInfo->foundUnknownCritical = CSSM_TRUE;
-                       break;
-               }
-               CSSM_CL_FreeFieldValue(tpCert->clHand(), 
-                       &CSSMOID_X509V3CertificateExtensionCStruct, 
-                       fieldValue);
-               fieldValue = NULL;
-       } /* for additional fields */
-                               
-fini:
-       if(fieldValue) {
-               CSSM_CL_FreeFieldValue(tpCert->clHand(), 
-                       &CSSMOID_X509V3CertificateExtensionCStruct, 
-                       fieldValue);
-       }
-       if(searchHand != CSSM_INVALID_HANDLE) {
-               CSSM_CL_CertAbortQuery(tpCert->clHand(), searchHand);
-       }
-       return crtn;
-}
-/*
- * Given a TPCertInfo, fetch the associated iSignCertInfo fields. 
- * Returns CSSM_FAIL on error. 
- */
-static CSSM_RETURN iSignGetCertInfo(
-       CssmAllocator           &alloc, 
-       TPCertInfo                      *tpCert,
-       iSignCertInfo           *certInfo)
-{
-       CSSM_RETURN                     crtn;
-       
-       /* first grind thru the extensions we're interested in */
-       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;
-       }
-       crtn = iSignFetchExtension(alloc,
-               tpCert,
-               &CSSMOID_SubjectAltName,
-               &certInfo->subjectAltName);
-       if(crtn) {
-               return crtn;
-       }
-
-       /* now look for extensions we don't understand - the only thing we're interested
-        * in is the critical flag. */
-       return iSignSearchUnknownExtensions(tpCert, certInfo);
-}
-
-/*
- * Free (via CL) the fields allocated in iSignGetCertInfo().
- */
-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(certInfo->subjectAltName.present) {
-               CSSM_CL_FreeFieldValue(clHand, &CSSMOID_SubjectAltName, 
-                       certInfo->subjectAltName.valToFree);
-       }
-}
-
-/* 
- * See if cert's Subject.{commonName,EmailAddress} matches caller-specified 
- * string. Returns CSSM_TRUE if match, else returns CSSM_FALSE. 
- * Also indicates whether *any* of the specified fields were found, regardless
- * of match state.
- */
-typedef enum {
-       SN_CommonName,                  // CSSMOID_CommonName, host name format
-       SN_Email                                // CSSMOID_EmailAddress
-} SubjSubjNameSearchType;
-
-static CSSM_BOOL tpCompareSubjectName(
-       TPCertInfo                              &cert,
-       SubjSubjNameSearchType  searchType,
-       const char                              *callerStr,                     // already tpToLower'd
-       uint32                                  callerStrLen,
-       bool                                    &fieldFound)
-{
-       char                    *certName = NULL;                       // from cert's subject name
-       uint32                  certNameLen = 0;
-       CSSM_DATA_PTR   subjNameData = NULL;
-       CSSM_RETURN     crtn;
-       CSSM_BOOL               ourRtn = CSSM_FALSE;
-       const CSSM_OID  *oidSrch;
-       
-       fieldFound = false;
-       switch(searchType) {
-               case SN_CommonName:
-                       oidSrch = &CSSMOID_CommonName;
-                       break;
-               case SN_Email:
-                       oidSrch = &CSSMOID_EmailAddress;
-                       break;
-               default:
-                       assert(0);
-                       return CSSM_FALSE;
-       }
-       crtn = cert.fetchField(&CSSMOID_X509V1SubjectNameCStruct, &subjNameData);
-       if(crtn) {
-               /* should never happen, we shouldn't be here if there is no subject */
-               tpPolicyError("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))) {
-               tpPolicyError("tp_verifySslOpts: malformed CSSM_X509_NAME");
-               cert.freeField(&CSSMOID_X509V1SubjectNameCStruct, subjNameData);
-               return CSSM_FALSE;
-       }
-
-       /* Now grunge thru the X509 name looking for a common name */
-       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, oidSrch)) {
-                               fieldFound = true;
-                               certName = (char *)ptvp->value.Data;
-                               certNameLen = ptvp->value.Length;
-                               switch(searchType) {
-                                       case SN_CommonName:
-                                               ourRtn = tpCompareHostNames(callerStr, callerStrLen, 
-                                                       certName, certNameLen);
-                                               break;
-                                       case SN_Email:
-                                               ourRtn = tpCompareEmailAddr(callerStr, callerStrLen,
-                                                       certName, certNameLen);
-                                               break;
-                               }
-                               if(ourRtn) {
-                                       /* success */
-                                       break;
-                               }
-                               /* else keep going, maybe there's another common name */
-                       }
-               }
-               if(ourRtn) {
-                       break;
-               }
-       }
-       cert.freeField(&CSSMOID_X509V1SubjectNameCStruct, subjNameData);
-       return ourRtn;
-}
-
-/*
- * Compare ASCII form of an IP address to a CSSM_DATA containing 
- * the IP address's numeric components. Returns true on match.
- */
-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') {
-               /* ignore NULL terminator */
-               strLen--;
-       }
-       for(unsigned dex=0; dex<numeric->Length; dex++) {
-               /* cp points to start of current string digit */
-               /* find next dot */
-               const char *lastChar = cp + strLen;
-               nextDot = cp + 1;
-               for( ; nextDot<lastChar; nextDot++) {
-                       if(*nextDot == '.') {
-                               break;
-                       }
-               }
-               if(nextDot == lastChar) {
-                       /* legal and required on last digit */
-                       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)) {
-                       /* preposterous */
-                       return CSSM_FALSE;
-               }
-               memmove(buf, cp, digLen);
-               buf[digLen] = '\0';
-               /* incr digLen to include the next dot */
-               digLen++;
-               cp += digLen;
-               strLen -= digLen;
-               int digVal = atoi(buf);
-               if(digVal != numeric->Data[dex]) {
-                       return CSSM_FALSE;
-               }
-       }
-       return CSSM_TRUE;
-}
-
-/* 
- * See if cert's subjectAltName contains an element matching caller-specified 
- * string, hostname, in the following forms:
- *
- * SAN_HostName : dnsName, iPAddress
- * SAN_Email    : RFC822Name
- *
- * Returns CSSM_TRUE if match, else returns CSSM_FALSE. 
- *
- * Also indicates whether or not a dnsName (search type HostName) or
- * RFC822Name (search type SAM_Email) was found, regardless of result
- * of comparison. 
- *
- * The appStr/appStrLen args are optional - if NULL/0, only the 
- * search for dnsName/RFC822Name is done.
- */
-typedef enum {
-       SAN_HostName,
-       SAN_Email
-} SubjAltNameSearchType;
-
-static CSSM_BOOL tpCompareSubjectAltName(
-       const iSignExtenInfo    &subjAltNameInfo,
-       const char                              *appStr,                        
-       uint32                                  appStrLen,
-       SubjAltNameSearchType   searchType,
-       bool                                    &dnsNameFound,          // RETURNED, SAN_HostName case
-       bool                                    &emailFound)            // RETURNED, SAN_Email case
-{
-       dnsNameFound = false;
-       emailFound = false;
-       if(!subjAltNameInfo.present) {
-               /* common failure, no subjectAltName found */
-               return CSSM_FALSE;
-       }
-
-       CE_GeneralNames *names = &subjAltNameInfo.extnData->subjectAltName;
-       CSSM_BOOL               ourRtn = CSSM_FALSE;    
-       char                    *certName;
-       unsigned                certNameLen;
-       
-       /* Search thru the CE_GeneralNames looking for the appropriate attribute */
-       for(unsigned dex=0; dex<names->numNames; dex++) {
-               CE_GeneralName *name = &names->generalName[dex];
-               switch(searchType) {
-                       case SAN_HostName:
-                               switch(name->nameType) {
-                                       case GNT_IPAddress:
-                                               if(appStr == NULL) {
-                                                       /* nothing to do here */
-                                                       break;
-                                               }
-                                               ourRtn = tpCompIpAddrStr(appStr, appStrLen, &name->name);
-                                               break;
-                                               
-                                       case GNT_DNSName:
-                                               if(name->berEncoded) {
-                                                       tpErrorLog("tpCompareSubjectAltName: malformed "
-                                                               "CE_GeneralName (1)\n");
-                                                       break;
-                                               }
-                                               certName = (char *)name->name.Data;
-                                               if(certName == NULL) {
-                                                       tpErrorLog("tpCompareSubjectAltName: malformed "
-                                                               "CE_GeneralName (2)\n");
-                                                       break;
-                                               }
-                                               certNameLen = name->name.Length;
-                                               dnsNameFound = true;
-                                               if(appStr != NULL) {
-                                                       /* skip if caller passed in NULL */
-                                                       ourRtn = tpCompareHostNames(appStr, appStrLen, 
-                                                               certName, certNameLen);
-                                               }
-                                               break;
-               
-                                       default:
-                                               /* not interested, proceed to next name */
-                                               break;
-                               }
-                               break;  /* from case HostName */
-                               
-                       case SAN_Email:
-                               if(name->nameType != GNT_RFC822Name) {
-                                       /* not interested */
-                                       break;
-                               }
-                               certName = (char *)name->name.Data;
-                               if(certName == NULL) {
-                                       tpErrorLog("tpCompareSubjectAltName: malformed "
-                                               "GNT_RFC822Name\n");
-                                       break;
-                               }
-                               certNameLen = name->name.Length;
-                               emailFound = true;
-                               if(appStr != NULL) {
-                                       ourRtn = tpCompareEmailAddr(appStr, appStrLen, certName, 
-                                               certNameLen);
-                               }
-                               break;
-               }
-               if(ourRtn) {
-                       /* success */
-                       break;
-               }
-       }
-       return ourRtn;
-}
-
-/* is host name in the form of a.b.c.d, where a,b,c, and d are digits? */
-static CSSM_BOOL tpIsNumeric(
-       const char *hostName, 
-       unsigned hostNameLen)
-{
-       if(hostName[hostNameLen - 1] == '\0') {
-               /* ignore NULL terminator */
-               hostNameLen--;
-       }
-       for(unsigned i=0; i<hostNameLen; i++) {
-               char c = *hostName++;
-               if(isdigit(c)) {
-                       continue;
-               }
-               if(c != '.') {
-                       return CSSM_FALSE;
-               }
-       }
-       return CSSM_TRUE;
-}
-
-/*
- * Verify SSL options. Currently this just consists of matching the 
- * leaf cert's subject common name against the caller's (optional)
- * server name.
- */
-static CSSM_RETURN tp_verifySslOpts(
-       TPCertGroup &certGroup,
-       const CSSM_DATA *sslFieldOpts,
-       const iSignCertInfo &leafCertInfo)
-{
-       /* first validate optional SSL options */
-       if((sslFieldOpts == NULL) || (sslFieldOpts->Data == NULL)) {
-               /* optional */
-               return CSSM_OK;
-       }
-       CSSM_APPLE_TP_SSL_OPTIONS *sslOpts;
-       sslOpts = (CSSM_APPLE_TP_SSL_OPTIONS *)sslFieldOpts->Data;
-       switch(sslOpts->Version) {
-               case CSSM_APPLE_TP_SSL_OPTS_VERSION:
-                       if(sslFieldOpts->Length != sizeof(CSSM_APPLE_TP_SSL_OPTIONS)) {
-                               return CSSMERR_TP_INVALID_POLICY_IDENTIFIERS;
-                       }
-                       break;
-               /* handle backwards compatibility here if necessary */
-               default:
-                       return CSSMERR_TP_INVALID_POLICY_IDENTIFIERS;
-       }
-
-       unsigned hostNameLen = sslOpts->ServerNameLen;
-       
-       if(hostNameLen == 0) {
-               /* optional */
-               return CSSM_OK;
-       }
-       if(sslOpts->ServerName == NULL) {
-               return CSSMERR_TP_INVALID_POINTER;
-       }
-
-       /* convert caller's hostname string to lower case */
-       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;
-       
-       /* First check subjectAltName... */
-       bool dnsNameFound = false;
-       bool dummy;
-       match = tpCompareSubjectAltName(leafCertInfo.subjectAltName, 
-               hostName, hostNameLen, 
-               SAN_HostName, dnsNameFound, dummy);
-               
-       /* 
-        * Then common name, if
-        *  -- no match from subjectAltName, AND
-        *  -- dnsName was NOT found, AND
-        *  -- hostName is not strictly numeric form (1.2.3.4)
-        */
-       if(!match && !dnsNameFound && !tpIsNumeric(hostName, hostNameLen)) {
-               bool fieldFound;
-               match = tpCompareSubjectName(*leaf, SN_CommonName, hostName, hostNameLen,
-                       fieldFound);
-       }
-       certGroup.alloc().free(hostName);       
-       if(match) {
-               return CSSM_OK;
-       }
-       else {
-               leaf->addStatusCode(CSSMERR_APPLETP_HOSTNAME_MISMATCH);
-               return CSSMERR_TP_VERIFY_ACTION_FAILED;
-       }
-}
-
-/*
- * Verify SMIME options. 
- */
-#define CE_CIPHER_MASK (~(CE_KU_EncipherOnly | CE_KU_DecipherOnly))
-
-static CSSM_RETURN tp_verifySmimeOpts(
-       TPCertGroup &certGroup,
-       const CSSM_DATA *smimeFieldOpts,
-       const iSignCertInfo &leafCertInfo)
-{
-       /* 
-        * First validate optional S/MIME options.
-        */
-       CSSM_APPLE_TP_SMIME_OPTIONS *smimeOpts = NULL;
-       if(smimeFieldOpts != NULL) {
-               smimeOpts = (CSSM_APPLE_TP_SMIME_OPTIONS *)smimeFieldOpts->Data;
-       }
-       if(smimeOpts != NULL) {
-               switch(smimeOpts->Version) {
-                       case CSSM_APPLE_TP_SMIME_OPTS_VERSION:
-                               if(smimeFieldOpts->Length != 
-                                               sizeof(CSSM_APPLE_TP_SMIME_OPTIONS)) {
-                                       return CSSMERR_TP_INVALID_POLICY_IDENTIFIERS;
-                               }
-                               break;
-                       /* handle backwards compatibility here if necessary */
-                       default:
-                               return CSSMERR_TP_INVALID_POLICY_IDENTIFIERS;
-               }
-       }
-       
-       TPCertInfo *leaf = certGroup.certAtIndex(0);
-       assert(leaf != NULL);
-
-       /* Verify optional email address */
-       unsigned emailLen = 0;
-       if(smimeOpts != NULL) {
-               emailLen = smimeOpts->SenderEmailLen;
-       }
-       bool emailFoundInSAN = false;
-       if(emailLen != 0) {
-               if(smimeOpts->SenderEmail == NULL) {
-                       return CSSMERR_TP_INVALID_POINTER;
-               }
-
-               /* normalize caller's email string */
-               char *email = (char *)certGroup.alloc().malloc(emailLen);
-               memmove(email, smimeOpts->SenderEmail, emailLen);
-               tpNormalizeAddrSpec(email, emailLen);
-               
-               CSSM_BOOL match = false;
-               
-               /* 
-                * First check subjectAltName. The emailFound bool indicates
-                * that *some* email address was found, regardless of a match
-                * condition.
-                */
-               bool dummy;
-               match = tpCompareSubjectAltName(leafCertInfo.subjectAltName, 
-                       email, emailLen, 
-                       SAN_Email, dummy, emailFoundInSAN);
-               
-               /* 
-                * Then subject DN, CSSMOID_EmailAddress, if no match from 
-                * subjectAltName
-                */
-               bool emailFoundInDn = false;
-               if(!match) {
-                       match = tpCompareSubjectName(*leaf, SN_Email, email, emailLen,
-                               emailFoundInDn);
-               }
-               certGroup.alloc().free(email);  
-               
-               /*
-                * Error here only if no match found but there was indeed *some*
-                * email address in the cert.
-                */
-               if(!match && (emailFoundInSAN || emailFoundInDn)) {
-                       leaf->addStatusCode(CSSMERR_APPLETP_SMIME_EMAIL_ADDRS_NOT_FOUND);
-                       tpPolicyError("SMIME email addrs in cert but no match");
-                       return CSSMERR_TP_VERIFY_ACTION_FAILED;
-               }
-       }
-       
-       /*
-        * Going by the letter of the law, here's what RFC 2632 has to say
-        * about the legality of an empty Subject Name:
-        *
-        *    ...the subject DN in a user's (i.e. end-entity) certificate MAY 
-        *    be an empty SEQUENCE in which case the subjectAltName extension 
-        *    will include the subject's identifier and MUST be marked as 
-        *    critical.
-        *
-        * OK, first examine the leaf cert's subject name.
-        */
-       CSSM_RETURN crtn;
-       CSSM_DATA_PTR subjNameData = NULL;
-       crtn = leaf->fetchField(&CSSMOID_X509V1SubjectNameCStruct, &subjNameData);
-       if(crtn) {
-               /* This should really never happen */
-               tpPolicyError("SMIME policy: error fetching subjectName");
-               leaf->addStatusCode(CSSMERR_TP_INVALID_CERTIFICATE);
-               return CSSMERR_TP_INVALID_CERTIFICATE;
-       }
-       /* must do a leaf->freeField(&CSSMOID_X509V1SubjectNameCStruct on exit */
-       
-       const CSSM_X509_NAME *x509Name = (const CSSM_X509_NAME *)subjNameData->Data;
-       if(x509Name->numberOfRDNs == 0) {
-               /* 
-                * Empty subject name. If we haven't already seen a valid 
-                * email address in the subject alternate name (by looking
-                * for a specific address specified by app), try to find 
-                * one now.
-                */
-               if(!emailFoundInSAN &&          // haven't found one, and
-                  (emailLen == 0)) {           // didn't even look yet
-                       bool dummy;
-                       tpCompareSubjectAltName(leafCertInfo.subjectAltName, 
-                                       NULL, 0,                                // email, emailLen, 
-                                       SAN_Email, dummy, 
-                                       emailFoundInSAN);               // the variable we're updating
-               }
-               if(!emailFoundInSAN) {
-                       tpPolicyError("SMIME policy fail: empty subject name and "
-                               "no Email Addrs in SubjectAltName");
-                       leaf->addStatusCode(CSSMERR_APPLETP_SMIME_NO_EMAIL_ADDRS);
-                       leaf->freeField(&CSSMOID_X509V1SubjectNameCStruct, subjNameData);
-                       return CSSMERR_TP_VERIFY_ACTION_FAILED;
-               }
-               
-               /*
-                * One more thing: this leaf must indeed have a subjAltName
-                * extension and it must be critical. We would not have gotten this
-                * far if the subjAltName extension was not actually present....
-                */
-               assert(leafCertInfo.subjectAltName.present);
-               if(!leafCertInfo.subjectAltName.critical) {
-                       tpPolicyError("SMIME policy fail: empty subject name and "
-                               "no Email Addrs in SubjectAltName");
-                       leaf->addStatusCode(CSSMERR_APPLETP_SMIME_SUBJ_ALT_NAME_NOT_CRIT);
-                       leaf->freeField(&CSSMOID_X509V1SubjectNameCStruct, subjNameData);
-                       return CSSMERR_TP_VERIFY_ACTION_FAILED;
-               }
-       }
-       leaf->freeField(&CSSMOID_X509V1SubjectNameCStruct, subjNameData);
-        
-       /*
-        * Enforce the usage of the key associated with the leaf cert.
-        * Cert's KeyUsage must be a superset of what the app is trying to do.
-        * Note the {en,de}cipherONly flags are handledÊseparately....
-        */
-       const iSignExtenInfo &kuInfo = leafCertInfo.keyUsage;
-       if(kuInfo.present) {
-               CE_KeyUsage certKu = *((CE_KeyUsage *)kuInfo.extnData);
-               CE_KeyUsage appKu = smimeOpts->IntendedUsage;
-               CE_KeyUsage intersection = certKu & appKu;
-               if((intersection & CE_CIPHER_MASK) != (appKu & CE_CIPHER_MASK)) {
-                       tpPolicyError("SMIME KeyUsage err: appKu 0x%x  certKu 0x%x",
-                               appKu, certKu);
-                       leaf->addStatusCode(CSSMERR_APPLETP_SMIME_BAD_KEY_USE);
-                       return CSSMERR_TP_VERIFY_ACTION_FAILED;
-               }
-               
-               /* Now the en/de cipher only bits - for keyAgreement only */
-               if(appKu & CE_KU_KeyAgreement) {
-                       /* 
-                        * 1. App wants to use this for key agreement; it must
-                        *    say what it wants to do with the derived key.
-                        *    In this context, the app's XXXonly bit means that
-                        *    it wants to use the key for that op - not necessarliy
-                        *    "only". 
-                        */
-                       if((appKu & (CE_KU_EncipherOnly | CE_KU_DecipherOnly)) == 0) {
-                               tpPolicyError("SMIME KeyUsage err: KeyAgreement with "
-                                       "no Encipher or Decipher");
-                               leaf->addStatusCode(CSSMERR_APPLETP_SMIME_BAD_KEY_USE);
-                               return CSSMERR_TP_VERIFY_ACTION_FAILED;
-                       }
-                       
-                       /*
-                        * 2. If cert restricts to encipher only make sure the
-                        *    app isn't trying to decipher.
-                        */
-                       if((certKu & CE_KU_EncipherOnly) && 
-                          (appKu & CE_KU_DecipherOnly)) {
-                               tpPolicyError("SMIME KeyUsage err: cert EncipherOnly, "
-                                       "app wants to decipher");
-                               leaf->addStatusCode(CSSMERR_APPLETP_SMIME_BAD_KEY_USE);
-                               return CSSMERR_TP_VERIFY_ACTION_FAILED;
-                       }
-                       
-                       /*
-                        * 3. If cert restricts to decipher only make sure the
-                        *    app isn't trying to encipher.
-                        */
-                       if((certKu & CE_KU_DecipherOnly) && 
-                          (appKu & CE_KU_EncipherOnly)) {
-                               tpPolicyError("SMIME KeyUsage err: cert DecipherOnly, "
-                                       "app wants to encipher");
-                               leaf->addStatusCode(CSSMERR_APPLETP_SMIME_BAD_KEY_USE);
-                               return CSSMERR_TP_VERIFY_ACTION_FAILED;
-                       }
-               }
-       }
-       
-       /*
-        * Ensure that, if an extendedKeyUsage extension is present in the 
-        * leaf, that either emailProtection or anyExtendedKeyUsage usages is present
-        */
-       const iSignExtenInfo &ekuInfo = leafCertInfo.extendKeyUsage;
-       if(ekuInfo.present) {
-               bool foundGoodEku = false;
-               CE_ExtendedKeyUsage *eku = (CE_ExtendedKeyUsage *)ekuInfo.extnData;
-               assert(eku != NULL);
-               for(unsigned i=0; i<eku->numPurposes; i++) {
-                       if(tpCompareOids(&eku->purposes[i], &CSSMOID_EmailProtection)) {
-                               foundGoodEku = true;
-                               break;
-                       }
-                       if(tpCompareOids(&eku->purposes[i], &CSSMOID_ExtendedKeyUsageAny)) {
-                               foundGoodEku = true;
-                               break;
-                       }
-               }
-               if(!foundGoodEku) {
-                       leaf->addStatusCode(CSSMERR_APPLETP_SMIME_BAD_EXT_KEY_USE);
-                       return CSSMERR_TP_VERIFY_ACTION_FAILED;
-               }
-       }
-        
-       return CSSM_OK;
-}
-
-/*
- * RFC2459 says basicConstraints must be flagged critical for
- * CA certs, but Verisign doesn't work that way.
- */
-#define BASIC_CONSTRAINTS_MUST_BE_CRITICAL             0
-
-/*
- * TP iSign spec says Extended Key Usage required for leaf certs,
- * but Verisign doesn't work that way. 
- */
-#define EXTENDED_KEY_USAGE_REQUIRED_FOR_LEAF   0
-
-/*
- * TP iSign spec says Subject Alternate Name required for leaf certs,
- * but Verisign doesn't work that way. 
- */
-#define SUBJECT_ALT_NAME_REQUIRED_FOR_LEAF             0
-
-/*
- * TP iSign spec originally required KeyUsage for all certs, but
- * Verisign doesn't have that in their roots.
- */
-#define KEY_USAGE_REQUIRED_FOR_ROOT                            0
-
-/*
- * RFC 2632, "S/MIME Version 3 Certificate Handling", section
- * 4.4.2, says that KeyUsage extensions MUST be flagged critical, 
- * but Thawte's intermediate cert (common namd "Thawte Personal 
- * Freemail Issuing CA" does not meet this requirement.
- */
-#define SMIME_KEY_USAGE_MUST_BE_CRITICAL               0
-
-/*
- * Public routine to perform TP verification on a constructed 
- * cert group.
- * Returns CSSM_TRUE on success.
- * Asumes the chain has passed basic subject/issuer verification. First cert of
- * incoming certGroup is end-entity (leaf). 
- *
- * Per-policy details:
- *   iSign: Assumes that last cert in incoming certGroup is a root cert.
- *                     Also assumes a cert group of more than one cert.
- *   kTPx509Basic: CertGroup of length one allowed. 
- */
-CSSM_RETURN tp_policyVerify(
-       TPPolicy                                                policy,
-       CssmAllocator                                   &alloc,
-       CSSM_CL_HANDLE                                  clHand,
-       CSSM_CSP_HANDLE                                 cspHand,
-       TPCertGroup                                     *certGroup,
-       CSSM_BOOL                                               verifiedToRoot, // last cert is good root
-       CSSM_APPLE_TP_ACTION_FLAGS              actionFlags,
-       const CSSM_DATA                                 *policyFieldData,       // optional
-       void                                                    *policyOpts)            // future options
-{
-       iSignCertInfo                   *certInfo = NULL;
-       uint32                                  numCerts;
-       iSignCertInfo                   *thisCertInfo;
-       uint16                                  expUsage;
-       uint16                                  actUsage;
-       unsigned                                certDex;
-       CSSM_BOOL                               cA = CSSM_FALSE;                // init for compiler warning
-       bool                                    isLeaf;                                 // end entity
-       bool                                    isRoot;                                 // root cert
-       CE_ExtendedKeyUsage             *extendUsage;
-       CE_AuthorityKeyID               *authorityId;
-       CSSM_RETURN                             outErr = CSSM_OK;               // for gross, non-policy errors
-       CSSM_BOOL                               policyFail = CSSM_FALSE;
-       
-       /* First, kTPDefault is a nop here */
-       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) {
-                       /* no way, this requires a root cert */
-                       return CSSMERR_TP_VERIFY_ACTION_FAILED;
-               }
-               if(numCerts <= 1) {
-                       /* nope, not for iSign */
-                       return CSSMERR_TP_VERIFY_ACTION_FAILED;
-               }
-       }
-       
-       /* cook up an iSignCertInfo array */
-       certInfo = (iSignCertInfo *)tpCalloc(alloc, numCerts, sizeof(iSignCertInfo));
-       /* subsequent errors to errOut: */
-       
-       /* fill it with interesting info from parsed certs */
-       for(certDex=0; certDex<numCerts; certDex++) {
-               if(iSignGetCertInfo(alloc, 
-                               certGroup->certAtIndex(certDex),                
-                               &certInfo[certDex])) {
-                       (certGroup->certAtIndex(certDex))->addStatusCode(
-                               CSSMERR_TP_INVALID_CERTIFICATE);
-                       /* this one is fatal */
-                       outErr = CSSMERR_TP_INVALID_CERTIFICATE;
-                       goto errOut;
-               }       
-       }
-               
-       /*
-        * OK, the heart of TP enforcement.
-        * First check for presence of required extensions and 
-        * critical extensions we don't understand.
-        */
-       for(certDex=0; certDex<numCerts; certDex++) {
-               thisCertInfo = &certInfo[certDex];
-               TPCertInfo *thisTpCertInfo = certGroup->certAtIndex(certDex);
-               
-               if(thisCertInfo->foundUnknownCritical) {
-                       /* illegal for all policies */
-                       tpPolicyError("tp_policyVerify: critical flag in unknown "
-                               "extension");
-                       thisTpCertInfo->addStatusCode(CSSMERR_APPLETP_UNKNOWN_CRITICAL_EXTEN);
-                       policyFail = CSSM_TRUE;
-               }
-               
-               /* 
-                * Note it's possible for both of these to be true, for a 
-                * of length one (kTPx509Basic, kCrlPolicy only!)
-                * FIXME: should this code work of the last cert in the chain is
-                * NOT a root?
-                */
-               isLeaf = thisTpCertInfo->isLeaf();
-               isRoot = thisTpCertInfo->isSelfSigned();
-                       
-               /*
-                * BasicConstraints.cA
-                * iSign:        required in all but leaf and root,
-                *               for which it is optional (with default values of false
-                *                       for leaf and true for root).
-                * kTPx509Basic,
-                * kTP_SSL,
-                * kTP_SMIME     always optional, default of false for leaf and
-                *                               true for others
-                * All:          cA must be false for leaf, true for others
-                */
-               if(!thisCertInfo->basicConstraints.present) {
-                       /*
-                        * No basicConstraints present; infer a cA value if appropriate.
-                        */
-                       if(isLeaf) {
-                               /* cool, use default; note that kTPx509Basic with
-                                * certGroup length of one may take this case */
-                               cA = CSSM_FALSE;
-                       }
-                       else if(isRoot) {
-                               /* cool, use default */
-                               cA = CSSM_TRUE;
-                       }
-                       else {
-                               switch(policy) {
-                                       case kTPx509Basic:
-                                       case kTP_SSL:
-                                       case kCrlPolicy:
-                                       case kTP_SMIME:
-                                               /* 
-                                                * not present, not leaf, not root.... 
-                                                * ....RFC2459 says this can not be a CA 
-                                                */
-                                               cA = CSSM_FALSE;
-                                               break;
-                                       case kTPiSign:
-                                               /* required for iSign in this position */
-                                               tpPolicyError("tp_policyVerify: no "
-                                                               "basicConstraints");
-                                               policyFail = CSSM_TRUE;
-                                               thisTpCertInfo->addStatusCode(
-                                                       CSSMERR_APPLETP_NO_BASIC_CONSTRAINTS);
-                                               break;
-                                       default:
-                                               /* not reached */
-                                               assert(0);
-                                               break;
-                               }
-                       }
-               }
-               else {
-                       /* basicConstraints present */
-                       #if             BASIC_CONSTRAINTS_MUST_BE_CRITICAL
-                       /* disabled for verisign compatibility */
-                       if(!thisCertInfo->basicConstraints.critical) {
-                               /* per RFC 2459 */
-                               tpPolicyError("tp_policyVerify: basicConstraints marked "
-                                       "not critical");
-                               policyFail = CSSM_TRUE;
-                               thisTpCertInfo->addStatusCode(CSSMERR_TP_VERIFY_ACTION_FAILED);
-                       }
-                       #endif  /* BASIC_CONSTRAINTS_MUST_BE_CRITICAL */
-
-                       const CE_BasicConstraints *bcp = 
-                               &thisCertInfo->basicConstraints.extnData->basicConstraints;
-                       
-                       cA = bcp->cA;
-                       
-                       /* Verify pathLenConstraint if present */
-                       if(!isLeaf &&                                                   // leaf, certDex=0, don't care
-                          cA &&                                                                // p.l.c. only valid for CAs
-                          bcp->pathLenConstraintPresent) {             // present?
-                               /*
-                                * pathLenConstraint=0 legal for certDex 1 only
-                                * pathLenConstraint=1 legal for certDex {1,2}
-                                * etc. 
-                                */ 
-                               if(certDex > (bcp->pathLenConstraint + 1)) {
-                                       tpPolicyError("tp_policyVerify: pathLenConstraint "
-                                               "exceeded");
-                                       policyFail = CSSM_TRUE;
-                                       thisTpCertInfo->addStatusCode(
-                                                       CSSMERR_APPLETP_PATH_LEN_CONSTRAINT);
-                               }
-                       }
-               }
-               
-               if(isLeaf) {
-                       /* 
-                        * Special cases to allow a chain of length 1, leaf and root 
-                        * both true, and for caller to override the "leaf can't be a CA"
-                        * requirement when a CA cert is explicitly being evaluated as the 
-                        * leaf.
-                        */
-                       if(cA && !isRoot && 
-                          !(actionFlags & CSSM_TP_ACTION_LEAF_IS_CA)) {
-                               tpPolicyError("tp_policyVerify: cA true for leaf");
-                               policyFail = CSSM_TRUE;
-                               thisTpCertInfo->addStatusCode(CSSMERR_APPLETP_INVALID_CA);
-                       }
-               } else if(!cA) {
-                       tpPolicyError("tp_policyVerify: cA false for non-leaf");
-                       policyFail = CSSM_TRUE;
-                       thisTpCertInfo->addStatusCode(CSSMERR_APPLETP_INVALID_CA);
-               }
-               
-               /*
-                * Authority Key Identifier optional
-                * iSign                : only allowed in !root. 
-                *                If present, must not be critical.
-                * kTPx509Basic,
-                * kTP_SSL,
-                * kTP_SMIME    : ignored (though used later for chain verification)
-                */ 
-               if((policy == kTPiSign) && thisCertInfo->authorityId.present) {
-                       if(isRoot) {
-                               tpPolicyError("tp_policyVerify: authorityId in root");
-                               policyFail = CSSM_TRUE;
-                               thisTpCertInfo->addStatusCode(CSSMERR_APPLETP_INVALID_AUTHORITY_ID); 
-                       }
-                       if(thisCertInfo->authorityId.critical) {
-                               /* illegal per RFC 2459 */
-                               tpPolicyError("tp_policyVerify: authorityId marked "
-                                       "critical");
-                               policyFail = CSSM_TRUE;
-                               thisTpCertInfo->addStatusCode(CSSMERR_APPLETP_INVALID_AUTHORITY_ID); 
-                       }
-               }
-
-               /*
-                * Subject Key Identifier optional 
-                * iSign                 : can't be critical. 
-                * kTPx509Basic,
-                * kTP_SSL,
-                * kTP_SMIME     : ignored (though used later for chain verification)
-                */ 
-               if(thisCertInfo->subjectId.present) {
-                       if((policy == kTPiSign) && thisCertInfo->subjectId.critical) {
-                               tpPolicyError("tp_policyVerify: subjectId marked critical");
-                               policyFail = CSSM_TRUE;
-                               thisTpCertInfo->addStatusCode(CSSMERR_APPLETP_INVALID_SUBJECT_ID); 
-                       }
-               }
-               
-               /*
-                * Key Usage optional except as noted required
-                * iSign        : required for non-root/non-leaf
-                *                Leaf cert : if present, usage = digitalSignature
-                *                                Exception : if leaf, and keyUsage not present, 
-                *                                                netscape-cert-type must be present, with
-                *                                                        Object Signing bit set
-                * kTPx509Basic,
-                * kTP_SSL,
-                * kTP_SMIME,   : non-leaf  : usage = keyCertSign
-                *                                Leaf: don't care
-                * kCrlPolicy   : Leaf: usage = CRLSign
-                * kTP_SMIME    : if present, must be critical
-                */ 
-               if(thisCertInfo->keyUsage.present) {
-                       /*
-                        * Leaf cert: usage = digitalSignature
-                        * Others:    usage = keyCertSign
-                        * We only require that one bit to be set, we ignore others. 
-                        */
-                       if(isLeaf) {
-                               switch(policy) {
-                                       case kTPiSign:
-                                               expUsage = CE_KU_DigitalSignature;
-                                               break;
-                                       case kCrlPolicy:
-                                               /* if present, this bit must be set */
-                                               expUsage = CE_KU_CRLSign;
-                                               break;
-                                       default:
-                                               /* hack to accept whatever's there */
-                                               expUsage = thisCertInfo->keyUsage.extnData->keyUsage;
-                                               break;
-                               }
-                       }
-                       else {
-                               /* this is true for all policies */
-                               expUsage = CE_KU_KeyCertSign;
-                       }
-                       actUsage = thisCertInfo->keyUsage.extnData->keyUsage;
-                       if(!(actUsage & expUsage)) {
-                               tpPolicyError("tp_policyVerify: bad keyUsage (leaf %s; "
-                                       "usage 0x%x)",
-                                       (certDex == 0) ? "TRUE" : "FALSE", actUsage);
-                               policyFail = CSSM_TRUE;
-                               thisTpCertInfo->addStatusCode(CSSMERR_APPLETP_INVALID_KEY_USAGE); 
-                       }
-                       #if 0
-                       if((policy == kTP_SMIME) && !thisCertInfo->keyUsage.critical) {
-                               /*
-                                * Per Radar 3410245, allow this for intermediate certs.
-                                */
-                               if(SMIME_KEY_USAGE_MUST_BE_CRITICAL || isLeaf || isRoot) {
-                                       tpPolicyError("tp_policyVerify: key usage, !critical, SMIME");
-                                       policyFail = CSSM_TRUE;
-                                       thisTpCertInfo->addStatusCode(CSSMERR_APPLETP_SMIME_KEYUSAGE_NOT_CRITICAL);
-                               }
-                       }
-                       #endif
-               }
-               else if(policy == kTPiSign) {
-                       /* 
-                        * iSign requires keyUsage present for non root OR
-                        * netscape-cert-type/ObjectSigning for leaf
-                        */
-                       if(isLeaf && thisCertInfo->netscapeCertType.present) {
-                               CE_NetscapeCertType ct = 
-                                       thisCertInfo->netscapeCertType.extnData->netscapeCertType;
-                                       
-                               if(!(ct & CE_NCT_ObjSign)) {
-                                       tpPolicyError("tp_policyVerify: netscape-cert-type, "
-                                               "!ObjectSign");
-                                       policyFail = CSSM_TRUE;
-                                       thisTpCertInfo->addStatusCode(CSSMERR_APPLETP_INVALID_KEY_USAGE);
-                               }
-                       }
-                       else if(!isRoot) {
-                               tpPolicyError("tp_policyVerify: !isRoot, no keyUsage, "
-                                       "!(leaf and netscapeCertType)");
-                               policyFail = CSSM_TRUE;
-                               thisTpCertInfo->addStatusCode(CSSMERR_APPLETP_INVALID_KEY_USAGE); 
-                       }
-               }                               
-       }       /* for certDex, checking presence of extensions */
-
-       /*
-        * Special case checking for leaf (end entity) cert     
-        *
-        * iSign only: Extended key usage, optional for leaf, 
-        * value CSSMOID_ExtendedUseCodeSigning
-        */
-       if((policy == kTPiSign) && certInfo[0].extendKeyUsage.present) {
-               extendUsage = &certInfo[0].extendKeyUsage.extnData->extendedKeyUsage;
-               if(extendUsage->numPurposes != 1) {
-                       tpPolicyError("tp_policyVerify: bad extendUsage->numPurposes "
-                               "(%d)",
-                               (int)extendUsage->numPurposes);
-                       policyFail = CSSM_TRUE;
-                       (certGroup->certAtIndex(0))->addStatusCode(
-                               CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE); 
-               }
-               if(!tpCompareOids(extendUsage->purposes,
-                               &CSSMOID_ExtendedUseCodeSigning)) {
-                       tpPolicyError("tp_policyVerify: bad extendKeyUsage");
-                       policyFail = CSSM_TRUE;
-                       (certGroup->certAtIndex(0))->addStatusCode(
-                               CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE); 
-               }
-       }
-       
-       /*
-        * Verify authorityId-->subjectId linkage.
-        * All optional - skip if needed fields not present.
-        * Also, always skip last (root) cert.  
-        */
-       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) {
-                       /* we only know how to compare keyIdentifier */
-                       continue;
-               }
-               if(!tpCompareCssmData(&authorityId->keyIdentifier,
-                               &certInfo[certDex+1].subjectId.extnData->subjectKeyID)) {
-                       tpPolicyError("tp_policyVerify: bad key ID linkage");
-                       policyFail = CSSM_TRUE;
-                       (certGroup->certAtIndex(certDex))->addStatusCode(
-                                       CSSMERR_APPLETP_INVALID_ID_LINKAGE); 
-               }
-       }
-       
-       /* 
-        * SSL: optionally verify common name.
-        * FIXME - should this be before or after the root cert test? How can
-        * we return both errors?
-        */
-       if(policy == kTP_SSL) {
-               CSSM_RETURN cerr = tp_verifySslOpts(*certGroup, policyFieldData,
-                       certInfo[0]);
-               if(cerr) {
-                       policyFail = CSSM_TRUE;
-               }
-       }
-       
-       /* S/MIME */
-       if(policy == kTP_SMIME) {
-               CSSM_RETURN cerr = tp_verifySmimeOpts(*certGroup, policyFieldData,
-                       certInfo[0]);
-               if(cerr) {
-                       policyFail = CSSM_TRUE;
-               }
-       }
-       
-       if(policyFail && (outErr == CSSM_OK)) {
-               /* only error in this function was policy failure */
-               outErr = CSSMERR_TP_VERIFY_ACTION_FAILED;
-       }
-errOut:
-       /* free resources */
-       for(certDex=0; certDex<numCerts; certDex++) {
-               thisCertInfo = &certInfo[certDex];
-               iSignFreeCertInfo(clHand, thisCertInfo);
-       }
-       tpFree(alloc, certInfo);
-       return outErr;
-}