2 * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
28 #include <AssertMacros.h>
29 #include "SOSAccountPriv.h"
32 #include <utilities/SecCFWrappers.h>
33 #include <utilities/SecCoreCrypto.h>
34 #include <Security/SecureObjectSync/SOSKVSKeys.h>
35 #include <SOSPeerInfoDER.h>
37 #include <Security/SecureObjectSync/SOSPeerInfoCollections.h>
41 static SOSAccountRef
SOSAccountCreateFromRemainingDER_v6(CFAllocatorRef allocator
,
42 SOSDataSourceFactoryRef factory
,
44 const uint8_t** der_p
, const uint8_t *der_end
)
46 SOSAccountRef result
= NULL
;
47 SOSAccountRef account
= NULL
;
48 CFArrayRef array
= NULL
;
49 CFDictionaryRef retiredPeers
= NULL
;
50 CFStringRef circle_name
= factory
->copy_name(factory
);
53 CFDictionaryRef decoded_gestalt
= NULL
;
54 *der_p
= der_decode_dictionary(kCFAllocatorDefault
, kCFPropertyListImmutable
, &decoded_gestalt
, error
,
60 account
= SOSAccountCreateBasic(allocator
, decoded_gestalt
, factory
);
61 CFReleaseNull(decoded_gestalt
);
64 *der_p
= der_decode_array(kCFAllocatorDefault
, 0, &array
, error
, *der_p
, der_end
);
66 uint64_t tmp_departure_code
= kSOSNeverAppliedToCircle
;
67 *der_p
= ccder_decode_uint64(&tmp_departure_code
, *der_p
, der_end
);
68 *der_p
= ccder_decode_bool(&account
->user_public_trusted
, *der_p
, der_end
);
69 *der_p
= der_decode_public_bytes(kCFAllocatorDefault
, kSecECDSAAlgorithmID
, &account
->user_public
, error
, *der_p
, der_end
);
70 *der_p
= der_decode_public_bytes(kCFAllocatorDefault
, kSecECDSAAlgorithmID
, &account
->previous_public
, error
, *der_p
, der_end
);
71 *der_p
= der_decode_data_or_null(kCFAllocatorDefault
, &account
->user_key_parameters
, error
, *der_p
, der_end
);
73 *der_p
= der_decode_dictionary(kCFAllocatorDefault
, kCFPropertyListMutableContainers
, (CFDictionaryRef
*) &retiredPeers
, error
, *der_p
, der_end
);
74 require_action_quiet(*der_p
== der_end
, fail
, *der_p
= NULL
);
76 account
->departure_code
= (enum DepartureReason
) tmp_departure_code
;
78 CFDictionaryForEach(retiredPeers
, ^(const void *key
, const void *value
) {
80 SOSPeerInfoRef retiree
= SOSPeerInfoCreateFromData(kCFAllocatorDefault
, NULL
, (CFDataRef
) value
);
82 CFSetAddValue(account
->retirees
, retiree
);
84 CFReleaseNull(retiree
);
88 require_quiet(array
&& *der_p
, fail
);
90 CFArrayForEach(array
, ^(const void *value
) {
91 CFDataRef circleData
= NULL
;
92 CFDataRef fullPeerInfoData
= NULL
;
95 circleData
= (CFDataRef
) value
;
96 } else if (isArray(value
)) {
97 CFArrayRef pair
= (CFArrayRef
) value
;
99 CFTypeRef circleObject
= CFArrayGetValueAtIndex(pair
, 0);
100 CFTypeRef fullPeerInfoObject
= CFArrayGetValueAtIndex(pair
, 1);
102 if (CFArrayGetCount(pair
) == 2 && isData(circleObject
) && isData(fullPeerInfoObject
)) {
103 circleData
= (CFDataRef
) circleObject
;
104 fullPeerInfoData
= (CFDataRef
) fullPeerInfoObject
;
109 SOSCircleRef circle
= SOSCircleCreateFromData(kCFAllocatorDefault
, circleData
, error
);
110 require_quiet(circle
&& CFEqualSafe(circle_name
, SOSCircleGetName(circle
)), fail
);
112 account
->trusted_circle
= CFRetainSafe(circle
);
114 if(fullPeerInfoData
) {
115 account
->my_identity
= SOSFullPeerInfoCreateFromData(kCFAllocatorDefault
, fullPeerInfoData
, NULL
);
119 CFReleaseNull(circle
);
122 CFReleaseNull(array
);
124 require_action_quiet(SOSAccountEnsureFactoryCircles(account
), fail
,
125 SOSCreateError(kSOSErrorBadFormat
, CFSTR("Cannot EnsureFactoryCircles"), (error
!= NULL
) ? *error
: NULL
, error
));
127 result
= CFRetainSafe(account
);
130 CFReleaseNull(account
);
134 static size_t der_sizeof_data_optional(CFDataRef data
)
136 return data
? der_sizeof_data(data
, NULL
) : 0;
140 static uint8_t* der_encode_data_optional(CFDataRef data
, CFErrorRef
*error
,
141 const uint8_t *der
, uint8_t *der_end
)
143 return data
? der_encode_data(data
, error
, der
, der_end
) : der_end
;
147 static const uint8_t* der_decode_data_optional(CFAllocatorRef allocator
, CFOptionFlags mutability
,
148 CFDataRef
* data
, CFErrorRef
*error
,
149 const uint8_t* der
, const uint8_t *der_end
)
151 const uint8_t *dt_end
= der_decode_data(allocator
, mutability
, data
, NULL
, der
, der_end
);
153 return dt_end
? dt_end
: der
;
156 static SOSAccountRef
SOSAccountCreateFromRemainingDER_v7(CFAllocatorRef allocator
,
157 SOSDataSourceFactoryRef factory
,
159 const uint8_t** der_p
, const uint8_t *der_end
)
161 SOSAccountRef account
= NULL
;
162 SOSAccountRef result
= NULL
;
165 CFDictionaryRef decoded_gestalt
= NULL
;
166 *der_p
= der_decode_dictionary(kCFAllocatorDefault
, kCFPropertyListImmutable
, &decoded_gestalt
, error
,
172 account
= SOSAccountCreateBasic(allocator
, decoded_gestalt
, factory
);
173 CFReleaseNull(decoded_gestalt
);
176 account
->trusted_circle
= SOSCircleCreateFromDER(kCFAllocatorDefault
, error
, der_p
, der_end
);
177 *der_p
= der_decode_fullpeer_or_null(kCFAllocatorDefault
, &account
->my_identity
, error
, *der_p
, der_end
);
179 uint64_t tmp_departure_code
= kSOSNeverAppliedToCircle
;
180 *der_p
= ccder_decode_uint64(&tmp_departure_code
, *der_p
, der_end
);
181 *der_p
= ccder_decode_bool(&account
->user_public_trusted
, *der_p
, der_end
);
182 *der_p
= der_decode_public_bytes(kCFAllocatorDefault
, kSecECDSAAlgorithmID
, &account
->user_public
, error
, *der_p
, der_end
);
183 *der_p
= der_decode_public_bytes(kCFAllocatorDefault
, kSecECDSAAlgorithmID
, &account
->previous_public
, error
, *der_p
, der_end
);
184 *der_p
= der_decode_data_or_null(kCFAllocatorDefault
, &account
->user_key_parameters
, error
, *der_p
, der_end
);
185 account
->retirees
= SOSPeerInfoSetCreateFromArrayDER(kCFAllocatorDefault
, &kSOSPeerSetCallbacks
, error
, der_p
, der_end
);
186 *der_p
= der_decode_data_optional(kCFAllocatorDefault
, kCFPropertyListImmutable
, &account
->backup_key
, error
, *der_p
, der_end
);
188 account
->departure_code
= (enum DepartureReason
) tmp_departure_code
;
190 require_action_quiet(*der_p
&& *der_p
== der_end
, fail
,
191 SOSCreateError(kSOSErrorBadFormat
, CFSTR("Didn't consume all bytes v7"), (error
!= NULL
) ? *error
: NULL
, error
));
193 result
= CFRetainSafe(account
);
196 CFReleaseNull(account
);
201 static SOSAccountRef
SOSAccountCreateFromRemainingDER_v8(CFAllocatorRef allocator
,
202 SOSDataSourceFactoryRef factory
,
204 const uint8_t** der_p
, const uint8_t *der_end
)
206 SOSAccountRef account
= NULL
;
207 SOSAccountRef result
= NULL
;
210 CFDictionaryRef decoded_gestalt
= NULL
;
211 *der_p
= der_decode_dictionary(kCFAllocatorDefault
, kCFPropertyListImmutable
, &decoded_gestalt
, error
,
217 account
= SOSAccountCreateBasic(allocator
, decoded_gestalt
, factory
);
218 CFReleaseNull(decoded_gestalt
);
220 CFReleaseNull(account
->trusted_circle
);
221 account
->trusted_circle
= SOSCircleCreateFromDER(kCFAllocatorDefault
, error
, der_p
, der_end
);
222 CFReleaseNull(account
->my_identity
);
223 *der_p
= der_decode_fullpeer_or_null(kCFAllocatorDefault
, &account
->my_identity
, error
, *der_p
, der_end
);
225 uint64_t tmp_departure_code
= kSOSNeverAppliedToCircle
;
226 *der_p
= ccder_decode_uint64(&tmp_departure_code
, *der_p
, der_end
);
227 *der_p
= ccder_decode_bool(&account
->user_public_trusted
, *der_p
, der_end
);
228 *der_p
= der_decode_public_bytes(kCFAllocatorDefault
, kSecECDSAAlgorithmID
, &account
->user_public
, error
, *der_p
, der_end
);
229 *der_p
= der_decode_public_bytes(kCFAllocatorDefault
, kSecECDSAAlgorithmID
, &account
->previous_public
, error
, *der_p
, der_end
);
230 *der_p
= der_decode_data_or_null(kCFAllocatorDefault
, &account
->user_key_parameters
, error
, *der_p
, der_end
);
231 CFReleaseNull(account
->retirees
);
232 account
->retirees
= SOSPeerInfoSetCreateFromArrayDER(kCFAllocatorDefault
, &kSOSPeerSetCallbacks
, error
, der_p
, der_end
);
233 *der_p
= der_decode_data_optional(kCFAllocatorDefault
, kCFPropertyListImmutable
, &account
->backup_key
, error
, *der_p
, der_end
);
235 CFDictionaryRef expansion
= NULL
;
236 *der_p
= der_decode_dictionary(kCFAllocatorDefault
, kCFPropertyListImmutable
, &expansion
, error
,
242 CFReleaseNull(account
->expansion
);
243 account
->expansion
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, expansion
);
244 CFReleaseNull(expansion
);
247 account
->departure_code
= (enum DepartureReason
) tmp_departure_code
;
249 require_action_quiet(*der_p
&& *der_p
== der_end
, fail
,
250 SOSCreateError(kSOSErrorBadFormat
, CFSTR("Didn't consume all bytes v7"), (error
!= NULL
) ? *error
: NULL
, error
));
252 result
= CFRetainSafe(account
);
255 CFReleaseNull(account
);
260 // Version History for Account
262 // 1-5 - InnsbruckTaos/Cab; Never supported even for upgrading.
263 // 6 - First version used in the field.
264 // 7 - One Circle version
265 // 8 - Adding expansion dictionary
268 #define CURRENT_ACCOUNT_PERSISTENT_VERSION 8
270 SOSAccountRef
SOSAccountCreateFromDER(CFAllocatorRef allocator
,
271 SOSDataSourceFactoryRef factory
,
273 const uint8_t** der_p
, const uint8_t *der_end
)
275 SOSAccountRef account
= NULL
;
276 SOSAccountRef result
= NULL
;
277 uint64_t version
= 0;
279 const uint8_t *sequence_end
;
280 *der_p
= ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
, &sequence_end
, *der_p
, der_end
);
281 *der_p
= ccder_decode_uint64(&version
, *der_p
, sequence_end
);
282 require_action_quiet(*der_p
, errOut
,
283 SOSCreateError(kSOSErrorBadFormat
, CFSTR("Version parsing failed"), (error
!= NULL
) ? *error
: NULL
, error
));
286 case CURRENT_ACCOUNT_PERSISTENT_VERSION
:
287 account
= SOSAccountCreateFromRemainingDER_v8(allocator
, factory
, error
, der_p
, sequence_end
);
291 account
= SOSAccountCreateFromRemainingDER_v7(allocator
, factory
, error
, der_p
, sequence_end
);
295 account
= SOSAccountCreateFromRemainingDER_v6(allocator
, factory
, error
, der_p
, sequence_end
);
299 SOSCreateErrorWithFormat(kSOSErrorBadFormat
, (error
!= NULL
) ? *error
: NULL
, error
,
300 NULL
, CFSTR("Unsupported version (%llu)"), version
);
304 require_quiet(account
, errOut
);
306 require_quiet(*der_p
&& *der_p
== sequence_end
, errOut
);
308 /* I may not always have an identity, but when I do, it has a private key */
309 if(account
->my_identity
) {
310 require_action_quiet(SOSFullPeerInfoPrivKeyExists(account
->my_identity
), errOut
, secnotice("account", "No private key associated with my_identity, resetting"));
313 require_action_quiet(SOSAccountEnsureFactoryCircles(account
), errOut
,
314 SOSCreateError(kSOSErrorBadFormat
, CFSTR("Cannot EnsureFactoryCircles"), (error
!= NULL
) ? *error
: NULL
, error
));
316 SOSPeerInfoRef myPI
= SOSAccountGetMyPeerInfo(account
);
318 // if we were syncing legacy keychain, ensure we include those legacy views.
319 bool wasSyncingLegacy
= !SOSPeerInfoVersionIsCurrent(myPI
) && SOSAccountIsInCircle(account
, NULL
);
320 CFSetRef viewsToEnsure
= SOSViewsCreateDefault(wasSyncingLegacy
, NULL
);
321 SOSAccountUpdateFullPeerInfo(account
, viewsToEnsure
);
322 CFReleaseNull(viewsToEnsure
);
325 SOSAccountCheckHasBeenInSync(account
);
327 result
= CFRetainSafe(account
);
330 CFReleaseNull(account
);
334 SOSAccountRef
SOSAccountCreateFromData(CFAllocatorRef allocator
, CFDataRef circleData
,
335 SOSDataSourceFactoryRef factory
,
338 size_t size
= CFDataGetLength(circleData
);
339 const uint8_t *der
= CFDataGetBytePtr(circleData
);
340 SOSAccountRef account
= SOSAccountCreateFromDER(allocator
, factory
,
346 CFMutableSetRef
SOSPeerInfoSetCreateFromArrayDER(CFAllocatorRef allocator
, const CFSetCallBacks
*callbacks
, CFErrorRef
* error
,
347 const uint8_t** der_p
, const uint8_t *der_end
);
348 size_t SOSPeerInfoSetGetDEREncodedArraySize(CFSetRef pia
, CFErrorRef
*error
);
349 uint8_t* SOSPeerInfoSetEncodeToArrayDER(CFSetRef pia
, CFErrorRef
* error
, const uint8_t* der
, uint8_t* der_end
);
351 size_t SOSAccountGetDEREncodedSize(SOSAccountRef account
, CFErrorRef
*error
)
353 size_t sequence_size
= 0;
354 uint64_t version
= CURRENT_ACCOUNT_PERSISTENT_VERSION
;
356 require_quiet(accumulate_size(&sequence_size
, ccder_sizeof_uint64(version
)), fail
);
357 require_quiet(accumulate_size(&sequence_size
, der_sizeof_dictionary(account
->gestalt
, error
)), fail
);
358 require_quiet(accumulate_size(&sequence_size
, SOSCircleGetDEREncodedSize(account
->trusted_circle
, error
)), fail
);
359 require_quiet(accumulate_size(&sequence_size
, der_sizeof_fullpeer_or_null(account
->my_identity
, error
)), fail
);
360 require_quiet(accumulate_size(&sequence_size
, ccder_sizeof_uint64(account
->departure_code
)), fail
);
361 require_quiet(accumulate_size(&sequence_size
, ccder_sizeof_bool(account
->user_public_trusted
, error
)), fail
);
362 require_quiet(accumulate_size(&sequence_size
, der_sizeof_public_bytes(account
->user_public
, error
)), fail
);
363 require_quiet(accumulate_size(&sequence_size
, der_sizeof_public_bytes(account
->previous_public
, error
)), fail
);
364 require_quiet(accumulate_size(&sequence_size
, der_sizeof_data_or_null(account
->user_key_parameters
, error
)), fail
);
365 require_quiet(accumulate_size(&sequence_size
, SOSPeerInfoSetGetDEREncodedArraySize(account
->retirees
, error
)), fail
);
366 accumulate_size(&sequence_size
, der_sizeof_data_optional(account
->backup_key
));
367 require_quiet(accumulate_size(&sequence_size
, der_sizeof_dictionary(account
->expansion
, error
)), fail
);
369 return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE
, sequence_size
);
372 SecCFDERCreateError(kSecDERErrorUnknownEncoding
, CFSTR("don't know how to encode"), NULL
, error
);
376 uint8_t* SOSAccountEncodeToDER(SOSAccountRef account
, CFErrorRef
* error
, const uint8_t* der
, uint8_t* der_end
)
378 uint64_t version
= CURRENT_ACCOUNT_PERSISTENT_VERSION
;
379 der_end
= ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
, der_end
, der
,
380 ccder_encode_uint64(version
, der
,
381 der_encode_dictionary(account
->gestalt
, error
, der
,
382 SOSCircleEncodeToDER(account
->trusted_circle
, error
, der
,
383 der_encode_fullpeer_or_null(account
->my_identity
, error
, der
,
384 ccder_encode_uint64(account
->departure_code
, der
,
385 ccder_encode_bool(account
->user_public_trusted
, der
,
386 der_encode_public_bytes(account
->user_public
, error
, der
,
387 der_encode_public_bytes(account
->previous_public
, error
, der
,
388 der_encode_data_or_null(account
->user_key_parameters
, error
, der
,
389 SOSPeerInfoSetEncodeToArrayDER(account
->retirees
, error
, der
,
390 der_encode_data_optional(account
->backup_key
, error
, der
,
391 der_encode_dictionary(account
->expansion
, error
, der
,
394 der_end
)))))))))))));
399 /************************/
401 CFDataRef
SOSAccountCopyEncodedData(SOSAccountRef account
, CFAllocatorRef allocator
, CFErrorRef
*error
)
403 size_t size
= SOSAccountGetDEREncodedSize(account
, error
);
406 uint8_t buffer
[size
];
407 uint8_t* start
= SOSAccountEncodeToDER(account
, error
, buffer
, buffer
+ sizeof(buffer
));
408 CFDataRef result
= CFDataCreate(kCFAllocatorDefault
, start
, size
);