]> git.saurik.com Git - apple/security.git/blob - OSX/sec/SOSCircle/SecureObjectSync/SOSFullPeerInfo.m
Security-58286.1.32.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_sync_signing_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 static bool SOSFullPeerInfoUpdate(SOSFullPeerInfoRef peer, 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(peer, error);
100 require_quiet(device_key, fail);
101
102 newPeer = create_modification(peer->peer_info, device_key, error);
103 require_quiet(newPeer, fail);
104
105 CFTransferRetained(peer->peer_info, newPeer);
106
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, SecKeyRef signingKey, SecKeyRef octagonSigningKey,
123 CFErrorRef* error) {
124 return SOSFullPeerInfoCreateWithViews(allocator, gestalt, backupKey, NULL, signingKey, octagonSigningKey, error);
125 }
126
127 SOSFullPeerInfoRef SOSFullPeerInfoCreateWithViews(CFAllocatorRef allocator,
128 CFDictionaryRef gestalt, CFDataRef backupKey, CFSetRef initialViews,
129 SecKeyRef signingKey, SecKeyRef octagonSigningKey, CFErrorRef* error) {
130
131 SOSFullPeerInfoRef result = NULL;
132 SOSFullPeerInfoRef fpi = CFTypeAllocate(SOSFullPeerInfo, struct __OpaqueSOSFullPeerInfo, allocator);
133
134 CFStringRef IDSID = CFSTR("");
135 CFStringRef transportType = SOSTransportMessageTypeIDSV2;
136 CFBooleanRef preferIDS = kCFBooleanFalse;
137 CFBooleanRef preferIDSFragmentation = kCFBooleanTrue;
138 CFBooleanRef preferACKModel = kCFBooleanTrue;
139
140 fpi->peer_info = SOSPeerInfoCreateWithTransportAndViews(allocator, gestalt, backupKey,
141 IDSID, transportType, preferIDS,
142 preferIDSFragmentation, preferACKModel, initialViews,
143 signingKey, octagonSigningKey, error);
144 require_quiet(fpi->peer_info, exit);
145
146 OSStatus status = SecKeyCopyPersistentRef(signingKey, &fpi->key_ref);
147 require_quiet(SecError(status, error, CFSTR("Inflating persistent ref")), exit);
148
149 status = SecKeyCopyPersistentRef(octagonSigningKey, &fpi->octagon_sync_signing_key_ref);
150 require_quiet(SecError(status, error, CFSTR("Inflating octagon persistent ref")), exit);
151
152 CFTransferRetained(result, fpi);
153
154 exit:
155 CFReleaseNull(fpi);
156 return result;
157 }
158
159 SOSFullPeerInfoRef SOSFullPeerInfoCopyFullPeerInfo(SOSFullPeerInfoRef toCopy) {
160 SOSFullPeerInfoRef retval = NULL;
161 SOSFullPeerInfoRef fpi = CFTypeAllocate(SOSFullPeerInfo, struct __OpaqueSOSFullPeerInfo, kCFAllocatorDefault);
162 SOSPeerInfoRef piToCopy = SOSFullPeerInfoGetPeerInfo(toCopy);
163
164 require_quiet(piToCopy, errOut);
165 require_quiet(fpi, errOut);
166 fpi->peer_info = SOSPeerInfoCreateCopy(kCFAllocatorDefault, piToCopy, NULL);
167 require_quiet(fpi->peer_info, errOut);
168 fpi->key_ref = toCopy->key_ref;
169 CFTransferRetained(retval, fpi);
170
171 errOut:
172 CFReleaseNull(fpi);
173 return retval;
174 }
175
176 bool SOSFullPeerInfoUpdateTransportType(SOSFullPeerInfoRef peer, CFStringRef transportType, CFErrorRef* error)
177 {
178 return SOSFullPeerInfoUpdate(peer, error, ^SOSPeerInfoRef(SOSPeerInfoRef peer, SecKeyRef key, CFErrorRef *error) {
179 return SOSPeerInfoSetTransportType(kCFAllocatorDefault, peer, transportType, key, error);
180 });
181 }
182
183 bool SOSFullPeerInfoUpdateDeviceID(SOSFullPeerInfoRef peer, CFStringRef deviceID, CFErrorRef* error){
184 return SOSFullPeerInfoUpdate(peer, error, ^SOSPeerInfoRef(SOSPeerInfoRef peer, SecKeyRef key, CFErrorRef *error) {
185 return SOSPeerInfoSetDeviceID(kCFAllocatorDefault, peer, deviceID, key, error);
186 });
187 }
188
189 bool SOSFullPeerInfoUpdateTransportPreference(SOSFullPeerInfoRef peer, CFBooleanRef preference, CFErrorRef* error){
190 return SOSFullPeerInfoUpdate(peer, error, ^SOSPeerInfoRef(SOSPeerInfoRef peer, SecKeyRef key, CFErrorRef *error) {
191 return SOSPeerInfoSetIDSPreference(kCFAllocatorDefault, peer, preference, key, error);
192 });
193 }
194
195 bool SOSFullPeerInfoUpdateTransportFragmentationPreference(SOSFullPeerInfoRef peer, CFBooleanRef preference, CFErrorRef* error){
196 return SOSFullPeerInfoUpdate(peer, error, ^SOSPeerInfoRef(SOSPeerInfoRef peer, SecKeyRef key, CFErrorRef *error) {
197 return SOSPeerInfoSetIDSFragmentationPreference(kCFAllocatorDefault, peer, preference, key, error);
198 });
199 }
200
201 bool SOSFullPeerInfoUpdateTransportAckModelPreference(SOSFullPeerInfoRef peer, CFBooleanRef preference, CFErrorRef* error){
202 return SOSFullPeerInfoUpdate(peer, error, ^SOSPeerInfoRef(SOSPeerInfoRef peer, SecKeyRef key, CFErrorRef *error) {
203 return SOSPeerInfoSetIDSACKModelPreference(kCFAllocatorDefault, peer, preference, key, error);
204 });
205 }
206
207 CFDataRef SOSPeerInfoCopyData(SOSPeerInfoRef pi, CFErrorRef *error)
208 {
209 CFTypeRef vData = NULL;
210 SecKeyRef pubKey = SOSPeerInfoCopyPubKey(pi, error);
211 CFDictionaryRef query = NULL;
212 require_quiet(pubKey, exit);
213
214
215 CFDataRef public_key_hash = SecKeyCopyPublicKeyHash(pubKey);
216
217 query = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
218 kSecClass, kSecClassKey,
219 kSecAttrKeyClass, kSecAttrKeyClassPrivate,
220 kSecAttrSynchronizable, kSecAttrSynchronizableAny,
221 kSecAttrApplicationLabel, public_key_hash,
222 kSecReturnData, kCFBooleanTrue,
223 NULL);
224 CFReleaseNull(public_key_hash);
225
226 require_quiet(SecError(SecItemCopyMatching(query, &vData),error ,
227 CFSTR("Error finding persistent ref to key from public: %@"), pubKey), exit);
228
229 exit:
230 CFReleaseNull(query);
231
232 secnotice("fpi","no private key found");
233 return (CFDataRef)vData;
234 }
235
236 SOSFullPeerInfoRef SOSFullPeerInfoCreateCloudIdentity(CFAllocatorRef allocator, SOSPeerInfoRef peer, CFErrorRef* error) {
237 SOSFullPeerInfoRef fpi = CFTypeAllocate(SOSFullPeerInfo, struct __OpaqueSOSFullPeerInfo, allocator);
238
239 SecKeyRef pubKey = NULL;
240
241 fpi->peer_info = peer;
242 CFRetainSafe(fpi->peer_info);
243 if (fpi->peer_info == NULL) {
244 CFReleaseNull(fpi);
245 goto exit;
246 }
247
248 pubKey = SOSPeerInfoCopyPubKey(peer, error);
249 require_quiet(pubKey, exit);
250
251 fpi->key_ref = SecKeyCreatePersistentRefToMatchingPrivateKey(pubKey, error);
252
253 if (fpi->key_ref == NULL) {
254 CFReleaseNull(fpi);
255 goto exit;
256 }
257
258 exit:
259 CFReleaseNull(pubKey);
260 return fpi;
261 }
262
263
264 SOSFullPeerInfoRef SOSFullPeerInfoCreateFromDER(CFAllocatorRef allocator, CFErrorRef* error,
265 const uint8_t** der_p, const uint8_t *der_end) {
266 SOSFullPeerInfoRef fpi = CFTypeAllocate(SOSFullPeerInfo, struct __OpaqueSOSFullPeerInfo, allocator);
267
268 const uint8_t *sequence_end;
269
270 *der_p = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &sequence_end, *der_p, der_end);
271 CFReleaseNull(fpi->peer_info);
272 fpi->peer_info = SOSPeerInfoCreateFromDER(allocator, error, der_p, der_end);
273 require_quiet(fpi->peer_info != NULL, fail);
274
275 *der_p = der_decode_data(allocator, kCFPropertyListImmutable, &fpi->key_ref, error, *der_p, sequence_end);
276 require_quiet(*der_p != NULL, fail);
277
278 return fpi;
279
280 fail:
281 CFReleaseNull(fpi);
282 return NULL;
283 }
284
285 SOSFullPeerInfoRef SOSFullPeerInfoCreateFromData(CFAllocatorRef allocator, CFDataRef fullPeerData, CFErrorRef *error)
286 {
287 if(!fullPeerData) return NULL;
288 size_t size = CFDataGetLength(fullPeerData);
289 const uint8_t *der = CFDataGetBytePtr(fullPeerData);
290 SOSFullPeerInfoRef inflated = SOSFullPeerInfoCreateFromDER(allocator, error, &der, der + size);
291 return inflated;
292 }
293
294 static void SOSFullPeerInfoDestroy(CFTypeRef aObj) {
295 SOSFullPeerInfoRef fpi = (SOSFullPeerInfoRef) aObj;
296
297 CFReleaseNull(fpi->peer_info);
298 CFReleaseNull(fpi->key_ref);
299 }
300
301 static Boolean SOSFullPeerInfoCompare(CFTypeRef lhs, CFTypeRef rhs) {
302 SOSFullPeerInfoRef lpeer = (SOSFullPeerInfoRef) lhs;
303 SOSFullPeerInfoRef rpeer = (SOSFullPeerInfoRef) rhs;
304
305 if (!CFEqual(lpeer->peer_info, rpeer->peer_info))
306 return false;
307
308 if (CFEqual(lpeer->key_ref, rpeer->key_ref))
309 return true;
310
311 SecKeyRef lpk = SOSFullPeerInfoCopyDeviceKey(lpeer, NULL);
312 SecKeyRef rpk = SOSFullPeerInfoCopyDeviceKey(rpeer, NULL);
313
314 bool match = lpk && rpk && CFEqual(lpk, rpk);
315
316 CFReleaseNull(lpk);
317 CFReleaseNull(rpk);
318
319 return match;
320 }
321
322 static CFHashCode SOSFullPeerInfoHash(CFTypeRef cf) {
323 SOSFullPeerInfoRef peer = (SOSFullPeerInfoRef) cf;
324
325 return CFHash(peer->peer_info);
326 }
327
328 static CFStringRef SOSFullPeerInfoCopyFormatDescription(CFTypeRef aObj, CFDictionaryRef formatOptions) {
329 SOSFullPeerInfoRef fpi = (SOSFullPeerInfoRef) aObj;
330
331 return CFStringCreateWithFormat(NULL, NULL, CFSTR("<SOSFullPeerInfo@%p: \"%@\">"), fpi, fpi->peer_info);
332 }
333
334 bool SOSFullPeerInfoUpdateGestalt(SOSFullPeerInfoRef peer, CFDictionaryRef gestalt, CFErrorRef* error)
335 {
336 return SOSFullPeerInfoUpdate(peer, error, ^SOSPeerInfoRef(SOSPeerInfoRef peer, SecKeyRef key, CFErrorRef *error) {
337 return SOSPeerInfoCopyWithGestaltUpdate(kCFAllocatorDefault, peer,
338 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(!(SOSPeerInfoV2DictionaryHasString(peer->peer_info, sDeviceID)))return true;
413 if(!(SOSPeerInfoV2DictionaryHasString(peer->peer_info, sTransportType))) return true;
414 if(!(SOSPeerInfoV2DictionaryHasBoolean(peer->peer_info, sPreferIDS))) return true;
415 if(!(SOSPeerInfoV2DictionaryHasBoolean(peer->peer_info, sPreferIDSFragmentation))) return true;
416 if(!(SOSPeerInfoV2DictionaryHasBoolean(peer->peer_info, sPreferIDSACKModel))) return true;
417 if(SOSFullPeerInfoNeedsViewUpdate(peer, minimumViews, excludedViews)) return true;
418
419 return false;
420 }
421
422 // Returning false indicates we don't need to upgrade.
423 bool SOSFullPeerInfoUpdateToCurrent(SOSFullPeerInfoRef peer, CFSetRef minimumViews, CFSetRef excludedViews) {
424 bool success = false;
425
426 CFMutableSetRef newViews = NULL;
427 CFErrorRef copyError = NULL;
428 CFErrorRef createError = NULL;
429 SecKeyRef device_key = NULL;
430
431 require_quiet(sosFullPeerInfoRequiresUpdate(peer, minimumViews, excludedViews), errOut);
432
433 newViews = SOSFullPeerInfoCopyViewUpdate(peer, minimumViews, excludedViews);
434
435 device_key = SOSFullPeerInfoCopyDeviceKey(peer, &copyError);
436 require_action_quiet(device_key, errOut,
437 secnotice("upgrade", "SOSFullPeerInfoCopyDeviceKey failed: %@", copyError));
438
439 SOSPeerInfoRef newPeer = SOSPeerInfoCreateCurrentCopy(kCFAllocatorDefault, peer->peer_info,
440 NULL, NULL, kCFBooleanFalse, kCFBooleanTrue, kCFBooleanTrue, newViews,
441 device_key, &createError);
442 require_action_quiet(newPeer, errOut,
443 secnotice("upgrade", "Peer info v2 create copy failed: %@", createError));
444
445 CFTransferRetained(peer->peer_info, newPeer);
446
447 success = true;
448
449 errOut:
450 CFReleaseNull(newViews);
451 CFReleaseNull(copyError);
452 CFReleaseNull(createError);
453 CFReleaseNull(device_key);
454 return success;
455 }
456
457 SOSViewResultCode SOSFullPeerInfoViewStatus(SOSFullPeerInfoRef peer, CFStringRef viewname, CFErrorRef *error)
458 {
459 SOSPeerInfoRef pi = SOSFullPeerInfoGetPeerInfo(peer);
460 if(!pi) return kSOSCCGeneralViewError;
461 return SOSPeerInfoViewStatus(pi, viewname, error);
462 }
463
464
465 SOSSecurityPropertyResultCode SOSFullPeerInfoUpdateSecurityProperty(SOSFullPeerInfoRef peer, SOSViewActionCode action, CFStringRef property, CFErrorRef* error)
466 {
467 SOSSecurityPropertyResultCode retval = kSOSCCGeneralSecurityPropertyError;
468 SecKeyRef device_key = SOSFullPeerInfoCopyDeviceKey(peer, error);
469 require_quiet(device_key, fail);
470
471 SOSPeerInfoRef newPeer = SOSPeerInfoCopyWithSecurityPropertyChange(kCFAllocatorDefault, peer->peer_info, action, property, &retval, device_key, error);
472
473 require_quiet(newPeer, fail);
474
475 CFReleaseNull(peer->peer_info);
476 peer->peer_info = newPeer;
477 newPeer = NULL;
478
479 fail:
480 CFReleaseNull(device_key);
481 return retval;
482 }
483
484 SOSSecurityPropertyResultCode SOSFullPeerInfoSecurityPropertyStatus(SOSFullPeerInfoRef peer, CFStringRef property, CFErrorRef *error)
485 {
486 SOSPeerInfoRef pi = SOSFullPeerInfoGetPeerInfo(peer);
487 secnotice("secprop", "have pi %s", (pi)? "true": "false");
488 if(!pi) return kSOSCCGeneralSecurityPropertyError;
489 return SOSPeerInfoSecurityPropertyStatus(pi, property, error);
490 }
491
492
493 SOSPeerInfoRef SOSFullPeerInfoGetPeerInfo(SOSFullPeerInfoRef fullPeer) {
494 return fullPeer?fullPeer->peer_info:NULL;
495 }
496
497 // MARK: Private Key Retrieval and Existence
498
499 SecKeyRef SOSFullPeerInfoCopyPubKey(SOSFullPeerInfoRef fpi, CFErrorRef *error) {
500 SecKeyRef retval = NULL;
501 require_quiet(fpi, errOut);
502 SOSPeerInfoRef pi = SOSFullPeerInfoGetPeerInfo(fpi);
503 require_quiet(pi, errOut);
504 retval = SOSPeerInfoCopyPubKey(pi, error);
505
506 errOut:
507 return retval;
508 }
509
510 static SecKeyRef SOSFullPeerInfoCopyOctagonPubKey(SOSFullPeerInfoRef fpi, CFErrorRef* error)
511 {
512 SecKeyRef retval = NULL;
513 require_quiet(fpi, errOut);
514 SOSPeerInfoRef pi = SOSFullPeerInfoGetPeerInfo(fpi);
515 require_quiet(pi, errOut);
516 retval = SOSPeerInfoCopyOctagonPubKey(pi, error);
517
518 errOut:
519 return retval;
520 }
521
522 static SecKeyRef SOSFullPeerInfoCopyMatchingPrivateKey(SOSFullPeerInfoRef fpi, CFErrorRef *error) {
523 SecKeyRef retval = NULL;
524
525 SecKeyRef pub = SOSFullPeerInfoCopyPubKey(fpi, error);
526 require_quiet(pub, exit);
527 retval = SecKeyCopyMatchingPrivateKey(pub, error);
528 exit:
529 CFReleaseNull(pub);
530 return retval;
531 }
532
533 static SecKeyRef SOSFullPeerInfoCopyMatchingOctagonPrivateKey(SOSFullPeerInfoRef fpi, CFErrorRef* error)
534 {
535 SecKeyRef retval = NULL;
536 SecKeyRef pub = SOSFullPeerInfoCopyOctagonPubKey(fpi, error);
537 require_quiet(pub, exit);
538 retval = SecKeyCopyMatchingPrivateKey(pub, error);
539
540 exit:
541 CFReleaseNull(pub);
542 return retval;
543 }
544
545 static OSStatus SOSFullPeerInfoGetMatchingPrivateKeyStatus(SOSFullPeerInfoRef fpi, CFErrorRef *error) {
546 OSStatus retval = errSecParam;
547 SecKeyRef pub = SOSFullPeerInfoCopyPubKey(fpi, error);
548 require_quiet(pub, exit);
549 retval = SecKeyGetMatchingPrivateKeyStatus(pub, error);
550
551 exit:
552 CFReleaseNull(pub);
553 return retval;
554 }
555
556 bool SOSFullPeerInfoValidate(SOSFullPeerInfoRef peer, CFErrorRef* error) {
557 OSStatus result = SOSFullPeerInfoGetMatchingPrivateKeyStatus(peer, error);
558 if(result == errSecSuccess) return true;
559 return false;
560 }
561
562 bool SOSFullPeerInfoPrivKeyExists(SOSFullPeerInfoRef peer) {
563 OSStatus result = SOSFullPeerInfoGetMatchingPrivateKeyStatus(peer, NULL);
564 if(result == errSecItemNotFound || result == errSecParam) return false;
565 return true;
566 }
567
568 bool SOSFullPeerInfoPurgePersistentKey(SOSFullPeerInfoRef fpi, CFErrorRef* error) {
569 bool result = false;
570 CFDictionaryRef privQuery = NULL;
571 CFMutableDictionaryRef query = NULL;
572 CFDictionaryRef octagonPrivQuery = NULL;
573 CFMutableDictionaryRef octagonQuery = NULL;
574
575 SecKeyRef pub = SOSFullPeerInfoCopyPubKey(fpi, error);
576 SecKeyRef octagonPub = SOSFullPeerInfoCopyOctagonPubKey(fpi, error);
577 require_quiet(pub, fail);
578 require_quiet(octagonPub, fail);
579
580 privQuery = CreatePrivateKeyMatchingQuery(pub, false);
581 query = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, privQuery);
582 CFDictionaryAddValue(query, kSecUseTombstones, kCFBooleanFalse);
583
584 result = SecError(SecItemDelete(query), error, CFSTR("Deleting while purging"));
585
586 // do the same thing to also purge the octagon sync signing key
587
588 octagonPrivQuery = CreatePrivateKeyMatchingQuery(octagonPub, false);
589 octagonQuery = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, octagonPrivQuery);
590 CFDictionaryAddValue(octagonQuery, kSecUseTombstones, kCFBooleanFalse);
591
592 result &= SecError(SecItemDelete(octagonQuery), error, CFSTR("Deleting while purging"));
593
594 fail:
595 CFReleaseNull(privQuery);
596 CFReleaseNull(query);
597 CFReleaseNull(pub);
598 CFReleaseNull(octagonPrivQuery);
599 CFReleaseNull(octagonQuery);
600 CFReleaseNull(octagonPub);
601 return result;
602 }
603
604 SecKeyRef SOSFullPeerInfoCopyDeviceKey(SOSFullPeerInfoRef fullPeer, CFErrorRef* error) {
605 return SOSFullPeerInfoCopyMatchingPrivateKey(fullPeer, error);
606 }
607
608 SecKeyRef SOSFullPeerInfoCopyOctagonSigningKey(SOSFullPeerInfoRef fullPeer, CFErrorRef* error)
609 {
610 return SOSFullPeerInfoCopyMatchingOctagonPrivateKey(fullPeer, error);
611 }
612
613 //
614 // MARK: Encode and decode
615 //
616 size_t SOSFullPeerInfoGetDEREncodedSize(SOSFullPeerInfoRef peer, CFErrorRef *error)
617 {
618 size_t peer_size = SOSPeerInfoGetDEREncodedSize(peer->peer_info, error);
619 if (peer_size == 0)
620 return 0;
621
622 size_t ref_size = der_sizeof_data(peer->key_ref, error);
623 if (ref_size == 0)
624 return 0;
625
626 return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE,
627 peer_size + ref_size);
628 }
629
630 uint8_t* SOSFullPeerInfoEncodeToDER(SOSFullPeerInfoRef peer, CFErrorRef* error, const uint8_t* der, uint8_t* der_end)
631 {
632 return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der,
633 SOSPeerInfoEncodeToDER(peer->peer_info, error, der,
634 der_encode_data(peer->key_ref, error, der, der_end)));
635 }
636
637 CFDataRef SOSFullPeerInfoCopyEncodedData(SOSFullPeerInfoRef peer, CFAllocatorRef allocator, CFErrorRef *error)
638 {
639 size_t size = SOSFullPeerInfoGetDEREncodedSize(peer, error);
640 if (size == 0)
641 return NULL;
642 uint8_t buffer[size];
643 uint8_t* start = SOSFullPeerInfoEncodeToDER(peer, error, buffer, buffer + sizeof(buffer));
644 CFDataRef result = CFDataCreate(kCFAllocatorDefault, start, size);
645 return result;
646 }
647
648 bool SOSFullPeerInfoPromoteToApplication(SOSFullPeerInfoRef fpi, SecKeyRef user_key, CFErrorRef *error)
649 {
650 bool success = false;
651 SOSPeerInfoRef old_pi = NULL;
652
653 SecKeyRef device_key = SOSFullPeerInfoCopyDeviceKey(fpi, error);
654 require_quiet(device_key, exit);
655
656 old_pi = fpi->peer_info;
657 fpi->peer_info = SOSPeerInfoCopyAsApplication(old_pi, user_key, device_key, error);
658
659 require_action_quiet(fpi->peer_info, exit, fpi->peer_info = old_pi; old_pi = NULL);
660
661 success = true;
662
663 exit:
664 CFReleaseSafe(old_pi);
665 CFReleaseSafe(device_key);
666 return success;
667 }
668
669 bool SOSFullPeerInfoUpgradeSignatures(SOSFullPeerInfoRef fpi, SecKeyRef user_key, CFErrorRef *error)
670 {
671 bool success = false;
672 SOSPeerInfoRef old_pi = NULL;
673
674 SecKeyRef device_key = SOSFullPeerInfoCopyDeviceKey(fpi, error);
675 require_quiet(device_key, exit);
676
677 old_pi = fpi->peer_info;
678 fpi->peer_info = SOSPeerInfoUpgradeSignatures(NULL, user_key, device_key, old_pi, error);
679
680 require_action_quiet(fpi->peer_info, exit, fpi->peer_info = old_pi; old_pi = NULL);
681
682 success = true;
683
684 exit:
685 CFReleaseSafe(old_pi);
686 CFReleaseSafe(device_key);
687 return success;
688 }
689
690 //
691 //
692 //
693
694 SOSPeerInfoRef SOSFullPeerInfoPromoteToRetiredAndCopy(SOSFullPeerInfoRef fpi, CFErrorRef *error)
695 {
696 SOSPeerInfoRef peer_to_free = NULL;
697 SOSPeerInfoRef retired_peer = NULL;
698 SecKeyRef key = SOSFullPeerInfoCopyDeviceKey(fpi, error);
699 require_quiet(key, error_out);
700
701 retired_peer = SOSPeerInfoCreateRetirementTicket(NULL, key, fpi->peer_info, error);
702
703 require_quiet(retired_peer, error_out);
704
705 peer_to_free = fpi->peer_info;
706 fpi->peer_info = retired_peer;
707 CFRetainSafe(fpi->peer_info);
708
709 error_out:
710 CFReleaseNull(key);
711 CFReleaseNull(peer_to_free);
712 return retired_peer;
713 }
714
715
716 bool SOSFullPeerInfoPing(SOSFullPeerInfoRef peer, CFErrorRef* error) {
717 bool retval = false;
718 SecKeyRef device_key = SOSFullPeerInfoCopyDeviceKey(peer, error);
719 require_quiet(device_key, fail);
720 SOSPeerInfoRef newPeer = SOSPeerInfoCopyWithPing(kCFAllocatorDefault, peer->peer_info, device_key, error);
721 require_quiet(newPeer, fail);
722
723 CFReleaseNull(peer->peer_info);
724 peer->peer_info = newPeer;
725 newPeer = NULL;
726 retval = true;
727 fail:
728 CFReleaseNull(device_key);
729 return retval;
730 }
731
732