]> git.saurik.com Git - apple/security.git/blob - sec/securityd/SecItemServer.c
Security-55163.44.tar.gz
[apple/security.git] / sec / securityd / SecItemServer.c
1 /*
2 * Copyright (c) 2006-2010 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 * SecItemServer.c - CoreFoundation-based constants and functions for
26 access to Security items (certificates, keys, identities, and
27 passwords.)
28 */
29
30 #include <securityd/SecItemServer.h>
31
32 #include <Security/SecItem.h>
33 #include <Security/SecItemPriv.h>
34 #include <Security/SecItemInternal.h>
35 #include <Security/SecKey.h>
36 #include <Security/SecKeyPriv.h>
37 #include <Security/SecCertificateInternal.h>
38 #include <Security/SecIdentity.h>
39 #include <Security/SecIdentityPriv.h>
40 #include <Security/SecFramework.h>
41 #include <Security/SecRandom.h>
42 #include <Security/SecBasePriv.h>
43 #include <errno.h>
44 #include <limits.h>
45 #include <pthread.h>
46 #include <stdint.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <sys/param.h>
50 #include <sys/stat.h>
51 #include <Security/SecBase.h>
52 #include <CoreFoundation/CFData.h>
53 #include <CoreFoundation/CFDate.h>
54 #include <CoreFoundation/CFDictionary.h>
55 #include <CoreFoundation/CFNumber.h>
56 #include <CoreFoundation/CFString.h>
57 #include <CoreFoundation/CFURL.h>
58 #include <CommonCrypto/CommonDigest.h>
59 #include <CommonCrypto/CommonCryptor.h>
60 #include <CommonCrypto/CommonCryptorSPI.h>
61 #include <libkern/OSByteOrder.h>
62 #include <security_utilities/debugging.h>
63 #include <assert.h>
64 #include <Security/SecInternal.h>
65 #include <TargetConditionals.h>
66 #include "securityd_client.h"
67 #include "securityd_server.h"
68 #include "sqlutils.h"
69 #include <AssertMacros.h>
70 #include <asl.h>
71 #include <inttypes.h>
72
73 #if TARGET_OS_EMBEDDED && !TARGET_IPHONE_SIMULATOR
74 #define USE_HWAES 1
75 #define USE_KEYSTORE 1
76 #else /* no hardware aes */
77 #define USE_HWAES 0
78 #define USE_KEYSTORE 0
79 #endif /* hardware aes */
80
81 #if USE_HWAES
82 #include <IOKit/IOKitLib.h>
83 #include <Kernel/IOKit/crypto/IOAESTypes.h>
84 #endif /* USE_HWAES */
85
86 #if USE_KEYSTORE
87 #include <Kernel/IOKit/crypto/AppleKeyStoreDefs.h>
88 #include <MobileKeyBag/MobileKeyBag.h>
89 typedef int32_t keyclass_t;
90 #else
91 /* TODO: this needs to be available in the sim! */
92 #define kAppleKeyStoreKeyWrap 0
93 #define kAppleKeyStoreKeyUnwrap 1
94 typedef int32_t keyclass_t;
95 typedef int32_t key_handle_t;
96 typedef int32_t keybag_handle_t;
97 enum key_classes {
98 key_class_ak = 6,
99 key_class_ck,
100 key_class_dk,
101 key_class_aku,
102 key_class_cku,
103 key_class_dku
104 };
105 #endif /* USE_KEYSTORE */
106
107 /* KEYBAG_LEGACY and KEYBAG_NONE are private to security and have special meaning.
108 They should not collide with AppleKeyStore constants, but are only referenced
109 in here.
110 */
111 enum {
112 KEYBAG_LEGACY = -3, /* Set q_keybag to KEYBAG_LEGACY to use legacy decrypt. */
113 KEYBAG_BACKUP = -2, /* -2 == backup_keybag_handle, constant dictated by AKS */
114 KEYBAG_NONE = -1, /* Set q_keybag to KEYBAG_NONE to obtain cleartext data. */
115 KEYBAG_DEVICE = 0, /* 0 == device_keybag_handle, constant dictated by AKS */
116 };
117
118 #if 0
119 #include <CoreFoundation/CFPriv.h>
120 #else
121 /* Pass NULL for the current user's home directory */
122 CF_EXPORT
123 CFURLRef CFCopyHomeDirectoryURLForUser(CFStringRef uName);
124 #endif
125
126 /* label when certificate data is joined with key data */
127 #define CERTIFICATE_DATA_COLUMN_LABEL "certdata"
128
129 #define CURRENT_DB_VERSION 5
130
131 #define CLOSE_DB 0
132
133 static bool isArray(CFTypeRef cfType) {
134 return cfType && CFGetTypeID(cfType) == CFArrayGetTypeID();
135 }
136
137 static bool isData(CFTypeRef cfType) {
138 return cfType && CFGetTypeID(cfType) == CFDataGetTypeID();
139 }
140
141 static bool isDictionary(CFTypeRef cfType) {
142 return cfType && CFGetTypeID(cfType) == CFDictionaryGetTypeID();
143 }
144
145 static bool isNumber(CFTypeRef cfType) {
146 return cfType && CFGetTypeID(cfType) == CFNumberGetTypeID();
147 }
148
149 static bool isNumberOfType(CFTypeRef cfType, CFNumberType number) {
150 return isNumber(cfType) && CFNumberGetType(cfType) == number;
151 }
152
153 static bool isString(CFTypeRef cfType) {
154 return cfType && CFGetTypeID(cfType) == CFStringGetTypeID();
155 }
156
157 typedef struct s3dl_db
158 {
159 char *db_name;
160 pthread_key_t key;
161 pthread_mutex_t mutex;
162 /* Linked list of s3dl_db_thread * */
163 struct s3dl_db_thread *dbt_head;
164 /* True iff crypto facilities are available and keychain key is usable. */
165 bool use_hwaes;
166 } s3dl_db;
167
168 typedef s3dl_db *db_handle;
169
170 typedef struct s3dl_db_thread
171 {
172 struct s3dl_db_thread *dbt_next;
173 s3dl_db *db;
174 sqlite3 *s3_handle;
175 bool autocommit;
176 bool in_transaction;
177 } s3dl_db_thread;
178
179 typedef struct s3dl_results_handle
180 {
181 uint32_t recordid;
182 sqlite3_stmt *stmt;
183 } s3dl_results_handle;
184
185 /* Mapping from class name to kc_class pointer. */
186 static CFDictionaryRef gClasses;
187
188 /* Forward declaration of import export SPIs. */
189 enum SecItemFilter {
190 kSecNoItemFilter,
191 kSecSysBoundItemFilter,
192 kSecBackupableItemFilter,
193 };
194
195 static CFDictionaryRef SecServerExportKeychainPlist(s3dl_db_thread *dbt,
196 keybag_handle_t src_keybag, keybag_handle_t dest_keybag,
197 enum SecItemFilter filter, int version, OSStatus *error);
198 static OSStatus SecServerImportKeychainInPlist(s3dl_db_thread *dbt,
199 keybag_handle_t src_keybag, keybag_handle_t dest_keybag,
200 CFDictionaryRef keychain, enum SecItemFilter filter);
201
202 #if USE_HWAES || USE_KEYSTORE
203 /*
204 * Encryption support.
205 */
206 static pthread_once_t hwcrypto_init_once = PTHREAD_ONCE_INIT;
207 static io_connect_t hwaes_codec = MACH_PORT_NULL;
208 static io_connect_t keystore = MACH_PORT_NULL;
209
210 static void service_matching_callback(void *refcon, io_iterator_t iterator)
211 {
212 io_object_t obj = IO_OBJECT_NULL;
213
214 while ((obj = IOIteratorNext(iterator))) {
215 kern_return_t ret = IOServiceOpen(obj, mach_task_self(), 0,
216 (io_connect_t*)refcon);
217 if (ret) {
218 asl_log(NULL, NULL, ASL_LEVEL_ERR,
219 "IOServiceOpen() failed: %x", ret);
220 }
221 IOObjectRelease(obj);
222 }
223 }
224
225 static void connect_to_service(const char *className, io_connect_t *connect)
226 {
227 kern_return_t kernResult;
228 io_iterator_t iterator = MACH_PORT_NULL;
229 IONotificationPortRef port = MACH_PORT_NULL;
230 CFDictionaryRef classToMatch;
231
232 if ((classToMatch = IOServiceMatching(className)) == NULL) {
233 asl_log(NULL, NULL, ASL_LEVEL_ERR,
234 "IOServiceMatching failed for '%s'", className);
235 return;
236 }
237
238 /* consumed by IOServiceGetMatchingServices, we need it if that fails. */
239 CFRetain(classToMatch);
240 kernResult = IOServiceGetMatchingServices(kIOMasterPortDefault,
241 classToMatch, &iterator);
242
243 if (kernResult == KERN_SUCCESS) {
244 CFRelease(classToMatch);
245 } else {
246 asl_log(NULL, NULL, ASL_LEVEL_WARNING,
247 "IOServiceGetMatchingServices() failed %x using notifiction",
248 kernResult);
249
250 port = IONotificationPortCreate(kIOMasterPortDefault);
251 if (!port) {
252 asl_log(NULL, NULL, ASL_LEVEL_ERR,
253 "IONotificationPortCreate() failed");
254 return;
255 }
256
257 kernResult = IOServiceAddMatchingNotification(port,
258 kIOFirstMatchNotification, classToMatch, service_matching_callback,
259 connect, &iterator);
260 if (kernResult) {
261 asl_log(NULL, NULL, ASL_LEVEL_ERR,
262 "IOServiceAddMatchingNotification() failed: %x", kernResult);
263 return;
264 }
265 }
266
267 /* Check whether it was already there before we registered for the
268 notification. */
269 service_matching_callback(connect, iterator);
270
271 if (port) {
272 /* We'll get set up to wait for it to appear */
273 if (*connect == MACH_PORT_NULL) {
274 asl_log(NULL, NULL, ASL_LEVEL_ERR,
275 "Waiting for %s to show up.", className);
276 CFStringRef mode = CFSTR("WaitForCryptoService");
277 CFRunLoopAddSource(CFRunLoopGetCurrent(),
278 IONotificationPortGetRunLoopSource(port), mode);
279 CFRunLoopRunInMode(mode, 30.0, true);
280 if (hwaes_codec == MACH_PORT_NULL)
281 asl_log(NULL, NULL, ASL_LEVEL_ERR, "Cannot find AES driver");
282 }
283 IONotificationPortDestroy(port);
284 }
285
286 IOObjectRelease(iterator);
287
288 if (*connect) {
289 asl_log(NULL, NULL, ASL_LEVEL_INFO, "Obtained connection %d for %s",
290 *connect, className);
291 }
292 return;
293 }
294
295 static void hwcrypto_init(void)
296 {
297 connect_to_service(kIOAESAcceleratorClass, &hwaes_codec);
298 connect_to_service(kAppleKeyStoreServiceName, &keystore);
299
300 if (keystore != MACH_PORT_NULL) {
301 IOReturn kernResult = IOConnectCallMethod(keystore,
302 kAppleKeyStoreUserClientOpen, NULL, 0, NULL, 0, NULL, NULL,
303 NULL, NULL);
304 if (kernResult) {
305 asl_log(NULL, NULL, ASL_LEVEL_ERR,
306 "Failed to open AppleKeyStore: %x", kernResult);
307 } else {
308 asl_log(NULL, NULL, ASL_LEVEL_INFO, "Opened AppleKeyStore");
309 }
310 }
311 /* TODO: Remove this once the kext runs the daemon on demand if
312 there is no system keybag. */
313 int kb_state = MKBGetDeviceLockState(NULL);
314 asl_log(NULL, NULL, ASL_LEVEL_INFO, "AppleKeyStore lock state: %d",
315 kb_state);
316 }
317
318 static bool hwaes_crypt(IOAESOperation operation, UInt32 keyHandle,
319 UInt32 keySizeInBits, const UInt8 *keyBits, const UInt8 *iv,
320 UInt32 textLength, UInt8 *plainText, UInt8 *cipherText)
321 {
322 struct IOAESAcceleratorRequest aesRequest;
323 kern_return_t kernResult;
324 IOByteCount outSize;
325
326 if (!hwaes_codec) {
327 asl_log(NULL, NULL, ASL_LEVEL_ERR, "aes codec not initialized");
328 return false;
329 }
330
331 aesRequest.plainText = plainText;
332 aesRequest.cipherText = cipherText;
333 aesRequest.textLength = textLength;
334 memcpy(aesRequest.iv.ivBytes, iv, 16);
335 aesRequest.operation = operation;
336 aesRequest.keyData.key.keyLength = keySizeInBits;
337 aesRequest.keyData.keyHandle = keyHandle;
338 if (keyBits) {
339 memcpy(aesRequest.keyData.key.keyBytes, keyBits, keySizeInBits / 8);
340 } else {
341 bzero(aesRequest.keyData.key.keyBytes, keySizeInBits / 8);
342 }
343
344 outSize = sizeof(aesRequest);
345 kernResult = IOConnectCallStructMethod(hwaes_codec,
346 kIOAESAcceleratorPerformAES, &aesRequest, outSize,
347 &aesRequest, &outSize);
348
349 if (kernResult != KERN_SUCCESS) {
350 asl_log(NULL, NULL, ASL_LEVEL_ERR, "kIOAESAcceleratorPerformAES: %x",
351 kernResult);
352 return false;
353 }
354
355 asl_log(NULL, NULL, ASL_LEVEL_INFO,
356 "kIOAESAcceleratorPerformAES processed: %lu bytes", textLength);
357
358 return true;
359 }
360
361 static bool hwaes_key_available(void)
362 {
363 /* The AES driver needs to have a 16byte aligned address */
364 UInt8 buf[32] = {};
365 UInt8 *bufp = (UInt8*)(((intptr_t)&buf[15]) & ~15);
366
367 pthread_once(&hwcrypto_init_once, hwcrypto_init);
368 return hwaes_crypt(IOAESOperationEncrypt,
369 kIOAESAcceleratorKeyHandleKeychain, 128, NULL, bufp, 16, bufp, bufp);
370 }
371
372
373 #else /* !USE_HWAES */
374
375 static bool hwaes_key_available(void)
376 {
377 return false;
378 }
379
380 #endif /* !USE_HWAES */
381
382 static int s3dl_create_path(const char *path)
383 {
384 char pathbuf[PATH_MAX];
385 size_t pos, len = strlen(path);
386 if (len == 0 || len > PATH_MAX)
387 return SQLITE_CANTOPEN;
388 memcpy(pathbuf, path, len);
389 for (pos = len; --pos > 0;)
390 {
391 /* Search backwards for trailing '/'. */
392 if (pathbuf[pos] == '/')
393 {
394 pathbuf[pos] = '\0';
395 /* Attempt to create parent directories of the database. */
396 if (!mkdir(pathbuf, 0777))
397 break;
398 else
399 {
400 int err = errno;
401 if (err == EEXIST)
402 return 0;
403 if (err == ENOTDIR)
404 return SQLITE_CANTOPEN;
405 if (err == EROFS)
406 return SQLITE_READONLY;
407 if (err == EACCES)
408 return SQLITE_PERM;
409 if (err == ENOSPC || err == EDQUOT)
410 return SQLITE_FULL;
411 if (err == EIO)
412 return SQLITE_IOERR;
413
414 /* EFAULT || ELOOP | ENAMETOOLONG || something else */
415 return SQLITE_INTERNAL;
416 }
417 }
418 }
419 return 0;
420 }
421
422 /* Start an exclusive transaction if we don't have one yet. */
423 static int s3dl_begin_transaction(s3dl_db_thread *dbt)
424 {
425 if (dbt->in_transaction)
426 return dbt->autocommit ? SQLITE_INTERNAL : SQLITE_OK;
427
428 int s3e = sqlite3_exec(dbt->s3_handle, "BEGIN EXCLUSIVE TRANSACTION",
429 NULL, NULL, NULL);
430 if (s3e == SQLITE_OK)
431 dbt->in_transaction = true;
432
433 return s3e;
434 }
435
436 /* Commit the current transaction if we have one. */
437 static int s3dl_commit_transaction(s3dl_db_thread *dbt)
438 {
439 if (!dbt->in_transaction)
440 return SQLITE_OK;
441
442 int s3e = sqlite3_exec(dbt->s3_handle, "COMMIT TRANSACTION",
443 NULL, NULL, NULL);
444 if (s3e == SQLITE_OK)
445 dbt->in_transaction = false;
446
447 return s3e;
448 }
449
450 /* Rollback the current transaction if we have one. */
451 static int s3dl_rollback_transaction(s3dl_db_thread *dbt)
452 {
453 if (!dbt->in_transaction)
454 return SQLITE_OK;
455
456 int s3e = sqlite3_exec(dbt->s3_handle, "ROLLBACK TRANSACTION",
457 NULL, NULL, NULL);
458 if (s3e == SQLITE_OK)
459 dbt->in_transaction = false;
460
461 return s3e;
462 }
463
464 /* If we are in a transaction and autocommt is on, commit the transaction
465 if s3e == SQLITE_OK, otherwise rollback the transaction. */
466 static int s3dl_end_transaction(s3dl_db_thread *dbt, int s3e)
467 {
468 if (dbt->autocommit)
469 {
470 if (s3e == SQLITE_OK)
471 return s3dl_commit_transaction(dbt);
472 else
473 s3dl_rollback_transaction(dbt);
474 }
475
476 return s3e;
477 }
478
479 static int s3dl_close_dbt(s3dl_db_thread *dbt)
480 {
481 int s3e = sqlite3_close(dbt->s3_handle);
482 free(dbt);
483 return s3e;
484 }
485
486 typedef enum {
487 kc_blob_attr, // CFString or CFData, preserves caller provided type.
488 kc_data_attr,
489 kc_string_attr,
490 kc_number_attr,
491 kc_date_attr,
492 kc_creation_date_attr,
493 kc_modification_date_attr
494 } kc_attr_kind;
495
496 enum {
497 kc_constrain_not_null = (1 << 0), // attr value can't be null
498 kc_constrain_default_0 = (1 << 1), // default attr value is 0
499 kc_constrain_default_empty = (1 << 2), // default attr value is ""
500 kc_digest_attr = (1 << 3), // col in db is sha1 of attr value
501 };
502
503 typedef struct kc_attr_desc {
504 CFStringRef name;
505 kc_attr_kind kind;
506 CFOptionFlags flags;
507 } kc_attr_desc;
508
509 typedef struct kc_class {
510 CFStringRef name;
511 CFIndex n_attrs;
512 const kc_attr_desc *attrs;
513 } kc_class;
514
515 #if 0
516 typedef struct kc_item {
517 kc_class *c;
518 CFMutableDictionaryRef a;
519 } kc_item;
520
521 typedef CFIndex kc_attr_id;
522 #endif
523
524 #define KC_ATTR(name, kind, flags) { CFSTR(name), kc_ ## kind ## _attr, flags }
525
526 static const kc_attr_desc genp_attrs[] = {
527 KC_ATTR("pdmn", string, 0),
528 KC_ATTR("agrp", string, 0),
529 KC_ATTR("cdat", creation_date, 0),
530 KC_ATTR("mdat", modification_date, 0),
531 KC_ATTR("desc", blob, kc_digest_attr),
532 KC_ATTR("icmt", blob, kc_digest_attr),
533 KC_ATTR("crtr", number, 0),
534 KC_ATTR("type", number, 0),
535 KC_ATTR("scrp", number, 0),
536 KC_ATTR("labl", blob, kc_digest_attr),
537 KC_ATTR("alis", blob, kc_digest_attr),
538 KC_ATTR("invi", number, 0),
539 KC_ATTR("nega", number, 0),
540 KC_ATTR("cusi", number, 0),
541 KC_ATTR("prot", blob, kc_digest_attr),
542 KC_ATTR("acct", blob, kc_constrain_not_null | kc_constrain_default_empty | kc_digest_attr),
543 KC_ATTR("svce", blob, kc_constrain_not_null | kc_constrain_default_empty | kc_digest_attr),
544 KC_ATTR("gena", blob, kc_digest_attr),
545 };
546 #if 0
547 static const kc_attr_id genp_unique[] = {
548 // acct, svce, agrp
549 15, 16, 1
550 };
551 static kc_class_constraint genp_constraints[] = {
552 { kc_unique_constraint, sizeof(genp_unique) / sizeof(*genp_unique), genp_unique },
553 };
554 #endif
555 static const kc_class genp_class = {
556 .name = CFSTR("genp"),
557 .n_attrs = sizeof(genp_attrs) / sizeof(*genp_attrs),
558 .attrs = genp_attrs,
559 };
560
561 static const kc_attr_desc inet_attrs[] = {
562 KC_ATTR("pdmn", string, 0),
563 KC_ATTR("agrp", string, 0),
564 KC_ATTR("cdat", creation_date, 0),
565 KC_ATTR("mdat", modification_date, 0),
566 KC_ATTR("desc", blob, kc_digest_attr),
567 KC_ATTR("icmt", blob, kc_digest_attr),
568 KC_ATTR("crtr", number, 0),
569 KC_ATTR("type", number, 0),
570 KC_ATTR("scrp", number, 0),
571 KC_ATTR("labl", blob, kc_digest_attr),
572 KC_ATTR("alis", blob, kc_digest_attr),
573 KC_ATTR("invi", number, 0),
574 KC_ATTR("nega", number, 0),
575 KC_ATTR("cusi", number, 0),
576 KC_ATTR("prot", blob, kc_digest_attr),
577 KC_ATTR("acct", blob, kc_constrain_not_null | kc_constrain_default_empty | kc_digest_attr),
578 KC_ATTR("sdmn", blob, kc_constrain_not_null | kc_constrain_default_empty | kc_digest_attr),
579 KC_ATTR("srvr", blob, kc_constrain_not_null | kc_constrain_default_empty | kc_digest_attr),
580 KC_ATTR("ptcl", number, kc_constrain_not_null | kc_constrain_default_0),
581 KC_ATTR("atyp", blob, kc_digest_attr),
582 KC_ATTR("port", number, kc_constrain_not_null | kc_constrain_default_0),
583 KC_ATTR("path", blob, kc_constrain_not_null | kc_constrain_default_empty | kc_digest_attr),
584 };
585 #if 0
586 static const kc_attr_id inet_unique[] = {
587 // acct, sdmn, srvr, ptcl, atyp, port, path, agrp
588 15, 16, 17, 18, 19, 20, 21, 1
589 };
590 static kc_class_constraint inet_constraints[] = {
591 { kc_unique_constraint, sizeof(inet_unique) / sizeof(*inet_unique), inet_unique },
592 };
593 #endif
594 static const kc_class inet_class = {
595 .name = CFSTR("inet"),
596 .n_attrs = sizeof(inet_attrs) / sizeof(*inet_attrs),
597 .attrs = inet_attrs,
598 };
599
600 static const kc_attr_desc cert_attrs[] = {
601 KC_ATTR("pdmn", string, 0),
602 KC_ATTR("agrp", string, 0),
603 KC_ATTR("cdat", creation_date, 0),
604 KC_ATTR("mdat", modification_date, 0),
605 KC_ATTR("ctyp", number, kc_constrain_not_null | kc_constrain_default_0),
606 KC_ATTR("cenc", number, 0),
607 KC_ATTR("labl", blob, kc_digest_attr),
608 KC_ATTR("alis", blob, kc_digest_attr),
609 KC_ATTR("subj", data, kc_digest_attr),
610 KC_ATTR("issr", data, kc_constrain_not_null | kc_constrain_default_empty | kc_digest_attr),
611 KC_ATTR("slnr", data, kc_constrain_not_null | kc_constrain_default_empty | kc_digest_attr),
612 KC_ATTR("skid", data, kc_digest_attr),
613 KC_ATTR("pkhh", data, 0),
614 };
615 #if 0
616 static const kc_attr_id cert_unique[] = {
617 //ctyp, issr, slnr, agrp
618 2, 7, 8, 1
619 };
620 static kc_class_constraint cert_constraints[] = {
621 { kc_unique_constraint, sizeof(cert_unique) / sizeof(*cert_unique), cert_unique, },
622 };
623 #endif
624 static const kc_class cert_class = {
625 .name = CFSTR("cert"),
626 .n_attrs = sizeof(cert_attrs) / sizeof(*cert_attrs),
627 .attrs = cert_attrs,
628 };
629
630 static const kc_attr_desc keys_attrs[] = {
631 KC_ATTR("pdmn", string, 0),
632 KC_ATTR("agrp", string, 0),
633 KC_ATTR("cdat", creation_date, 0),
634 KC_ATTR("mdat", modification_date, 0),
635 KC_ATTR("kcls", number, kc_constrain_not_null | kc_constrain_default_0),
636 KC_ATTR("labl", blob, kc_digest_attr),
637 KC_ATTR("alis", blob, kc_digest_attr),
638 KC_ATTR("perm", number, 0),
639 KC_ATTR("priv", number, 0),
640 KC_ATTR("modi", number, 0),
641 KC_ATTR("klbl", data, kc_constrain_not_null | kc_constrain_default_empty),
642 KC_ATTR("atag", blob, kc_constrain_not_null | kc_constrain_default_empty | kc_digest_attr),
643 KC_ATTR("crtr", number, kc_constrain_not_null | kc_constrain_default_0),
644 KC_ATTR("type", number, kc_constrain_not_null | kc_constrain_default_0),
645 KC_ATTR("bsiz", number, kc_constrain_not_null | kc_constrain_default_0),
646 KC_ATTR("esiz", number, kc_constrain_not_null | kc_constrain_default_0),
647 KC_ATTR("sdat", date, kc_constrain_not_null | kc_constrain_default_0),
648 KC_ATTR("edat", date, kc_constrain_not_null | kc_constrain_default_0),
649 KC_ATTR("sens", number, 0),
650 KC_ATTR("asen", number, 0),
651 KC_ATTR("extr", number, 0),
652 KC_ATTR("next", number, 0),
653 KC_ATTR("encr", number, 0),
654 KC_ATTR("decr", number, 0),
655 KC_ATTR("drve", number, 0),
656 KC_ATTR("sign", number, 0),
657 KC_ATTR("vrfy", number, 0),
658 KC_ATTR("snrc", number, 0),
659 KC_ATTR("vyrc", number, 0),
660 KC_ATTR("wrap", number, 0),
661 KC_ATTR("unwp", number, 0),
662 };
663 #if 0
664 static const kc_attr_id keys_unique[] = {
665 // kcls, klbl, atag, crtr, type, bsiz, esiz, sdat, edat, agrp
666 2, 8, 9, 10, 11, 12, 13, 14, 15, 1
667 };
668 static kc_class_constraint keys_constraints[] = {
669 { kc_unique_constraint, sizeof(keys_unique) / sizeof(*keys_unique), keys_unique, },
670 };
671 #endif
672 static const kc_class keys_class = {
673 .name = CFSTR("keys"),
674 .n_attrs = sizeof(keys_attrs) / sizeof(*keys_attrs),
675 .attrs = keys_attrs,
676 };
677
678 /* An identity which is really a cert + a key, so all cert and keys attrs are
679 allowed. */
680 static const kc_class identity_class = {
681 .name = CFSTR("idnt"),
682 .n_attrs = 0,
683 .attrs = NULL,
684 };
685
686 static const kc_attr_desc *kc_attr_desc_with_key(const kc_class *c,
687 CFTypeRef key,
688 OSStatus *error) {
689 /* Special case: identites can have all attributes of either cert
690 or keys. */
691 if (c == &identity_class) {
692 const kc_attr_desc *desc;
693 if (!(desc = kc_attr_desc_with_key(&cert_class, key, 0)))
694 desc = kc_attr_desc_with_key(&keys_class, key, error);
695 return desc;
696 }
697
698 if (isString(key)) {
699 CFIndex ix;
700 for (ix = 0; ix < c->n_attrs; ++ix) {
701 if (CFEqual(c->attrs[ix].name, key)) {
702 return &c->attrs[ix];
703 }
704 }
705
706 /* TODO: Remove this hack since it's violating this function's contract to always set an error when it returns NULL. */
707 if (CFEqual(key, kSecAttrSynchronizable))
708 return NULL;
709
710 }
711
712 if (error && !*error)
713 *error = errSecNoSuchAttr;
714
715 return NULL;
716 }
717
718 static const char * const s3dl_upgrade_sql[] = {
719 /* 0 */
720 /* Upgrade from version 0 -- empty db a.k.a. current schema. */
721 "CREATE TABLE genp("
722 "rowid INTEGER PRIMARY KEY AUTOINCREMENT,"
723 "cdat REAL,"
724 "mdat REAL,"
725 "desc BLOB,"
726 "icmt BLOB,"
727 "crtr INTEGER,"
728 "type INTEGER,"
729 "scrp INTEGER,"
730 "labl BLOB,"
731 "alis BLOB,"
732 "invi INTEGER,"
733 "nega INTEGER,"
734 "cusi INTEGER,"
735 "prot BLOB,"
736 "acct BLOB NOT NULL DEFAULT '',"
737 "svce BLOB NOT NULL DEFAULT '',"
738 "gena BLOB,"
739 "data BLOB,"
740 "agrp TEXT,"
741 "pdmn TEXT,"
742 "UNIQUE("
743 "acct,svce,agrp"
744 "));"
745 "CREATE TABLE inet("
746 "rowid INTEGER PRIMARY KEY AUTOINCREMENT,"
747 "cdat REAL,"
748 "mdat REAL,"
749 "desc BLOB,"
750 "icmt BLOB,"
751 "crtr INTEGER,"
752 "type INTEGER,"
753 "scrp INTEGER,"
754 "labl BLOB,"
755 "alis BLOB,"
756 "invi INTEGER,"
757 "nega INTEGER,"
758 "cusi INTEGER,"
759 "prot BLOB,"
760 "acct BLOB NOT NULL DEFAULT '',"
761 "sdmn BLOB NOT NULL DEFAULT '',"
762 "srvr BLOB NOT NULL DEFAULT '',"
763 "ptcl INTEGER NOT NULL DEFAULT 0,"
764 "atyp BLOB NOT NULL DEFAULT '',"
765 "port INTEGER NOT NULL DEFAULT 0,"
766 "path BLOB NOT NULL DEFAULT '',"
767 "data BLOB,"
768 "agrp TEXT,"
769 "pdmn TEXT,"
770 "UNIQUE("
771 "acct,sdmn,srvr,ptcl,atyp,port,path,agrp"
772 "));"
773 "CREATE TABLE cert("
774 "rowid INTEGER PRIMARY KEY AUTOINCREMENT,"
775 "cdat REAL,"
776 "mdat REAL,"
777 "ctyp INTEGER NOT NULL DEFAULT 0,"
778 "cenc INTEGER,"
779 "labl BLOB,"
780 "alis BLOB,"
781 "subj BLOB,"
782 "issr BLOB NOT NULL DEFAULT '',"
783 "slnr BLOB NOT NULL DEFAULT '',"
784 "skid BLOB,"
785 "pkhh BLOB,"
786 "data BLOB,"
787 "agrp TEXT,"
788 "pdmn TEXT,"
789 "UNIQUE("
790 "ctyp,issr,slnr,agrp"
791 "));"
792 "CREATE TABLE keys("
793 "rowid INTEGER PRIMARY KEY AUTOINCREMENT,"
794 "cdat REAL,"
795 "mdat REAL,"
796 "kcls INTEGER NOT NULL DEFAULT 0,"
797 "labl BLOB,"
798 "alis BLOB,"
799 "perm INTEGER,"
800 "priv INTEGER,"
801 "modi INTEGER,"
802 "klbl BLOB NOT NULL DEFAULT '',"
803 "atag BLOB NOT NULL DEFAULT '',"
804 "crtr INTEGER NOT NULL DEFAULT 0,"
805 "type INTEGER NOT NULL DEFAULT 0,"
806 "bsiz INTEGER NOT NULL DEFAULT 0,"
807 "esiz INTEGER NOT NULL DEFAULT 0,"
808 "sdat REAL NOT NULL DEFAULT 0,"
809 "edat REAL NOT NULL DEFAULT 0,"
810 "sens INTEGER,"
811 "asen INTEGER,"
812 "extr INTEGER,"
813 "next INTEGER,"
814 "encr INTEGER,"
815 "decr INTEGER,"
816 "drve INTEGER,"
817 "sign INTEGER,"
818 "vrfy INTEGER,"
819 "snrc INTEGER,"
820 "vyrc INTEGER,"
821 "wrap INTEGER,"
822 "unwp INTEGER,"
823 "data BLOB,"
824 "agrp TEXT,"
825 "pdmn TEXT,"
826 "UNIQUE("
827 "kcls,klbl,atag,crtr,type,bsiz,esiz,sdat,edat,agrp"
828 "));"
829 "CREATE TABLE tversion(version INTEGER);"
830 "INSERT INTO tversion(version) VALUES(5);",
831
832 /* 1 */
833 /* Create indices. */
834 "CREATE INDEX ialis ON cert(alis);"
835 "CREATE INDEX isubj ON cert(subj);"
836 "CREATE INDEX iskid ON cert(skid);"
837 "CREATE INDEX ipkhh ON cert(pkhh);"
838 "CREATE INDEX ikcls ON keys(kcls);"
839 "CREATE INDEX iklbl ON keys(klbl);"
840 "CREATE INDEX iencr ON keys(encr);"
841 "CREATE INDEX idecr ON keys(decr);"
842 "CREATE INDEX idrve ON keys(drve);"
843 "CREATE INDEX isign ON keys(sign);"
844 "CREATE INDEX ivrfy ON keys(vrfy);"
845 "CREATE INDEX iwrap ON keys(wrap);"
846 "CREATE INDEX iunwp ON keys(unwp);",
847
848 /* 2 */
849 /* Rename version 1 tables. */
850 "ALTER TABLE genp RENAME TO ogenp;"
851 "ALTER TABLE inet RENAME TO oinet;"
852 "ALTER TABLE cert RENAME TO ocert;"
853 "ALTER TABLE keys RENAME TO okeys;",
854
855 /* 3 */
856 /* Rename version 2 or version 3 tables and drop version table since
857 step 0 creates it. */
858 "ALTER TABLE genp RENAME TO ogenp;"
859 "ALTER TABLE inet RENAME TO oinet;"
860 "ALTER TABLE cert RENAME TO ocert;"
861 "ALTER TABLE keys RENAME TO okeys;"
862 "DROP TABLE tversion;",
863
864 /* 4 */
865 /* Move data from version 1 or version 2 tables to new ones and drop old
866 ones. */
867 /* Set the agrp on all (apple internal) items to apple. */
868 "INSERT INTO genp (rowid,cdat,mdat,desc,icmt,crtr,type,scrp,labl,alis,invi,nega,cusi,prot,acct,svce,gena,data) SELECT rowid,cdat,mdat,desc,icmt,crtr,type,scrp,labl,alis,invi,nega,cusi,prot,acct,svce,gena,data from ogenp;"
869 "INSERT INTO inet (rowid,cdat,mdat,desc,icmt,crtr,type,scrp,labl,alis,invi,nega,cusi,prot,acct,sdmn,srvr,ptcl,atyp,port,path,data) SELECT rowid,cdat,mdat,desc,icmt,crtr,type,scrp,labl,alis,invi,nega,cusi,prot,acct,sdmn,srvr,ptcl,atyp,port,path,data from oinet;"
870 "INSERT INTO cert (rowid,ctyp,cenc,labl,alis,subj,issr,slnr,skid,pkhh,data) SELECT rowid,ctyp,cenc,labl,alis,subj,issr,slnr,skid,pkhh,data from ocert;"
871 "INSERT INTO keys (rowid,kcls,labl,alis,perm,priv,modi,klbl,atag,crtr,type,bsiz,esiz,sdat,edat,sens,asen,extr,next,encr,decr,drve,sign,vrfy,snrc,vyrc,wrap,unwp,data) SELECT rowid,kcls,labl,alis,perm,priv,modi,klbl,atag,crtr,type,bsiz,esiz,sdat,edat,sens,asen,extr,next,encr,decr,drve,sign,vrfy,snrc,vyrc,wrap,unwp,data from okeys;"
872 "UPDATE genp SET agrp='apple';"
873 "UPDATE inet SET agrp='apple';"
874 "UPDATE cert SET agrp='apple';"
875 "UPDATE keys SET agrp='apple';"
876 "DROP TABLE ogenp;"
877 "DROP TABLE oinet;"
878 "DROP TABLE ocert;"
879 "DROP TABLE okeys;",
880
881 /* 5 */
882 /* Move data from version 3 tables to new ones and drop old ones. */
883 "INSERT INTO genp (rowid,cdat,mdat,desc,icmt,crtr,type,scrp,labl,alis,invi,nega,cusi,prot,acct,svce,gena,data,agrp) SELECT rowid,cdat,mdat,desc,icmt,crtr,type,scrp,labl,alis,invi,nega,cusi,prot,acct,svce,gena,data,agrp from ogenp;"
884 "INSERT INTO inet (rowid,cdat,mdat,desc,icmt,crtr,type,scrp,labl,alis,invi,nega,cusi,prot,acct,sdmn,srvr,ptcl,atyp,port,path,data,agrp) SELECT rowid,cdat,mdat,desc,icmt,crtr,type,scrp,labl,alis,invi,nega,cusi,prot,acct,sdmn,srvr,ptcl,atyp,port,path,data,agrp from oinet;"
885 "INSERT INTO cert (rowid,ctyp,cenc,labl,alis,subj,issr,slnr,skid,pkhh,data,agrp) SELECT rowid,ctyp,cenc,labl,alis,subj,issr,slnr,skid,pkhh,data,agrp from ocert;"
886 "INSERT INTO keys (rowid,kcls,labl,alis,perm,priv,modi,klbl,atag,crtr,type,bsiz,esiz,sdat,edat,sens,asen,extr,next,encr,decr,drve,sign,vrfy,snrc,vyrc,wrap,unwp,data,agrp) SELECT rowid,kcls,labl,alis,perm,priv,modi,klbl,atag,crtr,type,bsiz,esiz,sdat,edat,sens,asen,extr,next,encr,decr,drve,sign,vrfy,snrc,vyrc,wrap,unwp,data,agrp from okeys;"
887 "DROP TABLE ogenp;"
888 "DROP TABLE oinet;"
889 "DROP TABLE ocert;"
890 "DROP TABLE okeys;",
891
892 /* 6 */
893 /* Move data from version 4 tables to new ones and drop old ones. */
894 "INSERT INTO genp (rowid,cdat,mdat,desc,icmt,crtr,type,scrp,labl,alis,invi,nega,cusi,prot,acct,svce,gena,data,agrp,pdmn) SELECT rowid,cdat,mdat,desc,icmt,crtr,type,scrp,labl,alis,invi,nega,cusi,prot,acct,svce,gena,data,agrp,pdmn from ogenp;"
895 "INSERT INTO inet (rowid,cdat,mdat,desc,icmt,crtr,type,scrp,labl,alis,invi,nega,cusi,prot,acct,sdmn,srvr,ptcl,atyp,port,path,data,agrp,pdmn) SELECT rowid,cdat,mdat,desc,icmt,crtr,type,scrp,labl,alis,invi,nega,cusi,prot,acct,sdmn,srvr,ptcl,atyp,port,path,data,agrp,pdmn from oinet;"
896 "INSERT INTO cert (rowid,ctyp,cenc,labl,alis,subj,issr,slnr,skid,pkhh,data,agrp,pdmn) SELECT rowid,ctyp,cenc,labl,alis,subj,issr,slnr,skid,pkhh,data,agrp,pdmn from ocert;"
897 "INSERT INTO keys (rowid,kcls,labl,alis,perm,priv,modi,klbl,atag,crtr,type,bsiz,esiz,sdat,edat,sens,asen,extr,next,encr,decr,drve,sign,vrfy,snrc,vyrc,wrap,unwp,data,agrp,pdmn) SELECT rowid,kcls,labl,alis,perm,priv,modi,klbl,atag,crtr,type,bsiz,esiz,sdat,edat,sens,asen,extr,next,encr,decr,drve,sign,vrfy,snrc,vyrc,wrap,unwp,data,agrp,pdmn from okeys;"
898 "DROP TABLE ogenp;"
899 "DROP TABLE oinet;"
900 "DROP TABLE ocert;"
901 "DROP TABLE okeys;",
902 };
903
904 struct sql_stages {
905 int pre;
906 int main;
907 int post;
908 bool init_pdmn;
909 };
910
911 static struct sql_stages s3dl_upgrade_script[] = {
912 { -1, 0, 1, false }, /* Create version 5 database. */
913 { 2, 0, 4, true }, /* Upgrade to version 5 from version 1 (LittleBear). */
914 { 3, 0, 4, true }, /* Upgrade to version 5 from version 2 (BigBearBeta). */
915 { 3, 0, 5, true }, /* Upgrade to version 5 from version 3 (Apex). */
916 { 3, 0, 6, true }, /* Upgrade to version 5 from version 4 (Telluride). */
917 };
918
919 static int sql_run_script(s3dl_db_thread *dbt, int number)
920 {
921 int s3e;
922
923 /* Script -1 == skip this step. */
924 if (number < 0)
925 return SQLITE_OK;
926
927 /* If we are attempting to run a script we don't have, fail. */
928 if ((size_t)number >= sizeof(s3dl_upgrade_sql) / sizeof(*s3dl_upgrade_sql))
929 return SQLITE_CORRUPT;
930
931 char *errmsg = NULL;
932 s3e = sqlite3_exec(dbt->s3_handle, s3dl_upgrade_sql[number],
933 NULL, NULL, &errmsg);
934 if (errmsg) {
935 secwarning("script %d: %s", number, errmsg);
936 sqlite3_free(errmsg);
937 }
938
939 return s3e;
940 }
941
942
943 static int s3dl_dbt_upgrade_from_version(s3dl_db_thread *dbt, int version)
944 {
945 /* We need to go from db version to CURRENT_DB_VERSION, let's do so. */
946 int s3e;
947
948 /* If we are attempting to upgrade to a version greater than what we have
949 an upgrade script for, fail. */
950 if (version < 0 ||
951 (size_t)version >= sizeof(s3dl_upgrade_script) / sizeof(*s3dl_upgrade_script))
952 return SQLITE_CORRUPT;
953
954 struct sql_stages *script = &s3dl_upgrade_script[version];
955 s3e = sql_run_script(dbt, script->pre);
956 if (s3e == SQLITE_OK)
957 s3e = sql_run_script(dbt, script->main);
958 if (s3e == SQLITE_OK)
959 s3e = sql_run_script(dbt, script->post);
960 if (script->init_pdmn) {
961 OSStatus status = s3e;
962 /* version 3 and earlier used legacy blob. */
963 CFDictionaryRef backup = SecServerExportKeychainPlist(dbt,
964 version < 4 ? KEYBAG_LEGACY : KEYBAG_DEVICE,
965 KEYBAG_NONE, kSecNoItemFilter, version, &status);
966 if (backup) {
967 if (status) {
968 secerror("Ignoring export error: %d during upgrade", status);
969 }
970 status = SecServerImportKeychainInPlist(dbt, KEYBAG_NONE,
971 KEYBAG_DEVICE, backup, kSecNoItemFilter);
972 CFRelease(backup);
973 } else if (status == errSecInteractionNotAllowed){
974 status = errSecUpgradePending;
975 }
976 s3e = status;
977 }
978
979 return s3e;
980 }
981
982 static int s3dl_dbt_create_or_upgrade(s3dl_db_thread *dbt)
983 {
984 sqlite3_stmt *stmt = NULL;
985 int s3e;
986
987 /* Find out if we need to upgrade from version 0 (empty db) or version 1
988 -- the db schema before we had a tversion table. */
989 s3e = sqlite3_prepare(dbt->s3_handle, "SELECT cdat FROM genp", -1, &stmt, NULL);
990 if (stmt)
991 sqlite3_finalize(stmt);
992
993 return s3dl_dbt_upgrade_from_version(dbt, s3e ? 0 : 1);
994 }
995
996 /* Return the current database version in *version. Returns a
997 SQLITE error. */
998 static int s3dl_dbt_get_version(s3dl_db_thread *dbt, int *version)
999 {
1000 sqlite3 *s3h = dbt->s3_handle;
1001 int s3e;
1002
1003 sqlite3_stmt *stmt = NULL;
1004 static const char sql[] = "SELECT version FROM tversion LIMIT 1;";
1005 s3e = sqlite3_prepare(s3h, sql, sizeof(sql) - 1, &stmt, NULL);
1006 if (s3e)
1007 goto errOut;
1008
1009 s3e = sqlite3_step(stmt);
1010 if (s3e == SQLITE_ROW) {
1011 *version = sqlite3_column_int(stmt, 0);
1012 s3e = SQLITE_OK;
1013 } else if (s3e) {
1014 secwarning("SELECT version step: %s", sqlite3_errmsg(s3h));
1015 } else {
1016 /* We have a VERSION table but we didn't find a version
1017 value now what? I suppose we pretend the db is corrupted
1018 since this isn't supposed to ever happen. */
1019 s3e = SQLITE_CORRUPT;
1020 }
1021
1022 errOut:
1023 if (stmt) {
1024 /* We ignore this error since this function may return SQLITE_ERROR,
1025 SQLITE_IOERR_READ or SQLITE_ABORT if the stmt itself failed, but
1026 that's something we would have handeled already. */
1027 sqlite3_finalize(stmt);
1028 }
1029
1030 return s3e;
1031 }
1032
1033 /* This function is called if the db doesn't have the proper version. We
1034 start an exclusive transaction and recheck the version, and then perform
1035 the upgrade within that transaction. */
1036 static int s3dl_dbt_upgrade(s3dl_db_thread *dbt)
1037 {
1038 int version;
1039 int s3e;
1040
1041 require_noerr(s3e = s3dl_begin_transaction(dbt), errOut);
1042 s3e = s3dl_dbt_get_version(dbt, &version);
1043 if (!s3e) {
1044 s3e = s3dl_dbt_upgrade_from_version(dbt, version);
1045 } else {
1046 /* We have no version table yet so we need to create a new db or
1047 upgrade from version 1 (the db schema without a tversion table). */
1048 require_noerr(s3e = s3dl_dbt_create_or_upgrade(dbt), errOut);
1049 }
1050
1051 errOut:
1052
1053 return s3dl_end_transaction(dbt, s3e);
1054 }
1055
1056 static int s3dl_create_dbt(s3dl_db *db, s3dl_db_thread **pdbt, int create)
1057 {
1058 sqlite3 *s3h;
1059 int retries, s3e;
1060 for (retries = 0; retries < 2; ++retries) {
1061 s3e = sqlite3_open(db->db_name, &s3h);
1062 if (s3e == SQLITE_CANTOPEN && create)
1063 {
1064 /* Make sure the path to db->db_name exists and is writable, then
1065 try again. */
1066 s3dl_create_path(db->db_name);
1067 s3e = sqlite3_open(db->db_name, &s3h);
1068 }
1069
1070 if (!s3e) {
1071 s3dl_db_thread *dbt = (s3dl_db_thread *)malloc(sizeof(s3dl_db_thread));
1072 dbt->dbt_next = NULL;
1073 dbt->db = db;
1074 dbt->s3_handle = s3h;
1075 dbt->autocommit = true;
1076 dbt->in_transaction = false;
1077
1078 int version;
1079 s3e = s3dl_dbt_get_version(dbt, &version);
1080 if (s3e == SQLITE_EMPTY || s3e == SQLITE_ERROR || (!s3e && version < CURRENT_DB_VERSION)) {
1081 s3e = s3dl_dbt_upgrade(dbt);
1082 if (s3e) {
1083 asl_log(NULL, NULL, ASL_LEVEL_CRIT,
1084 "failed to upgrade keychain %s: %d", db->db_name, s3e);
1085 if (s3e != errSecUpgradePending) {
1086 s3e = SQLITE_CORRUPT;
1087 }
1088 }
1089 } else if (s3e) {
1090 asl_log(NULL, NULL, ASL_LEVEL_ERR,
1091 "failed to obtain database version for %s: %d",
1092 db->db_name, s3e);
1093 } else if (version > CURRENT_DB_VERSION) {
1094 /* We can't downgrade so we treat a too new db as corrupted. */
1095 asl_log(NULL, NULL, ASL_LEVEL_ERR,
1096 "found keychain %s with version: %d which is newer than %d marking as corrupted",
1097 db->db_name, version, CURRENT_DB_VERSION);
1098 s3e = SQLITE_CORRUPT;
1099 }
1100
1101 if (s3e) {
1102 s3dl_close_dbt(dbt);
1103 } else {
1104 *pdbt = dbt;
1105 break;
1106 }
1107 }
1108
1109 if (s3e == SQLITE_CORRUPT || s3e == SQLITE_NOTADB ||
1110 s3e == SQLITE_CANTOPEN || s3e == SQLITE_PERM ||
1111 s3e == SQLITE_CONSTRAINT) {
1112 size_t len = strlen(db->db_name);
1113 char *old_db_name = malloc(len + 9);
1114 memcpy(old_db_name, db->db_name, len);
1115 strcpy(old_db_name + len, ".corrupt");
1116 if (rename(db->db_name, old_db_name)) {
1117 asl_log(NULL, NULL, ASL_LEVEL_CRIT,
1118 "unable to rename corrupt keychain %s -> %s: %s",
1119 db->db_name, old_db_name, strerror(errno));
1120 free(old_db_name);
1121 break;
1122 } else {
1123 asl_log(NULL, NULL, ASL_LEVEL_ERR,
1124 "renamed corrupt keychain %s -> %s (%d)",
1125 db->db_name, old_db_name, s3e);
1126 }
1127 free(old_db_name);
1128 } else if (s3e) {
1129 asl_log(NULL, NULL, ASL_LEVEL_CRIT,
1130 "failed to open keychain %s: %d", db->db_name, s3e);
1131 break;
1132 }
1133 }
1134
1135 return s3e;
1136 }
1137
1138 /* Called when a thread that was using this db goes away. */
1139 static void s3dl_dbt_destructor(void *data)
1140 {
1141 s3dl_db_thread *dbt = (s3dl_db_thread *)data;
1142 int found = 0;
1143
1144 /* Remove the passed in dbt from the linked list. */
1145 /* TODO: Log pthread errors. */
1146 pthread_mutex_lock(&dbt->db->mutex);
1147 s3dl_db_thread **pdbt = &dbt->db->dbt_head;
1148 for (;*pdbt; pdbt = &(*pdbt)->dbt_next)
1149 {
1150 if (*pdbt == dbt)
1151 {
1152 *pdbt = dbt->dbt_next;
1153 found = 1;
1154 break;
1155 }
1156 }
1157 /* TODO: Log pthread errors. */
1158 pthread_mutex_unlock(&dbt->db->mutex);
1159
1160 /* Don't hold dbt->db->mutex while cleaning up the dbt. */
1161 if (found)
1162 s3dl_close_dbt(dbt);
1163 }
1164
1165 /* Agressivly write to pdbHandle since we want to be able to call internal SPI
1166 function during initialization. */
1167 static int s3dl_create_db_handle(const char *db_name, db_handle *pdbHandle,
1168 s3dl_db_thread **pdbt, bool autocommit, bool create, bool use_hwaes)
1169 {
1170 void *mem = malloc(sizeof(s3dl_db) + strlen(db_name) + 1);
1171 s3dl_db *db = (s3dl_db *)mem;
1172 db->db_name = ((char *)mem) + sizeof(*db);
1173 strcpy(db->db_name, db_name);
1174 /* Make sure we set this before calling s3dl_create_dbt, since that might
1175 trigger a db upgrade which needs to decrypt stuff. */
1176 db->use_hwaes = use_hwaes;
1177
1178 s3dl_db_thread *dbt;
1179 int s3e = s3dl_create_dbt(db, &dbt, create);
1180 if (s3e != SQLITE_OK)
1181 {
1182 if (s3e == errSecUpgradePending) {
1183 secerror("Device locked during initial open + upgrade attempt");
1184 dbt = NULL;
1185 } else {
1186 free(mem);
1187 return s3e;
1188 }
1189 } else {
1190 dbt->autocommit = autocommit;
1191 }
1192 db->dbt_head = dbt;
1193
1194 int err = pthread_key_create(&db->key, s3dl_dbt_destructor);
1195 if (!err)
1196 err = pthread_mutex_init(&db->mutex, NULL);
1197 if (!err && dbt)
1198 err = pthread_setspecific(db->key, dbt);
1199 if (err)
1200 {
1201 /* TODO: Log err (which is an errno) somehow. */
1202 if (dbt)
1203 s3e = s3dl_close_dbt(dbt);
1204 if (s3e == SQLITE_OK)
1205 s3e = SQLITE_INTERNAL;
1206
1207 free(mem);
1208 } else {
1209 if (pdbt)
1210 *pdbt = dbt;
1211
1212 *pdbHandle = (db_handle)db;
1213 }
1214
1215 return s3e;
1216 }
1217
1218 static int s3dl_close_db_handle(db_handle dbHandle)
1219 {
1220 s3dl_db *db = (s3dl_db *)dbHandle;
1221 int s3e = SQLITE_OK;
1222
1223 /* Walk the list of dbt's and close them all. */
1224 s3dl_db_thread *next_dbt = db->dbt_head;
1225 while (next_dbt)
1226 {
1227 s3dl_db_thread *dbt = next_dbt;
1228 next_dbt = next_dbt->dbt_next;
1229 int s3e2 = s3dl_close_dbt(dbt);
1230 if (s3e2 != SQLITE_OK && s3e == SQLITE_OK)
1231 s3e = s3e2;
1232 }
1233
1234 pthread_key_delete(db->key);
1235 free(db);
1236
1237 return s3e;
1238 }
1239
1240 static int s3dl_get_dbt(db_handle dbHandle, s3dl_db_thread **pdbt)
1241 {
1242 if (!dbHandle)
1243 return SQLITE_ERROR;
1244
1245 s3dl_db *db = (s3dl_db *)dbHandle;
1246 int s3e = SQLITE_OK;
1247 s3dl_db_thread *dbt = pthread_getspecific(db->key);
1248 if (!dbt)
1249 {
1250 /* We had no dbt yet, so create a new one, but don't create the
1251 database. */
1252 s3e = s3dl_create_dbt(db, &dbt, false);
1253 if (s3e == SQLITE_OK)
1254 {
1255 /* Lock the mutex, insert the new entry at the head of the
1256 linked list and release the lock. */
1257 int err = pthread_mutex_lock(&db->mutex);
1258 if (!err)
1259 {
1260 dbt->dbt_next = db->dbt_head;
1261 db->dbt_head = dbt;
1262 err = pthread_mutex_unlock(&db->mutex);
1263 }
1264
1265 /* Set the dbt as this threads dbt for db. */
1266 if (!err)
1267 err = pthread_setspecific(db->key, dbt);
1268 if (err)
1269 {
1270 /* TODO: Log err (which is an errno) somehow. */
1271 s3e = s3dl_close_dbt(dbt);
1272 if (s3e == SQLITE_OK)
1273 s3e = SQLITE_INTERNAL;
1274 }
1275 }
1276 }
1277 *pdbt = dbt;
1278 return s3e;
1279 }
1280
1281 /* Return an OSStatus for a sqlite3 error code. */
1282 static OSStatus osstatus_for_s3e(int s3e)
1283 {
1284 if (s3e > 0 && s3e <= SQLITE_DONE) switch (s3e)
1285 {
1286 case SQLITE_OK:
1287 return 0;
1288 case SQLITE_ERROR:
1289 return errSecNotAvailable; /* errSecDuplicateItem; */
1290 case SQLITE_FULL: /* Happens if we run out of uniqueids */
1291 return errSecNotAvailable; /* TODO: Replace with a better error code. */
1292 case SQLITE_PERM:
1293 case SQLITE_READONLY:
1294 return errSecNotAvailable;
1295 case SQLITE_CANTOPEN:
1296 return errSecNotAvailable;
1297 case SQLITE_EMPTY:
1298 return errSecNotAvailable;
1299 case SQLITE_CONSTRAINT:
1300 return errSecDuplicateItem;
1301 case SQLITE_ABORT:
1302 return -1;
1303 case SQLITE_MISMATCH:
1304 return errSecNoSuchAttr;
1305 case SQLITE_AUTH:
1306 return errSecNotAvailable;
1307 case SQLITE_NOMEM:
1308 return -2; /* TODO: Replace with a real error code. */
1309 case SQLITE_INTERNAL:
1310 default:
1311 return errSecNotAvailable; /* TODO: Replace with a real error code. */
1312 }
1313 return s3e;
1314 }
1315
1316 const uint32_t v0KeyWrapOverHead = 8;
1317
1318 /* Wrap takes a 128 - 256 bit key as input and returns output of
1319 inputsize + 64 bits.
1320 In bytes this means that a
1321 16 byte (128 bit) key returns a 24 byte wrapped key
1322 24 byte (192 bit) key returns a 32 byte wrapped key
1323 32 byte (256 bit) key returns a 40 byte wrapped key */
1324 static int ks_crypt(uint32_t selector, keybag_handle_t keybag,
1325 keyclass_t keyclass, uint32_t textLength, const uint8_t *source, uint8_t *dest, size_t *dest_len) {
1326 #if USE_KEYSTORE
1327 kern_return_t kernResult;
1328
1329 if (keystore == MACH_PORT_NULL) {
1330 asl_log(NULL, NULL, ASL_LEVEL_ERR, "No AppleKeyStore connection");
1331 return errSecNotAvailable;
1332 }
1333
1334 uint64_t inputs[] = { keybag, keyclass };
1335 uint32_t num_inputs = sizeof(inputs)/sizeof(*inputs);
1336 kernResult = IOConnectCallMethod(keystore, selector, inputs,
1337 num_inputs, source, textLength, NULL, NULL, dest, dest_len);
1338
1339 if (kernResult != KERN_SUCCESS) {
1340 if (kernResult == kIOReturnNotPermitted) {
1341 /* Access to item attempted while keychain is locked. */
1342 asl_log(NULL, NULL, ASL_LEVEL_INFO,
1343 "%s sel: %d bag: %d cls: %d src: %p len: %"PRIu32" err: kIOReturnNotPermitted",
1344 (selector == kAppleKeyStoreKeyWrap ? "kAppleKeyStoreKeyWrap"
1345 : "kAppleKeyStoreKeyUnwrap"),
1346 selector, keybag, keyclass, source, textLength);
1347 return errSecInteractionNotAllowed;
1348 } else if (kernResult == kIOReturnError) {
1349 /* Item can't be decrypted on this device, ever, so drop the item. */
1350 secerror("%s sel: %d bag: %d cls: %d src: %p len: %lu err: kIOReturnError",
1351 (selector == kAppleKeyStoreKeyWrap ? "kAppleKeyStoreKeyWrap"
1352 : "kAppleKeyStoreKeyUnwrap"),
1353 selector, keybag, keyclass, source, textLength);
1354 return errSecDecode;
1355 } else {
1356 secerror("%s sel: %d bag: %d cls: %d src: %p len: %lu err: %x",
1357 (selector == kAppleKeyStoreKeyWrap ? "kAppleKeyStoreKeyWrap"
1358 : "kAppleKeyStoreKeyUnwrap"),
1359 selector, keybag, keyclass, source, textLength, kernResult);
1360 return errSecNotAvailable;
1361 }
1362 }
1363 return errSecSuccess;
1364 #else
1365 if (selector == kAppleKeyStoreKeyWrap) {
1366 /* The no encryption case. */
1367 if (*dest_len >= textLength + 8) {
1368 memcpy(dest, source, textLength);
1369 memset(dest + textLength, 8, 8);
1370 *dest_len = textLength + 8;
1371 } else
1372 return errSecNotAvailable;
1373 } else if (selector == kAppleKeyStoreKeyUnwrap) {
1374 if (*dest_len + 8 >= textLength) {
1375 memcpy(dest, source, textLength - 8);
1376 *dest_len = textLength - 8;
1377 } else
1378 return errSecNotAvailable;
1379 }
1380 return errSecSuccess;
1381 #endif
1382 }
1383
1384 #if 0
1385
1386 typedef struct kc_item {
1387 CFMutableDictionaryRef item;
1388 CFIndex n_attrs;
1389 CFStringRef *attrs;
1390 void *values[];
1391 } kc_item;
1392
1393 #define kc_item_size(n) sizeof(kc_item) + 2 * sizeof(void *)
1394 #define kc_item_init(i, n) do { \
1395 kc_item *_kc_item_a = (i); \
1396 _kc_item_a->item = NULL; \
1397 _kc_item_a->n_attrs = (n); \
1398 _kc_item_a->attrs = (CFStringRef *)&_kc_item_a->values[_kc_item_a->n_attrs]; \
1399 } while(0)
1400
1401 static kc_item *kc_item_create(CFIndex n_attrs) {
1402 kc_item *item = malloc(kc_item_size(n_attrs));
1403 kc_item_init(item, n_attrs);
1404 return item;
1405 }
1406
1407 static void kc_item_destroy(kc_item *item) {
1408 CFReleaseSafe(item->item);
1409 free(item);
1410 }
1411
1412 static kc_item *kc_item_init_with_data() {
1413
1414 }
1415
1416 /* Encodes an item. */
1417 static CFDataRef kc_item_encode(const kc_item *item) {
1418 CFDictionaryRef attrs = CFDictionaryCreate(0, (const void **)item->attrs,
1419 (const void **)item->values,
1420 item->n_attrs, 0, 0);
1421 CFDataRef encoded = CFPropertyListCreateData(0, attrs,
1422 kCFPropertyListBinaryFormat_v1_0, 0, 0);
1423 CFRelease(attrs);
1424 return encoded;
1425 }
1426
1427 struct kc_item_set_attr {
1428 CFIndex ix;
1429 kc_item *item;
1430 OSStatus error;
1431 };
1432
1433 static void kc_item_set_attr(CFStringRef key, void *value,
1434 void *context) {
1435 struct kc_item_set_attr *c = context;
1436 if (CFGetTypeID(key) != CFStringGetTypeID()) {
1437 c->error = 1;
1438 return;
1439 }
1440 c->item->attrs[c->ix] = key;
1441 c->item->values[c->ix++] = value;
1442 }
1443
1444 /* Returns a malloced item. */
1445 static CFDictionaryRef kc_item_decode(CFDataRef encoded_item) {
1446 CFPropertyListFormat format;
1447 CFPropertyListRef attrs;
1448 attrs = CFPropertyListCreateWithData(0, encoded_item,
1449 kCFPropertyListImmutable, &format, 0);
1450 if (!attrs)
1451 return NULL;
1452
1453 kc_item *item = NULL;
1454 if (CFGetTypeID(attrs) != CFDictionaryGetTypeID())
1455 goto errOut;
1456
1457 item = kc_item_create(CFDictionaryGetCount(attrs));
1458 int failed = 0;
1459 CFDictionaryApplyFunction(attrs,
1460 (CFDictionaryApplierFunction)kc_item_set_attr,
1461 &failed);
1462
1463 errOut:
1464 #if 0
1465 CFRelease(attrs);
1466 return item;
1467 #else
1468 kc_item_destroy(item);
1469 return attrs;
1470 #endif
1471 }
1472
1473 #endif
1474
1475 /* Given plainText create and return a CFDataRef containing:
1476 BULK_KEY = RandomKey()
1477 version || keyclass || KeyStore_WRAP(keyclass, BULK_KEY) ||
1478 AES(BULK_KEY, NULL_IV, plainText || padding)
1479 */
1480 static int ks_encrypt_data(keybag_handle_t keybag,
1481 keyclass_t keyclass, CFDataRef plainText, CFDataRef *pBlob) {
1482 CFMutableDataRef blob = NULL;
1483 //check(keybag >= 0);
1484
1485 /* Precalculate output blob length. */
1486 const uint32_t bulkKeySize = 32; /* Use 256 bit AES key for bulkKey. */
1487 const uint32_t maxKeyWrapOverHead = 8 + 32;
1488 uint8_t bulkKey[bulkKeySize];
1489 uint8_t bulkKeyWrapped[bulkKeySize + maxKeyWrapOverHead];
1490 size_t bulkKeyWrappedSize = sizeof(bulkKeyWrapped);
1491 uint32_t key_wrapped_size;
1492
1493 /* TODO: We should return a better error here. */
1494 int s3e = errSecAllocate;
1495 if (!plainText || CFGetTypeID(plainText) != CFDataGetTypeID()
1496 || keyclass == 0) {
1497 s3e = errSecParam;
1498 goto out;
1499 }
1500
1501 size_t ptLen = CFDataGetLength(plainText);
1502 size_t ctLen = ptLen;
1503 size_t tagLen = 16;
1504 uint32_t version = 2;
1505
1506 if (SecRandomCopyBytes(kSecRandomDefault, bulkKeySize, bulkKey))
1507 goto out;
1508
1509 /* Now that we're done using the bulkKey, in place encrypt it. */
1510 require_noerr_quiet(s3e = ks_crypt(kAppleKeyStoreKeyWrap, keybag, keyclass,
1511 bulkKeySize, bulkKey, bulkKeyWrapped,
1512 &bulkKeyWrappedSize), out);
1513 key_wrapped_size = (uint32_t)bulkKeyWrappedSize;
1514
1515 size_t blobLen = sizeof(version) + sizeof(keyclass) +
1516 sizeof(key_wrapped_size) + key_wrapped_size + ctLen + tagLen;
1517
1518 require_quiet(blob = CFDataCreateMutable(NULL, blobLen), out);
1519 CFDataSetLength(blob, blobLen);
1520 UInt8 *cursor = CFDataGetMutableBytePtr(blob);
1521
1522 *((uint32_t *)cursor) = version;
1523 cursor += sizeof(version);
1524
1525 *((keyclass_t *)cursor) = keyclass;
1526 cursor += sizeof(keyclass);
1527
1528 *((uint32_t *)cursor) = key_wrapped_size;
1529 cursor += sizeof(key_wrapped_size);
1530
1531 memcpy(cursor, bulkKeyWrapped, key_wrapped_size);
1532 cursor += key_wrapped_size;
1533
1534 /* Encrypt the plainText with the bulkKey. */
1535 CCCryptorStatus ccerr = CCCryptorGCM(kCCEncrypt, kCCAlgorithmAES128,
1536 bulkKey, bulkKeySize,
1537 NULL, 0, /* iv */
1538 NULL, 0, /* auth data */
1539 CFDataGetBytePtr(plainText), ptLen,
1540 cursor,
1541 cursor + ctLen, &tagLen);
1542 if (ccerr) {
1543 asl_log(NULL, NULL, ASL_LEVEL_ERR, "CCCryptorGCM failed: %d", ccerr);
1544 s3e = errSecInternal;
1545 goto out;
1546 }
1547 if (tagLen != 16) {
1548 asl_log(NULL, NULL, ASL_LEVEL_ERR,
1549 "CCCryptorGCM expected: 16 got: %ld byte tag", tagLen);
1550 s3e = errSecInternal;
1551 goto out;
1552 }
1553
1554 out:
1555 memset(bulkKey, 0, sizeof(bulkKey));
1556 if (s3e) {
1557 CFReleaseSafe(blob);
1558 } else {
1559 *pBlob = blob;
1560 }
1561 return s3e;
1562 }
1563
1564 /* Given cipherText containing:
1565 version || keyclass || KeyStore_WRAP(keyclass, BULK_KEY) ||
1566 AES(BULK_KEY, NULL_IV, plainText || padding)
1567 return the plainText. */
1568 static int ks_decrypt_data(keybag_handle_t keybag,
1569 keyclass_t *pkeyclass, CFDataRef blob, CFDataRef *pPlainText,
1570 uint32_t *version_p) {
1571 const uint32_t bulkKeySize = 32; /* Use 256 bit AES key for bulkKey. */
1572 uint8_t bulkKey[bulkKeySize];
1573 size_t bulkKeyCapacity = sizeof(bulkKey);
1574
1575 CFMutableDataRef plainText = NULL;
1576 check(keybag >= 0);
1577
1578 int s3e = errSecDecode;
1579 if (!blob) {
1580 /* TODO: We should return a better error here. */
1581 s3e = errSecParam;
1582 goto out;
1583 }
1584
1585 size_t blobLen = CFDataGetLength(blob);
1586 const uint8_t *cursor = CFDataGetBytePtr(blob);
1587 uint32_t version;
1588 keyclass_t keyclass;
1589 uint32_t wrapped_key_size;
1590
1591 /* Check for underflow, ensuring we have at least one full AES block left. */
1592 if (blobLen < sizeof(version) + sizeof(keyclass) +
1593 bulkKeySize + v0KeyWrapOverHead + 16)
1594 goto out;
1595
1596 version = *((uint32_t *)cursor);
1597 cursor += sizeof(version);
1598
1599 keyclass = *((keyclass_t *)cursor);
1600 if (pkeyclass)
1601 *pkeyclass = keyclass;
1602 cursor += sizeof(keyclass);
1603
1604 size_t minimum_blob_len = sizeof(version) + sizeof(keyclass) + 16;
1605 size_t ctLen = blobLen - sizeof(version) - sizeof(keyclass);
1606 size_t tagLen = 0;
1607 switch (version) {
1608 case 0:
1609 wrapped_key_size = bulkKeySize + v0KeyWrapOverHead;
1610 break;
1611 case 2:
1612 tagLen = 16;
1613 minimum_blob_len -= 16; // Remove PKCS7 padding block requirement
1614 ctLen -= tagLen; // Remove tagLen from ctLen
1615 /* DROPTHROUGH */
1616 case 1:
1617 wrapped_key_size = *((uint32_t *)cursor);
1618 cursor += sizeof(wrapped_key_size);
1619 minimum_blob_len += sizeof(wrapped_key_size);
1620 ctLen -= sizeof(wrapped_key_size);
1621 break;
1622 default:
1623 goto out;
1624 }
1625
1626 /* Validate key wrap length against total length */
1627 require(blobLen - minimum_blob_len - tagLen >= wrapped_key_size, out);
1628 ctLen -= wrapped_key_size;
1629 if (version < 2 && (ctLen & 0xF) != 0)
1630 goto out;
1631
1632 /* Now unwrap the bulk key using a key in the keybag. */
1633 require_noerr_quiet(s3e = ks_crypt(kAppleKeyStoreKeyUnwrap, keybag,
1634 keyclass, wrapped_key_size, cursor, bulkKey, &bulkKeyCapacity), out);
1635 cursor += wrapped_key_size;
1636
1637 plainText = CFDataCreateMutable(NULL, ctLen);
1638 if (!plainText)
1639 goto out;
1640 CFDataSetLength(plainText, ctLen);
1641
1642 /* Decrypt the cipherText with the bulkKey. */
1643 CCCryptorStatus ccerr;
1644 if (tagLen) {
1645 uint8_t tag[tagLen];
1646 ccerr = CCCryptorGCM(kCCDecrypt, kCCAlgorithmAES128,
1647 bulkKey, bulkKeySize,
1648 NULL, 0, /* iv */
1649 NULL, 0, /* auth data */
1650 cursor, ctLen,
1651 CFDataGetMutableBytePtr(plainText),
1652 tag, &tagLen);
1653 if (ccerr) {
1654 secerror("CCCryptorGCM failed: %d", ccerr);
1655 /* TODO: Should this be errSecDecode once AppleKeyStore correctly
1656 identifies uuid unwrap failures? */
1657 s3e = errSecDecode; /* errSecInteractionNotAllowed; */
1658 goto out;
1659 }
1660 if (tagLen != 16) {
1661 secerror("CCCryptorGCM expected: 16 got: %ld byte tag", tagLen);
1662 s3e = errSecInternal;
1663 goto out;
1664 }
1665 cursor += ctLen;
1666 if (memcmp(tag, cursor, tagLen)) {
1667 secerror("CCCryptorGCM computed tag not same as tag in blob");
1668 s3e = errSecDecode;
1669 goto out;
1670 }
1671 } else {
1672 size_t ptLen;
1673 ccerr = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
1674 bulkKey, bulkKeySize, NULL, cursor, ctLen,
1675 CFDataGetMutableBytePtr(plainText), ctLen, &ptLen);
1676 if (ccerr) {
1677 secerror("CCCrypt failed: %d", ccerr);
1678 /* TODO: Should this be errSecDecode once AppleKeyStore correctly
1679 identifies uuid unwrap failures? */
1680 s3e = errSecDecode; /* errSecInteractionNotAllowed; */
1681 goto out;
1682 }
1683 CFDataSetLength(plainText, ptLen);
1684 }
1685 s3e = errSecSuccess;
1686 if (version_p) *version_p = version;
1687 out:
1688 memset(bulkKey, 0, bulkKeySize);
1689 if (s3e) {
1690 CFReleaseSafe(plainText);
1691 } else {
1692 *pPlainText = plainText;
1693 }
1694 return s3e;
1695 }
1696
1697 /* Iff dir_encrypt is true dir_encrypt source -> dest, otherwise decrypt
1698 source -> dest. In both cases iv is used asa the Initialization Vector and
1699 textLength bytes are encrypted or decrypted. TextLength must be a multiple
1700 of 16, since this function does not do any padding. */
1701 static bool kc_aes_crypt(s3dl_db_thread *dbt, bool dir_encrypt, const UInt8 *iv,
1702 UInt32 textLength, const UInt8 *source, UInt8 *dest) {
1703 #if USE_HWAES
1704 if (dbt->db->use_hwaes) {
1705 IOAESOperation operation;
1706 UInt8 *plainText;
1707 UInt8 *cipherText;
1708
1709 if (dir_encrypt) {
1710 operation = IOAESOperationEncrypt;
1711 plainText = (UInt8 *)source;
1712 cipherText = dest;
1713 } else {
1714 operation = IOAESOperationDecrypt;
1715 plainText = dest;
1716 cipherText = (UInt8 *)source;
1717 }
1718
1719 return hwaes_crypt(operation,
1720 kIOAESAcceleratorKeyHandleKeychain, 128, NULL, iv, textLength,
1721 plainText, cipherText);
1722 }
1723 else
1724 #endif /* USE_HWAES */
1725 {
1726 /* The no encryption case. */
1727 memcpy(dest, source, textLength);
1728 return true;
1729 }
1730 }
1731
1732 #if 0
1733 /* Pre 4.0 blob encryption code, unused when keystore support is enabled. */
1734
1735 /* Given plainText create and return a CFDataRef containing:
1736 IV || AES(KC_KEY, IV, plainText || SHA1(plainText) || padding)
1737 */
1738 static int kc_encrypt_data(s3dl_db_thread *dbt, CFDataRef plainText,
1739 CFDataRef *pCipherText) {
1740 CFMutableDataRef cipherText = NULL;
1741 /* TODO: We should return a better error here. */
1742 int s3e = SQLITE_AUTH;
1743 if (!plainText || CFGetTypeID(plainText) != CFDataGetTypeID()) {
1744 s3e = SQLITE_MISMATCH;
1745 goto out;
1746 }
1747
1748 CFIndex ptLen = CFDataGetLength(plainText);
1749 CFIndex ctLen = ptLen + CC_SHA1_DIGEST_LENGTH;
1750 CFIndex padLen = 16 - (ctLen & 15);
1751 /* Pad output buffer capacity to nearest multiple of 32 bytes for cache
1752 coherency. */
1753 CFIndex paddedTotalLength = (16 + ctLen + padLen + 0x1F) & ~0x1F;
1754 cipherText = CFDataCreateMutable(NULL, paddedTotalLength);
1755 if (!cipherText)
1756 goto out;
1757 CFDataSetLength(cipherText, 16 + ctLen + padLen);
1758 UInt8 *iv = CFDataGetMutableBytePtr(cipherText);
1759 if (SecRandomCopyBytes(kSecRandomDefault, 16, iv))
1760 goto out;
1761
1762 UInt8 *ct = iv + 16;
1763 const UInt8 *pt = CFDataGetBytePtr(plainText);
1764 memcpy(ct, pt, ptLen);
1765 CC_SHA1(pt, ptLen, ct + ptLen);
1766 memset(ct + ctLen, padLen, padLen);
1767
1768 /* Encrypt the data in place. */
1769 if (!kc_aes_crypt(dbt, true, iv, ctLen + padLen, ct, ct)) {
1770 goto out;
1771 }
1772
1773 s3e = SQLITE_OK;
1774 out:
1775 if (s3e) {
1776 CFReleaseSafe(cipherText);
1777 } else {
1778 *pCipherText = cipherText;
1779 }
1780 return s3e;
1781 }
1782 #endif
1783
1784 /* Given cipherText containing:
1785 IV || AES(KC_KEY, IV, plainText || SHA1(plainText) || padding)
1786 return the plainText. */
1787 static int kc_decrypt_data(s3dl_db_thread *dbt, CFDataRef cipherText,
1788 CFDataRef *pPlainText) {
1789 CFMutableDataRef plainText = NULL;
1790 /* TODO: We should return a better error here. */
1791 int s3e = SQLITE_AUTH;
1792 if (!cipherText)
1793 goto out;
1794
1795 CFIndex ctLen = CFDataGetLength(cipherText);
1796 if (ctLen < 48 || (ctLen & 0xF) != 0)
1797 goto out;
1798
1799 const UInt8 *iv = CFDataGetBytePtr(cipherText);
1800 const UInt8 *ct = iv + 16;
1801 CFIndex ptLen = ctLen - 16;
1802
1803 /* Cast: debug check for overflow before casting to uint32_t later */
1804 assert((unsigned long)ptLen<UINT32_MAX); /* correct as long as CFIndex is signed long */
1805
1806 /* Pad output buffer capacity to nearest multiple of 32 bytes for cache
1807 coherency. */
1808 CFIndex paddedLength = (ptLen + 0x1F) & ~0x1F;
1809 plainText = CFDataCreateMutable(NULL, paddedLength);
1810 if (!plainText)
1811 goto out;
1812 CFDataSetLength(plainText, ptLen);
1813 UInt8 *pt = CFDataGetMutableBytePtr(plainText);
1814
1815 /* 64 bits case: Worst case here is we dont decrypt the full data. No security issue */
1816 if (!kc_aes_crypt(dbt, false, iv, (uint32_t)ptLen, ct, pt)) {
1817 goto out;
1818 }
1819
1820 /* Now check and remove the padding. */
1821 UInt8 pad = pt[ptLen - 1];
1822 if (pad < 1 || pad > 16) {
1823 asl_log(NULL, NULL, ASL_LEVEL_ERR,
1824 "kc_decrypt_data: bad padding bytecount: 0x%02X", pad);
1825 goto out;
1826 }
1827 CFIndex ix;
1828 ptLen -= pad;
1829 for (ix = 0; ix < pad - 1; ++ix) {
1830 if (pt[ptLen + ix] != pad) {
1831 asl_log(NULL, NULL, ASL_LEVEL_ERR,
1832 "kc_decrypt_data: bad padding byte: %lu: 0x%02X",
1833 ix, pt[ptLen + ix]);
1834 goto out;
1835 }
1836 }
1837
1838 UInt8 sha1[CC_SHA1_DIGEST_LENGTH];
1839 ptLen -= CC_SHA1_DIGEST_LENGTH;
1840 /* 64 bits cast: worst case here is we dont hash the full data and the decrypt fail or
1841 suceed when it should not have. No security issue. */
1842 CC_SHA1(pt, (CC_LONG)ptLen, sha1);
1843 if (memcmp(sha1, pt + ptLen, CC_SHA1_DIGEST_LENGTH)) {
1844 asl_log(NULL, NULL, ASL_LEVEL_ERR, "kc_decrypt_data: digest mismatch");
1845 goto out;
1846 }
1847
1848 CFDataSetLength(plainText, ptLen);
1849
1850 s3e = SQLITE_OK;
1851 out:
1852 if (s3e) {
1853 CFReleaseSafe(plainText);
1854 } else {
1855 *pPlainText = plainText;
1856 }
1857 return s3e;
1858 }
1859
1860 /* AUDIT[securityd](done):
1861 value (ok) is a caller provided, non NULL CFTypeRef.
1862 */
1863 static int kc_bind_paramter(sqlite3_stmt *stmt, int param, CFTypeRef value)
1864 {
1865 CFTypeID valueId;
1866 int s3e;
1867
1868 /* TODO: Can we use SQLITE_STATIC below everwhere we currently use
1869 SQLITE_TRANSIENT since we finalize the statement before the value
1870 goes out of scope? */
1871 if (!value || (valueId = CFGetTypeID(value)) == CFNullGetTypeID()) {
1872 /* Skip bindings for NULL values. sqlite3 will interpret unbound
1873 params as NULL which is exactly what we want. */
1874 #if 1
1875 s3e = SQLITE_OK;
1876 #else
1877 s3e = sqlite3_bind_null(stmt, param);
1878 #endif
1879 secdebug("bind", "bind_null: %d", s3e);
1880 } else if (valueId == CFStringGetTypeID()) {
1881 const char *cstr = CFStringGetCStringPtr(value, kCFStringEncodingUTF8);
1882 if (cstr) {
1883 s3e = sqlite3_bind_text_wrapper(stmt, param, cstr, strlen(cstr),
1884 SQLITE_TRANSIENT);
1885 secdebug("bind", "quick bind_text: %s: %d", cstr, s3e);
1886 } else {
1887 CFIndex len = 0;
1888 CFRange range = { 0, CFStringGetLength(value) };
1889 CFStringGetBytes(value, range, kCFStringEncodingUTF8,
1890 0, FALSE, NULL, 0, &len);
1891 {
1892 CFIndex usedlen = 0;
1893 char buf[len];
1894 CFStringGetBytes(value, range, kCFStringEncodingUTF8,
1895 0, FALSE, (UInt8 *)buf, len, &usedlen);
1896 s3e = sqlite3_bind_text_wrapper(stmt, param, buf, usedlen,
1897 SQLITE_TRANSIENT);
1898 secdebug("bind", "slow bind_text: %.*s: %d", usedlen, buf, s3e);
1899 }
1900 }
1901 } else if (valueId == CFDataGetTypeID()) {
1902 CFIndex len = CFDataGetLength(value);
1903 if (len) {
1904 s3e = sqlite3_bind_blob_wrapper(stmt, param, CFDataGetBytePtr(value),
1905 len, SQLITE_TRANSIENT);
1906 secdebug("bind", "bind_blob: %.*s: %d",
1907 CFDataGetLength(value), CFDataGetBytePtr(value), s3e);
1908 } else {
1909 s3e = sqlite3_bind_text(stmt, param, "", 0, SQLITE_TRANSIENT);
1910 }
1911 } else if (valueId == CFDateGetTypeID()) {
1912 CFAbsoluteTime abs_time = CFDateGetAbsoluteTime(value);
1913 s3e = sqlite3_bind_double(stmt, param, abs_time);
1914 secdebug("bind", "bind_double: %f: %d", abs_time, s3e);
1915 } else if (valueId == CFBooleanGetTypeID()) {
1916 int bval = CFBooleanGetValue(value);
1917 s3e = sqlite3_bind_int(stmt, param, bval);
1918 secdebug("bind", "bind_int: %d: %d", bval, s3e);
1919 } else if (valueId == CFNumberGetTypeID()) {
1920 Boolean convertOk;
1921 if (CFNumberIsFloatType(value)) {
1922 double nval;
1923 convertOk = CFNumberGetValue(value, kCFNumberDoubleType, &nval);
1924 s3e = sqlite3_bind_double(stmt, param, nval);
1925 secdebug("bind", "bind_double: %f: %d", nval, s3e);
1926 } else {
1927 CFIndex len = CFNumberGetByteSize(value);
1928 /* TODO: should sizeof int be 4? sqlite seems to think so. */
1929 if (len <= (CFIndex)sizeof(int)) {
1930 int nval;
1931 convertOk = CFNumberGetValue(value, kCFNumberIntType, &nval);
1932 s3e = sqlite3_bind_int(stmt, param, nval);
1933 secdebug("bind", "bind_int: %d: %d", nval, s3e);
1934 } else {
1935 sqlite_int64 nval;
1936 convertOk = CFNumberGetValue(value, kCFNumberLongLongType,
1937 &nval);
1938 s3e = sqlite3_bind_int64(stmt, param, nval);
1939 secdebug("bind", "bind_int64: %lld: %d", nval, s3e);
1940 }
1941 }
1942 if (!convertOk) {
1943 /* TODO: CFNumberGetValue failed somehow. */
1944 s3e = SQLITE_INTERNAL;
1945 }
1946 } else {
1947 /* Unsupported CF type used. */
1948 s3e = SQLITE_MISMATCH;
1949 }
1950
1951 return s3e;
1952 }
1953
1954 /* Compile the statement in sql and return it as stmt. */
1955 static int kc_prepare_statement(sqlite3 *s3h, CFStringRef sql,
1956 sqlite3_stmt **stmt)
1957 {
1958 int s3e;
1959 const char *cstr = CFStringGetCStringPtr(sql, kCFStringEncodingUTF8);
1960 if (cstr) {
1961 secdebug("sql", "quick prepare: %s", cstr);
1962 s3e = sqlite3_prepare_wrapper(s3h, cstr, strlen(cstr), stmt, NULL);
1963 } else {
1964 CFIndex len = 0;
1965 CFRange range = { 0, CFStringGetLength(sql) };
1966 CFStringGetBytes(sql, range, kCFStringEncodingUTF8,
1967 0, FALSE, NULL, 0, &len);
1968 {
1969 CFIndex usedlen = 0;
1970 char buf[len];
1971 CFStringGetBytes(sql, range, kCFStringEncodingUTF8,
1972 0, FALSE, (UInt8 *)buf, len, &usedlen);
1973 secdebug("sql", "slow prepare: %.*s", usedlen, buf);
1974 s3e = sqlite3_prepare_wrapper(s3h, buf, usedlen, stmt, NULL);
1975 }
1976 }
1977
1978 /* sqlite3_prepare returns SQLITE_ERROR if the table doesn't exist or one
1979 of the attributes the caller passed in doesn't exist. */
1980 if (s3e == SQLITE_ERROR) {
1981 secdebug("sql", "sqlite3_prepare: %s", sqlite3_errmsg(s3h));
1982 s3e = errSecParam;
1983 }
1984
1985 return s3e;
1986 }
1987
1988 /* Return types. */
1989 typedef uint32_t ReturnTypeMask;
1990 enum
1991 {
1992 kSecReturnDataMask = 1 << 0,
1993 kSecReturnAttributesMask = 1 << 1,
1994 kSecReturnRefMask = 1 << 2,
1995 kSecReturnPersistentRefMask = 1 << 3,
1996 };
1997
1998 /* Constant indicating there is no limit to the number of results to return. */
1999 enum
2000 {
2001 kSecMatchUnlimited = kCFNotFound
2002 };
2003
2004 /* Upper limit for number of keys in a QUERY dictionary. */
2005 #ifdef NO_SERVER
2006 #define QUERY_KEY_LIMIT (31 + 53)
2007 #else
2008 #define QUERY_KEY_LIMIT (53)
2009 #endif
2010
2011 typedef struct Pair
2012 {
2013 const void *key;
2014 const void *value;
2015 } Pair;
2016
2017 /* Nothing in this struct is retained since all the
2018 values below are extracted from the dictionary passed in by the
2019 caller. */
2020 typedef struct Query
2021 {
2022 /* Class of this query. */
2023 const kc_class *q_class;
2024
2025 /* Dictionary with all attributes and values in clear (to be encrypted). */
2026 CFMutableDictionaryRef q_item;
2027
2028 /* q_pairs is an array of Pair structs. Elements with indices
2029 [0, q_attr_end) contain attribute key value pairs. Elements with
2030 indices [q_match_begin, q_match_end) contain match key value pairs.
2031 Thus q_attr_end is the number of attrs in q_pairs and
2032 q_match_begin - q_match_end is the number of matches in q_pairs. */
2033 CFIndex q_match_begin;
2034 CFIndex q_match_end;
2035 CFIndex q_attr_end;
2036
2037 OSStatus q_error;
2038 ReturnTypeMask q_return_type;
2039
2040 CFDataRef q_data;
2041 CFTypeRef q_ref;
2042 sqlite_int64 q_row_id;
2043
2044 CFArrayRef q_use_item_list;
2045 #if defined(MULTIPLE_KEYCHAINS)
2046 CFArrayRef q_use_keychain;
2047 CFArrayRef q_use_keychain_list;
2048 #endif /* !defined(MULTIPLE_KEYCHAINS) */
2049
2050 /* Value of kSecMatchLimit key if present. */
2051 CFIndex q_limit;
2052
2053 /* Keybag handle to use for this item. */
2054 keybag_handle_t q_keybag;
2055 keyclass_t q_keyclass;
2056 //CFStringRef q_keyclass_s;
2057
2058 Pair q_pairs[];
2059 } Query;
2060
2061 /* Inline accessors to attr and match values in a query. */
2062 static inline CFIndex query_attr_count(const Query *q)
2063 {
2064 return q->q_attr_end;
2065 }
2066
2067 static inline Pair query_attr_at(const Query *q, CFIndex ix)
2068 {
2069 return q->q_pairs[ix];
2070 }
2071
2072 static inline CFIndex query_match_count(const Query *q)
2073 {
2074 return q->q_match_end - q->q_match_begin;
2075 }
2076
2077 static inline Pair query_match_at(const Query *q, CFIndex ix)
2078 {
2079 return q->q_pairs[q->q_match_begin + ix];
2080 }
2081
2082 /* Private routines used to parse a query. */
2083
2084 /* Sets q_keyclass based on value. */
2085 static void query_parse_keyclass(const void *value, Query *q) {
2086 if (!isString(value)) {
2087 q->q_error = errSecParam;
2088 return;
2089 } else if (CFEqual(value, kSecAttrAccessibleWhenUnlocked)) {
2090 q->q_keyclass = key_class_ak;
2091 } else if (CFEqual(value, kSecAttrAccessibleAfterFirstUnlock)) {
2092 q->q_keyclass = key_class_ck;
2093 } else if (CFEqual(value, kSecAttrAccessibleAlways)) {
2094 q->q_keyclass = key_class_dk;
2095 } else if (CFEqual(value, kSecAttrAccessibleWhenUnlockedThisDeviceOnly)) {
2096 q->q_keyclass = key_class_aku;
2097 } else if (CFEqual(value, kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly)) {
2098 q->q_keyclass = key_class_cku;
2099 } else if (CFEqual(value, kSecAttrAccessibleAlwaysThisDeviceOnly)) {
2100 q->q_keyclass = key_class_dku;
2101 } else {
2102 q->q_error = errSecParam;
2103 return;
2104 }
2105 //q->q_keyclass_s = value;
2106 }
2107
2108 static CFStringRef copyString(CFTypeRef obj) {
2109 CFTypeID tid = CFGetTypeID(obj);
2110 if (tid == CFStringGetTypeID())
2111 return CFStringCreateCopy(0, obj);
2112 else if (tid == CFDataGetTypeID())
2113 return CFStringCreateFromExternalRepresentation(0, obj, kCFStringEncodingUTF8);
2114 else
2115 return NULL;
2116 }
2117
2118 static CFDataRef copyData(CFTypeRef obj) {
2119 CFTypeID tid = CFGetTypeID(obj);
2120 if (tid == CFDataGetTypeID()) {
2121 return CFDataCreateCopy(0, obj);
2122 } else if (tid == CFStringGetTypeID()) {
2123 return CFStringCreateExternalRepresentation(0, obj, kCFStringEncodingUTF8, 0);
2124 } else if (tid == CFNumberGetTypeID()) {
2125 SInt32 value;
2126 CFNumberGetValue(obj, kCFNumberSInt32Type, &value);
2127 return CFDataCreate(0, (const UInt8 *)&value, sizeof(value));
2128 } else {
2129 return NULL;
2130 }
2131 }
2132
2133 static CFTypeRef copyBlob(CFTypeRef obj) {
2134 CFTypeID tid = CFGetTypeID(obj);
2135 if (tid == CFDataGetTypeID()) {
2136 return CFDataCreateCopy(0, obj);
2137 } else if (tid == CFStringGetTypeID()) {
2138 return CFStringCreateCopy(0, obj);
2139 } else if (tid == CFNumberGetTypeID()) {
2140 CFRetain(obj);
2141 return obj;
2142 } else {
2143 return NULL;
2144 }
2145 }
2146
2147 static CFTypeRef copyNumber(CFTypeRef obj) {
2148 CFTypeID tid = CFGetTypeID(obj);
2149 if (tid == CFNumberGetTypeID()) {
2150 CFRetain(obj);
2151 return obj;
2152 } else if (tid == CFBooleanGetTypeID()) {
2153 SInt32 value = CFBooleanGetValue(obj);
2154 return CFNumberCreate(0, kCFNumberSInt32Type, &value);
2155 } else if (tid == CFStringGetTypeID()) {
2156 SInt32 value = CFStringGetIntValue(obj);
2157 CFStringRef t = CFStringCreateWithFormat(0, 0, CFSTR("%ld"), value);
2158 /* If a string converted to an int isn't equal to the int printed as
2159 a string, return a CFStringRef instead. */
2160 if (!CFEqual(t, obj)) {
2161 CFRelease(t);
2162 return CFStringCreateCopy(0, obj);
2163 }
2164 CFRelease(t);
2165 return CFNumberCreate(0, kCFNumberSInt32Type, &value);
2166 } else
2167 return NULL;
2168 }
2169
2170 static CFDateRef copyDate(CFTypeRef obj) {
2171 CFTypeID tid = CFGetTypeID(obj);
2172 if (tid == CFDateGetTypeID()) {
2173 CFRetain(obj);
2174 return obj;
2175 } else
2176 return NULL;
2177 }
2178
2179 /* AUDIT[securityd](done):
2180 key (ok) is a caller provided, string or number of length 4.
2181 value (ok) is a caller provided, non NULL CFTypeRef.
2182 */
2183 static void query_add_attribute(const void *key, const void *value, Query *q)
2184 {
2185 const kc_attr_desc *desc;
2186 if (!(desc = kc_attr_desc_with_key(q->q_class, key, &q->q_error)))
2187 return;
2188
2189 CFTypeRef attr = NULL;
2190 switch (desc->kind) {
2191 case kc_data_attr:
2192 attr = copyData(value);
2193 break;
2194 case kc_blob_attr:
2195 attr = copyBlob(value);
2196 break;
2197 case kc_date_attr:
2198 case kc_creation_date_attr:
2199 case kc_modification_date_attr:
2200 attr = copyDate(value);
2201 break;
2202 case kc_number_attr:
2203 attr = copyNumber(value);
2204 break;
2205 case kc_string_attr:
2206 attr = copyString(value);
2207 break;
2208 }
2209
2210 if (!attr) {
2211 q->q_error = errSecItemInvalidValue;
2212 return;
2213 }
2214
2215 /* Store plaintext attr data in q_item. */
2216 if (q->q_item) {
2217 CFDictionarySetValue(q->q_item, desc->name, attr);
2218 }
2219
2220 if (CFEqual(desc->name, kSecAttrAccessible)) {
2221 query_parse_keyclass(attr, q);
2222 }
2223
2224 /* Convert attr to (sha1) digest if requested. */
2225 if (desc->flags & kc_digest_attr) {
2226 CFDataRef data = copyData(attr);
2227 CFRelease(attr);
2228 if (!data) {
2229 q->q_error = errSecInternal;
2230 return;
2231 }
2232
2233 CFMutableDataRef digest = CFDataCreateMutable(0, CC_SHA1_DIGEST_LENGTH);
2234 CFDataSetLength(digest, CC_SHA1_DIGEST_LENGTH);
2235 /* 64 bits cast: worst case is we generate the wrong hash */
2236 assert((unsigned long)CFDataGetLength(data)<UINT32_MAX); /* Debug check. Correct as long as CFIndex is long */
2237 CC_SHA1(CFDataGetBytePtr(data), (CC_LONG)CFDataGetLength(data),
2238 CFDataGetMutableBytePtr(digest));
2239 CFRelease(data);
2240 attr = digest;
2241 }
2242
2243 /* Record the new attr key, value in q_pairs. */
2244 q->q_pairs[q->q_attr_end].key = desc->name;
2245 q->q_pairs[q->q_attr_end++].value = attr;
2246 }
2247
2248 /* First remove key from q->q_pairs if it's present, then add the attribute again. */
2249 static void query_set_attribute(const void *key, const void *value, Query *q) {
2250 if (CFDictionaryContainsKey(q->q_item, key)) {
2251 CFIndex ix;
2252 for (ix = 0; ix < q->q_attr_end; ++ix) {
2253 if (CFEqual(key, q->q_pairs[ix].key)) {
2254 CFReleaseSafe(q->q_pairs[ix].value);
2255 --q->q_attr_end;
2256 for (; ix < q->q_attr_end; ++ix) {
2257 q->q_pairs[ix] = q->q_pairs[ix + 1];
2258 }
2259 CFDictionaryRemoveValue(q->q_item, key);
2260 break;
2261 }
2262 }
2263 }
2264 query_add_attribute(key, value, q);
2265 }
2266
2267 /* AUDIT[securityd](done):
2268 key (ok) is a caller provided, string starting with 'm'.
2269 value (ok) is a caller provided, non NULL CFTypeRef.
2270 */
2271 static void query_add_match(const void *key, const void *value, Query *q)
2272 {
2273 /* Record the match key, value in q_pairs. */
2274 --(q->q_match_begin);
2275 q->q_pairs[q->q_match_begin].key = key;
2276 q->q_pairs[q->q_match_begin].value = value;
2277
2278 if (CFEqual(kSecMatchLimit, key)) {
2279 /* Figure out what the value for kSecMatchLimit is if specified. */
2280 if (CFGetTypeID(value) == CFNumberGetTypeID()) {
2281 if (!CFNumberGetValue(value, kCFNumberCFIndexType, &q->q_limit))
2282 q->q_error = errSecItemInvalidValue;
2283 } else if (CFEqual(kSecMatchLimitAll, value)) {
2284 q->q_limit = kSecMatchUnlimited;
2285 } else if (CFEqual(kSecMatchLimitOne, value)) {
2286 q->q_limit = 1;
2287 } else {
2288 q->q_error = errSecItemInvalidValue;
2289 }
2290 }
2291 }
2292
2293 static bool query_set_class(Query *q, CFStringRef c_name, OSStatus *error) {
2294 const void *value;
2295 if (c_name && CFGetTypeID(c_name) == CFStringGetTypeID() &&
2296 (value = CFDictionaryGetValue(gClasses, c_name)) &&
2297 (q->q_class == 0 || q->q_class == value)) {
2298 q->q_class = value;
2299 return true;
2300 }
2301
2302 if (error && !*error)
2303 *error = c_name ? errSecNoSuchClass : errSecItemClassMissing;
2304
2305 return false;
2306 }
2307
2308 static const kc_class *query_get_class(CFDictionaryRef query, OSStatus *error) {
2309 CFStringRef c_name = NULL;
2310 const void *value = CFDictionaryGetValue(query, kSecClass);
2311 if (isString(value)) {
2312 c_name = value;
2313 } else {
2314 value = CFDictionaryGetValue(query, kSecValuePersistentRef);
2315 if (isData(value)) {
2316 CFDataRef pref = value;
2317 _SecItemParsePersistentRef(pref, &c_name, 0);
2318 }
2319 }
2320
2321 if (c_name && (value = CFDictionaryGetValue(gClasses, c_name))) {
2322 return value;
2323 } else {
2324 if (error && !*error)
2325 *error = c_name ? errSecNoSuchClass : errSecItemClassMissing;
2326 return false;
2327 }
2328 }
2329
2330 /* AUDIT[securityd](done):
2331 key (ok) is a caller provided, string starting with 'c'.
2332 value (ok) is a caller provided, non NULL CFTypeRef.
2333 */
2334 static void query_add_class(const void *key, const void *value, Query *q)
2335 {
2336 if (CFEqual(key, kSecClass)) {
2337 query_set_class(q, value, &q->q_error);
2338 } else {
2339 q->q_error = errSecItemInvalidKey;
2340 }
2341 }
2342
2343 /* AUDIT[securityd](done):
2344 key (ok) is a caller provided, string starting with 'r'.
2345 value (ok) is a caller provided, non NULL CFTypeRef.
2346 */
2347 static void query_add_return(const void *key, const void *value, Query *q)
2348 {
2349 ReturnTypeMask mask;
2350 if (CFGetTypeID(value) != CFBooleanGetTypeID()) {
2351 q->q_error = errSecItemInvalidValue;
2352 return;
2353 }
2354
2355 int set_it = CFEqual(value, kCFBooleanTrue);
2356
2357 if (CFEqual(key, kSecReturnData))
2358 mask = kSecReturnDataMask;
2359 else if (CFEqual(key, kSecReturnAttributes))
2360 mask = kSecReturnAttributesMask;
2361 else if (CFEqual(key, kSecReturnRef))
2362 mask = kSecReturnRefMask;
2363 else if (CFEqual(key, kSecReturnPersistentRef))
2364 mask = kSecReturnPersistentRefMask;
2365 else {
2366 q->q_error = errSecItemInvalidKey;
2367 return;
2368 }
2369
2370 if ((q->q_return_type & mask) && !set_it) {
2371 /* Clear out this bit (it's set so xor with the mask will clear it). */
2372 q->q_return_type ^= mask;
2373 } else if (!(q->q_return_type & mask) && set_it) {
2374 /* Set this bit. */
2375 q->q_return_type |= mask;
2376 }
2377 }
2378
2379 /* AUDIT[securityd](done):
2380 key (ok) is a caller provided, string starting with 'u'.
2381 value (ok since q_use_item_list is unused) is a caller provided, non
2382 NULL CFTypeRef.
2383 */
2384 static void query_add_use(const void *key, const void *value, Query *q)
2385 {
2386 if (CFEqual(key, kSecUseItemList)) {
2387 /* TODO: Add sanity checking when we start using this. */
2388 q->q_use_item_list = value;
2389 }
2390 #if defined(MULTIPLE_KEYCHAINS)
2391 else if (CFEqual(key, kSecUseKeychain))
2392 q->q_use_keychain = value;
2393 else if (CFEqual(key, kSecUseKeychainList))
2394 q->q_use_keychain_list = value;
2395 #endif /* !defined(MULTIPLE_KEYCHAINS) */
2396 else {
2397 q->q_error = errSecItemInvalidKey;
2398 return;
2399 }
2400 }
2401
2402 static void query_set_data(const void *value, Query *q) {
2403 if (!isData(value)) {
2404 q->q_error = errSecItemInvalidValue;
2405 } else {
2406 q->q_data = value;
2407 if (q->q_item)
2408 CFDictionarySetValue(q->q_item, kSecValueData, value);
2409 }
2410 }
2411
2412 /* AUDIT[securityd](done):
2413 key (ok) is a caller provided, string starting with 'u'.
2414 value (ok) is a caller provided, non NULL CFTypeRef.
2415 */
2416 static void query_add_value(const void *key, const void *value, Query *q)
2417 {
2418 if (CFEqual(key, kSecValueData)) {
2419 query_set_data(value, q);
2420 #if NO_SERVER
2421 } else if (CFEqual(key, kSecValueRef)) {
2422 q->q_ref = value;
2423 /* TODO: Add value type sanity checking. */
2424 #endif
2425 } else if (CFEqual(key, kSecValuePersistentRef)) {
2426 CFStringRef c_name;
2427 if (_SecItemParsePersistentRef(value, &c_name, &q->q_row_id))
2428 query_set_class(q, c_name, &q->q_error);
2429 else
2430 q->q_error = errSecItemInvalidValue;
2431 } else {
2432 q->q_error = errSecItemInvalidKey;
2433 return;
2434 }
2435 }
2436
2437 /* AUDIT[securityd](done):
2438 key (ok) is a caller provided, unchecked.
2439 value (ok) is a caller provided, unchecked.
2440 */
2441 static void query_update_applier(const void *key, const void *value,
2442 void *context)
2443 {
2444 Query *q = (Query *)context;
2445 /* If something went wrong there is no point processing any more args. */
2446 if (q->q_error)
2447 return;
2448
2449 /* Make sure we have a string key. */
2450 if (!isString(key)) {
2451 q->q_error = errSecItemInvalidKeyType;
2452 return;
2453 }
2454
2455 if (!value) {
2456 q->q_error = errSecItemInvalidValue;
2457 return;
2458 }
2459
2460 if (CFEqual(key, kSecValueData)) {
2461 query_set_data(value, q);
2462 } else {
2463 /* Make sure we have a value. */
2464 if (!value) {
2465 q->q_error = errSecItemInvalidValue;
2466 return;
2467 }
2468
2469 query_add_attribute(key, value, q);
2470 }
2471 }
2472
2473 /* AUDIT[securityd](done):
2474 key (ok) is a caller provided, unchecked.
2475 value (ok) is a caller provided, unchecked.
2476 */
2477 static void query_applier(const void *key, const void *value, void *context)
2478 {
2479 Query *q = (Query *)context;
2480 /* If something went wrong there is no point processing any more args. */
2481 if (q->q_error)
2482 return;
2483
2484 /* Make sure we have a key. */
2485 if (!key) {
2486 q->q_error = errSecItemInvalidKeyType;
2487 return;
2488 }
2489
2490 /* Make sure we have a value. */
2491 if (!value) {
2492 q->q_error = errSecItemInvalidValue;
2493 return;
2494 }
2495
2496 /* Figure out what type of key we are dealing with. */
2497 CFTypeID key_id = CFGetTypeID(key);
2498 if (key_id == CFStringGetTypeID()) {
2499 CFIndex key_len = CFStringGetLength(key);
2500 /* String keys can be different things. The subtype is determined by:
2501 length 4 strings are all attributes. Otherwise the first char
2502 determines the type:
2503 c: class must be kSecClass
2504 m: match like kSecMatchPolicy
2505 r: return like kSecReturnData
2506 u: use keys
2507 v: value
2508 */
2509 if (key_len == 4) {
2510 /* attributes */
2511 query_add_attribute(key, value, q);
2512 } else if (key_len > 1) {
2513 UniChar k_first_char = CFStringGetCharacterAtIndex(key, 0);
2514 switch (k_first_char)
2515 {
2516 case 'c': /* class */
2517 query_add_class(key, value, q);
2518 break;
2519 case 'm': /* match */
2520 query_add_match(key, value, q);
2521 break;
2522 case 'r': /* return */
2523 query_add_return(key, value, q);
2524 break;
2525 case 'u': /* use */
2526 query_add_use(key, value, q);
2527 break;
2528 case 'v': /* value */
2529 query_add_value(key, value, q);
2530 break;
2531 default:
2532 q->q_error = errSecItemInvalidKey;
2533 break;
2534 }
2535 } else {
2536 q->q_error = errSecItemInvalidKey;
2537 }
2538 } else if (key_id == CFNumberGetTypeID()) {
2539 /* Numeric keys are always (extended) attributes. */
2540 /* TODO: Why is this here? query_add_attribute() doesn't take numbers. */
2541 query_add_attribute(key, value, q);
2542 } else {
2543 /* We only support string and number type keys. */
2544 q->q_error = errSecItemInvalidKeyType;
2545 }
2546 }
2547
2548 static CFStringRef query_infer_keyclass(Query *q, CFStringRef agrp) {
2549 /* apsd and lockdown are always dku. */
2550 if (CFEqual(agrp, CFSTR("com.apple.apsd"))
2551 || CFEqual(agrp, CFSTR("lockdown-identities"))) {
2552 return kSecAttrAccessibleAlwaysThisDeviceOnly;
2553 }
2554 /* All other certs or in the apple agrp is dk. */
2555 if (q->q_class == &cert_class) {
2556 /* third party certs are always dk. */
2557 return kSecAttrAccessibleAlways;
2558 }
2559 /* The rest defaults to ak. */
2560 return kSecAttrAccessibleWhenUnlocked;
2561 }
2562
2563 static void query_ensure_keyclass(Query *q, CFStringRef agrp) {
2564 if (q->q_keyclass == 0) {
2565 CFStringRef accessible = query_infer_keyclass(q, agrp);
2566 query_add_attribute(kSecAttrAccessible, accessible, q);
2567 }
2568 }
2569
2570 static void query_destroy(Query *q, OSStatus *status)
2571 {
2572 if (status && *status == 0 && q->q_error)
2573 *status = q->q_error;
2574
2575 CFIndex ix, attr_count = query_attr_count(q);
2576 for (ix = 0; ix < attr_count; ++ix) {
2577 CFReleaseSafe(query_attr_at(q, ix).value);
2578 }
2579 CFReleaseSafe(q->q_item);
2580 free(q);
2581 }
2582
2583 /* Allocate and initialize a Query object for query. */
2584 static Query *query_create(const kc_class *qclass, CFDictionaryRef query,
2585 OSStatus *error)
2586 {
2587 if (!qclass) {
2588 if (error && !*error)
2589 *error = errSecItemClassMissing;
2590 return NULL;
2591 }
2592
2593 /* Number of pairs we need is the number of attributes in this class
2594 plus the number of keys in the dictionary, minus one for each key in
2595 the dictionary that is a regular attribute. */
2596 CFIndex key_count = qclass->n_attrs;
2597 if (query) {
2598 key_count += CFDictionaryGetCount(query);
2599 CFIndex ix;
2600 for (ix = 0; ix < qclass->n_attrs; ++ix) {
2601 if (CFDictionaryContainsKey(query, qclass->attrs[ix].name))
2602 --key_count;
2603 }
2604 }
2605
2606 if (key_count > QUERY_KEY_LIMIT) {
2607 if (error && !*error)
2608 *error = errSecItemIllegalQuery;
2609 return NULL;
2610 }
2611
2612 Query *q = calloc(1, sizeof(Query) + sizeof(Pair) * key_count);
2613 if (q == NULL) {
2614 if (error && !*error)
2615 *error = errSecAllocate;
2616 return NULL;
2617 }
2618
2619 q->q_class = qclass;
2620 q->q_match_begin = q->q_match_end = key_count;
2621
2622 return q;
2623 }
2624
2625 /* Parse query for a Query object q. */
2626 static bool query_parse_with_applier(Query *q, CFDictionaryRef query,
2627 CFDictionaryApplierFunction applier,
2628 OSStatus *error) {
2629 if (q->q_item == NULL) {
2630 q->q_item = CFDictionaryCreateMutable(0, 0,
2631 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2632 }
2633 CFDictionaryApplyFunction(query, applier, q);
2634 if (q->q_error) {
2635 if (error && !*error)
2636 *error = q->q_error;
2637 return false;
2638 }
2639 return true;
2640 }
2641
2642 /* Parse query for a Query object q. */
2643 static bool query_parse(Query *q, CFDictionaryRef query,
2644 OSStatus *error) {
2645 return query_parse_with_applier(q, query, query_applier, error);
2646 }
2647
2648 /* Parse query for a Query object q. */
2649 static bool query_update_parse(Query *q, CFDictionaryRef update,
2650 OSStatus *error) {
2651 return query_parse_with_applier(q, update, query_update_applier, error);
2652 }
2653
2654 static Query *query_create_with_limit(CFDictionaryRef query, CFIndex limit,
2655 OSStatus *error) {
2656 Query *q;
2657 q = query_create(query_get_class(query, error), query, error);
2658 if (q) {
2659 q->q_limit = limit;
2660 if (!query_parse(q, query, error)) {
2661 query_destroy(q, error);
2662 return NULL;
2663 }
2664 }
2665 return q;
2666 }
2667
2668 /* Make sure all attributes that are marked as not_null have a value. If
2669 force_date is false, only set mdat and cdat if they aren't already set. */
2670 static void
2671 query_pre_add(Query *q, bool force_date) {
2672 CFDateRef now = CFDateCreate(0, CFAbsoluteTimeGetCurrent());
2673 CFIndex ix;
2674 for (ix = 0; ix < q->q_class->n_attrs; ++ix) {
2675 const kc_attr_desc *desc = &q->q_class->attrs[ix];
2676 if (desc->kind == kc_creation_date_attr ||
2677 desc->kind == kc_modification_date_attr) {
2678 if (force_date) {
2679 query_set_attribute(desc->name, now, q);
2680 } else if (!CFDictionaryContainsKey(q->q_item, desc->name)) {
2681 query_add_attribute(desc->name, now, q);
2682 }
2683 } else if ((desc->flags & kc_constrain_not_null) &&
2684 !CFDictionaryContainsKey(q->q_item, desc->name)) {
2685 CFTypeRef value = NULL;
2686 if (desc->flags & kc_constrain_default_0) {
2687 if (desc->kind == kc_date_attr)
2688 value = CFDateCreate(kCFAllocatorDefault, 0.0);
2689 else {
2690 SInt32 vzero = 0;
2691 value = CFNumberCreate(0, kCFNumberSInt32Type, &vzero);
2692 }
2693 } else if (desc->flags & kc_constrain_default_empty) {
2694 if (desc->kind == kc_data_attr)
2695 value = CFDataCreate(kCFAllocatorDefault, NULL, 0);
2696 else {
2697 value = CFSTR("");
2698 CFRetain(value);
2699 }
2700 }
2701 if (value) {
2702 /* Safe to use query_add_attribute here since the attr wasn't
2703 set yet. */
2704 query_add_attribute(desc->name, value, q);
2705 CFRelease(value);
2706 }
2707 }
2708 }
2709 CFReleaseSafe(now);
2710 }
2711
2712 /* Update modification_date if needed. */
2713 static void
2714 query_pre_update(Query *q) {
2715 CFIndex ix;
2716 for (ix = 0; ix < q->q_class->n_attrs; ++ix) {
2717 const kc_attr_desc *desc = &q->q_class->attrs[ix];
2718 if (desc->kind == kc_modification_date_attr) {
2719 CFDateRef now = CFDateCreate(0, CFAbsoluteTimeGetCurrent());
2720 query_set_attribute(desc->name, now, q);
2721 CFReleaseSafe(now);
2722 }
2723 }
2724 }
2725
2726 /* AUDIT[securityd](done):
2727 accessGroup (ok) is a caller provided, non NULL CFTypeRef.
2728
2729 Return true iff accessGroup is allowable according to accessGroups.
2730 */
2731 static bool accessGroupsAllows(CFArrayRef accessGroups,
2732 CFStringRef accessGroup) {
2733 /* NULL accessGroups is wildcard. */
2734 if (!accessGroups)
2735 return true;
2736 /* Make sure we have a string. */
2737 if (!isString(accessGroup))
2738 return false;
2739
2740 /* Having the special accessGroup "*" allows access to all accessGroups. */
2741 CFRange range = { 0, CFArrayGetCount(accessGroups) };
2742 if (range.length &&
2743 (CFArrayContainsValue(accessGroups, range, accessGroup) ||
2744 CFArrayContainsValue(accessGroups, range, CFSTR("*"))))
2745 return true;
2746
2747 return false;
2748 }
2749
2750 static bool itemInAccessGroup(CFDictionaryRef item, CFArrayRef accessGroups) {
2751 return accessGroupsAllows(accessGroups,
2752 CFDictionaryGetValue(item, kSecAttrAccessGroup));
2753 }
2754
2755 static void s3dl_merge_into_dict(const void *key, const void *value, void *context) {
2756 CFDictionarySetValue(context, key, value);
2757 }
2758
2759 /* Return whatever the caller requested based on the value of q->q_return_type.
2760 keys and values must be 3 larger than attr_count in size to accomadate the
2761 optional data, class and persistant ref results. This is so we can use
2762 the CFDictionaryCreate() api here rather than appending to a
2763 mutable dictionary. */
2764 static CFTypeRef handle_result(Query *q, CFMutableDictionaryRef item,
2765 sqlite_int64 rowid) {
2766 CFTypeRef a_result;
2767 CFDataRef data;
2768 data = CFDictionaryGetValue(item, kSecValueData);
2769 if (q->q_return_type == 0) {
2770 /* Caller isn't interested in any results at all. */
2771 a_result = kCFNull;
2772 } else if (q->q_return_type == kSecReturnDataMask) {
2773 if (data) {
2774 a_result = data;
2775 CFRetain(a_result);
2776 } else {
2777 a_result = CFDataCreate(kCFAllocatorDefault, NULL, 0);
2778 }
2779 } else if (q->q_return_type == kSecReturnPersistentRefMask) {
2780 a_result = _SecItemMakePersistentRef(q->q_class->name, rowid);
2781 } else {
2782 /* We need to return more than one value. */
2783 if (q->q_return_type & kSecReturnRefMask) {
2784 CFDictionarySetValue(item, kSecClass, q->q_class->name);
2785 } else if ((q->q_return_type & kSecReturnAttributesMask)) {
2786 if (!(q->q_return_type & kSecReturnDataMask)) {
2787 CFDictionaryRemoveValue(item, kSecValueData);
2788 }
2789 } else {
2790 if (data)
2791 CFRetain(data);
2792 CFDictionaryRemoveAllValues(item);
2793 if ((q->q_return_type & kSecReturnDataMask) && data) {
2794 CFDictionarySetValue(item, kSecValueData, data);
2795 CFRelease(data);
2796 }
2797 }
2798 if (q->q_return_type & kSecReturnPersistentRefMask) {
2799 CFDataRef pref = _SecItemMakePersistentRef(q->q_class->name, rowid);
2800 CFDictionarySetValue(item, kSecValuePersistentRef, pref);
2801 CFRelease(pref);
2802 }
2803
2804 a_result = item;
2805 CFRetain(item);
2806 }
2807
2808 return a_result;
2809 }
2810
2811 static CFStringRef s3dl_insert_sql(Query *q) {
2812 /* We always have at least one attribute, the agrp. */
2813 CFMutableStringRef sql = CFStringCreateMutable(NULL, 0);
2814 CFStringAppendFormat(sql, NULL, CFSTR("INSERT INTO %@(data"), q->q_class->name);
2815
2816 CFIndex ix, attr_count = query_attr_count(q);
2817 for (ix = 0; ix < attr_count; ++ix) {
2818 CFStringAppendFormat(sql, NULL, CFSTR(",%@"),
2819 query_attr_at(q, ix).key);
2820 }
2821 if (q->q_row_id) {
2822 CFStringAppendFormat(sql, NULL, CFSTR(",rowid"));
2823 }
2824
2825 CFStringAppend(sql, CFSTR(")VALUES(?"));
2826
2827 for (ix = 0; ix < attr_count; ++ix) {
2828 CFStringAppend(sql, CFSTR(",?"));
2829 }
2830 if (q->q_row_id) {
2831 CFStringAppendFormat(sql, NULL, CFSTR(",%qd"), q->q_row_id);
2832 }
2833 CFStringAppend(sql, CFSTR(");"));
2834 return sql;
2835 }
2836
2837 static CFDataRef s3dl_encode_item(keybag_handle_t keybag, keyclass_t keyclass,
2838 CFDictionaryRef item, OSStatus *error) {
2839 /* Encode to be encrypted item. */
2840 CFDataRef plain = CFPropertyListCreateData(0, item,
2841 kCFPropertyListBinaryFormat_v1_0, 0, 0);
2842 CFDataRef edata = NULL;
2843 if (plain) {
2844 int s3e = ks_encrypt_data(keybag, keyclass, plain, &edata);
2845 if (s3e) {
2846 asl_log(NULL, NULL, ASL_LEVEL_CRIT,
2847 "ks_encrypt_data: failed: %d", s3e);
2848 if (error && !*error)
2849 *error = s3e;
2850 }
2851 CFRelease(plain);
2852 } else {
2853 if (error && !*error)
2854 *error = errSecAllocate;
2855 }
2856 return edata;
2857 }
2858
2859 /* Bind the parameters to the INSERT statement. */
2860 static int s3dl_insert_bind(Query *q, sqlite3_stmt *stmt) {
2861 int s3e = SQLITE_OK;
2862 int param = 1;
2863 OSStatus error = 0;
2864 CFDataRef edata = s3dl_encode_item(q->q_keybag, q->q_keyclass, q->q_item, &error);
2865 if (edata) {
2866 s3e = sqlite3_bind_blob_wrapper(stmt, param, CFDataGetBytePtr(edata),
2867 CFDataGetLength(edata), SQLITE_TRANSIENT);
2868 secdebug("bind", "bind_blob: %.*s: %d",
2869 CFDataGetLength(edata), CFDataGetBytePtr(edata), s3e);
2870 CFRelease(edata);
2871 } else {
2872 s3e = error;
2873 }
2874 param++;
2875
2876 CFIndex ix, attr_count = query_attr_count(q);
2877 for (ix = 0; s3e == SQLITE_OK && ix < attr_count; ++ix) {
2878 s3e = kc_bind_paramter(stmt, param++, query_attr_at(q, ix).value);
2879 }
2880
2881 return s3e;
2882 }
2883
2884 /* AUDIT[securityd](done):
2885 attributes (ok) is a caller provided dictionary, only its cf type has
2886 been checked.
2887 */
2888 static OSStatus
2889 s3dl_query_add(s3dl_db_thread *dbt, Query *q, CFTypeRef *result)
2890 {
2891 int s3e;
2892
2893 if (query_match_count(q) != 0)
2894 return errSecItemMatchUnsupported;
2895
2896 /* Add requires a class to be specified unless we are adding a ref. */
2897 if (q->q_use_item_list)
2898 return errSecUseItemListUnsupported;
2899
2900 /* Actual work here. */
2901 sqlite3 *s3h = dbt->s3_handle;
2902
2903 CFStringRef sql = s3dl_insert_sql(q);
2904 sqlite3_stmt *stmt = NULL;
2905 s3e = kc_prepare_statement(s3h, sql, &stmt);
2906 CFRelease(sql);
2907
2908 if (s3e == SQLITE_OK)
2909 s3e = s3dl_insert_bind(q, stmt);
2910
2911 /* Now execute the INSERT statement (step). */
2912 if (s3e == SQLITE_OK) {
2913 s3e = sqlite3_step(stmt);
2914 if (s3e == SQLITE_DONE) {
2915 s3e = SQLITE_OK;
2916 if (q->q_return_type) {
2917 *result = handle_result(q, q->q_item, sqlite3_last_insert_rowid(s3h));
2918 }
2919 } else if (s3e == SQLITE_ERROR) {
2920 secdebug("sql", "insert: %s", sqlite3_errmsg(s3h));
2921 /* The object already existed. */
2922 s3e = errSecDuplicateItem;
2923 }
2924 }
2925
2926 /* Free the stmt. */
2927 if (stmt) {
2928 int s3e2 = sqlite3_finalize(stmt);
2929 if (s3e2 != SQLITE_OK && s3e == SQLITE_OK)
2930 s3e = s3e2;
2931 }
2932
2933 return s3e == SQLITE_OK ? 0 : osstatus_for_s3e(s3e);
2934 }
2935
2936 typedef void (*s3dl_handle_row)(sqlite3_stmt *stmt, void *context);
2937
2938 static CFMutableDictionaryRef
2939 s3dl_item_from_col(sqlite3_stmt *stmt, Query *q, int col,
2940 CFArrayRef accessGroups, keyclass_t *keyclass) {
2941 CFMutableDictionaryRef item = NULL;
2942 CFErrorRef error = NULL;
2943 CFDataRef edata = NULL;
2944 CFDataRef plain = NULL;
2945
2946 require_action(edata = CFDataCreateWithBytesNoCopy(0, sqlite3_column_blob(stmt, col),
2947 sqlite3_column_bytes(stmt, col),
2948 kCFAllocatorNull),
2949 out, q->q_error = errSecDecode);
2950
2951 /* Decrypt and decode the item and check the decoded attributes against the query. */
2952 uint32_t version;
2953 require_noerr((q->q_error = ks_decrypt_data(q->q_keybag, keyclass, edata, &plain, &version)), out);
2954 if (version < 2) {
2955 goto out;
2956 }
2957
2958 CFPropertyListFormat format;
2959 item = (CFMutableDictionaryRef)CFPropertyListCreateWithData(0, plain,
2960 kCFPropertyListMutableContainers, &format, &error);
2961 if (!item) {
2962 secerror("decode failed: %@ [item: %@]", error, plain);
2963 q->q_error = (OSStatus)CFErrorGetCode(error); /* possibly truncated error codes: whatever */
2964 CFRelease(error);
2965 } else if (!isDictionary(item)) {
2966 CFRelease(item);
2967 item = NULL;
2968 } else if (!itemInAccessGroup(item, accessGroups)) {
2969 secerror("items accessGroup %@ not in %@",
2970 CFDictionaryGetValue(item, kSecAttrAccessGroup),
2971 accessGroups);
2972 CFRelease(item);
2973 item = NULL;
2974 }
2975 /* TODO: Validate keyclass attribute. */
2976
2977 out:
2978 CFReleaseSafe(edata);
2979 CFReleaseSafe(plain);
2980 return item;
2981 }
2982
2983 struct s3dl_query_ctx {
2984 Query *q;
2985 CFArrayRef accessGroups;
2986 CFTypeRef result;
2987 int found;
2988 };
2989
2990 static void s3dl_query_row(sqlite3_stmt *stmt, void *context) {
2991 struct s3dl_query_ctx *c = context;
2992 Query *q = c->q;
2993
2994 CFMutableDictionaryRef item = s3dl_item_from_col(stmt, q, 1,
2995 c->accessGroups, NULL);
2996 if (!item)
2997 return;
2998
2999 if (q->q_class == &identity_class) {
3000 // TODO: Use col 2 for key rowid and use both rowids in persistant ref.
3001 CFMutableDictionaryRef key = s3dl_item_from_col(stmt, q, 3,
3002 c->accessGroups, NULL);
3003 if (!key)
3004 goto out;
3005
3006 CFDataRef certData = CFDictionaryGetValue(item, kSecValueData);
3007 if (certData) {
3008 CFDictionarySetValue(key, CFSTR(CERTIFICATE_DATA_COLUMN_LABEL),
3009 certData);
3010 CFDictionaryRemoveValue(item, kSecValueData);
3011 }
3012 CFDictionaryApplyFunction(item, s3dl_merge_into_dict, key);
3013 CFRelease(item);
3014 item = key;
3015 }
3016
3017 sqlite_int64 rowid = sqlite3_column_int64(stmt, 0);
3018 CFTypeRef a_result = handle_result(q, item, rowid);
3019 if (a_result) {
3020 if (a_result == kCFNull) {
3021 /* Caller wasn't interested in a result, but we still
3022 count this row as found. */
3023 } else if (q->q_limit == 1) {
3024 c->result = a_result;
3025 } else {
3026 CFArrayAppendValue((CFMutableArrayRef)c->result, a_result);
3027 CFRelease(a_result);
3028 }
3029 c->found++;
3030 }
3031
3032 out:
3033 CFRelease(item);
3034 }
3035
3036 struct s3dl_update_row_ctx {
3037 struct s3dl_query_ctx qc;
3038 Query *u;
3039 sqlite3_stmt *update_stmt;
3040 };
3041
3042
3043 static void s3dl_update_row(sqlite3_stmt *stmt, void *context)
3044 {
3045 struct s3dl_update_row_ctx *c = context;
3046 Query *q = c->qc.q;
3047
3048 int s3e = SQLITE_OK;
3049 CFDataRef edata = NULL;
3050 keyclass_t keyclass;
3051 sqlite_int64 rowid = sqlite3_column_int64(stmt, 0);
3052 CFMutableDictionaryRef item;
3053 require(item = s3dl_item_from_col(stmt, q, 1, c->qc.accessGroups,
3054 &keyclass), out);
3055
3056 /* Update modified attributes in item and reencrypt. */
3057 Query *u = c->u;
3058 CFDictionaryApplyFunction(u->q_item, s3dl_merge_into_dict, item);
3059 if (u->q_keyclass) {
3060 keyclass = u->q_keyclass;
3061 }
3062
3063 require(edata = s3dl_encode_item(q->q_keybag, keyclass, item, &q->q_error),
3064 out);
3065
3066 /* Bind rowid and data to UPDATE statement and step. */
3067 /* Skip over already bound attribute values being updated, since we don't
3068 change them for each item. */
3069 CFIndex count = 1 + query_attr_count(u);
3070 /* 64 bits cast: worst case is if you try to have more than 2^32 attributes, we will drop some */
3071 assert(count < INT_MAX); /* Debug check */
3072 int param = (int)count;
3073 s3e = sqlite3_bind_blob_wrapper(c->update_stmt, param++,
3074 CFDataGetBytePtr(edata), CFDataGetLength(edata),
3075 SQLITE_TRANSIENT);
3076 if (s3e == SQLITE_OK)
3077 s3e = sqlite3_bind_int64(c->update_stmt, param++, rowid);
3078
3079 /* Now execute the UPDATE statement (step). */
3080 if (s3e == SQLITE_OK) {
3081 s3e = sqlite3_step(c->update_stmt);
3082 if (s3e == SQLITE_DONE) {
3083 s3e = SQLITE_OK;
3084 c->qc.found++;
3085 secdebug("sql", "updated row: %llu", rowid);
3086 } else if (s3e == SQLITE_ERROR) {
3087 /* sqlite3_reset() below will return the real error. */
3088 s3e = SQLITE_OK;
3089 }
3090 }
3091
3092 out:
3093 if (s3e) q->q_error = osstatus_for_s3e(s3e);
3094 s3e = sqlite3_reset(c->update_stmt); /* Reset state, but not bindings. */
3095 if (s3e && !q->q_error) q->q_error = osstatus_for_s3e(s3e);
3096 if (q->q_error) { secdebug("sql", "update failed: %d", q->q_error); }
3097
3098 CFReleaseSafe(item);
3099 CFReleaseSafe(edata);
3100 }
3101
3102 /* Append AND is needWhere is NULL or *needWhere is false. Append WHERE
3103 otherwise. Upon return *needWhere will be false. */
3104 static void
3105 sqlAppendWhereOrAnd(CFMutableStringRef sql, bool *needWhere) {
3106 if (!needWhere || !*needWhere) {
3107 CFStringAppend(sql, CFSTR(" AND "));
3108 } else {
3109 CFStringAppend(sql, CFSTR(" WHERE "));
3110 *needWhere = false;
3111 }
3112 }
3113
3114 static void
3115 sqlAppendWhereBind(CFMutableStringRef sql, CFStringRef col, bool *needWhere) {
3116 sqlAppendWhereOrAnd(sql, needWhere);
3117 CFStringAppend(sql, col);
3118 CFStringAppend(sql, CFSTR("=?"));
3119 }
3120
3121 static void
3122 sqlAppendWhereROWID(CFMutableStringRef sql,
3123 CFStringRef col, sqlite_int64 row_id,
3124 bool *needWhere) {
3125 if (row_id > 0) {
3126 sqlAppendWhereOrAnd(sql, needWhere);
3127 CFStringAppendFormat(sql, NULL, CFSTR("%@=%lld"), col, row_id);
3128 }
3129 }
3130
3131 static void
3132 sqlAppendWhereAttrs(CFMutableStringRef sql, const Query *q, bool *needWhere) {
3133 CFIndex ix, attr_count = query_attr_count(q);
3134 for (ix = 0; ix < attr_count; ++ix) {
3135 sqlAppendWhereBind(sql, query_attr_at(q, ix).key, needWhere);
3136 }
3137 }
3138
3139 static void
3140 sqlAppendWhereAccessGroups(CFMutableStringRef sql,
3141 CFStringRef col,
3142 CFArrayRef accessGroups,
3143 bool *needWhere) {
3144 CFIndex ix, ag_count;
3145 if (!accessGroups || 0 == (ag_count = CFArrayGetCount(accessGroups))) {
3146 return;
3147 }
3148
3149 sqlAppendWhereOrAnd(sql, needWhere);
3150 #if 1
3151 CFStringAppend(sql, col);
3152 CFStringAppend(sql, CFSTR(" IN (?"));
3153 for (ix = 1; ix < ag_count; ++ix) {
3154 CFStringAppend(sql, CFSTR(",?"));
3155 }
3156 CFStringAppend(sql, CFSTR(")"));
3157 #else
3158 CFStringAppendFormat(sql, 0, CFSTR("(%@=?"), col);
3159 for (ix = 1; ix < ag_count; ++ix) {
3160 CFStringAppendFormat(sql, 0, CFSTR(" OR %@=?"), col);
3161 }
3162 CFStringAppend(sql, CFSTR(")"));
3163 #endif
3164 }
3165
3166 static void sqlAppendWhereClause(CFMutableStringRef sql, const Query *q,
3167 CFArrayRef accessGroups) {
3168 bool needWhere = true;
3169 sqlAppendWhereROWID(sql, CFSTR("ROWID"), q->q_row_id, &needWhere);
3170 sqlAppendWhereAttrs(sql, q, &needWhere);
3171 sqlAppendWhereAccessGroups(sql, CFSTR("agrp"), accessGroups, &needWhere);
3172 }
3173
3174 static void sqlAppendLimit(CFMutableStringRef sql, CFIndex limit) {
3175 if (limit != kSecMatchUnlimited)
3176 CFStringAppendFormat(sql, NULL, CFSTR(" LIMIT %d;"), limit);
3177 else
3178 CFStringAppend(sql, CFSTR(";"));
3179 }
3180
3181 static CFStringRef s3dl_select_sql(Query *q, int version, CFArrayRef accessGroups) {
3182 CFMutableStringRef sql = CFStringCreateMutable(NULL, 0);
3183 if (q->q_class == &identity_class) {
3184 CFStringAppendFormat(sql, NULL, CFSTR("SELECT crowid, "
3185 CERTIFICATE_DATA_COLUMN_LABEL ", rowid, data FROM "
3186 "(SELECT cert.rowid AS crowid, cert.labl AS labl,"
3187 " cert.issr AS issr, cert.slnr AS slnr, cert.skid AS skid,"
3188 " keys.*, cert.data AS " CERTIFICATE_DATA_COLUMN_LABEL
3189 " FROM keys, cert"
3190 " WHERE keys.priv == 1 AND cert.pkhh == keys.klbl"));
3191 sqlAppendWhereAccessGroups(sql, CFSTR("cert.agrp"), accessGroups, 0);
3192 /* The next 3 sqlAppendWhere calls are in the same order as in
3193 sqlAppendWhereClause(). This makes sqlBindWhereClause() work,
3194 as long as we do an extra sqlBindAccessGroups first. */
3195 sqlAppendWhereROWID(sql, CFSTR("crowid"), q->q_row_id, 0);
3196 CFStringAppend(sql, CFSTR(")"));
3197 bool needWhere = true;
3198 sqlAppendWhereAttrs(sql, q, &needWhere);
3199 sqlAppendWhereAccessGroups(sql, CFSTR("agrp"), accessGroups, &needWhere);
3200 } else {
3201 CFStringAppend(sql, (version < 5 ? CFSTR("SELECT * FROM ") :
3202 CFSTR("SELECT rowid, data FROM ")));
3203 CFStringAppend(sql, q->q_class->name);
3204 sqlAppendWhereClause(sql, q, accessGroups);
3205 }
3206 sqlAppendLimit(sql, q->q_limit);
3207
3208 return sql;
3209 }
3210
3211 static int sqlBindAccessGroups(sqlite3_stmt *stmt, CFArrayRef accessGroups,
3212 int *pParam) {
3213 int s3e = SQLITE_OK;
3214 int param = *pParam;
3215 CFIndex ix, count = accessGroups ? CFArrayGetCount(accessGroups) : 0;
3216 for (ix = 0; ix < count; ++ix) {
3217 s3e = kc_bind_paramter(stmt, param++,
3218 CFArrayGetValueAtIndex(accessGroups, ix));
3219 if (s3e)
3220 break;
3221 }
3222 *pParam = param;
3223 return s3e;
3224 }
3225
3226 static int sqlBindWhereClause(sqlite3_stmt *stmt, const Query *q,
3227 CFArrayRef accessGroups, int *pParam) {
3228 int s3e = SQLITE_OK;
3229 int param = *pParam;
3230 CFIndex ix, attr_count = query_attr_count(q);
3231 for (ix = 0; ix < attr_count; ++ix) {
3232 s3e = kc_bind_paramter(stmt, param++, query_attr_at(q, ix).value);
3233 if (s3e)
3234 break;
3235 }
3236
3237 /* Bind the access group to the sql. */
3238 if (s3e == SQLITE_OK) {
3239 s3e = sqlBindAccessGroups(stmt, accessGroups, &param);
3240 }
3241
3242 *pParam = param;
3243 return s3e;
3244 }
3245
3246 static OSStatus
3247 s3dl_query(s3dl_db_thread *dbt, s3dl_handle_row handle_row, int version,
3248 void *context)
3249 {
3250 struct s3dl_query_ctx *c = context;
3251 Query *q = c->q;
3252 CFArrayRef accessGroups = c->accessGroups;
3253 int s3e;
3254
3255 /* Sanity check the query. */
3256 if (q->q_ref)
3257 return errSecValueRefUnsupported;
3258 if (q->q_row_id && query_attr_count(q))
3259 return errSecItemIllegalQuery;
3260
3261 /* Actual work here. */
3262 sqlite3 *s3h = dbt->s3_handle;
3263
3264 CFStringRef sql = s3dl_select_sql(q, version, accessGroups);
3265 sqlite3_stmt *stmt = NULL;
3266 s3e = kc_prepare_statement(s3h, sql, &stmt);
3267 CFRelease(sql);
3268
3269 /* Bind the values being searched for to the SELECT statement. */
3270 if (s3e == SQLITE_OK) {
3271 int param = 1;
3272 if (q->q_class == &identity_class) {
3273 /* Bind the access groups to cert.agrp. */
3274 s3e = sqlBindAccessGroups(stmt, accessGroups, &param);
3275 }
3276 if (s3e == SQLITE_OK)
3277 s3e = sqlBindWhereClause(stmt, q, accessGroups, &param);
3278 }
3279
3280 /* Now execute the SELECT statement (step). */
3281 if (q->q_limit == 1) {
3282 c->result = NULL;
3283 } else {
3284 c->result = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
3285 }
3286 while (s3e == SQLITE_OK &&
3287 (q->q_limit == kSecMatchUnlimited || c->found < q->q_limit)) {
3288 s3e = sqlite3_step(stmt);
3289 if (s3e == SQLITE_ROW) {
3290 handle_row(stmt, context);
3291 /* Extract the error returned by handle_row. */
3292 s3e = q->q_error;
3293 if (s3e == errSecDecode) {
3294 secerror("Ignoring undecryptable %@ item: ", q->q_class->name);
3295 /* Ignore decode errors, since that means the item in question
3296 is unreadable forever, this allows export to skip these
3297 items and a backup/restore cycle to filter broken items
3298 from your keychain.
3299 Ideally we should mark the current rowid for removal since
3300 it's corrupt. The tricky bit is at this level we no longer
3301 know if the key or the cert failed to decode when dealing
3302 with identities. */
3303 s3e = SQLITE_OK;
3304 }
3305 } else if (s3e == SQLITE_DONE) {
3306 if (c->found == 0) {
3307 /* We ran out of rows and didn't get any matches yet. */
3308 s3e = errSecItemNotFound;
3309 } else {
3310 /* We got at least one match, so set the error status to ok. */
3311 s3e = SQLITE_OK;
3312 }
3313 break;
3314 } else if (s3e != SQLITE_OK) {
3315 secdebug("sql", "select: %d: %s", s3e, sqlite3_errmsg(s3h));
3316 }
3317 }
3318
3319 /* Free the stmt. */
3320 if (stmt) {
3321 int s3e2 = sqlite3_finalize(stmt);
3322 if (s3e2 != SQLITE_OK && s3e == SQLITE_OK)
3323 s3e = s3e2;
3324 }
3325
3326 OSStatus status;
3327 if (s3e) status = osstatus_for_s3e(s3e);
3328 else if (q->q_error) status = q->q_error;
3329 else return 0;
3330
3331 CFReleaseNull(c->result);
3332 return status;
3333 }
3334
3335 static OSStatus
3336 s3dl_copy_matching(s3dl_db_thread *dbt, Query *q, CFTypeRef *result,
3337 CFArrayRef accessGroups)
3338 {
3339 struct s3dl_query_ctx ctx = {
3340 .q = q, .accessGroups = accessGroups,
3341 };
3342 OSStatus status = s3dl_query(dbt, s3dl_query_row, CURRENT_DB_VERSION, &ctx);
3343 if (result)
3344 *result = ctx.result;
3345 else
3346 CFReleaseSafe(ctx.result);
3347 return status;
3348 }
3349
3350 static CFStringRef s3dl_update_sql(Query *q) {
3351 CFMutableStringRef sql = CFStringCreateMutable(NULL, 0);
3352 CFStringAppendFormat(sql, NULL, CFSTR("UPDATE %@ SET"), q->q_class->name);
3353
3354 CFIndex ix, attr_count = query_attr_count(q);
3355 for (ix = 0; ix < attr_count; ++ix) {
3356 CFStringAppendFormat(sql, NULL, CFSTR(" %@=?,"),
3357 query_attr_at(q, ix).key);
3358 }
3359 CFStringAppend(sql, CFSTR(" data=? WHERE ROWID=?;"));
3360
3361 return sql;
3362 }
3363
3364 /* Bind the parameters to the UPDATE statement; data=? and ROWID=? are left
3365 unbound, since they are bound in s3dl_update_row when the update statement
3366 is (re)used. */
3367 static int s3dl_update_bind(Query *q, sqlite3_stmt *stmt) {
3368 /* Bind the values being updated to the UPDATE statement. */
3369 int s3e = SQLITE_OK;
3370 int param = 1;
3371 CFIndex ix, attr_count = query_attr_count(q);
3372 for (ix = 0; s3e == SQLITE_OK && ix < attr_count; ++ix) {
3373 s3e = kc_bind_paramter(stmt, param++, query_attr_at(q, ix).value);
3374 }
3375 return s3e;
3376 }
3377
3378 /* AUDIT[securityd](done):
3379 attributesToUpdate (ok) is a caller provided dictionary,
3380 only its cf types have been checked.
3381 */
3382 static OSStatus
3383 s3dl_query_update(s3dl_db_thread *dbt, Query *q,
3384 CFDictionaryRef attributesToUpdate, CFArrayRef accessGroups)
3385 {
3386 /* Sanity check the query. */
3387 if (query_match_count(q) != 0)
3388 return errSecItemMatchUnsupported;
3389 if (q->q_ref)
3390 return errSecValueRefUnsupported;
3391 if (q->q_row_id && query_attr_count(q))
3392 return errSecItemIllegalQuery;
3393
3394 int s3e = SQLITE_OK;
3395
3396 Query *u = query_create(q->q_class, attributesToUpdate, &q->q_error);
3397 if (u == NULL) return q->q_error;
3398 if (!query_update_parse(u, attributesToUpdate, &q->q_error))
3399 goto errOut;
3400 query_pre_update(u);
3401
3402 /* Actual work here. */
3403 sqlite3 *s3h = dbt->s3_handle;
3404
3405 CFStringRef sql = s3dl_update_sql(u);
3406 sqlite3_stmt *stmt = NULL;
3407 s3e = kc_prepare_statement(s3h, sql, &stmt);
3408 CFRelease(sql);
3409
3410 if (s3e == SQLITE_OK)
3411 s3e = s3dl_update_bind(u, stmt);
3412
3413 if (s3e == SQLITE_OK) {
3414 s3e = s3dl_begin_transaction(dbt);
3415 q->q_return_type = 0;
3416 struct s3dl_update_row_ctx ctx = {
3417 .qc = {
3418 .q = q, .accessGroups = accessGroups,
3419 },
3420 .u = u,
3421 .update_stmt = stmt
3422 };
3423 u->q_error = s3dl_query(dbt, s3dl_update_row, CURRENT_DB_VERSION, &ctx);
3424 s3e = s3dl_end_transaction(dbt, s3e);
3425 }
3426
3427 /* Free the stmt. */
3428 if (stmt) {
3429 int s3e2 = sqlite3_finalize(stmt);
3430 if (s3e2 != SQLITE_OK && s3e == SQLITE_OK)
3431 s3e = s3e2;
3432 }
3433
3434 errOut:
3435 query_destroy(u, &q->q_error);
3436
3437 if (s3e) return osstatus_for_s3e(s3e);
3438 if (q->q_error) return q->q_error;
3439 return 0;
3440 }
3441
3442 static OSStatus
3443 s3dl_query_delete(s3dl_db_thread *dbt, Query *q, CFArrayRef accessGroups)
3444 {
3445 sqlite3 *s3h = dbt->s3_handle;
3446 sqlite3_stmt *stmt = NULL;
3447 CFMutableStringRef sql;
3448 int s3e;
3449
3450 sql = CFStringCreateMutable(NULL, 0);
3451 CFStringAppendFormat(sql, NULL, CFSTR("DELETE FROM %@"), q->q_class->name);
3452 sqlAppendWhereClause(sql, q, accessGroups);
3453 CFStringAppend(sql, CFSTR(";"));
3454 s3e = kc_prepare_statement(s3h, sql, &stmt);
3455 CFRelease(sql);
3456
3457 /* Bind the parameters to the DELETE statement. */
3458 if (s3e == SQLITE_OK) {
3459 int param = 1;
3460 s3e = sqlBindWhereClause(stmt, q, accessGroups, &param);
3461 }
3462
3463 /* Now execute the DELETE statement (step). */
3464 if (s3e == SQLITE_OK) {
3465 s3e = sqlite3_step(stmt);
3466 if (s3e == SQLITE_DONE) {
3467 int changes = sqlite3_changes(s3h);
3468 /* When doing a delete without a where clause sqlite reports 0
3469 changes since it drops and recreates the table rather than
3470 deleting all the records in it. */
3471 if (changes == 0 && query_attr_count(q) > 0) {
3472 s3e = errSecItemNotFound;
3473 } else {
3474 s3e = SQLITE_OK;
3475 secdebug("sql", "deleted: %d records", changes);
3476 }
3477 } else if (s3e != SQLITE_OK) {
3478 secdebug("sql", "delete: %d: %s", s3e, sqlite3_errmsg(s3h));
3479 }
3480 }
3481
3482 /* Free the stmt. */
3483 if (stmt) {
3484 int s3e2 = sqlite3_finalize(stmt);
3485 if (s3e2 != SQLITE_OK && s3e == SQLITE_OK)
3486 s3e = s3e2;
3487 }
3488
3489 return s3e;
3490 }
3491
3492 /* Return true iff the item in question should not be backed up, nor restored,
3493 but when restoring a backup the original version of the item should be
3494 added back to the keychain again after the restore completes. */
3495 static bool SecItemIsSystemBound(CFDictionaryRef item, const kc_class *class) {
3496 CFStringRef agrp = CFDictionaryGetValue(item, kSecAttrAccessGroup);
3497 if (!isString(agrp))
3498 return false;
3499
3500 if (CFEqual(agrp, CFSTR("lockdown-identities"))) {
3501 secdebug("backup", "found sys_bound item: %@", item);
3502 return true;
3503 }
3504
3505 if (CFEqual(agrp, CFSTR("apple")) && class == &genp_class) {
3506 CFStringRef service = CFDictionaryGetValue(item, kSecAttrService);
3507 CFStringRef account = CFDictionaryGetValue(item, kSecAttrAccount);
3508 if (isString(service) && isString(account) &&
3509 CFEqual(service, CFSTR("com.apple.managedconfiguration")) &&
3510 (CFEqual(account, CFSTR("Public")) ||
3511 CFEqual(account, CFSTR("Private")))) {
3512 secdebug("backup", "found sys_bound item: %@", item);
3513 return true;
3514 }
3515 }
3516 secdebug("backup", "found non sys_bound item: %@", item);
3517 return false;
3518 }
3519
3520 /* Delete all items from the current keychain. If this is not an in
3521 place upgrade we don't delete items in the 'lockdown-identities'
3522 access group, this ensures that an import or restore of a backup
3523 will never overwrite an existing activation record. */
3524 static OSStatus SecServerDeleteAll(s3dl_db_thread *dbt) {
3525 int s3e = sqlite3_exec(dbt->s3_handle,
3526 "DELETE from genp;"
3527 "DELETE from inet;"
3528 "DELETE FROM cert;"
3529 "DELETE FROM keys;",
3530 NULL, NULL, NULL);
3531 return s3e == SQLITE_OK ? 0 : osstatus_for_s3e(s3e);
3532 }
3533
3534 struct s3dl_export_row_ctx {
3535 struct s3dl_query_ctx qc;
3536 keybag_handle_t dest_keybag;
3537 enum SecItemFilter filter;
3538 int version;
3539 s3dl_db_thread *dbt;
3540 };
3541
3542 /* Return NULL if the current row isn't a match. Return kCFNull if the
3543 current row is a match and q->q_return_type == 0. Otherwise return
3544 whatever the caller requested based on the value of q->q_return_type. */
3545 static CFMutableDictionaryRef
3546 s3dl_item_from_pre_v5(sqlite3_stmt *stmt, Query *q, s3dl_db_thread *dbt,
3547 keyclass_t *keyclass, sqlite_int64 *rowid) {
3548 int cix = 0, cc = sqlite3_column_count(stmt);
3549
3550 CFMutableDictionaryRef item = CFDictionaryCreateMutable(0, 0,
3551 &kCFTypeDictionaryKeyCallBacks, & kCFTypeDictionaryValueCallBacks);
3552 for (cix = 0; cix < cc; ++cix) {
3553 const char *cname = sqlite3_column_name(stmt, cix);
3554 CFStringRef key = NULL;
3555 CFTypeRef value = NULL;
3556 int ctype = sqlite3_column_type(stmt, cix);
3557 switch (ctype) {
3558 case SQLITE_INTEGER:
3559 {
3560 sqlite_int64 i64Value = sqlite3_column_int64(stmt, cix);
3561 if (!strcmp(cname, "rowid")) {
3562 *rowid = i64Value;
3563 continue;
3564 } else if (i64Value > INT_MAX || i64Value < INT_MIN) {
3565 value = CFNumberCreate(0, kCFNumberLongLongType, &i64Value);
3566 } else {
3567 int iValue = (int)i64Value;
3568 value = CFNumberCreate(0, kCFNumberIntType, &iValue);
3569 }
3570 break;
3571 }
3572 case SQLITE_FLOAT:
3573 value = CFDateCreate(0, sqlite3_column_double(stmt, cix));
3574 break;
3575 case SQLITE_TEXT:
3576 value = CFStringCreateWithCString(0,
3577 (const char *)sqlite3_column_text(stmt, cix),
3578 kCFStringEncodingUTF8);
3579 break;
3580 case SQLITE_BLOB:
3581 value = CFDataCreate(0, sqlite3_column_blob(stmt, cix),
3582 sqlite3_column_bytes(stmt, cix));
3583 if (value && !strcmp(cname, "data")) {
3584 CFDataRef plain;
3585 if (q->q_keybag == KEYBAG_LEGACY) {
3586 q->q_error = kc_decrypt_data(dbt, value, &plain);
3587 } else {
3588 q->q_error = ks_decrypt_data(q->q_keybag, keyclass,
3589 value, &plain, 0);
3590 }
3591 CFRelease(value);
3592 if (q->q_error) {
3593 secerror("failed to decrypt data: %d", q->q_error);
3594 goto out;
3595 }
3596 value = plain;
3597 key = kSecValueData;
3598 }
3599 break;
3600 default:
3601 secwarning("Unsupported column type: %d", ctype);
3602 /*DROPTHROUGH*/
3603 case SQLITE_NULL:
3604 /* Don't return NULL valued attributes to the caller. */
3605 continue;
3606 }
3607
3608 if (!value)
3609 continue;
3610
3611 if (key) {
3612 CFDictionarySetValue(item, key, value);
3613 } else {
3614 key = CFStringCreateWithCString(0, cname, kCFStringEncodingUTF8);
3615 if (key) {
3616 CFDictionarySetValue(item, key, value);
3617 CFRelease(key);
3618 }
3619 }
3620 CFRelease(value);
3621 }
3622
3623 return item;
3624 out:
3625 CFReleaseSafe(item);
3626 return NULL;
3627 }
3628
3629 static void s3dl_export_row(sqlite3_stmt *stmt, void *context) {
3630 struct s3dl_export_row_ctx *c = context;
3631 Query *q = c->qc.q;
3632 keyclass_t keyclass = 0;
3633
3634 CFMutableDictionaryRef item;
3635 sqlite_int64 rowid = -1;
3636 if (c->version < 5) {
3637 item = s3dl_item_from_pre_v5(stmt, q, c->dbt, &keyclass, &rowid);
3638 } else {
3639 item = s3dl_item_from_col(stmt, q, 1, c->qc.accessGroups, &keyclass);
3640 rowid = sqlite3_column_int64(stmt, 0);
3641 }
3642
3643 if (item) {
3644 /* Only export sysbound items is do_sys_bound is true, only export non sysbound items otherwise. */
3645 bool do_sys_bound = c->filter == kSecSysBoundItemFilter;
3646 if (c->filter == kSecNoItemFilter ||
3647 SecItemIsSystemBound(item, q->q_class) == do_sys_bound) {
3648 /* Re-encode the item. */
3649 secdebug("item", "export rowid %llu item: %@", rowid, item);
3650 /* The code below could be moved into handle_row. */
3651 CFDataRef pref = _SecItemMakePersistentRef(q->q_class->name, rowid);
3652 if (pref) {
3653 if (c->dest_keybag != KEYBAG_NONE) {
3654 /* Encode and encrypt the item to the specified keybag. */
3655 CFDataRef plain = CFPropertyListCreateData(0, item, kCFPropertyListBinaryFormat_v1_0, 0, 0);
3656 CFDictionaryRemoveAllValues(item);
3657 if (plain) {
3658 CFDataRef edata = NULL;
3659 int s3e = ks_encrypt_data(c->dest_keybag, keyclass, plain, &edata);
3660 if (s3e)
3661 q->q_error = osstatus_for_s3e(s3e);
3662 if (edata) {
3663 CFDictionarySetValue(item, kSecValueData, edata);
3664 CFRelease(edata);
3665 }
3666 CFRelease(plain);
3667 }
3668 }
3669 if (CFDictionaryGetCount(item)) {
3670 CFDictionarySetValue(item, kSecValuePersistentRef, pref);
3671 CFArrayAppendValue((CFMutableArrayRef)c->qc.result, item);
3672 c->qc.found++;
3673 }
3674 CFRelease(pref);
3675 }
3676 }
3677 CFRelease(item);
3678 }
3679 }
3680
3681 static CFDictionaryRef SecServerExportKeychainPlist(s3dl_db_thread *dbt,
3682 keybag_handle_t src_keybag, keybag_handle_t dest_keybag,
3683 enum SecItemFilter filter, int version, OSStatus *error) {
3684 CFMutableDictionaryRef keychain;
3685 keychain = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
3686 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
3687 if (!keychain) {
3688 if (error && !*error)
3689 *error = errSecAllocate;
3690 goto errOut;
3691 }
3692 unsigned class_ix;
3693 Query q = { .q_keybag = src_keybag };
3694 q.q_return_type = kSecReturnDataMask | kSecReturnAttributesMask | \
3695 kSecReturnPersistentRefMask;
3696 q.q_limit = kSecMatchUnlimited;
3697
3698 /* Get rid of this duplicate. */
3699 const kc_class *kc_classes[] = {
3700 &genp_class,
3701 &inet_class,
3702 &cert_class,
3703 &keys_class
3704 };
3705
3706 for (class_ix = 0; class_ix < sizeof(kc_classes) / sizeof(*kc_classes);
3707 ++class_ix) {
3708 q.q_class = kc_classes[class_ix];
3709 struct s3dl_export_row_ctx ctx = {
3710 .qc = { .q = &q, },
3711 .dest_keybag = dest_keybag, .filter = filter, .version = version,
3712 .dbt = dbt,
3713 };
3714 ctx.qc.result = CFArrayCreateMutable(kCFAllocatorDefault, 0,
3715 &kCFTypeArrayCallBacks);
3716 if (ctx.qc.result) {
3717 OSStatus status = s3dl_query(dbt, s3dl_export_row, version, &ctx);
3718 if (status == noErr) {
3719 if (CFArrayGetCount(ctx.qc.result))
3720 CFDictionaryAddValue(keychain, q.q_class->name, ctx.qc.result);
3721 CFRelease(ctx.qc.result);
3722 } else if (status != errSecItemNotFound) {
3723 if (error && !*error)
3724 *error = status;
3725 if (status == errSecInteractionNotAllowed) {
3726 secerror("Device locked during attempted keychain upgrade");
3727 CFReleaseNull(keychain);
3728 break;
3729 }
3730 }
3731 }
3732 }
3733 errOut:
3734 return keychain;
3735 }
3736
3737 static OSStatus SecServerExportKeychain(s3dl_db_thread *dbt,
3738 keybag_handle_t src_keybag, keybag_handle_t dest_keybag,
3739 CFDataRef *data_out) {
3740 OSStatus status = noErr;
3741 /* Export everything except the items for which SecItemIsSystemBound()
3742 returns true. */
3743 CFDictionaryRef keychain = SecServerExportKeychainPlist(dbt,
3744 src_keybag, dest_keybag, kSecBackupableItemFilter, CURRENT_DB_VERSION,
3745 &status);
3746 if (keychain) {
3747 CFErrorRef error = NULL;
3748 *data_out = CFPropertyListCreateData(kCFAllocatorDefault, keychain,
3749 kCFPropertyListBinaryFormat_v1_0,
3750 0, &error);
3751 CFRelease(keychain);
3752 if (error) {
3753 secerror("Error encoding keychain: %@", error);
3754 status = (OSStatus)CFErrorGetCode(error); /* possibly truncated error code, whatever */
3755 CFRelease(error);
3756 }
3757 }
3758
3759 return status;
3760 }
3761
3762 struct SecServerImportClassState {
3763 s3dl_db_thread *dbt;
3764 OSStatus status;
3765 keybag_handle_t src_keybag;
3766 keybag_handle_t dest_keybag;
3767 enum SecItemFilter filter;
3768 };
3769
3770 struct SecServerImportItemState {
3771 const kc_class *class;
3772 struct SecServerImportClassState *s;
3773 };
3774
3775 /* Infer a keyclass for 3.x items being imported from a backup. Return NULL
3776 to leave keyclass unchanged. */
3777 static void SecItemImportInferAccessible(Query *q) {
3778 CFStringRef agrp = CFDictionaryGetValue(q->q_item, kSecAttrAccessGroup);
3779 CFStringRef accessible = NULL;
3780 if (isString(agrp)) {
3781 if (CFEqual(agrp, CFSTR("apple"))) {
3782 if (q->q_class == &cert_class) {
3783 /* apple certs are always dk. */
3784 accessible = kSecAttrAccessibleAlways;
3785 } else if (q->q_class == &genp_class) {
3786 CFStringRef svce = CFDictionaryGetValue(q->q_item, kSecAttrService);
3787 if (isString(svce)) {
3788 if (CFEqual(svce, CFSTR("iTools"))) {
3789 /* iTools password is dk for now. */
3790 accessible = kSecAttrAccessibleAlways;
3791 } else if (CFEqual(svce, CFSTR("BackupAgent"))) {
3792 /* We assume that acct == BackupPassword use aku. */
3793 accessible = kSecAttrAccessibleWhenUnlockedThisDeviceOnly;
3794 } else if (CFEqual(svce, CFSTR("MobileBluetooth"))) {
3795 /* MobileBlueTooh uses cku. */
3796 accessible = kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly;
3797 }
3798 }
3799 } else if (q->q_class == &inet_class) {
3800 CFStringRef ptcl = CFDictionaryGetValue(q->q_item, kSecAttrProtocol);
3801 if (isString(ptcl)) {
3802 /* LDAP is never needed without UI so ak. */
3803 if (CFEqual(ptcl, kSecAttrProtocolLDAP) ||
3804 CFEqual(ptcl, kSecAttrProtocolLDAPS)) {
3805 accessible = kSecAttrAccessibleWhenUnlocked;
3806 }
3807 }
3808 }
3809 if (accessible == NULL) {
3810 /* Everything not covered by a special case in the apple
3811 access group (including keys) ends up in class Ck. */
3812 accessible = kSecAttrAccessibleAfterFirstUnlock;
3813 }
3814 } else if (CFEqual(agrp, CFSTR("com.apple.apsd"))
3815 || CFEqual(agrp, CFSTR("lockdown-identities"))) {
3816 /* apsd and lockdown are always dku. */
3817 accessible = kSecAttrAccessibleAlwaysThisDeviceOnly;
3818 }
3819 }
3820 if (accessible == NULL) {
3821 if (q->q_class == &cert_class) {
3822 /* third party certs are always dk. */
3823 accessible = kSecAttrAccessibleAlways;
3824 } else {
3825 /* The rest defaults to ak. */
3826 accessible = kSecAttrAccessibleWhenUnlocked;
3827 }
3828 }
3829 query_add_attribute(kSecAttrAccessible, accessible, q);
3830 }
3831
3832 /* Infer accessibility and access group for pre-v2 (iOS4.x and earlier) items
3833 being imported from a backup. */
3834 static void SecItemImportMigrate(Query *q) {
3835 CFStringRef agrp = CFDictionaryGetValue(q->q_item, kSecAttrAccessGroup);
3836 CFStringRef accessible = CFDictionaryGetValue(q->q_item, kSecAttrAccessible);
3837
3838 if (!isString(agrp) || !isString(accessible))
3839 return;
3840 if (q->q_class == &genp_class && CFEqual(accessible, kSecAttrAccessibleAlways)) {
3841 CFStringRef svce = CFDictionaryGetValue(q->q_item, kSecAttrService);
3842 if (!isString(svce)) return;
3843 if (CFEqual(agrp, CFSTR("apple"))) {
3844 if (CFEqual(svce, CFSTR("AirPort"))) {
3845 query_set_attribute(kSecAttrAccessible, kSecAttrAccessibleAfterFirstUnlock, q);
3846 } else if (CFEqual(svce, CFSTR("com.apple.airplay.password"))) {
3847 query_set_attribute(kSecAttrAccessible, kSecAttrAccessibleWhenUnlocked, q);
3848 } else if (CFEqual(svce, CFSTR("YouTube"))) {
3849 query_set_attribute(kSecAttrAccessible, kSecAttrAccessibleWhenUnlocked, q);
3850 query_set_attribute(kSecAttrAccessGroup, CFSTR("com.apple.youtube.credentials"), q);
3851 } else {
3852 CFStringRef desc = CFDictionaryGetValue(q->q_item, kSecAttrDescription);
3853 if (!isString(desc)) return;
3854 if (CFEqual(desc, CFSTR("IPSec Shared Secret")) || CFEqual(desc, CFSTR("PPP Password"))) {
3855 query_set_attribute(kSecAttrAccessible, kSecAttrAccessibleAfterFirstUnlock, q);
3856 }
3857 }
3858 }
3859 } else if (q->q_class == &inet_class && CFEqual(accessible, kSecAttrAccessibleAlways)) {
3860 if (CFEqual(agrp, CFSTR("PrintKitAccessGroup"))) {
3861 query_set_attribute(kSecAttrAccessible, kSecAttrAccessibleWhenUnlocked, q);
3862 } else if (CFEqual(agrp, CFSTR("apple"))) {
3863 CFTypeRef ptcl = CFDictionaryGetValue(q->q_item, kSecAttrProtocol);
3864 bool is_proxy = false;
3865 if (isNumber(ptcl)) {
3866 SInt32 iptcl;
3867 CFNumberGetValue(ptcl, kCFNumberSInt32Type, &iptcl);
3868 is_proxy = (iptcl == FOUR_CHAR_CODE('htpx') ||
3869 iptcl == FOUR_CHAR_CODE('htsx') ||
3870 iptcl == FOUR_CHAR_CODE('ftpx') ||
3871 iptcl == FOUR_CHAR_CODE('rtsx') ||
3872 iptcl == FOUR_CHAR_CODE('xpth') ||
3873 iptcl == FOUR_CHAR_CODE('xsth') ||
3874 iptcl == FOUR_CHAR_CODE('xptf') ||
3875 iptcl == FOUR_CHAR_CODE('xstr'));
3876 } else if (isString(ptcl)) {
3877 is_proxy = (CFEqual(ptcl, kSecAttrProtocolHTTPProxy) ||
3878 CFEqual(ptcl, kSecAttrProtocolHTTPSProxy) ||
3879 CFEqual(ptcl, kSecAttrProtocolRTSPProxy) ||
3880 CFEqual(ptcl, kSecAttrProtocolFTPProxy));
3881 }
3882 if (is_proxy)
3883 query_set_attribute(kSecAttrAccessible, kSecAttrAccessibleWhenUnlocked, q);
3884 }
3885 }
3886 }
3887
3888 static void SecServerImportItem(const void *value, void *context) {
3889 struct SecServerImportItemState *state =
3890 (struct SecServerImportItemState *)context;
3891 if (state->s->status)
3892 return;
3893 if (!isDictionary(value)) {
3894 state->s->status = errSecParam;
3895 return;
3896 }
3897
3898 CFDictionaryRef item = (CFDictionaryRef)value;
3899
3900 /* We don't filter non sys_bound items during import since we know we
3901 will never have any in this case, we use the kSecSysBoundItemFilter
3902 to indicate that we don't preserve rowid's during import instead. */
3903 if (state->s->filter == kSecBackupableItemFilter &&
3904 SecItemIsSystemBound(item, state->class))
3905 return;
3906
3907 Query *q = query_create(state->class, item, &state->s->status);
3908 if (!q)
3909 return;
3910
3911 /* TODO: We'd like to use query_update_applier here instead of
3912 query_parse(), since only attrs, kSecValueData and kSecValuePersistentRef. */
3913 query_parse(q, item, &state->s->status);
3914
3915 CFDataRef pdata = NULL;
3916 if (state->s->src_keybag == KEYBAG_NONE) {
3917 /* Not strictly needed if we are restoring from cleartext db that is
3918 version 5 or later, but currently that never happens. Also the
3919 migrate code should be specific enough that it's still safe even
3920 in that case, it's just slower. */
3921 SecItemImportMigrate(q);
3922 } else {
3923 if (q->q_data) {
3924 keyclass_t keyclass;
3925 /* Decrypt the data using state->s->dest_keybag. */
3926 uint32_t version;
3927 q->q_error = ks_decrypt_data(state->s->src_keybag,
3928 &keyclass, q->q_data, &pdata, &version);
3929 if (q->q_error) {
3930 /* keyclass attribute doesn't match decoded value, fail. */
3931 q->q_error = errSecDecode;
3932 asl_log(NULL, NULL, ASL_LEVEL_ERR,
3933 "keyclass attribute %d doesn't match keyclass in blob %d",
3934 q->q_keyclass, keyclass);
3935 }
3936 if (version < 2) {
3937 /* Old V4 style keychain backup being imported. */
3938 /* Make sure the keyclass in the dictionary matched what we got
3939 back from decoding the data blob. */
3940 if (q->q_keyclass && q->q_keyclass != keyclass) {
3941 q->q_error = errSecDecode;
3942 asl_log(NULL, NULL, ASL_LEVEL_ERR,
3943 "keyclass attribute %d doesn't match keyclass in blob %d",
3944 q->q_keyclass, keyclass);
3945 } else {
3946 query_set_data(pdata, q);
3947 SecItemImportMigrate(q);
3948 }
3949 } else {
3950 /* version 2 or later backup. */
3951 CFErrorRef error = NULL;
3952 CFPropertyListFormat format;
3953 item = CFPropertyListCreateWithData(0, pdata, kCFPropertyListImmutable, &format, &error);
3954 if (item) {
3955 query_update_parse(q, item, &state->s->status);
3956 secdebug("item", "importing status: %ld %@",
3957 state->s->status, item);
3958 CFRelease(item);
3959 } else if (error) {
3960 secerror("failed to decode v%d item data: %@",
3961 version, error);
3962 CFRelease(error);
3963 }
3964 }
3965 }
3966 }
3967
3968 if (q->q_keyclass == 0)
3969 SecItemImportInferAccessible(q);
3970
3971 if (q->q_error) {
3972 state->s->status = q->q_error;
3973 } else {
3974 if (q->q_keyclass == 0) {
3975 state->s->status = errSecParam;
3976 } else {
3977 if (state->s->filter == kSecSysBoundItemFilter) {
3978 /* We don't set the rowid of sys_bound items we reimport
3979 after an import since that might fail if an item in the
3980 restored keychain already used that rowid. */
3981 q->q_row_id = 0;
3982 }
3983 query_pre_add(q, false);
3984 state->s->status = s3dl_query_add(state->s->dbt, q, NULL);
3985 }
3986 }
3987 CFReleaseSafe(pdata);
3988 query_destroy(q, &state->s->status);
3989
3990 /* Reset error if we had one, since we just skip the current item
3991 and continue importing what we can. */
3992 if (state->s->status) {
3993 secerror("Failed to import %@ item %ld ignoring error",
3994 state->class->name, state->s->status);
3995 state->s->status = 0;
3996 }
3997 }
3998
3999 static void SecServerImportClass(const void *key, const void *value,
4000 void *context) {
4001 struct SecServerImportClassState *state =
4002 (struct SecServerImportClassState *)context;
4003 if (state->status)
4004 return;
4005 if (!isString(key)) {
4006 state->status = errSecParam;
4007 return;
4008 }
4009 const void *desc = CFDictionaryGetValue(gClasses, key);
4010 const kc_class *class = desc;
4011 if (!class || class == &identity_class) {
4012 state->status = errSecParam;
4013 return;
4014 }
4015 struct SecServerImportItemState item_state = {
4016 .class = class, .s = state
4017 };
4018 if (isArray(value)) {
4019 CFArrayRef items = (CFArrayRef)value;
4020 CFArrayApplyFunction(items, CFRangeMake(0, CFArrayGetCount(items)),
4021 SecServerImportItem, &item_state);
4022 } else {
4023 CFDictionaryRef item = (CFDictionaryRef)value;
4024 SecServerImportItem(item, &item_state);
4025 }
4026 }
4027
4028 static OSStatus SecServerImportKeychainInPlist(s3dl_db_thread *dbt,
4029 keybag_handle_t src_keybag, keybag_handle_t dest_keybag,
4030 CFDictionaryRef keychain, enum SecItemFilter filter) {
4031 OSStatus status = errSecSuccess;
4032
4033 CFDictionaryRef sys_bound = NULL;
4034 if (filter == kSecBackupableItemFilter) {
4035 /* Grab a copy of all the items for which SecItemIsSystemBound()
4036 returns true. */
4037 require(sys_bound = SecServerExportKeychainPlist(dbt, KEYBAG_DEVICE,
4038 KEYBAG_NONE, kSecSysBoundItemFilter, CURRENT_DB_VERSION,
4039 &status), errOut);
4040 }
4041
4042 /* Delete everything in the keychain. */
4043 require_noerr(status = SecServerDeleteAll(dbt), errOut);
4044
4045 struct SecServerImportClassState state = {
4046 .dbt = dbt,
4047 .src_keybag = src_keybag,
4048 .dest_keybag = dest_keybag,
4049 .filter = filter
4050 };
4051 /* Import the provided items, preserving rowids. */
4052 CFDictionaryApplyFunction(keychain, SecServerImportClass, &state);
4053
4054 if (sys_bound) {
4055 state.src_keybag = KEYBAG_NONE;
4056 /* Import the items we preserved with random rowids. */
4057 state.filter = kSecSysBoundItemFilter;
4058 CFDictionaryApplyFunction(sys_bound, SecServerImportClass, &state);
4059 CFRelease(sys_bound);
4060 }
4061 status = state.status;
4062
4063 errOut:
4064 return status;
4065 }
4066
4067 static OSStatus SecServerImportKeychain(s3dl_db_thread *dbt,
4068 keybag_handle_t src_keybag,
4069 keybag_handle_t dest_keybag, CFDataRef data) {
4070 int s3e = s3dl_begin_transaction(dbt);
4071 OSStatus status = errSecSuccess;
4072 if (s3e != SQLITE_OK) {
4073 status = osstatus_for_s3e(s3e);
4074 } else {
4075 CFDictionaryRef keychain;
4076 CFPropertyListFormat format;
4077 CFErrorRef error = NULL;
4078 keychain = CFPropertyListCreateWithData(kCFAllocatorDefault, data,
4079 kCFPropertyListImmutable, &format,
4080 &error);
4081 if (keychain) {
4082 if (isDictionary(keychain)) {
4083 status = SecServerImportKeychainInPlist(dbt, src_keybag,
4084 dest_keybag, keychain,
4085 kSecBackupableItemFilter);
4086 } else {
4087 status = errSecParam;
4088 }
4089 CFRelease(keychain);
4090 } else {
4091 secerror("Error decoding keychain: %@", error);
4092 status = (OSStatus)CFErrorGetCode(error); /* possibly truncated error code, whatever */
4093 CFRelease(error);
4094 }
4095 }
4096
4097 s3e = s3dl_end_transaction(dbt, status);
4098 return status ? status : osstatus_for_s3e(s3e);
4099 }
4100
4101 static OSStatus
4102 SecServerMigrateKeychain(s3dl_db_thread *dbt,
4103 int32_t handle_in, CFDataRef data_in,
4104 int32_t *handle_out, CFDataRef *data_out) {
4105 OSStatus status;
4106
4107 if (handle_in == kSecMigrateKeychainImport) {
4108 if (data_in == NULL) {
4109 return errSecParam;
4110 }
4111 /* Import data_in. */
4112 status = SecServerImportKeychain(dbt, KEYBAG_NONE, KEYBAG_DEVICE, data_in);
4113 *data_out = NULL;
4114 *handle_out = 0;
4115 } else if (handle_in == kSecMigrateKeychainExport) {
4116 if (data_in != NULL) {
4117 return errSecParam;
4118 }
4119 /* Export the keychain and return the result in data_out. */
4120 status = SecServerExportKeychain(dbt, KEYBAG_DEVICE, KEYBAG_NONE, data_out);
4121 *handle_out = 0;
4122 } else {
4123 status = errSecParam;
4124 }
4125
4126 return status;
4127 }
4128
4129 static keybag_handle_t ks_open_keybag(CFDataRef keybag, CFDataRef password) {
4130 #if USE_KEYSTORE
4131 uint64_t outputs[] = { KEYBAG_NONE };
4132 uint32_t num_outputs = sizeof(outputs) / sizeof(*outputs);
4133 IOReturn kernResult;
4134
4135 kernResult = IOConnectCallMethod(keystore,
4136 kAppleKeyStoreKeyBagCreateWithData, NULL, 0, CFDataGetBytePtr(keybag),
4137 CFDataGetLength(keybag), outputs, &num_outputs, NULL, 0);
4138 if (kernResult) {
4139 asl_log(NULL, NULL, ASL_LEVEL_ERR,
4140 "kAppleKeyStoreKeyBagCreateWithData: %x", kernResult);
4141 goto errOut;
4142 }
4143 if (password) {
4144 kernResult = IOConnectCallMethod(keystore, kAppleKeyStoreKeyBagUnlock,
4145 outputs, 1, CFDataGetBytePtr(password), CFDataGetLength(password),
4146 NULL, 0, NULL, NULL);
4147 if (kernResult) {
4148 asl_log(NULL, NULL, ASL_LEVEL_ERR,
4149 "kAppleKeyStoreKeyBagCreateWithData: %x", kernResult);
4150 goto errOut;
4151 }
4152 }
4153 return (keybag_handle_t)outputs[0];
4154 errOut:
4155 return -3;
4156 #else
4157 return KEYBAG_NONE;
4158 #endif
4159 }
4160
4161 static void ks_close_keybag(keybag_handle_t keybag) {
4162 #if USE_KEYSTORE
4163 uint64_t inputs[] = { keybag };
4164 IOReturn kernResult = IOConnectCallMethod(keystore,
4165 kAppleKeyStoreKeyBagRelease, inputs, 1, NULL, 0, NULL, NULL, NULL, 0);
4166 if (kernResult) {
4167 asl_log(NULL, NULL, ASL_LEVEL_ERR,
4168 "kAppleKeyStoreKeyBagRelease: %d: %x", keybag, kernResult);
4169 }
4170 #endif
4171 }
4172
4173 static OSStatus SecServerKeychainBackup(s3dl_db_thread *dbt, CFDataRef keybag,
4174 CFDataRef password, CFDataRef *backup) {
4175 OSStatus status;
4176 keybag_handle_t backup_keybag = ks_open_keybag(keybag, password);
4177 /* Export from system keybag to backup keybag. */
4178 status = SecServerExportKeychain(dbt, KEYBAG_DEVICE, backup_keybag,
4179 backup);
4180 ks_close_keybag(backup_keybag);
4181 return status;
4182 }
4183
4184 static OSStatus SecServerKeychainRestore(s3dl_db_thread *dbt, CFDataRef backup,
4185 CFDataRef keybag, CFDataRef password) {
4186 OSStatus status;
4187 keybag_handle_t backup_keybag = ks_open_keybag(keybag, password);
4188 /* Import from backup keybag to system keybag. */
4189 status = SecServerImportKeychain(dbt, backup_keybag, KEYBAG_DEVICE,
4190 backup);
4191 ks_close_keybag(backup_keybag);
4192 return status;
4193 }
4194
4195 /* External SPI support code. */
4196
4197 /* Pthread_once protecting the kc_dbhandle and the singleton kc_dbhandle. */
4198 static pthread_once_t kc_dbhandle_init_once = PTHREAD_ONCE_INIT;
4199 static db_handle kc_dbhandle = NULL;
4200
4201 /* This function is called only once and should initialize kc_dbhandle. */
4202 static void kc_dbhandle_init(void)
4203 {
4204 #if 0
4205 CFTypeRef kc_attributes[] = {
4206 kSecAttrAccessible,
4207 kSecAttrAccessGroup,
4208 kSecAttrCreationDate,
4209 kSecAttrModificationDate,
4210 kSecAttrDescription,
4211 kSecAttrComment,
4212 kSecAttrCreator,
4213 kSecAttrType,
4214 kSecAttrLabel,
4215 kSecAttrIsInvisible,
4216 kSecAttrIsNegative,
4217 kSecAttrAccount,
4218 kSecAttrService,
4219 kSecAttrGeneric,
4220 kSecAttrSecurityDomain,
4221 kSecAttrServer,
4222 kSecAttrProtocol,
4223 kSecAttrAuthenticationType,
4224 kSecAttrPort,
4225 kSecAttrPath,
4226 kSecAttrSubject,
4227 kSecAttrIssuer,
4228 kSecAttrSerialNumber,
4229 kSecAttrSubjectKeyID,
4230 kSecAttrPublicKeyHash,
4231 kSecAttrCertificateType,
4232 kSecAttrCertificateEncoding,
4233 kSecAttrKeyClass,
4234 kSecAttrApplicationLabel,
4235 kSecAttrIsPermanent,
4236 kSecAttrApplicationTag,
4237 kSecAttrKeyType,
4238 kSecAttrKeySizeInBits,
4239 kSecAttrEffectiveKeySize,
4240 kSecAttrCanEncrypt,
4241 kSecAttrCanDecrypt,
4242 kSecAttrCanDerive,
4243 kSecAttrCanSign,
4244 kSecAttrCanVerify,
4245 kSecAttrCanWrap,
4246 kSecAttrCanUnwrap,
4247 kSecAttrScriptCode,
4248 kSecAttrAlias,
4249 kSecAttrHasCustomIcon,
4250 kSecAttrVolume,
4251 kSecAttrAddress,
4252 kSecAttrAFPServerSignature,
4253 kSecAttrCRLType,
4254 kSecAttrCRLEncoding,
4255 kSecAttrKeyCreator,
4256 kSecAttrIsPrivate,
4257 kSecAttrIsModifiable,
4258 kSecAttrStartDate,
4259 kSecAttrEndDate,
4260 kSecAttrIsSensitive,
4261 kSecAttrWasAlwaysSensitive,
4262 kSecAttrIsExtractable,
4263 kSecAttrWasNeverExtractable,
4264 kSecAttrCanSignRecover,
4265 kSecAttrCanVerifyRecover
4266 };
4267 #endif
4268 CFTypeRef kc_class_names[] = {
4269 kSecClassGenericPassword,
4270 kSecClassInternetPassword,
4271 kSecClassCertificate,
4272 kSecClassKey,
4273 kSecClassIdentity
4274 };
4275 const void *kc_classes[] = {
4276 &genp_class,
4277 &inet_class,
4278 &cert_class,
4279 &keys_class,
4280 &identity_class
4281 };
4282
4283 #if 0
4284 gAttributes = CFSetCreate(kCFAllocatorDefault, kc_attributes,
4285 sizeof(kc_attributes) / sizeof(*kc_attributes), &kCFTypeSetCallBacks);
4286 #endif
4287 gClasses = CFDictionaryCreate(kCFAllocatorDefault, kc_class_names,
4288 kc_classes,
4289 sizeof(kc_classes) / sizeof(*kc_classes),
4290 &kCFTypeDictionaryKeyCallBacks, 0);
4291
4292 const char *kcRelPath;
4293
4294 bool use_hwaes = hwaes_key_available();
4295 if (use_hwaes) {
4296 asl_log(NULL, NULL, ASL_LEVEL_INFO, "using hwaes key");
4297 kcRelPath = "/Library/Keychains/keychain-2.db";
4298 } else {
4299 asl_log(NULL, NULL, ASL_LEVEL_ERR, "unable to access hwaes key");
4300 kcRelPath = "/Library/Keychains/keychain-2-debug.db";
4301 }
4302
4303 bool autocommit = true;
4304 bool create = true;
4305
4306 #if NO_SERVER
4307 /* Added this block of code back to keep the tests happy for now. */
4308 const char *home = getenv("HOME");
4309 char path[PATH_MAX];
4310 size_t homeLen = strlen(home);
4311 size_t kcRelPathLen = strlen(kcRelPath);
4312 if (homeLen + kcRelPathLen > sizeof(path))
4313 return;
4314 strlcpy(path, home, sizeof(path));
4315 strlcat(path, kcRelPath, sizeof(path));
4316 kcRelPath = path;
4317 #endif
4318 s3dl_create_db_handle(kcRelPath, &kc_dbhandle, NULL /* dbt */, autocommit,
4319 create, use_hwaes);
4320 }
4321
4322 #if NO_SERVER
4323 void kc_dbhandle_reset(void);
4324 void kc_dbhandle_reset(void)
4325 {
4326 s3dl_close_db_handle(kc_dbhandle);
4327 kc_dbhandle_init();
4328 }
4329 #endif
4330
4331
4332 /* Return a per thread dbt handle for the keychain. If create is true create
4333 the database if it does not yet exist. If it is false, just return an
4334 error if it fails to auto-create. */
4335 static int kc_get_dbt(s3dl_db_thread **dbt, bool create)
4336 {
4337 return s3dl_get_dbt(kc_dbhandle, dbt);
4338 }
4339
4340 static int kc_release_dbt(s3dl_db_thread *dbt)
4341 {
4342 #if CLOSE_DB
4343 s3dl_dbt_destructor(dbt);
4344 pthread_setspecific(dbt->db->key, NULL);
4345 //int s3e = s3dl_close_db_handle(dbt->db);
4346 //return s3e;
4347 #endif
4348 return SQLITE_OK;
4349 }
4350
4351
4352 /****************************************************************************
4353 **************** Beginning of Externally Callable Interface ****************
4354 ****************************************************************************/
4355
4356
4357 /* AUDIT[securityd](done):
4358 query (ok) is a caller provided dictionary, only its cf type has been checked.
4359 */
4360 OSStatus
4361 _SecItemCopyMatching(CFDictionaryRef query, CFTypeRef *result,
4362 CFArrayRef accessGroups)
4363 {
4364 pthread_once(&kc_dbhandle_init_once, kc_dbhandle_init);
4365 CFIndex ag_count;
4366 if (!accessGroups || 0 == (ag_count = CFArrayGetCount(accessGroups)))
4367 return errSecMissingEntitlement;
4368
4369 /* Having the special accessGroup "*" allows access to all accessGroups. */
4370 if (CFArrayContainsValue(accessGroups, CFRangeMake(0, ag_count), CFSTR("*")))
4371 accessGroups = NULL;
4372
4373 OSStatus error = 0;
4374 Query *q = query_create_with_limit(query, 1, &error);
4375 if (q) {
4376 CFStringRef agrp = CFDictionaryGetValue(q->q_item, kSecAttrAccessGroup);
4377 if (agrp && accessGroupsAllows(accessGroups, agrp)) {
4378 const void *val = agrp;
4379 accessGroups = CFArrayCreate(0, &val, 1, &kCFTypeArrayCallBacks);
4380 } else {
4381 CFRetainSafe(accessGroups);
4382 }
4383
4384 /* Sanity check the query. */
4385 if (q->q_use_item_list) {
4386 error = errSecUseItemListUnsupported;
4387 #if defined(MULTIPLE_KEYCHAINS)
4388 } else if (q->q_use_keychain) {
4389 error = errSecUseKeychainUnsupported;
4390 #endif
4391 } else if (q->q_return_type != 0 && result == NULL) {
4392 error = errSecReturnMissingPointer;
4393 } else if (!q->q_error) {
4394 s3dl_db_thread *dbt;
4395 int s3e = s3dl_get_dbt(kc_dbhandle, &dbt);
4396 if (s3e == SQLITE_OK) {
4397 s3e = s3dl_copy_matching(dbt, q, result, accessGroups);
4398 /* TODO: Check error of this function if s3e is noErr. */
4399 kc_release_dbt(dbt);
4400 }
4401 if (s3e)
4402 error = osstatus_for_s3e(s3e);
4403 }
4404
4405 CFReleaseSafe(accessGroups);
4406 query_destroy(q, &error);
4407 }
4408
4409 return error;
4410 }
4411
4412 /* AUDIT[securityd](done):
4413 attributes (ok) is a caller provided dictionary, only its cf type has
4414 been checked.
4415 */
4416 OSStatus
4417 _SecItemAdd(CFDictionaryRef attributes, CFTypeRef *result,
4418 CFArrayRef accessGroups)
4419 {
4420 pthread_once(&kc_dbhandle_init_once, kc_dbhandle_init);
4421 CFIndex ag_count;
4422 if (!accessGroups || 0 == (ag_count = CFArrayGetCount(accessGroups)))
4423 return errSecMissingEntitlement;
4424
4425 OSStatus error = 0;
4426 Query *q = query_create_with_limit(attributes, 0, &error);
4427 if (q) {
4428 /* Access group sanity checking. */
4429 CFStringRef agrp = (CFStringRef)CFDictionaryGetValue(attributes,
4430 kSecAttrAccessGroup);
4431
4432 CFArrayRef ag = accessGroups;
4433 /* Having the special accessGroup "*" allows access to all accessGroups. */
4434 if (CFArrayContainsValue(accessGroups, CFRangeMake(0, ag_count), CFSTR("*")))
4435 accessGroups = NULL;
4436
4437 if (agrp) {
4438 /* The user specified an explicit access group, validate it. */
4439 if (!accessGroupsAllows(accessGroups, agrp))
4440 return errSecNoAccessForItem;
4441 } else {
4442 agrp = (CFStringRef)CFArrayGetValueAtIndex(ag, 0);
4443
4444 /* We are using an implicit access group, add it as if the user
4445 specified it as an attribute. */
4446 query_add_attribute(kSecAttrAccessGroup, agrp, q);
4447 }
4448
4449 query_ensure_keyclass(q, agrp);
4450
4451 if (q->q_row_id)
4452 error = errSecValuePersistentRefUnsupported;
4453 #if defined(MULTIPLE_KEYCHAINS)
4454 else if (q->q_use_keychain_list)
4455 error = errSecUseKeychainListUnsupported;
4456 #endif
4457 else if (!q->q_error) {
4458 s3dl_db_thread *dbt;
4459 int s3e = s3dl_get_dbt(kc_dbhandle, &dbt);
4460 if (s3e == SQLITE_OK) {
4461 s3e = s3dl_begin_transaction(dbt);
4462 if (s3e == SQLITE_OK) {
4463 query_pre_add(q, true);
4464 s3e = s3dl_query_add(dbt, q, result);
4465 }
4466 s3e = s3dl_end_transaction(dbt, s3e);
4467 }
4468
4469 /* TODO: Check error on this function if s3e is 0. */
4470 kc_release_dbt(dbt);
4471
4472 if (s3e)
4473 error = osstatus_for_s3e(s3e);
4474 }
4475 query_destroy(q, &error);
4476 }
4477 return error;
4478 }
4479
4480 /* AUDIT[securityd](done):
4481 query (ok) and attributesToUpdate (ok) are a caller provided dictionaries,
4482 only their cf types have been checked.
4483 */
4484 OSStatus
4485 _SecItemUpdate(CFDictionaryRef query,
4486 CFDictionaryRef attributesToUpdate, CFArrayRef accessGroups)
4487 {
4488 pthread_once(&kc_dbhandle_init_once, kc_dbhandle_init);
4489 CFIndex ag_count;
4490 if (!accessGroups || 0 == (ag_count = CFArrayGetCount(accessGroups)))
4491 return errSecMissingEntitlement;
4492
4493 /* Having the special accessGroup "*" allows access to all accessGroups. */
4494 if (CFArrayContainsValue(accessGroups, CFRangeMake(0, ag_count), CFSTR("*")))
4495 accessGroups = NULL;
4496
4497 OSStatus error = 0;
4498 Query *q = query_create_with_limit(query, kSecMatchUnlimited, &error);
4499 if (q) {
4500 /* Sanity check the query. */
4501 if (q->q_use_item_list) {
4502 error = errSecUseItemListUnsupported;
4503 } else if (q->q_return_type & kSecReturnDataMask) {
4504 /* Update doesn't return anything so don't ask for it. */
4505 error = errSecReturnDataUnsupported;
4506 } else if (q->q_return_type & kSecReturnAttributesMask) {
4507 error = errSecReturnAttributesUnsupported;
4508 } else if (q->q_return_type & kSecReturnRefMask) {
4509 error = errSecReturnRefUnsupported;
4510 } else {
4511 /* Access group sanity checking. */
4512 CFStringRef agrp = (CFStringRef)CFDictionaryGetValue(attributesToUpdate,
4513 kSecAttrAccessGroup);
4514 if (agrp) {
4515 /* The user is attempting to modify the access group column,
4516 validate it to make sure the new value is allowable. */
4517 if (!accessGroupsAllows(accessGroups, agrp))
4518 error = errSecNoAccessForItem;
4519 }
4520
4521 if (!error) {
4522 s3dl_db_thread *dbt;
4523 int s3e = s3dl_get_dbt(kc_dbhandle, &dbt);
4524 if (s3e == SQLITE_OK) {
4525 s3e = s3dl_query_update(dbt, q, attributesToUpdate, accessGroups);
4526
4527 /* TODO: Check error on this function if s3e is 0. */
4528 kc_release_dbt(dbt);
4529 }
4530
4531 if (s3e)
4532 error = osstatus_for_s3e(s3e);
4533 }
4534 }
4535 query_destroy(q, &error);
4536 }
4537 return error;
4538 }
4539
4540 /* AUDIT[securityd](done):
4541 query (ok) is a caller provided dictionary, only its cf type has been checked.
4542 */
4543 OSStatus
4544 _SecItemDelete(CFDictionaryRef query, CFArrayRef accessGroups)
4545 {
4546 pthread_once(&kc_dbhandle_init_once, kc_dbhandle_init);
4547 CFIndex ag_count;
4548 if (!accessGroups || 0 == (ag_count = CFArrayGetCount(accessGroups)))
4549 return errSecMissingEntitlement;
4550
4551 /* Having the special accessGroup "*" allows access to all accessGroups. */
4552 if (CFArrayContainsValue(accessGroups, CFRangeMake(0, ag_count), CFSTR("*")))
4553 accessGroups = NULL;
4554
4555 OSStatus error = 0;
4556 Query *q = query_create_with_limit(query, kSecMatchUnlimited, &error);
4557 if (q) {
4558 /* Sanity check the query. */
4559 if (q->q_limit != kSecMatchUnlimited)
4560 error = errSecMatchLimitUnsupported;
4561 else if (query_match_count(q) != 0)
4562 error = errSecItemMatchUnsupported;
4563 else if (q->q_ref)
4564 error = errSecValueRefUnsupported;
4565 else if (q->q_row_id && query_attr_count(q))
4566 error = errSecItemIllegalQuery;
4567 else {
4568 s3dl_db_thread *dbt;
4569 int s3e = s3dl_get_dbt(kc_dbhandle, &dbt);
4570 if (s3e == SQLITE_OK) {
4571 s3e = s3dl_query_delete(dbt, q, accessGroups);
4572
4573 /* TODO: Check error on this function if s3e is 0. */
4574 kc_release_dbt(dbt);
4575 }
4576 if (s3e)
4577 error = osstatus_for_s3e(s3e);
4578 }
4579 query_destroy(q, &error);
4580 }
4581 return error;
4582 }
4583
4584 /* AUDIT[securityd](done):
4585 No caller provided inputs.
4586 */
4587 bool
4588 _SecItemDeleteAll(void)
4589 {
4590 pthread_once(&kc_dbhandle_init_once, kc_dbhandle_init);
4591 static const char deleteAllSQL[] = "BEGIN EXCLUSIVE TRANSACTION; "
4592 "DELETE from inet; DELETE from cert; DELETE from keys; DELETE from genp; "
4593 "COMMIT TRANSACTION; VACUUM;";
4594
4595 s3dl_db_thread *dbt;
4596 int s3e = kc_get_dbt(&dbt, true);
4597 if (s3e == SQLITE_OK) {
4598 s3e = sqlite3_exec(dbt->s3_handle, deleteAllSQL, NULL, NULL, NULL);
4599 kc_release_dbt(dbt);
4600 }
4601 return (s3e == SQLITE_OK);
4602 }
4603
4604 /* TODO: Move to a location shared between securityd and Security framework. */
4605 static const char *restore_keychain_location = "/Library/Keychains/keychain.restoring";
4606
4607 /* AUDIT[securityd](done):
4608 No caller provided inputs.
4609 */
4610 OSStatus
4611 _SecServerRestoreKeychain(void)
4612 {
4613 static db_handle restore_dbhandle = NULL;
4614 s3dl_db_thread *restore_dbt = NULL, *dbt = NULL;
4615 CFDataRef backup = NULL;
4616 OSStatus status = errSecSuccess;
4617 int s3e;
4618
4619 pthread_once(&kc_dbhandle_init_once, kc_dbhandle_init);
4620 require_noerr(s3e = s3dl_get_dbt(kc_dbhandle, &dbt), errOut);
4621
4622 /* Export everything from the keychain we are restoring, this upgrades it
4623 to whatever version is current first if needed. */
4624 bool use_hwaes = hwaes_key_available();
4625 require_noerr(s3e = s3dl_create_db_handle(restore_keychain_location,
4626 &restore_dbhandle, &restore_dbt, true, false, use_hwaes), errOut);
4627 require_noerr(status = SecServerExportKeychain(restore_dbt, KEYBAG_DEVICE,
4628 KEYBAG_NONE, &backup), errOut);
4629 require_noerr(status = SecServerImportKeychain(dbt, KEYBAG_NONE,
4630 KEYBAG_DEVICE, backup), errOut);
4631
4632 errOut:
4633 s3e = s3dl_close_db_handle(restore_dbhandle);
4634 CFReleaseSafe(backup);
4635 kc_release_dbt(restore_dbt);
4636 kc_release_dbt(dbt);
4637
4638 if (s3e != SQLITE_OK)
4639 return osstatus_for_s3e(s3e);
4640 return status;
4641 }
4642
4643 /* AUDIT[securityd](done):
4644 args_in (ok) is a caller provided, CFArrayRef.
4645 */
4646 OSStatus
4647 _SecServerMigrateKeychain(CFArrayRef args_in, CFTypeRef *args_out)
4648 {
4649 pthread_once(&kc_dbhandle_init_once, kc_dbhandle_init);
4650 CFMutableArrayRef args = NULL;
4651 CFNumberRef hin = NULL, hout = NULL;
4652 int32_t handle_in, handle_out = 0;
4653 CFDataRef data_in, data_out = NULL;
4654 OSStatus status = errSecParam;
4655 CFIndex argc = CFArrayGetCount(args_in);
4656
4657 s3dl_db_thread *dbt;
4658 int s3e = s3dl_get_dbt(kc_dbhandle, &dbt);
4659 if (s3e != SQLITE_OK)
4660 return osstatus_for_s3e(s3e);
4661
4662 require_quiet(argc == 1 || argc == 2, errOut);
4663 hin = (CFNumberRef)CFArrayGetValueAtIndex(args_in, 0);
4664 require_quiet(isNumberOfType(hin, kCFNumberSInt32Type), errOut);
4665 require_quiet(CFNumberGetValue(hin, kCFNumberSInt32Type, &handle_in), errOut);
4666 if (argc > 1) {
4667 data_in = (CFDataRef)CFArrayGetValueAtIndex(args_in, 1);
4668 require_quiet(data_in, errOut);
4669 require_quiet(CFGetTypeID(data_in) == CFDataGetTypeID(), errOut);
4670 } else {
4671 data_in = NULL;
4672 }
4673
4674 secdebug("migrate", "migrate: %d %d", handle_in, data_in);
4675
4676 status = SecServerMigrateKeychain(dbt, handle_in, data_in, &handle_out, &data_out);
4677
4678 require_quiet(args = CFArrayCreateMutable(kCFAllocatorDefault, 2, &kCFTypeArrayCallBacks), errOut);
4679 require_quiet(hout = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &handle_out), errOut);
4680 CFArrayAppendValue(args, hout);
4681 if (data_out)
4682 CFArrayAppendValue(args, data_out);
4683 *args_out = args;
4684 args = NULL;
4685
4686 errOut:
4687 kc_release_dbt(dbt);
4688 CFReleaseSafe(args);
4689 CFReleaseSafe(hout);
4690 CFReleaseSafe(data_out);
4691 return status;
4692 }
4693
4694 OSStatus
4695 _SecServerKeychainBackup(CFArrayRef args_in, CFTypeRef *args_out) {
4696 pthread_once(&kc_dbhandle_init_once, kc_dbhandle_init);
4697 OSStatus status = errSecParam;
4698 CFIndex argc = args_in ? CFArrayGetCount(args_in) : 0;
4699 CFDataRef backup = NULL;
4700
4701 s3dl_db_thread *dbt;
4702 int s3e = s3dl_get_dbt(kc_dbhandle, &dbt);
4703 if (s3e != SQLITE_OK)
4704 return osstatus_for_s3e(s3e);
4705
4706 require_quiet(args_out != NULL, errOut);
4707 if (argc == 0) {
4708 #if USE_KEYSTORE
4709 require_noerr_quiet(status = SecServerExportKeychain(dbt, KEYBAG_DEVICE, backup_keybag_handle, &backup), errOut);
4710 #else
4711 goto errOut;
4712 #endif
4713 }
4714 else if (argc == 1 || argc == 2) {
4715 CFDataRef keybag = (CFDataRef)CFArrayGetValueAtIndex(args_in, 0);
4716 require_quiet(isData(keybag), errOut);
4717 CFDataRef password;
4718 if (argc > 1) {
4719 password = (CFDataRef)CFArrayGetValueAtIndex(args_in, 1);
4720 require_quiet(isData(password), errOut);
4721 } else {
4722 password = NULL;
4723 }
4724 require_noerr_quiet(status = SecServerKeychainBackup(dbt, keybag, password, &backup), errOut);
4725 }
4726 *args_out = backup;
4727
4728 errOut:
4729 kc_release_dbt(dbt);
4730 return status;
4731 }
4732
4733 OSStatus
4734 _SecServerKeychainRestore(CFArrayRef args_in, CFTypeRef *dummy) {
4735 pthread_once(&kc_dbhandle_init_once, kc_dbhandle_init);
4736 OSStatus status = errSecParam;
4737 CFIndex argc = CFArrayGetCount(args_in);
4738
4739 s3dl_db_thread *dbt;
4740 int s3e = s3dl_get_dbt(kc_dbhandle, &dbt);
4741 if (s3e != SQLITE_OK)
4742 return osstatus_for_s3e(s3e);
4743
4744 require_quiet(argc == 2 || argc == 3, errOut);
4745 CFDataRef backup = (CFDataRef)CFArrayGetValueAtIndex(args_in, 0);
4746 require_quiet(isData(backup), errOut);
4747 CFDataRef keybag = (CFDataRef)CFArrayGetValueAtIndex(args_in, 1);
4748 require_quiet(isData(keybag), errOut);
4749 CFDataRef password;
4750 if (argc > 2) {
4751 password = (CFDataRef)CFArrayGetValueAtIndex(args_in, 2);
4752 require_quiet(isData(password), errOut);
4753 } else {
4754 password = NULL;
4755 }
4756
4757 status = SecServerKeychainRestore(dbt, backup, keybag, password);
4758 if (!backup) {
4759 }
4760 if (dummy) {
4761 *dummy = NULL;
4762 }
4763
4764 status = errSecSuccess;
4765 errOut:
4766 kc_release_dbt(dbt);
4767 return status;
4768 }