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/SOSTransport.h>
39 #include <Security/SecureObjectSync/SOSPeerInfoCollections.h>
43 static SOSAccountRef
SOSAccountCreateFromRemainingDER_v6(CFAllocatorRef allocator
,
44 SOSDataSourceFactoryRef factory
,
46 const uint8_t** der_p
, const uint8_t *der_end
)
48 SOSAccountRef result
= NULL
;
49 SOSAccountRef account
= NULL
;
50 CFArrayRef array
= NULL
;
51 CFDictionaryRef retiredPeers
= NULL
;
52 CFStringRef circle_name
= factory
->copy_name(factory
);
55 CFDictionaryRef decoded_gestalt
= NULL
;
56 *der_p
= der_decode_dictionary(kCFAllocatorDefault
, kCFPropertyListImmutable
, &decoded_gestalt
, error
,
62 account
= SOSAccountCreateBasic(allocator
, decoded_gestalt
, factory
);
63 CFReleaseNull(decoded_gestalt
);
66 *der_p
= der_decode_array(kCFAllocatorDefault
, 0, &array
, error
, *der_p
, der_end
);
68 uint64_t tmp_departure_code
= kSOSNeverAppliedToCircle
;
69 *der_p
= ccder_decode_uint64(&tmp_departure_code
, *der_p
, der_end
);
70 *der_p
= ccder_decode_bool(&account
->user_public_trusted
, *der_p
, der_end
);
71 *der_p
= der_decode_public_bytes(kCFAllocatorDefault
, kSecECDSAAlgorithmID
, &account
->user_public
, error
, *der_p
, der_end
);
72 *der_p
= der_decode_public_bytes(kCFAllocatorDefault
, kSecECDSAAlgorithmID
, &account
->previous_public
, error
, *der_p
, der_end
);
73 *der_p
= der_decode_data_or_null(kCFAllocatorDefault
, &account
->user_key_parameters
, error
, *der_p
, der_end
);
75 *der_p
= der_decode_dictionary(kCFAllocatorDefault
, kCFPropertyListMutableContainers
, (CFDictionaryRef
*) &retiredPeers
, error
, *der_p
, der_end
);
76 require_action_quiet(*der_p
== der_end
, fail
, *der_p
= NULL
);
78 account
->departure_code
= (enum DepartureReason
) tmp_departure_code
;
80 CFDictionaryForEach(retiredPeers
, ^(const void *key
, const void *value
) {
82 SOSPeerInfoRef retiree
= SOSPeerInfoCreateFromData(kCFAllocatorDefault
, NULL
, (CFDataRef
) value
);
84 CFSetAddValue(account
->retirees
, retiree
);
86 CFReleaseNull(retiree
);
90 require_quiet(array
&& *der_p
, fail
);
92 CFArrayForEach(array
, ^(const void *value
) {
93 CFDataRef circleData
= NULL
;
94 CFDataRef fullPeerInfoData
= NULL
;
97 circleData
= (CFDataRef
) value
;
98 } else if (isArray(value
)) {
99 CFArrayRef pair
= (CFArrayRef
) value
;
101 CFTypeRef circleObject
= CFArrayGetValueAtIndex(pair
, 0);
102 CFTypeRef fullPeerInfoObject
= CFArrayGetValueAtIndex(pair
, 1);
104 if (CFArrayGetCount(pair
) == 2 && isData(circleObject
) && isData(fullPeerInfoObject
)) {
105 circleData
= (CFDataRef
) circleObject
;
106 fullPeerInfoData
= (CFDataRef
) fullPeerInfoObject
;
111 SOSCircleRef circle
= SOSCircleCreateFromData(kCFAllocatorDefault
, circleData
, error
);
112 require_quiet(circle
&& CFEqualSafe(circle_name
, SOSCircleGetName(circle
)), fail
);
114 account
->trusted_circle
= CFRetainSafe(circle
);
116 if(fullPeerInfoData
) {
117 account
->my_identity
= SOSFullPeerInfoCreateFromData(kCFAllocatorDefault
, fullPeerInfoData
, NULL
);
121 CFReleaseNull(circle
);
124 CFReleaseNull(array
);
126 require_action_quiet(SOSAccountEnsureFactoryCircles(account
), fail
,
127 SOSCreateError(kSOSErrorBadFormat
, CFSTR("Cannot EnsureFactoryCircles"), (error
!= NULL
) ? *error
: NULL
, error
));
129 result
= CFRetainSafe(account
);
132 CFReleaseNull(account
);
136 static size_t der_sizeof_data_optional(CFDataRef data
)
138 return data
? der_sizeof_data(data
, NULL
) : 0;
142 static uint8_t* der_encode_data_optional(CFDataRef data
, CFErrorRef
*error
,
143 const uint8_t *der
, uint8_t *der_end
)
145 return data
? der_encode_data(data
, error
, der
, der_end
) : der_end
;
149 static const uint8_t* der_decode_data_optional(CFAllocatorRef allocator
, CFOptionFlags mutability
,
150 CFDataRef
* data
, CFErrorRef
*error
,
151 const uint8_t* der
, const uint8_t *der_end
)
153 const uint8_t *dt_end
= der_decode_data(allocator
, mutability
, data
, NULL
, der
, der_end
);
155 return dt_end
? dt_end
: der
;
158 static SOSAccountRef
SOSAccountCreateFromRemainingDER_v7(CFAllocatorRef allocator
,
159 SOSDataSourceFactoryRef factory
,
161 const uint8_t** der_p
, const uint8_t *der_end
)
163 SOSAccountRef account
= NULL
;
164 SOSAccountRef result
= NULL
;
167 CFDictionaryRef decoded_gestalt
= NULL
;
168 *der_p
= der_decode_dictionary(kCFAllocatorDefault
, kCFPropertyListImmutable
, &decoded_gestalt
, error
,
174 account
= SOSAccountCreateBasic(allocator
, decoded_gestalt
, factory
);
175 CFReleaseNull(decoded_gestalt
);
178 account
->trusted_circle
= SOSCircleCreateFromDER(kCFAllocatorDefault
, error
, der_p
, der_end
);
179 *der_p
= der_decode_fullpeer_or_null(kCFAllocatorDefault
, &account
->my_identity
, error
, *der_p
, der_end
);
181 uint64_t tmp_departure_code
= kSOSNeverAppliedToCircle
;
182 *der_p
= ccder_decode_uint64(&tmp_departure_code
, *der_p
, der_end
);
183 *der_p
= ccder_decode_bool(&account
->user_public_trusted
, *der_p
, der_end
);
184 *der_p
= der_decode_public_bytes(kCFAllocatorDefault
, kSecECDSAAlgorithmID
, &account
->user_public
, error
, *der_p
, der_end
);
185 *der_p
= der_decode_public_bytes(kCFAllocatorDefault
, kSecECDSAAlgorithmID
, &account
->previous_public
, error
, *der_p
, der_end
);
186 *der_p
= der_decode_data_or_null(kCFAllocatorDefault
, &account
->user_key_parameters
, error
, *der_p
, der_end
);
187 account
->retirees
= SOSPeerInfoSetCreateFromArrayDER(kCFAllocatorDefault
, &kSOSPeerSetCallbacks
, error
, der_p
, der_end
);
188 *der_p
= der_decode_data_optional(kCFAllocatorDefault
, kCFPropertyListImmutable
, &account
->backup_key
, error
, *der_p
, der_end
);
190 account
->departure_code
= (enum DepartureReason
) tmp_departure_code
;
192 require_action_quiet(*der_p
&& *der_p
== der_end
, fail
,
193 SOSCreateError(kSOSErrorBadFormat
, CFSTR("Didn't consume all bytes v7"), (error
!= NULL
) ? *error
: NULL
, error
));
195 result
= CFRetainSafe(account
);
198 CFReleaseNull(account
);
203 static SOSAccountRef
SOSAccountCreateFromRemainingDER_v8(CFAllocatorRef allocator
,
204 SOSDataSourceFactoryRef factory
,
206 const uint8_t** der_p
, const uint8_t *der_end
)
208 SOSAccountRef account
= NULL
;
209 SOSAccountRef result
= NULL
;
212 CFDictionaryRef decoded_gestalt
= NULL
;
213 *der_p
= der_decode_dictionary(kCFAllocatorDefault
, kCFPropertyListImmutable
, &decoded_gestalt
, error
,
219 account
= SOSAccountCreateBasic(allocator
, decoded_gestalt
, factory
);
220 CFReleaseNull(decoded_gestalt
);
222 CFReleaseNull(account
->trusted_circle
);
223 account
->trusted_circle
= SOSCircleCreateFromDER(kCFAllocatorDefault
, error
, der_p
, der_end
);
224 CFReleaseNull(account
->my_identity
);
225 *der_p
= der_decode_fullpeer_or_null(kCFAllocatorDefault
, &account
->my_identity
, error
, *der_p
, der_end
);
227 uint64_t tmp_departure_code
= kSOSNeverAppliedToCircle
;
228 *der_p
= ccder_decode_uint64(&tmp_departure_code
, *der_p
, der_end
);
229 *der_p
= ccder_decode_bool(&account
->user_public_trusted
, *der_p
, der_end
);
230 *der_p
= der_decode_public_bytes(kCFAllocatorDefault
, kSecECDSAAlgorithmID
, &account
->user_public
, error
, *der_p
, der_end
);
231 *der_p
= der_decode_public_bytes(kCFAllocatorDefault
, kSecECDSAAlgorithmID
, &account
->previous_public
, error
, *der_p
, der_end
);
232 *der_p
= der_decode_data_or_null(kCFAllocatorDefault
, &account
->user_key_parameters
, error
, *der_p
, der_end
);
233 CFReleaseNull(account
->retirees
);
234 account
->retirees
= SOSPeerInfoSetCreateFromArrayDER(kCFAllocatorDefault
, &kSOSPeerSetCallbacks
, error
, der_p
, der_end
);
235 *der_p
= der_decode_data_optional(kCFAllocatorDefault
, kCFPropertyListImmutable
, &account
->backup_key
, error
, *der_p
, der_end
);
237 CFDictionaryRef expansion
= NULL
;
238 *der_p
= der_decode_dictionary(kCFAllocatorDefault
, kCFPropertyListImmutable
, &expansion
, error
,
244 CFReleaseNull(account
->expansion
);
245 account
->expansion
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, expansion
);
246 CFReleaseNull(expansion
);
249 account
->departure_code
= (enum DepartureReason
) tmp_departure_code
;
251 require_action_quiet(*der_p
&& *der_p
== der_end
, fail
,
252 SOSCreateError(kSOSErrorBadFormat
, CFSTR("Didn't consume all bytes v7"), (error
!= NULL
) ? *error
: NULL
, error
));
254 result
= CFRetainSafe(account
);
257 CFReleaseNull(account
);
262 // Version History for Account
264 // 1-5 - InnsbruckTaos/Cab; Never supported even for upgrading.
265 // 6 - First version used in the field.
266 // 7 - One Circle version
267 // 8 - Adding expansion dictionary
270 #define CURRENT_ACCOUNT_PERSISTENT_VERSION 8
272 SOSAccountRef
SOSAccountCreateFromDER(CFAllocatorRef allocator
,
273 SOSDataSourceFactoryRef factory
,
275 const uint8_t** der_p
, const uint8_t *der_end
)
277 SOSAccountRef account
= NULL
;
278 SOSAccountRef result
= NULL
;
279 uint64_t version
= 0;
281 const uint8_t *sequence_end
;
282 *der_p
= ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
, &sequence_end
, *der_p
, der_end
);
283 *der_p
= ccder_decode_uint64(&version
, *der_p
, sequence_end
);
284 require_action_quiet(*der_p
, errOut
,
285 SOSCreateError(kSOSErrorBadFormat
, CFSTR("Version parsing failed"), (error
!= NULL
) ? *error
: NULL
, error
));
288 case CURRENT_ACCOUNT_PERSISTENT_VERSION
:
289 account
= SOSAccountCreateFromRemainingDER_v8(allocator
, factory
, error
, der_p
, sequence_end
);
293 account
= SOSAccountCreateFromRemainingDER_v7(allocator
, factory
, error
, der_p
, sequence_end
);
297 account
= SOSAccountCreateFromRemainingDER_v6(allocator
, factory
, error
, der_p
, sequence_end
);
301 SOSCreateErrorWithFormat(kSOSErrorBadFormat
, (error
!= NULL
) ? *error
: NULL
, error
,
302 NULL
, CFSTR("Unsupported version (%llu)"), version
);
306 require_quiet(account
, errOut
);
308 require_quiet(*der_p
&& *der_p
== sequence_end
, errOut
);
310 /* I may not always have an identity, but when I do, it has a private key */
311 if(account
->my_identity
) {
312 require_action_quiet(SOSFullPeerInfoPrivKeyExists(account
->my_identity
), errOut
, secnotice("account", "No private key associated with my_identity, resetting"));
315 require_action_quiet(SOSAccountEnsureFactoryCircles(account
), errOut
,
316 SOSCreateError(kSOSErrorBadFormat
, CFSTR("Cannot EnsureFactoryCircles"), (error
!= NULL
) ? *error
: NULL
, error
));
318 SOSPeerInfoRef myPI
= SOSAccountGetMyPeerInfo(account
);
320 // if we were syncing legacy keychain, ensure we include those legacy views.
321 bool wasSyncingLegacy
= !SOSPeerInfoVersionIsCurrent(myPI
) && SOSAccountIsInCircle(account
, NULL
);
322 CFSetRef viewsToEnsure
= SOSViewsCreateDefault(wasSyncingLegacy
, NULL
);
323 SOSAccountUpdateFullPeerInfo(account
, viewsToEnsure
, SOSViewsGetV0ViewSet()); // We don't permit V0 view proper, only sub-views
324 CFReleaseNull(viewsToEnsure
);
327 SOSAccountCheckHasBeenInSync(account
);
329 SOSUpdateKeyInterest(account
);
331 result
= CFRetainSafe(account
);
334 CFReleaseNull(account
);
338 SOSAccountRef
SOSAccountCreateFromData(CFAllocatorRef allocator
, CFDataRef circleData
,
339 SOSDataSourceFactoryRef factory
,
342 size_t size
= CFDataGetLength(circleData
);
343 const uint8_t *der
= CFDataGetBytePtr(circleData
);
344 SOSAccountRef account
= SOSAccountCreateFromDER(allocator
, factory
,
350 CFMutableSetRef
SOSPeerInfoSetCreateFromArrayDER(CFAllocatorRef allocator
, const CFSetCallBacks
*callbacks
, CFErrorRef
* error
,
351 const uint8_t** der_p
, const uint8_t *der_end
);
352 size_t SOSPeerInfoSetGetDEREncodedArraySize(CFSetRef pia
, CFErrorRef
*error
);
353 uint8_t* SOSPeerInfoSetEncodeToArrayDER(CFSetRef pia
, CFErrorRef
* error
, const uint8_t* der
, uint8_t* der_end
);
355 size_t SOSAccountGetDEREncodedSize(SOSAccountRef account
, CFErrorRef
*error
)
357 size_t sequence_size
= 0;
358 uint64_t version
= CURRENT_ACCOUNT_PERSISTENT_VERSION
;
360 require_quiet(accumulate_size(&sequence_size
, ccder_sizeof_uint64(version
)), fail
);
361 require_quiet(accumulate_size(&sequence_size
, der_sizeof_dictionary(account
->gestalt
, error
)), fail
);
362 require_quiet(accumulate_size(&sequence_size
, SOSCircleGetDEREncodedSize(account
->trusted_circle
, error
)), fail
);
363 require_quiet(accumulate_size(&sequence_size
, der_sizeof_fullpeer_or_null(account
->my_identity
, error
)), fail
);
364 require_quiet(accumulate_size(&sequence_size
, ccder_sizeof_uint64(account
->departure_code
)), fail
);
365 require_quiet(accumulate_size(&sequence_size
, ccder_sizeof_bool(account
->user_public_trusted
, error
)), fail
);
366 require_quiet(accumulate_size(&sequence_size
, der_sizeof_public_bytes(account
->user_public
, error
)), fail
);
367 require_quiet(accumulate_size(&sequence_size
, der_sizeof_public_bytes(account
->previous_public
, error
)), fail
);
368 require_quiet(accumulate_size(&sequence_size
, der_sizeof_data_or_null(account
->user_key_parameters
, error
)), fail
);
369 require_quiet(accumulate_size(&sequence_size
, SOSPeerInfoSetGetDEREncodedArraySize(account
->retirees
, error
)), fail
);
370 accumulate_size(&sequence_size
, der_sizeof_data_optional(account
->backup_key
));
371 require_quiet(accumulate_size(&sequence_size
, der_sizeof_dictionary(account
->expansion
, error
)), fail
);
373 return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE
, sequence_size
);
376 SecCFDERCreateError(kSecDERErrorUnknownEncoding
, CFSTR("don't know how to encode"), NULL
, error
);
380 uint8_t* SOSAccountEncodeToDER(SOSAccountRef account
, CFErrorRef
* error
, const uint8_t* der
, uint8_t* der_end
)
382 uint64_t version
= CURRENT_ACCOUNT_PERSISTENT_VERSION
;
383 der_end
= ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
, der_end
, der
,
384 ccder_encode_uint64(version
, der
,
385 der_encode_dictionary(account
->gestalt
, error
, der
,
386 SOSCircleEncodeToDER(account
->trusted_circle
, error
, der
,
387 der_encode_fullpeer_or_null(account
->my_identity
, error
, der
,
388 ccder_encode_uint64(account
->departure_code
, der
,
389 ccder_encode_bool(account
->user_public_trusted
, der
,
390 der_encode_public_bytes(account
->user_public
, error
, der
,
391 der_encode_public_bytes(account
->previous_public
, error
, der
,
392 der_encode_data_or_null(account
->user_key_parameters
, error
, der
,
393 SOSPeerInfoSetEncodeToArrayDER(account
->retirees
, error
, der
,
394 der_encode_data_optional(account
->backup_key
, error
, der
,
395 der_encode_dictionary(account
->expansion
, error
, der
,
398 der_end
)))))))))))));
403 /************************/
405 CFDataRef
SOSAccountCopyEncodedData(SOSAccountRef account
, CFAllocatorRef allocator
, CFErrorRef
*error
)
407 size_t size
= SOSAccountGetDEREncodedSize(account
, error
);
410 uint8_t buffer
[size
];
411 uint8_t* start
= SOSAccountEncodeToDER(account
, error
, buffer
, buffer
+ sizeof(buffer
));
412 CFDataRef result
= CFDataCreate(kCFAllocatorDefault
, start
, size
);