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