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);
314 pi->peerID = SOSCopyIDOfKey(publicKey, error);
316 require_quiet(pi->peerID, exit);
318 // ================ V2 Additions Start
320 if(!SOSPeerInfoUpdateToV2(pi, error)) {
325 // V2DictionarySetValue handles NULL as remove
326 if (backup_key != NULL) SOSPeerInfoV2DictionarySetValue(pi, sBackupKeyKey, backup_key);
327 SOSPeerInfoV2DictionarySetValue(pi, sDeviceID, IDSID);
328 SOSPeerInfoV2DictionarySetValue(pi, sTransportType, transportType);
329 SOSPeerInfoV2DictionarySetValue(pi, sPreferIDS, preferIDS);
330 SOSPeerInfoV2DictionarySetValue(pi, sPreferIDSFragmentation, preferFragmentation);
331 SOSPeerInfoV2DictionarySetValue(pi, sPreferIDSACKModel, preferAckModel);
332 SOSPeerInfoV2DictionarySetValue(pi, sViewsKey, enabledViews);
334 // ================ V2 Additions End
336 if (!SOSPeerInfoSign(signingKey, pi, error)) {
342 CFReleaseNull(versionNumber);
343 CFReleaseNull(publicKey);
344 CFReleaseNull(publicBytes);
345 CFReleaseNull(octagonPeerSigningPublicBytes);
346 CFReleaseNull(octagonPeerEncryptionPublicBytes);
350 SOSPeerInfoRef SOSPeerInfoCreate(CFAllocatorRef allocator, CFDictionaryRef gestalt, CFDataRef backup_key, SecKeyRef signingKey, SecKeyRef octagonPeerSigningKey, SecKeyRef octagonPeerEncryptionKey, CFErrorRef* error) {
351 return SOSPeerInfoCreate_Internal(allocator, gestalt, backup_key, NULL, NULL, NULL, NULL, NULL, NULL, signingKey, octagonPeerSigningKey, octagonPeerEncryptionKey, error, ^(CFMutableDictionaryRef description) {});
354 SOSPeerInfoRef SOSPeerInfoCreateWithTransportAndViews(CFAllocatorRef allocator, CFDictionaryRef gestalt, CFDataRef backup_key,
355 CFStringRef IDSID, CFStringRef transportType, CFBooleanRef preferIDS,
356 CFBooleanRef preferFragmentation, CFBooleanRef preferAckModel, CFSetRef enabledViews,
357 SecKeyRef signingKey,
358 SecKeyRef octagonPeerSigningKey,
359 SecKeyRef octagonPeerEncryptionKey,
362 return SOSPeerInfoCreate_Internal(allocator, gestalt, backup_key, IDSID, transportType, preferIDS, preferFragmentation, preferAckModel, enabledViews, signingKey, octagonPeerSigningKey, octagonPeerEncryptionKey, error, ^(CFMutableDictionaryRef description) {});
366 SOSPeerInfoRef SOSPeerInfoCreateCloudIdentity(CFAllocatorRef allocator, CFDictionaryRef gestalt, SecKeyRef signingKey, CFErrorRef* error) {
367 return SOSPeerInfoCreate_Internal(allocator, gestalt, NULL, NULL, NULL, NULL, NULL, NULL, NULL, signingKey, NULL, NULL, error, ^(CFMutableDictionaryRef description) {
368 CFDictionarySetValue(description, sCloudIdentityKey, kCFBooleanTrue);
374 SOSPeerInfoRef SOSPeerInfoCreateCopy(CFAllocatorRef allocator, SOSPeerInfoRef toCopy, CFErrorRef* error) {
375 if(!toCopy) return NULL;
376 SOSPeerInfoRef pi = CFTypeAllocate(SOSPeerInfo, struct __OpaqueSOSPeerInfo, allocator);
378 pi->description = CFDictionaryCreateMutableCopy(allocator, 0, toCopy->description);
379 pi->signature = CFDataCreateCopy(allocator, toCopy->signature);
381 pi->gestalt = CFDictionaryCreateCopy(allocator, toCopy->gestalt);
382 pi->peerID = CFStringCreateCopy(allocator, toCopy->peerID);
384 pi->version = toCopy->version;
385 if(!SOSPeerInfoVersionHasV2Data(pi)) SOSPeerInfoExpandV2Data(pi, error);
391 bool SOSPeerInfoVersionIsCurrent(SOSPeerInfoRef pi) {
392 return pi->version >= PEERINFO_CURRENT_VERSION;
395 bool SOSPeerInfoVersionHasV2Data(SOSPeerInfoRef pi) {
396 return pi->version >= kSOSPeerV2BaseVersion;
399 SOSPeerInfoRef SOSPeerInfoCreateCurrentCopy(CFAllocatorRef allocator, SOSPeerInfoRef toCopy,
400 CFStringRef IDSID, CFStringRef transportType, CFBooleanRef preferIDS, CFBooleanRef preferFragmentation, CFBooleanRef preferAckModel, CFSetRef enabledViews,
401 SecKeyRef signingKey, CFErrorRef* error) {
403 SOSPeerInfoRef pi = SOSPeerInfoCreateCopy(allocator, toCopy, error);
404 if(!SOSPeerInfoVersionHasV2Data(pi)) SOSPeerInfoUpdateToV2(pi, error);
406 //SOSPeerInfoSetSerialNumber(pi);
409 SOSPeerInfoV2DictionarySetValue(pi, sDeviceID, IDSID);
412 SOSPeerInfoV2DictionarySetValue(pi, sTransportType, transportType);
415 SOSPeerInfoV2DictionarySetValue(pi, sPreferIDS, preferIDS);
417 if (preferFragmentation) {
418 SOSPeerInfoV2DictionarySetValue(pi, sPreferIDSFragmentation, preferFragmentation);
420 if (preferAckModel) {
421 SOSPeerInfoV2DictionarySetValue(pi, sPreferIDSACKModel, preferAckModel);
424 SOSPeerInfoV2DictionarySetValue(pi, sViewsKey, enabledViews);
427 if(!SOSPeerInfoSign(signingKey, pi, error)) {
435 static SOSPeerInfoRef SOSPeerInfoCopyWithModification(CFAllocatorRef allocator, SOSPeerInfoRef original,
436 SecKeyRef signingKey, CFErrorRef *error,
437 bool (^modification)(SOSPeerInfoRef peerToModify, CFErrorRef *error)) {
439 SOSPeerInfoRef result = NULL;
440 SOSPeerInfoRef copy = SOSPeerInfoCreateCopy(allocator, original, error);
442 require_quiet(modification(copy, error), fail);
444 require_quiet(SOSPeerInfoSign(signingKey, copy, error), fail);
446 CFTransferRetained(result, copy);
454 SOSPeerInfoRef SOSPeerInfoCopyWithGestaltUpdate(CFAllocatorRef allocator, SOSPeerInfoRef toCopy, CFDictionaryRef gestalt, SecKeyRef signingKey, CFErrorRef* error) {
455 return SOSPeerInfoCopyWithModification(allocator, toCopy, signingKey, error,
456 ^bool(SOSPeerInfoRef peerToModify, CFErrorRef *error) {
457 if(!gestalt || !peerToModify) return false;
458 CFRetainAssign(peerToModify->gestalt, gestalt);
459 CFDictionarySetValue(peerToModify->description, sGestaltKey, peerToModify->gestalt);
466 SOSPeerInfoRef SOSPeerInfoCopyWithBackupKeyUpdate(CFAllocatorRef allocator, SOSPeerInfoRef toCopy, CFDataRef backupKey, SecKeyRef signingKey, CFErrorRef *error) {
467 return SOSPeerInfoCopyWithModification(allocator, toCopy, signingKey, error,
468 ^bool(SOSPeerInfoRef peerToModify, CFErrorRef *error) {
469 if (backupKey != NULL)
470 SOSPeerInfoV2DictionarySetValue(peerToModify, sBackupKeyKey, backupKey);
472 SOSPeerInfoV2DictionaryRemoveValue(peerToModify, sBackupKeyKey);
477 static CFDictionaryRef SOSPeerInfoUpdateAndCopyRecord(SOSPeerInfoRef peer, CFStringRef dsid, CFDictionaryRef escrowRecord){
479 CFMutableDictionaryRef existingEscrowRecords = SOSPeerInfoCopyEscrowRecord(peer);
481 if(escrowRecord == NULL && existingEscrowRecords != NULL)
483 CFDictionaryRemoveValue(existingEscrowRecords, dsid);
484 return existingEscrowRecords;
487 if(existingEscrowRecords == NULL)
488 existingEscrowRecords = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
490 CFDictionarySetValue(existingEscrowRecords, dsid, escrowRecord);
492 return existingEscrowRecords;
496 SOSPeerInfoRef SOSPeerInfoCopyWithEscrowRecordUpdate(CFAllocatorRef allocator, SOSPeerInfoRef toCopy, CFStringRef dsid, CFDictionaryRef escrowRecord, SecKeyRef signingKey, CFErrorRef *error) {
497 return SOSPeerInfoCopyWithModification(allocator, toCopy, signingKey, error,
498 ^bool(SOSPeerInfoRef peerToModify, CFErrorRef *error) {
500 CFDictionaryRef updatedEscrowRecords = SOSPeerInfoUpdateAndCopyRecord(peerToModify, dsid, escrowRecord);
501 SOSPeerInfoV2DictionarySetValue(peerToModify, sEscrowRecord, updatedEscrowRecords);
502 CFReleaseNull(updatedEscrowRecords);
507 SOSPeerInfoRef SOSPeerInfoCopyWithReplacedEscrowRecords(CFAllocatorRef allocator, SOSPeerInfoRef toCopy, CFDictionaryRef escrowRecords, SecKeyRef signingKey, CFErrorRef *error) {
508 return SOSPeerInfoCopyWithModification(allocator, toCopy, signingKey, error,
509 ^bool(SOSPeerInfoRef peerToModify, CFErrorRef *error) {
510 if(escrowRecords != NULL)
511 SOSPeerInfoV2DictionarySetValue(peerToModify, sEscrowRecord, escrowRecords);
517 CFDataRef SOSPeerInfoCopyBackupKey(SOSPeerInfoRef peer) {
518 return SOSPeerInfoV2DictionaryCopyData(peer, sBackupKeyKey);
521 CFMutableDictionaryRef SOSPeerInfoCopyEscrowRecord(SOSPeerInfoRef peer){
522 return SOSPeerInfoV2DictionaryCopyDictionary(peer, sEscrowRecord);
525 bool SOSPeerInfoHasBackupKey(SOSPeerInfoRef peer) {
526 CFDataRef bk = SOSPeerInfoCopyBackupKey(peer);
527 bool success = bk != NULL;
532 SOSPeerInfoRef SOSPeerInfoCopyWithViewsChange(CFAllocatorRef allocator, SOSPeerInfoRef toCopy,
533 SOSViewActionCode action, CFStringRef viewname, SOSViewResultCode *retval,
534 SecKeyRef signingKey, CFErrorRef* error) {
535 SOSPeerInfoRef pi = SOSPeerInfoCreateCopy(allocator, toCopy, error);
536 if(action == kSOSCCViewEnable) {
537 *retval = SOSViewsEnable(pi, viewname, error);
538 require((kSOSCCViewMember == *retval), exit);
539 } else if(action == kSOSCCViewDisable) {
540 *retval = SOSViewsDisable(pi, viewname, error);
541 require((kSOSCCViewNotMember == *retval), exit);
544 require_action_quiet(SOSPeerInfoSign(signingKey, pi, error), exit, *retval = kSOSCCGeneralViewError);
553 CFStringRef sPingKey = CFSTR("Ping");
555 SOSPeerInfoRef SOSPeerInfoCopyWithPing(CFAllocatorRef allocator, SOSPeerInfoRef toCopy, SecKeyRef signingKey, CFErrorRef* error) {
556 SOSPeerInfoRef pi = SOSPeerInfoCreateCopy(allocator, toCopy, error);
557 CFDataRef ping = CFDataCreateWithRandomBytes(8);
558 SOSPeerInfoV2DictionarySetValue(pi, sPingKey, ping);
559 SecKeyRef pub_key = SOSPeerInfoCopyPubKey(pi, error);
560 require_quiet(pub_key, exit);
561 pi->peerID = SOSCopyIDOfKey(pub_key, error);
562 require_quiet(pi->peerID, exit);
563 require_action_quiet(SOSPeerInfoSign(signingKey, pi, error), exit, CFReleaseNull(pi));
566 CFReleaseNull(pub_key);
571 SOSViewResultCode SOSPeerInfoViewStatus(SOSPeerInfoRef pi, CFStringRef view, CFErrorRef *error) {
572 return SOSViewsQuery(pi, view, error);
576 SOSPeerInfoRef SOSPeerInfoCopyWithSecurityPropertyChange(CFAllocatorRef allocator, SOSPeerInfoRef toCopy,
577 SOSSecurityPropertyActionCode action, CFStringRef property, SOSSecurityPropertyResultCode *retval,
578 SecKeyRef signingKey, CFErrorRef* error) {
579 SOSPeerInfoRef pi = SOSPeerInfoCreateCopy(allocator, toCopy, error);
580 if(action == kSOSCCSecurityPropertyEnable) {
581 *retval = SOSSecurityPropertyEnable(pi, property, error);
582 require((kSOSCCSecurityPropertyValid == *retval), exit);
583 } else if(action == kSOSCCSecurityPropertyDisable) {
584 *retval = SOSSecurityPropertyDisable(pi, property, error);
585 require((kSOSCCSecurityPropertyNotValid == *retval), exit);
588 require_action_quiet(SOSPeerInfoSign(signingKey, pi, error), exit, *retval = kSOSCCGeneralViewError);
596 SOSViewResultCode SOSPeerInfoSecurityPropertyStatus(SOSPeerInfoRef pi, CFStringRef property, CFErrorRef *error) {
597 return SOSSecurityPropertyQuery(pi, property, error);
602 static void SOSPeerInfoDestroy(CFTypeRef aObj) {
603 SOSPeerInfoRef pi = (SOSPeerInfoRef) aObj;
606 CFReleaseNull(pi->description);
607 CFReleaseNull(pi->signature);
608 CFReleaseNull(pi->gestalt);
609 CFReleaseNull(pi->peerID);
610 CFReleaseNull(pi->v2Dictionary);
613 static Boolean SOSPeerInfoCompare(CFTypeRef lhs, CFTypeRef rhs) {
614 SOSPeerInfoRef lpeer = (SOSPeerInfoRef) lhs;
615 SOSPeerInfoRef rpeer = (SOSPeerInfoRef) rhs;
616 if(!lpeer || !rpeer) return false;
617 return CFEqualSafe(lpeer->description, rpeer->description) && CFEqualSafe(lpeer->signature, rpeer->signature);
621 CFComparisonResult SOSPeerInfoCompareByID(const void *val1, const void *val2, void *context) {
622 // The code below is necessary but not sufficient; not returning a CFComparisonResult
623 // It probably is OK to say that a NULL is < <non-NULL>
624 if (val1 == NULL || val2 == NULL) {
625 ptrdiff_t dv = val1 - val2;
626 return dv < 0 ? kCFCompareLessThan : dv == 0 ? kCFCompareEqualTo : kCFCompareGreaterThan;
629 CFStringRef v1 = SOSPeerInfoGetPeerID((SOSPeerInfoRef) val1);
630 CFStringRef v2 = SOSPeerInfoGetPeerID((SOSPeerInfoRef) val2);
631 if (v1 == NULL || v2 == NULL) {
632 ptrdiff_t dv = (const void *)v1 - (const void *)v2;
633 return dv < 0 ? kCFCompareLessThan : dv == 0 ? kCFCompareEqualTo : kCFCompareGreaterThan;
636 return CFStringCompare(v1, v2, 0);
639 static CFHashCode SOSPeerInfoHash(CFTypeRef cf) {
640 SOSPeerInfoRef peer = (SOSPeerInfoRef) cf;
642 return CFHash(peer->description) ^ CFHash(peer->signature);
646 static char boolToChars(bool val, char truechar, char falsechar) {
647 return val? truechar: falsechar;
650 static CFStringRef isKnown(CFStringRef ref) {
651 return ref? ref: CFSTR("Unknown ");
654 static CFStringRef copyDescriptionWithFormatOptions(CFTypeRef aObj, CFDictionaryRef formatOptions){
656 SOSPeerInfoRef pi = (SOSPeerInfoRef) aObj;
659 CFStringRef description = NULL;
660 // Get the format options we care about:
661 bool retired = SOSPeerInfoIsRetirementTicket(pi);
662 bool selfValid = SOSPeerInfoVerify(pi, NULL);
663 bool backingUp = SOSPeerInfoHasBackupKey(pi);
664 bool isKVS = SOSPeerInfoKVSOnly(pi);
665 CFStringRef osVersion = CFDictionaryGetValue(pi->gestalt, kPIOSVersionKey);
666 CFStringRef tmp = SOSPeerInfoV2DictionaryCopyString(pi, sDeviceID);
667 CFStringRef deviceID = CFStringCreateTruncatedCopy(tmp, 8);
669 CFStringRef serialNum = SOSPeerInfoCopySerialNumber(pi);
670 CFStringRef peerID = CFStringCreateTruncatedCopy(SOSPeerInfoGetPeerID(pi), 8);
672 // Calculate the truncated length
674 CFStringRef objectPrefix = CFStringCreateWithFormat(kCFAllocatorDefault, formatOptions, CFSTR("PI@%p"), pi);
676 description = CFStringCreateWithFormat(kCFAllocatorDefault, formatOptions,
677 CFSTR("<%@: [name: %20@] [%c%c%c%c%c%c%c] [type: %-20@] [spid: %8@] [os: %10@] [devid: %10@] [serial: %12@]"),
679 isKnown(SOSPeerInfoGetPeerName(pi)),
682 boolToChars(selfValid, 'S', 's'),
683 boolToChars(retired, 'R', 'r'),
684 boolToChars(backingUp, 'B', 'b'),
685 boolToChars(isKVS, 'K', 'I'),
687 isKnown(SOSPeerInfoGetPeerDeviceType(pi)), isKnown(peerID),
688 isKnown(osVersion), isKnown(deviceID), isKnown(serialNum));
691 CFReleaseNull(peerID);
692 CFReleaseNull(deviceID);
693 CFReleaseNull(serialNum);
694 CFReleaseNull(objectPrefix);
699 static CFStringRef SOSPeerInfoCopyFormatDescription(CFTypeRef aObj, CFDictionaryRef formatOptions) {
701 CFStringRef description = NULL;
703 description = copyDescriptionWithFormatOptions(aObj, formatOptions);
708 void SOSPeerInfoLogState(char *category, SOSPeerInfoRef pi, SecKeyRef pubKey, CFStringRef myPID, char sigchr) {
710 bool appValid = SOSPeerInfoApplicationVerify(pi, pubKey, NULL);
711 bool retired = SOSPeerInfoIsRetirementTicket(pi);
712 bool selfValid = SOSPeerInfoVerify(pi, NULL);
713 bool backingUp = SOSPeerInfoHasBackupKey(pi);
714 bool isMe = CFEqualSafe(SOSPeerInfoGetPeerID(pi), myPID) == true;
715 bool isKVS = SOSPeerInfoKVSOnly(pi);
716 CFStringRef osVersion = CFDictionaryGetValue(pi->gestalt, kPIOSVersionKey);
717 CFStringRef tmp = SOSPeerInfoV2DictionaryCopyString(pi, sDeviceID);
718 CFStringRef deviceID = CFStringCreateTruncatedCopy(tmp, 8);
720 CFStringRef serialNum = SOSPeerInfoCopySerialNumber(pi);
721 CFStringRef peerID = CFStringCreateTruncatedCopy(SOSPeerInfoGetPeerID(pi), 8);
723 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)),
724 boolToChars(isMe, 'M', 'm'),
725 boolToChars(appValid, 'A', 'a'),
726 boolToChars(selfValid, 'S', 's'),
727 boolToChars(retired, 'R', 'r'),
728 boolToChars(backingUp, 'B', 'b'),
729 boolToChars(isKVS, 'K', 'I'),
731 isKnown(SOSPeerInfoGetPeerDeviceType(pi)), isKnown(peerID),
732 isKnown(osVersion), isKnown(deviceID), isKnown(serialNum));
734 CFReleaseNull(peerID);
735 CFReleaseNull(deviceID);
736 CFReleaseNull(serialNum);
739 CFDictionaryRef SOSPeerInfoCopyPeerGestalt(SOSPeerInfoRef pi) {
740 CFRetain(pi->gestalt);
744 CFDictionaryRef SOSPeerGetGestalt(SOSPeerInfoRef pi){
748 CFStringRef SOSPeerInfoGetPeerName(SOSPeerInfoRef peer) {
749 return SOSPeerInfoLookupGestaltValue(peer, kPIUserDefinedDeviceNameKey);
752 CFStringRef SOSPeerInfoGetPeerDeviceType(SOSPeerInfoRef peer) {
753 return SOSPeerInfoLookupGestaltValue(peer, kPIDeviceModelNameKey);
756 CFIndex SOSPeerInfoGetPeerProtocolVersion(SOSPeerInfoRef peer) {
757 CFIndex version = PEERINFO_CURRENT_VERSION;
758 CFTypeRef val = SOSPeerInfoLookupGestaltValue(peer, kPIMessageProtocolVersionKey);
759 if (val && CFGetTypeID(val) == CFNumberGetTypeID())
760 CFNumberGetValue(val, kCFNumberCFIndexType, &version);
764 CFTypeRef SOSPeerInfoLookupGestaltValue(SOSPeerInfoRef pi, CFStringRef key) {
765 return CFDictionaryGetValue(pi->gestalt, key);
768 CFStringRef SOSPeerInfoGetPeerID(SOSPeerInfoRef pi) {
769 return pi ? pi->peerID : NULL;
772 bool SOSPeerInfoPeerIDEqual(SOSPeerInfoRef pi, CFStringRef myPeerID) {
773 return CFEqualSafe(myPeerID, SOSPeerInfoGetPeerID(pi));
776 CFIndex SOSPeerInfoGetVersion(SOSPeerInfoRef pi) {
780 bool SOSPeerInfoUpdateDigestWithPublicKeyBytes(SOSPeerInfoRef peer, const struct ccdigest_info *di,
781 ccdigest_ctx_t ctx, CFErrorRef *error) {
782 CFDataRef pubKeyBytes = CFDictionaryGetValue(peer->description, sPublicKeyKey);
785 SOSCreateErrorWithFormat(kSOSErrorEncodeFailure, NULL, error, NULL, CFSTR("Digest failed – no public key"));
789 ccdigest_update(di, ctx, CFDataGetLength(pubKeyBytes), CFDataGetBytePtr(pubKeyBytes));
794 bool SOSPeerInfoUpdateDigestWithDescription(SOSPeerInfoRef peer, const struct ccdigest_info *di,
795 ccdigest_ctx_t ctx, CFErrorRef *error) {
796 if(SOSPeerInfoVersionHasV2Data(peer)) SOSPeerInfoPackV2Data(peer);
797 size_t description_size = der_sizeof_plist(peer->description, error);
798 if (description_size == 0) {
799 SOSCreateErrorWithFormat(kSOSErrorEncodeFailure, NULL, error, NULL, CFSTR("Description length failed"));
803 uint8_t * data = malloc(description_size);
805 SOSCreateErrorWithFormat(kSOSErrorEncodeFailure, NULL, error, NULL, CFSTR("Description alloc failed"));
808 uint8_t *data_end = data + description_size;
809 uint8_t *encoded = der_encode_plist(peer->description, error, data, data_end);
813 SOSCreateErrorWithFormat(kSOSErrorEncodeFailure, NULL, error, NULL, CFSTR("Description encode failed"));
817 ccdigest_update(di, ctx, description_size, data);
825 static CFDataRef sosCreateDate() {
826 CFDateRef now = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent());
827 size_t bufsiz = der_sizeof_date(now, NULL);
829 der_encode_date(now, NULL, buf, buf+bufsiz);
831 return CFDataCreate(NULL, buf, bufsiz);
834 static CFDateRef sosCreateCFDate(CFDataRef sosdate) {
836 der_decode_date(NULL, 0, &date, NULL, CFDataGetBytePtr(sosdate),
837 CFDataGetBytePtr(sosdate) + CFDataGetLength(sosdate));
841 static bool sospeer_application_hash(SOSPeerInfoRef pi, const struct ccdigest_info *di, uint8_t *hbuf) {
842 CFDataRef appdate = asData(CFDictionaryGetValue(pi->description, sApplicationDate), NULL);
843 if(!appdate) return false;
844 ccdigest_di_decl(di, ctx);
845 ccdigest_init(di, ctx);
846 ccdigest_update(di, ctx, CFDataGetLength(appdate), CFDataGetBytePtr(appdate));
847 if (!SOSPeerInfoUpdateDigestWithPublicKeyBytes(pi, di, ctx, NULL)) return false;
848 ccdigest_final(di, ctx, hbuf);
852 SOSPeerInfoRef SOSPeerInfoCopyAsApplication(SOSPeerInfoRef original, SecKeyRef userkey, SecKeyRef peerkey, CFErrorRef *error) {
853 SOSPeerInfoRef result = NULL;
854 SOSPeerInfoRef pi = SOSPeerInfoCreateCopy(kCFAllocatorDefault, original, error);
856 const struct ccdigest_info *di = ccsha256_di();
857 uint8_t hbuf[di->output_size];
858 CFDataRef usersig = NULL;
860 CFDataRef creationDate = sosCreateDate();
861 CFDictionarySetValue(pi->description, sApplicationDate, creationDate);
862 CFReleaseNull(creationDate);
864 // Create User Application Signature
865 require_action_quiet(sospeer_application_hash(pi, di, hbuf), fail,
866 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Failed to create hash for peer applicant"), NULL, error));
868 usersig = sosCopySignedHash(userkey, di, hbuf);
869 require_action_quiet(usersig, fail,
870 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Failed to sign public key hash for peer"), NULL, error));
872 CFDictionarySetValue(pi->description, sApplicationUsig, usersig);
874 require_quiet(SOSPeerInfoSign(peerkey, pi, error), fail);
880 CFReleaseNull(usersig);
885 bool SOSPeerInfoApplicationVerify(SOSPeerInfoRef pi, SecKeyRef userkey, CFErrorRef *error) {
886 const struct ccdigest_info *di = ccsha256_di();
887 uint8_t hbuf[di->output_size];
890 CFDataRef usig = CFDictionaryGetValue(pi->description, sApplicationUsig);
891 require_action_quiet(usig, exit,
892 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Peer is not an applicant"), NULL, error));
893 // Verify User Application Signature
894 require_action_quiet(sospeer_application_hash(pi, di, hbuf), exit,
895 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Failed to create hash for peer applicant"), NULL, error));
896 require_action_quiet(sosVerifyHash(userkey, di, hbuf, usig), exit,
897 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("user signature of public key hash fails to verify"), NULL, error));
899 result = SOSPeerInfoVerify(pi, error);
906 static CF_RETURNS_RETAINED CFDateRef sosPeerInfoGetDate(SOSPeerInfoRef pi, CFStringRef entry) {
908 CFDataRef sosdate = CFDictionaryGetValue(pi->description, entry);
909 if(!sosdate) return NULL;
910 CFDateRef date = sosCreateCFDate(sosdate);
915 CF_RETURNS_RETAINED CFDateRef SOSPeerInfoGetApplicationDate(SOSPeerInfoRef pi) {
916 return sosPeerInfoGetDate(pi, sApplicationDate);
919 CF_RETURNS_RETAINED CFDateRef SOSPeerInfoGetRetirementDate(SOSPeerInfoRef pi) {
920 return sosPeerInfoGetDate(pi, sRetirementDate);
929 CFStringRef SOSPeerGestaltGetName(CFDictionaryRef gestalt) {
930 CFStringRef name = SOSPeerGestaltGetAnswer(gestalt, kPIUserDefinedDeviceNameKey);
931 return isString(name) ? name : NULL;
934 CFTypeRef SOSPeerGestaltGetAnswer(CFDictionaryRef gestalt, CFStringRef question) {
935 return gestalt ? CFDictionaryGetValue(gestalt, question) : NULL;
943 SOSPeerInfoRef SOSPeerInfoCreateRetirementTicket(CFAllocatorRef allocator, SecKeyRef privKey, SOSPeerInfoRef peer, CFErrorRef *error) {
945 SOSPeerInfoRef pi = SOSPeerInfoCreateCopy(allocator, peer, error);
949 // Fill out Resignation Date
950 CFDataRef resignationDate = sosCreateDate();
951 CFDictionaryAddValue(pi->description, sRetirementDate, resignationDate);
952 CFReleaseNull(resignationDate);
954 require(SOSPeerInfoSign(privKey, pi, error), fail);
963 CFStringRef SOSPeerInfoInspectRetirementTicket(SOSPeerInfoRef pi, CFErrorRef *error) {
964 CFStringRef retval = NULL;
965 CFDateRef now = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent());
966 CFDateRef retirement = NULL;
968 require_quiet(SOSPeerInfoVerify(pi, error), err);
970 retirement = sosCreateCFDate(CFDictionaryGetValue(pi->description, sRetirementDate));
971 require_action_quiet(retirement, err,
972 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Peer is not retired"), NULL, error));
974 require_action_quiet(CFDateCompare(now, retirement, NULL) == kCFCompareGreaterThan, err,
975 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Retirement date is after current date"), NULL, error));
977 retval = SOSPeerInfoGetPeerID(pi);
981 CFReleaseNull(retirement);
985 bool SOSPeerInfoRetireRetirementTicket(size_t max_seconds, SOSPeerInfoRef pi) {
986 CFDateRef now = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent());
987 CFDateRef retirement = sosCreateCFDate(CFDictionaryGetValue(pi->description, sRetirementDate));
988 CFTimeInterval timediff = CFDateGetTimeIntervalSinceDate(now, retirement); // diff in seconds
990 CFReleaseNull(retirement);
991 if(timediff > (max_seconds)) return true;
995 bool SOSPeerInfoIsRetirementTicket(SOSPeerInfoRef pi) {
996 CFDataRef flag = CFDictionaryGetValue(pi->description, sRetirementDate);
1000 bool SOSPeerInfoIsCloudIdentity(SOSPeerInfoRef pi) {
1001 CFTypeRef value = CFDictionaryGetValue(pi->description, sCloudIdentityKey);
1002 return CFEqualSafe(value, kCFBooleanTrue);
1005 SOSPeerInfoRef SOSPeerInfoUpgradeSignatures(CFAllocatorRef allocator, SecKeyRef privKey, SecKeyRef peerKey, SOSPeerInfoRef peer, CFErrorRef *error) {
1006 SecKeyRef pubKey = SecKeyCreatePublicFromPrivate(privKey);
1007 SOSPeerInfoRef retval = NULL;
1009 retval = SOSPeerInfoCopyAsApplication(peer, privKey, peerKey, error);
1010 CFReleaseNull(pubKey);
1014 CFBooleanRef SOSPeerInfoCopyIDSPreference(SOSPeerInfoRef peer){
1015 CFBooleanRef preference = (CFBooleanRef)SOSPeerInfoV2DictionaryCopyBoolean(peer, sPreferIDS);
1016 return (preference ? preference : CFRetain(kCFBooleanFalse));
1020 SOSPeerInfoRef SOSPeerInfoSetIDSPreference(CFAllocatorRef allocator, SOSPeerInfoRef toCopy, CFBooleanRef preference, SecKeyRef signingKey, CFErrorRef *error){
1021 return SOSPeerInfoCopyWithModification(allocator, toCopy, signingKey, error,
1022 ^bool(SOSPeerInfoRef peerToModify, CFErrorRef *error) {
1023 SOSPeerInfoV2DictionarySetValue(peerToModify, sPreferIDS, preference);
1028 CFBooleanRef SOSPeerInfoCopyIDSFragmentationPreference(SOSPeerInfoRef peer){
1029 CFBooleanRef preference = (CFBooleanRef)SOSPeerInfoV2DictionaryCopyBoolean(peer, sPreferIDSFragmentation);
1030 return (preference ? preference : CFRetain(kCFBooleanFalse));
1033 CFBooleanRef SOSPeerInfoCopyIDSACKModelPreference(SOSPeerInfoRef peer){
1034 CFBooleanRef preference = (CFBooleanRef)SOSPeerInfoV2DictionaryCopyBoolean(peer, sPreferIDSACKModel);
1035 return (preference ? preference : CFRetain(kCFBooleanFalse));
1038 SOSPeerInfoRef CF_RETURNS_RETAINED SOSPeerInfoSetIDSFragmentationPreference(CFAllocatorRef allocator, SOSPeerInfoRef toCopy, CFBooleanRef preference, SecKeyRef signingKey, CFErrorRef *error){
1039 return SOSPeerInfoCopyWithModification(allocator, toCopy, signingKey, error,
1040 ^bool(SOSPeerInfoRef peerToModify, CFErrorRef *error) {
1041 SOSPeerInfoV2DictionarySetValue(peerToModify, sPreferIDSFragmentation, preference);
1046 SOSPeerInfoRef CF_RETURNS_RETAINED SOSPeerInfoSetIDSACKModelPreference(CFAllocatorRef allocator, SOSPeerInfoRef toCopy, CFBooleanRef preference, SecKeyRef signingKey, CFErrorRef *error){
1047 return SOSPeerInfoCopyWithModification(allocator, toCopy, signingKey, error,
1048 ^bool(SOSPeerInfoRef peerToModify, CFErrorRef *error) {
1049 SOSPeerInfoV2DictionarySetValue(peerToModify, sPreferIDSACKModel, preference);
1054 static SOSPeerInfoRef CF_RETURNS_RETAINED
1055 SOSPeerInfoSetOctagonKey(CFAllocatorRef allocator,
1056 SOSPeerInfoRef toCopy,
1057 CFStringRef descriptionKey,
1058 SecKeyRef octagonKey,
1059 SecKeyRef signingKey,
1062 CFDataRef publicKeyBytes = NULL;
1063 SOSPeerInfoRef pi = NULL;
1065 OSStatus copyResult = SecKeyCopyPublicBytes(octagonKey, &publicKeyBytes);
1066 require_action_quiet(0 == copyResult, fail, SecError(copyResult, error, CFSTR("failed to copy public key bytes")));
1068 pi = SOSPeerInfoCopyWithModification(allocator, toCopy, signingKey, error,
1069 ^bool(SOSPeerInfoRef peerToModify, CFErrorRef *error) {
1070 if(peerToModify && peerToModify->description && publicKeyBytes && descriptionKey) {
1071 CFDictionarySetValue(peerToModify->description, descriptionKey, publicKeyBytes);
1073 SecError(errSecParam, error, CFSTR("Bad key bytes or dictionary key"));
1080 CFReleaseNull(publicKeyBytes);
1084 SOSPeerInfoRef CF_RETURNS_RETAINED
1085 SOSPeerInfoSetOctagonSigningKey(CFAllocatorRef allocator,
1086 SOSPeerInfoRef toCopy,
1087 SecKeyRef octagonSigningKey,
1088 SecKeyRef signingKey,
1091 return SOSPeerInfoSetOctagonKey(allocator, toCopy, sOctagonPeerSigningPublicKeyKey, octagonSigningKey, signingKey, error);
1094 SOSPeerInfoRef CF_RETURNS_RETAINED
1095 SOSPeerInfoSetOctagonEncryptionKey(CFAllocatorRef allocator,
1096 SOSPeerInfoRef toCopy,
1097 SecKeyRef octagonEncryptionKey,
1098 SecKeyRef signingKey,
1101 return SOSPeerInfoSetOctagonKey(allocator, toCopy, sOctagonPeerEncryptionPublicKeyKey, octagonEncryptionKey, signingKey, error);
1104 bool SOSPeerInfoTransportTypeIs(SOSPeerInfoRef pi, CFStringRef transportType) {
1105 return SOSPeerInfoV2DictionaryHasStringValue(pi, sTransportType, transportType);
1108 CFStringRef SOSPeerInfoCopyTransportType(SOSPeerInfoRef peer){
1109 CFStringRef transportType = (CFStringRef)SOSPeerInfoV2DictionaryCopyString(peer, sTransportType);
1110 return (transportType ? transportType : CFRetain(SOSTransportMessageTypeKVS));
1113 SOSPeerInfoRef SOSPeerInfoSetTransportType(CFAllocatorRef allocator, SOSPeerInfoRef toCopy, CFStringRef transportType, SecKeyRef signingKey, CFErrorRef *error){
1115 return SOSPeerInfoCopyWithModification(allocator, toCopy, signingKey, error,
1116 ^bool(SOSPeerInfoRef peerToModify, CFErrorRef *error) {
1117 SOSPeerInfoV2DictionarySetValue(peerToModify, sTransportType, transportType);
1122 bool SOSPeerInfoKVSOnly(SOSPeerInfoRef pi) {
1123 CFStringRef transportType = SOSPeerInfoCopyTransportType(pi);
1124 bool retval = CFEqualSafe(transportType, SOSTransportMessageTypeKVS);
1125 CFReleaseNull(transportType);
1129 bool SOSPeerInfoHasDeviceID(SOSPeerInfoRef peer) {
1130 return SOSPeerInfoV2DictionaryHasString(peer, sDeviceID);
1133 CFStringRef SOSPeerInfoCopyDeviceID(SOSPeerInfoRef peer){
1134 return (CFStringRef)SOSPeerInfoV2DictionaryCopyString(peer, sDeviceID);
1137 SOSPeerInfoRef SOSPeerInfoSetDeviceID(CFAllocatorRef allocator, SOSPeerInfoRef toCopy, CFStringRef IDS, SecKeyRef signingKey, CFErrorRef *error){
1139 return SOSPeerInfoCopyWithModification(allocator, toCopy, signingKey, error,
1140 ^bool(SOSPeerInfoRef peerToModify, CFErrorRef *error) {
1141 SOSPeerInfoV2DictionarySetValue(peerToModify, sDeviceID, IDS);
1146 bool SOSPeerInfoShouldUseIDSTransport(SOSPeerInfoRef myPeer, SOSPeerInfoRef theirPeer){
1147 return SOSPeerInfoHasDeviceID(myPeer) && SOSPeerInfoTransportTypeIs(myPeer, SOSTransportMessageTypeIDSV2) &&
1148 SOSPeerInfoHasDeviceID(theirPeer) && SOSPeerInfoTransportTypeIs(theirPeer, SOSTransportMessageTypeIDSV2);
1151 bool SOSPeerInfoShouldUseIDSMessageFragmentation(SOSPeerInfoRef myPeer, SOSPeerInfoRef theirPeer){
1153 bool success = false;
1155 CFBooleanRef myPreference = SOSPeerInfoCopyIDSFragmentationPreference(myPeer);
1157 CFBooleanRef theirPreference = SOSPeerInfoCopyIDSFragmentationPreference(theirPeer);
1158 secnotice("IDS Transport", "mypreference: %@, theirpreference: %@", myPreference, theirPreference);
1159 if((myPreference == kCFBooleanTrue && theirPreference == kCFBooleanTrue))
1162 CFReleaseNull(myPreference);
1163 CFReleaseNull(theirPreference);
1167 bool SOSPeerInfoShouldUseACKModel(SOSPeerInfoRef myPeer, SOSPeerInfoRef theirPeer){
1168 bool success = false;
1170 CFBooleanRef myPreference = SOSPeerInfoCopyIDSACKModelPreference(myPeer);
1172 CFBooleanRef theirPreference = SOSPeerInfoCopyIDSACKModelPreference(theirPeer);
1173 secnotice("IDS Transport", "mypreference: %@, theirpreference: %@", myPreference, theirPreference);
1174 if((myPreference == kCFBooleanTrue && theirPreference == kCFBooleanTrue))
1177 CFReleaseNull(myPreference);
1178 CFReleaseNull(theirPreference);
1183 SOSPeerInfoDeviceClass SOSPeerInfoGetClass(SOSPeerInfoRef pi) {
1184 static CFDictionaryRef devID2Class = NULL;
1185 static dispatch_once_t onceToken = 0;
1187 dispatch_once(&onceToken, ^{
1188 CFNumberRef cfSOSPeerInfo_macOS = CFNumberCreateWithCFIndex(kCFAllocatorDefault, SOSPeerInfo_macOS);
1189 CFNumberRef cfSOSPeerInfo_iOS = CFNumberCreateWithCFIndex(kCFAllocatorDefault, SOSPeerInfo_iOS);
1190 CFNumberRef cfSOSPeerInfo_iCloud = CFNumberCreateWithCFIndex(kCFAllocatorDefault, SOSPeerInfo_iCloud);
1191 // CFNumberRef cfSOSPeerInfo_watchOS = CFNumberCreateWithCFIndex(kCFAllocatorDefault, SOSPeerInfo_watchOS);
1192 // CFNumberRef cfSOSPeerInfo_tvOS = CFNumberCreateWithCFIndex(kCFAllocatorDefault, SOSPeerInfo_tvOS);
1194 devID2Class = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
1195 CFSTR("Mac Pro"), cfSOSPeerInfo_macOS,
1196 CFSTR("MacBook"), cfSOSPeerInfo_macOS,
1197 CFSTR("MacBook Pro"), cfSOSPeerInfo_macOS,
1198 CFSTR("iCloud"), cfSOSPeerInfo_iCloud,
1199 CFSTR("iMac"), cfSOSPeerInfo_macOS,
1200 CFSTR("iPad"), cfSOSPeerInfo_iOS,
1201 CFSTR("iPhone"), cfSOSPeerInfo_iOS,
1202 CFSTR("iPod touch"), cfSOSPeerInfo_iOS,
1204 CFReleaseNull(cfSOSPeerInfo_macOS);
1205 CFReleaseNull(cfSOSPeerInfo_iOS);
1206 CFReleaseNull(cfSOSPeerInfo_iCloud);
1208 SOSPeerInfoDeviceClass retval = SOSPeerInfo_unknown;
1209 CFStringRef dt = SOSPeerInfoGetPeerDeviceType(pi);
1210 require_quiet(dt, errOut);
1211 CFNumberRef classNum = CFDictionaryGetValue(devID2Class, dt);
1212 require_quiet(classNum, errOut);
1214 require_quiet(CFNumberGetValue(classNum, kCFNumberCFIndexType, &tmp), errOut);
1215 retval = (SOSPeerInfoDeviceClass) tmp;
1220 bool SOSPeerInfoHasOctagonSigningPubKey(SOSPeerInfoRef peer){
1221 bool hasKey = false;
1222 SecKeyRef pubKey = SOSPeerInfoCopyOctagonSigningPublicKey(peer, NULL);
1225 CFReleaseNull(pubKey);
1229 bool SOSPeerInfoHasOctagonEncryptionPubKey(SOSPeerInfoRef peer){
1230 bool hasKey = false;
1231 SecKeyRef pubKey = SOSPeerInfoCopyOctagonEncryptionPublicKey(peer, NULL);
1234 CFReleaseNull(pubKey);