1/*
2 * Copyright (c) 2007-2009 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24/*
25 * SecTrustStore.c - CertificateSource API to a system root certificate store
26 */
27#include <Security/SecTrustStore.h>
28
29#include <Security/SecCertificateInternal.h>
30#include <Security/SecInternal.h>
31#include <CoreFoundation/CFString.h>
32#include <AssertMacros.h>
33#include "securityd_client.h"
34#include "SecuritydXPC.h"
35#include "SecFramework.h"
36#include <sys/stat.h>
37#include <stdio.h>
38#include <dirent.h>
39#include "SecTrustPriv.h"
40#include <utilities/SecCFError.h>
41#include "utilities/SecDb.h"
42
43static CFStringRef kSecTrustStoreUserName = CFSTR("user");
44
45SecTrustStoreRef SecTrustStoreForDomain(SecTrustStoreDomain domain) {
46    CFStringRef domainName;
47    if (domain == kSecTrustStoreDomainUser) {
48        domainName = kSecTrustStoreUserName;
49    } else {
50        return NULL;
51    }
52
53    if (gSecurityd) {
54        return gSecurityd->sec_trust_store_for_domain(domainName, NULL);
55    } else {
56        return (SecTrustStoreRef)domainName;
57    }
58}
59
60static bool string_data_to_bool_error(enum SecXPCOperation op, SecTrustStoreRef ts, CFDataRef digest, CFErrorRef *error)
61{
62    return securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) {
63        return SecXPCDictionarySetString(message, kSecXPCKeyDomain, (CFStringRef)ts, error) &&
64        SecXPCDictionarySetData(message, kSecXPCKeyDigest, digest, error);
65    }, NULL);
66}
67
68static bool string_data_to_bool_bool_error(enum SecXPCOperation op, SecTrustStoreRef ts, CFDataRef digest, bool *result, CFErrorRef *error)
69{
70    return securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) {
71        return SecXPCDictionarySetString(message, kSecXPCKeyDomain, (CFStringRef)ts, error) &&
72        SecXPCDictionarySetData(message, kSecXPCKeyDigest, digest, error);
73    }, ^bool(xpc_object_t response, CFErrorRef *error) {
74        if (result)
75            *result = xpc_dictionary_get_bool(response, kSecXPCKeyResult);
76        return true;
77    });
78}
79
80Boolean SecTrustStoreContains(SecTrustStoreRef ts,
81	SecCertificateRef certificate) {
82    CFDataRef digest;
83    bool ok = false;
84	__block bool contains = false;
85
86	require(ts, errOut);
87	require(digest = SecCertificateGetSHA1Digest(certificate), errOut);
88    ok = (SecOSStatusWith(^bool (CFErrorRef *error) {
89        return SECURITYD_XPC(sec_trust_store_contains, string_data_to_bool_bool_error, ts, digest, &contains, error);
90    }) == errSecSuccess);
91
92errOut:
93	return ok && contains;
94}
95
96static bool SecXPCDictionarySetCertificate(xpc_object_t message, const char *key, SecCertificateRef certificate, CFErrorRef *error) {
97    if (certificate) {
98        xpc_dictionary_set_data(message, key, SecCertificateGetBytePtr(certificate),
99                                SecCertificateGetLength(certificate));
100        return true;
101    }
102    return SecError(errSecParam, error, CFSTR("NULL certificate"));
103}
104
105
106static bool string_cert_cftype_to_error(enum SecXPCOperation op, SecTrustStoreRef ts, SecCertificateRef certificate, CFTypeRef trustSettingsDictOrArray, CFErrorRef *error)
107{
108    return securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) {
109        bool ok = false;
110        ok = SecXPCDictionarySetString(message, kSecXPCKeyDomain, (CFStringRef)ts, error) &&
111        SecXPCDictionarySetCertificate(message, kSecXPCKeyCertificate, certificate, error) &&
112        (!trustSettingsDictOrArray || SecXPCDictionarySetPList(message, kSecXPCKeySettings, trustSettingsDictOrArray, error));
113        return ok;
114    }, NULL);
115}
116
117OSStatus SecTrustStoreSetTrustSettings(SecTrustStoreRef ts,
118	SecCertificateRef certificate,
119    CFTypeRef trustSettingsDictOrArray) {
120    return SecOSStatusWith(^bool (CFErrorRef *error) {
121        return SECURITYD_XPC(sec_trust_store_set_trust_settings, string_cert_cftype_to_error, ts, certificate, trustSettingsDictOrArray, error);
122    });
123}
124
125OSStatus SecTrustStoreRemoveCertificate(SecTrustStoreRef ts,
126    SecCertificateRef certificate)
127{
128    CFDataRef digest;
129    OSStatus status = errSecParam;
130
131	require(ts, errOut);
132	require(digest = SecCertificateGetSHA1Digest(certificate), errOut);
133    require(gSecurityd || ts == (SecTrustStoreRef)kSecTrustStoreUserName, errOut);
134    status = SecOSStatusWith(^bool (CFErrorRef *error) {
135        return SECURITYD_XPC(sec_trust_store_remove_certificate, string_data_to_bool_error, ts, digest, error);
136    });
137
138errOut:
139	return status;
140}
141
142
143static CFIndex GetOTAAssetVersionNumber()
144{
145	CFIndex result = 0;
146    int version = 0;
147
148	if (errSecSuccess == SecTrustGetOTAPKIAssetVersionNumber(&version))
149	{
150		result = version;
151	}
152
153    return result;
154}
155
156
157
158OSStatus SecTrustStoreGetSettingsVersionNumber(SecTrustSettingsVersionNumber* p_settings_version_number)
159{
160    OSStatus status = errSecParam;
161    if (NULL == p_settings_version_number)
162    {
163        return status;
164    }
165
166    CFIndex versionNumber = GetOTAAssetVersionNumber();
167    *p_settings_version_number = (SecTrustSettingsVersionNumber)versionNumber;
168
169    return errSecSuccess;
170}
171