/ keychain / SecureObjectSync / SOSBackupSliceKeyBag.m
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          // let's not judge ripping out other recovery keys
764          return true;
765      }
766  }