2 * Copyright (c) 2000-2001,2011-2014 Apple Inc. All Rights Reserved.
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
20 * tpCertGroup.cpp - Cert group functions (construct, verify)
23 #include "AppleTPSession.h"
24 #include "certGroupUtils.h"
25 #include "TPCertInfo.h"
26 #include "TPCrlInfo.h"
27 #include "tpCertAllowList.h"
28 #include "tpPolicies.h"
29 #include "tpdebugging.h"
30 #include "tpCrlVerify.h"
31 #include <Security/oidsalg.h>
32 #include <Security/cssmapple.h>
35 * This is a temporary hack to allow verification of PKINIT server certs
36 * which are self-signed and not in the system anchors list. If the self-
37 * signed cert is in a magic keychain (whose location is not published),
38 * we'll allow it as if it were indeed a full-fledged anchor cert.
40 #define TP_PKINIT_SERVER_HACK 1
41 #if TP_PKINIT_SERVER_HACK
43 #include <Security/SecKeychain.h>
44 #include <Security/SecKeychainSearch.h>
45 #include <Security/SecCertificate.h>
46 #include <Security/oidscert.h>
47 #include <sys/types.h>
50 #define CFRELEASE(cf) if(cf) { CFRelease(cf); }
53 * Returns true if we are to allow/trust the specified
54 * cert as a PKINIT-only anchor.
56 static bool tpCheckPkinitServerCert(
57 TPCertGroup
&certGroup
)
60 * Basic requirement: exactly one cert, self-signed.
61 * The numCerts == 1 requirement might change...
63 unsigned numCerts
= certGroup
.numCerts();
65 tpDebug("tpCheckPkinitServerCert: too many certs");
69 TPCertInfo
*theCert
= certGroup
.certAtIndex(numCerts
- 1);
70 if(!theCert
->isSelfSigned()) {
71 tpDebug("tpCheckPkinitServerCert: 1 cert, not self-signed");
74 const CSSM_DATA
*subjectName
= theCert
->subjectName();
77 * Open the magic keychain.
78 * We're going up and over the Sec layer here, not generally
79 * kosher, but this is a hack.
82 SecKeychainRef kcRef
= NULL
;
84 const char *homeDir
= getenv("HOME");
87 // If $HOME is unset get the current user's home directory
88 // from the passwd file.
89 uid_t uid
= geteuid();
90 if (!uid
) uid
= getuid();
91 struct passwd
*pw
= getpwuid(uid
);
97 fullPathName
= homeDir
;
98 fullPathName
+= "/Library/Application Support/PKINIT/TrustedServers.keychain";
99 ortn
= SecKeychainOpen(fullPathName
.c_str(), &kcRef
);
101 tpDebug("tpCheckPkinitServerCert: keychain not found (1)");
104 /* subsequent errors to errOut: */
107 SecKeychainStatus kcStatus
;
108 CSSM_DATA_PTR subjSerial
= NULL
;
110 SecKeychainSearchRef srchRef
= NULL
;
111 SecKeychainAttributeList attrList
;
112 SecKeychainAttribute attrs
[2];
113 SecKeychainItemRef foundItem
= NULL
;
115 ortn
= SecKeychainGetStatus(kcRef
, &kcStatus
);
117 tpDebug("tpCheckPkinitServerCert: keychain not found (2)");
122 * We already have this cert's normalized name; get its
125 crtn
= theCert
->fetchField(&CSSMOID_X509V1SerialNumber
, &subjSerial
);
127 /* should never happen */
128 tpDebug("tpCheckPkinitServerCert: error fetching serial number");
132 attrs
[0].tag
= kSecSubjectItemAttr
;
133 attrs
[0].length
= (UInt32
)subjectName
->Length
;
134 attrs
[0].data
= subjectName
->Data
;
135 attrs
[1].tag
= kSecSerialNumberItemAttr
;
136 attrs
[1].length
= (UInt32
)subjSerial
->Length
;
137 attrs
[1].data
= subjSerial
->Data
;
139 attrList
.attr
= attrs
;
141 ortn
= SecKeychainSearchCreateFromAttributes(kcRef
,
142 kSecCertificateItemClass
,
146 tpDebug("tpCheckPkinitServerCert: search failure");
150 ortn
= SecKeychainSearchCopyNext(srchRef
, &foundItem
);
152 tpDebug("tpCheckPkinitServerCert: end search");
156 /* found a matching cert; do byte-for-byte compare */
158 ortn
= SecCertificateGetData((SecCertificateRef
)foundItem
, &certData
);
160 tpDebug("tpCheckPkinitServerCert: SecCertificateGetData failure");
163 if(tpCompareCssmData(&certData
, theCert
->itemData())){
164 tpDebug("tpCheckPkinitServerCert: FOUND CERT");
168 tpDebug("tpCheckPkinitServerCert: skipping matching cert");
169 CFRelease(foundItem
);
175 CFRELEASE(foundItem
);
176 if(subjSerial
!= NULL
) {
177 theCert
->freeField(&CSSMOID_X509V1SerialNumber
, subjSerial
);
181 #endif /* TP_PKINIT_SERVER_HACK */
183 /*-----------------------------------------------------------------------------
187 * This function returns a pointer to a mallocd CSSM_CERTGROUP which
188 * refers to a mallocd list of raw ordered X.509 certs which verify back as
189 * far as the TP is able to go. The first cert of the returned list is the
190 * subject cert. The TP will attempt to search thru the DBs passed in
191 * DBList in order to complete the chain. The chain is completed when a
192 * self-signed (root) cert is found in the chain. The root cert may be
193 * present in the input CertGroupFrag, or it may have been obtained from
194 * one of the DBs passed in DBList. It is not an error if no root cert is
197 * The error conditions are:
198 * -- The first cert of CertGroupFrag is an invalid cert. NULL is returned,
199 * err = CSSM_TP_INVALID_CERTIFICATE.
200 * -- The root cert (if found) fails to verify. Valid certgroup is returned,
201 * err = CSSMERR_TP_VERIFICATION_FAILURE.
202 * -- Any cert in the (possibly partially) constructed chain has expired or
203 * isn't valid yet, err = CSSMERR_TP_CERT_EXPIRED or
204 * CSSMERR_TP_CERT_NOT_VALID_YET. A CertGroup is returned.
205 * -- CSSMERR_TP_CERT_EXPIRED and CSSMERR_TP_CERT_NOT_VALID_YET. If one of these
206 * conditions obtains for the first (leaf) cert, the function throws this
207 * error immediately and the outgoing cert group is empty. For subsequent certs,
208 * the temporal validity of a cert is only tested AFTER a cert successfully
209 * meets the cert chaining criteria (subject/issuer match and signature
210 * verify). A cert in a chain with this error is not added to the outgoing
212 * -- the usual errors like bad handle or memory failure.
215 * Two handles - to an open CL and CSP. The CSP must be capable of
216 * dealing with the signature algorithms used by the certs. The CL must be
219 * CertGroupFrag, an unordered array of raw X.509 certs in the form of a
220 * CSSM_CERTGROUP_PTR. The first cert of this list is the subject cert
221 * which is eventually to be verified. The other certs can be in any order
222 * and may not even have any relevance to the cert chain being constructed.
223 * They may also be invalid certs.
225 * DBList, a list of DB/DL handles which may contain certs necessary to
226 * complete the desired cert chain. (Not currently implemented.)
228 *---------------------------------------------------------------------------*/
231 void AppleTPSession::CertGroupConstruct(CSSM_CL_HANDLE clHand
,
232 CSSM_CSP_HANDLE cspHand
,
233 const CSSM_DL_DB_LIST
&DBList
,
234 const void *ConstructParams
,
235 const CSSM_CERTGROUP
&CertGroupFrag
,
236 CSSM_CERTGROUP_PTR
&CertGroup
)
238 TPCertGroup
outCertGroup(*this, TGO_Caller
);
239 TPCertGroup
inCertGroup(CertGroupFrag
,
244 true, // firstCertMustBeValid
247 /* set up for disposal of TPCertInfos created by CertGroupConstructPriv */
248 TPCertGroup
gatheredCerts(*this, TGO_Group
);
250 CSSM_RETURN constructReturn
= CSSM_OK
;
251 CSSM_APPLE_TP_ACTION_FLAGS actionFlags
= 0;
252 CSSM_BOOL verifiedToRoot
; // not used
253 CSSM_BOOL verifiedToAnchor
; // not used
254 CSSM_BOOL verifiedViaTrustSetting
; // not used
257 CertGroupConstructPriv(clHand
,
270 verifiedViaTrustSetting
,
273 catch(const CssmError
&cerr
) {
274 constructReturn
= cerr
.error
;
275 /* abort if no certs found */
276 if(outCertGroup
.numCerts() == 0) {
277 CssmError::throwMe(constructReturn
);
280 CertGroup
= outCertGroup
.buildCssmCertGroup();
281 /* caller of this function never gets evidence... */
282 outCertGroup
.freeDbRecords();
284 if(constructReturn
) {
285 CssmError::throwMe(constructReturn
);
291 * Private version of CertGroupConstruct, used by CertGroupConstruct and
292 * CertGroupVerify. Populates a TP-style TPCertGroup for further processing.
293 * This only throws CSSM-style exceptions in the following cases:
295 * -- input parameter errors
296 * -- the first (leaf) cert is bad (doesn't parse, expired, not valid yet).
297 * -- root found but it doesn't self-verify
299 * All other cert-related errors simply result in the bad cert being ignored.
300 * Other exceptions are gross system errors like malloc failure.
302 void AppleTPSession::CertGroupConstructPriv(CSSM_CL_HANDLE clHand
,
303 CSSM_CSP_HANDLE cspHand
,
304 TPCertGroup
&inCertGroup
,
305 const CSSM_DL_DB_LIST
*DBList
, // optional here
306 const char *cssmTimeStr
, // optional
308 /* trusted anchors, optional */
309 /* FIXME - maybe this should be a TPCertGroup */
310 uint32 numAnchorCerts
,
311 const CSSM_DATA
*anchorCerts
,
313 /* CSSM_TP_ACTION_FETCH_CERT_FROM_NET, CSSM_TP_ACTION_TRUST_SETTINGS */
314 CSSM_APPLE_TP_ACTION_FLAGS actionFlags
,
316 /* optional user trust parameters */
317 const CSSM_OID
*policyOid
,
318 const char *policyStr
,
320 SecTrustSettingsKeyUsage keyUse
,
323 * Certs to be freed by caller (i.e., TPCertInfo which we allocate
324 * as a result of using a cert from anchorCerts or dbList) are added
327 TPCertGroup
&certsToBeFreed
,
330 CSSM_BOOL
&verifiedToRoot
, // end of chain self-verifies
331 CSSM_BOOL
&verifiedToAnchor
, // end of chain in anchors
332 CSSM_BOOL
&verifiedViaTrustSetting
, // chain ends per User Trust setting
333 TPCertGroup
&outCertGroup
) // RETURNED
335 TPCertInfo
*subjectCert
; // the one we're working on
336 CSSM_RETURN outErr
= CSSM_OK
;
338 /* this'll be the first subject cert in the main loop */
339 subjectCert
= inCertGroup
.certAtIndex(0);
341 /* Append leaf cert to outCertGroup */
342 outCertGroup
.appendCert(subjectCert
);
343 subjectCert
->isLeaf(true);
344 subjectCert
->isFromInputCerts(true);
345 outCertGroup
.setAllUnused();
346 subjectCert
->used(true);
348 outErr
= outCertGroup
.buildCertGroup(
358 &certsToBeFreed
, // gatheredCerts to accumulate net/DB fetches
359 CSSM_TRUE
, // subjectIsInGroup - enables root check on
369 verifiedViaTrustSetting
);
371 CssmError::throwMe(outErr
);
376 * Map a policy OID to one of the standard (non-revocation) policies.
377 * Returns true if it's a standard policy.
379 static bool checkPolicyOid(
381 TPPolicy
&tpPolicy
) /* RETURNED */
383 if(tpCompareOids(&oid
, &CSSMOID_APPLE_TP_SSL
)) {
387 else if(tpCompareOids(&oid
, &CSSMOID_APPLE_X509_BASIC
)) {
388 tpPolicy
= kTPx509Basic
;
391 else if(tpCompareOids(&oid
, &CSSMOID_APPLE_TP_SMIME
)) {
392 tpPolicy
= kTP_SMIME
;
395 else if(tpCompareOids(&oid
, &CSSMOID_APPLE_TP_EAP
)) {
399 else if(tpCompareOids(&oid
, &CSSMOID_APPLE_TP_SW_UPDATE_SIGNING
)) {
400 /* note: this was CSSMOID_APPLE_TP_CODE_SIGN until 8/15/06 */
401 tpPolicy
= kTP_SWUpdateSign
;
404 else if(tpCompareOids(&oid
, &CSSMOID_APPLE_TP_RESOURCE_SIGN
)) {
405 tpPolicy
= kTP_ResourceSign
;
408 else if(tpCompareOids(&oid
, &CSSMOID_APPLE_TP_IP_SEC
)) {
409 tpPolicy
= kTP_IPSec
;
412 else if(tpCompareOids(&oid
, &CSSMOID_APPLE_TP_ICHAT
)) {
413 tpPolicy
= kTP_iChat
;
416 else if(tpCompareOids(&oid
, &CSSMOID_APPLE_ISIGN
)) {
420 else if(tpCompareOids(&oid
, &CSSMOID_APPLE_TP_PKINIT_CLIENT
)) {
421 tpPolicy
= kTP_PKINIT_Client
;
424 else if(tpCompareOids(&oid
, &CSSMOID_APPLE_TP_PKINIT_SERVER
)) {
425 tpPolicy
= kTP_PKINIT_Server
;
428 else if(tpCompareOids(&oid
, &CSSMOID_APPLE_TP_CODE_SIGNING
)) {
429 tpPolicy
= kTP_CodeSigning
;
432 else if(tpCompareOids(&oid
, &CSSMOID_APPLE_TP_PACKAGE_SIGNING
)) {
433 tpPolicy
= kTP_PackageSigning
;
436 else if(tpCompareOids(&oid
, &CSSMOID_APPLE_TP_MACAPPSTORE_RECEIPT
)) {
437 tpPolicy
= kTP_MacAppStoreRec
;
440 else if(tpCompareOids(&oid
, &CSSMOID_APPLE_TP_APPLEID_SHARING
)) {
441 tpPolicy
= kTP_AppleIDSharing
;
444 else if(tpCompareOids(&oid
, &CSSMOID_APPLE_TP_TIMESTAMPING
)) {
445 tpPolicy
= kTP_TimeStamping
;
448 else if(tpCompareOids(&oid
, &CSSMOID_APPLE_TP_PASSBOOK_SIGNING
)) {
449 tpPolicy
= kTP_PassbookSigning
;
452 else if(tpCompareOids(&oid
, &CSSMOID_APPLE_TP_MOBILE_STORE
)) {
453 tpPolicy
= kTP_MobileStore
;
456 else if(tpCompareOids(&oid
, &CSSMOID_APPLE_TP_TEST_MOBILE_STORE
)) {
457 tpPolicy
= kTP_TestMobileStore
;
460 else if(tpCompareOids(&oid
, &CSSMOID_APPLE_TP_ESCROW_SERVICE
)) {
461 tpPolicy
= kTP_EscrowService
;
464 else if(tpCompareOids(&oid
, &CSSMOID_APPLE_TP_PROFILE_SIGNING
)) {
465 tpPolicy
= kTP_ProfileSigning
;
468 else if(tpCompareOids(&oid
, &CSSMOID_APPLE_TP_QA_PROFILE_SIGNING
)) {
469 tpPolicy
= kTP_QAProfileSigning
;
472 else if(tpCompareOids(&oid
, &CSSMOID_APPLE_TP_PCS_ESCROW_SERVICE
)) {
473 tpPolicy
= kTP_PCSEscrowService
;
476 else if(tpCompareOids(&oid
, &CSSMOID_APPLE_TP_PROVISIONING_PROFILE_SIGNING
)) {
477 tpPolicy
= kTP_ProvisioningProfileSigning
;
483 /*-----------------------------------------------------------------------------
487 * -- Construct a cert chain using TP_CertGroupConstruct.
488 * -- Attempt to verify that cert chain against one of the known
489 * good certs passed in AnchorCerts.
490 * -- Optionally enforces additional policies (TBD) when verifying the cert chain.
491 * -- Optionally returns the entire cert chain constructed in
492 * TP_CertGroupConstruct and here, all the way to an anchor cert or as
493 * far as we were able to go, in *Evidence.
496 * Two handles - to an open CL and CSP. The CSP must be capable of
497 * dealing with the signature algorithms used by the certs. The CL must be
500 * RawCerts, an unordered array of raw certs in the form of a
501 * CSSM_CERTGROUP_PTR. The first cert of this list is the subject cert
502 * which is eventually to be verified. The other certs can be in any order
503 * and may not even have any relevance to the cert chain being constructed.
504 * They may also be invalid certs.
506 * DBList, a list of DB/DL handles which may contain certs necessary to
507 * complete the desired cert chain. (Currently not implemented.)
509 * AnchorCerts, a list of known trusted certs.
510 * NumberOfAnchorCerts, size of AnchorCerts array.
512 * PolicyIdentifiers, Optional policy OID. NULL indicates default
513 * X.509 trust policy.
515 * Supported Policies:
516 * CSSMOID_APPLE_ISIGN
517 * CSSMOID_APPLE_X509_BASIC
519 * For both of these, the associated FieldValue must be {0, NULL},
521 * NumberOfPolicyIdentifiers, size of PolicyIdentifiers array, must be
524 * All other arguments must be zero/NULL.
527 * CSSM_OK : cert chain verified all the way back to an AnchorCert.
528 * CSSMERR_TP_INVALID_ANCHOR_CERT : In this case, the cert chain
529 * was validated back to a self-signed (root) cert found in either
530 * CertToBeVerified or in one of the DBs in DBList, but that root cert
531 * was *NOT* found in the AnchorCert list.
532 * CSSMERR_TP_NOT_TRUSTED: no root cert was found and no AnchorCert
533 * verified the end of the constructed cert chain.
534 * CSSMERR_TP_VERIFICATION_FAILURE: a root cert was found which does
536 * CSSMERR_TP_VERIFY_ACTION_FAILED: indicates a failure of the requested
538 * CSSMERR_TP_INVALID_CERTIFICATE: indicates a bad leaf cert.
539 * CSSMERR_TP_INVALID_REQUEST_INPUTS : no incoming VerifyContext.
540 * CSSMERR_TP_CERT_EXPIRED and CSSMERR_TP_CERT_NOT_VALID_YET: see comments
541 * for CertGroupConstruct.
542 * CSSMERR_TP_CERTIFICATE_CANT_OPERATE : issuer cert was found with a partial
543 * public key, rendering full verification impossible.
544 * CSSMERR_TP_INVALID_CERT_AUTHORITY : issuer cert was found with a partial
545 * public key and which failed to perform subsequent signature
547 *---------------------------------------------------------------------------*/
549 void AppleTPSession::CertGroupVerify(CSSM_CL_HANDLE clHand
,
550 CSSM_CSP_HANDLE cspHand
,
551 const CSSM_CERTGROUP
&CertGroupToBeVerified
,
552 const CSSM_TP_VERIFY_CONTEXT
*VerifyContext
,
553 CSSM_TP_VERIFY_CONTEXT_RESULT_PTR VerifyContextResult
)
555 CSSM_BOOL verifiedToRoot
= CSSM_FALSE
;
556 CSSM_BOOL verifiedToAnchor
= CSSM_FALSE
;
557 CSSM_BOOL verifiedViaTrustSetting
= CSSM_FALSE
;
558 CSSM_RETURN constructReturn
= CSSM_OK
;
559 CSSM_RETURN policyReturn
= CSSM_OK
;
560 const CSSM_TP_CALLERAUTH_CONTEXT
*cred
;
561 /* declare volatile as compiler workaround to avoid caching in CR4 */
562 const CSSM_APPLE_TP_ACTION_DATA
* volatile actionData
= NULL
;
563 CSSM_TIMESTRING cssmTimeStr
;
564 CSSM_APPLE_TP_ACTION_FLAGS actionFlags
= 0;
565 CSSM_TP_STOP_ON tpStopOn
= 0;
567 /* keep track of whether we did policy checking; if not, we do defaults */
568 bool didCertPolicy
= false;
569 bool didRevokePolicy
= false;
571 /* user trust parameters */
572 CSSM_OID utNullPolicy
= {0, NULL
};
573 const CSSM_OID
*utPolicyOid
= NULL
;
574 const char *utPolicyStr
= NULL
;
575 uint32 utPolicyStrLen
= 0;
576 SecTrustSettingsKeyUsage utKeyUse
= 0;
577 bool utTrustSettingEnabled
= false;
579 if(VerifyContextResult
) {
580 memset(VerifyContextResult
, 0, sizeof(*VerifyContextResult
));
583 /* verify input args, skipping the ones checked by CertGroupConstruct */
584 if((VerifyContext
== NULL
) || (VerifyContext
->Cred
== NULL
)) {
585 /* the spec says that this is optional but we require it */
586 CssmError::throwMe(CSSMERR_TP_INVALID_REQUEST_INPUTS
);
588 cred
= VerifyContext
->Cred
;
590 /* Optional ActionData affecting all policies */
591 actionData
= (CSSM_APPLE_TP_ACTION_DATA
* volatile)VerifyContext
->ActionData
.Data
;
592 if(actionData
!= NULL
) {
593 switch(actionData
->Version
) {
594 case CSSM_APPLE_TP_ACTION_VERSION
:
595 if(VerifyContext
->ActionData
.Length
!=
596 sizeof(CSSM_APPLE_TP_ACTION_DATA
)) {
597 CssmError::throwMe(CSSMERR_TP_INVALID_ACTION_DATA
);
600 /* handle backwards versions here if we ever go beyond version 0 */
602 CssmError::throwMe(CSSMERR_TP_INVALID_ACTION_DATA
);
604 actionFlags
= actionData
->ActionFlags
;
605 if(actionFlags
& CSSM_TP_ACTION_TRUST_SETTINGS
) {
606 utTrustSettingEnabled
= true;
610 /* optional, may be NULL */
611 cssmTimeStr
= cred
->VerifyTime
;
613 tpStopOn
= cred
->VerificationAbortOn
;
615 /* the only two we support */
616 case CSSM_TP_STOP_ON_NONE
:
617 case CSSM_TP_STOP_ON_FIRST_FAIL
:
619 /* default maps to stop on first fail */
620 case CSSM_TP_STOP_ON_POLICY
:
621 tpStopOn
= CSSM_TP_STOP_ON_FIRST_FAIL
;
624 CssmError::throwMe(CSSMERR_TP_INVALID_STOP_ON_POLICY
);
627 /* now the args we can't deal with */
628 if(cred
->CallerCredentials
!= NULL
) {
629 CssmError::throwMe(CSSMERR_TP_INVALID_CALLERAUTH_CONTEXT_POINTER
);
633 /* set up for optional user trust evaluation */
634 if(utTrustSettingEnabled
) {
635 const CSSM_TP_POLICYINFO
*pinfo
= &cred
->Policy
;
636 TPPolicy utPolicy
= kTPx509Basic
;
638 /* default policy OID in case caller hasn't specified one */
639 utPolicyOid
= &utNullPolicy
;
640 if(pinfo
->NumberOfPolicyIds
== 0) {
641 tpTrustSettingsDbg("CertGroupVerify: User trust enabled but no policies (1)");
642 /* keep going, I guess - no policy-specific info - use kTPx509Basic */
645 CSSM_FIELD_PTR utPolicyField
= &pinfo
->PolicyIds
[0];
646 utPolicyOid
= &utPolicyField
->FieldOid
;
647 bool foundPolicy
= checkPolicyOid(*utPolicyOid
, utPolicy
);
649 tpTrustSettingsDbg("CertGroupVerify: User trust enabled but no policies");
650 /* keep going, I guess - no policy-specific info - use kTPx509Basic */
653 /* get policy-specific info */
654 tp_policyTrustSettingParams(utPolicy
, &utPolicyField
->FieldValue
,
655 &utPolicyStr
, &utPolicyStrLen
, &utKeyUse
);
660 /* get verified (possibly partial) outCertGroup - error is fatal */
661 /* BUT: we still return partial evidence if asked to...from now on. */
662 TPCertGroup
outCertGroup(*this,
663 TGO_Caller
); // certs are owned by inCertGroup
664 TPCertGroup
inCertGroup(CertGroupToBeVerified
, clHand
, cspHand
, *this,
665 cssmTimeStr
, // optional 'this' time
666 true, // firstCertMustBeValid
669 /* set up for disposal of TPCertInfos created by CertGroupConstructPriv */
670 TPCertGroup
gatheredCerts(*this, TGO_Group
);
673 CertGroupConstructPriv(
679 cred
->NumberOfAnchorCerts
,
689 verifiedViaTrustSetting
,
692 catch(const CssmError
&cerr
) {
693 constructReturn
= cerr
.error
;
694 /* abort if no certs found */
695 if(outCertGroup
.numCerts() == 0) {
696 CssmError::throwMe(constructReturn
);
698 /* else press on, collecting as much info as we can */
700 /* others are way fatal */
701 assert(outCertGroup
.numCerts() >= 1);
703 /* Infer interim status from return values */
704 switch(constructReturn
) {
705 /* these values do not get overridden */
706 case CSSMERR_TP_CERTIFICATE_CANT_OPERATE
:
707 case CSSMERR_TP_INVALID_CERT_AUTHORITY
:
708 case CSSMERR_APPLETP_TRUST_SETTING_DENY
:
709 case errSecInvalidTrustSettings
:
712 /* infer status from these values... */
713 if(verifiedToAnchor
|| verifiedViaTrustSetting
) {
714 /* full success; anchor doesn't have to be root */
715 constructReturn
= CSSM_OK
;
717 else if(verifiedToRoot
) {
718 if(actionFlags
& CSSM_TP_ACTION_IMPLICIT_ANCHORS
) {
719 constructReturn
= CSSM_OK
;
722 /* verified to root which is not an anchor */
723 constructReturn
= CSSMERR_TP_INVALID_ANCHOR_CERT
;
727 /* partial chain, no root, not verifiable by anchor */
728 constructReturn
= CSSMERR_TP_NOT_TRUSTED
;
732 * Those errors can be allowed, cert-chain-wide, per individual
733 * certs' allowedErrors
735 if((constructReturn
!= CSSM_OK
) &&
736 outCertGroup
.isAllowedError(constructReturn
)) {
737 constructReturn
= CSSM_OK
;
741 * Allow non-trusted root if whitelist check permits
743 if (constructReturn
== CSSMERR_TP_NOT_TRUSTED
) {
744 constructReturn
= tpCheckCertificateAllowList(outCertGroup
);
750 * Parameters passed to tp_policyVerify() and which vary per policy
754 const CSSM_APPLE_TP_SSL_OPTIONS
*sslOpts
;
755 CSSM_RETURN thisPolicyRtn
= CSSM_OK
; // returned from tp_policyVerify()
757 /* common CRL verify parameters */
758 TPCrlGroup
*crlGroup
= NULL
;
760 crlGroup
= new TPCrlGroup(&VerifyContext
->Crls
,
763 NULL
, // cssmTimeStr - we want CRLs that are valid 'now'
766 catch(const CssmError
&cerr
) {
767 CSSM_RETURN cr
= cerr
.error
;
768 /* I don't see a straightforward way to report this error,
769 * other than adding it to the leaf cert's status... */
770 outCertGroup
.certAtIndex(0)->addStatusCode(cr
);
771 tpDebug("CertGroupVerify: error constructing CrlGroup; continuing\n");
773 /* others are way fatal */
775 TPVerifyContext
revokeVfyContext(*this,
779 cred
->NumberOfAnchorCerts
,
784 * This may consist of certs gathered from the net (which is the purpose
785 * of this argument) and from DLDBs (a side-effect optimization).
789 kRevokeNone
, // policy
792 NULL
, // OCSP options
798 /* true if we're to execute tp_policyVerify at end of loop */
800 /* true if we're to execute a revocation policy at end of loop */
801 bool doRevocationPolicy
;
803 /* grind thru each policy */
804 for(uint32 polDex
=0; polDex
<cred
->Policy
.NumberOfPolicyIds
; polDex
++) {
805 if(cred
->Policy
.PolicyIds
== NULL
) {
806 policyReturn
= CSSMERR_TP_INVALID_POLICY_IDENTIFIERS
;
809 CSSM_FIELD_PTR policyId
= &cred
->Policy
.PolicyIds
[polDex
];
810 const CSSM_DATA
*fieldVal
= &policyId
->FieldValue
;
811 const CSSM_OID
*oid
= &policyId
->FieldOid
;
812 thisPolicyRtn
= CSSM_OK
;
813 doPolicyVerify
= false;
814 doRevocationPolicy
= false;
817 /* first the basic cert policies */
818 doPolicyVerify
= checkPolicyOid(*oid
, tpPolicy
);
820 /* some basic checks... */
821 bool policyAbort
= false;
825 case kTP_PKINIT_Client
:
826 case kTP_PKINIT_Server
:
827 if(fieldVal
->Data
!= NULL
) {
828 policyReturn
= CSSMERR_TP_INVALID_POLICY_IDENTIFIERS
;
839 #if TP_PKINIT_SERVER_HACK
840 if(tpPolicy
== kTP_PKINIT_Server
) {
841 /* possible override of "root not in anchors" */
842 if(constructReturn
== CSSMERR_TP_INVALID_ANCHOR_CERT
) {
843 if(tpCheckPkinitServerCert(outCertGroup
)) {
844 constructReturn
= CSSM_OK
;
848 #endif /* TP_PKINIT_SERVER_HACK */
852 * Now revocation policies. Note some fields in revokeVfyContext can
853 * accumulate across multiple policy calls, e.g., signerCerts.
855 else if(tpCompareOids(oid
, &CSSMOID_APPLE_TP_REVOCATION_CRL
)) {
856 /* CRL-specific options */
857 const CSSM_APPLE_TP_CRL_OPTIONS
*crlOpts
;
858 crlOpts
= (CSSM_APPLE_TP_CRL_OPTIONS
*)fieldVal
->Data
;
859 thisPolicyRtn
= CSSM_OK
;
860 if(crlOpts
!= NULL
) {
861 switch(crlOpts
->Version
) {
862 case CSSM_APPLE_TP_CRL_OPTS_VERSION
:
863 if(fieldVal
->Length
!=
864 sizeof(CSSM_APPLE_TP_CRL_OPTIONS
)) {
866 CSSMERR_TP_INVALID_POLICY_IDENTIFIERS
;
870 /* handle backwards compatibility here if necessary */
872 thisPolicyRtn
= CSSMERR_TP_INVALID_POLICY_IDENTIFIERS
;
875 if(thisPolicyRtn
!= CSSM_OK
) {
876 policyReturn
= thisPolicyRtn
;
880 revokeVfyContext
.policy
= kRevokeCrlBasic
;
881 revokeVfyContext
.crlOpts
= crlOpts
;
882 doRevocationPolicy
= true;
884 else if(tpCompareOids(oid
, &CSSMOID_APPLE_TP_REVOCATION_OCSP
)) {
885 /* OCSP-specific options */
886 const CSSM_APPLE_TP_OCSP_OPTIONS
*ocspOpts
;
887 ocspOpts
= (CSSM_APPLE_TP_OCSP_OPTIONS
*)fieldVal
->Data
;
888 thisPolicyRtn
= CSSM_OK
;
889 if(ocspOpts
!= NULL
) {
890 switch(ocspOpts
->Version
) {
891 case CSSM_APPLE_TP_OCSP_OPTS_VERSION
:
892 if(fieldVal
->Length
!=
893 sizeof(CSSM_APPLE_TP_OCSP_OPTIONS
)) {
895 CSSMERR_TP_INVALID_POLICY_IDENTIFIERS
;
899 /* handle backwards compatibility here if necessary */
901 thisPolicyRtn
= CSSMERR_TP_INVALID_POLICY_IDENTIFIERS
;
904 if(thisPolicyRtn
!= CSSM_OK
) {
905 policyReturn
= thisPolicyRtn
;
909 revokeVfyContext
.policy
= kRevokeOcsp
;
910 revokeVfyContext
.ocspOpts
= ocspOpts
;
911 doRevocationPolicy
= true;
913 /* etc. - add more policies here */
915 /* unknown TP policy OID */
916 policyReturn
= CSSMERR_TP_INVALID_POLICY_IDENTIFIERS
;
920 /* common cert policy call */
922 assert(!doRevocationPolicy
); // one at a time
923 thisPolicyRtn
= tp_policyVerify(tpPolicy
,
929 verifiedViaTrustSetting
,
932 cred
->Policy
.PolicyControl
); // not currently used
933 didCertPolicy
= true;
935 /* common revocation policy call */
936 if(doRevocationPolicy
) {
937 assert(!doPolicyVerify
); // one at a time
938 thisPolicyRtn
= tpRevocationPolicyVerify(revokeVfyContext
, outCertGroup
);
939 didRevokePolicy
= true;
941 /* See if possible error is allowed, cert-chain-wide. */
942 if((thisPolicyRtn
!= CSSM_OK
) &&
943 outCertGroup
.isAllowedError(thisPolicyRtn
)) {
944 thisPolicyRtn
= CSSM_OK
;
947 /* Now remember the error if it's the first policy
948 * error we've seen. */
949 if(policyReturn
== CSSM_OK
) {
950 policyReturn
= thisPolicyRtn
;
953 if(tpStopOn
== CSSM_TP_STOP_ON_FIRST_FAIL
) {
954 /* Nope; we're done with policy evaluation */
958 } /* for each policy */
961 * Upon completion of the above loop, perform default policy ops if
964 if((policyReturn
== CSSM_OK
) || (tpStopOn
== CSSM_TP_STOP_ON_NONE
)) {
966 policyReturn
= tp_policyVerify(kTPDefault
,
972 verifiedViaTrustSetting
,
974 NULL
, // policyFieldData
975 cred
->Policy
.PolicyControl
); // not currently used
976 /* See if error is allowed, cert-chain-wide. */
977 if((policyReturn
!= CSSM_OK
) &&
978 outCertGroup
.isAllowedError(policyReturn
)) {
979 policyReturn
= CSSM_OK
;
982 if( !didRevokePolicy
&& // no revoke policy yet
983 ( (policyReturn
== CSSM_OK
|| // default cert policy OK
984 (tpStopOn
== CSSM_TP_STOP_ON_NONE
)) // keep going anyway
987 revokeVfyContext
.policy
= TP_CRL_POLICY_DEFAULT
;
988 CSSM_RETURN thisPolicyRtn
= tpRevocationPolicyVerify(revokeVfyContext
,
990 if((thisPolicyRtn
!= CSSM_OK
) &&
991 outCertGroup
.isAllowedError(thisPolicyRtn
)) {
992 thisPolicyRtn
= CSSM_OK
;
994 if((thisPolicyRtn
!= CSSM_OK
) && (policyReturn
== CSSM_OK
)) {
995 policyReturn
= thisPolicyRtn
;
999 } /* default policy opts */
1003 /* return evidence - i.e., constructed chain - if asked to */
1004 if(VerifyContextResult
!= NULL
) {
1006 * VerifyContextResult->Evidence[0] : CSSM_TP_APPLE_EVIDENCE_HEADER
1007 * VerifyContextResult->Evidence[1] : CSSM_CERTGROUP
1008 * VerifyContextResult->Evidence[2] : CSSM_TP_APPLE_EVIDENCE_INFO
1010 VerifyContextResult
->NumberOfEvidences
= 3;
1011 VerifyContextResult
->Evidence
=
1012 (CSSM_EVIDENCE_PTR
)calloc(3, sizeof(CSSM_EVIDENCE
));
1014 CSSM_TP_APPLE_EVIDENCE_HEADER
*hdr
=
1015 (CSSM_TP_APPLE_EVIDENCE_HEADER
*)malloc(
1016 sizeof(CSSM_TP_APPLE_EVIDENCE_HEADER
));
1017 hdr
->Version
= CSSM_TP_APPLE_EVIDENCE_VERSION
;
1018 CSSM_EVIDENCE_PTR ev
= &VerifyContextResult
->Evidence
[0];
1019 ev
->EvidenceForm
= CSSM_EVIDENCE_FORM_APPLE_HEADER
;
1022 ev
= &VerifyContextResult
->Evidence
[1];
1023 ev
->EvidenceForm
= CSSM_EVIDENCE_FORM_APPLE_CERTGROUP
;
1024 ev
->Evidence
= outCertGroup
.buildCssmCertGroup();
1026 ev
= &VerifyContextResult
->Evidence
[2];
1027 ev
->EvidenceForm
= CSSM_EVIDENCE_FORM_APPLE_CERT_INFO
;
1028 ev
->Evidence
= outCertGroup
.buildCssmEvidenceInfo();
1031 /* caller responsible for freeing these if they are for evidence.... */
1032 outCertGroup
.freeDbRecords();
1034 CSSM_RETURN outErr
= outCertGroup
.getReturnCode(constructReturn
, policyReturn
,
1038 CssmError::throwMe(outErr
);