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 "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/cssmapplePriv.h>
44 #include <Security/oidscert.h>
45 #include <Security/SecCertificatePriv.h>
46 #include <Security/SecPolicyPriv.h>
47 #include <security_keychain/KCCursor.h>
48 #include <security_ocspd/ocspdClient.h>
49 #include <CoreFoundation/CoreFoundation.h>
51 #include <Security/Authorization.h>
54 #define trustSettingsDbg(args...) secdebug("trustSettings", ## args)
55 #define trustSettingsEvalDbg(args...) secdebug("trustSettingsEval", ## args)
58 * Common error return for "malformed TrustSettings record"
60 #define errSecInvalidTrustedRootRecord errSecInvalidTrustSettings
62 using namespace KeychainCore
;
64 #pragma mark --- Static functions ---
67 * Comparator atoms to determine if an app's specified usage
68 * matches an individual trust setting. Each returns true on a match, false
69 * if the trust setting does not match the app's spec.
73 * -- the app has specified a field, and the cert has a spec for that
74 * field, and the two specs do not match;
78 * -- the cert has a spec for the field and the app hasn't specified the field
80 static bool tsCheckPolicy(
81 const CSSM_OID
*appPolicy
,
84 if(certPolicy
!= NULL
) {
85 if(appPolicy
== NULL
) {
86 trustSettingsEvalDbg("tsCheckPolicy: certPolicy, !appPolicy");
89 unsigned cLen
= (unsigned)CFDataGetLength(certPolicy
);
90 const UInt8
*cData
= CFDataGetBytePtr(certPolicy
);
91 if((cLen
!= appPolicy
->Length
) || memcmp(appPolicy
->Data
, cData
, cLen
)) {
92 trustSettingsEvalDbg("tsCheckPolicy: policy mismatch");
100 * This one's slightly different: the match is for *this* app, not one
101 * specified by the app.
103 static bool tsCheckApp(
106 if(certApp
!= NULL
) {
107 SecTrustedApplicationRef appRef
;
109 ortn
= SecTrustedApplicationCreateWithExternalRepresentation(certApp
, &appRef
);
111 trustSettingsDbg("tsCheckApp: bad trustedApp data\n");
114 ortn
= SecTrustedApplicationValidateWithPath(appRef
, NULL
);
124 static bool tsCheckKeyUse(
125 SecTrustSettingsKeyUsage appKeyUse
,
126 CFNumberRef certKeyUse
)
128 if(certKeyUse
!= NULL
) {
130 CFNumberGetValue(certKeyUse
, kCFNumberSInt32Type
, &certUse
);
131 SecTrustSettingsKeyUsage cku
= (SecTrustSettingsKeyUsage
)certUse
;
132 if(cku
== kSecTrustSettingsKeyUseAny
) {
133 /* explicitly allows anything */
136 /* cert specification must be a superset of app's intended use */
138 trustSettingsEvalDbg("tsCheckKeyUse: certKeyUsage, !appKeyUsage");
142 if((cku
& appKeyUse
) != appKeyUse
) {
143 trustSettingsEvalDbg("tsCheckKeyUse: keyUse mismatch");
150 static bool tsCheckPolicyStr(
151 const char *appPolicyStr
,
152 CFStringRef certPolicyStr
)
154 if(certPolicyStr
!= NULL
) {
155 if(appPolicyStr
== NULL
) {
156 trustSettingsEvalDbg("tsCheckPolicyStr: certPolicyStr, !appPolicyStr");
159 /* Let CF do the string compare */
160 CFStringRef cfPolicyStr
= CFStringCreateWithCString(NULL
, appPolicyStr
,
161 kCFStringEncodingUTF8
);
162 if(cfPolicyStr
== NULL
) {
163 /* I really don't see how this can happen */
164 trustSettingsEvalDbg("tsCheckPolicyStr: policyStr string conversion error");
168 // Some trust setting strings were created with a NULL character at the
169 // end, which was included in the length. Strip those off before compare
171 CFMutableStringRef certPolicyStrNoNULL
= CFStringCreateMutableCopy(NULL
, 0, certPolicyStr
);
172 if (certPolicyStrNoNULL
== NULL
) {
173 /* I really don't see how this can happen either */
174 trustSettingsEvalDbg("tsCheckPolicyStr: policyStr string conversion error 2");
178 CFStringFindAndReplace(certPolicyStrNoNULL
, CFSTR("\00"),
179 CFSTR(""), CFRangeMake(0, CFStringGetLength(certPolicyStrNoNULL
)), kCFCompareBackwards
);
181 CFComparisonResult res
= CFStringCompare(cfPolicyStr
, certPolicyStrNoNULL
, 0);
182 CFRelease(cfPolicyStr
);
183 CFRelease(certPolicyStrNoNULL
);
184 if(res
!= kCFCompareEqualTo
) {
185 trustSettingsEvalDbg("tsCheckPolicyStr: policyStr mismatch");
193 * Determine if a cert's trust settings dictionary satisfies the specified
194 * usage constraints. Returns true if so.
195 * Only certs with a SecTrustSettingsResult of kSecTrustSettingsResultTrustRoot
196 * or kSecTrustSettingsResultTrustAsRoot will match.
198 static bool qualifyUsageWithCertDict(
199 CFDictionaryRef certDict
,
200 const CSSM_OID
*policyOID
, /* optional */
201 const char *policyStr
, /* optional */
202 SecTrustSettingsKeyUsage keyUsage
, /* optional; default = any (actually "all" here) */
205 /* this array is optional */
206 CFArrayRef trustSettings
= (CFArrayRef
)CFDictionaryGetValue(certDict
,
207 kTrustRecordTrustSettings
);
208 CFIndex numSpecs
= 0;
209 if(trustSettings
!= NULL
) {
210 numSpecs
= CFArrayGetCount(trustSettings
);
214 * Trivial case: cert has no trust settings, indicating that
215 * it's used for everything.
217 trustSettingsEvalDbg("qualifyUsageWithCertDict: no trust settings");
220 for(CFIndex addDex
=0; addDex
<numSpecs
; addDex
++) {
221 CFDictionaryRef tsDict
= (CFDictionaryRef
)CFArrayGetValueAtIndex(trustSettings
,
224 /* per-cert specs: all optional */
225 CFDataRef certPolicy
= (CFDataRef
)CFDictionaryGetValue(tsDict
,
226 kSecTrustSettingsPolicy
);
227 CFDataRef certApp
= (CFDataRef
)CFDictionaryGetValue(tsDict
,
228 kSecTrustSettingsApplication
);
229 CFStringRef certPolicyStr
= (CFStringRef
)CFDictionaryGetValue(tsDict
,
230 kSecTrustSettingsPolicyString
);
231 CFNumberRef certKeyUsage
= (CFNumberRef
)CFDictionaryGetValue(tsDict
,
232 kSecTrustSettingsKeyUsage
);
233 CFNumberRef certResultType
= (CFNumberRef
)CFDictionaryGetValue(tsDict
,
234 kSecTrustSettingsResult
);
236 if(!tsCheckPolicy(policyOID
, certPolicy
)) {
239 if(!tsCheckApp(certApp
)) {
242 if(!tsCheckKeyUse(keyUsage
, certKeyUsage
)) {
245 if(!tsCheckPolicyStr(policyStr
, certPolicyStr
)) {
250 * This is a match, take whatever SecTrustSettingsResult is here,
251 * including the default if not specified.
253 SecTrustSettingsResult resultType
= kSecTrustSettingsResultTrustRoot
;
256 CFNumberGetValue(certResultType
, kCFNumberSInt32Type
, &s
);
257 resultType
= (SecTrustSettingsResult
)s
;
260 case kSecTrustSettingsResultTrustRoot
:
261 trustSettingsEvalDbg("qualifyUsageWithCertDict: TrustRoot MATCH");
263 case kSecTrustSettingsResultTrustAsRoot
:
265 trustSettingsEvalDbg("qualifyUsageWithCertDict: TrustAsRoot but not root");
268 trustSettingsEvalDbg("qualifyUsageWithCertDict: TrustAsRoot MATCH");
271 trustSettingsEvalDbg("qualifyUsageWithCertDict: bad resultType "
272 "(%lu)", (unsigned long)resultType
);
276 trustSettingsEvalDbg("qualifyUsageWithCertDict: NO MATCH");
281 * Create initial top-level dictionary when constructing a new TrustSettings.
283 static CFMutableDictionaryRef
tsInitialDict()
285 CFMutableDictionaryRef dict
= CFDictionaryCreateMutable(NULL
,
286 kSecTrustRecordNumTopDictKeys
,
287 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
289 /* the dictionary of per-cert entries */
290 CFMutableDictionaryRef trustDict
= CFDictionaryCreateMutable(NULL
, 0,
291 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
292 CFDictionaryAddValue(dict
, kTrustRecordTrustList
, trustDict
);
293 CFRelease(trustDict
);
295 SInt32 vers
= kSecTrustRecordVersionCurrent
;
296 CFNumberRef cfVers
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &vers
);
297 CFDictionaryAddValue(dict
, kTrustRecordVersion
, cfVers
);
303 * Set the modification date of a per-cert dictionary to current time.
305 static void tsSetModDate(
306 CFMutableDictionaryRef dict
)
310 modDate
= CFDateCreate(NULL
, CFAbsoluteTimeGetCurrent());
311 CFDictionarySetValue(dict
, kTrustRecordModDate
, modDate
);
315 /* make sure a presumed CFNumber can be converted to a 32-bit number */
317 bool tsIsGoodCfNum(CFNumberRef cfn
, SInt32
*num
= NULL
)
326 if(CFGetTypeID(cfn
) != CFNumberGetTypeID()) {
331 if(!CFNumberGetValue(cfn
, kCFNumberSInt32Type
, &s
)) {
342 TrustSettings::TrustSettings(SecTrustSettingsDomain domain
)
353 #pragma mark --- Public methods ---
356 * Normal constructor, from disk.
357 * If create is true, the absence of an on-disk TrustSettings file
358 * results in the creation of a new empty TrustSettings. If create is
359 * false and no on-disk TrustSettings exists, errSecNoTrustSettings is
361 * If trim is true, the components of the on-disk TrustSettings not
362 * needed for cert evaluation are discarded. This is for TrustSettings
363 * that will be cached in memory long-term.
365 OSStatus
TrustSettings::CreateTrustSettings(
366 SecTrustSettingsDomain domain
,
371 TrustSettings
* t
= new TrustSettings(domain
);
373 Allocator
&alloc
= Allocator::standard();
374 CSSM_DATA fileData
= {0, NULL
};
375 OSStatus ortn
= errSecSuccess
;
379 /* get trust settings from file, one way or another */
381 case kSecTrustSettingsDomainAdmin
:
383 * Quickie optimization: if it's not there, don't try to
384 * get it from ocspd. This is possible because the name of the
385 * admin file is hard coded, but the per-user files aren't.
387 path
= TRUST_SETTINGS_PATH
"/" ADMIN_TRUST_SETTINGS
;
388 if(stat(path
, &sb
)) {
389 trustSettingsDbg("TrustSettings: no admin record; skipping");
390 ortn
= errSecNoTrustSettings
;
393 /* else drop thru, get it from ocspd */
394 case kSecTrustSettingsDomainUser
:
395 /* get settings from ocspd */
396 ortn
= ocspdTrustSettingsRead(alloc
, domain
, fileData
);
398 case kSecTrustSettingsDomainSystem
:
399 /* immutable; it's safe for us to read this directly */
400 if(tsReadFile(SYSTEM_TRUST_SETTINGS_PATH
, alloc
, fileData
)) {
401 ortn
= errSecNoTrustSettings
;
410 trustSettingsDbg("TrustSettings: creating new record for domain %d",
412 t
->mPropList
= tsInitialDict();
416 trustSettingsDbg("TrustSettings: record not found for domain %d",
423 CFRef
<CFDataRef
> propList(CFDataCreate(NULL
, fileData
.Data
, fileData
.Length
));
424 t
->initFromData(propList
);
425 alloc
.free(fileData
.Data
);
427 t
->validatePropList(trim
);
430 return errSecSuccess
;
434 * Create from external data, obtained by createExternal().
435 * If externalData is NULL, we'll create an empty mTrustDict.
437 OSStatus
TrustSettings::CreateTrustSettings(
438 SecTrustSettingsDomain domain
,
439 CFDataRef externalData
,
443 case kSecTrustSettingsDomainUser
:
444 case kSecTrustSettingsDomainAdmin
:
445 case kSecTrustSettingsDomainMemory
:
447 case kSecTrustSettingsDomainSystem
: /* no can do, that implies writing to it */
452 TrustSettings
* t
= new TrustSettings(domain
);
454 if(externalData
!= NULL
) {
455 t
->initFromData(externalData
);
458 t
->mPropList
= tsInitialDict();
460 t
->validatePropList(TRIM_NO
); /* never trim this */
464 return errSecSuccess
;
468 TrustSettings::~TrustSettings()
470 trustSettingsDbg("TrustSettings(domain %d) destructor", (int)mDomain
);
471 CFRELEASE(mPropList
); /* may be null if trimmed */
472 CFRELEASE(mTrustDict
); /* normally always non-NULL */
476 /* common code to init mPropList from raw data */
477 void TrustSettings::initFromData(
478 CFDataRef trustSettingsData
)
480 CFStringRef errStr
= NULL
;
482 mPropList
= (CFMutableDictionaryRef
)CFPropertyListCreateFromXMLData(
485 kCFPropertyListMutableContainersAndLeaves
,
487 if(mPropList
== NULL
) {
488 trustSettingsDbg("TrustSettings::initFromData decode err (%s)",
489 errStr
? CFStringGetCStringPtr(errStr
, kCFStringEncodingUTF8
) : "<no err>");
493 MacOSError::throwMe(errSecInvalidTrustSettings
);
498 * Flush property list data out to disk if dirty.
500 void TrustSettings::flushToDisk()
503 trustSettingsDbg("flushToDisk, domain %d, !dirty!", (int)mDomain
);
506 if(mPropList
== NULL
) {
507 trustSettingsDbg("flushToDisk, domain %d, trimmed!", (int)mDomain
);
509 MacOSError::throwMe(errSecInternalComponent
);
512 case kSecTrustSettingsDomainSystem
:
513 case kSecTrustSettingsDomainMemory
:
514 /* caller shouldn't even try this */
516 trustSettingsDbg("flushToDisk, bad domain (%d)", (int)mDomain
);
517 MacOSError::throwMe(errSecInternalComponent
);
518 case kSecTrustSettingsDomainUser
:
519 case kSecTrustSettingsDomainAdmin
:
524 * Optimization: if there are no certs in the mTrustDict dictionary,
525 * we tell ocspd to *remove* the settings for the specified domain.
526 * Having *no* settings uses less memory and is faster than having
527 * an empty settings file, especially for the admin domain, where we
529 * an RPC if the settings file is simply not there.
531 CFRef
<CFDataRef
> xmlData
;
532 CSSM_DATA cssmXmlData
= {0, NULL
};
533 CFIndex numCerts
= CFDictionaryGetCount(mTrustDict
);
535 xmlData
.take(CFPropertyListCreateXMLData(NULL
, mPropList
));
537 /* we've been very careful; this should never happen */
538 trustSettingsDbg("flushToDisk, domain %d: error converting to XML", (int)mDomain
);
539 MacOSError::throwMe(errSecInternalComponent
);
541 cssmXmlData
.Data
= (uint8
*)CFDataGetBytePtr(xmlData
);
542 cssmXmlData
.Length
= CFDataGetLength(xmlData
);
545 trustSettingsDbg("flushToDisk, domain %d: DELETING trust settings", (int)mDomain
);
548 /* cook up auth stuff so ocspd can act on our behalf */
549 AuthorizationRef authRef
;
551 ortn
= AuthorizationCreate(NULL
, kAuthorizationEmptyEnvironment
,
554 trustSettingsDbg("flushToDisk, domain %d: AuthorizationCreate returned %ld",
555 (int)mDomain
, (long)ortn
);
556 MacOSError::throwMe(errSecInternalComponent
);
558 AuthorizationExternalForm authExt
;
559 CSSM_DATA authBlob
= {sizeof(authExt
), (uint8
*)&authExt
};
560 ortn
= AuthorizationMakeExternalForm(authRef
, &authExt
);
562 trustSettingsDbg("flushToDisk, domain %d: AuthorizationMakeExternalForm returned %ld",
563 (int)mDomain
, (long)ortn
);
564 ortn
= errSecInternalComponent
;
568 ortn
= ocspdTrustSettingsWrite(mDomain
, authBlob
, cssmXmlData
);
570 trustSettingsDbg("flushToDisk, domain %d: ocspdTrustSettingsWrite returned %ld",
571 (int)mDomain
, (long)ortn
);
574 trustSettingsDbg("flushToDisk, domain %d: wrote to disk", (int)mDomain
);
577 AuthorizationFree(authRef
, 0);
579 MacOSError::throwMe(ortn
);
584 * Obtain external representation of TrustSettings data.
586 CFDataRef
TrustSettings::createExternal()
589 CFDataRef xmlData
= CFPropertyListCreateXMLData(NULL
, mPropList
);
590 if(xmlData
== NULL
) {
591 trustSettingsDbg("createExternal, domain %d: error converting to XML",
593 MacOSError::throwMe(errSecInternalComponent
);
599 * Evaluate specified cert. Returns true if we found a record for the cert
600 * matching specified constraints.
601 * Note that a true return with a value of kSecTrustSettingsResultUnspecified for
602 * the resultType means that a cert isn't to be trusted or untrusted
603 * per se; it just means that we only found allowedErrors entries.
605 * Found "allows errors" values are added to the incoming allowedErrors
606 * array which is reallocd as needed (and which may be NULL or non-NULL on
609 bool TrustSettings::evaluateCert(
610 CFStringRef certHashStr
,
611 const CSSM_OID
*policyOID
, /* optional */
612 const char *policyStr
, /* optional */
613 SecTrustSettingsKeyUsage keyUsage
, /* optional */
614 bool isRootCert
, /* for checking default setting */
615 CSSM_RETURN
**allowedErrors
, /* IN/OUT; reallocd as needed */
616 uint32
*numAllowedErrors
, /* IN/OUT */
617 SecTrustSettingsResult
*resultType
, /* RETURNED */
618 bool *foundAnyEntry
) /* RETURNED */
620 assert(mTrustDict
!= NULL
);
622 /* get trust settings dictionary for this cert */
623 CFDictionaryRef certDict
= findDictionaryForCertHash(certHashStr
);
624 if((certDict
== NULL
) && isRootCert
) {
625 /* No? How about default root setting for this domain? */
626 certDict
= findDictionaryForCertHash(kSecTrustRecordDefaultRootCert
);
629 /* @@@ debug only @@@ */
630 /* print certificate hash and found dictionary reference */
631 const size_t maxHashStrLen
= 512;
632 char *buf
= (char*)malloc(maxHashStrLen
);
634 if (!CFStringGetCString(certHashStr
, buf
, (CFIndex
)maxHashStrLen
, kCFStringEncodingUTF8
)) {
637 trustSettingsEvalDbg("evaluateCert for \"%s\", found dict %p", buf
, certDict
);
642 if(certDict
== NULL
) {
643 *foundAnyEntry
= false;
646 *foundAnyEntry
= true;
648 /* to-be-returned array of allowed errors */
649 CSSM_RETURN
*allowedErrs
= *allowedErrors
;
650 uint32 numAllowedErrs
= *numAllowedErrors
;
652 /* this means "we found something other than allowedErrors" if true */
653 bool foundSettings
= false;
655 /* to be returned in *resultType if it ends up something other than Invalid */
656 SecTrustSettingsResult returnedResult
= kSecTrustSettingsResultInvalid
;
659 * Note since we validated the entire mPropList in our constructor, and we're careful
660 * about what we put into it, we don't bother typechecking its contents here.
661 * Also note that the kTrustRecordTrustSettings entry is optional.
663 CFArrayRef trustSettings
= (CFArrayRef
)CFDictionaryGetValue(certDict
,
664 kTrustRecordTrustSettings
);
665 CFIndex numSpecs
= 0;
666 if(trustSettings
!= NULL
) {
667 numSpecs
= CFArrayGetCount(trustSettings
);
671 * Trivial case: cert has no trust settings, indicating that
672 * it's used for everything.
674 trustSettingsEvalDbg("evaluateCert: no trust settings");
676 *resultType
= kSecTrustSettingsResultTrustRoot
;
681 * The decidedly nontrivial part: grind thru all of the cert's trust
682 * settings, see if the cert matches the caller's specified usage.
684 for(CFIndex addDex
=0; addDex
<numSpecs
; addDex
++) {
685 CFDictionaryRef tsDict
= (CFDictionaryRef
)CFArrayGetValueAtIndex(trustSettings
,
688 /* per-cert specs: all optional */
689 CFDataRef certPolicy
= (CFDataRef
)CFDictionaryGetValue(tsDict
,
690 kSecTrustSettingsPolicy
);
691 CFDataRef certApp
= (CFDataRef
)CFDictionaryGetValue(tsDict
,
692 kSecTrustSettingsApplication
);
693 CFStringRef certPolicyStr
= (CFStringRef
)CFDictionaryGetValue(tsDict
,
694 kSecTrustSettingsPolicyString
);
695 CFNumberRef certKeyUsage
= (CFNumberRef
)CFDictionaryGetValue(tsDict
,
696 kSecTrustSettingsKeyUsage
);
697 CFNumberRef certResultType
= (CFNumberRef
)CFDictionaryGetValue(tsDict
,
698 kSecTrustSettingsResult
);
699 CFNumberRef certAllowedErr
= (CFNumberRef
)CFDictionaryGetValue(tsDict
,
700 kSecTrustSettingsAllowedError
);
702 /* now, skip if we find a constraint that doesn't match intended use */
703 if(!tsCheckPolicy(policyOID
, certPolicy
)) {
706 if(!tsCheckApp(certApp
)) {
709 if(!tsCheckKeyUse(keyUsage
, certKeyUsage
)) {
712 if(!tsCheckPolicyStr(policyStr
, certPolicyStr
)) {
716 trustSettingsEvalDbg("evaluateCert: MATCH");
717 foundSettings
= true;
720 /* note we already validated this value */
722 CFNumberGetValue(certAllowedErr
, kCFNumberSInt32Type
, &s
);
723 allowedErrs
= (CSSM_RETURN
*)::realloc(allowedErrs
,
724 ++numAllowedErrs
* sizeof(CSSM_RETURN
));
725 allowedErrs
[numAllowedErrs
-1] = (CSSM_RETURN
) s
;
729 * We found a match, but we only return the current result type
730 * to caller if we haven't already returned something other than
731 * kSecTrustSettingsResultUnspecified. Once we find a valid result type,
732 * we keep on searching, but only for additional allowed errors.
734 switch(returnedResult
) {
735 /* found match but no valid resultType yet */
736 case kSecTrustSettingsResultUnspecified
:
737 /* haven't been thru here */
738 case kSecTrustSettingsResultInvalid
:
740 /* note we already validated this */
742 CFNumberGetValue(certResultType
, kCFNumberSInt32Type
, &s
);
743 returnedResult
= (SecTrustSettingsResult
)s
;
746 /* default is "copacetic" */
747 returnedResult
= kSecTrustSettingsResultTrustRoot
;
751 /* we already have a definitive resultType, don't change it */
754 } /* for each dictionary in trustSettings */
756 *allowedErrors
= allowedErrs
;
757 *numAllowedErrors
= numAllowedErrs
;
758 if(returnedResult
!= kSecTrustSettingsResultInvalid
) {
759 *resultType
= returnedResult
;
761 return foundSettings
;
766 * Find all certs in specified keychain list which have entries in this trust record.
767 * Certs already in the array are not added.
769 void TrustSettings::findCerts(
770 StorageManager::KeychainList
&keychains
,
771 CFMutableArrayRef certArray
)
773 findQualifiedCerts(keychains
,
775 false, /* onlyRoots */
776 NULL
, NULL
, kSecTrustSettingsKeyUseAny
,
780 void TrustSettings::findQualifiedCerts(
781 StorageManager::KeychainList
&keychains
,
783 * If findAll is true, all certs are returned and the subsequent
784 * qualifiers are ignored
787 /* if true, only return root (self-signed) certs */
789 const CSSM_OID
*policyOID
, /* optional */
790 const char *policyString
, /* optional */
791 SecTrustSettingsKeyUsage keyUsage
, /* optional */
792 CFMutableArrayRef certArray
) /* certs appended here */
794 StLock
<Mutex
> _(SecTrustKeychainsGetMutex());
797 * a set, hopefully with a good hash function for CFData, to keep track of what's
798 * been added to the outgoing array.
800 CFRef
<CFMutableSetRef
> certSet(CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
));
802 /* search: all certs, no attributes */
803 KCCursor
cursor(keychains
, CSSM_DL_DB_RECORD_X509_CERTIFICATE
, NULL
);
807 found
= cursor
->next(certItem
);
812 CFRef
<SecCertificateRef
> certRef((SecCertificateRef
)certItem
->handle());
814 /* must convert to unified SecCertificateRef */
815 SecPointer
<Certificate
> certificate(static_cast<Certificate
*>(&*certItem
));
816 CssmData certCssmData
= certificate
->data();
817 if (!(certCssmData
.Data
&& certCssmData
.Length
)) {
820 CFRef
<CFDataRef
> cfDataRef(CFDataCreate(NULL
, certCssmData
.Data
, certCssmData
.Length
));
821 CFRef
<SecCertificateRef
> certRef(SecCertificateCreateWithData(NULL
, cfDataRef
));
824 /* do we have an entry for this cert? */
825 CFDictionaryRef certDict
= findDictionaryForCert(certRef
);
826 if(certDict
== NULL
) {
832 if(!qualifyUsageWithCertDict(certDict
, policyOID
,
833 policyString
, keyUsage
, onlyRoots
)) {
838 /* see if we already have this one - get in CFData form */
840 OSStatus ortn
= SecCertificateGetData(certRef
, &certData
);
842 trustSettingsEvalDbg("findQualifiedCerts: SecCertificateGetData error");
845 CFRef
<CFDataRef
> cfData(CFDataCreate(NULL
, certData
.Data
, certData
.Length
));
846 CFDataRef cfd
= cfData
;
847 if(CFSetContainsValue(certSet
, cfd
)) {
848 trustSettingsEvalDbg("findQualifiedCerts: dup cert");
852 /* add to the tracking set, which owns the CFData now */
853 CFSetAddValue(certSet
, cfd
);
854 /* and add the SecCert to caller's array, which owns that now */
855 CFArrayAppendValue(certArray
, certRef
);
861 * Obtain trust settings for the specified cert. Returned settings array
862 * is in the public API form; caller must release. Returns NULL
863 * (does not throw) if the cert is not present in this TrustRecord.
865 CFArrayRef
TrustSettings::copyTrustSettings(
866 SecCertificateRef certRef
)
868 CFDictionaryRef certDict
= NULL
;
870 /* find the on-disk usage constraints for this cert */
871 certDict
= findDictionaryForCert(certRef
);
872 if(certDict
== NULL
) {
873 trustSettingsDbg("copyTrustSettings: dictionary not found");
876 CFArrayRef diskTrustSettings
= (CFArrayRef
)CFDictionaryGetValue(certDict
,
877 kTrustRecordTrustSettings
);
878 CFIndex numSpecs
= 0;
879 if(diskTrustSettings
!= NULL
) {
880 /* this field is optional */
881 numSpecs
= CFArrayGetCount(diskTrustSettings
);
885 * Convert to API-style array of dictionaries.
886 * We give the caller an array even if it's empty.
888 CFRef
<CFMutableArrayRef
> outArray(CFArrayCreateMutable(NULL
, numSpecs
,
889 &kCFTypeArrayCallBacks
));
890 for(CFIndex dex
=0; dex
<numSpecs
; dex
++) {
891 CFDictionaryRef diskTsDict
=
892 (CFDictionaryRef
)CFArrayGetValueAtIndex(diskTrustSettings
, dex
);
893 /* already validated... */
894 assert(CFGetTypeID(diskTsDict
) == CFDictionaryGetTypeID());
896 CFDataRef certPolicy
= (CFDataRef
) CFDictionaryGetValue(diskTsDict
, kSecTrustSettingsPolicy
);
897 CFDataRef certApp
= (CFDataRef
) CFDictionaryGetValue(diskTsDict
, kSecTrustSettingsApplication
);
898 CFStringRef policyStr
= (CFStringRef
)CFDictionaryGetValue(diskTsDict
, kSecTrustSettingsPolicyString
);
899 CFNumberRef allowedErr
= (CFNumberRef
)CFDictionaryGetValue(diskTsDict
, kSecTrustSettingsAllowedError
);
900 CFNumberRef resultType
= (CFNumberRef
)CFDictionaryGetValue(diskTsDict
, kSecTrustSettingsResult
);
901 CFNumberRef keyUsage
= (CFNumberRef
)CFDictionaryGetValue(diskTsDict
, kSecTrustSettingsKeyUsage
);
903 if((certPolicy
== NULL
) &&
905 (policyStr
== NULL
) &&
906 (allowedErr
== NULL
) &&
907 (resultType
== NULL
) &&
908 (keyUsage
== NULL
)) {
909 /* weird but legal */
912 CFRef
<CFMutableDictionaryRef
> outTsDict(CFDictionaryCreateMutable(NULL
,
914 &kCFTypeDictionaryKeyCallBacks
,
915 &kCFTypeDictionaryValueCallBacks
));
917 if(certPolicy
!= NULL
) {
918 /* convert OID as CFDataRef to SecPolicyRef */
919 SecPolicyRef policyRef
= NULL
;
920 CSSM_OID policyOid
= { CFDataGetLength(certPolicy
),
921 (uint8
*)CFDataGetBytePtr(certPolicy
) };
922 OSStatus ortn
= SecPolicyCopy(CSSM_CERT_X_509v3
, &policyOid
, &policyRef
);
924 trustSettingsDbg("copyTrustSettings: OID conversion error");
925 abort("Bad Policy OID in trusted root list", errSecInvalidTrustedRootRecord
);
927 CFDictionaryAddValue(outTsDict
, kSecTrustSettingsPolicy
, policyRef
);
928 CFRelease(policyRef
); // owned by dictionary
931 if(certApp
!= NULL
) {
932 /* convert app as CFDataRef to SecTrustedApplicationRef */
933 SecTrustedApplicationRef appRef
;
934 OSStatus ortn
= SecTrustedApplicationCreateWithExternalRepresentation(certApp
, &appRef
);
936 trustSettingsDbg("copyTrustSettings: App conversion error");
937 abort("Bad application data in trusted root list", errSecInvalidTrustedRootRecord
);
939 CFDictionaryAddValue(outTsDict
, kSecTrustSettingsApplication
, appRef
);
940 CFRelease(appRef
); // owned by dictionary
943 /* remaining 4 are trivial */
944 if(policyStr
!= NULL
) {
946 * copy, since policyStr is in our mutable dictionary and could change out from
949 CFStringRef str
= CFStringCreateCopy(NULL
, policyStr
);
950 CFDictionaryAddValue(outTsDict
, kSecTrustSettingsPolicyString
, str
);
951 CFRelease(str
); // owned by dictionary
953 if(allowedErr
!= NULL
) {
954 /* there is no mutable CFNumber, so.... */
955 CFDictionaryAddValue(outTsDict
, kSecTrustSettingsAllowedError
, allowedErr
);
957 if(resultType
!= NULL
) {
958 CFDictionaryAddValue(outTsDict
, kSecTrustSettingsResult
, resultType
);
960 if(keyUsage
!= NULL
) {
961 CFDictionaryAddValue(outTsDict
, kSecTrustSettingsKeyUsage
, keyUsage
);
963 CFArrayAppendValue(outArray
, outTsDict
);
964 /* outTsDict autoreleases; owned by outArray now */
966 CFRetain(outArray
); // now that it's good to go....
970 CFDateRef
TrustSettings::copyModDate(
971 SecCertificateRef certRef
)
973 CFDictionaryRef certDict
= NULL
;
975 /* find the on-disk usage constraints dictionary for this cert */
976 certDict
= findDictionaryForCert(certRef
);
977 if(certDict
== NULL
) {
978 trustSettingsDbg("copyModDate: dictionary not found");
981 CFDateRef modDate
= (CFDateRef
)CFDictionaryGetValue(certDict
, kTrustRecordModDate
);
982 if(modDate
== NULL
) {
986 /* this only works becuase there is no mutable CFDateRef */
992 * Modify cert's trust settings, or add a new cert to the record.
994 void TrustSettings::setTrustSettings(
995 SecCertificateRef certRef
,
996 CFTypeRef trustSettingsDictOrArray
)
998 /* to validate, we need to know if the cert is self-signed */
1000 Boolean isSelfSigned
= false;
1002 if(certRef
== kSecTrustSettingsDefaultRootCertSetting
) {
1004 * Validate settings as if this were root, specifically,
1005 * kSecTrustSettingsResultTrustRoot (explicitly or by
1008 isSelfSigned
= true;
1011 ortn
= SecCertificateIsSelfSigned(certRef
, &isSelfSigned
);
1013 MacOSError::throwMe(ortn
);
1017 /* caller's app/policy spec OK? */
1018 CFRef
<CFArrayRef
> trustSettings(validateApiTrustSettings(
1019 trustSettingsDictOrArray
, isSelfSigned
));
1021 /* caller is responsible for ensuring these */
1022 assert(mPropList
!= NULL
);
1023 assert(mDomain
!= kSecTrustSettingsDomainSystem
);
1025 /* extract issuer and serial number from the cert, if it's a cert */
1026 CFRef
<CFDataRef
> issuer
;
1027 CFRef
<CFDataRef
> serial
;
1028 if(certRef
!= kSecTrustSettingsDefaultRootCertSetting
) {
1029 copyIssuerAndSerial(certRef
, issuer
.take(), serial
.take());
1033 issuer
= CFDataCreate(NULL
, &dummy
, 0);
1034 serial
= CFDataCreate(NULL
, &dummy
, 0);
1037 /* SHA1 digest as string */
1038 CFRef
<CFStringRef
> certHashStr(SecTrustSettingsCertHashStrFromCert(certRef
));
1040 trustSettingsDbg("TrustSettings::setTrustSettings: CertHashStrFromCert error");
1041 MacOSError::throwMe(errSecItemNotFound
);
1045 * Find entry for this cert, if present.
1047 CFMutableDictionaryRef certDict
=
1048 (CFMutableDictionaryRef
)findDictionaryForCertHash(certHashStr
);
1049 if(certDict
== NULL
) {
1050 /* create new dictionary */
1051 certDict
= CFDictionaryCreateMutable(NULL
, kSecTrustRecordNumCertDictKeys
,
1052 &kCFCopyStringDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1053 if(certDict
== NULL
) {
1054 MacOSError::throwMe(errSecAllocate
);
1056 CFDictionaryAddValue(certDict
, kTrustRecordIssuer
, issuer
);
1057 CFDictionaryAddValue(certDict
, kTrustRecordSerialNumber
, serial
);
1058 if(CFArrayGetCount(trustSettings
) != 0) {
1059 /* skip this if the settings array is empty */
1060 CFDictionaryAddValue(certDict
, kTrustRecordTrustSettings
, trustSettings
);
1062 tsSetModDate(certDict
);
1064 /* add this new cert dictionary to top-level mTrustDict */
1065 CFDictionaryAddValue(mTrustDict
, static_cast<CFStringRef
>(certHashStr
), certDict
);
1067 /* mTrustDict owns the dictionary now */
1068 CFRelease(certDict
);
1072 tsSetModDate(certDict
);
1073 if(CFArrayGetCount(trustSettings
) != 0) {
1074 CFDictionarySetValue(certDict
, kTrustRecordTrustSettings
, trustSettings
);
1077 /* empty settings array: remove from dictionary */
1078 CFDictionaryRemoveValue(certDict
, kTrustRecordTrustSettings
);
1085 * Delete a certificate's trust settings.
1087 void TrustSettings::deleteTrustSettings(
1088 SecCertificateRef certRef
)
1090 CFDictionaryRef certDict
= NULL
;
1092 /* caller is responsible for ensuring these */
1093 assert(mPropList
!= NULL
);
1094 assert(mDomain
!= kSecTrustSettingsDomainSystem
);
1096 /* SHA1 digest as string */
1097 CFRef
<CFStringRef
> certHashStr(SecTrustSettingsCertHashStrFromCert(certRef
));
1099 MacOSError::throwMe(errSecItemNotFound
);
1102 /* present in top-level mTrustDict? */
1103 certDict
= findDictionaryForCertHash(certHashStr
);
1104 if(certDict
!= NULL
) {
1105 CFDictionaryRemoveValue(mTrustDict
, static_cast<CFStringRef
>(certHashStr
));
1110 * Throwing this error is the only reason we don't blindly do
1111 * a CFDictionaryRemoveValue() without first doing
1112 * findDictionaryForCertHash().
1114 trustSettingsDbg("TrustSettings::deleteRoot: cert dictionary not found");
1115 MacOSError::throwMe(errSecItemNotFound
);
1119 #pragma mark --- Private methods ---
1122 * Find a given cert's entry in the top-level mTrustDict. Return the
1123 * entry as a dictionary. Returned dictionary is not refcounted.
1124 * The mutability of the returned dictionary is the same as the mutability
1125 * of the underlying StickRecord::mPropList, which the caller is just
1126 * going to have to know (and cast accordingly if a mutable dictionary
1129 CFDictionaryRef
TrustSettings::findDictionaryForCert(
1130 SecCertificateRef certRef
)
1132 CFRef
<CFStringRef
> certHashStr(SecTrustSettingsCertHashStrFromCert(certRef
));
1133 if (certHashStr
.get() == NULL
)
1138 return findDictionaryForCertHash(static_cast<CFStringRef
>(certHashStr
));
1142 * Find entry in mTrustDict given cert hash string.
1144 CFDictionaryRef
TrustSettings::findDictionaryForCertHash(
1145 CFStringRef certHashStr
)
1147 assert(mTrustDict
!= NULL
);
1148 return (CFDictionaryRef
)CFDictionaryGetValue(mTrustDict
, certHashStr
);
1152 * Validate incoming trust settings, which may be NULL, a dictionary, or
1153 * an array of dictionaries. Convert from the API-style dictionaries
1154 * to the internal style suitable for writing to disk as part of
1157 * We return a refcounted CFArray in any case if the incoming parameter is good.
1159 CFArrayRef
TrustSettings::validateApiTrustSettings(
1160 CFTypeRef trustSettingsDictOrArray
,
1161 Boolean isSelfSigned
)
1163 CFArrayRef tmpInArray
= NULL
;
1165 if(trustSettingsDictOrArray
== NULL
) {
1167 #warning STU: temporarily unblocking build
1169 /* trivial case, only valid for roots */
1171 trustSettingsDbg("validateApiUsageConstraints: !isSelfSigned, no settings");
1172 MacOSError::throwMe(errSecParam
);
1175 return CFArrayCreate(NULL
, NULL
, 0, &kCFTypeArrayCallBacks
);
1177 else if(CFGetTypeID(trustSettingsDictOrArray
) == CFDictionaryGetTypeID()) {
1179 tmpInArray
= CFArrayCreate(NULL
, &trustSettingsDictOrArray
, 1,
1180 &kCFTypeArrayCallBacks
);
1182 else if(CFGetTypeID(trustSettingsDictOrArray
) == CFArrayGetTypeID()) {
1183 /* as is, refcount - we'll release later */
1184 tmpInArray
= (CFArrayRef
)trustSettingsDictOrArray
;
1185 CFRetain(tmpInArray
);
1188 trustSettingsDbg("validateApiUsageConstraints: bad trustSettingsDictOrArray");
1189 MacOSError::throwMe(errSecParam
);
1192 CFIndex numSpecs
= CFArrayGetCount(tmpInArray
);
1193 CFMutableArrayRef outArray
= CFArrayCreateMutable(NULL
, numSpecs
, &kCFTypeArrayCallBacks
);
1195 OSStatus ortn
= errSecSuccess
;
1196 SecPolicyRef certPolicy
;
1197 SecTrustedApplicationRef certApp
;
1200 for(CFIndex dex
=0; dex
<numSpecs
; dex
++) {
1201 CFDataRef oidData
= NULL
;
1202 CFDataRef appData
= NULL
;
1203 CFStringRef policyStr
= NULL
;
1204 CFNumberRef allowedErr
= NULL
;
1205 CFNumberRef resultType
= NULL
;
1206 CFNumberRef keyUsage
= NULL
;
1208 SecTrustSettingsResult result
;
1210 /* each element is a dictionary */
1211 CFDictionaryRef ucDict
= (CFDictionaryRef
)CFArrayGetValueAtIndex(tmpInArray
, dex
);
1212 if(CFGetTypeID(ucDict
) != CFDictionaryGetTypeID()) {
1213 trustSettingsDbg("validateAppPolicyArray: malformed usageConstraint dictionary");
1218 /* policy - optional */
1219 certPolicy
= (SecPolicyRef
)CFDictionaryGetValue(ucDict
, kSecTrustSettingsPolicy
);
1220 if(certPolicy
!= NULL
) {
1221 if(CFGetTypeID(certPolicy
) != SecPolicyGetTypeID()) {
1222 trustSettingsDbg("validateAppPolicyArray: malformed certPolicy");
1226 ortn
= SecPolicyGetOID(certPolicy
, &oid
);
1228 trustSettingsDbg("validateAppPolicyArray: SecPolicyGetOID error");
1231 oidData
= CFDataCreate(NULL
, oid
.Data
, oid
.Length
);
1234 /* application - optional */
1235 certApp
= (SecTrustedApplicationRef
)CFDictionaryGetValue(ucDict
, kSecTrustSettingsApplication
);
1236 if(certApp
!= NULL
) {
1237 if(CFGetTypeID(certApp
) != SecTrustedApplicationGetTypeID()) {
1238 trustSettingsDbg("validateAppPolicyArray: malformed certApp");
1242 ortn
= SecTrustedApplicationCopyExternalRepresentation(certApp
, &appData
);
1244 trustSettingsDbg("validateAppPolicyArray: "
1245 "SecTrustedApplicationCopyExternalRepresentation error");
1250 policyStr
= (CFStringRef
)CFDictionaryGetValue(ucDict
, kSecTrustSettingsPolicyString
);
1251 if(policyStr
!= NULL
) {
1252 if(CFGetTypeID(policyStr
) != CFStringGetTypeID()) {
1253 trustSettingsDbg("validateAppPolicyArray: malformed policyStr");
1258 allowedErr
= (CFNumberRef
)CFDictionaryGetValue(ucDict
, kSecTrustSettingsAllowedError
);
1259 if(!tsIsGoodCfNum(allowedErr
)) {
1260 trustSettingsDbg("validateAppPolicyArray: malformed allowedErr");
1264 resultType
= (CFNumberRef
)CFDictionaryGetValue(ucDict
, kSecTrustSettingsResult
);
1265 if(!tsIsGoodCfNum(resultType
, &resultNum
)) {
1266 trustSettingsDbg("validateAppPolicyArray: malformed resultType");
1271 /* validate result later */
1273 keyUsage
= (CFNumberRef
)CFDictionaryGetValue(ucDict
, kSecTrustSettingsKeyUsage
);
1274 if(!tsIsGoodCfNum(keyUsage
)) {
1275 trustSettingsDbg("validateAppPolicyArray: malformed keyUsage");
1280 if(!oidData
&& !appData
&& !policyStr
&&
1281 !allowedErr
&& !resultType
&& !keyUsage
) {
1282 /* nothing here - weird, but legal - skip it */
1286 /* create dictionary for this usageConstraint */
1287 CFMutableDictionaryRef outDict
= CFDictionaryCreateMutable(NULL
,
1289 &kCFTypeDictionaryKeyCallBacks
,
1290 &kCFTypeDictionaryValueCallBacks
);
1292 CFDictionaryAddValue(outDict
, kSecTrustSettingsPolicy
, oidData
);
1293 CFRelease(oidData
); // owned by dictionary
1296 CFDictionaryAddValue(outDict
, kSecTrustSettingsApplication
, appData
);
1297 CFRelease(appData
); // owned by dictionary
1300 CFDictionaryAddValue(outDict
, kSecTrustSettingsPolicyString
, policyStr
);
1301 /* still owned by ucDict */
1304 CFDictionaryAddValue(outDict
, kSecTrustSettingsAllowedError
, allowedErr
);
1307 #warning STU: temporarily unblocking build
1308 ortn
= errSecSuccess
;
1311 /* let's be really picky on this one */
1313 case kSecTrustSettingsResultInvalid
:
1316 case kSecTrustSettingsResultTrustRoot
:
1318 trustSettingsDbg("validateAppPolicyArray: TrustRoot, !isSelfSigned");
1322 case kSecTrustSettingsResultTrustAsRoot
:
1324 trustSettingsDbg("validateAppPolicyArray: TrustAsRoot, isSelfSigned");
1328 case kSecTrustSettingsResultDeny
:
1329 case kSecTrustSettingsResultUnspecified
:
1332 trustSettingsDbg("validateAppPolicyArray: bogus resultType");
1339 CFDictionaryAddValue(outDict
, kSecTrustSettingsResult
, resultType
);
1342 /* no resultType; default of TrustRoot only valid for root */
1344 trustSettingsDbg("validateAppPolicyArray: default result, !isSelfSigned");
1351 CFDictionaryAddValue(outDict
, kSecTrustSettingsKeyUsage
, keyUsage
);
1354 /* append dictionary to output */
1355 CFArrayAppendValue(outArray
, outDict
);
1356 /* array owns the dictionary now */
1359 } /* for each usage constraint dictionary */
1361 CFRelease(tmpInArray
);
1363 CFRelease(outArray
);
1364 MacOSError::throwMe(ortn
);
1370 * Validate an trust settings array obtained from disk.
1371 * Returns true if OK, else returns false.
1373 bool TrustSettings::validateTrustSettingsArray(
1374 CFArrayRef trustSettings
)
1376 CFIndex numSpecs
= CFArrayGetCount(trustSettings
);
1377 for(CFIndex dex
=0; dex
<numSpecs
; dex
++) {
1378 CFDictionaryRef ucDict
= (CFDictionaryRef
)CFArrayGetValueAtIndex(trustSettings
,
1380 if(CFGetTypeID(ucDict
) != CFDictionaryGetTypeID()) {
1381 trustSettingsDbg("validateAppPolicyArray: malformed app/policy dictionary");
1384 CFDataRef certPolicy
= (CFDataRef
)CFDictionaryGetValue(ucDict
, kSecTrustSettingsPolicy
);
1385 if((certPolicy
!= NULL
) && (CFGetTypeID(certPolicy
) != CFDataGetTypeID())) {
1386 trustSettingsDbg("validateAppPolicyArray: malformed certPolicy");
1389 CFDataRef certApp
= (CFDataRef
)CFDictionaryGetValue(ucDict
, kSecTrustSettingsApplication
);
1390 if((certApp
!= NULL
) && (CFGetTypeID(certApp
) != CFDataGetTypeID())) {
1391 trustSettingsDbg("validateAppPolicyArray: malformed certApp");
1394 CFStringRef policyStr
= (CFStringRef
)CFDictionaryGetValue(ucDict
, kSecTrustSettingsPolicyString
);
1395 if((policyStr
!= NULL
) && (CFGetTypeID(policyStr
) != CFStringGetTypeID())) {
1396 trustSettingsDbg("validateAppPolicyArray: malformed policyStr");
1399 CFNumberRef cfNum
= (CFNumberRef
)CFDictionaryGetValue(ucDict
, kSecTrustSettingsAllowedError
);
1400 if(!tsIsGoodCfNum(cfNum
)) {
1401 trustSettingsDbg("validateAppPolicyArray: malformed allowedErr");
1404 cfNum
= (CFNumberRef
)CFDictionaryGetValue(ucDict
, kSecTrustSettingsResult
);
1405 if(!tsIsGoodCfNum(cfNum
)) {
1406 trustSettingsDbg("validateAppPolicyArray: malformed resultType");
1409 cfNum
= (CFNumberRef
)CFDictionaryGetValue(ucDict
, kSecTrustSettingsKeyUsage
);
1410 if(!tsIsGoodCfNum(cfNum
)) {
1411 trustSettingsDbg("validateAppPolicyArray: malformed keyUsage");
1414 } /* for each usageConstraint dictionary */
1419 * Validate mPropList after it's read from disk or supplied as an external
1420 * representation. Allows subsequent use of mTrustDict to proceed with
1421 * relative impunity.
1423 void TrustSettings::validatePropList(bool trim
)
1425 /* top level dictionary */
1427 trustSettingsDbg("TrustSettings::validatePropList missing mPropList");
1428 abort("missing propList", errSecInvalidTrustedRootRecord
);
1431 if(CFGetTypeID(mPropList
) != CFDictionaryGetTypeID()) {
1432 trustSettingsDbg("TrustSettings::validatePropList: malformed mPropList");
1433 abort("malformed propList", errSecInvalidTrustedRootRecord
);
1436 /* That dictionary has two entries */
1437 CFNumberRef cfVers
= (CFNumberRef
)CFDictionaryGetValue(mPropList
, kTrustRecordVersion
);
1438 if((cfVers
== NULL
) || (CFGetTypeID(cfVers
) != CFNumberGetTypeID())) {
1439 trustSettingsDbg("TrustSettings::validatePropList: malformed version");
1440 abort("malformed version", errSecInvalidTrustedRootRecord
);
1442 if(!CFNumberGetValue(cfVers
, kCFNumberSInt32Type
, &mDictVersion
)) {
1443 trustSettingsDbg("TrustSettings::validatePropList: malformed version");
1444 abort("malformed version", errSecInvalidTrustedRootRecord
);
1446 if((mDictVersion
> kSecTrustRecordVersionCurrent
) ||
1447 (mDictVersion
== kSecTrustRecordVersionInvalid
)) {
1448 trustSettingsDbg("TrustSettings::validatePropList: incompatible version");
1449 abort("incompatible version", errSecInvalidTrustedRootRecord
);
1451 /* other backwards-compatibility handling done later, if needed, per mDictVersion */
1453 mTrustDict
= (CFMutableDictionaryRef
)CFDictionaryGetValue(mPropList
, kTrustRecordTrustList
);
1454 if(mTrustDict
!= NULL
) {
1455 CFRetain(mTrustDict
);
1457 if((mTrustDict
== NULL
) || (CFGetTypeID(mTrustDict
) != CFDictionaryGetTypeID())) {
1458 trustSettingsDbg("TrustSettings::validatePropList: malformed mTrustDict");
1459 abort("malformed TrustArray", errSecInvalidTrustedRootRecord
);
1462 /* grind through the per-cert entries */
1463 CFIndex numCerts
= CFDictionaryGetCount(mTrustDict
);
1464 const void *dictKeys
[numCerts
];
1465 const void *dictValues
[numCerts
];
1466 CFDictionaryGetKeysAndValues(mTrustDict
, dictKeys
, dictValues
);
1468 for(CFIndex dex
=0; dex
<numCerts
; dex
++) {
1469 /* get per-cert dictionary */
1470 CFMutableDictionaryRef certDict
= (CFMutableDictionaryRef
)dictValues
[dex
];
1471 if((certDict
== NULL
) || (CFGetTypeID(certDict
) != CFDictionaryGetTypeID())) {
1472 trustSettingsDbg("TrustSettings::validatePropList: malformed certDict");
1473 abort("malformed certDict", errSecInvalidTrustedRootRecord
);
1477 * That dictionary has exactly four entries.
1478 * If we're trimming, all we need is the actual trust settings.
1482 CFDataRef cfd
= (CFDataRef
)CFDictionaryGetValue(certDict
, kTrustRecordIssuer
);
1484 trustSettingsDbg("TrustSettings::validatePropList: missing issuer");
1485 abort("missing issuer", errSecInvalidTrustedRootRecord
);
1487 if(CFGetTypeID(cfd
) != CFDataGetTypeID()) {
1488 trustSettingsDbg("TrustSettings::validatePropList: malformed issuer");
1489 abort("malformed issuer", errSecInvalidTrustedRootRecord
);
1492 CFDictionaryRemoveValue(certDict
, kTrustRecordIssuer
);
1496 cfd
= (CFDataRef
)CFDictionaryGetValue(certDict
, kTrustRecordSerialNumber
);
1498 trustSettingsDbg("TrustSettings::validatePropList: missing serial number");
1499 abort("missing serial number", errSecInvalidTrustedRootRecord
);
1501 if(CFGetTypeID(cfd
) != CFDataGetTypeID()) {
1502 trustSettingsDbg("TrustSettings::validatePropList: malformed serial number");
1503 abort("malformed serial number", errSecInvalidTrustedRootRecord
);
1506 CFDictionaryRemoveValue(certDict
, kTrustRecordSerialNumber
);
1509 /* modification date */
1510 CFDateRef modDate
= (CFDateRef
)CFDictionaryGetValue(certDict
, kTrustRecordModDate
);
1511 if(modDate
== NULL
) {
1512 trustSettingsDbg("TrustSettings::validatePropList: missing modDate");
1513 abort("missing modDate", errSecInvalidTrustedRootRecord
);
1515 if(CFGetTypeID(modDate
) != CFDateGetTypeID()) {
1516 trustSettingsDbg("TrustSettings::validatePropList: malformed modDate");
1517 abort("malformed modDate", errSecInvalidTrustedRootRecord
);
1520 CFDictionaryRemoveValue(certDict
, kTrustRecordModDate
);
1523 /* the actual trust settings */
1524 CFArrayRef trustSettings
= (CFArrayRef
)CFDictionaryGetValue(certDict
,
1525 kTrustRecordTrustSettings
);
1526 if(trustSettings
== NULL
) {
1527 /* optional; this cert's entry is good */
1530 if(CFGetTypeID(trustSettings
) != CFArrayGetTypeID()) {
1531 trustSettingsDbg("TrustSettings::validatePropList: malformed useConstraint"
1533 abort("malformed useConstraint array", errSecInvalidTrustedRootRecord
);
1536 /* Now validate the usageConstraint array contents */
1537 if(!validateTrustSettingsArray(trustSettings
)) {
1538 abort("malformed useConstraint array", errSecInvalidTrustedRootRecord
);
1540 } /* for each cert dictionary in top-level array */
1543 /* we don't need the top-level dictionary any more */
1544 CFRelease(mPropList
);
1550 * Obtain non-normalized issuer and serial number for specified cert, both
1551 * returned as CFDataRefs owned by caller.
1553 void TrustSettings::copyIssuerAndSerial(
1554 SecCertificateRef certRef
,
1555 CFDataRef
*issuer
, /* optional, RETURNED */
1556 CFDataRef
*serial
) /* RETURNED */
1559 CFRef
<SecCertificateRef
> certificate
= SecCertificateCreateItemImplInstance(certRef
);
1561 CFRef
<SecCertificateRef
> certificate
= (SecCertificateRef
) ((certRef
) ? CFRetain(certRef
) : NULL
);
1564 SecPointer
<Certificate
> cert
= Certificate::required(certificate
);
1565 CSSM_DATA_PTR fieldVal
;
1567 if(issuer
!= NULL
) {
1568 fieldVal
= cert
->copyFirstFieldValue(CSSMOID_X509V1IssuerNameStd
);
1569 *issuer
= CFDataCreate(NULL
, fieldVal
->Data
, fieldVal
->Length
);
1570 cert
->releaseFieldValue(CSSMOID_X509V1IssuerNameStd
, fieldVal
);
1573 fieldVal
= cert
->copyFirstFieldValue(CSSMOID_X509V1SerialNumber
);
1574 *serial
= CFDataCreate(NULL
, fieldVal
->Data
, fieldVal
->Length
);
1575 cert
->releaseFieldValue(CSSMOID_X509V1SerialNumber
, fieldVal
);
1578 void TrustSettings::abort(
1582 Syslog::error("TrustSettings: %s", why
);
1583 MacOSError::throwMe(err
);