2 * Copyright (c) 2007-2010,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 * SecTrustStoreServer.c - CertificateSource API to a system root certificate store
27 #include "SecTrustStoreServer.h"
29 #include <Security/SecCertificateInternal.h>
30 #include <Security/SecFramework.h>
33 #include <dispatch/dispatch.h>
38 #include <sys/param.h>
41 #include <CoreFoundation/CFData.h>
42 #include <CoreFoundation/CFPropertyList.h>
43 #include <CoreFoundation/CFURL.h>
44 #include <AssertMacros.h>
45 #include <utilities/debugging.h>
46 #include "SecBasePriv.h"
47 #include <Security/SecInternal.h>
48 #include <ipc/securityd_client.h>
49 #include <securityd/SecTrustStoreServer.h>
50 #include "utilities/sqlutils.h"
51 #include "utilities/SecDb.h"
52 #include <utilities/SecCFError.h>
53 #include "utilities/SecFileLocations.h"
54 #include <utilities/SecDispatchRelease.h>
56 /* uid of the _securityd user. */
57 #define SECURTYD_UID 64
59 static dispatch_once_t kSecTrustStoreUserOnce
;
60 static SecTrustStoreRef kSecTrustStoreUser
= NULL
;
62 static const char copyParentsSQL
[] = "SELECT data FROM tsettings WHERE subj=?";
63 static const char containsSQL
[] = "SELECT tset FROM tsettings WHERE sha1=?";
64 static const char insertSQL
[] = "INSERT INTO tsettings(sha1,subj,tset,data)VALUES(?,?,?,?)";
65 static const char updateSQL
[] = "UPDATE tsettings SET tset=? WHERE sha1=?";
66 static const char deleteSQL
[] = "DELETE FROM tsettings WHERE sha1=?";
67 static const char deleteAllSQL
[] = "BEGIN EXCLUSIVE TRANSACTION; DELETE from tsettings; COMMIT TRANSACTION; VACUUM;";
69 #define kSecTrustStoreName CFSTR("TrustStore")
70 #define kSecTrustStoreDbExtension CFSTR("sqlite3")
72 #define kTrustStoreFileName CFSTR("TrustStore.sqlite3")
75 struct __SecTrustStore
{
76 dispatch_queue_t queue
;
78 sqlite3_stmt
*copyParents
;
79 sqlite3_stmt
*contains
;
83 static int sec_create_path(const char *path
)
85 char pathbuf
[PATH_MAX
];
86 size_t pos
, len
= strlen(path
);
87 if (len
== 0 || len
> PATH_MAX
)
88 return SQLITE_CANTOPEN
;
89 memcpy(pathbuf
, path
, len
);
90 for (pos
= len
-1; pos
> 0; --pos
)
92 /* Search backwards for trailing '/'. */
93 if (pathbuf
[pos
] == '/')
96 /* Attempt to create parent directories of the database. */
97 if (!mkdir(pathbuf
, 0777))
105 return SQLITE_CANTOPEN
;
107 return SQLITE_READONLY
;
110 if (err
== ENOSPC
|| err
== EDQUOT
)
115 /* EFAULT || ELOOP | ENAMETOOLONG || something else */
116 return SQLITE_INTERNAL
;
123 static int sec_sqlite3_open(const char *db_name
, sqlite3
**s3h
,
127 s3e
= sqlite3_open(db_name
, s3h
);
128 if (s3e
== SQLITE_CANTOPEN
&& create_path
) {
129 /* Make sure the path to db_name exists and is writable, then
131 s3e
= sec_create_path(db_name
);
133 s3e
= sqlite3_open(db_name
, s3h
);
139 static SecTrustStoreRef
SecTrustStoreCreate(const char *db_name
,
144 require(ts
= (SecTrustStoreRef
)malloc(sizeof(struct __SecTrustStore
)), errOut
);
145 ts
->queue
= dispatch_queue_create("truststore", DISPATCH_QUEUE_SERIAL
);
146 require_noerr(s3e
= sec_sqlite3_open(db_name
, &ts
->s3h
, create
), errOut
);
148 s3e
= sqlite3_prepare(ts
->s3h
, copyParentsSQL
, sizeof(copyParentsSQL
),
149 &ts
->copyParents
, NULL
);
150 if (create
&& s3e
== SQLITE_ERROR
) {
151 /* sqlite3_prepare returns SQLITE_ERROR if the table we are
152 compiling this statement for doesn't exist. */
154 s3e
= sqlite3_exec(ts
->s3h
,
155 "CREATE TABLE tsettings("
156 "sha1 BLOB NOT NULL DEFAULT '',"
157 "subj BLOB NOT NULL DEFAULT '',"
162 "CREATE INDEX isubj ON tsettings(subj);"
163 , NULL
, NULL
, &errmsg
);
165 secwarning("CREATE TABLE cert: %s", errmsg
);
166 sqlite3_free(errmsg
);
168 require_noerr(s3e
, errOut
);
169 s3e
= sqlite3_prepare(ts
->s3h
, copyParentsSQL
, sizeof(copyParentsSQL
),
170 &ts
->copyParents
, NULL
);
172 require_noerr(s3e
, errOut
);
173 require_noerr(s3e
= sqlite3_prepare(ts
->s3h
, containsSQL
, sizeof(containsSQL
),
174 &ts
->contains
, NULL
), errOut
);
180 sqlite3_close(ts
->s3h
);
181 dispatch_release_safe(ts
->queue
);
188 static bool SecExtractFilesystemPathForKeychainFile(CFStringRef file
, UInt8
*buffer
, CFIndex maxBufLen
)
190 bool translated
= false;
191 CFURLRef fileURL
= SecCopyURLForFileInKeychainDirectory(file
);
193 if (fileURL
&& CFURLGetFileSystemRepresentation(fileURL
, false, buffer
, maxBufLen
))
195 CFReleaseSafe(fileURL
);
200 static void SecTrustStoreInitUser(void) {
201 const char path
[MAXPATHLEN
];
203 if (SecExtractFilesystemPathForKeychainFile(kTrustStoreFileName
, (UInt8
*) path
, (CFIndex
) sizeof(path
)))
205 kSecTrustStoreUser
= SecTrustStoreCreate(path
, true);
206 if (kSecTrustStoreUser
)
207 kSecTrustStoreUser
->readOnly
= false;
211 /* AUDIT[securityd](done):
212 domainName (ok) is a caller provided string of any length (might be 0), only
213 its cf type has been checked.
215 SecTrustStoreRef
SecTrustStoreForDomainName(CFStringRef domainName
, CFErrorRef
*error
) {
216 if (CFEqual(CFSTR("user"), domainName
)) {
217 dispatch_once(&kSecTrustStoreUserOnce
, ^{ SecTrustStoreInitUser(); });
218 return kSecTrustStoreUser
;
220 SecError(errSecParam
, error
, CFSTR("unknown domain: %@"), domainName
);
225 /* AUDIT[securityd](done):
226 ts (ok) might be NULL.
227 certificate (ok) is a valid SecCertificateRef.
228 trustSettingsDictOrArray (checked by CFPropertyListCreateXMLData) is either
229 NULL, a dictionary or an array, but its contents have not been checked.
231 bool _SecTrustStoreSetTrustSettings(SecTrustStoreRef ts
,
232 SecCertificateRef certificate
,
233 CFTypeRef tsdoa
, CFErrorRef
*error
) {
235 require_action_quiet(ts
, errOutNotLocked
, ok
= SecError(errSecParam
, error
, CFSTR("truststore is NULL")));
236 require_action_quiet(!ts
->readOnly
, errOutNotLocked
, ok
= SecError(errSecReadOnly
, error
, CFSTR("truststore is readOnly")));
237 dispatch_sync(ts
->queue
, ^{
238 CFTypeRef trustSettingsDictOrArray
= tsdoa
;
239 sqlite3_stmt
*insert
= NULL
, *update
= NULL
;
240 CFDataRef xmlData
= NULL
;
241 CFArrayRef array
= NULL
;
244 require_action_quiet(subject
= SecCertificateGetNormalizedSubjectContent(certificate
),
245 errOut
, ok
= SecError(errSecParam
, error
, CFSTR("get normalized subject failed")));
247 require_action_quiet(digest
= SecCertificateGetSHA1Digest(certificate
), errOut
, ok
= SecError(errSecParam
, error
, CFSTR("get sha1 digest failed")));
249 /* Do some basic checks on the trust settings passed in. */
250 if (trustSettingsDictOrArray
== NULL
) {
251 require_action_quiet(array
= CFArrayCreate(NULL
, NULL
, 0, &kCFTypeArrayCallBacks
), errOut
, ok
= SecError(errSecAllocate
, error
, CFSTR("CFArrayCreate failed")));
252 trustSettingsDictOrArray
= array
;
254 else if(CFGetTypeID(trustSettingsDictOrArray
) == CFDictionaryGetTypeID()) {
256 array
= CFArrayCreate(NULL
, &trustSettingsDictOrArray
, 1,
257 &kCFTypeArrayCallBacks
);
258 trustSettingsDictOrArray
= array
;
261 require_action_quiet(CFGetTypeID(trustSettingsDictOrArray
) == CFArrayGetTypeID(), errOut
, ok
= SecError(errSecParam
, error
, CFSTR("trustSettingsDictOrArray neither dict nor array")));
264 require_action_quiet(xmlData
= CFPropertyListCreateXMLData(kCFAllocatorDefault
,
265 trustSettingsDictOrArray
), errOut
, ok
= SecError(errSecParam
, error
, CFSTR("xml encode failed")));
267 int s3e
= sqlite3_exec(ts
->s3h
, "BEGIN EXCLUSIVE TRANSACTION", NULL
, NULL
, NULL
);
268 require_action_quiet(s3e
== SQLITE_OK
, errOut
, ok
= SecError(errSecInternal
, error
, CFSTR("sqlite3 error: %d"), s3e
));
270 /* Parameter order is sha1,subj,tset,data. */
271 require_noerr_action_quiet(sqlite3_prepare(ts
->s3h
, insertSQL
, sizeof(insertSQL
),
272 &insert
, NULL
), errOutSql
, ok
= SecError(errSecInternal
, error
, CFSTR("sqlite3 error: %d"), s3e
));
273 require_noerr_action_quiet(sqlite3_bind_blob_wrapper(insert
, 1,
274 CFDataGetBytePtr(digest
), CFDataGetLength(digest
), SQLITE_STATIC
),
275 errOutSql
, ok
= SecError(errSecInternal
, error
, CFSTR("sqlite3 error: %d"), s3e
));
276 require_noerr_action_quiet(sqlite3_bind_blob_wrapper(insert
, 2,
277 CFDataGetBytePtr(subject
), CFDataGetLength(subject
),
278 SQLITE_STATIC
), errOutSql
, ok
= SecError(errSecInternal
, error
, CFSTR("sqlite3 error: %d"), s3e
));
279 require_noerr_action_quiet(sqlite3_bind_blob_wrapper(insert
, 3,
280 CFDataGetBytePtr(xmlData
), CFDataGetLength(xmlData
),
281 SQLITE_STATIC
), errOutSql
, ok
= SecError(errSecInternal
, error
, CFSTR("sqlite3 error: %d"), s3e
));
282 require_noerr_action_quiet(sqlite3_bind_blob_wrapper(insert
, 4,
283 SecCertificateGetBytePtr(certificate
),
284 SecCertificateGetLength(certificate
), SQLITE_STATIC
), errOutSql
, ok
= SecError(errSecInternal
, error
, CFSTR("sqlite3 error: %d"), s3e
));
285 s3e
= sqlite3_step(insert
);
286 if (s3e
== SQLITE_DONE
) {
287 /* Great the insert worked. */
289 } else if (s3e
== SQLITE_ERROR
) {
291 require_noerr_action_quiet(s3e
= sqlite3_prepare(ts
->s3h
, updateSQL
, sizeof(updateSQL
),
292 &update
, NULL
), errOutSql
, ok
= SecError(errSecInternal
, error
, CFSTR("sqlite3 error: %d"), s3e
));
293 require_noerr_action_quiet(s3e
= sqlite3_bind_blob_wrapper(update
, 1,
294 CFDataGetBytePtr(xmlData
), CFDataGetLength(xmlData
),
295 SQLITE_STATIC
), errOutSql
, ok
= SecError(errSecInternal
, error
, CFSTR("sqlite3 error: %d"), s3e
));
296 require_noerr_action_quiet(s3e
= sqlite3_bind_blob_wrapper(update
, 2,
297 CFDataGetBytePtr(digest
), CFDataGetLength(digest
), SQLITE_STATIC
),
298 errOutSql
, ok
= SecError(errSecInternal
, error
, CFSTR("sqlite3 error: %d"), s3e
));
299 s3e
= sqlite3_step(update
);
300 require_action_quiet(s3e
== SQLITE_DONE
, errOutSql
, ok
= SecError(errSecInternal
, error
, CFSTR("sqlite3 error: %d"), s3e
));
304 require_noerr_action_quiet(s3e
, errOutSql
, ok
= SecError(errSecInternal
, error
, CFSTR("sqlite3 error: %d"), s3e
));
310 s3e
= sqlite3_finalize(insert
);
312 s3e
= sqlite3_finalize(update
);
314 if (ok
&& s3e
== SQLITE_OK
)
315 s3e
= sqlite3_exec(ts
->s3h
, "COMMIT TRANSACTION", NULL
, NULL
, NULL
);
317 if (!ok
|| s3e
!= SQLITE_OK
) {
318 sqlite3_exec(ts
->s3h
, "ROLLBACK TRANSACTION", NULL
, NULL
, NULL
);
320 ok
= SecError(errSecInternal
, error
, CFSTR("sqlite3 error: %d"), s3e
);
325 CFReleaseSafe(xmlData
);
326 CFReleaseSafe(array
);
332 /* AUDIT[securityd](done):
333 ts (ok) might be NULL.
334 digest (ok) is a data of any length (might be 0).
336 bool SecTrustStoreRemoveCertificateWithDigest(SecTrustStoreRef ts
,
337 CFDataRef digest
, CFErrorRef
*error
) {
338 require_quiet(ts
, errOutNotLocked
);
339 require(!ts
->readOnly
, errOutNotLocked
);
340 dispatch_sync(ts
->queue
, ^{
341 sqlite3_stmt
*deleteStmt
= NULL
;
342 require_noerr(sqlite3_prepare(ts
->s3h
, deleteSQL
, sizeof(deleteSQL
),
343 &deleteStmt
, NULL
), errOut
);
344 require_noerr(sqlite3_bind_blob_wrapper(deleteStmt
, 1,
345 CFDataGetBytePtr(digest
), CFDataGetLength(digest
), SQLITE_STATIC
),
347 sqlite3_step(deleteStmt
);
351 verify_noerr(sqlite3_finalize(deleteStmt
));
358 bool _SecTrustStoreRemoveAll(SecTrustStoreRef ts
, CFErrorRef
*error
)
360 __block
bool removed_all
= false;
361 require(ts
, errOutNotLocked
);
362 require(!ts
->readOnly
, errOutNotLocked
);
363 dispatch_sync(ts
->queue
, ^{
364 if (SQLITE_OK
== sqlite3_exec(ts
->s3h
, deleteAllSQL
, NULL
, NULL
, NULL
))
367 /* prepared statements become unusable after deleteAllSQL, reset them */
369 sqlite3_finalize(ts
->copyParents
);
370 sqlite3_prepare(ts
->s3h
, copyParentsSQL
, sizeof(copyParentsSQL
),
371 &ts
->copyParents
, NULL
);
373 sqlite3_finalize(ts
->contains
);
374 sqlite3_prepare(ts
->s3h
, containsSQL
, sizeof(containsSQL
),
375 &ts
->contains
, NULL
);
381 CFArrayRef
SecTrustStoreCopyParents(SecTrustStoreRef ts
,
382 SecCertificateRef certificate
, CFErrorRef
*error
) {
383 __block CFMutableArrayRef parents
= NULL
;
384 require(ts
, errOutNotLocked
);
385 dispatch_sync(ts
->queue
, ^{
387 require(issuer
= SecCertificateGetNormalizedIssuerContent(certificate
),
389 /* @@@ Might have to use SQLITE_TRANSIENT */
390 require_noerr(sqlite3_bind_blob_wrapper(ts
->copyParents
, 1,
391 CFDataGetBytePtr(issuer
), CFDataGetLength(issuer
),
392 SQLITE_STATIC
), errOut
);
394 require(parents
= CFArrayCreateMutable(kCFAllocatorDefault
, 0,
395 &kCFTypeArrayCallBacks
), errOut
);
397 int s3e
= sqlite3_step(ts
->copyParents
);
398 if (s3e
== SQLITE_ROW
) {
399 SecCertificateRef cert
;
400 require(cert
= SecCertificateCreateWithBytes(kCFAllocatorDefault
,
401 sqlite3_column_blob(ts
->copyParents
, 0),
402 sqlite3_column_bytes(ts
->copyParents
, 0)), errOut
);
403 CFArrayAppendValue(parents
, cert
);
406 require(s3e
== SQLITE_DONE
, errOut
);
418 verify_noerr(sqlite3_reset(ts
->copyParents
));
419 verify_noerr(sqlite3_clear_bindings(ts
->copyParents
));
425 /* AUDIT[securityd](done):
426 ts (ok) might be NULL.
427 digest (ok) is a data of any length (might be 0), only its cf type has
430 bool SecTrustStoreContainsCertificateWithDigest(SecTrustStoreRef ts
,
431 CFDataRef digest
, bool *contains
, CFErrorRef
*error
) {
434 __block
bool ok
= true;
435 require_action_quiet(ts
, errOutNotLocked
, ok
= SecError(errSecParam
, error
, CFSTR("ts is NULL")));
436 dispatch_sync(ts
->queue
, ^{
438 require_noerr_action(s3e
= sqlite3_bind_blob_wrapper(ts
->contains
, 1,
439 CFDataGetBytePtr(digest
), CFDataGetLength(digest
), SQLITE_STATIC
),
440 errOut
, ok
= SecDbErrorWithStmt(s3e
, ts
->contains
, error
, CFSTR("sqlite3_bind_blob failed")));
441 s3e
= sqlite3_step(ts
->contains
);
442 if (s3e
== SQLITE_ROW
) {
446 require_action(s3e
== SQLITE_DONE
, errOut
, ok
= SecDbErrorWithStmt(s3e
, ts
->contains
, error
, CFSTR("sqlite3_step failed")));
450 verify_noerr(sqlite3_reset(ts
->contains
));
451 verify_noerr(sqlite3_clear_bindings(ts
->contains
));