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