2 * Copyright (c) 2015 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 * SOSViews.c - Implementation of views
28 #include <AssertMacros.h>
29 #include <TargetConditionals.h>
32 #include <utilities/SecCFWrappers.h>
33 #include <utilities/SecCFRelease.h>
34 #include <utilities/SecXPCError.h>
36 #include <utilities/SecCFError.h>
37 #include <utilities/der_set.h>
38 #include <Security/SecureObjectSync/SOSInternal.h>
40 #include <Security/SecureObjectSync/SOSPeerInfo.h>
41 #include <Security/SecureObjectSync/SOSPeerInfoV2.h>
42 #include <Security/SecureObjectSync/SOSPeerInfoPriv.h>
43 #include <Security/SecureObjectSync/SOSCloudCircle.h>
44 #include <Security/SecureObjectSync/SOSAccount.h>
45 #include <Security/SecureObjectSync/SOSAccountPriv.h>
47 CFStringRef viewMemError
= CFSTR("Failed to get memory for views in PeerInfo");
48 CFStringRef viewUnknownError
= CFSTR("Unknown view(%@) (ViewResultCode=%d)");
49 CFStringRef viewInvalidError
= CFSTR("Peer is invalid for this view(%@) (ViewResultCode=%d)");
52 const CFStringRef kSOSViewKeychainV0_tomb
= CFSTR("KeychainV0-tomb"); // iCloud Keychain backup for v0 peers (no tombstones)
53 const CFStringRef kSOSViewBackupBagV0_tomb
= CFSTR("BackupBagV0-tomb"); // iCloud Keychain backup bag for v0 peers (no tombstones)
54 const CFStringRef kSOSViewWiFi_tomb
= CFSTR("WiFi-tomb");
55 const CFStringRef kSOSViewAutofillPasswords_tomb
= CFSTR("Passwords-tomb");
56 const CFStringRef kSOSViewSafariCreditCards_tomb
= CFSTR("CreditCards-tomb");
57 const CFStringRef kSOSViewiCloudIdentity_tomb
= CFSTR("iCloudIdentity-tomb");
58 const CFStringRef kSOSViewOtherSyncable_tomb
= CFSTR("OtherSyncable-tomb");
61 const CFStringRef kSOSViewKeychainV0
= CFSTR("KeychainV0"); // iCloud Keychain syncing for v0 peers
63 const CFStringRef kSOSViewWiFi
= CFSTR("WiFi");
64 const CFStringRef kSOSViewAutofillPasswords
= CFSTR("Passwords");
65 const CFStringRef kSOSViewSafariCreditCards
= CFSTR("CreditCards");
66 const CFStringRef kSOSViewiCloudIdentity
= CFSTR("iCloudIdentity");
67 const CFStringRef kSOSViewBackupBagV0
= CFSTR("BackupBagV0"); // iCloud Keychain backup bag for v0 peers (single item)
68 const CFStringRef kSOSViewOtherSyncable
= CFSTR("OtherSyncable");
70 // PCS (Protected Cloud Storage) Views
71 const CFStringRef kSOSViewPCSMasterKey
= CFSTR("PCS-MasterKey");
72 const CFStringRef kSOSViewPCSiCloudDrive
= CFSTR("PCS-iCloudDrive"); // Bladerunner
73 const CFStringRef kSOSViewPCSPhotos
= CFSTR("PCS-Photos"); // Hyperion
74 const CFStringRef kSOSViewPCSCloudKit
= CFSTR("PCS-CloudKit"); // Liverpool
75 const CFStringRef kSOSViewPCSEscrow
= CFSTR("PCS-Escrow");
76 const CFStringRef kSOSViewPCSFDE
= CFSTR("PCS-FDE");
77 const CFStringRef kSOSViewPCSMailDrop
= CFSTR("PCS-Maildrop"); // PianoMover
78 const CFStringRef kSOSViewPCSiCloudBackup
= CFSTR("PCS-Backup");
79 const CFStringRef kSOSViewPCSNotes
= CFSTR("PCS-Notes");
80 const CFStringRef kSOSViewPCSiMessage
= CFSTR("PCS-iMessage");
81 const CFStringRef kSOSViewPCSFeldspar
= CFSTR("PCS-Feldspar");
83 const CFStringRef kSOSViewAppleTV
= CFSTR("AppleTV");
84 const CFStringRef kSOSViewHomeKit
= CFSTR("HomeKit");
87 // Note that by definition, there cannot be a V0 view hint
88 // These will be deprecated for new constants found in SecItemPriv.h
89 const CFStringRef kSOSViewHintPCSMasterKey
= CFSTR("PCS-MasterKey");
90 const CFStringRef kSOSViewHintPCSiCloudDrive
= CFSTR("PCS-iCloudDrive");
91 const CFStringRef kSOSViewHintPCSPhotos
= CFSTR("PCS-Photos");
92 const CFStringRef kSOSViewHintPCSCloudKit
= CFSTR("PCS-CloudKit");
93 const CFStringRef kSOSViewHintPCSEscrow
= CFSTR("PCS-Escrow");
94 const CFStringRef kSOSViewHintPCSFDE
= CFSTR("PCS-FDE");
95 const CFStringRef kSOSViewHintPCSMailDrop
= CFSTR("PCS-Maildrop");
96 const CFStringRef kSOSViewHintPCSiCloudBackup
= CFSTR("PCS-Backup");
97 const CFStringRef kSOSViewHintPCSNotes
= CFSTR("PCS-Notes");
98 const CFStringRef kSOSViewHintPCSiMessage
= CFSTR("PCS-iMessage");
99 const CFStringRef kSOSViewHintPCSFeldspar
= CFSTR("PCS-Feldspar");
101 const CFStringRef kSOSViewHintAppleTV
= CFSTR("AppleTV");
102 const CFStringRef kSOSViewHintHomeKit
= CFSTR("HomeKit");
104 CFGiblisGetSingleton(CFSetRef
, SOSViewsGetV0ViewSet
, defaultViewSet
, ^{
105 // Since peer->views must never be NULL, fill in with a default
106 const void *values
[] = { kSOSViewKeychainV0
};
107 *defaultViewSet
= CFSetCreate(kCFAllocatorDefault
, values
, array_size(values
), &kCFTypeSetCallBacks
);
110 CFGiblisGetSingleton(CFSetRef
, SOSViewsGetV0SubviewSet
, subViewSet
, (^{
111 // Since peer->views must never be NULL, fill in with a default
112 const void *values
[] = { kSOSViewWiFi
, kSOSViewAutofillPasswords
, kSOSViewSafariCreditCards
,
113 kSOSViewiCloudIdentity
, kSOSViewBackupBagV0
, kSOSViewOtherSyncable
};
114 *subViewSet
= CFSetCreate(kCFAllocatorDefault
, values
, array_size(values
), &kCFTypeSetCallBacks
);
117 CFGiblisGetSingleton(CFSetRef
, SOSViewsGetV0BackupViewSet
, defaultViewSet
, ^{
118 const void *values
[] = { kSOSViewKeychainV0_tomb
};
119 *defaultViewSet
= CFSetCreate(kCFAllocatorDefault
, values
, array_size(values
), &kCFTypeSetCallBacks
);
122 CFGiblisGetSingleton(CFSetRef
, SOSViewsGetV0BackupBagViewSet
, defaultViewSet
, ^{
123 const void *values
[] = { kSOSViewBackupBagV0_tomb
};
124 *defaultViewSet
= CFSetCreate(kCFAllocatorDefault
, values
, array_size(values
), &kCFTypeSetCallBacks
);
127 bool SOSViewsIsV0Subview(CFStringRef viewName
) {
128 return CFSetContainsValue(SOSViewsGetV0BackupViewSet(), viewName
);
131 CFSetRef sTestViewSet
= NULL
;
132 void SOSViewsSetTestViewsSet(CFSetRef testViewNames
) {
133 CFRetainAssign(sTestViewSet
, testViewNames
);
136 CFSetRef
SOSViewsGetAllCurrent(void) {
137 static dispatch_once_t dot
;
138 static CFMutableSetRef allViews
= NULL
;
139 dispatch_once(&dot
, ^{
140 allViews
= CFSetCreateMutableForCFTypes(kCFAllocatorDefault
);
141 CFSetAddValue(allViews
, kSOSViewKeychainV0
);
142 CFSetAddValue(allViews
, kSOSViewPCSMasterKey
);
143 CFSetAddValue(allViews
, kSOSViewPCSiCloudDrive
);
144 CFSetAddValue(allViews
, kSOSViewPCSPhotos
);
145 CFSetAddValue(allViews
, kSOSViewPCSCloudKit
);
146 CFSetAddValue(allViews
, kSOSViewPCSEscrow
);
147 CFSetAddValue(allViews
, kSOSViewPCSFDE
);
148 CFSetAddValue(allViews
, kSOSViewPCSMailDrop
);
149 CFSetAddValue(allViews
, kSOSViewPCSiCloudBackup
);
150 CFSetAddValue(allViews
, kSOSViewPCSNotes
);
151 CFSetAddValue(allViews
, kSOSViewPCSiMessage
);
152 CFSetAddValue(allViews
, kSOSViewPCSFeldspar
);
153 CFSetAddValue(allViews
, kSOSViewAppleTV
);
154 CFSetAddValue(allViews
, kSOSViewHomeKit
);
155 CFSetAddValue(allViews
, kSOSViewWiFi
);
156 CFSetAddValue(allViews
, kSOSViewAutofillPasswords
);
157 CFSetAddValue(allViews
, kSOSViewSafariCreditCards
);
158 CFSetAddValue(allViews
, kSOSViewiCloudIdentity
);
159 CFSetAddValue(allViews
, kSOSViewBackupBagV0
);
160 CFSetAddValue(allViews
, kSOSViewOtherSyncable
);
162 return sTestViewSet
? sTestViewSet
: allViews
;
165 static CFMutableSetRef
CFSetCreateMutableCopyForSOSViews(CFAllocatorRef allocator
, CFSetRef original
) {
166 if(!original
) return NULL
;
167 return CFSetCreateMutableCopy(allocator
, 0, original
);
170 CFMutableSetRef
SOSViewsCreateDefault(bool includeLegacy
, CFErrorRef
*error
) {
171 CFMutableSetRef result
= CFSetCreateMutableCopyForSOSViews(NULL
, SOSViewsGetAllCurrent());
173 // We don't by default particiate in V0, actually we don't want
174 // to let folks enable it.
175 CFSetRemoveValue(result
, kSOSViewKeychainV0
);
177 if (!includeLegacy
) {
178 // We don't by default participate in fractures of iCloudKeychain
179 CFSetRemoveValue(result
, kSOSViewWiFi
);
180 CFSetRemoveValue(result
, kSOSViewAutofillPasswords
);
181 CFSetRemoveValue(result
, kSOSViewSafariCreditCards
);
182 CFSetRemoveValue(result
, kSOSViewOtherSyncable
);
188 // Eventually this will want to know the gestalt or security properties...
189 void SOSViewsForEachDefaultEnabledViewName(void (^operation
)(CFStringRef viewName
)) {
190 CFMutableSetRef defaultViews
= SOSViewsCreateDefault(false, NULL
);
192 CFSetForEach(defaultViews
, ^(const void *value
) {
193 CFStringRef name
= asString(value
, NULL
);
200 CFReleaseNull(defaultViews
);
203 static bool SOSViewsIsKnownView(CFStringRef viewname
) {
204 CFSetRef allViews
= SOSViewsGetAllCurrent();
205 if(CFSetContainsValue(allViews
, viewname
)) return true;
206 secnotice("views","Not a known view");
210 bool SOSPeerInfoIsEnabledView(SOSPeerInfoRef pi
, CFStringRef viewName
) {
211 if (pi
->version
< kSOSPeerV2BaseVersion
) {
212 return CFSetContainsValue(SOSViewsGetV0ViewSet(), viewName
);
214 return SOSPeerInfoV2DictionaryHasSetContaining(pi
, sViewsKey
, viewName
);
218 void SOSPeerInfoWithEnabledViewSet(SOSPeerInfoRef pi
, void (^operation
)(CFSetRef enabled
)) {
219 if (pi
->version
< kSOSPeerV2BaseVersion
) {
220 operation(SOSViewsGetV0ViewSet());
222 SOSPeerInfoV2DictionaryWithSet(pi
, sViewsKey
, operation
);
226 CFMutableSetRef
SOSPeerInfoCopyEnabledViews(SOSPeerInfoRef pi
) {
227 if (pi
->version
< kSOSPeerV2BaseVersion
) {
228 return CFSetCreateMutableCopy(kCFAllocatorDefault
, CFSetGetCount(SOSViewsGetV0ViewSet()), SOSViewsGetV0ViewSet());
230 CFMutableSetRef views
= SOSPeerInfoV2DictionaryCopySet(pi
, sViewsKey
);
232 // This is unexpected: log and return an empty set to prevent <rdar://problem/21938868>
233 secerror("%@ v2 peer has no views", SOSPeerInfoGetPeerID(pi
));
234 views
= CFSetCreateMutableForCFTypes(kCFAllocatorDefault
);
240 CFSetRef
SOSPeerInfoGetPermittedViews(SOSPeerInfoRef pi
) {
241 return SOSViewsGetAllCurrent();
244 static void SOSPeerInfoSetViews(SOSPeerInfoRef pi
, CFSetRef newviews
) {
246 secnotice("views","Asked to swap to NULL views");
249 SOSPeerInfoV2DictionarySetValue(pi
, sViewsKey
, newviews
);
252 static bool SOSPeerInfoViewIsValid(SOSPeerInfoRef pi
, CFStringRef viewname
) {
256 static bool viewErrorReport(CFIndex errorCode
, CFErrorRef
*error
, CFStringRef format
, CFStringRef viewname
, int retval
) {
257 return SOSCreateErrorWithFormat(errorCode
, NULL
, error
, NULL
, format
, viewname
, retval
);
260 SOSViewResultCode
SOSViewsEnable(SOSPeerInfoRef pi
, CFStringRef viewname
, CFErrorRef
*error
) {
261 SOSViewResultCode retval
= kSOSCCGeneralViewError
;
263 CFMutableSetRef newviews
= SOSPeerInfoCopyEnabledViews(pi
);
264 require_action_quiet(newviews
, fail
,
265 SOSCreateError(kSOSErrorAllocationFailure
, viewMemError
, NULL
, error
));
266 require_action_quiet(SOSViewsIsKnownView(viewname
), fail
,
267 viewErrorReport(kSOSErrorNameMismatch
, error
, viewUnknownError
, viewname
, retval
= kSOSCCNoSuchView
));
268 require_action_quiet(SOSPeerInfoViewIsValid(pi
, viewname
), fail
,
269 viewErrorReport(kSOSErrorNameMismatch
, error
, viewInvalidError
, viewname
, retval
= kSOSCCViewNotQualified
));
270 CFSetAddValue(newviews
, viewname
);
271 SOSPeerInfoSetViews(pi
, newviews
);
272 CFReleaseSafe(newviews
);
273 return kSOSCCViewMember
;
276 CFReleaseNull(newviews
);
277 secnotice("views","Failed to enable view(%@): %@", viewname
, *error
);
281 bool SOSViewSetEnable(SOSPeerInfoRef pi
, CFSetRef viewSet
) {
282 __block
bool retval
= true;
283 __block
bool addedView
= false;
284 CFMutableSetRef newviews
= SOSPeerInfoCopyEnabledViews(pi
);
285 require_action_quiet(newviews
, errOut
, secnotice("views", "failed to copy enabled views"));
287 CFSetForEach(viewSet
, ^(const void *value
) {
288 CFStringRef viewName
= (CFStringRef
) value
;
289 if(SOSViewsIsKnownView(viewName
) && SOSPeerInfoViewIsValid(pi
, viewName
) && !CFSetContainsValue(newviews
, viewName
)) {
291 CFSetAddValue(newviews
, viewName
);
294 secnotice("views", "couldn't add view %@", viewName
);
297 require_quiet(retval
, errOut
);
300 SOSPeerInfoSetViews(pi
, newviews
);
304 CFReleaseNull(newviews
);
309 SOSViewResultCode
SOSViewsDisable(SOSPeerInfoRef pi
, CFStringRef viewname
, CFErrorRef
*error
) {
310 SOSViewResultCode retval
= kSOSCCGeneralViewError
;
311 CFMutableSetRef newviews
= SOSPeerInfoCopyEnabledViews(pi
);
312 require_action_quiet(newviews
, fail
,
313 SOSCreateError(kSOSErrorAllocationFailure
, viewMemError
, NULL
, error
));
314 require_action_quiet(SOSViewsIsKnownView(viewname
), fail
,
315 viewErrorReport(kSOSErrorNameMismatch
, error
, viewUnknownError
, viewname
, retval
= kSOSCCNoSuchView
));
317 CFSetRemoveValue(newviews
, viewname
);
318 SOSPeerInfoSetViews(pi
, newviews
);
319 CFReleaseSafe(newviews
);
320 return kSOSCCViewNotMember
;
323 CFReleaseNull(newviews
);
324 secnotice("views","Failed to disable view(%@): %@", viewname
, *error
);
329 bool SOSViewSetDisable(SOSPeerInfoRef pi
, CFSetRef viewSet
) {
330 __block
bool retval
= true;
331 __block
bool removed
= false;
332 CFMutableSetRef newviews
= SOSPeerInfoCopyEnabledViews(pi
);
333 require_action_quiet(newviews
, errOut
, secnotice("views", "failed to copy enabled views"));
335 CFSetForEach(viewSet
, ^(const void *value
) {
336 CFStringRef viewName
= (CFStringRef
) value
;
337 if(SOSViewsIsKnownView(viewName
) && CFSetContainsValue(newviews
, viewName
)) {
339 CFSetRemoveValue(newviews
, viewName
);
342 secnotice("views", "couldn't delete view %@", viewName
);
346 require_quiet(retval
, errOut
);
349 SOSPeerInfoSetViews(pi
, newviews
);
353 CFReleaseNull(newviews
);
358 SOSViewResultCode
SOSViewsQuery(SOSPeerInfoRef pi
, CFStringRef viewname
, CFErrorRef
*error
) {
359 SOSViewResultCode retval
= kSOSCCNoSuchView
;
360 CFSetRef views
= NULL
;
361 secnotice("views", "Querying %@", viewname
);
362 require_action_quiet(SOSViewsIsKnownView(viewname
), fail
,
363 SOSCreateError(kSOSErrorNameMismatch
, viewUnknownError
, NULL
, error
));
364 views
= SOSPeerInfoCopyEnabledViews(pi
);
366 retval
= kSOSCCViewNotMember
;
367 CFReleaseNull(views
);
370 retval
= (CFSetContainsValue(views
, viewname
)) ? kSOSCCViewMember
: kSOSCCViewNotMember
;
371 CFReleaseNull(views
);
375 secnotice("views","Failed to query view(%@): %@", viewname
, *error
);
376 CFReleaseNull(views
);
380 static CFArrayRef
SOSCreateActiveViewIntersectionArrayForPeerInfos(SOSPeerInfoRef pi1
, SOSPeerInfoRef pi2
) {
381 CFMutableArrayRef retval
= NULL
;
382 CFSetRef views1
= SOSPeerInfoCopyEnabledViews(pi1
);
383 CFSetRef views2
= SOSPeerInfoCopyEnabledViews(pi2
);
384 size_t count
= CFSetGetCount(views1
);
386 CFReleaseNull(views1
);
387 CFReleaseNull(views2
);
390 CFStringRef pi1views
[count
];
392 retval
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
393 CFSetGetValues(views1
, (const void **) &pi1views
);
394 for(size_t i
= 0; i
< count
; i
++) {
395 if(CFSetContainsValue(views2
, pi1views
[i
])) {
396 CFArrayAppendValue(retval
, pi1views
[i
]);
399 CFReleaseNull(views1
);
400 CFReleaseNull(views2
);
405 CFArrayRef
SOSCreateActiveViewIntersectionArrayForPeerID(SOSAccountRef account
, CFStringRef peerID
) {
406 CFArrayRef retval
= NULL
;
407 SOSPeerInfoRef myPI
= SOSAccountGetMyPeerInfo(account
);
408 SOSPeerInfoRef theirPI
= SOSAccountCopyPeerWithID(account
, peerID
, NULL
);
409 require_action_quiet(myPI
, errOut
, retval
= NULL
);
410 require_action_quiet(theirPI
, errOut
, retval
= NULL
);
412 retval
= SOSCreateActiveViewIntersectionArrayForPeerInfos(myPI
, theirPI
);
415 CFReleaseNull(theirPI
);
419 // This needs to create a dictionary of sets of intersected views for an account
420 CFDictionaryRef
SOSViewsCreateActiveViewMatrixDictionary(SOSAccountRef account
, SOSCircleRef circle
, CFErrorRef
*error
) {
421 CFMutableDictionaryRef retval
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
422 SOSPeerInfoRef myPI
= SOSAccountGetMyPeerInfo(account
);
424 // For now, all views require that a valid member peer is in the circle and active/valid
425 CFMutableSetRef peers
= SOSCircleCopyPeers(circle
, kCFAllocatorDefault
);
427 require_action_quiet(retval
, errOut
, SOSCreateError(kSOSErrorAllocationFailure
, CFSTR("Could not allocate ViewMatrix"), NULL
, error
));
428 require_action_quiet(myPI
, errOut
, SOSCreateError(kSOSErrorPeerNotFound
, CFSTR("Could not find our PeerInfo"), NULL
, error
));
429 require(peers
, errOut
);
431 CFSetRef myViews
= SOSPeerInfoCopyEnabledViews(myPI
);
434 CFSetForEach(myViews
, ^(const void *value
) {
435 CFStringRef viewname
= (CFStringRef
) value
;
436 CFMutableSetRef viewset
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
437 CFSetForEach(peers
, ^(const void *peervalue
) {
438 SOSPeerInfoRef pi
= (SOSPeerInfoRef
) peervalue
;
439 CFSetRef piViews
= SOSPeerInfoCopyEnabledViews(pi
);
441 if(piViews
&& CFSetContainsValue(piViews
, viewname
)) {
442 CFStringRef peerID
= SOSPeerInfoGetPeerID(pi
);
443 CFSetAddValue(viewset
, peerID
);
445 CFReleaseNull(piViews
);
448 CFDictionaryAddValue(retval
, viewname
, viewset
);
451 if(CFDictionaryGetCount(retval
) == 0) goto errOut
; // Not really an error - just no intersection of views with anyone
452 CFReleaseNull(peers
);
453 CFReleaseNull(myViews
);
457 CFReleaseNull(retval
);
458 CFReleaseNull(peers
);
466 /* Need XPC way to carry CFSets of views */
469 CFSetRef
CreateCFSetRefFromXPCObject(xpc_object_t xpcSetDER
, CFErrorRef
* error
) {
470 CFSetRef retval
= NULL
;
471 require_action_quiet(xpcSetDER
, errOut
, SecCFCreateErrorWithFormat(kSecXPCErrorUnexpectedNull
, sSecXPCErrorDomain
, NULL
, error
, NULL
, CFSTR("Unexpected Null Set to decode")));
473 require_action_quiet(xpc_get_type(xpcSetDER
) == XPC_TYPE_DATA
, errOut
, SecCFCreateErrorWithFormat(kSecXPCErrorUnexpectedType
, sSecXPCErrorDomain
, NULL
, error
, NULL
, CFSTR("xpcSetDER not data, got %@"), xpcSetDER
));
475 const uint8_t* der
= xpc_data_get_bytes_ptr(xpcSetDER
);
476 const uint8_t* der_end
= der
+ xpc_data_get_length(xpcSetDER
);
477 der
= der_decode_set(kCFAllocatorDefault
, kCFPropertyListMutableContainersAndLeaves
, &retval
, error
, der
, der_end
);
478 if (der
!= der_end
) {
479 SecError(errSecDecode
, error
, CFSTR("trailing garbage at end of SecAccessControl data"));
484 CFReleaseNull(retval
);
488 xpc_object_t
CreateXPCObjectWithCFSetRef(CFSetRef setref
, CFErrorRef
*error
) {
489 xpc_object_t result
= NULL
;
490 size_t data_size
= 0;
491 uint8_t *data
= NULL
;
492 require_action_quiet(setref
, errOut
, SecCFCreateErrorWithFormat(kSecXPCErrorUnexpectedNull
, sSecXPCErrorDomain
, NULL
, error
, NULL
, CFSTR("Unexpected Null Set to encode")));
493 require_quiet((data_size
= der_sizeof_set(setref
, error
)) != 0, errOut
);
494 require_quiet((data
= (uint8_t *)malloc(data_size
)) != NULL
, errOut
);
496 der_encode_set(setref
, error
, data
, data
+ data_size
);
497 result
= xpc_data_create(data
, data_size
);