2 * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
25 #include "SOSTestDataSource.h"
27 #include <corecrypto/ccder.h>
28 #include "keychain/SecureObjectSync/SOSDataSource.h"
29 #include "keychain/SecureObjectSync/SOSDigestVector.h"
30 #include <Security/SecureObjectSync/SOSViews.h>
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>
40 CFStringRef sSOSDataSourceErrorDomain
= CFSTR("com.apple.datasource");
42 typedef struct SOSTestDataSource
*SOSTestDataSourceRef
;
44 struct SOSTestDataSource
{
45 struct SOSDataSource ds
;
49 CFMutableDictionaryRef d2database
;
50 CFMutableDictionaryRef p2database
;
51 CFMutableDictionaryRef statedb
;
52 uint8_t manifest_digest
[SOSDigestSize
];
55 CFMutableArrayRef changes
;
56 SOSDataSourceNotifyBlock notifyBlock
;
59 typedef struct SOSTestDataSourceFactory
*SOSTestDataSourceFactoryRef
;
61 struct SOSTestDataSourceFactory
{
62 struct SOSDataSourceFactory dsf
;
63 CFMutableDictionaryRef data_sources
;
67 /* DataSource protocol. */
68 static SOSManifestRef
dsCopyManifestWithViewNameSet(SOSDataSourceRef data_source
, CFSetRef viewNameSet
, CFErrorRef
*error
) {
69 if (!CFSetContainsValue(viewNameSet
, kSOSViewKeychainV0
))
70 return SOSManifestCreateWithData(NULL
, error
);
72 struct SOSTestDataSource
*ds
= (struct SOSTestDataSource
*)data_source
;
74 __block
struct SOSDigestVector dv
= SOSDigestVectorInit
;
75 CFDictionaryForEach(ds
->d2database
, ^(const void *key
, const void *value
) {
76 SOSDigestVectorAppend(&dv
, CFDataGetBytePtr((CFDataRef
)key
));
78 SOSDigestVectorSort(&dv
);
79 SOSManifestRef manifest
= SOSManifestCreateWithDigestVector(&dv
, error
);
80 SOSDigestVectorFree(&dv
);
81 ccdigest(ccsha1_di(), SOSManifestGetSize(manifest
), SOSManifestGetBytePtr(manifest
), ds
->manifest_digest
);
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
;
90 __block
bool result
= true;
91 SOSManifestForEach(manifest
, ^(CFDataRef key
, bool *stop
) {
92 handle_object(key
, (SOSObjectRef
)CFDictionaryGetValue(ds
->d2database
, key
), stop
);
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
);
107 static SOSObjectRef
createWithPropertyList(CFDictionaryRef plist
, CFErrorRef
*error
) {
108 return (SOSObjectRef
)CFDictionaryCreateCopy(kCFAllocatorDefault
, plist
);
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
);
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
);
122 } else if (error
&& *error
== NULL
) {
123 *error
= CFErrorCreate(0, sSOSDataSourceErrorDomain
, kSOSDataSourceObjectMallocFailed
, NULL
);
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
);
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
);
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
);
145 CFDataRef digest
= NULL
;
147 digest
= ccdigest_copy_data(ccsha1_di(), CFDataGetLength(der
), CFDataGetBytePtr(der
), error
);
153 static CFDateRef
copyModDate(SOSObjectRef object
, CFErrorRef
*error
) {
154 return CFRetainSafe(asDate(CFDictionaryGetValue((CFDictionaryRef
) object
, kSecAttrModificationDate
), NULL
));
157 static CFDataRef
copyPrimaryKey(SOSObjectRef object
, CFErrorRef
*error
) {
158 CFMutableDictionaryRef ocopy
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
159 CFTypeRef pkNames
[] = {
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
);
189 CFDataRef der
= SOSObjectCopyDER((SOSObjectRef
)ocopy
, error
);
191 CFDataRef digest
= NULL
;
193 digest
= ccdigest_copy_data(ccsha1_di(), CFDataGetLength(der
), CFDataGetBytePtr(der
), error
);
199 static CFDictionaryRef
copyPropertyList(SOSObjectRef object
, CFErrorRef
*error
) {
200 return (CFDictionaryRef
) CFRetain(object
);
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
;
209 m1
= CFDictionaryGetValue(dict1
, kSecAttrModificationDate
);
210 m2
= CFDictionaryGetValue(dict2
, kSecAttrModificationDate
);
211 switch (CFDateCompare(m1
, m2
, NULL
)) {
212 case kCFCompareGreaterThan
:
213 result
= (SOSObjectRef
)dict1
;
215 case kCFCompareLessThan
:
216 result
= (SOSObjectRef
)dict2
;
218 case kCFCompareEqualTo
:
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
;
228 case kCFCompareLessThan
:
229 result
= (SOSObjectRef
)dict1
;
232 CFReleaseSafe(digest2
);
233 CFReleaseSafe(digest1
);
237 CFRetainSafe(result
);
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
);
246 SOSObjectRef myObject
= (SOSObjectRef
)CFDictionaryGetValue(ds
->p2database
, pk
);
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
;
255 mr
= kSOSMergeCreatedObject
;
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
);
266 CFArrayAppendValue(ds
->changes
, entry
);
270 CFDictionarySetValue(ds
->p2database
, pk
, merged
);
272 CFReleaseSafe(merged
);
274 SOSTestDataSourceAddObject((SOSDataSourceRef
)ds
, object
, error
);
275 mr
= kSOSMergePeersObject
;
281 static CFStringRef
dsGetName(SOSDataSourceRef ds
) {
282 return CFSTR("The sky is made of butterflies");
285 static void dsAddNotifyPhaseBlock(SOSDataSourceRef ds
, SOSDataSourceNotifyBlock notifyBlock
) {
286 SOSTestDataSourceRef tds
= (SOSTestDataSourceRef
)ds
;
287 assert(tds
->notifyBlock
== NULL
);
288 tds
->notifyBlock
= Block_copy(notifyBlock
);
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
);
299 static CFDataRef
dsCopyItemDataWithKeys(SOSDataSourceRef data_source
, CFDictionaryRef keys
, CFErrorRef
*error
) {
300 SecError(errSecUnimplemented
, error
, CFSTR("dsCopyItemDataWithKeys on test data source not implemented"));
304 static bool dsWith(SOSDataSourceRef ds
, CFErrorRef
*error
, SOSDataSourceTransactionSource source
, bool onCommitQueue
, void(^transaction
)(SOSTransactionRef txn
, bool *commit
)) {
305 SOSTestDataSourceRef tds
= (SOSTestDataSourceRef
)ds
;
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
);
315 static bool dsReadWith(SOSDataSourceRef ds
, CFErrorRef
*error
, SOSDataSourceTransactionSource source
, void(^perform
)(SOSTransactionRef txn
)) {
316 SOSTestDataSourceRef tds
= (SOSTestDataSourceRef
)ds
;
317 perform((SOSTransactionRef
)tds
);
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
);
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
335 static CFDictionaryRef
objectCopyBackup(SOSObjectRef object
, uint64_t handle
, CFErrorRef
*error
) {
336 // OMG We failed without an error.
341 SOSDataSourceRef
SOSTestDataSourceCreate(void) {
342 SOSTestDataSourceRef ds
= calloc(1, sizeof(struct SOSTestDataSource
));
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
;
352 ds
->ds
.dsWith
= dsWith
;
353 ds
->ds
.dsRelease
= dispose
;
354 ds
->ds
.dsReadWith
= dsReadWith
;
356 ds
->ds
.dsMergeObject
= mergeObject
;
357 ds
->ds
.dsSetStateWithKey
= dsSetStateWithKey
;
358 ds
->ds
.dsRestoreObject
= dsRestoreObject
;
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
;
366 ds
->d2database
= CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
367 ds
->p2database
= CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
368 ds
->statedb
= CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
370 ds
->changes
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
372 return (SOSDataSourceRef
)ds
;
375 static CFStringRef
SOSTestDataSourceFactoryCopyName(SOSDataSourceFactoryRef factory
)
377 SOSTestDataSourceFactoryRef dsf
= (SOSTestDataSourceFactoryRef
) factory
;
379 __block CFStringRef result
= NULL
;
380 CFDictionaryForEach(dsf
->data_sources
, ^(const void*key
, const void*value
) { if (isString(key
)) result
= key
; });
382 return CFRetainSafe(result
);
385 static SOSDataSourceRef
SOSTestDataSourceFactoryCreateDataSource(SOSDataSourceFactoryRef factory
, CFStringRef dataSourceName
, CFErrorRef
*error
)
387 SOSTestDataSourceFactoryRef dsf
= (SOSTestDataSourceFactoryRef
) factory
;
389 return (SOSDataSourceRef
) CFDictionaryGetValue(dsf
->data_sources
, dataSourceName
);
392 static void SOSTestDataSourceFactoryDispose(SOSDataSourceFactoryRef factory
)
394 SOSTestDataSourceFactoryRef dsf
= (SOSTestDataSourceFactoryRef
) factory
;
396 CFReleaseNull(dsf
->data_sources
);
400 SOSDataSourceFactoryRef
SOSTestDataSourceFactoryCreate() {
401 SOSTestDataSourceFactoryRef dsf
= calloc(1, sizeof(struct SOSTestDataSourceFactory
));
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
);
411 static bool do_nothing(SOSDataSourceRef ds
, CFErrorRef
*error
) {
415 void SOSTestDataSourceFactorySetDataSource(SOSDataSourceFactoryRef factory
, CFStringRef name
, SOSDataSourceRef ds
)
417 SOSTestDataSourceFactoryRef dsf
= (SOSTestDataSourceFactoryRef
) factory
;
419 // TODO This hack sucks. It leaks now.
420 ds
->dsRelease
= do_nothing
;
422 CFDictionaryRemoveAllValues(dsf
->data_sources
);
423 CFDictionarySetValue(dsf
->data_sources
, name
, ds
);
427 SOSMergeResult
SOSTestDataSourceAddObject(SOSDataSourceRef data_source
, SOSObjectRef object
, CFErrorRef
*error
) {
428 struct SOSTestDataSource
*ds
= (struct SOSTestDataSource
*)data_source
;
430 CFDataRef key
= copyDigest(object
, error
);
431 CFDataRef pk
= copyPrimaryKey(object
, error
);
433 SOSObjectRef myObject
= (SOSObjectRef
)CFDictionaryGetValue(ds
->p2database
, pk
);
434 SOSObjectRef merged
= NULL
;
436 merged
= copyMergedObject(object
, myObject
, error
);
443 if (!CFEqualSafe(merged
, 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
);
451 CFArrayAppendValue(ds
->changes
, entry
);
455 CFArrayAppendValue(ds
->changes
, merged
);
457 CFDictionarySetValue(ds
->d2database
, key
, merged
);
458 CFDictionarySetValue(ds
->p2database
, pk
, merged
);
469 bool SOSTestDataSourceDeleteObject(SOSDataSourceRef data_source
, CFDataRef key
, CFErrorRef
*error
) {
470 //struct SOSTestDataSource *ds = (struct SOSTestDataSource *)data_source;
474 CFMutableDictionaryRef
SOSTestDataSourceGetDatabase(SOSDataSourceRef data_source
) {
475 struct SOSTestDataSource
*ds
= (struct SOSTestDataSource
*)data_source
;
476 return ds
->d2database
;
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
) {
482 CFNumberRef zero
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberSInt32Type
, &value
);
484 CFNumberRef one
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberSInt32Type
, &value
);
485 CFAbsoluteTime timestamp
= 3700000 + (is_tomb
? 1 : 0);
486 CFDateRef now
= CFDateCreate(kCFAllocatorDefault
, timestamp
);
488 CFDataRef defaultData
= NULL
;
489 if (!is_tomb
&& !data
) {
490 defaultData
= CFDataCreate(NULL
, (UInt8
*)"some data", 9);
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
,
508 CFReleaseNull(defaultData
);
509 CFErrorRef localError
= NULL
;
510 SOSObjectRef object
= ds
->objectCreateWithPropertyList(dict
, &localError
);
512 secerror("createWithPropertyList: %@ failed: %@", dict
, localError
);
513 CFRelease(localError
);
519 SOSObjectRef
SOSDataSourceCreateGenericItem(SOSDataSourceRef ds
, CFStringRef account
, CFStringRef service
) {
520 return SOSDataSourceCreateGenericItemWithData(ds
, account
, service
, false, NULL
);
523 SOSObjectRef
SOSDataSourceCreateV0EngineStateWithData(SOSDataSourceRef ds
, CFDataRef engineStateData
) {
525 MANGO-iPhone:~ mobile$ security item class=genp,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
532 svce : SOSDataSource-ak
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
,
551 CFErrorRef localError
= NULL
;
552 SOSObjectRef object
= ds
->objectCreateWithPropertyList(item
, &localError
);
554 secerror("createWithPropertyList: %@ failed: %@", item
, localError
);
555 CFRelease(localError
);
561 SOSObjectRef
SOSDataSourceCopyObject(SOSDataSourceRef ds
, SOSObjectRef match
, CFErrorRef
*error
)
563 __block SOSObjectRef result
= NULL
;
565 CFDataRef digest
= SOSObjectCopyDigest(ds
, match
, error
);
566 SOSManifestRef manifest
= NULL
;
568 require(digest
, exit
);
569 manifest
= SOSManifestCreateWithData(digest
, error
);
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
);
576 } else if (result
== NULL
) {
577 result
= CFRetainSafe(object
);
582 CFReleaseNull(manifest
);
583 CFReleaseNull(digest
);