]> git.saurik.com Git - apple/security.git/blob - OSX/sec/SOSCircle/SecureObjectSync/SOSBackupSliceKeyBag.c
Security-57337.40.85.tar.gz
[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(SecRequirementError(BackupSliceKeyBag->aks_bag != NULL, error, CFSTR("null aks_bag in BackupSliceKeyBag")), fail);
126
127 size_t bag_size = der_sizeof_data(BackupSliceKeyBag->aks_bag, error);
128 require_quiet(bag_size, fail);
129
130 size_t peers_size = SOSPeerInfoSetGetDEREncodedArraySize(BackupSliceKeyBag->peers, error);
131 require_quiet(peers_size, fail);
132
133 size_t wrapped_keys_size = der_sizeof_dictionary(BackupSliceKeyBag->wrapped_keys, error);
134 require_quiet(wrapped_keys_size, fail);
135
136 result = ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, bag_size + peers_size + wrapped_keys_size);
137
138 fail:
139 return result;
140 }
141
142 uint8_t* der_encode_BackupSliceKeyBag(SOSBackupSliceKeyBagRef set, CFErrorRef *error,
143 const uint8_t *der, uint8_t *der_end) {
144 uint8_t *result = NULL;
145 if (der_end == NULL) return der_end;
146
147 require_quiet(SecRequirementError(set != NULL, error, CFSTR("Null set passed to encode")), fail);
148 require_quiet(set, fail); // This should be removed when SecRequirementError can squelch analyzer warnings
149
150 der_end = ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der,
151 der_encode_data(set->aks_bag, error, der,
152 SOSPeerInfoSetEncodeToArrayDER(set->peers, error, der,
153 der_encode_dictionary(set->wrapped_keys, error, der, der_end))));
154
155 require_quiet(der_end == der, fail);
156
157 result = der_end;
158 fail:
159 return result;
160 }
161
162
163 SOSBackupSliceKeyBagRef SOSBackupSliceKeyBagCreateFromData(CFAllocatorRef allocator, CFDataRef data, CFErrorRef *error) {
164 SOSBackupSliceKeyBagRef result = NULL;
165 SOSBackupSliceKeyBagRef decodedBag = NULL;
166
167 const uint8_t *der = CFDataGetBytePtr(data);
168 const uint8_t *der_end = der + CFDataGetLength(data);
169
170 der = der_decode_BackupSliceKeyBag(allocator, &decodedBag, error, der, der_end);
171
172 require_quiet(SecRequirementError(der == der_end, error, CFSTR("Didn't consume all data supplied")), fail);
173
174 CFTransferRetained(result, decodedBag);
175
176 fail:
177 CFReleaseNull(decodedBag);
178 return result;
179 }
180
181 //
182 // MARK: Construction
183 //
184
185 bool SOSBSKBIsGoodBackupPublic(CFDataRef publicKey, CFErrorRef *error) {
186 bool result = false;
187
188 ccec_pub_ctx_decl_cp(SOSGetBackupKeyCurveParameters(), pub_key);
189
190 int cc_result = ccec_compact_import_pub(SOSGetBackupKeyCurveParameters(), CFDataGetLength(publicKey), CFDataGetBytePtr(publicKey), pub_key);
191
192 require_action_quiet(cc_result == 0, exit, SOSErrorCreate(kSOSErrorDecodeFailure, error, NULL, CFSTR("Unable to decode public key: %@"), publicKey));
193
194 result = true;
195 exit:
196 return result;
197
198 }
199
200
201 static CFDataRef SOSCopyECWrapped(CFDataRef publicKey, CFDataRef secret, CFErrorRef *error) {
202 CFDataRef result = NULL;
203
204 ccec_pub_ctx_decl_cp(SOSGetBackupKeyCurveParameters(), pub_key);
205
206 int cc_result = ccec_compact_import_pub(SOSGetBackupKeyCurveParameters(), CFDataGetLength(publicKey), CFDataGetBytePtr(publicKey), pub_key);
207
208 require_action_quiet(cc_result == 0, exit, SOSErrorCreate(kSOSErrorDecodeFailure, error, NULL, CFSTR("Unable to decode public key: %@"), publicKey));
209
210 result = SOSCopyECWrappedData(pub_key, secret, error);
211
212 exit:
213 return result;
214 }
215
216
217 static CFDictionaryRef SOSBackupSliceKeyBagCopyWrappedKeys(SOSBackupSliceKeyBagRef vb, CFDataRef secret, CFErrorRef *error) {
218 CFDictionaryRef result = NULL;
219 CFMutableDictionaryRef wrappedKeys = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
220
221 __block bool success = true;
222 CFSetForEach(vb->peers, ^(const void *value) {
223 SOSPeerInfoRef pi = (SOSPeerInfoRef) value;
224 if (isSOSPeerInfo(pi)) {
225 CFStringRef id = SOSPeerInfoGetPeerID(pi);
226 CFDataRef backupKey = SOSPeerInfoCopyBackupKey(pi);
227
228 if (backupKey) {
229 CFDataRef wrappedKey = SOSCopyECWrapped(backupKey, secret, error);
230 if (wrappedKey) {
231 CFDictionaryAddValue(wrappedKeys, id, wrappedKey);
232 } else {
233 success = false;
234 }
235 CFReleaseNull(wrappedKey);
236 CFReleaseNull(backupKey);
237 }
238
239 }
240 });
241
242 if (success)
243 CFTransferRetained(result, wrappedKeys);
244
245 CFReleaseNull(wrappedKeys);
246 return result;
247 }
248
249 static bool SOSBackupSliceKeyBagCreateBackupBag(SOSBackupSliceKeyBagRef vb, CFErrorRef* error) {
250 CFReleaseNull(vb->aks_bag);
251
252 // Choose a random key.
253 PerformWithBufferAndClear(kAKSBagSecretLength, ^(size_t size, uint8_t *buffer) {
254 CFDataRef secret = NULL;
255
256 require_quiet(SecError(SecRandomCopyBytes(kSecRandomDefault, size, buffer), error, CFSTR("SecRandom falied!")), fail);
257
258 secret = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, buffer, size, kCFAllocatorNull);
259
260 CFAssignRetained(vb->wrapped_keys, SOSBackupSliceKeyBagCopyWrappedKeys(vb, secret, error));
261 CFAssignRetained(vb->aks_bag, SecAKSCopyBackupBagWithSecret(size, buffer, error));
262
263 fail:
264 CFReleaseSafe(secret);
265 });
266
267 return vb->aks_bag != NULL;
268 }
269
270
271 CFDataRef SOSBSKBCopyEncoded(SOSBackupSliceKeyBagRef BackupSliceKeyBag, CFErrorRef* error) {
272 CFDataRef result = NULL;
273 CFMutableDataRef encoded = NULL;
274
275 size_t encodedSize = der_sizeof_BackupSliceKeyBag(BackupSliceKeyBag, error);
276 require_quiet(encodedSize, fail);
277
278 encoded = CFDataCreateMutableWithScratch(kCFAllocatorDefault, encodedSize);
279 require_quiet(SecAllocationError(encoded, error, CFSTR("Faild to create scratch")), fail);
280
281 uint8_t *encode_to = CFDataGetMutableBytePtr(encoded);
282 uint8_t *encode_to_end = encode_to + CFDataGetLength(encoded);
283 require_quiet(encode_to == der_encode_BackupSliceKeyBag(BackupSliceKeyBag, error, encode_to, encode_to_end), fail);
284
285 CFTransferRetained(result, encoded);
286
287 fail:
288 CFReleaseSafe(encoded);
289 return result;
290 }
291
292 static CFSetRef SOSBackupSliceKeyBagCreatePeerSet(CFAllocatorRef allocator, CFSetRef peers) {
293 CFMutableSetRef result = CFSetCreateMutableForSOSPeerInfosByID(allocator);
294
295 CFSetForEach(peers, ^(const void *value) {
296 CFSetAddValue(result, value);
297 });
298
299 return result;
300 }
301
302 SOSBackupSliceKeyBagRef SOSBackupSliceKeyBagCreate(CFAllocatorRef allocator, CFSetRef peers, CFErrorRef* error) {
303 SOSBackupSliceKeyBagRef result = NULL;
304 SOSBackupSliceKeyBagRef vb = CFTypeAllocate(SOSBackupSliceKeyBag, struct __OpaqueSOSBackupSliceKeyBag, allocator);
305 require_quiet(SecAllocationError(vb, error, CFSTR("View bag allocation failed")), fail);
306
307 require_quiet(SecRequirementError(CFSetGetCount(peers) > 0, error, CFSTR("Need peers")), fail);
308
309 vb->peers = SOSBackupSliceKeyBagCreatePeerSet(allocator, peers);
310 vb->wrapped_keys = CFDictionaryCreateMutableForCFTypes(allocator);
311
312 require_quiet(SOSBackupSliceKeyBagCreateBackupBag(vb, error), fail);
313
314 CFTransferRetained(result, vb);
315
316 fail:
317 CFReleaseNull(vb);
318 return result;
319 }
320
321 SOSBackupSliceKeyBagRef SOSBackupSliceKeyBagCreateDirect(CFAllocatorRef allocator, CFDataRef aks_bag, CFErrorRef *error)
322 {
323 SOSBackupSliceKeyBagRef result = NULL;
324 SOSBackupSliceKeyBagRef vb = CFTypeAllocate(SOSBackupSliceKeyBag, struct __OpaqueSOSBackupSliceKeyBag, allocator);
325 require_quiet(SecAllocationError(vb, error, CFSTR("View bag allocation failed")), fail);
326
327 require_quiet(SecRequirementError(aks_bag, error, CFSTR("Need aks bag")), fail);
328
329 vb->aks_bag = CFRetainSafe(aks_bag);
330 vb->peers = CFSetCreateMutableForSOSPeerInfosByID(allocator);
331 vb->wrapped_keys = CFDictionaryCreateMutableForCFTypes(allocator);
332
333 CFTransferRetained(result, vb);
334
335 fail:
336 CFReleaseNull(vb);
337 return result;
338 }
339
340 //
341 // MARK: Use
342 //
343
344 bool SOSBSKBIsDirect(SOSBackupSliceKeyBagRef backupSliceKeyBag)
345 {
346 return 0 == CFSetGetCount(backupSliceKeyBag->peers);
347 }
348
349 CFDataRef SOSBSKBCopyAKSBag(SOSBackupSliceKeyBagRef backupSliceKeyBag, CFErrorRef* error)
350 {
351 return CFRetainSafe(backupSliceKeyBag->aks_bag);
352 }
353
354 CFSetRef SOSBSKBGetPeers(SOSBackupSliceKeyBagRef backupSliceKeyBag){
355 return backupSliceKeyBag->peers;
356 }
357
358 bskb_keybag_handle_t SOSBSKBLoadLocked(SOSBackupSliceKeyBagRef backupSliceKeyBag,
359 CFErrorRef *error)
360 {
361 #if !TARGET_HAS_KEYSTORE
362 return bad_keybag_handle;
363 #else
364 keybag_handle_t result = bad_keybag_handle;
365 keybag_handle_t bag_handle = bad_keybag_handle;
366
367 require_quiet(SecRequirementError(backupSliceKeyBag->aks_bag, error,
368 CFSTR("No aks bag to load")), exit);
369 require_quiet(SecRequirementError(CFDataGetLength(backupSliceKeyBag->aks_bag) < INT_MAX, error,
370 CFSTR("No aks bag to load")), exit);
371
372 kern_return_t aks_result;
373 aks_result = aks_load_bag(CFDataGetBytePtr(backupSliceKeyBag->aks_bag),
374 (int) CFDataGetLength(backupSliceKeyBag->aks_bag),
375 &bag_handle);
376 require_quiet(SecKernError(aks_result, error,
377 CFSTR("aks_load_bag failed: %d"), aks_result), exit);
378
379 result = bag_handle;
380 bag_handle = bad_keybag_handle;
381
382 exit:
383 if (bag_handle != bad_keybag_handle) {
384 (void) aks_unload_bag(bag_handle);
385 }
386
387 return result;
388 #endif
389
390 }
391
392 static keybag_handle_t SOSBSKBLoadAndUnlockBagWithSecret(SOSBackupSliceKeyBagRef backupSliceKeyBag,
393 size_t secretSize, const uint8_t *secret,
394 CFErrorRef *error)
395 {
396 #if !TARGET_HAS_KEYSTORE
397 return bad_keybag_handle;
398 #else
399 keybag_handle_t result = bad_keybag_handle;
400 keybag_handle_t bag_handle = bad_keybag_handle;
401
402 require_quiet(SecRequirementError(backupSliceKeyBag->aks_bag, error,
403 CFSTR("No aks bag to load")), exit);
404 require_quiet(SecRequirementError(CFDataGetLength(backupSliceKeyBag->aks_bag) < INT_MAX, error,
405 CFSTR("No aks bag to load")), exit);
406 require_quiet(SecRequirementError(secretSize <= INT_MAX, error,
407 CFSTR("secret too big")), exit);
408
409 kern_return_t aks_result;
410 aks_result = aks_load_bag(CFDataGetBytePtr(backupSliceKeyBag->aks_bag),
411 (int) CFDataGetLength(backupSliceKeyBag->aks_bag),
412 &bag_handle);
413 require_quiet(SecKernError(aks_result, error,
414 CFSTR("aks_load_bag failed: %d"), aks_result), exit);
415
416 aks_result = aks_unlock_bag(bag_handle, secret, (int) secretSize);
417 require_quiet(SecKernError(aks_result, error,
418 CFSTR("failed to unlock bag: %d"), aks_result), exit);
419
420 result = bag_handle;
421 bag_handle = bad_keybag_handle;
422
423 exit:
424 if (bag_handle != bad_keybag_handle) {
425 (void) aks_unload_bag(bag_handle);
426 }
427
428 return result;
429 #endif
430 }
431
432 keybag_handle_t SOSBSKBLoadAndUnlockWithPeerIDAndSecret(SOSBackupSliceKeyBagRef backupSliceKeyBag,
433 CFStringRef peerID, CFDataRef peerSecret,
434 CFErrorRef *error)
435 {
436 __block keybag_handle_t result = bad_keybag_handle;
437
438 CFDataRef lookedUpData = CFDictionaryGetValue(backupSliceKeyBag->wrapped_keys, peerID);
439 require_quiet(SecRequirementError(lookedUpData != NULL, error, CFSTR("%@ has no wrapped key in %@"), peerID, backupSliceKeyBag), exit);
440
441 require_quiet(SOSPerformWithDeviceBackupFullKey(SOSGetBackupKeyCurveParameters(), peerSecret, error, ^(ccec_full_ctx_t fullKey) {
442 SOSPerformWithUnwrappedData(fullKey, lookedUpData, error, ^(size_t size, uint8_t *buffer) {
443 result = SOSBSKBLoadAndUnlockBagWithSecret(backupSliceKeyBag, size, buffer, error);
444 });
445 }), exit);
446
447 exit:
448 return result;
449 }
450
451
452 keybag_handle_t SOSBSKBLoadAndUnlockWithPeerSecret(SOSBackupSliceKeyBagRef backupSliceKeyBag,
453 SOSPeerInfoRef peer, CFDataRef peerSecret,
454 CFErrorRef *error)
455 {
456 return SOSBSKBLoadAndUnlockWithPeerIDAndSecret(backupSliceKeyBag, SOSPeerInfoGetPeerID(peer), peerSecret, error);
457 }
458
459 keybag_handle_t SOSBSKBLoadAndUnlockWithDirectSecret(SOSBackupSliceKeyBagRef backupSliceKeyBag,
460 CFDataRef secret,
461 CFErrorRef *error)
462 {
463 keybag_handle_t result = bad_keybag_handle;
464 require_quiet(SecRequirementError(SOSBSKBIsDirect(backupSliceKeyBag), error, CFSTR("Not direct bag")), exit);
465
466 result = SOSBSKBLoadAndUnlockBagWithSecret(backupSliceKeyBag,
467 CFDataGetLength(secret),
468 CFDataGetBytePtr(secret),
469 error);
470
471 exit:
472 return result;
473 }