]> git.saurik.com Git - apple/security.git/blob - OSX/sec/SOSCircle/SecureObjectSync/SOSAccountPersistence.c
Security-57337.20.44.tar.gz
[apple/security.git] / OSX / 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 #include "SOSViews.h"
31
32 #include <utilities/SecCFWrappers.h>
33 #include <utilities/SecCoreCrypto.h>
34 #include <Security/SecureObjectSync/SOSKVSKeys.h>
35 #include <SOSPeerInfoDER.h>
36
37 #include <Security/SecureObjectSync/SOSTransport.h>
38
39 #include <Security/SecureObjectSync/SOSPeerInfoCollections.h>
40
41
42
43 static SOSAccountRef SOSAccountCreateFromRemainingDER_v6(CFAllocatorRef allocator,
44 SOSDataSourceFactoryRef factory,
45 CFErrorRef* error,
46 const uint8_t** der_p, const uint8_t *der_end)
47 {
48 SOSAccountRef result = NULL;
49 SOSAccountRef account = NULL;
50 CFArrayRef array = NULL;
51 CFDictionaryRef retiredPeers = NULL;
52 CFStringRef circle_name = factory->copy_name(factory);
53
54 {
55 CFDictionaryRef decoded_gestalt = NULL;
56 *der_p = der_decode_dictionary(kCFAllocatorDefault, kCFPropertyListImmutable, &decoded_gestalt, error,
57 *der_p, der_end);
58
59 if (*der_p == 0)
60 return NULL;
61
62 account = SOSAccountCreateBasic(allocator, decoded_gestalt, factory);
63 CFReleaseNull(decoded_gestalt);
64 }
65
66 *der_p = der_decode_array(kCFAllocatorDefault, 0, &array, error, *der_p, der_end);
67
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);
74
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);
77
78 account->departure_code = (enum DepartureReason) tmp_departure_code;
79
80 CFDictionaryForEach(retiredPeers, ^(const void *key, const void *value) {
81 if (isData(value)) {
82 SOSPeerInfoRef retiree = SOSPeerInfoCreateFromData(kCFAllocatorDefault, NULL, (CFDataRef) value);
83
84 CFSetAddValue(account->retirees, retiree);
85
86 CFReleaseNull(retiree);
87 }
88 });
89
90 require_quiet(array && *der_p, fail);
91
92 CFArrayForEach(array, ^(const void *value) {
93 CFDataRef circleData = NULL;
94 CFDataRef fullPeerInfoData = NULL;
95
96 if (isData(value)) {
97 circleData = (CFDataRef) value;
98 } else if (isArray(value)) {
99 CFArrayRef pair = (CFArrayRef) value;
100
101 CFTypeRef circleObject = CFArrayGetValueAtIndex(pair, 0);
102 CFTypeRef fullPeerInfoObject = CFArrayGetValueAtIndex(pair, 1);
103
104 if (CFArrayGetCount(pair) == 2 && isData(circleObject) && isData(fullPeerInfoObject)) {
105 circleData = (CFDataRef) circleObject;
106 fullPeerInfoData = (CFDataRef) fullPeerInfoObject;
107 }
108 }
109
110 if (circleData) {
111 SOSCircleRef circle = SOSCircleCreateFromData(kCFAllocatorDefault, circleData, error);
112 require_quiet(circle && CFEqualSafe(circle_name, SOSCircleGetName(circle)), fail);
113
114 account->trusted_circle = CFRetainSafe(circle);
115
116 if(fullPeerInfoData) {
117 account->my_identity = SOSFullPeerInfoCreateFromData(kCFAllocatorDefault, fullPeerInfoData, NULL);
118 }
119
120 fail:
121 CFReleaseNull(circle);
122 }
123 });
124 CFReleaseNull(array);
125
126 require_action_quiet(SOSAccountEnsureFactoryCircles(account), fail,
127 SOSCreateError(kSOSErrorBadFormat, CFSTR("Cannot EnsureFactoryCircles"), (error != NULL) ? *error : NULL, error));
128
129 result = CFRetainSafe(account);
130
131 fail:
132 CFReleaseNull(account);
133 return result;
134 }
135
136 static size_t der_sizeof_data_optional(CFDataRef data)
137 {
138 return data ? der_sizeof_data(data, NULL) : 0;
139
140 }
141
142 static uint8_t* der_encode_data_optional(CFDataRef data, CFErrorRef *error,
143 const uint8_t *der, uint8_t *der_end)
144 {
145 return data ? der_encode_data(data, error, der, der_end) : der_end;
146
147 }
148
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)
152 {
153 const uint8_t *dt_end = der_decode_data(allocator, mutability, data, NULL, der, der_end);
154
155 return dt_end ? dt_end : der;
156 }
157
158 static SOSAccountRef SOSAccountCreateFromRemainingDER_v7(CFAllocatorRef allocator,
159 SOSDataSourceFactoryRef factory,
160 CFErrorRef* error,
161 const uint8_t** der_p, const uint8_t *der_end)
162 {
163 SOSAccountRef account = NULL;
164 SOSAccountRef result = NULL;
165
166 {
167 CFDictionaryRef decoded_gestalt = NULL;
168 *der_p = der_decode_dictionary(kCFAllocatorDefault, kCFPropertyListImmutable, &decoded_gestalt, error,
169 *der_p, der_end);
170
171 if (*der_p == 0)
172 return NULL;
173
174 account = SOSAccountCreateBasic(allocator, decoded_gestalt, factory);
175 CFReleaseNull(decoded_gestalt);
176 }
177
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);
180
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);
189
190 account->departure_code = (enum DepartureReason) tmp_departure_code;
191
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));
194
195 result = CFRetainSafe(account);
196
197 fail:
198 CFReleaseNull(account);
199 return result;
200 }
201
202
203 static SOSAccountRef SOSAccountCreateFromRemainingDER_v8(CFAllocatorRef allocator,
204 SOSDataSourceFactoryRef factory,
205 CFErrorRef* error,
206 const uint8_t** der_p, const uint8_t *der_end)
207 {
208 SOSAccountRef account = NULL;
209 SOSAccountRef result = NULL;
210
211 {
212 CFDictionaryRef decoded_gestalt = NULL;
213 *der_p = der_decode_dictionary(kCFAllocatorDefault, kCFPropertyListImmutable, &decoded_gestalt, error,
214 *der_p, der_end);
215
216 if (*der_p == 0)
217 return NULL;
218
219 account = SOSAccountCreateBasic(allocator, decoded_gestalt, factory);
220 CFReleaseNull(decoded_gestalt);
221 }
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);
226
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);
236 {
237 CFDictionaryRef expansion = NULL;
238 *der_p = der_decode_dictionary(kCFAllocatorDefault, kCFPropertyListImmutable, &expansion, error,
239 *der_p, der_end);
240
241 if (*der_p == 0)
242 return NULL;
243
244 CFReleaseNull(account->expansion);
245 account->expansion = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, expansion);
246 CFReleaseNull(expansion);
247 }
248
249 account->departure_code = (enum DepartureReason) tmp_departure_code;
250
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));
253
254 result = CFRetainSafe(account);
255
256 fail:
257 CFReleaseNull(account);
258 return result;
259 }
260
261 //
262 // Version History for Account
263 //
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
268 //
269
270 #define CURRENT_ACCOUNT_PERSISTENT_VERSION 8
271
272 SOSAccountRef SOSAccountCreateFromDER(CFAllocatorRef allocator,
273 SOSDataSourceFactoryRef factory,
274 CFErrorRef* error,
275 const uint8_t** der_p, const uint8_t *der_end)
276 {
277 SOSAccountRef account = NULL;
278 SOSAccountRef result = NULL;
279 uint64_t version = 0;
280
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));
286
287 switch (version) {
288 case CURRENT_ACCOUNT_PERSISTENT_VERSION:
289 account = SOSAccountCreateFromRemainingDER_v8(allocator, factory, error, der_p, sequence_end);
290 break;
291
292 case 7:
293 account = SOSAccountCreateFromRemainingDER_v7(allocator, factory, error, der_p, sequence_end);
294 break;
295
296 case 6:
297 account = SOSAccountCreateFromRemainingDER_v6(allocator, factory, error, der_p, sequence_end);
298 break;
299
300 default:
301 SOSCreateErrorWithFormat(kSOSErrorBadFormat, (error != NULL) ? *error : NULL, error,
302 NULL, CFSTR("Unsupported version (%llu)"), version);
303 break;
304 }
305
306 require_quiet(account, errOut);
307
308 require_quiet(*der_p && *der_p == sequence_end, errOut);
309
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"));
313 }
314
315 require_action_quiet(SOSAccountEnsureFactoryCircles(account), errOut,
316 SOSCreateError(kSOSErrorBadFormat, CFSTR("Cannot EnsureFactoryCircles"), (error != NULL) ? *error : NULL, error));
317
318 SOSPeerInfoRef myPI = SOSAccountGetMyPeerInfo(account);
319 if (myPI) {
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);
325 }
326
327 SOSAccountCheckHasBeenInSync(account);
328
329 SOSUpdateKeyInterest(account);
330
331 result = CFRetainSafe(account);
332
333 errOut:
334 CFReleaseNull(account);
335 return result;
336 }
337
338 SOSAccountRef SOSAccountCreateFromData(CFAllocatorRef allocator, CFDataRef circleData,
339 SOSDataSourceFactoryRef factory,
340 CFErrorRef* error)
341 {
342 size_t size = CFDataGetLength(circleData);
343 const uint8_t *der = CFDataGetBytePtr(circleData);
344 SOSAccountRef account = SOSAccountCreateFromDER(allocator, factory,
345 error,
346 &der, der + size);
347 return account;
348 }
349
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);
354
355 size_t SOSAccountGetDEREncodedSize(SOSAccountRef account, CFErrorRef *error)
356 {
357 size_t sequence_size = 0;
358 uint64_t version = CURRENT_ACCOUNT_PERSISTENT_VERSION;
359
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);
372
373 return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, sequence_size);
374
375 fail:
376 SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("don't know how to encode"), NULL, error);
377 return 0;
378 }
379
380 uint8_t* SOSAccountEncodeToDER(SOSAccountRef account, CFErrorRef* error, const uint8_t* der, uint8_t* der_end)
381 {
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,
396
397
398 der_end)))))))))))));
399
400 return der_end;
401 }
402
403 /************************/
404
405 CFDataRef SOSAccountCopyEncodedData(SOSAccountRef account, CFAllocatorRef allocator, CFErrorRef *error)
406 {
407 size_t size = SOSAccountGetDEREncodedSize(account, error);
408 if (size == 0)
409 return NULL;
410 uint8_t buffer[size];
411 uint8_t* start = SOSAccountEncodeToDER(account, error, buffer, buffer + sizeof(buffer));
412 CFDataRef result = CFDataCreate(kCFAllocatorDefault, start, size);
413 return result;
414 }
415