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