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 "keychain/SecureObjectSync/SOSPeerInfoInternal.h"
30 #include "keychain/SecureObjectSync/SOSPeerInfoPriv.h"
31 #include "keychain/SecureObjectSync/SOSPeerInfoV2.h"
32 #include "keychain/SecureObjectSync/SOSCircle.h"
33 #include "keychain/SecureObjectSync/SOSInternal.h"
34 #include <ipc/securityd_client.h>
36 #include <CoreFoundation/CFArray.h>
37 #include <dispatch/dispatch.h>
41 #include <utilities/SecCFWrappers.h>
42 #include <utilities/SecCFRelease.h>
43 #include <utilities/SecCFError.h>
44 #include <utilities/SecXPCError.h>
46 #include <utilities/der_plist.h>
47 #include <utilities/der_plist_internal.h>
48 #include <corecrypto/ccder.h>
49 #include <utilities/der_date.h>
51 #include <corecrypto/ccdigest.h>
52 #include <corecrypto/ccsha2.h>
55 #include <CoreFoundation/CoreFoundation.h>
56 #include <CoreFoundation/CFDate.h>
61 #include <MobileGestalt.h>
64 #include <Security/SecBase64.h>
65 #include <Security/SecKeyPriv.h>
66 #include <Security/SecOTR.h>
67 #include <Security/SecuritydXPC.h>
69 CFGiblisWithHashFor(SOSPeerInfo);
72 const CFStringRef kPIUserDefinedDeviceNameKey = CFSTR("ComputerName");
73 const CFStringRef kPIDeviceModelNameKey = CFSTR("ModelName");
74 const CFStringRef kPIMessageProtocolVersionKey = CFSTR("MessageProtocolVersion");
75 const CFStringRef kPIOSVersionKey = CFSTR("OSVersion");
77 // Description Dictionary Entries
78 static CFStringRef sPublicKeyKey = CFSTR("PublicSigningKey");
79 static CFStringRef sOctagonPeerSigningPublicKeyKey = CFSTR("OctagonPublicSigningKey");
80 static CFStringRef sOctagonPeerEncryptionPublicKeyKey = CFSTR("OctagonPublicEncryptionKey");
81 const CFStringRef sGestaltKey = CFSTR("DeviceGestalt");
82 const CFStringRef sVersionKey = CFSTR("ConflictVersion");
83 static CFStringRef sCloudIdentityKey = CFSTR("CloudIdentity");
84 static CFStringRef sApplicationDate = CFSTR("ApplicationDate");
85 static CFStringRef sApplicationUsig = CFSTR("ApplicationUsig");
86 static CFStringRef sRetirementDate = CFSTR("RetirementDate");
89 CFStringRef kSOSPeerInfoDescriptionKey = CFSTR("SOSPeerInfoDescription");
90 CFStringRef kSOSPeerInfoSignatureKey = CFSTR("SOSPeerInfoSignature");
91 CFStringRef kSOSPeerInfoNameKey = CFSTR("SOSPeerInfoName");
93 //Peer Info V2 Dictionary IDS keys
94 CFStringRef sPreferIDS = CFSTR("PreferIDS");
95 CFStringRef sPreferIDSFragmentation = CFSTR("PreferIDFragmentation");
96 CFStringRef sPreferIDSACKModel = CFSTR("PreferIDSAckModel");
97 CFStringRef sTransportType = CFSTR("TransportType");
98 CFStringRef sDeviceID = CFSTR("DeviceID");
100 CFStringRef sCKKSForAll = CFSTR("CKKS4A");
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) {
162 size_t siglen = SIGLEN;
164 if(SecKeyRawSign(privkey, kSecPaddingNone, hbuf, di->output_size, sig, &siglen) != 0) {
167 return CFDataCreate(NULL, sig, (CFIndex)siglen);
170 static bool sosVerifyHash(SecKeyRef pubkey, const struct ccdigest_info *di, uint8_t *hbuf, CFDataRef signature) {
171 return SecKeyRawVerify(pubkey, kSecPaddingNone, hbuf, di->output_size,
172 CFDataGetBytePtr(signature), CFDataGetLength(signature)) == errSecSuccess;
175 bool SOSPeerInfoSign(SecKeyRef privKey, SOSPeerInfoRef peer, CFErrorRef *error) {
177 const struct ccdigest_info *di = ccsha256_di();
178 uint8_t hbuf[di->output_size];
179 CFDataRef newSignature = NULL;
181 require_action_quiet(SOSDescriptionHash(peer, di, hbuf, error), fail,
182 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Failed to hash description for peer"), NULL, error));
184 newSignature = sosCopySignedHash(privKey, di, hbuf);
185 require_action_quiet(newSignature, fail, SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Failed to sign peerinfo for peer"), NULL, error));
187 CFReleaseNull(peer->signature);
188 peer->signature = newSignature;
193 CFReleaseNull(newSignature);
197 // Return true (1) if the signature verifies.
198 bool SOSPeerInfoVerify(SOSPeerInfoRef peer, CFErrorRef *error) {
200 const struct ccdigest_info *di = ccsha256_di();
201 uint8_t hbuf[di->output_size];
203 SecKeyRef pubKey = SOSPeerInfoCopyPubKey(peer, error);
204 require_quiet(pubKey, error_out);
206 require_quiet(SOSDescriptionHash(peer, di, hbuf, error), error_out);
208 require_action_quiet(sosVerifyHash(pubKey, di, hbuf, peer->signature), error_out,
209 SOSErrorCreate(kSOSErrorBadSignature, error, NULL,
210 CFSTR("Signature didn't verify for %@"), peer));
214 CFReleaseNull(pubKey);
218 void SOSPeerInfoSetVersionNumber(SOSPeerInfoRef pi, int version) {
219 pi->version = version;
220 CFNumberRef versionNumber = CFNumberCreateWithCFIndex(NULL, pi->version);
221 CFDictionarySetValue(pi->description, sVersionKey, versionNumber);
222 CFReleaseNull(versionNumber);
225 static SOSPeerInfoRef SOSPeerInfoCreate_Internal(CFAllocatorRef allocator,
226 CFDictionaryRef gestalt, CFDataRef backup_key,
227 CFStringRef IDSID, CFStringRef transportType, CFBooleanRef preferIDS,
228 CFBooleanRef preferFragmentation, CFBooleanRef preferAckModel,
229 CFSetRef enabledViews,
230 SecKeyRef signingKey,
231 SecKeyRef octagonPeerSigningKey,
232 SecKeyRef octagonPeerEncryptionKey,
233 bool supportsCKKS4All,
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);
262 if (octagonPeerSigningKey) {
263 SecKeyRef octagonPeerSigningPublicKey = SecKeyCreatePublicFromPrivate(octagonPeerSigningKey);
264 if (octagonPeerSigningPublicKey == NULL) {
265 SOSCreateError(kSOSErrorBadKey, CFSTR("Unable to get public key"), NULL, error);
270 result = SecKeyCopyPublicBytes(octagonPeerSigningPublicKey, &octagonPeerSigningPublicBytes);
271 CFReleaseNull(octagonPeerSigningPublicKey);
272 if (result != errSecSuccess) {
273 SOSCreateError(kSOSErrorBadKey, CFSTR("Failed to export public bytes"), NULL, error);
279 if (octagonPeerEncryptionKey) {
280 SecKeyRef octagonPeerEncryptionPublicKey = SecKeyCreatePublicFromPrivate(octagonPeerEncryptionKey);
281 if (octagonPeerEncryptionPublicKey == NULL) {
282 SOSCreateError(kSOSErrorBadKey, CFSTR("Unable to get public key"), NULL, error);
287 result = SecKeyCopyPublicBytes(octagonPeerEncryptionPublicKey, &octagonPeerEncryptionPublicBytes);
288 CFReleaseNull(octagonPeerEncryptionPublicKey);
289 if (result != errSecSuccess) {
290 SOSCreateError(kSOSErrorBadKey, CFSTR("Failed to export public bytes"), NULL, error);
296 pi->signature = CFDataCreateMutable(allocator, 0);
298 versionNumber = CFNumberCreateWithCFIndex(NULL, pi->version);
300 pi->description = CFDictionaryCreateMutableForCFTypesWith(allocator,
301 sVersionKey, versionNumber,
302 sPublicKeyKey, publicBytes,
303 sGestaltKey, pi->gestalt,
305 if (octagonPeerSigningPublicBytes) {
306 CFDictionarySetValue(pi->description, sOctagonPeerSigningPublicKeyKey, octagonPeerSigningPublicBytes);
308 if (octagonPeerEncryptionPublicBytes) {
309 CFDictionarySetValue(pi->description, sOctagonPeerEncryptionPublicKeyKey, octagonPeerEncryptionPublicBytes);
313 description_modifier(pi->description);
315 pi->peerID = SOSCopyIDOfKey(publicKey, error);
316 pi->spid = CFStringCreateTruncatedCopy(pi->peerID, 8);
318 pi->verifiedAppKeyID = NULL;
319 pi->verifiedResult = false;
321 require_quiet(pi->peerID, exit);
323 // ================ V2 Additions Start
325 if(!SOSPeerInfoUpdateToV2(pi, error)) {
330 // V2DictionarySetValue handles NULL as remove
331 if (backup_key != NULL) SOSPeerInfoV2DictionarySetValue(pi, sBackupKeyKey, backup_key);
332 SOSPeerInfoV2DictionarySetValue(pi, sViewsKey, enabledViews);
334 SOSPeerInfoSetSupportsCKKSForAll(pi, supportsCKKS4All);
336 // ================ V2 Additions End
338 if (!SOSPeerInfoSign(signingKey, pi, error)) {
344 CFReleaseNull(versionNumber);
345 CFReleaseNull(publicKey);
346 CFReleaseNull(publicBytes);
347 CFReleaseNull(octagonPeerSigningPublicBytes);
348 CFReleaseNull(octagonPeerEncryptionPublicBytes);
352 SOSPeerInfoRef SOSPeerInfoCreate(CFAllocatorRef allocator, CFDictionaryRef gestalt, CFDataRef backup_key, SecKeyRef signingKey,
353 SecKeyRef octagonPeerSigningKey,
354 SecKeyRef octagonPeerEncryptionKey,
355 bool supportsCKKS4All,
357 return SOSPeerInfoCreate_Internal(allocator, gestalt, backup_key, NULL, NULL, NULL, NULL, NULL, NULL, signingKey, octagonPeerSigningKey, octagonPeerEncryptionKey,
359 error, ^(CFMutableDictionaryRef description) {});
362 SOSPeerInfoRef SOSPeerInfoCreateWithTransportAndViews(CFAllocatorRef allocator, CFDictionaryRef gestalt, CFDataRef backup_key,
363 CFStringRef IDSID, CFStringRef transportType, CFBooleanRef preferIDS,
364 CFBooleanRef preferFragmentation, CFBooleanRef preferAckModel, CFSetRef enabledViews,
365 SecKeyRef signingKey,
366 SecKeyRef octagonPeerSigningKey,
367 SecKeyRef octagonPeerEncryptionKey,
368 bool supportsCKKS4All,
371 return SOSPeerInfoCreate_Internal(allocator, gestalt, backup_key, IDSID, transportType, preferIDS, preferFragmentation, preferAckModel, enabledViews, signingKey,
372 octagonPeerSigningKey,
373 octagonPeerEncryptionKey,
375 error, ^(CFMutableDictionaryRef description) {});
379 SOSPeerInfoRef SOSPeerInfoCreateCloudIdentity(CFAllocatorRef allocator, CFDictionaryRef gestalt, SecKeyRef signingKey, CFErrorRef* error) {
380 return SOSPeerInfoCreate_Internal(allocator, gestalt, NULL, NULL, NULL, NULL, NULL, NULL, NULL, signingKey, NULL, NULL, false, error, ^(CFMutableDictionaryRef description) {
381 CFDictionarySetValue(description, sCloudIdentityKey, kCFBooleanTrue);
387 SOSPeerInfoRef SOSPeerInfoCreateCopy(CFAllocatorRef allocator, SOSPeerInfoRef toCopy, CFErrorRef* error) {
388 if(!toCopy) return NULL;
389 SOSPeerInfoRef pi = CFTypeAllocate(SOSPeerInfo, struct __OpaqueSOSPeerInfo, allocator);
391 pi->description = CFDictionaryCreateMutableCopy(allocator, 0, toCopy->description);
392 pi->signature = CFDataCreateCopy(allocator, toCopy->signature);
394 pi->gestalt = CFDictionaryCreateCopy(allocator, toCopy->gestalt);
395 pi->peerID = CFStringCreateCopy(allocator, toCopy->peerID);
396 pi->spid = CFStringCreateCopy(allocator, toCopy->spid);
397 pi->verifiedAppKeyID = NULL; // The peer resulting from this will need to be re-evaluated for an application signature.
398 pi->verifiedResult = false;
400 pi->version = toCopy->version;
401 if(!SOSPeerInfoVersionHasV2Data(pi)) SOSPeerInfoExpandV2Data(pi, error);
407 bool SOSPeerInfoVersionIsCurrent(SOSPeerInfoRef pi) {
408 return pi->version >= PEERINFO_CURRENT_VERSION;
411 bool SOSPeerInfoVersionHasV2Data(SOSPeerInfoRef pi) {
412 return pi->version >= kSOSPeerV2BaseVersion;
415 SOSPeerInfoRef SOSPeerInfoCreateCurrentCopy(CFAllocatorRef allocator, SOSPeerInfoRef toCopy,
416 CFStringRef IDSID, CFStringRef transportType, CFBooleanRef preferIDS, CFBooleanRef preferFragmentation, CFBooleanRef preferAckModel, CFSetRef enabledViews,
417 SecKeyRef signingKey, CFErrorRef* error) {
419 SOSPeerInfoRef pi = SOSPeerInfoCreateCopy(allocator, toCopy, error);
420 if(!SOSPeerInfoVersionHasV2Data(pi)) SOSPeerInfoUpdateToV2(pi, error);
423 SOSPeerInfoV2DictionarySetValue(pi, sViewsKey, enabledViews);
426 if(!SOSPeerInfoSign(signingKey, pi, error)) {
434 SOSPeerInfoRef SOSPeerInfoCopyWithModification(CFAllocatorRef allocator, SOSPeerInfoRef original,
435 SecKeyRef signingKey, CFErrorRef *error,
436 bool (^modification)(SOSPeerInfoRef peerToModify, CFErrorRef *error))
438 SOSPeerInfoRef result = NULL;
439 SOSPeerInfoRef copy = SOSPeerInfoCreateCopy(allocator, original, error);
441 require_quiet(modification(copy, error), fail);
443 require_quiet(SOSPeerInfoSign(signingKey, copy, error), fail);
445 CFTransferRetained(result, copy);
453 SOSPeerInfoRef SOSPeerInfoCopyWithGestaltUpdate(CFAllocatorRef allocator, SOSPeerInfoRef toCopy, CFDictionaryRef gestalt, SecKeyRef signingKey, CFErrorRef* error) {
454 return SOSPeerInfoCopyWithModification(allocator, toCopy, signingKey, error,
455 ^bool(SOSPeerInfoRef peerToModify, CFErrorRef *error) {
456 if(!gestalt || !peerToModify) return false;
457 CFRetainAssign(peerToModify->gestalt, gestalt);
458 CFDictionarySetValue(peerToModify->description, sGestaltKey, peerToModify->gestalt);
465 SOSPeerInfoRef SOSPeerInfoCopyWithBackupKeyUpdate(CFAllocatorRef allocator, SOSPeerInfoRef toCopy, CFDataRef backupKey, SecKeyRef signingKey, CFErrorRef *error) {
466 return SOSPeerInfoCopyWithModification(allocator, toCopy, signingKey, error,
467 ^bool(SOSPeerInfoRef peerToModify, CFErrorRef *error) {
468 if (backupKey != NULL)
469 SOSPeerInfoV2DictionarySetValue(peerToModify, sBackupKeyKey, backupKey);
471 SOSPeerInfoV2DictionaryRemoveValue(peerToModify, sBackupKeyKey);
476 SOSPeerInfoRef SOSPeerInfoCopyWithReplacedEscrowRecords(CFAllocatorRef allocator, SOSPeerInfoRef toCopy, CFDictionaryRef escrowRecords, SecKeyRef signingKey, CFErrorRef *error) {
477 return SOSPeerInfoCopyWithModification(allocator, toCopy, signingKey, error,
478 ^bool(SOSPeerInfoRef peerToModify, CFErrorRef *error) {
479 if(escrowRecords != NULL)
480 SOSPeerInfoV2DictionarySetValue(peerToModify, sEscrowRecord, escrowRecords);
486 CFDataRef SOSPeerInfoCopyBackupKey(SOSPeerInfoRef peer) {
487 return SOSPeerInfoV2DictionaryCopyData(peer, sBackupKeyKey);
490 bool SOSPeerInfoHasBackupKey(SOSPeerInfoRef peer) {
491 CFDataRef bk = SOSPeerInfoCopyBackupKey(peer);
492 bool success = bk != NULL;
497 SOSPeerInfoRef SOSPeerInfoCopyWithViewsChange(CFAllocatorRef allocator, SOSPeerInfoRef toCopy,
498 SOSViewActionCode action, CFStringRef viewname, SOSViewResultCode *retval,
499 SecKeyRef signingKey, CFErrorRef* error) {
500 SOSPeerInfoRef pi = SOSPeerInfoCreateCopy(allocator, toCopy, error);
501 if(action == kSOSCCViewEnable) {
502 *retval = SOSViewsEnable(pi, viewname, error);
503 require((kSOSCCViewMember == *retval), exit);
504 } else if(action == kSOSCCViewDisable) {
505 *retval = SOSViewsDisable(pi, viewname, error);
506 require((kSOSCCViewNotMember == *retval), exit);
509 require_action_quiet(SOSPeerInfoSign(signingKey, pi, error), exit, *retval = kSOSCCGeneralViewError);
518 CFStringRef sPingKey = CFSTR("Ping");
520 SOSPeerInfoRef SOSPeerInfoCopyWithPing(CFAllocatorRef allocator, SOSPeerInfoRef toCopy, SecKeyRef signingKey, CFErrorRef* error) {
521 SOSPeerInfoRef pi = SOSPeerInfoCreateCopy(allocator, toCopy, error);
522 CFDataRef ping = CFDataCreateWithRandomBytes(8);
523 SOSPeerInfoV2DictionarySetValue(pi, sPingKey, ping);
524 SecKeyRef pub_key = SOSPeerInfoCopyPubKey(pi, error);
525 require_quiet(pub_key, exit);
526 pi->peerID = SOSCopyIDOfKey(pub_key, error);
527 pi->spid = CFStringCreateTruncatedCopy(pi->peerID, 8);
528 require_quiet(pi->peerID, exit);
529 require_action_quiet(SOSPeerInfoSign(signingKey, pi, error), exit, CFReleaseNull(pi));
532 CFReleaseNull(pub_key);
537 SOSViewResultCode SOSPeerInfoViewStatus(SOSPeerInfoRef pi, CFStringRef view, CFErrorRef *error) {
538 return SOSViewsQuery(pi, view, error);
541 static void SOSPeerInfoDestroy(CFTypeRef aObj) {
542 SOSPeerInfoRef pi = (SOSPeerInfoRef) aObj;
545 CFReleaseNull(pi->description);
546 CFReleaseNull(pi->signature);
547 CFReleaseNull(pi->gestalt);
548 CFReleaseNull(pi->peerID);
549 CFReleaseNull(pi->spid);
550 CFReleaseNull(pi->verifiedAppKeyID);
551 CFReleaseNull(pi->v2Dictionary);
552 pi->verifiedResult = false;
555 static Boolean SOSPeerInfoCompare(CFTypeRef lhs, CFTypeRef rhs) {
556 SOSPeerInfoRef lpeer = (SOSPeerInfoRef) lhs;
557 SOSPeerInfoRef rpeer = (SOSPeerInfoRef) rhs;
558 if(!lpeer || !rpeer) return false;
559 return CFEqualSafe(lpeer->description, rpeer->description) && CFEqualSafe(lpeer->signature, rpeer->signature);
563 CFComparisonResult SOSPeerInfoCompareByID(const void *val1, const void *val2, void *context) {
564 // The code below is necessary but not sufficient; not returning a CFComparisonResult
565 // It probably is OK to say that a NULL is < <non-NULL>
566 if (val1 == NULL || val2 == NULL) {
567 ptrdiff_t dv = val1 - val2;
568 return dv < 0 ? kCFCompareLessThan : dv == 0 ? kCFCompareEqualTo : kCFCompareGreaterThan;
571 CFStringRef v1 = SOSPeerInfoGetPeerID((SOSPeerInfoRef) val1);
572 CFStringRef v2 = SOSPeerInfoGetPeerID((SOSPeerInfoRef) val2);
573 if (v1 == NULL || v2 == NULL) {
574 ptrdiff_t dv = (const void *)v1 - (const void *)v2;
575 return dv < 0 ? kCFCompareLessThan : dv == 0 ? kCFCompareEqualTo : kCFCompareGreaterThan;
578 return CFStringCompare(v1, v2, 0);
582 CFComparisonResult SOSPeerInfoCompareByApplicationDate(const void *val1, const void *val2, void *context) {
583 // The code below is necessary but not sufficient; not returning a CFComparisonResult
584 // It probably is OK to say that a NULL is < <non-NULL>
585 if (val1 == NULL || val2 == NULL) {
586 ptrdiff_t dv = val1 - val2;
587 return dv < 0 ? kCFCompareLessThan : dv == 0 ? kCFCompareEqualTo : kCFCompareGreaterThan;
590 CFDateRef v1 = SOSPeerInfoGetApplicationDate((SOSPeerInfoRef) val1);
591 CFDateRef v2 = SOSPeerInfoGetApplicationDate((SOSPeerInfoRef) val2);
592 if (v1 == NULL || v2 == NULL) {
593 ptrdiff_t dv = (const void *)v1 - (const void *)v2;
596 return dv < 0 ? kCFCompareLessThan : dv == 0 ? kCFCompareEqualTo : kCFCompareGreaterThan;
599 CFComparisonResult retval = CFDateCompare(v1, v2, 0);
605 static CFHashCode SOSPeerInfoHash(CFTypeRef cf) {
606 SOSPeerInfoRef peer = (SOSPeerInfoRef) cf;
608 return CFHash(peer->description) ^ CFHash(peer->signature);
612 static char boolToChars(bool val, char truechar, char falsechar) {
613 return val? truechar: falsechar;
616 static CFStringRef isKnown(CFStringRef ref) {
617 return ref? ref: CFSTR("Unknown ");
620 static CFStringRef copyDescriptionWithFormatOptions(CFTypeRef aObj, CFDictionaryRef formatOptions){
622 SOSPeerInfoRef pi = (SOSPeerInfoRef) aObj;
625 CFStringRef description = NULL;
626 // Get the format options we care about:
627 bool retired = SOSPeerInfoIsRetirementTicket(pi);
628 bool selfValid = SOSPeerInfoVerify(pi, NULL);
629 bool backingUp = SOSPeerInfoHasBackupKey(pi);
630 bool isKVS = SOSPeerInfoKVSOnly(pi);
631 bool isCKKSForAll = SOSPeerInfoSupportsCKKSForAll(pi);
632 CFStringRef osVersion = CFDictionaryGetValue(pi->gestalt, kPIOSVersionKey);
633 CFStringRef tmp = SOSPeerInfoV2DictionaryCopyString(pi, sDeviceID);
634 CFStringRef deviceID = CFStringCreateTruncatedCopy(tmp, 8);
636 CFStringRef serialNum = SOSPeerInfoCopySerialNumber(pi);
638 // Calculate the truncated length
640 CFStringRef objectPrefix = CFStringCreateWithFormat(kCFAllocatorDefault, formatOptions, CFSTR("PI@%p"), pi);
642 description = CFStringCreateWithFormat(kCFAllocatorDefault, formatOptions,
643 CFSTR("<%@: [name: %20@] [%c%c%c%c%c%c%c%c] [type: %-20@] [spid: %8@] [os: %10@] [devid: %10@] [serial: %12@]"),
645 isKnown(SOSPeerInfoGetPeerName(pi)),
648 boolToChars(selfValid, 'S', 's'),
649 boolToChars(retired, 'R', 'r'),
650 boolToChars(backingUp, 'B', 'b'),
651 boolToChars(isKVS, 'K', 'I'),
653 boolToChars(isCKKSForAll, 'C', '_'),
654 isKnown(SOSPeerInfoGetPeerDeviceType(pi)), isKnown(SOSPeerInfoGetSPID(pi)),
655 isKnown(osVersion), isKnown(deviceID), isKnown(serialNum));
657 CFReleaseNull(deviceID);
658 CFReleaseNull(serialNum);
659 CFReleaseNull(objectPrefix);
664 static CFStringRef SOSPeerInfoCopyFormatDescription(CFTypeRef aObj, CFDictionaryRef formatOptions) {
666 CFStringRef description = NULL;
668 description = copyDescriptionWithFormatOptions(aObj, formatOptions);
673 void SOSPeerInfoLogState(char *category, SOSPeerInfoRef pi, SecKeyRef pubKey, CFStringRef myPID, char sigchr) {
675 bool appValid = SOSPeerInfoApplicationVerify(pi, pubKey, NULL);
676 bool retired = SOSPeerInfoIsRetirementTicket(pi);
677 // We won't inflate invalid peerInfos. Mark this true to keep scanning utilities from breaking.
678 bool selfValid = true;
679 bool backingUp = SOSPeerInfoHasBackupKey(pi);
680 bool isMe = CFEqualSafe(SOSPeerInfoGetPeerID(pi), myPID) == true;
681 bool isKVS = SOSPeerInfoKVSOnly(pi);
682 bool isCKKSForAll = SOSPeerInfoSupportsCKKSForAll(pi);
683 CFStringRef osVersion = CFDictionaryGetValue(pi->gestalt, kPIOSVersionKey);
684 CFStringRef tmp = SOSPeerInfoV2DictionaryCopyString(pi, sDeviceID);
685 CFStringRef deviceID = CFStringCreateTruncatedCopy(tmp, 8);
687 CFStringRef serialNum = SOSPeerInfoCopySerialNumber(pi);
689 secnotice(category, "PI: [name: %-20@] [%c%c%c%c%c%c%c%c] [type: %-20@] [spid: %8@] [os: %10@] [devid: %10@] [serial: %12@]", isKnown(SOSPeerInfoGetPeerName(pi)),
690 boolToChars(isMe, 'M', 'm'),
691 boolToChars(appValid, 'A', 'a'),
692 boolToChars(selfValid, 'S', 's'),
693 boolToChars(retired, 'R', 'r'),
694 boolToChars(backingUp, 'B', 'b'),
695 boolToChars(isKVS, 'K', 'I'),
696 boolToChars(isCKKSForAll, 'C', '_'),
698 isKnown(SOSPeerInfoGetPeerDeviceType(pi)), isKnown(SOSPeerInfoGetSPID(pi)),
699 isKnown(osVersion), isKnown(deviceID), isKnown(serialNum));
701 CFReleaseNull(deviceID);
702 CFReleaseNull(serialNum);
705 CFDictionaryRef SOSPeerInfoCopyPeerGestalt(SOSPeerInfoRef pi) {
706 CFRetain(pi->gestalt);
710 CFDictionaryRef SOSPeerGetGestalt(SOSPeerInfoRef pi){
714 CFStringRef SOSPeerInfoGetPeerName(SOSPeerInfoRef peer) {
715 return SOSPeerInfoLookupGestaltValue(peer, kPIUserDefinedDeviceNameKey);
718 CFStringRef SOSPeerInfoGetPeerDeviceType(SOSPeerInfoRef peer) {
719 return SOSPeerInfoLookupGestaltValue(peer, kPIDeviceModelNameKey);
722 CFIndex SOSPeerInfoGetPeerProtocolVersion(SOSPeerInfoRef peer) {
723 CFIndex version = PEERINFO_CURRENT_VERSION;
724 CFTypeRef val = SOSPeerInfoLookupGestaltValue(peer, kPIMessageProtocolVersionKey);
725 if (val && CFGetTypeID(val) == CFNumberGetTypeID())
726 CFNumberGetValue(val, kCFNumberCFIndexType, &version);
730 CFTypeRef SOSPeerInfoLookupGestaltValue(SOSPeerInfoRef pi, CFStringRef key) {
731 return CFDictionaryGetValue(pi->gestalt, key);
734 CFStringRef SOSPeerInfoGetPeerID(SOSPeerInfoRef pi) {
735 return pi ? pi->peerID : NULL;
738 CFStringRef SOSPeerInfoGetSPID(SOSPeerInfoRef pi) {
739 return pi ? pi->spid : NULL;
742 bool SOSPeerInfoPeerIDEqual(SOSPeerInfoRef pi, CFStringRef myPeerID) {
743 return CFEqualSafe(myPeerID, SOSPeerInfoGetPeerID(pi));
746 CFIndex SOSPeerInfoGetVersion(SOSPeerInfoRef pi) {
750 bool SOSPeerInfoUpdateDigestWithPublicKeyBytes(SOSPeerInfoRef peer, const struct ccdigest_info *di,
751 ccdigest_ctx_t ctx, CFErrorRef *error) {
752 CFDataRef pubKeyBytes = CFDictionaryGetValue(peer->description, sPublicKeyKey);
755 SOSCreateErrorWithFormat(kSOSErrorEncodeFailure, NULL, error, NULL, CFSTR("Digest failed – no public key"));
759 ccdigest_update(di, ctx, CFDataGetLength(pubKeyBytes), CFDataGetBytePtr(pubKeyBytes));
764 bool SOSPeerInfoUpdateDigestWithDescription(SOSPeerInfoRef peer, const struct ccdigest_info *di,
765 ccdigest_ctx_t ctx, CFErrorRef *error) {
766 if(SOSPeerInfoVersionHasV2Data(peer)) SOSPeerInfoPackV2Data(peer);
767 size_t description_size = der_sizeof_plist(peer->description, error);
768 if (description_size == 0) {
769 SOSCreateErrorWithFormat(kSOSErrorEncodeFailure, NULL, error, NULL, CFSTR("Description length failed"));
773 uint8_t * data = malloc(description_size);
775 SOSCreateErrorWithFormat(kSOSErrorEncodeFailure, NULL, error, NULL, CFSTR("Description alloc failed"));
778 uint8_t *data_end = data + description_size;
779 uint8_t *encoded = der_encode_plist(peer->description, error, data, data_end);
783 SOSCreateErrorWithFormat(kSOSErrorEncodeFailure, NULL, error, NULL, CFSTR("Description encode failed"));
787 ccdigest_update(di, ctx, description_size, data);
795 static CFDataRef sosCreateDate() {
796 CFDateRef now = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent());
797 size_t bufsiz = der_sizeof_date(now, NULL);
799 der_encode_date(now, NULL, buf, buf+bufsiz);
801 return CFDataCreate(NULL, buf, bufsiz);
804 static CFDateRef sosCreateCFDate(CFDataRef sosdate) {
806 der_decode_date(NULL, &date, NULL, CFDataGetBytePtr(sosdate),
807 CFDataGetBytePtr(sosdate) + CFDataGetLength(sosdate));
811 static bool sospeer_application_hash(SOSPeerInfoRef pi, const struct ccdigest_info *di, uint8_t *hbuf) {
812 CFDataRef appdate = asData(CFDictionaryGetValue(pi->description, sApplicationDate), NULL);
813 if(!appdate) return false;
814 ccdigest_di_decl(di, ctx);
815 ccdigest_init(di, ctx);
816 ccdigest_update(di, ctx, CFDataGetLength(appdate), CFDataGetBytePtr(appdate));
817 if (!SOSPeerInfoUpdateDigestWithPublicKeyBytes(pi, di, ctx, NULL)) return false;
818 ccdigest_final(di, ctx, hbuf);
822 SOSPeerInfoRef SOSPeerInfoCopyAsApplication(SOSPeerInfoRef original, SecKeyRef userkey, SecKeyRef peerkey, CFErrorRef *error) {
823 SOSPeerInfoRef result = NULL;
824 SOSPeerInfoRef pi = SOSPeerInfoCreateCopy(kCFAllocatorDefault, original, error);
826 const struct ccdigest_info *di = ccsha256_di();
827 uint8_t hbuf[di->output_size];
828 CFDataRef usersig = NULL;
830 CFDataRef creationDate = sosCreateDate();
831 CFDictionarySetValue(pi->description, sApplicationDate, creationDate);
832 CFReleaseNull(creationDate);
834 // Create User Application Signature
835 require_action_quiet(sospeer_application_hash(pi, di, hbuf), fail,
836 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Failed to create hash for peer applicant"), NULL, error));
838 usersig = sosCopySignedHash(userkey, di, hbuf);
839 require_action_quiet(usersig, fail,
840 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Failed to sign public key hash for peer"), NULL, error));
842 CFDictionarySetValue(pi->description, sApplicationUsig, usersig);
843 pi->verifiedAppKeyID = SOSCopyIDOfKey(userkey, error);
844 if(pi->verifiedAppKeyID == NULL) {
845 secnotice("PICache", "failed to get userKeyID");
847 pi->verifiedResult = true;
849 require_quiet(SOSPeerInfoSign(peerkey, pi, error), fail);
855 CFReleaseNull(usersig);
860 bool SOSPeerInfoApplicationVerify(SOSPeerInfoRef pi, SecKeyRef userkey, CFErrorRef *error) {
861 const struct ccdigest_info *di = ccsha256_di();
862 uint8_t hbuf[di->output_size];
864 CFStringRef userKeyID = NULL;
866 // If we've already succeeded signature check with this key move on.
867 require_action_quiet(userkey, exit, SOSErrorCreate(kSOSErrorNoKey, error, NULL, CFSTR("Can't validate PeerInfos with no userKey")));
868 userKeyID = SOSCopyIDOfKey(userkey, error);
869 require_action_quiet(!CFEqualSafe(userKeyID, pi->verifiedAppKeyID), exit, result = pi->verifiedResult);
871 // verifiedAppKeyID was NULL or not the key we're looking for - clear it.
872 CFReleaseNull(pi->verifiedAppKeyID);
873 pi->verifiedResult = false;
874 CFDataRef usig = CFDictionaryGetValue(pi->description, sApplicationUsig);
875 require_action_quiet(usig, exit,
876 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Peer is not an applicant"), NULL, error));
877 // Verify User Application Signature
878 require_action_quiet(sospeer_application_hash(pi, di, hbuf), exit,
879 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Failed to create hash for peer applicant"), NULL, error));
880 require_action_quiet(sosVerifyHash(userkey, di, hbuf, usig), exit,
881 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("user signature of public key hash fails to verify"), NULL, error));
882 // Remember the userkey we validated for this peerinfo.
883 pi->verifiedAppKeyID = CFStringCreateCopy(kCFAllocatorDefault, userKeyID);
884 pi->verifiedResult = true;
886 result = SOSPeerInfoVerify(pi, error);
889 CFReleaseNull(userKeyID);
894 static CF_RETURNS_RETAINED CFDateRef sosPeerInfoGetDate(SOSPeerInfoRef pi, CFStringRef entry) {
896 CFDataRef sosdate = CFDictionaryGetValue(pi->description, entry);
897 if(!sosdate) return NULL;
898 CFDateRef date = sosCreateCFDate(sosdate);
903 CF_RETURNS_RETAINED CFDateRef SOSPeerInfoGetApplicationDate(SOSPeerInfoRef pi) {
904 return sosPeerInfoGetDate(pi, sApplicationDate);
907 CF_RETURNS_RETAINED CFDateRef SOSPeerInfoGetRetirementDate(SOSPeerInfoRef pi) {
908 return sosPeerInfoGetDate(pi, sRetirementDate);
917 CFStringRef SOSPeerGestaltGetName(CFDictionaryRef gestalt) {
918 CFStringRef name = SOSPeerGestaltGetAnswer(gestalt, kPIUserDefinedDeviceNameKey);
919 return isString(name) ? name : NULL;
922 CFTypeRef SOSPeerGestaltGetAnswer(CFDictionaryRef gestalt, CFStringRef question) {
923 return gestalt ? CFDictionaryGetValue(gestalt, question) : NULL;
931 SOSPeerInfoRef SOSPeerInfoCreateRetirementTicket(CFAllocatorRef allocator, SecKeyRef privKey, SOSPeerInfoRef peer, CFErrorRef *error) {
933 SOSPeerInfoRef pi = SOSPeerInfoCreateCopy(allocator, peer, error);
937 // Fill out Resignation Date
938 CFDataRef resignationDate = sosCreateDate();
939 CFDictionaryAddValue(pi->description, sRetirementDate, resignationDate);
940 CFReleaseNull(resignationDate);
942 require(SOSPeerInfoSign(privKey, pi, error), fail);
951 CFStringRef SOSPeerInfoInspectRetirementTicket(SOSPeerInfoRef pi, CFErrorRef *error) {
952 CFStringRef retval = NULL;
953 CFDateRef now = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent());
954 CFDateRef retirement = NULL;
956 require_quiet(SOSPeerInfoVerify(pi, error), err);
958 retirement = sosCreateCFDate(CFDictionaryGetValue(pi->description, sRetirementDate));
959 require_action_quiet(retirement, err,
960 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Peer is not retired"), NULL, error));
962 require_action_quiet(CFDateCompare(now, retirement, NULL) == kCFCompareGreaterThan, err,
963 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Retirement date is after current date"), NULL, error));
965 retval = SOSPeerInfoGetPeerID(pi);
969 CFReleaseNull(retirement);
973 bool SOSPeerInfoRetireRetirementTicket(size_t max_seconds, SOSPeerInfoRef pi) {
974 CFDateRef now = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent());
975 CFDateRef retirement = sosCreateCFDate(CFDictionaryGetValue(pi->description, sRetirementDate));
976 CFTimeInterval timediff = CFDateGetTimeIntervalSinceDate(now, retirement); // diff in seconds
978 CFReleaseNull(retirement);
979 if(timediff > (max_seconds)) return true;
983 static const void *SOSGetDescriptionValue(SOSPeerInfoRef pi, const void *key) {
984 if(pi && pi->description) {
985 return CFDictionaryGetValue(pi->description, key);
990 bool SOSPeerInfoIsRetirementTicket(SOSPeerInfoRef pi) {
991 CFDataRef flag = SOSGetDescriptionValue(pi, sRetirementDate);
995 bool SOSPeerInfoIsCloudIdentity(SOSPeerInfoRef pi) {
996 CFTypeRef value = SOSGetDescriptionValue(pi, sCloudIdentityKey);
997 return CFEqualSafe(value, kCFBooleanTrue);
1000 SOSPeerInfoRef SOSPeerInfoUpgradeSignatures(CFAllocatorRef allocator, SecKeyRef privKey, SecKeyRef peerKey, SOSPeerInfoRef peer, CFErrorRef *error) {
1001 SecKeyRef pubKey = SecKeyCreatePublicFromPrivate(privKey);
1002 SOSPeerInfoRef retval = NULL;
1004 retval = SOSPeerInfoCopyAsApplication(peer, privKey, peerKey, error);
1005 CFReleaseNull(pubKey);
1009 bool SOSPeerInfoSetOctagonKeysInDescription(SOSPeerInfoRef peer, SecKeyRef octagonSigningKey,
1010 SecKeyRef octagonEncryptionKey, CFErrorRef *error)
1013 CFDataRef signingPublicKeyBytes = NULL;
1014 CFDataRef encryptionPublicKeyBytes = NULL;
1016 OSStatus copySigningKeyResult = SecKeyCopyPublicBytes(octagonSigningKey, &signingPublicKeyBytes);
1017 OSStatus copyEncryptionKeyResult = SecKeyCopyPublicBytes(octagonEncryptionKey, &encryptionPublicKeyBytes);
1019 require_action_quiet(errSecSuccess == copySigningKeyResult, fail, SecError(copySigningKeyResult, error, CFSTR("failed to copy signing public key bytes")));
1020 require_action_quiet(errSecSuccess == copyEncryptionKeyResult, fail, SecError(copyEncryptionKeyResult, error, CFSTR("failed to copy encryption public key bytes")));
1023 CFDictionarySetValue(peer->description, sOctagonPeerSigningPublicKeyKey, signingPublicKeyBytes);
1024 CFDictionarySetValue(peer->description, sOctagonPeerEncryptionPublicKeyKey, encryptionPublicKeyBytes);
1029 CFReleaseNull(signingPublicKeyBytes);
1030 CFReleaseNull(encryptionPublicKeyBytes);
1036 static SOSPeerInfoRef CF_RETURNS_RETAINED
1037 SOSPeerInfoSetBothOctagonKeys(CFAllocatorRef allocator,
1038 SOSPeerInfoRef toCopy,
1039 CFStringRef descriptionSigningKey,
1040 CFStringRef descriptionEncryptionKey,
1041 SecKeyRef octagonSigningKey,
1042 SecKeyRef octagonEncryptionKey,
1043 SecKeyRef signingKey,
1046 CFDataRef signingPublicKeyBytes = NULL;
1047 CFDataRef encryptionPublicKeyBytes = NULL;
1049 SOSPeerInfoRef pi = NULL;
1051 OSStatus copySigningKeyResult = SecKeyCopyPublicBytes(octagonSigningKey, &signingPublicKeyBytes);
1052 OSStatus copyEncryptionKeyResult = SecKeyCopyPublicBytes(octagonEncryptionKey, &encryptionPublicKeyBytes);
1054 require_action_quiet(0 == copySigningKeyResult, fail, SecError(copySigningKeyResult, error, CFSTR("failed to copy signing public key bytes")));
1055 require_action_quiet(0 == copyEncryptionKeyResult, fail, SecError(copyEncryptionKeyResult, error, CFSTR("failed to copy encryption public key bytes")));
1057 pi = SOSPeerInfoCopyWithModification(allocator, toCopy, signingKey, error,
1058 ^bool(SOSPeerInfoRef peerToModify, CFErrorRef *error) {
1059 if(peerToModify && peerToModify->description && signingPublicKeyBytes && descriptionSigningKey && encryptionPublicKeyBytes && descriptionEncryptionKey) {
1060 CFDictionarySetValue(peerToModify->description, descriptionSigningKey, signingPublicKeyBytes);
1061 CFDictionarySetValue(peerToModify->description, descriptionEncryptionKey, encryptionPublicKeyBytes);
1063 SecError(errSecParam, error, CFSTR("Bad key bytes or dictionary key"));
1070 CFReleaseNull(signingPublicKeyBytes);
1071 CFReleaseNull(encryptionPublicKeyBytes);
1075 SOSPeerInfoRef CF_RETURNS_RETAINED
1076 SOSPeerInfoSetOctagonKeys(CFAllocatorRef allocator,
1077 SOSPeerInfoRef toCopy,
1078 SecKeyRef octagonSigningKey,
1079 SecKeyRef octagonEncryptionKey,
1080 SecKeyRef signingKey,
1083 return SOSPeerInfoSetBothOctagonKeys(allocator, toCopy, sOctagonPeerSigningPublicKeyKey, sOctagonPeerEncryptionPublicKeyKey, octagonSigningKey, octagonEncryptionKey, signingKey, error);
1086 static SOSPeerInfoRef CF_RETURNS_RETAINED
1087 SOSPeerInfoSetOctagonKey(CFAllocatorRef allocator,
1088 SOSPeerInfoRef toCopy,
1089 CFStringRef descriptionKey,
1090 SecKeyRef octagonKey,
1091 SecKeyRef signingKey,
1094 CFDataRef publicKeyBytes = NULL;
1095 SOSPeerInfoRef pi = NULL;
1097 OSStatus copyResult = SecKeyCopyPublicBytes(octagonKey, &publicKeyBytes);
1098 require_action_quiet(0 == copyResult, fail, SecError(copyResult, error, CFSTR("failed to copy public key bytes")));
1100 pi = SOSPeerInfoCopyWithModification(allocator, toCopy, signingKey, error,
1101 ^bool(SOSPeerInfoRef peerToModify, CFErrorRef *error) {
1102 if(peerToModify && peerToModify->description && publicKeyBytes && descriptionKey) {
1103 CFDictionarySetValue(peerToModify->description, descriptionKey, publicKeyBytes);
1105 SecError(errSecParam, error, CFSTR("Bad key bytes or dictionary key"));
1112 CFReleaseNull(publicKeyBytes);
1116 SOSPeerInfoRef CF_RETURNS_RETAINED
1117 SOSPeerInfoSetOctagonSigningKey(CFAllocatorRef allocator,
1118 SOSPeerInfoRef toCopy,
1119 SecKeyRef octagonSigningKey,
1120 SecKeyRef signingKey,
1123 return SOSPeerInfoSetOctagonKey(allocator, toCopy, sOctagonPeerSigningPublicKeyKey, octagonSigningKey, signingKey, error);
1126 SOSPeerInfoRef CF_RETURNS_RETAINED
1127 SOSPeerInfoSetOctagonEncryptionKey(CFAllocatorRef allocator,
1128 SOSPeerInfoRef toCopy,
1129 SecKeyRef octagonEncryptionKey,
1130 SecKeyRef signingKey,
1133 return SOSPeerInfoSetOctagonKey(allocator, toCopy, sOctagonPeerEncryptionPublicKeyKey, octagonEncryptionKey, signingKey, error);
1136 CFStringRef SOSPeerInfoCopyTransportType(SOSPeerInfoRef peer){
1137 CFStringRef transportType = (CFStringRef)SOSPeerInfoV2DictionaryCopyString(peer, sTransportType);
1138 return (transportType ? transportType : CFRetain(SOSTransportMessageTypeKVS));
1141 bool SOSPeerInfoKVSOnly(SOSPeerInfoRef pi) {
1142 CFStringRef transportType = SOSPeerInfoCopyTransportType(pi);
1143 bool retval = CFEqualSafe(transportType, SOSTransportMessageTypeKVS);
1144 CFReleaseNull(transportType);
1148 CFStringRef SOSPeerInfoCopyDeviceID(SOSPeerInfoRef peer){
1149 return CFSTR("not implemented");
1152 SOSPeerInfoDeviceClass SOSPeerInfoGetClass(SOSPeerInfoRef pi) {
1153 static CFDictionaryRef devID2Class = NULL;
1154 static dispatch_once_t onceToken = 0;
1156 dispatch_once(&onceToken, ^{
1157 CFNumberRef cfSOSPeerInfo_macOS = CFNumberCreateWithCFIndex(kCFAllocatorDefault, SOSPeerInfo_macOS);
1158 CFNumberRef cfSOSPeerInfo_iOS = CFNumberCreateWithCFIndex(kCFAllocatorDefault, SOSPeerInfo_iOS);
1159 CFNumberRef cfSOSPeerInfo_iCloud = CFNumberCreateWithCFIndex(kCFAllocatorDefault, SOSPeerInfo_iCloud);
1160 // CFNumberRef cfSOSPeerInfo_watchOS = CFNumberCreateWithCFIndex(kCFAllocatorDefault, SOSPeerInfo_watchOS);
1161 // CFNumberRef cfSOSPeerInfo_tvOS = CFNumberCreateWithCFIndex(kCFAllocatorDefault, SOSPeerInfo_tvOS);
1163 devID2Class = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
1164 CFSTR("Mac Pro"), cfSOSPeerInfo_macOS,
1165 CFSTR("MacBook"), cfSOSPeerInfo_macOS,
1166 CFSTR("MacBook Pro"), cfSOSPeerInfo_macOS,
1167 CFSTR("iCloud"), cfSOSPeerInfo_iCloud,
1168 CFSTR("iMac"), cfSOSPeerInfo_macOS,
1169 CFSTR("iPad"), cfSOSPeerInfo_iOS,
1170 CFSTR("iPhone"), cfSOSPeerInfo_iOS,
1171 CFSTR("iPod touch"), cfSOSPeerInfo_iOS,
1173 CFReleaseNull(cfSOSPeerInfo_macOS);
1174 CFReleaseNull(cfSOSPeerInfo_iOS);
1175 CFReleaseNull(cfSOSPeerInfo_iCloud);
1177 SOSPeerInfoDeviceClass retval = SOSPeerInfo_unknown;
1178 CFStringRef dt = SOSPeerInfoGetPeerDeviceType(pi);
1179 require_quiet(dt, errOut);
1180 CFNumberRef classNum = CFDictionaryGetValue(devID2Class, dt);
1181 require_quiet(classNum, errOut);
1183 require_quiet(CFNumberGetValue(classNum, kCFNumberCFIndexType, &tmp), errOut);
1184 retval = (SOSPeerInfoDeviceClass) tmp;