]> git.saurik.com Git - apple/security.git/blob - keychain/SecureObjectSync/SOSFullPeerInfo.m
Security-59754.41.1.tar.gz
[apple/security.git] / keychain / SecureObjectSync / SOSFullPeerInfo.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
27 #include "keychain/SecureObjectSync/SOSFullPeerInfo.h"
28 #include "keychain/SecureObjectSync/SOSPeerInfoV2.h"
29 #include "keychain/SecureObjectSync/SOSPeerInfoDER.h"
30 #include "keychain/SecureObjectSync/SOSPeerInfoPriv.h"
31
32 #include "keychain/SecureObjectSync/SOSCircle.h"
33
34 #include "keychain/SecureObjectSync/SOSInternal.h"
35
36 #include <Security/SecKeyPriv.h>
37 #include <Security/SecItemPriv.h>
38 #include <Security/SecOTR.h>
39 #include <CoreFoundation/CFArray.h>
40 #include <dispatch/dispatch.h>
41 #include <Security/SecFramework.h>
42
43 #include <stdlib.h>
44
45 #include <utilities/SecCFWrappers.h>
46 #include <utilities/SecCFRelease.h>
47
48 #include <utilities/der_plist.h>
49 #include <utilities/der_plist_internal.h>
50 #include <corecrypto/ccder.h>
51
52 #include <CommonCrypto/CommonDigest.h>
53 #include <CommonCrypto/CommonDigestSPI.h>
54
55 #include <CoreFoundation/CoreFoundation.h>
56
57 #include "utilities/iOSforOSX.h"
58
59 #include <AssertMacros.h>
60
61 #include <utilities/SecCFError.h>
62
63 // for OS X
64 #ifdef __cplusplus
65 extern "C" {
66 #endif
67
68 //---- missing
69
70 extern OSStatus SecKeyCopyPublicBytes(SecKeyRef key, CFDataRef* publicBytes);
71 extern SecKeyRef SecKeyCreatePublicFromPrivate(SecKeyRef privateKey);
72 #ifdef __cplusplus
73 }
74 #endif
75
76 struct __OpaqueSOSFullPeerInfo {
77 CFRuntimeBase _base;
78
79 SOSPeerInfoRef peer_info;
80 CFDataRef key_ref;
81 CFDataRef octagon_peer_signing_key_ref;
82 CFDataRef octagon_peer_encryption_key_ref;
83 };
84
85 CFGiblisWithHashFor(SOSFullPeerInfo);
86
87
88
89 CFStringRef kSOSFullPeerInfoDescriptionKey = CFSTR("SOSFullPeerInfoDescription");
90 CFStringRef kSOSFullPeerInfoSignatureKey = CFSTR("SOSFullPeerInfoSignature");
91 CFStringRef kSOSFullPeerInfoNameKey = CFSTR("SOSFullPeerInfoName");
92
93
94 bool SOSFullPeerInfoUpdate(SOSFullPeerInfoRef fullPeerInfo, CFErrorRef *error, SOSPeerInfoRef (^create_modification)(SOSPeerInfoRef peer, SecKeyRef key, CFErrorRef *error)) {
95 bool result = false;
96
97 SOSPeerInfoRef newPeer = NULL;
98 SecKeyRef device_key = SOSFullPeerInfoCopyDeviceKey(fullPeerInfo, error);
99 require_quiet(device_key, fail);
100
101 newPeer = create_modification(fullPeerInfo->peer_info, device_key, error);
102 require_quiet(newPeer, fail);
103
104 CFTransferRetained(fullPeerInfo->peer_info, newPeer);
105 result = true;
106
107 fail:
108 CFReleaseNull(device_key);
109 CFReleaseNull(newPeer);
110 return result;
111 }
112
113 bool SOSFullPeerInfoUpdateToThisPeer(SOSFullPeerInfoRef peer, SOSPeerInfoRef pi, CFErrorRef *error) {
114 return SOSFullPeerInfoUpdate(peer, error, ^SOSPeerInfoRef(SOSPeerInfoRef peer, SecKeyRef key, CFErrorRef *error) {
115 return SOSPeerInfoSign(key, pi, error) ? CFRetainSafe(pi): NULL;
116 });
117 }
118
119 SOSFullPeerInfoRef SOSFullPeerInfoCreate(CFAllocatorRef allocator, CFDictionaryRef gestalt,
120 CFDataRef backupKey,
121 SecKeyRef signingKey,
122 SecKeyRef octagonPeerSigningKey,
123 SecKeyRef octagonPeerEncryptionKey,
124 CFErrorRef* error) {
125 return SOSFullPeerInfoCreateWithViews(allocator, gestalt, backupKey, NULL, signingKey,
126 octagonPeerSigningKey, octagonPeerEncryptionKey, error);
127 }
128
129 SOSFullPeerInfoRef SOSFullPeerInfoCreateWithViews(CFAllocatorRef allocator,
130 CFDictionaryRef gestalt, CFDataRef backupKey, CFSetRef initialViews,
131 SecKeyRef signingKey,
132 SecKeyRef octagonPeerSigningKey,
133 SecKeyRef octagonPeerEncryptionKey,
134 CFErrorRef* error) {
135
136 SOSFullPeerInfoRef result = NULL;
137 SOSFullPeerInfoRef fpi = CFTypeAllocate(SOSFullPeerInfo, struct __OpaqueSOSFullPeerInfo, allocator);
138
139 CFStringRef IDSID = CFSTR("");
140 CFStringRef transportType = SOSTransportMessageTypeKVS;
141 CFBooleanRef preferIDS = kCFBooleanFalse;
142 CFBooleanRef preferIDSFragmentation = kCFBooleanTrue;
143 CFBooleanRef preferACKModel = kCFBooleanTrue;
144
145 fpi->peer_info = SOSPeerInfoCreateWithTransportAndViews(allocator, gestalt, backupKey,
146 IDSID, transportType, preferIDS,
147 preferIDSFragmentation, preferACKModel, initialViews,
148 signingKey, octagonPeerSigningKey, octagonPeerEncryptionKey,
149 // All newly-created FullPeerInfos are on software that supports CKKS4All
150 true,
151 error);
152 require_quiet(fpi->peer_info, exit);
153
154 OSStatus status = SecKeyCopyPersistentRef(signingKey, &fpi->key_ref);
155 require_quiet(SecError(status, error, CFSTR("Inflating persistent ref")), exit);
156 status = SecKeyCopyPersistentRef(octagonPeerSigningKey, &fpi->octagon_peer_signing_key_ref);
157 require_quiet(SecError(status, error, CFSTR("Inflating octagon peer signing persistent ref")), exit);
158 status = SecKeyCopyPersistentRef(octagonPeerEncryptionKey, &fpi->octagon_peer_encryption_key_ref);
159 require_quiet(SecError(status, error, CFSTR("Inflating octagon peer encryption persistent ref")), exit);
160
161 CFTransferRetained(result, fpi);
162
163 exit:
164 CFReleaseNull(fpi);
165 return result;
166 }
167
168 SOSFullPeerInfoRef SOSFullPeerInfoCopyFullPeerInfo(SOSFullPeerInfoRef toCopy) {
169 SOSFullPeerInfoRef retval = NULL;
170 SOSFullPeerInfoRef fpi = CFTypeAllocate(SOSFullPeerInfo, struct __OpaqueSOSFullPeerInfo, kCFAllocatorDefault);
171 SOSPeerInfoRef piToCopy = SOSFullPeerInfoGetPeerInfo(toCopy);
172
173 require_quiet(piToCopy, errOut);
174 require_quiet(fpi, errOut);
175 fpi->peer_info = SOSPeerInfoCreateCopy(kCFAllocatorDefault, piToCopy, NULL);
176 require_quiet(fpi->peer_info, errOut);
177 fpi->key_ref = CFRetainSafe(toCopy->key_ref);
178 CFTransferRetained(retval, fpi);
179
180 errOut:
181 CFReleaseNull(fpi);
182 return retval;
183 }
184
185 bool SOSFullPeerInfoUpdateOctagonKeys(SOSFullPeerInfoRef peer, SecKeyRef octagonSigningKey, SecKeyRef octagonEncryptionKey, CFErrorRef* error){
186 return SOSFullPeerInfoUpdate(peer, error, ^SOSPeerInfoRef(SOSPeerInfoRef peer, SecKeyRef key, CFErrorRef *error) {
187 return SOSPeerInfoSetOctagonKeys(kCFAllocatorDefault, peer, octagonSigningKey, octagonEncryptionKey, key, error);
188 });
189 }
190
191 bool SOSFullPeerInfoUpdateOctagonSigningKey(SOSFullPeerInfoRef peer, SecKeyRef octagonSigningKey, CFErrorRef* error){
192 return SOSFullPeerInfoUpdate(peer, error, ^SOSPeerInfoRef(SOSPeerInfoRef peer, SecKeyRef key, CFErrorRef *error) {
193 return SOSPeerInfoSetOctagonSigningKey(kCFAllocatorDefault, peer, octagonSigningKey, key, error);
194 });
195 }
196
197 bool SOSFullPeerInfoUpdateOctagonEncryptionKey(SOSFullPeerInfoRef peer, SecKeyRef octagonEncryptionKey, CFErrorRef* error){
198 return SOSFullPeerInfoUpdate(peer, error, ^SOSPeerInfoRef(SOSPeerInfoRef peer, SecKeyRef key, CFErrorRef *error) {
199 return SOSPeerInfoSetOctagonEncryptionKey(kCFAllocatorDefault, peer, octagonEncryptionKey, key, error);
200 });
201 }
202
203 bool SOSFullPeerInfoSetCKKS4AllSupport(SOSFullPeerInfoRef fullPeerInfo, bool support, CFErrorRef* error) {
204
205 SOSPeerInfoRef peerInfo = SOSFullPeerInfoGetPeerInfo(fullPeerInfo);
206 bool supportsCKKS4All = SOSPeerInfoSupportsCKKSForAll(peerInfo);
207
208 if(supportsCKKS4All == support) {
209 // Early-exit: no change needed
210 return true;
211 }
212
213 secnotice("circleChange", "Setting CKKS4All status to '%@'", support ? @"supported" : @"not supported");
214
215 return SOSFullPeerInfoUpdate(fullPeerInfo, error, ^SOSPeerInfoRef(SOSPeerInfoRef currentPeerInfo, SecKeyRef key, CFErrorRef *blockerror) {
216 SOSPeerInfoRef newPeerInfo = SOSPeerInfoCopyWithModification(kCFAllocatorDefault, currentPeerInfo, key, blockerror,
217 ^bool(SOSPeerInfoRef peerToModify, CFErrorRef *innerblockerror) {
218 SOSPeerInfoSetSupportsCKKSForAll(peerToModify, support);
219 return true;
220 });
221 return newPeerInfo;
222 });
223 }
224
225
226 CFDataRef SOSPeerInfoCopyData(SOSPeerInfoRef pi, CFErrorRef *error)
227 {
228 CFTypeRef vData = NULL;
229 SecKeyRef pubKey = SOSPeerInfoCopyPubKey(pi, error);
230 CFDictionaryRef query = NULL;
231 require_quiet(pubKey, exit);
232
233
234 CFDataRef public_key_hash = SecKeyCopyPublicKeyHash(pubKey);
235
236 query = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
237 kSecClass, kSecClassKey,
238 kSecAttrKeyClass, kSecAttrKeyClassPrivate,
239 kSecAttrSynchronizable, kSecAttrSynchronizableAny,
240 kSecAttrApplicationLabel, public_key_hash,
241 kSecReturnData, kCFBooleanTrue,
242 NULL);
243 CFReleaseNull(public_key_hash);
244
245 require_quiet(SecError(SecItemCopyMatching(query, &vData),error ,
246 CFSTR("Error finding persistent ref to key from public: %@"), pubKey), exit);
247
248 exit:
249 CFReleaseNull(query);
250 CFReleaseNull(pubKey);
251 if (vData == NULL) {
252 secnotice("fpi","no private key found");
253 }
254 return (CFDataRef)vData;
255 }
256
257 SOSFullPeerInfoRef SOSFullPeerInfoCreateCloudIdentity(CFAllocatorRef allocator, SOSPeerInfoRef peer, CFErrorRef* error) {
258 SOSFullPeerInfoRef fpi = CFTypeAllocate(SOSFullPeerInfo, struct __OpaqueSOSFullPeerInfo, allocator);
259
260 SecKeyRef pubKey = NULL;
261
262 fpi->peer_info = peer;
263 CFRetainSafe(fpi->peer_info);
264 if (fpi->peer_info == NULL) {
265 CFReleaseNull(fpi);
266 goto exit;
267 }
268
269 pubKey = SOSPeerInfoCopyPubKey(peer, error);
270 require_quiet(pubKey, exit);
271
272 fpi->key_ref = SecKeyCreatePersistentRefToMatchingPrivateKey(pubKey, error);
273
274 if (fpi->key_ref == NULL) {
275 CFReleaseNull(fpi);
276 goto exit;
277 }
278
279 exit:
280 CFReleaseNull(pubKey);
281 return fpi;
282 }
283
284
285 SOSFullPeerInfoRef SOSFullPeerInfoCreateFromDER(CFAllocatorRef allocator, CFErrorRef* error,
286 const uint8_t** der_p, const uint8_t *der_end) {
287 SOSFullPeerInfoRef fpi = CFTypeAllocate(SOSFullPeerInfo, struct __OpaqueSOSFullPeerInfo, allocator);
288
289 const uint8_t *sequence_end;
290
291 *der_p = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &sequence_end, *der_p, der_end);
292 CFReleaseNull(fpi->peer_info);
293 fpi->peer_info = SOSPeerInfoCreateFromDER(allocator, error, der_p, der_end);
294 require_quiet(fpi->peer_info != NULL, fail);
295
296 *der_p = der_decode_data(allocator, &fpi->key_ref, error, *der_p, sequence_end);
297 require_quiet(*der_p != NULL, fail);
298
299 return fpi;
300
301 fail:
302 CFReleaseNull(fpi);
303 return NULL;
304 }
305
306 SOSFullPeerInfoRef SOSFullPeerInfoCreateFromData(CFAllocatorRef allocator, CFDataRef fullPeerData, CFErrorRef *error)
307 {
308 if(!fullPeerData) return NULL;
309 size_t size = CFDataGetLength(fullPeerData);
310 const uint8_t *der = CFDataGetBytePtr(fullPeerData);
311 SOSFullPeerInfoRef inflated = SOSFullPeerInfoCreateFromDER(allocator, error, &der, der + size);
312 return inflated;
313 }
314
315 static void SOSFullPeerInfoDestroy(CFTypeRef aObj) {
316 SOSFullPeerInfoRef fpi = (SOSFullPeerInfoRef) aObj;
317
318 CFReleaseNull(fpi->peer_info);
319 CFReleaseNull(fpi->key_ref);
320 CFReleaseNull(fpi->octagon_peer_signing_key_ref);
321 CFReleaseNull(fpi->octagon_peer_encryption_key_ref);
322 }
323
324 static Boolean SOSFullPeerInfoCompare(CFTypeRef lhs, CFTypeRef rhs) {
325 SOSFullPeerInfoRef lpeer = (SOSFullPeerInfoRef) lhs;
326 SOSFullPeerInfoRef rpeer = (SOSFullPeerInfoRef) rhs;
327
328 if (!CFEqual(lpeer->peer_info, rpeer->peer_info))
329 return false;
330
331 if (CFEqual(lpeer->key_ref, rpeer->key_ref))
332 return true;
333
334 SecKeyRef lpk = SOSFullPeerInfoCopyDeviceKey(lpeer, NULL);
335 SecKeyRef rpk = SOSFullPeerInfoCopyDeviceKey(rpeer, NULL);
336
337 bool match = lpk && rpk && CFEqual(lpk, rpk);
338
339 CFReleaseNull(lpk);
340 CFReleaseNull(rpk);
341
342 return match;
343 }
344
345 static CFHashCode SOSFullPeerInfoHash(CFTypeRef cf) {
346 SOSFullPeerInfoRef peer = (SOSFullPeerInfoRef) cf;
347
348 return CFHash(peer->peer_info);
349 }
350
351 static CFStringRef SOSFullPeerInfoCopyFormatDescription(CFTypeRef aObj, CFDictionaryRef formatOptions) {
352 SOSFullPeerInfoRef fpi = (SOSFullPeerInfoRef) aObj;
353
354 return CFStringCreateWithFormat(NULL, NULL, CFSTR("<SOSFullPeerInfo@%p: \"%@\">"), fpi, fpi->peer_info);
355 }
356
357 bool SOSFullPeerInfoUpdateGestalt(SOSFullPeerInfoRef peer, CFDictionaryRef gestalt, CFErrorRef* error)
358 {
359 return SOSFullPeerInfoUpdate(peer, error, ^SOSPeerInfoRef(SOSPeerInfoRef peer, SecKeyRef key, CFErrorRef *error) {
360 return SOSPeerInfoCopyWithGestaltUpdate(kCFAllocatorDefault, peer, gestalt, key, error);
361 });
362 }
363
364 bool SOSFullPeerInfoUpdateV2Dictionary(SOSFullPeerInfoRef peer, CFDictionaryRef newv2dict, CFErrorRef* error)
365 {
366 return SOSFullPeerInfoUpdate(peer, error, ^SOSPeerInfoRef(SOSPeerInfoRef peer, SecKeyRef key, CFErrorRef *error) {
367 return SOSPeerInfoCopyWithV2DictionaryUpdate(kCFAllocatorDefault, peer,
368 newv2dict, key, error);
369 });
370 }
371
372 bool SOSFullPeerInfoUpdateBackupKey(SOSFullPeerInfoRef peer, CFDataRef backupKey, CFErrorRef* error)
373 {
374 return SOSFullPeerInfoUpdate(peer, error, ^SOSPeerInfoRef(SOSPeerInfoRef peer, SecKeyRef key, CFErrorRef *error) {
375 return SOSPeerInfoCopyWithBackupKeyUpdate(kCFAllocatorDefault, peer, backupKey, key, error);
376 });
377 }
378
379 bool SOSFullPeerInfoReplaceEscrowRecords(SOSFullPeerInfoRef peer, CFDictionaryRef escrowRecords, CFErrorRef* error)
380 {
381 return SOSFullPeerInfoUpdate(peer, error, ^SOSPeerInfoRef(SOSPeerInfoRef peer, SecKeyRef key, CFErrorRef *error) {
382 return SOSPeerInfoCopyWithReplacedEscrowRecords(kCFAllocatorDefault, peer, escrowRecords, key, error);
383 });
384 }
385
386 SOSViewResultCode SOSFullPeerInfoUpdateViews(SOSFullPeerInfoRef peer, SOSViewActionCode action, CFStringRef viewname, CFErrorRef* error)
387 {
388 __block SOSViewResultCode retval = kSOSCCGeneralViewError;
389
390 secnotice("viewChange", "%s view %@", SOSViewsXlateAction(action), viewname);
391
392 return SOSFullPeerInfoUpdate(peer, error, ^SOSPeerInfoRef(SOSPeerInfoRef peer, SecKeyRef key, CFErrorRef *error) {
393 return SOSPeerInfoCopyWithViewsChange(kCFAllocatorDefault, peer, action, viewname, &retval, key, error);
394 }) ? retval : kSOSCCGeneralViewError;
395 }
396
397 static CFMutableSetRef SOSFullPeerInfoCopyViewUpdate(SOSFullPeerInfoRef peer, CFSetRef minimumViews, CFSetRef excludedViews) {
398 CFSetRef enabledViews = SOSPeerInfoCopyEnabledViews(peer->peer_info);
399 CFMutableSetRef newViews = SOSPeerInfoCopyEnabledViews(peer->peer_info);
400
401 if (isSet(minimumViews)) {
402 CFSetUnion(newViews, minimumViews);
403 }
404 if (isSet(excludedViews)) {
405 CFSetSubtract(newViews, excludedViews);
406 }
407
408 if (CFEqualSafe(newViews, enabledViews)) {
409 CFReleaseNull(newViews);
410 }
411
412 CFReleaseNull(enabledViews);
413 return newViews;
414 }
415
416 static bool SOSFullPeerInfoNeedsViewUpdate(SOSFullPeerInfoRef peer, CFSetRef minimumViews, CFSetRef excludedViews) {
417 CFSetRef updatedViews = SOSFullPeerInfoCopyViewUpdate(peer, minimumViews, excludedViews);
418 bool needsUpdate = (updatedViews != NULL);
419 CFReleaseNull(updatedViews);
420 return needsUpdate;
421 }
422
423 static bool sosFullPeerInfoRequiresUpdate(SOSFullPeerInfoRef peer, CFSetRef minimumViews, CFSetRef excludedViews) {
424
425 if(!SOSPeerInfoVersionIsCurrent(peer->peer_info)) return true;
426 if(!SOSPeerInfoSerialNumberIsSet(peer->peer_info)) return true;
427 if(SOSFullPeerInfoNeedsViewUpdate(peer, minimumViews, excludedViews)) return true;
428
429 return false;
430 }
431
432 // Returning false indicates we don't need to upgrade.
433 bool SOSFullPeerInfoUpdateToCurrent(SOSFullPeerInfoRef peer, CFSetRef minimumViews, CFSetRef excludedViews) {
434 bool success = false;
435
436 CFMutableSetRef newViews = NULL;
437 CFErrorRef copyError = NULL;
438 CFErrorRef createError = NULL;
439 SecKeyRef device_key = NULL;
440
441 require_quiet(sosFullPeerInfoRequiresUpdate(peer, minimumViews, excludedViews), errOut);
442
443 newViews = SOSFullPeerInfoCopyViewUpdate(peer, minimumViews, excludedViews);
444
445 device_key = SOSFullPeerInfoCopyDeviceKey(peer, &copyError);
446 require_action_quiet(device_key, errOut,
447 secnotice("upgrade", "SOSFullPeerInfoCopyDeviceKey failed: %@", copyError));
448
449 SOSPeerInfoRef newPeer = SOSPeerInfoCreateCurrentCopy(kCFAllocatorDefault, peer->peer_info,
450 NULL, NULL, kCFBooleanFalse, kCFBooleanTrue, kCFBooleanTrue, newViews,
451 device_key, &createError);
452 require_action_quiet(newPeer, errOut,
453 secnotice("upgrade", "Peer info v2 create copy failed: %@", createError));
454
455 CFTransferRetained(peer->peer_info, newPeer);
456
457 success = true;
458
459 errOut:
460 CFReleaseNull(newViews);
461 CFReleaseNull(copyError);
462 CFReleaseNull(createError);
463 CFReleaseNull(device_key);
464 return success;
465 }
466
467 SOSViewResultCode SOSFullPeerInfoViewStatus(SOSFullPeerInfoRef peer, CFStringRef viewname, CFErrorRef *error)
468 {
469 SOSPeerInfoRef pi = SOSFullPeerInfoGetPeerInfo(peer);
470 if(!pi) return kSOSCCGeneralViewError;
471 return SOSPeerInfoViewStatus(pi, viewname, error);
472 }
473
474 SOSPeerInfoRef SOSFullPeerInfoGetPeerInfo(SOSFullPeerInfoRef fullPeer) {
475 return fullPeer?fullPeer->peer_info:NULL;
476 }
477
478 // MARK: Private Key Retrieval and Existence
479
480 SecKeyRef SOSFullPeerInfoCopyPubKey(SOSFullPeerInfoRef fpi, CFErrorRef *error) {
481 SecKeyRef retval = NULL;
482 require_quiet(fpi, errOut);
483 SOSPeerInfoRef pi = SOSFullPeerInfoGetPeerInfo(fpi);
484 require_quiet(pi, errOut);
485 retval = SOSPeerInfoCopyPubKey(pi, error);
486
487 errOut:
488 return retval;
489 }
490
491 SecKeyRef SOSFullPeerInfoCopyOctagonPublicSigningKey(SOSFullPeerInfoRef fpi, CFErrorRef* error)
492 {
493 SecKeyRef retval = NULL;
494 require_quiet(fpi, errOut);
495 SOSPeerInfoRef pi = SOSFullPeerInfoGetPeerInfo(fpi);
496 require_quiet(pi, errOut);
497 retval = SOSPeerInfoCopyOctagonSigningPublicKey(pi, error);
498 errOut:
499 return retval;
500 }
501
502 SecKeyRef SOSFullPeerInfoCopyOctagonPublicEncryptionKey(SOSFullPeerInfoRef fpi, CFErrorRef* error)
503 {
504 SecKeyRef retval = NULL;
505 require_quiet(fpi, errOut);
506 SOSPeerInfoRef pi = SOSFullPeerInfoGetPeerInfo(fpi);
507 require_quiet(pi, errOut);
508 retval = SOSPeerInfoCopyOctagonEncryptionPublicKey(pi, error);
509
510 errOut:
511 return retval;
512 }
513
514
515 static SecKeyRef SOSFullPeerInfoCopyMatchingPrivateKey(SOSFullPeerInfoRef fpi, CFErrorRef *error) {
516 SecKeyRef retval = NULL;
517 SecKeyRef pub = SOSFullPeerInfoCopyPubKey(fpi, error);
518 if(pub) {
519 retval = SecKeyCopyMatchingPrivateKey(pub, error);
520 if(!retval) {
521 secnotice("circleOp", "Failed to find my private key for spid %@", SOSPeerInfoGetSPID(SOSFullPeerInfoGetPeerInfo(fpi)));
522 }
523 CFReleaseNull(pub);
524 }
525 return retval;
526 }
527
528 static SecKeyRef SOSFullPeerInfoCopyMatchingOctagonSigningPrivateKey(SOSFullPeerInfoRef fpi, CFErrorRef* error)
529 {
530 SecKeyRef retval = NULL;
531 SecKeyRef pub = SOSFullPeerInfoCopyOctagonPublicSigningKey(fpi, error);
532 require_quiet(pub, exit);
533 retval = SecKeyCopyMatchingPrivateKey(pub, error);
534
535 exit:
536 CFReleaseNull(pub);
537 return retval;
538 }
539 static SecKeyRef SOSFullPeerInfoCopyMatchingOctagonEncryptionPrivateKey(SOSFullPeerInfoRef fpi, CFErrorRef* error)
540 {
541 SecKeyRef retval = NULL;
542 SecKeyRef pub = SOSFullPeerInfoCopyOctagonPublicEncryptionKey(fpi, error);
543 require_quiet(pub, exit);
544 retval = SecKeyCopyMatchingPrivateKey(pub, error);
545
546 exit:
547 CFReleaseNull(pub);
548 return retval;
549 }
550
551
552 static OSStatus SOSFullPeerInfoGetMatchingPrivateKeyStatus(SOSFullPeerInfoRef fpi, CFErrorRef *error) {
553 OSStatus retval = errSecParam;
554 SecKeyRef pub = SOSFullPeerInfoCopyPubKey(fpi, error);
555 require_quiet(pub, exit);
556 retval = SecKeyGetMatchingPrivateKeyStatus(pub, error);
557
558 exit:
559 CFReleaseNull(pub);
560 return retval;
561 }
562
563 bool SOSFullPeerInfoValidate(SOSFullPeerInfoRef peer, CFErrorRef* error) {
564 OSStatus result = SOSFullPeerInfoGetMatchingPrivateKeyStatus(peer, error);
565 if(result == errSecSuccess) return true;
566 return false;
567 }
568
569 bool SOSFullPeerInfoPrivKeyExists(SOSFullPeerInfoRef peer) {
570 OSStatus result = SOSFullPeerInfoGetMatchingPrivateKeyStatus(peer, NULL);
571 if(result == errSecItemNotFound || result == errSecParam) return false;
572 return true;
573 }
574
575 bool SOSFullPeerInfoPurgePersistentKey(SOSFullPeerInfoRef fpi, CFErrorRef* error) {
576 bool result = false;
577 CFDictionaryRef privQuery = NULL;
578 CFMutableDictionaryRef query = NULL;
579 CFDictionaryRef octagonPrivQuery = NULL;
580 CFMutableDictionaryRef octagonQuery = NULL;
581
582 SecKeyRef pub = SOSFullPeerInfoCopyPubKey(fpi, error);
583 SecKeyRef octagonSigningPub = SOSFullPeerInfoCopyOctagonPublicSigningKey(fpi, error);
584 SecKeyRef octagonEncryptionPub = SOSFullPeerInfoCopyOctagonPublicEncryptionKey(fpi, error);
585 require_quiet(pub, fail);
586 // iCloud Identities doesn't have either signing or encryption key here. Don't fail if they're not present.
587
588 privQuery = CreatePrivateKeyMatchingQuery(pub, false);
589 query = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, privQuery);
590 CFDictionaryAddValue(query, kSecUseTombstones, kCFBooleanFalse);
591
592 result = SecError(SecItemDelete(query), error, CFSTR("Deleting while purging"));
593
594 // do the same thing to also purge the octagon sync signing key
595 if(octagonSigningPub) {
596 octagonPrivQuery = CreatePrivateKeyMatchingQuery(octagonSigningPub, false);
597 octagonQuery = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, octagonPrivQuery);
598 CFDictionaryAddValue(octagonQuery, kSecUseTombstones, kCFBooleanFalse);
599
600 result &= SecError(SecItemDelete(octagonQuery), error, CFSTR("Deleting signing key while purging"));
601 }
602
603 CFReleaseNull(octagonPrivQuery);
604 CFReleaseNull(octagonQuery);
605
606 // do the same thing to also purge the octagon encryption key
607 if(octagonEncryptionPub) {
608 octagonPrivQuery = CreatePrivateKeyMatchingQuery(octagonEncryptionPub, false);
609 octagonQuery = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, octagonPrivQuery);
610 CFDictionaryAddValue(octagonQuery, kSecUseTombstones, kCFBooleanFalse);
611
612 result &= SecError(SecItemDelete(octagonQuery), error, CFSTR("Deleting encryption key while purging"));
613 }
614
615 fail:
616 CFReleaseNull(privQuery);
617 CFReleaseNull(query);
618 CFReleaseNull(pub);
619 CFReleaseNull(octagonPrivQuery);
620 CFReleaseNull(octagonQuery);
621 CFReleaseNull(octagonSigningPub);
622 CFReleaseNull(octagonEncryptionPub);
623 return result;
624 }
625
626 SecKeyRef SOSFullPeerInfoCopyDeviceKey(SOSFullPeerInfoRef fullPeer, CFErrorRef* error)
627 {
628 return SOSFullPeerInfoCopyMatchingPrivateKey(fullPeer, error);
629 }
630
631 SecKeyRef SOSFullPeerInfoCopyOctagonSigningKey(SOSFullPeerInfoRef fullPeer, CFErrorRef* error)
632 {
633 return SOSFullPeerInfoCopyMatchingOctagonSigningPrivateKey(fullPeer, error);
634 }
635
636 SecKeyRef SOSFullPeerInfoCopyOctagonEncryptionKey(SOSFullPeerInfoRef fullPeer, CFErrorRef* error)
637 {
638 return SOSFullPeerInfoCopyMatchingOctagonEncryptionPrivateKey(fullPeer, error);
639 }
640
641
642 //
643 // MARK: Encode and decode
644 //
645 size_t SOSFullPeerInfoGetDEREncodedSize(SOSFullPeerInfoRef peer, CFErrorRef *error)
646 {
647 size_t peer_size = SOSPeerInfoGetDEREncodedSize(peer->peer_info, error);
648 if (peer_size == 0)
649 return 0;
650
651 size_t ref_size = der_sizeof_data(peer->key_ref, error);
652 if (ref_size == 0)
653 return 0;
654
655 return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE,
656 peer_size + ref_size);
657 }
658
659 uint8_t* SOSFullPeerInfoEncodeToDER(SOSFullPeerInfoRef peer, CFErrorRef* error, const uint8_t* der, uint8_t* der_end)
660 {
661 return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der,
662 SOSPeerInfoEncodeToDER(peer->peer_info, error, der,
663 der_encode_data(peer->key_ref, error, der, der_end)));
664 }
665
666 CFDataRef SOSFullPeerInfoCopyEncodedData(SOSFullPeerInfoRef peer, CFAllocatorRef allocator, CFErrorRef *error)
667 {
668 return CFDataCreateWithDER(kCFAllocatorDefault, SOSFullPeerInfoGetDEREncodedSize(peer, error), ^uint8_t*(size_t size, uint8_t *buffer) {
669 return SOSFullPeerInfoEncodeToDER(peer, error, buffer, (uint8_t *) buffer + size);
670 });
671 }
672
673 bool SOSFullPeerInfoPromoteToApplication(SOSFullPeerInfoRef fpi, SecKeyRef user_key, CFErrorRef *error)
674 {
675 bool success = false;
676 SOSPeerInfoRef old_pi = NULL;
677
678 SecKeyRef device_key = SOSFullPeerInfoCopyDeviceKey(fpi, error);
679 require_quiet(device_key, exit);
680
681 old_pi = fpi->peer_info;
682 fpi->peer_info = SOSPeerInfoCopyAsApplication(old_pi, user_key, device_key, error);
683
684 require_action_quiet(fpi->peer_info, exit, fpi->peer_info = old_pi; old_pi = NULL);
685
686 success = true;
687
688 exit:
689 CFReleaseSafe(old_pi);
690 CFReleaseSafe(device_key);
691 return success;
692 }
693
694 bool SOSFullPeerInfoUpgradeSignatures(SOSFullPeerInfoRef fpi, SecKeyRef user_key, CFErrorRef *error)
695 {
696 bool success = false;
697 SOSPeerInfoRef old_pi = NULL;
698
699 SecKeyRef device_key = SOSFullPeerInfoCopyDeviceKey(fpi, error);
700 require_quiet(device_key, exit);
701
702 old_pi = fpi->peer_info;
703 fpi->peer_info = SOSPeerInfoUpgradeSignatures(NULL, user_key, device_key, old_pi, error);
704
705 require_action_quiet(fpi->peer_info, exit, fpi->peer_info = old_pi; old_pi = NULL);
706
707 success = true;
708
709 exit:
710 CFReleaseSafe(old_pi);
711 CFReleaseSafe(device_key);
712 return success;
713 }
714
715 //
716 //
717 //
718
719 SOSPeerInfoRef SOSFullPeerInfoPromoteToRetiredAndCopy(SOSFullPeerInfoRef fpi, CFErrorRef *error)
720 {
721 SOSPeerInfoRef peer_to_free = NULL;
722 SOSPeerInfoRef retired_peer = NULL;
723 SecKeyRef key = SOSFullPeerInfoCopyDeviceKey(fpi, error);
724 require_quiet(key, error_out);
725
726 retired_peer = SOSPeerInfoCreateRetirementTicket(NULL, key, fpi->peer_info, error);
727
728 require_quiet(retired_peer, error_out);
729
730 peer_to_free = fpi->peer_info;
731 fpi->peer_info = retired_peer;
732 CFRetainSafe(fpi->peer_info);
733
734 error_out:
735 CFReleaseNull(key);
736 CFReleaseNull(peer_to_free);
737 return retired_peer;
738 }
739
740
741 bool SOSFullPeerInfoPing(SOSFullPeerInfoRef peer, CFErrorRef* error) {
742 bool retval = false;
743 SecKeyRef device_key = SOSFullPeerInfoCopyDeviceKey(peer, error);
744 require_quiet(device_key, fail);
745 SOSPeerInfoRef newPeer = SOSPeerInfoCopyWithPing(kCFAllocatorDefault, peer->peer_info, device_key, error);
746 require_quiet(newPeer, fail);
747
748 CFReleaseNull(peer->peer_info);
749 peer->peer_info = newPeer;
750 newPeer = NULL;
751 retval = true;
752 fail:
753 CFReleaseNull(device_key);
754 return retval;
755 }
756
757