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