]> git.saurik.com Git - apple/security.git/blob - keychain/SecureObjectSync/SOSPeerInfo.m
Security-59306.11.20.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 static CFDictionaryRef SOSPeerInfoUpdateAndCopyRecord(SOSPeerInfoRef peer, CFStringRef dsid, CFDictionaryRef escrowRecord){
460
461 CFMutableDictionaryRef existingEscrowRecords = SOSPeerInfoCopyEscrowRecord(peer);
462
463 if(escrowRecord == NULL && existingEscrowRecords != NULL)
464 {
465 CFDictionaryRemoveValue(existingEscrowRecords, dsid);
466 return existingEscrowRecords;
467 }
468
469 if(existingEscrowRecords == NULL)
470 existingEscrowRecords = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
471
472 CFDictionarySetValue(existingEscrowRecords, dsid, escrowRecord);
473
474 return existingEscrowRecords;
475 }
476
477
478 SOSPeerInfoRef SOSPeerInfoCopyWithEscrowRecordUpdate(CFAllocatorRef allocator, SOSPeerInfoRef toCopy, CFStringRef dsid, CFDictionaryRef escrowRecord, SecKeyRef signingKey, CFErrorRef *error) {
479 return SOSPeerInfoCopyWithModification(allocator, toCopy, signingKey, error,
480 ^bool(SOSPeerInfoRef peerToModify, CFErrorRef *error) {
481
482 CFDictionaryRef updatedEscrowRecords = SOSPeerInfoUpdateAndCopyRecord(peerToModify, dsid, escrowRecord);
483 SOSPeerInfoV2DictionarySetValue(peerToModify, sEscrowRecord, updatedEscrowRecords);
484 CFReleaseNull(updatedEscrowRecords);
485 return true;
486 });
487 }
488
489 SOSPeerInfoRef SOSPeerInfoCopyWithReplacedEscrowRecords(CFAllocatorRef allocator, SOSPeerInfoRef toCopy, CFDictionaryRef escrowRecords, SecKeyRef signingKey, CFErrorRef *error) {
490 return SOSPeerInfoCopyWithModification(allocator, toCopy, signingKey, error,
491 ^bool(SOSPeerInfoRef peerToModify, CFErrorRef *error) {
492 if(escrowRecords != NULL)
493 SOSPeerInfoV2DictionarySetValue(peerToModify, sEscrowRecord, escrowRecords);
494
495 return true;
496 });
497 }
498
499 CFDataRef SOSPeerInfoCopyBackupKey(SOSPeerInfoRef peer) {
500 return SOSPeerInfoV2DictionaryCopyData(peer, sBackupKeyKey);
501 }
502
503 CFMutableDictionaryRef SOSPeerInfoCopyEscrowRecord(SOSPeerInfoRef peer){
504 return SOSPeerInfoV2DictionaryCopyDictionary(peer, sEscrowRecord);
505 }
506
507 bool SOSPeerInfoHasBackupKey(SOSPeerInfoRef peer) {
508 CFDataRef bk = SOSPeerInfoCopyBackupKey(peer);
509 bool success = bk != NULL;
510 CFReleaseNull(bk);
511 return success;
512 }
513
514 SOSPeerInfoRef SOSPeerInfoCopyWithViewsChange(CFAllocatorRef allocator, SOSPeerInfoRef toCopy,
515 SOSViewActionCode action, CFStringRef viewname, SOSViewResultCode *retval,
516 SecKeyRef signingKey, CFErrorRef* error) {
517 SOSPeerInfoRef pi = SOSPeerInfoCreateCopy(allocator, toCopy, error);
518 if(action == kSOSCCViewEnable) {
519 *retval = SOSViewsEnable(pi, viewname, error);
520 require((kSOSCCViewMember == *retval), exit);
521 } else if(action == kSOSCCViewDisable) {
522 *retval = SOSViewsDisable(pi, viewname, error);
523 require((kSOSCCViewNotMember == *retval), exit);
524 }
525
526 require_action_quiet(SOSPeerInfoSign(signingKey, pi, error), exit, *retval = kSOSCCGeneralViewError);
527 return pi;
528
529 exit:
530 CFReleaseNull(pi);
531 return NULL;
532 }
533
534
535 CFStringRef sPingKey = CFSTR("Ping");
536
537 SOSPeerInfoRef SOSPeerInfoCopyWithPing(CFAllocatorRef allocator, SOSPeerInfoRef toCopy, SecKeyRef signingKey, CFErrorRef* error) {
538 SOSPeerInfoRef pi = SOSPeerInfoCreateCopy(allocator, toCopy, error);
539 CFDataRef ping = CFDataCreateWithRandomBytes(8);
540 SOSPeerInfoV2DictionarySetValue(pi, sPingKey, ping);
541 SecKeyRef pub_key = SOSPeerInfoCopyPubKey(pi, error);
542 require_quiet(pub_key, exit);
543 pi->peerID = SOSCopyIDOfKey(pub_key, error);
544 require_quiet(pi->peerID, exit);
545 require_action_quiet(SOSPeerInfoSign(signingKey, pi, error), exit, CFReleaseNull(pi));
546 exit:
547 CFReleaseNull(ping);
548 CFReleaseNull(pub_key);
549 return pi;
550 }
551
552
553 SOSViewResultCode SOSPeerInfoViewStatus(SOSPeerInfoRef pi, CFStringRef view, CFErrorRef *error) {
554 return SOSViewsQuery(pi, view, error);
555 }
556
557 static void SOSPeerInfoDestroy(CFTypeRef aObj) {
558 SOSPeerInfoRef pi = (SOSPeerInfoRef) aObj;
559
560 if(!pi) return;
561 CFReleaseNull(pi->description);
562 CFReleaseNull(pi->signature);
563 CFReleaseNull(pi->gestalt);
564 CFReleaseNull(pi->peerID);
565 CFReleaseNull(pi->v2Dictionary);
566 CFReleaseNull(pi->verifiedAppKeyID);
567 pi->verifiedResult = false;
568 }
569
570 static Boolean SOSPeerInfoCompare(CFTypeRef lhs, CFTypeRef rhs) {
571 SOSPeerInfoRef lpeer = (SOSPeerInfoRef) lhs;
572 SOSPeerInfoRef rpeer = (SOSPeerInfoRef) rhs;
573 if(!lpeer || !rpeer) return false;
574 return CFEqualSafe(lpeer->description, rpeer->description) && CFEqualSafe(lpeer->signature, rpeer->signature);
575 }
576
577
578 CFComparisonResult SOSPeerInfoCompareByID(const void *val1, const void *val2, void *context) {
579 // The code below is necessary but not sufficient; not returning a CFComparisonResult
580 // It probably is OK to say that a NULL is < <non-NULL>
581 if (val1 == NULL || val2 == NULL) {
582 ptrdiff_t dv = val1 - val2;
583 return dv < 0 ? kCFCompareLessThan : dv == 0 ? kCFCompareEqualTo : kCFCompareGreaterThan;
584 }
585
586 CFStringRef v1 = SOSPeerInfoGetPeerID((SOSPeerInfoRef) val1);
587 CFStringRef v2 = SOSPeerInfoGetPeerID((SOSPeerInfoRef) val2);
588 if (v1 == NULL || v2 == NULL) {
589 ptrdiff_t dv = (const void *)v1 - (const void *)v2;
590 return dv < 0 ? kCFCompareLessThan : dv == 0 ? kCFCompareEqualTo : kCFCompareGreaterThan;
591 }
592
593 return CFStringCompare(v1, v2, 0);
594 }
595
596
597 CFComparisonResult SOSPeerInfoCompareByApplicationDate(const void *val1, const void *val2, void *context) {
598 // The code below is necessary but not sufficient; not returning a CFComparisonResult
599 // It probably is OK to say that a NULL is < <non-NULL>
600 if (val1 == NULL || val2 == NULL) {
601 ptrdiff_t dv = val1 - val2;
602 return dv < 0 ? kCFCompareLessThan : dv == 0 ? kCFCompareEqualTo : kCFCompareGreaterThan;
603 }
604
605 CFDateRef v1 = SOSPeerInfoGetApplicationDate((SOSPeerInfoRef) val1);
606 CFDateRef v2 = SOSPeerInfoGetApplicationDate((SOSPeerInfoRef) val2);
607 if (v1 == NULL || v2 == NULL) {
608 ptrdiff_t dv = (const void *)v1 - (const void *)v2;
609 CFReleaseNull(v1);
610 CFReleaseNull(v2);
611 return dv < 0 ? kCFCompareLessThan : dv == 0 ? kCFCompareEqualTo : kCFCompareGreaterThan;
612 }
613
614 CFComparisonResult retval = CFDateCompare(v1, v2, 0);
615 CFReleaseNull(v1);
616 CFReleaseNull(v2);
617 return retval;
618 }
619
620 static CFHashCode SOSPeerInfoHash(CFTypeRef cf) {
621 SOSPeerInfoRef peer = (SOSPeerInfoRef) cf;
622
623 return CFHash(peer->description) ^ CFHash(peer->signature);
624 }
625
626
627 static char boolToChars(bool val, char truechar, char falsechar) {
628 return val? truechar: falsechar;
629 }
630
631 static CFStringRef isKnown(CFStringRef ref) {
632 return ref? ref: CFSTR("Unknown ");
633 }
634
635 static CFStringRef copyDescriptionWithFormatOptions(CFTypeRef aObj, CFDictionaryRef formatOptions){
636
637 SOSPeerInfoRef pi = (SOSPeerInfoRef) aObj;
638 if(!pi) return NULL;
639
640 CFStringRef description = NULL;
641 // Get the format options we care about:
642 bool retired = SOSPeerInfoIsRetirementTicket(pi);
643 bool selfValid = SOSPeerInfoVerify(pi, NULL);
644 bool backingUp = SOSPeerInfoHasBackupKey(pi);
645 bool isKVS = SOSPeerInfoKVSOnly(pi);
646 CFStringRef osVersion = CFDictionaryGetValue(pi->gestalt, kPIOSVersionKey);
647 CFStringRef tmp = SOSPeerInfoV2DictionaryCopyString(pi, sDeviceID);
648 CFStringRef deviceID = CFStringCreateTruncatedCopy(tmp, 8);
649 CFReleaseNull(tmp);
650 CFStringRef serialNum = SOSPeerInfoCopySerialNumber(pi);
651 CFStringRef peerID = CFStringCreateTruncatedCopy(SOSPeerInfoGetPeerID(pi), 8);
652
653 // Calculate the truncated length
654
655 CFStringRef objectPrefix = CFStringCreateWithFormat(kCFAllocatorDefault, formatOptions, CFSTR("PI@%p"), pi);
656
657 description = CFStringCreateWithFormat(kCFAllocatorDefault, formatOptions,
658 CFSTR("<%@: [name: %20@] [%c%c%c%c%c%c%c] [type: %-20@] [spid: %8@] [os: %10@] [devid: %10@] [serial: %12@]"),
659 objectPrefix,
660 isKnown(SOSPeerInfoGetPeerName(pi)),
661 '-',
662 '-',
663 boolToChars(selfValid, 'S', 's'),
664 boolToChars(retired, 'R', 'r'),
665 boolToChars(backingUp, 'B', 'b'),
666 boolToChars(isKVS, 'K', 'I'),
667 '-',
668 isKnown(SOSPeerInfoGetPeerDeviceType(pi)), isKnown(peerID),
669 isKnown(osVersion), isKnown(deviceID), isKnown(serialNum));
670
671 CFReleaseNull(peerID);
672 CFReleaseNull(deviceID);
673 CFReleaseNull(serialNum);
674 CFReleaseNull(objectPrefix);
675
676 return description;
677 }
678
679 static CFStringRef SOSPeerInfoCopyFormatDescription(CFTypeRef aObj, CFDictionaryRef formatOptions) {
680
681 CFStringRef description = NULL;
682
683 description = copyDescriptionWithFormatOptions(aObj, formatOptions);
684
685 return description;
686 }
687
688 void SOSPeerInfoLogState(char *category, SOSPeerInfoRef pi, SecKeyRef pubKey, CFStringRef myPID, char sigchr) {
689 if(!pi) return;
690 bool appValid = SOSPeerInfoApplicationVerify(pi, pubKey, NULL);
691 bool retired = SOSPeerInfoIsRetirementTicket(pi);
692 // We won't inflate invalid peerInfos. Mark this true to keep scanning utilities from breaking.
693 bool selfValid = true;
694 bool backingUp = SOSPeerInfoHasBackupKey(pi);
695 bool isMe = CFEqualSafe(SOSPeerInfoGetPeerID(pi), myPID) == true;
696 bool isKVS = SOSPeerInfoKVSOnly(pi);
697 CFStringRef osVersion = CFDictionaryGetValue(pi->gestalt, kPIOSVersionKey);
698 CFStringRef tmp = SOSPeerInfoV2DictionaryCopyString(pi, sDeviceID);
699 CFStringRef deviceID = CFStringCreateTruncatedCopy(tmp, 8);
700 CFReleaseNull(tmp);
701 CFStringRef serialNum = SOSPeerInfoCopySerialNumber(pi);
702 CFStringRef peerID = CFStringCreateTruncatedCopy(SOSPeerInfoGetPeerID(pi), 8);
703
704 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)),
705 boolToChars(isMe, 'M', 'm'),
706 boolToChars(appValid, 'A', 'a'),
707 boolToChars(selfValid, 'S', 's'),
708 boolToChars(retired, 'R', 'r'),
709 boolToChars(backingUp, 'B', 'b'),
710 boolToChars(isKVS, 'K', 'I'),
711 sigchr,
712 isKnown(SOSPeerInfoGetPeerDeviceType(pi)), isKnown(peerID),
713 isKnown(osVersion), isKnown(deviceID), isKnown(serialNum));
714
715 CFReleaseNull(peerID);
716 CFReleaseNull(deviceID);
717 CFReleaseNull(serialNum);
718 }
719
720 CFDictionaryRef SOSPeerInfoCopyPeerGestalt(SOSPeerInfoRef pi) {
721 CFRetain(pi->gestalt);
722 return pi->gestalt;
723 }
724
725 CFDictionaryRef SOSPeerGetGestalt(SOSPeerInfoRef pi){
726 return pi->gestalt;
727 }
728
729 CFStringRef SOSPeerInfoGetPeerName(SOSPeerInfoRef peer) {
730 return SOSPeerInfoLookupGestaltValue(peer, kPIUserDefinedDeviceNameKey);
731 }
732
733 CFStringRef SOSPeerInfoGetPeerDeviceType(SOSPeerInfoRef peer) {
734 return SOSPeerInfoLookupGestaltValue(peer, kPIDeviceModelNameKey);
735 }
736
737 CFIndex SOSPeerInfoGetPeerProtocolVersion(SOSPeerInfoRef peer) {
738 CFIndex version = PEERINFO_CURRENT_VERSION;
739 CFTypeRef val = SOSPeerInfoLookupGestaltValue(peer, kPIMessageProtocolVersionKey);
740 if (val && CFGetTypeID(val) == CFNumberGetTypeID())
741 CFNumberGetValue(val, kCFNumberCFIndexType, &version);
742 return version;
743 }
744
745 CFTypeRef SOSPeerInfoLookupGestaltValue(SOSPeerInfoRef pi, CFStringRef key) {
746 return CFDictionaryGetValue(pi->gestalt, key);
747 }
748
749 CFStringRef SOSPeerInfoGetPeerID(SOSPeerInfoRef pi) {
750 return pi ? pi->peerID : NULL;
751 }
752
753 bool SOSPeerInfoPeerIDEqual(SOSPeerInfoRef pi, CFStringRef myPeerID) {
754 return CFEqualSafe(myPeerID, SOSPeerInfoGetPeerID(pi));
755 }
756
757 CFIndex SOSPeerInfoGetVersion(SOSPeerInfoRef pi) {
758 return pi->version;
759 }
760
761 bool SOSPeerInfoUpdateDigestWithPublicKeyBytes(SOSPeerInfoRef peer, const struct ccdigest_info *di,
762 ccdigest_ctx_t ctx, CFErrorRef *error) {
763 CFDataRef pubKeyBytes = CFDictionaryGetValue(peer->description, sPublicKeyKey);
764
765 if(!pubKeyBytes) {
766 SOSCreateErrorWithFormat(kSOSErrorEncodeFailure, NULL, error, NULL, CFSTR("Digest failed – no public key"));
767 return false;
768 }
769
770 ccdigest_update(di, ctx, CFDataGetLength(pubKeyBytes), CFDataGetBytePtr(pubKeyBytes));
771
772 return true;
773 }
774
775 bool SOSPeerInfoUpdateDigestWithDescription(SOSPeerInfoRef peer, const struct ccdigest_info *di,
776 ccdigest_ctx_t ctx, CFErrorRef *error) {
777 if(SOSPeerInfoVersionHasV2Data(peer)) SOSPeerInfoPackV2Data(peer);
778 size_t description_size = der_sizeof_plist(peer->description, error);
779 if (description_size == 0) {
780 SOSCreateErrorWithFormat(kSOSErrorEncodeFailure, NULL, error, NULL, CFSTR("Description length failed"));
781 return false;
782 }
783
784 uint8_t * data = malloc(description_size);
785 if (data == NULL) {
786 SOSCreateErrorWithFormat(kSOSErrorEncodeFailure, NULL, error, NULL, CFSTR("Description alloc failed"));
787 return false;
788 }
789 uint8_t *data_end = data + description_size;
790 uint8_t *encoded = der_encode_plist(peer->description, error, data, data_end);
791
792 if(!encoded) {
793 free(data);
794 SOSCreateErrorWithFormat(kSOSErrorEncodeFailure, NULL, error, NULL, CFSTR("Description encode failed"));
795 return false;
796 }
797
798 ccdigest_update(di, ctx, description_size, data);
799
800 free(data);
801
802 return true;
803 }
804
805
806 static CFDataRef sosCreateDate() {
807 CFDateRef now = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent());
808 size_t bufsiz = der_sizeof_date(now, NULL);
809 uint8_t buf[bufsiz];
810 der_encode_date(now, NULL, buf, buf+bufsiz);
811 CFReleaseNull(now);
812 return CFDataCreate(NULL, buf, bufsiz);
813 }
814
815 static CFDateRef sosCreateCFDate(CFDataRef sosdate) {
816 CFDateRef date;
817 der_decode_date(NULL, 0, &date, NULL, CFDataGetBytePtr(sosdate),
818 CFDataGetBytePtr(sosdate) + CFDataGetLength(sosdate));
819 return date;
820 }
821
822 static bool sospeer_application_hash(SOSPeerInfoRef pi, const struct ccdigest_info *di, uint8_t *hbuf) {
823 CFDataRef appdate = asData(CFDictionaryGetValue(pi->description, sApplicationDate), NULL);
824 if(!appdate) return false;
825 ccdigest_di_decl(di, ctx);
826 ccdigest_init(di, ctx);
827 ccdigest_update(di, ctx, CFDataGetLength(appdate), CFDataGetBytePtr(appdate));
828 if (!SOSPeerInfoUpdateDigestWithPublicKeyBytes(pi, di, ctx, NULL)) return false;
829 ccdigest_final(di, ctx, hbuf);
830 return true;
831 }
832
833 SOSPeerInfoRef SOSPeerInfoCopyAsApplication(SOSPeerInfoRef original, SecKeyRef userkey, SecKeyRef peerkey, CFErrorRef *error) {
834 SOSPeerInfoRef result = NULL;
835 SOSPeerInfoRef pi = SOSPeerInfoCreateCopy(kCFAllocatorDefault, original, error);
836
837 const struct ccdigest_info *di = ccsha256_di();
838 uint8_t hbuf[di->output_size];
839 CFDataRef usersig = NULL;
840
841 CFDataRef creationDate = sosCreateDate();
842 CFDictionarySetValue(pi->description, sApplicationDate, creationDate);
843 CFReleaseNull(creationDate);
844
845 // Create User Application Signature
846 require_action_quiet(sospeer_application_hash(pi, di, hbuf), fail,
847 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Failed to create hash for peer applicant"), NULL, error));
848
849 usersig = sosCopySignedHash(userkey, di, hbuf);
850 require_action_quiet(usersig, fail,
851 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Failed to sign public key hash for peer"), NULL, error));
852
853 CFDictionarySetValue(pi->description, sApplicationUsig, usersig);
854 pi->verifiedAppKeyID = SOSCopyIDOfKey(userkey, error);
855 if(pi->verifiedAppKeyID == NULL) {
856 secnotice("PICache", "failed to get userKeyID");
857 } else {
858 pi->verifiedResult = true;
859 }
860 require_quiet(SOSPeerInfoSign(peerkey, pi, error), fail);
861
862 result = pi;
863 pi = NULL;
864
865 fail:
866 CFReleaseNull(usersig);
867 CFReleaseNull(pi);
868 return result;
869 }
870
871 bool SOSPeerInfoApplicationVerify(SOSPeerInfoRef pi, SecKeyRef userkey, CFErrorRef *error) {
872 const struct ccdigest_info *di = ccsha256_di();
873 uint8_t hbuf[di->output_size];
874 bool result = false;
875 CFStringRef userKeyID = NULL;
876
877 // If we've already succeeded signature check with this key move on.
878 require_action_quiet(userkey, exit, SOSErrorCreate(kSOSErrorNoKey, error, NULL, CFSTR("Can't validate PeerInfos with no userKey")));
879 userKeyID = SOSCopyIDOfKey(userkey, error);
880 require_action_quiet(!CFEqualSafe(userKeyID, pi->verifiedAppKeyID), exit, result = pi->verifiedResult);
881
882 // verifiedAppKeyID was NULL or not the key we're looking for - clear it.
883 CFReleaseNull(pi->verifiedAppKeyID);
884 pi->verifiedResult = false;
885 CFDataRef usig = CFDictionaryGetValue(pi->description, sApplicationUsig);
886 require_action_quiet(usig, exit,
887 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Peer is not an applicant"), NULL, error));
888 // Verify User Application Signature
889 require_action_quiet(sospeer_application_hash(pi, di, hbuf), exit,
890 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Failed to create hash for peer applicant"), NULL, error));
891 require_action_quiet(sosVerifyHash(userkey, di, hbuf, usig), exit,
892 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("user signature of public key hash fails to verify"), NULL, error));
893 // Remember the userkey we validated for this peerinfo.
894 pi->verifiedAppKeyID = CFStringCreateCopy(kCFAllocatorDefault, userKeyID);
895 pi->verifiedResult = true;
896
897 result = SOSPeerInfoVerify(pi, error);
898
899 exit:
900 CFReleaseNull(userKeyID);
901 return result;
902 }
903
904
905 static CF_RETURNS_RETAINED CFDateRef sosPeerInfoGetDate(SOSPeerInfoRef pi, CFStringRef entry) {
906 if(!pi) return NULL;
907 CFDataRef sosdate = CFDictionaryGetValue(pi->description, entry);
908 if(!sosdate) return NULL;
909 CFDateRef date = sosCreateCFDate(sosdate);
910
911 return date;
912 }
913
914 CF_RETURNS_RETAINED CFDateRef SOSPeerInfoGetApplicationDate(SOSPeerInfoRef pi) {
915 return sosPeerInfoGetDate(pi, sApplicationDate);
916 }
917
918 CF_RETURNS_RETAINED CFDateRef SOSPeerInfoGetRetirementDate(SOSPeerInfoRef pi) {
919 return sosPeerInfoGetDate(pi, sRetirementDate);
920 }
921
922
923
924 //
925 // Gestalt helpers
926 //
927
928 CFStringRef SOSPeerGestaltGetName(CFDictionaryRef gestalt) {
929 CFStringRef name = SOSPeerGestaltGetAnswer(gestalt, kPIUserDefinedDeviceNameKey);
930 return isString(name) ? name : NULL;
931 }
932
933 CFTypeRef SOSPeerGestaltGetAnswer(CFDictionaryRef gestalt, CFStringRef question) {
934 return gestalt ? CFDictionaryGetValue(gestalt, question) : NULL;
935 }
936
937 //
938 // Peer Retirement
939 //
940
941
942 SOSPeerInfoRef SOSPeerInfoCreateRetirementTicket(CFAllocatorRef allocator, SecKeyRef privKey, SOSPeerInfoRef peer, CFErrorRef *error) {
943 // Copy PeerInfo
944 SOSPeerInfoRef pi = SOSPeerInfoCreateCopy(allocator, peer, error);
945
946 require(pi, fail);
947
948 // Fill out Resignation Date
949 CFDataRef resignationDate = sosCreateDate();
950 CFDictionaryAddValue(pi->description, sRetirementDate, resignationDate);
951 CFReleaseNull(resignationDate);
952
953 require(SOSPeerInfoSign(privKey, pi, error), fail);
954
955 return pi;
956
957 fail:
958 CFReleaseNull(pi);
959 return NULL;
960 }
961
962 CFStringRef SOSPeerInfoInspectRetirementTicket(SOSPeerInfoRef pi, CFErrorRef *error) {
963 CFStringRef retval = NULL;
964 CFDateRef now = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent());
965 CFDateRef retirement = NULL;
966
967 require_quiet(SOSPeerInfoVerify(pi, error), err);
968
969 retirement = sosCreateCFDate(CFDictionaryGetValue(pi->description, sRetirementDate));
970 require_action_quiet(retirement, err,
971 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Peer is not retired"), NULL, error));
972
973 require_action_quiet(CFDateCompare(now, retirement, NULL) == kCFCompareGreaterThan, err,
974 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Retirement date is after current date"), NULL, error));
975
976 retval = SOSPeerInfoGetPeerID(pi);
977
978 err:
979 CFReleaseNull(now);
980 CFReleaseNull(retirement);
981 return retval;
982 }
983
984 bool SOSPeerInfoRetireRetirementTicket(size_t max_seconds, SOSPeerInfoRef pi) {
985 CFDateRef now = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent());
986 CFDateRef retirement = sosCreateCFDate(CFDictionaryGetValue(pi->description, sRetirementDate));
987 CFTimeInterval timediff = CFDateGetTimeIntervalSinceDate(now, retirement); // diff in seconds
988 CFReleaseNull(now);
989 CFReleaseNull(retirement);
990 if(timediff > (max_seconds)) return true;
991 return false;
992 }
993
994 static const void *SOSGetDescriptionValue(SOSPeerInfoRef pi, const void *key) {
995 if(pi && pi->description) {
996 return CFDictionaryGetValue(pi->description, key);
997 }
998 return NULL;
999 }
1000
1001 bool SOSPeerInfoIsRetirementTicket(SOSPeerInfoRef pi) {
1002 CFDataRef flag = SOSGetDescriptionValue(pi, sRetirementDate);
1003 return flag != NULL;
1004 }
1005
1006 bool SOSPeerInfoIsCloudIdentity(SOSPeerInfoRef pi) {
1007 CFTypeRef value = SOSGetDescriptionValue(pi, sCloudIdentityKey);
1008 return CFEqualSafe(value, kCFBooleanTrue);
1009 }
1010
1011 SOSPeerInfoRef SOSPeerInfoUpgradeSignatures(CFAllocatorRef allocator, SecKeyRef privKey, SecKeyRef peerKey, SOSPeerInfoRef peer, CFErrorRef *error) {
1012 SecKeyRef pubKey = SecKeyCreatePublicFromPrivate(privKey);
1013 SOSPeerInfoRef retval = NULL;
1014
1015 retval = SOSPeerInfoCopyAsApplication(peer, privKey, peerKey, error);
1016 CFReleaseNull(pubKey);
1017 return retval;
1018 }
1019
1020 void SOSPeerInfoSetOctagonKeysInDescription(SOSPeerInfoRef peer, SecKeyRef octagonSigningKey,
1021 SecKeyRef octagonEncryptionKey, CFErrorRef *error)
1022 {
1023 CFDataRef signingPublicKeyBytes = NULL;
1024 CFDataRef encryptionPublicKeyBytes = NULL;
1025
1026 OSStatus copySigningKeyResult = SecKeyCopyPublicBytes(octagonSigningKey, &signingPublicKeyBytes);
1027 OSStatus copyEncryptionKeyResult = SecKeyCopyPublicBytes(octagonEncryptionKey, &encryptionPublicKeyBytes);
1028
1029 require_action_quiet(errSecSuccess == copySigningKeyResult, fail, SecError(copySigningKeyResult, error, CFSTR("failed to copy signing public key bytes")));
1030 require_action_quiet(errSecSuccess == copyEncryptionKeyResult, fail, SecError(copyEncryptionKeyResult, error, CFSTR("failed to copy encryption public key bytes")));
1031
1032
1033 CFDictionarySetValue(peer->description, sOctagonPeerSigningPublicKeyKey, signingPublicKeyBytes);
1034 CFDictionarySetValue(peer->description, sOctagonPeerEncryptionPublicKeyKey, encryptionPublicKeyBytes);
1035
1036 fail:
1037 CFReleaseNull(signingPublicKeyBytes);
1038 CFReleaseNull(encryptionPublicKeyBytes);
1039 }
1040
1041
1042 static SOSPeerInfoRef CF_RETURNS_RETAINED
1043 SOSPeerInfoSetBothOctagonKeys(CFAllocatorRef allocator,
1044 SOSPeerInfoRef toCopy,
1045 CFStringRef descriptionSigningKey,
1046 CFStringRef descriptionEncryptionKey,
1047 SecKeyRef octagonSigningKey,
1048 SecKeyRef octagonEncryptionKey,
1049 SecKeyRef signingKey,
1050 CFErrorRef *error)
1051 {
1052 CFDataRef signingPublicKeyBytes = NULL;
1053 CFDataRef encryptionPublicKeyBytes = NULL;
1054
1055 SOSPeerInfoRef pi = NULL;
1056
1057 OSStatus copySigningKeyResult = SecKeyCopyPublicBytes(octagonSigningKey, &signingPublicKeyBytes);
1058 OSStatus copyEncryptionKeyResult = SecKeyCopyPublicBytes(octagonEncryptionKey, &encryptionPublicKeyBytes);
1059
1060 require_action_quiet(0 == copySigningKeyResult, fail, SecError(copySigningKeyResult, error, CFSTR("failed to copy signing public key bytes")));
1061 require_action_quiet(0 == copyEncryptionKeyResult, fail, SecError(copyEncryptionKeyResult, error, CFSTR("failed to copy encryption public key bytes")));
1062
1063 pi = SOSPeerInfoCopyWithModification(allocator, toCopy, signingKey, error,
1064 ^bool(SOSPeerInfoRef peerToModify, CFErrorRef *error) {
1065 if(peerToModify && peerToModify->description && signingPublicKeyBytes && descriptionSigningKey && encryptionPublicKeyBytes && descriptionEncryptionKey) {
1066 CFDictionarySetValue(peerToModify->description, descriptionSigningKey, signingPublicKeyBytes);
1067 CFDictionarySetValue(peerToModify->description, descriptionEncryptionKey, encryptionPublicKeyBytes);
1068 } else {
1069 SecError(errSecParam, error, CFSTR("Bad key bytes or dictionary key"));
1070 }
1071 return true;
1072 });
1073 require(pi, fail);
1074
1075 fail:
1076 CFReleaseNull(signingPublicKeyBytes);
1077 CFReleaseNull(encryptionPublicKeyBytes);
1078 return pi;
1079 }
1080
1081 SOSPeerInfoRef CF_RETURNS_RETAINED
1082 SOSPeerInfoSetOctagonKeys(CFAllocatorRef allocator,
1083 SOSPeerInfoRef toCopy,
1084 SecKeyRef octagonSigningKey,
1085 SecKeyRef octagonEncryptionKey,
1086 SecKeyRef signingKey,
1087 CFErrorRef *error)
1088 {
1089 return SOSPeerInfoSetBothOctagonKeys(allocator, toCopy, sOctagonPeerSigningPublicKeyKey, sOctagonPeerEncryptionPublicKeyKey, octagonSigningKey, octagonEncryptionKey, signingKey, error);
1090 }
1091
1092 static SOSPeerInfoRef CF_RETURNS_RETAINED
1093 SOSPeerInfoSetOctagonKey(CFAllocatorRef allocator,
1094 SOSPeerInfoRef toCopy,
1095 CFStringRef descriptionKey,
1096 SecKeyRef octagonKey,
1097 SecKeyRef signingKey,
1098 CFErrorRef *error)
1099 {
1100 CFDataRef publicKeyBytes = NULL;
1101 SOSPeerInfoRef pi = NULL;
1102
1103 OSStatus copyResult = SecKeyCopyPublicBytes(octagonKey, &publicKeyBytes);
1104 require_action_quiet(0 == copyResult, fail, SecError(copyResult, error, CFSTR("failed to copy public key bytes")));
1105
1106 pi = SOSPeerInfoCopyWithModification(allocator, toCopy, signingKey, error,
1107 ^bool(SOSPeerInfoRef peerToModify, CFErrorRef *error) {
1108 if(peerToModify && peerToModify->description && publicKeyBytes && descriptionKey) {
1109 CFDictionarySetValue(peerToModify->description, descriptionKey, publicKeyBytes);
1110 } else {
1111 SecError(errSecParam, error, CFSTR("Bad key bytes or dictionary key"));
1112 }
1113 return true;
1114 });
1115 require(pi, fail);
1116
1117 fail:
1118 CFReleaseNull(publicKeyBytes);
1119 return pi;
1120 }
1121
1122 SOSPeerInfoRef CF_RETURNS_RETAINED
1123 SOSPeerInfoSetOctagonSigningKey(CFAllocatorRef allocator,
1124 SOSPeerInfoRef toCopy,
1125 SecKeyRef octagonSigningKey,
1126 SecKeyRef signingKey,
1127 CFErrorRef *error)
1128 {
1129 return SOSPeerInfoSetOctagonKey(allocator, toCopy, sOctagonPeerSigningPublicKeyKey, octagonSigningKey, signingKey, error);
1130 }
1131
1132 SOSPeerInfoRef CF_RETURNS_RETAINED
1133 SOSPeerInfoSetOctagonEncryptionKey(CFAllocatorRef allocator,
1134 SOSPeerInfoRef toCopy,
1135 SecKeyRef octagonEncryptionKey,
1136 SecKeyRef signingKey,
1137 CFErrorRef *error)
1138 {
1139 return SOSPeerInfoSetOctagonKey(allocator, toCopy, sOctagonPeerEncryptionPublicKeyKey, octagonEncryptionKey, signingKey, error);
1140 }
1141
1142 CFStringRef SOSPeerInfoCopyTransportType(SOSPeerInfoRef peer){
1143 CFStringRef transportType = (CFStringRef)SOSPeerInfoV2DictionaryCopyString(peer, sTransportType);
1144 return (transportType ? transportType : CFRetain(SOSTransportMessageTypeKVS));
1145 }
1146
1147 bool SOSPeerInfoKVSOnly(SOSPeerInfoRef pi) {
1148 CFStringRef transportType = SOSPeerInfoCopyTransportType(pi);
1149 bool retval = CFEqualSafe(transportType, SOSTransportMessageTypeKVS);
1150 CFReleaseNull(transportType);
1151 return retval;
1152 }
1153
1154 CFStringRef SOSPeerInfoCopyDeviceID(SOSPeerInfoRef peer){
1155 return CFSTR("not implemented");
1156 }
1157
1158 SOSPeerInfoDeviceClass SOSPeerInfoGetClass(SOSPeerInfoRef pi) {
1159 static CFDictionaryRef devID2Class = NULL;
1160 static dispatch_once_t onceToken = 0;
1161
1162 dispatch_once(&onceToken, ^{
1163 CFNumberRef cfSOSPeerInfo_macOS = CFNumberCreateWithCFIndex(kCFAllocatorDefault, SOSPeerInfo_macOS);
1164 CFNumberRef cfSOSPeerInfo_iOS = CFNumberCreateWithCFIndex(kCFAllocatorDefault, SOSPeerInfo_iOS);
1165 CFNumberRef cfSOSPeerInfo_iCloud = CFNumberCreateWithCFIndex(kCFAllocatorDefault, SOSPeerInfo_iCloud);
1166 // CFNumberRef cfSOSPeerInfo_watchOS = CFNumberCreateWithCFIndex(kCFAllocatorDefault, SOSPeerInfo_watchOS);
1167 // CFNumberRef cfSOSPeerInfo_tvOS = CFNumberCreateWithCFIndex(kCFAllocatorDefault, SOSPeerInfo_tvOS);
1168
1169 devID2Class = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
1170 CFSTR("Mac Pro"), cfSOSPeerInfo_macOS,
1171 CFSTR("MacBook"), cfSOSPeerInfo_macOS,
1172 CFSTR("MacBook Pro"), cfSOSPeerInfo_macOS,
1173 CFSTR("iCloud"), cfSOSPeerInfo_iCloud,
1174 CFSTR("iMac"), cfSOSPeerInfo_macOS,
1175 CFSTR("iPad"), cfSOSPeerInfo_iOS,
1176 CFSTR("iPhone"), cfSOSPeerInfo_iOS,
1177 CFSTR("iPod touch"), cfSOSPeerInfo_iOS,
1178 NULL);
1179 CFReleaseNull(cfSOSPeerInfo_macOS);
1180 CFReleaseNull(cfSOSPeerInfo_iOS);
1181 CFReleaseNull(cfSOSPeerInfo_iCloud);
1182 });
1183 SOSPeerInfoDeviceClass retval = SOSPeerInfo_unknown;
1184 CFStringRef dt = SOSPeerInfoGetPeerDeviceType(pi);
1185 require_quiet(dt, errOut);
1186 CFNumberRef classNum = CFDictionaryGetValue(devID2Class, dt);
1187 require_quiet(classNum, errOut);
1188 CFIndex tmp;
1189 require_quiet(CFNumberGetValue(classNum, kCFNumberCFIndexType, &tmp), errOut);
1190 retval = (SOSPeerInfoDeviceClass) tmp;
1191 errOut:
1192 return retval;
1193 }