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