]> git.saurik.com Git - apple/security.git/blob - OSX/sec/SOSCircle/SecureObjectSync/SOSPeerInfo.m
24d0cb0f66a1783e37526e4698842018351e3aa0
[apple/security.git] / OSX / sec / SOSCircle / SecureObjectSync / SOSPeerInfo.m
1 /*
2 * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25 #include <AssertMacros.h>
26 #include <TargetConditionals.h>
27
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>
36
37 #include <CoreFoundation/CFArray.h>
38 #include <dispatch/dispatch.h>
39
40 #include <stdlib.h>
41 #include <assert.h>
42
43 #include <utilities/SecCFWrappers.h>
44 #include <utilities/SecCFRelease.h>
45 #include <utilities/SecCFError.h>
46 #include <utilities/SecXPCError.h>
47
48 #include <utilities/der_plist.h>
49 #include <utilities/der_plist_internal.h>
50 #include <corecrypto/ccder.h>
51 #include <utilities/der_date.h>
52
53 #include <corecrypto/ccdigest.h>
54 #include <corecrypto/ccsha2.h>
55
56
57 #include <CoreFoundation/CoreFoundation.h>
58 #include <CoreFoundation/CFDate.h>
59
60 #include <xpc/xpc.h>
61
62 #if TARGET_OS_IPHONE || TARGET_OS_EMBEDDED
63 #include <MobileGestalt.h>
64 #endif
65
66 #include <Security/SecBase64.h>
67 #include <Security/SecKeyPriv.h>
68 #include <Security/SecOTR.h>
69 #include <Security/SecuritydXPC.h>
70
71 CFGiblisWithHashFor(SOSPeerInfo);
72
73
74 const CFStringRef kPIUserDefinedDeviceNameKey = CFSTR("ComputerName");
75 const CFStringRef kPIDeviceModelNameKey = CFSTR("ModelName");
76 const CFStringRef kPIMessageProtocolVersionKey = CFSTR("MessageProtocolVersion");
77 const CFStringRef kPIOSVersionKey = CFSTR("OSVersion");
78
79 // Description Dictionary Entries
80 static CFStringRef sPublicKeyKey = CFSTR("PublicSigningKey");
81 static CFStringRef sOctagonPublicKeyKey = CFSTR("OctagonPublicSigningKey");
82 const CFStringRef sGestaltKey = CFSTR("DeviceGestalt");
83 const CFStringRef sVersionKey = CFSTR("ConflictVersion");
84 static CFStringRef sCloudIdentityKey = CFSTR("CloudIdentity");
85 static CFStringRef sApplicationDate = CFSTR("ApplicationDate");
86 static CFStringRef sApplicationUsig = CFSTR("ApplicationUsig");
87 static CFStringRef sRetirementDate = CFSTR("RetirementDate");
88
89 // Peerinfo Entries
90 CFStringRef kSOSPeerInfoDescriptionKey = CFSTR("SOSPeerInfoDescription");
91 CFStringRef kSOSPeerInfoSignatureKey = CFSTR("SOSPeerInfoSignature");
92 CFStringRef kSOSPeerInfoNameKey = CFSTR("SOSPeerInfoName");
93
94 //Peer Info V2 Dictionary IDS keys
95 CFStringRef sPreferIDS = CFSTR("PreferIDS");
96 CFStringRef sPreferIDSFragmentation = CFSTR("PreferIDFragmentation");
97 CFStringRef sPreferIDSACKModel = CFSTR("PreferIDSAckModel");
98 CFStringRef sTransportType = CFSTR("TransportType");
99 CFStringRef sDeviceID = CFSTR("DeviceID");
100
101 const CFStringRef peerIDLengthKey = CFSTR("idLength");
102
103 SOSPeerInfoRef SOSPeerInfoAllocate(CFAllocatorRef allocator) {
104 return CFTypeAllocate(SOSPeerInfo, struct __OpaqueSOSPeerInfo, allocator);
105 }
106
107 static SecKeyRef _SOSPeerInfoCopyPubKey(SOSPeerInfoRef peer, CFStringRef keyDictionaryKey, CFErrorRef* error)
108 {
109 SecKeyRef result = NULL;
110
111 CFDataRef pubKeyBytes = asData(CFDictionaryGetValue(peer->description, keyDictionaryKey), error);
112 require_quiet(pubKeyBytes, fail);
113
114 CFAllocatorRef allocator = CFGetAllocator(peer);
115 result = SecKeyCreateFromPublicData(allocator, kSecECDSAAlgorithmID, pubKeyBytes);
116
117 require_quiet(SecAllocationError(result, error, CFSTR("Failed to create public key from data %@"), pubKeyBytes), fail);
118
119 fail:
120 return result;
121 }
122
123 SecKeyRef SOSPeerInfoCopyPubKey(SOSPeerInfoRef peer, CFErrorRef* error) {
124 return _SOSPeerInfoCopyPubKey(peer, sPublicKeyKey, error);
125 }
126
127 SecKeyRef SOSPeerInfoCopyOctagonPubKey(SOSPeerInfoRef peer, CFErrorRef* error)
128 {
129 return _SOSPeerInfoCopyPubKey(peer, sOctagonPublicKeyKey, error);
130 }
131
132 CFDataRef SOSPeerInfoGetAutoAcceptInfo(SOSPeerInfoRef peer) {
133 CFDataRef pubKeyBytes = NULL;
134
135 pubKeyBytes = CFDictionaryGetValue(peer->description, sPublicKeyKey);
136 if (!pubKeyBytes || CFGetTypeID(pubKeyBytes) != CFDataGetTypeID()) {
137 pubKeyBytes = NULL;
138 }
139
140 return pubKeyBytes;
141 }
142
143 static bool SOSDescriptionHash(SOSPeerInfoRef peer, const struct ccdigest_info *di, void *hashresult, CFErrorRef *error) {
144 ccdigest_di_decl(di, ctx);
145 ccdigest_init(di, ctx);
146 void *ctx_p = ctx;
147 if(!SOSPeerInfoUpdateDigestWithDescription(peer, di, ctx_p, error)) return false;
148 ccdigest_final(di, ctx, hashresult);
149 return true;
150 }
151
152
153 #define SIGLEN 128
154 static CFDataRef sosCopySignedHash(SecKeyRef privkey, const struct ccdigest_info *di, uint8_t *hbuf) {
155 OSStatus stat;
156 size_t siglen = SIGLEN;
157 uint8_t sig[siglen];
158 if((stat = SecKeyRawSign(privkey, kSecPaddingNone, hbuf, di->output_size, sig, &siglen)) != 0) {
159 return NULL;
160 }
161 return CFDataCreate(NULL, sig, (CFIndex)siglen);
162 }
163
164 static bool sosVerifyHash(SecKeyRef pubkey, const struct ccdigest_info *di, uint8_t *hbuf, CFDataRef signature) {
165 return SecKeyRawVerify(pubkey, kSecPaddingNone, hbuf, di->output_size,
166 CFDataGetBytePtr(signature), CFDataGetLength(signature)) == errSecSuccess;
167 }
168
169 bool SOSPeerInfoSign(SecKeyRef privKey, SOSPeerInfoRef peer, CFErrorRef *error) {
170 bool status = false;
171 const struct ccdigest_info *di = ccsha256_di();
172 uint8_t hbuf[di->output_size];
173 CFDataRef newSignature = NULL;
174
175 require_action_quiet(SOSDescriptionHash(peer, di, hbuf, error), fail,
176 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Failed to hash description for peer"), NULL, error));
177
178 newSignature = sosCopySignedHash(privKey, di, hbuf);
179 require_action_quiet(newSignature, fail, SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Failed to sign peerinfo for peer"), NULL, error));
180
181 CFReleaseNull(peer->signature);
182 peer->signature = newSignature;
183 newSignature = NULL;
184 status = true;
185
186 fail:
187 CFReleaseNull(newSignature);
188 return status;
189 }
190
191 // Return true (1) if the signature verifies.
192 bool SOSPeerInfoVerify(SOSPeerInfoRef peer, CFErrorRef *error) {
193 bool result = false;
194 const struct ccdigest_info *di = ccsha256_di();
195 uint8_t hbuf[di->output_size];
196
197 SecKeyRef pubKey = SOSPeerInfoCopyPubKey(peer, error);
198 require_quiet(pubKey, error_out);
199
200 require_quiet(SOSDescriptionHash(peer, di, hbuf, error), error_out);
201
202 require_action_quiet(sosVerifyHash(pubKey, di, hbuf, peer->signature), error_out,
203 SOSErrorCreate(kSOSErrorBadSignature, error, NULL,
204 CFSTR("Signature didn't verify for %@"), peer));
205 result = true;
206
207 error_out:
208 CFReleaseNull(pubKey);
209 return result;
210 }
211
212 void SOSPeerInfoSetVersionNumber(SOSPeerInfoRef pi, int version) {
213 pi->version = version;
214 CFNumberRef versionNumber = CFNumberCreateWithCFIndex(NULL, pi->version);
215 CFDictionarySetValue(pi->description, sVersionKey, versionNumber);
216 CFReleaseNull(versionNumber);
217 }
218
219 static SOSPeerInfoRef SOSPeerInfoCreate_Internal(CFAllocatorRef allocator,
220 CFDictionaryRef gestalt, CFDataRef backup_key,
221 CFStringRef IDSID, CFStringRef transportType, CFBooleanRef preferIDS,
222 CFBooleanRef preferFragmentation, CFBooleanRef preferAckModel,
223 CFSetRef enabledViews,
224 SecKeyRef signingKey, SecKeyRef octagonSigningKey, CFErrorRef* error,
225 void (^ description_modifier)(CFMutableDictionaryRef description)) {
226 SOSPeerInfoRef pi = CFTypeAllocate(SOSPeerInfo, struct __OpaqueSOSPeerInfo, allocator);
227 pi->gestalt = gestalt;
228 CFRetain(pi->gestalt);
229
230 pi->version = SOSPeerInfoGetPeerProtocolVersion(pi);
231 CFDataRef publicBytes = NULL;
232 CFDataRef octagonPublicBytes = NULL;
233 CFNumberRef versionNumber = NULL;
234
235 SecKeyRef publicKey = SecKeyCreatePublicFromPrivate(signingKey);
236 if (publicKey == NULL) {
237 SOSCreateError(kSOSErrorBadKey, CFSTR("Unable to get public"), NULL, error);
238 CFReleaseNull(pi);
239 goto exit;
240 }
241
242 OSStatus result = SecKeyCopyPublicBytes(publicKey, &publicBytes);
243
244 if (result != errSecSuccess) {
245 SOSCreateError(kSOSErrorBadKey, CFSTR("Failed to export public bytes"), NULL, error);
246 CFReleaseNull(pi);
247 goto exit;
248 }
249
250 SecKeyRef octagonPublicKey = SecKeyCreatePublicFromPrivate(octagonSigningKey);
251 if (octagonPublicKey == NULL) {
252 SOSCreateError(kSOSErrorBadKey, CFSTR("Unable to get public key"), NULL, error);
253 CFReleaseNull(pi);
254 goto exit;
255 }
256
257 result = SecKeyCopyPublicBytes(octagonPublicKey, &octagonPublicBytes);
258
259 if (result != errSecSuccess) {
260 SOSCreateError(kSOSErrorBadKey, CFSTR("Failed to export public bytes"), NULL, error);
261 CFReleaseNull(pi);
262 goto exit;
263 }
264
265 pi->signature = CFDataCreateMutable(allocator, 0);
266
267 versionNumber = CFNumberCreateWithCFIndex(NULL, pi->version);
268
269 pi->description = CFDictionaryCreateMutableForCFTypesWith(allocator,
270 sVersionKey, versionNumber,
271 sPublicKeyKey, publicBytes,
272 sOctagonPublicKeyKey, octagonPublicBytes,
273 sGestaltKey, pi->gestalt,
274 NULL);
275
276
277 description_modifier(pi->description);
278
279
280 pi->id = SOSCopyIDOfKey(publicKey, error);
281 CFReleaseNull(publicKey);
282 CFReleaseNull(octagonPublicKey);
283
284 require_quiet(pi->id, exit);
285
286 // ================ V2 Additions Start
287
288 if(!SOSPeerInfoUpdateToV2(pi, error)) {
289 CFReleaseNull(pi);
290 goto exit;
291 }
292
293 // V2DictionarySetValue handles NULL as remove
294 if (backup_key != NULL) SOSPeerInfoV2DictionarySetValue(pi, sBackupKeyKey, backup_key);
295 SOSPeerInfoV2DictionarySetValue(pi, sDeviceID, IDSID);
296 SOSPeerInfoV2DictionarySetValue(pi, sTransportType, transportType);
297 SOSPeerInfoV2DictionarySetValue(pi, sPreferIDS, preferIDS);
298 SOSPeerInfoV2DictionarySetValue(pi, sPreferIDSFragmentation, preferFragmentation);
299 SOSPeerInfoV2DictionarySetValue(pi, sPreferIDSACKModel, preferAckModel);
300 SOSPeerInfoV2DictionarySetValue(pi, sViewsKey, enabledViews);
301
302 // ================ V2 Additions End
303
304 if (!SOSPeerInfoSign(signingKey, pi, error)) {
305 CFReleaseNull(pi);
306 goto exit;
307 }
308
309 exit:
310 CFReleaseNull(versionNumber);
311 CFReleaseNull(publicBytes);
312 CFReleaseNull(octagonPublicBytes);
313 return pi;
314 }
315
316 SOSPeerInfoRef SOSPeerInfoCreate(CFAllocatorRef allocator, CFDictionaryRef gestalt, CFDataRef backup_key, SecKeyRef signingKey, SecKeyRef octagonSigningKey, CFErrorRef* error) {
317 return SOSPeerInfoCreate_Internal(allocator, gestalt, backup_key, NULL, NULL, NULL, NULL, NULL, NULL, signingKey, octagonSigningKey, error, ^(CFMutableDictionaryRef description) {});
318 }
319
320 SOSPeerInfoRef SOSPeerInfoCreateWithTransportAndViews(CFAllocatorRef allocator, CFDictionaryRef gestalt, CFDataRef backup_key,
321 CFStringRef IDSID, CFStringRef transportType, CFBooleanRef preferIDS,
322 CFBooleanRef preferFragmentation, CFBooleanRef preferAckModel, CFSetRef enabledViews, SecKeyRef signingKey, SecKeyRef octagonSigningKey, CFErrorRef* error)
323 {
324 return SOSPeerInfoCreate_Internal(allocator, gestalt, backup_key, IDSID, transportType, preferIDS, preferFragmentation, preferAckModel, enabledViews, signingKey, octagonSigningKey, error, ^(CFMutableDictionaryRef description) {});
325 }
326
327
328 SOSPeerInfoRef SOSPeerInfoCreateCloudIdentity(CFAllocatorRef allocator, CFDictionaryRef gestalt, SecKeyRef signingKey, SecKeyRef octagonSigningKey, CFErrorRef* error) {
329 return SOSPeerInfoCreate_Internal(allocator, gestalt, NULL, NULL, NULL, NULL, NULL, NULL, NULL, signingKey, octagonSigningKey, error, ^(CFMutableDictionaryRef description) {
330 CFDictionarySetValue(description, sCloudIdentityKey, kCFBooleanTrue);
331 });
332
333 }
334
335
336 SOSPeerInfoRef SOSPeerInfoCreateCopy(CFAllocatorRef allocator, SOSPeerInfoRef toCopy, CFErrorRef* error) {
337 if(!toCopy) return NULL;
338 SOSPeerInfoRef pi = CFTypeAllocate(SOSPeerInfo, struct __OpaqueSOSPeerInfo, allocator);
339
340 pi->description = CFDictionaryCreateMutableCopy(allocator, 0, toCopy->description);
341 pi->signature = CFDataCreateCopy(allocator, toCopy->signature);
342
343 pi->gestalt = CFDictionaryCreateCopy(allocator, toCopy->gestalt);
344 pi->id = CFStringCreateCopy(allocator, toCopy->id);
345
346 pi->version = toCopy->version;
347 if(!SOSPeerInfoVersionHasV2Data(pi)) SOSPeerInfoExpandV2Data(pi, error);
348
349 return pi;
350 }
351
352
353 bool SOSPeerInfoVersionIsCurrent(SOSPeerInfoRef pi) {
354 return pi->version >= PEERINFO_CURRENT_VERSION;
355 }
356
357 bool SOSPeerInfoVersionHasV2Data(SOSPeerInfoRef pi) {
358 return pi->version >= kSOSPeerV2BaseVersion;
359 }
360
361 SOSPeerInfoRef SOSPeerInfoCreateCurrentCopy(CFAllocatorRef allocator, SOSPeerInfoRef toCopy,
362 CFStringRef IDSID, CFStringRef transportType, CFBooleanRef preferIDS, CFBooleanRef preferFragmentation, CFBooleanRef preferAckModel, CFSetRef enabledViews,
363 SecKeyRef signingKey, CFErrorRef* error) {
364
365 SOSPeerInfoRef pi = SOSPeerInfoCreateCopy(allocator, toCopy, error);
366 if(!SOSPeerInfoVersionHasV2Data(pi)) SOSPeerInfoUpdateToV2(pi, error);
367
368 //SOSPeerInfoSetSerialNumber(pi);
369
370 if (IDSID) {
371 SOSPeerInfoV2DictionarySetValue(pi, sDeviceID, IDSID);
372 }
373 if (transportType) {
374 SOSPeerInfoV2DictionarySetValue(pi, sTransportType, transportType);
375 }
376 if (preferIDS) {
377 SOSPeerInfoV2DictionarySetValue(pi, sPreferIDS, preferIDS);
378 }
379 if (preferFragmentation) {
380 SOSPeerInfoV2DictionarySetValue(pi, sPreferIDSFragmentation, preferFragmentation);
381 }
382 if (preferAckModel) {
383 SOSPeerInfoV2DictionarySetValue(pi, sPreferIDSACKModel, preferAckModel);
384 }
385 if (enabledViews) {
386 SOSPeerInfoV2DictionarySetValue(pi, sViewsKey, enabledViews);
387 }
388
389 if(!SOSPeerInfoSign(signingKey, pi, error)) {
390 CFReleaseNull(pi);
391 }
392
393 return pi;
394 }
395
396
397 static SOSPeerInfoRef SOSPeerInfoCopyWithModification(CFAllocatorRef allocator, SOSPeerInfoRef original,
398 SecKeyRef signingKey, CFErrorRef *error,
399 bool (^modification)(SOSPeerInfoRef peerToModify, CFErrorRef *error)) {
400
401 SOSPeerInfoRef result = NULL;
402 SOSPeerInfoRef copy = SOSPeerInfoCreateCopy(allocator, original, error);
403
404 require_quiet(modification(copy, error), fail);
405
406 require_quiet(SOSPeerInfoSign(signingKey, copy, error), fail);
407
408 CFTransferRetained(result, copy);
409
410 fail:
411 CFReleaseNull(copy);
412 return result;
413
414 }
415
416 SOSPeerInfoRef SOSPeerInfoCopyWithGestaltUpdate(CFAllocatorRef allocator, SOSPeerInfoRef toCopy, CFDictionaryRef gestalt, SecKeyRef signingKey, CFErrorRef* error) {
417 return SOSPeerInfoCopyWithModification(allocator, toCopy, signingKey, error,
418 ^bool(SOSPeerInfoRef peerToModify, CFErrorRef *error) {
419 if(!gestalt || !peerToModify) return false;
420 CFRetainAssign(peerToModify->gestalt, gestalt);
421 CFDictionarySetValue(peerToModify->description, sGestaltKey, peerToModify->gestalt);
422 return true;
423
424 });
425 }
426
427
428 SOSPeerInfoRef SOSPeerInfoCopyWithBackupKeyUpdate(CFAllocatorRef allocator, SOSPeerInfoRef toCopy, CFDataRef backupKey, SecKeyRef signingKey, CFErrorRef *error) {
429 return SOSPeerInfoCopyWithModification(allocator, toCopy, signingKey, error,
430 ^bool(SOSPeerInfoRef peerToModify, CFErrorRef *error) {
431 if (backupKey != NULL)
432 SOSPeerInfoV2DictionarySetValue(peerToModify, sBackupKeyKey, backupKey);
433 else
434 SOSPeerInfoV2DictionaryRemoveValue(peerToModify, sBackupKeyKey);
435 return true;
436 });
437 }
438
439 static CFDictionaryRef SOSPeerInfoUpdateAndCopyRecord(SOSPeerInfoRef peer, CFStringRef dsid, CFDictionaryRef escrowRecord){
440
441 CFMutableDictionaryRef existingEscrowRecords = SOSPeerInfoCopyEscrowRecord(peer);
442
443 if(escrowRecord == NULL && existingEscrowRecords != NULL)
444 {
445 CFDictionaryRemoveValue(existingEscrowRecords, dsid);
446 return existingEscrowRecords;
447 }
448
449 if(existingEscrowRecords == NULL)
450 existingEscrowRecords = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
451
452 CFDictionarySetValue(existingEscrowRecords, dsid, escrowRecord);
453
454 return existingEscrowRecords;
455 }
456
457
458 SOSPeerInfoRef SOSPeerInfoCopyWithEscrowRecordUpdate(CFAllocatorRef allocator, SOSPeerInfoRef toCopy, CFStringRef dsid, CFDictionaryRef escrowRecord, SecKeyRef signingKey, CFErrorRef *error) {
459 return SOSPeerInfoCopyWithModification(allocator, toCopy, signingKey, error,
460 ^bool(SOSPeerInfoRef peerToModify, CFErrorRef *error) {
461
462 CFDictionaryRef updatedEscrowRecords = SOSPeerInfoUpdateAndCopyRecord(peerToModify, dsid, escrowRecord);
463 SOSPeerInfoV2DictionarySetValue(peerToModify, sEscrowRecord, updatedEscrowRecords);
464 CFReleaseNull(updatedEscrowRecords);
465 return true;
466 });
467 }
468
469 SOSPeerInfoRef SOSPeerInfoCopyWithReplacedEscrowRecords(CFAllocatorRef allocator, SOSPeerInfoRef toCopy, CFDictionaryRef escrowRecords, SecKeyRef signingKey, CFErrorRef *error) {
470 return SOSPeerInfoCopyWithModification(allocator, toCopy, signingKey, error,
471 ^bool(SOSPeerInfoRef peerToModify, CFErrorRef *error) {
472 if(escrowRecords != NULL)
473 SOSPeerInfoV2DictionarySetValue(peerToModify, sEscrowRecord, escrowRecords);
474
475 return true;
476 });
477 }
478
479 CFDataRef SOSPeerInfoCopyBackupKey(SOSPeerInfoRef peer) {
480 return SOSPeerInfoV2DictionaryCopyData(peer, sBackupKeyKey);
481 }
482
483 CFMutableDictionaryRef SOSPeerInfoCopyEscrowRecord(SOSPeerInfoRef peer){
484 return SOSPeerInfoV2DictionaryCopyDictionary(peer, sEscrowRecord);
485 }
486
487 bool SOSPeerInfoHasBackupKey(SOSPeerInfoRef peer) {
488 CFDataRef bk = SOSPeerInfoCopyBackupKey(peer);
489 bool success = bk != NULL;
490 CFReleaseNull(bk);
491 return success;
492 }
493
494 SOSPeerInfoRef SOSPeerInfoCopyWithViewsChange(CFAllocatorRef allocator, SOSPeerInfoRef toCopy,
495 SOSViewActionCode action, CFStringRef viewname, SOSViewResultCode *retval,
496 SecKeyRef signingKey, CFErrorRef* error) {
497 SOSPeerInfoRef pi = SOSPeerInfoCreateCopy(allocator, toCopy, error);
498 if(action == kSOSCCViewEnable) {
499 *retval = SOSViewsEnable(pi, viewname, error);
500 require((kSOSCCViewMember == *retval), exit);
501 } else if(action == kSOSCCViewDisable) {
502 *retval = SOSViewsDisable(pi, viewname, error);
503 require((kSOSCCViewNotMember == *retval), exit);
504 }
505
506 require_action_quiet(SOSPeerInfoSign(signingKey, pi, error), exit, *retval = kSOSCCGeneralViewError);
507 return pi;
508
509 exit:
510 CFReleaseNull(pi);
511 return NULL;
512 }
513
514
515 CFStringRef sPingKey = CFSTR("Ping");
516
517 SOSPeerInfoRef SOSPeerInfoCopyWithPing(CFAllocatorRef allocator, SOSPeerInfoRef toCopy, SecKeyRef signingKey, CFErrorRef* error) {
518 SOSPeerInfoRef pi = SOSPeerInfoCreateCopy(allocator, toCopy, error);
519 CFDataRef ping = CFDataCreateWithRandomBytes(8);
520 SOSPeerInfoV2DictionarySetValue(pi, sPingKey, ping);
521 SecKeyRef pub_key = SOSPeerInfoCopyPubKey(pi, error);
522 require_quiet(pub_key, exit);
523 pi->id = SOSCopyIDOfKey(pub_key, error);
524 require_quiet(pi->id, exit);
525 require_action_quiet(SOSPeerInfoSign(signingKey, pi, error), exit, CFReleaseNull(pi));
526 exit:
527 CFReleaseNull(ping);
528 CFReleaseNull(pub_key);
529 return pi;
530 }
531
532
533 SOSViewResultCode SOSPeerInfoViewStatus(SOSPeerInfoRef pi, CFStringRef view, CFErrorRef *error) {
534 return SOSViewsQuery(pi, view, error);
535 }
536
537
538 SOSPeerInfoRef SOSPeerInfoCopyWithSecurityPropertyChange(CFAllocatorRef allocator, SOSPeerInfoRef toCopy,
539 SOSSecurityPropertyActionCode action, CFStringRef property, SOSSecurityPropertyResultCode *retval,
540 SecKeyRef signingKey, CFErrorRef* error) {
541 SOSPeerInfoRef pi = SOSPeerInfoCreateCopy(allocator, toCopy, error);
542 if(action == kSOSCCSecurityPropertyEnable) {
543 *retval = SOSSecurityPropertyEnable(pi, property, error);
544 require((kSOSCCSecurityPropertyValid == *retval), exit);
545 } else if(action == kSOSCCSecurityPropertyDisable) {
546 *retval = SOSSecurityPropertyDisable(pi, property, error);
547 require((kSOSCCSecurityPropertyNotValid == *retval), exit);
548 }
549
550 require_action_quiet(SOSPeerInfoSign(signingKey, pi, error), exit, *retval = kSOSCCGeneralViewError);
551 return pi;
552
553 exit:
554 CFReleaseNull(pi);
555 return NULL;
556 }
557
558 SOSViewResultCode SOSPeerInfoSecurityPropertyStatus(SOSPeerInfoRef pi, CFStringRef property, CFErrorRef *error) {
559 return SOSSecurityPropertyQuery(pi, property, error);
560 }
561
562
563
564 static void SOSPeerInfoDestroy(CFTypeRef aObj) {
565 SOSPeerInfoRef pi = (SOSPeerInfoRef) aObj;
566
567 if(!pi) return;
568 CFReleaseNull(pi->description);
569 CFReleaseNull(pi->signature);
570 CFReleaseNull(pi->gestalt);
571 CFReleaseNull(pi->id);
572 if(pi->v2Dictionary) CFReleaseNull(pi->v2Dictionary);
573 }
574
575 static Boolean SOSPeerInfoCompare(CFTypeRef lhs, CFTypeRef rhs) {
576 SOSPeerInfoRef lpeer = (SOSPeerInfoRef) lhs;
577 SOSPeerInfoRef rpeer = (SOSPeerInfoRef) rhs;
578 if(!lpeer || !rpeer) return false;
579 return CFEqualSafe(lpeer->description, rpeer->description) && CFEqualSafe(lpeer->signature, rpeer->signature);
580 }
581
582
583 CFComparisonResult SOSPeerInfoCompareByID(const void *val1, const void *val2, void *context) {
584 // The code below is necessary but not sufficient; not returning a CFComparisonResult
585 // It probably is OK to say that a NULL is < <non-NULL>
586 if (val1 == NULL || val2 == NULL) {
587 ptrdiff_t dv = val1 - val2;
588 return dv < 0 ? kCFCompareLessThan : dv == 0 ? kCFCompareEqualTo : kCFCompareGreaterThan;
589 }
590
591 CFStringRef v1 = SOSPeerInfoGetPeerID((SOSPeerInfoRef) val1);
592 CFStringRef v2 = SOSPeerInfoGetPeerID((SOSPeerInfoRef) val2);
593 if (v1 == NULL || v2 == NULL) {
594 ptrdiff_t dv = (const void *)v1 - (const void *)v2;
595 return dv < 0 ? kCFCompareLessThan : dv == 0 ? kCFCompareEqualTo : kCFCompareGreaterThan;
596 }
597
598 return CFStringCompare(v1, v2, 0);
599 }
600
601 static CFHashCode SOSPeerInfoHash(CFTypeRef cf) {
602 SOSPeerInfoRef peer = (SOSPeerInfoRef) cf;
603
604 return CFHash(peer->description) ^ CFHash(peer->signature);
605 }
606
607
608 static char boolToChars(bool val, char truechar, char falsechar) {
609 return val? truechar: falsechar;
610 }
611
612 static CFStringRef isKnown(CFStringRef ref) {
613 return ref? ref: CFSTR("Unknown ");
614 }
615
616 static CFStringRef copyDescriptionWithFormatOptions(CFTypeRef aObj, CFDictionaryRef formatOptions){
617
618 SOSPeerInfoRef pi = (SOSPeerInfoRef) aObj;
619 if(!pi) return NULL;
620
621 CFStringRef description = NULL;
622 // Get the format options we care about:
623 bool retired = SOSPeerInfoIsRetirementTicket(pi);
624 bool selfValid = SOSPeerInfoVerify(pi, NULL);
625 bool backingUp = SOSPeerInfoHasBackupKey(pi);
626 bool isKVS = SOSPeerInfoKVSOnly(pi);
627 CFStringRef osVersion = CFDictionaryGetValue(pi->gestalt, kPIOSVersionKey);
628 CFStringRef tmp = SOSPeerInfoV2DictionaryCopyString(pi, sDeviceID);
629 CFStringRef deviceID = CFStringCreateTruncatedCopy(tmp, 8);
630 CFReleaseNull(tmp);
631 CFStringRef serialNum = SOSPeerInfoCopySerialNumber(pi);
632 CFStringRef peerID = CFStringCreateTruncatedCopy(SOSPeerInfoGetPeerID(pi), 8);
633
634 // Calculate the truncated length
635
636 CFStringRef objectPrefix = CFStringCreateWithFormat(kCFAllocatorDefault, formatOptions, CFSTR("PI@%p"), pi);
637
638 description = CFStringCreateWithFormat(kCFAllocatorDefault, formatOptions,
639 CFSTR("<%@: [name: %20@] [%c%c%c%c%c%c%c] [type: %-20@] [spid: %8@] [os: %10@] [devid: %10@] [serial: %12@]"),
640 objectPrefix,
641 isKnown(SOSPeerInfoGetPeerName(pi)),
642 '-',
643 '-',
644 boolToChars(selfValid, 'S', 's'),
645 boolToChars(retired, 'R', 'r'),
646 boolToChars(backingUp, 'B', 'b'),
647 boolToChars(isKVS, 'K', 'I'),
648 '-',
649 isKnown(SOSPeerInfoGetPeerDeviceType(pi)), isKnown(peerID),
650 isKnown(osVersion), isKnown(deviceID), isKnown(serialNum));
651
652
653 CFReleaseNull(peerID);
654 CFReleaseNull(deviceID);
655 CFReleaseNull(serialNum);
656 CFReleaseNull(objectPrefix);
657
658 return description;
659 }
660
661 static CFStringRef SOSPeerInfoCopyFormatDescription(CFTypeRef aObj, CFDictionaryRef formatOptions) {
662
663 CFStringRef description = NULL;
664
665 description = copyDescriptionWithFormatOptions(aObj, formatOptions);
666
667 return description;
668 }
669
670 void SOSPeerInfoLogState(char *category, SOSPeerInfoRef pi, SecKeyRef pubKey, CFStringRef myPID, char sigchr) {
671 if(!pi) return;
672 bool appValid = SOSPeerInfoApplicationVerify(pi, pubKey, NULL);
673 bool retired = SOSPeerInfoIsRetirementTicket(pi);
674 bool selfValid = SOSPeerInfoVerify(pi, NULL);
675 bool backingUp = SOSPeerInfoHasBackupKey(pi);
676 bool isMe = CFEqualSafe(SOSPeerInfoGetPeerID(pi), myPID) == true;
677 bool isKVS = SOSPeerInfoKVSOnly(pi);
678 CFStringRef osVersion = CFDictionaryGetValue(pi->gestalt, kPIOSVersionKey);
679 CFStringRef tmp = SOSPeerInfoV2DictionaryCopyString(pi, sDeviceID);
680 CFStringRef deviceID = CFStringCreateTruncatedCopy(tmp, 8);
681 CFReleaseNull(tmp);
682 CFStringRef serialNum = SOSPeerInfoCopySerialNumber(pi);
683 CFStringRef peerID = CFStringCreateTruncatedCopy(SOSPeerInfoGetPeerID(pi), 8);
684
685 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)),
686 boolToChars(isMe, 'M', 'm'),
687 boolToChars(appValid, 'A', 'a'),
688 boolToChars(selfValid, 'S', 's'),
689 boolToChars(retired, 'R', 'r'),
690 boolToChars(backingUp, 'B', 'b'),
691 boolToChars(isKVS, 'K', 'I'),
692 sigchr,
693 isKnown(SOSPeerInfoGetPeerDeviceType(pi)), isKnown(peerID),
694 isKnown(osVersion), isKnown(deviceID), isKnown(serialNum));
695
696 CFReleaseNull(peerID);
697 CFReleaseNull(deviceID);
698 CFReleaseNull(serialNum);
699 }
700
701 CFDictionaryRef SOSPeerInfoCopyPeerGestalt(SOSPeerInfoRef pi) {
702 CFRetain(pi->gestalt);
703 return pi->gestalt;
704 }
705
706 CFDictionaryRef SOSPeerGetGestalt(SOSPeerInfoRef pi){
707 return pi->gestalt;
708 }
709
710 CFStringRef SOSPeerInfoGetPeerName(SOSPeerInfoRef peer) {
711 return SOSPeerInfoLookupGestaltValue(peer, kPIUserDefinedDeviceNameKey);
712 }
713
714 CFStringRef SOSPeerInfoGetPeerDeviceType(SOSPeerInfoRef peer) {
715 return SOSPeerInfoLookupGestaltValue(peer, kPIDeviceModelNameKey);
716 }
717
718 CFIndex SOSPeerInfoGetPeerProtocolVersion(SOSPeerInfoRef peer) {
719 CFIndex version = PEERINFO_CURRENT_VERSION;
720 CFTypeRef val = SOSPeerInfoLookupGestaltValue(peer, kPIMessageProtocolVersionKey);
721 if (val && CFGetTypeID(val) == CFNumberGetTypeID())
722 CFNumberGetValue(val, kCFNumberCFIndexType, &version);
723 return version;
724 }
725
726 CFTypeRef SOSPeerInfoLookupGestaltValue(SOSPeerInfoRef pi, CFStringRef key) {
727 return CFDictionaryGetValue(pi->gestalt, key);
728 }
729
730 CFStringRef SOSPeerInfoGetPeerID(SOSPeerInfoRef pi) {
731 return pi ? pi->id : NULL;
732 }
733
734 bool SOSPeerInfoPeerIDEqual(SOSPeerInfoRef pi, CFStringRef myPeerID) {
735 return CFEqualSafe(myPeerID, SOSPeerInfoGetPeerID(pi));
736 }
737
738 CFIndex SOSPeerInfoGetVersion(SOSPeerInfoRef pi) {
739 return pi->version;
740 }
741
742 bool SOSPeerInfoUpdateDigestWithPublicKeyBytes(SOSPeerInfoRef peer, const struct ccdigest_info *di,
743 ccdigest_ctx_t ctx, CFErrorRef *error) {
744 CFDataRef pubKeyBytes = CFDictionaryGetValue(peer->description, sPublicKeyKey);
745
746 if(!pubKeyBytes) {
747 SOSCreateErrorWithFormat(kSOSErrorEncodeFailure, NULL, error, NULL, CFSTR("Digest failed – no public key"));
748 return false;
749 }
750
751 ccdigest_update(di, ctx, CFDataGetLength(pubKeyBytes), CFDataGetBytePtr(pubKeyBytes));
752
753 return true;
754 }
755
756 bool SOSPeerInfoUpdateDigestWithDescription(SOSPeerInfoRef peer, const struct ccdigest_info *di,
757 ccdigest_ctx_t ctx, CFErrorRef *error) {
758 if(SOSPeerInfoVersionHasV2Data(peer)) SOSPeerInfoPackV2Data(peer);
759 size_t description_size = der_sizeof_plist(peer->description, error);
760 uint8_t data_begin[description_size];
761 uint8_t *data_end = data_begin + description_size;
762 uint8_t *encoded = der_encode_plist(peer->description, error, data_begin, data_end);
763
764 if(!encoded) {
765 SOSCreateErrorWithFormat(kSOSErrorEncodeFailure, NULL, error, NULL, CFSTR("Description encode failed"));
766 return false;
767 }
768
769 ccdigest_update(di, ctx, description_size, data_begin);
770
771 return true;
772 }
773
774
775 static CFDataRef sosCreateDate() {
776 CFDateRef now = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent());
777 size_t bufsiz = der_sizeof_date(now, NULL);
778 uint8_t buf[bufsiz];
779 der_encode_date(now, NULL, buf, buf+bufsiz);
780 CFReleaseNull(now);
781 return CFDataCreate(NULL, buf, bufsiz);
782 }
783
784 static CFDateRef sosCreateCFDate(CFDataRef sosdate) {
785 CFDateRef date;
786 der_decode_date(NULL, 0, &date, NULL, CFDataGetBytePtr(sosdate),
787 CFDataGetBytePtr(sosdate) + CFDataGetLength(sosdate));
788 return date;
789 }
790
791 static bool sospeer_application_hash(SOSPeerInfoRef pi, const struct ccdigest_info *di, uint8_t *hbuf) {
792 CFDataRef appdate = asData(CFDictionaryGetValue(pi->description, sApplicationDate), NULL);
793 if(!appdate) return false;
794 ccdigest_di_decl(di, ctx);
795 ccdigest_init(di, ctx);
796 ccdigest_update(di, ctx, CFDataGetLength(appdate), CFDataGetBytePtr(appdate));
797 if (!SOSPeerInfoUpdateDigestWithPublicKeyBytes(pi, di, ctx, NULL)) return false;
798 ccdigest_final(di, ctx, hbuf);
799 return true;
800 }
801
802 SOSPeerInfoRef SOSPeerInfoCopyAsApplication(SOSPeerInfoRef original, SecKeyRef userkey, SecKeyRef peerkey, CFErrorRef *error) {
803 SOSPeerInfoRef result = NULL;
804 SOSPeerInfoRef pi = SOSPeerInfoCreateCopy(kCFAllocatorDefault, original, error);
805
806 const struct ccdigest_info *di = ccsha256_di();
807 uint8_t hbuf[di->output_size];
808 CFDataRef usersig = NULL;
809
810 CFDataRef creationDate = sosCreateDate();
811 CFDictionarySetValue(pi->description, sApplicationDate, creationDate);
812 CFReleaseNull(creationDate);
813
814 // Create User Application Signature
815 require_action_quiet(sospeer_application_hash(pi, di, hbuf), fail,
816 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Failed to create hash for peer applicant"), NULL, error));
817
818 usersig = sosCopySignedHash(userkey, di, hbuf);
819 require_action_quiet(usersig, fail,
820 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Failed to sign public key hash for peer"), NULL, error));
821
822 CFDictionarySetValue(pi->description, sApplicationUsig, usersig);
823
824 require_quiet(SOSPeerInfoSign(peerkey, pi, error), fail);
825
826 result = pi;
827 pi = NULL;
828
829 fail:
830 CFReleaseNull(usersig);
831 CFReleaseNull(pi);
832 return result;
833 }
834
835 bool SOSPeerInfoApplicationVerify(SOSPeerInfoRef pi, SecKeyRef userkey, CFErrorRef *error) {
836 const struct ccdigest_info *di = ccsha256_di();
837 uint8_t hbuf[di->output_size];
838 bool result = false;
839
840 CFDataRef usig = CFDictionaryGetValue(pi->description, sApplicationUsig);
841 require_action_quiet(usig, exit,
842 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Peer is not an applicant"), NULL, error));
843 // Verify User Application Signature
844 require_action_quiet(sospeer_application_hash(pi, di, hbuf), exit,
845 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Failed to create hash for peer applicant"), NULL, error));
846 require_action_quiet(sosVerifyHash(userkey, di, hbuf, usig), exit,
847 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("user signature of public key hash fails to verify"), NULL, error));
848
849 result = SOSPeerInfoVerify(pi, error);
850
851 exit:
852 return result;
853 }
854
855
856 static CF_RETURNS_RETAINED CFDateRef sosPeerInfoGetDate(SOSPeerInfoRef pi, CFStringRef entry) {
857 if(!pi) return NULL;
858 CFDataRef sosdate = CFDictionaryGetValue(pi->description, entry);
859 if(!sosdate) return NULL;
860 CFDateRef date = sosCreateCFDate(sosdate);
861
862 return date;
863 }
864
865 CF_RETURNS_RETAINED CFDateRef SOSPeerInfoGetApplicationDate(SOSPeerInfoRef pi) {
866 return sosPeerInfoGetDate(pi, sApplicationDate);
867 }
868
869 CF_RETURNS_RETAINED CFDateRef SOSPeerInfoGetRetirementDate(SOSPeerInfoRef pi) {
870 return sosPeerInfoGetDate(pi, sRetirementDate);
871 }
872
873
874
875 //
876 // Gestalt helpers
877 //
878
879 CFStringRef SOSPeerGestaltGetName(CFDictionaryRef gestalt) {
880 CFStringRef name = SOSPeerGestaltGetAnswer(gestalt, kPIUserDefinedDeviceNameKey);
881 return isString(name) ? name : NULL;
882 }
883
884 CFTypeRef SOSPeerGestaltGetAnswer(CFDictionaryRef gestalt, CFStringRef question) {
885 return gestalt ? CFDictionaryGetValue(gestalt, question) : NULL;
886 }
887
888 //
889 // Peer Retirement
890 //
891
892
893 SOSPeerInfoRef SOSPeerInfoCreateRetirementTicket(CFAllocatorRef allocator, SecKeyRef privKey, SOSPeerInfoRef peer, CFErrorRef *error) {
894 // Copy PeerInfo
895 SOSPeerInfoRef pi = SOSPeerInfoCreateCopy(allocator, peer, error);
896
897 require(pi, fail);
898
899 // Fill out Resignation Date
900 CFDataRef resignationDate = sosCreateDate();
901 CFDictionaryAddValue(pi->description, sRetirementDate, resignationDate);
902 CFReleaseNull(resignationDate);
903
904 require(SOSPeerInfoSign(privKey, pi, error), fail);
905
906 return pi;
907
908 fail:
909 CFReleaseNull(pi);
910 return NULL;
911 }
912
913 CFStringRef SOSPeerInfoInspectRetirementTicket(SOSPeerInfoRef pi, CFErrorRef *error) {
914 CFStringRef retval = NULL;
915 CFDateRef now = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent());
916 CFDateRef retirement = NULL;
917
918 require_quiet(SOSPeerInfoVerify(pi, error), err);
919
920 retirement = sosCreateCFDate(CFDictionaryGetValue(pi->description, sRetirementDate));
921 require_action_quiet(retirement, err,
922 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Peer is not retired"), NULL, error));
923
924 require_action_quiet(CFDateCompare(now, retirement, NULL) == kCFCompareGreaterThan, err,
925 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Retirement date is after current date"), NULL, error));
926
927 retval = SOSPeerInfoGetPeerID(pi);
928
929 err:
930 CFReleaseNull(now);
931 CFReleaseNull(retirement);
932 return retval;
933 }
934
935 bool SOSPeerInfoRetireRetirementTicket(size_t max_seconds, SOSPeerInfoRef pi) {
936 CFDateRef now = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent());
937 CFDateRef retirement = sosCreateCFDate(CFDictionaryGetValue(pi->description, sRetirementDate));
938 CFTimeInterval timediff = CFDateGetTimeIntervalSinceDate(now, retirement); // diff in seconds
939 CFReleaseNull(now);
940 CFReleaseNull(retirement);
941 if(timediff > (max_seconds)) return true;
942 return false;
943 }
944
945 bool SOSPeerInfoIsRetirementTicket(SOSPeerInfoRef pi) {
946 CFDataRef flag = CFDictionaryGetValue(pi->description, sRetirementDate);
947 return flag != NULL;
948 }
949
950 bool SOSPeerInfoIsCloudIdentity(SOSPeerInfoRef pi) {
951 CFTypeRef value = CFDictionaryGetValue(pi->description, sCloudIdentityKey);
952 return CFEqualSafe(value, kCFBooleanTrue);
953 }
954
955 SOSPeerInfoRef SOSPeerInfoUpgradeSignatures(CFAllocatorRef allocator, SecKeyRef privKey, SecKeyRef peerKey, SOSPeerInfoRef peer, CFErrorRef *error) {
956 SecKeyRef pubKey = SecKeyCreatePublicFromPrivate(privKey);
957 SOSPeerInfoRef retval = NULL;
958
959 retval = SOSPeerInfoCopyAsApplication(peer, privKey, peerKey, error);
960 CFReleaseNull(pubKey);
961 return retval;
962 }
963
964 CFBooleanRef SOSPeerInfoCopyIDSPreference(SOSPeerInfoRef peer){
965 CFBooleanRef preference = (CFBooleanRef)SOSPeerInfoV2DictionaryCopyBoolean(peer, sPreferIDS);
966 return (preference ? preference : CFRetain(kCFBooleanFalse));
967 }
968
969
970 SOSPeerInfoRef SOSPeerInfoSetIDSPreference(CFAllocatorRef allocator, SOSPeerInfoRef toCopy, CFBooleanRef preference, SecKeyRef signingKey, CFErrorRef *error){
971 return SOSPeerInfoCopyWithModification(allocator, toCopy, signingKey, error,
972 ^bool(SOSPeerInfoRef peerToModify, CFErrorRef *error) {
973 SOSPeerInfoV2DictionarySetValue(peerToModify, sPreferIDS, preference);
974 return true;
975 });
976 }
977
978 CFBooleanRef SOSPeerInfoCopyIDSFragmentationPreference(SOSPeerInfoRef peer){
979 CFBooleanRef preference = (CFBooleanRef)SOSPeerInfoV2DictionaryCopyBoolean(peer, sPreferIDSFragmentation);
980 return (preference ? preference : CFRetain(kCFBooleanFalse));
981 }
982
983 CFBooleanRef SOSPeerInfoCopyIDSACKModelPreference(SOSPeerInfoRef peer){
984 CFBooleanRef preference = (CFBooleanRef)SOSPeerInfoV2DictionaryCopyBoolean(peer, sPreferIDSACKModel);
985 return (preference ? preference : CFRetain(kCFBooleanFalse));
986 }
987
988 SOSPeerInfoRef SOSPeerInfoSetIDSFragmentationPreference(CFAllocatorRef allocator, SOSPeerInfoRef toCopy, CFBooleanRef preference, SecKeyRef signingKey, CFErrorRef *error){
989 return SOSPeerInfoCopyWithModification(allocator, toCopy, signingKey, error,
990 ^bool(SOSPeerInfoRef peerToModify, CFErrorRef *error) {
991 SOSPeerInfoV2DictionarySetValue(peerToModify, sPreferIDSFragmentation, preference);
992 return true;
993 });
994 }
995
996 SOSPeerInfoRef SOSPeerInfoSetIDSACKModelPreference(CFAllocatorRef allocator, SOSPeerInfoRef toCopy, CFBooleanRef preference, SecKeyRef signingKey, CFErrorRef *error){
997 return SOSPeerInfoCopyWithModification(allocator, toCopy, signingKey, error,
998 ^bool(SOSPeerInfoRef peerToModify, CFErrorRef *error) {
999 SOSPeerInfoV2DictionarySetValue(peerToModify, sPreferIDSACKModel, preference);
1000 return true;
1001 });
1002 }
1003
1004 bool SOSPeerInfoTransportTypeIs(SOSPeerInfoRef pi, CFStringRef transportType) {
1005 return SOSPeerInfoV2DictionaryHasStringValue(pi, sTransportType, transportType);
1006 }
1007
1008 CFStringRef SOSPeerInfoCopyTransportType(SOSPeerInfoRef peer){
1009 CFStringRef transportType = (CFStringRef)SOSPeerInfoV2DictionaryCopyString(peer, sTransportType);
1010 return (transportType ? transportType : CFRetain(SOSTransportMessageTypeKVS));
1011 }
1012
1013 SOSPeerInfoRef SOSPeerInfoSetTransportType(CFAllocatorRef allocator, SOSPeerInfoRef toCopy, CFStringRef transportType, SecKeyRef signingKey, CFErrorRef *error){
1014
1015 return SOSPeerInfoCopyWithModification(allocator, toCopy, signingKey, error,
1016 ^bool(SOSPeerInfoRef peerToModify, CFErrorRef *error) {
1017 SOSPeerInfoV2DictionarySetValue(peerToModify, sTransportType, transportType);
1018 return true;
1019 });
1020 }
1021
1022 bool SOSPeerInfoKVSOnly(SOSPeerInfoRef pi) {
1023 CFStringRef transportType = SOSPeerInfoCopyTransportType(pi);
1024 bool retval = CFEqualSafe(transportType, SOSTransportMessageTypeKVS);
1025 CFReleaseNull(transportType);
1026 return retval;
1027 }
1028
1029 bool SOSPeerInfoHasDeviceID(SOSPeerInfoRef peer) {
1030 return SOSPeerInfoV2DictionaryHasString(peer, sDeviceID);
1031 }
1032
1033 CFStringRef SOSPeerInfoCopyDeviceID(SOSPeerInfoRef peer){
1034 return (CFStringRef)SOSPeerInfoV2DictionaryCopyString(peer, sDeviceID);
1035 }
1036
1037 SOSPeerInfoRef SOSPeerInfoSetDeviceID(CFAllocatorRef allocator, SOSPeerInfoRef toCopy, CFStringRef IDS, SecKeyRef signingKey, CFErrorRef *error){
1038
1039 return SOSPeerInfoCopyWithModification(allocator, toCopy, signingKey, error,
1040 ^bool(SOSPeerInfoRef peerToModify, CFErrorRef *error) {
1041 SOSPeerInfoV2DictionarySetValue(peerToModify, sDeviceID, IDS);
1042 return true;
1043 });
1044 }
1045
1046 bool SOSPeerInfoShouldUseIDSTransport(SOSPeerInfoRef myPeer, SOSPeerInfoRef theirPeer){
1047 return SOSPeerInfoHasDeviceID(myPeer) && SOSPeerInfoTransportTypeIs(myPeer, SOSTransportMessageTypeIDSV2) &&
1048 SOSPeerInfoHasDeviceID(theirPeer) && SOSPeerInfoTransportTypeIs(theirPeer, SOSTransportMessageTypeIDSV2);
1049 }
1050
1051 bool SOSPeerInfoShouldUseIDSMessageFragmentation(SOSPeerInfoRef myPeer, SOSPeerInfoRef theirPeer){
1052
1053 bool success = false;
1054
1055 CFBooleanRef myPreference = SOSPeerInfoCopyIDSFragmentationPreference(myPeer);
1056
1057 CFBooleanRef theirPreference = SOSPeerInfoCopyIDSFragmentationPreference(theirPeer);
1058 secnotice("IDS Transport", "mypreference: %@, theirpreference: %@", myPreference, theirPreference);
1059 if((myPreference == kCFBooleanTrue && theirPreference == kCFBooleanTrue))
1060 success = true;
1061
1062 CFReleaseNull(myPreference);
1063 CFReleaseNull(theirPreference);
1064 return success;
1065 }
1066
1067 bool SOSPeerInfoShouldUseACKModel(SOSPeerInfoRef myPeer, SOSPeerInfoRef theirPeer){
1068 bool success = false;
1069
1070 CFBooleanRef myPreference = SOSPeerInfoCopyIDSACKModelPreference(myPeer);
1071
1072 CFBooleanRef theirPreference = SOSPeerInfoCopyIDSACKModelPreference(theirPeer);
1073 secnotice("IDS Transport", "mypreference: %@, theirpreference: %@", myPreference, theirPreference);
1074 if((myPreference == kCFBooleanTrue && theirPreference == kCFBooleanTrue))
1075 success = true;
1076
1077 CFReleaseNull(myPreference);
1078 CFReleaseNull(theirPreference);
1079 return success;
1080
1081 }
1082
1083 SOSPeerInfoDeviceClass SOSPeerInfoGetClass(SOSPeerInfoRef pi) {
1084 static CFDictionaryRef devID2Class = NULL;
1085 static dispatch_once_t onceToken = 0;
1086
1087 dispatch_once(&onceToken, ^{
1088 CFNumberRef cfSOSPeerInfo_macOS = CFNumberCreateWithCFIndex(kCFAllocatorDefault, SOSPeerInfo_macOS);
1089 CFNumberRef cfSOSPeerInfo_iOS = CFNumberCreateWithCFIndex(kCFAllocatorDefault, SOSPeerInfo_iOS);
1090 CFNumberRef cfSOSPeerInfo_iCloud = CFNumberCreateWithCFIndex(kCFAllocatorDefault, SOSPeerInfo_iCloud);
1091 // CFNumberRef cfSOSPeerInfo_watchOS = CFNumberCreateWithCFIndex(kCFAllocatorDefault, SOSPeerInfo_watchOS);
1092 // CFNumberRef cfSOSPeerInfo_tvOS = CFNumberCreateWithCFIndex(kCFAllocatorDefault, SOSPeerInfo_tvOS);
1093
1094 devID2Class = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
1095 CFSTR("Mac Pro"), cfSOSPeerInfo_macOS,
1096 CFSTR("MacBook"), cfSOSPeerInfo_macOS,
1097 CFSTR("MacBook Pro"), cfSOSPeerInfo_macOS,
1098 CFSTR("iCloud"), cfSOSPeerInfo_iCloud,
1099 CFSTR("iMac"), cfSOSPeerInfo_macOS,
1100 CFSTR("iPad"), cfSOSPeerInfo_iOS,
1101 CFSTR("iPhone"), cfSOSPeerInfo_iOS,
1102 CFSTR("iPod touch"), cfSOSPeerInfo_iOS,
1103 NULL);
1104 CFReleaseNull(cfSOSPeerInfo_macOS);
1105 CFReleaseNull(cfSOSPeerInfo_iOS);
1106 CFReleaseNull(cfSOSPeerInfo_iCloud);
1107 });
1108 SOSPeerInfoDeviceClass retval = SOSPeerInfo_unknown;
1109 CFStringRef dt = SOSPeerInfoGetPeerDeviceType(pi);
1110 require_quiet(dt, errOut);
1111 CFNumberRef classNum = CFDictionaryGetValue(devID2Class, dt);
1112 require_quiet(classNum, errOut);
1113 CFIndex tmp;
1114 require_quiet(CFNumberGetValue(classNum, kCFNumberCFIndexType, &tmp), errOut);
1115 retval = (SOSPeerInfoDeviceClass) tmp;
1116 errOut:
1117 return retval;
1118 }