]> git.saurik.com Git - apple/security.git/blob - OSX/sec/SOSCircle/SecureObjectSync/SOSBackupSliceKeyBag.c
2cd87920cb70169da8d110bbbc7b0b4f6a6f49a7
[apple/security.git] / OSX / sec / SOSCircle / SecureObjectSync / SOSBackupSliceKeyBag.c
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
26 #include <Security/SecureObjectSync/SOSBackupSliceKeyBag.h>
27
28
29 // Needed headers for implementation
30 #include "AssertMacros.h"
31 #include <utilities/SecCFWrappers.h>
32 #include <utilities/SecAKSWrappers.h>
33 #include <utilities/SecBuffer.h>
34 #include <utilities/SecCFError.h>
35 #include <utilities/der_set.h>
36 #include <utilities/der_plist_internal.h>
37 #include <Security/SecRandom.h>
38 #include <Security/SecureObjectSync/SOSPeerInfo.h>
39 #include <Security/SecureObjectSync/SOSPeerInfoCollections.h>
40 #include <Security/SecureObjectSync/SOSInternal.h>
41
42 #include <corecrypto/ccec.h>
43 #include <corecrypto/ccsha2.h>
44 #include <corecrypto/ccrng.h>
45
46 #include <limits.h>
47
48 #include "SOSInternal.h"
49
50 //
51 // MARK: Type creation
52 //
53
54 CFGiblisFor(SOSBackupSliceKeyBag);
55
56 const int kAKSBagSecretLength = 32;
57
58 struct __OpaqueSOSBackupSliceKeyBag {
59 CFRuntimeBase _base;
60
61 CFDataRef aks_bag;
62
63 CFSetRef peers;
64 CFDictionaryRef wrapped_keys;
65 };
66
67 static void SOSBackupSliceKeyBagDestroy(CFTypeRef aObj) {
68 SOSBackupSliceKeyBagRef vb = (SOSBackupSliceKeyBagRef) aObj;
69
70 CFReleaseNull(vb->aks_bag);
71 CFReleaseNull(vb->peers);
72 CFReleaseNull(vb->wrapped_keys);
73 }
74
75 static CFStringRef SOSBackupSliceKeyBagCopyFormatDescription(CFTypeRef aObj, CFDictionaryRef formatOptions) {
76 SOSBackupSliceKeyBagRef vb = (SOSBackupSliceKeyBagRef) aObj;
77
78 CFMutableStringRef description = CFStringCreateMutable(kCFAllocatorDefault, 0);
79
80 CFStringAppendFormat(description, NULL, CFSTR("<SOSBackupSliceKeyBag@%p %ld"), vb, vb->peers ? CFSetGetCount(vb->peers) : 0);
81 CFStringAppend(description, CFSTR(">"));
82
83 return description;
84 }
85
86
87 //
88 // MARK: Encode/Decode
89 //
90
91 const uint8_t* der_decode_BackupSliceKeyBag(CFAllocatorRef allocator,
92 SOSBackupSliceKeyBagRef* BackupSliceKeyBag, CFErrorRef *error,
93 const uint8_t* der, const uint8_t *der_end) {
94 if (der == NULL) return der;
95
96 const uint8_t *result = NULL;
97 SOSBackupSliceKeyBagRef vb = CFTypeAllocate(SOSBackupSliceKeyBag, struct __OpaqueSOSBackupSliceKeyBag, allocator);
98 require_quiet(SecAllocationError(vb, error, CFSTR("View bag allocation failed")), fail);
99
100 const uint8_t *sequence_end = NULL;
101 der = ccder_decode_sequence_tl(&sequence_end, der, der_end);
102 require_quiet(sequence_end == der_end, fail);
103
104 der = der_decode_data(kCFAllocatorDefault, kCFPropertyListImmutable, &vb->aks_bag, error, der, sequence_end);
105 vb->peers = SOSPeerInfoSetCreateFromArrayDER(kCFAllocatorDefault, &kSOSPeerSetCallbacks, error,
106 &der, der_end);
107 der = der_decode_dictionary(kCFAllocatorDefault, kCFPropertyListImmutable, &vb->wrapped_keys, error, der, sequence_end);
108
109 require_quiet(SecRequirementError(der == der_end, error, CFSTR("Extra space in sequence")), fail);
110
111 if (BackupSliceKeyBag)
112 CFTransferRetained(*BackupSliceKeyBag, vb);
113
114 result = der;
115
116 fail:
117 CFReleaseNull(vb);
118 return result;
119 }
120
121 size_t der_sizeof_BackupSliceKeyBag(SOSBackupSliceKeyBagRef BackupSliceKeyBag, CFErrorRef *error) {
122 size_t result = 0;
123
124 require_quiet(SecRequirementError(BackupSliceKeyBag != NULL, error, CFSTR("Null BackupSliceKeyBag")), fail);
125 require_quiet(BackupSliceKeyBag != NULL, fail); // this is redundant with what happens in SecRequirementError, but the analyzer can't understand that.
126 require_quiet(SecRequirementError(BackupSliceKeyBag->aks_bag != NULL, error, CFSTR("null aks_bag in BackupSliceKeyBag")), fail);
127 require_quiet(BackupSliceKeyBag->aks_bag != NULL, fail); // this is redundant with what happens in SecRequirementError, but the analyzer can't understand that.
128
129 size_t bag_size = der_sizeof_data(BackupSliceKeyBag->aks_bag, error);
130 require_quiet(bag_size, fail);
131
132 size_t peers_size = SOSPeerInfoSetGetDEREncodedArraySize(BackupSliceKeyBag->peers, error);
133 require_quiet(peers_size, fail);
134
135 size_t wrapped_keys_size = der_sizeof_dictionary(BackupSliceKeyBag->wrapped_keys, error);
136 require_quiet(wrapped_keys_size, fail);
137
138 result = ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, bag_size + peers_size + wrapped_keys_size);
139
140 fail:
141 return result;
142 }
143
144 uint8_t* der_encode_BackupSliceKeyBag(SOSBackupSliceKeyBagRef set, CFErrorRef *error,
145 const uint8_t *der, uint8_t *der_end) {
146 uint8_t *result = NULL;
147 if (der_end == NULL) return der_end;
148
149 require_quiet(SecRequirementError(set != NULL, error, CFSTR("Null set passed to encode")), fail);
150 require_quiet(set, fail); // Silence the NULL warning.
151
152 require_quiet(SecRequirementError(set->aks_bag != NULL, error, CFSTR("Null set passed to encode")), fail);
153 require_quiet(set->aks_bag, fail); // Silence the warning.
154
155 der_end = ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der,
156 der_encode_data(set->aks_bag, error, der,
157 SOSPeerInfoSetEncodeToArrayDER(set->peers, error, der,
158 der_encode_dictionary(set->wrapped_keys, error, der, der_end))));
159
160 require_quiet(der_end == der, fail);
161
162 result = der_end;
163 fail:
164 return result;
165 }
166
167
168 SOSBackupSliceKeyBagRef SOSBackupSliceKeyBagCreateFromData(CFAllocatorRef allocator, CFDataRef data, CFErrorRef *error) {
169 SOSBackupSliceKeyBagRef result = NULL;
170 SOSBackupSliceKeyBagRef decodedBag = NULL;
171
172 const uint8_t *der = CFDataGetBytePtr(data);
173 const uint8_t *der_end = der + CFDataGetLength(data);
174
175 der = der_decode_BackupSliceKeyBag(allocator, &decodedBag, error, der, der_end);
176
177 require_quiet(SecRequirementError(der == der_end, error, CFSTR("Didn't consume all data supplied")), fail);
178
179 CFTransferRetained(result, decodedBag);
180
181 fail:
182 CFReleaseNull(decodedBag);
183 return result;
184 }
185
186 //
187 // MARK: Construction
188 //
189
190 bool SOSBSKBIsGoodBackupPublic(CFDataRef publicKey, CFErrorRef *error) {
191 bool result = false;
192
193 ccec_pub_ctx_decl_cp(SOSGetBackupKeyCurveParameters(), pub_key);
194
195 int cc_result = ccec_compact_import_pub(SOSGetBackupKeyCurveParameters(), CFDataGetLength(publicKey), CFDataGetBytePtr(publicKey), pub_key);
196
197 require_action_quiet(cc_result == 0, exit, SOSErrorCreate(kSOSErrorDecodeFailure, error, NULL, CFSTR("Unable to decode public key: %@"), publicKey));
198
199 result = true;
200 exit:
201 return result;
202
203 }
204
205
206 static CFDataRef SOSCopyECWrapped(CFDataRef publicKey, CFDataRef secret, CFErrorRef *error) {
207 CFDataRef result = NULL;
208
209 ccec_pub_ctx_decl_cp(SOSGetBackupKeyCurveParameters(), pub_key);
210
211 int cc_result = ccec_compact_import_pub(SOSGetBackupKeyCurveParameters(), CFDataGetLength(publicKey), CFDataGetBytePtr(publicKey), pub_key);
212
213 require_action_quiet(cc_result == 0, exit, SOSErrorCreate(kSOSErrorDecodeFailure, error, NULL, CFSTR("Unable to decode public key: %@"), publicKey));
214
215 result = SOSCopyECWrappedData(pub_key, secret, error);
216
217 exit:
218 return result;
219 }
220
221
222 static CFDictionaryRef SOSBackupSliceKeyBagCopyWrappedKeys(SOSBackupSliceKeyBagRef vb, CFDataRef secret, CFErrorRef *error) {
223 CFDictionaryRef result = NULL;
224 CFMutableDictionaryRef wrappedKeys = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
225
226 __block bool success = true;
227 CFSetForEach(vb->peers, ^(const void *value) {
228 SOSPeerInfoRef pi = (SOSPeerInfoRef) value;
229 if (isSOSPeerInfo(pi)) {
230 CFStringRef id = SOSPeerInfoGetPeerID(pi);
231 CFDataRef backupKey = SOSPeerInfoCopyBackupKey(pi);
232
233 if (backupKey) {
234 CFErrorRef wrapError = NULL;
235 CFDataRef wrappedKey = SOSCopyECWrapped(backupKey, secret, &wrapError);
236 if (wrappedKey) {
237 CFDictionaryAddValue(wrappedKeys, id, wrappedKey);
238 CFDataPerformWithHexString(backupKey, ^(CFStringRef backupKeyString) {
239 CFDataPerformWithHexString(wrappedKey, ^(CFStringRef wrappedKeyString) {
240 secnotice("bskb", "Add for id: %@, bk: %@, wrapped: %@", id, backupKeyString, wrappedKeyString);
241 });
242 });
243 } else {
244 CFDataPerformWithHexString(backupKey, ^(CFStringRef backupKeyString) {
245 secnotice("bskb", "Failed at id: %@, bk: %@ error: %@", id, backupKeyString, wrapError);
246 });
247 CFErrorPropagate(wrapError, error);
248 success = false;
249 }
250 CFReleaseNull(wrappedKey);
251 CFReleaseNull(backupKey);
252 } else {
253 secnotice("bskb", "Skipping id %@, no backup key.", id);
254 }
255
256 }
257 });
258
259 if (success)
260 CFTransferRetained(result, wrappedKeys);
261
262 CFReleaseNull(wrappedKeys);
263 return result;
264 }
265
266 static bool SOSBackupSliceKeyBagCreateBackupBag(SOSBackupSliceKeyBagRef vb, CFErrorRef* error) {
267 CFReleaseNull(vb->aks_bag);
268
269 // Choose a random key.
270 PerformWithBufferAndClear(kAKSBagSecretLength, ^(size_t size, uint8_t *buffer) {
271 CFDataRef secret = NULL;
272
273 require_quiet(SecError(SecRandomCopyBytes(kSecRandomDefault, size, buffer), error, CFSTR("SecRandom falied!")), fail);
274
275 secret = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, buffer, size, kCFAllocatorNull);
276
277 CFAssignRetained(vb->wrapped_keys, SOSBackupSliceKeyBagCopyWrappedKeys(vb, secret, error));
278 CFAssignRetained(vb->aks_bag, SecAKSCopyBackupBagWithSecret(size, buffer, error));
279
280 fail:
281 CFReleaseSafe(secret);
282 });
283
284 return vb->aks_bag != NULL;
285 }
286
287
288 CFDataRef SOSBSKBCopyEncoded(SOSBackupSliceKeyBagRef BackupSliceKeyBag, CFErrorRef* error) {
289 CFDataRef result = NULL;
290 CFMutableDataRef encoded = NULL;
291
292 size_t encodedSize = der_sizeof_BackupSliceKeyBag(BackupSliceKeyBag, error);
293 require_quiet(encodedSize, fail);
294
295 encoded = CFDataCreateMutableWithScratch(kCFAllocatorDefault, encodedSize);
296 require_quiet(SecAllocationError(encoded, error, CFSTR("Faild to create scratch")), fail);
297
298 uint8_t *encode_to = CFDataGetMutableBytePtr(encoded);
299 uint8_t *encode_to_end = encode_to + CFDataGetLength(encoded);
300 require_quiet(encode_to == der_encode_BackupSliceKeyBag(BackupSliceKeyBag, error, encode_to, encode_to_end), fail);
301
302 CFTransferRetained(result, encoded);
303
304 fail:
305 CFReleaseSafe(encoded);
306 return result;
307 }
308
309 static CFSetRef SOSBackupSliceKeyBagCreatePeerSet(CFAllocatorRef allocator, CFSetRef peers) {
310 CFMutableSetRef result = CFSetCreateMutableForSOSPeerInfosByID(allocator);
311
312 CFSetForEach(peers, ^(const void *value) {
313 CFSetAddValue(result, value);
314 });
315
316 return result;
317 }
318
319 SOSBackupSliceKeyBagRef SOSBackupSliceKeyBagCreate(CFAllocatorRef allocator, CFSetRef peers, CFErrorRef* error) {
320 SOSBackupSliceKeyBagRef result = NULL;
321 SOSBackupSliceKeyBagRef vb = CFTypeAllocate(SOSBackupSliceKeyBag, struct __OpaqueSOSBackupSliceKeyBag, allocator);
322 require_quiet(SecAllocationError(vb, error, CFSTR("View bag allocation failed")), fail);
323
324 require_quiet(SecRequirementError(CFSetGetCount(peers) > 0, error, CFSTR("Need peers")), fail);
325
326 vb->peers = SOSBackupSliceKeyBagCreatePeerSet(allocator, peers);
327 vb->wrapped_keys = CFDictionaryCreateMutableForCFTypes(allocator);
328
329 require_quiet(SOSBackupSliceKeyBagCreateBackupBag(vb, error), fail);
330
331 CFTransferRetained(result, vb);
332
333 fail:
334 CFReleaseNull(vb);
335 return result;
336 }
337
338 SOSBackupSliceKeyBagRef SOSBackupSliceKeyBagCreateDirect(CFAllocatorRef allocator, CFDataRef aks_bag, CFErrorRef *error)
339 {
340 SOSBackupSliceKeyBagRef result = NULL;
341 SOSBackupSliceKeyBagRef vb = CFTypeAllocate(SOSBackupSliceKeyBag, struct __OpaqueSOSBackupSliceKeyBag, allocator);
342 require_quiet(SecAllocationError(vb, error, CFSTR("View bag allocation failed")), fail);
343
344 require_quiet(SecRequirementError(aks_bag, error, CFSTR("Need aks bag")), fail);
345
346 vb->aks_bag = CFRetainSafe(aks_bag);
347 vb->peers = CFSetCreateMutableForSOSPeerInfosByID(allocator);
348 vb->wrapped_keys = CFDictionaryCreateMutableForCFTypes(allocator);
349
350 CFTransferRetained(result, vb);
351
352 fail:
353 CFReleaseNull(vb);
354 return result;
355 }
356
357 //
358 // MARK: Use
359 //
360
361 bool SOSBSKBIsDirect(SOSBackupSliceKeyBagRef backupSliceKeyBag)
362 {
363 return 0 == CFSetGetCount(backupSliceKeyBag->peers);
364 }
365
366 CFDataRef SOSBSKBCopyAKSBag(SOSBackupSliceKeyBagRef backupSliceKeyBag, CFErrorRef* error)
367 {
368 return CFRetainSafe(backupSliceKeyBag->aks_bag);
369 }
370
371 CFSetRef SOSBSKBGetPeers(SOSBackupSliceKeyBagRef backupSliceKeyBag){
372 return backupSliceKeyBag->peers;
373 }
374
375 int SOSBSKBCountPeers(SOSBackupSliceKeyBagRef backupSliceKeyBag) {
376 return (int) CFSetGetCount(backupSliceKeyBag->peers);
377 }
378
379 bool SOSBSKBPeerIsInKeyBag(SOSBackupSliceKeyBagRef backupSliceKeyBag, SOSPeerInfoRef pi) {
380 return CFSetGetValue(backupSliceKeyBag->peers, pi) != NULL;
381 }
382
383 bskb_keybag_handle_t SOSBSKBLoadLocked(SOSBackupSliceKeyBagRef backupSliceKeyBag,
384 CFErrorRef *error)
385 {
386 #if !TARGET_HAS_KEYSTORE
387 return bad_keybag_handle;
388 #else
389 keybag_handle_t result = bad_keybag_handle;
390 keybag_handle_t bag_handle = bad_keybag_handle;
391
392 require_quiet(SecRequirementError(backupSliceKeyBag->aks_bag, error,
393 CFSTR("No aks bag to load")), exit);
394 require_quiet(SecRequirementError(CFDataGetLength(backupSliceKeyBag->aks_bag) < INT_MAX, error,
395 CFSTR("No aks bag to load")), exit);
396
397 kern_return_t aks_result;
398 aks_result = aks_load_bag(CFDataGetBytePtr(backupSliceKeyBag->aks_bag),
399 (int) CFDataGetLength(backupSliceKeyBag->aks_bag),
400 &bag_handle);
401 require_quiet(SecKernError(aks_result, error,
402 CFSTR("aks_load_bag failed: %d"), aks_result), exit);
403
404 result = bag_handle;
405 bag_handle = bad_keybag_handle;
406
407 exit:
408 if (bag_handle != bad_keybag_handle) {
409 (void) aks_unload_bag(bag_handle);
410 }
411
412 return result;
413 #endif
414
415 }
416
417 static keybag_handle_t SOSBSKBLoadAndUnlockBagWithSecret(SOSBackupSliceKeyBagRef backupSliceKeyBag,
418 size_t secretSize, const uint8_t *secret,
419 CFErrorRef *error)
420 {
421 #if !TARGET_HAS_KEYSTORE
422 return bad_keybag_handle;
423 #else
424 keybag_handle_t result = bad_keybag_handle;
425 keybag_handle_t bag_handle = bad_keybag_handle;
426
427 require_quiet(SecRequirementError(backupSliceKeyBag->aks_bag, error,
428 CFSTR("No aks bag to load")), exit);
429 require_quiet(SecRequirementError(CFDataGetLength(backupSliceKeyBag->aks_bag) < INT_MAX, error,
430 CFSTR("No aks bag to load")), exit);
431 require_quiet(SecRequirementError(secretSize <= INT_MAX, error,
432 CFSTR("secret too big")), exit);
433
434 kern_return_t aks_result;
435 aks_result = aks_load_bag(CFDataGetBytePtr(backupSliceKeyBag->aks_bag),
436 (int) CFDataGetLength(backupSliceKeyBag->aks_bag),
437 &bag_handle);
438 require_quiet(SecKernError(aks_result, error,
439 CFSTR("aks_load_bag failed: %d"), aks_result), exit);
440
441 aks_result = aks_unlock_bag(bag_handle, secret, (int) secretSize);
442 require_quiet(SecKernError(aks_result, error,
443 CFSTR("failed to unlock bag: %d"), aks_result), exit);
444
445 result = bag_handle;
446 bag_handle = bad_keybag_handle;
447
448 exit:
449 if (bag_handle != bad_keybag_handle) {
450 (void) aks_unload_bag(bag_handle);
451 }
452
453 return result;
454 #endif
455 }
456
457 keybag_handle_t SOSBSKBLoadAndUnlockWithPeerIDAndSecret(SOSBackupSliceKeyBagRef backupSliceKeyBag,
458 CFStringRef peerID, CFDataRef peerSecret,
459 CFErrorRef *error)
460 {
461 __block keybag_handle_t result = bad_keybag_handle;
462
463 CFDataRef lookedUpData = CFDictionaryGetValue(backupSliceKeyBag->wrapped_keys, peerID);
464 require_quiet(SecRequirementError(lookedUpData != NULL, error, CFSTR("%@ has no wrapped key in %@"), peerID, backupSliceKeyBag), exit);
465
466 require_quiet(SOSPerformWithDeviceBackupFullKey(SOSGetBackupKeyCurveParameters(), peerSecret, error, ^(ccec_full_ctx_t fullKey) {
467 SOSPerformWithUnwrappedData(fullKey, lookedUpData, error, ^(size_t size, uint8_t *buffer) {
468 result = SOSBSKBLoadAndUnlockBagWithSecret(backupSliceKeyBag, size, buffer, error);
469 });
470 }), exit);
471
472 exit:
473 return result;
474 }
475
476
477 keybag_handle_t SOSBSKBLoadAndUnlockWithPeerSecret(SOSBackupSliceKeyBagRef backupSliceKeyBag,
478 SOSPeerInfoRef peer, CFDataRef peerSecret,
479 CFErrorRef *error)
480 {
481 return SOSBSKBLoadAndUnlockWithPeerIDAndSecret(backupSliceKeyBag, SOSPeerInfoGetPeerID(peer), peerSecret, error);
482 }
483
484 keybag_handle_t SOSBSKBLoadAndUnlockWithDirectSecret(SOSBackupSliceKeyBagRef backupSliceKeyBag,
485 CFDataRef secret,
486 CFErrorRef *error)
487 {
488 keybag_handle_t result = bad_keybag_handle;
489 require_quiet(SecRequirementError(SOSBSKBIsDirect(backupSliceKeyBag), error, CFSTR("Not direct bag")), exit);
490
491 result = SOSBSKBLoadAndUnlockBagWithSecret(backupSliceKeyBag,
492 CFDataGetLength(secret),
493 CFDataGetBytePtr(secret),
494 error);
495
496 exit:
497 return result;
498 }