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