]> git.saurik.com Git - apple/security.git/blob - keychain/SecureObjectSync/Regressions/SOSTestDataSource.c
Security-59754.41.1.tar.gz
[apple/security.git] / keychain / SecureObjectSync / Regressions / SOSTestDataSource.c
1 /*
2 * Copyright (c) 2012-2014 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 #include "SOSTestDataSource.h"
26
27 #include <corecrypto/ccder.h>
28 #include "keychain/SecureObjectSync/SOSDataSource.h"
29 #include "keychain/SecureObjectSync/SOSDigestVector.h"
30 #include <Security/SecureObjectSync/SOSViews.h>
31
32 #include <utilities/array_size.h>
33 #include <utilities/der_plist.h>
34 #include <utilities/SecCFError.h>
35 #include <utilities/SecCFWrappers.h>
36 #include <Security/SecItem.h>
37 #include <Security/SecItemPriv.h>
38 #include <AssertMacros.h>
39
40 CFStringRef sSOSDataSourceErrorDomain = CFSTR("com.apple.datasource");
41
42 typedef struct SOSTestDataSource *SOSTestDataSourceRef;
43
44 struct SOSTestDataSource {
45 struct SOSDataSource ds;
46 unsigned gm_count;
47 unsigned cm_count;
48 unsigned co_count;
49 CFMutableDictionaryRef d2database;
50 CFMutableDictionaryRef p2database;
51 CFMutableDictionaryRef statedb;
52 uint8_t manifest_digest[SOSDigestSize];
53 bool clean;
54
55 CFMutableArrayRef changes;
56 SOSDataSourceNotifyBlock notifyBlock;
57 };
58
59 typedef struct SOSTestDataSourceFactory *SOSTestDataSourceFactoryRef;
60
61 struct SOSTestDataSourceFactory {
62 struct SOSDataSourceFactory dsf;
63 CFMutableDictionaryRef data_sources;
64 };
65
66
67 /* DataSource protocol. */
68 static SOSManifestRef dsCopyManifestWithViewNameSet(SOSDataSourceRef data_source, CFSetRef viewNameSet, CFErrorRef *error) {
69 if (!CFSetContainsValue(viewNameSet, kSOSViewKeychainV0))
70 return SOSManifestCreateWithData(NULL, error);
71
72 struct SOSTestDataSource *ds = (struct SOSTestDataSource *)data_source;
73 ds->cm_count++;
74 __block struct SOSDigestVector dv = SOSDigestVectorInit;
75 CFDictionaryForEach(ds->d2database, ^(const void *key, const void *value) {
76 SOSDigestVectorAppend(&dv, CFDataGetBytePtr((CFDataRef)key));
77 });
78 SOSDigestVectorSort(&dv);
79 SOSManifestRef manifest = SOSManifestCreateWithDigestVector(&dv, error);
80 SOSDigestVectorFree(&dv);
81 ccdigest(ccsha1_di(), SOSManifestGetSize(manifest), SOSManifestGetBytePtr(manifest), ds->manifest_digest);
82 ds->clean = true;
83
84 return manifest;
85 }
86
87 static bool foreach_object(SOSDataSourceRef data_source, SOSTransactionRef txn, SOSManifestRef manifest, CFErrorRef *error, void (^handle_object)(CFDataRef key, SOSObjectRef object, bool *stop)) {
88 struct SOSTestDataSource *ds = (struct SOSTestDataSource *)data_source;
89 ds->co_count++;
90 __block bool result = true;
91 SOSManifestForEach(manifest, ^(CFDataRef key, bool *stop) {
92 handle_object(key, (SOSObjectRef)CFDictionaryGetValue(ds->d2database, key), stop);
93 });
94 return result;
95 }
96
97 static bool dispose(SOSDataSourceRef data_source, CFErrorRef *error) {
98 struct SOSTestDataSource *ds = (struct SOSTestDataSource *)data_source;
99 CFReleaseSafe(ds->d2database);
100 CFReleaseSafe(ds->p2database);
101 CFReleaseSafe(ds->statedb);
102 CFReleaseSafe(ds->changes);
103 free(ds);
104 return true;
105 }
106
107 static SOSObjectRef createWithPropertyList(CFDictionaryRef plist, CFErrorRef *error) {
108 return (SOSObjectRef)CFDictionaryCreateCopy(kCFAllocatorDefault, plist);
109 }
110
111 static CFDataRef SOSObjectCopyDER(SOSObjectRef object, CFErrorRef *error) {
112 CFDictionaryRef dict = (CFDictionaryRef)object;
113 size_t size = der_sizeof_plist(dict, error);
114 CFMutableDataRef data = CFDataCreateMutable(0, size);
115 if (data) {
116 CFDataSetLength(data, size);
117 uint8_t *der = (uint8_t *)CFDataGetMutableBytePtr(data);
118 uint8_t *der_end = der + size;
119 der_end = der_encode_plist(dict, error, der, der_end);
120 assert(der_end == der);
121 (void)der_end;
122 } else if (error && *error == NULL) {
123 *error = CFErrorCreate(0, sSOSDataSourceErrorDomain, kSOSDataSourceObjectMallocFailed, NULL);
124 }
125 return data;
126 }
127
128 static CFDataRef ccdigest_copy_data(const struct ccdigest_info *di, size_t len,
129 const void *data, CFErrorRef *error) {
130 CFMutableDataRef digest = CFDataCreateMutable(0, di->output_size);
131 if (digest) {
132 CFDataSetLength(digest, di->output_size);
133 ccdigest(di, len, data, CFDataGetMutableBytePtr(digest));
134 } else if (error && *error == NULL) {
135 *error = CFErrorCreate(0, sSOSDataSourceErrorDomain, kSOSDataSourceObjectMallocFailed, NULL);
136 }
137 return digest;
138 }
139
140 static CFDataRef copyDigest(SOSObjectRef object, CFErrorRef *error) {
141 CFMutableDictionaryRef ocopy = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, (CFDictionaryRef)object);
142 CFDictionaryRemoveValue(ocopy, kSecClass);
143 CFDataRef der = SOSObjectCopyDER((SOSObjectRef)ocopy, error);
144 CFRelease(ocopy);
145 CFDataRef digest = NULL;
146 if (der) {
147 digest = ccdigest_copy_data(ccsha1_di(), CFDataGetLength(der), CFDataGetBytePtr(der), error);
148 CFRelease(der);
149 }
150 return digest;
151 }
152
153 static CFDateRef copyModDate(SOSObjectRef object, CFErrorRef *error) {
154 return CFRetainSafe(asDate(CFDictionaryGetValue((CFDictionaryRef) object, kSecAttrModificationDate), NULL));
155 }
156
157 static CFDataRef copyPrimaryKey(SOSObjectRef object, CFErrorRef *error) {
158 CFMutableDictionaryRef ocopy = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
159 CFTypeRef pkNames[] = {
160 CFSTR("acct"),
161 CFSTR("agrp"),
162 CFSTR("svce"),
163 CFSTR("sync"),
164 CFSTR("sdmn"),
165 CFSTR("srvr"),
166 CFSTR("ptcl"),
167 CFSTR("atyp"),
168 CFSTR("port"),
169 CFSTR("path"),
170 CFSTR("ctyp"),
171 CFSTR("issr"),
172 CFSTR("slnr"),
173 CFSTR("kcls"),
174 CFSTR("klbl"),
175 CFSTR("atag"),
176 CFSTR("crtr"),
177 CFSTR("type"),
178 CFSTR("bsiz"),
179 CFSTR("esiz"),
180 CFSTR("sdat"),
181 CFSTR("edat"),
182 };
183 CFSetRef pkAttrs = CFSetCreate(kCFAllocatorDefault, pkNames, array_size(pkNames), &kCFTypeSetCallBacks);
184 CFDictionaryForEach((CFDictionaryRef)object, ^(const void *key, const void *value) {
185 if (CFSetContainsValue(pkAttrs, key))
186 CFDictionaryAddValue(ocopy, key, value);
187 });
188 CFRelease(pkAttrs);
189 CFDataRef der = SOSObjectCopyDER((SOSObjectRef)ocopy, error);
190 CFRelease(ocopy);
191 CFDataRef digest = NULL;
192 if (der) {
193 digest = ccdigest_copy_data(ccsha1_di(), CFDataGetLength(der), CFDataGetBytePtr(der), error);
194 CFRelease(der);
195 }
196 return digest;
197 }
198
199 static CFDictionaryRef copyPropertyList(SOSObjectRef object, CFErrorRef *error) {
200 return (CFDictionaryRef) CFRetain(object);
201 }
202
203 // Return the newest object
204 static SOSObjectRef copyMergedObject(SOSObjectRef object1, SOSObjectRef object2, CFErrorRef *error) {
205 CFDictionaryRef dict1 = (CFDictionaryRef)object1;
206 CFDictionaryRef dict2 = (CFDictionaryRef)object2;
207 SOSObjectRef result = NULL;
208 CFDateRef m1, m2;
209 m1 = CFDictionaryGetValue(dict1, kSecAttrModificationDate);
210 m2 = CFDictionaryGetValue(dict2, kSecAttrModificationDate);
211 switch (CFDateCompare(m1, m2, NULL)) {
212 case kCFCompareGreaterThan:
213 result = (SOSObjectRef)dict1;
214 break;
215 case kCFCompareLessThan:
216 result = (SOSObjectRef)dict2;
217 break;
218 case kCFCompareEqualTo:
219 {
220 // Return the item with the smallest digest.
221 CFDataRef digest1 = copyDigest(object1, error);
222 CFDataRef digest2 = copyDigest(object2, error);
223 if (digest1 && digest2) switch (CFDataCompareDERData(digest1, digest2)) {
224 case kCFCompareGreaterThan:
225 case kCFCompareEqualTo:
226 result = (SOSObjectRef)dict2;
227 break;
228 case kCFCompareLessThan:
229 result = (SOSObjectRef)dict1;
230 break;
231 }
232 CFReleaseSafe(digest2);
233 CFReleaseSafe(digest1);
234 break;
235 }
236 }
237 CFRetainSafe(result);
238 return result;
239 }
240
241 static SOSMergeResult mergeObject(SOSTransactionRef txn, SOSObjectRef object, SOSObjectRef *mergedObject, CFErrorRef *error) {
242 SOSTestDataSourceRef ds = (SOSTestDataSourceRef)txn;
243 SOSMergeResult mr = kSOSMergeFailure;
244 CFDataRef pk = copyPrimaryKey(object, error);
245 if (!pk) return mr;
246 SOSObjectRef myObject = (SOSObjectRef)CFDictionaryGetValue(ds->p2database, pk);
247 if (myObject) {
248 SOSObjectRef merged = copyMergedObject(object, myObject, error);
249 if (mergedObject) *mergedObject = CFRetainSafe(merged);
250 if (CFEqualSafe(merged, myObject)) {
251 mr = kSOSMergeLocalObject;
252 } else if (CFEqualSafe(merged, object)) {
253 mr = kSOSMergePeersObject;
254 } else {
255 mr = kSOSMergeCreatedObject;
256 }
257 if (mr != kSOSMergeLocalObject) {
258 CFDataRef myKey = copyDigest(myObject, error);
259 CFDictionaryRemoveValue(ds->d2database, myKey);
260 CFReleaseSafe(myKey);
261 CFDataRef key = copyDigest(merged, error);
262 CFDictionarySetValue(ds->d2database, key, merged);
263 const void *values[2] = { myObject, merged };
264 CFTypeRef entry = CFArrayCreate(kCFAllocatorDefault, values, 2, &kCFTypeArrayCallBacks);
265 if (entry) {
266 CFArrayAppendValue(ds->changes, entry);
267 CFRelease(entry);
268 }
269 CFReleaseSafe(key);
270 CFDictionarySetValue(ds->p2database, pk, merged);
271 }
272 CFReleaseSafe(merged);
273 } else {
274 SOSTestDataSourceAddObject((SOSDataSourceRef)ds, object, error);
275 mr = kSOSMergePeersObject;
276 }
277 CFReleaseSafe(pk);
278 return mr;
279 }
280
281 static CFStringRef dsGetName(SOSDataSourceRef ds) {
282 return CFSTR("The sky is made of butterflies");
283 }
284
285 static void dsAddNotifyPhaseBlock(SOSDataSourceRef ds, SOSDataSourceNotifyBlock notifyBlock) {
286 SOSTestDataSourceRef tds = (SOSTestDataSourceRef)ds;
287 assert(tds->notifyBlock == NULL);
288 tds->notifyBlock = Block_copy(notifyBlock);
289 }
290
291 static CFDataRef dsCopyStateWithKey(SOSDataSourceRef ds, CFStringRef key, CFStringRef pdmn, SOSTransactionRef txn, CFErrorRef *error) {
292 SOSTestDataSourceRef tds = (SOSTestDataSourceRef)ds;
293 CFStringRef dbkey = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@-%@"), pdmn, key);
294 CFDataRef state = CFDictionaryGetValue(tds->statedb, dbkey);
295 CFReleaseSafe(dbkey);
296 return CFRetainSafe(state);
297 }
298
299 static CFDataRef dsCopyItemDataWithKeys(SOSDataSourceRef data_source, CFDictionaryRef keys, CFErrorRef *error) {
300 SecError(errSecUnimplemented, error, CFSTR("dsCopyItemDataWithKeys on test data source not implemented"));
301 return NULL;
302 }
303
304 static bool dsWith(SOSDataSourceRef ds, CFErrorRef *error, SOSDataSourceTransactionSource source, bool onCommitQueue, void(^transaction)(SOSTransactionRef txn, bool *commit)) {
305 SOSTestDataSourceRef tds = (SOSTestDataSourceRef)ds;
306 bool commit = true;
307 transaction((SOSTransactionRef)ds, &commit);
308 if (commit && ((SOSTestDataSourceRef)ds)->notifyBlock && (CFArrayGetCount(tds->changes))) {
309 ((SOSTestDataSourceRef)ds)->notifyBlock(ds, (SOSTransactionRef)ds, kSOSDataSourceTransactionWillCommit, source, tds->changes);
310 CFArrayRemoveAllValues(tds->changes);
311 }
312 return true;
313 }
314
315 static bool dsReadWith(SOSDataSourceRef ds, CFErrorRef *error, SOSDataSourceTransactionSource source, void(^perform)(SOSTransactionRef txn)) {
316 SOSTestDataSourceRef tds = (SOSTestDataSourceRef)ds;
317 perform((SOSTransactionRef)tds);
318 return true;
319 }
320
321 static bool dsSetStateWithKey(SOSDataSourceRef ds, SOSTransactionRef txn, CFStringRef key, CFStringRef pdmn, CFDataRef state, CFErrorRef *error) {
322 SOSTestDataSourceRef tds = (SOSTestDataSourceRef)ds;
323 CFStringRef dbkey = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@-%@"), pdmn, key);
324 CFDictionarySetValue(tds->statedb, dbkey, state);
325 CFReleaseSafe(dbkey);
326 return true;
327 }
328
329 static bool dsRestoreObject(SOSTransactionRef txn, uint64_t handle, CFDictionaryRef item, CFErrorRef *error) {
330 // TODO: Just call merge, probably doesn't belong in protocol at all
331 assert(false);
332 return true;
333 }
334
335 static CFDictionaryRef objectCopyBackup(SOSObjectRef object, uint64_t handle, CFErrorRef *error) {
336 // OMG We failed without an error.
337 assert(false);
338 return NULL;
339 }
340
341 SOSDataSourceRef SOSTestDataSourceCreate(void) {
342 SOSTestDataSourceRef ds = calloc(1, sizeof(struct SOSTestDataSource));
343
344 ds->ds.engine = NULL;
345 ds->ds.dsGetName = dsGetName;
346 ds->ds.dsAddNotifyPhaseBlock = dsAddNotifyPhaseBlock;
347 ds->ds.dsCopyManifestWithViewNameSet = dsCopyManifestWithViewNameSet;
348 ds->ds.dsForEachObject = foreach_object;
349 ds->ds.dsCopyStateWithKey = dsCopyStateWithKey;
350 ds->ds.dsCopyItemDataWithKeys = dsCopyItemDataWithKeys;
351
352 ds->ds.dsWith = dsWith;
353 ds->ds.dsRelease = dispose;
354 ds->ds.dsReadWith = dsReadWith;
355
356 ds->ds.dsMergeObject = mergeObject;
357 ds->ds.dsSetStateWithKey = dsSetStateWithKey;
358 ds->ds.dsRestoreObject = dsRestoreObject;
359
360 ds->ds.objectCopyDigest = copyDigest;
361 ds->ds.objectCopyModDate = copyModDate;
362 ds->ds.objectCreateWithPropertyList = createWithPropertyList;
363 ds->ds.objectCopyPropertyList = copyPropertyList;
364 ds->ds.objectCopyBackup = objectCopyBackup;
365
366 ds->d2database = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
367 ds->p2database = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
368 ds->statedb = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
369 ds->clean = false;
370 ds->changes = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
371
372 return (SOSDataSourceRef)ds;
373 }
374
375 static CFStringRef SOSTestDataSourceFactoryCopyName(SOSDataSourceFactoryRef factory)
376 {
377 SOSTestDataSourceFactoryRef dsf = (SOSTestDataSourceFactoryRef) factory;
378
379 __block CFStringRef result = NULL;
380 CFDictionaryForEach(dsf->data_sources, ^(const void*key, const void*value) { if (isString(key)) result = key; });
381
382 return CFRetainSafe(result);
383 }
384
385 static SOSDataSourceRef SOSTestDataSourceFactoryCreateDataSource(SOSDataSourceFactoryRef factory, CFStringRef dataSourceName, CFErrorRef *error)
386 {
387 SOSTestDataSourceFactoryRef dsf = (SOSTestDataSourceFactoryRef) factory;
388
389 return (SOSDataSourceRef) CFDictionaryGetValue(dsf->data_sources, dataSourceName);
390 }
391
392 static void SOSTestDataSourceFactoryDispose(SOSDataSourceFactoryRef factory)
393 {
394 SOSTestDataSourceFactoryRef dsf = (SOSTestDataSourceFactoryRef) factory;
395
396 CFReleaseNull(dsf->data_sources);
397 free(dsf);
398 }
399
400 SOSDataSourceFactoryRef SOSTestDataSourceFactoryCreate() {
401 SOSTestDataSourceFactoryRef dsf = calloc(1, sizeof(struct SOSTestDataSourceFactory));
402
403 dsf->dsf.copy_name = SOSTestDataSourceFactoryCopyName;
404 dsf->dsf.create_datasource = SOSTestDataSourceFactoryCreateDataSource;
405 dsf->dsf.release = SOSTestDataSourceFactoryDispose;
406 dsf->data_sources = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, NULL);
407
408 return &(dsf->dsf);
409 }
410
411 static bool do_nothing(SOSDataSourceRef ds, CFErrorRef *error) {
412 return true;
413 }
414
415 void SOSTestDataSourceFactorySetDataSource(SOSDataSourceFactoryRef factory, CFStringRef name, SOSDataSourceRef ds)
416 {
417 SOSTestDataSourceFactoryRef dsf = (SOSTestDataSourceFactoryRef) factory;
418
419 // TODO This hack sucks. It leaks now.
420 ds->dsRelease = do_nothing;
421
422 CFDictionaryRemoveAllValues(dsf->data_sources);
423 CFDictionarySetValue(dsf->data_sources, name, ds);
424
425 }
426
427 SOSMergeResult SOSTestDataSourceAddObject(SOSDataSourceRef data_source, SOSObjectRef object, CFErrorRef *error) {
428 struct SOSTestDataSource *ds = (struct SOSTestDataSource *)data_source;
429 bool result = false;
430 CFDataRef key = copyDigest(object, error);
431 CFDataRef pk = copyPrimaryKey(object, error);
432 if (key && pk) {
433 SOSObjectRef myObject = (SOSObjectRef)CFDictionaryGetValue(ds->p2database, pk);
434 SOSObjectRef merged = NULL;
435 if (myObject) {
436 merged = copyMergedObject(object, myObject, error);
437 } else {
438 merged = object;
439 CFRetain(merged);
440 }
441 if (merged) {
442 result = true;
443 if (!CFEqualSafe(merged, myObject)) {
444 if (myObject) {
445 CFDataRef myKey = copyDigest(myObject, error);
446 CFDictionaryRemoveValue(ds->d2database, myKey);
447 CFReleaseSafe(myKey);
448 const void *values[2] = { myObject, merged };
449 CFTypeRef entry = CFArrayCreate(kCFAllocatorDefault, values, 2, &kCFTypeArrayCallBacks);
450 if (entry) {
451 CFArrayAppendValue(ds->changes, entry);
452 CFRelease(entry);
453 }
454 } else {
455 CFArrayAppendValue(ds->changes, merged);
456 }
457 CFDictionarySetValue(ds->d2database, key, merged);
458 CFDictionarySetValue(ds->p2database, pk, merged);
459 ds->clean = false;
460 }
461 CFRelease(merged);
462 }
463 }
464 CFReleaseSafe(pk);
465 CFReleaseSafe(key);
466 return result;
467 }
468
469 bool SOSTestDataSourceDeleteObject(SOSDataSourceRef data_source, CFDataRef key, CFErrorRef *error) {
470 //struct SOSTestDataSource *ds = (struct SOSTestDataSource *)data_source;
471 return false;
472 }
473
474 CFMutableDictionaryRef SOSTestDataSourceGetDatabase(SOSDataSourceRef data_source) {
475 struct SOSTestDataSource *ds = (struct SOSTestDataSource *)data_source;
476 return ds->d2database;
477 }
478
479 // This works for any datasource, not just the test one, but it's only used in testcases, so it's here for now.
480 SOSObjectRef SOSDataSourceCreateGenericItemWithData(SOSDataSourceRef ds, CFStringRef account, CFStringRef service, bool is_tomb, CFDataRef data) {
481 int32_t value = 0;
482 CFNumberRef zero = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &value);
483 value = 1;
484 CFNumberRef one = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &value);
485 CFAbsoluteTime timestamp = 3700000 + (is_tomb ? 1 : 0);
486 CFDateRef now = CFDateCreate(kCFAllocatorDefault, timestamp);
487
488 CFDataRef defaultData = NULL;
489 if (!is_tomb && !data) {
490 defaultData = CFDataCreate(NULL, (UInt8*)"some data", 9);
491 data = defaultData;
492 }
493 CFDictionaryRef dict = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
494 kSecClass, kSecClassGenericPassword,
495 kSecAttrSynchronizable, one,
496 kSecAttrTombstone, is_tomb ? one : zero,
497 kSecAttrAccount, account,
498 kSecAttrService, service,
499 kSecAttrCreationDate, now,
500 kSecAttrModificationDate, now,
501 kSecAttrAccessGroup, CFSTR("test"),
502 kSecAttrAccessible, kSecAttrAccessibleWhenUnlocked,
503 !is_tomb && data ? kSecValueData : NULL,data,
504 NULL);
505 CFRelease(one);
506 CFRelease(zero);
507 CFReleaseSafe(now);
508 CFReleaseNull(defaultData);
509 CFErrorRef localError = NULL;
510 SOSObjectRef object = ds->objectCreateWithPropertyList(dict, &localError);
511 if (!object) {
512 secerror("createWithPropertyList: %@ failed: %@", dict, localError);
513 CFRelease(localError);
514 }
515 CFRelease(dict);
516 return object;
517 }
518
519 SOSObjectRef SOSDataSourceCreateGenericItem(SOSDataSourceRef ds, CFStringRef account, CFStringRef service) {
520 return SOSDataSourceCreateGenericItemWithData(ds, account, service, false, NULL);
521 }
522
523 SOSObjectRef SOSDataSourceCreateV0EngineStateWithData(SOSDataSourceRef ds, CFDataRef engineStateData) {
524 /*
525 MANGO-iPhone:~ mobile$ security item class=genp,acct=engine-state
526 acct : engine-state
527 agrp : com.apple.security.sos
528 cdat : 2016-04-18 20:40:33 +0000
529 mdat : 2016-04-18 20:40:33 +0000
530 musr : //
531 pdmn : dk
532 svce : SOSDataSource-ak
533 sync : 0
534 tomb : 0
535 */
536 CFAbsoluteTime timestamp = 3700000;
537 CFDateRef now = CFDateCreate(kCFAllocatorDefault, timestamp);
538 CFDictionaryRef item = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
539 kSecClass, kSecClassGenericPassword,
540 kSecAttrSynchronizable, kCFBooleanFalse,
541 kSecAttrTombstone, kCFBooleanFalse,
542 kSecAttrAccount, CFSTR("engine-state"),
543 kSecAttrService, CFSTR("SOSDataSource-ak"),
544 kSecAttrCreationDate, now,
545 kSecAttrModificationDate, now,
546 kSecAttrAccessGroup, CFSTR("com.apple.security.sos"),
547 kSecAttrAccessible, kSecAttrAccessibleAlwaysPrivate,
548 engineStateData ? kSecValueData : NULL, engineStateData,
549 NULL);
550 CFReleaseSafe(now);
551 CFErrorRef localError = NULL;
552 SOSObjectRef object = ds->objectCreateWithPropertyList(item, &localError);
553 if (!object) {
554 secerror("createWithPropertyList: %@ failed: %@", item, localError);
555 CFRelease(localError);
556 }
557 CFRelease(item);
558 return object;
559 }
560
561 SOSObjectRef SOSDataSourceCopyObject(SOSDataSourceRef ds, SOSObjectRef match, CFErrorRef *error)
562 {
563 __block SOSObjectRef result = NULL;
564
565 CFDataRef digest = SOSObjectCopyDigest(ds, match, error);
566 SOSManifestRef manifest = NULL;
567
568 require(digest, exit);
569 manifest = SOSManifestCreateWithData(digest, error);
570
571 SOSDataSourceForEachObject(ds, NULL, manifest, error, ^void (CFDataRef key, SOSObjectRef object, bool *stop) {
572 if (object == NULL) {
573 if (error && !*error) {
574 SecCFCreateErrorWithFormat(kSOSDataSourceObjectNotFoundError, sSOSDataSourceErrorDomain, NULL, error, 0, CFSTR("key %@ not in database"), key);
575 }
576 } else if (result == NULL) {
577 result = CFRetainSafe(object);
578 }
579 });
580
581 exit:
582 CFReleaseNull(manifest);
583 CFReleaseNull(digest);
584 return result;
585 }