]> git.saurik.com Git - apple/security.git/blob - sec/securityd/SecItemServer.c
Security-55471.14.18.tar.gz
[apple/security.git] / sec / securityd / SecItemServer.c
1 /*
2 * Copyright (c) 2006-2013 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 #include <securityd/SecDbItem.h>
32
33 #include <Security/SecItem.h>
34 #include <Security/SecItemPriv.h>
35 #include <Security/SecItemInternal.h>
36 #include <Security/SecKey.h>
37 #include <Security/SecKeyPriv.h>
38 #include <Security/SecCertificateInternal.h>
39 #include <Security/SecIdentity.h>
40 #include <Security/SecIdentityPriv.h>
41 #include <Security/SecFramework.h>
42 #include <Security/SecRandom.h>
43 #include <Security/SecBasePriv.h>
44 #include <utilities/SecIOFormat.h>
45 #include <utilities/SecCFWrappers.h>
46 #include <utilities/SecCFError.h>
47 #include <utilities/der_plist.h>
48 #include <limits.h>
49 #include <stdint.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <sys/param.h>
53 #include <sys/stat.h>
54 #include <Security/SecBase.h>
55 #include <CoreFoundation/CFData.h>
56 #include <CoreFoundation/CFDate.h>
57 #include <CoreFoundation/CFArray.h>
58 #include <CoreFoundation/CFDictionary.h>
59 #include <CoreFoundation/CFNumber.h>
60 #include <CoreFoundation/CFString.h>
61 #include <CoreFoundation/CFURL.h>
62 #include <CommonCrypto/CommonDigest.h>
63 #include <CommonCrypto/CommonDigestSPI.h>
64 #include <CommonCrypto/CommonCryptor.h>
65 #include <CommonCrypto/CommonCryptorSPI.h>
66 #include <libkern/OSByteOrder.h>
67 #include <utilities/debugging.h>
68 #include <assert.h>
69 #include <Security/SecInternal.h>
70 #include "securityd_client.h"
71 #include "utilities/sqlutils.h"
72 #include "utilities/SecIOFormat.h"
73 #include "utilities/SecFileLocations.h"
74 #include <utilities/iCloudKeychainTrace.h>
75 #include <AssertMacros.h>
76 #include <asl.h>
77 #include <inttypes.h>
78 #include <utilities/array_size.h>
79 #include <utilities/SecDb.h>
80 #include <securityd/SOSCloudCircleServer.h>
81 #include <notify.h>
82 #include "OTATrustUtilities.h"
83
84 #if USE_KEYSTORE
85 #include <IOKit/IOKitLib.h>
86 #include <libaks.h>
87 #if TARGET_OS_EMBEDDED
88 #include <MobileKeyBag/MobileKeyBag.h>
89 #endif
90 #endif /* USE_KEYSTORE */
91
92
93 /* g_keychain_handle is the keybag handle used for encrypting item in the keychain.
94 For testing purposes, it can be set to something other than the default, with SecItemServerSetKeychainKeybag */
95 #if USE_KEYSTORE
96 #if TARGET_OS_MAC && !TARGET_OS_EMBEDDED
97 static keybag_handle_t g_keychain_keybag = session_keybag_handle;
98 #else
99 static keybag_handle_t g_keychain_keybag = device_keybag_handle;
100 #endif
101 #else /* !USE_KEYSTORE */
102 static int32_t g_keychain_keybag = 0; /* 0 == device_keybag_handle, constant dictated by AKS */
103 #endif /* USE_KEYSTORE */
104
105 void SecItemServerSetKeychainKeybag(int32_t keybag)
106 {
107 g_keychain_keybag=keybag;
108 }
109
110 void SecItemServerResetKeychainKeybag(void)
111 {
112 #if USE_KEYSTORE
113 #if TARGET_OS_MAC && !TARGET_OS_EMBEDDED
114 g_keychain_keybag = session_keybag_handle;
115 #else
116 g_keychain_keybag = device_keybag_handle;
117 #endif
118 #else /* !USE_KEYSTORE */
119 g_keychain_keybag = 0; /* 0 == device_keybag_handle, constant dictated by AKS */
120 #endif /* USE_KEYSTORE */
121 }
122
123 /* KEYBAG_NONE is private to security and have special meaning.
124 They should not collide with AppleKeyStore constants, but are only referenced
125 in here.
126 */
127 #define KEYBAG_NONE (-1) /* Set q_keybag to KEYBAG_NONE to obtain cleartext data. */
128 #define KEYBAG_DEVICE (g_keychain_keybag) /* actual keybag used to encrypt items */
129
130 /* Changed the name of the keychain changed notification, for testing */
131 static const char *g_keychain_changed_notification = kSecServerKeychainChangedNotification;
132
133 void SecItemServerSetKeychainChangedNotification(const char *notification_name)
134 {
135 g_keychain_changed_notification = notification_name;
136 }
137
138 /* label when certificate data is joined with key data */
139 #define CERTIFICATE_DATA_COLUMN_LABEL "certdata"
140
141 #define CURRENT_DB_VERSION 6
142
143 #define CLOSE_DB 0
144
145 /* Forward declaration of import export SPIs. */
146 enum SecItemFilter {
147 kSecNoItemFilter,
148 kSecSysBoundItemFilter,
149 kSecBackupableItemFilter,
150 };
151
152 static CF_RETURNS_RETAINED CFDictionaryRef SecServerExportKeychainPlist(SecDbConnectionRef dbt,
153 keybag_handle_t src_keybag, keybag_handle_t dest_keybag,
154 enum SecItemFilter filter, CFErrorRef *error);
155 static bool SecServerImportKeychainInPlist(SecDbConnectionRef dbt,
156 keybag_handle_t src_keybag, keybag_handle_t dest_keybag,
157 CFDictionaryRef keychain, enum SecItemFilter filter, CFErrorRef *error);
158
159 #if USE_KEYSTORE
160
161 static bool hwaes_key_available(void)
162 {
163 keybag_handle_t handle = bad_keybag_handle;
164 keybag_handle_t special_handle = bad_keybag_handle;
165 #if TARGET_OS_MAC && !TARGET_OS_EMBEDDED
166 special_handle = session_keybag_handle;
167 #elif TARGET_OS_EMBEDDED
168 special_handle = device_keybag_handle;
169 #endif
170 kern_return_t kr = aks_get_system(special_handle, &handle);
171 if (kr != kIOReturnSuccess) {
172 #if TARGET_OS_EMBEDDED
173 /* TODO: Remove this once the kext runs the daemon on demand if
174 there is no system keybag. */
175 int kb_state = MKBGetDeviceLockState(NULL);
176 asl_log(NULL, NULL, ASL_LEVEL_INFO, "AppleKeyStore lock state: %d", kb_state);
177 #endif
178 }
179 return true;
180 }
181
182 #else /* !USE_KEYSTORE */
183
184 static bool hwaes_key_available(void)
185 {
186 return false;
187 }
188
189 #endif /* USE_KEYSTORE */
190
191 // MARK -
192 // MARK Keychain version 6 schema
193
194 #define __FLAGS(ARG, ...) SECDBFLAGS(__VA_ARGS__)
195 #define SECDBFLAGS(ARG, ...) __FLAGS_##ARG | __FLAGS(__VA_ARGS__)
196
197 #define SecDbFlags(P,L,I,S,A,D,R,C,H,B,Z,E,N) (__FLAGS_##P|__FLAGS_##L|__FLAGS_##I|__FLAGS_##S|__FLAGS_##A|__FLAGS_##D|__FLAGS_##R|__FLAGS_##C|__FLAGS_##H|__FLAGS_##B|__FLAGS_##Z|__FLAGS_##E|__FLAGS_##N)
198
199 #define __FLAGS_ 0
200 #define __FLAGS_P kSecDbPrimaryKeyFlag
201 #define __FLAGS_L kSecDbInFlag
202 #define __FLAGS_I kSecDbIndexFlag
203 #define __FLAGS_S kSecDbSHA1ValueInFlag
204 #define __FLAGS_A kSecDbReturnAttrFlag
205 #define __FLAGS_D kSecDbReturnDataFlag
206 #define __FLAGS_R kSecDbReturnRefFlag
207 #define __FLAGS_C kSecDbInCryptoDataFlag
208 #define __FLAGS_H kSecDbInHashFlag
209 #define __FLAGS_B kSecDbInBackupFlag
210 #define __FLAGS_Z kSecDbDefault0Flag
211 #define __FLAGS_E kSecDbDefaultEmptyFlag
212 #define __FLAGS_N kSecDbNotNullFlag
213
214 // ,------------- P : Part of primary key
215 // / ,------------ L : Stored in local database
216 // / / ,----------- I : Attribute wants an index in the database
217 // / / / ,---------- S : SHA1 hashed attribute value in database (implies L)
218 // / / / / ,--------- A : Returned to client as attribute in queries
219 // / / / / / ,-------- D : Returned to client as data in queries
220 // / / / / / / ,------- R : Returned to client as ref/persistant ref in queries
221 // / / / / / / / ,------ C : Part of encrypted blob
222 // / / / / / / / / ,----- H : Attribute is part of item SHA1 hash (Implied by C)
223 // / / / / / / / / / ,---- B : Attribute is part of iTunes/iCloud backup bag
224 // / / / / / / / / / / ,--- Z : Attribute has a default value of 0
225 // / / / / / / / / / / / ,-- E : Attribute has a default value of "" or empty data
226 // / / / / / / / / / / / / ,- N : Attribute must have a value
227 // / / / / / / / / / / / / /
228 // / / / / / / / / / / / / /
229 // | | | | | | | | | | | | |
230 // common to all | | | | | | | | | | | | |
231 SECDB_ATTR(v6rowid, "rowid", RowId, SecDbFlags( ,L, , , , ,R, , ,B, , , ));
232 SECDB_ATTR(v6cdat, "cdat", CreationDate, SecDbFlags( ,L, , ,A, , ,C,H, , , , ));
233 SECDB_ATTR(v6mdat, "mdat",ModificationDate,SecDbFlags( ,L, , ,A, , ,C,H, , , , ));
234 SECDB_ATTR(v6labl, "labl", Blob, SecDbFlags( ,L, ,S,A, , ,C,H, , , , ));
235 SECDB_ATTR(v6data, "data", EncryptedData, SecDbFlags( ,L, , , , , , , ,B, , , ));
236 SECDB_ATTR(v6agrp, "agrp", String, SecDbFlags(P,L, , ,A, , ,C,H, , , , ));
237 SECDB_ATTR(v6pdmn, "pdmn", Access, SecDbFlags( ,L, , ,A, , ,C,H, , , , ));
238 SECDB_ATTR(v6sync, "sync", Sync, SecDbFlags(P,L,I, ,A, , ,C,H, ,Z, ,N));
239 SECDB_ATTR(v6tomb, "tomb", Tomb, SecDbFlags( ,L, , , , , ,C,H, ,Z, ,N));
240 SECDB_ATTR(v6sha1, "sha1", SHA1, SecDbFlags( ,L,I, ,A, ,R, , , , , , ));
241 SECDB_ATTR(v6v_Data, "v_Data", Data, SecDbFlags( , , , , ,D, ,C,H, , , , ));
242 SECDB_ATTR(v6v_pk, "v_pk", PrimaryKey, SecDbFlags( , , , , , , , , , , , , ));
243 // genp and inet and keys | | | | | | | | | | | | |
244 SECDB_ATTR(v6crtr, "crtr", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , ));
245 SECDB_ATTR(v6alis, "alis", Blob, SecDbFlags( ,L, ,S,A, , ,C,H, , , , ));
246 // genp and inet | | | | | | | | | | | | |
247 SECDB_ATTR(v6desc, "desc", Blob, SecDbFlags( ,L, ,S,A, , ,C,H, , , , ));
248 SECDB_ATTR(v6icmt, "icmt", Blob, SecDbFlags( ,L, ,S,A, , ,C,H, , , , ));
249 SECDB_ATTR(v6type, "type", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , ));
250 SECDB_ATTR(v6invi, "invi", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , ));
251 SECDB_ATTR(v6nega, "nega", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , ));
252 SECDB_ATTR(v6cusi, "cusi", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , ));
253 SECDB_ATTR(v6prot, "prot", Blob, SecDbFlags( ,L, ,S,A, , ,C,H, , , , ));
254 SECDB_ATTR(v6scrp, "scrp", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , ));
255 SECDB_ATTR(v6acct, "acct", Blob, SecDbFlags(P,L, ,S,A, , ,C,H, , ,E,N));
256 // genp only | | | | | | | | | | | | |
257 SECDB_ATTR(v6svce, "svce", Blob, SecDbFlags(P,L, ,S,A, , ,C,H, , ,E,N));
258 SECDB_ATTR(v6gena, "gena", Blob, SecDbFlags( ,L, ,S,A, , ,C,H, , , , ));
259 // inet only | | | | | | | | | | | | |
260 SECDB_ATTR(v6sdmn, "sdmn", Blob, SecDbFlags(P,L, ,S,A, , ,C,H, , ,E,N));
261 SECDB_ATTR(v6srvr, "srvr", Blob, SecDbFlags(P,L, ,S,A, , ,C,H, , ,E,N));
262 SECDB_ATTR(v6ptcl, "ptcl", Number, SecDbFlags(P,L, , ,A, , ,C,H, ,Z, ,N));
263 SECDB_ATTR(v6atyp, "atyp", Blob, SecDbFlags(P,L, ,S,A, , ,C,H, , ,E,N));
264 SECDB_ATTR(v6port, "port", Number, SecDbFlags(P,L, , ,A, , ,C,H, ,Z, ,N));
265 SECDB_ATTR(v6path, "path", Blob, SecDbFlags(P,L, ,S,A, , ,C,H, , ,E,N));
266 // cert only | | | | | | | | | | | | |
267 SECDB_ATTR(v6ctyp, "ctyp", Number, SecDbFlags(P,L, , ,A, , ,C,H, ,Z, ,N));
268 SECDB_ATTR(v6cenc, "cenc", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , ));
269 SECDB_ATTR(v6subj, "subj", Data, SecDbFlags( ,L,I,S,A, , ,C,H, , , , ));
270 SECDB_ATTR(v6issr, "issr", Data, SecDbFlags(P,L, ,S,A, , ,C,H, , ,E,N));
271 SECDB_ATTR(v6slnr, "slnr", Data, SecDbFlags(P,L, ,S,A, , ,C,H, , ,E,N));
272 SECDB_ATTR(v6skid, "skid", Data, SecDbFlags( ,L,I,S,A, , ,C,H, , , , ));
273 SECDB_ATTR(v6pkhh, "pkhh", Data, SecDbFlags( ,L,I, ,A, , ,C,H, , , , ));
274 // cert attributes that share names with common ones but have different flags
275 SECDB_ATTR(v6certalis, "alis", Blob, SecDbFlags( ,L,I,S,A, , ,C,H, , , , ));
276 // keys only | | | | | | | | | | | | |
277 SECDB_ATTR(v6kcls, "kcls", Number, SecDbFlags(P,L,I,S,A, , ,C,H, ,Z, ,N));
278 SECDB_ATTR(v6perm, "perm", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , ));
279 SECDB_ATTR(v6priv, "priv", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , ));
280 SECDB_ATTR(v6modi, "modi", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , ));
281 SECDB_ATTR(v6klbl, "klbl", Data, SecDbFlags(P,L,I, ,A, , ,C,H, , ,E,N));
282 SECDB_ATTR(v6atag, "atag", Blob, SecDbFlags(P,L, ,S,A, , ,C,H, , ,E,N));
283 SECDB_ATTR(v6bsiz, "bsiz", Number, SecDbFlags(P,L, , ,A, , ,C,H, ,Z, ,N));
284 SECDB_ATTR(v6esiz, "esiz", Number, SecDbFlags(P,L, , ,A, , ,C,H, ,Z, ,N));
285 SECDB_ATTR(v6sdat, "sdat", Date, SecDbFlags(P,L, , ,A, , ,C,H, ,Z, ,N));
286 SECDB_ATTR(v6edat, "edat", Date, SecDbFlags(P,L, , ,A, , ,C,H, ,Z, ,N));
287 SECDB_ATTR(v6sens, "sens", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , ));
288 SECDB_ATTR(v6asen, "asen", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , ));
289 SECDB_ATTR(v6extr, "extr", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , ));
290 SECDB_ATTR(v6next, "next", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , ));
291 SECDB_ATTR(v6encr, "encr", Number, SecDbFlags( ,L,I, ,A, , ,C,H, , , , ));
292 SECDB_ATTR(v6decr, "decr", Number, SecDbFlags( ,L,I, ,A, , ,C,H, , , , ));
293 SECDB_ATTR(v6drve, "drve", Number, SecDbFlags( ,L,I, ,A, , ,C,H, , , , ));
294 SECDB_ATTR(v6sign, "sign", Number, SecDbFlags( ,L,I, ,A, , ,C,H, , , , ));
295 SECDB_ATTR(v6vrfy, "vrfy", Number, SecDbFlags( ,L,I, ,A, , ,C,H, , , , ));
296 SECDB_ATTR(v6snrc, "snrc", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , ));
297 SECDB_ATTR(v6vyrc, "vyrc", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , ));
298 SECDB_ATTR(v6wrap, "wrap", Number, SecDbFlags( ,L,I, ,A, , ,C,H, , , , ));
299 SECDB_ATTR(v6unwp, "unwp", Number, SecDbFlags( ,L,I, ,A, , ,C,H, , , , ));
300 // keys attributes that share names with common ones but have different flags
301 SECDB_ATTR(v6keytype, "type", Number, SecDbFlags(P,L, , ,A, , ,C,H, ,Z, ,N));
302 SECDB_ATTR(v6keycrtr, "crtr", Number, SecDbFlags(P,L, , ,A, , ,C,H, ,Z, ,N));
303
304 static const SecDbClass genp_class = {
305 .name = CFSTR("genp"),
306 .attrs = {
307 &v6rowid,
308 &v6cdat,
309 &v6mdat,
310 &v6desc,
311 &v6icmt,
312 &v6crtr,
313 &v6type,
314 &v6scrp,
315 &v6labl,
316 &v6alis,
317 &v6invi,
318 &v6nega,
319 &v6cusi,
320 &v6prot,
321 &v6acct,
322 &v6svce,
323 &v6gena,
324 &v6data,
325 &v6agrp,
326 &v6pdmn,
327 &v6sync,
328 &v6tomb,
329 &v6sha1,
330 &v6v_Data,
331 &v6v_pk,
332 NULL
333 },
334 };
335
336 static const SecDbClass inet_class = {
337 .name = CFSTR("inet"),
338 .attrs = {
339 &v6rowid,
340 &v6cdat,
341 &v6mdat,
342 &v6desc,
343 &v6icmt,
344 &v6crtr,
345 &v6type,
346 &v6scrp,
347 &v6labl,
348 &v6alis,
349 &v6invi,
350 &v6nega,
351 &v6cusi,
352 &v6prot,
353 &v6acct,
354 &v6sdmn,
355 &v6srvr,
356 &v6ptcl,
357 &v6atyp,
358 &v6port,
359 &v6path,
360 &v6data,
361 &v6agrp,
362 &v6pdmn,
363 &v6sync,
364 &v6tomb,
365 &v6sha1,
366 &v6v_Data,
367 &v6v_pk,
368 0
369 },
370 };
371
372 static const SecDbClass cert_class = {
373 .name = CFSTR("cert"),
374 .attrs = {
375 &v6rowid,
376 &v6cdat,
377 &v6mdat,
378 &v6ctyp,
379 &v6cenc,
380 &v6labl,
381 &v6certalis,
382 &v6subj,
383 &v6issr,
384 &v6slnr,
385 &v6skid,
386 &v6pkhh,
387 &v6data,
388 &v6agrp,
389 &v6pdmn,
390 &v6sync,
391 &v6tomb,
392 &v6sha1,
393 &v6v_Data,
394 &v6v_pk,
395 0
396 },
397 };
398
399 static const SecDbClass keys_class = {
400 .name = CFSTR("keys"),
401 .attrs = {
402 &v6rowid,
403 &v6cdat,
404 &v6mdat,
405 &v6kcls,
406 &v6labl,
407 &v6alis,
408 &v6perm,
409 &v6priv,
410 &v6modi,
411 &v6klbl,
412 &v6atag,
413 &v6keycrtr,
414 &v6keytype,
415 &v6bsiz,
416 &v6esiz,
417 &v6sdat,
418 &v6edat,
419 &v6sens,
420 &v6asen,
421 &v6extr,
422 &v6next,
423 &v6encr,
424 &v6decr,
425 &v6drve,
426 &v6sign,
427 &v6vrfy,
428 &v6snrc,
429 &v6vyrc,
430 &v6wrap,
431 &v6unwp,
432 &v6data,
433 &v6agrp,
434 &v6pdmn,
435 &v6sync,
436 &v6tomb,
437 &v6sha1,
438 &v6v_Data,
439 &v6v_pk,
440 0
441 }
442 };
443
444 /* An identity which is really a cert + a key, so all cert and keys attrs are
445 allowed. */
446 static const SecDbClass identity_class = {
447 .name = CFSTR("idnt"),
448 .attrs = {
449 0
450 },
451 };
452
453 static const SecDbAttr *SecDbAttrWithKey(const SecDbClass *c,
454 CFTypeRef key,
455 CFErrorRef *error) {
456 /* Special case: identites can have all attributes of either cert
457 or keys. */
458 if (c == &identity_class) {
459 const SecDbAttr *desc;
460 if (!(desc = SecDbAttrWithKey(&cert_class, key, 0)))
461 desc = SecDbAttrWithKey(&keys_class, key, error);
462 return desc;
463 }
464
465 if (isString(key)) {
466 SecDbForEachAttr(c, a) {
467 if (CFEqual(a->name, key))
468 return a;
469 }
470 }
471
472 SecError(errSecNoSuchAttr, error, CFSTR("attribute %@ not found in class %@"), key, c->name);
473
474 return NULL;
475 }
476
477 static bool kc_transaction(SecDbConnectionRef dbt, CFErrorRef *error, bool(^perform)()) {
478 __block bool ok = true;
479 return ok && SecDbTransaction(dbt, kSecDbExclusiveTransactionType, error, ^(bool *commit) {
480 ok = *commit = perform();
481 });
482 }
483
484 static CFStringRef SecDbGetKindSQL(SecDbAttrKind kind) {
485 switch (kind) {
486 case kSecDbBlobAttr:
487 case kSecDbDataAttr:
488 case kSecDbSHA1Attr:
489 case kSecDbPrimaryKeyAttr:
490 case kSecDbEncryptedDataAttr:
491 return CFSTR("BLOB");
492 case kSecDbAccessAttr:
493 case kSecDbStringAttr:
494 return CFSTR("TEXT");
495 case kSecDbNumberAttr:
496 case kSecDbSyncAttr:
497 case kSecDbTombAttr:
498 return CFSTR("INTEGER");
499 case kSecDbDateAttr:
500 case kSecDbCreationDateAttr:
501 case kSecDbModificationDateAttr:
502 return CFSTR("REAL");
503 case kSecDbRowIdAttr:
504 return CFSTR("INTEGER PRIMARY KEY AUTOINCREMENT");
505 }
506 }
507
508 static void SecDbAppendUnqiue(CFMutableStringRef sql, CFStringRef value, bool *haveUnique) {
509 assert(haveUnique);
510 if (!*haveUnique)
511 CFStringAppend(sql, CFSTR("UNIQUE("));
512
513 SecDbAppendElement(sql, value, haveUnique);
514 }
515
516 static void SecDbAppendCreateTableWithClass(CFMutableStringRef sql, const SecDbClass *c) {
517 CFStringAppendFormat(sql, 0, CFSTR("CREATE TABLE %@("), c->name);
518 SecDbForEachAttrWithMask(c,desc,kSecDbInFlag) {
519 CFStringAppendFormat(sql, 0, CFSTR("%@ %@"), desc->name, SecDbGetKindSQL(desc->kind));
520 if (desc->flags & kSecDbNotNullFlag)
521 CFStringAppend(sql, CFSTR(" NOT NULL"));
522 if (desc->flags & kSecDbDefault0Flag)
523 CFStringAppend(sql, CFSTR(" DEFAULT 0"));
524 if (desc->flags & kSecDbDefaultEmptyFlag)
525 CFStringAppend(sql, CFSTR(" DEFAULT ''"));
526 CFStringAppend(sql, CFSTR(","));
527 }
528
529 bool haveUnique = false;
530 SecDbForEachAttrWithMask(c,desc,kSecDbPrimaryKeyFlag | kSecDbInFlag) {
531 SecDbAppendUnqiue(sql, desc->name, &haveUnique);
532 }
533 if (haveUnique)
534 CFStringAppend(sql, CFSTR(")"));
535
536 CFStringAppend(sql, CFSTR(");"));
537 }
538
539 static const char * const s3dl_upgrade_sql[] = {
540 /* 0 */
541 "",
542
543 /* 1 */
544 /* Create indices. */
545 "CREATE INDEX igsha ON genp(sha1);"
546 "CREATE INDEX iisha ON inet(sha1);"
547 "CREATE INDEX icsha ON cert(sha1);"
548 "CREATE INDEX iksha ON keys(sha1);"
549 "CREATE INDEX ialis ON cert(alis);"
550 "CREATE INDEX isubj ON cert(subj);"
551 "CREATE INDEX iskid ON cert(skid);"
552 "CREATE INDEX ipkhh ON cert(pkhh);"
553 "CREATE INDEX ikcls ON keys(kcls);"
554 "CREATE INDEX iklbl ON keys(klbl);"
555 "CREATE INDEX iencr ON keys(encr);"
556 "CREATE INDEX idecr ON keys(decr);"
557 "CREATE INDEX idrve ON keys(drve);"
558 "CREATE INDEX isign ON keys(sign);"
559 "CREATE INDEX ivrfy ON keys(vrfy);"
560 "CREATE INDEX iwrap ON keys(wrap);"
561 "CREATE INDEX iunwp ON keys(unwp);",
562
563 /* 2 */
564 "",
565
566 /* 3 */
567 /* Rename version 2 or version 3 tables and drop version table since
568 step 0 creates it. */
569 "ALTER TABLE genp RENAME TO ogenp;"
570 "ALTER TABLE inet RENAME TO oinet;"
571 "ALTER TABLE cert RENAME TO ocert;"
572 "ALTER TABLE keys RENAME TO okeys;"
573 "DROP TABLE tversion;",
574
575 /* 4 */
576 "",
577
578 /* 5 */
579 "",
580
581 /* 6 */
582 "",
583
584 /* 7 */
585 /* Move data from version 5 tables to new ones and drop old ones. */
586 "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;"
587 "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;"
588 "INSERT INTO cert (rowid,cdat,mdat,ctyp,cenc,labl,alis,subj,issr,slnr,skid,pkhh,data,agrp,pdmn) SELECT rowid,cdat,mdat,ctyp,cenc,labl,alis,subj,issr,slnr,skid,pkhh,data,agrp,pdmn from ocert;"
589 "INSERT INTO keys (rowid,cdat,mdat,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,cdat,mdat,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;"
590 "DROP TABLE ogenp;"
591 "DROP TABLE oinet;"
592 "DROP TABLE ocert;"
593 "DROP TABLE okeys;"
594 "CREATE INDEX igsha ON genp(sha1);"
595 "CREATE INDEX iisha ON inet(sha1);"
596 "CREATE INDEX icsha ON cert(sha1);"
597 "CREATE INDEX iksha ON keys(sha1);",
598 };
599
600 struct sql_stages {
601 int pre;
602 int main;
603 int post;
604 bool init_pdmn; // If true do a full export followed by an import of the entire database so all items are re-encoded.
605 };
606
607 /* On disk database format version upgrade scripts.
608 If pre is 0, version is unsupported and db is considered corrupt for having that version.
609 First entry creates the current db, each susequent entry upgrade to current from the version
610 represented by the index of the slot. Each script is either -1 (disabled) of the number of
611 the script in the main table.
612 {pre,main,post, reencode} */
613 static struct sql_stages s3dl_upgrade_script[] = {
614 { -1, 0, 1, false },/* 0->current: Create version 6 database. */
615 {}, /* 1->current: Upgrade to version 6 from version 1 (LittleBear) -- Unsupported. */
616 {}, /* 2->current: Upgrade to version 6 from version 2 (BigBearBeta) -- Unsupported */
617 {}, /* 3->current: Upgrade to version 6 from version 3 (Apex) -- Unsupported */
618 {}, /* 4->current: Upgrade to version 6 from version 4 (Telluride) -- Unsupported */
619 { 3, 0, 7, true }, /* 5->current: Upgrade to version 6 from version 5 (TellurideGM). */
620 };
621
622 static bool sql_run_script(SecDbConnectionRef dbt, int number, CFErrorRef *error)
623 {
624 /* Script -1 == skip this step. */
625 if (number < 0)
626 return true;
627
628 /* If we are attempting to run a script we don't have, fail. */
629 if ((size_t)number >= array_size(s3dl_upgrade_sql))
630 return SecDbError(SQLITE_CORRUPT, error, CFSTR("script %d exceeds maximum %d"),
631 number, (int)(array_size(s3dl_upgrade_sql)));
632 __block bool ok = true;
633 if (number == 0) {
634 CFMutableStringRef sql = CFStringCreateMutable(0, 0);
635 SecDbAppendCreateTableWithClass(sql, &genp_class);
636 SecDbAppendCreateTableWithClass(sql, &inet_class);
637 SecDbAppendCreateTableWithClass(sql, &cert_class);
638 SecDbAppendCreateTableWithClass(sql, &keys_class);
639 CFStringAppend(sql, CFSTR("CREATE TABLE tversion(version INTEGER);INSERT INTO tversion(version) VALUES(6);"));
640 CFStringPerformWithCString(sql, ^(const char *sql_string) {
641 ok = SecDbErrorWithDb(sqlite3_exec(SecDbHandle(dbt), sql_string, NULL, NULL, NULL),
642 SecDbHandle(dbt), error, CFSTR("sqlite3_exec: %s"), sql_string);
643 });
644 CFReleaseSafe(sql);
645 } else {
646 ok = SecDbErrorWithDb(sqlite3_exec(SecDbHandle(dbt), s3dl_upgrade_sql[number], NULL, NULL, NULL),
647 SecDbHandle(dbt), error, CFSTR("sqlite3_exec: %s"), s3dl_upgrade_sql[number]);
648 }
649 return ok;
650 }
651
652 /* Return the current database version in *version. Returns a
653 SQLITE error. */
654 static bool s3dl_dbt_get_version(SecDbConnectionRef dbt, int *version, CFErrorRef *error)
655 {
656 CFStringRef sql = CFSTR("SELECT version FROM tversion LIMIT 1");
657 return SecDbWithSQL(dbt, sql, error, ^(sqlite3_stmt *stmt) {
658 __block bool found_version = false;
659 bool step_ok = SecDbForEach(stmt, error, ^(int row_index __unused) {
660 if (!found_version) {
661 *version = sqlite3_column_int(stmt, 0);
662 found_version = true;
663 }
664 return found_version;
665 });
666 if (!found_version) {
667 /* We have a tversion table but we didn't find a single version
668 value, now what? I suppose we pretend the db is corrupted
669 since this isn't supposed to ever happen. */
670 step_ok = SecDbError(SQLITE_CORRUPT, error, CFSTR("Failed to read version: database corrupt"));
671 secwarning("SELECT version step: %@", error ? *error : NULL);
672 }
673 return step_ok;
674 });
675 }
676
677 static bool s3dl_dbt_upgrade_from_version(SecDbConnectionRef dbt, int version, CFErrorRef *error)
678 {
679 /* We need to go from db version to CURRENT_DB_VERSION, let's do so. */
680 __block bool ok = true;
681 /* O, guess we're done already. */
682 if (version == CURRENT_DB_VERSION)
683 return ok;
684
685 if (ok && version < 6) {
686 // Pre v6 keychains need to have WAL enabled, since SecDb only
687 // does this at db creation time.
688 // NOTE: This has to be run outside of a transaction.
689 ok = (SecDbExec(dbt, CFSTR("PRAGMA auto_vacuum = FULL"), error) &&
690 SecDbExec(dbt, CFSTR("PRAGMA journal_mode = WAL"), error));
691 }
692
693 // Start a transaction to do the upgrade within
694 if (ok) { ok = SecDbTransaction(dbt, kSecDbExclusiveTransactionType, error, ^(bool *commit) {
695 // Be conservative and get the version again once we start a transaction.
696 int cur_version = version;
697 s3dl_dbt_get_version(dbt, &cur_version, NULL);
698
699 /* If we are attempting to upgrade to a version greater than what we have
700 an upgrade script for, fail. */
701 if (ok && (cur_version < 0 ||
702 (size_t)cur_version >= array_size(s3dl_upgrade_script))) {
703 ok = SecDbError(SQLITE_CORRUPT, error, CFSTR("no upgrade script for version: %d"), cur_version);
704 secerror("no upgrade script for version %d", cur_version);
705 }
706
707 struct sql_stages *script;
708 if (ok) {
709 script = &s3dl_upgrade_script[cur_version];
710 if (script->pre == 0)
711 ok = SecDbError(SQLITE_CORRUPT, error, CFSTR("unsupported db version %d"), cur_version);
712 }
713 if (ok)
714 ok = sql_run_script(dbt, script->pre, error);
715 if (ok)
716 ok = sql_run_script(dbt, script->main, error);
717 if (ok)
718 ok = sql_run_script(dbt, script->post, error);
719 if (ok && script->init_pdmn) {
720 CFErrorRef localError = NULL;
721 CFDictionaryRef backup = SecServerExportKeychainPlist(dbt,
722 KEYBAG_DEVICE, KEYBAG_NONE, kSecNoItemFilter, &localError);
723 if (backup) {
724 if (localError) {
725 secerror("Ignoring export error: %@ during upgrade export", localError);
726 CFReleaseNull(localError);
727 }
728 ok = SecServerImportKeychainInPlist(dbt, KEYBAG_NONE,
729 KEYBAG_DEVICE, backup, kSecNoItemFilter, &localError);
730 CFRelease(backup);
731 } else {
732 ok = false;
733
734 if (localError && CFErrorGetCode(localError) == errSecInteractionNotAllowed) {
735 SecError(errSecUpgradePending, error,
736 CFSTR("unable to complete upgrade due to device lock state"));
737 secerror("unable to complete upgrade due to device lock state");
738 } else {
739 secerror("unable to complete upgrade for unknown reason, marking DB as corrupt: %@", localError);
740 SecDbCorrupt(dbt);
741 }
742 }
743
744 if (localError) {
745 if (error && !*error)
746 *error = localError;
747 else
748 CFRelease(localError);
749 }
750 } else if (!ok) {
751 secerror("unable to complete upgrade scripts, marking DB as corrupt: %@", error ? *error : NULL);
752 SecDbCorrupt(dbt);
753 }
754 *commit = ok;
755 }); } else {
756 secerror("unable to complete upgrade scripts, marking DB as corrupt: %@", error ? *error : NULL);
757 SecDbCorrupt(dbt);
758 }
759
760 return ok;
761 }
762
763
764 /* This function is called if the db doesn't have the proper version. We
765 start an exclusive transaction and recheck the version, and then perform
766 the upgrade within that transaction. */
767 static bool s3dl_dbt_upgrade(SecDbConnectionRef dbt, CFErrorRef *error)
768 {
769 // Already in a transaction
770 //return kc_transaction(dbt, error, ^{
771 int version = 0; // Upgrade from version 0 == create new db
772 s3dl_dbt_get_version(dbt, &version, NULL);
773 return s3dl_dbt_upgrade_from_version(dbt, version, error);
774 //});
775 }
776
777 const uint32_t v0KeyWrapOverHead = 8;
778
779 /* Wrap takes a 128 - 256 bit key as input and returns output of
780 inputsize + 64 bits.
781 In bytes this means that a
782 16 byte (128 bit) key returns a 24 byte wrapped key
783 24 byte (192 bit) key returns a 32 byte wrapped key
784 32 byte (256 bit) key returns a 40 byte wrapped key */
785 static bool ks_crypt(uint32_t selector, keybag_handle_t keybag,
786 keyclass_t keyclass, uint32_t textLength, const uint8_t *source, uint8_t *dest, size_t *dest_len, CFErrorRef *error) {
787 #if USE_KEYSTORE
788 kern_return_t kernResult = kIOReturnBadArgument;
789
790 if (selector == kAppleKeyStoreKeyWrap) {
791 kernResult = aks_wrap_key(source, textLength, keyclass, keybag, dest, (int*)dest_len);
792 } else if (selector == kAppleKeyStoreKeyUnwrap) {
793 kernResult = aks_unwrap_key(source, textLength, keyclass, keybag, dest, (int*)dest_len);
794 }
795
796 if (kernResult != KERN_SUCCESS) {
797 if ((kernResult == kIOReturnNotPermitted) || (kernResult == kIOReturnNotPrivileged)) {
798 /* Access to item attempted while keychain is locked. */
799 return SecError(errSecInteractionNotAllowed, error, CFSTR("ks_crypt: %x failed to %s item (class %"PRId32", bag: %"PRId32") Access to item attempted while keychain is locked."),
800 kernResult, (selector == kAppleKeyStoreKeyWrap ? "wrap" : "unwrap"), keyclass, keybag);
801 } else if (kernResult == kIOReturnError) {
802 /* Item can't be decrypted on this device, ever, so drop the item. */
803 return SecError(errSecDecode, error, CFSTR("ks_crypt: %x failed to %s item (class %"PRId32", bag: %"PRId32") Item can't be decrypted on this device, ever, so drop the item."),
804 kernResult, (selector == kAppleKeyStoreKeyWrap ? "wrap" : "unwrap"), keyclass, keybag);
805 } else {
806 return SecError(errSecNotAvailable, error, CFSTR("ks_crypt: %x failed to %s item (class %"PRId32", bag: %"PRId32")"),
807 kernResult, (selector == kAppleKeyStoreKeyWrap ? "wrap" : "unwrap"), keyclass, keybag);
808 }
809 }
810 return true;
811 #else /* !USE_KEYSTORE */
812 if (selector == kAppleKeyStoreKeyWrap) {
813 /* The no encryption case. */
814 if (*dest_len >= textLength + 8) {
815 memcpy(dest, source, textLength);
816 memset(dest + textLength, 8, 8);
817 *dest_len = textLength + 8;
818 } else
819 return SecError(errSecNotAvailable, error, CFSTR("ks_crypt: failed to wrap item (class %"PRId32")"), keyclass);
820 } else if (selector == kAppleKeyStoreKeyUnwrap) {
821 if (*dest_len + 8 >= textLength) {
822 memcpy(dest, source, textLength - 8);
823 *dest_len = textLength - 8;
824 } else
825 return SecError(errSecNotAvailable, error, CFSTR("ks_crypt: failed to unwrap item (class %"PRId32")"), keyclass);
826 }
827 return true;
828 #endif /* USE_KEYSTORE */
829 }
830
831
832 CFDataRef kc_plist_copy_der(CFPropertyListRef plist, CFErrorRef *error) {
833 size_t len = der_sizeof_plist(plist, error);
834 CFMutableDataRef encoded = CFDataCreateMutable(0, len);
835 CFDataSetLength(encoded, len);
836 uint8_t *der_end = CFDataGetMutableBytePtr(encoded);
837 const uint8_t *der = der_end;
838 der_end += len;
839 der_end = der_encode_plist(plist, error, der, der_end);
840 if (!der_end) {
841 CFReleaseNull(encoded);
842 } else {
843 assert(!der_end || der_end == der);
844 }
845 return encoded;
846 }
847
848 static CFDataRef kc_copy_digest(const struct ccdigest_info *di, size_t len,
849 const void *data, CFErrorRef *error) {
850 CFMutableDataRef digest = CFDataCreateMutable(0, di->output_size);
851 CFDataSetLength(digest, di->output_size);
852 ccdigest(di, len, data, CFDataGetMutableBytePtr(digest));
853 return digest;
854 }
855
856 CFDataRef kc_copy_sha1(size_t len, const void *data, CFErrorRef *error) {
857 return kc_copy_digest(ccsha1_di(), len, data, error);
858 }
859
860 CFDataRef kc_copy_plist_sha1(CFPropertyListRef plist, CFErrorRef *error) {
861 CFDataRef der = kc_plist_copy_der(plist, error);
862 CFDataRef digest = NULL;
863 if (der) {
864 digest = kc_copy_sha1(CFDataGetLength(der), CFDataGetBytePtr(der), error);
865 CFRelease(der);
866 }
867 return digest;
868 }
869
870 /* Given plainText create and return a CFDataRef containing:
871 BULK_KEY = RandomKey()
872 version || keyclass || KeyStore_WRAP(keyclass, BULK_KEY) ||
873 AES(BULK_KEY, NULL_IV, plainText || padding)
874 */
875 bool ks_encrypt_data(keybag_handle_t keybag,
876 keyclass_t keyclass, CFDataRef plainText, CFDataRef *pBlob, CFErrorRef *error) {
877 CFMutableDataRef blob = NULL;
878 bool ok = true;
879 //check(keybag >= 0);
880
881 /* Precalculate output blob length. */
882 const uint32_t bulkKeySize = 32; /* Use 256 bit AES key for bulkKey. */
883 const uint32_t maxKeyWrapOverHead = 8 + 32;
884 uint8_t bulkKey[bulkKeySize];
885 uint8_t bulkKeyWrapped[bulkKeySize + maxKeyWrapOverHead];
886 size_t bulkKeyWrappedSize = sizeof(bulkKeyWrapped);
887 uint32_t key_wrapped_size;
888
889 if (!plainText || CFGetTypeID(plainText) != CFDataGetTypeID()
890 || keyclass == 0) {
891 ok = SecError(errSecParam, error, CFSTR("ks_encrypt_data: invalid plain text"));
892 goto out;
893 }
894
895 size_t ptLen = CFDataGetLength(plainText);
896 size_t ctLen = ptLen;
897 size_t tagLen = 16;
898 uint32_t version = 3;
899
900 if (SecRandomCopyBytes(kSecRandomDefault, bulkKeySize, bulkKey)) {
901 ok = SecError(errSecAllocate, error, CFSTR("ks_encrypt_data: SecRandomCopyBytes failed"));
902 goto out;
903 }
904
905 /* Now that we're done using the bulkKey, in place encrypt it. */
906 require_quiet(ok = ks_crypt(kAppleKeyStoreKeyWrap, keybag, keyclass,
907 bulkKeySize, bulkKey, bulkKeyWrapped,
908 &bulkKeyWrappedSize, error), out);
909 key_wrapped_size = (uint32_t)bulkKeyWrappedSize;
910
911 size_t blobLen = sizeof(version) + sizeof(keyclass) +
912 sizeof(key_wrapped_size) + key_wrapped_size + ctLen + tagLen;
913
914 require_quiet(blob = CFDataCreateMutable(NULL, blobLen), out);
915 CFDataSetLength(blob, blobLen);
916 UInt8 *cursor = CFDataGetMutableBytePtr(blob);
917
918 *((uint32_t *)cursor) = version;
919 cursor += sizeof(version);
920
921 *((keyclass_t *)cursor) = keyclass;
922 cursor += sizeof(keyclass);
923
924 *((uint32_t *)cursor) = key_wrapped_size;
925 cursor += sizeof(key_wrapped_size);
926
927 memcpy(cursor, bulkKeyWrapped, key_wrapped_size);
928 cursor += key_wrapped_size;
929
930 /* Encrypt the plainText with the bulkKey. */
931 CCCryptorStatus ccerr = CCCryptorGCM(kCCEncrypt, kCCAlgorithmAES128,
932 bulkKey, bulkKeySize,
933 NULL, 0, /* iv */
934 NULL, 0, /* auth data */
935 CFDataGetBytePtr(plainText), ptLen,
936 cursor,
937 cursor + ctLen, &tagLen);
938 if (ccerr) {
939 ok = SecError(errSecInternal, error, CFSTR("ks_encrypt_data: CCCryptorGCM failed: %d"), ccerr);
940 goto out;
941 }
942 if (tagLen != 16) {
943 ok = SecError(errSecInternal, error, CFSTR("ks_encrypt_data: CCCryptorGCM expected: 16 got: %ld byte tag"), tagLen);
944 goto out;
945 }
946
947 out:
948 memset(bulkKey, 0, sizeof(bulkKey));
949 if (!ok) {
950 CFReleaseSafe(blob);
951 } else {
952 *pBlob = blob;
953 }
954 return ok;
955 }
956
957 /* Given cipherText containing:
958 version || keyclass || KeyStore_WRAP(keyclass, BULK_KEY) ||
959 AES(BULK_KEY, NULL_IV, plainText || padding)
960 return the plainText. */
961 bool ks_decrypt_data(keybag_handle_t keybag,
962 keyclass_t *pkeyclass, CFDataRef blob, CFDataRef *pPlainText,
963 uint32_t *version_p, CFErrorRef *error) {
964 const uint32_t bulkKeySize = 32; /* Use 256 bit AES key for bulkKey. */
965 uint8_t bulkKey[bulkKeySize];
966 size_t bulkKeyCapacity = sizeof(bulkKey);
967 bool ok = true;
968
969 CFMutableDataRef plainText = NULL;
970 #if USE_KEYSTORE
971 #if TARGET_OS_IPHONE
972 check(keybag >= 0);
973 #else
974 check((keybag >= 0) || (keybag == session_keybag_handle));
975 #endif
976 #endif
977
978 if (!blob) {
979 ok = SecError(errSecParam, error, CFSTR("ks_decrypt_data: invalid blob"));
980 goto out;
981 }
982
983 size_t blobLen = CFDataGetLength(blob);
984 const uint8_t *cursor = CFDataGetBytePtr(blob);
985 uint32_t version;
986 keyclass_t keyclass;
987 uint32_t wrapped_key_size;
988
989 /* Check for underflow, ensuring we have at least one full AES block left. */
990 if (blobLen < sizeof(version) + sizeof(keyclass) +
991 bulkKeySize + v0KeyWrapOverHead + 16) {
992 ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: Check for underflow"));
993 goto out;
994 }
995
996 version = *((uint32_t *)cursor);
997 cursor += sizeof(version);
998
999 keyclass = *((keyclass_t *)cursor);
1000 if (pkeyclass)
1001 *pkeyclass = keyclass;
1002 cursor += sizeof(keyclass);
1003
1004 size_t minimum_blob_len = sizeof(version) + sizeof(keyclass) + 16;
1005 size_t ctLen = blobLen - sizeof(version) - sizeof(keyclass);
1006 size_t tagLen = 0;
1007 switch (version) {
1008 case 0:
1009 wrapped_key_size = bulkKeySize + v0KeyWrapOverHead;
1010 break;
1011 case 2:
1012 /* DROPTHROUGH */
1013 /* v2 and v3 have the same crypto, just different dictionary encodings. */
1014 case 3:
1015 tagLen = 16;
1016 minimum_blob_len -= 16; // Remove PKCS7 padding block requirement
1017 ctLen -= tagLen; // Remove tagLen from ctLen
1018 /* DROPTHROUGH */
1019 case 1:
1020 wrapped_key_size = *((uint32_t *)cursor);
1021 cursor += sizeof(wrapped_key_size);
1022 minimum_blob_len += sizeof(wrapped_key_size);
1023 ctLen -= sizeof(wrapped_key_size);
1024 break;
1025 default:
1026 ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: invalid version %d"), version);
1027 goto out;
1028 }
1029
1030 /* Validate key wrap length against total length */
1031 require(blobLen - minimum_blob_len - tagLen >= wrapped_key_size, out);
1032 ctLen -= wrapped_key_size;
1033 if (version < 2 && (ctLen & 0xF) != 0) {
1034 ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: invalid version"));
1035 goto out;
1036 }
1037
1038 /* Now unwrap the bulk key using a key in the keybag. */
1039 require_quiet(ok = ks_crypt(kAppleKeyStoreKeyUnwrap, keybag,
1040 keyclass, wrapped_key_size, cursor, bulkKey, &bulkKeyCapacity, error), out);
1041 cursor += wrapped_key_size;
1042
1043 plainText = CFDataCreateMutable(NULL, ctLen);
1044 if (!plainText) {
1045 ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: failed to allocate data for plain text"));
1046 goto out;
1047 }
1048 CFDataSetLength(plainText, ctLen);
1049
1050 /* Decrypt the cipherText with the bulkKey. */
1051 CCCryptorStatus ccerr;
1052 if (tagLen) {
1053 uint8_t tag[tagLen];
1054 ccerr = CCCryptorGCM(kCCDecrypt, kCCAlgorithmAES128,
1055 bulkKey, bulkKeySize,
1056 NULL, 0, /* iv */
1057 NULL, 0, /* auth data */
1058 cursor, ctLen,
1059 CFDataGetMutableBytePtr(plainText),
1060 tag, &tagLen);
1061 if (ccerr) {
1062 /* TODO: Should this be errSecDecode once AppleKeyStore correctly
1063 identifies uuid unwrap failures? */
1064 /* errSecInteractionNotAllowed; */
1065 ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: CCCryptorGCM failed: %d"), ccerr);
1066 goto out;
1067 }
1068 if (tagLen != 16) {
1069 ok = SecError(errSecInternal, error, CFSTR("ks_decrypt_data: CCCryptorGCM expected: 16 got: %ld byte tag"), tagLen);
1070 goto out;
1071 }
1072 cursor += ctLen;
1073 if (memcmp(tag, cursor, tagLen)) {
1074 ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: CCCryptorGCM computed tag not same as tag in blob"));
1075 goto out;
1076 }
1077 } else {
1078 size_t ptLen;
1079 ccerr = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
1080 bulkKey, bulkKeySize, NULL, cursor, ctLen,
1081 CFDataGetMutableBytePtr(plainText), ctLen, &ptLen);
1082 if (ccerr) {
1083 /* TODO: Should this be errSecDecode once AppleKeyStore correctly
1084 identifies uuid unwrap failures? */
1085 /* errSecInteractionNotAllowed; */
1086 ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: CCCrypt failed: %d"), ccerr);
1087 goto out;
1088 }
1089 CFDataSetLength(plainText, ptLen);
1090 }
1091 if (version_p) *version_p = version;
1092 out:
1093 memset(bulkKey, 0, bulkKeySize);
1094 if (!ok) {
1095 CFReleaseSafe(plainText);
1096 } else {
1097 *pPlainText = plainText;
1098 }
1099 return ok;
1100 }
1101
1102 static bool use_hwaes() {
1103 static bool use_hwaes;
1104 static dispatch_once_t check_once;
1105 dispatch_once(&check_once, ^{
1106 use_hwaes = hwaes_key_available();
1107 if (use_hwaes) {
1108 asl_log(NULL, NULL, ASL_LEVEL_INFO, "using hwaes key");
1109 } else {
1110 asl_log(NULL, NULL, ASL_LEVEL_ERR, "unable to access hwaes key");
1111 }
1112 });
1113 return use_hwaes;
1114 }
1115
1116 /* Upper limit for number of keys in a QUERY dictionary. */
1117 #define QUERY_KEY_LIMIT_BASE (128)
1118 #ifdef NO_SERVER
1119 #define QUERY_KEY_LIMIT (31 + QUERY_KEY_LIMIT_BASE)
1120 #else
1121 #define QUERY_KEY_LIMIT QUERY_KEY_LIMIT_BASE
1122 #endif
1123
1124 /* Inline accessors to attr and match values in a query. */
1125 static inline CFIndex query_attr_count(const Query *q)
1126 {
1127 return q->q_attr_end;
1128 }
1129
1130 static inline Pair query_attr_at(const Query *q, CFIndex ix)
1131 {
1132 return q->q_pairs[ix];
1133 }
1134
1135 static inline CFIndex query_match_count(const Query *q)
1136 {
1137 return q->q_match_end - q->q_match_begin;
1138 }
1139
1140 static inline Pair query_match_at(const Query *q, CFIndex ix)
1141 {
1142 return q->q_pairs[q->q_match_begin + ix];
1143 }
1144
1145 /* Private routines used to parse a query. */
1146
1147 /* Sets q_keyclass based on value. */
1148 static void query_parse_keyclass(const void *value, Query *q) {
1149 if (!isString(value)) {
1150 SecError(errSecParam, &q->q_error, CFSTR("accessible attribute %@ not a string"), value);
1151 return;
1152 } else if (CFEqual(value, kSecAttrAccessibleWhenUnlocked)) {
1153 q->q_keyclass = key_class_ak;
1154 } else if (CFEqual(value, kSecAttrAccessibleAfterFirstUnlock)) {
1155 q->q_keyclass = key_class_ck;
1156 } else if (CFEqual(value, kSecAttrAccessibleAlways)) {
1157 q->q_keyclass = key_class_dk;
1158 } else if (CFEqual(value, kSecAttrAccessibleWhenUnlockedThisDeviceOnly)) {
1159 q->q_keyclass = key_class_aku;
1160 } else if (CFEqual(value, kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly)) {
1161 q->q_keyclass = key_class_cku;
1162 } else if (CFEqual(value, kSecAttrAccessibleAlwaysThisDeviceOnly)) {
1163 q->q_keyclass = key_class_dku;
1164 } else {
1165 SecError(errSecParam, &q->q_error, CFSTR("accessible attribute %@ unknown"), value);
1166 return;
1167 }
1168 //q->q_keyclass_s = value;
1169 }
1170
1171 static const SecDbClass *kc_class_with_name(CFStringRef name) {
1172 if (isString(name)) {
1173 #if 0
1174 // TODO Iterate kc_db_classes and look for name == class->name.
1175 // Or get clever and switch on first letter of class name and compare to verify
1176 static const void *kc_db_classes[] = {
1177 &genp_class,
1178 &inet_class,
1179 &cert_class,
1180 &keys_class,
1181 &identity_class
1182 };
1183 #endif
1184 if (CFEqual(name, kSecClassGenericPassword))
1185 return &genp_class;
1186 else if (CFEqual(name, kSecClassInternetPassword))
1187 return &inet_class;
1188 else if (CFEqual(name, kSecClassCertificate))
1189 return &cert_class;
1190 else if (CFEqual(name, kSecClassKey))
1191 return &keys_class;
1192 else if (CFEqual(name, kSecClassIdentity))
1193 return &identity_class;
1194 }
1195 return NULL;
1196 }
1197
1198 /* AUDIT[securityd](done):
1199 key (ok) is a caller provided, string or number of length 4.
1200 value (ok) is a caller provided, non NULL CFTypeRef.
1201 */
1202 static void query_add_attribute_with_desc(const SecDbAttr *desc, const void *value, Query *q)
1203 {
1204 if (CFEqual(desc->name, kSecAttrSynchronizable)) {
1205 q->q_sync = true;
1206 if (CFEqual(value, kSecAttrSynchronizableAny))
1207 return; /* skip the attribute so it isn't part of the search */
1208 }
1209
1210 CFTypeRef attr = NULL;
1211 switch (desc->kind) {
1212 case kSecDbDataAttr:
1213 attr = copyData(value);
1214 break;
1215 case kSecDbBlobAttr:
1216 attr = copyBlob(value);
1217 break;
1218 case kSecDbDateAttr:
1219 case kSecDbCreationDateAttr:
1220 case kSecDbModificationDateAttr:
1221 attr = copyDate(value);
1222 break;
1223 case kSecDbNumberAttr:
1224 case kSecDbSyncAttr:
1225 case kSecDbTombAttr:
1226 attr = copyNumber(value);
1227 break;
1228 case kSecDbAccessAttr:
1229 case kSecDbStringAttr:
1230 attr = copyString(value);
1231 break;
1232 case kSecDbSHA1Attr:
1233 attr = copySHA1(value);
1234 break;
1235 case kSecDbRowIdAttr:
1236 case kSecDbPrimaryKeyAttr:
1237 case kSecDbEncryptedDataAttr:
1238 break;
1239 }
1240
1241 if (!attr) {
1242 SecError(errSecItemInvalidValue, &q->q_error, CFSTR("attribute %@: value: %@ failed to convert"), desc->name, value);
1243 return;
1244 }
1245
1246 /* Store plaintext attr data in q_item unless it's a kSecDbSHA1Attr. */
1247 if (q->q_item && desc->kind != kSecDbSHA1Attr) {
1248 CFDictionarySetValue(q->q_item, desc->name, attr);
1249 }
1250
1251 if (CFEqual(desc->name, kSecAttrAccessible)) {
1252 query_parse_keyclass(attr, q);
1253 }
1254
1255 /* Convert attr to (sha1) digest if requested. */
1256 if (desc->flags & kSecDbSHA1ValueInFlag) {
1257 CFDataRef data = copyData(attr);
1258 CFRelease(attr);
1259 if (!data) {
1260 SecError(errSecInternal, &q->q_error, CFSTR("failed to get attribute %@ data"), desc->name);
1261 return;
1262 }
1263
1264 CFMutableDataRef digest = CFDataCreateMutable(0, CC_SHA1_DIGEST_LENGTH);
1265 CFDataSetLength(digest, CC_SHA1_DIGEST_LENGTH);
1266 /* 64 bits cast: worst case is we generate the wrong hash */
1267 assert((unsigned long)CFDataGetLength(data)<UINT32_MAX); /* Debug check. Correct as long as CFIndex is long */
1268 CCDigest(kCCDigestSHA1, CFDataGetBytePtr(data), (CC_LONG)CFDataGetLength(data),
1269 CFDataGetMutableBytePtr(digest));
1270 CFRelease(data);
1271 attr = digest;
1272 }
1273
1274 /* Record the new attr key, value in q_pairs. */
1275 q->q_pairs[q->q_attr_end].key = desc->name;
1276 q->q_pairs[q->q_attr_end++].value = attr;
1277 }
1278
1279 static void query_add_attribute(const void *key, const void *value, Query *q)
1280 {
1281 const SecDbAttr *desc = SecDbAttrWithKey(q->q_class, key, &q->q_error);
1282 if (desc)
1283 query_add_attribute_with_desc(desc, value, q);
1284 }
1285
1286 /* First remove key from q->q_pairs if it's present, then add the attribute again. */
1287 static void query_set_attribute_with_desc(const SecDbAttr *desc, const void *value, Query *q) {
1288 if (CFDictionaryContainsKey(q->q_item, desc->name)) {
1289 CFIndex ix;
1290 for (ix = 0; ix < q->q_attr_end; ++ix) {
1291 if (CFEqual(desc->name, q->q_pairs[ix].key)) {
1292 CFReleaseSafe(q->q_pairs[ix].value);
1293 --q->q_attr_end;
1294 for (; ix < q->q_attr_end; ++ix) {
1295 q->q_pairs[ix] = q->q_pairs[ix + 1];
1296 }
1297 CFDictionaryRemoveValue(q->q_item, desc->name);
1298 break;
1299 }
1300 }
1301 }
1302 query_add_attribute_with_desc(desc, value, q);
1303 }
1304
1305 /* AUDIT[securityd](done):
1306 key (ok) is a caller provided, string starting with 'm'.
1307 value (ok) is a caller provided, non NULL CFTypeRef.
1308 */
1309 static void query_add_match(const void *key, const void *value, Query *q)
1310 {
1311 /* Record the match key, value in q_pairs. */
1312 --(q->q_match_begin);
1313 q->q_pairs[q->q_match_begin].key = key;
1314 q->q_pairs[q->q_match_begin].value = value;
1315
1316 if (CFEqual(kSecMatchLimit, key)) {
1317 /* Figure out what the value for kSecMatchLimit is if specified. */
1318 if (CFGetTypeID(value) == CFNumberGetTypeID()) {
1319 if (!CFNumberGetValue(value, kCFNumberCFIndexType, &q->q_limit))
1320 SecError(errSecItemInvalidValue, &q->q_error, CFSTR("failed to convert match limit %@ to CFIndex"), value);
1321 } else if (CFEqual(kSecMatchLimitAll, value)) {
1322 q->q_limit = kSecMatchUnlimited;
1323 } else if (CFEqual(kSecMatchLimitOne, value)) {
1324 q->q_limit = 1;
1325 } else {
1326 SecError(errSecItemInvalidValue, &q->q_error, CFSTR("unsupported match limit %@"), value);
1327 }
1328 } else if (CFEqual(kSecMatchIssuers, key) &&
1329 (CFGetTypeID(value) == CFArrayGetTypeID()))
1330 {
1331 CFMutableArrayRef canonical_issuers = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
1332 if (canonical_issuers) {
1333 CFIndex i, count = CFArrayGetCount(value);
1334 for (i = 0; i < count; i++) {
1335 CFTypeRef issuer_data = CFArrayGetValueAtIndex(value, i);
1336 CFDataRef issuer_canonical = NULL;
1337 if (CFDataGetTypeID() == CFGetTypeID(issuer_data))
1338 issuer_canonical = SecDistinguishedNameCopyNormalizedContent((CFDataRef)issuer_data);
1339 if (issuer_canonical) {
1340 CFArrayAppendValue(canonical_issuers, issuer_canonical);
1341 CFRelease(issuer_canonical);
1342 }
1343 }
1344
1345 if (CFArrayGetCount(canonical_issuers) > 0) {
1346 q->q_match_issuer = canonical_issuers;
1347 } else
1348 CFRelease(canonical_issuers);
1349 }
1350 }
1351 }
1352
1353 static bool query_set_class(Query *q, CFStringRef c_name, CFErrorRef *error) {
1354 const SecDbClass *value;
1355 if (c_name && CFGetTypeID(c_name) == CFStringGetTypeID() &&
1356 (value = kc_class_with_name(c_name)) &&
1357 (q->q_class == 0 || q->q_class == value)) {
1358 q->q_class = value;
1359 return true;
1360 }
1361
1362 if (error && !*error)
1363 SecError((c_name ? errSecNoSuchClass : errSecItemClassMissing), error, CFSTR("can find class named: %@"), c_name);
1364
1365
1366 return false;
1367 }
1368
1369 static const SecDbClass *query_get_class(CFDictionaryRef query, CFErrorRef *error) {
1370 CFStringRef c_name = NULL;
1371 const void *value = CFDictionaryGetValue(query, kSecClass);
1372 if (isString(value)) {
1373 c_name = value;
1374 } else {
1375 value = CFDictionaryGetValue(query, kSecValuePersistentRef);
1376 if (isData(value)) {
1377 CFDataRef pref = value;
1378 _SecItemParsePersistentRef(pref, &c_name, 0);
1379 }
1380 }
1381
1382 if (c_name && (value = kc_class_with_name(c_name))) {
1383 return value;
1384 } else {
1385 if (c_name)
1386 SecError(errSecNoSuchClass, error, CFSTR("can't find class named: %@"), c_name);
1387 else
1388 SecError(errSecItemClassMissing, error, CFSTR("query missing class name"));
1389 return NULL;
1390 }
1391 }
1392
1393 /* AUDIT[securityd](done):
1394 key (ok) is a caller provided, string starting with 'c'.
1395 value (ok) is a caller provided, non NULL CFTypeRef.
1396 */
1397 static void query_add_class(const void *key, const void *value, Query *q)
1398 {
1399 if (CFEqual(key, kSecClass)) {
1400 query_set_class(q, value, &q->q_error);
1401 } else {
1402 SecError(errSecItemInvalidKey, &q->q_error, CFSTR("add_class: key %@ is not %@"), key, kSecClass);
1403 }
1404 }
1405
1406 /* AUDIT[securityd](done):
1407 key (ok) is a caller provided, string starting with 'r'.
1408 value (ok) is a caller provided, non NULL CFTypeRef.
1409 */
1410 static void query_add_return(const void *key, const void *value, Query *q)
1411 {
1412 ReturnTypeMask mask;
1413 if (CFGetTypeID(value) != CFBooleanGetTypeID()) {
1414 SecError(errSecItemInvalidValue, &q->q_error, CFSTR("add_return: value %@ is not CFBoolean"), value);
1415 return;
1416 }
1417
1418 int set_it = CFEqual(value, kCFBooleanTrue);
1419
1420 if (CFEqual(key, kSecReturnData))
1421 mask = kSecReturnDataMask;
1422 else if (CFEqual(key, kSecReturnAttributes))
1423 mask = kSecReturnAttributesMask;
1424 else if (CFEqual(key, kSecReturnRef))
1425 mask = kSecReturnRefMask;
1426 else if (CFEqual(key, kSecReturnPersistentRef))
1427 mask = kSecReturnPersistentRefMask;
1428 else {
1429 SecError(errSecItemInvalidKey, &q->q_error, CFSTR("add_return: unknown key %@"), key);
1430 return;
1431 }
1432
1433 if ((q->q_return_type & mask) && !set_it) {
1434 /* Clear out this bit (it's set so xor with the mask will clear it). */
1435 q->q_return_type ^= mask;
1436 } else if (!(q->q_return_type & mask) && set_it) {
1437 /* Set this bit. */
1438 q->q_return_type |= mask;
1439 }
1440 }
1441
1442 /* AUDIT[securityd](done):
1443 key (ok) is a caller provided, string starting with 'u'.
1444 value (ok since q_use_item_list is unused) is a caller provided, non
1445 NULL CFTypeRef.
1446 */
1447 static void query_add_use(const void *key, const void *value, Query *q)
1448 {
1449 if (CFEqual(key, kSecUseItemList)) {
1450 /* TODO: Add sanity checking when we start using this. */
1451 q->q_use_item_list = value;
1452 } else if (CFEqual(key, kSecUseTombstones)) {
1453 if (CFGetTypeID(value) == CFBooleanGetTypeID()) {
1454 q->q_use_tomb = value;
1455 } else if (CFGetTypeID(value) == CFNumberGetTypeID()) {
1456 q->q_use_tomb = CFBooleanGetValue(value) ? kCFBooleanTrue : kCFBooleanFalse;
1457 } else if (CFGetTypeID(value) == CFStringGetTypeID()) {
1458 q->q_use_tomb = CFStringGetIntValue(value) ? kCFBooleanTrue : kCFBooleanFalse;
1459 } else {
1460 SecError(errSecItemInvalidValue, &q->q_error, CFSTR("add_use: value %@ for key %@ is neither CFBoolean nor CFNumber"), value, key);
1461 return;
1462 }
1463 #if defined(MULTIPLE_KEYCHAINS)
1464 } else if (CFEqual(key, kSecUseKeychain)) {
1465 q->q_use_keychain = value;
1466 } else if (CFEqual(key, kSecUseKeychainList)) {
1467 q->q_use_keychain_list = value;
1468 #endif /* !defined(MULTIPLE_KEYCHAINS) */
1469 } else {
1470 SecError(errSecItemInvalidKey, &q->q_error, CFSTR("add_use: unknown key %@"), key);
1471 return;
1472 }
1473 }
1474
1475 static void query_set_data(const void *value, Query *q) {
1476 if (!isData(value)) {
1477 SecError(errSecItemInvalidValue, &q->q_error, CFSTR("set_data: value %@ is not type data"), value);
1478 } else {
1479 q->q_data = value;
1480 if (q->q_item)
1481 CFDictionarySetValue(q->q_item, kSecValueData, value);
1482 }
1483 }
1484
1485 /* AUDIT[securityd](done):
1486 key (ok) is a caller provided, string starting with 'u'.
1487 value (ok) is a caller provided, non NULL CFTypeRef.
1488 */
1489 static void query_add_value(const void *key, const void *value, Query *q)
1490 {
1491 if (CFEqual(key, kSecValueData)) {
1492 query_set_data(value, q);
1493 #ifdef NO_SERVER
1494 } else if (CFEqual(key, kSecValueRef)) {
1495 q->q_ref = value;
1496 /* TODO: Add value type sanity checking. */
1497 #endif
1498 } else if (CFEqual(key, kSecValuePersistentRef)) {
1499 CFStringRef c_name;
1500 if (_SecItemParsePersistentRef(value, &c_name, &q->q_row_id))
1501 query_set_class(q, c_name, &q->q_error);
1502 else
1503 SecError(errSecItemInvalidValue, &q->q_error, CFSTR("add_value: value %@ is not a valid persitent ref"), value);
1504 } else {
1505 SecError(errSecItemInvalidKey, &q->q_error, CFSTR("add_value: unknown key %@"), key);
1506 return;
1507 }
1508 }
1509
1510 /* AUDIT[securityd](done):
1511 key (ok) is a caller provided, unchecked.
1512 value (ok) is a caller provided, unchecked.
1513 */
1514 static void query_update_applier(const void *key, const void *value,
1515 void *context)
1516 {
1517 Query *q = (Query *)context;
1518 /* If something went wrong there is no point processing any more args. */
1519 if (q->q_error)
1520 return;
1521
1522 /* Make sure we have a string key. */
1523 if (!isString(key)) {
1524 SecError(errSecItemInvalidKeyType, &q->q_error, CFSTR("update_applier: unknown key type %@"), key);
1525 return;
1526 }
1527
1528 if (!value) {
1529 SecError(errSecItemInvalidValue, &q->q_error, CFSTR("update_applier: key %@ has NULL value"), key);
1530 return;
1531 }
1532
1533 if (CFEqual(key, kSecValueData)) {
1534 query_set_data(value, q);
1535 } else {
1536 query_add_attribute(key, value, q);
1537 }
1538 }
1539
1540 /* AUDIT[securityd](done):
1541 key (ok) is a caller provided, unchecked.
1542 value (ok) is a caller provided, unchecked.
1543 */
1544 static void query_applier(const void *key, const void *value, void *context)
1545 {
1546 Query *q = (Query *)context;
1547 /* If something went wrong there is no point processing any more args. */
1548 if (q->q_error)
1549 return;
1550
1551 /* Make sure we have a key. */
1552 if (!key) {
1553 SecError(errSecItemInvalidKeyType, &q->q_error, CFSTR("applier: NULL key"));
1554 return;
1555 }
1556
1557 /* Make sure we have a value. */
1558 if (!value) {
1559 SecError(errSecItemInvalidValue, &q->q_error, CFSTR("applier: key %@ has NULL value"), key);
1560 return;
1561 }
1562
1563 /* Figure out what type of key we are dealing with. */
1564 CFTypeID key_id = CFGetTypeID(key);
1565 if (key_id == CFStringGetTypeID()) {
1566 CFIndex key_len = CFStringGetLength(key);
1567 /* String keys can be different things. The subtype is determined by:
1568 length 4 strings are all attributes. Otherwise the first char
1569 determines the type:
1570 c: class must be kSecClass
1571 m: match like kSecMatchPolicy
1572 r: return like kSecReturnData
1573 u: use keys
1574 v: value
1575 */
1576 if (key_len == 4) {
1577 /* attributes */
1578 query_add_attribute(key, value, q);
1579 } else if (key_len > 1) {
1580 UniChar k_first_char = CFStringGetCharacterAtIndex(key, 0);
1581 switch (k_first_char)
1582 {
1583 case 'c': /* class */
1584 query_add_class(key, value, q);
1585 break;
1586 case 'm': /* match */
1587 query_add_match(key, value, q);
1588 break;
1589 case 'r': /* return */
1590 query_add_return(key, value, q);
1591 break;
1592 case 'u': /* use */
1593 query_add_use(key, value, q);
1594 break;
1595 case 'v': /* value */
1596 query_add_value(key, value, q);
1597 break;
1598 default:
1599 SecError(errSecItemInvalidKey, &q->q_error, CFSTR("applier: key %@ invalid"), key);
1600 break;
1601 }
1602 } else {
1603 SecError(errSecItemInvalidKey, &q->q_error, CFSTR("applier: key %@ invalid length"), key);
1604 }
1605 } else if (key_id == CFNumberGetTypeID()) {
1606 /* Numeric keys are always (extended) attributes. */
1607 /* TODO: Why is this here? query_add_attribute() doesn't take numbers. */
1608 query_add_attribute(key, value, q);
1609 } else {
1610 /* We only support string and number type keys. */
1611 SecError(errSecItemInvalidKeyType, &q->q_error, CFSTR("applier: key %@ neither string nor number"), key);
1612 }
1613 }
1614
1615 static CFStringRef query_infer_keyclass(Query *q, CFStringRef agrp) {
1616 /* apsd and lockdown are always dku. */
1617 if (CFEqual(agrp, CFSTR("com.apple.apsd"))
1618 || CFEqual(agrp, CFSTR("lockdown-identities"))) {
1619 return kSecAttrAccessibleAlwaysThisDeviceOnly;
1620 }
1621 /* All other certs or in the apple agrp is dk. */
1622 if (q->q_class == &cert_class) {
1623 /* third party certs are always dk. */
1624 return kSecAttrAccessibleAlways;
1625 }
1626 /* The rest defaults to ak. */
1627 return kSecAttrAccessibleWhenUnlocked;
1628 }
1629
1630 static void query_ensure_keyclass(Query *q, CFStringRef agrp) {
1631 if (q->q_keyclass == 0) {
1632 CFStringRef accessible = query_infer_keyclass(q, agrp);
1633 query_add_attribute(kSecAttrAccessible, accessible, q);
1634 }
1635 }
1636
1637 static bool query_error(Query *q, CFErrorRef *error) {
1638 if (q->q_error) {
1639 CFErrorRef tmp = q->q_error;
1640 q->q_error = NULL;
1641 if (error && !*error) {
1642 *error = tmp;
1643 } else {
1644 CFRelease(tmp);
1645 }
1646 return false;
1647 }
1648 return true;
1649 }
1650
1651 bool query_destroy(Query *q, CFErrorRef *error) {
1652 bool ok = query_error(q, error);
1653 CFIndex ix, attr_count = query_attr_count(q);
1654 for (ix = 0; ix < attr_count; ++ix) {
1655 CFReleaseSafe(query_attr_at(q, ix).value);
1656 }
1657 CFReleaseSafe(q->q_item);
1658 CFReleaseSafe(q->q_primary_key_digest);
1659 CFReleaseSafe(q->q_match_issuer);
1660
1661 free(q);
1662 return ok;
1663 }
1664
1665 static void SecKeychainChanged(bool syncWithPeers) {
1666 uint32_t result = notify_post(g_keychain_changed_notification);
1667 if (syncWithPeers)
1668 SOSCCSyncWithAllPeers();
1669 if (result == NOTIFY_STATUS_OK)
1670 secnotice("item", "Sent %s%s", syncWithPeers ? "SyncWithAllPeers and " : "", g_keychain_changed_notification);
1671 else
1672 secerror("%snotify_post %s returned: %" PRIu32, syncWithPeers ? "Sent SyncWithAllPeers, " : "", g_keychain_changed_notification, result);
1673 }
1674
1675 static bool query_notify_and_destroy(Query *q, bool ok, CFErrorRef *error) {
1676 if (ok && !q->q_error && q->q_sync_changed) {
1677 SecKeychainChanged(true);
1678 }
1679 return query_destroy(q, error) && ok;
1680 }
1681
1682 /* Allocate and initialize a Query object for query. */
1683 Query *query_create(const SecDbClass *qclass, CFDictionaryRef query,
1684 CFErrorRef *error)
1685 {
1686 if (!qclass) {
1687 if (error && !*error)
1688 SecError(errSecItemClassMissing, error, CFSTR("Missing class"));
1689 return NULL;
1690 }
1691
1692 /* Number of pairs we need is the number of attributes in this class
1693 plus the number of keys in the dictionary, minus one for each key in
1694 the dictionary that is a regular attribute. */
1695 CFIndex key_count = SecDbClassAttrCount(qclass);
1696 if (key_count == 0) {
1697 // Identities claim to have 0 attributes, but they really support any keys or cert attribute.
1698 key_count = SecDbClassAttrCount(&cert_class) + SecDbClassAttrCount(&keys_class);
1699 }
1700
1701 if (query) {
1702 key_count += CFDictionaryGetCount(query);
1703 SecDbForEachAttr(qclass, attr) {
1704 if (CFDictionaryContainsKey(query, attr->name))
1705 --key_count;
1706 }
1707 }
1708
1709 if (key_count > QUERY_KEY_LIMIT) {
1710 if (error && !*error)
1711 {
1712 secerror("key_count: %ld, QUERY_KEY_LIMIT: %d", (long)key_count, QUERY_KEY_LIMIT);
1713 SecError(errSecItemIllegalQuery, error, CFSTR("Past query key limit"));
1714 }
1715 return NULL;
1716 }
1717
1718 Query *q = calloc(1, sizeof(Query) + sizeof(Pair) * key_count);
1719 if (q == NULL) {
1720 if (error && !*error)
1721 SecError(errSecAllocate, error, CFSTR("Out of memory"));
1722 return NULL;
1723 }
1724
1725 q->q_keybag = KEYBAG_DEVICE;
1726 q->q_class = qclass;
1727 q->q_match_begin = q->q_match_end = key_count;
1728 q->q_item = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1729
1730 return q;
1731 }
1732
1733 /* Parse query for a Query object q. */
1734 static bool query_parse_with_applier(Query *q, CFDictionaryRef query,
1735 CFDictionaryApplierFunction applier,
1736 CFErrorRef *error) {
1737 CFDictionaryApplyFunction(query, applier, q);
1738 return query_error(q, error);
1739 }
1740
1741 /* Parse query for a Query object q. */
1742 static bool query_parse(Query *q, CFDictionaryRef query,
1743 CFErrorRef *error) {
1744 return query_parse_with_applier(q, query, query_applier, error);
1745 }
1746
1747 /* Parse query for a Query object q. */
1748 static bool query_update_parse(Query *q, CFDictionaryRef update,
1749 CFErrorRef *error) {
1750 return query_parse_with_applier(q, update, query_update_applier, error);
1751 }
1752
1753 static Query *query_create_with_limit(CFDictionaryRef query, CFIndex limit,
1754 CFErrorRef *error) {
1755 Query *q;
1756 q = query_create(query_get_class(query, error), query, error);
1757 if (q) {
1758 q->q_limit = limit;
1759 if (!query_parse(q, query, error)) {
1760 query_destroy(q, error);
1761 return NULL;
1762 }
1763 if (!q->q_sync && !q->q_row_id) {
1764 /* query did not specify a kSecAttrSynchronizable attribute,
1765 * and did not contain a persistent reference. */
1766 query_add_attribute(kSecAttrSynchronizable, kCFBooleanFalse, q);
1767 }
1768 }
1769 return q;
1770 }
1771
1772
1773 //TODO: Move this to SecDbItemRef
1774
1775 /* Make sure all attributes that are marked as not_null have a value. If
1776 force_date is false, only set mdat and cdat if they aren't already set. */
1777 static void
1778 query_pre_add(Query *q, bool force_date) {
1779 CFDateRef now = CFDateCreate(0, CFAbsoluteTimeGetCurrent());
1780 SecDbForEachAttrWithMask(q->q_class, desc, kSecDbInFlag) {
1781 if (desc->kind == kSecDbCreationDateAttr ||
1782 desc->kind == kSecDbModificationDateAttr) {
1783 if (force_date) {
1784 query_set_attribute_with_desc(desc, now, q);
1785 } else if (!CFDictionaryContainsKey(q->q_item, desc->name)) {
1786 query_add_attribute_with_desc(desc, now, q);
1787 }
1788 } else if ((desc->flags & kSecDbNotNullFlag) &&
1789 !CFDictionaryContainsKey(q->q_item, desc->name)) {
1790 CFTypeRef value = NULL;
1791 if (desc->flags & kSecDbDefault0Flag) {
1792 if (desc->kind == kSecDbDateAttr)
1793 value = CFDateCreate(kCFAllocatorDefault, 0.0);
1794 else {
1795 SInt32 vzero = 0;
1796 value = CFNumberCreate(0, kCFNumberSInt32Type, &vzero);
1797 }
1798 } else if (desc->flags & kSecDbDefaultEmptyFlag) {
1799 if (desc->kind == kSecDbDataAttr)
1800 value = CFDataCreate(kCFAllocatorDefault, NULL, 0);
1801 else {
1802 value = CFSTR("");
1803 CFRetain(value);
1804 }
1805 }
1806 if (value) {
1807 /* Safe to use query_add_attribute here since the attr wasn't
1808 set yet. */
1809 query_add_attribute_with_desc(desc, value, q);
1810 CFRelease(value);
1811 }
1812 }
1813 }
1814 CFReleaseSafe(now);
1815 }
1816
1817 //TODO: Move this to SecDbItemRef
1818
1819 /* Update modification_date if needed. */
1820 static void
1821 query_pre_update(Query *q) {
1822 SecDbForEachAttr(q->q_class, desc) {
1823 if (desc->kind == kSecDbModificationDateAttr) {
1824 CFDateRef now = CFDateCreate(0, CFAbsoluteTimeGetCurrent());
1825 query_set_attribute_with_desc(desc, now, q);
1826 CFReleaseSafe(now);
1827 }
1828 }
1829 }
1830
1831 /* AUDIT[securityd](done):
1832 accessGroup (ok) is a caller provided, non NULL CFTypeRef.
1833
1834 Return true iff accessGroup is allowable according to accessGroups.
1835 */
1836 static bool accessGroupsAllows(CFArrayRef accessGroups,
1837 CFStringRef accessGroup) {
1838 /* NULL accessGroups is wildcard. */
1839 if (!accessGroups)
1840 return true;
1841 /* Make sure we have a string. */
1842 if (!isString(accessGroup))
1843 return false;
1844
1845 /* Having the special accessGroup "*" allows access to all accessGroups. */
1846 CFRange range = { 0, CFArrayGetCount(accessGroups) };
1847 if (range.length &&
1848 (CFArrayContainsValue(accessGroups, range, accessGroup) ||
1849 CFArrayContainsValue(accessGroups, range, CFSTR("*"))))
1850 return true;
1851
1852 return false;
1853 }
1854
1855 static bool itemInAccessGroup(CFDictionaryRef item, CFArrayRef accessGroups) {
1856 return accessGroupsAllows(accessGroups,
1857 CFDictionaryGetValue(item, kSecAttrAccessGroup));
1858 }
1859
1860 static void s3dl_merge_into_dict(const void *key, const void *value, void *context) {
1861 CFDictionarySetValue(context, key, value);
1862 }
1863
1864 /* Return whatever the caller requested based on the value of q->q_return_type.
1865 keys and values must be 3 larger than attr_count in size to accomadate the
1866 optional data, class and persistent ref results. This is so we can use
1867 the CFDictionaryCreate() api here rather than appending to a
1868 mutable dictionary. */
1869 static CFTypeRef handle_result(Query *q, CFMutableDictionaryRef item,
1870 sqlite_int64 rowid) {
1871 CFTypeRef a_result;
1872 CFDataRef data;
1873 data = CFDictionaryGetValue(item, kSecValueData);
1874 if (q->q_return_type == 0) {
1875 /* Caller isn't interested in any results at all. */
1876 a_result = kCFNull;
1877 } else if (q->q_return_type == kSecReturnDataMask) {
1878 if (data) {
1879 a_result = data;
1880 CFRetain(a_result);
1881 } else {
1882 a_result = CFDataCreate(kCFAllocatorDefault, NULL, 0);
1883 }
1884 } else if (q->q_return_type == kSecReturnPersistentRefMask) {
1885 a_result = _SecItemMakePersistentRef(q->q_class->name, rowid);
1886 } else {
1887 /* We need to return more than one value. */
1888 if (q->q_return_type & kSecReturnRefMask) {
1889 CFDictionarySetValue(item, kSecClass, q->q_class->name);
1890 } else if ((q->q_return_type & kSecReturnAttributesMask)) {
1891 if (!(q->q_return_type & kSecReturnDataMask)) {
1892 CFDictionaryRemoveValue(item, kSecValueData);
1893 }
1894 } else {
1895 if (data)
1896 CFRetain(data);
1897 CFDictionaryRemoveAllValues(item);
1898 if ((q->q_return_type & kSecReturnDataMask) && data) {
1899 CFDictionarySetValue(item, kSecValueData, data);
1900 CFRelease(data);
1901 }
1902 }
1903 if (q->q_return_type & kSecReturnPersistentRefMask) {
1904 CFDataRef pref = _SecItemMakePersistentRef(q->q_class->name, rowid);
1905 CFDictionarySetValue(item, kSecValuePersistentRef, pref);
1906 CFRelease(pref);
1907 }
1908
1909 a_result = item;
1910 CFRetain(item);
1911 }
1912
1913 return a_result;
1914 }
1915
1916 static CFDataRef SecDbItemMakePersistentRef(SecDbItemRef item, CFErrorRef *error) {
1917 sqlite3_int64 row_id = SecDbItemGetRowId(item, error);
1918 if (row_id)
1919 return _SecItemMakePersistentRef(SecDbItemGetClass(item)->name, row_id);
1920 return NULL;
1921 }
1922
1923 static CFTypeRef SecDbItemCopyResult(SecDbItemRef item, ReturnTypeMask return_type, CFErrorRef *error) {
1924 CFTypeRef a_result;
1925
1926 if (return_type == 0) {
1927 /* Caller isn't interested in any results at all. */
1928 a_result = kCFNull;
1929 } else if (return_type == kSecReturnDataMask) {
1930 a_result = SecDbItemGetCachedValueWithName(item, kSecValueData);
1931 if (a_result) {
1932 CFRetainSafe(a_result);
1933 } else {
1934 a_result = CFDataCreate(kCFAllocatorDefault, NULL, 0);
1935 }
1936 } else if (return_type == kSecReturnPersistentRefMask) {
1937 a_result = SecDbItemMakePersistentRef(item, error);
1938 } else {
1939 CFMutableDictionaryRef dict = CFDictionaryCreateMutableForCFTypes(CFGetAllocator(item));
1940 /* We need to return more than one value. */
1941 if (return_type & kSecReturnRefMask) {
1942 CFDictionarySetValue(dict, kSecClass, SecDbItemGetClass(item)->name);
1943 }
1944 CFOptionFlags mask = (((return_type & kSecReturnDataMask || return_type & kSecReturnRefMask) ? kSecDbReturnDataFlag : 0) |
1945 ((return_type & kSecReturnAttributesMask || return_type & kSecReturnRefMask) ? kSecDbReturnAttrFlag : 0));
1946 SecDbForEachAttr(SecDbItemGetClass(item), desc) {
1947 if ((desc->flags & mask) != 0) {
1948 CFTypeRef value = SecDbItemGetValue(item, desc, error);
1949 if (value && !CFEqual(kCFNull, value)) {
1950 CFDictionarySetValue(dict, desc->name, value);
1951 } else if (value == NULL) {
1952 CFReleaseNull(dict);
1953 break;
1954 }
1955 }
1956 }
1957 if (return_type & kSecReturnPersistentRefMask) {
1958 CFDataRef pref = SecDbItemMakePersistentRef(item, error);
1959 CFDictionarySetValue(dict, kSecValuePersistentRef, pref);
1960 CFRelease(pref);
1961 }
1962
1963 a_result = dict;
1964 }
1965
1966 return a_result;
1967 }
1968
1969
1970 // MARK: -
1971 // MARK: Forward declarations
1972
1973 static CFMutableDictionaryRef
1974 s3dl_item_from_col(sqlite3_stmt *stmt, Query *q, int col,
1975 CFArrayRef accessGroups, keyclass_t *keyclass, CFErrorRef *error);
1976
1977 /* AUDIT[securityd](done):
1978 attributes (ok) is a caller provided dictionary, only its cf type has
1979 been checked.
1980 */
1981 static bool
1982 s3dl_query_add(SecDbConnectionRef dbt, Query *q, CFTypeRef *result, CFErrorRef *error)
1983 {
1984 if (query_match_count(q) != 0)
1985 return errSecItemMatchUnsupported;
1986
1987 /* Add requires a class to be specified unless we are adding a ref. */
1988 if (q->q_use_item_list)
1989 return errSecUseItemListUnsupported;
1990
1991 /* Actual work here. */
1992 SecDbItemRef item = SecDbItemCreateWithAttributes(kCFAllocatorDefault, q->q_class, q->q_item, KEYBAG_DEVICE, error);
1993 if (!item)
1994 return false;
1995
1996 bool ok = true;
1997 if (q->q_data)
1998 ok = SecDbItemSetValueWithName(item, CFSTR("v_Data"), q->q_data, error);
1999 if (q->q_row_id)
2000 ok = SecDbItemSetRowId(item, q->q_row_id, error);
2001
2002 if (ok)
2003 ok = SecDbItemInsert(item, dbt, error);
2004 if (ok) {
2005 if (result && q->q_return_type) {
2006 *result = SecDbItemCopyResult(item, q->q_return_type, error);
2007 }
2008 }
2009 if (!ok && error && *error) {
2010 if (CFEqual(CFErrorGetDomain(*error), kSecDbErrorDomain) && CFErrorGetCode(*error) == SQLITE_CONSTRAINT) {
2011 CFReleaseNull(*error);
2012 SecError(errSecDuplicateItem, error, CFSTR("duplicate item %@"), item);
2013 }
2014 }
2015
2016 if (ok) {
2017 q->q_changed = true;
2018 if (SecDbItemIsSyncable(item))
2019 q->q_sync_changed = true;
2020 }
2021
2022 secdebug("dbitem", "inserting item %@%s%@", item, ok ? "" : "failed: ", ok || error == NULL ? (CFErrorRef)CFSTR("") : *error);
2023
2024 CFRelease(item);
2025
2026 return ok;
2027 }
2028
2029 typedef void (*s3dl_handle_row)(sqlite3_stmt *stmt, void *context);
2030
2031 /* Return a (mutable) dictionary if plist is a dictionary, return NULL and set error otherwise. Does nothing if plist is already NULL. */
2032 static CFMutableDictionaryRef dictionaryFromPlist(CFPropertyListRef plist, CFErrorRef *error) {
2033 if (plist && !isDictionary(plist)) {
2034 CFStringRef typeName = CFCopyTypeIDDescription(CFGetTypeID((CFTypeRef)plist));
2035 SecError(errSecDecode, error, CFSTR("plist is a %@, expecting a dictionary"), typeName);
2036 CFReleaseSafe(typeName);
2037 CFReleaseNull(plist);
2038 }
2039 return (CFMutableDictionaryRef)plist;
2040 }
2041
2042 static CFMutableDictionaryRef s3dl_item_v2_decode(CFDataRef plain, CFErrorRef *error) {
2043 CFPropertyListRef item;
2044 item = CFPropertyListCreateWithData(0, plain, kCFPropertyListMutableContainers, NULL, error);
2045 return dictionaryFromPlist(item, error);
2046 }
2047
2048 static CFMutableDictionaryRef s3dl_item_v3_decode(CFDataRef plain, CFErrorRef *error) {
2049 CFPropertyListRef item = NULL;
2050 const uint8_t *der = CFDataGetBytePtr(plain);
2051 const uint8_t *der_end = der + CFDataGetLength(plain);
2052 der = der_decode_plist(0, kCFPropertyListMutableContainers, &item, error, der, der_end);
2053 if (der && der != der_end) {
2054 SecCFCreateError(errSecDecode, kSecErrorDomain, CFSTR("trailing garbage at end of decrypted item"), NULL, error);
2055 CFReleaseNull(item);
2056 }
2057 return dictionaryFromPlist(item, error);
2058 }
2059
2060 static CFMutableDictionaryRef
2061 s3dl_item_from_data(CFDataRef edata, Query *q, CFArrayRef accessGroups, keyclass_t *keyclass, CFErrorRef *error) {
2062 CFMutableDictionaryRef item = NULL;
2063 CFDataRef plain = NULL;
2064
2065 /* Decrypt and decode the item and check the decoded attributes against the query. */
2066 uint32_t version;
2067 require_quiet((ks_decrypt_data(q->q_keybag, keyclass, edata, &plain, &version, error)), out);
2068 if (version < 2) {
2069 goto out;
2070 }
2071
2072 if (version < 3) {
2073 item = s3dl_item_v2_decode(plain, error);
2074 } else {
2075 item = s3dl_item_v3_decode(plain, error);
2076 }
2077
2078 if (!item && plain) {
2079 secerror("decode v%d failed: %@ [item: %@]", version, error ? *error : NULL, plain);
2080 }
2081 if (item && !itemInAccessGroup(item, accessGroups)) {
2082 secerror("items accessGroup %@ not in %@",
2083 CFDictionaryGetValue(item, kSecAttrAccessGroup),
2084 accessGroups);
2085 CFReleaseNull(item);
2086 }
2087 /* TODO: Validate keyclass attribute. */
2088
2089 out:
2090 CFReleaseSafe(plain);
2091 return item;
2092 }
2093
2094 static CFDataRef
2095 s3dl_copy_data_from_col(sqlite3_stmt *stmt, int col, CFErrorRef *error) {
2096 return CFDataCreateWithBytesNoCopy(0, sqlite3_column_blob(stmt, col),
2097 sqlite3_column_bytes(stmt, col),
2098 kCFAllocatorNull);
2099 }
2100
2101 static CFMutableDictionaryRef
2102 s3dl_item_from_col(sqlite3_stmt *stmt, Query *q, int col,
2103 CFArrayRef accessGroups, keyclass_t *keyclass, CFErrorRef *error) {
2104 CFMutableDictionaryRef item = NULL;
2105 CFDataRef edata = NULL;
2106 require(edata = s3dl_copy_data_from_col(stmt, col, error), out);
2107 item = s3dl_item_from_data(edata, q, accessGroups, keyclass, error);
2108
2109 out:
2110 CFReleaseSafe(edata);
2111 return item;
2112 }
2113
2114 struct s3dl_query_ctx {
2115 Query *q;
2116 CFArrayRef accessGroups;
2117 CFTypeRef result;
2118 int found;
2119 };
2120
2121 static bool match_item(Query *q, CFArrayRef accessGroups, CFDictionaryRef item);
2122
2123 static void s3dl_query_row(sqlite3_stmt *stmt, void *context) {
2124 struct s3dl_query_ctx *c = context;
2125 Query *q = c->q;
2126
2127 CFMutableDictionaryRef item = s3dl_item_from_col(stmt, q, 1,
2128 c->accessGroups, NULL, &q->q_error);
2129 sqlite_int64 rowid = sqlite3_column_int64(stmt, 0);
2130 if (!item) {
2131 secerror("decode %@,rowid=%" PRId64 " failed (%ld): %@", q->q_class->name, rowid, CFErrorGetCode(q->q_error), q->q_error);
2132 // errSecDecode means the tiem is corrupted, stash it for delete.
2133 if(CFErrorGetCode(q->q_error)==errSecDecode)
2134 {
2135 secerror("We should attempt to delete this row (%lld)", rowid);
2136
2137 {
2138 CFDataRef edata = s3dl_copy_data_from_col(stmt, 1, NULL);
2139 CFMutableStringRef edatastring = CFStringCreateMutable(kCFAllocatorDefault, 0);
2140 if(edatastring) {
2141 CFStringAppendEncryptedData(edatastring, edata);
2142 secnotice("item", "corrupted edata=%@", edatastring);
2143 }
2144 CFReleaseSafe(edata);
2145 CFReleaseSafe(edatastring);
2146 }
2147
2148 if(q->corrupted_rows==NULL) {
2149 q->corrupted_rows=CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
2150 }
2151
2152 if(q->corrupted_rows==NULL) {
2153 secerror("Could not create a mutable array to store corrupted row! No memory ?");
2154 } else {
2155 long long row=rowid;
2156 CFNumberRef number = CFNumberCreate(kCFAllocatorDefault, kCFNumberLongLongType, &row);
2157 if(number==NULL) {
2158 secerror("Could not create a CFNumber to store corrupted row! No memory ?");
2159 } else {
2160 CFArrayAppendValue(q->corrupted_rows, number);
2161 CFReleaseNull(number);
2162 /* Hide this error, this will just pretend the item didnt exist at all */
2163 CFReleaseNull(q->q_error);
2164 }
2165 }
2166 }
2167 // q->q_error will be released appropriately by a call to query_error
2168 return;
2169 }
2170
2171 if (q->q_class == &identity_class) {
2172 // TODO: Use col 2 for key rowid and use both rowids in persistent ref.
2173 CFMutableDictionaryRef key = s3dl_item_from_col(stmt, q, 3,
2174 c->accessGroups, NULL, &q->q_error);
2175
2176 /* TODO : if there is a errSecDecode error here, we should cleanup */
2177 if (!key)
2178 goto out;
2179
2180 CFDataRef certData = CFDictionaryGetValue(item, kSecValueData);
2181 if (certData) {
2182 CFDictionarySetValue(key, CFSTR(CERTIFICATE_DATA_COLUMN_LABEL),
2183 certData);
2184 CFDictionaryRemoveValue(item, kSecValueData);
2185 }
2186 CFDictionaryApplyFunction(item, s3dl_merge_into_dict, key);
2187 CFRelease(item);
2188 item = key;
2189 }
2190
2191 if (!match_item(q, c->accessGroups, item))
2192 goto out;
2193
2194 CFTypeRef a_result = handle_result(q, item, rowid);
2195 if (a_result) {
2196 if (a_result == kCFNull) {
2197 /* Caller wasn't interested in a result, but we still
2198 count this row as found. */
2199 } else if (q->q_limit == 1) {
2200 c->result = a_result;
2201 } else {
2202 CFArrayAppendValue((CFMutableArrayRef)c->result, a_result);
2203 CFRelease(a_result);
2204 }
2205 c->found++;
2206 }
2207
2208 out:
2209 CFRelease(item);
2210 }
2211
2212 static void
2213 SecDbAppendWhereROWID(CFMutableStringRef sql,
2214 CFStringRef col, sqlite_int64 row_id,
2215 bool *needWhere) {
2216 if (row_id > 0) {
2217 SecDbAppendWhereOrAnd(sql, needWhere);
2218 CFStringAppendFormat(sql, NULL, CFSTR("%@=%lld"), col, row_id);
2219 }
2220 }
2221
2222 static void
2223 SecDbAppendWhereAttrs(CFMutableStringRef sql, const Query *q, bool *needWhere) {
2224 CFIndex ix, attr_count = query_attr_count(q);
2225 for (ix = 0; ix < attr_count; ++ix) {
2226 SecDbAppendWhereOrAndEquals(sql, query_attr_at(q, ix).key, needWhere);
2227 }
2228 }
2229
2230 static void
2231 SecDbAppendWhereAccessGroups(CFMutableStringRef sql,
2232 CFStringRef col,
2233 CFArrayRef accessGroups,
2234 bool *needWhere) {
2235 CFIndex ix, ag_count;
2236 if (!accessGroups || 0 == (ag_count = CFArrayGetCount(accessGroups))) {
2237 return;
2238 }
2239
2240 SecDbAppendWhereOrAnd(sql, needWhere);
2241 CFStringAppend(sql, col);
2242 CFStringAppend(sql, CFSTR(" IN (?"));
2243 for (ix = 1; ix < ag_count; ++ix) {
2244 CFStringAppend(sql, CFSTR(",?"));
2245 }
2246 CFStringAppend(sql, CFSTR(")"));
2247 }
2248
2249 static void SecDbAppendWhereClause(CFMutableStringRef sql, const Query *q,
2250 CFArrayRef accessGroups) {
2251 bool needWhere = true;
2252 SecDbAppendWhereROWID(sql, CFSTR("ROWID"), q->q_row_id, &needWhere);
2253 SecDbAppendWhereAttrs(sql, q, &needWhere);
2254 SecDbAppendWhereAccessGroups(sql, CFSTR("agrp"), accessGroups, &needWhere);
2255 }
2256
2257 static void SecDbAppendLimit(CFMutableStringRef sql, CFIndex limit) {
2258 if (limit != kSecMatchUnlimited)
2259 CFStringAppendFormat(sql, NULL, CFSTR(" LIMIT %" PRIdCFIndex), limit);
2260 }
2261
2262 static CFStringRef s3dl_select_sql(Query *q, CFArrayRef accessGroups) {
2263 CFMutableStringRef sql = CFStringCreateMutable(NULL, 0);
2264 if (q->q_class == &identity_class) {
2265 CFStringAppendFormat(sql, NULL, CFSTR("SELECT crowid, "
2266 CERTIFICATE_DATA_COLUMN_LABEL ", rowid,data FROM "
2267 "(SELECT cert.rowid AS crowid, cert.labl AS labl,"
2268 " cert.issr AS issr, cert.slnr AS slnr, cert.skid AS skid,"
2269 " keys.*,cert.data AS " CERTIFICATE_DATA_COLUMN_LABEL
2270 " FROM keys, cert"
2271 " WHERE keys.priv == 1 AND cert.pkhh == keys.klbl"));
2272 SecDbAppendWhereAccessGroups(sql, CFSTR("cert.agrp"), accessGroups, 0);
2273 /* The next 3 SecDbAppendWhere calls are in the same order as in
2274 SecDbAppendWhereClause(). This makes sqlBindWhereClause() work,
2275 as long as we do an extra sqlBindAccessGroups first. */
2276 SecDbAppendWhereROWID(sql, CFSTR("crowid"), q->q_row_id, 0);
2277 CFStringAppend(sql, CFSTR(")"));
2278 bool needWhere = true;
2279 SecDbAppendWhereAttrs(sql, q, &needWhere);
2280 SecDbAppendWhereAccessGroups(sql, CFSTR("agrp"), accessGroups, &needWhere);
2281 } else {
2282 CFStringAppend(sql, CFSTR("SELECT rowid, data FROM "));
2283 CFStringAppend(sql, q->q_class->name);
2284 SecDbAppendWhereClause(sql, q, accessGroups);
2285 }
2286 SecDbAppendLimit(sql, q->q_limit);
2287
2288 return sql;
2289 }
2290
2291 static bool sqlBindAccessGroups(sqlite3_stmt *stmt, CFArrayRef accessGroups,
2292 int *pParam, CFErrorRef *error) {
2293 bool result = true;
2294 int param = *pParam;
2295 CFIndex ix, count = accessGroups ? CFArrayGetCount(accessGroups) : 0;
2296 for (ix = 0; ix < count; ++ix) {
2297 result = SecDbBindObject(stmt, param++,
2298 CFArrayGetValueAtIndex(accessGroups, ix),
2299 error);
2300 if (!result)
2301 break;
2302 }
2303 *pParam = param;
2304 return result;
2305 }
2306
2307 static bool sqlBindWhereClause(sqlite3_stmt *stmt, const Query *q,
2308 CFArrayRef accessGroups, int *pParam, CFErrorRef *error) {
2309 bool result = true;
2310 int param = *pParam;
2311 CFIndex ix, attr_count = query_attr_count(q);
2312 for (ix = 0; ix < attr_count; ++ix) {
2313 result = SecDbBindObject(stmt, param++, query_attr_at(q, ix).value, error);
2314 if (!result)
2315 break;
2316 }
2317
2318 /* Bind the access group to the sql. */
2319 if (result) {
2320 result = sqlBindAccessGroups(stmt, accessGroups, &param, error);
2321 }
2322
2323 *pParam = param;
2324 return result;
2325 }
2326
2327 static bool SecDbItemQuery(SecDbQueryRef query, CFArrayRef accessGroups, SecDbConnectionRef dbconn, CFErrorRef *error,
2328 void (^handle_row)(SecDbItemRef item, bool *stop)) {
2329 __block bool ok = true;
2330 /* Sanity check the query. */
2331 if (query->q_ref)
2332 return SecError(errSecValueRefUnsupported, error, CFSTR("value ref not supported by queries"));
2333
2334 bool (^return_attr)(const SecDbAttr *attr) = ^bool (const SecDbAttr * attr) {
2335 return attr->kind == kSecDbRowIdAttr || attr->kind == kSecDbEncryptedDataAttr;
2336 };
2337
2338 CFStringRef sql = s3dl_select_sql(query, accessGroups);
2339 ok = sql;
2340 if (sql) {
2341 ok &= SecDbPrepare(dbconn, sql, error, ^(sqlite3_stmt *stmt) {
2342 /* Bind the values being searched for to the SELECT statement. */
2343 int param = 1;
2344 if (query->q_class == &identity_class) {
2345 /* Bind the access groups to cert.agrp. */
2346 ok &= sqlBindAccessGroups(stmt, accessGroups, &param, error);
2347 }
2348 if (ok)
2349 ok &= sqlBindWhereClause(stmt, query, accessGroups, &param, error);
2350 if (ok) {
2351 SecDbStep(dbconn, stmt, error, ^(bool *stop) {
2352 SecDbItemRef item = SecDbItemCreateWithStatement(kCFAllocatorDefault, query->q_class, stmt, query->q_keybag, error, return_attr);
2353 if (item) {
2354 if (match_item(query, accessGroups, item->attributes))
2355 handle_row(item, stop);
2356 CFRelease(item);
2357 } else {
2358 secerror("failed to create item from stmt: %@", error ? *error : (CFErrorRef)"no error");
2359 if (error) {
2360 CFReleaseNull(*error);
2361 }
2362 //*stop = true;
2363 //ok = false;
2364 }
2365 });
2366 }
2367 });
2368 CFRelease(sql);
2369 }
2370
2371 return ok;
2372 }
2373
2374 static bool
2375 s3dl_query(SecDbConnectionRef dbt, s3dl_handle_row handle_row,
2376 void *context, CFErrorRef *error)
2377 {
2378 struct s3dl_query_ctx *c = context;
2379 Query *q = c->q;
2380 CFArrayRef accessGroups = c->accessGroups;
2381
2382 /* Sanity check the query. */
2383 if (q->q_ref)
2384 return SecError(errSecValueRefUnsupported, error, CFSTR("value ref not supported by queries"));
2385
2386 /* Actual work here. */
2387 if (q->q_limit == 1) {
2388 c->result = NULL;
2389 } else {
2390 c->result = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
2391 }
2392 CFStringRef sql = s3dl_select_sql(q, accessGroups);
2393 bool ok = SecDbWithSQL(dbt, sql, error, ^(sqlite3_stmt *stmt) {
2394 bool sql_ok = true;
2395 /* Bind the values being searched for to the SELECT statement. */
2396 int param = 1;
2397 if (q->q_class == &identity_class) {
2398 /* Bind the access groups to cert.agrp. */
2399 sql_ok = sqlBindAccessGroups(stmt, accessGroups, &param, error);
2400 }
2401 if (sql_ok)
2402 sql_ok = sqlBindWhereClause(stmt, q, accessGroups, &param, error);
2403 if (sql_ok) {
2404 SecDbForEach(stmt, error, ^bool (int row_index) {
2405 handle_row(stmt, context);
2406 return (!q->q_error) && (q->q_limit == kSecMatchUnlimited || c->found < q->q_limit);
2407 });
2408 }
2409 return sql_ok;
2410 });
2411
2412 CFRelease(sql);
2413
2414 // First get the error from the query, since errSecDuplicateItem from an
2415 // update query should superceed the errSecItemNotFound below.
2416 if (!query_error(q, error))
2417 ok = false;
2418 if (ok && c->found == 0)
2419 ok = SecError(errSecItemNotFound, error, CFSTR("no matching items found"));
2420
2421 return ok;
2422 }
2423
2424 #if 0
2425 /* Gross hack to recover from item corruption */
2426 static void
2427 s3dl_cleanup_corrupted(SecDbConnectionRef dbt, Query *q, CFErrorRef *error)
2428 {
2429
2430 if(q->corrupted_rows==NULL)
2431 return;
2432
2433 __security_simulatecrash(CFSTR("Corrupted items found in keychain"));
2434
2435 if (q->q_class == &identity_class) {
2436 /* TODO: how to cleanup in that case */
2437 secerror("Cleaning up corrupted identities is not implemented yet");
2438 goto out;
2439 }
2440
2441 CFArrayForEach(q->corrupted_rows, ^(const void *value) {
2442 CFMutableStringRef sql=CFStringCreateMutable(kCFAllocatorDefault, 0);
2443
2444 if(sql==NULL) {
2445 secerror("Could not allocate CFString for sql, out of memory ?");
2446 } else {
2447 CFStringAppend(sql, CFSTR("DELETE FROM "));
2448 CFStringAppend(sql, q->q_class->name);
2449 CFStringAppendFormat(sql, NULL, CFSTR(" WHERE rowid=%@"), value);
2450
2451 secerror("Attempting cleanup with %@", sql);
2452
2453 if(!SecDbExec(dbt, sql, error)) {
2454 secerror("Cleanup Failed using %@, error: %@", sql, error?NULL:*error);
2455 } else {
2456 secerror("Cleanup Succeeded using %@", sql);
2457 }
2458
2459 CFReleaseSafe(sql);
2460 }
2461 });
2462
2463 out:
2464 CFReleaseNull(q->corrupted_rows);
2465 }
2466 #endif
2467
2468 static bool
2469 s3dl_copy_matching(SecDbConnectionRef dbt, Query *q, CFTypeRef *result,
2470 CFArrayRef accessGroups, CFErrorRef *error)
2471 {
2472 struct s3dl_query_ctx ctx = {
2473 .q = q, .accessGroups = accessGroups,
2474 };
2475 if (q->q_row_id && query_attr_count(q))
2476 return SecError(errSecItemIllegalQuery, error,
2477 CFSTR("attributes to query illegal; both row_id and other attributes can't be searched at the same time"));
2478
2479 // Only copy things that aren't tombstones unless the client explicitly asks otherwise.
2480 if (!CFDictionaryContainsKey(q->q_item, kSecAttrTombstone))
2481 query_add_attribute(kSecAttrTombstone, kCFBooleanFalse, q);
2482 bool ok = s3dl_query(dbt, s3dl_query_row, &ctx, error);
2483 if (ok && result)
2484 *result = ctx.result;
2485 else
2486 CFReleaseSafe(ctx.result);
2487
2488 // s3dl_cleanup_corrupted(dbt, q, error);
2489
2490 return ok;
2491 }
2492
2493 /* AUDIT[securityd](done):
2494 attributesToUpdate (ok) is a caller provided dictionary,
2495 only its cf types have been checked.
2496 */
2497 static bool
2498 s3dl_query_update(SecDbConnectionRef dbt, Query *q,
2499 CFDictionaryRef attributesToUpdate, CFArrayRef accessGroups, CFErrorRef *error)
2500 {
2501 /* Sanity check the query. */
2502 if (query_match_count(q) != 0)
2503 return SecError(errSecItemMatchUnsupported, error, CFSTR("match not supported in attributes to update"));
2504 if (q->q_ref)
2505 return SecError(errSecValueRefUnsupported, error, CFSTR("value ref not supported in attributes to update"));
2506 if (q->q_row_id && query_attr_count(q))
2507 return SecError(errSecItemIllegalQuery, error, CFSTR("attributes to update illegal; both row_id and other attributes can't be updated at the same time"));
2508
2509 __block bool result = true;
2510 Query *u = query_create(q->q_class, attributesToUpdate, error);
2511 if (u == NULL) return false;
2512 require_action_quiet(query_update_parse(u, attributesToUpdate, error), errOut, result = false);
2513 query_pre_update(u);
2514 result &= SecDbTransaction(dbt, kSecDbExclusiveTransactionType, error, ^(bool *commit) {
2515 // Make sure we only update real items, not tombstones, unless the client explicitly asks otherwise.
2516 if (!CFDictionaryContainsKey(q->q_item, kSecAttrTombstone))
2517 query_add_attribute(kSecAttrTombstone, kCFBooleanFalse, q);
2518 result &= SecDbItemQuery(q, accessGroups, dbt, error, ^(SecDbItemRef item, bool *stop) {
2519 //We always need to know the error here.
2520 CFErrorRef localError = NULL;
2521 SecDbItemRef new_item = SecDbItemCopyWithUpdates(item, u->q_item, &localError);
2522 if(SecErrorGetOSStatus(localError)==errSecDecode) {
2523 // We just ignore this, and treat as if item is not found
2524 secerror("Trying to update to a corrupted item");
2525 CFReleaseSafe(localError);
2526 return;
2527 }
2528
2529 if (error && *error == NULL) {
2530 *error = localError;
2531 localError = NULL;
2532 }
2533 CFReleaseSafe(localError);
2534
2535 result = new_item;
2536 if (new_item) {
2537 bool item_is_sync = SecDbItemIsSyncable(item);
2538 bool makeTombstone = q->q_use_tomb ? CFBooleanGetValue(q->q_use_tomb) : (item_is_sync && !SecDbItemIsTombstone(item));
2539 result = SecDbItemUpdate(item, new_item, dbt, makeTombstone, error);
2540 if (result) {
2541 q->q_changed = true;
2542 if (item_is_sync || SecDbItemIsSyncable(new_item))
2543 q->q_sync_changed = true;
2544 }
2545 CFRelease(new_item);
2546 }
2547 if (!result)
2548 *stop = true;
2549 });
2550 if (!result)
2551 *commit = false;
2552 });
2553 if (result && !q->q_changed)
2554 result = SecError(errSecItemNotFound, error, CFSTR("No items updated"));
2555 errOut:
2556 if (!query_destroy(u, error))
2557 result = false;
2558 return result;
2559 }
2560
2561 static bool
2562 s3dl_query_delete(SecDbConnectionRef dbt, Query *q, CFArrayRef accessGroups, CFErrorRef *error)
2563 {
2564 __block bool ok = true;
2565 // Only delete things that aren't tombstones, unless the client explicitly asks otherwise.
2566 if (!CFDictionaryContainsKey(q->q_item, kSecAttrTombstone))
2567 query_add_attribute(kSecAttrTombstone, kCFBooleanFalse, q);
2568 ok &= SecDbItemSelect(q, dbt, error, ^bool(const SecDbAttr *attr) {
2569 return false;
2570 },^bool(CFMutableStringRef sql, bool *needWhere) {
2571 SecDbAppendWhereClause(sql, q, accessGroups);
2572 return true;
2573 },^bool(sqlite3_stmt * stmt, int col) {
2574 return sqlBindWhereClause(stmt, q, accessGroups, &col, error);
2575 }, ^(SecDbItemRef item, bool *stop) {
2576 bool item_is_sync = SecDbItemIsSyncable(item);
2577 bool makeTombstone = q->q_use_tomb ? CFBooleanGetValue(q->q_use_tomb) : (item_is_sync && !SecDbItemIsTombstone(item));
2578 ok = SecDbItemDelete(item, dbt, makeTombstone, error);
2579 if (ok) {
2580 q->q_changed = true;
2581 if (item_is_sync)
2582 q->q_sync_changed = true;
2583 }
2584 });
2585 if (ok && !q->q_changed) {
2586 ok = SecError(errSecItemNotFound, error, CFSTR("Delete failed to delete anything"));
2587 }
2588 return ok;
2589 }
2590
2591 /* Return true iff the item in question should not be backed up, nor restored,
2592 but when restoring a backup the original version of the item should be
2593 added back to the keychain again after the restore completes. */
2594 static bool SecItemIsSystemBound(CFDictionaryRef item, const SecDbClass *class) {
2595 CFStringRef agrp = CFDictionaryGetValue(item, kSecAttrAccessGroup);
2596 if (!isString(agrp))
2597 return false;
2598
2599 if (CFEqual(agrp, CFSTR("lockdown-identities"))) {
2600 secdebug("backup", "found sys_bound item: %@", item);
2601 return true;
2602 }
2603
2604 if (CFEqual(agrp, CFSTR("apple")) && class == &genp_class) {
2605 CFStringRef service = CFDictionaryGetValue(item, kSecAttrService);
2606 CFStringRef account = CFDictionaryGetValue(item, kSecAttrAccount);
2607 if (isString(service) && isString(account) &&
2608 CFEqual(service, CFSTR("com.apple.managedconfiguration")) &&
2609 (CFEqual(account, CFSTR("Public")) ||
2610 CFEqual(account, CFSTR("Private")))) {
2611 secdebug("backup", "found sys_bound item: %@", item);
2612 return true;
2613 }
2614 }
2615 secdebug("backup", "found non sys_bound item: %@", item);
2616 return false;
2617 }
2618
2619 /* Delete all items from the current keychain. If this is not an in
2620 place upgrade we don't delete items in the 'lockdown-identities'
2621 access group, this ensures that an import or restore of a backup
2622 will never overwrite an existing activation record. */
2623 static bool SecServerDeleteAll(SecDbConnectionRef dbt, CFErrorRef *error) {
2624 return kc_transaction(dbt, error, ^{
2625 bool ok = (SecDbExec(dbt, CFSTR("DELETE from genp;"), error) &&
2626 SecDbExec(dbt, CFSTR("DELETE from inet;"), error) &&
2627 SecDbExec(dbt, CFSTR("DELETE from cert;"), error) &&
2628 SecDbExec(dbt, CFSTR("DELETE from keys;"), error));
2629 return ok;
2630 });
2631 }
2632
2633 struct s3dl_export_row_ctx {
2634 struct s3dl_query_ctx qc;
2635 keybag_handle_t dest_keybag;
2636 enum SecItemFilter filter;
2637 SecDbConnectionRef dbt;
2638 };
2639
2640 static void s3dl_export_row(sqlite3_stmt *stmt, void *context) {
2641 struct s3dl_export_row_ctx *c = context;
2642 Query *q = c->qc.q;
2643 keyclass_t keyclass = 0;
2644 CFErrorRef localError = NULL;
2645
2646 sqlite_int64 rowid = sqlite3_column_int64(stmt, 0);
2647 CFMutableDictionaryRef item = s3dl_item_from_col(stmt, q, 1, c->qc.accessGroups, &keyclass, &localError);
2648
2649 if (item) {
2650 /* Only export sysbound items is do_sys_bound is true, only export non sysbound items otherwise. */
2651 bool do_sys_bound = c->filter == kSecSysBoundItemFilter;
2652 if (c->filter == kSecNoItemFilter ||
2653 SecItemIsSystemBound(item, q->q_class) == do_sys_bound) {
2654 /* Re-encode the item. */
2655 secdebug("item", "export rowid %llu item: %@", rowid, item);
2656 /* The code below could be moved into handle_row. */
2657 CFDataRef pref = _SecItemMakePersistentRef(q->q_class->name, rowid);
2658 if (pref) {
2659 if (c->dest_keybag != KEYBAG_NONE) {
2660 /* Encode and encrypt the item to the specified keybag. */
2661 CFDataRef plain = kc_plist_copy_der(item, &q->q_error);
2662 CFDictionaryRemoveAllValues(item);
2663 if (plain) {
2664 CFDataRef edata = NULL;
2665 if (ks_encrypt_data(c->dest_keybag, keyclass, plain, &edata, &q->q_error)) {
2666 CFDictionarySetValue(item, kSecValueData, edata);
2667 CFReleaseSafe(edata);
2668 } else {
2669 seccritical("ks_encrypt_data %@,rowid=%" PRId64 ": failed: %@", q->q_class->name, rowid, q->q_error);
2670 CFReleaseNull(q->q_error);
2671 }
2672 CFRelease(plain);
2673 }
2674 }
2675 if (CFDictionaryGetCount(item)) {
2676 CFDictionarySetValue(item, kSecValuePersistentRef, pref);
2677 CFArrayAppendValue((CFMutableArrayRef)c->qc.result, item);
2678 c->qc.found++;
2679 }
2680 CFReleaseSafe(pref);
2681 }
2682 }
2683 CFRelease(item);
2684 } else {
2685 /* This happens a lot when trying to migrate keychain before first unlock, so only a notice */
2686 /* If the error is "corrupted item" then we just ignore it, otherwise we save it in the query */
2687 secnotice("item","Could not export item for rowid %llu: %@", rowid, localError);
2688 if(SecErrorGetOSStatus(localError)==errSecDecode) {
2689 CFReleaseNull(localError);
2690 } else {
2691 CFReleaseSafe(q->q_error);
2692 q->q_error=localError;
2693 }
2694 }
2695 }
2696
2697 static CF_RETURNS_RETAINED CFDictionaryRef SecServerExportKeychainPlist(SecDbConnectionRef dbt,
2698 keybag_handle_t src_keybag, keybag_handle_t dest_keybag,
2699 enum SecItemFilter filter, CFErrorRef *error) {
2700 CFMutableDictionaryRef keychain;
2701 keychain = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
2702 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2703 if (!keychain) {
2704 if (error && !*error)
2705 SecError(errSecAllocate, error, CFSTR("Can't create keychain dictionary"));
2706 goto errOut;
2707 }
2708 unsigned class_ix;
2709 Query q = { .q_keybag = src_keybag };
2710 q.q_return_type = kSecReturnDataMask | kSecReturnAttributesMask | \
2711 kSecReturnPersistentRefMask;
2712 q.q_limit = kSecMatchUnlimited;
2713
2714 /* Get rid of this duplicate. */
2715 const SecDbClass *SecDbClasses[] = {
2716 &genp_class,
2717 &inet_class,
2718 &cert_class,
2719 &keys_class
2720 };
2721
2722 for (class_ix = 0; class_ix < array_size(SecDbClasses);
2723 ++class_ix) {
2724 q.q_class = SecDbClasses[class_ix];
2725 struct s3dl_export_row_ctx ctx = {
2726 .qc = { .q = &q, },
2727 .dest_keybag = dest_keybag, .filter = filter,
2728 .dbt = dbt,
2729 };
2730
2731 secnotice("item", "exporting class '%@'", q.q_class->name);
2732
2733 CFErrorRef localError = NULL;
2734 if (s3dl_query(dbt, s3dl_export_row, &ctx, &localError)) {
2735 if (CFArrayGetCount(ctx.qc.result))
2736 CFDictionaryAddValue(keychain, q.q_class->name, ctx.qc.result);
2737
2738 } else {
2739 OSStatus status = (OSStatus)CFErrorGetCode(localError);
2740 if (status == errSecItemNotFound) {
2741 CFRelease(localError);
2742 } else {
2743 secerror("Export failed: %@", localError);
2744 if (error) {
2745 CFReleaseSafe(*error);
2746 *error = localError;
2747 } else {
2748 CFRelease(localError);
2749 }
2750 CFReleaseNull(keychain);
2751 break;
2752 }
2753 }
2754 CFReleaseNull(ctx.qc.result);
2755 }
2756 errOut:
2757 return keychain;
2758 }
2759
2760 static CF_RETURNS_RETAINED CFDataRef SecServerExportKeychain(SecDbConnectionRef dbt,
2761 keybag_handle_t src_keybag, keybag_handle_t dest_keybag, CFErrorRef *error) {
2762 CFDataRef data_out = NULL;
2763 /* Export everything except the items for which SecItemIsSystemBound()
2764 returns true. */
2765 CFDictionaryRef keychain = SecServerExportKeychainPlist(dbt,
2766 src_keybag, dest_keybag, kSecBackupableItemFilter,
2767 error);
2768 if (keychain) {
2769 data_out = CFPropertyListCreateData(kCFAllocatorDefault, keychain,
2770 kCFPropertyListBinaryFormat_v1_0,
2771 0, error);
2772 CFRelease(keychain);
2773 }
2774
2775 return data_out;
2776 }
2777
2778 struct SecServerImportClassState {
2779 SecDbConnectionRef dbt;
2780 CFErrorRef error;
2781 keybag_handle_t src_keybag;
2782 keybag_handle_t dest_keybag;
2783 enum SecItemFilter filter;
2784 };
2785
2786 struct SecServerImportItemState {
2787 const SecDbClass *class;
2788 struct SecServerImportClassState *s;
2789 };
2790
2791 /* Infer accessibility and access group for pre-v2 (iOS4.x and earlier) items
2792 being imported from a backup. */
2793 static bool SecDbItemImportMigrate(SecDbItemRef item, CFErrorRef *error) {
2794 bool ok = true;
2795 CFStringRef agrp = SecDbItemGetCachedValueWithName(item, kSecAttrAccessGroup);
2796 CFStringRef accessible = SecDbItemGetCachedValueWithName(item, kSecAttrAccessible);
2797
2798 if (!isString(agrp) || !isString(accessible))
2799 return ok;
2800 if (SecDbItemGetClass(item) == &genp_class && CFEqual(accessible, kSecAttrAccessibleAlways)) {
2801 CFStringRef svce = SecDbItemGetCachedValueWithName(item, kSecAttrService);
2802 if (!isString(svce)) return ok;
2803 if (CFEqual(agrp, CFSTR("apple"))) {
2804 if (CFEqual(svce, CFSTR("AirPort"))) {
2805 ok = SecDbItemSetValueWithName(item, kSecAttrAccessible, kSecAttrAccessibleAfterFirstUnlock, error);
2806 } else if (CFEqual(svce, CFSTR("com.apple.airplay.password"))) {
2807 ok = SecDbItemSetValueWithName(item, kSecAttrAccessible, kSecAttrAccessibleWhenUnlocked, error);
2808 } else if (CFEqual(svce, CFSTR("YouTube"))) {
2809 ok = (SecDbItemSetValueWithName(item, kSecAttrAccessible, kSecAttrAccessibleWhenUnlocked, error) &&
2810 SecDbItemSetValueWithName(item, kSecAttrAccessGroup, CFSTR("com.apple.youtube.credentials"), error));
2811 } else {
2812 CFStringRef desc = SecDbItemGetCachedValueWithName(item, kSecAttrDescription);
2813 if (!isString(desc)) return ok;
2814 if (CFEqual(desc, CFSTR("IPSec Shared Secret")) || CFEqual(desc, CFSTR("PPP Password"))) {
2815 ok = SecDbItemSetValueWithName(item, kSecAttrAccessible, kSecAttrAccessibleAfterFirstUnlock, error);
2816 }
2817 }
2818 }
2819 } else if (SecDbItemGetClass(item) == &inet_class && CFEqual(accessible, kSecAttrAccessibleAlways)) {
2820 if (CFEqual(agrp, CFSTR("PrintKitAccessGroup"))) {
2821 ok = SecDbItemSetValueWithName(item, kSecAttrAccessible, kSecAttrAccessibleWhenUnlocked, error);
2822 } else if (CFEqual(agrp, CFSTR("apple"))) {
2823 CFTypeRef ptcl = SecDbItemGetCachedValueWithName(item, kSecAttrProtocol);
2824 bool is_proxy = false;
2825 if (isNumber(ptcl)) {
2826 SInt32 iptcl;
2827 CFNumberGetValue(ptcl, kCFNumberSInt32Type, &iptcl);
2828 is_proxy = (iptcl == FOUR_CHAR_CODE('htpx') ||
2829 iptcl == FOUR_CHAR_CODE('htsx') ||
2830 iptcl == FOUR_CHAR_CODE('ftpx') ||
2831 iptcl == FOUR_CHAR_CODE('rtsx') ||
2832 iptcl == FOUR_CHAR_CODE('xpth') ||
2833 iptcl == FOUR_CHAR_CODE('xsth') ||
2834 iptcl == FOUR_CHAR_CODE('xptf') ||
2835 iptcl == FOUR_CHAR_CODE('xstr'));
2836 } else if (isString(ptcl)) {
2837 is_proxy = (CFEqual(ptcl, kSecAttrProtocolHTTPProxy) ||
2838 CFEqual(ptcl, kSecAttrProtocolHTTPSProxy) ||
2839 CFEqual(ptcl, kSecAttrProtocolRTSPProxy) ||
2840 CFEqual(ptcl, kSecAttrProtocolFTPProxy));
2841 }
2842 if (is_proxy)
2843 ok = SecDbItemSetValueWithName(item, kSecAttrAccessible, kSecAttrAccessibleWhenUnlocked, error);
2844 }
2845 }
2846 return ok;
2847 }
2848
2849 bool SecDbItemDecrypt(SecDbItemRef item, CFDataRef edata, CFErrorRef *error) {
2850 bool ok = true;
2851 CFDataRef pdata = NULL;
2852 keyclass_t keyclass;
2853 uint32_t version;
2854 ok = ks_decrypt_data(SecDbItemGetKeybag(item), &keyclass, edata, &pdata, &version, error);
2855 if (!ok)
2856 return ok;
2857
2858 if (version < 2) {
2859 /* Old V4 style keychain backup being imported. */
2860 ok = SecDbItemSetValueWithName(item, CFSTR("v_Data"), pdata, error) &&
2861 SecDbItemImportMigrate(item, error);
2862 } else {
2863 CFDictionaryRef dict;
2864 if (version < 3) {
2865 dict = s3dl_item_v2_decode(pdata, error);
2866 } else {
2867 dict = s3dl_item_v3_decode(pdata, error);
2868 }
2869 ok = dict && SecDbItemSetValues(item, dict, error);
2870 CFReleaseSafe(dict);
2871 }
2872
2873 CFReleaseSafe(pdata);
2874
2875 keyclass_t my_keyclass = SecDbItemGetKeyclass(item, NULL);
2876 if (!my_keyclass) {
2877 ok = ok && SecDbItemSetKeyclass(item, keyclass, error);
2878 } else {
2879 /* Make sure the keyclass in the dictionary matched what we got
2880 back from decoding the data blob. */
2881 if (my_keyclass != keyclass) {
2882 ok = SecError(errSecDecode, error, CFSTR("keyclass attribute %d doesn't match keyclass in blob %d"), my_keyclass, keyclass);
2883 }
2884 }
2885
2886 return ok;
2887 }
2888
2889 /* Automagically make a item syncable, based on various attributes. */
2890 static bool SecDbItemInferSyncable(SecDbItemRef item, CFErrorRef *error)
2891 {
2892 CFStringRef agrp = SecDbItemGetCachedValueWithName(item, kSecAttrAccessGroup);
2893
2894 if (!isString(agrp))
2895 return true;
2896
2897 if (CFEqual(agrp, CFSTR("com.apple.cfnetwork")) && SecDbItemGetClass(item) == &inet_class) {
2898 CFTypeRef srvr = SecDbItemGetCachedValueWithName(item, kSecAttrServer);
2899 CFTypeRef ptcl = SecDbItemGetCachedValueWithName(item, kSecAttrProtocol);
2900 CFTypeRef atyp = SecDbItemGetCachedValueWithName(item, kSecAttrAuthenticationType);
2901
2902 if (isString(srvr) && isString(ptcl) && isString(atyp)) {
2903 /* This looks like a Mobile Safari Password, make syncable */
2904 secnotice("item", "Make this item syncable: %@", item);
2905 return SecDbItemSetSyncable(item, true, error);
2906 }
2907 }
2908
2909 return true;
2910 }
2911
2912 /* This create a SecDbItem from the item dictionnary that are exported for backups.
2913 Item are stored in the backup as a dictionary containing two keys:
2914 - v_Data: the encrypted data blob
2915 - v_PersistentRef: a persistent Ref.
2916 src_keybag is normally the backup keybag.
2917 dst_keybag is normally the device keybag.
2918 */
2919 static SecDbItemRef SecDbItemCreateWithBackupDictionary(CFAllocatorRef allocator, const SecDbClass *dbclass, CFDictionaryRef dict, keybag_handle_t src_keybag, keybag_handle_t dst_keybag, CFErrorRef *error)
2920 {
2921 CFDataRef edata = CFDictionaryGetValue(dict, CFSTR("v_Data"));
2922 SecDbItemRef item = NULL;
2923
2924 if (edata) {
2925 item = SecDbItemCreateWithEncryptedData(kCFAllocatorDefault, dbclass, edata, src_keybag, error);
2926 if (item)
2927 if (!SecDbItemSetKeybag(item, dst_keybag, error))
2928 CFReleaseNull(item);
2929 } else {
2930 SecError(errSecDecode, error, CFSTR("No v_Data in backup dictionary %@"), dict);
2931 }
2932
2933 return item;
2934 }
2935
2936 static bool SecDbItemExtractRowIdFromBackupDictionary(SecDbItemRef item, CFDictionaryRef dict, CFErrorRef *error) {
2937 CFDataRef ref = CFDictionaryGetValue(dict, CFSTR("v_PersistentRef"));
2938 if (!ref)
2939 return SecError(errSecDecode, error, CFSTR("No v_PersistentRef in backup dictionary %@"), dict);
2940
2941 CFStringRef className;
2942 sqlite3_int64 rowid;
2943 if (!_SecItemParsePersistentRef(ref, &className, &rowid))
2944 return SecError(errSecDecode, error, CFSTR("v_PersistentRef %@ failed to decode"), ref);
2945
2946 if (!CFEqual(SecDbItemGetClass(item)->name, className))
2947 return SecError(errSecDecode, error, CFSTR("v_PersistentRef has unexpected class %@"), className);
2948
2949 return SecDbItemSetRowId(item, rowid, error);
2950 }
2951
2952 static void SecServerImportItem(const void *value, void *context) {
2953 struct SecServerImportItemState *state =
2954 (struct SecServerImportItemState *)context;
2955 if (state->s->error)
2956 return;
2957 if (!isDictionary(value)) {
2958 SecError(errSecParam, &state->s->error, CFSTR("value %@ is not a dictionary"), value);
2959 return;
2960 }
2961
2962 CFDictionaryRef dict = (CFDictionaryRef)value;
2963
2964 secdebug("item", "Import Item : %@", dict);
2965
2966 /* We don't filter non sys_bound items during import since we know we
2967 will never have any in this case, we use the kSecSysBoundItemFilter
2968 to indicate that we don't preserve rowid's during import instead. */
2969 if (state->s->filter == kSecBackupableItemFilter &&
2970 SecItemIsSystemBound(dict, state->class))
2971 return;
2972
2973 SecDbItemRef item;
2974
2975 /* This is sligthly confusing:
2976 - During upgrade all items are exported with KEYBAG_NONE.
2977 - During restore from backup, existing sys_bound items are exported with KEYBAG_NONE, and are exported as dictionary of attributes.
2978 - Item in the actual backup are export with a real keybag, and are exported as encrypted v_Data and v_PersistentRef
2979 */
2980 if (state->s->src_keybag == KEYBAG_NONE) {
2981 item = SecDbItemCreateWithAttributes(kCFAllocatorDefault, state->class, dict, state->s->dest_keybag, &state->s->error);
2982 } else {
2983 item = SecDbItemCreateWithBackupDictionary(kCFAllocatorDefault, state->class, dict, state->s->src_keybag, state->s->dest_keybag, &state->s->error);
2984 }
2985
2986 if (item) {
2987 if(state->s->filter != kSecSysBoundItemFilter) {
2988 SecDbItemExtractRowIdFromBackupDictionary(item, dict, &state->s->error);
2989 }
2990 SecDbItemInferSyncable(item, &state->s->error);
2991 SecDbItemInsert(item, state->s->dbt, &state->s->error);
2992 }
2993
2994 /* Reset error if we had one, since we just skip the current item
2995 and continue importing what we can. */
2996 if (state->s->error) {
2997 secwarning("Failed to import an item (%@) of class '%@': %@ - ignoring error.",
2998 item, state->class->name, state->s->error);
2999 CFReleaseNull(state->s->error);
3000 }
3001
3002 CFReleaseSafe(item);
3003 }
3004
3005 static void SecServerImportClass(const void *key, const void *value,
3006 void *context) {
3007 struct SecServerImportClassState *state =
3008 (struct SecServerImportClassState *)context;
3009 if (state->error)
3010 return;
3011 if (!isString(key)) {
3012 SecError(errSecParam, &state->error, CFSTR("class name %@ is not a string"), key);
3013 return;
3014 }
3015 const SecDbClass *class = kc_class_with_name(key);
3016 if (!class || class == &identity_class) {
3017 SecError(errSecParam, &state->error, CFSTR("attempt to import an identity"));
3018 return;
3019 }
3020 struct SecServerImportItemState item_state = {
3021 .class = class, .s = state
3022 };
3023 if (isArray(value)) {
3024 CFArrayRef items = (CFArrayRef)value;
3025 CFArrayApplyFunction(items, CFRangeMake(0, CFArrayGetCount(items)),
3026 SecServerImportItem, &item_state);
3027 } else {
3028 CFDictionaryRef item = (CFDictionaryRef)value;
3029 SecServerImportItem(item, &item_state);
3030 }
3031 }
3032
3033 static bool SecServerImportKeychainInPlist(SecDbConnectionRef dbt,
3034 keybag_handle_t src_keybag, keybag_handle_t dest_keybag,
3035 CFDictionaryRef keychain, enum SecItemFilter filter, CFErrorRef *error) {
3036 bool ok = true;
3037
3038 CFDictionaryRef sys_bound = NULL;
3039 if (filter == kSecBackupableItemFilter) {
3040 /* Grab a copy of all the items for which SecItemIsSystemBound()
3041 returns true. */
3042 require(sys_bound = SecServerExportKeychainPlist(dbt, KEYBAG_DEVICE,
3043 KEYBAG_NONE, kSecSysBoundItemFilter,
3044 error), errOut);
3045 }
3046
3047 /* Delete everything in the keychain. */
3048 require(ok = SecServerDeleteAll(dbt, error), errOut);
3049
3050 struct SecServerImportClassState state = {
3051 .dbt = dbt,
3052 .src_keybag = src_keybag,
3053 .dest_keybag = dest_keybag,
3054 .filter = filter,
3055 };
3056 /* Import the provided items, preserving rowids. */
3057 CFDictionaryApplyFunction(keychain, SecServerImportClass, &state);
3058
3059 if (sys_bound) {
3060 state.src_keybag = KEYBAG_NONE;
3061 /* Import the items we preserved with random rowids. */
3062 state.filter = kSecSysBoundItemFilter;
3063 CFDictionaryApplyFunction(sys_bound, SecServerImportClass, &state);
3064 CFRelease(sys_bound);
3065 }
3066 if (state.error) {
3067 if (error) {
3068 CFReleaseSafe(*error);
3069 *error = state.error;
3070 } else {
3071 CFRelease(state.error);
3072 }
3073 ok = false;
3074 }
3075
3076 errOut:
3077 return ok;
3078 }
3079
3080 static bool SecServerImportKeychain(SecDbConnectionRef dbt,
3081 keybag_handle_t src_keybag,
3082 keybag_handle_t dest_keybag, CFDataRef data, CFErrorRef *error) {
3083 return kc_transaction(dbt, error, ^{
3084 bool ok = false;
3085 CFDictionaryRef keychain;
3086 keychain = CFPropertyListCreateWithData(kCFAllocatorDefault, data,
3087 kCFPropertyListImmutable, NULL,
3088 error);
3089 if (keychain) {
3090 if (isDictionary(keychain)) {
3091 ok = SecServerImportKeychainInPlist(dbt, src_keybag,
3092 dest_keybag, keychain,
3093 kSecBackupableItemFilter,
3094 error);
3095 } else {
3096 ok = SecError(errSecParam, error, CFSTR("import: keychain is not a dictionary"));
3097 }
3098 CFRelease(keychain);
3099 }
3100 return ok;
3101 });
3102 }
3103
3104 static bool ks_open_keybag(CFDataRef keybag, CFDataRef password, keybag_handle_t *handle, CFErrorRef *error) {
3105 #if USE_KEYSTORE
3106 kern_return_t kernResult;
3107 kernResult = aks_load_bag(CFDataGetBytePtr(keybag), (int)CFDataGetLength(keybag), handle);
3108 if (kernResult)
3109 return SecKernError(kernResult, error, CFSTR("aks_load_bag failed: %@"), keybag);
3110
3111 if (password) {
3112 kernResult = aks_unlock_bag(*handle, CFDataGetBytePtr(password), (int)CFDataGetLength(password));
3113 if (kernResult) {
3114 aks_unload_bag(*handle);
3115 return SecKernError(kernResult, error, CFSTR("aks_unlock_bag failed"));
3116 }
3117 }
3118 return true;
3119 #else /* !USE_KEYSTORE */
3120 *handle = KEYBAG_NONE;
3121 return true;
3122 #endif /* USE_KEYSTORE */
3123 }
3124
3125 static bool ks_close_keybag(keybag_handle_t keybag, CFErrorRef *error) {
3126 #if USE_KEYSTORE
3127 IOReturn kernResult = aks_unload_bag(keybag);
3128 if (kernResult) {
3129 return SecKernError(kernResult, error, CFSTR("aks_unload_bag failed"));
3130 }
3131 #endif /* USE_KEYSTORE */
3132 return true;
3133 }
3134
3135 static CF_RETURNS_RETAINED CFDataRef SecServerKeychainBackup(SecDbConnectionRef dbt, CFDataRef keybag,
3136 CFDataRef password, CFErrorRef *error) {
3137 CFDataRef backup = NULL;
3138 keybag_handle_t backup_keybag;
3139 if (ks_open_keybag(keybag, password, &backup_keybag, error)) {
3140 /* Export from system keybag to backup keybag. */
3141 backup = SecServerExportKeychain(dbt, KEYBAG_DEVICE, backup_keybag, error);
3142 if (!ks_close_keybag(backup_keybag, error)) {
3143 CFReleaseNull(backup);
3144 }
3145 }
3146 return backup;
3147 }
3148
3149 static bool SecServerKeychainRestore(SecDbConnectionRef dbt, CFDataRef backup,
3150 CFDataRef keybag, CFDataRef password, CFErrorRef *error) {
3151 keybag_handle_t backup_keybag;
3152 if (!ks_open_keybag(keybag, password, &backup_keybag, error))
3153 return false;
3154
3155 /* Import from backup keybag to system keybag. */
3156 bool ok = SecServerImportKeychain(dbt, backup_keybag, KEYBAG_DEVICE,
3157 backup, error);
3158 ok &= ks_close_keybag(backup_keybag, error);
3159
3160 return ok;
3161 }
3162
3163
3164 // MARK - External SPI support code.
3165
3166 CFStringRef __SecKeychainCopyPath(void) {
3167 CFStringRef kcRelPath = NULL;
3168 if (use_hwaes()) {
3169 kcRelPath = CFSTR("keychain-2.db");
3170 } else {
3171 kcRelPath = CFSTR("keychain-2-debug.db");
3172 }
3173
3174 CFStringRef kcPath = NULL;
3175 CFURLRef kcURL = SecCopyURLForFileInKeychainDirectory(kcRelPath);
3176 if (kcURL) {
3177 kcPath = CFURLCopyFileSystemPath(kcURL, kCFURLPOSIXPathStyle);
3178 CFRelease(kcURL);
3179 }
3180 return kcPath;
3181
3182 }
3183
3184 // MARK; -
3185 // MARK: kc_dbhandle init and reset
3186
3187 static SecDbRef SecKeychainDbCreate(CFStringRef path) {
3188 return SecDbCreate(path, ^bool (SecDbConnectionRef dbconn, bool didCreate, CFErrorRef *localError) {
3189 bool ok;
3190 if (didCreate)
3191 ok = s3dl_dbt_upgrade_from_version(dbconn, 0, localError);
3192 else
3193 ok = s3dl_dbt_upgrade(dbconn, localError);
3194
3195 if (!ok)
3196 secerror("Upgrade %sfailed: %@", didCreate ? "from v0 " : "", localError ? *localError : NULL);
3197
3198 return ok;
3199 });
3200 }
3201
3202 static SecDbRef _kc_dbhandle = NULL;
3203
3204 static void kc_dbhandle_init(void) {
3205 SecDbRef oldHandle = _kc_dbhandle;
3206 _kc_dbhandle = NULL;
3207 CFStringRef dbPath = __SecKeychainCopyPath();
3208 if (dbPath) {
3209 _kc_dbhandle = SecKeychainDbCreate(dbPath);
3210 CFRelease(dbPath);
3211 }
3212 if (oldHandle) {
3213 secerror("replaced %@ with %@", oldHandle, _kc_dbhandle);
3214 CFRelease(oldHandle);
3215 }
3216 }
3217
3218 static dispatch_once_t _kc_dbhandle_once;
3219
3220 static SecDbRef kc_dbhandle(void) {
3221 dispatch_once(&_kc_dbhandle_once, ^{
3222 kc_dbhandle_init();
3223 });
3224 return _kc_dbhandle;
3225 }
3226
3227 /* For whitebox testing only */
3228 void kc_dbhandle_reset(void);
3229 void kc_dbhandle_reset(void)
3230 {
3231 __block bool done = false;
3232 dispatch_once(&_kc_dbhandle_once, ^{
3233 kc_dbhandle_init();
3234 done = true;
3235 });
3236 // TODO: Not thread safe at all! - FOR DEBUGGING ONLY
3237 if (!done)
3238 kc_dbhandle_init();
3239 }
3240
3241 static SecDbConnectionRef kc_aquire_dbt(bool writeAndRead, CFErrorRef *error) {
3242 return SecDbConnectionAquire(kc_dbhandle(), !writeAndRead, error);
3243 }
3244
3245 /* Return a per thread dbt handle for the keychain. If create is true create
3246 the database if it does not yet exist. If it is false, just return an
3247 error if it fails to auto-create. */
3248 static bool kc_with_dbt(bool writeAndRead, CFErrorRef *error, bool (^perform)(SecDbConnectionRef dbt))
3249 {
3250 bool ok = false;
3251 SecDbConnectionRef dbt = kc_aquire_dbt(writeAndRead, error);
3252 if (dbt) {
3253 ok = perform(dbt);
3254 SecDbConnectionRelease(dbt);
3255 }
3256 return ok;
3257 }
3258
3259 static bool
3260 items_matching_issuer_parent(CFArrayRef accessGroups,
3261 CFDataRef issuer, CFArrayRef issuers, int recurse)
3262 {
3263 Query *q;
3264 CFArrayRef results = NULL;
3265 SecDbConnectionRef dbt = NULL;
3266 CFIndex i, count;
3267 bool found = false;
3268
3269 if (CFArrayContainsValue(issuers, CFRangeMake(0, CFArrayGetCount(issuers)), issuer))
3270 return true;
3271
3272 const void *keys[] = { kSecClass, kSecReturnRef, kSecAttrSubject };
3273 const void *vals[] = { kSecClassCertificate, kCFBooleanTrue, issuer };
3274 CFDictionaryRef query = CFDictionaryCreate(kCFAllocatorDefault, keys, vals, array_size(keys), NULL, NULL);
3275
3276 if (!query)
3277 return false;
3278
3279 CFErrorRef localError = NULL;
3280 q = query_create_with_limit(query, kSecMatchUnlimited, &localError);
3281 CFRelease(query);
3282 if (q) {
3283 if ((dbt = SecDbConnectionAquire(kc_dbhandle(), true, &localError))) {
3284 s3dl_copy_matching(dbt, q, (CFTypeRef*)&results, accessGroups, &localError);
3285 SecDbConnectionRelease(dbt);
3286 }
3287 query_destroy(q, &localError);
3288 }
3289 if (localError) {
3290 secerror("items matching issuer parent: %@", localError);
3291 CFReleaseNull(localError);
3292 return false;
3293 }
3294
3295 count = CFArrayGetCount(results);
3296 for (i = 0; (i < count) && !found; i++) {
3297 CFDictionaryRef cert_dict = (CFDictionaryRef)CFArrayGetValueAtIndex(results, i);
3298 CFDataRef cert_issuer = CFDictionaryGetValue(cert_dict, kSecAttrIssuer);
3299 if (CFEqual(cert_issuer, issuer))
3300 continue;
3301 if (recurse-- > 0)
3302 found = items_matching_issuer_parent(accessGroups, cert_issuer, issuers, recurse);
3303 }
3304 CFRelease(results);
3305
3306 return found;
3307 }
3308
3309 static bool match_item(Query *q, CFArrayRef accessGroups, CFDictionaryRef item)
3310 {
3311 if (q->q_match_issuer) {
3312 CFDataRef issuer = CFDictionaryGetValue(item, kSecAttrIssuer);
3313 if (!items_matching_issuer_parent(accessGroups, issuer, q->q_match_issuer, 10 /*max depth*/))
3314 return false;
3315 }
3316
3317 /* Add future match checks here. */
3318
3319 return true;
3320 }
3321
3322 /****************************************************************************
3323 **************** Beginning of Externally Callable Interface ****************
3324 ****************************************************************************/
3325
3326 #if 0
3327 // TODO Use as a safety wrapper
3328 static bool SecErrorWith(CFErrorRef *in_error, bool (^perform)(CFErrorRef *error)) {
3329 CFErrorRef error = in_error ? *in_error : NULL;
3330 bool ok;
3331 if ((ok = perform(&error))) {
3332 assert(error == NULL);
3333 if (error)
3334 secerror("error + success: %@", error);
3335 } else {
3336 assert(error);
3337 OSStatus status = SecErrorGetOSStatus(error);
3338 if (status != errSecItemNotFound) // Occurs in normal operation, so exclude
3339 secerror("error:[%" PRIdOSStatus "] %@", status, error);
3340 if (in_error) {
3341 *in_error = error;
3342 } else {
3343 CFReleaseNull(error);
3344 }
3345 }
3346 return ok;
3347 }
3348 #endif
3349
3350 /* AUDIT[securityd](done):
3351 query (ok) is a caller provided dictionary, only its cf type has been checked.
3352 */
3353 static bool
3354 SecItemServerCopyMatching(CFDictionaryRef query, CFTypeRef *result,
3355 CFArrayRef accessGroups, CFErrorRef *error)
3356 {
3357 CFIndex ag_count;
3358 if (!accessGroups || 0 == (ag_count = CFArrayGetCount(accessGroups))) {
3359 return SecError(errSecMissingEntitlement, error,
3360 CFSTR("client has neither application-identifier nor keychain-access-groups entitlements"));
3361 }
3362
3363 if (CFArrayContainsValue(accessGroups, CFRangeMake(0, ag_count), CFSTR("*"))) {
3364 /* Having the special accessGroup "*" allows access to all accessGroups. */
3365 accessGroups = NULL;
3366 }
3367
3368 bool ok = false;
3369 Query *q = query_create_with_limit(query, 1, error);
3370 if (q) {
3371 CFStringRef agrp = CFDictionaryGetValue(q->q_item, kSecAttrAccessGroup);
3372 if (agrp && accessGroupsAllows(accessGroups, agrp)) {
3373 // TODO: Return an error if agrp is not NULL and accessGroupsAllows() fails above.
3374 const void *val = agrp;
3375 accessGroups = CFArrayCreate(0, &val, 1, &kCFTypeArrayCallBacks);
3376 } else {
3377 CFRetainSafe(accessGroups);
3378 }
3379
3380 /* Sanity check the query. */
3381 if (q->q_use_item_list) {
3382 ok = SecError(errSecUseItemListUnsupported, error, CFSTR("use item list unsupported"));
3383 #if defined(MULTIPLE_KEYCHAINS)
3384 } else if (q->q_use_keychain) {
3385 ok = SecError(errSecUseKeychainUnsupported, error, CFSTR("use keychain list unsupported"));
3386 #endif
3387 } else if (q->q_match_issuer && ((q->q_class != &cert_class) &&
3388 (q->q_class != &identity_class))) {
3389 ok = SecError(errSecUnsupportedOperation, error, CFSTR("unsupported match attribute"));
3390 } else if (q->q_return_type != 0 && result == NULL) {
3391 ok = SecError(errSecReturnMissingPointer, error, CFSTR("missing pointer"));
3392 } else if (!q->q_error) {
3393 ok = kc_with_dbt(false, error, ^(SecDbConnectionRef dbt) {
3394 return s3dl_copy_matching(dbt, q, result, accessGroups, error);
3395 });
3396 }
3397
3398 CFReleaseSafe(accessGroups);
3399 if (!query_destroy(q, error))
3400 ok = false;
3401 }
3402
3403 return ok;
3404 }
3405
3406 bool
3407 _SecItemCopyMatching(CFDictionaryRef query, CFArrayRef accessGroups, CFTypeRef *result, CFErrorRef *error) {
3408 return SecItemServerCopyMatching(query, result, accessGroups, error);
3409 }
3410
3411 /* AUDIT[securityd](done):
3412 attributes (ok) is a caller provided dictionary, only its cf type has
3413 been checked.
3414 */
3415 bool
3416 _SecItemAdd(CFDictionaryRef attributes, CFArrayRef accessGroups,
3417 CFTypeRef *result, CFErrorRef *error)
3418 {
3419 bool ok = true;
3420 CFIndex ag_count;
3421 if (!accessGroups || 0 == (ag_count = CFArrayGetCount(accessGroups)))
3422 return SecError(errSecMissingEntitlement, error,
3423 CFSTR("client has neither application-identifier nor keychain-access-groups entitlements"));
3424
3425 Query *q = query_create_with_limit(attributes, 0, error);
3426 if (q) {
3427 /* Access group sanity checking. */
3428 CFStringRef agrp = (CFStringRef)CFDictionaryGetValue(attributes,
3429 kSecAttrAccessGroup);
3430
3431 CFArrayRef ag = accessGroups;
3432 /* Having the special accessGroup "*" allows access to all accessGroups. */
3433 if (CFArrayContainsValue(accessGroups, CFRangeMake(0, ag_count), CFSTR("*")))
3434 accessGroups = NULL;
3435
3436 if (agrp) {
3437 /* The user specified an explicit access group, validate it. */
3438 if (!accessGroupsAllows(accessGroups, agrp))
3439 return SecError(errSecNoAccessForItem, error, CFSTR("NoAccessForItem"));
3440 } else {
3441 agrp = (CFStringRef)CFArrayGetValueAtIndex(ag, 0);
3442
3443 /* We are using an implicit access group, add it as if the user
3444 specified it as an attribute. */
3445 query_add_attribute(kSecAttrAccessGroup, agrp, q);
3446 }
3447
3448 query_ensure_keyclass(q, agrp);
3449
3450 if (q->q_row_id)
3451 ok = SecError(errSecValuePersistentRefUnsupported, error, CFSTR("q_row_id")); // TODO: better error string
3452 #if defined(MULTIPLE_KEYCHAINS)
3453 else if (q->q_use_keychain_list)
3454 ok = SecError(errSecUseKeychainListUnsupported, error, CFSTR("q_use_keychain_list")); // TODO: better error string;
3455 #endif
3456 else if (!q->q_error) {
3457 ok = kc_with_dbt(true, error, ^(SecDbConnectionRef dbt){
3458 return kc_transaction(dbt, error, ^{
3459 query_pre_add(q, true);
3460 return s3dl_query_add(dbt, q, result, error);
3461 });
3462 });
3463 }
3464 ok = query_notify_and_destroy(q, ok, error);
3465 } else {
3466 ok = false;
3467 }
3468 return ok;
3469 }
3470
3471 /* AUDIT[securityd](done):
3472 query (ok) and attributesToUpdate (ok) are a caller provided dictionaries,
3473 only their cf types have been checked.
3474 */
3475 bool
3476 _SecItemUpdate(CFDictionaryRef query, CFDictionaryRef attributesToUpdate,
3477 CFArrayRef accessGroups, CFErrorRef *error)
3478 {
3479 CFIndex ag_count;
3480 if (!accessGroups || 0 == (ag_count = CFArrayGetCount(accessGroups))) {
3481 return SecError(errSecMissingEntitlement, error,
3482 CFSTR("client has neither application-identifier nor keychain-access-groups entitlements"));
3483 }
3484
3485 if (CFArrayContainsValue(accessGroups, CFRangeMake(0, ag_count), CFSTR("*"))) {
3486 /* Having the special accessGroup "*" allows access to all accessGroups. */
3487 accessGroups = NULL;
3488 }
3489
3490 bool ok = true;
3491 Query *q = query_create_with_limit(query, kSecMatchUnlimited, error);
3492 if (!q) {
3493 ok = false;
3494 }
3495 if (ok) {
3496 /* Sanity check the query. */
3497 if (q->q_use_item_list) {
3498 ok = SecError(errSecUseItemListUnsupported, error, CFSTR("use item list not supported"));
3499 } else if (q->q_return_type & kSecReturnDataMask) {
3500 /* Update doesn't return anything so don't ask for it. */
3501 ok = SecError(errSecReturnDataUnsupported, error, CFSTR("return data not supported by update"));
3502 } else if (q->q_return_type & kSecReturnAttributesMask) {
3503 ok = SecError(errSecReturnAttributesUnsupported, error, CFSTR("return attributes not supported by update"));
3504 } else if (q->q_return_type & kSecReturnRefMask) {
3505 ok = SecError(errSecReturnRefUnsupported, error, CFSTR("return ref not supported by update"));
3506 } else if (q->q_return_type & kSecReturnPersistentRefMask) {
3507 ok = SecError(errSecReturnPersitentRefUnsupported, error, CFSTR("return persistent ref not supported by update"));
3508 } else {
3509 /* Access group sanity checking. */
3510 CFStringRef agrp = (CFStringRef)CFDictionaryGetValue(attributesToUpdate,
3511 kSecAttrAccessGroup);
3512 if (agrp) {
3513 /* The user is attempting to modify the access group column,
3514 validate it to make sure the new value is allowable. */
3515 if (!accessGroupsAllows(accessGroups, agrp)) {
3516 ok = SecError(errSecNoAccessForItem, error, CFSTR("accessGroup %@ not in %@"), agrp, accessGroups);
3517 }
3518 }
3519 }
3520 }
3521 if (ok) {
3522 if (!q->q_use_tomb && SOSCCThisDeviceDefinitelyNotActiveInCircle()) {
3523 q->q_use_tomb = kCFBooleanFalse;
3524 }
3525 ok = kc_with_dbt(true, error, ^(SecDbConnectionRef dbt) {
3526 return s3dl_query_update(dbt, q, attributesToUpdate, accessGroups, error);
3527 });
3528 }
3529 if (q) {
3530 ok = query_notify_and_destroy(q, ok, error);
3531 }
3532 return ok;
3533 }
3534
3535
3536 /* AUDIT[securityd](done):
3537 query (ok) is a caller provided dictionary, only its cf type has been checked.
3538 */
3539 bool
3540 _SecItemDelete(CFDictionaryRef query, CFArrayRef accessGroups, CFErrorRef *error)
3541 {
3542 CFIndex ag_count;
3543 if (!accessGroups || 0 == (ag_count = CFArrayGetCount(accessGroups))) {
3544 return SecError(errSecMissingEntitlement, error,
3545 CFSTR("client has neither application-identifier nor keychain-access-groups entitlements"));
3546 }
3547
3548 if (CFArrayContainsValue(accessGroups, CFRangeMake(0, ag_count), CFSTR("*"))) {
3549 /* Having the special accessGroup "*" allows access to all accessGroups. */
3550 accessGroups = NULL;
3551 }
3552
3553 Query *q = query_create_with_limit(query, kSecMatchUnlimited, error);
3554 bool ok;
3555 if (q) {
3556 /* Sanity check the query. */
3557 if (q->q_limit != kSecMatchUnlimited)
3558 ok = SecError(errSecMatchLimitUnsupported, error, CFSTR("match limit not supported by delete"));
3559 else if (query_match_count(q) != 0)
3560 ok = SecError(errSecItemMatchUnsupported, error, CFSTR("match not supported by delete"));
3561 else if (q->q_ref)
3562 ok = SecError(errSecValueRefUnsupported, error, CFSTR("value ref not supported by delete"));
3563 else if (q->q_row_id && query_attr_count(q))
3564 ok = SecError(errSecItemIllegalQuery, error, CFSTR("rowid and other attributes are mutually exclusive"));
3565 else {
3566 if (!q->q_use_tomb && SOSCCThisDeviceDefinitelyNotActiveInCircle()) {
3567 q->q_use_tomb = kCFBooleanFalse;
3568 }
3569 ok = kc_with_dbt(true, error, ^(SecDbConnectionRef dbt) {
3570 return s3dl_query_delete(dbt, q, accessGroups, error);
3571 });
3572 }
3573 ok = query_notify_and_destroy(q, ok, error);
3574 } else {
3575 ok = false;
3576 }
3577 return ok;
3578 }
3579
3580
3581 /* AUDIT[securityd](done):
3582 No caller provided inputs.
3583 */
3584 static bool
3585 SecItemServerDeleteAll(CFErrorRef *error) {
3586 return kc_with_dbt(true, error, ^bool (SecDbConnectionRef dbt) {
3587 return (kc_transaction(dbt, error, ^bool {
3588 return (SecDbExec(dbt, CFSTR("DELETE from genp;"), error) &&
3589 SecDbExec(dbt, CFSTR("DELETE from inet;"), error) &&
3590 SecDbExec(dbt, CFSTR("DELETE from cert;"), error) &&
3591 SecDbExec(dbt, CFSTR("DELETE from keys;"), error));
3592 }) && SecDbExec(dbt, CFSTR("VACUUM;"), error));
3593 });
3594 }
3595
3596 bool
3597 _SecItemDeleteAll(CFErrorRef *error) {
3598 return SecItemServerDeleteAll(error);
3599 }
3600
3601 CFDataRef
3602 _SecServerKeychainBackup(CFDataRef keybag, CFDataRef passcode, CFErrorRef *error) {
3603 CFDataRef backup;
3604 SecDbConnectionRef dbt = SecDbConnectionAquire(kc_dbhandle(), false, error);
3605
3606 if (!dbt)
3607 return NULL;
3608
3609 if (keybag == NULL && passcode == NULL) {
3610 #if USE_KEYSTORE
3611 backup = SecServerExportKeychain(dbt, KEYBAG_DEVICE, backup_keybag_handle, error);
3612 #else /* !USE_KEYSTORE */
3613 SecError(errSecParam, error, CFSTR("Why are you doing this?"));
3614 backup = NULL;
3615 #endif /* USE_KEYSTORE */
3616 } else {
3617 backup = SecServerKeychainBackup(dbt, keybag, passcode, error);
3618 }
3619
3620 SecDbConnectionRelease(dbt);
3621
3622 return backup;
3623 }
3624
3625 bool
3626 _SecServerKeychainRestore(CFDataRef backup, CFDataRef keybag, CFDataRef passcode, CFErrorRef *error) {
3627 if (backup == NULL || keybag == NULL)
3628 return SecError(errSecParam, error, CFSTR("backup or keybag missing"));
3629
3630 __block bool ok = true;
3631 ok &= SecDbPerformWrite(kc_dbhandle(), error, ^(SecDbConnectionRef dbconn) {
3632 ok = SecServerKeychainRestore(dbconn, backup, keybag, passcode, error);
3633 });
3634
3635 if (ok) {
3636 SecKeychainChanged(true);
3637 }
3638
3639 return ok;
3640 }
3641
3642
3643 /*
3644 *
3645 *
3646 * SecItemDataSource
3647 *
3648 *
3649 */
3650 static CFStringRef kSecItemDataSourceErrorDomain = CFSTR("com.apple.secitem.datasource");
3651
3652 enum {
3653 kSecObjectMallocFailed = 1,
3654 kSecAddDuplicateEntry,
3655 kSecObjectNotFoundError,
3656 kSOSAccountCreationFailed,
3657 };
3658
3659 typedef struct SecItemDataSource *SecItemDataSourceRef;
3660
3661 struct SecItemDataSource {
3662 struct SOSDataSource ds;
3663 SecDbRef db;
3664 bool readOnly;
3665 SecDbConnectionRef _dbconn;
3666 unsigned gm_count;
3667 unsigned cm_count;
3668 unsigned co_count;
3669 bool dv_loaded;
3670 struct SOSDigestVector dv;
3671 struct SOSDigestVector toadd;
3672 struct SOSDigestVector todel;
3673 SOSManifestRef manifest;
3674 uint8_t manifest_digest[SOSDigestSize];
3675 bool changed;
3676 bool syncWithPeersWhenDone;
3677 };
3678
3679 static SecDbConnectionRef SecItemDataSourceGetConnection(SecItemDataSourceRef ds, CFErrorRef *error) {
3680 if (!ds->_dbconn) {
3681 ds->_dbconn = SecDbConnectionAquire(ds->db, ds->readOnly, error);
3682 if (ds->_dbconn) {
3683 ds->changed = false;
3684 } else {
3685 secerror("SecDbConnectionAquire failed: %@", error ? *error : NULL);
3686 }
3687 }
3688 return ds->_dbconn;
3689 }
3690
3691 static bool SecItemDataSourceRecordUpdate(SecItemDataSourceRef ds, SecDbItemRef deleted, SecDbItemRef inserted, CFErrorRef *error) {
3692 bool ok = true;
3693 CFDataRef digest;
3694 if (ds->dv_loaded) {
3695 if (inserted) {
3696 ok = digest = SecDbItemGetSHA1(inserted, error);
3697 if (ok) SOSDigestVectorAppend(&ds->toadd, CFDataGetBytePtr(digest));
3698 }
3699 if (ok && deleted) {
3700 ok = digest = SecDbItemGetSHA1(deleted, error);
3701 if (ok) SOSDigestVectorAppend(&ds->todel, CFDataGetBytePtr(digest));
3702 }
3703 if (inserted || deleted) {
3704 CFReleaseNull(ds->manifest);
3705 ds->changed = true;
3706 }
3707
3708 if (!ok) {
3709 ds->dv_loaded = false;
3710 }
3711 }
3712 return ok;
3713 }
3714
3715 static bool SecItemDataSourceRecordAdd(SecItemDataSourceRef ds, SecDbItemRef inserted, CFErrorRef *error) {
3716 return SecItemDataSourceRecordUpdate(ds, NULL, inserted, error);
3717 }
3718
3719 static bool SecDbItemSelectSHA1(SecDbQueryRef query, SecDbConnectionRef dbconn, CFErrorRef *error,
3720 bool (^use_attr_in_where)(const SecDbAttr *attr),
3721 bool (^add_where_sql)(CFMutableStringRef sql, bool *needWhere),
3722 bool (^bind_added_where)(sqlite3_stmt *stmt, int col),
3723 void (^row)(sqlite3_stmt *stmt, bool *stop)) {
3724 __block bool ok = true;
3725 bool (^return_attr)(const SecDbAttr *attr) = ^bool (const SecDbAttr * attr) {
3726 return attr->kind == kSecDbSHA1Attr;
3727 };
3728 CFStringRef sql = SecDbItemCopySelectSQL(query, return_attr, use_attr_in_where, add_where_sql);
3729 if (sql) {
3730 ok &= SecDbPrepare(dbconn, sql, error, ^(sqlite3_stmt *stmt) {
3731 ok = (SecDbItemSelectBind(query, stmt, error, use_attr_in_where, bind_added_where) &&
3732 SecDbStep(dbconn, stmt, error, ^(bool *stop){ row(stmt, stop); }));
3733 });
3734 CFRelease(sql);
3735 } else {
3736 ok = false;
3737 }
3738 return ok;
3739 }
3740
3741 static bool SecItemDataSourceLoadManifest(SecItemDataSourceRef ds, CFErrorRef *error) {
3742 bool ok = true;
3743 SecDbConnectionRef dbconn;
3744 if (!(dbconn = SecItemDataSourceGetConnection(ds, error))) return false;
3745
3746 /* Fetch all syncable items. */
3747 const SecDbClass *synced_classes[] = {
3748 &genp_class,
3749 &inet_class,
3750 &keys_class,
3751 };
3752
3753 ds->dv.count = 0; // Empty the digest vectory before we begin
3754 CFErrorRef localError = NULL;
3755 for (size_t class_ix = 0; class_ix < array_size(synced_classes);
3756 ++class_ix) {
3757 Query *q = query_create(synced_classes[class_ix], NULL, &localError);
3758 if (q) {
3759 q->q_return_type = kSecReturnDataMask | kSecReturnAttributesMask;
3760 q->q_limit = kSecMatchUnlimited;
3761 q->q_keybag = KEYBAG_DEVICE;
3762 query_add_attribute(kSecAttrSynchronizable, kCFBooleanTrue, q);
3763 //query_add_attribute(kSecAttrAccessible, ds->name, q);
3764 // Select everything including tombstones that is synchronizable.
3765 if (!SecDbItemSelectSHA1(q, dbconn, &localError, ^bool(const SecDbAttr *attr) {
3766 return attr->kind == kSecDbSyncAttr;
3767 }, NULL, NULL, ^(sqlite3_stmt *stmt, bool *stop) {
3768 const uint8_t *digest = sqlite3_column_blob(stmt, 0);
3769 size_t digestLen = sqlite3_column_bytes(stmt, 0);
3770 if (digestLen != SOSDigestSize) {
3771 secerror("digest %zu bytes", digestLen);
3772 } else {
3773 SOSDigestVectorAppend(&ds->dv, digest);
3774 }
3775 })) {
3776 secerror("SecDbItemSelect failed: %@", localError);
3777 CFReleaseNull(localError);
3778 }
3779 query_destroy(q, &localError);
3780 if (localError) {
3781 secerror("query_destroy failed: %@", localError);
3782 CFReleaseNull(localError);
3783 }
3784 } else if (localError) {
3785 secerror("query_create failed: %@", localError);
3786 CFReleaseNull(localError);
3787 }
3788 }
3789 SOSDigestVectorSort(&ds->dv);
3790 return ok;
3791 }
3792
3793 static bool SecItemDataSourceEnsureFreshManifest(SecItemDataSourceRef ds, CFErrorRef *error) {
3794 bool ok = true;
3795 if (ds->dv_loaded && (ds->toadd.count || ds->todel.count)) {
3796 CFErrorRef patchError = NULL;
3797 struct SOSDigestVector new_dv = SOSDigestVectorInit;
3798 ok = SOSDigestVectorPatch(&ds->dv, &ds->todel, &ds->toadd, &new_dv, &patchError);
3799 if (!ok) secerror("patch failed %@ manifest: %@ toadd: %@ todel: %@", patchError, &ds->dv, &ds->todel, &ds->toadd);
3800 CFReleaseSafe(patchError);
3801 SOSDigestVectorFree(&ds->dv);
3802 SOSDigestVectorFree(&ds->toadd);
3803 SOSDigestVectorFree(&ds->todel);
3804 ds->dv = new_dv;
3805 }
3806 // If we failed to patch or we haven't loaded yet, force a load from the db.
3807 return (ok && ds->dv_loaded) || (ds->dv_loaded = SecItemDataSourceLoadManifest(ds, error));
3808 }
3809
3810 /* DataSource protocol. */
3811 static bool ds_get_manifest_digest(SOSDataSourceRef data_source, uint8_t *out_digest, CFErrorRef *error) {
3812 struct SecItemDataSource *ds = (struct SecItemDataSource *)data_source;
3813 if (!ds->manifest) {
3814 SOSManifestRef mf = data_source->copy_manifest(data_source, error);
3815 if (mf) {
3816 CFRelease(mf);
3817 } else {
3818 return false;
3819 }
3820 }
3821 memcpy(out_digest, ds->manifest_digest, SOSDigestSize);
3822 ds->gm_count++;
3823 return true;
3824 }
3825
3826 static SOSManifestRef ds_copy_manifest(SOSDataSourceRef data_source, CFErrorRef *error) {
3827 struct SecItemDataSource *ds = (struct SecItemDataSource *)data_source;
3828 ds->cm_count++;
3829 if (ds->manifest) {
3830 CFRetain(ds->manifest);
3831 return ds->manifest;
3832 }
3833
3834 if (!SecItemDataSourceEnsureFreshManifest(ds, error)) return NULL;
3835
3836 ds->manifest = SOSManifestCreateWithBytes((const uint8_t *)ds->dv.digest, ds->dv.count * SOSDigestSize, error);
3837 // TODO move digest
3838 ccdigest(ccsha1_di(), SOSManifestGetSize(ds->manifest), SOSManifestGetBytePtr(ds->manifest), ds->manifest_digest);
3839
3840 return (SOSManifestRef)CFRetain(ds->manifest);
3841 }
3842
3843 static bool ds_foreach_object(SOSDataSourceRef data_source, SOSManifestRef manifest, CFErrorRef *error, bool (^handle_object)(SOSObjectRef object, CFErrorRef *error)) {
3844 struct SecItemDataSource *ds = (struct SecItemDataSource *)data_source;
3845 ds->co_count++;
3846 __block bool result = true;
3847 const SecDbAttr *sha1Attr = SecDbClassAttrWithKind(&genp_class, kSecDbSHA1Attr, error);
3848 if (!sha1Attr) return false;
3849 bool (^return_attr)(const SecDbAttr *attr) = ^bool (const SecDbAttr * attr) {
3850 return attr->kind == kSecDbRowIdAttr || attr->kind == kSecDbEncryptedDataAttr;
3851 };
3852 bool (^use_attr_in_where)(const SecDbAttr *attr) = ^bool (const SecDbAttr * attr) {
3853 return attr->kind == kSecDbSHA1Attr;
3854 };
3855 const SecDbClass *synced_classes[] = {
3856 &genp_class,
3857 &inet_class,
3858 &keys_class,
3859 };
3860 Query *select_queries[array_size(synced_classes)];
3861 CFStringRef select_sql[array_size(synced_classes)];
3862 sqlite3_stmt *select_stmts[array_size(synced_classes)];
3863
3864 __block Query **queries = select_queries;
3865 __block CFStringRef *sqls = select_sql;
3866 __block sqlite3_stmt **stmts = select_stmts;
3867
3868 SecDbConnectionRef dbconn;
3869 result = dbconn = SecItemDataSourceGetConnection(ds, error);
3870
3871 // Setup
3872 for (size_t class_ix = 0; class_ix < array_size(synced_classes); ++class_ix) {
3873 result = (result
3874 && (queries[class_ix] = query_create(synced_classes[class_ix], NULL, error))
3875 && (sqls[class_ix] = SecDbItemCopySelectSQL(queries[class_ix], return_attr, use_attr_in_where, NULL))
3876 && (stmts[class_ix] = SecDbCopyStmt(dbconn, sqls[class_ix], NULL, error)));
3877 }
3878
3879 if (result) SOSManifestForEach(manifest, ^(CFDataRef key) {
3880 __block bool gotItem = false;
3881 for (size_t class_ix = 0; result && !gotItem && class_ix < array_size(synced_classes); ++class_ix) {
3882 CFDictionarySetValue(queries[class_ix]->q_item, sha1Attr->name, key);
3883 result &= (SecDbItemSelectBind(queries[class_ix], stmts[class_ix], error, use_attr_in_where, NULL) && SecDbStep(dbconn, stmts[class_ix], error, ^(bool *stop) {
3884 SecDbItemRef item = SecDbItemCreateWithStatement(kCFAllocatorDefault, queries[class_ix]->q_class, stmts[class_ix], KEYBAG_DEVICE, error, return_attr);
3885 if (item) {
3886 CFErrorRef localError=NULL;
3887 gotItem = true;
3888 // Stop on errors from handle_object, except decode errors
3889 if(!(result=handle_object((SOSObjectRef)item, &localError))){
3890 if (SecErrorGetOSStatus(localError) == errSecDecode) {
3891 const uint8_t *p=CFDataGetBytePtr(key);
3892 secnotice("item", "Found corrupted item, removing from manifest key=%02X%02X%02X%02X, item=%@", p[0],p[1],p[2],p[3], item);
3893 /* Removing from Manifest: */
3894 SOSDigestVectorAppend(&ds->todel, p);
3895 CFReleaseNull(ds->manifest);
3896 } else {
3897 *stop=true;
3898 }
3899 if(error && *error == NULL) {
3900 *error = localError;
3901 localError = NULL;
3902 }
3903 }
3904 CFRelease(item);
3905 CFReleaseSafe(localError);
3906 }
3907 })) && SecDbReset(stmts[class_ix], error);
3908 }
3909 if (!gotItem) {
3910 result = false;
3911 if (error && !*error) {
3912 SecCFCreateErrorWithFormat(kSecObjectNotFoundError, kSecItemDataSourceErrorDomain, NULL, error, 0, CFSTR("key %@ not in database"), key);
3913 }
3914 }
3915 });
3916
3917 // Cleanup
3918 for (size_t class_ix = 0; class_ix < array_size(synced_classes); ++class_ix) {
3919 result &= SecDbReleaseCachedStmt(dbconn, sqls[class_ix], stmts[class_ix], error);
3920 CFReleaseSafe(sqls[class_ix]);
3921 result &= query_destroy(queries[class_ix], error);
3922 }
3923 return result;
3924 }
3925
3926 static void ds_dispose(SOSDataSourceRef data_source) {
3927 struct SecItemDataSource *ds = (struct SecItemDataSource *)data_source;
3928 if (ds->_dbconn)
3929 SecDbConnectionRelease(ds->_dbconn);
3930 if (ds->changed)
3931 SecKeychainChanged(ds->syncWithPeersWhenDone);
3932 CFReleaseSafe(ds->manifest);
3933 SOSDigestVectorFree(&ds->dv);
3934 free(ds);
3935 }
3936
3937 static SOSObjectRef ds_create_with_property_list(SOSDataSourceRef ds, CFDictionaryRef plist, CFErrorRef *error) {
3938 SecDbItemRef item = NULL;
3939 const SecDbClass *class = NULL;
3940 CFTypeRef cname = CFDictionaryGetValue(plist, kSecClass);
3941 if (cname) {
3942 class = kc_class_with_name(cname);
3943 if (class) {
3944 item = SecDbItemCreateWithAttributes(kCFAllocatorDefault, class, plist, KEYBAG_DEVICE, error);
3945 } else {
3946 SecError(errSecNoSuchClass, error, CFSTR("can find class named: %@"), cname);
3947 }
3948 } else {
3949 SecError(errSecItemClassMissing, error, CFSTR("query missing %@ attribute"), kSecClass);
3950 }
3951 return (SOSObjectRef)item;
3952 }
3953
3954 static CFDataRef ds_copy_digest(SOSObjectRef object, CFErrorRef *error) {
3955 SecDbItemRef item = (SecDbItemRef) object;
3956 CFDataRef digest = SecDbItemGetSHA1(item, error);
3957 CFRetainSafe(digest);
3958 return digest;
3959 }
3960
3961 static CFDataRef ds_copy_primary_key(SOSObjectRef object, CFErrorRef *error) {
3962 SecDbItemRef item = (SecDbItemRef) object;
3963 CFDataRef pk = SecDbItemGetPrimaryKey(item, error);
3964 CFRetainSafe(pk);
3965 return pk;
3966 }
3967
3968 static CFDictionaryRef ds_copy_property_list(SOSObjectRef object, CFErrorRef *error) {
3969 SecDbItemRef item = (SecDbItemRef) object;
3970 CFMutableDictionaryRef plist = SecDbItemCopyPListWithMask(item, kSecDbInCryptoDataFlag, error);
3971 if (plist)
3972 CFDictionaryAddValue(plist, kSecClass, SecDbItemGetClass(item)->name);
3973 return plist;
3974 }
3975
3976 // Return the newest object
3977 static SOSObjectRef ds_copy_merged_object(SOSObjectRef object1, SOSObjectRef object2, CFErrorRef *error) {
3978 SecDbItemRef item1 = (SecDbItemRef) object1;
3979 SecDbItemRef item2 = (SecDbItemRef) object2;
3980 SOSObjectRef result = NULL;
3981 CFDateRef m1, m2;
3982 const SecDbAttr *desc = SecDbAttrWithKey(SecDbItemGetClass(item1), kSecAttrModificationDate, error);
3983 m1 = SecDbItemGetValue(item1, desc, error);
3984 if (!m1)
3985 return NULL;
3986 m2 = SecDbItemGetValue(item2, desc, error);
3987 if (!m2)
3988 return NULL;
3989 switch (CFDateCompare(m1, m2, NULL)) {
3990 case kCFCompareGreaterThan:
3991 result = (SOSObjectRef)item1;
3992 break;
3993 case kCFCompareLessThan:
3994 result = (SOSObjectRef)item2;
3995 break;
3996 case kCFCompareEqualTo:
3997 {
3998 // Return the item with the smallest digest.
3999 CFDataRef digest1 = ds_copy_digest(object1, error);
4000 CFDataRef digest2 = ds_copy_digest(object2, error);
4001 if (digest1 && digest2) switch (CFDataCompare(digest1, digest2)) {
4002 case kCFCompareGreaterThan:
4003 case kCFCompareEqualTo:
4004 result = (SOSObjectRef)item2;
4005 break;
4006 case kCFCompareLessThan:
4007 result = (SOSObjectRef)item1;
4008 break;
4009 }
4010 CFReleaseSafe(digest2);
4011 CFReleaseSafe(digest1);
4012 break;
4013 }
4014 }
4015 CFRetainSafe(result);
4016 return result;
4017 }
4018
4019 static SOSMergeResult dsMergeObject(SOSDataSourceRef data_source, SOSObjectRef peersObject, CFErrorRef *error) {
4020 struct SecItemDataSource *ds = (struct SecItemDataSource *)data_source;
4021 SecDbItemRef peersItem = (SecDbItemRef)peersObject;
4022 SecDbConnectionRef dbconn = SecItemDataSourceGetConnection(ds, error);
4023 __block SOSMergeResult mr = kSOSMergeFailure;
4024 __block SecDbItemRef mergedItem = NULL;
4025 __block SecDbItemRef replacedItem = NULL;
4026 if (!peersItem || !dbconn || !SecDbItemSetKeybag(peersItem, KEYBAG_DEVICE, error)) return mr;
4027 if (SecDbItemInsertOrReplace(peersItem, dbconn, error, ^(SecDbItemRef myItem, SecDbItemRef *replace) {
4028 // An item with the same primary key as dbItem already exists in the the database. That item is old_item.
4029 // Let the conflict resolver choose which item to keep.
4030 mergedItem = (SecDbItemRef)ds_copy_merged_object(peersObject, (SOSObjectRef)myItem, error);
4031 if (!mergedItem) return;
4032 if (CFEqual(mergedItem, myItem)) {
4033 // Conflict resolver choose my (local) item
4034 mr = kSOSMergeLocalObject;
4035 } else {
4036 CFRetainSafe(myItem);
4037 replacedItem = myItem;
4038 CFRetainSafe(mergedItem);
4039 *replace = mergedItem;
4040 if (CFEqual(mergedItem, peersItem)) {
4041 // Conflict resolver choose peers item
4042 mr = kSOSMergePeersObject;
4043 } else {
4044 mr = kSOSMergeCreatedObject;
4045 }
4046 }
4047 })) {
4048 if (mr == kSOSMergeFailure) {
4049 mr = kSOSMergePeersObject;
4050 SecItemDataSourceRecordAdd(ds, peersItem, error);
4051 } else if (mr != kSOSMergeLocalObject) {
4052 SecItemDataSourceRecordUpdate(ds, replacedItem, mergedItem, error);
4053 }
4054 }
4055
4056 if (error && *error && mr != kSOSMergeFailure)
4057 CFReleaseNull(*error);
4058
4059 CFReleaseSafe(mergedItem);
4060 CFReleaseSafe(replacedItem);
4061 return mr;
4062 }
4063
4064
4065 /*
4066 Truthy backup format is a dictionary from sha1 => item.
4067 Each item has class, hash and item data.
4068
4069 TODO: sha1 is included as binary blob to avoid parsing key.
4070 */
4071 enum {
4072 kSecBackupIndexHash = 0,
4073 kSecBackupIndexClass,
4074 kSecBackupIndexData,
4075 };
4076
4077 static const void *kSecBackupKeys[] = {
4078 [kSecBackupIndexHash] = CFSTR("hash"),
4079 [kSecBackupIndexClass] = CFSTR("class"),
4080 [kSecBackupIndexData] = CFSTR("data"),
4081 };
4082
4083 #define kSecBackupHash kSecBackupKeys[kSecBackupIndexHash]
4084 #define kSecBackupClass kSecBackupKeys[kSecBackupIndexClass]
4085 #define kSecBackupData kSecBackupKeys[kSecBackupIndexData]
4086
4087 static CFDictionaryRef ds_backup_object(SOSObjectRef object, uint64_t handle, CFErrorRef *error) {
4088 const void *values[array_size(kSecBackupKeys)];
4089 SecDbItemRef item = (SecDbItemRef)object;
4090 CFDictionaryRef backup_item = NULL;
4091
4092 if ((values[kSecBackupIndexHash] = SecDbItemGetSHA1(item, error))) {
4093 if ((values[kSecBackupIndexData] = SecDbItemCopyEncryptedDataToBackup(item, handle, error))) {
4094 values[kSecBackupIndexClass] = SecDbItemGetClass(item)->name;
4095 backup_item = CFDictionaryCreate(kCFAllocatorDefault, kSecBackupKeys, values, array_size(kSecBackupKeys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
4096 CFRelease(values[kSecBackupIndexData]);
4097 }
4098 }
4099
4100 return backup_item;
4101 }
4102
4103 static bool ds_restore_object(SOSDataSourceRef data_source, uint64_t handle, CFDictionaryRef item, CFErrorRef *error) {
4104 struct SecItemDataSource *ds = (struct SecItemDataSource *)data_source;
4105 SecDbConnectionRef dbconn = SecItemDataSourceGetConnection(ds, error);
4106 if (!dbconn) return false;
4107
4108 CFStringRef item_class = CFDictionaryGetValue(item, kSecBackupClass);
4109 CFDataRef data = CFDictionaryGetValue(item, kSecBackupData);
4110 const SecDbClass *dbclass = NULL;
4111
4112 if (!item_class || !data)
4113 return SecError(errSecDecode, error, CFSTR("no class or data in object"));
4114
4115 dbclass = kc_class_with_name(item_class);
4116 if (!dbclass)
4117 return SecError(errSecDecode, error, CFSTR("no such class %@; update kc_class_with_name "), item_class);
4118
4119 __block SecDbItemRef dbitem = SecDbItemCreateWithEncryptedData(kCFAllocatorDefault, dbclass, data, (keybag_handle_t)handle, error);
4120 if (!dbitem)
4121 return false;
4122
4123 __block bool ok = SecDbItemSetKeybag(dbitem, KEYBAG_DEVICE, error);
4124
4125 if (ok) {
4126 __block SecDbItemRef replaced_item = NULL;
4127 ok &= SecDbItemInsertOrReplace(dbitem, dbconn, error, ^(SecDbItemRef old_item, SecDbItemRef *replace) {
4128 // An item with the same primary key as dbItem already exists in the the database. That item is old_item.
4129 // Let the conflict resolver choose which item to keep.
4130 SecDbItemRef chosen_item = (SecDbItemRef)ds_copy_merged_object((SOSObjectRef)dbitem, (SOSObjectRef)old_item, error);
4131 if (chosen_item) {
4132 if (CFEqual(chosen_item, old_item)) {
4133 // We're keeping the exisiting item, so we don't need to change anything.
4134 CFRelease(chosen_item);
4135 CFReleaseNull(dbitem);
4136 } else {
4137 // We choose a different item than what's in the database already. Let's set dbitem to what
4138 // we are replacing the item in the database with, and set replaced_item to the item we are replacing.
4139 CFRelease(dbitem); // Release the item created via SecDbItemCreateWithEncryptedData
4140 // Record what we put in the database
4141 CFRetain(chosen_item); // retain what we are about to return in *replace, since SecDbItemInsertOrReplace() CFReleases it.
4142 *replace = dbitem = chosen_item;
4143 // Record that we are replaced old_item in replaced_item.
4144 CFRetain(old_item);
4145 replaced_item = old_item;
4146 }
4147 } else {
4148 ok = false;
4149 }
4150 })
4151 && SecItemDataSourceRecordUpdate(ds, replaced_item, dbitem, error);
4152 CFReleaseSafe(replaced_item);
4153 }
4154 CFReleaseSafe(dbitem);
4155
4156 return ok;
4157 }
4158
4159
4160 static SOSDataSourceRef SecItemDataSourceCreate(SecDbRef db, bool readOnly, bool syncWithPeersWhenDone, CFErrorRef *error) {
4161 __block SecItemDataSourceRef ds = calloc(1, sizeof(struct SecItemDataSource));
4162 ds->ds.get_manifest_digest = ds_get_manifest_digest;
4163 ds->ds.copy_manifest = ds_copy_manifest;
4164 ds->ds.foreach_object = ds_foreach_object;
4165 ds->ds.release = ds_dispose;
4166 ds->ds.add = dsMergeObject;
4167
4168 ds->ds.createWithPropertyList = ds_create_with_property_list;
4169 ds->ds.copyDigest = ds_copy_digest;
4170 ds->ds.copyPrimaryKey = ds_copy_primary_key;
4171 ds->ds.copyPropertyList = ds_copy_property_list;
4172 ds->ds.copyMergedObject = ds_copy_merged_object;
4173 ds->ds.backupObject = ds_backup_object;
4174 ds->ds.restoreObject = ds_restore_object;
4175
4176 ds->syncWithPeersWhenDone = syncWithPeersWhenDone;
4177 ds->db = (SecDbRef)CFRetain(db);
4178 ds->readOnly = readOnly;
4179
4180 ds->changed = false;
4181 struct SOSDigestVector dv = SOSDigestVectorInit;
4182 ds->dv = dv;
4183
4184 return (SOSDataSourceRef)ds;
4185 }
4186
4187 static CFArrayRef SecItemDataSourceFactoryCopyNames(SOSDataSourceFactoryRef factory)
4188 {
4189 return CFArrayCreateForCFTypes(kCFAllocatorDefault,
4190 kSecAttrAccessibleWhenUnlocked,
4191 //kSecAttrAccessibleAfterFirstUnlock,
4192 //kSecAttrAccessibleAlways,
4193 NULL);
4194 }
4195
4196 struct SecItemDataSourceFactory {
4197 struct SOSDataSourceFactory factory;
4198 SecDbRef db;
4199 };
4200
4201
4202 static SOSDataSourceRef SecItemDataSourceFactoryCopyDataSource(SOSDataSourceFactoryRef factory, CFStringRef dataSourceName, bool readOnly, CFErrorRef *error)
4203 {
4204 struct SecItemDataSourceFactory *f = (struct SecItemDataSourceFactory *)factory;
4205 return SecItemDataSourceCreate(f->db, readOnly, false, error);
4206 }
4207
4208 static void SecItemDataSourceFactoryDispose(SOSDataSourceFactoryRef factory)
4209 {
4210 struct SecItemDataSourceFactory *f = (struct SecItemDataSourceFactory *)factory;
4211 CFReleaseSafe(f->db);
4212 free(f);
4213 }
4214
4215 SOSDataSourceFactoryRef SecItemDataSourceFactoryCreate(SecDbRef db) {
4216 struct SecItemDataSourceFactory *dsf = calloc(1, sizeof(struct SecItemDataSourceFactory));
4217 dsf->factory.copy_names = SecItemDataSourceFactoryCopyNames;
4218 dsf->factory.create_datasource = SecItemDataSourceFactoryCopyDataSource;
4219 dsf->factory.release = SecItemDataSourceFactoryDispose;
4220 CFRetainSafe(db);
4221 dsf->db = db;
4222
4223 return &dsf->factory;
4224 }
4225
4226 SOSDataSourceFactoryRef SecItemDataSourceFactoryCreateDefault(void) {
4227 return SecItemDataSourceFactoryCreate(kc_dbhandle());
4228 }
4229
4230 void SecItemServerAppendItemDescription(CFMutableStringRef desc, CFDictionaryRef object) {
4231 SOSObjectRef item = ds_create_with_property_list(NULL, object, NULL);
4232 if (item) {
4233 CFStringRef itemDesc = CFCopyDescription(item);
4234 if (itemDesc) {
4235 CFStringAppend(desc, itemDesc);
4236 CFReleaseSafe(itemDesc);
4237 }
4238 CFRelease(item);
4239 }
4240 }
4241
4242 /* AUDIT[securityd]:
4243 args_in (ok) is a caller provided, CFDictionaryRef.
4244 */
4245 bool
4246 _SecServerKeychainSyncUpdate(CFDictionaryRef updates, CFErrorRef *error) {
4247 // This never fails, trust us!
4248 CFRetainSafe(updates);
4249 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
4250 SOSCCHandleUpdate(updates);
4251 CFReleaseSafe(updates);
4252 });
4253 return true;
4254 }
4255
4256 //
4257 // Truthiness in the cloud backup/restore support.
4258 //
4259
4260 static CFStringRef SOSCopyItemKey(SOSDataSourceRef ds, SOSObjectRef object, CFErrorRef *error)
4261 {
4262 CFStringRef item_key = NULL;
4263 CFDataRef digest_data = ds->copyDigest(object, error);
4264 if (digest_data) {
4265 item_key = CFDataCopyHexString(digest_data);
4266 CFRelease(digest_data);
4267 }
4268 return item_key;
4269 }
4270
4271 static SOSManifestRef SOSCopyManifestFromBackup(CFDictionaryRef backup)
4272 {
4273 CFMutableDataRef manifest = CFDataCreateMutable(kCFAllocatorDefault, 0);
4274 if (backup) {
4275 CFDictionaryForEach(backup, ^void (const void * key, const void * value) {
4276 if (isDictionary(value)) {
4277 /* converting key back to binary blob is horrible */
4278 CFDataRef sha1 = CFDictionaryGetValue(value, kSecBackupHash);
4279 if (isData(sha1))
4280 CFDataAppend(manifest, sha1);
4281 }
4282 });
4283 }
4284 return (SOSManifestRef)manifest;
4285 }
4286
4287 static CFDictionaryRef
4288 _SecServerCopyTruthInTheCloud(CFDataRef keybag, CFDataRef password,
4289 CFDictionaryRef backup, CFErrorRef *error)
4290 {
4291 SOSManifestRef mold = NULL, mnow = NULL, mdelete = NULL, madd = NULL;
4292 CFErrorRef foreachError = NULL;
4293 CFDictionaryRef backup_out = NULL;
4294 keybag_handle_t bag_handle;
4295 if (!ks_open_keybag(keybag, password, &bag_handle, error))
4296 return NULL;
4297
4298 CFMutableDictionaryRef backup_new = NULL;
4299 SOSDataSourceRef ds = SecItemDataSourceCreate(kc_dbhandle(), true, false, error);
4300 if (ds) {
4301 backup_new = backup ? CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, backup) : CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
4302 mold = SOSCopyManifestFromBackup(backup);
4303 mnow = ds->copy_manifest(ds, error);
4304 SOSManifestDiff(mold, mnow, &mdelete, &madd, error);
4305
4306 // Delete everything from the new_backup that is no longer in the datasource according to the datasources manifest.
4307 SOSManifestForEach(mdelete, ^(CFDataRef digest_data) {
4308 CFStringRef deleted_item_key = CFDataCopyHexString(digest_data);
4309 CFDictionaryRemoveValue(backup_new, deleted_item_key);
4310 CFRelease(deleted_item_key);
4311 });
4312
4313 if(!ds->foreach_object(ds, madd, &foreachError, ^bool(SOSObjectRef object, CFErrorRef *localError) {
4314 bool ok = true;
4315 CFStringRef key = SOSCopyItemKey(ds, object, localError);
4316 CFTypeRef value = ds->backupObject(object, bag_handle, localError);
4317
4318 if (!key || !value) {
4319 ok = false;
4320 } else {
4321 CFDictionarySetValue(backup_new, key, value);
4322 }
4323 CFReleaseSafe(key);
4324 CFReleaseSafe(value);
4325 return ok;
4326 })) {
4327 if(!SecErrorGetOSStatus(foreachError)==errSecDecode) {
4328 if(error && *error==NULL) {
4329 *error = foreachError;
4330 foreachError = NULL;
4331 }
4332 goto out;
4333 }
4334 }
4335
4336 backup_out = backup_new;
4337 backup_new = NULL;
4338 }
4339
4340 out:
4341 if(ds)
4342 ds->release(ds);
4343
4344 CFReleaseSafe(foreachError);
4345 CFReleaseSafe(mold);
4346 CFReleaseSafe(mnow);
4347 CFReleaseSafe(madd);
4348 CFReleaseSafe(mdelete);
4349 CFReleaseSafe(backup_new);
4350
4351 if (!ks_close_keybag(bag_handle, error))
4352 CFReleaseNull(backup_out);
4353
4354 return backup_out;
4355 }
4356
4357 static bool
4358 _SecServerRestoreTruthInTheCloud(CFDataRef keybag, CFDataRef password, CFDictionaryRef backup_in, CFErrorRef *error) {
4359 __block bool ok = true;
4360 keybag_handle_t bag_handle;
4361 if (!ks_open_keybag(keybag, password, &bag_handle, error))
4362 return false;
4363
4364 SOSManifestRef mbackup = SOSCopyManifestFromBackup(backup_in);
4365 if (mbackup) {
4366 SOSDataSourceRef ds = SecItemDataSourceCreate(kc_dbhandle(), false, true, error);
4367 if (ds) {
4368 SOSManifestRef mnow = ds->copy_manifest(ds, error);
4369 SOSManifestRef mdelete = NULL, madd = NULL;
4370 SOSManifestDiff(mnow, mbackup, &mdelete, &madd, error);
4371
4372 // Don't delete everything in datasource not in backup.
4373
4374 // Add items from the backup
4375 SOSManifestForEach(madd, ^void(CFDataRef e) {
4376 CFDictionaryRef item = NULL;
4377 CFStringRef sha1 = CFDataCopyHexString(e);
4378 if (sha1) {
4379 item = CFDictionaryGetValue(backup_in, sha1);
4380 CFRelease(sha1);
4381 }
4382 if (item) {
4383 CFErrorRef localError = NULL;
4384 if (!ds->restoreObject(ds, bag_handle, item, &localError)) {
4385 if (SecErrorGetOSStatus(localError) == errSecDuplicateItem) {
4386 // Log and ignore duplicate item errors during restore
4387 secnotice("titc", "restore %@ not replacing existing item", item);
4388 } else {
4389 // Propagate the first other error upwards (causing the restore to fail).
4390 secerror("restore %@ failed %@", item, localError);
4391 ok = false;
4392 if (error && !*error) {
4393 *error = localError;
4394 localError = NULL;
4395 }
4396 }
4397 CFReleaseSafe(localError);
4398 }
4399 }
4400 });
4401
4402 ds->release(ds);
4403 CFReleaseNull(mdelete);
4404 CFReleaseNull(madd);
4405 CFReleaseNull(mnow);
4406 } else {
4407 ok = false;
4408 }
4409 CFRelease(mbackup);
4410 }
4411
4412 ok &= ks_close_keybag(bag_handle, error);
4413
4414 return ok;
4415 }
4416
4417
4418 CF_RETURNS_RETAINED CFDictionaryRef
4419 _SecServerBackupSyncable(CFDictionaryRef backup, CFDataRef keybag, CFDataRef password, CFErrorRef *error) {
4420 require_action_quiet(isData(keybag), errOut, SecError(errSecParam, error, CFSTR("keybag %@ not a data"), keybag));
4421 require_action_quiet(!backup || isDictionary(backup), errOut, SecError(errSecParam, error, CFSTR("backup %@ not a dictionary"), backup));
4422 require_action_quiet(!password || isData(password), errOut, SecError(errSecParam, error, CFSTR("password %@ not a data"), password));
4423
4424 return _SecServerCopyTruthInTheCloud(keybag, password, backup, error);
4425
4426 errOut:
4427 return NULL;
4428 }
4429
4430 bool
4431 _SecServerRestoreSyncable(CFDictionaryRef backup, CFDataRef keybag, CFDataRef password, CFErrorRef *error) {
4432 bool ok;
4433 require_action_quiet(isData(keybag), errOut, ok = SecError(errSecParam, error, CFSTR("keybag %@ not a data"), keybag));
4434 require_action_quiet(isDictionary(backup), errOut, ok = SecError(errSecParam, error, CFSTR("backup %@ not a dictionary"), backup));
4435 if (password) {
4436 require_action_quiet(isData(password), errOut, ok = SecError(errSecParam, error, CFSTR("password not a data")));
4437 }
4438
4439 ok = _SecServerRestoreTruthInTheCloud(keybag, password, backup, error);
4440
4441 errOut:
4442 return ok;
4443 }
4444
4445
4446