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