]> git.saurik.com Git - apple/security.git/blob - OSX/sec/SOSCircle/SecureObjectSync/SOSAccountPersistence.m
Security-58286.51.6.tar.gz
[apple/security.git] / OSX / sec / SOSCircle / SecureObjectSync / SOSAccountPersistence.m
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 "SOSViews.h"
30
31 #include <utilities/SecCFWrappers.h>
32 #include <utilities/SecNSAdditions.h>
33
34 #include <utilities/SecCoreCrypto.h>
35 #include <utilities/SecBuffer.h>
36
37 #include <Security/SecureObjectSync/SOSKVSKeys.h>
38 #include <SOSPeerInfoDER.h>
39
40 #include <Security/SecureObjectSync/SOSTransport.h>
41
42 #include <Security/SecureObjectSync/SOSPeerInfoCollections.h>
43 #include <os/state_private.h>
44
45 #import <Security/SecureObjectSync/SOSAccountPriv.h>
46 #import <Security/SecureObjectSync/SOSAccountTrust.h>
47 #import <Security/SecureObjectSync/SOSCircleDer.h>
48 #import "Security/SecureObjectSync/SOSAccountTrustClassic.h"
49
50 #define kSecServerPeerInfoAvailable "com.apple.security.fpiAvailable"
51
52 @implementation SOSAccount (Persistence)
53
54
55 static SOSAccount* SOSAccountCreateFromRemainingDER_v6(CFAllocatorRef allocator,
56 SOSDataSourceFactoryRef factory,
57 CFErrorRef* error,
58 const uint8_t** der_p, const uint8_t *der_end)
59 {
60 SOSAccount* result = NULL;
61 SOSAccount* account = NULL;
62
63 CFArrayRef array = NULL;
64 CFDictionaryRef retiredPeers = NULL;
65
66 CFStringRef circle_name = factory->copy_name(factory);
67
68 {
69 CFDictionaryRef decoded_gestalt = NULL;
70 *der_p = der_decode_dictionary(kCFAllocatorDefault, kCFPropertyListImmutable, &decoded_gestalt, error,
71 *der_p, der_end);
72
73 if (*der_p == 0)
74 return NULL;
75
76 account = SOSAccountCreate(allocator, decoded_gestalt, factory);
77
78 CFReleaseNull(decoded_gestalt);
79 }
80 SOSAccountTrustClassic *trust = account.trust;
81
82 *der_p = der_decode_array(kCFAllocatorDefault, 0, &array, error, *der_p, der_end);
83
84 uint64_t tmp_departure_code = kSOSNeverAppliedToCircle;
85 *der_p = ccder_decode_uint64(&tmp_departure_code, *der_p, der_end);
86 [trust setDepartureCode:(enum DepartureReason)tmp_departure_code];
87
88 bool userPublicTrusted;
89 *der_p = ccder_decode_bool(&userPublicTrusted, *der_p, der_end);
90 account.accountKeyIsTrusted = userPublicTrusted;
91
92 SecKeyRef userPublic = NULL;
93 SecKeyRef previousUserPublic = NULL;
94 *der_p = der_decode_public_bytes(kCFAllocatorDefault, kSecECDSAAlgorithmID, &userPublic, error, *der_p, der_end);
95 *der_p = der_decode_public_bytes(kCFAllocatorDefault, kSecECDSAAlgorithmID, &previousUserPublic, error, *der_p, der_end);
96 account.accountKey = userPublic;
97 account.previousAccountKey = previousUserPublic;
98 CFReleaseNull(userPublic);
99 CFReleaseNull(previousUserPublic);
100
101 {
102 CFDataRef parms = NULL;
103 *der_p = der_decode_data_or_null(kCFAllocatorDefault, &parms, error, *der_p, der_end);
104 [account setAccountKeyDerivationParamters:(__bridge_transfer NSData*) parms];
105 }
106
107 *der_p = der_decode_dictionary(kCFAllocatorDefault, kCFPropertyListMutableContainers, (CFDictionaryRef *) &retiredPeers, error, *der_p, der_end);
108
109 if(*der_p != der_end) {
110 *der_p = NULL;
111 return result;
112 }
113
114 {
115 CFMutableSetRef retirees = CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
116
117 CFDictionaryForEach(retiredPeers, ^(const void *key, const void *value) {
118 if (isData(value)) {
119 SOSPeerInfoRef retiree = SOSPeerInfoCreateFromData(kCFAllocatorDefault, NULL, (CFDataRef) value);
120
121 CFSetAddValue(retirees, retiree);
122
123 CFReleaseNull(retiree);
124 }
125 });
126
127 [trust setRetirees:(__bridge NSMutableSet *)retirees];
128 CFReleaseNull(retirees);
129 }
130
131 if(!array || !*der_p)
132 return result;
133
134 CFArrayForEach(array, ^(const void *value) {
135 CFDataRef circleData = NULL;
136 CFDataRef fullPeerInfoData = NULL;
137
138 if (isData(value)) {
139 circleData = (CFDataRef) value;
140 } else if (isArray(value)) {
141 CFArrayRef pair = (CFArrayRef) value;
142
143 CFTypeRef circleObject = CFArrayGetValueAtIndex(pair, 0);
144 CFTypeRef fullPeerInfoObject = CFArrayGetValueAtIndex(pair, 1);
145
146 if (CFArrayGetCount(pair) == 2 && isData(circleObject) && isData(fullPeerInfoObject)) {
147 circleData = (CFDataRef) circleObject;
148 fullPeerInfoData = (CFDataRef) fullPeerInfoObject;
149 }
150 }
151
152 if (circleData) {
153 SOSCircleRef circle = SOSCircleCreateFromData(kCFAllocatorDefault, circleData, error);
154 require_quiet(circle && CFEqualSafe(circle_name, SOSCircleGetName(circle)), fail);
155 [trust setTrustedCircle:circle];
156 CFReleaseNull(circle);
157
158 if(fullPeerInfoData) {
159 SOSFullPeerInfoRef identity = SOSFullPeerInfoCreateFromData(kCFAllocatorDefault, fullPeerInfoData, NULL);
160 trust.fullPeerInfo = identity;
161 CFReleaseNull(identity);
162 }
163
164 fail:
165 CFReleaseNull(circle);
166 }
167 });
168 CFReleaseNull(array);
169 require_action_quiet([account ensureFactoryCircles], fail,
170 SOSCreateError(kSOSErrorBadFormat, CFSTR("Cannot EnsureFactoryCircles"), (error != NULL) ? *error : NULL, error));
171 result = account;
172
173 fail:
174
175 return result;
176 }
177
178 static const uint8_t* der_decode_data_optional(CFAllocatorRef allocator, CFOptionFlags mutability,
179 CFDataRef* data, CFErrorRef *error,
180 const uint8_t* der, const uint8_t *der_end)
181 {
182 const uint8_t *dt_end = der_decode_data(allocator, mutability, data, NULL, der, der_end);
183
184 return dt_end ? dt_end : der;
185 }
186
187 static SOSAccount* SOSAccountCreateFromRemainingDER_v7(CFAllocatorRef allocator,
188 SOSDataSourceFactoryRef factory,
189 CFErrorRef* error,
190 const uint8_t** der_p, const uint8_t *der_end)
191 {
192 SOSAccount* account = NULL;
193 SOSAccount* result = NULL;
194
195 {
196 CFDictionaryRef decoded_gestalt = NULL;
197 *der_p = der_decode_dictionary(kCFAllocatorDefault, kCFPropertyListImmutable, &decoded_gestalt, error,
198 *der_p, der_end);
199
200 if (*der_p == 0)
201 return NULL;
202
203 account = SOSAccountCreate(kCFAllocatorDefault, decoded_gestalt, factory);
204 CFReleaseNull(decoded_gestalt);
205 }
206
207 enum DepartureReason departure_code = 0;
208 SOSAccountTrustClassic *trust = account.trust;
209
210 {
211 SOSCircleRef circle = SOSCircleCreateFromDER(kCFAllocatorDefault, error, der_p, der_end);
212 [trust setTrustedCircle:circle];
213 CFReleaseNull(circle);
214 }
215
216 {
217 SOSFullPeerInfoRef identity = NULL;
218 *der_p = der_decode_fullpeer_or_null(kCFAllocatorDefault, &identity, error, *der_p, der_end);
219 trust.fullPeerInfo = identity;
220 CFReleaseNull(identity);
221 }
222
223 uint64_t tmp_departure_code = kSOSNeverAppliedToCircle;
224 *der_p = ccder_decode_uint64(&tmp_departure_code, *der_p, der_end);
225 bool userPublicTrusted;
226
227 *der_p = ccder_decode_bool(&userPublicTrusted, *der_p, der_end);
228 account.accountKeyIsTrusted = userPublicTrusted;
229
230 {
231 SecKeyRef userPublic = NULL;
232 *der_p = der_decode_public_bytes(kCFAllocatorDefault, kSecECDSAAlgorithmID, &userPublic, error, *der_p, der_end);
233 account.accountKey = userPublic;
234 CFReleaseNull(userPublic);
235 }
236
237 {
238 SecKeyRef previousUserPublic = NULL;
239 *der_p = der_decode_public_bytes(kCFAllocatorDefault, kSecECDSAAlgorithmID, &previousUserPublic, error, *der_p, der_end);
240 account.previousAccountKey = previousUserPublic;
241 CFReleaseNull(previousUserPublic);
242 }
243
244 {
245 CFDataRef parms = NULL;
246 *der_p = der_decode_data_or_null(kCFAllocatorDefault, &parms, error, *der_p, der_end);
247 account.accountKeyDerivationParamters = (__bridge_transfer NSData*)parms;
248 }
249
250 {
251 CFSetRef retirees = SOSPeerInfoSetCreateFromArrayDER(kCFAllocatorDefault, &kSOSPeerSetCallbacks, error, der_p, der_end);
252 [trust setRetirees:(__bridge NSMutableSet *)retirees];
253 }
254
255 {
256 CFDataRef bKey = NULL;
257 *der_p = der_decode_data_optional(kCFAllocatorDefault, kCFPropertyListImmutable, &bKey, error, *der_p, der_end);
258 if(bKey != NULL)
259 [account setBackup_key:(__bridge_transfer NSData *)bKey];
260 }
261
262 departure_code = (enum DepartureReason) tmp_departure_code;
263
264 [trust setDepartureCode:departure_code];
265 require_action_quiet(*der_p && *der_p == der_end, fail,
266 SOSCreateError(kSOSErrorBadFormat, CFSTR("Didn't consume all bytes v7"), (error != NULL) ? *error : NULL, error));
267
268 result = account;
269
270 fail:
271 return result;
272 }
273
274
275 static SOSAccount* SOSAccountCreateFromRemainingDER_v8(CFAllocatorRef allocator,
276 SOSDataSourceFactoryRef factory,
277 CFErrorRef* error,
278 const uint8_t** der_p, const uint8_t *der_end)
279 {
280 SOSAccount* account = NULL;
281 SOSAccount* result = NULL;
282
283 {
284 CFDictionaryRef decoded_gestalt = NULL;
285 *der_p = der_decode_dictionary(kCFAllocatorDefault, kCFPropertyListImmutable, &decoded_gestalt, error,
286 *der_p, der_end);
287
288 if (*der_p == 0) {
289 CFReleaseNull(decoded_gestalt);
290 return NULL;
291 }
292
293 account = SOSAccountCreate(kCFAllocatorDefault, decoded_gestalt, factory);
294 CFReleaseNull(decoded_gestalt);
295 }
296
297 SOSAccountTrustClassic *trust = account.trust;
298
299 {
300 SOSCircleRef circle = SOSCircleCreateFromDER(kCFAllocatorDefault, error, der_p, der_end);
301 [trust setTrustedCircle:circle];
302 CFReleaseNull(circle);
303 }
304
305 {
306 SOSFullPeerInfoRef identity = NULL;
307 *der_p = der_decode_fullpeer_or_null(kCFAllocatorDefault, &identity, error, *der_p, der_end);
308 trust.fullPeerInfo = identity;
309 CFReleaseNull(identity);
310 }
311
312 uint64_t tmp_departure_code = kSOSNeverAppliedToCircle;
313 *der_p = ccder_decode_uint64(&tmp_departure_code, *der_p, der_end);
314 [trust setDepartureCode:(enum DepartureReason) tmp_departure_code];
315
316 bool userPublicTrusted;
317 *der_p = ccder_decode_bool(&userPublicTrusted, *der_p, der_end);
318 account.accountKeyIsTrusted = userPublicTrusted;
319
320 {
321 SecKeyRef userPublic = NULL;
322 *der_p = der_decode_public_bytes(kCFAllocatorDefault, kSecECDSAAlgorithmID, &userPublic, error, *der_p, der_end);
323 account.accountKey = userPublic;
324 CFReleaseNull(userPublic);
325 }
326
327 {
328 SecKeyRef previousUserPublic = NULL;
329 *der_p = der_decode_public_bytes(kCFAllocatorDefault, kSecECDSAAlgorithmID, &previousUserPublic, error, *der_p, der_end);
330 account.previousAccountKey = previousUserPublic;
331 CFReleaseNull(previousUserPublic);
332 }
333
334 {
335 CFDataRef parms;
336 *der_p = der_decode_data_or_null(kCFAllocatorDefault, &parms, error, *der_p, der_end);
337 account.accountKeyDerivationParamters = (__bridge_transfer NSData*)parms;
338 parms = NULL;
339 }
340
341 {
342 CFMutableSetRef retirees = SOSPeerInfoSetCreateFromArrayDER(kCFAllocatorDefault, &kSOSPeerSetCallbacks, error, der_p, der_end);
343 [trust setRetirees:(__bridge NSMutableSet *)retirees];
344 CFReleaseNull(retirees);
345 }
346
347 CFDataRef bKey = NULL;
348 *der_p = der_decode_data_optional(kCFAllocatorDefault, kCFPropertyListImmutable, &bKey, error, *der_p, der_end);
349 {
350 CFDictionaryRef expansion = NULL;
351 *der_p = der_decode_dictionary(kCFAllocatorDefault, kCFPropertyListImmutable, &expansion, error,
352 *der_p, der_end);
353
354 if (*der_p == 0) {
355 CFReleaseNull(bKey);
356 CFReleaseNull(expansion);
357 return NULL;
358 }
359
360 if(expansion) {
361 [trust setExpansion:(__bridge NSMutableDictionary *)(expansion)];
362 }
363 CFReleaseNull(expansion);
364 }
365 if(bKey) {
366 [account setBackup_key:[[NSData alloc] initWithData:(__bridge NSData * _Nonnull)(bKey)]];
367 }
368 CFReleaseNull(bKey);
369
370 require_action_quiet(*der_p && *der_p == der_end, fail,
371 SOSCreateError(kSOSErrorBadFormat, CFSTR("Didn't consume all bytes v7"), (error != NULL) ? *error : NULL, error));
372
373 result = account;
374
375 fail:
376 return result;
377 }
378
379 //
380 // Version History for Account
381 //
382 // 1-5 - InnsbruckTaos/Cab; Never supported even for upgrading.
383 // 6 - First version used in the field.
384 // 7 - One Circle version
385 // 8 - Adding expansion dictionary
386 //
387
388 #define CURRENT_ACCOUNT_PERSISTENT_VERSION 8
389
390 static SOSAccount* SOSAccountCreateFromDER(CFAllocatorRef allocator,
391 SOSDataSourceFactoryRef factory,
392 CFErrorRef* error,
393 const uint8_t** der_p, const uint8_t *der_end)
394 {
395 SOSAccount* account = NULL;
396 uint64_t version = 0;
397
398 SOSFullPeerInfoRef identity = NULL;
399
400 const uint8_t *sequence_end;
401 *der_p = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &sequence_end, *der_p, der_end);
402 *der_p = ccder_decode_uint64(&version, *der_p, sequence_end);
403 if (*der_p == NULL) {
404 SOSCreateError(kSOSErrorBadFormat, CFSTR("Version parsing failed"), (error != NULL) ? *error : NULL, error);
405 return nil;
406 }
407
408 switch (version) {
409 case CURRENT_ACCOUNT_PERSISTENT_VERSION:
410 account = SOSAccountCreateFromRemainingDER_v8(allocator, factory, error, der_p, sequence_end);
411 break;
412
413 case 7:
414 account = SOSAccountCreateFromRemainingDER_v7(allocator, factory, error, der_p, sequence_end);
415 break;
416
417 case 6:
418 account = SOSAccountCreateFromRemainingDER_v6(allocator, factory, error, der_p, sequence_end);
419 break;
420
421 default:
422 SOSCreateErrorWithFormat(kSOSErrorBadFormat, (error != NULL) ? *error : NULL, error,
423 NULL, CFSTR("Unsupported version (%llu)"), version);
424 break;
425 }
426
427 if (!account) {
428 // Error should have been filled in above.
429 return nil;
430 }
431
432 if (*der_p != sequence_end) {
433 SOSCreateError(kSOSErrorBadFormat, CFSTR("Extra data at the end of saved acount"), (error != NULL) ? *error : NULL, error);
434 return nil;
435 }
436
437 identity = account.fullPeerInfo;
438 /* I may not always have an identity, but when I do, it has a private key */
439 if(identity) {
440 if(!(SOSFullPeerInfoPrivKeyExists(identity)))
441 {
442 SOSUnregisterTransportKeyParameter(account.key_transport);
443 SOSUnregisterTransportCircle((SOSCircleStorageTransport*)account.circle_transport);
444 SOSUnregisterTransportMessage((SOSMessage*)account.ids_message_transport);
445 SOSUnregisterTransportMessage(account.kvs_message_transport);
446
447 secnotice("account", "No private key associated with my_identity, resetting");
448 return nil;
449 }
450 notify_post(kSecServerPeerInfoAvailable);
451 if(account.deviceID && [account.deviceID length] != 0){
452 SOSFullPeerInfoUpdateDeviceID(identity, (__bridge CFStringRef)(account.deviceID), error);
453 account.trust.fullPeerInfo = identity;
454 }
455 }
456
457 if (![account ensureFactoryCircles]) {
458 SOSCreateError(kSOSErrorBadFormat, CFSTR("Cannot EnsureFactoryCircles"), (error != NULL) ? *error : NULL, error);
459 return nil;
460 }
461
462 SOSPeerInfoRef oldPI = CFRetainSafe(account.peerInfo);
463 if (oldPI) {
464 SOSAccountCheckForAlwaysOnViews(account);
465 // if UpdateFullPeerInfo did something - we need to make sure we have the right Ref
466 SOSPeerInfoRef myPI = account.peerInfo;
467 CFStringRef transportTypeInflatedFromDER = SOSPeerInfoCopyTransportType(myPI);
468
469 if(CFStringCompare(transportTypeInflatedFromDER, CFSTR("KVS"), 0) != 0){
470 SOSFullPeerInfoUpdateTransportType(identity, SOSTransportMessageTypeKVS, NULL);
471 }
472
473 CFReleaseNull(transportTypeInflatedFromDER);
474 }
475 CFReleaseNull(oldPI);
476
477 SOSAccountEnsureRecoveryRing(account);
478
479 [account performTransaction:^(SOSAccountTransaction * _Nonnull txn) {
480 secnotice("circleop", "Setting account.key_interests_need_updating to true in SOSAccountCreateFromDER");
481 account.key_interests_need_updating = true;
482 }];
483
484 SOSAccountEnsureUUID(account);
485
486 return account;
487 }
488
489 +(instancetype) accountFromDER: (const uint8_t**) der
490 end: (const uint8_t*) der_end
491 factory: (SOSDataSourceFactoryRef) factory
492 error: (NSError**) error {
493 CFErrorRef failure = NULL;
494 SOSAccount* result = SOSAccountCreateFromDER(kCFAllocatorDefault, factory, &failure, der, der_end);
495
496 if (result == nil) {
497 if (error) {
498 *error = (__bridge_transfer NSError*) failure;
499 failure = NULL;
500 }
501 }
502 CFReleaseNull(failure);
503
504 return result;
505 }
506
507 +(instancetype) accountFromData: (NSData*) data
508 factory: (SOSDataSourceFactoryRef) factory
509 error: (NSError**) error {
510 size_t size = [data length];
511 const uint8_t *der = [data bytes];
512 return [self accountFromDER: &der end: der+size factory: factory error: error];
513 }
514
515 CFMutableSetRef SOSPeerInfoSetCreateFromArrayDER(CFAllocatorRef allocator, const CFSetCallBacks *callbacks, CFErrorRef* error,
516 const uint8_t** der_p, const uint8_t *der_end);
517 size_t SOSPeerInfoSetGetDEREncodedArraySize(CFSetRef pia, CFErrorRef *error);
518 uint8_t* SOSPeerInfoSetEncodeToArrayDER(CFSetRef pia, CFErrorRef* error, const uint8_t* der, uint8_t* der_end);
519
520 /************************/
521
522
523 - (NSData*) encodedData: (NSError* __autoreleasing *) error {
524 NSUInteger expected = [self.trust getDEREncodedSize: self err:error];
525 if (expected == 0) return nil;
526
527 return [NSMutableData dataWithSpace:expected
528 DEREncode:^uint8_t *(size_t size, uint8_t *buffer) {
529 return [self.trust encodeToDER:self
530 err:error
531 start:buffer
532 end:buffer + size];
533 }];
534 }
535
536 @end