]> git.saurik.com Git - apple/security.git/blob - sec/securityd/SecDbItem.c
Security-55471.tar.gz
[apple/security.git] / sec / securityd / SecDbItem.c
1 /*
2 * Copyright (c) 2012 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 * SecDbItem.c - CoreFoundation-based constants and functions representing
26 * database items (certificates, keys, identities, and passwords.)
27 * Created by Michael Brouwer on 11/15/12.
28 */
29
30 #include <securityd/SecDbItem.h>
31 #include <utilities/SecCFWrappers.h>
32 #include <utilities/der_date.h>
33 #include <utilities/debugging.h>
34
35 #include <Security/SecBasePriv.h>
36 #include <Security/SecInternal.h>
37 #include <corecrypto/ccsha1.h>
38 #include <Security/SecItem.h>
39 #include <Security/SecItemPriv.h>
40
41 // MARK: type converters
42
43 CFStringRef copyString(CFTypeRef obj) {
44 CFTypeID tid = CFGetTypeID(obj);
45 if (tid == CFStringGetTypeID())
46 return CFStringCreateCopy(0, obj);
47 else if (tid == CFDataGetTypeID())
48 return CFStringCreateFromExternalRepresentation(0, obj, kCFStringEncodingUTF8);
49 else
50 return NULL;
51 }
52
53 CFDataRef copyData(CFTypeRef obj) {
54 CFTypeID tid = CFGetTypeID(obj);
55 if (tid == CFDataGetTypeID()) {
56 return CFDataCreateCopy(0, obj);
57 } else if (tid == CFStringGetTypeID()) {
58 return CFStringCreateExternalRepresentation(0, obj, kCFStringEncodingUTF8, 0);
59 } else if (tid == CFNumberGetTypeID()) {
60 SInt32 value;
61 CFNumberGetValue(obj, kCFNumberSInt32Type, &value);
62 return CFDataCreate(0, (const UInt8 *)&value, sizeof(value));
63 } else {
64 return NULL;
65 }
66 }
67
68 CFTypeRef copyBlob(CFTypeRef obj) {
69 CFTypeID tid = CFGetTypeID(obj);
70 if (tid == CFDataGetTypeID()) {
71 return CFDataCreateCopy(0, obj);
72 } else if (tid == CFStringGetTypeID()) {
73 return CFStringCreateCopy(0, obj);
74 } else if (tid == CFNumberGetTypeID()) {
75 CFRetain(obj);
76 return obj;
77 } else {
78 return NULL;
79 }
80 }
81
82 CFDataRef copySHA1(CFTypeRef obj) {
83 CFTypeID tid = CFGetTypeID(obj);
84 if (tid == CFDataGetTypeID() && CFDataGetLength(obj) == CCSHA1_OUTPUT_SIZE) {
85 return CFDataCreateCopy(CFGetAllocator(obj), obj);
86 } else {
87 return NULL;
88 }
89 }
90
91 CFTypeRef copyNumber(CFTypeRef obj) {
92 CFTypeID tid = CFGetTypeID(obj);
93 if (tid == CFNumberGetTypeID()) {
94 CFRetain(obj);
95 return obj;
96 } else if (tid == CFBooleanGetTypeID()) {
97 SInt32 value = CFBooleanGetValue(obj);
98 return CFNumberCreate(0, kCFNumberSInt32Type, &value);
99 } else if (tid == CFStringGetTypeID()) {
100 SInt32 value = CFStringGetIntValue(obj);
101 CFStringRef t = CFStringCreateWithFormat(0, 0, CFSTR("%ld"), (long) value);
102 /* If a string converted to an int isn't equal to the int printed as
103 a string, return a CFStringRef instead. */
104 if (!CFEqual(t, obj)) {
105 CFRelease(t);
106 return CFStringCreateCopy(0, obj);
107 }
108 CFRelease(t);
109 return CFNumberCreate(0, kCFNumberSInt32Type, &value);
110 } else
111 return NULL;
112 }
113
114 CFDateRef copyDate(CFTypeRef obj) {
115 CFTypeID tid = CFGetTypeID(obj);
116 if (tid == CFDateGetTypeID()) {
117 CFRetain(obj);
118 return obj;
119 } else
120 return NULL;
121 }
122
123 // MARK: SecDbColumn accessors, to retrieve values as CF types in SecDbStep.
124
125 static CFDataRef SecDbColumnCopyData(CFAllocatorRef allocator, sqlite3_stmt *stmt, int col, CFErrorRef *error) {
126 return CFDataCreate(allocator, sqlite3_column_blob(stmt, col),
127 sqlite3_column_bytes(stmt, col));
128 //return CFDataCreateWithBytesNoCopy(0, sqlite3_column_blob(stmt, col),
129 // sqlite3_column_bytes(stmt, col),
130 // kCFAllocatorNull);
131 }
132
133 static CFDateRef SecDbColumnCopyDate(CFAllocatorRef allocator, sqlite3_stmt *stmt, int col, CFErrorRef *error) {
134 return CFDateCreate(allocator, sqlite3_column_double(stmt, col));
135 }
136
137 static CFNumberRef SecDbColumnCopyDouble(CFAllocatorRef allocator, sqlite3_stmt *stmt, int col, CFErrorRef *error) {
138 double number = sqlite3_column_double(stmt, col);
139 return CFNumberCreate(allocator, kCFNumberDoubleType, &number);
140 }
141
142 static CFNumberRef SecDbColumnCopyNumber64(CFAllocatorRef allocator, sqlite3_stmt *stmt, int col, CFErrorRef *error) {
143 sqlite_int64 number = sqlite3_column_int64(stmt, col);
144 return CFNumberCreate(allocator, kCFNumberSInt64Type, &number);
145 }
146
147 static CFNumberRef SecDbColumnCopyNumber(CFAllocatorRef allocator, sqlite3_stmt *stmt, int col, CFErrorRef *error) {
148 sqlite_int64 number = sqlite3_column_int64(stmt, col);
149 if (INT32_MIN <= number && number <= INT32_MAX) {
150 int32_t num32 = (int32_t)number;
151 return CFNumberCreate(allocator, kCFNumberSInt32Type, &num32);
152 } else {
153 return CFNumberCreate(allocator, kCFNumberSInt64Type, &number);
154 }
155 }
156
157 static CFStringRef SecDbColumnCopyString(CFAllocatorRef allocator, sqlite3_stmt *stmt, int col, CFErrorRef *error) {
158 const unsigned char *text = sqlite3_column_text(stmt, col);
159 return CFStringCreateWithBytes(allocator, text, strlen((const char *)text), kCFStringEncodingUTF8, false);
160 }
161
162 // MARK: SecDbClass helpers
163
164 const SecDbAttr *SecDbClassAttrWithKind(const SecDbClass *class, SecDbAttrKind kind, CFErrorRef *error) {
165 const SecDbAttr *result = NULL;
166 SecDbForEachAttr(class, desc) {
167 if (desc->kind == kind)
168 result = desc;
169 }
170
171 if (!result)
172 SecError(errSecInternal, error, CFSTR("Can't find attribute of kind %d in class %@"), kind, class->name);
173
174 return result;
175 }
176
177 // MARK: SecDbAttr helpers
178
179 static bool SecDbIsTombstoneDbSelectAttr(const SecDbAttr *attr) {
180 return attr->flags & kSecDbPrimaryKeyFlag || attr->kind == kSecDbTombAttr;
181 }
182
183 #if 0
184 static bool SecDbIsTombstoneDbInsertAttr(const SecDbAttr *attr) {
185 return SecDbIsTombstoneDbSelectAttr(attr) || attr->kind == kSecDbAccessAttr || attr->kind == kSecDbCreationDateAttr || attr->kind == kSecDbModificationDateAttr;
186 }
187 #endif
188
189 static bool SecDbIsTombstoneDbUpdateAttr(const SecDbAttr *attr) {
190 return SecDbIsTombstoneDbSelectAttr(attr) || attr->kind == kSecDbAccessAttr || attr->kind == kSecDbCreationDateAttr || attr->kind == kSecDbRowIdAttr;
191 }
192
193 static bool SecDbAttrBind(const SecDbAttr *attr, sqlite3_stmt *stmt, int col, CFTypeRef value, CFErrorRef *error) {
194 bool ok = true;
195 if (value && !CFEqual(kCFNull, value) && attr->flags & kSecDbSHA1ValueInFlag) {
196 CFDataRef data = copyData(value);
197 if (!data) {
198 SecError(errSecInternal, error, CFSTR("failed to get attribute %@ data"), attr->name);
199 return false;
200 }
201
202 CFMutableDataRef digest = CFDataCreateMutable(kCFAllocatorDefault, CCSHA1_OUTPUT_SIZE);
203 CFDataSetLength(digest, CCSHA1_OUTPUT_SIZE);
204 /* 64 bits cast: worst case is we generate the wrong hash */
205 assert((unsigned long)CFDataGetLength(data)<UINT32_MAX); /* Debug check. Correct as long as CFIndex is long */
206 ccdigest(ccsha1_di(), CFDataGetLength(data), CFDataGetBytePtr(data), CFDataGetMutableBytePtr(digest));
207 CFRelease(data);
208 ok &= SecDbBindObject(stmt, col, digest, error);
209 CFRelease(digest);
210 } else {
211 ok &= SecDbBindObject(stmt, col, value, error);
212 }
213 return ok;
214 }
215
216 // MARK: SecDbItem
217
218 CFTypeRef SecDbItemGetCachedValueWithName(SecDbItemRef item, CFStringRef name) {
219 return CFDictionaryGetValue(item->attributes, name);
220 }
221
222 static CFTypeRef SecDbItemGetCachedValue(SecDbItemRef item, const SecDbAttr *desc) {
223 return CFDictionaryGetValue(item->attributes, desc->name);
224 }
225
226 CFMutableDictionaryRef SecDbItemCopyPListWithMask(SecDbItemRef item, CFOptionFlags mask, CFErrorRef *error) {
227 CFMutableDictionaryRef dict = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
228 SecDbForEachAttrWithMask(item->class, desc, mask) {
229 CFTypeRef value = SecDbItemGetValue(item, desc, error);
230 if (value) {
231 if (!CFEqual(kCFNull, value)) {
232 CFDictionarySetValue(dict, desc->name, value);
233 } else if (desc->flags & kSecDbNotNullFlag) {
234 SecError(errSecInternal, error, CFSTR("attribute %@ has NULL value"), desc->name);
235 secerror("%@", error ? *error : (CFErrorRef)CFSTR("error == NULL"));
236 CFReleaseNull(dict);
237 break;
238 }
239 } else {
240 CFReleaseNull(dict);
241 break;
242 }
243 }
244 return dict;
245 }
246
247 static CFDataRef SecDbItemCopyDERWithMask(SecDbItemRef item, CFOptionFlags mask, CFErrorRef *error) {
248 CFDataRef der = NULL;
249 CFMutableDictionaryRef dict = SecDbItemCopyPListWithMask(item, mask, error);
250 if (dict) {
251 der = kc_plist_copy_der(dict, error);
252 CFRelease(dict);
253 }
254 return der;
255 }
256
257 static CFDataRef SecDbItemCopyDigestWithMask(SecDbItemRef item, CFOptionFlags mask, CFErrorRef *error) {
258 CFDataRef digest = NULL;
259 CFDataRef der = SecDbItemCopyDERWithMask(item, mask, error);
260 if (der) {
261 digest = kc_copy_sha1(CFDataGetLength(der), CFDataGetBytePtr(der), error);
262 CFRelease(der);
263 }
264 return digest;
265 }
266
267 static CFDataRef SecDbItemCopyPrimaryKey(SecDbItemRef item, CFErrorRef *error) {
268 return SecDbItemCopyDigestWithMask(item, kSecDbPrimaryKeyFlag, error);
269 }
270
271 static CFDataRef SecDbItemCopySHA1(SecDbItemRef item, CFErrorRef *error) {
272 return SecDbItemCopyDigestWithMask(item, kSecDbInHashFlag, error);
273 }
274
275 static CFDataRef SecDbItemCopyUnencryptedData(SecDbItemRef item, CFErrorRef *error) {
276 return SecDbItemCopyDERWithMask(item, kSecDbInCryptoDataFlag, error);
277 }
278
279 static keyclass_t SecDbItemParseKeyclass(CFTypeRef value, CFErrorRef *error) {
280 if (!isString(value)) {
281 SecError(errSecParam, error, CFSTR("accessible attribute %@ not a string"), value);
282 } else if (CFEqual(value, kSecAttrAccessibleWhenUnlocked)) {
283 return key_class_ak;
284 } else if (CFEqual(value, kSecAttrAccessibleAfterFirstUnlock)) {
285 return key_class_ck;
286 } else if (CFEqual(value, kSecAttrAccessibleAlways)) {
287 return key_class_dk;
288 } else if (CFEqual(value, kSecAttrAccessibleWhenUnlockedThisDeviceOnly)) {
289 return key_class_aku;
290 } else if (CFEqual(value, kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly)) {
291 return key_class_cku;
292 } else if (CFEqual(value, kSecAttrAccessibleAlwaysThisDeviceOnly)) {
293 return key_class_dku;
294 } else {
295 SecError(errSecParam, error, CFSTR("accessible attribute %@ unknown"), value);
296 }
297 return 0;
298 }
299
300 keyclass_t SecDbItemGetKeyclass(SecDbItemRef item, CFErrorRef *error) {
301 if (!item->keyclass) {
302 const SecDbAttr *desc = SecDbClassAttrWithKind(item->class, kSecDbAccessAttr, error);
303 if (desc) {
304 CFTypeRef value = SecDbItemGetValue(item, desc, error);
305 if (value) {
306 item->keyclass = SecDbItemParseKeyclass(value, error);
307 }
308 }
309 }
310 return item->keyclass;
311 }
312
313 static CFDataRef SecDbItemCopyEncryptedData(SecDbItemRef item, CFErrorRef *error) {
314 CFDataRef edata = NULL;
315 CFDataRef plain = SecDbItemCopyUnencryptedData(item, error);
316 if (plain) {
317 keyclass_t keyclass = SecDbItemGetKeyclass(item, error);
318 if (keyclass) {
319 if (ks_encrypt_data(item->keybag, keyclass, plain, &edata, error)) {
320 item->_edataState = kSecDbItemEncrypting;
321 } else {
322 seccritical("ks_encrypt_data (db): failed: %@", error ? *error : (CFErrorRef)CFSTR(""));
323 }
324 }
325 CFRelease(plain);
326 }
327
328 return edata;
329 }
330
331 CFDataRef SecDbItemCopyEncryptedDataToBackup(SecDbItemRef item, uint64_t handle, CFErrorRef *error) {
332 CFDataRef edata = NULL;
333 keybag_handle_t keybag = (keybag_handle_t)handle;
334 CFDataRef plain = SecDbItemCopyUnencryptedData(item, error);
335 if (plain) {
336 keyclass_t keyclass = SecDbItemGetKeyclass(item, error);
337 if (keyclass) {
338 if (!ks_encrypt_data(keybag, keyclass, plain, &edata, error))
339 seccritical("ks_encrypt_data (db): failed: %@", error ? *error : (CFErrorRef)CFSTR(""));
340 }
341 CFRelease(plain);
342 }
343 return edata;
344 }
345
346 static bool SecDbItemEnsureDecrypted(SecDbItemRef item, CFErrorRef *error) {
347
348 // If we haven't yet decrypted the item, make sure we do so now
349 bool result = true;
350 if (item->_edataState == kSecDbItemEncrypted) {
351 const SecDbAttr *attr = SecDbClassAttrWithKind(item->class, kSecDbEncryptedDataAttr, error);
352 if (attr) {
353 CFDataRef edata = SecDbItemGetCachedValue(item, attr);
354 if (!edata)
355 return SecError(errSecInternal, error, CFSTR("state= encrypted but edata is NULL"));
356 // Decrypt calls set value a bunch of times which clears our edata and changes our state.
357 item->_edataState = kSecDbItemDecrypting;
358 result = SecDbItemDecrypt(item, edata, error);
359 if (result)
360 item->_edataState = kSecDbItemClean;
361 else
362 item->_edataState = kSecDbItemEncrypted;
363 }
364 }
365 return result;
366 }
367
368 // Only called if cached value is not found.
369 static CFTypeRef SecDbItemCopyValue(SecDbItemRef item, const SecDbAttr *attr, CFErrorRef *error) {
370 CFTypeRef value = NULL;
371 switch (attr->kind) {
372 case kSecDbSHA1Attr:
373 value = SecDbItemCopySHA1(item, error);
374 break;
375 case kSecDbEncryptedDataAttr:
376 value = SecDbItemCopyEncryptedData(item, error);
377 break;
378 case kSecDbPrimaryKeyAttr:
379 value = SecDbItemCopyPrimaryKey(item, error);
380 break;
381 case kSecDbAccessAttr:
382 case kSecDbStringAttr:
383 case kSecDbBlobAttr:
384 if (attr->flags & kSecDbNotNullFlag) {
385 if (attr->flags & kSecDbDefault0Flag) {
386 value = CFSTR("0");
387 break;
388 } else if (attr->kind != kSecDbBlobAttr && attr->flags & kSecDbDefaultEmptyFlag) {
389 // blob drops through to data everything else is empty string
390 value = CFSTR("");
391 break;
392 }
393 }
394 //DROPTHROUGH
395 case kSecDbDataAttr:
396 if (attr->flags & kSecDbNotNullFlag && attr->flags & kSecDbDefaultEmptyFlag) {
397 value = CFDataCreate(CFGetAllocator(item), NULL, 0);
398 } else {
399 value = kCFNull;
400 }
401 break;
402 case kSecDbNumberAttr:
403 case kSecDbSyncAttr:
404 case kSecDbTombAttr:
405 if (attr->flags & kSecDbNotNullFlag) {
406 int32_t zero = 0;
407 value = CFNumberCreate(CFGetAllocator(item), kCFNumberSInt32Type, &zero);
408 } else {
409 value = kCFNull;
410 }
411 break;
412 case kSecDbDateAttr:
413 if (attr->flags & kSecDbNotNullFlag && attr->flags & kSecDbDefault0Flag) {
414 value = CFDateCreate(kCFAllocatorDefault, 0.0);
415 } else {
416 value = kCFNull;
417 }
418 break;
419 case kSecDbRowIdAttr:
420 if (attr->flags & kSecDbNotNullFlag) {
421 // No can do, error?
422 }
423 value = kCFNull;
424 break;
425 case kSecDbCreationDateAttr:
426 case kSecDbModificationDateAttr:
427 value = CFDateCreate(CFGetAllocator(item), CFAbsoluteTimeGetCurrent());
428 break;
429 }
430
431 return value;
432 }
433
434 // SecDbItemGetValue will return kCFNull if there is no value for an attribute and this was not
435 // an error. It will return NULL and optionally set *error if there was an error computing an
436 // attribute, or if a required attribute was missing a value and had no known way to compute
437 // it's value.
438 CF_RETURNS_NOT_RETAINED CFTypeRef SecDbItemGetValue(SecDbItemRef item, const SecDbAttr *desc, CFErrorRef *error) {
439 // Propagate chained errors
440 if (!desc)
441 return NULL;
442
443 if (desc->flags & kSecDbInCryptoDataFlag) {
444 if (!SecDbItemEnsureDecrypted(item, error))
445 return NULL;
446 }
447
448 CFTypeRef value = SecDbItemGetCachedValue(item, desc);
449 if (!value) {
450 value = SecDbItemCopyValue(item, desc, error);
451 if (value) {
452 if (!CFEqual(kCFNull, value)) {
453 SecDbItemSetValue(item, desc, value, error);
454 CFRelease(value);
455 value = SecDbItemGetCachedValue(item, desc);
456 }
457 }
458 }
459 return value;
460 }
461
462 static bool SecDbItemGetBoolValue(SecDbItemRef item, const SecDbAttr *desc, bool *bvalue, CFErrorRef *error) {
463 CFTypeRef value = SecDbItemGetValue(item, desc, error);
464 if (!value)
465 return false;
466 char cvalue;
467 *bvalue = (isNumber(value) && CFNumberGetValue(value, kCFNumberCharType, &cvalue) && cvalue == 1);
468 return true;
469 }
470
471 static CFStringRef SecDbItemCopyDescription(CFTypeRef cf) {
472 #if 0 //defined(DEBUG) && DEBUG != 0
473 SecDbItemRef item = (SecDbItemRef)cf;
474 CFMutableStringRef desc = CFStringCreateMutable(CFGetAllocator(cf), 0);
475 CFStringAppendFormat(desc, NULL, CFSTR("<%@"), item->class->name);
476 SecDbForEachAttr(item->class, attr) {
477 CFTypeRef value = SecDbItemGetValue(item, attr, NULL);
478 if (value) {
479 CFStringAppend(desc, CFSTR(","));
480 CFStringAppend(desc, attr->name);
481 CFStringAppend(desc, CFSTR("="));
482 if (CFEqual(CFSTR("data"), attr->name)) {
483 CFStringAppendEncryptedData(desc, value);
484 } else if (CFEqual(CFSTR("v_Data"), attr->name)) {
485 CFStringAppend(desc, CFSTR("<?>"));
486 } else if (isData(value)) {
487 CFStringAppendHexData(desc, value);
488 } else {
489 CFStringAppendFormat(desc, 0, CFSTR("%@"), value);
490 }
491 }
492 }
493 CFStringAppend(desc, CFSTR(">"));
494 #else
495 SecDbItemRef item = (SecDbItemRef)cf;
496 const UInt8 zero4[4] = {};
497 const UInt8 *pk = &zero4[0], *sha1 = &zero4[0];
498 char sync = 0;
499 char tomb = 0;
500 SInt64 rowid = 0;
501 CFStringRef access = NULL;
502 uint8_t mdatbuf[32] = {};
503 uint8_t *mdat = &mdatbuf[0];
504 CFMutableStringRef attrs = CFStringCreateMutable(kCFAllocatorDefault, 0);
505 CFStringRef agrp = NULL;
506
507 SecDbForEachAttr(item->class, attr) {
508 CFTypeRef value;
509 switch (attr->kind) {
510 case kSecDbBlobAttr:
511 case kSecDbDataAttr:
512 case kSecDbStringAttr:
513 case kSecDbNumberAttr:
514 case kSecDbDateAttr:
515 case kSecDbEncryptedDataAttr:
516 if (attr->flags & (kSecDbReturnAttrFlag | kSecDbReturnDataFlag) && (value = SecDbItemGetValue(item, attr, NULL)) && !CFEqual(value, kCFNull)) {
517 if (isString(value) && CFEqual(attr->name, kSecAttrAccessGroup)) {
518 agrp = value;
519 } else {
520 // We don't log these, just record that we saw the attribute.
521 CFStringAppend(attrs, CFSTR(","));
522 CFStringAppend(attrs, attr->name);
523 }
524 }
525 break;
526 case kSecDbCreationDateAttr:
527 // We don't care about this and every object has one.
528 break;
529 case kSecDbModificationDateAttr:
530 value = SecDbItemGetValue(item, attr, NULL);
531 if (isDate(value))
532 mdat = der_encode_generalizedtime_body(CFDateGetAbsoluteTime(value), NULL, mdat, &mdatbuf[31]);
533 break;
534 case kSecDbSHA1Attr:
535 value = SecDbItemGetValue(item, attr, NULL);
536 if (isData(value))
537 sha1 = CFDataGetBytePtr(value);
538 break;
539 case kSecDbRowIdAttr:
540 value = SecDbItemGetValue(item, attr, NULL);
541 if (isNumber(value))
542 CFNumberGetValue(value, kCFNumberSInt64Type, &rowid);
543 break;
544 case kSecDbPrimaryKeyAttr:
545 value = SecDbItemGetValue(item, attr, NULL);
546 if (isData(value))
547 pk = CFDataGetBytePtr(value);
548 break;
549 case kSecDbSyncAttr:
550 value = SecDbItemGetValue(item, attr, NULL);
551 if (isNumber(value))
552 CFNumberGetValue(value, kCFNumberCharType, &sync);
553 break;
554 case kSecDbTombAttr:
555 value = SecDbItemGetValue(item, attr, NULL);
556 if (isNumber(value))
557 CFNumberGetValue(value, kCFNumberCharType, &tomb);
558 break;
559 case kSecDbAccessAttr:
560 value = SecDbItemGetValue(item, attr, NULL);
561 if (isString(value))
562 access = value;
563 break;
564 }
565 }
566
567 CFStringRef desc = CFStringCreateWithFormat(CFGetAllocator(cf), NULL,
568 CFSTR(
569 "%s,"
570 "%@,"
571 "%02X%02X%02X%02X,"
572 "%s,"
573 "%@,"
574 "%@,"
575 "%"PRId64
576 "%@,"
577 "%s,"
578 "%02X%02X%02X%02X"),
579 tomb ? "T" : "O",
580 item->class->name,
581 pk[0], pk[1], pk[2], pk[3],
582 sync ? "S" : "L",
583 access,
584 agrp,
585 rowid,
586 attrs,
587 mdat,
588 sha1[0], sha1[1], sha1[2], sha1[3]);
589 CFReleaseSafe(attrs);
590 #endif
591
592 return desc;
593 }
594
595 static void SecDbItemDestroy(CFTypeRef cf) {
596 SecDbItemRef item = (SecDbItemRef)cf;
597 CFReleaseSafe(item->attributes);
598 }
599
600 static CFHashCode SecDbItemHash(CFTypeRef cf) {
601 SecDbItemRef item = (SecDbItemRef)cf;
602 CFDataRef digest = SecDbItemGetSHA1(item, NULL);
603 CFHashCode code;
604 const UInt8 *p = CFDataGetBytePtr(digest);
605 // Read first 8 bytes of digest in order
606 code = p[0] + ((p[1] + ((p[2] + ((p[3] + ((p[4] + ((p[5] + ((p[6] + (p[7] << 8)) << 8)) << 8)) << 8)) << 8)) << 8)) << 8);
607 return code;
608 }
609
610 static Boolean SecDbItemCompare(CFTypeRef cf1, CFTypeRef cf2) {
611 SecDbItemRef item1 = (SecDbItemRef)cf1;
612 SecDbItemRef item2 = (SecDbItemRef)cf2;
613 CFDataRef digest1 = NULL;
614 CFDataRef digest2 = NULL;
615 if (item1)
616 digest1 = SecDbItemGetSHA1(item1, NULL);
617 if (item2)
618 digest2 = SecDbItemGetSHA1(item2, NULL);
619 Boolean equal = CFEqual(digest1, digest2);
620 return equal;
621 }
622
623 CFGiblisWithHashFor(SecDbItem)
624
625 static SecDbItemRef SecDbItemCreate(CFAllocatorRef allocator, const SecDbClass *class, keybag_handle_t keybag) {
626 SecDbItemRef item = CFTypeAllocate(SecDbItem, struct SecDbItem, allocator);
627 item->class = class;
628 item->attributes = CFDictionaryCreateMutableForCFTypes(allocator);
629 item->keybag = keybag;
630 item->_edataState = kSecDbItemDirty;
631 return item;
632 }
633
634 const SecDbClass *SecDbItemGetClass(SecDbItemRef item) {
635 return item->class;
636 }
637
638 const keybag_handle_t SecDbItemGetKeybag(SecDbItemRef item) {
639 return item->keybag;
640 }
641
642 bool SecDbItemSetKeybag(SecDbItemRef item, keybag_handle_t keybag, CFErrorRef *error) {
643 if (!SecDbItemEnsureDecrypted(item, error))
644 return false;
645 if (item->keybag != keybag) {
646 item->keybag = keybag;
647 if (item->_edataState == kSecDbItemClean) {
648 SecDbItemSetValue(item, SecDbClassAttrWithKind(item->class, kSecDbEncryptedDataAttr, NULL), kCFNull, NULL);
649 }
650 }
651
652 return true;
653 }
654
655 bool SecDbItemSetValue(SecDbItemRef item, const SecDbAttr *desc, CFTypeRef value, CFErrorRef *error) {
656 // Propagate chained errors.
657 if (!desc)
658 return false;
659
660 bool changed = false;
661 CFTypeRef attr = NULL;
662 if (desc->flags & kSecDbInCryptoDataFlag)
663 if (!SecDbItemEnsureDecrypted(item, error))
664 return false;
665
666 switch (desc->kind) {
667 case kSecDbPrimaryKeyAttr:
668 case kSecDbDataAttr:
669 attr = copyData(value);
670 break;
671 case kSecDbEncryptedDataAttr:
672 attr = copyData(value);
673 if (attr) {
674 if (item->_edataState == kSecDbItemEncrypting)
675 item->_edataState = kSecDbItemClean;
676 else
677 item->_edataState = kSecDbItemEncrypted;
678 } else if (!value || CFEqual(kCFNull, value)) {
679 item->_edataState = kSecDbItemDirty;
680 }
681 break;
682 case kSecDbBlobAttr:
683 attr = copyBlob(value);
684 break;
685 case kSecDbDateAttr:
686 case kSecDbCreationDateAttr:
687 case kSecDbModificationDateAttr:
688 attr = copyDate(value);
689 break;
690 case kSecDbNumberAttr:
691 case kSecDbSyncAttr:
692 case kSecDbTombAttr:
693 case kSecDbRowIdAttr:
694 attr = copyNumber(value);
695 break;
696 case kSecDbAccessAttr:
697 case kSecDbStringAttr:
698 attr = copyString(value);
699 break;
700 case kSecDbSHA1Attr:
701 attr = copySHA1(value);
702 break;
703 }
704
705 if (attr) {
706 CFTypeRef ovalue = CFDictionaryGetValue(item->attributes, desc->name);
707 changed = (!ovalue || !CFEqual(ovalue, attr));
708 CFDictionarySetValue(item->attributes, desc->name, attr);
709 CFRelease(attr);
710 } else {
711 if (value && !CFEqual(kCFNull, value)) {
712 SecError(errSecItemInvalidValue, error, CFSTR("attribute %@: value: %@ failed to convert"), desc->name, value);
713 return false;
714 }
715 CFTypeRef ovalue = CFDictionaryGetValue(item->attributes, desc->name);
716 changed = (ovalue && !CFEqual(ovalue, kCFNull));
717 CFDictionaryRemoveValue(item->attributes, desc->name);
718 }
719
720 if (changed) {
721 if (desc->flags & kSecDbInHashFlag)
722 SecDbItemSetValue(item, SecDbClassAttrWithKind(item->class, kSecDbSHA1Attr, NULL), kCFNull, NULL);
723 if (desc->flags & kSecDbPrimaryKeyFlag)
724 SecDbItemSetValue(item, SecDbClassAttrWithKind(item->class, kSecDbPrimaryKeyAttr, NULL), kCFNull, NULL);
725 if (desc->flags & kSecDbInCryptoDataFlag && item->_edataState == kSecDbItemClean)
726 SecDbItemSetValue(item, SecDbClassAttrWithKind(item->class, kSecDbEncryptedDataAttr, NULL), kCFNull, NULL);
727 }
728
729 return true;
730 }
731
732 bool SecDbItemSetValues(SecDbItemRef item, CFDictionaryRef values, CFErrorRef *error) {
733 SecDbForEachAttr(item->class, attr) {
734 CFTypeRef value = CFDictionaryGetValue(values, attr->name);
735 if (value && !SecDbItemSetValue(item, attr, value, error))
736 return false;
737 }
738 return true;
739 }
740
741 bool SecDbItemSetValueWithName(SecDbItemRef item, CFStringRef name, CFTypeRef value, CFErrorRef *error) {
742 SecDbForEachAttr(item->class, attr) {
743 if (CFEqual(attr->name, name)) {
744 return SecDbItemSetValue(item, attr, value, error);
745 }
746 }
747 return false;
748 }
749
750 static bool SecDbItemSetNumber(SecDbItemRef item, const SecDbAttr *desc, int32_t number, CFErrorRef *error) {
751 bool ok = true;
752 CFNumberRef value = CFNumberCreate(CFGetAllocator(item), kCFNumberSInt32Type, &number);
753 if (value) {
754 ok = SecDbItemSetValue(item, desc, value, error);
755 CFRelease(value);
756 } else {
757 ok = SecError(errSecInternal, error, CFSTR("Failed to create CFNumber for %" PRId32), number);
758 }
759 return ok;
760 }
761
762 bool SecDbItemSetKeyclass(SecDbItemRef item, keyclass_t keyclass, CFErrorRef *error) {
763 bool ok = SecDbItemSetValue(item, SecDbClassAttrWithKind(item->class, kSecDbEncryptedDataAttr, error), kCFNull, error);
764 if (ok) {
765 item->_edataState = kSecDbItemDirty;
766 ok = SecDbItemSetNumber(item, SecDbClassAttrWithKind(item->class, kSecDbAccessAttr, error), keyclass, error);
767 }
768 return ok;
769 }
770
771 SecDbItemRef SecDbItemCreateWithAttributes(CFAllocatorRef allocator, const SecDbClass *class, CFDictionaryRef attributes, keybag_handle_t keybag, CFErrorRef *error) {
772 SecDbItemRef item = SecDbItemCreate(kCFAllocatorDefault, class, keybag);
773 if (item && !SecDbItemSetValues(item, attributes, error))
774 CFReleaseNull(item);
775 return item;
776 }
777
778 static CFTypeRef
779 SecDbColumnCopyValueWithAttr(CFAllocatorRef allocator, sqlite3_stmt *stmt, const SecDbAttr *attr, int col, CFErrorRef *error) {
780 CFTypeRef value = NULL;
781 switch (attr->kind) {
782 case kSecDbDateAttr:
783 case kSecDbCreationDateAttr:
784 case kSecDbModificationDateAttr:
785 value = SecDbColumnCopyDate(allocator, stmt, col, error);
786 break;
787 case kSecDbBlobAttr:
788 switch (sqlite3_column_type(stmt, col)) {
789 case SQLITE_INTEGER:
790 value = SecDbColumnCopyNumber(allocator, stmt, col, error);
791 break;
792 case SQLITE_FLOAT:
793 value = SecDbColumnCopyDouble(allocator, stmt, col, error);
794 break;
795 case SQLITE_TEXT:
796 value = SecDbColumnCopyString(allocator, stmt, col, error);
797 break;
798 case SQLITE_BLOB:
799 value = SecDbColumnCopyData(allocator, stmt, col, error);
800 break;
801 case SQLITE_NULL:
802 value = kCFNull;
803 break;
804 }
805 break;
806 case kSecDbAccessAttr:
807 case kSecDbStringAttr:
808 value = SecDbColumnCopyString(allocator, stmt, col, error);
809 break;
810 case kSecDbDataAttr:
811 case kSecDbSHA1Attr:
812 case kSecDbPrimaryKeyAttr:
813 value = SecDbColumnCopyData(allocator, stmt, col, error);
814 break;
815 case kSecDbEncryptedDataAttr:
816 value = SecDbColumnCopyData(allocator, stmt, col, error);
817 break;
818 case kSecDbSyncAttr:
819 case kSecDbTombAttr:
820 case kSecDbNumberAttr:
821 value = SecDbColumnCopyNumber(allocator, stmt, col, error);
822 break;
823 case kSecDbRowIdAttr:
824 value = SecDbColumnCopyNumber64(allocator, stmt, col, error);
825 break;
826 }
827 return value;
828 }
829
830 SecDbItemRef SecDbItemCreateWithStatement(CFAllocatorRef allocator, const SecDbClass *class, sqlite3_stmt *stmt, keybag_handle_t keybag, CFErrorRef *error, bool (^return_attr)(const SecDbAttr *attr)) {
831 SecDbItemRef item = SecDbItemCreate(allocator, class, keybag);
832 int col = 0;
833 SecDbForEachAttr(class, attr) {
834 if (return_attr(attr)) {
835 CFTypeRef value = SecDbColumnCopyValueWithAttr(allocator, stmt, attr, col++, error);
836 if (value) {
837 SecDbItemSetValue(item, attr, value, error);
838 CFRelease(value);
839 }
840 }
841 }
842
843 return item;
844 }
845
846 SecDbItemRef SecDbItemCreateWithEncryptedData(CFAllocatorRef allocator, const SecDbClass *class,
847 CFDataRef edata, keybag_handle_t keybag, CFErrorRef *error) {
848 SecDbItemRef item = SecDbItemCreate(allocator, class, keybag);
849 const SecDbAttr *edata_attr = SecDbClassAttrWithKind(class, kSecDbEncryptedDataAttr, error);
850 if (edata_attr) {
851 if (!SecDbItemSetValue(item, edata_attr, edata, error))
852 CFReleaseNull(item);
853 }
854 return item;
855 }
856
857 #if 0
858 SecDbItemRef SecDbItemCreateWithRowId(CFAllocatorRef allocator, const SecDbClass *class, sqlite_int64 row_id, keybag_handle_t keybag, CFErrorRef *error) {
859 SecDbItemRef item = SecDbItemCreate(allocator, class, keybag);
860 if (!SecDbItemSetRowId(item, row_id, error))
861 CFReleaseNull(item);
862 return item;
863 }
864 #endif
865
866 SecDbItemRef SecDbItemCopyWithUpdates(SecDbItemRef item, CFDictionaryRef updates, CFErrorRef *error) {
867 SecDbItemRef new_item = SecDbItemCreate(CFGetAllocator(item), item->class, item->keybag);
868 SecDbForEachAttr(item->class, attr) {
869 // Copy each attribute, except the mod date attribute (it will be reset to now when needed),
870 // from the updates dict unless it's not there in which case we copy the attribute from the passed in item.
871 if (attr->kind != kSecDbModificationDateAttr && attr->kind != kSecDbEncryptedDataAttr && attr->kind != kSecDbSHA1Attr && attr->kind != kSecDbPrimaryKeyAttr) {
872 CFTypeRef value = NULL;
873 if (CFDictionaryGetValueIfPresent(updates, attr->name, &value)) {
874 if (!value)
875 SecError(errSecParam, error, CFSTR("NULL value in dictionary"));
876 } else {
877 value = SecDbItemGetValue(item, attr, error);
878 }
879 if (!value || !SecDbItemSetValue(new_item, attr, value, error)) {
880 CFReleaseNull(new_item);
881 break;
882 }
883 }
884 }
885 return new_item;
886 }
887
888 // Ensure that the date value of attr of new_item is greater than that of old_item.
889 static bool SecDbItemMakeAttrYounger(SecDbItemRef new_item, SecDbItemRef old_item, const SecDbAttr *attr, CFErrorRef *error) {
890 CFDateRef old_date = SecDbItemGetValue(old_item, attr, error);
891 if (!old_date)
892 return false;
893 CFDateRef new_date = SecDbItemGetValue(new_item, attr, error);
894 if (!new_date)
895 return false;
896 bool ok = true;
897 if (CFDateCompare(new_date, old_date, NULL) != kCFCompareGreaterThan) {
898 CFDateRef adjusted_date = CFDateCreate(kCFAllocatorDefault, CFDateGetAbsoluteTime(old_date) + 0.001);
899 if (adjusted_date) {
900 ok = SecDbItemSetValue(new_item, attr, adjusted_date, error);
901 CFRelease(adjusted_date);
902 }
903 }
904 return ok;
905 }
906
907 // Ensure that the mod date of new_item is greater than that of old_item.
908 static bool SecDbItemMakeYounger(SecDbItemRef new_item, SecDbItemRef old_item, CFErrorRef *error) {
909 const SecDbAttr *attr = SecDbClassAttrWithKind(new_item->class, kSecDbModificationDateAttr, error);
910 return attr && SecDbItemMakeAttrYounger(new_item, old_item, attr, error);
911 }
912
913 SecDbItemRef SecDbItemCopyTombstone(SecDbItemRef item, CFErrorRef *error) {
914 SecDbItemRef new_item = SecDbItemCreate(CFGetAllocator(item), item->class, item->keybag);
915 SecDbForEachAttr(item->class, attr) {
916 if (attr->kind == kSecDbTombAttr) {
917 // Set the tomb attr to true to indicate a tombstone.
918 if (!SecDbItemSetValue(new_item, attr, kCFBooleanTrue, error)) {
919 CFReleaseNull(new_item);
920 break;
921 }
922 } else if (SecDbIsTombstoneDbUpdateAttr(attr)) {
923 // Copy all primary key attributes and creation timestamps from the original item.
924 CFTypeRef value = SecDbItemGetValue(item, attr, error);
925 if (!value || (!CFEqual(kCFNull, value) && !SecDbItemSetValue(new_item, attr, value, error))) {
926 CFReleaseNull(new_item);
927 break;
928 }
929 } else if (attr->kind == kSecDbModificationDateAttr) {
930 if (!SecDbItemMakeAttrYounger(new_item, item, attr, error)) {
931 CFReleaseNull(new_item);
932 break;
933 }
934 }
935 }
936
937 return new_item;
938 }
939
940 // MARK: -
941 // MARK: SQL Construction helpers -- These should become private in the future
942
943 void SecDbAppendElement(CFMutableStringRef sql, CFStringRef value, bool *needComma) {
944 assert(needComma);
945 if (*needComma) {
946 CFStringAppend(sql, CFSTR(","));
947 } else {
948 *needComma = true;
949 }
950 CFStringAppend(sql, value);
951 }
952
953 static void SecDbAppendElementEquals(CFMutableStringRef sql, CFStringRef value, bool *needComma) {
954 SecDbAppendElement(sql, value, needComma);
955 CFStringAppend(sql, CFSTR("=?"));
956 }
957
958 /* Append AND is needWhere is NULL or *needWhere is false. Append WHERE
959 otherwise. Upon return *needWhere will be false. */
960 void
961 SecDbAppendWhereOrAnd(CFMutableStringRef sql, bool *needWhere) {
962 if (!needWhere || !*needWhere) {
963 CFStringAppend(sql, CFSTR(" AND "));
964 } else {
965 CFStringAppend(sql, CFSTR(" WHERE "));
966 *needWhere = false;
967 }
968 }
969
970 void
971 SecDbAppendWhereOrAndEquals(CFMutableStringRef sql, CFStringRef col, bool *needWhere) {
972 SecDbAppendWhereOrAnd(sql, needWhere);
973 CFStringAppend(sql, col);
974 CFStringAppend(sql, CFSTR("=?"));
975 }
976
977 static CFStringRef SecDbItemCopyInsertSQL(SecDbItemRef item, bool(^use_attr)(const SecDbAttr *attr)) {
978 CFMutableStringRef sql = CFStringCreateMutable(CFGetAllocator(item), 0);
979 CFStringAppend(sql, CFSTR("INSERT INTO "));
980 CFStringAppend(sql, item->class->name);
981 CFStringAppend(sql, CFSTR("("));
982 bool needComma = false;
983 CFIndex used_attr = 0;
984 SecDbForEachAttr(item->class, attr) {
985 if (use_attr(attr)) {
986 ++used_attr;
987 SecDbAppendElement(sql, attr->name, &needComma);
988 }
989 }
990 CFStringAppend(sql, CFSTR(")VALUES(?"));
991 while (used_attr-- > 1) {
992 CFStringAppend(sql, CFSTR(",?"));
993 }
994 CFStringAppend(sql, CFSTR(")"));
995 return sql;
996
997 }
998
999 static bool SecDbItemInsertBind(SecDbItemRef item, sqlite3_stmt *stmt, CFErrorRef *error, bool(^use_attr)(const SecDbAttr *attr)) {
1000 bool ok = true;
1001 int param = 0;
1002 SecDbForEachAttr(item->class, attr) {
1003 if (use_attr(attr)) {
1004 CFTypeRef value = SecDbItemGetValue(item, attr, error);
1005 if (!value || !SecDbAttrBind(attr, stmt, ++param, value, error)) {
1006 ok = false;
1007 break;
1008 }
1009 }
1010 }
1011 return ok;
1012 }
1013
1014 sqlite3_int64 SecDbItemGetRowId(SecDbItemRef item, CFErrorRef *error) {
1015 sqlite3_int64 row_id = 0;
1016 const SecDbAttr *attr = SecDbClassAttrWithKind(item->class, kSecDbRowIdAttr, error);
1017 if (attr) {
1018 CFNumberRef number = SecDbItemGetValue(item, attr, error);
1019 if (!isNumber(number)|| !CFNumberGetValue(number, kCFNumberSInt64Type, &row_id))
1020 SecDbError(SQLITE_ERROR, error, CFSTR("rowid %@ is not a 64 bit number"), number);
1021 }
1022
1023 return row_id;
1024 }
1025
1026 static CFNumberRef SecDbItemCreateRowId(SecDbItemRef item, sqlite3_int64 rowid, CFErrorRef *error) {
1027 return CFNumberCreate(CFGetAllocator(item), kCFNumberSInt64Type, &rowid);
1028 }
1029
1030 bool SecDbItemSetRowId(SecDbItemRef item, sqlite3_int64 rowid, CFErrorRef *error) {
1031 bool ok = true;
1032 const SecDbAttr *attr = SecDbClassAttrWithKind(item->class, kSecDbRowIdAttr, error);
1033 if (attr) {
1034 CFNumberRef value = SecDbItemCreateRowId(item, rowid, error);
1035 if (!value)
1036 return false;
1037
1038 ok = SecDbItemSetValue(item, attr, value, error);
1039 CFRelease(value);
1040 }
1041 return ok;
1042 }
1043
1044 static bool SecDbItemClearRowId(SecDbItemRef item, CFErrorRef *error) {
1045 bool ok = true;
1046 const SecDbAttr *attr = SecDbClassAttrWithKind(item->class, kSecDbRowIdAttr, error);
1047 if (attr) {
1048 CFDictionaryRemoveValue(item->attributes, attr->name);
1049 //ok = SecDbItemSetValue(item, attr, kCFNull, error);
1050 }
1051 return ok;
1052 }
1053
1054 static bool SecDbItemSetLastInsertRowId(SecDbItemRef item, SecDbConnectionRef dbconn, CFErrorRef *error) {
1055 sqlite3_int64 rowid = sqlite3_last_insert_rowid(SecDbHandle(dbconn));
1056 return SecDbItemSetRowId(item, rowid, error);
1057 }
1058
1059 bool SecDbItemIsSyncable(SecDbItemRef item) {
1060 bool is_syncable;
1061 if (SecDbItemGetBoolValue(item, SecDbClassAttrWithKind(item->class, kSecDbSyncAttr, NULL), &is_syncable, NULL))
1062 return is_syncable;
1063 return false;
1064 }
1065
1066 bool SecDbItemSetSyncable(SecDbItemRef item, bool sync, CFErrorRef *error)
1067 {
1068 return SecDbItemSetValue(item, SecDbClassAttrWithKind(item->class, kSecDbSyncAttr, error), sync ? kCFBooleanTrue : kCFBooleanFalse, error);
1069 }
1070
1071 bool SecDbItemIsTombstone(SecDbItemRef item) {
1072 bool is_tomb;
1073 if (SecDbItemGetBoolValue(item, SecDbClassAttrWithKind(item->class, kSecDbTombAttr, NULL), &is_tomb, NULL))
1074 return is_tomb;
1075 return false;
1076 }
1077
1078 CFDataRef SecDbItemGetPrimaryKey(SecDbItemRef item, CFErrorRef *error) {
1079 return SecDbItemGetValue(item, SecDbClassAttrWithKind(item->class, kSecDbPrimaryKeyAttr, error), error);
1080 }
1081
1082 CFDataRef SecDbItemGetSHA1(SecDbItemRef item, CFErrorRef *error) {
1083 return SecDbItemGetValue(item, SecDbClassAttrWithKind(item->class, kSecDbSHA1Attr, error), error);
1084 }
1085
1086 static SecDbQueryRef SecDbQueryCreateWithItemPrimaryKey(SecDbItemRef item, CFErrorRef *error) {
1087 CFMutableDictionaryRef dict = SecDbItemCopyPListWithMask(item, kSecDbPrimaryKeyFlag, error);
1088 if (!dict)
1089 return NULL;
1090
1091 SecDbQueryRef query = query_create(item->class, NULL, error);
1092 if (query)
1093 query->q_item = dict;
1094 else
1095 CFRelease(dict);
1096
1097 return query;
1098 }
1099
1100 static bool SecDbItemIsCorrupt(SecDbItemRef item, bool *is_corrupt, CFErrorRef *error) {
1101 CFErrorRef localError = NULL;
1102 bool ok = SecDbItemEnsureDecrypted(item, &localError);
1103 if (localError) {
1104 if (SecErrorGetOSStatus(localError) == errSecDecode) {
1105 // We failed to decrypt the item
1106 secerror("error %@ reading item %@ (corrupted)", localError, item);
1107 __security_simulatecrash(CFSTR("Corrupted item found in keychain"), __sec_exception_code_CorruptItem);
1108 *is_corrupt = true;
1109 ok = true;
1110 } else if (error && *error == NULL) {
1111 *error = localError;
1112 localError = NULL;
1113 }
1114 CFReleaseSafe(localError);
1115 }
1116 return ok;
1117 }
1118
1119 static bool SecDbItemDoInsert(SecDbItemRef item, SecDbConnectionRef dbconn, CFErrorRef *error) {
1120 bool (^use_attr)(const SecDbAttr *attr) = ^bool(const SecDbAttr *attr) {
1121 return (attr->flags & kSecDbInFlag);
1122 };
1123 CFStringRef sql = SecDbItemCopyInsertSQL(item, use_attr);
1124 __block bool ok = sql;
1125 if (sql) {
1126 ok &= SecDbPrepare(dbconn, sql, error, ^(sqlite3_stmt *stmt) {
1127 ok = (SecDbItemInsertBind(item, stmt, error, use_attr) &&
1128 SecDbStep(dbconn, stmt, error, NULL) &&
1129 SecDbItemSetLastInsertRowId(item, dbconn, error));
1130 });
1131 CFRelease(sql);
1132 }
1133 if (ok)
1134 secnotice("item", "inserted %@", item);
1135
1136 return ok;
1137 }
1138
1139 bool SecDbItemInsertOrReplace(SecDbItemRef item, SecDbConnectionRef dbconn, CFErrorRef *error, void(^duplicate)(SecDbItemRef item, SecDbItemRef *replace)) {
1140 __block CFErrorRef localError = NULL;
1141 __block bool ok = SecDbItemDoInsert(item, dbconn, &localError);
1142 if (!ok && localError && CFErrorGetCode(localError) == SQLITE_CONSTRAINT && CFEqual(kSecDbErrorDomain, CFErrorGetDomain(localError))) {
1143 SecDbQueryRef query = SecDbQueryCreateWithItemPrimaryKey(item, error);
1144 if (query) {
1145 SecDbItemSelect(query, dbconn, error, ^bool(const SecDbAttr *attr) {
1146 return attr->flags & kSecDbPrimaryKeyFlag;
1147 }, NULL, NULL, ^(SecDbItemRef old_item, bool *stop) {
1148 bool is_corrupt = false;
1149 ok = SecDbItemIsCorrupt(old_item, &is_corrupt, error);
1150 SecDbItemRef replace = NULL;
1151 if (is_corrupt) {
1152 // If old_item is corrupted pretend it's not there and just replace it.
1153 replace = item;
1154 CFRetain(replace);
1155 } else if (ok && duplicate) {
1156 duplicate(old_item, &replace);
1157 }
1158 if (replace) {
1159 const SecDbAttr *rowid_attr = SecDbClassAttrWithKind(old_item->class, kSecDbRowIdAttr, error);
1160 CFNumberRef oldrowid = SecDbItemGetCachedValue(old_item, rowid_attr);
1161 if (oldrowid) {
1162 ok = SecDbItemSetValue(replace, rowid_attr, oldrowid, &localError);
1163 if (ok && !is_corrupt) {
1164 ok = SecDbItemMakeYounger(replace, old_item, error);
1165 }
1166 ok = ok && SecDbItemDoUpdate(old_item, replace, dbconn, &localError, ^bool (const SecDbAttr *attr) {
1167 return attr->kind == kSecDbRowIdAttr;
1168 });
1169 } else {
1170 ok = SecError(errSecInternal, &localError, CFSTR("no rowid for %@"), old_item);
1171 }
1172 CFRelease(replace);
1173 if (ok)
1174 CFReleaseNull(localError); // Clear the error, since we replaced the item.
1175 }
1176 });
1177 ok &= query_destroy(query, error);
1178 }
1179 if (localError)
1180 ok = false; // We didn't clear the error so we're failing again.
1181 }
1182
1183 if (!ok) {
1184 /*
1185 CFErrorRef e = localError ? localError : error ? *error : NULL;
1186 secerror("INSERT %@ failed: %@%s", item, e, (e && CFErrorGetCode(e) == SQLITE_CONSTRAINT) ?
1187 " and SELECT failed to find tombstone" : "");
1188 */
1189 secerror("INSERT failed: %@", localError);
1190 if (localError) {
1191 if (error && *error == NULL) {
1192 *error = localError;
1193 localError = NULL;
1194 } else {
1195 CFReleaseNull(localError);
1196 }
1197 }
1198 }
1199
1200 return ok;
1201 }
1202
1203 bool SecDbItemInsert(SecDbItemRef item, SecDbConnectionRef dbconn, CFErrorRef *error) {
1204 return SecDbItemInsertOrReplace(item, dbconn, error, ^(SecDbItemRef old_item, SecDbItemRef *replace) {
1205 if (SecDbItemIsTombstone(old_item)) {
1206 CFRetain(item);
1207 *replace = item;
1208 }
1209 });
1210 }
1211
1212 static CFStringRef SecDbItemCopyUpdateSQL(SecDbItemRef old_item, SecDbItemRef new_item, bool(^use_attr_in_where)(const SecDbAttr *attr)) {
1213 CFMutableStringRef sql = CFStringCreateMutable(CFGetAllocator(new_item), 0);
1214 CFStringAppend(sql, CFSTR("UPDATE "));
1215 CFStringAppend(sql, new_item->class->name);
1216 CFStringAppend(sql, CFSTR(" SET "));
1217 bool needComma = false;
1218 CFIndex used_attr = 0;
1219 SecDbForEachAttrWithMask(new_item->class, attr, kSecDbInFlag) {
1220 ++used_attr;
1221 SecDbAppendElementEquals(sql, attr->name, &needComma);
1222 }
1223
1224 bool needWhere = true;
1225 SecDbForEachAttr(old_item->class, attr) {
1226 if (use_attr_in_where(attr)) {
1227 SecDbAppendWhereOrAndEquals(sql, attr->name, &needWhere);
1228 }
1229 }
1230
1231 return sql;
1232 }
1233
1234 static bool SecDbItemUpdateBind(SecDbItemRef old_item, SecDbItemRef new_item, sqlite3_stmt *stmt, CFErrorRef *error, bool(^use_attr_in_where)(const SecDbAttr *attr)) {
1235 bool ok = true;
1236 int param = 0;
1237 SecDbForEachAttrWithMask(new_item->class, attr, kSecDbInFlag) {
1238 CFTypeRef value = SecDbItemGetValue(new_item, attr, error);
1239 ok &= value && SecDbAttrBind(attr, stmt, ++param, value, error);
1240 if (!ok)
1241 break;
1242 }
1243 SecDbForEachAttr(old_item->class, attr) {
1244 if (use_attr_in_where(attr)) {
1245 CFTypeRef value = SecDbItemGetValue(old_item, attr, error);
1246 ok &= value && SecDbAttrBind(attr, stmt, ++param, value, error);
1247 if (!ok)
1248 break;
1249 }
1250 }
1251 return ok;
1252 }
1253
1254 // Primary keys are the same -- do an update
1255 bool SecDbItemDoUpdate(SecDbItemRef old_item, SecDbItemRef new_item, SecDbConnectionRef dbconn, CFErrorRef *error, bool (^use_attr_in_where)(const SecDbAttr *attr)) {
1256 CFStringRef sql = SecDbItemCopyUpdateSQL(old_item, new_item, use_attr_in_where);
1257 __block bool ok = sql;
1258 if (sql) {
1259 ok &= SecDbPrepare(dbconn, sql, error, ^(sqlite3_stmt *stmt) {
1260 ok = SecDbItemUpdateBind(old_item, new_item, stmt, error, use_attr_in_where) && SecDbStep(dbconn, stmt, error, NULL);
1261 });
1262 CFRelease(sql);
1263 }
1264 if (ok)
1265 secnotice("item", "replaced %@ with %@ in %@", old_item, new_item, dbconn);
1266 return ok;
1267 }
1268
1269 static CFStringRef SecDbItemCopyDeleteSQL(SecDbItemRef item, bool(^use_attr_in_where)(const SecDbAttr *attr)) {
1270 CFMutableStringRef sql = CFStringCreateMutable(CFGetAllocator(item), 0);
1271 CFStringAppend(sql, CFSTR("DELETE FROM "));
1272 CFStringAppend(sql, item->class->name);
1273 bool needWhere = true;
1274 SecDbForEachAttr(item->class, attr) {
1275 if (use_attr_in_where(attr)) {
1276 SecDbAppendWhereOrAndEquals(sql, attr->name, &needWhere);
1277 }
1278 }
1279
1280 return sql;
1281 }
1282
1283 static bool SecDbItemDeleteBind(SecDbItemRef item, sqlite3_stmt *stmt, CFErrorRef *error, bool(^use_attr_in_where)(const SecDbAttr *attr)) {
1284 bool ok = true;
1285 int param = 0;
1286 SecDbForEachAttr(item->class, attr) {
1287 if (use_attr_in_where(attr)) {
1288 CFTypeRef value = SecDbItemGetValue(item, attr, error);
1289 ok &= value && SecDbAttrBind(attr, stmt, ++param, value, error);
1290 if (!ok)
1291 break;
1292 }
1293 }
1294 return ok;
1295 }
1296
1297 static bool SecDbItemDoDelete(SecDbItemRef item, SecDbConnectionRef dbconn, CFErrorRef *error, bool (^use_attr_in_where)(const SecDbAttr *attr)) {
1298 CFStringRef sql = SecDbItemCopyDeleteSQL(item, use_attr_in_where);
1299 __block bool ok = sql;
1300 if (sql) {
1301 ok &= SecDbPrepare(dbconn, sql, error, ^(sqlite3_stmt *stmt) {
1302 ok = SecDbItemDeleteBind(item, stmt, error, use_attr_in_where) && SecDbStep(dbconn, stmt, error, NULL);
1303 });
1304 CFRelease(sql);
1305 }
1306 if (ok)
1307 secnotice("item", "deleted %@ from %@", item, dbconn);
1308 return ok;
1309 }
1310
1311 #if 0
1312 static bool SecDbItemDeleteTombstone(SecDbItemRef item, SecDbConnectionRef dbconn, CFErrorRef *error) {
1313 bool ok = true;
1314 // TODO: Treat non decryptable items like tombstones here too and delete them
1315 SecDbItemRef tombstone = SecDbItemCopyTombstone(item, error);
1316 ok = tombstone;
1317 if (tombstone) {
1318 ok = SecDbItemClearRowId(tombstone, error);
1319 if (ok) {
1320 ok = SecDbItemDoDelete(tombstone, dbconn, error, ^bool (const SecDbAttr *attr) {
1321 return SecDbIsTombstoneDbSelectAttr(attr);
1322 });
1323 }
1324 CFRelease(tombstone);
1325 }
1326 return ok;
1327 }
1328 #endif
1329
1330 // Replace old_item with new_item. If primary keys are the same this does an update otherwise it does a delete + add
1331 bool SecDbItemUpdate(SecDbItemRef old_item, SecDbItemRef new_item, SecDbConnectionRef dbconn, bool makeTombstone, CFErrorRef *error) {
1332 __block bool ok = true;
1333 __block CFErrorRef localError = NULL;
1334
1335 CFDataRef old_pk = SecDbItemGetPrimaryKey(old_item, error);
1336 CFDataRef new_pk = SecDbItemGetPrimaryKey(new_item, error);
1337
1338 ok = old_pk && new_pk;
1339
1340 bool pk_equal = ok && CFEqual(old_pk, new_pk);
1341 if (pk_equal) {
1342 ok = SecDbItemMakeYounger(new_item, old_item, error);
1343 }
1344 ok = ok && SecDbItemDoUpdate(old_item, new_item, dbconn, &localError, ^bool(const SecDbAttr *attr) {
1345 return attr->kind == kSecDbRowIdAttr;
1346 });
1347
1348 if (localError) {
1349 if(CFErrorGetCode(localError) == SQLITE_CONSTRAINT && CFEqual(kSecDbErrorDomain, CFErrorGetDomain(localError))) {
1350 /* Update failed because we changed the PrimaryKey and there was a dup.
1351 Find the dup and see if it is a tombstone or corrupted item. */
1352 SecDbQueryRef query = SecDbQueryCreateWithItemPrimaryKey(new_item, error);
1353 ok = query;
1354 if (query) {
1355 ok &= SecDbItemSelect(query, dbconn, error, ^bool(const SecDbAttr *attr) {
1356 return attr->flags & kSecDbPrimaryKeyFlag;
1357 }, NULL, NULL, ^(SecDbItemRef duplicate_item, bool *stop) {
1358 bool is_corrupt = false;
1359 bool is_tomb = false;
1360 ok = SecDbItemIsCorrupt(duplicate_item, &is_corrupt, error);
1361 if (ok && !is_corrupt) {
1362 if ((is_tomb = SecDbItemIsTombstone(duplicate_item)))
1363 ok = SecDbItemMakeYounger(new_item, duplicate_item, error);
1364 }
1365 if (ok && (is_corrupt || is_tomb)) {
1366 ok = SecDbItemDoDelete(old_item, dbconn, error, ^bool (const SecDbAttr *attr) {
1367 return attr->kind == kSecDbRowIdAttr;
1368 });
1369 ok = ok && SecDbItemDoUpdate(duplicate_item, new_item, dbconn, error, ^bool (const SecDbAttr *attr) {
1370 return attr->kind == kSecDbRowIdAttr;
1371 });
1372 CFReleaseNull(localError);
1373 }
1374 });
1375 ok &= query_destroy(query, error);
1376 }
1377 }
1378
1379 if (localError) {
1380 ok = false;
1381 if (error && *error == NULL) {
1382 *error = localError;
1383 localError = NULL;
1384 }
1385 CFReleaseSafe(localError);
1386 }
1387 }
1388
1389 if (ok && !pk_equal && makeTombstone) {
1390 /* The primary key of new_item is different than that of old_item, we
1391 have been asked to make a tombstone so leave one for the old_item. */
1392 SecDbItemRef tombstone = SecDbItemCopyTombstone(old_item, error);
1393 ok = tombstone;
1394 if (tombstone) {
1395 ok = (SecDbItemClearRowId(tombstone, error) &&
1396 SecDbItemDoInsert(tombstone, dbconn, error));
1397 CFRelease(tombstone);
1398 }
1399 }
1400
1401 return ok;
1402 }
1403
1404 // Replace the object with a tombstone
1405 bool SecDbItemDelete(SecDbItemRef item, SecDbConnectionRef dbconn, bool makeTombstone, CFErrorRef *error) {
1406 bool ok = false;
1407 if (makeTombstone) {
1408 SecDbItemRef tombstone = SecDbItemCopyTombstone(item, error);
1409 if (tombstone) {
1410 ok = SecDbItemDoUpdate(item, tombstone, dbconn, error, ^bool(const SecDbAttr *attr) {
1411 return attr->kind == kSecDbRowIdAttr;
1412 });
1413 CFRelease(tombstone);
1414 }
1415 } else {
1416 ok = SecDbItemDoDelete(item, dbconn, error, ^bool(const SecDbAttr *attr) {
1417 return attr->kind == kSecDbRowIdAttr;
1418 });
1419 }
1420 return ok;
1421 }
1422
1423 CFStringRef SecDbItemCopySelectSQL(SecDbQueryRef query,
1424 bool (^return_attr)(const SecDbAttr *attr),
1425 bool (^use_attr_in_where)(const SecDbAttr *attr),
1426 bool (^add_where_sql)(CFMutableStringRef sql, bool *needWhere)) {
1427 CFMutableStringRef sql = CFStringCreateMutable(kCFAllocatorDefault, 0);
1428 CFStringAppend(sql, CFSTR("SELECT "));
1429 // What are we selecting?
1430 bool needComma = false;
1431 SecDbForEachAttr(query->q_class, attr) {
1432 if (return_attr(attr))
1433 SecDbAppendElement(sql, attr->name, &needComma);
1434 }
1435
1436 // From which table?
1437 CFStringAppend(sql, CFSTR(" FROM "));
1438 CFStringAppend(sql, query->q_class->name);
1439
1440 // And which elements do we want to select
1441 bool needWhere = true;
1442 SecDbForEachAttr(query->q_class, attr) {
1443 if (use_attr_in_where(attr)) {
1444 SecDbAppendWhereOrAndEquals(sql, attr->name, &needWhere);
1445 }
1446 }
1447 // Append SQL for access groups and limits.
1448 if (add_where_sql)
1449 add_where_sql(sql, &needWhere);
1450
1451 return sql;
1452 }
1453
1454 bool SecDbItemSelectBind(SecDbQueryRef query, sqlite3_stmt *stmt, CFErrorRef *error,
1455 bool (^use_attr_in_where)(const SecDbAttr *attr),
1456 bool (^bind_added_where)(sqlite3_stmt *stmt, int col)) {
1457 bool ok = true;
1458 int param = 0;
1459 SecDbForEachAttr(query->q_class, attr) {
1460 if (use_attr_in_where(attr)) {
1461 CFTypeRef value = CFDictionaryGetValue(query->q_item, attr->name);
1462 ok &= SecDbAttrBind(attr, stmt, ++param, value, error);
1463 if (!ok)
1464 break;
1465 }
1466 }
1467 // TODO: Bind arguments for access groups and limits.
1468 if (bind_added_where)
1469 bind_added_where(stmt, ++param);
1470
1471 return ok;
1472 }
1473
1474 bool SecDbItemSelect(SecDbQueryRef query, SecDbConnectionRef dbconn, CFErrorRef *error,
1475 bool (^use_attr_in_where)(const SecDbAttr *attr),
1476 bool (^add_where_sql)(CFMutableStringRef sql, bool *needWhere),
1477 bool (^bind_added_where)(sqlite3_stmt *stmt, int col),
1478 void (^handle_row)(SecDbItemRef item, bool *stop)) {
1479 __block bool ok = true;
1480 bool (^return_attr)(const SecDbAttr *attr) = ^bool (const SecDbAttr * attr) {
1481 return attr->kind == kSecDbRowIdAttr || attr->kind == kSecDbEncryptedDataAttr;
1482 };
1483 CFStringRef sql = SecDbItemCopySelectSQL(query, return_attr, use_attr_in_where, add_where_sql);
1484 if (sql) {
1485 ok &= SecDbPrepare(dbconn, sql, error, ^(sqlite3_stmt *stmt) {
1486 ok = (SecDbItemSelectBind(query, stmt, error, use_attr_in_where, bind_added_where) &&
1487 SecDbStep(dbconn, stmt, error, ^(bool *stop) {
1488 SecDbItemRef item = SecDbItemCreateWithStatement(kCFAllocatorDefault, query->q_class, stmt, query->q_keybag, error, return_attr);
1489 if (item) {
1490 handle_row(item, stop);
1491 CFRelease(item);
1492 } else {
1493 //*stop = true;
1494 //ok = false;
1495 }
1496 }));
1497 });
1498 CFRelease(sql);
1499 } else {
1500 ok = false;
1501 }
1502 return ok;
1503 }
1504