2 * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 #include <AssertMacros.h>
27 #include <Security/SecureObjectSync/SOSFullPeerInfo.h>
28 #include <Security/SecureObjectSync/SOSPeerInfoV2.h>
29 #include <Security/SecureObjectSync/SOSPeerInfoDER.h>
30 #include <Security/SecureObjectSync/SOSPeerInfoPriv.h>
32 #include <Security/SecureObjectSync/SOSCircle.h>
34 #include <Security/SecureObjectSync/SOSInternal.h>
35 #include <Security/SecureObjectSync/SOSPeerInfoDER.h>
37 #include <Security/SecKeyPriv.h>
38 #include <Security/SecItemPriv.h>
39 #include <Security/SecOTR.h>
40 #include <CoreFoundation/CFArray.h>
41 #include <dispatch/dispatch.h>
42 #include <Security/SecFramework.h>
47 #include <utilities/SecCFWrappers.h>
48 #include <utilities/SecCFRelease.h>
50 #include <utilities/der_plist.h>
51 #include <utilities/der_plist_internal.h>
52 #include <corecrypto/ccder.h>
54 #include <CommonCrypto/CommonDigest.h>
55 #include <CommonCrypto/CommonDigestSPI.h>
57 #include <CoreFoundation/CoreFoundation.h>
59 #include "utilities/iOSforOSX.h"
61 #include <AssertMacros.h>
63 #include <utilities/SecCFError.h>
72 extern OSStatus SecKeyCopyPublicBytes(SecKeyRef key, CFDataRef* publicBytes);
73 extern SecKeyRef SecKeyCreatePublicFromPrivate(SecKeyRef privateKey);
78 struct __OpaqueSOSFullPeerInfo {
81 SOSPeerInfoRef peer_info;
83 CFDataRef octagon_peer_signing_key_ref;
84 CFDataRef octagon_peer_encryption_key_ref;
87 CFGiblisWithHashFor(SOSFullPeerInfo);
91 CFStringRef kSOSFullPeerInfoDescriptionKey = CFSTR("SOSFullPeerInfoDescription");
92 CFStringRef kSOSFullPeerInfoSignatureKey = CFSTR("SOSFullPeerInfoSignature");
93 CFStringRef kSOSFullPeerInfoNameKey = CFSTR("SOSFullPeerInfoName");
96 static bool SOSFullPeerInfoUpdate(SOSFullPeerInfoRef fullPeerInfo, CFErrorRef *error, SOSPeerInfoRef (^create_modification)(SOSPeerInfoRef peer, SecKeyRef key, CFErrorRef *error)) {
99 SOSPeerInfoRef newPeer = NULL;
100 SecKeyRef device_key = SOSFullPeerInfoCopyDeviceKey(fullPeerInfo, error);
101 require_quiet(device_key, fail);
103 newPeer = create_modification(fullPeerInfo->peer_info, device_key, error);
104 require_quiet(newPeer, fail);
106 CFTransferRetained(fullPeerInfo->peer_info, newPeer);
110 CFReleaseNull(device_key);
111 CFReleaseNull(newPeer);
115 bool SOSFullPeerInfoUpdateToThisPeer(SOSFullPeerInfoRef peer, SOSPeerInfoRef pi, CFErrorRef *error) {
116 return SOSFullPeerInfoUpdate(peer, error, ^SOSPeerInfoRef(SOSPeerInfoRef peer, SecKeyRef key, CFErrorRef *error) {
117 return SOSPeerInfoSign(key, pi, error) ? CFRetainSafe(pi): NULL;
121 SOSFullPeerInfoRef SOSFullPeerInfoCreate(CFAllocatorRef allocator, CFDictionaryRef gestalt,
123 SecKeyRef signingKey,
124 SecKeyRef octagonPeerSigningKey,
125 SecKeyRef octagonPeerEncryptionKey,
127 return SOSFullPeerInfoCreateWithViews(allocator, gestalt, backupKey, NULL, signingKey,
128 octagonPeerSigningKey, octagonPeerEncryptionKey, error);
131 SOSFullPeerInfoRef SOSFullPeerInfoCreateWithViews(CFAllocatorRef allocator,
132 CFDictionaryRef gestalt, CFDataRef backupKey, CFSetRef initialViews,
133 SecKeyRef signingKey,
134 SecKeyRef octagonPeerSigningKey,
135 SecKeyRef octagonPeerEncryptionKey,
138 SOSFullPeerInfoRef result = NULL;
139 SOSFullPeerInfoRef fpi = CFTypeAllocate(SOSFullPeerInfo, struct __OpaqueSOSFullPeerInfo, allocator);
141 CFStringRef IDSID = CFSTR("");
142 CFStringRef transportType = SOSTransportMessageTypeKVS;
143 CFBooleanRef preferIDS = kCFBooleanFalse;
144 CFBooleanRef preferIDSFragmentation = kCFBooleanTrue;
145 CFBooleanRef preferACKModel = kCFBooleanTrue;
147 fpi->peer_info = SOSPeerInfoCreateWithTransportAndViews(allocator, gestalt, backupKey,
148 IDSID, transportType, preferIDS,
149 preferIDSFragmentation, preferACKModel, initialViews,
150 signingKey, octagonPeerSigningKey, octagonPeerEncryptionKey, error);
151 require_quiet(fpi->peer_info, exit);
153 OSStatus status = SecKeyCopyPersistentRef(signingKey, &fpi->key_ref);
154 require_quiet(SecError(status, error, CFSTR("Inflating persistent ref")), exit);
156 status = SecKeyCopyPersistentRef(octagonPeerSigningKey, &fpi->octagon_peer_signing_key_ref);
157 require_quiet(SecError(status, error, CFSTR("Inflating octagon peer signing persistent ref")), exit);
158 status = SecKeyCopyPersistentRef(octagonPeerSigningKey, &fpi->octagon_peer_encryption_key_ref);
159 require_quiet(SecError(status, error, CFSTR("Inflating octagon peer encryption persistent ref")), exit);
161 CFTransferRetained(result, fpi);
168 SOSFullPeerInfoRef SOSFullPeerInfoCopyFullPeerInfo(SOSFullPeerInfoRef toCopy) {
169 SOSFullPeerInfoRef retval = NULL;
170 SOSFullPeerInfoRef fpi = CFTypeAllocate(SOSFullPeerInfo, struct __OpaqueSOSFullPeerInfo, kCFAllocatorDefault);
171 SOSPeerInfoRef piToCopy = SOSFullPeerInfoGetPeerInfo(toCopy);
173 require_quiet(piToCopy, errOut);
174 require_quiet(fpi, errOut);
175 fpi->peer_info = SOSPeerInfoCreateCopy(kCFAllocatorDefault, piToCopy, NULL);
176 require_quiet(fpi->peer_info, errOut);
177 fpi->key_ref = CFRetainSafe(toCopy->key_ref);
178 CFTransferRetained(retval, fpi);
185 bool SOSFullPeerInfoUpdateTransportType(SOSFullPeerInfoRef peer, CFStringRef transportType, CFErrorRef* error)
187 return SOSFullPeerInfoUpdate(peer, error, ^SOSPeerInfoRef(SOSPeerInfoRef peer, SecKeyRef key, CFErrorRef *error) {
188 return SOSPeerInfoSetTransportType(kCFAllocatorDefault, peer, transportType, key, error);
192 bool SOSFullPeerInfoUpdateDeviceID(SOSFullPeerInfoRef peer, CFStringRef deviceID, CFErrorRef* error){
193 return SOSFullPeerInfoUpdate(peer, error, ^SOSPeerInfoRef(SOSPeerInfoRef peer, SecKeyRef key, CFErrorRef *error) {
194 return SOSPeerInfoSetDeviceID(kCFAllocatorDefault, peer, deviceID, key, error);
198 bool SOSFullPeerInfoUpdateTransportPreference(SOSFullPeerInfoRef peer, CFBooleanRef preference, CFErrorRef* error){
199 return SOSFullPeerInfoUpdate(peer, error, ^SOSPeerInfoRef(SOSPeerInfoRef peer, SecKeyRef key, CFErrorRef *error) {
200 return SOSPeerInfoSetIDSPreference(kCFAllocatorDefault, peer, preference, key, error);
204 bool SOSFullPeerInfoUpdateTransportFragmentationPreference(SOSFullPeerInfoRef peer, CFBooleanRef preference, CFErrorRef* error){
205 return SOSFullPeerInfoUpdate(peer, error, ^SOSPeerInfoRef(SOSPeerInfoRef peer, SecKeyRef key, CFErrorRef *error) {
206 return SOSPeerInfoSetIDSFragmentationPreference(kCFAllocatorDefault, peer, preference, key, error);
210 bool SOSFullPeerInfoUpdateTransportAckModelPreference(SOSFullPeerInfoRef peer, CFBooleanRef preference, CFErrorRef* error){
211 return SOSFullPeerInfoUpdate(peer, error, ^SOSPeerInfoRef(SOSPeerInfoRef peer, SecKeyRef key, CFErrorRef *error) {
212 return SOSPeerInfoSetIDSACKModelPreference(kCFAllocatorDefault, peer, preference, key, error);
216 bool SOSFullPeerInfoUpdateOctagonSigningKey(SOSFullPeerInfoRef peer, SecKeyRef octagonSigningKey, CFErrorRef* error){
217 return SOSFullPeerInfoUpdate(peer, error, ^SOSPeerInfoRef(SOSPeerInfoRef peer, SecKeyRef key, CFErrorRef *error) {
218 return SOSPeerInfoSetOctagonSigningKey(kCFAllocatorDefault, peer, octagonSigningKey, key, error);
222 bool SOSFullPeerInfoUpdateOctagonEncryptionKey(SOSFullPeerInfoRef peer, SecKeyRef octagonEncryptionKey, CFErrorRef* error){
223 return SOSFullPeerInfoUpdate(peer, error, ^SOSPeerInfoRef(SOSPeerInfoRef peer, SecKeyRef key, CFErrorRef *error) {
224 return SOSPeerInfoSetOctagonEncryptionKey(kCFAllocatorDefault, peer, octagonEncryptionKey, key, error);
230 CFDataRef SOSPeerInfoCopyData(SOSPeerInfoRef pi, CFErrorRef *error)
232 CFTypeRef vData = NULL;
233 SecKeyRef pubKey = SOSPeerInfoCopyPubKey(pi, error);
234 CFDictionaryRef query = NULL;
235 require_quiet(pubKey, exit);
238 CFDataRef public_key_hash = SecKeyCopyPublicKeyHash(pubKey);
240 query = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
241 kSecClass, kSecClassKey,
242 kSecAttrKeyClass, kSecAttrKeyClassPrivate,
243 kSecAttrSynchronizable, kSecAttrSynchronizableAny,
244 kSecAttrApplicationLabel, public_key_hash,
245 kSecReturnData, kCFBooleanTrue,
247 CFReleaseNull(public_key_hash);
249 require_quiet(SecError(SecItemCopyMatching(query, &vData),error ,
250 CFSTR("Error finding persistent ref to key from public: %@"), pubKey), exit);
253 CFReleaseNull(query);
254 CFReleaseNull(pubKey);
256 secnotice("fpi","no private key found");
257 return (CFDataRef)vData;
260 SOSFullPeerInfoRef SOSFullPeerInfoCreateCloudIdentity(CFAllocatorRef allocator, SOSPeerInfoRef peer, CFErrorRef* error) {
261 SOSFullPeerInfoRef fpi = CFTypeAllocate(SOSFullPeerInfo, struct __OpaqueSOSFullPeerInfo, allocator);
263 SecKeyRef pubKey = NULL;
265 fpi->peer_info = peer;
266 CFRetainSafe(fpi->peer_info);
267 if (fpi->peer_info == NULL) {
272 pubKey = SOSPeerInfoCopyPubKey(peer, error);
273 require_quiet(pubKey, exit);
275 fpi->key_ref = SecKeyCreatePersistentRefToMatchingPrivateKey(pubKey, error);
277 if (fpi->key_ref == NULL) {
283 CFReleaseNull(pubKey);
288 SOSFullPeerInfoRef SOSFullPeerInfoCreateFromDER(CFAllocatorRef allocator, CFErrorRef* error,
289 const uint8_t** der_p, const uint8_t *der_end) {
290 SOSFullPeerInfoRef fpi = CFTypeAllocate(SOSFullPeerInfo, struct __OpaqueSOSFullPeerInfo, allocator);
292 const uint8_t *sequence_end;
294 *der_p = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &sequence_end, *der_p, der_end);
295 CFReleaseNull(fpi->peer_info);
296 fpi->peer_info = SOSPeerInfoCreateFromDER(allocator, error, der_p, der_end);
297 require_quiet(fpi->peer_info != NULL, fail);
299 *der_p = der_decode_data(allocator, kCFPropertyListImmutable, &fpi->key_ref, error, *der_p, sequence_end);
300 require_quiet(*der_p != NULL, fail);
309 SOSFullPeerInfoRef SOSFullPeerInfoCreateFromData(CFAllocatorRef allocator, CFDataRef fullPeerData, CFErrorRef *error)
311 if(!fullPeerData) return NULL;
312 size_t size = CFDataGetLength(fullPeerData);
313 const uint8_t *der = CFDataGetBytePtr(fullPeerData);
314 SOSFullPeerInfoRef inflated = SOSFullPeerInfoCreateFromDER(allocator, error, &der, der + size);
318 static void SOSFullPeerInfoDestroy(CFTypeRef aObj) {
319 SOSFullPeerInfoRef fpi = (SOSFullPeerInfoRef) aObj;
321 CFReleaseNull(fpi->peer_info);
322 CFReleaseNull(fpi->key_ref);
323 CFReleaseNull(fpi->octagon_peer_signing_key_ref);
324 CFReleaseNull(fpi->octagon_peer_encryption_key_ref);
327 static Boolean SOSFullPeerInfoCompare(CFTypeRef lhs, CFTypeRef rhs) {
328 SOSFullPeerInfoRef lpeer = (SOSFullPeerInfoRef) lhs;
329 SOSFullPeerInfoRef rpeer = (SOSFullPeerInfoRef) rhs;
331 if (!CFEqual(lpeer->peer_info, rpeer->peer_info))
334 if (CFEqual(lpeer->key_ref, rpeer->key_ref))
337 SecKeyRef lpk = SOSFullPeerInfoCopyDeviceKey(lpeer, NULL);
338 SecKeyRef rpk = SOSFullPeerInfoCopyDeviceKey(rpeer, NULL);
340 bool match = lpk && rpk && CFEqual(lpk, rpk);
348 static CFHashCode SOSFullPeerInfoHash(CFTypeRef cf) {
349 SOSFullPeerInfoRef peer = (SOSFullPeerInfoRef) cf;
351 return CFHash(peer->peer_info);
354 static CFStringRef SOSFullPeerInfoCopyFormatDescription(CFTypeRef aObj, CFDictionaryRef formatOptions) {
355 SOSFullPeerInfoRef fpi = (SOSFullPeerInfoRef) aObj;
357 return CFStringCreateWithFormat(NULL, NULL, CFSTR("<SOSFullPeerInfo@%p: \"%@\">"), fpi, fpi->peer_info);
360 bool SOSFullPeerInfoUpdateGestalt(SOSFullPeerInfoRef peer, CFDictionaryRef gestalt, CFErrorRef* error)
362 return SOSFullPeerInfoUpdate(peer, error, ^SOSPeerInfoRef(SOSPeerInfoRef peer, SecKeyRef key, CFErrorRef *error) {
363 return SOSPeerInfoCopyWithGestaltUpdate(kCFAllocatorDefault, peer, gestalt, key, error);
367 bool SOSFullPeerInfoUpdateV2Dictionary(SOSFullPeerInfoRef peer, CFDictionaryRef newv2dict, CFErrorRef* error)
369 return SOSFullPeerInfoUpdate(peer, error, ^SOSPeerInfoRef(SOSPeerInfoRef peer, SecKeyRef key, CFErrorRef *error) {
370 return SOSPeerInfoCopyWithV2DictionaryUpdate(kCFAllocatorDefault, peer,
371 newv2dict, key, error);
375 bool SOSFullPeerInfoUpdateBackupKey(SOSFullPeerInfoRef peer, CFDataRef backupKey, CFErrorRef* error)
377 return SOSFullPeerInfoUpdate(peer, error, ^SOSPeerInfoRef(SOSPeerInfoRef peer, SecKeyRef key, CFErrorRef *error) {
378 return SOSPeerInfoCopyWithBackupKeyUpdate(kCFAllocatorDefault, peer, backupKey, key, error);
382 bool SOSFullPeerInfoAddEscrowRecord(SOSFullPeerInfoRef peer, CFStringRef dsid, CFDictionaryRef escrowRecord, CFErrorRef* error)
384 return SOSFullPeerInfoUpdate(peer, error, ^SOSPeerInfoRef(SOSPeerInfoRef peer, SecKeyRef key, CFErrorRef *error) {
385 return SOSPeerInfoCopyWithEscrowRecordUpdate(kCFAllocatorDefault, peer, dsid, escrowRecord, key, error);
389 bool SOSFullPeerInfoReplaceEscrowRecords(SOSFullPeerInfoRef peer, CFDictionaryRef escrowRecords, CFErrorRef* error)
391 return SOSFullPeerInfoUpdate(peer, error, ^SOSPeerInfoRef(SOSPeerInfoRef peer, SecKeyRef key, CFErrorRef *error) {
392 return SOSPeerInfoCopyWithReplacedEscrowRecords(kCFAllocatorDefault, peer, escrowRecords, key, error);
396 SOSViewResultCode SOSFullPeerInfoUpdateViews(SOSFullPeerInfoRef peer, SOSViewActionCode action, CFStringRef viewname, CFErrorRef* error)
398 __block SOSViewResultCode retval = kSOSCCGeneralViewError;
400 secnotice("viewChange", "%s view %@", SOSViewsXlateAction(action), viewname);
402 return SOSFullPeerInfoUpdate(peer, error, ^SOSPeerInfoRef(SOSPeerInfoRef peer, SecKeyRef key, CFErrorRef *error) {
403 return SOSPeerInfoCopyWithViewsChange(kCFAllocatorDefault, peer, action, viewname, &retval, key, error);
404 }) ? retval : kSOSCCGeneralViewError;
407 static CFMutableSetRef SOSFullPeerInfoCopyViewUpdate(SOSFullPeerInfoRef peer, CFSetRef minimumViews, CFSetRef excludedViews) {
408 CFSetRef enabledViews = SOSPeerInfoCopyEnabledViews(peer->peer_info);
409 CFMutableSetRef newViews = SOSPeerInfoCopyEnabledViews(peer->peer_info);
411 if (isSet(minimumViews)) {
412 CFSetUnion(newViews, minimumViews);
414 if (isSet(excludedViews)) {
415 CFSetSubtract(newViews, excludedViews);
418 if (CFEqualSafe(newViews, enabledViews)) {
419 CFReleaseNull(newViews);
422 CFReleaseNull(enabledViews);
426 static bool SOSFullPeerInfoNeedsViewUpdate(SOSFullPeerInfoRef peer, CFSetRef minimumViews, CFSetRef excludedViews) {
427 CFSetRef updatedViews = SOSFullPeerInfoCopyViewUpdate(peer, minimumViews, excludedViews);
428 bool needsUpdate = (updatedViews != NULL);
429 CFReleaseNull(updatedViews);
433 static bool sosFullPeerInfoRequiresUpdate(SOSFullPeerInfoRef peer, CFSetRef minimumViews, CFSetRef excludedViews) {
435 if(!SOSPeerInfoVersionIsCurrent(peer->peer_info)) return true;
436 if(!SOSPeerInfoSerialNumberIsSet(peer->peer_info)) return true;
437 if(!(SOSPeerInfoV2DictionaryHasString(peer->peer_info, sDeviceID)))return true;
438 if(!(SOSPeerInfoV2DictionaryHasString(peer->peer_info, sTransportType))) return true;
439 if(!(SOSPeerInfoV2DictionaryHasBoolean(peer->peer_info, sPreferIDS))) return true;
440 if(!(SOSPeerInfoV2DictionaryHasBoolean(peer->peer_info, sPreferIDSFragmentation))) return true;
441 if(!(SOSPeerInfoV2DictionaryHasBoolean(peer->peer_info, sPreferIDSACKModel))) return true;
442 if(SOSFullPeerInfoNeedsViewUpdate(peer, minimumViews, excludedViews)) return true;
447 // Returning false indicates we don't need to upgrade.
448 bool SOSFullPeerInfoUpdateToCurrent(SOSFullPeerInfoRef peer, CFSetRef minimumViews, CFSetRef excludedViews) {
449 bool success = false;
451 CFMutableSetRef newViews = NULL;
452 CFErrorRef copyError = NULL;
453 CFErrorRef createError = NULL;
454 SecKeyRef device_key = NULL;
456 require_quiet(sosFullPeerInfoRequiresUpdate(peer, minimumViews, excludedViews), errOut);
458 newViews = SOSFullPeerInfoCopyViewUpdate(peer, minimumViews, excludedViews);
460 device_key = SOSFullPeerInfoCopyDeviceKey(peer, ©Error);
461 require_action_quiet(device_key, errOut,
462 secnotice("upgrade", "SOSFullPeerInfoCopyDeviceKey failed: %@", copyError));
464 SOSPeerInfoRef newPeer = SOSPeerInfoCreateCurrentCopy(kCFAllocatorDefault, peer->peer_info,
465 NULL, NULL, kCFBooleanFalse, kCFBooleanTrue, kCFBooleanTrue, newViews,
466 device_key, &createError);
467 require_action_quiet(newPeer, errOut,
468 secnotice("upgrade", "Peer info v2 create copy failed: %@", createError));
470 CFTransferRetained(peer->peer_info, newPeer);
475 CFReleaseNull(newViews);
476 CFReleaseNull(copyError);
477 CFReleaseNull(createError);
478 CFReleaseNull(device_key);
482 SOSViewResultCode SOSFullPeerInfoViewStatus(SOSFullPeerInfoRef peer, CFStringRef viewname, CFErrorRef *error)
484 SOSPeerInfoRef pi = SOSFullPeerInfoGetPeerInfo(peer);
485 if(!pi) return kSOSCCGeneralViewError;
486 return SOSPeerInfoViewStatus(pi, viewname, error);
490 SOSSecurityPropertyResultCode SOSFullPeerInfoUpdateSecurityProperty(SOSFullPeerInfoRef peer, SOSViewActionCode action, CFStringRef property, CFErrorRef* error)
492 SOSSecurityPropertyResultCode retval = kSOSCCGeneralSecurityPropertyError;
493 SecKeyRef device_key = SOSFullPeerInfoCopyDeviceKey(peer, error);
494 require_quiet(device_key, fail);
496 SOSPeerInfoRef newPeer = SOSPeerInfoCopyWithSecurityPropertyChange(kCFAllocatorDefault, peer->peer_info, action, property, &retval, device_key, error);
498 require_quiet(newPeer, fail);
500 CFReleaseNull(peer->peer_info);
501 peer->peer_info = newPeer;
505 CFReleaseNull(device_key);
509 SOSSecurityPropertyResultCode SOSFullPeerInfoSecurityPropertyStatus(SOSFullPeerInfoRef peer, CFStringRef property, CFErrorRef *error)
511 SOSPeerInfoRef pi = SOSFullPeerInfoGetPeerInfo(peer);
512 secnotice("secprop", "have pi %s", (pi)? "true": "false");
513 if(!pi) return kSOSCCGeneralSecurityPropertyError;
514 return SOSPeerInfoSecurityPropertyStatus(pi, property, error);
518 SOSPeerInfoRef SOSFullPeerInfoGetPeerInfo(SOSFullPeerInfoRef fullPeer) {
519 return fullPeer?fullPeer->peer_info:NULL;
522 // MARK: Private Key Retrieval and Existence
524 SecKeyRef SOSFullPeerInfoCopyPubKey(SOSFullPeerInfoRef fpi, CFErrorRef *error) {
525 SecKeyRef retval = NULL;
526 require_quiet(fpi, errOut);
527 SOSPeerInfoRef pi = SOSFullPeerInfoGetPeerInfo(fpi);
528 require_quiet(pi, errOut);
529 retval = SOSPeerInfoCopyPubKey(pi, error);
535 SecKeyRef SOSFullPeerInfoCopyOctagonPublicSigningKey(SOSFullPeerInfoRef fpi, CFErrorRef* error)
537 SecKeyRef retval = NULL;
538 require_quiet(fpi, errOut);
539 SOSPeerInfoRef pi = SOSFullPeerInfoGetPeerInfo(fpi);
540 require_quiet(pi, errOut);
541 retval = SOSPeerInfoCopyOctagonSigningPublicKey(pi, error);
547 SecKeyRef SOSFullPeerInfoCopyOctagonPublicEncryptionKey(SOSFullPeerInfoRef fpi, CFErrorRef* error)
549 SecKeyRef retval = NULL;
550 require_quiet(fpi, errOut);
551 SOSPeerInfoRef pi = SOSFullPeerInfoGetPeerInfo(fpi);
552 require_quiet(pi, errOut);
553 retval = SOSPeerInfoCopyOctagonEncryptionPublicKey(pi, error);
560 static SecKeyRef SOSFullPeerInfoCopyMatchingPrivateKey(SOSFullPeerInfoRef fpi, CFErrorRef *error) {
561 SecKeyRef retval = NULL;
563 SecKeyRef pub = SOSFullPeerInfoCopyPubKey(fpi, error);
564 require_quiet(pub, exit);
565 retval = SecKeyCopyMatchingPrivateKey(pub, error);
571 static SecKeyRef SOSFullPeerInfoCopyMatchingOctagonSigningPrivateKey(SOSFullPeerInfoRef fpi, CFErrorRef* error)
573 SecKeyRef retval = NULL;
574 SecKeyRef pub = SOSFullPeerInfoCopyOctagonPublicSigningKey(fpi, error);
575 require_quiet(pub, exit);
576 retval = SecKeyCopyMatchingPrivateKey(pub, error);
582 static SecKeyRef SOSFullPeerInfoCopyMatchingOctagonEncryptionPrivateKey(SOSFullPeerInfoRef fpi, CFErrorRef* error)
584 SecKeyRef retval = NULL;
585 SecKeyRef pub = SOSFullPeerInfoCopyOctagonPublicEncryptionKey(fpi, error);
586 require_quiet(pub, exit);
587 retval = SecKeyCopyMatchingPrivateKey(pub, error);
595 static OSStatus SOSFullPeerInfoGetMatchingPrivateKeyStatus(SOSFullPeerInfoRef fpi, CFErrorRef *error) {
596 OSStatus retval = errSecParam;
597 SecKeyRef pub = SOSFullPeerInfoCopyPubKey(fpi, error);
598 require_quiet(pub, exit);
599 retval = SecKeyGetMatchingPrivateKeyStatus(pub, error);
606 bool SOSFullPeerInfoValidate(SOSFullPeerInfoRef peer, CFErrorRef* error) {
607 OSStatus result = SOSFullPeerInfoGetMatchingPrivateKeyStatus(peer, error);
608 if(result == errSecSuccess) return true;
612 bool SOSFullPeerInfoPrivKeyExists(SOSFullPeerInfoRef peer) {
613 OSStatus result = SOSFullPeerInfoGetMatchingPrivateKeyStatus(peer, NULL);
614 if(result == errSecItemNotFound || result == errSecParam) return false;
618 bool SOSFullPeerInfoPurgePersistentKey(SOSFullPeerInfoRef fpi, CFErrorRef* error) {
620 CFDictionaryRef privQuery = NULL;
621 CFMutableDictionaryRef query = NULL;
622 CFDictionaryRef octagonPrivQuery = NULL;
623 CFMutableDictionaryRef octagonQuery = NULL;
625 SecKeyRef pub = SOSFullPeerInfoCopyPubKey(fpi, error);
626 SecKeyRef octagonSigningPub = SOSFullPeerInfoCopyOctagonPublicSigningKey(fpi, error);
627 SecKeyRef octagonEncryptionPub = SOSFullPeerInfoCopyOctagonPublicEncryptionKey(fpi, error);
628 require_quiet(pub, fail);
629 // iCloud Identities doesn't have either signing or encryption key here. Don't fail if they're not present.
631 privQuery = CreatePrivateKeyMatchingQuery(pub, false);
632 query = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, privQuery);
633 CFDictionaryAddValue(query, kSecUseTombstones, kCFBooleanFalse);
635 result = SecError(SecItemDelete(query), error, CFSTR("Deleting while purging"));
637 // do the same thing to also purge the octagon sync signing key
638 if(octagonSigningPub) {
639 octagonPrivQuery = CreatePrivateKeyMatchingQuery(octagonSigningPub, false);
640 octagonQuery = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, octagonPrivQuery);
641 CFDictionaryAddValue(octagonQuery, kSecUseTombstones, kCFBooleanFalse);
643 result &= SecError(SecItemDelete(octagonQuery), error, CFSTR("Deleting signing key while purging"));
646 CFReleaseNull(octagonPrivQuery);
647 CFReleaseNull(octagonQuery);
649 // do the same thing to also purge the octagon encryption key
650 if(octagonEncryptionPub) {
651 octagonPrivQuery = CreatePrivateKeyMatchingQuery(octagonEncryptionPub, false);
652 octagonQuery = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, octagonPrivQuery);
653 CFDictionaryAddValue(octagonQuery, kSecUseTombstones, kCFBooleanFalse);
655 result &= SecError(SecItemDelete(octagonQuery), error, CFSTR("Deleting encryption key while purging"));
659 CFReleaseNull(privQuery);
660 CFReleaseNull(query);
662 CFReleaseNull(octagonPrivQuery);
663 CFReleaseNull(octagonQuery);
664 CFReleaseNull(octagonSigningPub);
665 CFReleaseNull(octagonEncryptionPub);
669 SecKeyRef SOSFullPeerInfoCopyDeviceKey(SOSFullPeerInfoRef fullPeer, CFErrorRef* error)
671 return SOSFullPeerInfoCopyMatchingPrivateKey(fullPeer, error);
674 SecKeyRef SOSFullPeerInfoCopyOctagonSigningKey(SOSFullPeerInfoRef fullPeer, CFErrorRef* error)
676 return SOSFullPeerInfoCopyMatchingOctagonSigningPrivateKey(fullPeer, error);
679 SecKeyRef SOSFullPeerInfoCopyOctagonEncryptionKey(SOSFullPeerInfoRef fullPeer, CFErrorRef* error)
681 return SOSFullPeerInfoCopyMatchingOctagonEncryptionPrivateKey(fullPeer, error);
684 bool SOSFullPeerInfoHaveOctagonKeys(SOSFullPeerInfoRef fullPeer)
686 SOSPeerInfoRef pi = SOSFullPeerInfoGetPeerInfo(fullPeer);
692 SOSPeerInfoHasOctagonSigningPubKey(pi) &&
693 SOSPeerInfoHasOctagonEncryptionPubKey(pi);
698 // MARK: Encode and decode
700 size_t SOSFullPeerInfoGetDEREncodedSize(SOSFullPeerInfoRef peer, CFErrorRef *error)
702 size_t peer_size = SOSPeerInfoGetDEREncodedSize(peer->peer_info, error);
706 size_t ref_size = der_sizeof_data(peer->key_ref, error);
710 return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE,
711 peer_size + ref_size);
714 uint8_t* SOSFullPeerInfoEncodeToDER(SOSFullPeerInfoRef peer, CFErrorRef* error, const uint8_t* der, uint8_t* der_end)
716 return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der,
717 SOSPeerInfoEncodeToDER(peer->peer_info, error, der,
718 der_encode_data(peer->key_ref, error, der, der_end)));
721 CFDataRef SOSFullPeerInfoCopyEncodedData(SOSFullPeerInfoRef peer, CFAllocatorRef allocator, CFErrorRef *error)
723 size_t size = SOSFullPeerInfoGetDEREncodedSize(peer, error);
726 uint8_t buffer[size];
727 uint8_t* start = SOSFullPeerInfoEncodeToDER(peer, error, buffer, buffer + sizeof(buffer));
728 CFDataRef result = CFDataCreate(kCFAllocatorDefault, start, size);
732 bool SOSFullPeerInfoPromoteToApplication(SOSFullPeerInfoRef fpi, SecKeyRef user_key, CFErrorRef *error)
734 bool success = false;
735 SOSPeerInfoRef old_pi = NULL;
737 SecKeyRef device_key = SOSFullPeerInfoCopyDeviceKey(fpi, error);
738 require_quiet(device_key, exit);
740 old_pi = fpi->peer_info;
741 fpi->peer_info = SOSPeerInfoCopyAsApplication(old_pi, user_key, device_key, error);
743 require_action_quiet(fpi->peer_info, exit, fpi->peer_info = old_pi; old_pi = NULL);
748 CFReleaseSafe(old_pi);
749 CFReleaseSafe(device_key);
753 bool SOSFullPeerInfoUpgradeSignatures(SOSFullPeerInfoRef fpi, SecKeyRef user_key, CFErrorRef *error)
755 bool success = false;
756 SOSPeerInfoRef old_pi = NULL;
758 SecKeyRef device_key = SOSFullPeerInfoCopyDeviceKey(fpi, error);
759 require_quiet(device_key, exit);
761 old_pi = fpi->peer_info;
762 fpi->peer_info = SOSPeerInfoUpgradeSignatures(NULL, user_key, device_key, old_pi, error);
764 require_action_quiet(fpi->peer_info, exit, fpi->peer_info = old_pi; old_pi = NULL);
769 CFReleaseSafe(old_pi);
770 CFReleaseSafe(device_key);
778 SOSPeerInfoRef SOSFullPeerInfoPromoteToRetiredAndCopy(SOSFullPeerInfoRef fpi, CFErrorRef *error)
780 SOSPeerInfoRef peer_to_free = NULL;
781 SOSPeerInfoRef retired_peer = NULL;
782 SecKeyRef key = SOSFullPeerInfoCopyDeviceKey(fpi, error);
783 require_quiet(key, error_out);
785 retired_peer = SOSPeerInfoCreateRetirementTicket(NULL, key, fpi->peer_info, error);
787 require_quiet(retired_peer, error_out);
789 peer_to_free = fpi->peer_info;
790 fpi->peer_info = retired_peer;
791 CFRetainSafe(fpi->peer_info);
795 CFReleaseNull(peer_to_free);
800 bool SOSFullPeerInfoPing(SOSFullPeerInfoRef peer, CFErrorRef* error) {
802 SecKeyRef device_key = SOSFullPeerInfoCopyDeviceKey(peer, error);
803 require_quiet(device_key, fail);
804 SOSPeerInfoRef newPeer = SOSPeerInfoCopyWithPing(kCFAllocatorDefault, peer->peer_info, device_key, error);
805 require_quiet(newPeer, fail);
807 CFReleaseNull(peer->peer_info);
808 peer->peer_info = newPeer;
812 CFReleaseNull(device_key);