2 * Copyright (c) 2005 Apple Computer, 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.
27 * Created May 10 2005 by dmitch.
30 #include "TrustSettings.h"
31 #include "TrustSettingsSchema.h"
32 #include "SecTrustSettings.h"
33 #include "TrustSettingsUtils.h"
34 #include "TrustKeychains.h"
35 #include "SecCertificatePriv.h"
36 #include "SecPolicyPriv.h"
37 #include "Certificate.h"
38 #include "cssmdatetime.h"
39 #include <Security/SecBase.h>
40 #include "SecTrustedApplicationPriv.h"
41 #include <security_utilities/errors.h>
42 #include <security_utilities/debugging.h>
43 #include <security_utilities/logging.h>
44 #include <security_utilities/cfutilities.h>
45 #include <security_utilities/alloc.h>
46 #include <Security/cssmapplePriv.h>
47 #include <Security/oidscert.h>
48 #include <security_keychain/KCCursor.h>
49 #include <security_ocspd/ocspdClient.h>
50 #include <CoreFoundation/CoreFoundation.h>
52 #include <Security/Authorization.h>
55 #define trustSettingsDbg(args...) secdebug("trustSettings", ## args)
56 #define trustSettingsEvalDbg(args...) secdebug("trustSettingsEval", ## args)
59 * Common error return for "malformed TrustSettings record"
61 #define errSecInvalidTrustedRootRecord errSecInvalidTrustSettings
63 using namespace KeychainCore
;
65 #pragma mark --- Static functions ---
68 * Comparator atoms to determine if an app's specified usage
69 * matches an individual trust setting. Each returns true on a match, false
70 * if the trust setting does not match the app's spec.
74 * -- the app has specified a field, and the cert has a spec for that
75 * field, and the two specs do not match;
79 * -- the cert has a spec for the field and the app hasn't specified the field
81 static bool tsCheckPolicy(
82 const CSSM_OID
*appPolicy
,
85 if(certPolicy
!= NULL
) {
86 if(appPolicy
== NULL
) {
87 trustSettingsEvalDbg("tsCheckPolicy: certPolicy, !appPolicy");
90 unsigned cLen
= (unsigned)CFDataGetLength(certPolicy
);
91 const UInt8
*cData
= CFDataGetBytePtr(certPolicy
);
92 if((cLen
!= appPolicy
->Length
) || memcmp(appPolicy
->Data
, cData
, cLen
)) {
93 trustSettingsEvalDbg("tsCheckPolicy: policy mismatch");
101 * This one's slightly different: the match is for *this* app, not one
102 * specified by the app.
104 static bool tsCheckApp(
107 if(certApp
!= NULL
) {
108 SecTrustedApplicationRef appRef
;
110 ortn
= SecTrustedApplicationCreateWithExternalRepresentation(certApp
, &appRef
);
112 trustSettingsDbg("tsCheckApp: bad trustedApp data\n");
115 ortn
= SecTrustedApplicationValidateWithPath(appRef
, NULL
);
125 static bool tsCheckKeyUse(
126 SecTrustSettingsKeyUsage appKeyUse
,
127 CFNumberRef certKeyUse
)
129 if(certKeyUse
!= NULL
) {
131 CFNumberGetValue(certKeyUse
, kCFNumberSInt32Type
, &certUse
);
132 SecTrustSettingsKeyUsage cku
= (SecTrustSettingsKeyUsage
)certUse
;
133 if(cku
== kSecTrustSettingsKeyUseAny
) {
134 /* explicitly allows anything */
137 /* cert specification must be a superset of app's intended use */
139 trustSettingsEvalDbg("tsCheckKeyUse: certKeyUsage, !appKeyUsage");
143 if((cku
& appKeyUse
) != appKeyUse
) {
144 trustSettingsEvalDbg("tsCheckKeyUse: keyUse mismatch");
151 static bool tsCheckPolicyStr(
152 const char *appPolicyStr
,
153 CFStringRef certPolicyStr
)
155 if(certPolicyStr
!= NULL
) {
156 if(appPolicyStr
== NULL
) {
157 trustSettingsEvalDbg("tsCheckPolicyStr: certPolicyStr, !appPolicyStr");
160 /* Let CF do the string compare */
161 CFStringRef cfPolicyStr
= CFStringCreateWithCString(NULL
, appPolicyStr
,
162 kCFStringEncodingUTF8
);
163 if(cfPolicyStr
== NULL
) {
164 /* I really don't see how this can happen */
165 trustSettingsEvalDbg("tsCheckPolicyStr: policyStr string conversion error");
169 // Some trust setting strings were created with a NULL character at the
170 // end, which was included in the length. Strip those off before compare
172 CFMutableStringRef certPolicyStrNoNULL
= CFStringCreateMutableCopy(NULL
, 0, certPolicyStr
);
173 if (certPolicyStrNoNULL
== NULL
) {
174 /* I really don't see how this can happen either */
175 trustSettingsEvalDbg("tsCheckPolicyStr: policyStr string conversion error 2");
179 CFStringFindAndReplace(certPolicyStrNoNULL
, CFSTR("\00"),
180 CFSTR(""), CFRangeMake(0, CFStringGetLength(certPolicyStrNoNULL
)), kCFCompareBackwards
);
182 CFComparisonResult res
= CFStringCompare(cfPolicyStr
, certPolicyStrNoNULL
, 0);
183 CFRelease(cfPolicyStr
);
184 CFRelease(certPolicyStrNoNULL
);
185 if(res
!= kCFCompareEqualTo
) {
186 trustSettingsEvalDbg("tsCheckPolicyStr: policyStr mismatch");
194 * Determine if a cert's trust settings dictionary satisfies the specified
195 * usage constraints. Returns true if so.
196 * Only certs with a SecTrustSettingsResult of kSecTrustSettingsResultTrustRoot
197 * or kSecTrustSettingsResultTrustAsRoot will match.
199 static bool qualifyUsageWithCertDict(
200 CFDictionaryRef certDict
,
201 const CSSM_OID
*policyOID
, /* optional */
202 const char *policyStr
, /* optional */
203 SecTrustSettingsKeyUsage keyUsage
, /* optional; default = any (actually "all" here) */
206 /* this array is optional */
207 CFArrayRef trustSettings
= (CFArrayRef
)CFDictionaryGetValue(certDict
,
208 kTrustRecordTrustSettings
);
209 CFIndex numSpecs
= 0;
210 if(trustSettings
!= NULL
) {
211 numSpecs
= CFArrayGetCount(trustSettings
);
215 * Trivial case: cert has no trust settings, indicating that
216 * it's used for everything.
218 trustSettingsEvalDbg("qualifyUsageWithCertDict: no trust settings");
221 for(CFIndex addDex
=0; addDex
<numSpecs
; addDex
++) {
222 CFDictionaryRef tsDict
= (CFDictionaryRef
)CFArrayGetValueAtIndex(trustSettings
,
225 /* per-cert specs: all optional */
226 CFDataRef certPolicy
= (CFDataRef
)CFDictionaryGetValue(tsDict
,
227 kSecTrustSettingsPolicy
);
228 CFDataRef certApp
= (CFDataRef
)CFDictionaryGetValue(tsDict
,
229 kSecTrustSettingsApplication
);
230 CFStringRef certPolicyStr
= (CFStringRef
)CFDictionaryGetValue(tsDict
,
231 kSecTrustSettingsPolicyString
);
232 CFNumberRef certKeyUsage
= (CFNumberRef
)CFDictionaryGetValue(tsDict
,
233 kSecTrustSettingsKeyUsage
);
234 CFNumberRef certResultType
= (CFNumberRef
)CFDictionaryGetValue(tsDict
,
235 kSecTrustSettingsResult
);
237 if(!tsCheckPolicy(policyOID
, certPolicy
)) {
240 if(!tsCheckApp(certApp
)) {
243 if(!tsCheckKeyUse(keyUsage
, certKeyUsage
)) {
246 if(!tsCheckPolicyStr(policyStr
, certPolicyStr
)) {
251 * This is a match, take whatever SecTrustSettingsResult is here,
252 * including the default if not specified.
254 SecTrustSettingsResult resultType
= kSecTrustSettingsResultTrustRoot
;
257 CFNumberGetValue(certResultType
, kCFNumberSInt32Type
, &s
);
258 resultType
= (SecTrustSettingsResult
)s
;
261 case kSecTrustSettingsResultTrustRoot
:
262 trustSettingsEvalDbg("qualifyUsageWithCertDict: TrustRoot MATCH");
264 case kSecTrustSettingsResultTrustAsRoot
:
266 trustSettingsEvalDbg("qualifyUsageWithCertDict: TrustAsRoot but not root");
269 trustSettingsEvalDbg("qualifyUsageWithCertDict: TrustAsRoot MATCH");
272 trustSettingsEvalDbg("qualifyUsageWithCertDict: bad resultType "
273 "(%lu)", (unsigned long)resultType
);
277 trustSettingsEvalDbg("qualifyUsageWithCertDict: NO MATCH");
282 * Create initial top-level dictionary when constructing a new TrustSettings.
284 static CFMutableDictionaryRef
tsInitialDict()
286 CFMutableDictionaryRef dict
= CFDictionaryCreateMutable(NULL
,
287 kSecTrustRecordNumTopDictKeys
,
288 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
290 /* the dictionary of per-cert entries */
291 CFMutableDictionaryRef trustDict
= CFDictionaryCreateMutable(NULL
, 0,
292 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
293 CFDictionaryAddValue(dict
, kTrustRecordTrustList
, trustDict
);
294 CFRelease(trustDict
);
296 SInt32 vers
= kSecTrustRecordVersionCurrent
;
297 CFNumberRef cfVers
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &vers
);
298 CFDictionaryAddValue(dict
, kTrustRecordVersion
, cfVers
);
304 * Set the modification date of a per-cert dictionary to current time.
306 static void tsSetModDate(
307 CFMutableDictionaryRef dict
)
311 modDate
= CFDateCreate(NULL
, CFAbsoluteTimeGetCurrent());
312 CFDictionarySetValue(dict
, kTrustRecordModDate
, modDate
);
316 /* make sure a presumed CFNumber can be converted to a 32-bit number */
318 bool tsIsGoodCfNum(CFNumberRef cfn
, SInt32
*num
= NULL
)
327 if(CFGetTypeID(cfn
) != CFNumberGetTypeID()) {
332 if(!CFNumberGetValue(cfn
, kCFNumberSInt32Type
, &s
)) {
343 TrustSettings::TrustSettings(SecTrustSettingsDomain domain
)
354 #pragma mark --- Public methods ---
357 * Normal constructor, from disk.
358 * If create is true, the absence of an on-disk TrustSettings file
359 * results in the creation of a new empty TrustSettings. If create is
360 * false and no on-disk TrustSettings exists, errSecNoTrustSettings is
362 * If trim is true, the components of the on-disk TrustSettings not
363 * needed for cert evaluation are discarded. This is for TrustSettings
364 * that will be cached in memory long-term.
366 OSStatus
TrustSettings::CreateTrustSettings(
367 SecTrustSettingsDomain domain
,
372 TrustSettings
* t
= new TrustSettings(domain
);
374 Allocator
&alloc
= Allocator::standard();
375 CSSM_DATA fileData
= {0, NULL
};
376 OSStatus ortn
= errSecSuccess
;
380 /* get trust settings from file, one way or another */
382 case kSecTrustSettingsDomainAdmin
:
384 * Quickie optimization: if it's not there, don't try to
385 * get it from ocspd. This is possible because the name of the
386 * admin file is hard coded, but the per-user files aren't.
388 path
= TRUST_SETTINGS_PATH
"/" ADMIN_TRUST_SETTINGS
;
389 if(stat(path
, &sb
)) {
390 trustSettingsDbg("TrustSettings: no admin record; skipping");
391 ortn
= errSecNoTrustSettings
;
394 /* else drop thru, get it from ocspd */
395 case kSecTrustSettingsDomainUser
:
396 /* get settings from ocspd */
397 ortn
= ocspdTrustSettingsRead(alloc
, domain
, fileData
);
399 case kSecTrustSettingsDomainSystem
:
400 /* immutable; it's safe for us to read this directly */
401 if(tsReadFile(SYSTEM_TRUST_SETTINGS_PATH
, alloc
, fileData
)) {
402 ortn
= errSecNoTrustSettings
;
411 trustSettingsDbg("TrustSettings: creating new record for domain %d",
413 t
->mPropList
= tsInitialDict();
417 trustSettingsDbg("TrustSettings: record not found for domain %d",
424 CFRef
<CFDataRef
> propList(CFDataCreate(NULL
, fileData
.Data
, fileData
.Length
));
425 t
->initFromData(propList
);
426 alloc
.free(fileData
.Data
);
428 t
->validatePropList(trim
);
431 return errSecSuccess
;
435 * Create from external data, obtained by createExternal().
436 * If externalData is NULL, we'll create an empty mTrustDict.
438 OSStatus
TrustSettings::CreateTrustSettings(
439 SecTrustSettingsDomain domain
,
440 CFDataRef externalData
,
444 case kSecTrustSettingsDomainUser
:
445 case kSecTrustSettingsDomainAdmin
:
446 case kSecTrustSettingsDomainMemory
:
448 case kSecTrustSettingsDomainSystem
: /* no can do, that implies writing to it */
453 TrustSettings
* t
= new TrustSettings(domain
);
455 if(externalData
!= NULL
) {
456 t
->initFromData(externalData
);
459 t
->mPropList
= tsInitialDict();
461 t
->validatePropList(TRIM_NO
); /* never trim this */
465 return errSecSuccess
;
469 TrustSettings::~TrustSettings()
471 trustSettingsDbg("TrustSettings(domain %d) destructor", (int)mDomain
);
472 CFRELEASE(mPropList
); /* may be null if trimmed */
473 CFRELEASE(mTrustDict
); /* normally always non-NULL */
477 /* common code to init mPropList from raw data */
478 void TrustSettings::initFromData(
479 CFDataRef trustSettingsData
)
481 CFStringRef errStr
= NULL
;
483 mPropList
= (CFMutableDictionaryRef
)CFPropertyListCreateFromXMLData(
486 kCFPropertyListMutableContainersAndLeaves
,
488 if(mPropList
== NULL
) {
489 trustSettingsDbg("TrustSettings::initFromData decode err (%s)",
490 errStr
? CFStringGetCStringPtr(errStr
, kCFStringEncodingUTF8
) : "<no err>");
494 MacOSError::throwMe(errSecInvalidTrustSettings
);
499 * Flush property list data out to disk if dirty.
501 void TrustSettings::flushToDisk()
504 trustSettingsDbg("flushToDisk, domain %d, !dirty!", (int)mDomain
);
507 if(mPropList
== NULL
) {
508 trustSettingsDbg("flushToDisk, domain %d, trimmed!", (int)mDomain
);
510 MacOSError::throwMe(errSecInternalComponent
);
513 case kSecTrustSettingsDomainSystem
:
514 case kSecTrustSettingsDomainMemory
:
515 /* caller shouldn't even try this */
517 trustSettingsDbg("flushToDisk, bad domain (%d)", (int)mDomain
);
518 MacOSError::throwMe(errSecInternalComponent
);
519 case kSecTrustSettingsDomainUser
:
520 case kSecTrustSettingsDomainAdmin
:
525 * Optimization: if there are no certs in the mTrustDict dictionary,
526 * we tell ocspd to *remove* the settings for the specified domain.
527 * Having *no* settings uses less memory and is faster than having
528 * an empty settings file, especially for the admin domain, where we
530 * an RPC if the settings file is simply not there.
532 CFRef
<CFDataRef
> xmlData
;
533 CSSM_DATA cssmXmlData
= {0, NULL
};
534 CFIndex numCerts
= CFDictionaryGetCount(mTrustDict
);
536 xmlData
.take(CFPropertyListCreateXMLData(NULL
, mPropList
));
538 /* we've been very careful; this should never happen */
539 trustSettingsDbg("flushToDisk, domain %d: error converting to XML", (int)mDomain
);
540 MacOSError::throwMe(errSecInternalComponent
);
542 cssmXmlData
.Data
= (uint8
*)CFDataGetBytePtr(xmlData
);
543 cssmXmlData
.Length
= CFDataGetLength(xmlData
);
546 trustSettingsDbg("flushToDisk, domain %d: DELETING trust settings", (int)mDomain
);
549 /* cook up auth stuff so ocspd can act on our behalf */
550 AuthorizationRef authRef
;
552 ortn
= AuthorizationCreate(NULL
, kAuthorizationEmptyEnvironment
,
555 trustSettingsDbg("flushToDisk, domain %d: AuthorizationCreate returned %ld",
556 (int)mDomain
, (long)ortn
);
557 MacOSError::throwMe(errSecInternalComponent
);
559 AuthorizationExternalForm authExt
;
560 CSSM_DATA authBlob
= {sizeof(authExt
), (uint8
*)&authExt
};
561 ortn
= AuthorizationMakeExternalForm(authRef
, &authExt
);
563 trustSettingsDbg("flushToDisk, domain %d: AuthorizationMakeExternalForm returned %ld",
564 (int)mDomain
, (long)ortn
);
565 ortn
= errSecInternalComponent
;
569 ortn
= ocspdTrustSettingsWrite(mDomain
, authBlob
, cssmXmlData
);
571 trustSettingsDbg("flushToDisk, domain %d: ocspdTrustSettingsWrite returned %ld",
572 (int)mDomain
, (long)ortn
);
575 trustSettingsDbg("flushToDisk, domain %d: wrote to disk", (int)mDomain
);
578 AuthorizationFree(authRef
, 0);
580 MacOSError::throwMe(ortn
);
585 * Obtain external representation of TrustSettings data.
587 CFDataRef
TrustSettings::createExternal()
590 CFDataRef xmlData
= CFPropertyListCreateXMLData(NULL
, mPropList
);
591 if(xmlData
== NULL
) {
592 trustSettingsDbg("createExternal, domain %d: error converting to XML",
594 MacOSError::throwMe(errSecInternalComponent
);
600 * Evaluate specified cert. Returns true if we found a record for the cert
601 * matching specified constraints.
602 * Note that a true return with a value of kSecTrustSettingsResultUnspecified for
603 * the resultType means that a cert isn't to be trusted or untrusted
604 * per se; it just means that we only found allowedErrors entries.
606 * Found "allows errors" values are added to the incoming allowedErrors
607 * array which is reallocd as needed (and which may be NULL or non-NULL on
610 bool TrustSettings::evaluateCert(
611 CFStringRef certHashStr
,
612 const CSSM_OID
*policyOID
, /* optional */
613 const char *policyStr
, /* optional */
614 SecTrustSettingsKeyUsage keyUsage
, /* optional */
615 bool isRootCert
, /* for checking default setting */
616 CSSM_RETURN
**allowedErrors
, /* IN/OUT; reallocd as needed */
617 uint32
*numAllowedErrors
, /* IN/OUT */
618 SecTrustSettingsResult
*resultType
, /* RETURNED */
619 bool *foundAnyEntry
) /* RETURNED */
621 assert(mTrustDict
!= NULL
);
623 /* get trust settings dictionary for this cert */
624 CFDictionaryRef certDict
= findDictionaryForCertHash(certHashStr
);
625 if((certDict
== NULL
) && isRootCert
) {
626 /* No? How about default root setting for this domain? */
627 certDict
= findDictionaryForCertHash(kSecTrustRecordDefaultRootCert
);
630 /* @@@ debug only @@@ */
631 /* print certificate hash and found dictionary reference */
632 const size_t maxHashStrLen
= 512;
633 char *buf
= (char*)malloc(maxHashStrLen
);
635 if (!CFStringGetCString(certHashStr
, buf
, (CFIndex
)maxHashStrLen
, kCFStringEncodingUTF8
)) {
638 trustSettingsEvalDbg("evaluateCert for \"%s\", found dict %p", buf
, certDict
);
643 if(certDict
== NULL
) {
644 *foundAnyEntry
= false;
647 *foundAnyEntry
= true;
649 /* to-be-returned array of allowed errors */
650 CSSM_RETURN
*allowedErrs
= *allowedErrors
;
651 uint32 numAllowedErrs
= *numAllowedErrors
;
653 /* this means "we found something other than allowedErrors" if true */
654 bool foundSettings
= false;
656 /* to be returned in *resultType if it ends up something other than Invalid */
657 SecTrustSettingsResult returnedResult
= kSecTrustSettingsResultInvalid
;
660 * Note since we validated the entire mPropList in our constructor, and we're careful
661 * about what we put into it, we don't bother typechecking its contents here.
662 * Also note that the kTrustRecordTrustSettings entry is optional.
664 CFArrayRef trustSettings
= (CFArrayRef
)CFDictionaryGetValue(certDict
,
665 kTrustRecordTrustSettings
);
666 CFIndex numSpecs
= 0;
667 if(trustSettings
!= NULL
) {
668 numSpecs
= CFArrayGetCount(trustSettings
);
672 * Trivial case: cert has no trust settings, indicating that
673 * it's used for everything.
675 trustSettingsEvalDbg("evaluateCert: no trust settings");
677 *resultType
= kSecTrustSettingsResultTrustRoot
;
682 * The decidedly nontrivial part: grind thru all of the cert's trust
683 * settings, see if the cert matches the caller's specified usage.
685 for(CFIndex addDex
=0; addDex
<numSpecs
; addDex
++) {
686 CFDictionaryRef tsDict
= (CFDictionaryRef
)CFArrayGetValueAtIndex(trustSettings
,
689 /* per-cert specs: all optional */
690 CFDataRef certPolicy
= (CFDataRef
)CFDictionaryGetValue(tsDict
,
691 kSecTrustSettingsPolicy
);
692 CFDataRef certApp
= (CFDataRef
)CFDictionaryGetValue(tsDict
,
693 kSecTrustSettingsApplication
);
694 CFStringRef certPolicyStr
= (CFStringRef
)CFDictionaryGetValue(tsDict
,
695 kSecTrustSettingsPolicyString
);
696 CFNumberRef certKeyUsage
= (CFNumberRef
)CFDictionaryGetValue(tsDict
,
697 kSecTrustSettingsKeyUsage
);
698 CFNumberRef certResultType
= (CFNumberRef
)CFDictionaryGetValue(tsDict
,
699 kSecTrustSettingsResult
);
700 CFNumberRef certAllowedErr
= (CFNumberRef
)CFDictionaryGetValue(tsDict
,
701 kSecTrustSettingsAllowedError
);
703 /* now, skip if we find a constraint that doesn't match intended use */
704 if(!tsCheckPolicy(policyOID
, certPolicy
)) {
707 if(!tsCheckApp(certApp
)) {
710 if(!tsCheckKeyUse(keyUsage
, certKeyUsage
)) {
713 if(!tsCheckPolicyStr(policyStr
, certPolicyStr
)) {
717 trustSettingsEvalDbg("evaluateCert: MATCH");
718 foundSettings
= true;
721 /* note we already validated this value */
723 CFNumberGetValue(certAllowedErr
, kCFNumberSInt32Type
, &s
);
724 allowedErrs
= (CSSM_RETURN
*)::realloc(allowedErrs
,
725 ++numAllowedErrs
* sizeof(CSSM_RETURN
));
726 allowedErrs
[numAllowedErrs
-1] = (CSSM_RETURN
) s
;
730 * We found a match, but we only return the current result type
731 * to caller if we haven't already returned something other than
732 * kSecTrustSettingsResultUnspecified. Once we find a valid result type,
733 * we keep on searching, but only for additional allowed errors.
735 switch(returnedResult
) {
736 /* found match but no valid resultType yet */
737 case kSecTrustSettingsResultUnspecified
:
738 /* haven't been thru here */
739 case kSecTrustSettingsResultInvalid
:
741 /* note we already validated this */
743 CFNumberGetValue(certResultType
, kCFNumberSInt32Type
, &s
);
744 returnedResult
= (SecTrustSettingsResult
)s
;
747 /* default is "copacetic" */
748 returnedResult
= kSecTrustSettingsResultTrustRoot
;
752 /* we already have a definitive resultType, don't change it */
755 } /* for each dictionary in trustSettings */
757 *allowedErrors
= allowedErrs
;
758 *numAllowedErrors
= numAllowedErrs
;
759 if(returnedResult
!= kSecTrustSettingsResultInvalid
) {
760 *resultType
= returnedResult
;
762 return foundSettings
;
767 * Find all certs in specified keychain list which have entries in this trust record.
768 * Certs already in the array are not added.
770 void TrustSettings::findCerts(
771 StorageManager::KeychainList
&keychains
,
772 CFMutableArrayRef certArray
)
774 findQualifiedCerts(keychains
,
776 false, /* onlyRoots */
777 NULL
, NULL
, kSecTrustSettingsKeyUseAny
,
781 void TrustSettings::findQualifiedCerts(
782 StorageManager::KeychainList
&keychains
,
784 * If findAll is true, all certs are returned and the subsequent
785 * qualifiers are ignored
788 /* if true, only return root (self-signed) certs */
790 const CSSM_OID
*policyOID
, /* optional */
791 const char *policyString
, /* optional */
792 SecTrustSettingsKeyUsage keyUsage
, /* optional */
793 CFMutableArrayRef certArray
) /* certs appended here */
795 StLock
<Mutex
> _(SecTrustKeychainsGetMutex());
798 * a set, hopefully with a good hash function for CFData, to keep track of what's
799 * been added to the outgoing array.
801 CFRef
<CFMutableSetRef
> certSet(CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
));
803 /* search: all certs, no attributes */
804 KCCursor
cursor(keychains
, CSSM_DL_DB_RECORD_X509_CERTIFICATE
, NULL
);
808 found
= cursor
->next(certItem
);
812 CFRef
<SecCertificateRef
> certRef((SecCertificateRef
)certItem
->handle());
814 /* do we have an entry for this cert? */
815 CFDictionaryRef certDict
= findDictionaryForCert(certRef
);
816 if(certDict
== NULL
) {
822 if(!qualifyUsageWithCertDict(certDict
, policyOID
,
823 policyString
, keyUsage
, onlyRoots
)) {
828 /* see if we already have this one - get in CFData form */
830 OSStatus ortn
= SecCertificateGetData(certRef
, &certData
);
832 trustSettingsEvalDbg("findQualifiedCerts: SecCertificateGetData error");
835 CFRef
<CFDataRef
> cfData(CFDataCreate(NULL
, certData
.Data
, certData
.Length
));
836 CFDataRef cfd
= cfData
;
837 if(CFSetContainsValue(certSet
, cfd
)) {
838 trustSettingsEvalDbg("findQualifiedCerts: dup cert");
842 /* add to the tracking set, which owns the CFData now */
843 CFSetAddValue(certSet
, cfd
);
844 /* and add the SecCert to caller's array, which owns that now */
845 CFArrayAppendValue(certArray
, certRef
);
851 * Obtain trust settings for the specified cert. Returned settings array
852 * is in the public API form; caller must release. Returns NULL
853 * (does not throw) if the cert is not present in this TrustRecord.
855 CFArrayRef
TrustSettings::copyTrustSettings(
856 SecCertificateRef certRef
)
858 CFDictionaryRef certDict
= NULL
;
860 /* find the on-disk usage constraints for this cert */
861 certDict
= findDictionaryForCert(certRef
);
862 if(certDict
== NULL
) {
863 trustSettingsDbg("copyTrustSettings: dictionary not found");
866 CFArrayRef diskTrustSettings
= (CFArrayRef
)CFDictionaryGetValue(certDict
,
867 kTrustRecordTrustSettings
);
868 CFIndex numSpecs
= 0;
869 if(diskTrustSettings
!= NULL
) {
870 /* this field is optional */
871 numSpecs
= CFArrayGetCount(diskTrustSettings
);
875 * Convert to API-style array of dictionaries.
876 * We give the caller an array even if it's empty.
878 CFRef
<CFMutableArrayRef
> outArray(CFArrayCreateMutable(NULL
, numSpecs
,
879 &kCFTypeArrayCallBacks
));
880 for(CFIndex dex
=0; dex
<numSpecs
; dex
++) {
881 CFDictionaryRef diskTsDict
=
882 (CFDictionaryRef
)CFArrayGetValueAtIndex(diskTrustSettings
, dex
);
883 /* already validated... */
884 assert(CFGetTypeID(diskTsDict
) == CFDictionaryGetTypeID());
886 CFDataRef certPolicy
= (CFDataRef
) CFDictionaryGetValue(diskTsDict
, kSecTrustSettingsPolicy
);
887 CFDataRef certApp
= (CFDataRef
) CFDictionaryGetValue(diskTsDict
, kSecTrustSettingsApplication
);
888 CFStringRef policyStr
= (CFStringRef
)CFDictionaryGetValue(diskTsDict
, kSecTrustSettingsPolicyString
);
889 CFNumberRef allowedErr
= (CFNumberRef
)CFDictionaryGetValue(diskTsDict
, kSecTrustSettingsAllowedError
);
890 CFNumberRef resultType
= (CFNumberRef
)CFDictionaryGetValue(diskTsDict
, kSecTrustSettingsResult
);
891 CFNumberRef keyUsage
= (CFNumberRef
)CFDictionaryGetValue(diskTsDict
, kSecTrustSettingsKeyUsage
);
893 if((certPolicy
== NULL
) &&
895 (policyStr
== NULL
) &&
896 (allowedErr
== NULL
) &&
897 (resultType
== NULL
) &&
898 (keyUsage
== NULL
)) {
899 /* weird but legal */
902 CFRef
<CFMutableDictionaryRef
> outTsDict(CFDictionaryCreateMutable(NULL
,
904 &kCFTypeDictionaryKeyCallBacks
,
905 &kCFTypeDictionaryValueCallBacks
));
907 if(certPolicy
!= NULL
) {
908 /* convert OID as CFDataRef to SecPolicyRef */
909 SecPolicyRef policyRef
= NULL
;
910 CSSM_OID policyOid
= { CFDataGetLength(certPolicy
),
911 (uint8
*)CFDataGetBytePtr(certPolicy
) };
912 OSStatus ortn
= SecPolicyCopy(CSSM_CERT_X_509v3
, &policyOid
, &policyRef
);
914 trustSettingsDbg("copyTrustSettings: OID conversion error");
915 abort("Bad Policy OID in trusted root list", errSecInvalidTrustedRootRecord
);
917 CFDictionaryAddValue(outTsDict
, kSecTrustSettingsPolicy
, policyRef
);
918 CFRelease(policyRef
); // owned by dictionary
921 if(certApp
!= NULL
) {
922 /* convert app as CFDataRef to SecTrustedApplicationRef */
923 SecTrustedApplicationRef appRef
;
924 OSStatus ortn
= SecTrustedApplicationCreateWithExternalRepresentation(certApp
, &appRef
);
926 trustSettingsDbg("copyTrustSettings: App conversion error");
927 abort("Bad application data in trusted root list", errSecInvalidTrustedRootRecord
);
929 CFDictionaryAddValue(outTsDict
, kSecTrustSettingsApplication
, appRef
);
930 CFRelease(appRef
); // owned by dictionary
933 /* remaining 4 are trivial */
934 if(policyStr
!= NULL
) {
936 * copy, since policyStr is in our mutable dictionary and could change out from
939 CFStringRef str
= CFStringCreateCopy(NULL
, policyStr
);
940 CFDictionaryAddValue(outTsDict
, kSecTrustSettingsPolicyString
, str
);
941 CFRelease(str
); // owned by dictionary
943 if(allowedErr
!= NULL
) {
944 /* there is no mutable CFNumber, so.... */
945 CFDictionaryAddValue(outTsDict
, kSecTrustSettingsAllowedError
, allowedErr
);
947 if(resultType
!= NULL
) {
948 CFDictionaryAddValue(outTsDict
, kSecTrustSettingsResult
, resultType
);
950 if(keyUsage
!= NULL
) {
951 CFDictionaryAddValue(outTsDict
, kSecTrustSettingsKeyUsage
, keyUsage
);
953 CFArrayAppendValue(outArray
, outTsDict
);
954 /* outTsDict autoreleases; owned by outArray now */
956 CFRetain(outArray
); // now that it's good to go....
960 CFDateRef
TrustSettings::copyModDate(
961 SecCertificateRef certRef
)
963 CFDictionaryRef certDict
= NULL
;
965 /* find the on-disk usage constraints dictionary for this cert */
966 certDict
= findDictionaryForCert(certRef
);
967 if(certDict
== NULL
) {
968 trustSettingsDbg("copyModDate: dictionary not found");
971 CFDateRef modDate
= (CFDateRef
)CFDictionaryGetValue(certDict
, kTrustRecordModDate
);
972 if(modDate
== NULL
) {
976 /* this only works becuase there is no mutable CFDateRef */
982 * Modify cert's trust settings, or add a new cert to the record.
984 void TrustSettings::setTrustSettings(
985 SecCertificateRef certRef
,
986 CFTypeRef trustSettingsDictOrArray
)
988 /* to validate, we need to know if the cert is self-signed */
990 Boolean isSelfSigned
= false;
992 if(certRef
== kSecTrustSettingsDefaultRootCertSetting
) {
994 * Validate settings as if this were root, specifically,
995 * kSecTrustSettingsResultTrustRoot (explicitly or by
1001 ortn
= SecCertificateIsSelfSigned(certRef
, &isSelfSigned
);
1003 MacOSError::throwMe(ortn
);
1007 /* caller's app/policy spec OK? */
1008 CFRef
<CFArrayRef
> trustSettings(validateApiTrustSettings(
1009 trustSettingsDictOrArray
, isSelfSigned
));
1011 /* caller is responsible for ensuring these */
1012 assert(mPropList
!= NULL
);
1013 assert(mDomain
!= kSecTrustSettingsDomainSystem
);
1015 /* extract issuer and serial number from the cert, if it's a cert */
1016 CFRef
<CFDataRef
> issuer
;
1017 CFRef
<CFDataRef
> serial
;
1018 if(certRef
!= kSecTrustSettingsDefaultRootCertSetting
) {
1019 copyIssuerAndSerial(certRef
, issuer
.take(), serial
.take());
1023 issuer
= CFDataCreate(NULL
, &dummy
, 0);
1024 serial
= CFDataCreate(NULL
, &dummy
, 0);
1027 /* SHA1 digest as string */
1028 CFRef
<CFStringRef
> certHashStr(SecTrustSettingsCertHashStrFromCert(certRef
));
1030 trustSettingsDbg("TrustSettings::setTrustSettings: CertHashStrFromCert error");
1031 MacOSError::throwMe(errSecItemNotFound
);
1035 * Find entry for this cert, if present.
1037 CFMutableDictionaryRef certDict
=
1038 (CFMutableDictionaryRef
)findDictionaryForCertHash(certHashStr
);
1039 if(certDict
== NULL
) {
1040 /* create new dictionary */
1041 certDict
= CFDictionaryCreateMutable(NULL
, kSecTrustRecordNumCertDictKeys
,
1042 &kCFCopyStringDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1043 if(certDict
== NULL
) {
1044 MacOSError::throwMe(errSecAllocate
);
1046 CFDictionaryAddValue(certDict
, kTrustRecordIssuer
, issuer
);
1047 CFDictionaryAddValue(certDict
, kTrustRecordSerialNumber
, serial
);
1048 if(CFArrayGetCount(trustSettings
) != 0) {
1049 /* skip this if the settings array is empty */
1050 CFDictionaryAddValue(certDict
, kTrustRecordTrustSettings
, trustSettings
);
1052 tsSetModDate(certDict
);
1054 /* add this new cert dictionary to top-level mTrustDict */
1055 CFDictionaryAddValue(mTrustDict
, static_cast<CFStringRef
>(certHashStr
), certDict
);
1057 /* mTrustDict owns the dictionary now */
1058 CFRelease(certDict
);
1062 tsSetModDate(certDict
);
1063 if(CFArrayGetCount(trustSettings
) != 0) {
1064 CFDictionarySetValue(certDict
, kTrustRecordTrustSettings
, trustSettings
);
1067 /* empty settings array: remove from dictionary */
1068 CFDictionaryRemoveValue(certDict
, kTrustRecordTrustSettings
);
1075 * Delete a certificate's trust settings.
1077 void TrustSettings::deleteTrustSettings(
1078 SecCertificateRef certRef
)
1080 CFDictionaryRef certDict
= NULL
;
1082 /* caller is responsible for ensuring these */
1083 assert(mPropList
!= NULL
);
1084 assert(mDomain
!= kSecTrustSettingsDomainSystem
);
1086 /* SHA1 digest as string */
1087 CFRef
<CFStringRef
> certHashStr(SecTrustSettingsCertHashStrFromCert(certRef
));
1089 MacOSError::throwMe(errSecItemNotFound
);
1092 /* present in top-level mTrustDict? */
1093 certDict
= findDictionaryForCertHash(certHashStr
);
1094 if(certDict
!= NULL
) {
1095 CFDictionaryRemoveValue(mTrustDict
, static_cast<CFStringRef
>(certHashStr
));
1100 * Throwing this error is the only reason we don't blindly do
1101 * a CFDictionaryRemoveValue() without first doing
1102 * findDictionaryForCertHash().
1104 trustSettingsDbg("TrustSettings::deleteRoot: cert dictionary not found");
1105 MacOSError::throwMe(errSecItemNotFound
);
1109 #pragma mark --- Private methods ---
1112 * Find a given cert's entry in the top-level mTrustDict. Return the
1113 * entry as a dictionary. Returned dictionary is not refcounted.
1114 * The mutability of the returned dictionary is the same as the mutability
1115 * of the underlying StickRecord::mPropList, which the caller is just
1116 * going to have to know (and cast accordingly if a mutable dictionary
1119 CFDictionaryRef
TrustSettings::findDictionaryForCert(
1120 SecCertificateRef certRef
)
1122 CFRef
<CFStringRef
> certHashStr(SecTrustSettingsCertHashStrFromCert(certRef
));
1123 if (certHashStr
.get() == NULL
)
1128 return findDictionaryForCertHash(static_cast<CFStringRef
>(certHashStr
));
1132 * Find entry in mTrustDict given cert hash string.
1134 CFDictionaryRef
TrustSettings::findDictionaryForCertHash(
1135 CFStringRef certHashStr
)
1137 assert(mTrustDict
!= NULL
);
1138 return (CFDictionaryRef
)CFDictionaryGetValue(mTrustDict
, certHashStr
);
1142 * Validate incoming trust settings, which may be NULL, a dictionary, or
1143 * an array of dictionaries. Convert from the API-style dictionaries
1144 * to the internal style suitable for writing to disk as part of
1147 * We return a refcounted CFArray in any case if the incoming parameter is good.
1149 CFArrayRef
TrustSettings::validateApiTrustSettings(
1150 CFTypeRef trustSettingsDictOrArray
,
1151 Boolean isSelfSigned
)
1153 CFArrayRef tmpInArray
= NULL
;
1155 if(trustSettingsDictOrArray
== NULL
) {
1156 /* trivial case, only valid for roots */
1158 trustSettingsDbg("validateApiUsageConstraints: !isSelfSigned, no settings");
1159 MacOSError::throwMe(errSecParam
);
1161 return CFArrayCreate(NULL
, NULL
, 0, &kCFTypeArrayCallBacks
);
1163 else if(CFGetTypeID(trustSettingsDictOrArray
) == CFDictionaryGetTypeID()) {
1165 tmpInArray
= CFArrayCreate(NULL
, &trustSettingsDictOrArray
, 1,
1166 &kCFTypeArrayCallBacks
);
1168 else if(CFGetTypeID(trustSettingsDictOrArray
) == CFArrayGetTypeID()) {
1169 /* as is, refcount - we'll release later */
1170 tmpInArray
= (CFArrayRef
)trustSettingsDictOrArray
;
1171 CFRetain(tmpInArray
);
1174 trustSettingsDbg("validateApiUsageConstraints: bad trustSettingsDictOrArray");
1175 MacOSError::throwMe(errSecParam
);
1178 CFIndex numSpecs
= CFArrayGetCount(tmpInArray
);
1179 CFMutableArrayRef outArray
= CFArrayCreateMutable(NULL
, numSpecs
, &kCFTypeArrayCallBacks
);
1181 OSStatus ortn
= errSecSuccess
;
1182 SecPolicyRef certPolicy
;
1183 SecTrustedApplicationRef certApp
;
1186 for(CFIndex dex
=0; dex
<numSpecs
; dex
++) {
1187 CFDataRef oidData
= NULL
;
1188 CFDataRef appData
= NULL
;
1189 CFStringRef policyStr
= NULL
;
1190 CFNumberRef allowedErr
= NULL
;
1191 CFNumberRef resultType
= NULL
;
1192 CFNumberRef keyUsage
= NULL
;
1194 SecTrustSettingsResult result
;
1196 /* each element is a dictionary */
1197 CFDictionaryRef ucDict
= (CFDictionaryRef
)CFArrayGetValueAtIndex(tmpInArray
, dex
);
1198 if(CFGetTypeID(ucDict
) != CFDictionaryGetTypeID()) {
1199 trustSettingsDbg("validateAppPolicyArray: malformed usageConstraint dictionary");
1204 /* policy - optional */
1205 certPolicy
= (SecPolicyRef
)CFDictionaryGetValue(ucDict
, kSecTrustSettingsPolicy
);
1206 if(certPolicy
!= NULL
) {
1207 if(CFGetTypeID(certPolicy
) != SecPolicyGetTypeID()) {
1208 trustSettingsDbg("validateAppPolicyArray: malformed certPolicy");
1212 ortn
= SecPolicyGetOID(certPolicy
, &oid
);
1214 trustSettingsDbg("validateAppPolicyArray: SecPolicyGetOID error");
1217 oidData
= CFDataCreate(NULL
, oid
.Data
, oid
.Length
);
1220 /* application - optional */
1221 certApp
= (SecTrustedApplicationRef
)CFDictionaryGetValue(ucDict
, kSecTrustSettingsApplication
);
1222 if(certApp
!= NULL
) {
1223 if(CFGetTypeID(certApp
) != SecTrustedApplicationGetTypeID()) {
1224 trustSettingsDbg("validateAppPolicyArray: malformed certApp");
1228 ortn
= SecTrustedApplicationCopyExternalRepresentation(certApp
, &appData
);
1230 trustSettingsDbg("validateAppPolicyArray: "
1231 "SecTrustedApplicationCopyExternalRepresentation error");
1236 policyStr
= (CFStringRef
)CFDictionaryGetValue(ucDict
, kSecTrustSettingsPolicyString
);
1237 if(policyStr
!= NULL
) {
1238 if(CFGetTypeID(policyStr
) != CFStringGetTypeID()) {
1239 trustSettingsDbg("validateAppPolicyArray: malformed policyStr");
1244 allowedErr
= (CFNumberRef
)CFDictionaryGetValue(ucDict
, kSecTrustSettingsAllowedError
);
1245 if(!tsIsGoodCfNum(allowedErr
)) {
1246 trustSettingsDbg("validateAppPolicyArray: malformed allowedErr");
1250 resultType
= (CFNumberRef
)CFDictionaryGetValue(ucDict
, kSecTrustSettingsResult
);
1251 if(!tsIsGoodCfNum(resultType
, &resultNum
)) {
1252 trustSettingsDbg("validateAppPolicyArray: malformed resultType");
1257 /* validate result later */
1259 keyUsage
= (CFNumberRef
)CFDictionaryGetValue(ucDict
, kSecTrustSettingsKeyUsage
);
1260 if(!tsIsGoodCfNum(keyUsage
)) {
1261 trustSettingsDbg("validateAppPolicyArray: malformed keyUsage");
1266 if(!oidData
&& !appData
&& !policyStr
&&
1267 !allowedErr
&& !resultType
&& !keyUsage
) {
1268 /* nothing here - weird, but legal - skip it */
1272 /* create dictionary for this usageConstraint */
1273 CFMutableDictionaryRef outDict
= CFDictionaryCreateMutable(NULL
,
1275 &kCFTypeDictionaryKeyCallBacks
,
1276 &kCFTypeDictionaryValueCallBacks
);
1278 CFDictionaryAddValue(outDict
, kSecTrustSettingsPolicy
, oidData
);
1279 CFRelease(oidData
); // owned by dictionary
1282 CFDictionaryAddValue(outDict
, kSecTrustSettingsApplication
, appData
);
1283 CFRelease(appData
); // owned by dictionary
1286 CFDictionaryAddValue(outDict
, kSecTrustSettingsPolicyString
, policyStr
);
1287 /* still owned by ucDict */
1290 CFDictionaryAddValue(outDict
, kSecTrustSettingsAllowedError
, allowedErr
);
1293 /* let's be really picky on this one */
1295 case kSecTrustSettingsResultInvalid
:
1298 case kSecTrustSettingsResultTrustRoot
:
1300 trustSettingsDbg("validateAppPolicyArray: TrustRoot, !isSelfSigned");
1304 case kSecTrustSettingsResultTrustAsRoot
:
1306 trustSettingsDbg("validateAppPolicyArray: TrustAsRoot, isSelfSigned");
1310 case kSecTrustSettingsResultDeny
:
1311 case kSecTrustSettingsResultUnspecified
:
1314 trustSettingsDbg("validateAppPolicyArray: bogus resultType");
1321 CFDictionaryAddValue(outDict
, kSecTrustSettingsResult
, resultType
);
1324 /* no resultType; default of TrustRoot only valid for root */
1326 trustSettingsDbg("validateAppPolicyArray: default result, !isSelfSigned");
1332 CFDictionaryAddValue(outDict
, kSecTrustSettingsKeyUsage
, keyUsage
);
1335 /* append dictionary to output */
1336 CFArrayAppendValue(outArray
, outDict
);
1337 /* array owns the dictionary now */
1340 } /* for each usage constraint dictionary */
1342 CFRelease(tmpInArray
);
1344 CFRelease(outArray
);
1345 MacOSError::throwMe(ortn
);
1351 * Validate an trust settings array obtained from disk.
1352 * Returns true if OK, else returns false.
1354 bool TrustSettings::validateTrustSettingsArray(
1355 CFArrayRef trustSettings
)
1357 CFIndex numSpecs
= CFArrayGetCount(trustSettings
);
1358 for(CFIndex dex
=0; dex
<numSpecs
; dex
++) {
1359 CFDictionaryRef ucDict
= (CFDictionaryRef
)CFArrayGetValueAtIndex(trustSettings
,
1361 if(CFGetTypeID(ucDict
) != CFDictionaryGetTypeID()) {
1362 trustSettingsDbg("validateAppPolicyArray: malformed app/policy dictionary");
1365 CFDataRef certPolicy
= (CFDataRef
)CFDictionaryGetValue(ucDict
, kSecTrustSettingsPolicy
);
1366 if((certPolicy
!= NULL
) && (CFGetTypeID(certPolicy
) != CFDataGetTypeID())) {
1367 trustSettingsDbg("validateAppPolicyArray: malformed certPolicy");
1370 CFDataRef certApp
= (CFDataRef
)CFDictionaryGetValue(ucDict
, kSecTrustSettingsApplication
);
1371 if((certApp
!= NULL
) && (CFGetTypeID(certApp
) != CFDataGetTypeID())) {
1372 trustSettingsDbg("validateAppPolicyArray: malformed certApp");
1375 CFStringRef policyStr
= (CFStringRef
)CFDictionaryGetValue(ucDict
, kSecTrustSettingsPolicyString
);
1376 if((policyStr
!= NULL
) && (CFGetTypeID(policyStr
) != CFStringGetTypeID())) {
1377 trustSettingsDbg("validateAppPolicyArray: malformed policyStr");
1380 CFNumberRef cfNum
= (CFNumberRef
)CFDictionaryGetValue(ucDict
, kSecTrustSettingsAllowedError
);
1381 if(!tsIsGoodCfNum(cfNum
)) {
1382 trustSettingsDbg("validateAppPolicyArray: malformed allowedErr");
1385 cfNum
= (CFNumberRef
)CFDictionaryGetValue(ucDict
, kSecTrustSettingsResult
);
1386 if(!tsIsGoodCfNum(cfNum
)) {
1387 trustSettingsDbg("validateAppPolicyArray: malformed resultType");
1390 cfNum
= (CFNumberRef
)CFDictionaryGetValue(ucDict
, kSecTrustSettingsKeyUsage
);
1391 if(!tsIsGoodCfNum(cfNum
)) {
1392 trustSettingsDbg("validateAppPolicyArray: malformed keyUsage");
1395 } /* for each usageConstraint dictionary */
1400 * Validate mPropList after it's read from disk or supplied as an external
1401 * representation. Allows subsequent use of mTrustDict to proceed with
1402 * relative impunity.
1404 void TrustSettings::validatePropList(bool trim
)
1406 /* top level dictionary */
1408 trustSettingsDbg("TrustSettings::validatePropList missing mPropList");
1409 abort("missing propList", errSecInvalidTrustedRootRecord
);
1412 if(CFGetTypeID(mPropList
) != CFDictionaryGetTypeID()) {
1413 trustSettingsDbg("TrustSettings::validatePropList: malformed mPropList");
1414 abort("malformed propList", errSecInvalidTrustedRootRecord
);
1417 /* That dictionary has two entries */
1418 CFNumberRef cfVers
= (CFNumberRef
)CFDictionaryGetValue(mPropList
, kTrustRecordVersion
);
1419 if((cfVers
== NULL
) || (CFGetTypeID(cfVers
) != CFNumberGetTypeID())) {
1420 trustSettingsDbg("TrustSettings::validatePropList: malformed version");
1421 abort("malformed version", errSecInvalidTrustedRootRecord
);
1423 if(!CFNumberGetValue(cfVers
, kCFNumberSInt32Type
, &mDictVersion
)) {
1424 trustSettingsDbg("TrustSettings::validatePropList: malformed version");
1425 abort("malformed version", errSecInvalidTrustedRootRecord
);
1427 if((mDictVersion
> kSecTrustRecordVersionCurrent
) ||
1428 (mDictVersion
== kSecTrustRecordVersionInvalid
)) {
1429 trustSettingsDbg("TrustSettings::validatePropList: incompatible version");
1430 abort("incompatible version", errSecInvalidTrustedRootRecord
);
1432 /* other backwards-compatibility handling done later, if needed, per mDictVersion */
1434 mTrustDict
= (CFMutableDictionaryRef
)CFDictionaryGetValue(mPropList
, kTrustRecordTrustList
);
1435 if(mTrustDict
!= NULL
) {
1436 CFRetain(mTrustDict
);
1438 if((mTrustDict
== NULL
) || (CFGetTypeID(mTrustDict
) != CFDictionaryGetTypeID())) {
1439 trustSettingsDbg("TrustSettings::validatePropList: malformed mTrustDict");
1440 abort("malformed TrustArray", errSecInvalidTrustedRootRecord
);
1443 /* grind through the per-cert entries */
1444 CFIndex numCerts
= CFDictionaryGetCount(mTrustDict
);
1445 const void *dictKeys
[numCerts
];
1446 const void *dictValues
[numCerts
];
1447 CFDictionaryGetKeysAndValues(mTrustDict
, dictKeys
, dictValues
);
1449 for(CFIndex dex
=0; dex
<numCerts
; dex
++) {
1450 /* get per-cert dictionary */
1451 CFMutableDictionaryRef certDict
= (CFMutableDictionaryRef
)dictValues
[dex
];
1452 if((certDict
== NULL
) || (CFGetTypeID(certDict
) != CFDictionaryGetTypeID())) {
1453 trustSettingsDbg("TrustSettings::validatePropList: malformed certDict");
1454 abort("malformed certDict", errSecInvalidTrustedRootRecord
);
1458 * That dictionary has exactly four entries.
1459 * If we're trimming, all we need is the actual trust settings.
1463 CFDataRef cfd
= (CFDataRef
)CFDictionaryGetValue(certDict
, kTrustRecordIssuer
);
1465 trustSettingsDbg("TrustSettings::validatePropList: missing issuer");
1466 abort("missing issuer", errSecInvalidTrustedRootRecord
);
1468 if(CFGetTypeID(cfd
) != CFDataGetTypeID()) {
1469 trustSettingsDbg("TrustSettings::validatePropList: malformed issuer");
1470 abort("malformed issuer", errSecInvalidTrustedRootRecord
);
1473 CFDictionaryRemoveValue(certDict
, kTrustRecordIssuer
);
1477 cfd
= (CFDataRef
)CFDictionaryGetValue(certDict
, kTrustRecordSerialNumber
);
1479 trustSettingsDbg("TrustSettings::validatePropList: missing serial number");
1480 abort("missing serial number", errSecInvalidTrustedRootRecord
);
1482 if(CFGetTypeID(cfd
) != CFDataGetTypeID()) {
1483 trustSettingsDbg("TrustSettings::validatePropList: malformed serial number");
1484 abort("malformed serial number", errSecInvalidTrustedRootRecord
);
1487 CFDictionaryRemoveValue(certDict
, kTrustRecordSerialNumber
);
1490 /* modification date */
1491 CFDateRef modDate
= (CFDateRef
)CFDictionaryGetValue(certDict
, kTrustRecordModDate
);
1492 if(modDate
== NULL
) {
1493 trustSettingsDbg("TrustSettings::validatePropList: missing modDate");
1494 abort("missing modDate", errSecInvalidTrustedRootRecord
);
1496 if(CFGetTypeID(modDate
) != CFDateGetTypeID()) {
1497 trustSettingsDbg("TrustSettings::validatePropList: malformed modDate");
1498 abort("malformed modDate", errSecInvalidTrustedRootRecord
);
1501 CFDictionaryRemoveValue(certDict
, kTrustRecordModDate
);
1504 /* the actual trust settings */
1505 CFArrayRef trustSettings
= (CFArrayRef
)CFDictionaryGetValue(certDict
,
1506 kTrustRecordTrustSettings
);
1507 if(trustSettings
== NULL
) {
1508 /* optional; this cert's entry is good */
1511 if(CFGetTypeID(trustSettings
) != CFArrayGetTypeID()) {
1512 trustSettingsDbg("TrustSettings::validatePropList: malformed useConstraint"
1514 abort("malformed useConstraint array", errSecInvalidTrustedRootRecord
);
1517 /* Now validate the usageConstraint array contents */
1518 if(!validateTrustSettingsArray(trustSettings
)) {
1519 abort("malformed useConstraint array", errSecInvalidTrustedRootRecord
);
1521 } /* for each cert dictionary in top-level array */
1524 /* we don't need the top-level dictionary any more */
1525 CFRelease(mPropList
);
1531 * Obtain non-normalized issuer and serial number for specified cert, both
1532 * returned as CFDataRefs owned by caller.
1534 void TrustSettings::copyIssuerAndSerial(
1535 SecCertificateRef certRef
,
1536 CFDataRef
*issuer
, /* optional, RETURNED */
1537 CFDataRef
*serial
) /* RETURNED */
1539 SecPointer
<Certificate
> cert
= Certificate::required(certRef
);
1540 CSSM_DATA_PTR fieldVal
;
1542 if(issuer
!= NULL
) {
1543 fieldVal
= cert
->copyFirstFieldValue(CSSMOID_X509V1IssuerNameStd
);
1544 *issuer
= CFDataCreate(NULL
, fieldVal
->Data
, fieldVal
->Length
);
1545 cert
->releaseFieldValue(CSSMOID_X509V1IssuerNameStd
, fieldVal
);
1548 fieldVal
= cert
->copyFirstFieldValue(CSSMOID_X509V1SerialNumber
);
1549 *serial
= CFDataCreate(NULL
, fieldVal
->Data
, fieldVal
->Length
);
1550 cert
->releaseFieldValue(CSSMOID_X509V1SerialNumber
, fieldVal
);
1553 void TrustSettings::abort(
1557 Syslog::error("TrustSettings: %s", why
);
1558 MacOSError::throwMe(err
);