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