2 * Copyright (c) 2007-2018 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 * SecTrustStore.c - CertificateSource API to a system root certificate store
27 #include <Security/SecTrustStore.h>
29 #include <Security/SecCertificateInternal.h>
30 #include <Security/SecInternal.h>
31 #include <Security/SecuritydXPC.h>
32 #include <Security/SecPolicyPriv.h>
33 #include <Security/SecPolicyInternal.h>
34 #include <CoreFoundation/CFString.h>
35 #include <AssertMacros.h>
36 #include <ipc/securityd_client.h>
37 #include "SecFramework.h"
40 #include <os/activity.h>
42 #include "SecTrustPriv.h"
43 #include <Security/SecTrustSettingsPriv.h>
44 #include <utilities/SecCFError.h>
45 #include <utilities/SecCFWrappers.h>
46 #include "utilities/SecDb.h"
47 #include "SecTrustInternal.h"
49 static CFStringRef kSecTrustStoreUserName
= CFSTR("user");
51 SecTrustStoreRef
SecTrustStoreForDomain(SecTrustStoreDomain domain
) {
52 CFStringRef domainName
;
53 if (domain
== kSecTrustStoreDomainUser
) {
54 domainName
= kSecTrustStoreUserName
;
60 return gTrustd
->sec_trust_store_for_domain(domainName
, NULL
);
62 return (SecTrustStoreRef
)domainName
;
66 static bool string_data_to_bool_error(enum SecXPCOperation op
, SecTrustStoreRef ts
, CFDataRef digest
, CFErrorRef
*error
)
68 return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
69 return SecXPCDictionarySetString(message
, kSecXPCKeyDomain
, (CFStringRef
)ts
, error
) &&
70 SecXPCDictionarySetData(message
, kSecXPCKeyDigest
, digest
, error
);
74 static bool string_data_to_bool_bool_error(enum SecXPCOperation op
, SecTrustStoreRef ts
, CFDataRef digest
, bool *result
, CFErrorRef
*error
)
76 os_activity_t activity
= os_activity_create("SecTrustStoreContains", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
77 os_activity_scope(activity
);
78 bool status
= securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
79 return SecXPCDictionarySetString(message
, kSecXPCKeyDomain
, (CFStringRef
)ts
, error
) &&
80 SecXPCDictionarySetData(message
, kSecXPCKeyDigest
, digest
, error
);
81 }, ^bool(xpc_object_t response
, CFErrorRef
*error
) {
83 *result
= xpc_dictionary_get_bool(response
, kSecXPCKeyResult
);
90 Boolean
SecTrustStoreContains(SecTrustStoreRef ts
,
91 SecCertificateRef certificate
) {
94 __block
bool contains
= false;
97 require(digest
= SecCertificateGetSHA1Digest(certificate
), errOut
);
100 ok
= (SecOSStatusWith(^bool (CFErrorRef
*error
) {
101 return TRUSTD_XPC(sec_trust_store_contains
, string_data_to_bool_bool_error
, ts
, digest
, &contains
, error
);
102 }) == errSecSuccess
);
105 return ok
&& contains
;
108 static bool SecXPCDictionarySetCertificate(xpc_object_t message
, const char *key
, SecCertificateRef certificate
, CFErrorRef
*error
) {
110 xpc_dictionary_set_data(message
, key
, SecCertificateGetBytePtr(certificate
),
111 SecCertificateGetLength(certificate
));
114 return SecError(errSecParam
, error
, CFSTR("NULL certificate"));
118 static bool string_cert_cftype_to_error(enum SecXPCOperation op
, SecTrustStoreRef ts
, SecCertificateRef certificate
, CFTypeRef trustSettingsDictOrArray
, CFErrorRef
*error
)
120 return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
122 ok
= SecXPCDictionarySetString(message
, kSecXPCKeyDomain
, (CFStringRef
)ts
, error
) &&
123 SecXPCDictionarySetCertificate(message
, kSecXPCKeyCertificate
, certificate
, error
) &&
124 (!trustSettingsDictOrArray
|| SecXPCDictionarySetPList(message
, kSecXPCKeySettings
, trustSettingsDictOrArray
, error
));
129 static OSStatus
validateConstraint(Boolean isSelfSigned
, CFMutableDictionaryRef trustSettingsDict
) {
130 OSStatus result
= errSecSuccess
;
132 /* Check "TrustRoot"/"TrustAsRoot" */
133 CFNumberRef resultNumber
= NULL
;
134 resultNumber
= (CFNumberRef
)CFDictionaryGetValue(trustSettingsDict
, kSecTrustSettingsResult
);
135 uint32_t resultValue
= kSecTrustSettingsResultInvalid
;
136 if (!isNumber(resultNumber
) && !isSelfSigned
) {
137 /* only self-signed certs get default of TrustAsRoot */
140 if (isNumber(resultNumber
) && CFNumberGetValue(resultNumber
, kCFNumberSInt32Type
, &resultValue
)) {
141 if (isSelfSigned
&& resultValue
== kSecTrustSettingsResultTrustAsRoot
) {
144 if (!isSelfSigned
&& resultValue
== kSecTrustSettingsResultTrustRoot
) {
149 /* If there's a policy specified, change the contents */
150 SecPolicyRef policy
= NULL
;
151 policy
= (SecPolicyRef
)CFDictionaryGetValue(trustSettingsDict
, kSecTrustSettingsPolicy
);
153 CFStringRef policyOid
= NULL
, policyName
= NULL
;
154 policyOid
= SecPolicyGetOidString(policy
);
155 policyName
= SecPolicyGetName(policy
);
156 CFDictionarySetValue(trustSettingsDict
, kSecTrustSettingsPolicy
, policyOid
);
157 if (policyName
) { CFDictionaryAddValue(trustSettingsDict
, kSecTrustSettingsPolicyName
, policyName
); }
163 static OSStatus
validateTrustSettings(Boolean isSelfSigned
,
164 CFTypeRef trustSettingsDictOrArray
,
165 CFTypeRef
* CF_RETURNS_RETAINED modifiedTrustSettings
) {
166 OSStatus status
= errSecParam
;
167 CFTypeRef result
= NULL
;
169 /* NULL is a valid input */
170 if (!trustSettingsDictOrArray
&& isSelfSigned
) {
171 return errSecSuccess
;
172 } else if (!trustSettingsDictOrArray
&& !isSelfSigned
) {
176 if (CFDictionaryGetTypeID() == CFGetTypeID(trustSettingsDictOrArray
)) {
177 result
= CFDictionaryCreateMutableCopy(NULL
, 0, trustSettingsDictOrArray
);
178 status
= validateConstraint(isSelfSigned
, (CFMutableDictionaryRef
)result
);
179 } else if (CFArrayGetTypeID() == CFGetTypeID(trustSettingsDictOrArray
)) {
180 require_action_quiet(result
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
),
181 out
, status
= errSecAllocate
);
182 CFIndex ix
, count
= CFArrayGetCount(trustSettingsDictOrArray
);
183 for (ix
= 0; ix
< count
; ix
++) {
184 CFDictionaryRef constraint
= CFArrayGetValueAtIndex(trustSettingsDictOrArray
, ix
);
185 CFDictionaryRef modifiedConstraint
= NULL
;
186 require_noerr_quiet(status
= validateTrustSettings(isSelfSigned
, constraint
, (CFTypeRef
*)&modifiedConstraint
), out
);
187 CFArrayAppendValue((CFMutableArrayRef
)result
, modifiedConstraint
);
188 CFReleaseNull(modifiedConstraint
); /* constraint now owned by array */
193 if (errSecSuccess
== status
&& modifiedTrustSettings
) {
194 *modifiedTrustSettings
= CFRetainSafe(result
);
196 CFReleaseNull(result
);
200 OSStatus
SecTrustStoreSetTrustSettings(SecTrustStoreRef ts
,
201 SecCertificateRef certificate
,
202 CFTypeRef trustSettingsDictOrArray
) {
203 __block OSStatus result
;
204 __block CFTypeRef validatedTrustSettings
= NULL
;
206 Boolean isSelfSigned
= false;
207 require_noerr_quiet(result
= SecCertificateIsSelfSigned(certificate
, &isSelfSigned
), out
);
208 require_noerr_quiet(result
= validateTrustSettings(isSelfSigned
, trustSettingsDictOrArray
, &validatedTrustSettings
), out
);
210 os_activity_initiate("SecTrustStoreSetTrustSettings", OS_ACTIVITY_FLAG_DEFAULT
, ^{
211 result
= SecOSStatusWith(^bool (CFErrorRef
*error
) {
212 return TRUSTD_XPC(sec_trust_store_set_trust_settings
, string_cert_cftype_to_error
, ts
, certificate
, validatedTrustSettings
, error
);
217 CFReleaseNull(validatedTrustSettings
);
221 OSStatus
SecTrustStoreRemoveCertificate(SecTrustStoreRef ts
,
222 SecCertificateRef certificate
)
225 __block OSStatus status
= errSecParam
;
227 os_activity_t activity
= os_activity_create("SecTrustStoreRemoveCertificate", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
228 os_activity_scope(activity
);
230 require(digest
= SecCertificateGetSHA1Digest(certificate
), errOut
);
231 require(gTrustd
|| ts
== (SecTrustStoreRef
)kSecTrustStoreUserName
, errOut
);
233 status
= SecOSStatusWith(^bool (CFErrorRef
*error
) {
234 return TRUSTD_XPC(sec_trust_store_remove_certificate
, string_data_to_bool_error
, ts
, digest
, error
);
238 os_release(activity
);
242 OSStatus
SecTrustStoreGetSettingsVersionNumber(SecTrustSettingsVersionNumber
* p_settings_version_number
)
244 if (NULL
== p_settings_version_number
) {
248 OSStatus status
= errSecSuccess
;
249 CFErrorRef error
= nil
;
250 uint64_t versionNumber
= SecTrustGetTrustStoreVersionNumber(&error
);
251 *p_settings_version_number
= (SecTrustSettingsVersionNumber
)versionNumber
;
254 status
= (OSStatus
)CFErrorGetCode(error
);
256 CFReleaseSafe(error
);
260 OSStatus
SecTrustStoreGetSettingsAssetVersionNumber(SecTrustSettingsAssetVersionNumber
* p_settings_asset_version_number
)
262 if (NULL
== p_settings_asset_version_number
) {
266 OSStatus status
= errSecSuccess
;
267 CFErrorRef error
= nil
;
268 uint64_t versionNumber
= SecTrustGetAssetVersionNumber(&error
);
269 *p_settings_asset_version_number
= (SecTrustSettingsAssetVersionNumber
)versionNumber
;
272 status
= (OSStatus
)CFErrorGetCode(error
);
274 CFReleaseSafe(error
);
278 static bool string_to_array_error(enum SecXPCOperation op
, SecTrustStoreRef ts
, CFArrayRef
*trustStoreContents
, CFErrorRef
*error
)
280 return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
281 return SecXPCDictionarySetString(message
, kSecXPCKeyDomain
, (CFStringRef
)ts
, error
);
282 }, ^bool(xpc_object_t response
, CFErrorRef
*error
) {
283 if (trustStoreContents
) {
284 *trustStoreContents
= SecXPCDictionaryCopyArray(response
, kSecXPCKeyResult
, error
);
285 if (!*trustStoreContents
) return false;
291 OSStatus
SecTrustStoreCopyAll(SecTrustStoreRef ts
, CFArrayRef
*trustStoreContents
)
293 __block CFArrayRef results
= NULL
;
294 OSStatus status
= errSecParam
;
296 os_activity_t activity
= os_activity_create("SecTrustStoreCopyAll", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
297 os_activity_scope(activity
);
300 status
= SecOSStatusWith(^bool (CFErrorRef
*error
) {
301 return TRUSTD_XPC(sec_trust_store_copy_all
, string_to_array_error
, ts
, &results
, error
);
304 *trustStoreContents
= results
;
307 os_release(activity
);
311 static bool string_data_to_array_error(enum SecXPCOperation op
, SecTrustStoreRef ts
, CFDataRef digest
, CFArrayRef
*usageConstraints
, CFErrorRef
*error
)
313 return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
314 return SecXPCDictionarySetString(message
, kSecXPCKeyDomain
, (CFStringRef
)ts
, error
) &&
315 SecXPCDictionarySetData(message
, kSecXPCKeyDigest
, digest
, error
);
316 }, ^bool(xpc_object_t response
, CFErrorRef
*error
) {
317 return SecXPCDictionaryCopyArrayOptional(response
, kSecXPCKeyResult
, usageConstraints
, error
);
321 OSStatus
SecTrustStoreCopyUsageConstraints(SecTrustStoreRef ts
, SecCertificateRef certificate
, CFArrayRef
*usageConstraints
)
324 __block CFArrayRef results
= NULL
;
325 OSStatus status
= errSecParam
;
327 os_activity_t activity
= os_activity_create("SecTrustStoreCopyUsageConstraints", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
328 os_activity_scope(activity
);
330 require(certificate
, errOut
);
331 require(digest
= SecCertificateGetSHA1Digest(certificate
), errOut
);
332 require(usageConstraints
, errOut
);
334 status
= SecOSStatusWith(^bool (CFErrorRef
*error
) {
335 return TRUSTD_XPC(sec_trust_store_copy_usage_constraints
, string_data_to_array_error
, ts
, digest
, &results
, error
);
338 *usageConstraints
= results
;
341 os_release(activity
);
345 #define do_if_registered(sdp, ...) if (gTrustd && gTrustd->sdp) { return gTrustd->sdp(__VA_ARGS__); }
347 /* MARK: CT Enforcement Exceptions */
349 const CFStringRef kSecCTExceptionsCAsKey
= CFSTR("DisabledForCAs");
350 const CFStringRef kSecCTExceptionsDomainsKey
= CFSTR("DisabledForDomains");
351 const CFStringRef kSecCTExceptionsHashAlgorithmKey
= CFSTR("HashAlgorithm");
352 const CFStringRef kSecCTExceptionsSPKIHashKey
= CFSTR("SubjectPublicKeyInfoHash");
354 bool SecTrustStoreSetCTExceptions(CFStringRef applicationIdentifier
, CFDictionaryRef exceptions
, CFErrorRef
*error
) {
355 do_if_registered(sec_trust_store_set_ct_exceptions
, applicationIdentifier
, exceptions
, error
);
357 os_activity_t activity
= os_activity_create("SecTrustStoreSetCTExceptions", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
358 os_activity_scope(activity
);
360 __block
bool result
= false;
361 securityd_send_sync_and_do(kSecXPCOpSetCTExceptions
, error
, ^bool(xpc_object_t message
, CFErrorRef
*block_error
) {
362 SecXPCDictionarySetPListOptional(message
, kSecTrustExceptionsKey
, exceptions
, block_error
);
363 SecXPCDictionarySetStringOptional(message
, kSecTrustEventApplicationID
, applicationIdentifier
, block_error
);
365 }, ^bool(xpc_object_t response
, CFErrorRef
*block_error
) {
366 result
= SecXPCDictionaryGetBool(response
, kSecXPCKeyResult
, block_error
);
370 os_release(activity
);
374 CFDictionaryRef
SecTrustStoreCopyCTExceptions(CFStringRef applicationIdentifier
, CFErrorRef
*error
) {
375 do_if_registered(sec_trust_store_copy_ct_exceptions
, applicationIdentifier
, error
);
377 os_activity_t activity
= os_activity_create("SecTrustStoreCopyCTExceptions", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
378 os_activity_scope(activity
);
380 __block CFDictionaryRef result
= NULL
;
381 securityd_send_sync_and_do(kSecXPCOpCopyCTExceptions
, error
, ^bool(xpc_object_t message
, CFErrorRef
*block_error
) {
382 SecXPCDictionarySetStringOptional(message
, kSecTrustEventApplicationID
, applicationIdentifier
, block_error
);
384 }, ^bool(xpc_object_t response
, CFErrorRef
*block_error
) {
385 (void)SecXPCDictionaryCopyDictionaryOptional(response
, kSecTrustExceptionsKey
, &result
, block_error
);
389 os_release(activity
);