]> git.saurik.com Git - apple/security.git/blob - OSX/sec/SOSCircle/SecureObjectSync/SOSAccountPersistence.c
Security-57740.31.2.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 <utilities/SecBuffer.h>
35
36 #include <Security/SecureObjectSync/SOSKVSKeys.h>
37 #include <SOSPeerInfoDER.h>
38
39 #include <Security/SecureObjectSync/SOSTransport.h>
40
41 #include <Security/SecureObjectSync/SOSPeerInfoCollections.h>
42 #include <os/state_private.h>
43
44 #include "SOSAccountPriv.h"
45 #define kSecServerPeerInfoAvailable "com.apple.security.fpiAvailable"
46
47
48 static SOSAccountRef SOSAccountCreateFromRemainingDER_v6(CFAllocatorRef allocator,
49 SOSDataSourceFactoryRef factory,
50 CFErrorRef* error,
51 const uint8_t** der_p, const uint8_t *der_end)
52 {
53 SOSAccountRef result = NULL;
54 SOSAccountRef account = NULL;
55 CFArrayRef array = NULL;
56 CFDictionaryRef retiredPeers = NULL;
57 CFStringRef circle_name = factory->copy_name(factory);
58
59 {
60 CFDictionaryRef decoded_gestalt = NULL;
61 *der_p = der_decode_dictionary(kCFAllocatorDefault, kCFPropertyListImmutable, &decoded_gestalt, error,
62 *der_p, der_end);
63
64 if (*der_p == 0)
65 return NULL;
66
67 account = SOSAccountCreateBasic(allocator, decoded_gestalt, factory);
68 CFReleaseNull(decoded_gestalt);
69 }
70
71 *der_p = der_decode_array(kCFAllocatorDefault, 0, &array, error, *der_p, der_end);
72
73 uint64_t tmp_departure_code = kSOSNeverAppliedToCircle;
74 *der_p = ccder_decode_uint64(&tmp_departure_code, *der_p, der_end);
75 *der_p = ccder_decode_bool(&account->user_public_trusted, *der_p, der_end);
76 *der_p = der_decode_public_bytes(kCFAllocatorDefault, kSecECDSAAlgorithmID, &account->user_public, error, *der_p, der_end);
77 *der_p = der_decode_public_bytes(kCFAllocatorDefault, kSecECDSAAlgorithmID, &account->previous_public, error, *der_p, der_end);
78 *der_p = der_decode_data_or_null(kCFAllocatorDefault, &account->user_key_parameters, error, *der_p, der_end);
79
80 *der_p = der_decode_dictionary(kCFAllocatorDefault, kCFPropertyListMutableContainers, (CFDictionaryRef *) &retiredPeers, error, *der_p, der_end);
81 require_action_quiet(*der_p == der_end, fail, *der_p = NULL);
82
83 account->departure_code = (enum DepartureReason) tmp_departure_code;
84
85 CFDictionaryForEach(retiredPeers, ^(const void *key, const void *value) {
86 if (isData(value)) {
87 SOSPeerInfoRef retiree = SOSPeerInfoCreateFromData(kCFAllocatorDefault, NULL, (CFDataRef) value);
88
89 CFSetAddValue(account->retirees, retiree);
90
91 CFReleaseNull(retiree);
92 }
93 });
94
95 require_quiet(array && *der_p, fail);
96
97 CFArrayForEach(array, ^(const void *value) {
98 CFDataRef circleData = NULL;
99 CFDataRef fullPeerInfoData = NULL;
100
101 if (isData(value)) {
102 circleData = (CFDataRef) value;
103 } else if (isArray(value)) {
104 CFArrayRef pair = (CFArrayRef) value;
105
106 CFTypeRef circleObject = CFArrayGetValueAtIndex(pair, 0);
107 CFTypeRef fullPeerInfoObject = CFArrayGetValueAtIndex(pair, 1);
108
109 if (CFArrayGetCount(pair) == 2 && isData(circleObject) && isData(fullPeerInfoObject)) {
110 circleData = (CFDataRef) circleObject;
111 fullPeerInfoData = (CFDataRef) fullPeerInfoObject;
112 }
113 }
114
115 if (circleData) {
116 SOSCircleRef circle = SOSCircleCreateFromData(kCFAllocatorDefault, circleData, error);
117 require_quiet(circle && CFEqualSafe(circle_name, SOSCircleGetName(circle)), fail);
118
119 account->trusted_circle = CFRetainSafe(circle);
120
121 if(fullPeerInfoData) {
122 account->my_identity = SOSFullPeerInfoCreateFromData(kCFAllocatorDefault, fullPeerInfoData, NULL);
123 }
124
125 fail:
126 CFReleaseNull(circle);
127 }
128 });
129 CFReleaseNull(array);
130
131 require_action_quiet(SOSAccountEnsureFactoryCircles(account), fail,
132 SOSCreateError(kSOSErrorBadFormat, CFSTR("Cannot EnsureFactoryCircles"), (error != NULL) ? *error : NULL, error));
133
134 result = CFRetainSafe(account);
135
136 fail:
137 CFReleaseNull(account);
138 return result;
139 }
140
141 static size_t der_sizeof_data_optional(CFDataRef data)
142 {
143 return data ? der_sizeof_data(data, NULL) : 0;
144
145 }
146
147 static uint8_t* der_encode_data_optional(CFDataRef data, CFErrorRef *error,
148 const uint8_t *der, uint8_t *der_end)
149 {
150 return data ? der_encode_data(data, error, der, der_end) : der_end;
151
152 }
153
154 static const uint8_t* der_decode_data_optional(CFAllocatorRef allocator, CFOptionFlags mutability,
155 CFDataRef* data, CFErrorRef *error,
156 const uint8_t* der, const uint8_t *der_end)
157 {
158 const uint8_t *dt_end = der_decode_data(allocator, mutability, data, NULL, der, der_end);
159
160 return dt_end ? dt_end : der;
161 }
162
163 static SOSAccountRef SOSAccountCreateFromRemainingDER_v7(CFAllocatorRef allocator,
164 SOSDataSourceFactoryRef factory,
165 CFErrorRef* error,
166 const uint8_t** der_p, const uint8_t *der_end)
167 {
168 SOSAccountRef account = NULL;
169 SOSAccountRef result = NULL;
170
171 {
172 CFDictionaryRef decoded_gestalt = NULL;
173 *der_p = der_decode_dictionary(kCFAllocatorDefault, kCFPropertyListImmutable, &decoded_gestalt, error,
174 *der_p, der_end);
175
176 if (*der_p == 0)
177 return NULL;
178
179 account = SOSAccountCreateBasic(allocator, decoded_gestalt, factory);
180 CFReleaseNull(decoded_gestalt);
181 }
182
183 account->trusted_circle = SOSCircleCreateFromDER(kCFAllocatorDefault, error, der_p, der_end);
184 *der_p = der_decode_fullpeer_or_null(kCFAllocatorDefault, &account->my_identity, error, *der_p, der_end);
185
186 uint64_t tmp_departure_code = kSOSNeverAppliedToCircle;
187 *der_p = ccder_decode_uint64(&tmp_departure_code, *der_p, der_end);
188 *der_p = ccder_decode_bool(&account->user_public_trusted, *der_p, der_end);
189 *der_p = der_decode_public_bytes(kCFAllocatorDefault, kSecECDSAAlgorithmID, &account->user_public, error, *der_p, der_end);
190 *der_p = der_decode_public_bytes(kCFAllocatorDefault, kSecECDSAAlgorithmID, &account->previous_public, error, *der_p, der_end);
191 *der_p = der_decode_data_or_null(kCFAllocatorDefault, &account->user_key_parameters, error, *der_p, der_end);
192 account->retirees = SOSPeerInfoSetCreateFromArrayDER(kCFAllocatorDefault, &kSOSPeerSetCallbacks, error, der_p, der_end);
193 *der_p = der_decode_data_optional(kCFAllocatorDefault, kCFPropertyListImmutable, &account->backup_key, error, *der_p, der_end);
194
195 account->departure_code = (enum DepartureReason) tmp_departure_code;
196
197 require_action_quiet(*der_p && *der_p == der_end, fail,
198 SOSCreateError(kSOSErrorBadFormat, CFSTR("Didn't consume all bytes v7"), (error != NULL) ? *error : NULL, error));
199
200 result = CFRetainSafe(account);
201
202 fail:
203 CFReleaseNull(account);
204 return result;
205 }
206
207
208 static SOSAccountRef SOSAccountCreateFromRemainingDER_v8(CFAllocatorRef allocator,
209 SOSDataSourceFactoryRef factory,
210 CFErrorRef* error,
211 const uint8_t** der_p, const uint8_t *der_end)
212 {
213 SOSAccountRef account = NULL;
214 SOSAccountRef result = NULL;
215
216 {
217 CFDictionaryRef decoded_gestalt = NULL;
218 *der_p = der_decode_dictionary(kCFAllocatorDefault, kCFPropertyListImmutable, &decoded_gestalt, error,
219 *der_p, der_end);
220
221 if (*der_p == 0)
222 return NULL;
223
224 account = SOSAccountCreateBasic(allocator, decoded_gestalt, factory);
225 CFReleaseNull(decoded_gestalt);
226 }
227 CFReleaseNull(account->trusted_circle);
228 account->trusted_circle = SOSCircleCreateFromDER(kCFAllocatorDefault, error, der_p, der_end);
229 CFReleaseNull(account->my_identity);
230 *der_p = der_decode_fullpeer_or_null(kCFAllocatorDefault, &account->my_identity, error, *der_p, der_end);
231
232 uint64_t tmp_departure_code = kSOSNeverAppliedToCircle;
233 *der_p = ccder_decode_uint64(&tmp_departure_code, *der_p, der_end);
234 *der_p = ccder_decode_bool(&account->user_public_trusted, *der_p, der_end);
235 *der_p = der_decode_public_bytes(kCFAllocatorDefault, kSecECDSAAlgorithmID, &account->user_public, error, *der_p, der_end);
236 *der_p = der_decode_public_bytes(kCFAllocatorDefault, kSecECDSAAlgorithmID, &account->previous_public, error, *der_p, der_end);
237 *der_p = der_decode_data_or_null(kCFAllocatorDefault, &account->user_key_parameters, error, *der_p, der_end);
238 CFReleaseNull(account->retirees);
239 account->retirees = SOSPeerInfoSetCreateFromArrayDER(kCFAllocatorDefault, &kSOSPeerSetCallbacks, error, der_p, der_end);
240 *der_p = der_decode_data_optional(kCFAllocatorDefault, kCFPropertyListImmutable, &account->backup_key, error, *der_p, der_end);
241 {
242 CFDictionaryRef expansion = NULL;
243 *der_p = der_decode_dictionary(kCFAllocatorDefault, kCFPropertyListImmutable, &expansion, error,
244 *der_p, der_end);
245
246 if (*der_p == 0)
247 return NULL;
248
249 CFReleaseNull(account->expansion);
250 account->expansion = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, expansion);
251 CFReleaseNull(expansion);
252 }
253
254 account->departure_code = (enum DepartureReason) tmp_departure_code;
255
256 require_action_quiet(*der_p && *der_p == der_end, fail,
257 SOSCreateError(kSOSErrorBadFormat, CFSTR("Didn't consume all bytes v7"), (error != NULL) ? *error : NULL, error));
258
259 result = CFRetainSafe(account);
260
261 fail:
262 CFReleaseNull(account);
263 return result;
264 }
265
266 //
267 // Version History for Account
268 //
269 // 1-5 - InnsbruckTaos/Cab; Never supported even for upgrading.
270 // 6 - First version used in the field.
271 // 7 - One Circle version
272 // 8 - Adding expansion dictionary
273 //
274
275 #define CURRENT_ACCOUNT_PERSISTENT_VERSION 8
276
277 SOSAccountRef SOSAccountCreateFromDER(CFAllocatorRef allocator,
278 SOSDataSourceFactoryRef factory,
279 CFErrorRef* error,
280 const uint8_t** der_p, const uint8_t *der_end)
281 {
282 SOSAccountRef account = NULL;
283 SOSAccountRef result = NULL;
284 uint64_t version = 0;
285
286 const uint8_t *sequence_end;
287 *der_p = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &sequence_end, *der_p, der_end);
288 *der_p = ccder_decode_uint64(&version, *der_p, sequence_end);
289 require_action_quiet(*der_p, errOut,
290 SOSCreateError(kSOSErrorBadFormat, CFSTR("Version parsing failed"), (error != NULL) ? *error : NULL, error));
291
292 switch (version) {
293 case CURRENT_ACCOUNT_PERSISTENT_VERSION:
294 account = SOSAccountCreateFromRemainingDER_v8(allocator, factory, error, der_p, sequence_end);
295 break;
296
297 case 7:
298 account = SOSAccountCreateFromRemainingDER_v7(allocator, factory, error, der_p, sequence_end);
299 break;
300
301 case 6:
302 account = SOSAccountCreateFromRemainingDER_v6(allocator, factory, error, der_p, sequence_end);
303 break;
304
305 default:
306 SOSCreateErrorWithFormat(kSOSErrorBadFormat, (error != NULL) ? *error : NULL, error,
307 NULL, CFSTR("Unsupported version (%llu)"), version);
308 break;
309 }
310
311 require_quiet(account, errOut);
312
313 require_quiet(*der_p && *der_p == sequence_end, errOut);
314
315 /* I may not always have an identity, but when I do, it has a private key */
316 if(account->my_identity) {
317 require_action_quiet(SOSFullPeerInfoPrivKeyExists(account->my_identity), errOut, secnotice("account", "No private key associated with my_identity, resetting"));
318 notify_post(kSecServerPeerInfoAvailable);
319 if(account->deviceID)
320 SOSFullPeerInfoUpdateDeviceID(account->my_identity, account->deviceID, error);
321 }
322
323 require_action_quiet(SOSAccountEnsureFactoryCircles(account), errOut,
324 SOSCreateError(kSOSErrorBadFormat, CFSTR("Cannot EnsureFactoryCircles"), (error != NULL) ? *error : NULL, error));
325
326 SOSPeerInfoRef myPI = SOSAccountGetMyPeerInfo(account);
327 if (myPI) {
328 if(SOSAccountHasCompletedInitialSync(account)) {
329 CFMutableSetRef viewsToEnsure = SOSViewCopyViewSet(kViewSetAlwaysOn);
330
331 // Previous version PeerInfo if we were syncing legacy keychain, ensure we include those legacy views.
332 if(!SOSPeerInfoVersionIsCurrent(myPI) && SOSAccountIsInCircle(account, NULL)) {
333 CFSetRef V0toAdd = SOSViewCopyViewSet(kViewSetV0);
334 CFSetUnion(viewsToEnsure, V0toAdd);
335 CFReleaseNull(V0toAdd);
336 }
337
338 SOSAccountUpdateFullPeerInfo(account, viewsToEnsure, SOSViewsGetV0ViewSet()); // We don't permit V0 view proper, only sub-views
339 CFReleaseNull(viewsToEnsure);
340 }
341
342 SOSPeerInfoRef oldPI = myPI;
343 // if UpdateFullPeerInfo did something - we need to make sure we have the right Ref
344 myPI = SOSAccountGetMyPeerInfo(account);
345 if(oldPI != myPI) secnotice("canary", "Caught spot where PIs differ in account setup");
346 CFStringRef transportTypeInflatedFromDER = SOSPeerInfoCopyTransportType(myPI);
347 if (CFStringCompare(transportTypeInflatedFromDER, CFSTR("IDS"), 0) == 0 || CFStringCompare(transportTypeInflatedFromDER, CFSTR("KVS"), 0) == 0)
348 SOSFullPeerInfoUpdateTransportType(account->my_identity, SOSTransportMessageTypeIDSV2, NULL); //update the transport type to the current IDS V2 type
349
350 CFReleaseNull(transportTypeInflatedFromDER);
351 }
352
353 SOSAccountWithTransactionSync(account, ^(SOSAccountRef account, SOSAccountTransactionRef txn) {
354 account->key_interests_need_updating = true;
355 });
356
357 result = CFRetainSafe(account);
358
359 errOut:
360 CFReleaseNull(account);
361 return result;
362 }
363
364 SOSAccountRef SOSAccountCreateFromData(CFAllocatorRef allocator, CFDataRef circleData,
365 SOSDataSourceFactoryRef factory,
366 CFErrorRef* error)
367 {
368 size_t size = CFDataGetLength(circleData);
369 const uint8_t *der = CFDataGetBytePtr(circleData);
370 SOSAccountRef account = SOSAccountCreateFromDER(allocator, factory,
371 error,
372 &der, der + size);
373 return account;
374 }
375
376 CFMutableSetRef SOSPeerInfoSetCreateFromArrayDER(CFAllocatorRef allocator, const CFSetCallBacks *callbacks, CFErrorRef* error,
377 const uint8_t** der_p, const uint8_t *der_end);
378 size_t SOSPeerInfoSetGetDEREncodedArraySize(CFSetRef pia, CFErrorRef *error);
379 uint8_t* SOSPeerInfoSetEncodeToArrayDER(CFSetRef pia, CFErrorRef* error, const uint8_t* der, uint8_t* der_end);
380
381 size_t SOSAccountGetDEREncodedSize(SOSAccountRef account, CFErrorRef *error)
382 {
383 size_t sequence_size = 0;
384 uint64_t version = CURRENT_ACCOUNT_PERSISTENT_VERSION;
385
386 require_quiet(accumulate_size(&sequence_size, ccder_sizeof_uint64(version)), fail);
387 require_quiet(accumulate_size(&sequence_size, der_sizeof_dictionary(account->gestalt, error)), fail);
388 require_quiet(accumulate_size(&sequence_size, SOSCircleGetDEREncodedSize(account->trusted_circle, error)), fail);
389 require_quiet(accumulate_size(&sequence_size, der_sizeof_fullpeer_or_null(account->my_identity, error)), fail);
390 require_quiet(accumulate_size(&sequence_size, ccder_sizeof_uint64(account->departure_code)), fail);
391 require_quiet(accumulate_size(&sequence_size, ccder_sizeof_bool(account->user_public_trusted, error)), fail);
392 require_quiet(accumulate_size(&sequence_size, der_sizeof_public_bytes(account->user_public, error)), fail);
393 require_quiet(accumulate_size(&sequence_size, der_sizeof_public_bytes(account->previous_public, error)), fail);
394 require_quiet(accumulate_size(&sequence_size, der_sizeof_data_or_null(account->user_key_parameters, error)), fail);
395 require_quiet(accumulate_size(&sequence_size, SOSPeerInfoSetGetDEREncodedArraySize(account->retirees, error)), fail);
396 accumulate_size(&sequence_size, der_sizeof_data_optional(account->backup_key));
397 require_quiet(accumulate_size(&sequence_size, der_sizeof_dictionary(account->expansion, error)), fail);
398
399 return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, sequence_size);
400
401 fail:
402 SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("don't know how to encode"), NULL, error);
403 return 0;
404 }
405
406 uint8_t* SOSAccountEncodeToDER(SOSAccountRef account, CFErrorRef* error, const uint8_t* der, uint8_t* der_end)
407 {
408 uint64_t version = CURRENT_ACCOUNT_PERSISTENT_VERSION;
409 der_end = ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der,
410 ccder_encode_uint64(version, der,
411 der_encode_dictionary(account->gestalt, error, der,
412 SOSCircleEncodeToDER(account->trusted_circle, error, der,
413 der_encode_fullpeer_or_null(account->my_identity, error, der,
414 ccder_encode_uint64(account->departure_code, der,
415 ccder_encode_bool(account->user_public_trusted, der,
416 der_encode_public_bytes(account->user_public, error, der,
417 der_encode_public_bytes(account->previous_public, error, der,
418 der_encode_data_or_null(account->user_key_parameters, error, der,
419 SOSPeerInfoSetEncodeToArrayDER(account->retirees, error, der,
420 der_encode_data_optional(account->backup_key, error, der,
421 der_encode_dictionary(account->expansion, error, der,
422
423
424 der_end)))))))))))));
425
426 return der_end;
427 }
428
429 /************************/
430
431 CFDataRef SOSAccountCopyEncodedData(SOSAccountRef account, CFAllocatorRef allocator, CFErrorRef *error)
432 {
433 return CFDataCreateWithDER(kCFAllocatorDefault, SOSAccountGetDEREncodedSize(account, error), ^uint8_t*(size_t size, uint8_t *buffer) {
434 return SOSAccountEncodeToDER(account, error, buffer, (uint8_t *) buffer + size);
435 });
436 }
437
438