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