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