2 * Copyright (c) 2005,2011-2015 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
25 * TrustSettings.h - class to manage cert trust settings.
29 #include "TrustSettings.h"
30 #include "TrustSettingsSchema.h"
31 #include <Security/SecTrustSettings.h>
32 #include "TrustSettingsUtils.h"
33 #include "TrustKeychains.h"
34 #include "Certificate.h"
35 #include "cssmdatetime.h"
36 #include <Security/SecBase.h>
37 #include "SecTrustedApplicationPriv.h"
38 #include <security_utilities/errors.h>
39 #include <security_utilities/debugging.h>
40 #include <security_utilities/logging.h>
41 #include <security_utilities/cfutilities.h>
42 #include <security_utilities/alloc.h>
43 #include <security_utilities/casts.h>
44 #include <utilities/SecCFRelease.h>
45 #include <Security/Authorization.h>
46 #include <Security/cssmapplePriv.h>
47 #include <Security/oidscert.h>
48 #include <Security/SecCertificatePriv.h>
49 #include <Security/SecPolicyPriv.h>
50 #include <security_keychain/KCCursor.h>
51 #include <security_ocspd/ocspdClient.h>
52 #include <CoreFoundation/CoreFoundation.h>
53 #include <security_utilities/simulatecrash_assert.h>
54 #include <dispatch/dispatch.h>
59 #define trustSettingsDbg(args...) syslog(LOG_ERR, ## args)
60 #define trustSettingsEvalDbg(args...) syslog(LOG_ERR, ## args)
62 #define trustSettingsDbg(args...) secinfo("trustSettings", ## args)
63 #define trustSettingsEvalDbg(args...) secinfo("trustSettingsEval", ## args)
67 * Common error return for "malformed TrustSettings record"
69 #define errSecInvalidTrustedRootRecord errSecInvalidTrustSettings
71 using namespace KeychainCore
;
73 #pragma mark --- Static functions ---
76 * Comparator atoms to determine if an app's specified usage
77 * matches an individual trust setting. Each returns true on a match, false
78 * if the trust setting does not match the app's spec.
82 * -- the app has specified a field, and the cert has a spec for that
83 * field, and the two specs do not match;
87 * -- the cert has a spec for the field and the app hasn't specified the field
89 static bool tsCheckPolicy(
90 const CSSM_OID
*appPolicy
,
93 if(certPolicy
!= NULL
) {
94 if(appPolicy
== NULL
) {
95 trustSettingsEvalDbg("tsCheckPolicy: certPolicy, !appPolicy");
98 unsigned cLen
= (unsigned)CFDataGetLength(certPolicy
);
99 const UInt8
*cData
= CFDataGetBytePtr(certPolicy
);
100 if((cLen
!= appPolicy
->Length
) || memcmp(appPolicy
->Data
, cData
, cLen
)) {
101 trustSettingsEvalDbg("tsCheckPolicy: policy mismatch");
109 * This one's slightly different: the match is for *this* app, not one
110 * specified by the app.
112 static bool tsCheckApp(
115 if(certApp
!= NULL
) {
116 SecTrustedApplicationRef appRef
;
118 ortn
= SecTrustedApplicationCreateWithExternalRepresentation(certApp
, &appRef
);
120 trustSettingsDbg("tsCheckApp: bad trustedApp data");
123 ortn
= SecTrustedApplicationValidateWithPath(appRef
, NULL
);
133 static bool tsCheckKeyUse(
134 SecTrustSettingsKeyUsage appKeyUse
,
135 CFNumberRef certKeyUse
)
137 if(certKeyUse
!= NULL
) {
139 CFNumberGetValue(certKeyUse
, kCFNumberSInt32Type
, &certUse
);
140 SecTrustSettingsKeyUsage cku
= (SecTrustSettingsKeyUsage
)certUse
;
141 if(cku
== kSecTrustSettingsKeyUseAny
) {
142 /* explicitly allows anything */
145 /* cert specification must be a superset of app's intended use */
147 trustSettingsEvalDbg("tsCheckKeyUse: certKeyUsage, !appKeyUsage");
151 if((cku
& appKeyUse
) != appKeyUse
) {
152 trustSettingsEvalDbg("tsCheckKeyUse: keyUse mismatch");
159 static bool tsCheckPolicyStr(
160 const char *appPolicyStr
,
161 CFStringRef certPolicyStr
)
163 if(certPolicyStr
!= NULL
) {
164 if(appPolicyStr
== NULL
) {
165 trustSettingsEvalDbg("tsCheckPolicyStr: certPolicyStr, !appPolicyStr");
168 /* Let CF do the string compare */
169 CFStringRef cfPolicyStr
= CFStringCreateWithCString(NULL
, appPolicyStr
,
170 kCFStringEncodingUTF8
);
171 if(cfPolicyStr
== NULL
) {
172 /* I really don't see how this can happen */
173 trustSettingsEvalDbg("tsCheckPolicyStr: policyStr string conversion error");
177 // Some trust setting strings were created with a NULL character at the
178 // end, which was included in the length. Strip those off before compare
180 CFMutableStringRef certPolicyStrNoNULL
= CFStringCreateMutableCopy(NULL
, 0, certPolicyStr
);
181 if (certPolicyStrNoNULL
== NULL
) {
182 /* I really don't see how this can happen either */
183 trustSettingsEvalDbg("tsCheckPolicyStr: policyStr string conversion error 2");
184 CFReleaseNull(cfPolicyStr
);
188 CFStringFindAndReplace(certPolicyStrNoNULL
, CFSTR("\00"),
189 CFSTR(""), CFRangeMake(0, CFStringGetLength(certPolicyStrNoNULL
)), kCFCompareBackwards
);
191 CFComparisonResult res
= CFStringCompare(cfPolicyStr
, certPolicyStrNoNULL
, 0);
192 CFRelease(cfPolicyStr
);
193 CFRelease(certPolicyStrNoNULL
);
194 if(res
!= kCFCompareEqualTo
) {
195 trustSettingsEvalDbg("tsCheckPolicyStr: policyStr mismatch");
203 * Determine if a cert's trust settings dictionary satisfies the specified
204 * usage constraints. Returns true if so.
205 * Only certs with a SecTrustSettingsResult of kSecTrustSettingsResultTrustRoot
206 * or kSecTrustSettingsResultTrustAsRoot will match.
208 static bool qualifyUsageWithCertDict(
209 CFDictionaryRef certDict
,
210 const CSSM_OID
*policyOID
, /* optional */
211 const char *policyStr
, /* optional */
212 SecTrustSettingsKeyUsage keyUsage
, /* optional; default = any (actually "all" here) */
215 /* this array is optional */
216 CFArrayRef trustSettings
= (CFArrayRef
)CFDictionaryGetValue(certDict
,
217 kTrustRecordTrustSettings
);
218 CFIndex numSpecs
= 0;
219 if(trustSettings
!= NULL
) {
220 numSpecs
= CFArrayGetCount(trustSettings
);
224 * Trivial case: cert has no trust settings, indicating that
225 * it's used for everything.
227 trustSettingsEvalDbg("qualifyUsageWithCertDict: no trust settings");
230 for(CFIndex addDex
=0; addDex
<numSpecs
; addDex
++) {
231 CFDictionaryRef tsDict
= (CFDictionaryRef
)CFArrayGetValueAtIndex(trustSettings
,
234 /* per-cert specs: all optional */
235 CFDataRef certPolicy
= (CFDataRef
)CFDictionaryGetValue(tsDict
,
236 kSecTrustSettingsPolicy
);
237 CFDataRef certApp
= (CFDataRef
)CFDictionaryGetValue(tsDict
,
238 kSecTrustSettingsApplication
);
239 CFStringRef certPolicyStr
= (CFStringRef
)CFDictionaryGetValue(tsDict
,
240 kSecTrustSettingsPolicyString
);
241 CFNumberRef certKeyUsage
= (CFNumberRef
)CFDictionaryGetValue(tsDict
,
242 kSecTrustSettingsKeyUsage
);
243 CFNumberRef certResultType
= (CFNumberRef
)CFDictionaryGetValue(tsDict
,
244 kSecTrustSettingsResult
);
246 if(!tsCheckPolicy(policyOID
, certPolicy
)) {
249 if(!tsCheckApp(certApp
)) {
252 if(!tsCheckKeyUse(keyUsage
, certKeyUsage
)) {
255 if(!tsCheckPolicyStr(policyStr
, certPolicyStr
)) {
260 * This is a match, take whatever SecTrustSettingsResult is here,
261 * including the default if not specified.
263 SecTrustSettingsResult resultType
= kSecTrustSettingsResultTrustRoot
;
266 CFNumberGetValue(certResultType
, kCFNumberSInt32Type
, &s
);
267 resultType
= (SecTrustSettingsResult
)s
;
270 case kSecTrustSettingsResultTrustRoot
:
271 trustSettingsEvalDbg("qualifyUsageWithCertDict: TrustRoot MATCH");
273 case kSecTrustSettingsResultTrustAsRoot
:
275 trustSettingsEvalDbg("qualifyUsageWithCertDict: TrustAsRoot but not root");
278 trustSettingsEvalDbg("qualifyUsageWithCertDict: TrustAsRoot MATCH");
281 trustSettingsEvalDbg("qualifyUsageWithCertDict: bad resultType "
282 "(%lu)", (unsigned long)resultType
);
286 trustSettingsEvalDbg("qualifyUsageWithCertDict: NO MATCH");
291 * Create initial top-level dictionary when constructing a new TrustSettings.
293 static CFMutableDictionaryRef
tsInitialDict()
295 CFMutableDictionaryRef dict
= CFDictionaryCreateMutable(NULL
,
296 kSecTrustRecordNumTopDictKeys
,
297 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
299 /* the dictionary of per-cert entries */
300 CFMutableDictionaryRef trustDict
= CFDictionaryCreateMutable(NULL
, 0,
301 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
302 CFDictionaryAddValue(dict
, kTrustRecordTrustList
, trustDict
);
303 CFRelease(trustDict
);
305 SInt32 vers
= kSecTrustRecordVersionCurrent
;
306 CFNumberRef cfVers
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &vers
);
307 CFDictionaryAddValue(dict
, kTrustRecordVersion
, cfVers
);
313 * Set the modification date of a per-cert dictionary to current time.
315 static void tsSetModDate(
316 CFMutableDictionaryRef dict
)
320 modDate
= CFDateCreate(NULL
, CFAbsoluteTimeGetCurrent());
321 CFDictionarySetValue(dict
, kTrustRecordModDate
, modDate
);
325 /* make sure a presumed CFNumber can be converted to a 32-bit number */
327 bool tsIsGoodCfNum(CFNumberRef cfn
, SInt32
*num
= NULL
)
336 if(CFGetTypeID(cfn
) != CFNumberGetTypeID()) {
341 if(!CFNumberGetValue(cfn
, kCFNumberSInt32Type
, &s
)) {
352 TrustSettings::TrustSettings(SecTrustSettingsDomain domain
)
363 #pragma mark --- Public methods ---
366 * Normal constructor, from disk.
367 * If create is true, the absence of an on-disk TrustSettings file
368 * results in the creation of a new empty TrustSettings. If create is
369 * false and no on-disk TrustSettings exists, errSecNoTrustSettings is
371 * If trim is true, the components of the on-disk TrustSettings not
372 * needed for cert evaluation are discarded. This is for TrustSettings
373 * that will be cached in memory long-term.
375 OSStatus
TrustSettings::CreateTrustSettings(
376 SecTrustSettingsDomain domain
,
381 TrustSettings
* t
= new TrustSettings(domain
);
383 Allocator
&alloc
= Allocator::standard();
384 CSSM_DATA fileData
= {0, NULL
};
385 OSStatus ortn
= errSecSuccess
;
389 /* get trust settings from file, one way or another */
391 case kSecTrustSettingsDomainAdmin
:
393 * Quickie optimization: if it's not there, don't try to
394 * get it from ocspd. This is possible because the name of the
395 * admin file is hard coded, but the per-user files aren't.
397 path
= TRUST_SETTINGS_PATH
"/" ADMIN_TRUST_SETTINGS
;
398 if(stat(path
, &sb
)) {
399 trustSettingsDbg("TrustSettings: no admin record; skipping");
400 ortn
= errSecNoTrustSettings
;
403 /* else drop thru, get it from ocspd */
404 case kSecTrustSettingsDomainUser
:
405 /* get settings from ocspd */
406 ortn
= ocspdTrustSettingsRead(alloc
, domain
, fileData
);
408 case kSecTrustSettingsDomainSystem
:
409 /* immutable; it's safe for us to read this directly */
410 if(tsReadFile(SYSTEM_TRUST_SETTINGS_PATH
, alloc
, fileData
)) {
411 ortn
= errSecNoTrustSettings
;
420 trustSettingsDbg("TrustSettings: creating new record for domain %d",
422 t
->mPropList
= tsInitialDict();
426 trustSettingsDbg("TrustSettings: record not found for domain %d",
433 CFRef
<CFDataRef
> propList(CFDataCreate(NULL
, fileData
.Data
, fileData
.Length
));
434 t
->initFromData(propList
);
435 alloc
.free(fileData
.Data
);
437 t
->validatePropList(trim
);
440 return errSecSuccess
;
444 * Create from external data, obtained by createExternal().
445 * If externalData is NULL, we'll create an empty mTrustDict.
447 OSStatus
TrustSettings::CreateTrustSettings(
448 SecTrustSettingsDomain domain
,
449 CFDataRef externalData
,
453 case kSecTrustSettingsDomainUser
:
454 case kSecTrustSettingsDomainAdmin
:
455 case kSecTrustSettingsDomainMemory
:
457 case kSecTrustSettingsDomainSystem
: /* no can do, that implies writing to it */
462 TrustSettings
* t
= new TrustSettings(domain
);
464 if(externalData
!= NULL
) {
465 t
->initFromData(externalData
);
468 t
->mPropList
= tsInitialDict();
470 t
->validatePropList(TRIM_NO
); /* never trim this */
474 return errSecSuccess
;
478 TrustSettings::~TrustSettings()
480 trustSettingsDbg("TrustSettings(domain %d) destructor", (int)mDomain
);
481 CFRELEASE(mPropList
); /* may be null if trimmed */
482 CFRELEASE(mTrustDict
); /* normally always non-NULL */
486 /* common code to init mPropList from raw data */
487 void TrustSettings::initFromData(
488 CFDataRef trustSettingsData
)
490 CFStringRef errStr
= NULL
;
492 mPropList
= (CFMutableDictionaryRef
)CFPropertyListCreateFromXMLData(
495 kCFPropertyListMutableContainersAndLeaves
,
497 if(mPropList
== NULL
) {
498 trustSettingsDbg("TrustSettings::initFromData decode err (%s)",
499 errStr
? CFStringGetCStringPtr(errStr
, kCFStringEncodingUTF8
) : "<no err>");
503 MacOSError::throwMe(errSecInvalidTrustSettings
);
508 * Flush property list data out to disk if dirty.
510 void TrustSettings::flushToDisk()
513 trustSettingsDbg("flushToDisk, domain %d, !dirty!", (int)mDomain
);
516 if(mPropList
== NULL
) {
517 trustSettingsDbg("flushToDisk, domain %d, trimmed!", (int)mDomain
);
519 MacOSError::throwMe(errSecInternalComponent
);
522 case kSecTrustSettingsDomainSystem
:
523 case kSecTrustSettingsDomainMemory
:
524 /* caller shouldn't even try this */
526 trustSettingsDbg("flushToDisk, bad domain (%d)", (int)mDomain
);
527 MacOSError::throwMe(errSecInternalComponent
);
528 case kSecTrustSettingsDomainUser
:
529 case kSecTrustSettingsDomainAdmin
:
534 * Optimization: if there are no certs in the mTrustDict dictionary,
535 * we tell ocspd to *remove* the settings for the specified domain.
536 * Having *no* settings uses less memory and is faster than having
537 * an empty settings file, especially for the admin domain, where we
539 * an RPC if the settings file is simply not there.
541 CFRef
<CFDataRef
> xmlData
;
542 CSSM_DATA cssmXmlData
= {0, NULL
};
543 CFIndex numCerts
= CFDictionaryGetCount(mTrustDict
);
545 xmlData
.take(CFPropertyListCreateXMLData(NULL
, mPropList
));
547 /* we've been very careful; this should never happen */
548 trustSettingsDbg("flushToDisk, domain %d: error converting to XML", (int)mDomain
);
549 MacOSError::throwMe(errSecInternalComponent
);
551 cssmXmlData
.Data
= (uint8
*)CFDataGetBytePtr(xmlData
);
552 cssmXmlData
.Length
= CFDataGetLength(xmlData
);
555 trustSettingsDbg("flushToDisk, domain %d: DELETING trust settings", (int)mDomain
);
558 /* cook up auth stuff so ocspd can act on our behalf */
559 AuthorizationRef authRef
;
561 ortn
= AuthorizationCreate(NULL
, kAuthorizationEmptyEnvironment
,
564 trustSettingsDbg("flushToDisk, domain %d: AuthorizationCreate returned %ld",
565 (int)mDomain
, (long)ortn
);
566 MacOSError::throwMe(errSecInternalComponent
);
568 AuthorizationExternalForm authExt
;
569 CSSM_DATA authBlob
= {sizeof(authExt
), (uint8
*)&authExt
};
570 ortn
= AuthorizationMakeExternalForm(authRef
, &authExt
);
572 trustSettingsDbg("flushToDisk, domain %d: AuthorizationMakeExternalForm returned %ld",
573 (int)mDomain
, (long)ortn
);
574 ortn
= errSecInternalComponent
;
578 ortn
= ocspdTrustSettingsWrite(mDomain
, authBlob
, cssmXmlData
);
580 trustSettingsDbg("flushToDisk, domain %d: ocspdTrustSettingsWrite returned %ld",
581 (int)mDomain
, (long)ortn
);
584 trustSettingsDbg("flushToDisk, domain %d: wrote to disk", (int)mDomain
);
587 AuthorizationFree(authRef
, 0);
589 MacOSError::throwMe(ortn
);
594 * Obtain external representation of TrustSettings data.
596 CFDataRef
TrustSettings::createExternal()
599 CFDataRef xmlData
= CFPropertyListCreateXMLData(NULL
, mPropList
);
600 if(xmlData
== NULL
) {
601 trustSettingsDbg("createExternal, domain %d: error converting to XML",
603 MacOSError::throwMe(errSecInternalComponent
);
609 * Evaluate specified cert. Returns true if we found a record for the cert
610 * matching specified constraints.
611 * Note that a true return with a value of kSecTrustSettingsResultUnspecified for
612 * the resultType means that a cert isn't to be trusted or untrusted
613 * per se; it just means that we only found allowedErrors entries.
615 * Found "allows errors" values are added to the incoming allowedErrors
616 * array which is reallocd as needed (and which may be NULL or non-NULL on
619 bool TrustSettings::evaluateCert(
620 CFStringRef certHashStr
,
621 const CSSM_OID
*policyOID
, /* optional */
622 const char *policyStr
, /* optional */
623 SecTrustSettingsKeyUsage keyUsage
, /* optional */
624 bool isRootCert
, /* for checking default setting */
625 CSSM_RETURN
**allowedErrors
, /* IN/OUT; reallocd as needed */
626 uint32
*numAllowedErrors
, /* IN/OUT */
627 SecTrustSettingsResult
*resultType
, /* RETURNED */
628 bool *foundAnyEntry
) /* RETURNED */
630 assert(mTrustDict
!= NULL
);
632 /* get trust settings dictionary for this cert */
633 CFDictionaryRef certDict
= findDictionaryForCertHash(certHashStr
);
635 /* @@@ debug only @@@ */
636 /* print certificate hash and found dictionary reference */
637 const size_t maxHashStrLen
= 512;
638 char *buf
= (char*)malloc(maxHashStrLen
);
640 if (!CFStringGetCString(certHashStr
, buf
, (CFIndex
)maxHashStrLen
, kCFStringEncodingUTF8
)) {
643 trustSettingsEvalDbg("evaluateCert for \"%s\", found dict %p", buf
, certDict
);
648 if(certDict
== NULL
) {
649 *foundAnyEntry
= false;
652 *foundAnyEntry
= true;
654 /* to-be-returned array of allowed errors */
655 CSSM_RETURN
*allowedErrs
= *allowedErrors
;
656 uint32 numAllowedErrs
= *numAllowedErrors
;
658 /* this means "we found something other than allowedErrors" if true */
659 bool foundSettings
= false;
661 /* to be returned in *resultType if it ends up something other than Invalid */
662 SecTrustSettingsResult returnedResult
= kSecTrustSettingsResultInvalid
;
665 * Note since we validated the entire mPropList in our constructor, and we're careful
666 * about what we put into it, we don't bother typechecking its contents here.
667 * Also note that the kTrustRecordTrustSettings entry is optional.
669 CFArrayRef trustSettings
= (CFArrayRef
)CFDictionaryGetValue(certDict
,
670 kTrustRecordTrustSettings
);
671 CFIndex numSpecs
= 0;
672 if(trustSettings
!= NULL
) {
673 numSpecs
= CFArrayGetCount(trustSettings
);
677 * Trivial case: cert has no trust settings, indicating that
678 * it's used for everything.
680 trustSettingsEvalDbg("evaluateCert: no trust settings");
682 *resultType
= kSecTrustSettingsResultTrustRoot
;
687 * The decidedly nontrivial part: grind thru all of the cert's trust
688 * settings, see if the cert matches the caller's specified usage.
690 for(CFIndex addDex
=0; addDex
<numSpecs
; addDex
++) {
691 CFDictionaryRef tsDict
= (CFDictionaryRef
)CFArrayGetValueAtIndex(trustSettings
,
694 /* per-cert specs: all optional */
695 CFDataRef certPolicy
= (CFDataRef
)CFDictionaryGetValue(tsDict
,
696 kSecTrustSettingsPolicy
);
697 CFDataRef certApp
= (CFDataRef
)CFDictionaryGetValue(tsDict
,
698 kSecTrustSettingsApplication
);
699 CFStringRef certPolicyStr
= (CFStringRef
)CFDictionaryGetValue(tsDict
,
700 kSecTrustSettingsPolicyString
);
701 CFNumberRef certKeyUsage
= (CFNumberRef
)CFDictionaryGetValue(tsDict
,
702 kSecTrustSettingsKeyUsage
);
703 CFNumberRef certResultType
= (CFNumberRef
)CFDictionaryGetValue(tsDict
,
704 kSecTrustSettingsResult
);
705 CFNumberRef certAllowedErr
= (CFNumberRef
)CFDictionaryGetValue(tsDict
,
706 kSecTrustSettingsAllowedError
);
708 /* now, skip if we find a constraint that doesn't match intended use */
709 if(!tsCheckPolicy(policyOID
, certPolicy
)) {
712 if(!tsCheckApp(certApp
)) {
715 if(!tsCheckKeyUse(keyUsage
, certKeyUsage
)) {
718 if(!tsCheckPolicyStr(policyStr
, certPolicyStr
)) {
722 trustSettingsEvalDbg("evaluateCert: MATCH");
723 foundSettings
= true;
726 /* note we already validated this value */
728 CFNumberGetValue(certAllowedErr
, kCFNumberSInt32Type
, &s
);
729 allowedErrs
= (CSSM_RETURN
*)::realloc(allowedErrs
,
730 ++numAllowedErrs
* sizeof(CSSM_RETURN
));
731 allowedErrs
[numAllowedErrs
-1] = (CSSM_RETURN
) s
;
735 * We found a match, but we only return the current result type
736 * to caller if we haven't already returned something other than
737 * kSecTrustSettingsResultUnspecified. Once we find a valid result type,
738 * we keep on searching, but only for additional allowed errors.
740 switch(returnedResult
) {
741 /* found match but no valid resultType yet */
742 case kSecTrustSettingsResultUnspecified
:
743 /* haven't been thru here */
744 case kSecTrustSettingsResultInvalid
:
746 /* note we already validated this */
748 CFNumberGetValue(certResultType
, kCFNumberSInt32Type
, &s
);
749 returnedResult
= (SecTrustSettingsResult
)s
;
752 /* default is "copacetic" */
753 returnedResult
= kSecTrustSettingsResultTrustRoot
;
757 /* we already have a definitive resultType, don't change it */
760 } /* for each dictionary in trustSettings */
762 *allowedErrors
= allowedErrs
;
763 *numAllowedErrors
= numAllowedErrs
;
764 if(returnedResult
!= kSecTrustSettingsResultInvalid
) {
765 *resultType
= returnedResult
;
767 return foundSettings
;
772 * Find all certs in specified keychain list which have entries in this trust record.
773 * Certs already in the array are not added.
775 void TrustSettings::findCerts(
776 StorageManager::KeychainList
&keychains
,
777 CFMutableArrayRef certArray
)
779 findQualifiedCerts(keychains
,
781 false, /* onlyRoots */
782 NULL
, NULL
, kSecTrustSettingsKeyUseAny
,
786 void TrustSettings::findQualifiedCerts(
787 StorageManager::KeychainList
&keychains
,
789 * If findAll is true, all certs are returned and the subsequent
790 * qualifiers are ignored
793 /* if true, only return root (self-signed) certs */
795 const CSSM_OID
*policyOID
, /* optional */
796 const char *policyString
, /* optional */
797 SecTrustSettingsKeyUsage keyUsage
, /* optional */
798 CFMutableArrayRef certArray
) /* certs appended here */
800 StLock
<Mutex
> _(SecTrustKeychainsGetMutex());
803 * a set, hopefully with a good hash function for CFData, to keep track of what's
804 * been added to the outgoing array.
806 CFRef
<CFMutableSetRef
> certSet(CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
));
808 /* search: all certs, no attributes */
809 KCCursor
cursor(keychains
, (SecItemClass
) CSSM_DL_DB_RECORD_X509_CERTIFICATE
, NULL
);
812 unsigned int total
=0, entries
=0, qualified
=0;
814 found
= cursor
->next(certItem
);
820 /* must convert to unified SecCertificateRef */
821 SecPointer
<Certificate
> certificate(static_cast<Certificate
*>(&*certItem
));
822 CssmData certCssmData
;
824 certCssmData
= certificate
->data();
827 if (!(certCssmData
.Data
&& certCssmData
.Length
)) {
830 CFRef
<CFDataRef
> cfDataRef(CFDataCreate(NULL
, certCssmData
.Data
, certCssmData
.Length
));
831 CFRef
<SecCertificateRef
> certRef(SecCertificateCreateWithData(NULL
, cfDataRef
));
833 /* do we have an entry for this cert? */
834 CFDictionaryRef certDict
= findDictionaryForCert(certRef
);
835 if(certDict
== NULL
) {
842 if(!qualifyUsageWithCertDict(certDict
, policyOID
,
843 policyString
, keyUsage
, onlyRoots
)) {
849 /* see if we already have this one - get in CFData form */
851 OSStatus ortn
= SecCertificateGetData(certRef
, &certData
);
853 trustSettingsEvalDbg("findQualifiedCerts: SecCertificateGetData error");
856 CFRef
<CFDataRef
> cfData(CFDataCreate(NULL
, certData
.Data
, certData
.Length
));
857 CFDataRef cfd
= cfData
.get();
858 if(CFSetContainsValue(certSet
, cfd
)) {
859 trustSettingsEvalDbg("findQualifiedCerts: dup cert");
863 /* add to the tracking set, which owns the CFData now */
864 CFSetAddValue(certSet
, cfd
);
865 /* and add the SecCert to caller's array, which owns that now */
866 CFArrayAppendValue(certArray
, certRef
);
870 trustSettingsEvalDbg("findQualifiedCerts: examined %d certs, qualified %d of %d",
871 total
, qualified
, entries
);
875 * Obtain trust settings for the specified cert. Returned settings array
876 * is in the public API form; caller must release. Returns NULL
877 * (does not throw) if the cert is not present in this TrustRecord.
879 CFArrayRef
TrustSettings::copyTrustSettings(
880 SecCertificateRef certRef
)
882 CFDictionaryRef certDict
= NULL
;
884 /* find the on-disk usage constraints for this cert */
885 certDict
= findDictionaryForCert(certRef
);
886 if(certDict
== NULL
) {
887 trustSettingsDbg("copyTrustSettings: dictionary not found");
890 CFArrayRef diskTrustSettings
= (CFArrayRef
)CFDictionaryGetValue(certDict
,
891 kTrustRecordTrustSettings
);
892 CFIndex numSpecs
= 0;
893 if(diskTrustSettings
!= NULL
) {
894 /* this field is optional */
895 numSpecs
= CFArrayGetCount(diskTrustSettings
);
899 * Convert to API-style array of dictionaries.
900 * We give the caller an array even if it's empty.
902 CFRef
<CFMutableArrayRef
> outArray(CFArrayCreateMutable(NULL
, numSpecs
,
903 &kCFTypeArrayCallBacks
));
904 for(CFIndex dex
=0; dex
<numSpecs
; dex
++) {
905 CFDictionaryRef diskTsDict
=
906 (CFDictionaryRef
)CFArrayGetValueAtIndex(diskTrustSettings
, dex
);
907 /* already validated... */
908 assert(CFGetTypeID(diskTsDict
) == CFDictionaryGetTypeID());
910 CFTypeRef certPolicy
= (CFTypeRef
) CFDictionaryGetValue(diskTsDict
, kSecTrustSettingsPolicy
);
911 CFStringRef policyName
= (CFStringRef
)CFDictionaryGetValue(diskTsDict
, kSecTrustSettingsPolicyName
);
912 CFDataRef certApp
= (CFDataRef
) CFDictionaryGetValue(diskTsDict
, kSecTrustSettingsApplication
);
913 CFStringRef policyStr
= (CFStringRef
)CFDictionaryGetValue(diskTsDict
, kSecTrustSettingsPolicyString
);
914 CFNumberRef allowedErr
= (CFNumberRef
)CFDictionaryGetValue(diskTsDict
, kSecTrustSettingsAllowedError
);
915 CFNumberRef resultType
= (CFNumberRef
)CFDictionaryGetValue(diskTsDict
, kSecTrustSettingsResult
);
916 CFNumberRef keyUsage
= (CFNumberRef
)CFDictionaryGetValue(diskTsDict
, kSecTrustSettingsKeyUsage
);
918 if((certPolicy
== NULL
) &&
920 (policyStr
== NULL
) &&
921 (allowedErr
== NULL
) &&
922 (resultType
== NULL
) &&
923 (keyUsage
== NULL
)) {
924 /* weird but legal */
927 CFRef
<CFMutableDictionaryRef
> outTsDict(CFDictionaryCreateMutable(NULL
,
929 &kCFTypeDictionaryKeyCallBacks
,
930 &kCFTypeDictionaryValueCallBacks
));
932 if(certPolicy
!= NULL
) {
933 SecPolicyRef policyRef
= NULL
;
934 if (CFDataGetTypeID() == CFGetTypeID(certPolicy
)) {
935 /* convert OID as CFDataRef to SecPolicyRef */
936 CSSM_OID policyOid
= { int_cast
<CFIndex
, CSSM_SIZE
>(CFDataGetLength((CFDataRef
)certPolicy
)),
937 (uint8
*)CFDataGetBytePtr((CFDataRef
)certPolicy
) };
938 OSStatus ortn
= SecPolicyCopy(CSSM_CERT_X_509v3
, &policyOid
, &policyRef
);
940 trustSettingsDbg("copyTrustSettings: OID conversion error");
941 abort("Bad Policy OID in trusted root list", errSecInvalidTrustedRootRecord
);
943 } else if (CFStringGetTypeID() == CFGetTypeID(certPolicy
)) {
944 policyRef
= SecPolicyCreateWithProperties(certPolicy
, NULL
);
947 CFDictionaryAddValue(outTsDict
, kSecTrustSettingsPolicy
, policyRef
);
948 CFRelease(policyRef
); // owned by dictionary
952 if (policyName
!= NULL
) {
954 * copy, since policyName is in our mutable dictionary and could change out from
957 CFStringRef str
= CFStringCreateCopy(NULL
, policyName
);
958 CFDictionaryAddValue(outTsDict
, kSecTrustSettingsPolicyName
, str
);
959 CFRelease(str
); // owned by dictionary
962 if(certApp
!= NULL
) {
963 /* convert app as CFDataRef to SecTrustedApplicationRef */
964 SecTrustedApplicationRef appRef
;
965 OSStatus ortn
= SecTrustedApplicationCreateWithExternalRepresentation(certApp
, &appRef
);
967 trustSettingsDbg("copyTrustSettings: App conversion error");
968 abort("Bad application data in trusted root list", errSecInvalidTrustedRootRecord
);
970 CFDictionaryAddValue(outTsDict
, kSecTrustSettingsApplication
, appRef
);
971 CFRelease(appRef
); // owned by dictionary
974 /* remaining 4 are trivial */
975 if(policyStr
!= NULL
) {
977 * copy, since policyStr is in our mutable dictionary and could change out from
980 CFStringRef str
= CFStringCreateCopy(NULL
, policyStr
);
981 CFDictionaryAddValue(outTsDict
, kSecTrustSettingsPolicyString
, str
);
982 CFRelease(str
); // owned by dictionary
984 if(allowedErr
!= NULL
) {
985 /* there is no mutable CFNumber, so.... */
986 CFDictionaryAddValue(outTsDict
, kSecTrustSettingsAllowedError
, allowedErr
);
988 if(resultType
!= NULL
) {
989 CFDictionaryAddValue(outTsDict
, kSecTrustSettingsResult
, resultType
);
991 if(keyUsage
!= NULL
) {
992 CFDictionaryAddValue(outTsDict
, kSecTrustSettingsKeyUsage
, keyUsage
);
994 CFArrayAppendValue(outArray
, outTsDict
);
995 /* outTsDict autoreleases; owned by outArray now */
997 CFRetain(outArray
); // now that it's good to go....
1001 CFDateRef
TrustSettings::copyModDate(
1002 SecCertificateRef certRef
)
1004 CFDictionaryRef certDict
= NULL
;
1006 /* find the on-disk usage constraints dictionary for this cert */
1007 certDict
= findDictionaryForCert(certRef
);
1008 if(certDict
== NULL
) {
1009 trustSettingsDbg("copyModDate: dictionary not found");
1012 CFDateRef modDate
= (CFDateRef
)CFDictionaryGetValue(certDict
, kTrustRecordModDate
);
1013 if(modDate
== NULL
) {
1017 /* this only works becuase there is no mutable CFDateRef */
1022 bool TrustSettings::contains(SecCertificateRef certRef
)
1024 if(findDictionaryForCert(certRef
) != NULL
) {
1031 * Modify cert's trust settings, or add a new cert to the record.
1033 void TrustSettings::setTrustSettings(
1034 SecCertificateRef certRef
,
1035 CFTypeRef trustSettingsDictOrArray
)
1037 /* to validate, we need to know if the cert is self-signed */
1039 Boolean isSelfSigned
= false;
1041 if(certRef
== kSecTrustSettingsDefaultRootCertSetting
) {
1043 * Validate settings as if this were root, specifically,
1044 * kSecTrustSettingsResultTrustRoot (explicitly or by
1047 isSelfSigned
= true;
1050 ortn
= SecCertificateIsSelfSigned(certRef
, &isSelfSigned
);
1052 MacOSError::throwMe(ortn
);
1056 /* caller's app/policy spec OK? */
1057 CFRef
<CFArrayRef
> trustSettings(validateApiTrustSettings(
1058 trustSettingsDictOrArray
, isSelfSigned
));
1060 /* caller is responsible for ensuring these */
1061 assert(mPropList
!= NULL
);
1062 assert(mDomain
!= kSecTrustSettingsDomainSystem
);
1064 /* extract issuer and serial number from the cert, if it's a cert */
1065 CFRef
<CFDataRef
> issuer
;
1066 CFRef
<CFDataRef
> serial
;
1067 if(certRef
!= kSecTrustSettingsDefaultRootCertSetting
) {
1068 copyIssuerAndSerial(certRef
, issuer
.take(), serial
.take());
1072 issuer
= CFDataCreate(NULL
, &dummy
, 0);
1073 serial
= CFDataCreate(NULL
, &dummy
, 0);
1076 /* SHA1 digest as string */
1077 CFRef
<CFStringRef
> certHashStr(SecTrustSettingsCertHashStrFromCert(certRef
));
1079 trustSettingsDbg("TrustSettings::setTrustSettings: CertHashStrFromCert error");
1080 MacOSError::throwMe(errSecItemNotFound
);
1084 * Find entry for this cert, if present.
1086 CFMutableDictionaryRef certDict
=
1087 (CFMutableDictionaryRef
)findDictionaryForCertHash(certHashStr
);
1088 if(certDict
== NULL
) {
1089 /* create new dictionary */
1090 certDict
= CFDictionaryCreateMutable(NULL
, kSecTrustRecordNumCertDictKeys
,
1091 &kCFCopyStringDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1092 if(certDict
== NULL
) {
1093 MacOSError::throwMe(errSecAllocate
);
1095 CFDictionaryAddValue(certDict
, kTrustRecordIssuer
, issuer
);
1096 CFDictionaryAddValue(certDict
, kTrustRecordSerialNumber
, serial
);
1097 if(CFArrayGetCount(trustSettings
) != 0) {
1098 /* skip this if the settings array is empty */
1099 CFDictionaryAddValue(certDict
, kTrustRecordTrustSettings
, trustSettings
);
1101 tsSetModDate(certDict
);
1103 /* add this new cert dictionary to top-level mTrustDict */
1104 CFDictionaryAddValue(mTrustDict
, static_cast<CFStringRef
>(certHashStr
), certDict
);
1106 /* mTrustDict owns the dictionary now */
1107 CFRelease(certDict
);
1111 tsSetModDate(certDict
);
1112 if(CFArrayGetCount(trustSettings
) != 0) {
1113 CFDictionarySetValue(certDict
, kTrustRecordTrustSettings
, trustSettings
);
1116 /* empty settings array: remove from dictionary */
1117 CFDictionaryRemoveValue(certDict
, kTrustRecordTrustSettings
);
1124 * Delete a certificate's trust settings.
1126 void TrustSettings::deleteTrustSettings(
1127 SecCertificateRef certRef
)
1129 CFDictionaryRef certDict
= NULL
;
1131 /* caller is responsible for ensuring these */
1132 assert(mPropList
!= NULL
);
1133 assert(mDomain
!= kSecTrustSettingsDomainSystem
);
1135 /* SHA1 digest as string */
1136 CFRef
<CFStringRef
> certHashStr(SecTrustSettingsCertHashStrFromCert(certRef
));
1138 MacOSError::throwMe(errSecItemNotFound
);
1141 /* present in top-level mTrustDict? */
1142 certDict
= findDictionaryForCertHash(certHashStr
);
1143 if(certDict
!= NULL
) {
1144 CFDictionaryRemoveValue(mTrustDict
, static_cast<CFStringRef
>(certHashStr
));
1149 * Throwing this error is the only reason we don't blindly do
1150 * a CFDictionaryRemoveValue() without first doing
1151 * findDictionaryForCertHash().
1153 trustSettingsDbg("TrustSettings::deleteRoot: cert dictionary not found");
1154 MacOSError::throwMe(errSecItemNotFound
);
1158 #pragma mark --- Private methods ---
1161 * Find a given cert's entry in the top-level mTrustDict. Return the
1162 * entry as a dictionary. Returned dictionary is not refcounted.
1163 * The mutability of the returned dictionary is the same as the mutability
1164 * of the underlying StickRecord::mPropList, which the caller is just
1165 * going to have to know (and cast accordingly if a mutable dictionary
1168 CFDictionaryRef
TrustSettings::findDictionaryForCert(
1169 SecCertificateRef certRef
)
1171 CFRef
<CFStringRef
> certHashStr(SecTrustSettingsCertHashStrFromCert(certRef
));
1172 if (certHashStr
.get() == NULL
)
1177 return findDictionaryForCertHash(static_cast<CFStringRef
>(certHashStr
.get()));
1181 * Find entry in mTrustDict given cert hash string.
1183 CFDictionaryRef
TrustSettings::findDictionaryForCertHash(
1184 CFStringRef certHashStr
)
1186 assert(mTrustDict
!= NULL
);
1187 return (CFDictionaryRef
)CFDictionaryGetValue(mTrustDict
, certHashStr
);
1191 * Validate incoming trust settings, which may be NULL, a dictionary, or
1192 * an array of dictionaries. Convert from the API-style dictionaries
1193 * to the internal style suitable for writing to disk as part of
1196 * We return a refcounted CFArray in any case if the incoming parameter is good.
1198 CFArrayRef
TrustSettings::validateApiTrustSettings(
1199 CFTypeRef trustSettingsDictOrArray
,
1200 Boolean isSelfSigned
)
1202 CFArrayRef tmpInArray
= NULL
;
1204 if(trustSettingsDictOrArray
== NULL
) {
1205 /* trivial case, only valid for roots */
1207 trustSettingsDbg("validateApiUsageConstraints: !isSelfSigned, no settings");
1208 MacOSError::throwMe(errSecParam
);
1210 return CFArrayCreate(NULL
, NULL
, 0, &kCFTypeArrayCallBacks
);
1212 else if(CFGetTypeID(trustSettingsDictOrArray
) == CFDictionaryGetTypeID()) {
1214 tmpInArray
= CFArrayCreate(NULL
, &trustSettingsDictOrArray
, 1,
1215 &kCFTypeArrayCallBacks
);
1217 else if(CFGetTypeID(trustSettingsDictOrArray
) == CFArrayGetTypeID()) {
1218 /* as is, refcount - we'll release later */
1219 tmpInArray
= (CFArrayRef
)trustSettingsDictOrArray
;
1220 CFRetain(tmpInArray
);
1223 trustSettingsDbg("validateApiUsageConstraints: bad trustSettingsDictOrArray");
1224 MacOSError::throwMe(errSecParam
);
1227 CFIndex numSpecs
= CFArrayGetCount(tmpInArray
);
1228 CFMutableArrayRef outArray
= CFArrayCreateMutable(NULL
, numSpecs
, &kCFTypeArrayCallBacks
);
1230 OSStatus ortn
= errSecSuccess
;
1231 SecPolicyRef certPolicy
;
1232 SecTrustedApplicationRef certApp
;
1233 CFTypeRef oidData
= NULL
;
1236 for(CFIndex dex
=0; dex
<numSpecs
; dex
++) {
1237 CFStringRef policyName
= NULL
;
1238 CFDataRef appData
= NULL
;
1239 CFStringRef policyStr
= NULL
;
1240 CFNumberRef allowedErr
= NULL
;
1241 CFNumberRef resultType
= NULL
;
1242 CFNumberRef keyUsage
= NULL
;
1244 SecTrustSettingsResult result
;
1246 /* each element is a dictionary */
1247 CFDictionaryRef ucDict
= (CFDictionaryRef
)CFArrayGetValueAtIndex(tmpInArray
, dex
);
1248 if(CFGetTypeID(ucDict
) != CFDictionaryGetTypeID()) {
1249 trustSettingsDbg("validateAppPolicyArray: malformed usageConstraint dictionary");
1254 /* policy - optional */
1255 certPolicy
= (SecPolicyRef
)CFDictionaryGetValue(ucDict
, kSecTrustSettingsPolicy
);
1256 if(certPolicy
!= NULL
) {
1257 if(CFGetTypeID(certPolicy
) != SecPolicyGetTypeID()) {
1258 trustSettingsDbg("validateAppPolicyArray: malformed certPolicy");
1262 ortn
= SecPolicyGetOID(certPolicy
, &oid
);
1264 /* newer policies don't have CSSM OIDs but they do have string OIDs */
1265 oidData
= CFRetain(SecPolicyGetOidString(certPolicy
));
1267 oidData
= CFDataCreate(NULL
, oid
.Data
, oid
.Length
);
1271 trustSettingsDbg("validateAppPolicyArray: SecPolicyGetOID error");
1274 policyName
= SecPolicyGetName(certPolicy
);
1277 /* application - optional */
1278 certApp
= (SecTrustedApplicationRef
)CFDictionaryGetValue(ucDict
, kSecTrustSettingsApplication
);
1279 if(certApp
!= NULL
) {
1280 if(CFGetTypeID(certApp
) != SecTrustedApplicationGetTypeID()) {
1281 trustSettingsDbg("validateAppPolicyArray: malformed certApp");
1285 ortn
= SecTrustedApplicationCopyExternalRepresentation(certApp
, &appData
);
1287 trustSettingsDbg("validateAppPolicyArray: "
1288 "SecTrustedApplicationCopyExternalRepresentation error");
1293 policyStr
= (CFStringRef
)CFDictionaryGetValue(ucDict
, kSecTrustSettingsPolicyString
);
1294 if(policyStr
!= NULL
) {
1295 if(CFGetTypeID(policyStr
) != CFStringGetTypeID()) {
1296 trustSettingsDbg("validateAppPolicyArray: malformed policyStr");
1301 allowedErr
= (CFNumberRef
)CFDictionaryGetValue(ucDict
, kSecTrustSettingsAllowedError
);
1302 if(!tsIsGoodCfNum(allowedErr
)) {
1303 trustSettingsDbg("validateAppPolicyArray: malformed allowedErr");
1307 resultType
= (CFNumberRef
)CFDictionaryGetValue(ucDict
, kSecTrustSettingsResult
);
1308 if(!tsIsGoodCfNum(resultType
, &resultNum
)) {
1309 trustSettingsDbg("validateAppPolicyArray: malformed resultType");
1313 result
= (SecTrustSettingsResult
) resultNum
;
1314 /* validate result later */
1316 keyUsage
= (CFNumberRef
)CFDictionaryGetValue(ucDict
, kSecTrustSettingsKeyUsage
);
1317 if(!tsIsGoodCfNum(keyUsage
)) {
1318 trustSettingsDbg("validateAppPolicyArray: malformed keyUsage");
1323 if(!oidData
&& !appData
&& !policyStr
&&
1324 !allowedErr
&& !resultType
&& !keyUsage
) {
1325 /* nothing here - weird, but legal - skip it */
1329 /* create dictionary for this usageConstraint */
1330 CFMutableDictionaryRef outDict
= CFDictionaryCreateMutable(NULL
,
1332 &kCFTypeDictionaryKeyCallBacks
,
1333 &kCFTypeDictionaryValueCallBacks
);
1335 CFDictionaryAddValue(outDict
, kSecTrustSettingsPolicy
, oidData
);
1336 CFReleaseNull(oidData
); // owned by dictionary
1339 CFDictionaryAddValue(outDict
, kSecTrustSettingsPolicyName
, policyName
);
1340 /* still owned by ucDict */
1343 CFDictionaryAddValue(outDict
, kSecTrustSettingsApplication
, appData
);
1344 CFRelease(appData
); // owned by dictionary
1347 CFDictionaryAddValue(outDict
, kSecTrustSettingsPolicyString
, policyStr
);
1348 /* still owned by ucDict */
1351 CFDictionaryAddValue(outDict
, kSecTrustSettingsAllowedError
, allowedErr
);
1354 ortn
= errSecSuccess
;
1357 /* let's be really picky on this one */
1359 case kSecTrustSettingsResultInvalid
:
1362 case kSecTrustSettingsResultTrustRoot
:
1364 trustSettingsDbg("validateAppPolicyArray: TrustRoot, !isSelfSigned");
1368 case kSecTrustSettingsResultTrustAsRoot
:
1370 trustSettingsDbg("validateAppPolicyArray: TrustAsRoot, isSelfSigned");
1374 case kSecTrustSettingsResultDeny
:
1375 case kSecTrustSettingsResultUnspecified
:
1378 trustSettingsDbg("validateAppPolicyArray: bogus resultType");
1385 CFDictionaryAddValue(outDict
, kSecTrustSettingsResult
, resultType
);
1388 /* no resultType; default of TrustRoot only valid for root */
1390 trustSettingsDbg("validateAppPolicyArray: default result, !isSelfSigned");
1397 CFDictionaryAddValue(outDict
, kSecTrustSettingsKeyUsage
, keyUsage
);
1400 /* append dictionary to output */
1401 CFArrayAppendValue(outArray
, outDict
);
1402 /* array owns the dictionary now */
1405 } /* for each usage constraint dictionary */
1407 CFReleaseNull(oidData
);
1408 CFRelease(tmpInArray
);
1410 CFRelease(outArray
);
1411 MacOSError::throwMe(ortn
);
1417 * Validate an trust settings array obtained from disk.
1418 * Returns true if OK, else returns false.
1420 bool TrustSettings::validateTrustSettingsArray(
1421 CFArrayRef trustSettings
)
1423 CFIndex numSpecs
= CFArrayGetCount(trustSettings
);
1424 for(CFIndex dex
=0; dex
<numSpecs
; dex
++) {
1425 CFDictionaryRef ucDict
= (CFDictionaryRef
)CFArrayGetValueAtIndex(trustSettings
,
1427 if(CFGetTypeID(ucDict
) != CFDictionaryGetTypeID()) {
1428 trustSettingsDbg("validateAppPolicyArray: malformed app/policy dictionary");
1431 CFDataRef certPolicy
= (CFDataRef
)CFDictionaryGetValue(ucDict
, kSecTrustSettingsPolicy
);
1432 if((certPolicy
!= NULL
) && (CFGetTypeID(certPolicy
) != CFDataGetTypeID())) {
1433 trustSettingsDbg("validateAppPolicyArray: malformed certPolicy");
1436 CFDataRef certApp
= (CFDataRef
)CFDictionaryGetValue(ucDict
, kSecTrustSettingsApplication
);
1437 if((certApp
!= NULL
) && (CFGetTypeID(certApp
) != CFDataGetTypeID())) {
1438 trustSettingsDbg("validateAppPolicyArray: malformed certApp");
1441 CFStringRef policyStr
= (CFStringRef
)CFDictionaryGetValue(ucDict
, kSecTrustSettingsPolicyString
);
1442 if((policyStr
!= NULL
) && (CFGetTypeID(policyStr
) != CFStringGetTypeID())) {
1443 trustSettingsDbg("validateAppPolicyArray: malformed policyStr");
1446 CFNumberRef cfNum
= (CFNumberRef
)CFDictionaryGetValue(ucDict
, kSecTrustSettingsAllowedError
);
1447 if(!tsIsGoodCfNum(cfNum
)) {
1448 trustSettingsDbg("validateAppPolicyArray: malformed allowedErr");
1451 cfNum
= (CFNumberRef
)CFDictionaryGetValue(ucDict
, kSecTrustSettingsResult
);
1452 if(!tsIsGoodCfNum(cfNum
)) {
1453 trustSettingsDbg("validateAppPolicyArray: malformed resultType");
1456 cfNum
= (CFNumberRef
)CFDictionaryGetValue(ucDict
, kSecTrustSettingsKeyUsage
);
1457 if(!tsIsGoodCfNum(cfNum
)) {
1458 trustSettingsDbg("validateAppPolicyArray: malformed keyUsage");
1461 } /* for each usageConstraint dictionary */
1466 * Validate mPropList after it's read from disk or supplied as an external
1467 * representation. Allows subsequent use of mTrustDict to proceed with
1468 * relative impunity.
1470 void TrustSettings::validatePropList(bool trim
)
1472 /* top level dictionary */
1474 trustSettingsDbg("TrustSettings::validatePropList missing mPropList");
1475 abort("missing propList", errSecInvalidTrustedRootRecord
);
1478 if(CFGetTypeID(mPropList
) != CFDictionaryGetTypeID()) {
1479 trustSettingsDbg("TrustSettings::validatePropList: malformed mPropList");
1480 abort("malformed propList", errSecInvalidTrustedRootRecord
);
1483 /* That dictionary has two entries */
1484 CFNumberRef cfVers
= (CFNumberRef
)CFDictionaryGetValue(mPropList
, kTrustRecordVersion
);
1485 if((cfVers
== NULL
) || (CFGetTypeID(cfVers
) != CFNumberGetTypeID())) {
1486 trustSettingsDbg("TrustSettings::validatePropList: malformed version");
1487 abort("malformed version", errSecInvalidTrustedRootRecord
);
1489 if(!CFNumberGetValue(cfVers
, kCFNumberSInt32Type
, &mDictVersion
)) {
1490 trustSettingsDbg("TrustSettings::validatePropList: malformed version");
1491 abort("malformed version", errSecInvalidTrustedRootRecord
);
1493 if((mDictVersion
> kSecTrustRecordVersionCurrent
) ||
1494 (mDictVersion
== kSecTrustRecordVersionInvalid
)) {
1495 trustSettingsDbg("TrustSettings::validatePropList: incompatible version");
1496 abort("incompatible version", errSecInvalidTrustedRootRecord
);
1498 /* other backwards-compatibility handling done later, if needed, per mDictVersion */
1500 mTrustDict
= (CFMutableDictionaryRef
)CFDictionaryGetValue(mPropList
, kTrustRecordTrustList
);
1501 if(mTrustDict
!= NULL
) {
1502 CFRetain(mTrustDict
);
1504 if((mTrustDict
== NULL
) || (CFGetTypeID(mTrustDict
) != CFDictionaryGetTypeID())) {
1505 trustSettingsDbg("TrustSettings::validatePropList: malformed mTrustDict");
1506 abort("malformed TrustArray", errSecInvalidTrustedRootRecord
);
1509 /* grind through the per-cert entries */
1510 CFIndex numCerts
= CFDictionaryGetCount(mTrustDict
);
1511 const void *dictKeys
[numCerts
];
1512 const void *dictValues
[numCerts
];
1513 CFDictionaryGetKeysAndValues(mTrustDict
, dictKeys
, dictValues
);
1515 for(CFIndex dex
=0; dex
<numCerts
; dex
++) {
1516 /* get per-cert dictionary */
1517 CFMutableDictionaryRef certDict
= (CFMutableDictionaryRef
)dictValues
[dex
];
1518 if((certDict
== NULL
) || (CFGetTypeID(certDict
) != CFDictionaryGetTypeID())) {
1519 trustSettingsDbg("TrustSettings::validatePropList: malformed certDict");
1520 abort("malformed certDict", errSecInvalidTrustedRootRecord
);
1524 * That dictionary has exactly four entries.
1525 * If we're trimming, all we need is the actual trust settings.
1529 CFDataRef cfd
= (CFDataRef
)CFDictionaryGetValue(certDict
, kTrustRecordIssuer
);
1531 trustSettingsDbg("TrustSettings::validatePropList: missing issuer");
1532 abort("missing issuer", errSecInvalidTrustedRootRecord
);
1534 if(CFGetTypeID(cfd
) != CFDataGetTypeID()) {
1535 trustSettingsDbg("TrustSettings::validatePropList: malformed issuer");
1536 abort("malformed issuer", errSecInvalidTrustedRootRecord
);
1539 CFDictionaryRemoveValue(certDict
, kTrustRecordIssuer
);
1543 cfd
= (CFDataRef
)CFDictionaryGetValue(certDict
, kTrustRecordSerialNumber
);
1545 trustSettingsDbg("TrustSettings::validatePropList: missing serial number");
1546 abort("missing serial number", errSecInvalidTrustedRootRecord
);
1548 if(CFGetTypeID(cfd
) != CFDataGetTypeID()) {
1549 trustSettingsDbg("TrustSettings::validatePropList: malformed serial number");
1550 abort("malformed serial number", errSecInvalidTrustedRootRecord
);
1553 CFDictionaryRemoveValue(certDict
, kTrustRecordSerialNumber
);
1556 /* modification date */
1557 CFDateRef modDate
= (CFDateRef
)CFDictionaryGetValue(certDict
, kTrustRecordModDate
);
1558 if(modDate
== NULL
) {
1559 trustSettingsDbg("TrustSettings::validatePropList: missing modDate");
1560 abort("missing modDate", errSecInvalidTrustedRootRecord
);
1562 if(CFGetTypeID(modDate
) != CFDateGetTypeID()) {
1563 trustSettingsDbg("TrustSettings::validatePropList: malformed modDate");
1564 abort("malformed modDate", errSecInvalidTrustedRootRecord
);
1567 CFDictionaryRemoveValue(certDict
, kTrustRecordModDate
);
1570 /* the actual trust settings */
1571 CFArrayRef trustSettings
= (CFArrayRef
)CFDictionaryGetValue(certDict
,
1572 kTrustRecordTrustSettings
);
1573 if(trustSettings
== NULL
) {
1574 /* optional; this cert's entry is good */
1577 if(CFGetTypeID(trustSettings
) != CFArrayGetTypeID()) {
1578 trustSettingsDbg("TrustSettings::validatePropList: malformed useConstraint"
1580 abort("malformed useConstraint array", errSecInvalidTrustedRootRecord
);
1583 /* Now validate the usageConstraint array contents */
1584 if(!validateTrustSettingsArray(trustSettings
)) {
1585 abort("malformed useConstraint array", errSecInvalidTrustedRootRecord
);
1587 } /* for each cert dictionary in top-level array */
1590 /* we don't need the top-level dictionary any more */
1591 CFRelease(mPropList
);
1597 * Obtain non-normalized issuer and serial number for specified cert, both
1598 * returned as CFDataRefs owned by caller.
1600 void TrustSettings::copyIssuerAndSerial(
1601 SecCertificateRef certRef
,
1602 CFDataRef
*issuer
, /* optional, RETURNED */
1603 CFDataRef
*serial
) /* RETURNED */
1605 CFRef
<SecCertificateRef
> certificate
= SecCertificateCreateItemImplInstance(certRef
);
1607 SecPointer
<Certificate
> cert
= Certificate::required(certificate
);
1608 CSSM_DATA_PTR fieldVal
;
1610 if(issuer
!= NULL
) {
1611 fieldVal
= cert
->copyFirstFieldValue(CSSMOID_X509V1IssuerNameStd
);
1612 *issuer
= CFDataCreate(NULL
, fieldVal
->Data
, fieldVal
->Length
);
1613 cert
->releaseFieldValue(CSSMOID_X509V1IssuerNameStd
, fieldVal
);
1616 fieldVal
= cert
->copyFirstFieldValue(CSSMOID_X509V1SerialNumber
);
1617 *serial
= CFDataCreate(NULL
, fieldVal
->Data
, fieldVal
->Length
);
1618 cert
->releaseFieldValue(CSSMOID_X509V1SerialNumber
, fieldVal
);
1621 void TrustSettings::abort(
1625 Syslog::error("TrustSettings: %s", why
);
1626 MacOSError::throwMe(err
);