]> git.saurik.com Git - apple/security.git/blob - OSX/sec/SOSCircle/SecureObjectSync/SOSViews.c
Security-57740.1.18.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 #undef DOVIEWMACRO
64 #define DOVIEWMACRO(VIEWNAME, DEFSTRING, CMDSTRING, DEFAULTSETTING, INITIALSYNCSETTING, ALWAYSONSETTING, BACKUPSETTING, V0SETTING) \
65 const CFStringRef kSOSView##VIEWNAME = CFSTR(DEFSTRING);
66 #include "Security/SecureObjectSync/ViewList.list"
67
68 // View Hints
69 // Note that by definition, there cannot be a V0 view hint
70 // These will be deprecated for new constants found in SecItemPriv.h
71 const CFStringRef kSOSViewHintPCSMasterKey = CFSTR("PCS-MasterKey");
72 const CFStringRef kSOSViewHintPCSiCloudDrive = CFSTR("PCS-iCloudDrive");
73 const CFStringRef kSOSViewHintPCSPhotos = CFSTR("PCS-Photos");
74 const CFStringRef kSOSViewHintPCSCloudKit = CFSTR("PCS-CloudKit");
75 const CFStringRef kSOSViewHintPCSEscrow = CFSTR("PCS-Escrow");
76 const CFStringRef kSOSViewHintPCSFDE = CFSTR("PCS-FDE");
77 const CFStringRef kSOSViewHintPCSMailDrop = CFSTR("PCS-Maildrop");
78 const CFStringRef kSOSViewHintPCSiCloudBackup = CFSTR("PCS-Backup");
79 const CFStringRef kSOSViewHintPCSNotes = CFSTR("PCS-Notes");
80 const CFStringRef kSOSViewHintPCSiMessage = CFSTR("PCS-iMessage");
81 const CFStringRef kSOSViewHintPCSFeldspar = CFSTR("PCS-Feldspar");
82
83 const CFStringRef kSOSViewHintAppleTV = CFSTR("AppleTV");
84 const CFStringRef kSOSViewHintHomeKit = CFSTR("HomeKit");
85
86 CFMutableSetRef SOSViewCopyViewSet(ViewSetKind setKind) {
87 CFMutableSetRef result = CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
88
89 #undef DOVIEWMACRO
90 #define __TYPE_MEMBER_ false
91 #define __TYPE_MEMBER_D true
92 #define __TYPE_MEMBER_I true
93 #define __TYPE_MEMBER_A true
94 #define __TYPE_MEMBER_V true
95 #define __TYPE_MEMBER_B true
96 #define DOVIEWMACRO(VIEWNAME, DEFSTRING, CMDSTRING, DEFAULT, INITIAL, ALWAYSON, BACKUP, V0) \
97 if ((setKind == kViewSetAll) || \
98 ((setKind == kViewSetDefault) && __TYPE_MEMBER_##DEFAULT) || \
99 ((setKind == kViewSetInitial) && __TYPE_MEMBER_##INITIAL) || \
100 ((setKind == kViewSetAlwaysOn) && __TYPE_MEMBER_##ALWAYSON) || \
101 ((setKind == kViewSetRequiredForBackup) && __TYPE_MEMBER_##BACKUP) || \
102 ((setKind == kViewSetV0) && __TYPE_MEMBER_##V0) ) { \
103 CFSetAddValue(result, kSOSView##VIEWNAME); \
104 }
105
106 #include "Security/SecureObjectSync/ViewList.list"
107
108 return result;
109 }
110
111 CFGiblisGetSingleton(CFSetRef, SOSViewsGetV0ViewSet, defaultViewSet, ^{
112 // Since peer->views must never be NULL, fill in with a default
113 const void *values[] = { kSOSViewKeychainV0 };
114 *defaultViewSet = CFSetCreate(kCFAllocatorDefault, values, array_size(values), &kCFTypeSetCallBacks);
115 });
116
117 CFGiblisGetSingleton(CFSetRef, SOSViewsGetV0SubviewSet, subViewSet, (^{
118 // Since peer->views must never be NULL, fill in with a default
119 *subViewSet = SOSViewCopyViewSet(kViewSetV0);
120 }));
121
122 CFGiblisGetSingleton(CFSetRef, SOSViewsGetV0BackupViewSet, defaultViewSet, ^{
123 const void *values[] = { kSOSViewKeychainV0_tomb };
124 *defaultViewSet = CFSetCreate(kCFAllocatorDefault, values, array_size(values), &kCFTypeSetCallBacks);
125 });
126
127 CFGiblisGetSingleton(CFSetRef, SOSViewsGetV0BackupBagViewSet, defaultViewSet, ^{
128 const void *values[] = { kSOSViewBackupBagV0_tomb };
129 *defaultViewSet = CFSetCreate(kCFAllocatorDefault, values, array_size(values), &kCFTypeSetCallBacks);
130 });
131
132
133 CFGiblisGetSingleton(CFSetRef, SOSViewsGetInitialSyncSubviewSet, subViewSet, (^{
134 *subViewSet = SOSViewCopyViewSet(kViewSetInitial);
135 }));
136
137
138 bool SOSViewsIsV0Subview(CFStringRef viewName) {
139 return CFSetContainsValue(SOSViewsGetV0SubviewSet(), viewName);
140 }
141
142 CFSetRef sTestViewSet = NULL;
143 void SOSViewsSetTestViewsSet(CFSetRef testViewNames) {
144 CFRetainAssign(sTestViewSet, testViewNames);
145 }
146
147 CFSetRef SOSViewsGetAllCurrent(void) {
148 static dispatch_once_t dot;
149 static CFMutableSetRef allViews = NULL;
150 dispatch_once(&dot, ^{
151 allViews = SOSViewCopyViewSet(kViewSetAll);
152
153 CFSetAddValue(allViews, kSOSViewKeychainV0);
154 if(sTestViewSet) CFSetUnion(allViews, sTestViewSet);
155 });
156 return allViews;
157 }
158
159 const char *SOSViewsXlateAction(SOSViewActionCode action) {
160 switch(action) {
161 case kSOSCCViewEnable: return "kSOSCCViewEnable";
162 case kSOSCCViewDisable: return "kSOSCCViewDisable";
163 case kSOSCCViewQuery: return "kSOSCCViewQuery";
164 default: return "unknownViewAction";
165 }
166 }
167
168
169 // Eventually this will want to know the gestalt or security properties...
170 void SOSViewsForEachDefaultEnabledViewName(void (^operation)(CFStringRef viewName)) {
171 CFMutableSetRef defaultViews = SOSViewCopyViewSet(kViewSetDefault);
172
173 CFSetForEach(defaultViews, ^(const void *value) {
174 CFStringRef name = asString(value, NULL);
175
176 if (name) {
177 operation(name);
178 }
179 });
180
181 CFReleaseNull(defaultViews);
182 }
183
184 static bool SOSViewsIsKnownView(CFStringRef viewname) {
185 CFSetRef allViews = SOSViewsGetAllCurrent();
186 if(CFSetContainsValue(allViews, viewname)) return true;
187 secnotice("views","Not a known view");
188 return false;
189 }
190
191 static bool viewErrorReport(CFIndex errorCode, CFErrorRef *error, CFStringRef format, CFStringRef viewname, int retval) {
192 return SOSCreateErrorWithFormat(errorCode, NULL, error, NULL, format, viewname, retval);
193 }
194
195 static bool SOSViewsRequireIsKnownView(CFStringRef viewname, CFErrorRef* error) {
196 return SOSViewsIsKnownView(viewname) || viewErrorReport(kSOSErrorNameMismatch, error, viewUnknownError, viewname, kSOSCCNoSuchView);
197 }
198
199 bool SOSPeerInfoIsEnabledView(SOSPeerInfoRef pi, CFStringRef viewName) {
200 if (pi->version < kSOSPeerV2BaseVersion) {
201 return CFSetContainsValue(SOSViewsGetV0ViewSet(), viewName);
202 } else {
203 return SOSPeerInfoV2DictionaryHasSetContaining(pi, sViewsKey, viewName);
204 }
205 }
206
207 void SOSPeerInfoWithEnabledViewSet(SOSPeerInfoRef pi, void (^operation)(CFSetRef enabled)) {
208 if (pi->version < kSOSPeerV2BaseVersion) {
209 operation(SOSViewsGetV0ViewSet());
210 } else {
211 SOSPeerInfoV2DictionaryWithSet(pi, sViewsKey, operation);
212 }
213 }
214
215 CFMutableSetRef SOSPeerInfoCopyEnabledViews(SOSPeerInfoRef pi) {
216 if (pi->version < kSOSPeerV2BaseVersion) {
217 return CFSetCreateMutableCopy(kCFAllocatorDefault, CFSetGetCount(SOSViewsGetV0ViewSet()), SOSViewsGetV0ViewSet());
218 } else {
219 CFMutableSetRef views = SOSPeerInfoV2DictionaryCopySet(pi, sViewsKey);
220 if (!views) {
221 // This is unexpected: log and return an empty set to prevent <rdar://problem/21938868>
222 secerror("%@ v2 peer has no views", SOSPeerInfoGetPeerID(pi));
223 views = CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
224 }
225 return views;
226 }
227 }
228
229 CFSetRef SOSPeerInfoGetPermittedViews(SOSPeerInfoRef pi) {
230 return SOSViewsGetAllCurrent();
231 }
232
233 static void SOSPeerInfoSetViews(SOSPeerInfoRef pi, CFSetRef newviews) {
234 if(!newviews) {
235 secnotice("views","Asked to swap to NULL views");
236 return;
237 }
238 SOSPeerInfoV2DictionarySetValue(pi, sViewsKey, newviews);
239 }
240
241 static bool SOSPeerInfoViewIsValid(SOSPeerInfoRef pi, CFStringRef viewname) {
242 return true;
243 }
244
245 SOSViewResultCode SOSViewsEnable(SOSPeerInfoRef pi, CFStringRef viewname, CFErrorRef *error) {
246 SOSViewResultCode retval = kSOSCCGeneralViewError;
247
248 CFMutableSetRef newviews = SOSPeerInfoCopyEnabledViews(pi);
249 require_action_quiet(newviews, fail,
250 SOSCreateError(kSOSErrorAllocationFailure, viewMemError, NULL, error));
251 require_action_quiet(SOSViewsRequireIsKnownView(viewname, error), fail,
252 retval = kSOSCCNoSuchView);
253 require_action_quiet(SOSPeerInfoViewIsValid(pi, viewname), fail,
254 viewErrorReport(kSOSErrorNameMismatch, error, viewInvalidError, viewname, retval = kSOSCCViewNotQualified));
255 CFSetAddValue(newviews, viewname);
256 SOSPeerInfoSetViews(pi, newviews);
257 CFReleaseSafe(newviews);
258 return kSOSCCViewMember;
259
260 fail:
261 CFReleaseNull(newviews);
262 secnotice("views","Failed to enable view(%@): %@", viewname, error ? *error : NULL);
263 return retval;
264 }
265
266 bool SOSViewSetEnable(SOSPeerInfoRef pi, CFSetRef viewSet) {
267 __block bool addedView = false;
268 CFMutableSetRef newviews = SOSPeerInfoCopyEnabledViews(pi);
269 require_action_quiet(newviews, errOut, secnotice("views", "failed to copy enabled views"));
270
271 CFSetForEach(viewSet, ^(const void *value) {
272 CFStringRef viewName = (CFStringRef) value;
273 if(SOSViewsIsKnownView(viewName) && SOSPeerInfoViewIsValid(pi, viewName)) {
274 if (!CFSetContainsValue(newviews, viewName)) {
275 addedView = true;
276 CFSetAddValue(newviews, viewName);
277 }
278 } else {
279 secnotice("views", "couldn't add view %@", viewName);
280 }
281 });
282 require_quiet(addedView, errOut);
283
284 SOSPeerInfoSetViews(pi, newviews);
285
286 errOut:
287 CFReleaseNull(newviews);
288 return addedView;
289 }
290
291
292 SOSViewResultCode SOSViewsDisable(SOSPeerInfoRef pi, CFStringRef viewname, CFErrorRef *error) {
293 SOSViewResultCode retval = kSOSCCGeneralViewError;
294 CFMutableSetRef newviews = SOSPeerInfoCopyEnabledViews(pi);
295 require_action_quiet(newviews, fail,
296 SOSCreateError(kSOSErrorAllocationFailure, viewMemError, NULL, error));
297 require_action_quiet(SOSViewsRequireIsKnownView(viewname, error), fail, retval = kSOSCCNoSuchView);
298
299 CFSetRemoveValue(newviews, viewname);
300 SOSPeerInfoSetViews(pi, newviews);
301 CFReleaseSafe(newviews);
302 return kSOSCCViewNotMember;
303
304 fail:
305 CFReleaseNull(newviews);
306 secnotice("views","Failed to disable view(%@): %@", viewname, error ? *error : NULL);
307 return retval;
308 }
309
310
311 bool SOSViewSetDisable(SOSPeerInfoRef pi, CFSetRef viewSet) {
312 __block bool removed = false;
313 CFMutableSetRef newviews = SOSPeerInfoCopyEnabledViews(pi);
314 require_action_quiet(newviews, errOut, secnotice("views", "failed to copy enabled views"));
315
316 CFSetForEach(viewSet, ^(const void *value) {
317 CFStringRef viewName = (CFStringRef) value;
318 if(SOSViewsIsKnownView(viewName) && CFSetContainsValue(newviews, viewName)) {
319 removed = true;
320 CFSetRemoveValue(newviews, viewName);
321 } else {
322 secnotice("views", "couldn't delete view %@", viewName);
323 }
324 });
325
326 require_quiet(removed, errOut);
327
328 SOSPeerInfoSetViews(pi, newviews);
329
330 errOut:
331 CFReleaseNull(newviews);
332 return removed;
333 }
334
335
336 SOSViewResultCode SOSViewsQuery(SOSPeerInfoRef pi, CFStringRef viewname, CFErrorRef *error) {
337 SOSViewResultCode retval = kSOSCCNoSuchView;
338 CFSetRef views = NULL;
339 require_quiet(SOSViewsRequireIsKnownView(viewname, error), fail);
340
341 views = SOSPeerInfoCopyEnabledViews(pi);
342 if(!views){
343 retval = kSOSCCViewNotMember;
344 CFReleaseNull(views);
345 return retval;
346 }
347
348 // kSOSViewKeychainV0 is set if there is a V0 PeerInfo in the circle. It represents all of the subviews in
349 // SOSViewsGetV0SubviewSet() so we return kSOSCCViewMember for that case. kSOSViewKeychainV0 and the subviews
350 // are mutually exclusive.
351 else if(CFSetContainsValue(views, kSOSViewKeychainV0) && CFSetContainsValue(SOSViewsGetV0SubviewSet(), viewname)) {
352 retval = kSOSCCViewMember;
353 } else {
354 retval = (CFSetContainsValue(views, viewname)) ? kSOSCCViewMember: kSOSCCViewNotMember;
355 }
356
357 CFReleaseNull(views);
358 return retval;
359
360 fail:
361 secnotice("views","Failed to query view(%@): %@", viewname, error ? *error : NULL);
362 CFReleaseNull(views);
363 return retval;
364 }
365
366 static CFArrayRef SOSCreateActiveViewIntersectionArrayForPeerInfos(SOSPeerInfoRef pi1, SOSPeerInfoRef pi2) {
367 CFMutableArrayRef retval = NULL;
368 CFSetRef views1 = SOSPeerInfoCopyEnabledViews(pi1);
369 CFSetRef views2 = SOSPeerInfoCopyEnabledViews(pi2);
370 size_t count = CFSetGetCount(views1);
371 if(count == 0){
372 CFReleaseNull(views1);
373 CFReleaseNull(views2);
374 return NULL;
375 }
376 CFStringRef pi1views[count];
377
378 retval = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
379 CFSetGetValues(views1, (const void **) &pi1views);
380 for(size_t i = 0; i < count; i++) {
381 if(CFSetContainsValue(views2, pi1views[i])) {
382 CFArrayAppendValue(retval, pi1views[i]);
383 }
384 }
385 CFReleaseNull(views1);
386 CFReleaseNull(views2);
387
388 return retval;
389 }
390
391 CFArrayRef SOSCreateActiveViewIntersectionArrayForPeerID(SOSAccountRef account, CFStringRef peerID) {
392 CFArrayRef retval = NULL;
393 SOSPeerInfoRef myPI = SOSAccountGetMyPeerInfo(account);
394 SOSPeerInfoRef theirPI = SOSAccountCopyPeerWithID(account, peerID, NULL);
395 require_action_quiet(myPI, errOut, retval = NULL);
396 require_action_quiet(theirPI, errOut, retval = NULL);
397
398 retval = SOSCreateActiveViewIntersectionArrayForPeerInfos(myPI, theirPI);
399
400 errOut:
401 CFReleaseNull(theirPI);
402 return retval;
403 }
404
405 // This needs to create a dictionary of sets of intersected views for an account
406 CFDictionaryRef SOSViewsCreateActiveViewMatrixDictionary(SOSAccountRef account, SOSCircleRef circle, CFErrorRef *error) {
407 CFMutableDictionaryRef retval = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
408 SOSPeerInfoRef myPI = SOSAccountGetMyPeerInfo(account);
409
410 // For now, all views require that a valid member peer is in the circle and active/valid
411 CFMutableSetRef peers = SOSCircleCopyPeers(circle, kCFAllocatorDefault);
412
413 require_action_quiet(retval, errOut, SOSCreateError(kSOSErrorAllocationFailure, CFSTR("Could not allocate ViewMatrix"), NULL, error));
414 require_action_quiet(myPI, errOut, SOSCreateError(kSOSErrorPeerNotFound, CFSTR("Could not find our PeerInfo"), NULL, error));
415 require(peers, errOut);
416
417 CFSetRef myViews = SOSPeerInfoCopyEnabledViews(myPI);
418
419 if (myViews)
420 CFSetForEach(myViews, ^(const void *value) {
421 CFStringRef viewname = (CFStringRef) value;
422 CFMutableSetRef viewset = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
423 CFSetForEach(peers, ^(const void *peervalue) {
424 SOSPeerInfoRef pi = (SOSPeerInfoRef) peervalue;
425 CFSetRef piViews = SOSPeerInfoCopyEnabledViews(pi);
426
427 if(piViews && CFSetContainsValue(piViews, viewname)) {
428 CFStringRef peerID = SOSPeerInfoGetPeerID(pi);
429 CFSetAddValue(viewset, peerID);
430 }
431 CFReleaseNull(piViews);
432
433 });
434 CFDictionaryAddValue(retval, viewname, viewset);
435 });
436
437 if(CFDictionaryGetCount(retval) == 0) goto errOut; // Not really an error - just no intersection of views with anyone
438 CFReleaseNull(peers);
439 CFReleaseNull(myViews);
440 return retval;
441
442 errOut:
443 CFReleaseNull(retval);
444 CFReleaseNull(peers);
445 return NULL;
446 }
447
448
449
450
451
452 /* Need XPC way to carry CFSets of views */
453
454
455 CFSetRef CreateCFSetRefFromXPCObject(xpc_object_t xpcSetDER, CFErrorRef* error) {
456 CFSetRef retval = NULL;
457 require_action_quiet(xpcSetDER, errOut, SecCFCreateErrorWithFormat(kSecXPCErrorUnexpectedNull, sSecXPCErrorDomain, NULL, error, NULL, CFSTR("Unexpected Null Set to decode")));
458
459 require_action_quiet(xpc_get_type(xpcSetDER) == XPC_TYPE_DATA, errOut, SecCFCreateErrorWithFormat(kSecXPCErrorUnexpectedType, sSecXPCErrorDomain, NULL, error, NULL, CFSTR("xpcSetDER not data, got %@"), xpcSetDER));
460
461 const uint8_t* der = xpc_data_get_bytes_ptr(xpcSetDER);
462 const uint8_t* der_end = der + xpc_data_get_length(xpcSetDER);
463 der = der_decode_set(kCFAllocatorDefault, kCFPropertyListMutableContainersAndLeaves, &retval, error, der, der_end);
464 if (der != der_end) {
465 SecError(errSecDecode, error, CFSTR("trailing garbage at end of SecAccessControl data"));
466 goto errOut;
467 }
468 return retval;
469 errOut:
470 CFReleaseNull(retval);
471 return NULL;
472 }
473
474 xpc_object_t CreateXPCObjectWithCFSetRef(CFSetRef setref, CFErrorRef *error) {
475 xpc_object_t result = NULL;
476 size_t data_size = 0;
477 uint8_t *data = NULL;
478 require_action_quiet(setref, errOut, SecCFCreateErrorWithFormat(kSecXPCErrorUnexpectedNull, sSecXPCErrorDomain, NULL, error, NULL, CFSTR("Unexpected Null Set to encode")));
479 require_quiet((data_size = der_sizeof_set(setref, error)) != 0, errOut);
480 require_quiet((data = (uint8_t *)malloc(data_size)) != NULL, errOut);
481
482 der_encode_set(setref, error, data, data + data_size);
483 result = xpc_data_create(data, data_size);
484 free(data);
485 errOut:
486 return result;
487 }
488