+++ /dev/null
-/*
- * Copyright (c) 2000-2001,2011-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.
- */
-
-
-/*
- * tpCertGroup.cpp - Cert group functions (construct, verify)
- */
-
-#include "AppleTPSession.h"
-#include "certGroupUtils.h"
-#include "TPCertInfo.h"
-#include "TPCrlInfo.h"
-#include "tpCertAllowList.h"
-#include "tpPolicies.h"
-#include "tpdebugging.h"
-#include "tpCrlVerify.h"
-#include <Security/oidsalg.h>
-#include <Security/cssmapple.h>
-
-/*
- * This is a temporary hack to allow verification of PKINIT server certs
- * which are self-signed and not in the system anchors list. If the self-
- * signed cert is in a magic keychain (whose location is not published),
- * we'll allow it as if it were indeed a full-fledged anchor cert.
- */
-#define TP_PKINIT_SERVER_HACK 1
-#if TP_PKINIT_SERVER_HACK
-
-#include <Security/SecKeychain.h>
-#include <Security/SecKeychainSearch.h>
-#include <Security/SecCertificate.h>
-#include <Security/oidscert.h>
-#include <sys/types.h>
-#include <pwd.h>
-
-#define CFRELEASE(cf) if(cf) { CFRelease(cf); }
-
-/*
- * Returns true if we are to allow/trust the specified
- * cert as a PKINIT-only anchor.
- */
-static bool tpCheckPkinitServerCert(
- TPCertGroup &certGroup)
-{
- /*
- * Basic requirement: exactly one cert, self-signed.
- * The numCerts == 1 requirement might change...
- */
- unsigned numCerts = certGroup.numCerts();
- if(numCerts != 1) {
- tpDebug("tpCheckPkinitServerCert: too many certs");
- return false;
- }
- /* end of chain... */
- TPCertInfo *theCert = certGroup.certAtIndex(numCerts - 1);
- if(!theCert->isSelfSigned()) {
- tpDebug("tpCheckPkinitServerCert: 1 cert, not self-signed");
- return false;
- }
- const CSSM_DATA *subjectName = theCert->subjectName();
-
- /*
- * Open the magic keychain.
- * We're going up and over the Sec layer here, not generally
- * kosher, but this is a hack.
- */
- OSStatus ortn;
- SecKeychainRef kcRef = NULL;
- string fullPathName;
- const char *homeDir = getenv("HOME");
- if (homeDir == NULL)
- {
- // If $HOME is unset get the current user's home directory
- // from the passwd file.
- uid_t uid = geteuid();
- if (!uid) uid = getuid();
- struct passwd *pw = getpwuid(uid);
- if (!pw) {
- return false;
- }
- homeDir = pw->pw_dir;
- }
- fullPathName = homeDir;
- fullPathName += "/Library/Application Support/PKINIT/TrustedServers.keychain";
- ortn = SecKeychainOpen(fullPathName.c_str(), &kcRef);
- if(ortn) {
- tpDebug("tpCheckPkinitServerCert: keychain not found (1)");
- return false;
- }
- /* subsequent errors to errOut: */
-
- bool ourRtn = false;
- SecKeychainStatus kcStatus;
- CSSM_DATA_PTR subjSerial = NULL;
- CSSM_RETURN crtn;
- SecKeychainSearchRef srchRef = NULL;
- SecKeychainAttributeList attrList;
- SecKeychainAttribute attrs[2];
- SecKeychainItemRef foundItem = NULL;
-
- ortn = SecKeychainGetStatus(kcRef, &kcStatus);
- if(ortn) {
- tpDebug("tpCheckPkinitServerCert: keychain not found (2)");
- goto errOut;
- }
-
- /*
- * We already have this cert's normalized name; get its
- * serial number.
- */
- crtn = theCert->fetchField(&CSSMOID_X509V1SerialNumber, &subjSerial);
- if(crtn) {
- /* should never happen */
- tpDebug("tpCheckPkinitServerCert: error fetching serial number");
- goto errOut;
- }
-
- attrs[0].tag = kSecSubjectItemAttr;
- attrs[0].length = (UInt32)subjectName->Length;
- attrs[0].data = subjectName->Data;
- attrs[1].tag = kSecSerialNumberItemAttr;
- attrs[1].length = (UInt32)subjSerial->Length;
- attrs[1].data = subjSerial->Data;
- attrList.count = 2;
- attrList.attr = attrs;
-
- ortn = SecKeychainSearchCreateFromAttributes(kcRef,
- kSecCertificateItemClass,
- &attrList,
- &srchRef);
- if(ortn) {
- tpDebug("tpCheckPkinitServerCert: search failure");
- goto errOut;
- }
- for(;;) {
- ortn = SecKeychainSearchCopyNext(srchRef, &foundItem);
- if(ortn) {
- tpDebug("tpCheckPkinitServerCert: end search");
- break;
- }
-
- /* found a matching cert; do byte-for-byte compare */
- CSSM_DATA certData;
- ortn = SecCertificateGetData((SecCertificateRef)foundItem, &certData);
- if(ortn) {
- tpDebug("tpCheckPkinitServerCert: SecCertificateGetData failure");
- continue;
- }
- if(tpCompareCssmData(&certData, theCert->itemData())){
- tpDebug("tpCheckPkinitServerCert: FOUND CERT");
- ourRtn = true;
- break;
- }
- tpDebug("tpCheckPkinitServerCert: skipping matching cert");
- CFRelease(foundItem);
- foundItem = NULL;
- }
-errOut:
- CFRELEASE(kcRef);
- CFRELEASE(srchRef);
- CFRELEASE(foundItem);
- if(subjSerial != NULL) {
- theCert->freeField(&CSSMOID_X509V1SerialNumber, subjSerial);
- }
- return ourRtn;
-}
-#endif /* TP_PKINIT_SERVER_HACK */
-
-/*-----------------------------------------------------------------------------
- * CertGroupConstruct
- *
- * Description:
- * This function returns a pointer to a mallocd CSSM_CERTGROUP which
- * refers to a mallocd list of raw ordered X.509 certs which verify back as
- * far as the TP is able to go. The first cert of the returned list is the
- * subject cert. The TP will attempt to search thru the DBs passed in
- * DBList in order to complete the chain. The chain is completed when a
- * self-signed (root) cert is found in the chain. The root cert may be
- * present in the input CertGroupFrag, or it may have been obtained from
- * one of the DBs passed in DBList. It is not an error if no root cert is
- * found.
- *
- * The error conditions are:
- * -- The first cert of CertGroupFrag is an invalid cert. NULL is returned,
- * err = CSSM_TP_INVALID_CERTIFICATE.
- * -- The root cert (if found) fails to verify. Valid certgroup is returned,
- * err = CSSMERR_TP_VERIFICATION_FAILURE.
- * -- Any cert in the (possibly partially) constructed chain has expired or
- * isn't valid yet, err = CSSMERR_TP_CERT_EXPIRED or
- * CSSMERR_TP_CERT_NOT_VALID_YET. A CertGroup is returned.
- * -- CSSMERR_TP_CERT_EXPIRED and CSSMERR_TP_CERT_NOT_VALID_YET. If one of these
- * conditions obtains for the first (leaf) cert, the function throws this
- * error immediately and the outgoing cert group is empty. For subsequent certs,
- * the temporal validity of a cert is only tested AFTER a cert successfully
- * meets the cert chaining criteria (subject/issuer match and signature
- * verify). A cert in a chain with this error is not added to the outgoing
- * cert group.
- * -- the usual errors like bad handle or memory failure.
- *
- * Parameters:
- * Two handles - to an open CL and CSP. The CSP must be capable of
- * dealing with the signature algorithms used by the certs. The CL must be
- * an X.509-savvy CL.
- *
- * CertGroupFrag, an unordered array of raw X.509 certs in the form of a
- * CSSM_CERTGROUP_PTR. The first cert of this list is the subject cert
- * which is eventually to be verified. The other certs can be in any order
- * and may not even have any relevance to the cert chain being constructed.
- * They may also be invalid certs.
- *
- * DBList, a list of DB/DL handles which may contain certs necessary to
- * complete the desired cert chain. (Not currently implemented.)
- *
- *---------------------------------------------------------------------------*/
-
-/* public version */
-void AppleTPSession::CertGroupConstruct(CSSM_CL_HANDLE clHand,
- CSSM_CSP_HANDLE cspHand,
- const CSSM_DL_DB_LIST &DBList,
- const void *ConstructParams,
- const CSSM_CERTGROUP &CertGroupFrag,
- CSSM_CERTGROUP_PTR &CertGroup)
-{
- TPCertGroup outCertGroup(*this, TGO_Caller);
- TPCertGroup inCertGroup(CertGroupFrag,
- clHand,
- cspHand,
- *this,
- NULL, // cssmTimeStr
- true, // firstCertMustBeValid
- TGO_Group);
-
- /* set up for disposal of TPCertInfos created by CertGroupConstructPriv */
- TPCertGroup gatheredCerts(*this, TGO_Group);
-
- CSSM_RETURN constructReturn = CSSM_OK;
- CSSM_APPLE_TP_ACTION_FLAGS actionFlags = 0;
- CSSM_BOOL verifiedToRoot; // not used
- CSSM_BOOL verifiedToAnchor; // not used
- CSSM_BOOL verifiedViaTrustSetting; // not used
-
- try {
- CertGroupConstructPriv(clHand,
- cspHand,
- inCertGroup,
- &DBList,
- NULL, // cssmTimeStr
- /* no anchors */
- 0, NULL,
- actionFlags,
- /* no user trust */
- NULL, NULL, 0, 0,
- gatheredCerts,
- verifiedToRoot,
- verifiedToAnchor,
- verifiedViaTrustSetting,
- outCertGroup);
- }
- catch(const CssmError &cerr) {
- constructReturn = cerr.error;
- /* abort if no certs found */
- if(outCertGroup.numCerts() == 0) {
- CssmError::throwMe(constructReturn);
- }
- }
- CertGroup = outCertGroup.buildCssmCertGroup();
- /* caller of this function never gets evidence... */
- outCertGroup.freeDbRecords();
-
- if(constructReturn) {
- CssmError::throwMe(constructReturn);
- }
-}
-
-
-/*
- * Private version of CertGroupConstruct, used by CertGroupConstruct and
- * CertGroupVerify. Populates a TP-style TPCertGroup for further processing.
- * This only throws CSSM-style exceptions in the following cases:
- *
- * -- input parameter errors
- * -- the first (leaf) cert is bad (doesn't parse, expired, not valid yet).
- * -- root found but it doesn't self-verify
- *
- * All other cert-related errors simply result in the bad cert being ignored.
- * Other exceptions are gross system errors like malloc failure.
- */
-void AppleTPSession::CertGroupConstructPriv(CSSM_CL_HANDLE clHand,
- CSSM_CSP_HANDLE cspHand,
- TPCertGroup &inCertGroup,
- const CSSM_DL_DB_LIST *DBList, // optional here
- const char *cssmTimeStr, // optional
-
- /* trusted anchors, optional */
- /* FIXME - maybe this should be a TPCertGroup */
- uint32 numAnchorCerts,
- const CSSM_DATA *anchorCerts,
-
- /* CSSM_TP_ACTION_FETCH_CERT_FROM_NET, CSSM_TP_ACTION_TRUST_SETTINGS */
- CSSM_APPLE_TP_ACTION_FLAGS actionFlags,
-
- /* optional user trust parameters */
- const CSSM_OID *policyOid,
- const char *policyStr,
- uint32 policyStrLen,
- SecTrustSettingsKeyUsage keyUse,
-
- /*
- * Certs to be freed by caller (i.e., TPCertInfo which we allocate
- * as a result of using a cert from anchorCerts or dbList) are added
- * to this group.
- */
- TPCertGroup &certsToBeFreed,
-
- /* returned */
- CSSM_BOOL &verifiedToRoot, // end of chain self-verifies
- CSSM_BOOL &verifiedToAnchor, // end of chain in anchors
- CSSM_BOOL &verifiedViaTrustSetting, // chain ends per User Trust setting
- TPCertGroup &outCertGroup) // RETURNED
-{
- TPCertInfo *subjectCert; // the one we're working on
- CSSM_RETURN outErr = CSSM_OK;
-
- /* this'll be the first subject cert in the main loop */
- subjectCert = inCertGroup.certAtIndex(0);
-
- /* Append leaf cert to outCertGroup */
- outCertGroup.appendCert(subjectCert);
- subjectCert->isLeaf(true);
- subjectCert->isFromInputCerts(true);
- outCertGroup.setAllUnused();
- subjectCert->used(true);
-
- outErr = outCertGroup.buildCertGroup(
- *subjectCert,
- &inCertGroup,
- DBList,
- clHand,
- cspHand,
- cssmTimeStr,
- numAnchorCerts,
- anchorCerts,
- certsToBeFreed,
- &certsToBeFreed, // gatheredCerts to accumulate net/DB fetches
- CSSM_TRUE, // subjectIsInGroup - enables root check on
- // subject cert
- actionFlags,
- policyOid,
- policyStr,
- policyStrLen,
- keyUse,
-
- verifiedToRoot,
- verifiedToAnchor,
- verifiedViaTrustSetting);
- if(outErr) {
- CssmError::throwMe(outErr);
- }
-}
-
-/*
- * Map a policy OID to one of the standard (non-revocation) policies.
- * Returns true if it's a standard policy.
- */
-static bool checkPolicyOid(
- const CSSM_OID &oid,
- TPPolicy &tpPolicy) /* RETURNED */
-{
- if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_SSL)) {
- tpPolicy = kTP_SSL;
- return true;
- }
- else if(tpCompareOids(&oid, &CSSMOID_APPLE_X509_BASIC)) {
- tpPolicy = kTPx509Basic;
- return true;
- }
- else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_SMIME)) {
- tpPolicy = kTP_SMIME;
- return true;
- }
- else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_EAP)) {
- tpPolicy = kTP_EAP;
- return true;
- }
- else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_SW_UPDATE_SIGNING)) {
- /* note: this was CSSMOID_APPLE_TP_CODE_SIGN until 8/15/06 */
- tpPolicy = kTP_SWUpdateSign;
- return true;
- }
- else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_RESOURCE_SIGN)) {
- tpPolicy = kTP_ResourceSign;
- return true;
- }
- else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_IP_SEC)) {
- tpPolicy = kTP_IPSec;
- return true;
- }
- else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_ICHAT)) {
- tpPolicy = kTP_iChat;
- return true;
- }
- else if(tpCompareOids(&oid, &CSSMOID_APPLE_ISIGN)) {
- tpPolicy = kTPiSign;
- return true;
- }
- else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_PKINIT_CLIENT)) {
- tpPolicy = kTP_PKINIT_Client;
- return true;
- }
- else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_PKINIT_SERVER)) {
- tpPolicy = kTP_PKINIT_Server;
- return true;
- }
- else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_CODE_SIGNING)) {
- tpPolicy = kTP_CodeSigning;
- return true;
- }
- else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_PACKAGE_SIGNING)) {
- tpPolicy = kTP_PackageSigning;
- return true;
- }
- else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_MACAPPSTORE_RECEIPT)) {
- tpPolicy = kTP_MacAppStoreRec;
- return true;
- }
- else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_APPLEID_SHARING)) {
- tpPolicy = kTP_AppleIDSharing;
- return true;
- }
- else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_TIMESTAMPING)) {
- tpPolicy = kTP_TimeStamping;
- return true;
- }
- else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_PASSBOOK_SIGNING)) {
- tpPolicy = kTP_PassbookSigning;
- return true;
- }
- else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_MOBILE_STORE)) {
- tpPolicy = kTP_MobileStore;
- return true;
- }
- else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_TEST_MOBILE_STORE)) {
- tpPolicy = kTP_TestMobileStore;
- return true;
- }
- else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_ESCROW_SERVICE)) {
- tpPolicy = kTP_EscrowService;
- return true;
- }
- else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_PROFILE_SIGNING)) {
- tpPolicy = kTP_ProfileSigning;
- return true;
- }
- else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_QA_PROFILE_SIGNING)) {
- tpPolicy = kTP_QAProfileSigning;
- return true;
- }
- else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_PCS_ESCROW_SERVICE)) {
- tpPolicy = kTP_PCSEscrowService;
- return true;
- }
- return false;
-}
-
-/*-----------------------------------------------------------------------------
- * CertGroupVerify
- *
- * Description:
- * -- Construct a cert chain using TP_CertGroupConstruct.
- * -- Attempt to verify that cert chain against one of the known
- * good certs passed in AnchorCerts.
- * -- Optionally enforces additional policies (TBD) when verifying the cert chain.
- * -- Optionally returns the entire cert chain constructed in
- * TP_CertGroupConstruct and here, all the way to an anchor cert or as
- * far as we were able to go, in *Evidence.
- *
- * Parameters:
- * Two handles - to an open CL and CSP. The CSP must be capable of
- * dealing with the signature algorithms used by the certs. The CL must be
- * an X.509-savvy CL.
- *
- * RawCerts, an unordered array of raw certs in the form of a
- * CSSM_CERTGROUP_PTR. The first cert of this list is the subject cert
- * which is eventually to be verified. The other certs can be in any order
- * and may not even have any relevance to the cert chain being constructed.
- * They may also be invalid certs.
- *
- * DBList, a list of DB/DL handles which may contain certs necessary to
- * complete the desired cert chain. (Currently not implemented.)
- *
- * AnchorCerts, a list of known trusted certs.
- * NumberOfAnchorCerts, size of AnchorCerts array.
- *
- * PolicyIdentifiers, Optional policy OID. NULL indicates default
- * X.509 trust policy.
- *
- * Supported Policies:
- * CSSMOID_APPLE_ISIGN
- * CSSMOID_APPLE_X509_BASIC
- *
- * For both of these, the associated FieldValue must be {0, NULL},
- *
- * NumberOfPolicyIdentifiers, size of PolicyIdentifiers array, must be
- * zero or one.
- *
- * All other arguments must be zero/NULL.
- *
- * Returns:
- * CSSM_OK : cert chain verified all the way back to an AnchorCert.
- * CSSMERR_TP_INVALID_ANCHOR_CERT : In this case, the cert chain
- * was validated back to a self-signed (root) cert found in either
- * CertToBeVerified or in one of the DBs in DBList, but that root cert
- * was *NOT* found in the AnchorCert list.
- * CSSMERR_TP_NOT_TRUSTED: no root cert was found and no AnchorCert
- * verified the end of the constructed cert chain.
- * CSSMERR_TP_VERIFICATION_FAILURE: a root cert was found which does
- * not self-verify.
- * CSSMERR_TP_VERIFY_ACTION_FAILED: indicates a failure of the requested
- * policy action.
- * CSSMERR_TP_INVALID_CERTIFICATE: indicates a bad leaf cert.
- * CSSMERR_TP_INVALID_REQUEST_INPUTS : no incoming VerifyContext.
- * CSSMERR_TP_CERT_EXPIRED and CSSMERR_TP_CERT_NOT_VALID_YET: see comments
- * for CertGroupConstruct.
- * CSSMERR_TP_CERTIFICATE_CANT_OPERATE : issuer cert was found with a partial
- * public key, rendering full verification impossible.
- * CSSMERR_TP_INVALID_CERT_AUTHORITY : issuer cert was found with a partial
- * public key and which failed to perform subsequent signature
- * verification.
- *---------------------------------------------------------------------------*/
-
-void AppleTPSession::CertGroupVerify(CSSM_CL_HANDLE clHand,
- CSSM_CSP_HANDLE cspHand,
- const CSSM_CERTGROUP &CertGroupToBeVerified,
- const CSSM_TP_VERIFY_CONTEXT *VerifyContext,
- CSSM_TP_VERIFY_CONTEXT_RESULT_PTR VerifyContextResult)
-{
- CSSM_BOOL verifiedToRoot = CSSM_FALSE;
- CSSM_BOOL verifiedToAnchor = CSSM_FALSE;
- CSSM_BOOL verifiedViaTrustSetting = CSSM_FALSE;
- CSSM_RETURN constructReturn = CSSM_OK;
- CSSM_RETURN policyReturn = CSSM_OK;
- const CSSM_TP_CALLERAUTH_CONTEXT *cred;
- /* declare volatile as compiler workaround to avoid caching in CR4 */
- const CSSM_APPLE_TP_ACTION_DATA * volatile actionData = NULL;
- CSSM_TIMESTRING cssmTimeStr;
- CSSM_APPLE_TP_ACTION_FLAGS actionFlags = 0;
- CSSM_TP_STOP_ON tpStopOn = 0;
-
- /* keep track of whether we did policy checking; if not, we do defaults */
- bool didCertPolicy = false;
- bool didRevokePolicy = false;
-
- /* user trust parameters */
- CSSM_OID utNullPolicy = {0, NULL};
- const CSSM_OID *utPolicyOid = NULL;
- const char *utPolicyStr = NULL;
- uint32 utPolicyStrLen = 0;
- SecTrustSettingsKeyUsage utKeyUse = 0;
- bool utTrustSettingEnabled = false;
-
- if(VerifyContextResult) {
- memset(VerifyContextResult, 0, sizeof(*VerifyContextResult));
- }
-
- /* verify input args, skipping the ones checked by CertGroupConstruct */
- if((VerifyContext == NULL) || (VerifyContext->Cred == NULL)) {
- /* the spec says that this is optional but we require it */
- CssmError::throwMe(CSSMERR_TP_INVALID_REQUEST_INPUTS);
- }
- cred = VerifyContext->Cred;
-
- /* Optional ActionData affecting all policies */
- actionData = (CSSM_APPLE_TP_ACTION_DATA * volatile)VerifyContext->ActionData.Data;
- if(actionData != NULL) {
- switch(actionData->Version) {
- case CSSM_APPLE_TP_ACTION_VERSION:
- if(VerifyContext->ActionData.Length !=
- sizeof(CSSM_APPLE_TP_ACTION_DATA)) {
- CssmError::throwMe(CSSMERR_TP_INVALID_ACTION_DATA);
- }
- break;
- /* handle backwards versions here if we ever go beyond version 0 */
- default:
- CssmError::throwMe(CSSMERR_TP_INVALID_ACTION_DATA);
- }
- actionFlags = actionData->ActionFlags;
- if(actionFlags & CSSM_TP_ACTION_TRUST_SETTINGS) {
- utTrustSettingEnabled = true;
- }
- }
-
- /* optional, may be NULL */
- cssmTimeStr = cred->VerifyTime;
-
- tpStopOn = cred->VerificationAbortOn;
- switch(tpStopOn) {
- /* the only two we support */
- case CSSM_TP_STOP_ON_NONE:
- case CSSM_TP_STOP_ON_FIRST_FAIL:
- break;
- /* default maps to stop on first fail */
- case CSSM_TP_STOP_ON_POLICY:
- tpStopOn = CSSM_TP_STOP_ON_FIRST_FAIL;
- break;
- default:
- CssmError::throwMe(CSSMERR_TP_INVALID_STOP_ON_POLICY);
- }
-
- /* now the args we can't deal with */
- if(cred->CallerCredentials != NULL) {
- CssmError::throwMe(CSSMERR_TP_INVALID_CALLERAUTH_CONTEXT_POINTER);
- }
- /* ...any others? */
-
- /* set up for optional user trust evaluation */
- if(utTrustSettingEnabled) {
- const CSSM_TP_POLICYINFO *pinfo = &cred->Policy;
- TPPolicy utPolicy = kTPx509Basic;
-
- /* default policy OID in case caller hasn't specified one */
- utPolicyOid = &utNullPolicy;
- if(pinfo->NumberOfPolicyIds == 0) {
- tpTrustSettingsDbg("CertGroupVerify: User trust enabled but no policies (1)");
- /* keep going, I guess - no policy-specific info - use kTPx509Basic */
- }
- else {
- CSSM_FIELD_PTR utPolicyField = &pinfo->PolicyIds[0];
- utPolicyOid = &utPolicyField->FieldOid;
- bool foundPolicy = checkPolicyOid(*utPolicyOid, utPolicy);
- if(!foundPolicy) {
- tpTrustSettingsDbg("CertGroupVerify: User trust enabled but no policies");
- /* keep going, I guess - no policy-specific info - use kTPx509Basic */
- }
- else {
- /* get policy-specific info */
- tp_policyTrustSettingParams(utPolicy, &utPolicyField->FieldValue,
- &utPolicyStr, &utPolicyStrLen, &utKeyUse);
- }
- }
- }
-
- /* get verified (possibly partial) outCertGroup - error is fatal */
- /* BUT: we still return partial evidence if asked to...from now on. */
- TPCertGroup outCertGroup(*this,
- TGO_Caller); // certs are owned by inCertGroup
- TPCertGroup inCertGroup(CertGroupToBeVerified, clHand, cspHand, *this,
- cssmTimeStr, // optional 'this' time
- true, // firstCertMustBeValid
- TGO_Group);
-
- /* set up for disposal of TPCertInfos created by CertGroupConstructPriv */
- TPCertGroup gatheredCerts(*this, TGO_Group);
-
- try {
- CertGroupConstructPriv(
- clHand,
- cspHand,
- inCertGroup,
- cred->DBList,
- cssmTimeStr,
- cred->NumberOfAnchorCerts,
- cred->AnchorCerts,
- actionFlags,
- utPolicyOid,
- utPolicyStr,
- utPolicyStrLen,
- utKeyUse,
- gatheredCerts,
- verifiedToRoot,
- verifiedToAnchor,
- verifiedViaTrustSetting,
- outCertGroup);
- }
- catch(const CssmError &cerr) {
- constructReturn = cerr.error;
- /* abort if no certs found */
- if(outCertGroup.numCerts() == 0) {
- CssmError::throwMe(constructReturn);
- }
- /* else press on, collecting as much info as we can */
- }
- /* others are way fatal */
- assert(outCertGroup.numCerts() >= 1);
-
- /* Infer interim status from return values */
- switch(constructReturn) {
- /* these values do not get overridden */
- case CSSMERR_TP_CERTIFICATE_CANT_OPERATE:
- case CSSMERR_TP_INVALID_CERT_AUTHORITY:
- case CSSMERR_APPLETP_TRUST_SETTING_DENY:
- case errSecInvalidTrustSettings:
- break;
- default:
- /* infer status from these values... */
- if(verifiedToAnchor || verifiedViaTrustSetting) {
- /* full success; anchor doesn't have to be root */
- constructReturn = CSSM_OK;
- }
- else if(verifiedToRoot) {
- if(actionFlags & CSSM_TP_ACTION_IMPLICIT_ANCHORS) {
- constructReturn = CSSM_OK;
- }
- else {
- /* verified to root which is not an anchor */
- constructReturn = CSSMERR_TP_INVALID_ANCHOR_CERT;
- }
- }
- else {
- /* partial chain, no root, not verifiable by anchor */
- constructReturn = CSSMERR_TP_NOT_TRUSTED;
- }
-
- /*
- * Those errors can be allowed, cert-chain-wide, per individual
- * certs' allowedErrors
- */
- if((constructReturn != CSSM_OK) &&
- outCertGroup.isAllowedError(constructReturn)) {
- constructReturn = CSSM_OK;
- }
-
- /*
- * Allow non-trusted root if whitelist check permits
- */
- if (constructReturn == CSSMERR_TP_NOT_TRUSTED) {
- constructReturn = tpCheckCertificateAllowList(outCertGroup);
- }
- break;
- }
-
- /*
- * Parameters passed to tp_policyVerify() and which vary per policy
- * in the loop below
- */
- TPPolicy tpPolicy;
- const CSSM_APPLE_TP_SSL_OPTIONS *sslOpts;
- CSSM_RETURN thisPolicyRtn = CSSM_OK; // returned from tp_policyVerify()
-
- /* common CRL verify parameters */
- TPCrlGroup *crlGroup = NULL;
- try {
- crlGroup = new TPCrlGroup(&VerifyContext->Crls,
- clHand, cspHand,
- *this, // alloc
- NULL, // cssmTimeStr - we want CRLs that are valid 'now'
- TGO_Group);
- }
- catch(const CssmError &cerr) {
- CSSM_RETURN cr = cerr.error;
- /* I don't see a straightforward way to report this error,
- * other than adding it to the leaf cert's status... */
- outCertGroup.certAtIndex(0)->addStatusCode(cr);
- tpDebug("CertGroupVerify: error constructing CrlGroup; continuing\n");
- }
- /* others are way fatal */
-
- TPVerifyContext revokeVfyContext(*this,
- clHand,
- cspHand,
- cssmTimeStr,
- cred->NumberOfAnchorCerts,
- cred->AnchorCerts,
- &inCertGroup,
- crlGroup,
- /*
- * This may consist of certs gathered from the net (which is the purpose
- * of this argument) and from DLDBs (a side-effect optimization).
- */
- gatheredCerts,
- cred->DBList,
- kRevokeNone, // policy
- actionFlags,
- NULL, // CRL options
- NULL, // OCSP options
- utPolicyOid,
- utPolicyStr,
- utPolicyStrLen,
- utKeyUse);
-
- /* true if we're to execute tp_policyVerify at end of loop */
- bool doPolicyVerify;
- /* true if we're to execute a revocation policy at end of loop */
- bool doRevocationPolicy;
-
- /* grind thru each policy */
- for(uint32 polDex=0; polDex<cred->Policy.NumberOfPolicyIds; polDex++) {
- if(cred->Policy.PolicyIds == NULL) {
- policyReturn = CSSMERR_TP_INVALID_POLICY_IDENTIFIERS;
- break;
- }
- CSSM_FIELD_PTR policyId = &cred->Policy.PolicyIds[polDex];
- const CSSM_DATA *fieldVal = &policyId->FieldValue;
- const CSSM_OID *oid = &policyId->FieldOid;
- thisPolicyRtn = CSSM_OK;
- doPolicyVerify = false;
- doRevocationPolicy = false;
- sslOpts = NULL;
-
- /* first the basic cert policies */
- doPolicyVerify = checkPolicyOid(*oid, tpPolicy);
- if(doPolicyVerify) {
- /* some basic checks... */
- bool policyAbort = false;
- switch(tpPolicy) {
- case kTPx509Basic:
- case kTPiSign:
- case kTP_PKINIT_Client:
- case kTP_PKINIT_Server:
- if(fieldVal->Data != NULL) {
- policyReturn = CSSMERR_TP_INVALID_POLICY_IDENTIFIERS;
- policyAbort = true;
- break;
- }
- break;
- default:
- break;
- }
- if(policyAbort) {
- break;
- }
- #if TP_PKINIT_SERVER_HACK
- if(tpPolicy == kTP_PKINIT_Server) {
- /* possible override of "root not in anchors" */
- if(constructReturn == CSSMERR_TP_INVALID_ANCHOR_CERT) {
- if(tpCheckPkinitServerCert(outCertGroup)) {
- constructReturn = CSSM_OK;
- }
- }
- }
- #endif /* TP_PKINIT_SERVER_HACK */
- }
-
- /*
- * Now revocation policies. Note some fields in revokeVfyContext can
- * accumulate across multiple policy calls, e.g., signerCerts.
- */
- else if(tpCompareOids(oid, &CSSMOID_APPLE_TP_REVOCATION_CRL)) {
- /* CRL-specific options */
- const CSSM_APPLE_TP_CRL_OPTIONS *crlOpts;
- crlOpts = (CSSM_APPLE_TP_CRL_OPTIONS *)fieldVal->Data;
- thisPolicyRtn = CSSM_OK;
- if(crlOpts != NULL) {
- switch(crlOpts->Version) {
- case CSSM_APPLE_TP_CRL_OPTS_VERSION:
- if(fieldVal->Length !=
- sizeof(CSSM_APPLE_TP_CRL_OPTIONS)) {
- thisPolicyRtn =
- CSSMERR_TP_INVALID_POLICY_IDENTIFIERS;
- break;
- }
- break;
- /* handle backwards compatibility here if necessary */
- default:
- thisPolicyRtn = CSSMERR_TP_INVALID_POLICY_IDENTIFIERS;
- break;
- }
- if(thisPolicyRtn != CSSM_OK) {
- policyReturn = thisPolicyRtn;
- break;
- }
- }
- revokeVfyContext.policy = kRevokeCrlBasic;
- revokeVfyContext.crlOpts = crlOpts;
- doRevocationPolicy = true;
- }
- else if(tpCompareOids(oid, &CSSMOID_APPLE_TP_REVOCATION_OCSP)) {
- /* OCSP-specific options */
- const CSSM_APPLE_TP_OCSP_OPTIONS *ocspOpts;
- ocspOpts = (CSSM_APPLE_TP_OCSP_OPTIONS *)fieldVal->Data;
- thisPolicyRtn = CSSM_OK;
- if(ocspOpts != NULL) {
- switch(ocspOpts->Version) {
- case CSSM_APPLE_TP_OCSP_OPTS_VERSION:
- if(fieldVal->Length !=
- sizeof(CSSM_APPLE_TP_OCSP_OPTIONS)) {
- thisPolicyRtn =
- CSSMERR_TP_INVALID_POLICY_IDENTIFIERS;
- break;
- }
- break;
- /* handle backwards compatibility here if necessary */
- default:
- thisPolicyRtn = CSSMERR_TP_INVALID_POLICY_IDENTIFIERS;
- break;
- }
- if(thisPolicyRtn != CSSM_OK) {
- policyReturn = thisPolicyRtn;
- break;
- }
- }
- revokeVfyContext.policy = kRevokeOcsp;
- revokeVfyContext.ocspOpts = ocspOpts;
- doRevocationPolicy = true;
- }
- /* etc. - add more policies here */
- else {
- /* unknown TP policy OID */
- policyReturn = CSSMERR_TP_INVALID_POLICY_IDENTIFIERS;
- break;
- }
-
- /* common cert policy call */
- if(doPolicyVerify) {
- assert(!doRevocationPolicy); // one at a time
- thisPolicyRtn = tp_policyVerify(tpPolicy,
- *this,
- clHand,
- cspHand,
- &outCertGroup,
- verifiedToRoot,
- verifiedViaTrustSetting,
- actionFlags,
- fieldVal,
- cred->Policy.PolicyControl); // not currently used
- didCertPolicy = true;
- }
- /* common revocation policy call */
- if(doRevocationPolicy) {
- assert(!doPolicyVerify); // one at a time
- thisPolicyRtn = tpRevocationPolicyVerify(revokeVfyContext, outCertGroup);
- didRevokePolicy = true;
- }
- /* See if possible error is allowed, cert-chain-wide. */
- if((thisPolicyRtn != CSSM_OK) &&
- outCertGroup.isAllowedError(thisPolicyRtn)) {
- thisPolicyRtn = CSSM_OK;
- }
- if(thisPolicyRtn) {
- /* Now remember the error if it's the first policy
- * error we've seen. */
- if(policyReturn == CSSM_OK) {
- policyReturn = thisPolicyRtn;
- }
- /* Keep going? */
- if(tpStopOn == CSSM_TP_STOP_ON_FIRST_FAIL) {
- /* Nope; we're done with policy evaluation */
- break;
- }
- }
- } /* for each policy */
-
- /*
- * Upon completion of the above loop, perform default policy ops if
- * appropriate.
- */
- if((policyReturn == CSSM_OK) || (tpStopOn == CSSM_TP_STOP_ON_NONE)) {
- if(!didCertPolicy) {
- policyReturn = tp_policyVerify(kTPDefault,
- *this,
- clHand,
- cspHand,
- &outCertGroup,
- verifiedToRoot,
- verifiedViaTrustSetting,
- actionFlags,
- NULL, // policyFieldData
- cred->Policy.PolicyControl); // not currently used
- /* See if error is allowed, cert-chain-wide. */
- if((policyReturn != CSSM_OK) &&
- outCertGroup.isAllowedError(policyReturn)) {
- policyReturn = CSSM_OK;
- }
- }
- if( !didRevokePolicy && // no revoke policy yet
- ( (policyReturn == CSSM_OK || // default cert policy OK
- (tpStopOn == CSSM_TP_STOP_ON_NONE)) // keep going anyway
- )
- ) {
- revokeVfyContext.policy = TP_CRL_POLICY_DEFAULT;
- CSSM_RETURN thisPolicyRtn = tpRevocationPolicyVerify(revokeVfyContext,
- outCertGroup);
- if((thisPolicyRtn != CSSM_OK) &&
- outCertGroup.isAllowedError(thisPolicyRtn)) {
- thisPolicyRtn = CSSM_OK;
- }
- if((thisPolicyRtn != CSSM_OK) && (policyReturn == CSSM_OK)) {
- policyReturn = thisPolicyRtn;
- }
-
- }
- } /* default policy opts */
-
- delete crlGroup;
-
- /* return evidence - i.e., constructed chain - if asked to */
- if(VerifyContextResult != NULL) {
- /*
- * VerifyContextResult->Evidence[0] : CSSM_TP_APPLE_EVIDENCE_HEADER
- * VerifyContextResult->Evidence[1] : CSSM_CERTGROUP
- * VerifyContextResult->Evidence[2] : CSSM_TP_APPLE_EVIDENCE_INFO
- */
- VerifyContextResult->NumberOfEvidences = 3;
- VerifyContextResult->Evidence =
- (CSSM_EVIDENCE_PTR)calloc(3, sizeof(CSSM_EVIDENCE));
-
- CSSM_TP_APPLE_EVIDENCE_HEADER *hdr =
- (CSSM_TP_APPLE_EVIDENCE_HEADER *)malloc(
- sizeof(CSSM_TP_APPLE_EVIDENCE_HEADER));
- hdr->Version = CSSM_TP_APPLE_EVIDENCE_VERSION;
- CSSM_EVIDENCE_PTR ev = &VerifyContextResult->Evidence[0];
- ev->EvidenceForm = CSSM_EVIDENCE_FORM_APPLE_HEADER;
- ev->Evidence = hdr;
-
- ev = &VerifyContextResult->Evidence[1];
- ev->EvidenceForm = CSSM_EVIDENCE_FORM_APPLE_CERTGROUP;
- ev->Evidence = outCertGroup.buildCssmCertGroup();
-
- ev = &VerifyContextResult->Evidence[2];
- ev->EvidenceForm = CSSM_EVIDENCE_FORM_APPLE_CERT_INFO;
- ev->Evidence = outCertGroup.buildCssmEvidenceInfo();
- }
- else {
- /* caller responsible for freeing these if they are for evidence.... */
- outCertGroup.freeDbRecords();
- }
- CSSM_RETURN outErr = outCertGroup.getReturnCode(constructReturn, policyReturn,
- actionFlags);
-
- if(outErr) {
- CssmError::throwMe(outErr);
- }
-}
-
-