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