]> git.saurik.com Git - apple/security.git/blob - OSX/sec/SOSCircle/SecureObjectSync/SOSViews.c
Security-57336.1.9.tar.gz
[apple/security.git] / OSX / sec / SOSCircle / SecureObjectSync / SOSViews.c
1 /*
2 * Copyright (c) 2015 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 * SOSViews.c - Implementation of views
26 */
27
28 #include <AssertMacros.h>
29 #include <TargetConditionals.h>
30
31 #include "SOSViews.h"
32 #include <utilities/SecCFWrappers.h>
33 #include <utilities/SecCFRelease.h>
34 #include <utilities/SecXPCError.h>
35
36 #include <utilities/SecCFError.h>
37 #include <utilities/der_set.h>
38 #include <Security/SecureObjectSync/SOSInternal.h>
39
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>
46
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)");
50
51 // Internal Views:
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");
59
60 // Views
61 const CFStringRef kSOSViewKeychainV0 = CFSTR("KeychainV0"); // iCloud Keychain syncing for v0 peers
62
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");
69
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");
82
83 const CFStringRef kSOSViewAppleTV = CFSTR("AppleTV");
84 const CFStringRef kSOSViewHomeKit = CFSTR("HomeKit");
85
86 // View Hints
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");
100
101 const CFStringRef kSOSViewHintAppleTV = CFSTR("AppleTV");
102 const CFStringRef kSOSViewHintHomeKit = CFSTR("HomeKit");
103
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);
108 });
109
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);
115 }));
116
117 CFGiblisGetSingleton(CFSetRef, SOSViewsGetV0BackupViewSet, defaultViewSet, ^{
118 const void *values[] = { kSOSViewKeychainV0_tomb };
119 *defaultViewSet = CFSetCreate(kCFAllocatorDefault, values, array_size(values), &kCFTypeSetCallBacks);
120 });
121
122 CFGiblisGetSingleton(CFSetRef, SOSViewsGetV0BackupBagViewSet, defaultViewSet, ^{
123 const void *values[] = { kSOSViewBackupBagV0_tomb };
124 *defaultViewSet = CFSetCreate(kCFAllocatorDefault, values, array_size(values), &kCFTypeSetCallBacks);
125 });
126
127 bool SOSViewsIsV0Subview(CFStringRef viewName) {
128 return CFSetContainsValue(SOSViewsGetV0BackupViewSet(), viewName);
129 }
130
131 CFSetRef sTestViewSet = NULL;
132 void SOSViewsSetTestViewsSet(CFSetRef testViewNames) {
133 CFRetainAssign(sTestViewSet, testViewNames);
134 }
135
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);
161 });
162 return sTestViewSet ? sTestViewSet : allViews;
163 }
164
165 static CFMutableSetRef CFSetCreateMutableCopyForSOSViews(CFAllocatorRef allocator, CFSetRef original) {
166 if(!original) return NULL;
167 return CFSetCreateMutableCopy(allocator, 0, original);
168 }
169
170 CFMutableSetRef SOSViewsCreateDefault(bool includeLegacy, CFErrorRef *error) {
171 CFMutableSetRef result = CFSetCreateMutableCopyForSOSViews(NULL, SOSViewsGetAllCurrent());
172
173 // We don't by default particiate in V0, actually we don't want
174 // to let folks enable it.
175 CFSetRemoveValue(result, kSOSViewKeychainV0);
176
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);
183 }
184
185 return result;
186 }
187
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);
191
192 CFSetForEach(defaultViews, ^(const void *value) {
193 CFStringRef name = asString(value, NULL);
194
195 if (name) {
196 operation(name);
197 }
198 });
199
200 CFReleaseNull(defaultViews);
201 }
202
203 static bool SOSViewsIsKnownView(CFStringRef viewname) {
204 CFSetRef allViews = SOSViewsGetAllCurrent();
205 if(CFSetContainsValue(allViews, viewname)) return true;
206 secnotice("views","Not a known view");
207 return false;
208 }
209
210 bool SOSPeerInfoIsEnabledView(SOSPeerInfoRef pi, CFStringRef viewName) {
211 if (pi->version < kSOSPeerV2BaseVersion) {
212 return CFSetContainsValue(SOSViewsGetV0ViewSet(), viewName);
213 } else {
214 return SOSPeerInfoV2DictionaryHasSetContaining(pi, sViewsKey, viewName);
215 }
216 }
217
218 void SOSPeerInfoWithEnabledViewSet(SOSPeerInfoRef pi, void (^operation)(CFSetRef enabled)) {
219 if (pi->version < kSOSPeerV2BaseVersion) {
220 operation(SOSViewsGetV0ViewSet());
221 } else {
222 SOSPeerInfoV2DictionaryWithSet(pi, sViewsKey, operation);
223 }
224 }
225
226 CFMutableSetRef SOSPeerInfoCopyEnabledViews(SOSPeerInfoRef pi) {
227 if (pi->version < kSOSPeerV2BaseVersion) {
228 return CFSetCreateMutableCopy(kCFAllocatorDefault, CFSetGetCount(SOSViewsGetV0ViewSet()), SOSViewsGetV0ViewSet());
229 } else {
230 CFMutableSetRef views = SOSPeerInfoV2DictionaryCopySet(pi, sViewsKey);
231 if (!views) {
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);
235 }
236 return views;
237 }
238 }
239
240 CFSetRef SOSPeerInfoGetPermittedViews(SOSPeerInfoRef pi) {
241 return SOSViewsGetAllCurrent();
242 }
243
244 static void SOSPeerInfoSetViews(SOSPeerInfoRef pi, CFSetRef newviews) {
245 if(!newviews) {
246 secnotice("views","Asked to swap to NULL views");
247 return;
248 }
249 SOSPeerInfoV2DictionarySetValue(pi, sViewsKey, newviews);
250 }
251
252 static bool SOSPeerInfoViewIsValid(SOSPeerInfoRef pi, CFStringRef viewname) {
253 return true;
254 }
255
256 static bool viewErrorReport(CFIndex errorCode, CFErrorRef *error, CFStringRef format, CFStringRef viewname, int retval) {
257 return SOSCreateErrorWithFormat(errorCode, NULL, error, NULL, format, viewname, retval);
258 }
259
260 SOSViewResultCode SOSViewsEnable(SOSPeerInfoRef pi, CFStringRef viewname, CFErrorRef *error) {
261 SOSViewResultCode retval = kSOSCCGeneralViewError;
262
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;
274
275 fail:
276 CFReleaseNull(newviews);
277 secnotice("views","Failed to enable view(%@): %@", viewname, *error);
278 return retval;
279 }
280
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"));
286
287 CFSetForEach(viewSet, ^(const void *value) {
288 CFStringRef viewName = (CFStringRef) value;
289 if(SOSViewsIsKnownView(viewName) && SOSPeerInfoViewIsValid(pi, viewName) && !CFSetContainsValue(newviews, viewName)) {
290 addedView = true;
291 CFSetAddValue(newviews, viewName);
292 } else {
293 retval = false;
294 secnotice("views", "couldn't add view %@", viewName);
295 }
296 });
297 require_quiet(retval, errOut);
298
299 if (addedView) {
300 SOSPeerInfoSetViews(pi, newviews);
301 }
302
303 errOut:
304 CFReleaseNull(newviews);
305 return retval;
306 }
307
308
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));
316
317 CFSetRemoveValue(newviews, viewname);
318 SOSPeerInfoSetViews(pi, newviews);
319 CFReleaseSafe(newviews);
320 return kSOSCCViewNotMember;
321
322 fail:
323 CFReleaseNull(newviews);
324 secnotice("views","Failed to disable view(%@): %@", viewname, *error);
325 return retval;
326 }
327
328
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"));
334
335 CFSetForEach(viewSet, ^(const void *value) {
336 CFStringRef viewName = (CFStringRef) value;
337 if(SOSViewsIsKnownView(viewName) && CFSetContainsValue(newviews, viewName)) {
338 removed = true;
339 CFSetRemoveValue(newviews, viewName);
340 } else {
341 retval = false;
342 secnotice("views", "couldn't delete view %@", viewName);
343 }
344 });
345
346 require_quiet(retval, errOut);
347
348 if(removed) {
349 SOSPeerInfoSetViews(pi, newviews);
350 }
351
352 errOut:
353 CFReleaseNull(newviews);
354 return retval;
355 }
356
357
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);
365 if(!views){
366 retval = kSOSCCViewNotMember;
367 CFReleaseNull(views);
368 return retval;
369 }
370 retval = (CFSetContainsValue(views, viewname)) ? kSOSCCViewMember: kSOSCCViewNotMember;
371 CFReleaseNull(views);
372 return retval;
373
374 fail:
375 secnotice("views","Failed to query view(%@): %@", viewname, *error);
376 CFReleaseNull(views);
377 return retval;
378 }
379
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);
385 if(count == 0){
386 CFReleaseNull(views1);
387 CFReleaseNull(views2);
388 return NULL;
389 }
390 CFStringRef pi1views[count];
391
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]);
397 }
398 }
399 CFReleaseNull(views1);
400 CFReleaseNull(views2);
401
402 return retval;
403 }
404
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);
411
412 retval = SOSCreateActiveViewIntersectionArrayForPeerInfos(myPI, theirPI);
413
414 errOut:
415 CFReleaseNull(theirPI);
416 return retval;
417 }
418
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);
423
424 // For now, all views require that a valid member peer is in the circle and active/valid
425 CFMutableSetRef peers = SOSCircleCopyPeers(circle, kCFAllocatorDefault);
426
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);
430
431 CFSetRef myViews = SOSPeerInfoCopyEnabledViews(myPI);
432
433 if (myViews)
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);
440
441 if(piViews && CFSetContainsValue(piViews, viewname)) {
442 CFStringRef peerID = SOSPeerInfoGetPeerID(pi);
443 CFSetAddValue(viewset, peerID);
444 }
445 CFReleaseNull(piViews);
446
447 });
448 CFDictionaryAddValue(retval, viewname, viewset);
449 });
450
451 if(CFDictionaryGetCount(retval) == 0) goto errOut; // Not really an error - just no intersection of views with anyone
452 CFReleaseNull(peers);
453 CFReleaseNull(myViews);
454 return retval;
455
456 errOut:
457 CFReleaseNull(retval);
458 CFReleaseNull(peers);
459 return NULL;
460 }
461
462
463
464
465
466 /* Need XPC way to carry CFSets of views */
467
468
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")));
472
473 require_action_quiet(xpc_get_type(xpcSetDER) == XPC_TYPE_DATA, errOut, SecCFCreateErrorWithFormat(kSecXPCErrorUnexpectedType, sSecXPCErrorDomain, NULL, error, NULL, CFSTR("xpcSetDER not data, got %@"), xpcSetDER));
474
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"));
480 goto errOut;
481 }
482 return retval;
483 errOut:
484 CFReleaseNull(retval);
485 return NULL;
486 }
487
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);
495
496 der_encode_set(setref, error, data, data + data_size);
497 result = xpc_data_create(data, data_size);
498 free(data);
499 errOut:
500 return result;
501 }
502