X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/5dd5f9ec28f304ca377c42fd7f711d6cf12b90e1..5c19dc3ae3bd8e40a9c028b0deddd50ff337692c:/Security/libsecurity_apple_x509_tp/lib/tpPolicies.cpp diff --git a/Security/libsecurity_apple_x509_tp/lib/tpPolicies.cpp b/Security/libsecurity_apple_x509_tp/lib/tpPolicies.cpp deleted file mode 100644 index 761dc806..00000000 --- a/Security/libsecurity_apple_x509_tp/lib/tpPolicies.cpp +++ /dev/null @@ -1,3366 +0,0 @@ -/* - * Copyright (c) 2000-2014 Apple 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 -*/ - -#include -#include -#include "tpPolicies.h" -#include -#include "tpdebugging.h" -#include "certGroupUtils.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunused-const-variable" - -/* - * 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; - iSignExtenInfo certPolicies; - iSignExtenInfo qualCertStatements; - iSignExtenInfo nameConstraints; - iSignExtenInfo policyMappings; - iSignExtenInfo policyConstraints; - iSignExtenInfo inhibitAnyPolicy; - iSignExtenInfo certificatePolicies; - - /* flag indicating presence of CSSMOID_APPLE_EXTENSION_PASSBOOK_SIGNING */ - CSSM_BOOL foundPassbookSigning; - /* flag indicating presence of CSSMOID_APPLE_EXTENSION_SYSINT2_INTERMEDIATE */ - CSSM_BOOL foundAppleSysInt2Marker; - /* flag indicating presence of CSSMOID_APPLE_EXTENSION_SERVER_AUTHENTICATION */ - CSSM_BOOL foundAppleServerAuthMarker; - /* flag indicating presence of CSSMOID_APPLE_EXTENSION_ESCROW_SERVICE */ - CSSM_BOOL foundEscrowServiceMarker; - /* flag indicating presence of a critical extension we don't understand */ - CSSM_BOOL foundUnknownCritical; - /* flag indicating that this certificate was signed with a known-broken algorithm */ - CSSM_BOOL untrustedSigAlg; - -} iSignCertInfo; - -/* - * The list of Qualified Cert Statement statementIds we understand, even though - * we don't actually do anything with them; if these are found in a Qualified - * Cert Statement that's critical, we can truthfully say "yes we understand this". - */ -static const CSSM_OID_PTR knownQualifiedCertStatements[] = -{ - (const CSSM_OID_PTR)&CSSMOID_OID_QCS_SYNTAX_V1, - (const CSSM_OID_PTR)&CSSMOID_OID_QCS_SYNTAX_V2, - (const CSSM_OID_PTR)&CSSMOID_ETSI_QCS_QC_COMPLIANCE, - (const CSSM_OID_PTR)&CSSMOID_ETSI_QCS_QC_LIMIT_VALUE, - (const CSSM_OID_PTR)&CSSMOID_ETSI_QCS_QC_RETENTION, - (const CSSM_OID_PTR)&CSSMOID_ETSI_QCS_QC_SSCD -}; -#define NUM_KNOWN_QUAL_CERT_STATEMENTS (sizeof(knownQualifiedCertStatements) / sizeof(CSSM_OID_PTR)) - -static CSSM_RETURN tp_verifyMacAppStoreReceiptOpts(TPCertGroup &certGroup, - const CSSM_DATA *fieldOpts, const iSignCertInfo *certInfo); - -static CSSM_RETURN tp_verifyPassbookSigningOpts(TPCertGroup &certGroup, - const CSSM_DATA *fieldOpts, const iSignCertInfo *certInfo); - -bool certificatePoliciesContainsOID(const CE_CertPolicies *certPolicies, const CSSM_OID *oidToFind); - -#define kSecPolicySHA1Size 20 -static const UInt8 kAppleCASHA1[kSecPolicySHA1Size] = { - 0x61, 0x1E, 0x5B, 0x66, 0x2C, 0x59, 0x3A, 0x08, 0xFF, 0x58, - 0xD1, 0x4A, 0xE2, 0x24, 0x52, 0xD1, 0x98, 0xDF, 0x6C, 0x60 -}; - -static const UInt8 kMobileRootSHA1[kSecPolicySHA1Size] = { - 0xBD, 0xD6, 0x7C, 0x34, 0xD0, 0xB2, 0x68, 0x5D, 0x31, 0x82, - 0xCD, 0x32, 0xCB, 0xF4, 0x54, 0x69, 0xA1, 0xF1, 0x6B, 0x09 -}; - -static const UInt8 kAppleCorpCASHA1[kSecPolicySHA1Size] = { - 0xA1, 0x71, 0xDC, 0xDE, 0xE0, 0x8B, 0x1B, 0xAE, 0x30, 0xA1, - 0xAE, 0x6C, 0xC6, 0xD4, 0x03, 0x3B, 0xFD, 0xEF, 0x91, 0xCE -}; - -/* - * Certificate policy OIDs - */ - -/* 2.5.29.32.0 */ -#define ANY_POLICY_OID OID_EXTENSION, 0x32, 0x00 -#define ANY_POLICY_OID_LEN OID_EXTENSION_LENGTH + 2 - -/* 2.5.29.54 */ -#define INHIBIT_ANY_POLICY_OID OID_EXTENSION, 0x54 -#define INHIBIT_ANY_POLICY_OID_LEN OID_EXTENSION_LENGTH + 1 - -/* 2.16.840.1.101.2.1 */ -#define US_DOD_INFOSEC 0x60, 0x86, 0x48, 0x01, 0x65, 0x02, 0x01 -#define US_DOD_INFOSEC_LEN 7 - -/* 2.16.840.1.101.2.1.11.10 */ -#define PIV_AUTH_OID US_DOD_INFOSEC, 0x0B, 0x0A -#define PIV_AUTH_OID_LEN US_DOD_INFOSEC_LEN + 2 - -/* 2.16.840.1.101.2.1.11.20 */ -#define PIV_AUTH_2048_OID US_DOD_INFOSEC, 0x0B, 0x14 -#define PIV_AUTH_2048_OID_LEN US_DOD_INFOSEC_LEN + 2 - -static const uint8 OID_ANY_POLICY[] = {ANY_POLICY_OID}; -const CSSM_OID CSSMOID_ANY_POLICY = {ANY_POLICY_OID_LEN, (uint8 *)OID_ANY_POLICY}; -static const uint8 OID_INHIBIT_ANY_POLICY[] = {INHIBIT_ANY_POLICY_OID}; -const CSSM_OID CSSMOID_INHIBIT_ANY_POLICY = {INHIBIT_ANY_POLICY_OID_LEN, (uint8 *)OID_INHIBIT_ANY_POLICY}; -static const uint8 OID_PIV_AUTH[] = {PIV_AUTH_OID}; -const CSSM_OID CSSMOID_PIV_AUTH = {PIV_AUTH_OID_LEN, (uint8 *)OID_PIV_AUTH}; -static const uint8 OID_PIV_AUTH_2048[] = {PIV_AUTH_2048_OID}; -const CSSM_OID CSSMOID_PIV_AUTH_2048 = {PIV_AUTH_2048_OID_LEN, (uint8 *)OID_PIV_AUTH_2048}; - -static CSSM_RETURN tp_verifyAppleIDSharingOpts(TPCertGroup &certGroup, - const CSSM_DATA *fieldOpts, // optional Common Name - const iSignCertInfo *certInfo); -/* - * Setup a single iSignExtenInfo. Called once per known extension - * per cert. - */ -static CSSM_RETURN tpSetupExtension( - Allocator &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( - Allocator &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); -} - -/* - * This function performs a check of an extension marked 'critical' - * to see if it's one we understand. Returns CSSM_OK if the extension - * is acceptable, CSSMERR_APPLETP_UNKNOWN_CRITICAL_EXTEN if unknown. - */ -static CSSM_RETURN iSignVerifyCriticalExtension( - CSSM_X509_EXTENSION *cssmExt) -{ - if (!cssmExt || !cssmExt->extnId.Data) - return CSSMERR_TP_INVALID_FIELD_POINTER; - - if (!cssmExt->critical) - return CSSM_OK; - - /* FIXME: remove when policyConstraints NSS template is fixed */ - if (!memcmp(cssmExt->extnId.Data, CSSMOID_PolicyConstraints.Data, CSSMOID_PolicyConstraints.Length)) - return CSSM_OK; - - if (cssmExt->extnId.Length > APPLE_EXTENSION_OID_LENGTH && - !memcmp(cssmExt->extnId.Data, CSSMOID_APPLE_EXTENSION.Data, APPLE_EXTENSION_OID_LENGTH)) { - /* This extension's OID is under the appleCertificateExtensions arc */ - return CSSM_OK; - - } - return CSSMERR_APPLETP_UNKNOWN_CRITICAL_EXTEN; -} - -/* - * Search for all 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; - - certInfo->foundPassbookSigning = CSSM_FALSE; - certInfo->foundAppleSysInt2Marker = CSSM_FALSE; - certInfo->foundEscrowServiceMarker = CSSM_FALSE; - - 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->extnId.Length == APPLE_EXTENSION_CODE_SIGNING_LENGTH+1 && - !memcmp(cssmExt->extnId.Data, CSSMOID_APPLE_EXTENSION_PASSBOOK_SIGNING.Data, - APPLE_EXTENSION_CODE_SIGNING_LENGTH+1)) { - /* this is the Passbook Signing extension */ - certInfo->foundPassbookSigning = CSSM_TRUE; - } - if (cssmExt->extnId.Length == APPLE_EXTENSION_SYSINT2_INTERMEDIATE_LENGTH && - !memcmp(cssmExt->extnId.Data, CSSMOID_APPLE_EXTENSION_SYSINT2_INTERMEDIATE.Data, - APPLE_EXTENSION_SYSINT2_INTERMEDIATE_LENGTH)) { - /* this is the Apple System Integration 2 Signing extension */ - certInfo->foundAppleSysInt2Marker = CSSM_TRUE; - } - if (cssmExt->extnId.Length == APPLE_EXTENSION_ESCROW_SERVICE_LENGTH && - !memcmp(cssmExt->extnId.Data, CSSMOID_APPLE_EXTENSION_ESCROW_SERVICE.Data, - APPLE_EXTENSION_ESCROW_SERVICE_LENGTH)) { - /* this is the Escrow Service Signing extension */ - certInfo->foundEscrowServiceMarker = CSSM_TRUE; - } - - if(iSignVerifyCriticalExtension(cssmExt) != CSSM_OK) { - /* 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; iclHand(), - 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->extnId.Length == APPLE_EXTENSION_CODE_SIGNING_LENGTH+1 && - !memcmp(cssmExt->extnId.Data, CSSMOID_APPLE_EXTENSION_PASSBOOK_SIGNING.Data, - APPLE_EXTENSION_CODE_SIGNING_LENGTH+1)) { - /* this is the Passbook Signing extension */ - certInfo->foundPassbookSigning = CSSM_TRUE; - } - if (cssmExt->extnId.Length == APPLE_EXTENSION_SYSINT2_INTERMEDIATE_LENGTH && - !memcmp(cssmExt->extnId.Data, CSSMOID_APPLE_EXTENSION_SYSINT2_INTERMEDIATE.Data, - APPLE_EXTENSION_SYSINT2_INTERMEDIATE_LENGTH)) { - /* this is the Apple System Integration 2 Signing extension */ - certInfo->foundAppleSysInt2Marker = CSSM_TRUE; - } - if (cssmExt->extnId.Length == APPLE_EXTENSION_SERVER_AUTHENTICATION_LENGTH && - !memcmp(cssmExt->extnId.Data, CSSMOID_APPLE_EXTENSION_SERVER_AUTHENTICATION.Data, - APPLE_EXTENSION_SERVER_AUTHENTICATION_LENGTH)) { - /* this is the Apple Server Authentication extension */ - certInfo->foundAppleServerAuthMarker = CSSM_TRUE; - } - if (cssmExt->extnId.Length == APPLE_EXTENSION_ESCROW_SERVICE_LENGTH && - !memcmp(cssmExt->extnId.Data, CSSMOID_APPLE_EXTENSION_ESCROW_SERVICE.Data, - APPLE_EXTENSION_ESCROW_SERVICE_LENGTH)) { - /* this is the Escrow Service Signing extension */ - certInfo->foundEscrowServiceMarker = CSSM_TRUE; - } - - if(iSignVerifyCriticalExtension(cssmExt) != CSSM_OK) { - /* 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; -} - -/* - * Check the signature algorithm. If it's known to be untrusted, - * flag certInfo->untrustedSigAlg. - */ -static void iSignCheckSignatureAlgorithm( - TPCertInfo *tpCert, - iSignCertInfo *certInfo) -{ - CSSM_X509_ALGORITHM_IDENTIFIER *algId = NULL; - CSSM_DATA_PTR valueToFree = NULL; - - algId = tp_CertGetAlgId(tpCert, &valueToFree); - if(!algId || - tpCompareCssmData(&algId->algorithm, &CSSMOID_MD2) || - tpCompareCssmData(&algId->algorithm, &CSSMOID_MD2WithRSA) || - tpCompareCssmData(&algId->algorithm, &CSSMOID_MD5) || - tpCompareCssmData(&algId->algorithm, &CSSMOID_MD5WithRSA) ) { - certInfo->untrustedSigAlg = CSSM_TRUE; - } else { - certInfo->untrustedSigAlg = CSSM_FALSE; - } - - if (valueToFree) { - tp_CertFreeAlgId(tpCert->clHand(), valueToFree); - } -} - -/* - * Given a TPCertInfo, fetch the associated iSignCertInfo fields. - * Returns CSSM_FAIL on error. - */ -static CSSM_RETURN iSignGetCertInfo( - Allocator &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; - } - crtn = iSignFetchExtension(alloc, - tpCert, - &CSSMOID_CertificatePolicies, - &certInfo->certPolicies); - if(crtn) { - return crtn; - } - crtn = iSignFetchExtension(alloc, - tpCert, - &CSSMOID_QC_Statements, - &certInfo->qualCertStatements); - if(crtn) { - return crtn; - } - crtn = iSignFetchExtension(alloc, - tpCert, - &CSSMOID_NameConstraints, - &certInfo->nameConstraints); - if(crtn) { - return crtn; - } - crtn = iSignFetchExtension(alloc, - tpCert, - &CSSMOID_PolicyMappings, - &certInfo->policyMappings); - if(crtn) { - return crtn; - } - crtn = iSignFetchExtension(alloc, - tpCert, - &CSSMOID_PolicyConstraints, - &certInfo->policyConstraints); - if(crtn) { - return crtn; - } - crtn = iSignFetchExtension(alloc, - tpCert, - &CSSMOID_InhibitAnyPolicy, - &certInfo->inhibitAnyPolicy); - if(crtn) { - return crtn; - } - crtn = iSignFetchExtension(alloc, - tpCert, - &CSSMOID_CertificatePolicies, - &certInfo->certificatePolicies); - if(crtn) { - return crtn; - } - - /* check signature algorithm field */ - iSignCheckSignatureAlgorithm(tpCert, certInfo); - - /* 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); - } - if(certInfo->certPolicies.present) { - CSSM_CL_FreeFieldValue(clHand, &CSSMOID_CertificatePolicies, - certInfo->certPolicies.valToFree); - } -// if(certInfo->policyConstraints.present) { -// CSSM_CL_FreeFieldValue(clHand, &CSSMOID_PolicyConstraints, -// certInfo->policyConstraints.valToFree); -// } - if(certInfo->qualCertStatements.present) { - CSSM_CL_FreeFieldValue(clHand, &CSSMOID_QC_Statements, - certInfo->qualCertStatements.valToFree); - } - if(certInfo->certificatePolicies.present) { - CSSM_CL_FreeFieldValue(clHand, &CSSMOID_CertificatePolicies, - certInfo->certificatePolicies.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 - SN_UserID, // CSSMOID_UserID - SN_OrgUnit // CSSMOID_OrganizationalUnitName -} SubjSubjNameSearchType; - -static CSSM_BOOL tpCompareSubjectName( - TPCertInfo &cert, - SubjSubjNameSearchType searchType, - bool normalizeAll, // for SN_Email case: lower-case all of - // the cert's value, not just the portion - // after the '@' - 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; - - const char x500_userid_oid[] = { 0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x01 }; - CSSM_OID X500_UserID_OID = { sizeof(x500_userid_oid), (uint8*)x500_userid_oid }; - - fieldFound = false; - switch(searchType) { - case SN_CommonName: - oidSrch = &CSSMOID_CommonName; - break; - case SN_Email: - oidSrch = &CSSMOID_EmailAddress; - break; - case SN_UserID: - oidSrch = &X500_UserID_OID; - break; - case SN_OrgUnit: - oidSrch = &CSSMOID_OrganizationalUnitName; - 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("tpCompareSubjectName: 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("tpCompareSubjectName: 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; rdnDexnumberOfRDNs; rdnDex++) { - rdnp = &x509name->RelativeDistinguishedName[rdnDex]; - for(pairDex=0; pairDexnumberOfPairs; pairDex++) { - ptvp = &rdnp->AttributeTypeAndValue[pairDex]; - if(tpCompareOids(&ptvp->type, oidSrch)) { - fieldFound = true; - certName = (char *)ptvp->value.Data; - certNameLen = (uint32)ptvp->value.Length; - switch(searchType) { - case SN_CommonName: - { - /* handle odd encodings that we need to convert to 8-bit */ - CFStringBuiltInEncodings encoding; - CFDataRef cfd = NULL; - bool doConvert = false; - switch(ptvp->valueType) { - case BER_TAG_T61_STRING: - /* a.k.a. Teletex */ - encoding = kCFStringEncodingISOLatin1; - doConvert = true; - break; - case BER_TAG_PKIX_BMP_STRING: - encoding = kCFStringEncodingUnicode; - doConvert = true; - break; - /* - * All others - either take as is, or let it fail due to - * illegal/incomprehensible format - */ - default: - break; - } - if(doConvert) { - /* raw data ==> CFString */ - cfd = CFDataCreate(NULL, (UInt8 *)certName, certNameLen); - if(cfd == NULL) { - /* try next component */ - break; - } - CFStringRef cfStr = CFStringCreateFromExternalRepresentation( - NULL, cfd, encoding); - CFRelease(cfd); - if(cfStr == NULL) { - tpPolicyError("tpCompareSubjectName: bad str (1)"); - break; - } - - /* CFString ==> straight ASCII */ - cfd = CFStringCreateExternalRepresentation(NULL, - cfStr, kCFStringEncodingASCII, 0); - CFRelease(cfStr); - if(cfd == NULL) { - tpPolicyError("tpCompareSubjectName: bad str (2)"); - break; - } - certNameLen = (uint32)CFDataGetLength(cfd); - certName = (char *)CFDataGetBytePtr(cfd); - } - ourRtn = tpCompareHostNames(callerStr, callerStrLen, - certName, certNameLen); - if(doConvert) { - assert(cfd != NULL); - CFRelease(cfd); - } - break; - } - case SN_Email: - ourRtn = tpCompareEmailAddr(callerStr, callerStrLen, - certName, certNameLen, normalizeAll); - break; - case SN_UserID: - case SN_OrgUnit: - /* exact match only here, for now */ - ourRtn = ((callerStrLen == certNameLen) && - !memcmp(callerStr, certName, certNameLen)) ? - CSSM_TRUE : CSSM_FALSE; - 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; dexLength; dex++) { - /* cp points to start of current string digit */ - /* find next dot */ - const char *lastChar = cp + strLen; - nextDot = cp + 1; - for( ; nextDotLength - 1)) { - return CSSM_FALSE; - } - } - else if(dex == (numeric->Length - 1)) { - return CSSM_FALSE; - } - ptrdiff_t 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, // caller has lower-cased as appropriate - uint32 appStrLen, - SubjAltNameSearchType searchType, - bool normalizeAll, // for SAN_Email case: lower-case all of - // the cert's value, not just the portion - // after the '@' - 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; - uint32 certNameLen; - - /* Search thru the CE_GeneralNames looking for the appropriate attribute */ - for(unsigned dex=0; dexnumNames; 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 = (uint32)(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 = (uint32)(name->name.Length); - emailFound = true; - if(appStr != NULL) { - ourRtn = tpCompareEmailAddr(appStr, appStrLen, certName, - certNameLen, normalizeAll); - } - 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; ivalueType) { - case BER_TAG_T61_STRING: - /* a.k.a. Teletex */ - encoding = kCFStringEncodingISOLatin1; - break; - case BER_TAG_PKIX_BMP_STRING: - encoding = kCFStringEncodingUnicode; - break; - case BER_TAG_PRINTABLE_STRING: - case BER_TAG_IA5_STRING: - case BER_TAG_PKIX_UTF8_STRING: - encoding = kCFStringEncodingUTF8; - break; - default: - return NULL; - } - - /* raw data ==> CFString */ - CFDataRef cfd = CFDataCreate(NULL, tvp->value.Data, tvp->value.Length); - if(cfd == NULL) { - return NULL; - } - CFStringRef cfStr = CFStringCreateFromExternalRepresentation(NULL, cfd, encoding); - CFRelease(cfd); - return cfStr; -} - -/* - * Compare a CFString and a string represented by a CSSM_X509_TYPE_VALUE_PAIR. - * Returns CSSM_TRUE if they are equal. - */ -static bool tpCompareTvpToCfString( - const CSSM_X509_TYPE_VALUE_PAIR *tvp, - CFStringRef refStr, - CFOptionFlags flags) // e.g., kCFCompareCaseInsensitive -{ - CFStringRef cfStr = tpTvpToCfString(tvp); - if(cfStr == NULL) { - return false; - } - CFComparisonResult res = CFStringCompare(refStr, cfStr, flags); - CFRelease(cfStr); - if(res == kCFCompareEqualTo) { - return true; - } - else { - return false; - } -} - -/* - * Given one iSignCertInfo, determine whether or not the specified - * EKU OID, or - optionally - CSSMOID_ExtendedKeyUsageAny - is present. - * Returns true if so, else false. - */ -static bool tpVerifyEKU( - const iSignCertInfo &certInfo, - const CSSM_OID &ekuOid, - bool ekuAnyOK) // if true, CSSMOID_ExtendedKeyUsageAny counts as "found" -{ - if(!certInfo.extendKeyUsage.present) { - return false; - } - CE_ExtendedKeyUsage *eku = &certInfo.extendKeyUsage.extnData->extendedKeyUsage; - assert(eku != NULL); - - for(unsigned i=0; inumPurposes; i++) { - const CSSM_OID *foundEku = &eku->purposes[i]; - if(tpCompareOids(foundEku, &ekuOid)) { - return true; - } - if(ekuAnyOK && tpCompareOids(foundEku, &CSSMOID_ExtendedKeyUsageAny)) { - return true; - } - } - return false; -} - -/* - * Given one iSignCertInfo, determine whether or not the specified - * Certificate Policy OID, or - optionally - CSSMOID_ANY_POLICY - is present. - * Returns true if so, else false. - */ -static bool tpVerifyCPE( - const iSignCertInfo &certInfo, - const CSSM_OID &cpOid, - bool anyPolicyOK) // if true, CSSMOID_ANY_POLICY counts as "found" -{ - if(!certInfo.certPolicies.present) { - return false; - } - CE_CertPolicies *cp = &certInfo.certPolicies.extnData->certPolicies; - assert(cp != NULL); - - for(unsigned i=0; inumPolicies; i++) { - const CE_PolicyInformation *foundPolicy = &cp->policies[i]; - if(tpCompareOids(&foundPolicy->certPolicyId, &cpOid)) { - return true; - } - if(anyPolicyOK && tpCompareOids(&foundPolicy->certPolicyId, &CSSMOID_ANY_POLICY)) { - return true; - } - } - return false; -} - -/* - * Verify iChat handle. We search for a matching (case-insensitive) string - * comprised of: - * - * -- name component ("dmitch") from subject name's CommonName - * -- implicit '@' - * -- domain name from subject name's organizationalUnit - * - * Plus we require an Organization component of "Apple Computer, Inc." or "Apple Inc." - */ -static bool tpCompareIChatHandleName( - TPCertInfo &cert, - const char *iChatHandle, // UTF8 - uint32 iChatHandleLen) -{ - CSSM_DATA_PTR subjNameData = NULL; // from fetchField - CSSM_RETURN crtn; - bool ourRtn = false; - CSSM_X509_NAME_PTR x509name; - CSSM_X509_TYPE_VALUE_PAIR *ptvp; - CSSM_X509_RDN_PTR rdnp; - unsigned rdnDex; - unsigned pairDex; - - /* search until all of these are true */ - CSSM_BOOL commonNameMatch = CSSM_FALSE; // name before '@' - CSSM_BOOL orgUnitMatch = CSSM_FALSE; // domain after '@ - CSSM_BOOL orgMatch = CSSM_FALSE; // Apple Computer, Inc. (or Apple Inc.) - - /* - * incoming UTF8 handle ==> two components. - * First convert to CFString. - */ - if(iChatHandle[iChatHandleLen - 1] == '\0') { - /* avoid NULL when creating CFStrings */ - iChatHandleLen--; - } - CFDataRef cfd = CFDataCreate(NULL, (const UInt8 *)iChatHandle, iChatHandleLen); - if(cfd == NULL) { - return false; - } - CFStringRef handleStr = CFStringCreateFromExternalRepresentation(NULL, cfd, - kCFStringEncodingUTF8); - CFRelease(cfd); - if(handleStr == NULL) { - tpPolicyError("tpCompareIChatHandleName: bad incoming handle (1)"); - return false; - } - - /* - * Find the '@' delimiter - */ - CFRange whereIsAt; - whereIsAt = CFStringFind(handleStr, CFSTR("@"), 0); - if(whereIsAt.length == 0) { - tpPolicyError("tpCompareIChatHandleName: bad incoming handle: no @"); - CFRelease(handleStr); - return false; - } - - /* - * Two components, before and after delimiter - */ - CFRange r = {0, whereIsAt.location}; - CFStringRef iChatName = CFStringCreateWithSubstring(NULL, handleStr, r); - if(iChatName == NULL) { - tpPolicyError("tpCompareIChatHandleName: bad incoming handle (2)"); - CFRelease(handleStr); - return false; - } - r.location = whereIsAt.location + 1; // after the '@' - r.length = CFStringGetLength(handleStr) - r.location; - CFStringRef iChatDomain = CFStringCreateWithSubstring(NULL, handleStr, r); - CFRelease(handleStr); - if(iChatDomain == NULL) { - tpPolicyError("tpCompareIChatHandleName: bad incoming handle (3)"); - CFRelease(iChatName); - return false; - } - /* subsequent errors to errOut: */ - - /* get subject name in CSSM form, all subsequent ops work on that */ - crtn = cert.fetchField(&CSSMOID_X509V1SubjectNameCStruct, &subjNameData); - if(crtn) { - /* should never happen, we shouldn't be here if there is no subject */ - tpPolicyError("tpCompareIChatHandleName: error retrieving subject name"); - goto errOut; - } - - x509name = (CSSM_X509_NAME_PTR)subjNameData->Data; - if((x509name == NULL) || (subjNameData->Length != sizeof(CSSM_X509_NAME))) { - tpPolicyError("tpCompareIChatHandleName: malformed CSSM_X509_NAME"); - goto errOut; - } - - /* Now grunge thru the X509 name looking for three fields */ - - for(rdnDex=0; rdnDexnumberOfRDNs; rdnDex++) { - rdnp = &x509name->RelativeDistinguishedName[rdnDex]; - for(pairDex=0; pairDexnumberOfPairs; pairDex++) { - ptvp = &rdnp->AttributeTypeAndValue[pairDex]; - if(!commonNameMatch && - tpCompareOids(&ptvp->type, &CSSMOID_CommonName) && - tpCompareTvpToCfString(ptvp, iChatName, kCFCompareCaseInsensitive)) { - commonNameMatch = CSSM_TRUE; - } - - if(!orgUnitMatch && - tpCompareOids(&ptvp->type, &CSSMOID_OrganizationalUnitName) && - tpCompareTvpToCfString(ptvp, iChatDomain, kCFCompareCaseInsensitive)) { - orgUnitMatch = CSSM_TRUE; - } - - if(!orgMatch && - tpCompareOids(&ptvp->type, &CSSMOID_OrganizationName) && - /* this one is case sensitive */ - (tpCompareTvpToCfString(ptvp, CFSTR("Apple Computer, Inc."), 0) || - tpCompareTvpToCfString(ptvp, CFSTR("Apple Inc."), 0))) { - orgMatch = CSSM_TRUE; - } - - if(commonNameMatch && orgUnitMatch && orgMatch) { - /* TA DA */ - ourRtn = true; - goto errOut; - } - } - } -errOut: - cert.freeField(&CSSMOID_X509V1SubjectNameCStruct, subjNameData); - CFRelease(iChatName); - CFRelease(iChatDomain); - return ourRtn; -} - -/* - * 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( - TPPolicy policy, - TPCertGroup &certGroup, - const CSSM_DATA *sslFieldOpts, - const iSignCertInfo *certInfo) // all certs, size certGroup.numCerts() -{ - const iSignCertInfo &leafCertInfo = certInfo[0]; - CSSM_APPLE_TP_SSL_OPTIONS *sslOpts = NULL; - unsigned hostNameLen = 0; - const char *serverName = NULL; - TPCertInfo *leaf = certGroup.certAtIndex(0); - assert(leaf != NULL); - - /* CSSM_APPLE_TP_SSL_OPTIONS is optional */ - if((sslFieldOpts != NULL) && (sslFieldOpts->Data != NULL)) { - 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; - } - hostNameLen = sslOpts->ServerNameLen; - serverName = sslOpts->ServerName; - } - - /* host name check is optional */ - if(hostNameLen != 0) { - if(serverName == NULL) { - return CSSMERR_TP_INVALID_POINTER; - } - - /* convert caller's hostname string to lower case */ - char *hostName = (char *)certGroup.alloc().malloc(hostNameLen); - memmove(hostName, serverName, hostNameLen); - tpToLower(hostName, hostNameLen); - - CSSM_BOOL match = CSSM_FALSE; - - /* First check subjectAltName... */ - bool dnsNameFound = false; - bool dummy; - match = tpCompareSubjectAltName(leafCertInfo.subjectAltName, - hostName, hostNameLen, - SAN_HostName, false, 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, false, hostName, hostNameLen, - fieldFound); - } - - /* - * Limit allowed domains for specific anchors - */ - CSSM_BOOL domainMatch = CSSM_TRUE; - if(match) { - TPCertInfo *tpCert = certGroup.lastCert(); - if (tpCert) { - const CSSM_DATA *certData = tpCert->itemData(); - unsigned char digest[CC_SHA1_DIGEST_LENGTH]; - CC_SHA1(certData->Data, (CC_LONG)certData->Length, digest); - if (!memcmp(digest, kAppleCorpCASHA1, sizeof(digest))) { - const char *dnlist[] = { "apple.com", "icloud.com" }; - unsigned int idx, dncount=2; - domainMatch = CSSM_FALSE; - for(idx=0;idxaddStatusCode(CSSMERR_APPLETP_HOSTNAME_MISMATCH)) { - return CSSMERR_APPLETP_HOSTNAME_MISMATCH; - } - } - if(!domainMatch) { - if(leaf->addStatusCode(CSSMERR_APPLETP_CA_PIN_MISMATCH)) { - return CSSMERR_APPLETP_CA_PIN_MISMATCH; - } - } - } - - /* - * Ensure that, if an extendedKeyUsage extension is present in the - * leaf, that either anyExtendedKeyUsage or the appropriate - * CSSMOID_{Server,Client}Auth, or a SeverGatedCrypto usage is present. - */ - const iSignExtenInfo &ekuInfo = leafCertInfo.extendKeyUsage; - if(ekuInfo.present) { - bool foundGoodEku = false; - bool isServer = true; - CE_ExtendedKeyUsage *eku = (CE_ExtendedKeyUsage *)ekuInfo.extnData; - assert(eku != NULL); - - /* - * Determine appropriate extended key usage; default is SSL server - */ - const CSSM_OID *extUse = &CSSMOID_ServerAuth; - if((sslOpts != NULL) && /* optional, default server side */ - (sslOpts->Version > 0) && /* this was added in struct version 1 */ - (sslOpts->Flags & CSSM_APPLE_TP_SSL_CLIENT)) { - extUse = &CSSMOID_ClientAuth; - isServer = false; - } - - /* search for that one or for "any" indicator */ - for(unsigned i=0; inumPurposes; i++) { - const CSSM_OID *purpose = &eku->purposes[i]; - if(tpCompareOids(purpose, extUse)) { - foundGoodEku = true; - break; - } - if(tpCompareOids(purpose, &CSSMOID_ExtendedKeyUsageAny)) { - foundGoodEku = true; - break; - } - if((policy == kTP_IPSec) && (tpCompareOids(purpose, &CSSMOID_EKU_IPSec))) { - foundGoodEku = true; - break; - } - if(isServer) { - /* server gated crypto: server side only */ - if(tpCompareOids(purpose, &CSSMOID_NetscapeSGC)) { - foundGoodEku = true; - break; - } - if(tpCompareOids(purpose, &CSSMOID_MicrosoftSGC)) { - foundGoodEku = true; - break; - } - } - } - if(!foundGoodEku) { - if(leaf->addStatusCode(CSSMERR_APPLETP_SSL_BAD_EXT_KEY_USE)) { - return CSSMERR_TP_VERIFY_ACTION_FAILED; - } - } - } - - /* - * Check for additional options flag (2nd lowest bit set) which indicates - * we must be issued by an Apple intermediate with a particular extension. - * (This flag is set by SecPolicyCreateAppleSSLService in SecPolicy.cpp.) - */ - if((sslOpts != NULL) && - (sslOpts->Version > 0) && /* this was added in struct version 1 */ - (sslOpts->Flags & 0x00000002)) { - - if (certGroup.numCerts() > 1) { - const iSignCertInfo *isCertInfo = &certInfo[1]; - if (!(isCertInfo->foundAppleServerAuthMarker == CSSM_TRUE)) { - TPCertInfo *tpCert = certGroup.certAtIndex(1); - tpCert->addStatusCode(CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION); - return CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION; - } - } - else { - /* we only have the leaf? */ - if(leaf->addStatusCode(CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION)) { - return CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION; - } - } - } - return CSSM_OK; -} - -/* - * Verify SMIME and iChat options. - * This deals with both S/MIME and iChat policies; within the iChat domain it - * deals with Apple-specific .mac certs as well as what we call "generic AIM" - * certs, as used in the Windows AIM client. - */ -#define CE_CIPHER_MASK (~(CE_KU_EncipherOnly | CE_KU_DecipherOnly)) - -static CSSM_RETURN tp_verifySmimeOpts( - TPPolicy policy, - TPCertGroup &certGroup, - const CSSM_DATA *smimeFieldOpts, - const iSignCertInfo *certInfo) // all certs, size certGroup.numCerts() -{ - const iSignCertInfo &leafCertInfo = certInfo[0]; - bool iChat = (policy == kTP_iChat) ? true : false; - /* - * The CSSM_APPLE_TP_SMIME_OPTIONS pointer is optional as is everything in it. - */ - 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, a.k.a. handle for iChat policy */ - unsigned emailLen = 0; - if(smimeOpts != NULL) { - emailLen = smimeOpts->SenderEmailLen; - } - - bool match = false; - bool emailFoundInSAN = false; - bool iChatHandleFound = false; /* indicates a genuine Apple iChat cert */ - bool emailFoundInDN = false; - if(emailLen != 0) { - if(smimeOpts->SenderEmail == NULL) { - return CSSMERR_TP_INVALID_POINTER; - } - - /* iChat - first try the Apple custom format */ - if(iChat) { - iChatHandleFound = tpCompareIChatHandleName(*leaf, smimeOpts->SenderEmail, - emailLen); - if(iChatHandleFound) { - match = true; - } - - } - - if(!match) { - /* - * normalize caller's email string - * SMIME - lowercase only the portion after '@' - * iChat - lowercase all of it - */ - char *email = (char *)certGroup.alloc().malloc(emailLen); - memmove(email, smimeOpts->SenderEmail, emailLen); - tpNormalizeAddrSpec(email, emailLen, iChat); - - - /* - * 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, iChat, dummy, emailFoundInSAN); - - /* - * Then subject DN, CSSMOID_EmailAddress, if no match from - * subjectAltName. In this case the whole email address is - * case insensitive (RFC 3280, section 4.1.2.6), so - * renormalize. - */ - if(!match) { - tpNormalizeAddrSpec(email, emailLen, true); - match = tpCompareSubjectName(*leaf, SN_Email, true, email, emailLen, - emailFoundInDN); - } - certGroup.alloc().free(email); - - /* - * Error here if no match found but there was indeed *some* - * email address in the cert. - */ - if(!match && (emailFoundInSAN || emailFoundInDN)) { - if(leaf->addStatusCode(CSSMERR_APPLETP_SMIME_EMAIL_ADDRS_NOT_FOUND)) { - tpPolicyError("SMIME email addrs in cert but no match"); - return CSSMERR_APPLETP_SMIME_EMAIL_ADDRS_NOT_FOUND; - } - } - } - - /* - * iChat only: error if app specified email address but there was - * none in the cert. - */ - if(iChat && !emailFoundInSAN && !emailFoundInDN && !iChatHandleFound) { - if(leaf->addStatusCode(CSSMERR_APPLETP_SMIME_NO_EMAIL_ADDRS)) { - tpPolicyError("iChat: no email address or handle in cert"); - return CSSMERR_APPLETP_SMIME_NO_EMAIL_ADDRS; - } - } - } - - /* - * 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; - const iSignExtenInfo &kuInfo = leafCertInfo.keyUsage; - const iSignExtenInfo &ekuInfo = leafCertInfo.extendKeyUsage; - const CSSM_X509_NAME *x509Name = NULL; - - if(iChat) { - /* empty subject name processing is S/MIME only */ - goto checkEku; - } - - 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 */ - - 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, false, dummy, - emailFoundInSAN); // the variable we're updating - } - if(!emailFoundInSAN) { - tpPolicyError("SMIME policy fail: empty subject name and " - "no Email Addrs in SubjectAltName"); - if(leaf->addStatusCode(CSSMERR_APPLETP_SMIME_NO_EMAIL_ADDRS)) { - leaf->freeField(&CSSMOID_X509V1SubjectNameCStruct, subjNameData); - return CSSMERR_TP_VERIFY_ACTION_FAILED; - } - else { - /* have to skip the next block */ - goto postSAN; - } - } - - /* - * 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"); - if(leaf->addStatusCode(CSSMERR_APPLETP_SMIME_SUBJ_ALT_NAME_NOT_CRIT)) { - leaf->freeField(&CSSMOID_X509V1SubjectNameCStruct, subjNameData); - return CSSMERR_TP_VERIFY_ACTION_FAILED; - } - } - } -postSAN: - 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.... - */ - if(kuInfo.present && (smimeOpts != NULL)) { - 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); - if(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"); - if(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"); - if(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"); - if(leaf->addStatusCode(CSSMERR_APPLETP_SMIME_BAD_KEY_USE)) { - return CSSMERR_TP_VERIFY_ACTION_FAILED; - } - } - } - } - - /* - * Extended Key Use verification, which is different for the two policies. - */ -checkEku: - if(iChat && !ekuInfo.present) { - /* - * iChat: whether generic AIM cert or Apple .mac/iChat cert, we must have an - * extended key use extension. - */ - tpPolicyError("iChat: No extended Key Use"); - if(leaf->addStatusCode(CSSMERR_APPLETP_SMIME_BAD_EXT_KEY_USE)) { - return CSSMERR_APPLETP_SMIME_BAD_EXT_KEY_USE; - } - } - - if(!iChatHandleFound) { - /* - * S/MIME and generic AIM certs when evaluating iChat policy. - * Look for either emailProtection or anyExtendedKeyUsage usages. - * - * S/MIME : the whole extension is optional. - * iChat : extension must be there (which we've already covered, above) - * and we must find one of those extensions. - */ - if(ekuInfo.present) { - bool foundGoodEku = false; - CE_ExtendedKeyUsage *eku = (CE_ExtendedKeyUsage *)ekuInfo.extnData; - assert(eku != NULL); - for(unsigned i=0; inumPurposes; i++) { - if(tpCompareOids(&eku->purposes[i], &CSSMOID_EmailProtection)) { - foundGoodEku = true; - break; - } - if(tpCompareOids(&eku->purposes[i], &CSSMOID_ExtendedKeyUsageAny)) { - foundGoodEku = true; - break; - } - } - if(!foundGoodEku) { - tpPolicyError("iChat/SMIME: No appropriate extended Key Use"); - if(leaf->addStatusCode(CSSMERR_APPLETP_SMIME_BAD_EXT_KEY_USE)) { - return CSSMERR_APPLETP_SMIME_BAD_EXT_KEY_USE; - } - } - } - } - else { - /* - * Apple iChat cert. Look for anyExtendedKeyUsage, iChatSigning, - * ichatEncrypting - the latter of two which can optionally be - * required by app. - */ - assert(iChat); /* or we could not have even looked for an iChat style handle */ - assert(ekuInfo.present); /* checked above */ - bool foundAnyEku = false; - bool foundIChatSign = false; - bool foundISignEncrypt = false; - CE_ExtendedKeyUsage *eku = (CE_ExtendedKeyUsage *)ekuInfo.extnData; - assert(eku != NULL); - - for(unsigned i=0; inumPurposes; i++) { - if(tpCompareOids(&eku->purposes[i], - &CSSMOID_APPLE_EKU_ICHAT_SIGNING)) { - foundIChatSign = true; - } - else if(tpCompareOids(&eku->purposes[i], - &CSSMOID_APPLE_EKU_ICHAT_ENCRYPTION)) { - foundISignEncrypt = true; - } - else if(tpCompareOids(&eku->purposes[i], &CSSMOID_ExtendedKeyUsageAny)) { - foundAnyEku = true; - } - } - - if(!foundAnyEku && !foundISignEncrypt && !foundIChatSign) { - /* No go - no acceptable uses found */ - tpPolicyError("iChat: No valid extended Key Uses found"); - if(leaf->addStatusCode(CSSMERR_APPLETP_SMIME_BAD_EXT_KEY_USE)) { - return CSSMERR_APPLETP_SMIME_BAD_EXT_KEY_USE; - } - } - - /* check for specifically required uses */ - if((smimeOpts != NULL) && (smimeOpts->IntendedUsage != 0)) { - if(smimeOpts->IntendedUsage & CE_KU_DigitalSignature) { - if(!foundIChatSign) { - tpPolicyError("iChat: ICHAT_SIGNING required, but missing"); - if(leaf->addStatusCode(CSSMERR_APPLETP_SMIME_BAD_EXT_KEY_USE)) { - return CSSMERR_APPLETP_SMIME_BAD_EXT_KEY_USE; - } - } - } - if(smimeOpts->IntendedUsage & CE_KU_DataEncipherment) { - if(!foundISignEncrypt) { - tpPolicyError("iChat: ICHAT_ENCRYPT required, but missing"); - if(leaf->addStatusCode(CSSMERR_APPLETP_SMIME_BAD_EXT_KEY_USE)) { - return CSSMERR_APPLETP_SMIME_BAD_EXT_KEY_USE; - } - } - } - } /* checking IntendedUsage */ - } /* iChat cert format */ - - return CSSM_OK; -} - -/* - * Verify Apple SW Update signing (was Apple Code Signing, pre-Leopard) options. - * - * -- Must have one intermediate cert - * -- intermediate must have basic constraints with path length 0 - * -- intermediate has CSSMOID_APPLE_EKU_CODE_SIGNING EKU - * -- leaf cert has either CODE_SIGNING or CODE_SIGN_DEVELOPMENT EKU (the latter of - * which triggers a CSSMERR_APPLETP_CODE_SIGN_DEVELOPMENT error) - */ -static CSSM_RETURN tp_verifySWUpdateSigningOpts( - TPCertGroup &certGroup, - const CSSM_DATA *fieldOpts, // currently unused - const iSignCertInfo *certInfo) // all certs, size certGroup.numCerts() -{ - unsigned numCerts = certGroup.numCerts(); - const iSignCertInfo *isCertInfo; - TPCertInfo *tpCert; -// const CE_BasicConstraints *bc; // currently unused - CE_ExtendedKeyUsage *eku; - CSSM_RETURN crtn = CSSM_OK; - - if(numCerts != 3) { - if(!certGroup.isAllowedError(CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH)) { - tpPolicyError("tp_verifySWUpdateSigningOpts: numCerts %u", numCerts); - return CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH; - } - else if(numCerts < 3) { - /* this error allowed, but no intermediate...check leaf */ - goto checkLeaf; - } - } - - /* verify intermediate cert */ - isCertInfo = &certInfo[1]; - tpCert = certGroup.certAtIndex(1); - - if(!isCertInfo->basicConstraints.present) { - tpPolicyError("tp_verifySWUpdateSigningOpts: no basicConstraints in intermediate"); - if(tpCert->addStatusCode(CSSMERR_APPLETP_CS_NO_BASIC_CONSTRAINTS)) { - return CSSMERR_APPLETP_CS_NO_BASIC_CONSTRAINTS; - } - } - - /* ExtendedKeyUse required, one legal value */ - if(!isCertInfo->extendKeyUsage.present) { - tpPolicyError("tp_verifySWUpdateSigningOpts: no extendedKeyUse in intermediate"); - if(tpCert->addStatusCode(CSSMERR_APPLETP_CS_NO_EXTENDED_KEY_USAGE)) { - return CSSMERR_APPLETP_CS_NO_EXTENDED_KEY_USAGE; - } - else { - goto checkLeaf; - } - } - - eku = &isCertInfo->extendKeyUsage.extnData->extendedKeyUsage; - assert(eku != NULL); - if(eku->numPurposes != 1) { - tpPolicyError("tp_verifySWUpdateSigningOpts: bad eku->numPurposes in intermediate (%lu)", - (unsigned long)eku->numPurposes); - if(tpCert->addStatusCode(CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE)) { - return CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE; - } - else if(eku->numPurposes == 0) { - /* ignore that error but no EKU - skip EKU check */ - goto checkLeaf; - } - /* else ignore error and we have an intermediate EKU; proceed */ - } - - if(!tpCompareOids(&eku->purposes[0], &CSSMOID_APPLE_EKU_CODE_SIGNING)) { - tpPolicyError("tp_verifySWUpdateSigningOpts: bad EKU"); - if(tpCert->addStatusCode(CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE)) { - crtn = CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE; - } - } - -checkLeaf: - - /* verify leaf cert */ - isCertInfo = &certInfo[0]; - tpCert = certGroup.certAtIndex(0); - if(!isCertInfo->extendKeyUsage.present) { - tpPolicyError("tp_verifySWUpdateSigningOpts: no extendedKeyUse in leaf"); - if(tpCert->addStatusCode(CSSMERR_APPLETP_CS_NO_EXTENDED_KEY_USAGE)) { - return crtn ? crtn : CSSMERR_APPLETP_CS_NO_EXTENDED_KEY_USAGE; - } - else { - /* have to skip remainder */ - return CSSM_OK; - } - } - - eku = &isCertInfo->extendKeyUsage.extnData->extendedKeyUsage; - assert(eku != NULL); - if(eku->numPurposes != 1) { - tpPolicyError("tp_verifySWUpdateSigningOpts: bad eku->numPurposes (%lu)", - (unsigned long)eku->numPurposes); - if(tpCert->addStatusCode(CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE)) { - if(crtn == CSSM_OK) { - crtn = CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE; - } - } - return crtn; - } - if(!tpCompareOids(&eku->purposes[0], &CSSMOID_APPLE_EKU_CODE_SIGNING)) { - if(tpCompareOids(&eku->purposes[0], &CSSMOID_APPLE_EKU_CODE_SIGNING_DEV)) { - tpPolicyError("tp_verifySWUpdateSigningOpts: DEVELOPMENT cert"); - if(tpCert->addStatusCode(CSSMERR_APPLETP_CODE_SIGN_DEVELOPMENT)) { - if(crtn == CSSM_OK) { - crtn = CSSMERR_APPLETP_CODE_SIGN_DEVELOPMENT; - } - } - } - else { - tpPolicyError("tp_verifySWUpdateSigningOpts: bad EKU in leaf"); - if(tpCert->addStatusCode(CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE)) { - if(crtn == CSSM_OK) { - crtn = CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE; - } - } - } - } - - return crtn; -} - -/* - * Verify Apple Resource Signing options. - * - * -- leaf cert must have CSSMOID_APPLE_EKU_RESOURCE_SIGNING EKU - * -- chain length must be >= 2 - * -- mainline code already verified that leaf KeyUsage = digitalSignature (only) - */ -static CSSM_RETURN tp_verifyResourceSigningOpts( - TPCertGroup &certGroup, - const CSSM_DATA *fieldOpts, // currently unused - const iSignCertInfo *certInfo) // all certs, size certGroup.numCerts() -{ - unsigned numCerts = certGroup.numCerts(); - if(numCerts < 2) { - if(!certGroup.isAllowedError(CSSMERR_APPLETP_RS_BAD_CERT_CHAIN_LENGTH)) { - tpPolicyError("tp_verifyResourceSigningOpts: numCerts %u", numCerts); - return CSSMERR_APPLETP_RS_BAD_CERT_CHAIN_LENGTH; - } - } - const iSignCertInfo &leafCert = certInfo[0]; - TPCertInfo *leaf = certGroup.certAtIndex(0); - - /* leaf ExtendedKeyUse required, one legal value */ - if(!tpVerifyEKU(leafCert, CSSMOID_APPLE_EKU_RESOURCE_SIGNING, false)) { - tpPolicyError("tp_verifyResourceSigningOpts: no RESOURCE_SIGNING EKU"); - if(leaf->addStatusCode(CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE)) { - return CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE; - } - } - - return CSSM_OK; -} - -/* - * Common code for Apple Code Signing and Apple Package Signing. - * For now we just require an RFC3280-style CodeSigning EKU in the leaf - * for both policies. - */ -static CSSM_RETURN tp_verifyCodePkgSignOpts( - TPPolicy policy, - TPCertGroup &certGroup, - const CSSM_DATA *fieldOpts, // currently unused - const iSignCertInfo *certInfo) // all certs, size certGroup.numCerts() -{ - const iSignCertInfo &leafCert = certInfo[0]; - - /* leaf ExtendedKeyUse required, one legal value */ - if(!tpVerifyEKU(leafCert, CSSMOID_ExtendedUseCodeSigning, false)) { - TPCertInfo *leaf = certGroup.certAtIndex(0); - tpPolicyError("tp_verifyCodePkgSignOpts: no CodeSigning EKU"); - if(leaf->addStatusCode(CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE)) { - return CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE; - } - } - - return CSSM_OK; - -} - -/* - * Verify MacAppStore receipt verification policy options. - * - * -- Must have one intermediate cert - * -- intermediate must be the FairPlay intermediate - * -- leaf cert has the CSSMOID_APPLE_EXTENSION_MACAPPSTORE_RECEIPT marker extension - */ -static CSSM_RETURN tp_verifyMacAppStoreReceiptOpts( - TPCertGroup &certGroup, - const CSSM_DATA *fieldOpts, // currently unused - const iSignCertInfo *certInfo) // all certs, size certGroup.numCerts() -{ - unsigned numCerts = certGroup.numCerts(); - if (numCerts < 3) - { - if (!certGroup.isAllowedError(CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH)) - { - tpPolicyError("tp_verifyMacAppStoreReceiptOpts: numCerts %u", numCerts); - return CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH; - } - } - - const iSignCertInfo *isCertInfo; - TPCertInfo *tpCert; - - /* verify intermediate cert */ - isCertInfo = &certInfo[1]; - tpCert = certGroup.certAtIndex(1); - - if (!isCertInfo->basicConstraints.present) - { - tpPolicyError("tp_verifyAppleIDSharingOpts: no basicConstraints in intermediate"); - if (tpCert->addStatusCode(CSSMERR_APPLETP_CS_NO_BASIC_CONSTRAINTS)) - return CSSMERR_APPLETP_CS_NO_BASIC_CONSTRAINTS; - } - - // Now check the leaf - isCertInfo = &certInfo[0]; - tpCert = certGroup.certAtIndex(0); - if (certInfo->certificatePolicies.present) - { - // syslog(LOG_ERR, "tp_verifyMacAppStoreReceiptOpts: found certificatePolicies"); - const CE_CertPolicies *certPolicies = - &isCertInfo->certificatePolicies.extnData->certPolicies; - if (!certificatePoliciesContainsOID(certPolicies, &CSSMOID_MACAPPSTORE_RECEIPT_CERT_POLICY)) - if (tpCert->addStatusCode(CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION)) - return CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION; - } - else - { - // syslog(LOG_ERR, "tp_verifyMacAppStoreReceiptOpts: no certificatePolicies present"); // DEBUG - tpPolicyError("tp_verifyMacAppStoreReceiptOpts: no certificatePolicies present in leaf"); - if (tpCert->addStatusCode(CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION)) - return CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION; - } - - return CSSM_OK; -} - -bool certificatePoliciesContainsOID(const CE_CertPolicies *certPolicies, const CSSM_OID *oidToFind) -{ - // returns true if the given OID is present in the cert policies - - if (!certPolicies || !oidToFind) - return false; - - const uint32 maxIndex = 100; // sanity check - for (uint32 policyIndex = 0; policyIndex < certPolicies->numPolicies && policyIndex < maxIndex; policyIndex++) - { - CE_PolicyInformation *certPolicyInfo = &certPolicies->policies[policyIndex]; - CSSM_OID_PTR oid = &certPolicyInfo->certPolicyId; - if (oid && tpCompareOids(oid, oidToFind)) // found it - return true; - } - - return false; -} - - -/* - * Verify Apple ID Sharing options. - * - * -- Do basic cert validation (OCSP-based certs) - * -- Validate that the cert is an Apple ID sharing cert: - * has a custom extension: OID: Apple ID Sharing Certificate ( 1 2 840 113635 100 4 7 ) - * (CSSMOID_APPLE_EXTENSION_APPLEID_SHARING) - * EKU should have both client and server authentication - * chains to the "Apple Application Integration Certification Authority" intermediate - * -- optionally has a client-specified common name, which is the Apple ID account's UUID. - - * -- Must have one intermediate cert ("Apple Application Integration Certification Authority") - * -- intermediate must have basic constraints with path length 0 - * -- intermediate has CSSMOID_APPLE_EXTENSION_AAI_INTERMEDIATE extension (OID 1 2 840 113635 100 6 2 3) - OR APPLE_EXTENSION_AAI_INTERMEDIATE_2 - */ - -static CSSM_RETURN tp_verifyAppleIDSharingOpts(TPCertGroup &certGroup, - const CSSM_DATA *fieldOpts, // optional Common Name - const iSignCertInfo *certInfo) // all certs, size certGroup.numCerts() -{ - unsigned numCerts = certGroup.numCerts(); - const iSignCertInfo *isCertInfo; - TPCertInfo *tpCert; - // const CE_BasicConstraints *bc; // currently unused - CE_ExtendedKeyUsage *eku; - CSSM_RETURN crtn = CSSM_OK; - unsigned int serverNameLen = 0; - const char *serverName = NULL; - - // The CSSM_APPLE_TP_SMIME_OPTIONS pointer is optional as is everything in it. - if (fieldOpts && fieldOpts->Data) - { - CSSM_APPLE_TP_SSL_OPTIONS *sslOpts = (CSSM_APPLE_TP_SSL_OPTIONS *)fieldOpts->Data; - switch (sslOpts->Version) - { - case CSSM_APPLE_TP_SSL_OPTS_VERSION: - if (fieldOpts->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; - } - serverNameLen = sslOpts->ServerNameLen; - serverName = sslOpts->ServerName; - } - - //------------------------------------------------------------------------ - - if (numCerts != 3) - { - if (!certGroup.isAllowedError(CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH)) - { - tpPolicyError("tp_verifyAppleIDSharingOpts: numCerts %u", numCerts); - return CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH; - } - else - if (numCerts < 3) - { - /* this error allowed, but no intermediate...check leaf */ - goto checkLeaf; - } - } - - /* verify intermediate cert */ - isCertInfo = &certInfo[1]; - tpCert = certGroup.certAtIndex(1); - - if (!isCertInfo->basicConstraints.present) - { - tpPolicyError("tp_verifyAppleIDSharingOpts: no basicConstraints in intermediate"); - if (tpCert->addStatusCode(CSSMERR_APPLETP_CS_NO_BASIC_CONSTRAINTS)) - return CSSMERR_APPLETP_CS_NO_BASIC_CONSTRAINTS; - } - -checkLeaf: - - /* verify leaf cert */ - isCertInfo = &certInfo[0]; - tpCert = certGroup.certAtIndex(0); - - /* host name check is optional */ - if (serverNameLen != 0) - { - if (serverName == NULL) - return CSSMERR_TP_INVALID_POINTER; - - /* convert caller's hostname string to lower case */ - char *hostName = (char *)certGroup.alloc().malloc(serverNameLen); - memmove(hostName, serverName, serverNameLen); - tpToLower(hostName, serverNameLen); - - /* Check common name... */ - - bool fieldFound; - CSSM_BOOL match = tpCompareSubjectName(*tpCert, SN_CommonName, false, hostName, - serverNameLen, fieldFound); - - certGroup.alloc().free(hostName); - if (!match && tpCert->addStatusCode(CSSMERR_APPLETP_HOSTNAME_MISMATCH)) - return CSSMERR_APPLETP_HOSTNAME_MISMATCH; - } - - if (certInfo->certificatePolicies.present) - { - const CE_CertPolicies *certPolicies = - &isCertInfo->certificatePolicies.extnData->certPolicies; - if (!certificatePoliciesContainsOID(certPolicies, &CSSMOID_APPLEID_SHARING_CERT_POLICY)) - if (tpCert->addStatusCode(CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION)) - return CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION; - } - else - if (tpCert->addStatusCode(CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION)) - return CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION; - - if (!isCertInfo->extendKeyUsage.present) - { - tpPolicyError("tp_verifyAppleIDSharingOpts: no extendedKeyUse in leaf"); - if (tpCert->addStatusCode(CSSMERR_APPLETP_CS_NO_EXTENDED_KEY_USAGE)) - return crtn ? crtn : CSSMERR_APPLETP_CS_NO_EXTENDED_KEY_USAGE; - - /* have to skip remainder */ - return CSSM_OK; - } - - // Check that certificate can do Client and Server Authentication (EKU) - eku = &isCertInfo->extendKeyUsage.extnData->extendedKeyUsage; - assert(eku != NULL); - if(eku->numPurposes != 2) - { - tpPolicyError("tp_verifyAppleIDSharingOpts: bad eku->numPurposes (%lu)", - (unsigned long)eku->numPurposes); - if (tpCert->addStatusCode(CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE)) - { - if (crtn == CSSM_OK) - crtn = CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE; - } - return crtn; - } - bool canDoClientAuth = false, canDoServerAuth = false, ekuError = false; - for (int ix=0;ix<2;ix++) - { - if (tpCompareOids(&eku->purposes[ix], &CSSMOID_ClientAuth)) - canDoClientAuth = true; - else - if (tpCompareOids(&eku->purposes[ix], &CSSMOID_ServerAuth)) - canDoServerAuth = true; - else - { - ekuError = true; - break; - } - } - - if (!(canDoClientAuth && canDoServerAuth)) - ekuError = true; - if (ekuError) - { - tpPolicyError("tp_verifyAppleIDSharingOpts: bad EKU in leaf"); - if (tpCert->addStatusCode(CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE)) - { - if (crtn == CSSM_OK) - crtn = CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE; - } - } - - return crtn; -} - -/* - * Verify Time Stamping (RFC3161) policy options. - * - * -- Leaf must contain Extended Key Usage (EKU), marked critical - * -- The EKU must contain the id-kp-timeStamping purpose and no other - */ -static CSSM_RETURN tp_verifyTimeStampingOpts(TPCertGroup &certGroup, - const CSSM_DATA *fieldOpts, // currently unused - const iSignCertInfo *certInfo) // all certs, size certGroup.numCerts() -{ - //unsigned numCerts = certGroup.numCerts(); - const iSignCertInfo *isCertInfo; - TPCertInfo *tpCert; - CE_ExtendedKeyUsage *eku; - - isCertInfo = &certInfo[0]; - tpCert = certGroup.certAtIndex(0); - - if (!isCertInfo->extendKeyUsage.present) - { - tpPolicyError("tp_verifyTimeStampingOpts: no extendedKeyUse in leaf"); - tpCert->addStatusCode(CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION); - return CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION; - } - - if(!isCertInfo->extendKeyUsage.critical) - { - tpPolicyError("tp_verifyTimeStampingOpts: extended key usage !critical"); - tpCert->addStatusCode(CSSMERR_APPLETP_EXT_KEYUSAGE_NOT_CRITICAL); - return CSSMERR_APPLETP_EXT_KEYUSAGE_NOT_CRITICAL; - } - - eku = &isCertInfo->extendKeyUsage.extnData->extendedKeyUsage; - assert(eku != NULL); - - if(eku->numPurposes != 1) - { - tpPolicyError("tp_verifyTimeStampingOpts: bad eku->numPurposes (%lu)", - (unsigned long)eku->numPurposes); - tpCert->addStatusCode(CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE); - return CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE; - } - - if(!tpCompareOids(&eku->purposes[0], &CSSMOID_TimeStamping)) - { - tpPolicyError("tp_verifyTimeStampingOpts: TimeStamping purpose not found"); - tpCert->addStatusCode(CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE); - return CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE; - } - - return CSSM_OK; -} - -/* - * Verify Passbook Signing policy options. - * - * -- Do basic cert validation (OCSP-based certs) - * -- Chains to the Apple root CA - * -- Has custom marker extension (1.2.840.113635.100.6.1.16) - * (CSSMOID_APPLE_EXTENSION_PASSBOOK_SIGNING) - * -- EKU contains Passbook Signing purpose (1.2.840.113635.100.4.14) - * (CSSMOID_APPLE_EKU_PASSBOOK_SIGNING) - * -- UID field of Subject must contain provided card signer string - * -- OU field of Subject must contain provided team identifier string - */ -static CSSM_RETURN tp_verifyPassbookSigningOpts(TPCertGroup &certGroup, - const CSSM_DATA *fieldOpts, - const iSignCertInfo *certInfo) // all certs, size certGroup.numCerts() -{ - unsigned numCerts = certGroup.numCerts(); - const iSignCertInfo *isCertInfo; - TPCertInfo *tpCert; - CE_ExtendedKeyUsage *eku; - CSSM_RETURN crtn = CSSM_OK; - unsigned int nameLen = 0; - const char *name = NULL; - char *p, *signerName = NULL, *teamIdentifier = NULL; - bool found; - - isCertInfo = &certInfo[0]; - tpCert = certGroup.certAtIndex(0); - - /* The CSSM_APPLE_TP_SMIME_OPTIONS pointer is required. */ - if (!fieldOpts || !fieldOpts->Data) - return CSSMERR_TP_INVALID_POLICY_IDENTIFIERS; - else { - CSSM_APPLE_TP_SMIME_OPTIONS *opts = (CSSM_APPLE_TP_SMIME_OPTIONS *)fieldOpts->Data; - switch (opts->Version) - { - case CSSM_APPLE_TP_SMIME_OPTS_VERSION: - if (fieldOpts->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; - } - nameLen = opts->SenderEmailLen; - name = opts->SenderEmail; - if (!name || !nameLen) - return CSSMERR_APPLETP_IDENTIFIER_MISSING; - } - - /* Split the provided name into signer name and team identifier - * (allocates memory, which must be freed at end) */ - signerName = (char *)certGroup.alloc().malloc(nameLen); - teamIdentifier = (char *)certGroup.alloc().malloc(nameLen); - memmove(signerName, name, nameLen); - teamIdentifier[0] = '\0'; - if ((p = strchr(signerName, '\t')) != NULL) { - *p++ = '\0'; - memmove(teamIdentifier, p, strlen(p)+1); - } - - /* Check signer name in UID field */ - if (CSSM_FALSE == tpCompareSubjectName(*tpCert, - SN_UserID, false, signerName, (unsigned int)strlen(signerName), found)) { - tpPolicyError("tp_verifyPassbookSigningOpts: signer name not in subject UID field"); - tpCert->addStatusCode(CSSMERR_APPLETP_IDENTIFIER_MISSING); - crtn = CSSMERR_APPLETP_IDENTIFIER_MISSING; - goto cleanup; - } - - /* Check team identifier in OU field */ - if (CSSM_FALSE == tpCompareSubjectName(*tpCert, - SN_OrgUnit, false, teamIdentifier, (unsigned int)strlen(teamIdentifier), found)) { - tpPolicyError("tp_verifyPassbookSigningOpts: team identifier not in subject OU field"); - tpCert->addStatusCode(CSSMERR_APPLETP_IDENTIFIER_MISSING); - crtn = CSSMERR_APPLETP_IDENTIFIER_MISSING; - goto cleanup; - } - - /* Check that EKU extension is present */ - if (!isCertInfo->extendKeyUsage.present) { - tpPolicyError("tp_verifyPassbookSigningOpts: no extendedKeyUse in leaf"); - tpCert->addStatusCode(CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION); - crtn = CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION; - goto cleanup; - } - - /* Check that EKU contains Passbook Signing purpose */ - eku = &isCertInfo->extendKeyUsage.extnData->extendedKeyUsage; - assert(eku != NULL); - found = false; - for (int ix=0;ixnumPurposes;ix++) { - if (tpCompareOids(&eku->purposes[ix], &CSSMOID_APPLE_EKU_PASSBOOK_SIGNING)) { - found = true; - break; - } - } - if (!found) { - tpPolicyError("tp_verifyPassbookSigningOpts: Passbook Signing purpose not found"); - tpCert->addStatusCode(CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE); - crtn = CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE; - goto cleanup; - } - - /* Check that Passbook Signing marker extension is present */ - if (!(isCertInfo->foundPassbookSigning == CSSM_TRUE)) { - tpPolicyError("tp_verifyPassbookSigningOpts: no Passbook Signing extension in leaf"); - tpCert->addStatusCode(CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION); - crtn = CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION; - goto cleanup; - } - - /* Check that cert chain is anchored by the Apple Root CA */ - if (numCerts < 3) { - tpPolicyError("tp_verifyPassbookSigningOpts: numCerts %u", numCerts); - crtn = CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH; - goto cleanup; - } - else { - tpCert = certGroup.certAtIndex(numCerts-1); - const CSSM_DATA *certData = tpCert->itemData(); - unsigned char digest[CC_SHA1_DIGEST_LENGTH]; - CC_SHA1(certData->Data, (CC_LONG)certData->Length, digest); - if (memcmp(digest, kAppleCASHA1, sizeof(digest))) { - tpPolicyError("tp_verifyPassbookSigningOpts: invalid anchor for policy"); - tpCert->addStatusCode(CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH); - crtn = CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH; - goto cleanup; - } - } - -cleanup: - if (signerName) - certGroup.alloc().free(signerName); - if (teamIdentifier) - certGroup.alloc().free(teamIdentifier); - - return crtn; -} - -/* - * Verify Mobile Store policy options. - * - * -- Do basic cert validation. - * -- Chain length must be exactly 3. - * -- Must chain to known Mobile Store root. - * -- Intermediate must have CSSMOID_APPLE_EXTENSION_SYSINT2_INTERMEDIATE marker - * (1.2.840.113635.100.6.2.10) - * -- Key usage in leaf certificate must be Digital Signature. - * -- Leaf has certificatePolicies extension with appropriate policy: - * (1.2.840.113635.100.5.12) if testPolicy is false - * (1.2.840.113635.100.5.12.1) if testPolicy is true - */ -static CSSM_RETURN tp_verifyMobileStoreSigningOpts(TPCertGroup &certGroup, - const CSSM_DATA *fieldOpts, - const iSignCertInfo *certInfo, // all certs, size certGroup.numCerts() - bool testPolicy) -{ - unsigned numCerts = certGroup.numCerts(); - const iSignCertInfo *isCertInfo; - TPCertInfo *tpCert; - CE_KeyUsage ku; - CSSM_RETURN crtn = CSSM_OK; - - isCertInfo = &certInfo[0]; - tpCert = certGroup.certAtIndex(0); - - /* Check that KU extension is present */ - if (!isCertInfo->keyUsage.present) { - tpPolicyError("tp_verifyMobileStoreSigningOpts: no keyUsage in leaf"); - tpCert->addStatusCode(CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION); - crtn = CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION; - goto cleanup; - } - - /* Check that KU contains Digital Signature usage */ - ku = isCertInfo->keyUsage.extnData->keyUsage; - if (!(ku & CE_KU_DigitalSignature)) { - tpPolicyError("tp_verifyMobileStoreSigningOpts: DigitalSignature usage not found"); - tpCert->addStatusCode(CSSMERR_APPLETP_INVALID_KEY_USAGE); - crtn = CSSMERR_APPLETP_INVALID_KEY_USAGE; - goto cleanup; - } - - /* Check that Mobile Store Signing certicate policy is present in leaf */ - if (isCertInfo->certificatePolicies.present) - { - const CE_CertPolicies *certPolicies = - &isCertInfo->certificatePolicies.extnData->certPolicies; - const CSSM_OID *policyOID = (testPolicy) ? - &CSSMOID_TEST_MOBILE_STORE_SIGNING_POLICY : - &CSSMOID_MOBILE_STORE_SIGNING_POLICY; - if (!certificatePoliciesContainsOID(certPolicies, policyOID)) - if (tpCert->addStatusCode(CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION)) - return CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION; - } - else - { - tpPolicyError("tp_verifyMobileStoreSigningOpts: no certificatePolicies present in leaf"); - if (tpCert->addStatusCode(CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION)) - return CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION; - } - - /* Check that cert chain length is 3 */ - if (numCerts != 3) { - tpPolicyError("tp_verifyMobileStoreSigningOpts: numCerts %u", numCerts); - crtn = CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH; - goto cleanup; - } - - /* Check that cert chain is anchored by a known root */ - { - tpCert = certGroup.certAtIndex(numCerts-1); - const CSSM_DATA *certData = tpCert->itemData(); - unsigned char digest[CC_SHA1_DIGEST_LENGTH]; - CC_SHA1(certData->Data, (CC_LONG)certData->Length, digest); - if (memcmp(digest, kMobileRootSHA1, sizeof(digest))) { - tpPolicyError("tp_verifyMobileStoreSigningOpts: invalid anchor for policy"); - tpCert->addStatusCode(CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH); - crtn = CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH; - goto cleanup; - } - } - - /* Check that Apple System Integration 2 marker extension is present in intermediate */ - isCertInfo = &certInfo[1]; - tpCert = certGroup.certAtIndex(1); - if (!(isCertInfo->foundAppleSysInt2Marker == CSSM_TRUE)) { - tpPolicyError("tp_verifyMobileStoreSigningOpts: intermediate marker extension not found"); - tpCert->addStatusCode(CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION); - crtn = CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION; - goto cleanup; - } - -cleanup: - return crtn; -} - -/* - * Verify Escrow Service policy options. - * - * -- Chain length must be exactly 2. - * -- Must be issued by known escrow root. - * -- Key usage in leaf certificate must be Key Encipherment. - * -- Leaf has CSSMOID_APPLE_EXTENSION_ESCROW_SERVICE_MARKER extension - * (1.2.840.113635.100.6.23.1) - */ -static CSSM_RETURN tp_verifyEscrowServiceCommon(TPCertGroup &certGroup, - const CSSM_DATA *fieldOpts, - const iSignCertInfo *certInfo, // all certs, size certGroup.numCerts() - SecCertificateEscrowRootType rootType) -{ - unsigned numCerts = certGroup.numCerts(); - const iSignCertInfo *isCertInfo; - TPCertInfo *tpCert; - CE_KeyUsage ku; - CSSM_RETURN crtn = CSSM_OK; - - isCertInfo = &certInfo[0]; - tpCert = certGroup.certAtIndex(0); - - /* Check that KU extension is present */ - if (!isCertInfo->keyUsage.present) { - tpPolicyError("tp_verifyEscrowServiceCommon: no keyUsage in leaf"); - tpCert->addStatusCode(CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION); - crtn = CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION; - goto cleanup; - } - - /* Check that KU contains Key Encipherment usage */ - ku = isCertInfo->keyUsage.extnData->keyUsage; - if (!(ku & CE_KU_KeyEncipherment)) { - tpPolicyError("tp_verifyEscrowServiceCommon: KeyEncipherment usage not found"); - tpCert->addStatusCode(CSSMERR_APPLETP_INVALID_KEY_USAGE); - crtn = CSSMERR_APPLETP_INVALID_KEY_USAGE; - goto cleanup; - } - - /* Check that Escrow Service marker extension is present */ - if (!(isCertInfo->foundEscrowServiceMarker == CSSM_TRUE)) { - tpPolicyError("tp_verifyEscrowServiceCommon: no Escrow Service extension in leaf"); - tpCert->addStatusCode(CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION); - crtn = CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION; - goto cleanup; - } - - /* Check that cert chain length is 2 */ - if (numCerts != 2) { - tpPolicyError("tp_verifyEscrowServiceCommon: numCerts %u", numCerts); - crtn = CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH; - goto cleanup; - } - - /* Check that cert chain is anchored by a known root */ - { - tpCert = certGroup.certAtIndex(numCerts-1); - const CSSM_DATA *certData = tpCert->itemData(); - bool anchorMatch = false; - SecCertificateRef anchor = NULL; - OSStatus status = SecCertificateCreateFromData(certData, CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER, &anchor); - if (!status) { - CFArrayRef anchors = SecCertificateCopyEscrowRoots(rootType); - CFIndex idx, count = (anchors) ? CFArrayGetCount(anchors) : 0; - for (idx = 0; idx < count; idx++) { - SecCertificateRef cert = (SecCertificateRef) CFArrayGetValueAtIndex(anchors, idx); - if (cert && CFEqual(cert, anchor)) { - anchorMatch = true; - break; - } - } - if (anchors) - CFRelease(anchors); - } - if (anchor) - CFRelease(anchor); - - if (!anchorMatch) { - tpPolicyError("tp_verifyEscrowServiceCommon: invalid anchor for policy"); - tpCert->addStatusCode(CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH); - crtn = CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH; - goto cleanup; - } - } - -cleanup: - return crtn; -} - -static CSSM_RETURN tp_verifyEscrowServiceSigningOpts(TPCertGroup &certGroup, - const CSSM_DATA *fieldOpts, - const iSignCertInfo *certInfo) // all certs, size certGroup.numCerts() -{ - return tp_verifyEscrowServiceCommon(certGroup, fieldOpts, certInfo, kSecCertificateProductionEscrowRoot); -} - -static CSSM_RETURN tp_verifyPCSEscrowServiceSigningOpts(TPCertGroup &certGroup, - const CSSM_DATA *fieldOpts, - const iSignCertInfo *certInfo) // all certs, size certGroup.numCerts() -{ - return tp_verifyEscrowServiceCommon(certGroup, fieldOpts, certInfo, kSecCertificateProductionPCSEscrowRoot); -} - -/* - * Verify Configuration Profile Signing policy options. - * - * -- Do basic cert validation (OCSP-based certs) - * -- Chains to the Apple root CA - * -- Leaf has EKU extension with appropriate purpose: - * (1.2.840.113635.100.4.16) if testPolicy is false - * (1.2.840.113635.100.4.17) if testPolicy is true - */ -static CSSM_RETURN tp_verifyProfileSigningOpts(TPCertGroup &certGroup, - const CSSM_DATA *fieldOpts, - const iSignCertInfo *certInfo, // all certs, size certGroup.numCerts() - bool testPolicy) -{ - unsigned numCerts = certGroup.numCerts(); - const iSignCertInfo *isCertInfo; - TPCertInfo *tpCert; - CE_ExtendedKeyUsage *eku; - CSSM_RETURN crtn = CSSM_OK; - bool found; - - isCertInfo = &certInfo[0]; - tpCert = certGroup.certAtIndex(0); - - /* Check that EKU extension is present */ - if (!isCertInfo->extendKeyUsage.present) { - tpPolicyError("tp_verifyProfileSigningOpts: no extendedKeyUse in leaf"); - tpCert->addStatusCode(CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION); - crtn = CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION; - goto cleanup; - } - - /* Check that EKU contains appropriate Profile Signing purpose */ - eku = &isCertInfo->extendKeyUsage.extnData->extendedKeyUsage; - assert(eku != NULL); - found = false; - for (int ix=0;ixnumPurposes;ix++) { - if (tpCompareOids(&eku->purposes[ix], (testPolicy) ? - &CSSMOID_APPLE_EKU_QA_PROFILE_SIGNING : - &CSSMOID_APPLE_EKU_PROFILE_SIGNING)) { - found = true; - break; - } - } - if (!found) { - tpPolicyError("tp_verifyProfileSigningOpts: Profile Signing purpose not found"); - tpCert->addStatusCode(CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE); - crtn = CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE; - goto cleanup; - } - - /* Check that cert chain is anchored by the Apple Root CA */ - if (numCerts < 3) { - tpPolicyError("tp_verifyProfileSigningOpts: numCerts %u", numCerts); - crtn = CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH; - goto cleanup; - } - else { - tpCert = certGroup.certAtIndex(numCerts-1); - const CSSM_DATA *certData = tpCert->itemData(); - unsigned char digest[CC_SHA1_DIGEST_LENGTH]; - CC_SHA1(certData->Data, (CC_LONG)certData->Length, digest); - if (memcmp(digest, kAppleCASHA1, sizeof(digest))) { - tpPolicyError("tp_verifyProfileSigningOpts: invalid anchor for policy"); - tpCert->addStatusCode(CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH); - crtn = CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH; - goto cleanup; - } - } - -cleanup: - return crtn; -} - -/* - * 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 name "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_OK on success. - * Assumes 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, - Allocator &alloc, - CSSM_CL_HANDLE clHand, - CSSM_CSP_HANDLE cspHand, - TPCertGroup *certGroup, - CSSM_BOOL verifiedToRoot, // last cert is good root - CSSM_BOOL verifiedViaTrustSetting, // last cert verified via - // user trust - 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_KEY_PTR pubKey; - CSSM_RETURN outErr = CSSM_OK; // for gross, non-policy errors - CSSM_BOOL policyFail = CSSM_FALSE;// generic CSSMERR_TP_VERIFY_ACTION_FAILED - CSSM_RETURN policyError = CSSM_OK; // policy-specific failure - - /* 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; certDexcertAtIndex(certDex), - &certInfo[certDex])) { - (certGroup->certAtIndex(certDex))->addStatusCode( - CSSMERR_TP_INVALID_CERTIFICATE); - /* this one is fatal (and can't ignore) */ - outErr = CSSMERR_TP_INVALID_CERTIFICATE; - goto errOut; - } - } - - /* - * OK, the heart of TP enforcement. - */ - for(certDex=0; certDexcertAtIndex(certDex); - - /* - * First check for presence of required extensions and - * critical extensions we don't understand. - */ - if(thisCertInfo->foundUnknownCritical) { - /* illegal for all policies */ - tpPolicyError("tp_policyVerify: critical flag in unknown extension"); - if(thisTpCertInfo->addStatusCode(CSSMERR_APPLETP_UNKNOWN_CRITICAL_EXTEN)) { - policyFail = CSSM_TRUE; - } - } - - /* - * Check for unsupported key length, per - */ - if((pubKey=thisTpCertInfo->pubKey()) != NULL) { - CSSM_KEYHEADER *keyHdr = &pubKey->KeyHeader; - if(keyHdr->AlgorithmId == CSSM_ALGID_RSA && keyHdr->LogicalKeySizeInBits < 1024) { - tpPolicyError("tp_policyVerify: RSA key size too small"); - if(thisTpCertInfo->addStatusCode(CSSMERR_CSP_UNSUPPORTED_KEY_SIZE)) { - policyFail = CSSM_TRUE; - } - } - } - - /* - * Note it's possible for both of these to be true, for a chain - * of length one (kTPx509Basic, kCrlPolicy only!) - * FIXME: should this code work if the last cert in the chain is NOT a root? - */ - isLeaf = thisTpCertInfo->isLeaf(); - isRoot = thisTpCertInfo->isSelfSigned(true); - - /* - * 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). - * all others: 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) { - default: - /* - * 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"); - if(thisTpCertInfo->addStatusCode( - CSSMERR_APPLETP_NO_BASIC_CONSTRAINTS)) { - policyFail = CSSM_TRUE; - } - break; - } - } - } /* inferred a default value */ - 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"); - if(thisTpCertInfo->addStatusCode(CSSMERR_TP_VERIFY_ACTION_FAILED)) { - policyFail = CSSM_TRUE; - } - } - #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"); - if(thisTpCertInfo->addStatusCode( - CSSMERR_APPLETP_PATH_LEN_CONSTRAINT)) { - policyFail = CSSM_TRUE; - } - } - } - } - - 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"); - if(thisTpCertInfo->addStatusCode(CSSMERR_APPLETP_INVALID_CA)) { - policyFail = CSSM_TRUE; - } - } - } else if(!cA) { - tpPolicyError("tp_policyVerify: cA false for non-leaf"); - if(thisTpCertInfo->addStatusCode(CSSMERR_APPLETP_INVALID_CA)) { - policyFail = CSSM_TRUE; - } - } - - /* - * Authority Key Identifier optional - * iSign : only allowed in !root. - * If present, must not be critical. - * all others : ignored (though used later for chain verification) - */ - if((policy == kTPiSign) && thisCertInfo->authorityId.present) { - if(isRoot) { - tpPolicyError("tp_policyVerify: authorityId in root"); - if(thisTpCertInfo->addStatusCode(CSSMERR_APPLETP_INVALID_AUTHORITY_ID)) { - policyFail = CSSM_TRUE; - } - } - if(thisCertInfo->authorityId.critical) { - /* illegal per RFC 2459 */ - tpPolicyError("tp_policyVerify: authorityId marked " - "critical"); - if(thisTpCertInfo->addStatusCode(CSSMERR_APPLETP_INVALID_AUTHORITY_ID)) { - policyFail = CSSM_TRUE; - } - } - } - - /* - * Subject Key Identifier optional - * iSign : can't be critical. - * all others : ignored (though used later for chain verification) - */ - if(thisCertInfo->subjectId.present) { - if((policy == kTPiSign) && thisCertInfo->subjectId.critical) { - tpPolicyError("tp_policyVerify: subjectId marked critical"); - if(thisTpCertInfo->addStatusCode(CSSMERR_APPLETP_INVALID_SUBJECT_ID)) { - policyFail = CSSM_TRUE; - } - } - } - - /* - * Key Usage optional except required as noted - * 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 - * kCrlPolicy : Leaf: usage = CRLSign - * kTP_SMIME : if present, must be critical - * kTP_SWUpdateSign, kTP_ResourceSign, kTP_CodeSigning, kTP_PackageSigning : Leaf : - usage = digitalSignature - * all others : non-leaf : usage = keyCertSign - * Leaf : don't care - */ - if(thisCertInfo->keyUsage.present) { - /* - * Leaf cert: - * iSign and *Signing: usage = digitalSignature - * all others : don't care - * Others: usage = keyCertSign - * We only require that one bit to be set, we ignore others. - */ - if(isLeaf) { - switch(policy) { - case kTPiSign: - case kTP_SWUpdateSign: - case kTP_ResourceSign: - case kTP_CodeSigning: - case kTP_PackageSigning: - expUsage = CE_KU_DigitalSignature; - break; - case kCrlPolicy: - /* if present, this bit must be set */ - expUsage = CE_KU_CRLSign; - break; - default: - /* accept whatever's there */ - expUsage = thisCertInfo->keyUsage.extnData->keyUsage; - break; - } - } - else { - /* !leaf: 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); - if(thisTpCertInfo->addStatusCode(CSSMERR_APPLETP_INVALID_KEY_USAGE)) { - policyFail = CSSM_TRUE; - } - } - - #if 0 - /* - * Radar 3523221 renders this whole check obsolete, but I'm leaving - * the code here to document its conspicuous functional absence. - */ - 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"); - if(thisTpCertInfo->addStatusCode( - CSSMERR_APPLETP_SMIME_KEYUSAGE_NOT_CRITICAL)) { - policyFail = CSSM_TRUE; - } - } - } - #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"); - if(thisTpCertInfo->addStatusCode(CSSMERR_APPLETP_INVALID_KEY_USAGE)) { - policyFail = CSSM_TRUE; - } - } - } - else if(!isRoot) { - tpPolicyError("tp_policyVerify: !isRoot, no keyUsage, " - "!(leaf and netscapeCertType)"); - if(thisTpCertInfo->addStatusCode(CSSMERR_APPLETP_INVALID_KEY_USAGE)) { - policyFail = CSSM_TRUE; - } - } - } - - /* - * RFC 3280, 4.1.2.6, says that an empty subject name can only appear in a - * leaf cert, and only if subjectAltName is present and marked critical. - */ - if(isLeaf && thisTpCertInfo->hasEmptySubjectName()) { - bool badEmptySubject = false; - if(actionFlags & CSSM_TP_ACTION_LEAF_IS_CA) { - /* - * True when evaluating a CA cert as well as when - * evaluating a CRL's cert chain. Note the odd case of a CRL's - * signer having an empty subject matching an empty issuer - * in the CRL. That'll be caught here. - */ - badEmptySubject = true; - } - else if(!thisCertInfo->subjectAltName.present || /* no subjectAltName */ - !thisCertInfo->subjectAltName.critical) { /* not critical */ - badEmptySubject = true; - } - if(badEmptySubject) { - tpPolicyError("tp_policyVerify: bad empty subject"); - if(thisTpCertInfo->addStatusCode(CSSMERR_APPLETP_INVALID_EMPTY_SUBJECT)) { - policyFail = CSSM_TRUE; - } - } - } - - /* - * RFC 3739: if this cert has a Qualified Cert Statements extension, and - * it's Critical, make sure we understand all of the extension's statementIds. - */ - if(thisCertInfo->qualCertStatements.present && - thisCertInfo->qualCertStatements.critical) { - CE_QC_Statements *qcss = - &thisCertInfo->qualCertStatements.extnData->qualifiedCertStatements; - uint32 numQcs = qcss->numQCStatements; - for(unsigned qdex=0; qdexqcStatements[qdex].statementId; - bool ok = false; - for(unsigned kdex=0; kdexaddStatusCode(CSSMERR_APPLETP_UNKNOWN_QUAL_CERT_STATEMENT)) { - policyFail = CSSM_TRUE; - break; - } - } - } - } /* critical Qualified Cert Statement */ - - /* - * Certificate Policies extension validation, per section 1.2 of: - * http://iase.disa.mil/pki/dod_cp_v10_final_2_mar_09_signed.pdf - */ - if (tpVerifyCPE(*thisCertInfo, CSSMOID_PIV_AUTH, false) || - tpVerifyCPE(*thisCertInfo, CSSMOID_PIV_AUTH_2048, false)) { - /* - * Certificate asserts one of the PIV-Auth Certificate Policy OIDs; - * check the required Key Usage extension for compliance. - * - * Leaf cert: - * usage = digitalSignature (only; no other bits asserted) - * Others: - * usage = keyCertSign (required; other bits ignored) - */ - if(thisCertInfo->keyUsage.present) { - actUsage = thisCertInfo->keyUsage.extnData->keyUsage; - } else { - /* No key usage! Policy fail. */ - actUsage = 0; - } - if(!(actionFlags & CSSM_TP_ACTION_LEAF_IS_CA) && (certDex == 0)) { - expUsage = CE_KU_DigitalSignature; - } else { - expUsage = actUsage | CE_KU_KeyCertSign; - } - if(!(actUsage == expUsage)) { - tpPolicyError("tp_policyVerify: bad keyUsage for PIV-Auth policy (leaf %s; " - "usage 0x%x)", - (certDex == 0) ? "TRUE" : "FALSE", actUsage); - if(thisTpCertInfo->addStatusCode(CSSMERR_APPLETP_INVALID_KEY_USAGE)) { - policyFail = CSSM_TRUE; - } - } - } /* Certificate Policies */ - - - } /* 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); - if((certGroup->certAtIndex(0))->addStatusCode( - CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE)) { - policyFail = CSSM_TRUE; - } - } - if(!tpCompareOids(extendUsage->purposes, - &CSSMOID_ExtendedUseCodeSigning)) { - tpPolicyError("tp_policyVerify: bad extendKeyUsage"); - if((certGroup->certAtIndex(0))->addStatusCode( - CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE)) { - policyFail = CSSM_TRUE; - } - } - } - - /* - * 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"); - if((certGroup->certAtIndex(certDex))->addStatusCode( - CSSMERR_APPLETP_INVALID_ID_LINKAGE)) { - policyFail = CSSM_TRUE; - } - } - } - - /* - * Check signature algorithm on all non-root certs, - * reject if known to be untrusted - */ - for(certDex=0; certDex<(numCerts-1); certDex++) { - if(certInfo[certDex].untrustedSigAlg) { - tpPolicyError("tp_policyVerify: untrusted signature algorithm"); - if((certGroup->certAtIndex(certDex))->addStatusCode( - CSSMERR_TP_INVALID_CERTIFICATE)) { - policyFail = CSSM_TRUE; - } - } - } - - /* specific per-policy checking */ - switch(policy) { - case kTP_SSL: - case kTP_EAP: - case kTP_IPSec: - /* - * SSL, EAP, IPSec: optionally verify common name; all are identical - * other than their names. - * FIXME - should this be before or after the root cert test? How can - * we return both errors? - */ - policyError = tp_verifySslOpts(policy, *certGroup, policyFieldData, certInfo); - break; - - case kTP_iChat: - tpDebug("iChat policy"); - /* fall thru */ - case kTP_SMIME: - policyError = tp_verifySmimeOpts(policy, *certGroup, policyFieldData, certInfo); - break; - case kTP_SWUpdateSign: - policyError = tp_verifySWUpdateSigningOpts(*certGroup, policyFieldData, certInfo); - break; - case kTP_ResourceSign: - policyError = tp_verifyResourceSigningOpts(*certGroup, policyFieldData, certInfo); - break; - case kTP_CodeSigning: - case kTP_PackageSigning: - policyError = tp_verifyCodePkgSignOpts(policy, *certGroup, policyFieldData, certInfo); - break; - case kTP_MacAppStoreRec: - policyError = tp_verifyMacAppStoreReceiptOpts(*certGroup, policyFieldData, certInfo); - break; - case kTP_AppleIDSharing: - policyError = tp_verifyAppleIDSharingOpts(*certGroup, policyFieldData, certInfo); - break; - case kTP_TimeStamping: - policyError = tp_verifyTimeStampingOpts(*certGroup, policyFieldData, certInfo); - break; - case kTP_PassbookSigning: - policyError = tp_verifyPassbookSigningOpts(*certGroup, policyFieldData, certInfo); - break; - case kTP_MobileStore: - policyError = tp_verifyMobileStoreSigningOpts(*certGroup, policyFieldData, certInfo, false); - break; - case kTP_TestMobileStore: - policyError = tp_verifyMobileStoreSigningOpts(*certGroup, policyFieldData, certInfo, true); - break; - case kTP_EscrowService: - policyError = tp_verifyEscrowServiceSigningOpts(*certGroup, policyFieldData, certInfo); - break; - case kTP_ProfileSigning: - policyError = tp_verifyProfileSigningOpts(*certGroup, policyFieldData, certInfo, false); - break; - case kTP_QAProfileSigning: - policyError = tp_verifyProfileSigningOpts(*certGroup, policyFieldData, certInfo, true); - break; - case kTP_PCSEscrowService: - policyError = tp_verifyPCSEscrowServiceSigningOpts(*certGroup, policyFieldData, certInfo); - break; - case kTPx509Basic: - case kTPiSign: - case kCrlPolicy: - case kTP_PKINIT_Client: - default: - break; - - } - - if(outErr == CSSM_OK) { - /* policy-specific error takes precedence here */ - if(policyError != CSSM_OK) { - outErr = policyError; - } - else if(policyFail) { - /* plain vanilla error return from this module */ - outErr = CSSMERR_TP_VERIFY_ACTION_FAILED; - } - } -errOut: - /* free resources */ - for(certDex=0; certDexData == NULL)) { - /* currently, no further action possible */ - return; - } - switch(policy) { - case kTP_SSL: - case kTP_EAP: - case kTP_IPSec: - { - if(policyData->Length != sizeof(CSSM_APPLE_TP_SSL_OPTIONS)) { - /* this error will be caught later */ - return; - } - CSSM_APPLE_TP_SSL_OPTIONS *sslOpts = - (CSSM_APPLE_TP_SSL_OPTIONS *)policyData->Data; - *policyStr = sslOpts->ServerName; - *policyStrLen = sslOpts->ServerNameLen; - if(sslOpts->Flags & CSSM_APPLE_TP_SSL_CLIENT) { - /* - * Client signs with its priv key. Server end, - * which (also) verifies the client cert, verifies. - */ - *keyUse = kSecTrustSettingsKeyUseSignature; - } - else { - /* server decrypts */ - *keyUse = kSecTrustSettingsKeyUseEnDecryptKey; - } - return; - } - - case kTP_iChat: - case kTP_SMIME: - { - if(policyData->Length != sizeof(CSSM_APPLE_TP_SMIME_OPTIONS)) { - /* this error will be caught later */ - return; - } - CSSM_APPLE_TP_SMIME_OPTIONS *smimeOpts = - (CSSM_APPLE_TP_SMIME_OPTIONS *)policyData->Data; - *policyStr = smimeOpts->SenderEmail; - *policyStrLen = smimeOpts->SenderEmailLen; - SecTrustSettingsKeyUsage ku = 0; - CE_KeyUsage smimeKu = smimeOpts->IntendedUsage; - if(smimeKu & (CE_KU_DigitalSignature | CE_KU_KeyCertSign | CE_KU_CRLSign)) { - ku |= kSecTrustSettingsKeyUseSignature; - } - if(smimeKu & (CE_KU_KeyEncipherment | CE_KU_DataEncipherment)) { - ku |= kSecTrustSettingsKeyUseEnDecryptKey; - } - *keyUse = ku; - return; - } - - default: - /* no other options */ - return; - } -} - -#pragma clang diagnostic pop