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