]> git.saurik.com Git - apple/security.git/blob - Security/sec/SOSCircle/SecureObjectSync/SOSAccountPersistence.c
Security-57031.20.26.tar.gz
[apple/security.git] / Security / sec / SOSCircle / SecureObjectSync / SOSAccountPersistence.c
1 /*
2 * Copyright (c) 2013-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 <stdio.h>
26 #include <stdlib.h>
27 #include <assert.h>
28 #include <AssertMacros.h>
29 #include "SOSAccountPriv.h"
30
31 #include <utilities/SecCFWrappers.h>
32 #include <SecureObjectSync/SOSKVSKeys.h>
33
34 SOSAccountRef SOSAccountCreateFromDER_V1(CFAllocatorRef allocator,
35 SOSDataSourceFactoryRef factory,
36 CFErrorRef* error,
37 const uint8_t** der_p, const uint8_t *der_end)
38 {
39 SOSAccountRef account = NULL;
40
41 const uint8_t *sequence_end;
42 *der_p = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &sequence_end, *der_p, der_end);
43
44 {
45 CFDictionaryRef decoded_gestalt = NULL;
46 *der_p = der_decode_dictionary(kCFAllocatorDefault, kCFPropertyListImmutable, &decoded_gestalt, error,
47 *der_p, der_end);
48
49 if (*der_p == 0)
50 return NULL;
51
52 account = SOSAccountCreateBasic(allocator, decoded_gestalt, factory);
53 CFReleaseNull(decoded_gestalt);
54 }
55
56 CFArrayRef array = NULL;
57 *der_p = der_decode_array(kCFAllocatorDefault, 0, &array, error, *der_p, sequence_end);
58
59 *der_p = ccder_decode_bool(&account->user_public_trusted, *der_p, sequence_end);
60 *der_p = der_decode_public_bytes(kCFAllocatorDefault, kSecECDSAAlgorithmID, &account->user_public, error, *der_p, sequence_end);
61 *der_p = der_decode_data_or_null(kCFAllocatorDefault, &account->user_key_parameters, error, *der_p, sequence_end);
62 *der_p = der_decode_dictionary(kCFAllocatorDefault, kCFPropertyListMutableContainers, (CFDictionaryRef *) &account->retired_peers, error, *der_p, sequence_end);
63 if (*der_p != sequence_end)
64 *der_p = NULL;
65
66 __block bool success = true;
67
68 require_quiet(array && *der_p, fail);
69
70 CFArrayForEach(array, ^(const void *value) {
71 if (success) {
72 if (isString(value)) {
73 CFDictionaryAddValue(account->circles, value, kCFNull);
74 } else {
75 CFDataRef circleData = NULL;
76 CFDataRef fullPeerInfoData = NULL;
77
78 if (isData(value)) {
79 circleData = (CFDataRef) value;
80 } else if (isArray(value)) {
81 CFArrayRef pair = (CFArrayRef) value;
82
83 CFTypeRef circleObject = CFArrayGetValueAtIndex(pair, 0);
84 CFTypeRef fullPeerInfoObject = CFArrayGetValueAtIndex(pair, 1);
85
86 if (CFArrayGetCount(pair) == 2 && isData(circleObject) && isData(fullPeerInfoObject)) {
87 circleData = (CFDataRef) circleObject;
88 fullPeerInfoData = (CFDataRef) fullPeerInfoObject;
89 }
90 }
91
92 if (circleData) {
93 SOSCircleRef circle = SOSCircleCreateFromData(kCFAllocatorDefault, circleData, error);
94 require_action_quiet(circle, fail, success = false);
95
96 CFStringRef circleName = SOSCircleGetName(circle);
97 CFDictionaryAddValue(account->circles, circleName, circle);
98
99 if (fullPeerInfoData) {
100 SOSFullPeerInfoRef full_peer = SOSFullPeerInfoCreateFromData(kCFAllocatorDefault, fullPeerInfoData, error);
101 require_action_quiet(full_peer, fail, success = false);
102
103 CFDictionaryAddValue(account->circle_identities, circleName, full_peer);
104 CFReleaseNull(full_peer);
105 }
106 fail:
107 CFReleaseNull(circle);
108 }
109 }
110 }
111 });
112 CFReleaseNull(array);
113
114 require_quiet(success, fail);
115 require_action_quiet(SOSAccountEnsureFactoryCircles(account), fail,
116 SOSCreateError(kSOSErrorBadFormat, CFSTR("Cannot EnsureFactoryCircles"), (error != NULL) ? *error : NULL, error));
117
118 return account;
119
120 fail:
121 // Create a default error if we don't have one:
122 SOSCreateError(kSOSErrorBadFormat, CFSTR("Bad Account DER"), NULL, error);
123 CFReleaseNull(account);
124 return NULL;
125 }
126
127 SOSAccountRef SOSAccountCreateFromDER_V2(CFAllocatorRef allocator,
128 SOSDataSourceFactoryRef factory,
129 CFErrorRef* error,
130 const uint8_t** der_p, const uint8_t *der_end)
131 {
132 SOSAccountRef account = NULL;
133 const uint8_t *dersave = *der_p;
134 const uint8_t *derend = der_end;
135
136 const uint8_t *sequence_end;
137 *der_p = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &sequence_end, *der_p, der_end);
138
139 {
140 CFDictionaryRef decoded_gestalt = NULL;
141 *der_p = der_decode_dictionary(kCFAllocatorDefault, kCFPropertyListImmutable, &decoded_gestalt, error,
142 *der_p, der_end);
143
144 if (*der_p == 0)
145 return NULL;
146
147 account = SOSAccountCreateBasic(allocator, decoded_gestalt, factory);
148 CFReleaseNull(decoded_gestalt);
149 }
150
151 CFArrayRef array = NULL;
152 *der_p = der_decode_array(kCFAllocatorDefault, 0, &array, error, *der_p, sequence_end);
153
154 uint64_t tmp_departure_code = kSOSNeverAppliedToCircle;
155 *der_p = ccder_decode_uint64(&tmp_departure_code, *der_p, sequence_end);
156 *der_p = ccder_decode_bool(&account->user_public_trusted, *der_p, sequence_end);
157 *der_p = der_decode_public_bytes(kCFAllocatorDefault, kSecECDSAAlgorithmID, &account->user_public, error, *der_p, sequence_end);
158 *der_p = der_decode_data_or_null(kCFAllocatorDefault, &account->user_key_parameters, error, *der_p, sequence_end);
159 *der_p = der_decode_dictionary(kCFAllocatorDefault, kCFPropertyListMutableContainers, (CFDictionaryRef *) &account->retired_peers, error, *der_p, sequence_end);
160 if (*der_p != sequence_end)
161 *der_p = NULL;
162 account->departure_code = (enum DepartureReason) tmp_departure_code;
163
164 __block bool success = true;
165
166 require_quiet(array && *der_p, fail);
167
168 CFArrayForEach(array, ^(const void *value) {
169 if (success) {
170 if (isString(value)) {
171 CFDictionaryAddValue(account->circles, value, kCFNull);
172 } else {
173 CFDataRef circleData = NULL;
174 CFDataRef fullPeerInfoData = NULL;
175
176 if (isData(value)) {
177 circleData = (CFDataRef) value;
178 } else if (isArray(value)) {
179 CFArrayRef pair = (CFArrayRef) value;
180
181 CFTypeRef circleObject = CFArrayGetValueAtIndex(pair, 0);
182 CFTypeRef fullPeerInfoObject = CFArrayGetValueAtIndex(pair, 1);
183
184 if (CFArrayGetCount(pair) == 2 && isData(circleObject) && isData(fullPeerInfoObject)) {
185 circleData = (CFDataRef) circleObject;
186 fullPeerInfoData = (CFDataRef) fullPeerInfoObject;
187 }
188 }
189
190 if (circleData) {
191 SOSCircleRef circle = SOSCircleCreateFromData(kCFAllocatorDefault, circleData, error);
192 require_action_quiet(circle, fail, success = false);
193
194 CFStringRef circleName = SOSCircleGetName(circle);
195 CFDictionaryAddValue(account->circles, circleName, circle);
196
197 if (fullPeerInfoData) {
198 SOSFullPeerInfoRef full_peer = SOSFullPeerInfoCreateFromData(kCFAllocatorDefault, fullPeerInfoData, error);
199 require_action_quiet(full_peer, fail, success = false);
200
201 CFDictionaryAddValue(account->circle_identities, circleName, full_peer);
202 CFReleaseSafe(full_peer);
203 }
204 fail:
205 CFReleaseNull(circle);
206 }
207 }
208 }
209 });
210 CFReleaseNull(array);
211
212 require_quiet(success, fail);
213 require_action_quiet(SOSAccountEnsureFactoryCircles(account), fail,
214 SOSCreateError(kSOSErrorBadFormat, CFSTR("Cannot EnsureFactoryCircles"), (error != NULL) ? *error : NULL, error));
215
216 return account;
217
218 fail:
219 // Create a default error if we don't have one:
220 account->factory = NULL; // give the factory back.
221 CFReleaseNull(account);
222 // Try the der inflater from the previous release.
223 account = SOSAccountCreateFromDER_V1(allocator, factory, error, &dersave, derend);
224 if(account) account->departure_code = kSOSNeverAppliedToCircle;
225 return account;
226 }
227
228 static void SOSAccountConvertKVSDictionaryToRetirementDictionary(SOSAccountRef account)
229 {
230 CFMutableDictionaryRef old_retired_peers = account->retired_peers;
231 account->retired_peers = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
232
233 CFDictionaryForEach(old_retired_peers, ^(const void *key, const void *value) {
234 if (isDictionary(value)) {
235 CFDictionaryAddValue(account->retired_peers, key, value);
236 } else if (isString(key) && isData(value)) {
237 CFDataRef retired_peer_data = (CFDataRef) value;
238 CFStringRef circle_name = NULL;
239 CFStringRef retired_peer_id = NULL;
240
241 if (kRetirementKey == SOSKVSKeyGetKeyTypeAndParse(key, &circle_name, &retired_peer_id, NULL)) {
242 CFMutableDictionaryRef circle_retirees = CFDictionaryEnsureCFDictionaryAndGetCurrentValue(account->retired_peers, circle_name);
243
244 CFDictionarySetValue(circle_retirees, retired_peer_id, retired_peer_data);
245 }
246
247 CFReleaseSafe(circle_name);
248 CFReleaseSafe(retired_peer_id);
249 }
250 });
251 CFReleaseSafe(old_retired_peers);
252 }
253
254
255 #define CURRENT_ACCOUNT_PERSISTENT_VERSION 6
256
257 SOSAccountRef SOSAccountCreateFromDER(CFAllocatorRef allocator,
258 SOSDataSourceFactoryRef factory,
259 CFErrorRef* error,
260 const uint8_t** der_p, const uint8_t *der_end)
261 {
262 SOSAccountRef account = NULL;
263 #if UPGRADE_FROM_PREVIOUS_VERSION
264 const uint8_t *dersave = *der_p;
265 const uint8_t *derend = der_end;
266 #endif
267 uint64_t version = 0;
268
269 const uint8_t *sequence_end;
270 *der_p = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &sequence_end, *der_p, der_end);
271 *der_p = ccder_decode_uint64(&version, *der_p, sequence_end);
272 if(!(*der_p) || version < CURRENT_ACCOUNT_PERSISTENT_VERSION) {
273 #if UPGRADE_FROM_PREVIOUS_VERSION
274 return SOSAccountCreateFromDER_V3(allocator, factory, error, &dersave, derend);
275 #else
276 return NULL;
277 #endif
278 }
279
280 {
281 CFDictionaryRef decoded_gestalt = NULL;
282 *der_p = der_decode_dictionary(kCFAllocatorDefault, kCFPropertyListImmutable, &decoded_gestalt, error,
283 *der_p, der_end);
284
285 if (*der_p == 0)
286 return NULL;
287
288 account = SOSAccountCreateBasic(allocator, decoded_gestalt, factory);
289 CFReleaseNull(decoded_gestalt);
290 }
291
292 CFArrayRef array = NULL;
293 *der_p = der_decode_array(kCFAllocatorDefault, 0, &array, error, *der_p, sequence_end);
294
295 uint64_t tmp_departure_code = kSOSNeverAppliedToCircle;
296 *der_p = ccder_decode_uint64(&tmp_departure_code, *der_p, sequence_end);
297 *der_p = ccder_decode_bool(&account->user_public_trusted, *der_p, sequence_end);
298 *der_p = der_decode_public_bytes(kCFAllocatorDefault, kSecECDSAAlgorithmID, &account->user_public, error, *der_p, sequence_end);
299 *der_p = der_decode_public_bytes(kCFAllocatorDefault, kSecECDSAAlgorithmID, &account->previous_public, error, *der_p, sequence_end);
300 *der_p = der_decode_data_or_null(kCFAllocatorDefault, &account->user_key_parameters, error, *der_p, sequence_end);
301 *der_p = der_decode_dictionary(kCFAllocatorDefault, kCFPropertyListMutableContainers, (CFDictionaryRef *) &account->retired_peers, error, *der_p, sequence_end);
302 if (*der_p != sequence_end)
303 *der_p = NULL;
304 account->departure_code = (enum DepartureReason) tmp_departure_code;
305
306 __block bool success = true;
307
308 require_quiet(array && *der_p, fail);
309
310 CFArrayForEach(array, ^(const void *value) {
311 if (success) {
312 if (isString(value)) {
313 CFDictionaryAddValue(account->circles, value, kCFNull);
314 } else {
315 CFDataRef circleData = NULL;
316 CFDataRef fullPeerInfoData = NULL;
317
318 if (isData(value)) {
319 circleData = (CFDataRef) value;
320 } else if (isArray(value)) {
321 CFArrayRef pair = (CFArrayRef) value;
322
323 CFTypeRef circleObject = CFArrayGetValueAtIndex(pair, 0);
324 CFTypeRef fullPeerInfoObject = CFArrayGetValueAtIndex(pair, 1);
325
326 if (CFArrayGetCount(pair) == 2 && isData(circleObject) && isData(fullPeerInfoObject)) {
327 circleData = (CFDataRef) circleObject;
328 fullPeerInfoData = (CFDataRef) fullPeerInfoObject;
329 }
330 }
331
332 if (circleData) {
333 SOSCircleRef circle = SOSCircleCreateFromData(kCFAllocatorDefault, circleData, error);
334 require_action_quiet(circle, fail, success = false);
335
336 CFStringRef circleName = SOSCircleGetName(circle);
337 CFDictionaryAddValue(account->circles, circleName, circle);
338
339 if (fullPeerInfoData) {
340 SOSFullPeerInfoRef full_peer = SOSFullPeerInfoCreateFromData(kCFAllocatorDefault, fullPeerInfoData, error);
341 require_action_quiet(full_peer, fail, success = false);
342
343 CFDictionaryAddValue(account->circle_identities, circleName, full_peer);
344 CFReleaseNull(full_peer);
345 }
346 fail:
347 CFReleaseNull(circle);
348 }
349 }
350 }
351 });
352 CFReleaseNull(array);
353
354 require_quiet(success, fail);
355
356 require_action_quiet(SOSAccountEnsureFactoryCircles(account), fail,
357 SOSCreateError(kSOSErrorBadFormat, CFSTR("Cannot EnsureFactoryCircles"), (error != NULL) ? *error : NULL, error));
358
359 SOSAccountConvertKVSDictionaryToRetirementDictionary(account);
360
361 return account;
362
363 fail:
364 account->factory = NULL; // give the factory back.
365 CFReleaseNull(account);
366 return NULL;
367 }
368
369
370 SOSAccountRef SOSAccountCreateFromDER_V3(CFAllocatorRef allocator,
371 SOSDataSourceFactoryRef factory,
372 CFErrorRef* error,
373 const uint8_t** der_p, const uint8_t *der_end)
374 {
375 SOSAccountRef account = NULL;
376 uint64_t version = 0;
377
378 const uint8_t *sequence_end;
379 *der_p = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &sequence_end, *der_p, der_end);
380 *der_p = ccder_decode_uint64(&version, *der_p, sequence_end);
381 if(!(*der_p) || version != 3) {
382 // In this case we want to silently fail so that an account gets newly created.
383 return NULL;
384 }
385
386 {
387 CFDictionaryRef decoded_gestalt = NULL;
388 *der_p = der_decode_dictionary(kCFAllocatorDefault, kCFPropertyListImmutable, &decoded_gestalt, error,
389 *der_p, der_end);
390
391 if (*der_p == 0)
392 return NULL;
393
394 account = SOSAccountCreateBasic(allocator, decoded_gestalt, factory);
395 CFReleaseNull(decoded_gestalt);
396 }
397
398 CFArrayRef array = NULL;
399 *der_p = der_decode_array(kCFAllocatorDefault, 0, &array, error, *der_p, sequence_end);
400
401 uint64_t tmp_departure_code = kSOSNeverAppliedToCircle;
402 *der_p = ccder_decode_uint64(&tmp_departure_code, *der_p, sequence_end);
403 *der_p = ccder_decode_bool(&account->user_public_trusted, *der_p, sequence_end);
404 *der_p = der_decode_public_bytes(kCFAllocatorDefault, kSecECDSAAlgorithmID, &account->user_public, error, *der_p, sequence_end);
405 *der_p = der_decode_data_or_null(kCFAllocatorDefault, &account->user_key_parameters, error, *der_p, sequence_end);
406 *der_p = der_decode_dictionary(kCFAllocatorDefault, kCFPropertyListMutableContainers, (CFDictionaryRef *) &account->retired_peers, error, *der_p, sequence_end);
407 if (*der_p != sequence_end)
408 *der_p = NULL;
409 account->departure_code = (enum DepartureReason) tmp_departure_code;
410
411 __block bool success = true;
412
413 require_quiet(array && *der_p, fail);
414
415 CFArrayForEach(array, ^(const void *value) {
416 if (success) {
417 if (isString(value)) {
418 CFDictionaryAddValue(account->circles, value, kCFNull);
419 } else {
420 CFDataRef circleData = NULL;
421 CFDataRef fullPeerInfoData = NULL;
422
423 if (isData(value)) {
424 circleData = (CFDataRef) value;
425 } else if (isArray(value)) {
426 CFArrayRef pair = (CFArrayRef) value;
427
428 CFTypeRef circleObject = CFArrayGetValueAtIndex(pair, 0);
429 CFTypeRef fullPeerInfoObject = CFArrayGetValueAtIndex(pair, 1);
430
431 if (CFArrayGetCount(pair) == 2 && isData(circleObject) && isData(fullPeerInfoObject)) {
432 circleData = (CFDataRef) circleObject;
433 fullPeerInfoData = (CFDataRef) fullPeerInfoObject;
434 }
435 }
436
437 if (circleData) {
438 SOSCircleRef circle = SOSCircleCreateFromData(kCFAllocatorDefault, circleData, error);
439 require_action_quiet(circle, fail, success = false);
440
441 CFStringRef circleName = SOSCircleGetName(circle);
442 CFDictionaryAddValue(account->circles, circleName, circle);
443
444 if (fullPeerInfoData) {
445 SOSFullPeerInfoRef full_peer = SOSFullPeerInfoCreateFromData(kCFAllocatorDefault, fullPeerInfoData, error);
446 require_action_quiet(full_peer, fail, success = false);
447
448 CFDictionaryAddValue(account->circle_identities, circleName, full_peer);
449 CFReleaseNull(full_peer);
450 }
451 fail:
452 CFReleaseNull(circle);
453 }
454 }
455 }
456 });
457 CFReleaseNull(array);
458
459 require_quiet(success, fail);
460 require_action_quiet(SOSAccountEnsureFactoryCircles(account), fail,
461 SOSCreateError(kSOSErrorBadFormat, CFSTR("Cannot EnsureFactoryCircles"), (error != NULL) ? *error : NULL, error));
462
463 SOSAccountConvertKVSDictionaryToRetirementDictionary(account);
464
465 return account;
466
467 fail:
468 // Create a default error if we don't have one:
469 account->factory = NULL; // give the factory back.
470 CFReleaseNull(account);
471 // Don't try the der inflater from the previous release.
472 // account = SOSAccountCreateFromDER_V2(allocator, transport, factory, error, &dersave, derend);
473 if(account) account->departure_code = kSOSNeverAppliedToCircle;
474 return account;
475 }
476
477 SOSAccountRef SOSAccountCreateFromData(CFAllocatorRef allocator, CFDataRef circleData,
478 SOSDataSourceFactoryRef factory,
479 CFErrorRef* error)
480 {
481 size_t size = CFDataGetLength(circleData);
482 const uint8_t *der = CFDataGetBytePtr(circleData);
483 SOSAccountRef account = SOSAccountCreateFromDER(allocator, factory,
484 error,
485 &der, der + size);
486 return account;
487 }
488
489 static CFMutableArrayRef SOSAccountCopyCircleArrayToEncode(SOSAccountRef account)
490 {
491 CFMutableArrayRef arrayToEncode = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
492
493 CFDictionaryForEach(account->circles, ^(const void *key, const void *value) {
494 if (isNull(value)) {
495 CFArrayAppendValue(arrayToEncode, key); // Encode the name of the circle that's out of date.
496 } else {
497 SOSCircleRef circle = (SOSCircleRef) value;
498 CFDataRef encodedCircle = SOSCircleCopyEncodedData(circle, kCFAllocatorDefault, NULL);
499 CFTypeRef arrayEntry = encodedCircle;
500 CFRetainSafe(arrayEntry);
501
502 SOSFullPeerInfoRef full_peer = (SOSFullPeerInfoRef) CFDictionaryGetValue(account->circle_identities, key);
503
504 if (full_peer) {
505 CFDataRef encodedPeer = SOSFullPeerInfoCopyEncodedData(full_peer, kCFAllocatorDefault, NULL);
506 CFTypeRef originalArrayEntry = arrayEntry;
507 arrayEntry = CFArrayCreateForCFTypes(kCFAllocatorDefault, encodedCircle, encodedPeer, NULL);
508
509 CFReleaseSafe(originalArrayEntry);
510 CFReleaseNull(encodedPeer);
511 }
512
513 CFArrayAppendValue(arrayToEncode, arrayEntry);
514
515 CFReleaseSafe(arrayEntry);
516 CFReleaseNull(encodedCircle);
517 }
518
519 });
520
521 return arrayToEncode;
522 }
523
524 size_t SOSAccountGetDEREncodedSize(SOSAccountRef account, CFErrorRef *error)
525 {
526 size_t sequence_size = 0;
527 CFMutableArrayRef arrayToEncode = SOSAccountCopyCircleArrayToEncode(account);
528 uint64_t version = CURRENT_ACCOUNT_PERSISTENT_VERSION;
529
530 require_quiet(accumulate_size(&sequence_size, ccder_sizeof_uint64(version)), fail);
531 require_quiet(accumulate_size(&sequence_size, der_sizeof_dictionary(account->gestalt, error)), fail);
532 require_quiet(accumulate_size(&sequence_size, der_sizeof_array(arrayToEncode, error)), fail);
533 require_quiet(accumulate_size(&sequence_size, ccder_sizeof_uint64(account->departure_code)), fail);
534 require_quiet(accumulate_size(&sequence_size, ccder_sizeof_bool(account->user_public_trusted, error)), fail);
535 require_quiet(accumulate_size(&sequence_size, der_sizeof_public_bytes(account->user_public, error)), fail);
536 require_quiet(accumulate_size(&sequence_size, der_sizeof_public_bytes(account->previous_public, error)), fail);
537 require_quiet(accumulate_size(&sequence_size, der_sizeof_data_or_null(account->user_key_parameters, error)), fail);
538 require_quiet(accumulate_size(&sequence_size, der_sizeof_dictionary(account->retired_peers, error)), fail);
539
540 CFReleaseNull(arrayToEncode);
541 return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, sequence_size);
542
543 fail:
544 CFReleaseNull(arrayToEncode);
545 SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("don't know how to encode"), NULL, error);
546 return 0;
547 }
548
549 uint8_t* SOSAccountEncodeToDER(SOSAccountRef account, CFErrorRef* error, const uint8_t* der, uint8_t* der_end)
550 {
551 CFMutableArrayRef arrayToEncode = SOSAccountCopyCircleArrayToEncode(account);
552 uint64_t version = CURRENT_ACCOUNT_PERSISTENT_VERSION;
553 der_end = ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der,
554 ccder_encode_uint64(version, der,
555 der_encode_dictionary(account->gestalt, error, der,
556 der_encode_array(arrayToEncode, error, der,
557 ccder_encode_uint64(account->departure_code, der,
558 ccder_encode_bool(account->user_public_trusted, der,
559 der_encode_public_bytes(account->user_public, error, der,
560 der_encode_public_bytes(account->previous_public, error, der,
561 der_encode_data_or_null(account->user_key_parameters, error, der,
562 der_encode_dictionary(account->retired_peers, error, der, der_end))))))))));
563
564 CFReleaseNull(arrayToEncode);
565
566 return der_end;
567 }
568
569
570
571 size_t SOSAccountGetDEREncodedSize_V3(SOSAccountRef account, CFErrorRef *error)
572 {
573 size_t sequence_size = 0;
574 CFMutableArrayRef arrayToEncode = SOSAccountCopyCircleArrayToEncode(account);
575 uint64_t version = CURRENT_ACCOUNT_PERSISTENT_VERSION;
576
577 require_quiet(accumulate_size(&sequence_size, ccder_sizeof_uint64(version)), fail);
578 require_quiet(accumulate_size(&sequence_size, der_sizeof_dictionary(account->gestalt, error)), fail);
579 require_quiet(accumulate_size(&sequence_size, der_sizeof_array(arrayToEncode, error)), fail);
580 require_quiet(accumulate_size(&sequence_size, ccder_sizeof_uint64(account->departure_code)), fail);
581 require_quiet(accumulate_size(&sequence_size, ccder_sizeof_bool(account->user_public_trusted, error)), fail);
582 require_quiet(accumulate_size(&sequence_size, der_sizeof_public_bytes(account->user_public, error)), fail);
583 require_quiet(accumulate_size(&sequence_size, der_sizeof_data_or_null(account->user_key_parameters, error)), fail);
584 require_quiet(accumulate_size(&sequence_size, der_sizeof_dictionary(account->retired_peers, error)), fail);
585
586 CFReleaseNull(arrayToEncode);
587 return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, sequence_size);
588
589 fail:
590 CFReleaseNull(arrayToEncode);
591 SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("don't know how to encode"), NULL, error);
592 return 0;
593 }
594
595 uint8_t* SOSAccountEncodeToDER_V3(SOSAccountRef account, CFErrorRef* error, const uint8_t* der, uint8_t* der_end)
596 {
597 CFMutableArrayRef arrayToEncode = SOSAccountCopyCircleArrayToEncode(account);
598 uint64_t version = 3;
599 der_end = ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der,
600 ccder_encode_uint64(version, der,
601 der_encode_dictionary(account->gestalt, error, der,
602 der_encode_array(arrayToEncode, error, der,
603 ccder_encode_uint64(account->departure_code, der,
604 ccder_encode_bool(account->user_public_trusted, der,
605 der_encode_public_bytes(account->user_public, error, der,
606 der_encode_data_or_null(account->user_key_parameters, error, der,
607 der_encode_dictionary(account->retired_peers, error, der, der_end)))))))));
608
609 CFReleaseNull(arrayToEncode);
610
611 return der_end;
612 }
613
614 /* Original V2 encoders */
615
616 size_t SOSAccountGetDEREncodedSize_V2(SOSAccountRef account, CFErrorRef *error)
617 {
618 size_t sequence_size = 0;
619 CFMutableArrayRef arrayToEncode = SOSAccountCopyCircleArrayToEncode(account);
620
621 require_quiet(accumulate_size(&sequence_size, der_sizeof_dictionary(account->gestalt, error)), fail);
622 require_quiet(accumulate_size(&sequence_size, der_sizeof_array(arrayToEncode, error)), fail);
623 require_quiet(accumulate_size(&sequence_size, ccder_sizeof_uint64(account->departure_code)), fail);
624 require_quiet(accumulate_size(&sequence_size, ccder_sizeof_bool(account->user_public_trusted, error)), fail);
625 require_quiet(accumulate_size(&sequence_size, der_sizeof_public_bytes(account->user_public, error)), fail);
626 require_quiet(accumulate_size(&sequence_size, der_sizeof_data_or_null(account->user_key_parameters, error)), fail);
627 require_quiet(accumulate_size(&sequence_size, der_sizeof_dictionary(account->retired_peers, error)), fail);
628
629 CFReleaseNull(arrayToEncode);
630 return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, sequence_size);
631
632 fail:
633 CFReleaseNull(arrayToEncode);
634 SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("don't know how to encode"), NULL, error);
635 return 0;
636 }
637
638 uint8_t* SOSAccountEncodeToDER_V2(SOSAccountRef account, CFErrorRef* error, const uint8_t* der, uint8_t* der_end)
639 {
640 CFMutableArrayRef arrayToEncode = SOSAccountCopyCircleArrayToEncode(account);
641
642 der_end = ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der,
643 der_encode_dictionary(account->gestalt, error, der,
644 der_encode_array(arrayToEncode, error, der,
645 ccder_encode_uint64(account->departure_code, der,
646 ccder_encode_bool(account->user_public_trusted, der,
647 der_encode_public_bytes(account->user_public, error, der,
648 der_encode_data_or_null(account->user_key_parameters, error, der,
649 der_encode_dictionary(account->retired_peers, error, der, der_end))))))));
650
651 CFReleaseNull(arrayToEncode);
652
653 return der_end;
654 }
655
656
657 /* Original V1 encoders */
658
659
660 size_t SOSAccountGetDEREncodedSize_V1(SOSAccountRef account, CFErrorRef *error)
661 {
662 size_t sequence_size = 0;
663 CFMutableArrayRef arrayToEncode = SOSAccountCopyCircleArrayToEncode(account);
664
665 require_quiet(accumulate_size(&sequence_size, der_sizeof_dictionary(account->gestalt, error)), fail);
666 require_quiet(accumulate_size(&sequence_size, der_sizeof_array(arrayToEncode, error)), fail);
667 require_quiet(accumulate_size(&sequence_size, ccder_sizeof_bool(account->user_public_trusted, error)), fail);
668 require_quiet(accumulate_size(&sequence_size, der_sizeof_public_bytes(account->user_public, error)), fail);
669 require_quiet(accumulate_size(&sequence_size, der_sizeof_data_or_null(account->user_key_parameters, error)), fail);
670 require_quiet(accumulate_size(&sequence_size, der_sizeof_dictionary(account->retired_peers, error)), fail);
671
672 CFReleaseNull(arrayToEncode);
673 return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, sequence_size);
674
675 fail:
676 CFReleaseNull(arrayToEncode);
677 SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("don't know how to encode"), NULL, error);
678 return 0;
679 }
680
681 uint8_t* SOSAccountEncodeToDER_V1(SOSAccountRef account, CFErrorRef* error, const uint8_t* der, uint8_t* der_end)
682 {
683 CFMutableArrayRef arrayToEncode = SOSAccountCopyCircleArrayToEncode(account);
684
685 der_end = ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der,
686 der_encode_dictionary(account->gestalt, error, der,
687 der_encode_array(arrayToEncode, error, der,
688 ccder_encode_bool(account->user_public_trusted, der,
689 der_encode_public_bytes(account->user_public, error, der,
690 der_encode_data_or_null(account->user_key_parameters, error, der,
691 der_encode_dictionary(account->retired_peers, error, der, der_end)))))));
692
693 CFReleaseNull(arrayToEncode);
694
695 return der_end;
696 }
697
698 /************************/
699
700 CFDataRef SOSAccountCopyEncodedData(SOSAccountRef account, CFAllocatorRef allocator, CFErrorRef *error)
701 {
702 size_t size = SOSAccountGetDEREncodedSize(account, error);
703 if (size == 0)
704 return NULL;
705 uint8_t buffer[size];
706 uint8_t* start = SOSAccountEncodeToDER(account, error, buffer, buffer + sizeof(buffer));
707 CFDataRef result = CFDataCreate(kCFAllocatorDefault, start, size);
708 return result;
709 }
710