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"
48 static CFStringRef kSecTrustStoreUserName
= CFSTR("user");
50 SecTrustStoreRef
SecTrustStoreForDomain(SecTrustStoreDomain domain
) {
51 CFStringRef domainName
;
52 if (domain
== kSecTrustStoreDomainUser
) {
53 domainName
= kSecTrustStoreUserName
;
59 return gTrustd
->sec_trust_store_for_domain(domainName
, NULL
);
61 return (SecTrustStoreRef
)domainName
;
65 static bool string_data_to_bool_error(enum SecXPCOperation op
, SecTrustStoreRef ts
, CFDataRef digest
, CFErrorRef
*error
)
67 return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
68 return SecXPCDictionarySetString(message
, kSecXPCKeyDomain
, (CFStringRef
)ts
, error
) &&
69 SecXPCDictionarySetData(message
, kSecXPCKeyDigest
, digest
, error
);
73 static bool string_data_to_bool_bool_error(enum SecXPCOperation op
, SecTrustStoreRef ts
, CFDataRef digest
, bool *result
, CFErrorRef
*error
)
75 os_activity_t activity
= os_activity_create("SecTrustStoreContains", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
76 os_activity_scope(activity
);
77 bool status
= securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
78 return SecXPCDictionarySetString(message
, kSecXPCKeyDomain
, (CFStringRef
)ts
, error
) &&
79 SecXPCDictionarySetData(message
, kSecXPCKeyDigest
, digest
, error
);
80 }, ^bool(xpc_object_t response
, CFErrorRef
*error
) {
82 *result
= xpc_dictionary_get_bool(response
, kSecXPCKeyResult
);
89 Boolean
SecTrustStoreContains(SecTrustStoreRef ts
,
90 SecCertificateRef certificate
) {
93 __block
bool contains
= false;
96 require(digest
= SecCertificateGetSHA1Digest(certificate
), errOut
);
99 ok
= (SecOSStatusWith(^bool (CFErrorRef
*error
) {
100 return TRUSTD_XPC(sec_trust_store_contains
, string_data_to_bool_bool_error
, ts
, digest
, &contains
, error
);
101 }) == errSecSuccess
);
104 return ok
&& contains
;
107 static bool SecXPCDictionarySetCertificate(xpc_object_t message
, const char *key
, SecCertificateRef certificate
, CFErrorRef
*error
) {
109 xpc_dictionary_set_data(message
, key
, SecCertificateGetBytePtr(certificate
),
110 SecCertificateGetLength(certificate
));
113 return SecError(errSecParam
, error
, CFSTR("NULL certificate"));
117 static bool string_cert_cftype_to_error(enum SecXPCOperation op
, SecTrustStoreRef ts
, SecCertificateRef certificate
, CFTypeRef trustSettingsDictOrArray
, CFErrorRef
*error
)
119 return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
121 ok
= SecXPCDictionarySetString(message
, kSecXPCKeyDomain
, (CFStringRef
)ts
, error
) &&
122 SecXPCDictionarySetCertificate(message
, kSecXPCKeyCertificate
, certificate
, error
) &&
123 (!trustSettingsDictOrArray
|| SecXPCDictionarySetPList(message
, kSecXPCKeySettings
, trustSettingsDictOrArray
, error
));
128 static OSStatus
validateConstraint(Boolean isSelfSigned
, CFMutableDictionaryRef trustSettingsDict
) {
129 OSStatus result
= errSecSuccess
;
131 /* Check "TrustRoot"/"TrustAsRoot" */
132 CFNumberRef resultNumber
= NULL
;
133 resultNumber
= (CFNumberRef
)CFDictionaryGetValue(trustSettingsDict
, kSecTrustSettingsResult
);
134 uint32_t resultValue
= kSecTrustSettingsResultInvalid
;
135 if (!isNumber(resultNumber
) && !isSelfSigned
) {
136 /* only self-signed certs get default of TrustAsRoot */
139 if (isNumber(resultNumber
) && CFNumberGetValue(resultNumber
, kCFNumberSInt32Type
, &resultValue
)) {
140 if (isSelfSigned
&& resultValue
== kSecTrustSettingsResultTrustAsRoot
) {
143 if (!isSelfSigned
&& resultValue
== kSecTrustSettingsResultTrustRoot
) {
148 /* If there's a policy specified, change the contents */
149 SecPolicyRef policy
= NULL
;
150 policy
= (SecPolicyRef
)CFDictionaryGetValue(trustSettingsDict
, kSecTrustSettingsPolicy
);
152 CFStringRef policyOid
= NULL
, policyName
= NULL
;
153 policyOid
= SecPolicyGetOidString(policy
);
154 policyName
= SecPolicyGetName(policy
);
155 CFDictionarySetValue(trustSettingsDict
, kSecTrustSettingsPolicy
, policyOid
);
156 if (policyName
) { CFDictionaryAddValue(trustSettingsDict
, kSecTrustSettingsPolicyName
, policyName
); }
162 static OSStatus
validateTrustSettings(Boolean isSelfSigned
,
163 CFTypeRef trustSettingsDictOrArray
,
164 CFTypeRef
* CF_RETURNS_RETAINED modifiedTrustSettings
) {
165 OSStatus status
= errSecParam
;
166 CFTypeRef result
= NULL
;
168 /* NULL is a valid input */
169 if (!trustSettingsDictOrArray
&& isSelfSigned
) {
170 return errSecSuccess
;
171 } else if (!trustSettingsDictOrArray
&& !isSelfSigned
) {
175 if (CFDictionaryGetTypeID() == CFGetTypeID(trustSettingsDictOrArray
)) {
176 result
= CFDictionaryCreateMutableCopy(NULL
, 0, trustSettingsDictOrArray
);
177 status
= validateConstraint(isSelfSigned
, (CFMutableDictionaryRef
)result
);
178 } else if (CFArrayGetTypeID() == CFGetTypeID(trustSettingsDictOrArray
)) {
179 require_action_quiet(result
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
),
180 out
, status
= errSecAllocate
);
181 CFIndex ix
, count
= CFArrayGetCount(trustSettingsDictOrArray
);
182 for (ix
= 0; ix
< count
; ix
++) {
183 CFDictionaryRef constraint
= CFArrayGetValueAtIndex(trustSettingsDictOrArray
, ix
);
184 CFDictionaryRef modifiedConstraint
= NULL
;
185 require_noerr_quiet(status
= validateTrustSettings(isSelfSigned
, constraint
, (CFTypeRef
*)&modifiedConstraint
), out
);
186 CFArrayAppendValue((CFMutableArrayRef
)result
, modifiedConstraint
);
187 CFReleaseNull(modifiedConstraint
); /* constraint now owned by array */
192 if (errSecSuccess
== status
&& modifiedTrustSettings
) {
193 *modifiedTrustSettings
= CFRetainSafe(result
);
195 CFReleaseNull(result
);
199 OSStatus
SecTrustStoreSetTrustSettings(SecTrustStoreRef ts
,
200 SecCertificateRef certificate
,
201 CFTypeRef trustSettingsDictOrArray
) {
202 __block OSStatus result
;
203 __block CFTypeRef validatedTrustSettings
= NULL
;
205 Boolean isSelfSigned
= false;
206 require_noerr_quiet(result
= SecCertificateIsSelfSigned(certificate
, &isSelfSigned
), out
);
207 require_noerr_quiet(result
= validateTrustSettings(isSelfSigned
, trustSettingsDictOrArray
, &validatedTrustSettings
), out
);
209 os_activity_initiate("SecTrustStoreSetTrustSettings", OS_ACTIVITY_FLAG_DEFAULT
, ^{
210 result
= SecOSStatusWith(^bool (CFErrorRef
*error
) {
211 return TRUSTD_XPC(sec_trust_store_set_trust_settings
, string_cert_cftype_to_error
, ts
, certificate
, validatedTrustSettings
, error
);
216 CFReleaseNull(validatedTrustSettings
);
220 OSStatus
SecTrustStoreRemoveCertificate(SecTrustStoreRef ts
,
221 SecCertificateRef certificate
)
224 __block OSStatus status
= errSecParam
;
226 os_activity_t activity
= os_activity_create("SecTrustStoreRemoveCertificate", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
227 os_activity_scope(activity
);
229 require(digest
= SecCertificateGetSHA1Digest(certificate
), errOut
);
230 require(gTrustd
|| ts
== (SecTrustStoreRef
)kSecTrustStoreUserName
, errOut
);
232 status
= SecOSStatusWith(^bool (CFErrorRef
*error
) {
233 return TRUSTD_XPC(sec_trust_store_remove_certificate
, string_data_to_bool_error
, ts
, digest
, error
);
237 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 static bool string_to_array_error(enum SecXPCOperation op
, SecTrustStoreRef ts
, CFArrayRef
*trustStoreContents
, CFErrorRef
*error
)
262 return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
263 return SecXPCDictionarySetString(message
, kSecXPCKeyDomain
, (CFStringRef
)ts
, error
);
264 }, ^bool(xpc_object_t response
, CFErrorRef
*error
) {
265 if (trustStoreContents
) {
266 *trustStoreContents
= SecXPCDictionaryCopyArray(response
, kSecXPCKeyResult
, error
);
267 if (!*trustStoreContents
) return false;
273 OSStatus
SecTrustStoreCopyAll(SecTrustStoreRef ts
, CFArrayRef
*trustStoreContents
)
275 __block CFArrayRef results
= NULL
;
276 OSStatus status
= errSecParam
;
278 os_activity_t activity
= os_activity_create("SecTrustStoreCopyAll", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
279 os_activity_scope(activity
);
282 status
= SecOSStatusWith(^bool (CFErrorRef
*error
) {
283 return TRUSTD_XPC(sec_trust_store_copy_all
, string_to_array_error
, ts
, &results
, error
);
286 *trustStoreContents
= results
;
289 os_release(activity
);
293 static bool string_data_to_array_error(enum SecXPCOperation op
, SecTrustStoreRef ts
, CFDataRef digest
, CFArrayRef
*usageConstraints
, CFErrorRef
*error
)
295 return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
296 return SecXPCDictionarySetString(message
, kSecXPCKeyDomain
, (CFStringRef
)ts
, error
) &&
297 SecXPCDictionarySetData(message
, kSecXPCKeyDigest
, digest
, error
);
298 }, ^bool(xpc_object_t response
, CFErrorRef
*error
) {
299 return SecXPCDictionaryCopyArrayOptional(response
, kSecXPCKeyResult
, usageConstraints
, error
);
303 OSStatus
SecTrustStoreCopyUsageConstraints(SecTrustStoreRef ts
, SecCertificateRef certificate
, CFArrayRef
*usageConstraints
)
306 __block CFArrayRef results
= NULL
;
307 OSStatus status
= errSecParam
;
309 os_activity_t activity
= os_activity_create("SecTrustStoreCopyUsageConstraints", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
310 os_activity_scope(activity
);
312 require(certificate
, errOut
);
313 require(digest
= SecCertificateGetSHA1Digest(certificate
), errOut
);
314 require(usageConstraints
, errOut
);
316 status
= SecOSStatusWith(^bool (CFErrorRef
*error
) {
317 return TRUSTD_XPC(sec_trust_store_copy_usage_constraints
, string_data_to_array_error
, ts
, digest
, &results
, error
);
320 *usageConstraints
= results
;
323 os_release(activity
);