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