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>
26 #include <TargetConditionals.h>
28 #include <Security/SecureObjectSync/SOSPeerInfo.h>
29 #include <Security/SecureObjectSync/SOSPeerInfoInternal.h>
30 #include <Security/SecureObjectSync/SOSPeerInfoPriv.h>
31 #include <Security/SecureObjectSync/SOSPeerInfoV2.h>
32 #include <Security/SecureObjectSync/SOSPeerInfoSecurityProperties.h>
33 #include <Security/SecureObjectSync/SOSCircle.h>
34 #include <Security/SecureObjectSync/SOSInternal.h>
35 #include <ipc/securityd_client.h>
37 #include <CoreFoundation/CFArray.h>
38 #include <dispatch/dispatch.h>
43 #include <utilities/SecCFWrappers.h>
44 #include <utilities/SecCFRelease.h>
45 #include <utilities/SecCFError.h>
46 #include <utilities/SecXPCError.h>
48 #include <utilities/der_plist.h>
49 #include <utilities/der_plist_internal.h>
50 #include <corecrypto/ccder.h>
51 #include <utilities/der_date.h>
53 #include <corecrypto/ccdigest.h>
54 #include <corecrypto/ccsha2.h>
57 #include <CoreFoundation/CoreFoundation.h>
58 #include <CoreFoundation/CFDate.h>
62 #if TARGET_OS_IPHONE || TARGET_OS_EMBEDDED
63 #include <MobileGestalt.h>
66 #include <Security/SecBase64.h>
67 #include <Security/SecKeyPriv.h>
68 #include <Security/SecOTR.h>
69 #include <Security/SecuritydXPC.h>
71 CFGiblisWithHashFor(SOSPeerInfo);
74 const CFStringRef kPIUserDefinedDeviceNameKey = CFSTR("ComputerName");
75 const CFStringRef kPIDeviceModelNameKey = CFSTR("ModelName");
76 const CFStringRef kPIMessageProtocolVersionKey = CFSTR("MessageProtocolVersion");
77 const CFStringRef kPIOSVersionKey = CFSTR("OSVersion");
79 // Description Dictionary Entries
80 static CFStringRef sPublicKeyKey = CFSTR("PublicSigningKey");
81 static CFStringRef sOctagonPeerSigningPublicKeyKey = CFSTR("OctagonPublicSigningKey");
82 static CFStringRef sOctagonPeerEncryptionPublicKeyKey = CFSTR("OctagonPublicEncryptionKey");
83 const CFStringRef sGestaltKey = CFSTR("DeviceGestalt");
84 const CFStringRef sVersionKey = CFSTR("ConflictVersion");
85 static CFStringRef sCloudIdentityKey = CFSTR("CloudIdentity");
86 static CFStringRef sApplicationDate = CFSTR("ApplicationDate");
87 static CFStringRef sApplicationUsig = CFSTR("ApplicationUsig");
88 static CFStringRef sRetirementDate = CFSTR("RetirementDate");
91 CFStringRef kSOSPeerInfoDescriptionKey = CFSTR("SOSPeerInfoDescription");
92 CFStringRef kSOSPeerInfoSignatureKey = CFSTR("SOSPeerInfoSignature");
93 CFStringRef kSOSPeerInfoNameKey = CFSTR("SOSPeerInfoName");
95 //Peer Info V2 Dictionary IDS keys
96 CFStringRef sPreferIDS = CFSTR("PreferIDS");
97 CFStringRef sPreferIDSFragmentation = CFSTR("PreferIDFragmentation");
98 CFStringRef sPreferIDSACKModel = CFSTR("PreferIDSAckModel");
99 CFStringRef sTransportType = CFSTR("TransportType");
100 CFStringRef sDeviceID = CFSTR("DeviceID");
102 const CFStringRef peerIDLengthKey = CFSTR("idLength");
104 SOSPeerInfoRef SOSPeerInfoAllocate(CFAllocatorRef allocator) {
105 return CFTypeAllocate(SOSPeerInfo, struct __OpaqueSOSPeerInfo, allocator);
108 static SecKeyRef _SOSPeerInfoCopyPubKey(SOSPeerInfoRef peer, CFStringRef keyDictionaryKey, CFErrorRef* error)
110 SecKeyRef result = NULL;
112 CFDataRef pubKeyBytes = asData(CFDictionaryGetValue(peer->description, keyDictionaryKey), error);
113 require_quiet(pubKeyBytes, fail);
115 CFAllocatorRef allocator = CFGetAllocator(peer);
116 result = SecKeyCreateFromPublicData(allocator, kSecECDSAAlgorithmID, pubKeyBytes);
118 require_quiet(SecAllocationError(result, error, CFSTR("Failed to create public key from data %@"), pubKeyBytes), fail);
124 SecKeyRef SOSPeerInfoCopyPubKey(SOSPeerInfoRef peer, CFErrorRef* error) {
125 return _SOSPeerInfoCopyPubKey(peer, sPublicKeyKey, error);
128 SecKeyRef SOSPeerInfoCopyOctagonSigningPublicKey(SOSPeerInfoRef peer, CFErrorRef* error)
130 return _SOSPeerInfoCopyPubKey(peer, sOctagonPeerSigningPublicKeyKey, error);
133 SecKeyRef SOSPeerInfoCopyOctagonEncryptionPublicKey(SOSPeerInfoRef peer, CFErrorRef* error)
135 return _SOSPeerInfoCopyPubKey(peer, sOctagonPeerEncryptionPublicKeyKey, error);
139 CFDataRef SOSPeerInfoGetAutoAcceptInfo(SOSPeerInfoRef peer) {
140 CFDataRef pubKeyBytes = NULL;
142 pubKeyBytes = CFDictionaryGetValue(peer->description, sPublicKeyKey);
143 if (!pubKeyBytes || CFGetTypeID(pubKeyBytes) != CFDataGetTypeID()) {
150 static bool SOSDescriptionHash(SOSPeerInfoRef peer, const struct ccdigest_info *di, void *hashresult, CFErrorRef *error) {
151 ccdigest_di_decl(di, ctx);
152 ccdigest_init(di, ctx);
154 if(!SOSPeerInfoUpdateDigestWithDescription(peer, di, ctx_p, error)) return false;
155 ccdigest_final(di, ctx, hashresult);
161 static CFDataRef sosCopySignedHash(SecKeyRef privkey, const struct ccdigest_info *di, uint8_t *hbuf) {
163 size_t siglen = SIGLEN;
165 if((stat = SecKeyRawSign(privkey, kSecPaddingNone, hbuf, di->output_size, sig, &siglen)) != 0) {
168 return CFDataCreate(NULL, sig, (CFIndex)siglen);
171 static bool sosVerifyHash(SecKeyRef pubkey, const struct ccdigest_info *di, uint8_t *hbuf, CFDataRef signature) {
172 return SecKeyRawVerify(pubkey, kSecPaddingNone, hbuf, di->output_size,
173 CFDataGetBytePtr(signature), CFDataGetLength(signature)) == errSecSuccess;
176 bool SOSPeerInfoSign(SecKeyRef privKey, SOSPeerInfoRef peer, CFErrorRef *error) {
178 const struct ccdigest_info *di = ccsha256_di();
179 uint8_t hbuf[di->output_size];
180 CFDataRef newSignature = NULL;
182 require_action_quiet(SOSDescriptionHash(peer, di, hbuf, error), fail,
183 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Failed to hash description for peer"), NULL, error));
185 newSignature = sosCopySignedHash(privKey, di, hbuf);
186 require_action_quiet(newSignature, fail, SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Failed to sign peerinfo for peer"), NULL, error));
188 CFReleaseNull(peer->signature);
189 peer->signature = newSignature;
194 CFReleaseNull(newSignature);
198 // Return true (1) if the signature verifies.
199 bool SOSPeerInfoVerify(SOSPeerInfoRef peer, CFErrorRef *error) {
201 const struct ccdigest_info *di = ccsha256_di();
202 uint8_t hbuf[di->output_size];
204 SecKeyRef pubKey = SOSPeerInfoCopyPubKey(peer, error);
205 require_quiet(pubKey, error_out);
207 require_quiet(SOSDescriptionHash(peer, di, hbuf, error), error_out);
209 require_action_quiet(sosVerifyHash(pubKey, di, hbuf, peer->signature), error_out,
210 SOSErrorCreate(kSOSErrorBadSignature, error, NULL,
211 CFSTR("Signature didn't verify for %@"), peer));
215 CFReleaseNull(pubKey);
219 void SOSPeerInfoSetVersionNumber(SOSPeerInfoRef pi, int version) {
220 pi->version = version;
221 CFNumberRef versionNumber = CFNumberCreateWithCFIndex(NULL, pi->version);
222 CFDictionarySetValue(pi->description, sVersionKey, versionNumber);
223 CFReleaseNull(versionNumber);
226 static SOSPeerInfoRef SOSPeerInfoCreate_Internal(CFAllocatorRef allocator,
227 CFDictionaryRef gestalt, CFDataRef backup_key,
228 CFStringRef IDSID, CFStringRef transportType, CFBooleanRef preferIDS,
229 CFBooleanRef preferFragmentation, CFBooleanRef preferAckModel,
230 CFSetRef enabledViews,
231 SecKeyRef signingKey,
232 SecKeyRef octagonPeerSigningKey,
233 SecKeyRef octagonPeerEncryptionKey,
235 void (^ description_modifier)(CFMutableDictionaryRef description)) {
236 SOSPeerInfoRef pi = CFTypeAllocate(SOSPeerInfo, struct __OpaqueSOSPeerInfo, allocator);
237 pi->gestalt = gestalt;
238 CFRetain(pi->gestalt);
240 pi->version = SOSPeerInfoGetPeerProtocolVersion(pi);
241 CFDataRef publicBytes = NULL;
242 CFDataRef octagonPeerSigningPublicBytes = NULL;
243 CFDataRef octagonPeerEncryptionPublicBytes = NULL;
244 CFNumberRef versionNumber = NULL;
246 SecKeyRef publicKey = SecKeyCreatePublicFromPrivate(signingKey);
247 if (publicKey == NULL) {
248 SOSCreateError(kSOSErrorBadKey, CFSTR("Unable to get public"), NULL, error);
253 OSStatus result = SecKeyCopyPublicBytes(publicKey, &publicBytes);
255 if (result != errSecSuccess) {
256 SOSCreateError(kSOSErrorBadKey, CFSTR("Failed to export public bytes"), NULL, error);
261 if (octagonPeerSigningKey) {
262 SecKeyRef octagonPeerSigningPublicKey = SecKeyCreatePublicFromPrivate(octagonPeerSigningKey);
263 if (octagonPeerSigningPublicKey == NULL) {
264 SOSCreateError(kSOSErrorBadKey, CFSTR("Unable to get public key"), NULL, error);
269 result = SecKeyCopyPublicBytes(octagonPeerSigningPublicKey, &octagonPeerSigningPublicBytes);
270 CFReleaseNull(octagonPeerSigningPublicKey);
271 if (result != errSecSuccess) {
272 SOSCreateError(kSOSErrorBadKey, CFSTR("Failed to export public bytes"), NULL, error);
278 if (octagonPeerEncryptionKey) {
279 SecKeyRef octagonPeerEncryptionPublicKey = SecKeyCreatePublicFromPrivate(octagonPeerEncryptionKey);
280 if (octagonPeerEncryptionPublicKey == NULL) {
281 SOSCreateError(kSOSErrorBadKey, CFSTR("Unable to get public key"), NULL, error);
286 result = SecKeyCopyPublicBytes(octagonPeerEncryptionPublicKey, &octagonPeerEncryptionPublicBytes);
287 CFReleaseNull(octagonPeerEncryptionPublicKey);
288 if (result != errSecSuccess) {
289 SOSCreateError(kSOSErrorBadKey, CFSTR("Failed to export public bytes"), NULL, error);
295 pi->signature = CFDataCreateMutable(allocator, 0);
297 versionNumber = CFNumberCreateWithCFIndex(NULL, pi->version);
299 pi->description = CFDictionaryCreateMutableForCFTypesWith(allocator,
300 sVersionKey, versionNumber,
301 sPublicKeyKey, publicBytes,
302 sGestaltKey, pi->gestalt,
304 if (octagonPeerSigningPublicBytes) {
305 CFDictionarySetValue(pi->description, sOctagonPeerSigningPublicKeyKey, octagonPeerSigningPublicBytes);
307 if (octagonPeerEncryptionPublicBytes) {
308 CFDictionarySetValue(pi->description, sOctagonPeerEncryptionPublicKeyKey, octagonPeerEncryptionPublicBytes);
312 description_modifier(pi->description);
315 pi->peerID = SOSCopyIDOfKey(publicKey, error);
317 CFReleaseNull(publicKey);
319 require_quiet(pi->peerID, exit);
321 // ================ V2 Additions Start
323 if(!SOSPeerInfoUpdateToV2(pi, error)) {
328 // V2DictionarySetValue handles NULL as remove
329 if (backup_key != NULL) SOSPeerInfoV2DictionarySetValue(pi, sBackupKeyKey, backup_key);
330 SOSPeerInfoV2DictionarySetValue(pi, sDeviceID, IDSID);
331 SOSPeerInfoV2DictionarySetValue(pi, sTransportType, transportType);
332 SOSPeerInfoV2DictionarySetValue(pi, sPreferIDS, preferIDS);
333 SOSPeerInfoV2DictionarySetValue(pi, sPreferIDSFragmentation, preferFragmentation);
334 SOSPeerInfoV2DictionarySetValue(pi, sPreferIDSACKModel, preferAckModel);
335 SOSPeerInfoV2DictionarySetValue(pi, sViewsKey, enabledViews);
337 // ================ V2 Additions End
339 if (!SOSPeerInfoSign(signingKey, pi, error)) {
345 CFReleaseNull(versionNumber);
346 CFReleaseNull(publicBytes);
347 CFReleaseNull(octagonPeerSigningPublicBytes);
348 CFReleaseNull(octagonPeerEncryptionPublicBytes);
352 SOSPeerInfoRef SOSPeerInfoCreate(CFAllocatorRef allocator, CFDictionaryRef gestalt, CFDataRef backup_key, SecKeyRef signingKey, SecKeyRef octagonPeerSigningKey, SecKeyRef octagonPeerEncryptionKey, CFErrorRef* error) {
353 return SOSPeerInfoCreate_Internal(allocator, gestalt, backup_key, NULL, NULL, NULL, NULL, NULL, NULL, signingKey, octagonPeerSigningKey, octagonPeerEncryptionKey, error, ^(CFMutableDictionaryRef description) {});
356 SOSPeerInfoRef SOSPeerInfoCreateWithTransportAndViews(CFAllocatorRef allocator, CFDictionaryRef gestalt, CFDataRef backup_key,
357 CFStringRef IDSID, CFStringRef transportType, CFBooleanRef preferIDS,
358 CFBooleanRef preferFragmentation, CFBooleanRef preferAckModel, CFSetRef enabledViews,
359 SecKeyRef signingKey,
360 SecKeyRef octagonPeerSigningKey,
361 SecKeyRef octagonPeerEncryptionKey,
364 return SOSPeerInfoCreate_Internal(allocator, gestalt, backup_key, IDSID, transportType, preferIDS, preferFragmentation, preferAckModel, enabledViews, signingKey, octagonPeerSigningKey, octagonPeerEncryptionKey, error, ^(CFMutableDictionaryRef description) {});
368 SOSPeerInfoRef SOSPeerInfoCreateCloudIdentity(CFAllocatorRef allocator, CFDictionaryRef gestalt, SecKeyRef signingKey, CFErrorRef* error) {
369 return SOSPeerInfoCreate_Internal(allocator, gestalt, NULL, NULL, NULL, NULL, NULL, NULL, NULL, signingKey, NULL, NULL, error, ^(CFMutableDictionaryRef description) {
370 CFDictionarySetValue(description, sCloudIdentityKey, kCFBooleanTrue);
376 SOSPeerInfoRef SOSPeerInfoCreateCopy(CFAllocatorRef allocator, SOSPeerInfoRef toCopy, CFErrorRef* error) {
377 if(!toCopy) return NULL;
378 SOSPeerInfoRef pi = CFTypeAllocate(SOSPeerInfo, struct __OpaqueSOSPeerInfo, allocator);
380 pi->description = CFDictionaryCreateMutableCopy(allocator, 0, toCopy->description);
381 pi->signature = CFDataCreateCopy(allocator, toCopy->signature);
383 pi->gestalt = CFDictionaryCreateCopy(allocator, toCopy->gestalt);
384 pi->peerID = CFStringCreateCopy(allocator, toCopy->peerID);
386 pi->version = toCopy->version;
387 if(!SOSPeerInfoVersionHasV2Data(pi)) SOSPeerInfoExpandV2Data(pi, error);
393 bool SOSPeerInfoVersionIsCurrent(SOSPeerInfoRef pi) {
394 return pi->version >= PEERINFO_CURRENT_VERSION;
397 bool SOSPeerInfoVersionHasV2Data(SOSPeerInfoRef pi) {
398 return pi->version >= kSOSPeerV2BaseVersion;
401 SOSPeerInfoRef SOSPeerInfoCreateCurrentCopy(CFAllocatorRef allocator, SOSPeerInfoRef toCopy,
402 CFStringRef IDSID, CFStringRef transportType, CFBooleanRef preferIDS, CFBooleanRef preferFragmentation, CFBooleanRef preferAckModel, CFSetRef enabledViews,
403 SecKeyRef signingKey, CFErrorRef* error) {
405 SOSPeerInfoRef pi = SOSPeerInfoCreateCopy(allocator, toCopy, error);
406 if(!SOSPeerInfoVersionHasV2Data(pi)) SOSPeerInfoUpdateToV2(pi, error);
408 //SOSPeerInfoSetSerialNumber(pi);
411 SOSPeerInfoV2DictionarySetValue(pi, sDeviceID, IDSID);
414 SOSPeerInfoV2DictionarySetValue(pi, sTransportType, transportType);
417 SOSPeerInfoV2DictionarySetValue(pi, sPreferIDS, preferIDS);
419 if (preferFragmentation) {
420 SOSPeerInfoV2DictionarySetValue(pi, sPreferIDSFragmentation, preferFragmentation);
422 if (preferAckModel) {
423 SOSPeerInfoV2DictionarySetValue(pi, sPreferIDSACKModel, preferAckModel);
426 SOSPeerInfoV2DictionarySetValue(pi, sViewsKey, enabledViews);
429 if(!SOSPeerInfoSign(signingKey, pi, error)) {
437 static SOSPeerInfoRef SOSPeerInfoCopyWithModification(CFAllocatorRef allocator, SOSPeerInfoRef original,
438 SecKeyRef signingKey, CFErrorRef *error,
439 bool (^modification)(SOSPeerInfoRef peerToModify, CFErrorRef *error)) {
441 SOSPeerInfoRef result = NULL;
442 SOSPeerInfoRef copy = SOSPeerInfoCreateCopy(allocator, original, error);
444 require_quiet(modification(copy, error), fail);
446 require_quiet(SOSPeerInfoSign(signingKey, copy, error), fail);
448 CFTransferRetained(result, copy);
456 SOSPeerInfoRef SOSPeerInfoCopyWithGestaltUpdate(CFAllocatorRef allocator, SOSPeerInfoRef toCopy, CFDictionaryRef gestalt, SecKeyRef signingKey, CFErrorRef* error) {
457 return SOSPeerInfoCopyWithModification(allocator, toCopy, signingKey, error,
458 ^bool(SOSPeerInfoRef peerToModify, CFErrorRef *error) {
459 if(!gestalt || !peerToModify) return false;
460 CFRetainAssign(peerToModify->gestalt, gestalt);
461 CFDictionarySetValue(peerToModify->description, sGestaltKey, peerToModify->gestalt);
468 SOSPeerInfoRef SOSPeerInfoCopyWithBackupKeyUpdate(CFAllocatorRef allocator, SOSPeerInfoRef toCopy, CFDataRef backupKey, SecKeyRef signingKey, CFErrorRef *error) {
469 return SOSPeerInfoCopyWithModification(allocator, toCopy, signingKey, error,
470 ^bool(SOSPeerInfoRef peerToModify, CFErrorRef *error) {
471 if (backupKey != NULL)
472 SOSPeerInfoV2DictionarySetValue(peerToModify, sBackupKeyKey, backupKey);
474 SOSPeerInfoV2DictionaryRemoveValue(peerToModify, sBackupKeyKey);
479 static CFDictionaryRef SOSPeerInfoUpdateAndCopyRecord(SOSPeerInfoRef peer, CFStringRef dsid, CFDictionaryRef escrowRecord){
481 CFMutableDictionaryRef existingEscrowRecords = SOSPeerInfoCopyEscrowRecord(peer);
483 if(escrowRecord == NULL && existingEscrowRecords != NULL)
485 CFDictionaryRemoveValue(existingEscrowRecords, dsid);
486 return existingEscrowRecords;
489 if(existingEscrowRecords == NULL)
490 existingEscrowRecords = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
492 CFDictionarySetValue(existingEscrowRecords, dsid, escrowRecord);
494 return existingEscrowRecords;
498 SOSPeerInfoRef SOSPeerInfoCopyWithEscrowRecordUpdate(CFAllocatorRef allocator, SOSPeerInfoRef toCopy, CFStringRef dsid, CFDictionaryRef escrowRecord, SecKeyRef signingKey, CFErrorRef *error) {
499 return SOSPeerInfoCopyWithModification(allocator, toCopy, signingKey, error,
500 ^bool(SOSPeerInfoRef peerToModify, CFErrorRef *error) {
502 CFDictionaryRef updatedEscrowRecords = SOSPeerInfoUpdateAndCopyRecord(peerToModify, dsid, escrowRecord);
503 SOSPeerInfoV2DictionarySetValue(peerToModify, sEscrowRecord, updatedEscrowRecords);
504 CFReleaseNull(updatedEscrowRecords);
509 SOSPeerInfoRef SOSPeerInfoCopyWithReplacedEscrowRecords(CFAllocatorRef allocator, SOSPeerInfoRef toCopy, CFDictionaryRef escrowRecords, SecKeyRef signingKey, CFErrorRef *error) {
510 return SOSPeerInfoCopyWithModification(allocator, toCopy, signingKey, error,
511 ^bool(SOSPeerInfoRef peerToModify, CFErrorRef *error) {
512 if(escrowRecords != NULL)
513 SOSPeerInfoV2DictionarySetValue(peerToModify, sEscrowRecord, escrowRecords);
519 CFDataRef SOSPeerInfoCopyBackupKey(SOSPeerInfoRef peer) {
520 return SOSPeerInfoV2DictionaryCopyData(peer, sBackupKeyKey);
523 CFMutableDictionaryRef SOSPeerInfoCopyEscrowRecord(SOSPeerInfoRef peer){
524 return SOSPeerInfoV2DictionaryCopyDictionary(peer, sEscrowRecord);
527 bool SOSPeerInfoHasBackupKey(SOSPeerInfoRef peer) {
528 CFDataRef bk = SOSPeerInfoCopyBackupKey(peer);
529 bool success = bk != NULL;
534 SOSPeerInfoRef SOSPeerInfoCopyWithViewsChange(CFAllocatorRef allocator, SOSPeerInfoRef toCopy,
535 SOSViewActionCode action, CFStringRef viewname, SOSViewResultCode *retval,
536 SecKeyRef signingKey, CFErrorRef* error) {
537 SOSPeerInfoRef pi = SOSPeerInfoCreateCopy(allocator, toCopy, error);
538 if(action == kSOSCCViewEnable) {
539 *retval = SOSViewsEnable(pi, viewname, error);
540 require((kSOSCCViewMember == *retval), exit);
541 } else if(action == kSOSCCViewDisable) {
542 *retval = SOSViewsDisable(pi, viewname, error);
543 require((kSOSCCViewNotMember == *retval), exit);
546 require_action_quiet(SOSPeerInfoSign(signingKey, pi, error), exit, *retval = kSOSCCGeneralViewError);
555 CFStringRef sPingKey = CFSTR("Ping");
557 SOSPeerInfoRef SOSPeerInfoCopyWithPing(CFAllocatorRef allocator, SOSPeerInfoRef toCopy, SecKeyRef signingKey, CFErrorRef* error) {
558 SOSPeerInfoRef pi = SOSPeerInfoCreateCopy(allocator, toCopy, error);
559 CFDataRef ping = CFDataCreateWithRandomBytes(8);
560 SOSPeerInfoV2DictionarySetValue(pi, sPingKey, ping);
561 SecKeyRef pub_key = SOSPeerInfoCopyPubKey(pi, error);
562 require_quiet(pub_key, exit);
563 pi->peerID = SOSCopyIDOfKey(pub_key, error);
564 require_quiet(pi->peerID, exit);
565 require_action_quiet(SOSPeerInfoSign(signingKey, pi, error), exit, CFReleaseNull(pi));
568 CFReleaseNull(pub_key);
573 SOSViewResultCode SOSPeerInfoViewStatus(SOSPeerInfoRef pi, CFStringRef view, CFErrorRef *error) {
574 return SOSViewsQuery(pi, view, error);
578 SOSPeerInfoRef SOSPeerInfoCopyWithSecurityPropertyChange(CFAllocatorRef allocator, SOSPeerInfoRef toCopy,
579 SOSSecurityPropertyActionCode action, CFStringRef property, SOSSecurityPropertyResultCode *retval,
580 SecKeyRef signingKey, CFErrorRef* error) {
581 SOSPeerInfoRef pi = SOSPeerInfoCreateCopy(allocator, toCopy, error);
582 if(action == kSOSCCSecurityPropertyEnable) {
583 *retval = SOSSecurityPropertyEnable(pi, property, error);
584 require((kSOSCCSecurityPropertyValid == *retval), exit);
585 } else if(action == kSOSCCSecurityPropertyDisable) {
586 *retval = SOSSecurityPropertyDisable(pi, property, error);
587 require((kSOSCCSecurityPropertyNotValid == *retval), exit);
590 require_action_quiet(SOSPeerInfoSign(signingKey, pi, error), exit, *retval = kSOSCCGeneralViewError);
598 SOSViewResultCode SOSPeerInfoSecurityPropertyStatus(SOSPeerInfoRef pi, CFStringRef property, CFErrorRef *error) {
599 return SOSSecurityPropertyQuery(pi, property, error);
604 static void SOSPeerInfoDestroy(CFTypeRef aObj) {
605 SOSPeerInfoRef pi = (SOSPeerInfoRef) aObj;
608 CFReleaseNull(pi->description);
609 CFReleaseNull(pi->signature);
610 CFReleaseNull(pi->gestalt);
611 CFReleaseNull(pi->peerID);
612 CFReleaseNull(pi->v2Dictionary);
615 static Boolean SOSPeerInfoCompare(CFTypeRef lhs, CFTypeRef rhs) {
616 SOSPeerInfoRef lpeer = (SOSPeerInfoRef) lhs;
617 SOSPeerInfoRef rpeer = (SOSPeerInfoRef) rhs;
618 if(!lpeer || !rpeer) return false;
619 return CFEqualSafe(lpeer->description, rpeer->description) && CFEqualSafe(lpeer->signature, rpeer->signature);
623 CFComparisonResult SOSPeerInfoCompareByID(const void *val1, const void *val2, void *context) {
624 // The code below is necessary but not sufficient; not returning a CFComparisonResult
625 // It probably is OK to say that a NULL is < <non-NULL>
626 if (val1 == NULL || val2 == NULL) {
627 ptrdiff_t dv = val1 - val2;
628 return dv < 0 ? kCFCompareLessThan : dv == 0 ? kCFCompareEqualTo : kCFCompareGreaterThan;
631 CFStringRef v1 = SOSPeerInfoGetPeerID((SOSPeerInfoRef) val1);
632 CFStringRef v2 = SOSPeerInfoGetPeerID((SOSPeerInfoRef) val2);
633 if (v1 == NULL || v2 == NULL) {
634 ptrdiff_t dv = (const void *)v1 - (const void *)v2;
635 return dv < 0 ? kCFCompareLessThan : dv == 0 ? kCFCompareEqualTo : kCFCompareGreaterThan;
638 return CFStringCompare(v1, v2, 0);
641 static CFHashCode SOSPeerInfoHash(CFTypeRef cf) {
642 SOSPeerInfoRef peer = (SOSPeerInfoRef) cf;
644 return CFHash(peer->description) ^ CFHash(peer->signature);
648 static char boolToChars(bool val, char truechar, char falsechar) {
649 return val? truechar: falsechar;
652 static CFStringRef isKnown(CFStringRef ref) {
653 return ref? ref: CFSTR("Unknown ");
656 static CFStringRef copyDescriptionWithFormatOptions(CFTypeRef aObj, CFDictionaryRef formatOptions){
658 SOSPeerInfoRef pi = (SOSPeerInfoRef) aObj;
661 CFStringRef description = NULL;
662 // Get the format options we care about:
663 bool retired = SOSPeerInfoIsRetirementTicket(pi);
664 bool selfValid = SOSPeerInfoVerify(pi, NULL);
665 bool backingUp = SOSPeerInfoHasBackupKey(pi);
666 bool isKVS = SOSPeerInfoKVSOnly(pi);
667 CFStringRef osVersion = CFDictionaryGetValue(pi->gestalt, kPIOSVersionKey);
668 CFStringRef tmp = SOSPeerInfoV2DictionaryCopyString(pi, sDeviceID);
669 CFStringRef deviceID = CFStringCreateTruncatedCopy(tmp, 8);
671 CFStringRef serialNum = SOSPeerInfoCopySerialNumber(pi);
672 CFStringRef peerID = CFStringCreateTruncatedCopy(SOSPeerInfoGetPeerID(pi), 8);
674 // Calculate the truncated length
676 CFStringRef objectPrefix = CFStringCreateWithFormat(kCFAllocatorDefault, formatOptions, CFSTR("PI@%p"), pi);
678 description = CFStringCreateWithFormat(kCFAllocatorDefault, formatOptions,
679 CFSTR("<%@: [name: %20@] [%c%c%c%c%c%c%c] [type: %-20@] [spid: %8@] [os: %10@] [devid: %10@] [serial: %12@]"),
681 isKnown(SOSPeerInfoGetPeerName(pi)),
684 boolToChars(selfValid, 'S', 's'),
685 boolToChars(retired, 'R', 'r'),
686 boolToChars(backingUp, 'B', 'b'),
687 boolToChars(isKVS, 'K', 'I'),
689 isKnown(SOSPeerInfoGetPeerDeviceType(pi)), isKnown(peerID),
690 isKnown(osVersion), isKnown(deviceID), isKnown(serialNum));
693 CFReleaseNull(peerID);
694 CFReleaseNull(deviceID);
695 CFReleaseNull(serialNum);
696 CFReleaseNull(objectPrefix);
701 static CFStringRef SOSPeerInfoCopyFormatDescription(CFTypeRef aObj, CFDictionaryRef formatOptions) {
703 CFStringRef description = NULL;
705 description = copyDescriptionWithFormatOptions(aObj, formatOptions);
710 void SOSPeerInfoLogState(char *category, SOSPeerInfoRef pi, SecKeyRef pubKey, CFStringRef myPID, char sigchr) {
712 bool appValid = SOSPeerInfoApplicationVerify(pi, pubKey, NULL);
713 bool retired = SOSPeerInfoIsRetirementTicket(pi);
714 bool selfValid = SOSPeerInfoVerify(pi, NULL);
715 bool backingUp = SOSPeerInfoHasBackupKey(pi);
716 bool isMe = CFEqualSafe(SOSPeerInfoGetPeerID(pi), myPID) == true;
717 bool isKVS = SOSPeerInfoKVSOnly(pi);
718 CFStringRef osVersion = CFDictionaryGetValue(pi->gestalt, kPIOSVersionKey);
719 CFStringRef tmp = SOSPeerInfoV2DictionaryCopyString(pi, sDeviceID);
720 CFStringRef deviceID = CFStringCreateTruncatedCopy(tmp, 8);
722 CFStringRef serialNum = SOSPeerInfoCopySerialNumber(pi);
723 CFStringRef peerID = CFStringCreateTruncatedCopy(SOSPeerInfoGetPeerID(pi), 8);
725 secnotice(category, "PI: [name: %-20@] [%c%c%c%c%c%c%c] [type: %-20@] [spid: %8@] [os: %10@] [devid: %10@] [serial: %12@]", isKnown(SOSPeerInfoGetPeerName(pi)),
726 boolToChars(isMe, 'M', 'm'),
727 boolToChars(appValid, 'A', 'a'),
728 boolToChars(selfValid, 'S', 's'),
729 boolToChars(retired, 'R', 'r'),
730 boolToChars(backingUp, 'B', 'b'),
731 boolToChars(isKVS, 'K', 'I'),
733 isKnown(SOSPeerInfoGetPeerDeviceType(pi)), isKnown(peerID),
734 isKnown(osVersion), isKnown(deviceID), isKnown(serialNum));
736 CFReleaseNull(peerID);
737 CFReleaseNull(deviceID);
738 CFReleaseNull(serialNum);
741 CFDictionaryRef SOSPeerInfoCopyPeerGestalt(SOSPeerInfoRef pi) {
742 CFRetain(pi->gestalt);
746 CFDictionaryRef SOSPeerGetGestalt(SOSPeerInfoRef pi){
750 CFStringRef SOSPeerInfoGetPeerName(SOSPeerInfoRef peer) {
751 return SOSPeerInfoLookupGestaltValue(peer, kPIUserDefinedDeviceNameKey);
754 CFStringRef SOSPeerInfoGetPeerDeviceType(SOSPeerInfoRef peer) {
755 return SOSPeerInfoLookupGestaltValue(peer, kPIDeviceModelNameKey);
758 CFIndex SOSPeerInfoGetPeerProtocolVersion(SOSPeerInfoRef peer) {
759 CFIndex version = PEERINFO_CURRENT_VERSION;
760 CFTypeRef val = SOSPeerInfoLookupGestaltValue(peer, kPIMessageProtocolVersionKey);
761 if (val && CFGetTypeID(val) == CFNumberGetTypeID())
762 CFNumberGetValue(val, kCFNumberCFIndexType, &version);
766 CFTypeRef SOSPeerInfoLookupGestaltValue(SOSPeerInfoRef pi, CFStringRef key) {
767 return CFDictionaryGetValue(pi->gestalt, key);
770 CFStringRef SOSPeerInfoGetPeerID(SOSPeerInfoRef pi) {
771 return pi ? pi->peerID : NULL;
774 bool SOSPeerInfoPeerIDEqual(SOSPeerInfoRef pi, CFStringRef myPeerID) {
775 return CFEqualSafe(myPeerID, SOSPeerInfoGetPeerID(pi));
778 CFIndex SOSPeerInfoGetVersion(SOSPeerInfoRef pi) {
782 bool SOSPeerInfoUpdateDigestWithPublicKeyBytes(SOSPeerInfoRef peer, const struct ccdigest_info *di,
783 ccdigest_ctx_t ctx, CFErrorRef *error) {
784 CFDataRef pubKeyBytes = CFDictionaryGetValue(peer->description, sPublicKeyKey);
787 SOSCreateErrorWithFormat(kSOSErrorEncodeFailure, NULL, error, NULL, CFSTR("Digest failed – no public key"));
791 ccdigest_update(di, ctx, CFDataGetLength(pubKeyBytes), CFDataGetBytePtr(pubKeyBytes));
796 bool SOSPeerInfoUpdateDigestWithDescription(SOSPeerInfoRef peer, const struct ccdigest_info *di,
797 ccdigest_ctx_t ctx, CFErrorRef *error) {
798 if(SOSPeerInfoVersionHasV2Data(peer)) SOSPeerInfoPackV2Data(peer);
799 size_t description_size = der_sizeof_plist(peer->description, error);
800 uint8_t data_begin[description_size];
801 uint8_t *data_end = data_begin + description_size;
802 uint8_t *encoded = der_encode_plist(peer->description, error, data_begin, data_end);
805 SOSCreateErrorWithFormat(kSOSErrorEncodeFailure, NULL, error, NULL, CFSTR("Description encode failed"));
809 ccdigest_update(di, ctx, description_size, data_begin);
815 static CFDataRef sosCreateDate() {
816 CFDateRef now = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent());
817 size_t bufsiz = der_sizeof_date(now, NULL);
819 der_encode_date(now, NULL, buf, buf+bufsiz);
821 return CFDataCreate(NULL, buf, bufsiz);
824 static CFDateRef sosCreateCFDate(CFDataRef sosdate) {
826 der_decode_date(NULL, 0, &date, NULL, CFDataGetBytePtr(sosdate),
827 CFDataGetBytePtr(sosdate) + CFDataGetLength(sosdate));
831 static bool sospeer_application_hash(SOSPeerInfoRef pi, const struct ccdigest_info *di, uint8_t *hbuf) {
832 CFDataRef appdate = asData(CFDictionaryGetValue(pi->description, sApplicationDate), NULL);
833 if(!appdate) return false;
834 ccdigest_di_decl(di, ctx);
835 ccdigest_init(di, ctx);
836 ccdigest_update(di, ctx, CFDataGetLength(appdate), CFDataGetBytePtr(appdate));
837 if (!SOSPeerInfoUpdateDigestWithPublicKeyBytes(pi, di, ctx, NULL)) return false;
838 ccdigest_final(di, ctx, hbuf);
842 SOSPeerInfoRef SOSPeerInfoCopyAsApplication(SOSPeerInfoRef original, SecKeyRef userkey, SecKeyRef peerkey, CFErrorRef *error) {
843 SOSPeerInfoRef result = NULL;
844 SOSPeerInfoRef pi = SOSPeerInfoCreateCopy(kCFAllocatorDefault, original, error);
846 const struct ccdigest_info *di = ccsha256_di();
847 uint8_t hbuf[di->output_size];
848 CFDataRef usersig = NULL;
850 CFDataRef creationDate = sosCreateDate();
851 CFDictionarySetValue(pi->description, sApplicationDate, creationDate);
852 CFReleaseNull(creationDate);
854 // Create User Application Signature
855 require_action_quiet(sospeer_application_hash(pi, di, hbuf), fail,
856 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Failed to create hash for peer applicant"), NULL, error));
858 usersig = sosCopySignedHash(userkey, di, hbuf);
859 require_action_quiet(usersig, fail,
860 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Failed to sign public key hash for peer"), NULL, error));
862 CFDictionarySetValue(pi->description, sApplicationUsig, usersig);
864 require_quiet(SOSPeerInfoSign(peerkey, pi, error), fail);
870 CFReleaseNull(usersig);
875 bool SOSPeerInfoApplicationVerify(SOSPeerInfoRef pi, SecKeyRef userkey, CFErrorRef *error) {
876 const struct ccdigest_info *di = ccsha256_di();
877 uint8_t hbuf[di->output_size];
880 CFDataRef usig = CFDictionaryGetValue(pi->description, sApplicationUsig);
881 require_action_quiet(usig, exit,
882 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Peer is not an applicant"), NULL, error));
883 // Verify User Application Signature
884 require_action_quiet(sospeer_application_hash(pi, di, hbuf), exit,
885 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Failed to create hash for peer applicant"), NULL, error));
886 require_action_quiet(sosVerifyHash(userkey, di, hbuf, usig), exit,
887 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("user signature of public key hash fails to verify"), NULL, error));
889 result = SOSPeerInfoVerify(pi, error);
896 static CF_RETURNS_RETAINED CFDateRef sosPeerInfoGetDate(SOSPeerInfoRef pi, CFStringRef entry) {
898 CFDataRef sosdate = CFDictionaryGetValue(pi->description, entry);
899 if(!sosdate) return NULL;
900 CFDateRef date = sosCreateCFDate(sosdate);
905 CF_RETURNS_RETAINED CFDateRef SOSPeerInfoGetApplicationDate(SOSPeerInfoRef pi) {
906 return sosPeerInfoGetDate(pi, sApplicationDate);
909 CF_RETURNS_RETAINED CFDateRef SOSPeerInfoGetRetirementDate(SOSPeerInfoRef pi) {
910 return sosPeerInfoGetDate(pi, sRetirementDate);
919 CFStringRef SOSPeerGestaltGetName(CFDictionaryRef gestalt) {
920 CFStringRef name = SOSPeerGestaltGetAnswer(gestalt, kPIUserDefinedDeviceNameKey);
921 return isString(name) ? name : NULL;
924 CFTypeRef SOSPeerGestaltGetAnswer(CFDictionaryRef gestalt, CFStringRef question) {
925 return gestalt ? CFDictionaryGetValue(gestalt, question) : NULL;
933 SOSPeerInfoRef SOSPeerInfoCreateRetirementTicket(CFAllocatorRef allocator, SecKeyRef privKey, SOSPeerInfoRef peer, CFErrorRef *error) {
935 SOSPeerInfoRef pi = SOSPeerInfoCreateCopy(allocator, peer, error);
939 // Fill out Resignation Date
940 CFDataRef resignationDate = sosCreateDate();
941 CFDictionaryAddValue(pi->description, sRetirementDate, resignationDate);
942 CFReleaseNull(resignationDate);
944 require(SOSPeerInfoSign(privKey, pi, error), fail);
953 CFStringRef SOSPeerInfoInspectRetirementTicket(SOSPeerInfoRef pi, CFErrorRef *error) {
954 CFStringRef retval = NULL;
955 CFDateRef now = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent());
956 CFDateRef retirement = NULL;
958 require_quiet(SOSPeerInfoVerify(pi, error), err);
960 retirement = sosCreateCFDate(CFDictionaryGetValue(pi->description, sRetirementDate));
961 require_action_quiet(retirement, err,
962 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Peer is not retired"), NULL, error));
964 require_action_quiet(CFDateCompare(now, retirement, NULL) == kCFCompareGreaterThan, err,
965 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Retirement date is after current date"), NULL, error));
967 retval = SOSPeerInfoGetPeerID(pi);
971 CFReleaseNull(retirement);
975 bool SOSPeerInfoRetireRetirementTicket(size_t max_seconds, SOSPeerInfoRef pi) {
976 CFDateRef now = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent());
977 CFDateRef retirement = sosCreateCFDate(CFDictionaryGetValue(pi->description, sRetirementDate));
978 CFTimeInterval timediff = CFDateGetTimeIntervalSinceDate(now, retirement); // diff in seconds
980 CFReleaseNull(retirement);
981 if(timediff > (max_seconds)) return true;
985 bool SOSPeerInfoIsRetirementTicket(SOSPeerInfoRef pi) {
986 CFDataRef flag = CFDictionaryGetValue(pi->description, sRetirementDate);
990 bool SOSPeerInfoIsCloudIdentity(SOSPeerInfoRef pi) {
991 CFTypeRef value = CFDictionaryGetValue(pi->description, sCloudIdentityKey);
992 return CFEqualSafe(value, kCFBooleanTrue);
995 SOSPeerInfoRef SOSPeerInfoUpgradeSignatures(CFAllocatorRef allocator, SecKeyRef privKey, SecKeyRef peerKey, SOSPeerInfoRef peer, CFErrorRef *error) {
996 SecKeyRef pubKey = SecKeyCreatePublicFromPrivate(privKey);
997 SOSPeerInfoRef retval = NULL;
999 retval = SOSPeerInfoCopyAsApplication(peer, privKey, peerKey, error);
1000 CFReleaseNull(pubKey);
1004 CFBooleanRef SOSPeerInfoCopyIDSPreference(SOSPeerInfoRef peer){
1005 CFBooleanRef preference = (CFBooleanRef)SOSPeerInfoV2DictionaryCopyBoolean(peer, sPreferIDS);
1006 return (preference ? preference : CFRetain(kCFBooleanFalse));
1010 SOSPeerInfoRef SOSPeerInfoSetIDSPreference(CFAllocatorRef allocator, SOSPeerInfoRef toCopy, CFBooleanRef preference, SecKeyRef signingKey, CFErrorRef *error){
1011 return SOSPeerInfoCopyWithModification(allocator, toCopy, signingKey, error,
1012 ^bool(SOSPeerInfoRef peerToModify, CFErrorRef *error) {
1013 SOSPeerInfoV2DictionarySetValue(peerToModify, sPreferIDS, preference);
1018 CFBooleanRef SOSPeerInfoCopyIDSFragmentationPreference(SOSPeerInfoRef peer){
1019 CFBooleanRef preference = (CFBooleanRef)SOSPeerInfoV2DictionaryCopyBoolean(peer, sPreferIDSFragmentation);
1020 return (preference ? preference : CFRetain(kCFBooleanFalse));
1023 CFBooleanRef SOSPeerInfoCopyIDSACKModelPreference(SOSPeerInfoRef peer){
1024 CFBooleanRef preference = (CFBooleanRef)SOSPeerInfoV2DictionaryCopyBoolean(peer, sPreferIDSACKModel);
1025 return (preference ? preference : CFRetain(kCFBooleanFalse));
1028 SOSPeerInfoRef SOSPeerInfoSetIDSFragmentationPreference(CFAllocatorRef allocator, SOSPeerInfoRef toCopy, CFBooleanRef preference, SecKeyRef signingKey, CFErrorRef *error){
1029 return SOSPeerInfoCopyWithModification(allocator, toCopy, signingKey, error,
1030 ^bool(SOSPeerInfoRef peerToModify, CFErrorRef *error) {
1031 SOSPeerInfoV2DictionarySetValue(peerToModify, sPreferIDSFragmentation, preference);
1036 SOSPeerInfoRef SOSPeerInfoSetIDSACKModelPreference(CFAllocatorRef allocator, SOSPeerInfoRef toCopy, CFBooleanRef preference, SecKeyRef signingKey, CFErrorRef *error){
1037 return SOSPeerInfoCopyWithModification(allocator, toCopy, signingKey, error,
1038 ^bool(SOSPeerInfoRef peerToModify, CFErrorRef *error) {
1039 SOSPeerInfoV2DictionarySetValue(peerToModify, sPreferIDSACKModel, preference);
1044 static SOSPeerInfoRef CF_RETURNS_RETAINED
1045 SOSPeerInfoSetOctagonKey(CFAllocatorRef allocator,
1046 SOSPeerInfoRef toCopy,
1047 CFStringRef descriptionKey,
1048 SecKeyRef octagonKey,
1049 SecKeyRef signingKey,
1052 CFDataRef publicKeyBytes = NULL;
1053 SOSPeerInfoRef pi = NULL;
1055 OSStatus copyResult = SecKeyCopyPublicBytes(octagonKey, &publicKeyBytes);
1056 require_action_quiet(0 == copyResult, fail, SecError(copyResult, error, CFSTR("failed to copy public key bytes")));
1058 pi = SOSPeerInfoCopyWithModification(allocator, toCopy, signingKey, error,
1059 ^bool(SOSPeerInfoRef peerToModify, CFErrorRef *error) {
1060 if(peerToModify && peerToModify->description && publicKeyBytes && descriptionKey) {
1061 CFDictionarySetValue(peerToModify->description, descriptionKey, publicKeyBytes);
1063 SecError(errSecParam, error, CFSTR("Bad key bytes or dictionary key"));
1070 CFReleaseNull(publicKeyBytes);
1074 SOSPeerInfoRef CF_RETURNS_RETAINED
1075 SOSPeerInfoSetOctagonSigningKey(CFAllocatorRef allocator,
1076 SOSPeerInfoRef toCopy,
1077 SecKeyRef octagonSigningKey,
1078 SecKeyRef signingKey,
1081 return SOSPeerInfoSetOctagonKey(allocator, toCopy, sOctagonPeerSigningPublicKeyKey, octagonSigningKey, signingKey, error);
1084 SOSPeerInfoRef CF_RETURNS_RETAINED
1085 SOSPeerInfoSetOctagonEncryptionKey(CFAllocatorRef allocator,
1086 SOSPeerInfoRef toCopy,
1087 SecKeyRef octagonEncryptionKey,
1088 SecKeyRef signingKey,
1091 return SOSPeerInfoSetOctagonKey(allocator, toCopy, sOctagonPeerEncryptionPublicKeyKey, octagonEncryptionKey, signingKey, error);
1094 bool SOSPeerInfoTransportTypeIs(SOSPeerInfoRef pi, CFStringRef transportType) {
1095 return SOSPeerInfoV2DictionaryHasStringValue(pi, sTransportType, transportType);
1098 CFStringRef SOSPeerInfoCopyTransportType(SOSPeerInfoRef peer){
1099 CFStringRef transportType = (CFStringRef)SOSPeerInfoV2DictionaryCopyString(peer, sTransportType);
1100 return (transportType ? transportType : CFRetain(SOSTransportMessageTypeKVS));
1103 SOSPeerInfoRef SOSPeerInfoSetTransportType(CFAllocatorRef allocator, SOSPeerInfoRef toCopy, CFStringRef transportType, SecKeyRef signingKey, CFErrorRef *error){
1105 return SOSPeerInfoCopyWithModification(allocator, toCopy, signingKey, error,
1106 ^bool(SOSPeerInfoRef peerToModify, CFErrorRef *error) {
1107 SOSPeerInfoV2DictionarySetValue(peerToModify, sTransportType, transportType);
1112 bool SOSPeerInfoKVSOnly(SOSPeerInfoRef pi) {
1113 CFStringRef transportType = SOSPeerInfoCopyTransportType(pi);
1114 bool retval = CFEqualSafe(transportType, SOSTransportMessageTypeKVS);
1115 CFReleaseNull(transportType);
1119 bool SOSPeerInfoHasDeviceID(SOSPeerInfoRef peer) {
1120 return SOSPeerInfoV2DictionaryHasString(peer, sDeviceID);
1123 CFStringRef SOSPeerInfoCopyDeviceID(SOSPeerInfoRef peer){
1124 return (CFStringRef)SOSPeerInfoV2DictionaryCopyString(peer, sDeviceID);
1127 SOSPeerInfoRef SOSPeerInfoSetDeviceID(CFAllocatorRef allocator, SOSPeerInfoRef toCopy, CFStringRef IDS, SecKeyRef signingKey, CFErrorRef *error){
1129 return SOSPeerInfoCopyWithModification(allocator, toCopy, signingKey, error,
1130 ^bool(SOSPeerInfoRef peerToModify, CFErrorRef *error) {
1131 SOSPeerInfoV2DictionarySetValue(peerToModify, sDeviceID, IDS);
1136 bool SOSPeerInfoShouldUseIDSTransport(SOSPeerInfoRef myPeer, SOSPeerInfoRef theirPeer){
1137 return SOSPeerInfoHasDeviceID(myPeer) && SOSPeerInfoTransportTypeIs(myPeer, SOSTransportMessageTypeIDSV2) &&
1138 SOSPeerInfoHasDeviceID(theirPeer) && SOSPeerInfoTransportTypeIs(theirPeer, SOSTransportMessageTypeIDSV2);
1141 bool SOSPeerInfoShouldUseIDSMessageFragmentation(SOSPeerInfoRef myPeer, SOSPeerInfoRef theirPeer){
1143 bool success = false;
1145 CFBooleanRef myPreference = SOSPeerInfoCopyIDSFragmentationPreference(myPeer);
1147 CFBooleanRef theirPreference = SOSPeerInfoCopyIDSFragmentationPreference(theirPeer);
1148 secnotice("IDS Transport", "mypreference: %@, theirpreference: %@", myPreference, theirPreference);
1149 if((myPreference == kCFBooleanTrue && theirPreference == kCFBooleanTrue))
1152 CFReleaseNull(myPreference);
1153 CFReleaseNull(theirPreference);
1157 bool SOSPeerInfoShouldUseACKModel(SOSPeerInfoRef myPeer, SOSPeerInfoRef theirPeer){
1158 bool success = false;
1160 CFBooleanRef myPreference = SOSPeerInfoCopyIDSACKModelPreference(myPeer);
1162 CFBooleanRef theirPreference = SOSPeerInfoCopyIDSACKModelPreference(theirPeer);
1163 secnotice("IDS Transport", "mypreference: %@, theirpreference: %@", myPreference, theirPreference);
1164 if((myPreference == kCFBooleanTrue && theirPreference == kCFBooleanTrue))
1167 CFReleaseNull(myPreference);
1168 CFReleaseNull(theirPreference);
1173 SOSPeerInfoDeviceClass SOSPeerInfoGetClass(SOSPeerInfoRef pi) {
1174 static CFDictionaryRef devID2Class = NULL;
1175 static dispatch_once_t onceToken = 0;
1177 dispatch_once(&onceToken, ^{
1178 CFNumberRef cfSOSPeerInfo_macOS = CFNumberCreateWithCFIndex(kCFAllocatorDefault, SOSPeerInfo_macOS);
1179 CFNumberRef cfSOSPeerInfo_iOS = CFNumberCreateWithCFIndex(kCFAllocatorDefault, SOSPeerInfo_iOS);
1180 CFNumberRef cfSOSPeerInfo_iCloud = CFNumberCreateWithCFIndex(kCFAllocatorDefault, SOSPeerInfo_iCloud);
1181 // CFNumberRef cfSOSPeerInfo_watchOS = CFNumberCreateWithCFIndex(kCFAllocatorDefault, SOSPeerInfo_watchOS);
1182 // CFNumberRef cfSOSPeerInfo_tvOS = CFNumberCreateWithCFIndex(kCFAllocatorDefault, SOSPeerInfo_tvOS);
1184 devID2Class = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
1185 CFSTR("Mac Pro"), cfSOSPeerInfo_macOS,
1186 CFSTR("MacBook"), cfSOSPeerInfo_macOS,
1187 CFSTR("MacBook Pro"), cfSOSPeerInfo_macOS,
1188 CFSTR("iCloud"), cfSOSPeerInfo_iCloud,
1189 CFSTR("iMac"), cfSOSPeerInfo_macOS,
1190 CFSTR("iPad"), cfSOSPeerInfo_iOS,
1191 CFSTR("iPhone"), cfSOSPeerInfo_iOS,
1192 CFSTR("iPod touch"), cfSOSPeerInfo_iOS,
1194 CFReleaseNull(cfSOSPeerInfo_macOS);
1195 CFReleaseNull(cfSOSPeerInfo_iOS);
1196 CFReleaseNull(cfSOSPeerInfo_iCloud);
1198 SOSPeerInfoDeviceClass retval = SOSPeerInfo_unknown;
1199 CFStringRef dt = SOSPeerInfoGetPeerDeviceType(pi);
1200 require_quiet(dt, errOut);
1201 CFNumberRef classNum = CFDictionaryGetValue(devID2Class, dt);
1202 require_quiet(classNum, errOut);
1204 require_quiet(CFNumberGetValue(classNum, kCFNumberCFIndexType, &tmp), errOut);
1205 retval = (SOSPeerInfoDeviceClass) tmp;
1210 bool SOSPeerInfoHasOctagonSigningPubKey(SOSPeerInfoRef peer){
1211 bool hasKey = false;
1212 SecKeyRef pubKey = SOSPeerInfoCopyOctagonSigningPublicKey(peer, NULL);
1215 CFReleaseNull(pubKey);
1219 bool SOSPeerInfoHasOctagonEncryptionPubKey(SOSPeerInfoRef peer){
1220 bool hasKey = false;
1221 SecKeyRef pubKey = SOSPeerInfoCopyOctagonEncryptionPublicKey(peer, NULL);
1224 CFReleaseNull(pubKey);