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
34SOSAccountRef 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
120fail:
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
127SOSAccountRef 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
218fail:
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
228static 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
257SOSAccountRef 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    require_action_quiet(SOSAccountEnsureFactoryCircles(account), fail,
356                         SOSCreateError(kSOSErrorBadFormat, CFSTR("Cannot EnsureFactoryCircles"), (error != NULL) ? *error : NULL, error));
357
358    SOSAccountConvertKVSDictionaryToRetirementDictionary(account);
359
360    return account;
361
362fail:
363    account->factory = NULL; // give the factory back.
364    CFReleaseNull(account);
365    return NULL;
366}
367
368
369SOSAccountRef SOSAccountCreateFromDER_V3(CFAllocatorRef allocator,
370                                         SOSDataSourceFactoryRef factory,
371                                         CFErrorRef* error,
372                                         const uint8_t** der_p, const uint8_t *der_end)
373{
374    SOSAccountRef account = NULL;
375    uint64_t version = 0;
376
377    const uint8_t *sequence_end;
378    *der_p = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &sequence_end, *der_p, der_end);
379    *der_p = ccder_decode_uint64(&version, *der_p, sequence_end);
380    if(!(*der_p) || version != 3) {
381        // In this case we want to silently fail so that an account gets newly created.
382        return NULL;
383    }
384
385    {
386        CFDictionaryRef decoded_gestalt = NULL;
387        *der_p = der_decode_dictionary(kCFAllocatorDefault, kCFPropertyListImmutable, &decoded_gestalt, error,
388                                       *der_p, der_end);
389
390        if (*der_p == 0)
391            return NULL;
392
393        account = SOSAccountCreateBasic(allocator, decoded_gestalt, factory);
394        CFReleaseNull(decoded_gestalt);
395    }
396
397    CFArrayRef array = NULL;
398    *der_p = der_decode_array(kCFAllocatorDefault, 0, &array, error, *der_p, sequence_end);
399
400    uint64_t tmp_departure_code = kSOSNeverAppliedToCircle;
401    *der_p = ccder_decode_uint64(&tmp_departure_code, *der_p, sequence_end);
402    *der_p = ccder_decode_bool(&account->user_public_trusted, *der_p, sequence_end);
403    *der_p = der_decode_public_bytes(kCFAllocatorDefault, kSecECDSAAlgorithmID, &account->user_public, error, *der_p, sequence_end);
404    *der_p = der_decode_data_or_null(kCFAllocatorDefault, &account->user_key_parameters, error, *der_p, sequence_end);
405    *der_p = der_decode_dictionary(kCFAllocatorDefault, kCFPropertyListMutableContainers, (CFDictionaryRef *) &account->retired_peers, error, *der_p, sequence_end);
406    if (*der_p != sequence_end)
407        *der_p = NULL;
408    account->departure_code = (enum DepartureReason) tmp_departure_code;
409
410    __block bool success = true;
411
412    require_quiet(array && *der_p, fail);
413
414    CFArrayForEach(array, ^(const void *value) {
415        if (success) {
416            if (isString(value)) {
417                CFDictionaryAddValue(account->circles, value, kCFNull);
418            } else {
419                CFDataRef circleData = NULL;
420                CFDataRef fullPeerInfoData = NULL;
421
422                if (isData(value)) {
423                    circleData = (CFDataRef) value;
424                } else if (isArray(value)) {
425                    CFArrayRef pair = (CFArrayRef) value;
426
427                    CFTypeRef circleObject = CFArrayGetValueAtIndex(pair, 0);
428                    CFTypeRef fullPeerInfoObject = CFArrayGetValueAtIndex(pair, 1);
429
430                    if (CFArrayGetCount(pair) == 2 && isData(circleObject) && isData(fullPeerInfoObject)) {
431                        circleData = (CFDataRef) circleObject;
432                        fullPeerInfoData = (CFDataRef) fullPeerInfoObject;
433                    }
434                }
435
436                if (circleData) {
437                    SOSCircleRef circle = SOSCircleCreateFromData(kCFAllocatorDefault, circleData, error);
438                    require_action_quiet(circle, fail, success = false);
439
440                    CFStringRef circleName = SOSCircleGetName(circle);
441                    CFDictionaryAddValue(account->circles, circleName, circle);
442
443                    if (fullPeerInfoData) {
444                        SOSFullPeerInfoRef full_peer = SOSFullPeerInfoCreateFromData(kCFAllocatorDefault, fullPeerInfoData, error);
445                        require_action_quiet(full_peer, fail, success = false);
446
447                        CFDictionaryAddValue(account->circle_identities, circleName, full_peer);
448                        CFReleaseNull(full_peer);
449                    }
450                fail:
451                    CFReleaseNull(circle);
452                }
453            }
454        }
455    });
456    CFReleaseNull(array);
457
458    require_quiet(success, fail);
459    require_action_quiet(SOSAccountEnsureFactoryCircles(account), fail,
460                         SOSCreateError(kSOSErrorBadFormat, CFSTR("Cannot EnsureFactoryCircles"), (error != NULL) ? *error : NULL, error));
461
462    SOSAccountConvertKVSDictionaryToRetirementDictionary(account);
463
464    return account;
465
466fail:
467    // Create a default error if we don't have one:
468    account->factory = NULL; // give the factory back.
469    CFReleaseNull(account);
470    // Don't try the der inflater from the previous release.
471    // account = SOSAccountCreateFromDER_V2(allocator, transport, factory, error, &dersave, derend);
472    if(account) account->departure_code = kSOSNeverAppliedToCircle;
473    return account;
474}
475
476SOSAccountRef SOSAccountCreateFromData(CFAllocatorRef allocator, CFDataRef circleData,
477                                       SOSDataSourceFactoryRef factory,
478                                       CFErrorRef* error)
479{
480    size_t size = CFDataGetLength(circleData);
481    const uint8_t *der = CFDataGetBytePtr(circleData);
482    SOSAccountRef account = SOSAccountCreateFromDER(allocator, factory,
483                                                    error,
484                                                    &der, der + size);
485    return account;
486}
487
488static CFMutableArrayRef SOSAccountCopyCircleArrayToEncode(SOSAccountRef account)
489{
490    CFMutableArrayRef arrayToEncode = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
491
492    CFDictionaryForEach(account->circles, ^(const void *key, const void *value) {
493        if (isNull(value)) {
494            CFArrayAppendValue(arrayToEncode, key); // Encode the name of the circle that's out of date.
495        } else {
496            SOSCircleRef circle = (SOSCircleRef) value;
497            CFDataRef encodedCircle = SOSCircleCopyEncodedData(circle, kCFAllocatorDefault, NULL);
498            CFTypeRef arrayEntry = encodedCircle;
499            CFRetainSafe(arrayEntry);
500
501            SOSFullPeerInfoRef full_peer = (SOSFullPeerInfoRef) CFDictionaryGetValue(account->circle_identities, key);
502
503            if (full_peer) {
504                CFDataRef encodedPeer = SOSFullPeerInfoCopyEncodedData(full_peer, kCFAllocatorDefault, NULL);
505                CFTypeRef originalArrayEntry = arrayEntry;
506                arrayEntry = CFArrayCreateForCFTypes(kCFAllocatorDefault, encodedCircle, encodedPeer, NULL);
507
508                CFReleaseSafe(originalArrayEntry);
509                CFReleaseNull(encodedPeer);
510            }
511
512            CFArrayAppendValue(arrayToEncode, arrayEntry);
513
514            CFReleaseSafe(arrayEntry);
515            CFReleaseNull(encodedCircle);
516        }
517
518    });
519
520    return arrayToEncode;
521}
522
523size_t SOSAccountGetDEREncodedSize(SOSAccountRef account, CFErrorRef *error)
524{
525    size_t sequence_size = 0;
526    CFMutableArrayRef arrayToEncode = SOSAccountCopyCircleArrayToEncode(account);
527    uint64_t version = CURRENT_ACCOUNT_PERSISTENT_VERSION;
528
529    require_quiet(accumulate_size(&sequence_size, ccder_sizeof_uint64(version)),                                    fail);
530    require_quiet(accumulate_size(&sequence_size, der_sizeof_dictionary(account->gestalt, error)),                  fail);
531    require_quiet(accumulate_size(&sequence_size, der_sizeof_array(arrayToEncode, error)),                          fail);
532    require_quiet(accumulate_size(&sequence_size, ccder_sizeof_uint64(account->departure_code)),                    fail);
533    require_quiet(accumulate_size(&sequence_size, ccder_sizeof_bool(account->user_public_trusted, error)),          fail);
534    require_quiet(accumulate_size(&sequence_size, der_sizeof_public_bytes(account->user_public, error)),            fail);
535    require_quiet(accumulate_size(&sequence_size, der_sizeof_public_bytes(account->previous_public, error)),        fail);
536    require_quiet(accumulate_size(&sequence_size, der_sizeof_data_or_null(account->user_key_parameters, error)),    fail);
537    require_quiet(accumulate_size(&sequence_size, der_sizeof_dictionary(account->retired_peers, error)),            fail);
538
539    CFReleaseNull(arrayToEncode);
540    return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, sequence_size);
541
542fail:
543    CFReleaseNull(arrayToEncode);
544    SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("don't know how to encode"), NULL, error);
545    return 0;
546}
547
548uint8_t* SOSAccountEncodeToDER(SOSAccountRef account, CFErrorRef* error, const uint8_t* der, uint8_t* der_end)
549{
550    CFMutableArrayRef arrayToEncode = SOSAccountCopyCircleArrayToEncode(account);
551    uint64_t version = CURRENT_ACCOUNT_PERSISTENT_VERSION;
552    der_end =  ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der,
553    ccder_encode_uint64(version, der,
554    der_encode_dictionary(account->gestalt, error, der,
555    der_encode_array(arrayToEncode, error, der,
556    ccder_encode_uint64(account->departure_code, der,
557    ccder_encode_bool(account->user_public_trusted, der,
558    der_encode_public_bytes(account->user_public, error, der,
559    der_encode_public_bytes(account->previous_public, error, der,
560    der_encode_data_or_null(account->user_key_parameters, error, der,
561    der_encode_dictionary(account->retired_peers, error, der, der_end))))))))));
562
563    CFReleaseNull(arrayToEncode);
564
565    return der_end;
566}
567
568
569
570size_t SOSAccountGetDEREncodedSize_V3(SOSAccountRef account, CFErrorRef *error)
571{
572    size_t sequence_size = 0;
573    CFMutableArrayRef arrayToEncode = SOSAccountCopyCircleArrayToEncode(account);
574    uint64_t version = CURRENT_ACCOUNT_PERSISTENT_VERSION;
575
576    require_quiet(accumulate_size(&sequence_size, ccder_sizeof_uint64(version)),                                    fail);
577    require_quiet(accumulate_size(&sequence_size, der_sizeof_dictionary(account->gestalt, error)),                  fail);
578    require_quiet(accumulate_size(&sequence_size, der_sizeof_array(arrayToEncode, error)),                          fail);
579    require_quiet(accumulate_size(&sequence_size, ccder_sizeof_uint64(account->departure_code)),                    fail);
580    require_quiet(accumulate_size(&sequence_size, ccder_sizeof_bool(account->user_public_trusted, error)),          fail);
581    require_quiet(accumulate_size(&sequence_size, der_sizeof_public_bytes(account->user_public, error)),            fail);
582    require_quiet(accumulate_size(&sequence_size, der_sizeof_data_or_null(account->user_key_parameters, error)),    fail);
583    require_quiet(accumulate_size(&sequence_size, der_sizeof_dictionary(account->retired_peers, error)),            fail);
584
585    CFReleaseNull(arrayToEncode);
586    return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, sequence_size);
587
588fail:
589    CFReleaseNull(arrayToEncode);
590    SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("don't know how to encode"), NULL, error);
591    return 0;
592}
593
594uint8_t* SOSAccountEncodeToDER_V3(SOSAccountRef account, CFErrorRef* error, const uint8_t* der, uint8_t* der_end)
595{
596    CFMutableArrayRef arrayToEncode = SOSAccountCopyCircleArrayToEncode(account);
597    uint64_t version = 3;
598    der_end =  ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der,
599    ccder_encode_uint64(version, der,
600    der_encode_dictionary(account->gestalt, error, der,
601    der_encode_array(arrayToEncode, error, der,
602    ccder_encode_uint64(account->departure_code, der,
603    ccder_encode_bool(account->user_public_trusted, der,
604    der_encode_public_bytes(account->user_public, error, der,
605    der_encode_data_or_null(account->user_key_parameters, error, der,
606    der_encode_dictionary(account->retired_peers, error, der, der_end)))))))));
607
608    CFReleaseNull(arrayToEncode);
609
610    return der_end;
611}
612
613/* Original V2 encoders */
614
615size_t SOSAccountGetDEREncodedSize_V2(SOSAccountRef account, CFErrorRef *error)
616{
617    size_t sequence_size = 0;
618    CFMutableArrayRef arrayToEncode = SOSAccountCopyCircleArrayToEncode(account);
619
620    require_quiet(accumulate_size(&sequence_size, der_sizeof_dictionary(account->gestalt, error)),                  fail);
621    require_quiet(accumulate_size(&sequence_size, der_sizeof_array(arrayToEncode, error)),                          fail);
622    require_quiet(accumulate_size(&sequence_size, ccder_sizeof_uint64(account->departure_code)), fail);
623    require_quiet(accumulate_size(&sequence_size, ccder_sizeof_bool(account->user_public_trusted, error)),          fail);
624    require_quiet(accumulate_size(&sequence_size, der_sizeof_public_bytes(account->user_public, error)),            fail);
625    require_quiet(accumulate_size(&sequence_size, der_sizeof_data_or_null(account->user_key_parameters, error)),    fail);
626    require_quiet(accumulate_size(&sequence_size, der_sizeof_dictionary(account->retired_peers, error)),            fail);
627
628    CFReleaseNull(arrayToEncode);
629    return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, sequence_size);
630
631fail:
632    CFReleaseNull(arrayToEncode);
633    SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("don't know how to encode"), NULL, error);
634    return 0;
635}
636
637uint8_t* SOSAccountEncodeToDER_V2(SOSAccountRef account, CFErrorRef* error, const uint8_t* der, uint8_t* der_end)
638{
639    CFMutableArrayRef arrayToEncode = SOSAccountCopyCircleArrayToEncode(account);
640
641    der_end =  ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der,
642    der_encode_dictionary(account->gestalt, error, der,
643    der_encode_array(arrayToEncode, error, der,
644    ccder_encode_uint64(account->departure_code, der,
645    ccder_encode_bool(account->user_public_trusted, der,
646    der_encode_public_bytes(account->user_public, error, der,
647    der_encode_data_or_null(account->user_key_parameters, error, der,
648    der_encode_dictionary(account->retired_peers, error, der, der_end))))))));
649
650    CFReleaseNull(arrayToEncode);
651
652    return der_end;
653}
654
655
656/* Original V1 encoders */
657
658
659size_t SOSAccountGetDEREncodedSize_V1(SOSAccountRef account, CFErrorRef *error)
660{
661    size_t sequence_size = 0;
662    CFMutableArrayRef arrayToEncode = SOSAccountCopyCircleArrayToEncode(account);
663
664    require_quiet(accumulate_size(&sequence_size, der_sizeof_dictionary(account->gestalt, error)),                  fail);
665    require_quiet(accumulate_size(&sequence_size, der_sizeof_array(arrayToEncode, error)),                          fail);
666    require_quiet(accumulate_size(&sequence_size, ccder_sizeof_bool(account->user_public_trusted, error)),          fail);
667    require_quiet(accumulate_size(&sequence_size, der_sizeof_public_bytes(account->user_public, error)),            fail);
668    require_quiet(accumulate_size(&sequence_size, der_sizeof_data_or_null(account->user_key_parameters, error)),    fail);
669    require_quiet(accumulate_size(&sequence_size, der_sizeof_dictionary(account->retired_peers, error)),            fail);
670
671    CFReleaseNull(arrayToEncode);
672    return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, sequence_size);
673
674fail:
675    CFReleaseNull(arrayToEncode);
676    SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("don't know how to encode"), NULL, error);
677    return 0;
678}
679
680uint8_t* SOSAccountEncodeToDER_V1(SOSAccountRef account, CFErrorRef* error, const uint8_t* der, uint8_t* der_end)
681{
682    CFMutableArrayRef arrayToEncode = SOSAccountCopyCircleArrayToEncode(account);
683
684    der_end =  ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der,
685    der_encode_dictionary(account->gestalt, error, der,
686    der_encode_array(arrayToEncode, error, der,
687    ccder_encode_bool(account->user_public_trusted, der,
688    der_encode_public_bytes(account->user_public, error, der,
689    der_encode_data_or_null(account->user_key_parameters, error, der,
690    der_encode_dictionary(account->retired_peers, error, der, der_end)))))));
691
692    CFReleaseNull(arrayToEncode);
693
694    return der_end;
695}
696
697/************************/
698
699CFDataRef SOSAccountCopyEncodedData(SOSAccountRef account, CFAllocatorRef allocator, CFErrorRef *error)
700{
701    size_t size = SOSAccountGetDEREncodedSize(account, error);
702    if (size == 0)
703        return NULL;
704    uint8_t buffer[size];
705    uint8_t* start = SOSAccountEncodeToDER(account, error, buffer, buffer + sizeof(buffer));
706    CFDataRef result = CFDataCreate(kCFAllocatorDefault, start, size);
707    return result;
708}
709
710