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