]> git.saurik.com Git - apple/security.git/blob - keychain/SecureObjectSync/SOSBackupSliceKeyBag.m
Security-59306.101.1.tar.gz
[apple/security.git] / keychain / SecureObjectSync / SOSBackupSliceKeyBag.m
1 /*
2 * Copyright (c) 2015-2017 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 // Our Header
26
27 #include <Security/SecureObjectSync/SOSBackupSliceKeyBag.h>
28
29
30 // Needed headers for implementation
31 #include "AssertMacros.h"
32 #include <utilities/SecCFWrappers.h>
33 #include <utilities/SecAKSWrappers.h>
34 #include <utilities/SecBuffer.h>
35 #include <utilities/SecCFError.h>
36 #include <utilities/der_set.h>
37 #include <utilities/der_plist_internal.h>
38 #include <Security/SecRandom.h>
39 #include <Security/SecureObjectSync/SOSPeerInfo.h>
40 #include "keychain/SecureObjectSync/SOSPeerInfoCollections.h"
41 #include "keychain/SecureObjectSync/SOSInternal.h"
42
43 #include <corecrypto/ccec.h>
44 #include <corecrypto/ccsha2.h>
45 #include <corecrypto/ccrng.h>
46
47 #include <limits.h>
48
49 #include <Security/SecRecoveryKey.h>
50 #include "SOSKeyedPubKeyIdentifier.h"
51 #include "keychain/SecureObjectSync/SOSInternal.h"
52 #include "SecADWrapper.h"
53 #include "SecCFAllocator.h"
54
55 CFStringRef bskbRkbgPrefix = CFSTR("RK");
56
57 CFDataRef SOSRKNullKey(void) {
58 static CFDataRef localNullKey = NULL;
59 static dispatch_once_t onceToken;
60 dispatch_once(&onceToken, ^{
61 localNullKey = CFDataCreate(kCFAllocatorDefault, (const UInt8*) "nullkey", 8);
62 });
63 return localNullKey;
64 }
65
66 //
67 // MARK: Type creation
68 //
69
70 CFGiblisFor(SOSBackupSliceKeyBag);
71
72 const int kAKSBagSecretLength = 32;
73
74 struct __OpaqueSOSBackupSliceKeyBag {
75 CFRuntimeBase _base;
76
77 CFDataRef aks_bag;
78
79 CFSetRef peers;
80 CFDictionaryRef wrapped_keys;
81 };
82
83 static void SOSBackupSliceKeyBagDestroy(CFTypeRef aObj) {
84 SOSBackupSliceKeyBagRef vb = (SOSBackupSliceKeyBagRef) aObj;
85
86 CFReleaseNull(vb->aks_bag);
87 CFReleaseNull(vb->peers);
88 CFReleaseNull(vb->wrapped_keys);
89 }
90
91 static CFSetRef SOSBackupSliceKeyBagCopyPeerNames(SOSBackupSliceKeyBagRef bksb) {
92 CFMutableSetRef retval = CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
93 if(!retval) return NULL;
94 CFSetForEach(bksb->peers, ^(const void *value) {
95 SOSPeerInfoRef pi = (SOSPeerInfoRef) value;
96 CFSetAddValue(retval, SOSPeerInfoGetPeerName(pi));
97 });
98 return retval;
99 }
100
101 static CFStringRef SOSBackupSliceKeyBagCopyFormatDescription(CFTypeRef aObj, CFDictionaryRef formatOptions) {
102 SOSBackupSliceKeyBagRef vb = (SOSBackupSliceKeyBagRef) aObj;
103
104 CFMutableStringRef retval = CFStringCreateMutable(kCFAllocatorDefault, 0);
105
106 CFSetRef peerIDs = SOSBackupSliceKeyBagCopyPeerNames(vb);
107 CFStringSetPerformWithDescription(peerIDs, ^(CFStringRef description) {
108 CFStringAppendFormat(retval, NULL, CFSTR("<SOSBackupSliceKeyBag@%p %ld %@"), vb, vb->peers ? CFSetGetCount(vb->peers) : 0, description);
109 });
110 CFReleaseNull(peerIDs);
111 CFStringAppend(retval, CFSTR(">"));
112
113 return retval;
114 }
115
116
117 //
118 // MARK: Encode/Decode
119 //
120
121 const uint8_t* der_decode_BackupSliceKeyBag(CFAllocatorRef allocator,
122 SOSBackupSliceKeyBagRef* BackupSliceKeyBag, CFErrorRef *error,
123 const uint8_t* der, const uint8_t *der_end) {
124 if (der == NULL) return der;
125
126 const uint8_t *result = NULL;
127 SOSBackupSliceKeyBagRef vb = CFTypeAllocate(SOSBackupSliceKeyBag, struct __OpaqueSOSBackupSliceKeyBag, allocator);
128 require_quiet(SecAllocationError(vb, error, CFSTR("View bag allocation failed")), fail);
129
130 const uint8_t *sequence_end = NULL;
131 der = ccder_decode_sequence_tl(&sequence_end, der, der_end);
132 require_quiet(sequence_end == der_end, fail);
133
134 der = der_decode_data(kCFAllocatorDefault, kCFPropertyListImmutable, &vb->aks_bag, error, der, sequence_end);
135 vb->peers = SOSPeerInfoSetCreateFromArrayDER(kCFAllocatorDefault, &kSOSPeerSetCallbacks, error,
136 &der, der_end);
137 der = der_decode_dictionary(kCFAllocatorDefault, kCFPropertyListImmutable, &vb->wrapped_keys, error, der, sequence_end);
138
139 require_quiet(SecRequirementError(der == der_end, error, CFSTR("Extra space in sequence")), fail);
140
141 if (BackupSliceKeyBag)
142 CFTransferRetained(*BackupSliceKeyBag, vb);
143
144 result = der;
145
146 fail:
147 CFReleaseNull(vb);
148 return result;
149 }
150
151 size_t der_sizeof_BackupSliceKeyBag(SOSBackupSliceKeyBagRef BackupSliceKeyBag, CFErrorRef *error) {
152 size_t result = 0;
153
154 require_quiet(SecRequirementError(BackupSliceKeyBag != NULL, error, CFSTR("Null BackupSliceKeyBag")), fail);
155 require_quiet(BackupSliceKeyBag != NULL, fail); // this is redundant with what happens in SecRequirementError, but the analyzer can't understand that.
156 require_quiet(SecRequirementError(BackupSliceKeyBag->aks_bag != NULL, error, CFSTR("null aks_bag in BackupSliceKeyBag")), fail);
157 require_quiet(BackupSliceKeyBag->aks_bag != NULL, fail); // this is redundant with what happens in SecRequirementError, but the analyzer can't understand that.
158
159 size_t bag_size = der_sizeof_data(BackupSliceKeyBag->aks_bag, error);
160 require_quiet(bag_size, fail);
161
162 size_t peers_size = SOSPeerInfoSetGetDEREncodedArraySize(BackupSliceKeyBag->peers, error);
163 require_quiet(peers_size, fail);
164
165 size_t wrapped_keys_size = der_sizeof_dictionary(BackupSliceKeyBag->wrapped_keys, error);
166 require_quiet(wrapped_keys_size, fail);
167
168 result = ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, bag_size + peers_size + wrapped_keys_size);
169
170 fail:
171 return result;
172 }
173
174 uint8_t* der_encode_BackupSliceKeyBag(SOSBackupSliceKeyBagRef set, CFErrorRef *error,
175 const uint8_t *der, uint8_t *der_end) {
176 uint8_t *result = NULL;
177 if (der_end == NULL) return der_end;
178
179 require_quiet(SecRequirementError(set != NULL, error, CFSTR("Null set passed to encode")), fail);
180 require_quiet(set, fail); // Silence the NULL warning.
181
182 require_quiet(SecRequirementError(set->aks_bag != NULL, error, CFSTR("Null set passed to encode")), fail);
183 require_quiet(set->aks_bag, fail); // Silence the warning.
184
185 der_end = ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der,
186 der_encode_data(set->aks_bag, error, der,
187 SOSPeerInfoSetEncodeToArrayDER(set->peers, error, der,
188 der_encode_dictionary(set->wrapped_keys, error, der, der_end))));
189
190 require_quiet(der_end == der, fail);
191
192 result = der_end;
193 fail:
194 return result;
195 }
196
197
198
199 SOSBackupSliceKeyBagRef SOSBackupSliceKeyBagCreateFromData(CFAllocatorRef allocator, CFDataRef data, CFErrorRef *error) {
200 SOSBackupSliceKeyBagRef result = NULL;
201 SOSBackupSliceKeyBagRef decodedBag = NULL;
202
203 const uint8_t *der = CFDataGetBytePtr(data);
204 const uint8_t *der_end = der + CFDataGetLength(data);
205
206 der = der_decode_BackupSliceKeyBag(allocator, &decodedBag, error, der, der_end);
207
208 require_quiet(SecRequirementError(der == der_end, error, CFSTR("Didn't consume all data supplied")), fail);
209
210 CFTransferRetained(result, decodedBag);
211
212 fail:
213 CFReleaseNull(decodedBag);
214 return result;
215 }
216
217 //
218 // MARK: Construction
219 //
220
221 bool SOSBSKBIsGoodBackupPublic(CFDataRef publicKey, CFErrorRef *error) {
222 bool result = false;
223
224 ccec_pub_ctx_decl_cp(SOSGetBackupKeyCurveParameters(), pub_key);
225
226 int cc_result = ccec_compact_import_pub(SOSGetBackupKeyCurveParameters(), CFDataGetLength(publicKey), CFDataGetBytePtr(publicKey), pub_key);
227
228 require_action_quiet(cc_result == 0, exit, SOSErrorCreate(kSOSErrorDecodeFailure, error, NULL, CFSTR("Unable to decode public key: %@"), publicKey));
229
230 result = true;
231 exit:
232 return result;
233
234 }
235
236
237 static CFDataRef SOSCopyECWrapped(CFDataRef publicKey, CFDataRef secret, CFErrorRef *error) {
238 CFDataRef result = NULL;
239
240 ccec_pub_ctx_decl_cp(SOSGetBackupKeyCurveParameters(), pub_key);
241
242 int cc_result = ccec_compact_import_pub(SOSGetBackupKeyCurveParameters(), CFDataGetLength(publicKey), CFDataGetBytePtr(publicKey), pub_key);
243
244 require_action_quiet(cc_result == 0, exit, SOSErrorCreate(kSOSErrorDecodeFailure, error, NULL, CFSTR("Unable to decode public key: %@"), publicKey));
245
246 result = SOSCopyECWrappedData(pub_key, secret, error);
247
248 exit:
249 return result;
250 }
251
252
253 static CFDictionaryRef SOSBackupSliceKeyBagCopyWrappedKeys(SOSBackupSliceKeyBagRef vb, CFDataRef secret, CFDictionaryRef additionalKeys, CFErrorRef *error) {
254 CFDictionaryRef result = NULL;
255 CFMutableDictionaryRef wrappedKeys = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
256
257 __block bool success = true;
258 CFSetForEach(vb->peers, ^(const void *value) {
259 SOSPeerInfoRef pi = (SOSPeerInfoRef) value;
260 if (isSOSPeerInfo(pi)) {
261 CFStringRef id = SOSPeerInfoGetPeerID(pi);
262 CFDataRef backupKey = SOSPeerInfoCopyBackupKey(pi);
263
264 if (backupKey) {
265 CFErrorRef wrapError = NULL;
266 CFDataRef wrappedKey = SOSCopyECWrapped(backupKey, secret, &wrapError);
267 if (wrappedKey) {
268 CFDictionaryAddValue(wrappedKeys, id, wrappedKey);
269 CFDataPerformWithHexString(backupKey, ^(CFStringRef backupKeyString) {
270 CFDataPerformWithHexString(wrappedKey, ^(CFStringRef wrappedKeyString) {
271 secnotice("bskb", "Add for id: %@, bk: %@, wrapped: %@", id, backupKeyString, wrappedKeyString);
272 });
273 });
274 } else {
275 CFDataPerformWithHexString(backupKey, ^(CFStringRef backupKeyString) {
276 secnotice("bskb", "Failed at id: %@, bk: %@ error: %@", id, backupKeyString, wrapError);
277 });
278 CFErrorPropagate(wrapError, error);
279 success = false;
280 }
281 CFReleaseNull(wrappedKey);
282 CFReleaseNull(backupKey);
283 } else {
284 secnotice("bskb", "Skipping id %@, no backup key.", id);
285 }
286
287 }
288 });
289
290 CFDictionaryForEach(additionalKeys, ^(const void *key, const void *value) {
291 CFStringRef prefix = asString(key, NULL);
292 CFDataRef backupKey = asData(value, NULL);
293 if (backupKey) {
294 CFDataRef wrappedKey = NULL;
295 CFErrorRef localError = NULL;
296 CFStringRef id = SOSKeyedPubKeyIdentifierCreateWithData(prefix, backupKey);
297 require_quiet(id, done);
298
299 wrappedKey = SOSCopyECWrapped(backupKey, secret, &localError);
300 require_quiet(wrappedKey, done);
301
302 CFDictionaryAddValue(wrappedKeys, id, wrappedKey);
303
304 done:
305 if (!localError) {
306 CFDataPerformWithHexString(backupKey, ^(CFStringRef backupKeyString) {
307 CFDataPerformWithHexString(wrappedKey, ^(CFStringRef wrappedKeyString) {
308 secnotice("bskb", "Add for bk: %@, wrapped: %@", backupKeyString, wrappedKeyString);
309 });
310 });
311 } else {
312 CFDataPerformWithHexString(backupKey, ^(CFStringRef backupKeyString) {
313 secnotice("bskb", "Failed at bk: %@ error: %@", backupKeyString, localError);
314 });
315 CFErrorPropagate(localError, error);
316 success = false;
317 }
318 CFReleaseNull(wrappedKey);
319 CFReleaseNull(id);
320 } else {
321 secnotice("bskb", "Skipping %@, not data.", value);
322 }
323 });
324
325 if (success)
326 CFTransferRetained(result, wrappedKeys);
327
328 CFReleaseNull(wrappedKeys);
329 return result;
330 }
331
332 static bool SOSBackupSliceKeyBagCreateBackupBag(SOSBackupSliceKeyBagRef vb, CFDictionaryRef/*CFDataRef*/ additionalKeys, CFErrorRef* error) {
333 CFReleaseNull(vb->aks_bag);
334
335 // Choose a random key.
336 PerformWithBufferAndClear(kAKSBagSecretLength, ^(size_t size, uint8_t *buffer) {
337 CFDataRef secret = NULL;
338
339 require_quiet(SecError(SecRandomCopyBytes(kSecRandomDefault, size, buffer), error, CFSTR("SecRandom falied!")), fail);
340
341 secret = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, buffer, size, kCFAllocatorNull);
342
343 CFAssignRetained(vb->wrapped_keys, SOSBackupSliceKeyBagCopyWrappedKeys(vb, secret, additionalKeys, error));
344 CFAssignRetained(vb->aks_bag, SecAKSCopyBackupBagWithSecret(size, buffer, error));
345
346 fail:
347 CFReleaseSafe(secret);
348 });
349
350 return vb->aks_bag != NULL;
351 }
352
353
354 CFDataRef SOSBSKBCopyEncoded(SOSBackupSliceKeyBagRef BackupSliceKeyBag, CFErrorRef* error) {
355 CFDataRef result = NULL;
356 CFMutableDataRef encoded = NULL;
357
358 size_t encodedSize = der_sizeof_BackupSliceKeyBag(BackupSliceKeyBag, error);
359 require_quiet(encodedSize, fail);
360
361 encoded = CFDataCreateMutableWithScratch(kCFAllocatorDefault, encodedSize);
362 require_quiet(SecAllocationError(encoded, error, CFSTR("Faild to create scratch")), fail);
363
364 uint8_t *encode_to = CFDataGetMutableBytePtr(encoded);
365 uint8_t *encode_to_end = encode_to + CFDataGetLength(encoded);
366 require_quiet(encode_to == der_encode_BackupSliceKeyBag(BackupSliceKeyBag, error, encode_to, encode_to_end), fail);
367
368 CFTransferRetained(result, encoded);
369
370 fail:
371 CFReleaseSafe(encoded);
372 return result;
373 }
374
375 static CFSetRef SOSBackupSliceKeyBagCreatePeerSet(CFAllocatorRef allocator, CFSetRef peers) {
376 CFMutableSetRef result = CFSetCreateMutableForSOSPeerInfosByID(allocator);
377
378 CFSetForEach(peers, ^(const void *value) {
379 CFSetAddValue(result, value);
380 });
381
382 return result;
383 }
384
385 SOSBackupSliceKeyBagRef SOSBackupSliceKeyBagCreate(CFAllocatorRef allocator, CFSetRef peers, CFErrorRef* error) {
386 CFMutableDictionaryRef additionalKeys = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
387
388 SOSBackupSliceKeyBagRef result = SOSBackupSliceKeyBagCreateWithAdditionalKeys(allocator, peers, additionalKeys, NULL);
389
390 CFReleaseNull(additionalKeys);
391
392 return result;
393 }
394
395 SOSBackupSliceKeyBagRef SOSBackupSliceKeyBagCreateWithAdditionalKeys(CFAllocatorRef allocator,
396 CFSetRef /*SOSPeerInfoRef*/ peers,
397 CFDictionaryRef /*CFStringRef (prefix) CFDataRef (keydata) */ additionalKeys,
398 CFErrorRef* error) {
399 SOSBackupSliceKeyBagRef result = NULL;
400 SOSBackupSliceKeyBagRef vb = CFTypeAllocate(SOSBackupSliceKeyBag, struct __OpaqueSOSBackupSliceKeyBag, allocator);
401 require_quiet(SecAllocationError(vb, error, CFSTR("View bag allocation failed")), fail);
402
403 require_quiet(SecRequirementError(CFSetGetCount(peers) > 0, error, CFSTR("Need peers")), fail);
404
405 vb->peers = SOSBackupSliceKeyBagCreatePeerSet(allocator, peers);
406 vb->wrapped_keys = CFDictionaryCreateMutableForCFTypes(allocator);
407
408 require_quiet(SOSBackupSliceKeyBagCreateBackupBag(vb, additionalKeys, error), fail);
409
410 CFTransferRetained(result, vb);
411
412 fail:
413 CFReleaseNull(vb);
414 return result;
415 }
416
417
418 SOSBackupSliceKeyBagRef SOSBackupSliceKeyBagCreateDirect(CFAllocatorRef allocator, CFDataRef aks_bag, CFErrorRef *error)
419 {
420 SOSBackupSliceKeyBagRef result = NULL;
421 SOSBackupSliceKeyBagRef vb = CFTypeAllocate(SOSBackupSliceKeyBag, struct __OpaqueSOSBackupSliceKeyBag, allocator);
422 require_quiet(SecAllocationError(vb, error, CFSTR("View bag allocation failed")), fail);
423
424 require_quiet(SecRequirementError(aks_bag, error, CFSTR("Need aks bag")), fail);
425
426 vb->aks_bag = CFRetainSafe(aks_bag);
427 vb->peers = CFSetCreateMutableForSOSPeerInfosByID(allocator);
428 vb->wrapped_keys = CFDictionaryCreateMutableForCFTypes(allocator);
429
430 CFTransferRetained(result, vb);
431
432 fail:
433 CFReleaseNull(vb);
434 return result;
435 }
436
437 //
438 // MARK: Use
439 //
440
441 bool SOSBSKBIsDirect(SOSBackupSliceKeyBagRef backupSliceKeyBag)
442 {
443 return 0 == CFSetGetCount(backupSliceKeyBag->peers);
444 }
445
446 CFDataRef SOSBSKBCopyAKSBag(SOSBackupSliceKeyBagRef backupSliceKeyBag, CFErrorRef* error)
447 {
448 return CFRetainSafe(backupSliceKeyBag->aks_bag);
449 }
450
451 CFSetRef SOSBSKBGetPeers(SOSBackupSliceKeyBagRef backupSliceKeyBag){
452 return backupSliceKeyBag->peers;
453 }
454
455 int SOSBSKBCountPeers(SOSBackupSliceKeyBagRef backupSliceKeyBag) {
456 return (backupSliceKeyBag->peers) ? (int) CFSetGetCount(backupSliceKeyBag->peers): 0;
457 }
458
459 bool SOSBSKBPeerIsInKeyBag(SOSBackupSliceKeyBagRef backupSliceKeyBag, SOSPeerInfoRef pi) {
460 return CFSetGetValue(backupSliceKeyBag->peers, pi) != NULL;
461 }
462
463
464
465 bool SOSBKSBKeyIsInKeyBag(SOSBackupSliceKeyBagRef backupSliceKeyBag, CFDataRef publicKey) {
466 bool result = false;
467 CFStringRef keyID = SOSCopyIDOfDataBuffer(publicKey, NULL);
468 require_quiet(keyID, done);
469
470 result = CFDictionaryContainsKey(backupSliceKeyBag->wrapped_keys, keyID);
471
472 done:
473 CFReleaseSafe(keyID);
474 return result;
475 }
476
477 bool SOSBKSBPeerBackupKeyIsInKeyBag(SOSBackupSliceKeyBagRef backupSliceKeyBag, SOSPeerInfoRef pi) {
478 bool result = false;
479 CFDataRef bskbBackupKey = NULL;
480
481 CFDataRef backupKey = SOSPeerInfoCopyBackupKey(pi);
482 SOSPeerInfoRef backupPI = asSOSPeerInfo(CFSetGetValue(backupSliceKeyBag->peers, pi));
483 if(backupPI) {
484 bskbBackupKey = SOSPeerInfoCopyBackupKey(backupPI);
485 }
486 result = CFEqualSafe(backupKey, bskbBackupKey);
487 CFReleaseNull(bskbBackupKey);
488 CFReleaseNull(backupKey);
489 return result;
490 }
491
492 // returns true if all peers in (peers) and only those peers have matching backupKeys in the BSKB
493 bool SOSBSKBAllPeersBackupKeysAreInKeyBag(SOSBackupSliceKeyBagRef backupSliceKeyBag, CFSetRef peers) {
494 __block bool result = false;
495 if(backupSliceKeyBag && peers) {
496 result = (SOSBSKBCountPeers(backupSliceKeyBag) == CFSetGetCount(peers));
497 if(result) {
498 CFSetForEach(peers, ^(const void *value) {
499 SOSPeerInfoRef pi = asSOSPeerInfo(value);
500 result &= pi && SOSBKSBPeerBackupKeyIsInKeyBag(backupSliceKeyBag, pi);
501 });
502 }
503 }
504 return result;
505 }
506
507 bool SOSBKSBPrefixedKeyIsInKeyBag(SOSBackupSliceKeyBagRef backupSliceKeyBag, CFStringRef prefix, CFDataRef publicKey) {
508 bool result = false;
509 CFStringRef kpkid = SOSKeyedPubKeyIdentifierCreateWithData(prefix, publicKey);
510 require_quiet(kpkid, done);
511
512 result = CFDictionaryContainsKey(backupSliceKeyBag->wrapped_keys, kpkid);
513
514 done:
515 CFReleaseSafe(kpkid);
516 return result;
517
518 }
519
520
521
522 bskb_keybag_handle_t SOSBSKBLoadLocked(SOSBackupSliceKeyBagRef backupSliceKeyBag,
523 CFErrorRef *error)
524 {
525 #if !TARGET_HAS_KEYSTORE
526 return bad_keybag_handle;
527 #else
528 keybag_handle_t result = bad_keybag_handle;
529 keybag_handle_t bag_handle = bad_keybag_handle;
530
531 require_quiet(SecRequirementError(backupSliceKeyBag->aks_bag, error,
532 CFSTR("No aks bag to load")), exit);
533 require_quiet(SecRequirementError(CFDataGetLength(backupSliceKeyBag->aks_bag) < INT_MAX, error,
534 CFSTR("No aks bag to load")), exit);
535
536 kern_return_t aks_result;
537 aks_result = aks_load_bag(CFDataGetBytePtr(backupSliceKeyBag->aks_bag),
538 (int) CFDataGetLength(backupSliceKeyBag->aks_bag),
539 &bag_handle);
540 require_quiet(SecKernError(aks_result, error,
541 CFSTR("aks_load_bag failed: %d"), aks_result), exit);
542
543 result = bag_handle;
544 bag_handle = bad_keybag_handle;
545
546 exit:
547 if (bag_handle != bad_keybag_handle) {
548 (void) aks_unload_bag(bag_handle);
549 }
550
551 return result;
552 #endif
553
554 }
555
556 static keybag_handle_t SOSBSKBLoadAndUnlockBagWithSecret(SOSBackupSliceKeyBagRef backupSliceKeyBag,
557 size_t secretSize, const uint8_t *secret,
558 CFErrorRef *error)
559 {
560 #if !TARGET_HAS_KEYSTORE
561 return bad_keybag_handle;
562 #else
563 keybag_handle_t result = bad_keybag_handle;
564 keybag_handle_t bag_handle = bad_keybag_handle;
565
566 require_quiet(SecRequirementError(backupSliceKeyBag->aks_bag, error,
567 CFSTR("No aks bag to load")), exit);
568 require_quiet(SecRequirementError(CFDataGetLength(backupSliceKeyBag->aks_bag) < INT_MAX, error,
569 CFSTR("No aks bag to load")), exit);
570 require_quiet(SecRequirementError(secretSize <= INT_MAX, error,
571 CFSTR("secret too big")), exit);
572
573 kern_return_t aks_result;
574 aks_result = aks_load_bag(CFDataGetBytePtr(backupSliceKeyBag->aks_bag),
575 (int) CFDataGetLength(backupSliceKeyBag->aks_bag),
576 &bag_handle);
577 require_quiet(SecKernError(aks_result, error,
578 CFSTR("aks_load_bag failed: %d"), aks_result), exit);
579
580 aks_result = aks_unlock_bag(bag_handle, secret, (int) secretSize);
581 require_quiet(SecKernError(aks_result, error,
582 CFSTR("failed to unlock bag: %d"), aks_result), exit);
583
584 result = bag_handle;
585 bag_handle = bad_keybag_handle;
586
587 exit:
588 if (bag_handle != bad_keybag_handle) {
589 (void) aks_unload_bag(bag_handle);
590 }
591
592 return result;
593 #endif
594 }
595
596 keybag_handle_t SOSBSKBLoadAndUnlockWithPeerIDAndSecret(SOSBackupSliceKeyBagRef backupSliceKeyBag,
597 CFStringRef peerID, CFDataRef peerSecret,
598 CFErrorRef *error)
599 {
600 __block keybag_handle_t result = bad_keybag_handle;
601
602 CFDataRef lookedUpData = CFDictionaryGetValue(backupSliceKeyBag->wrapped_keys, peerID);
603 require_quiet(SecRequirementError(lookedUpData != NULL, error, CFSTR("%@ has no wrapped key in %@"), peerID, backupSliceKeyBag), exit);
604
605 require_quiet(SOSPerformWithDeviceBackupFullKey(SOSGetBackupKeyCurveParameters(), peerSecret, error, ^(ccec_full_ctx_t fullKey) {
606 SOSPerformWithUnwrappedData(fullKey, lookedUpData, error, ^(size_t size, uint8_t *buffer) {
607 result = SOSBSKBLoadAndUnlockBagWithSecret(backupSliceKeyBag, size, buffer, error);
608 });
609 }), exit);
610
611 exit:
612 return result;
613 }
614
615
616 keybag_handle_t SOSBSKBLoadAndUnlockWithPeerSecret(SOSBackupSliceKeyBagRef backupSliceKeyBag,
617 SOSPeerInfoRef peer, CFDataRef peerSecret,
618 CFErrorRef *error)
619 {
620 return SOSBSKBLoadAndUnlockWithPeerIDAndSecret(backupSliceKeyBag, SOSPeerInfoGetPeerID(peer), peerSecret, error);
621 }
622
623 keybag_handle_t SOSBSKBLoadAndUnlockWithDirectSecret(SOSBackupSliceKeyBagRef backupSliceKeyBag,
624 CFDataRef secret,
625 CFErrorRef *error)
626 {
627 keybag_handle_t result = bad_keybag_handle;
628 require_quiet(SecRequirementError(SOSBSKBIsDirect(backupSliceKeyBag), error, CFSTR("Not direct bag")), exit);
629
630 result = SOSBSKBLoadAndUnlockBagWithSecret(backupSliceKeyBag,
631 CFDataGetLength(secret),
632 CFDataGetBytePtr(secret),
633 error);
634
635 exit:
636 return result;
637 }
638
639 #include <Security/SecRecoveryKey.h>
640
641 static bool SOSPerformWithRecoveryKeyFullKey(CFDataRef wrappingSecret, CFErrorRef *error, void (^operation)(ccec_full_ctx_t fullKey, CFStringRef keyID)) {
642 bool result = false;
643
644 CFStringRef keyID = NULL;
645 NSError *nserror = NULL;
646 SecRecoveryKey *sRecKey = NULL;
647 NSData* fullKeyBytes = NULL;
648 NSData* pubKeyBytes = NULL;
649 CFStringRef restoreKeySecret = CFStringCreateWithBytes(SecCFAllocatorZeroize(), CFDataGetBytePtr(wrappingSecret), CFDataGetLength(wrappingSecret), kCFStringEncodingUTF8, false);
650 require_action_quiet(restoreKeySecret, errOut, SOSErrorCreate(kSOSErrorDecodeFailure, error, NULL, CFSTR("Unable to create key string from data.")));
651
652 sRecKey = SecRKCreateRecoveryKeyWithError((__bridge NSString *)(restoreKeySecret), &nserror);
653 if(!sRecKey) {
654 if (error)
655 *error = (CFErrorRef)CFBridgingRetain(nserror);
656 goto errOut;
657 }
658
659 require_action_quiet(sRecKey, errOut, SOSErrorCreate(kSOSErrorDecodeFailure, error, NULL, CFSTR("Unable to create recovery key from string.")));
660
661 fullKeyBytes = SecRKCopyBackupFullKey(sRecKey);
662 pubKeyBytes = SecRKCopyBackupPublicKey(sRecKey);
663 require_action_quiet(fullKeyBytes && pubKeyBytes, errOut, SOSErrorCreate(kSOSErrorDecodeFailure, error, NULL, CFSTR("Unable to get recovery key public and private keys.")));
664 keyID = SOSCopyIDOfDataBuffer(((__bridge CFDataRef) pubKeyBytes), error);
665 require_quiet(keyID, errOut);
666 {
667 size_t keysize = ccec_compact_import_priv_size(CFDataGetLength((__bridge CFDataRef)fullKeyBytes));
668 ccec_const_cp_t cp = ccec_curve_for_length_lookup(keysize, ccec_cp_256(), ccec_cp_384(), ccec_cp_521());
669 ccec_full_ctx_decl_cp(cp, fullKey);
670 int res = ccec_compact_import_priv(cp, CFDataGetLength((__bridge CFDataRef)fullKeyBytes), CFDataGetBytePtr((__bridge CFDataRef)fullKeyBytes), fullKey);
671 if(res == 0) {
672 operation(fullKey, keyID);
673 result = true;
674 ccec_full_ctx_clear_cp(cp, fullKey);
675 }
676 }
677 if(!result) SOSErrorCreate(kSOSErrorProcessingFailure, error, NULL, CFSTR("Unable to perform crypto operation from fullKeyBytes."));
678
679 errOut:
680 CFReleaseNull(keyID);
681 CFReleaseNull(restoreKeySecret);
682 return result;
683 }
684
685 bskb_keybag_handle_t SOSBSKBLoadAndUnlockWithWrappingSecret(SOSBackupSliceKeyBagRef backupSliceKeyBag,
686 CFDataRef wrappingSecret,
687 CFErrorRef *error) {
688 __block keybag_handle_t result = bad_keybag_handle;
689
690 CFDataRef lookedUpData = SOSBSKBCopyRecoveryKey(backupSliceKeyBag);
691 require_quiet(SecRequirementError(lookedUpData != NULL, error, CFSTR("no recovery key found in %@"), backupSliceKeyBag), errOut);
692
693 SOSPerformWithRecoveryKeyFullKey(wrappingSecret, error, ^(ccec_full_ctx_t fullKey, CFStringRef keyID) {
694 SOSPerformWithUnwrappedData(fullKey, lookedUpData, error, ^(size_t size, uint8_t *buffer) {
695 result = SOSBSKBLoadAndUnlockBagWithSecret(backupSliceKeyBag, size, buffer, error);
696 });
697 });
698
699 errOut:
700 CFReleaseSafe(lookedUpData);
701 return result;
702 }
703
704 // fixed for <rdar://problem/30918831> CrashTracer: secdtests at secdtests: SOSBSKBCopyAdditionalKeysWithPrefix
705 static CFDictionaryRef SOSBSKBCopyAdditionalKeysWithPrefix(CFAllocatorRef allocator, SOSBackupSliceKeyBagRef bskb, CFStringRef prefix) {
706 if(!bskb || !bskb->wrapped_keys) return NULL;
707 CFMutableDictionaryRef retval = CFDictionaryCreateMutableForCFTypes(allocator);
708 if(!retval) return NULL;
709 CFDictionaryForEach(bskb->wrapped_keys, ^(const void *key, const void *value) {
710 CFStringRef kpkid = asString(key, NULL);
711 CFDataRef keyData = asData(value, NULL);
712 if(kpkid && keyData && SOSKeyedPubKeyIdentifierIsPrefixed(kpkid)) {
713 CFStringRef idPrefix = SOSKeyedPubKeyIdentifierCopyPrefix(kpkid);
714 if(CFEqualSafe(idPrefix, prefix)) {
715 CFDictionaryAddValue(retval, kpkid, keyData);
716 }
717 CFReleaseNull(idPrefix);
718 }
719 });
720 return retval;
721 }
722
723 static bool SOSBSKBHasPrefixedKey(SOSBackupSliceKeyBagRef bskb, CFStringRef prefix) {
724 CFDictionaryRef keyDict = SOSBSKBCopyAdditionalKeysWithPrefix(kCFAllocatorDefault, bskb, prefix);
725 bool haveKeys = keyDict && CFDictionaryGetCount(keyDict) > 0;
726 CFReleaseNull(keyDict);
727 return haveKeys;
728 }
729
730 CFDataRef SOSBSKBCopyRecoveryKey(SOSBackupSliceKeyBagRef bskb) {
731 if(!bskb) return NULL;
732 CFDictionaryRef keyDict = SOSBSKBCopyAdditionalKeysWithPrefix(kCFAllocatorDefault, bskb, bskbRkbgPrefix);
733 if(!keyDict) return NULL;
734 CFDataRef result = NULL;
735 if(CFDictionaryGetCount(keyDict) == 1) {
736 __block CFDataRef keyData = NULL;
737 CFDictionaryForEach(keyDict, ^(const void *key, const void *value) {
738 keyData = asData(value, NULL);
739 });
740 result = CFDataCreateCopy(kCFAllocatorDefault, keyData);
741 }
742 CFReleaseNull(keyDict);
743 return result;
744 }
745
746 bool SOSBSKBHasRecoveryKey(SOSBackupSliceKeyBagRef bskb) {
747 if(!bskb) return false;
748 if(SOSBSKBHasPrefixedKey(bskb, bskbRkbgPrefix)) {
749 return true;
750 }
751 // old way for RecoveryKeys
752 int keyCount = (bskb->wrapped_keys != NULL) ? (int) CFDictionaryGetCount(bskb->wrapped_keys): 0;
753 int peerCount = SOSBSKBCountPeers(bskb);
754 return !SOSBSKBIsDirect(bskb) && ((keyCount - peerCount) > 0);
755 }
756
757 bool SOSBSKBHasThisRecoveryKey(SOSBackupSliceKeyBagRef bskb, CFDataRef backupKey) {
758 if(backupKey) {
759 CFStringRef id = SOSKeyedPubKeyIdentifierCreateWithData(bskbRkbgPrefix, backupKey);
760 bool result = (bskb && id && CFDictionaryContainsKey(bskb->wrapped_keys, id));
761 CFReleaseNull(id);
762 return result;
763 } else {
764 return CFDictionaryGetCount(bskb->wrapped_keys) == SOSBSKBCountPeers(bskb);
765 }
766 }