2 * Copyright (c) 2007-2009,2012-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 * 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 "SecTrustSettings.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 gSecurityd
->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 return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
76 return SecXPCDictionarySetString(message
, kSecXPCKeyDomain
, (CFStringRef
)ts
, error
) &&
77 SecXPCDictionarySetData(message
, kSecXPCKeyDigest
, digest
, error
);
78 }, ^bool(xpc_object_t response
, CFErrorRef
*error
) {
80 *result
= xpc_dictionary_get_bool(response
, kSecXPCKeyResult
);
85 Boolean
SecTrustStoreContains(SecTrustStoreRef ts
,
86 SecCertificateRef certificate
) {
89 __block
bool contains
= false;
91 os_activity_t trace_activity
= os_activity_start("SecTrustStoreContains", OS_ACTIVITY_FLAG_DEFAULT
);
93 require(digest
= SecCertificateGetSHA1Digest(certificate
), errOut
);
96 ok
= (SecOSStatusWith(^bool (CFErrorRef
*error
) {
97 return SECURITYD_XPC(sec_trust_store_contains
, string_data_to_bool_bool_error
, ts
, digest
, &contains
, error
);
101 os_activity_end(trace_activity
);
102 return ok
&& contains
;
105 static bool SecXPCDictionarySetCertificate(xpc_object_t message
, const char *key
, SecCertificateRef certificate
, CFErrorRef
*error
) {
107 xpc_dictionary_set_data(message
, key
, SecCertificateGetBytePtr(certificate
),
108 SecCertificateGetLength(certificate
));
111 return SecError(errSecParam
, error
, CFSTR("NULL certificate"));
115 static bool string_cert_cftype_to_error(enum SecXPCOperation op
, SecTrustStoreRef ts
, SecCertificateRef certificate
, CFTypeRef trustSettingsDictOrArray
, CFErrorRef
*error
)
117 return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
119 ok
= SecXPCDictionarySetString(message
, kSecXPCKeyDomain
, (CFStringRef
)ts
, error
) &&
120 SecXPCDictionarySetCertificate(message
, kSecXPCKeyCertificate
, certificate
, error
) &&
121 (!trustSettingsDictOrArray
|| SecXPCDictionarySetPList(message
, kSecXPCKeySettings
, trustSettingsDictOrArray
, error
));
126 static OSStatus
validateConstraint(Boolean isSelfSigned
, CFMutableDictionaryRef trustSettingsDict
) {
127 OSStatus result
= errSecSuccess
;
129 /* Check "TrustRoot"/"TrustAsRoot" */
130 CFNumberRef resultNumber
= NULL
;
131 resultNumber
= (CFNumberRef
)CFDictionaryGetValue(trustSettingsDict
, kSecTrustSettingsResult
);
132 uint32_t resultValue
= kSecTrustSettingsResultInvalid
;
133 if (!isNumber(resultNumber
) && !isSelfSigned
) {
134 /* only self-signed certs get default of TrustAsRoot */
137 if (isNumber(resultNumber
) && CFNumberGetValue(resultNumber
, kCFNumberSInt32Type
, &resultValue
)) {
138 if (isSelfSigned
&& resultValue
== kSecTrustSettingsResultTrustAsRoot
) {
141 if (!isSelfSigned
&& resultValue
== kSecTrustSettingsResultTrustRoot
) {
146 /* If there's a policy specified, change the contents */
147 SecPolicyRef policy
= NULL
;
148 policy
= (SecPolicyRef
)CFDictionaryGetValue(trustSettingsDict
, kSecTrustSettingsPolicy
);
150 CFStringRef policyOid
= NULL
, policyName
= NULL
;
151 policyOid
= SecPolicyGetOidString(policy
);
152 policyName
= SecPolicyGetName(policy
);
153 CFDictionarySetValue(trustSettingsDict
, kSecTrustSettingsPolicy
, policyOid
);
154 if (policyName
) { CFDictionaryAddValue(trustSettingsDict
, kSecTrustSettingsPolicyName
, policyName
); }
160 static OSStatus
validateTrustSettings(Boolean isSelfSigned
,
161 CFTypeRef trustSettingsDictOrArray
,
162 CFTypeRef
* CF_RETURNS_RETAINED modifiedTrustSettings
) {
163 OSStatus status
= errSecParam
;
164 CFTypeRef result
= NULL
;
166 /* NULL is a valid input */
167 if (!trustSettingsDictOrArray
&& isSelfSigned
) {
168 return errSecSuccess
;
169 } else if (!trustSettingsDictOrArray
&& !isSelfSigned
) {
173 if (CFDictionaryGetTypeID() == CFGetTypeID(trustSettingsDictOrArray
)) {
174 result
= CFDictionaryCreateMutableCopy(NULL
, 0, trustSettingsDictOrArray
);
175 status
= validateConstraint(isSelfSigned
, (CFMutableDictionaryRef
)result
);
176 } else if (CFArrayGetTypeID() == CFGetTypeID(trustSettingsDictOrArray
)) {
177 require_action_quiet(result
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
),
178 out
, status
= errSecAllocate
);
179 CFIndex ix
, count
= CFArrayGetCount(trustSettingsDictOrArray
);
180 for (ix
= 0; ix
< count
; ix
++) {
181 CFDictionaryRef constraint
= CFArrayGetValueAtIndex(trustSettingsDictOrArray
, ix
);
182 CFDictionaryRef modifiedConstraint
= NULL
;
183 require_noerr_quiet(status
= validateTrustSettings(isSelfSigned
, constraint
, (CFTypeRef
*)&modifiedConstraint
), out
);
184 CFArrayAppendValue((CFMutableArrayRef
)result
, modifiedConstraint
);
185 CFReleaseNull(modifiedConstraint
); /* constraint now owned by array */
190 if (errSecSuccess
== status
&& modifiedTrustSettings
) {
191 *modifiedTrustSettings
= CFRetainSafe(result
);
193 CFReleaseNull(result
);
197 OSStatus
SecTrustStoreSetTrustSettings(SecTrustStoreRef ts
,
198 SecCertificateRef certificate
,
199 CFTypeRef trustSettingsDictOrArray
) {
200 __block OSStatus result
;
201 __block CFTypeRef validatedTrustSettings
= NULL
;
203 Boolean isSelfSigned
= false;
204 require_noerr_quiet(result
= SecCertificateIsSelfSigned(certificate
, &isSelfSigned
), out
);
205 require_noerr_quiet(result
= validateTrustSettings(isSelfSigned
, trustSettingsDictOrArray
, &validatedTrustSettings
), out
);
207 os_activity_initiate("SecTrustStoreSetTrustSettings", OS_ACTIVITY_FLAG_DEFAULT
, ^{
208 result
= SecOSStatusWith(^bool (CFErrorRef
*error
) {
209 return SECURITYD_XPC(sec_trust_store_set_trust_settings
, string_cert_cftype_to_error
, ts
, certificate
, validatedTrustSettings
, error
);
214 CFReleaseNull(validatedTrustSettings
);
218 OSStatus
SecTrustStoreRemoveCertificate(SecTrustStoreRef ts
,
219 SecCertificateRef certificate
)
222 __block OSStatus status
= errSecParam
;
224 os_activity_t trace_activity
= os_activity_start("SecTrustStoreRemoveCertificate", OS_ACTIVITY_FLAG_DEFAULT
);
226 require(digest
= SecCertificateGetSHA1Digest(certificate
), errOut
);
227 require(gSecurityd
|| ts
== (SecTrustStoreRef
)kSecTrustStoreUserName
, errOut
);
229 status
= SecOSStatusWith(^bool (CFErrorRef
*error
) {
230 return SECURITYD_XPC(sec_trust_store_remove_certificate
, string_data_to_bool_error
, ts
, digest
, error
);
234 os_activity_end(trace_activity
);
239 static CFIndex
GetOTAAssetVersionNumber()
244 if (errSecSuccess
== SecTrustGetOTAPKIAssetVersionNumber(&version
))
254 OSStatus
SecTrustStoreGetSettingsVersionNumber(SecTrustSettingsVersionNumber
* p_settings_version_number
)
256 OSStatus status
= errSecParam
;
257 if (NULL
== p_settings_version_number
)
262 CFIndex versionNumber
= GetOTAAssetVersionNumber();
263 *p_settings_version_number
= (SecTrustSettingsVersionNumber
)versionNumber
;
265 return errSecSuccess
;
268 static bool string_to_array_error(enum SecXPCOperation op
, SecTrustStoreRef ts
, CFArrayRef
*trustStoreContents
, CFErrorRef
*error
)
270 return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
271 return SecXPCDictionarySetString(message
, kSecXPCKeyDomain
, (CFStringRef
)ts
, error
);
272 }, ^bool(xpc_object_t response
, CFErrorRef
*error
) {
273 if (trustStoreContents
) {
274 *trustStoreContents
= SecXPCDictionaryCopyArray(response
, kSecXPCKeyResult
, error
);
275 if (!*trustStoreContents
) return false;
281 OSStatus
SecTrustStoreCopyAll(SecTrustStoreRef ts
, CFArrayRef
*trustStoreContents
)
283 __block CFArrayRef results
= NULL
;
284 OSStatus status
= errSecParam
;
286 os_activity_t trace_activity
= os_activity_start("SecTrustStoreCopyAll", OS_ACTIVITY_FLAG_DEFAULT
);
289 status
= SecOSStatusWith(^bool (CFErrorRef
*error
) {
290 return SECURITYD_XPC(sec_trust_store_copy_all
, string_to_array_error
, ts
, &results
, error
);
293 *trustStoreContents
= results
;
296 os_activity_end(trace_activity
);
300 static bool string_data_to_array_error(enum SecXPCOperation op
, SecTrustStoreRef ts
, CFDataRef digest
, CFArrayRef
*usageConstraints
, CFErrorRef
*error
)
302 return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
303 return SecXPCDictionarySetString(message
, kSecXPCKeyDomain
, (CFStringRef
)ts
, error
) &&
304 SecXPCDictionarySetData(message
, kSecXPCKeyDigest
, digest
, error
);
305 }, ^bool(xpc_object_t response
, CFErrorRef
*error
) {
306 return SecXPCDictionaryCopyArrayOptional(response
, kSecXPCKeyResult
, usageConstraints
, error
);
310 OSStatus
SecTrustStoreCopyUsageConstraints(SecTrustStoreRef ts
, SecCertificateRef certificate
, CFArrayRef
*usageConstraints
)
313 __block CFArrayRef results
= NULL
;
314 OSStatus status
= errSecParam
;
316 os_activity_t trace_activity
= os_activity_start("SecTrustStoreCopyUsageConstraints", OS_ACTIVITY_FLAG_DEFAULT
);
318 require(certificate
, errOut
);
319 require(digest
= SecCertificateGetSHA1Digest(certificate
), errOut
);
320 require(usageConstraints
, errOut
);
322 status
= SecOSStatusWith(^bool (CFErrorRef
*error
) {
323 return SECURITYD_XPC(sec_trust_store_copy_usage_constraints
, string_data_to_array_error
, ts
, digest
, &results
, error
);
326 *usageConstraints
= results
;
329 os_activity_end(trace_activity
);