]> git.saurik.com Git - apple/security.git/blob - OSX/sec/SOSCircle/SecureObjectSync/SOSFullPeerInfo.c
Security-57337.60.2.tar.gz
[apple/security.git] / OSX / sec / SOSCircle / SecureObjectSync / SOSFullPeerInfo.c
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
30 #include <Security/SecureObjectSync/SOSCircle.h>
31
32 #include <Security/SecureObjectSync/SOSInternal.h>
33 #include <Security/SecureObjectSync/SOSAccountPriv.h>
34
35 #include <Security/SecKeyPriv.h>
36 #include <Security/SecItemPriv.h>
37 #include <Security/SecOTR.h>
38 #include <CoreFoundation/CFArray.h>
39 #include <dispatch/dispatch.h>
40 #include <SOSPeerInfoDER.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 };
83
84 CFGiblisWithHashFor(SOSFullPeerInfo);
85
86
87 CFStringRef kSOSFullPeerInfoDescriptionKey = CFSTR("SOSFullPeerInfoDescription");
88 CFStringRef kSOSFullPeerInfoSignatureKey = CFSTR("SOSFullPeerInfoSignature");
89 CFStringRef kSOSFullPeerInfoNameKey = CFSTR("SOSFullPeerInfoName");
90
91
92 static bool SOSFullPeerInfoUpdate(SOSFullPeerInfoRef peer, CFErrorRef *error, SOSPeerInfoRef (^create_modification)(SOSPeerInfoRef peer, SecKeyRef key, CFErrorRef *error)) {
93 bool result = false;
94
95 SOSPeerInfoRef newPeer = NULL;
96 SecKeyRef device_key = SOSFullPeerInfoCopyDeviceKey(peer, error);
97 require_quiet(device_key, fail);
98
99 newPeer = create_modification(peer->peer_info, device_key, error);
100 require_quiet(newPeer, fail);
101
102 CFTransferRetained(peer->peer_info, newPeer);
103
104 result = true;
105
106 fail:
107 CFReleaseNull(device_key);
108 CFReleaseNull(newPeer);
109 return result;
110 }
111
112 bool SOSFullPeerInfoUpdateToThisPeer(SOSFullPeerInfoRef peer, SOSPeerInfoRef pi, CFErrorRef *error) {
113 return SOSFullPeerInfoUpdate(peer, error, ^SOSPeerInfoRef(SOSPeerInfoRef peer, SecKeyRef key, CFErrorRef *error) {
114 return SOSPeerInfoSign(key, pi, error) ? pi: NULL;
115 });
116 }
117
118 SOSFullPeerInfoRef SOSFullPeerInfoCreate(CFAllocatorRef allocator, CFDictionaryRef gestalt,
119 CFDataRef backupKey, SecKeyRef signingKey,
120 CFErrorRef* error) {
121 return SOSFullPeerInfoCreateWithViews(allocator, gestalt, backupKey, NULL, signingKey, error);
122 }
123
124 SOSFullPeerInfoRef SOSFullPeerInfoCreateWithViews(CFAllocatorRef allocator,
125 CFDictionaryRef gestalt, CFDataRef backupKey, CFSetRef initialViews,
126 SecKeyRef signingKey, CFErrorRef* error) {
127
128 SOSFullPeerInfoRef result = NULL;
129 SOSFullPeerInfoRef fpi = CFTypeAllocate(SOSFullPeerInfo, struct __OpaqueSOSFullPeerInfo, allocator);
130
131 CFStringRef transportType = NULL;
132 CFBooleanRef preferIDS = NULL;
133 CFStringRef IDSID = CFSTR("");
134
135 if (whichTransportType == kSOSTransportFuture || whichTransportType == kSOSTransportIDS){
136 transportType =SOSTransportMessageTypeIDS;
137 preferIDS = kCFBooleanTrue;
138 }
139 else{
140 transportType =SOSTransportMessageTypeKVS;
141 preferIDS = kCFBooleanTrue;
142 }
143
144 fpi->peer_info = SOSPeerInfoCreateWithTransportAndViews(allocator, gestalt, backupKey,
145 IDSID, transportType, preferIDS,
146 initialViews,
147 signingKey, error);
148 require_quiet(fpi->peer_info, exit);
149
150 OSStatus status = SecKeyCopyPersistentRef(signingKey, &fpi->key_ref);
151 require_quiet(SecError(status, error, CFSTR("Inflating persistent ref")), exit);
152
153 CFTransferRetained(result, fpi);
154
155 exit:
156 CFReleaseNull(fpi);
157 return result;
158 }
159
160 SOSFullPeerInfoRef SOSFullPeerInfoCopyFullPeerInfo(SOSFullPeerInfoRef toCopy) {
161 SOSFullPeerInfoRef retval = NULL;
162 SOSFullPeerInfoRef fpi = CFTypeAllocate(SOSFullPeerInfo, struct __OpaqueSOSFullPeerInfo, kCFAllocatorDefault);
163 SOSPeerInfoRef piToCopy = SOSFullPeerInfoGetPeerInfo(toCopy);
164
165 require_quiet(piToCopy, errOut);
166 require_quiet(fpi, errOut);
167 fpi->peer_info = SOSPeerInfoCreateCopy(kCFAllocatorDefault, piToCopy, NULL);
168 require_quiet(fpi->peer_info, errOut);
169 fpi->key_ref = toCopy->key_ref;
170 CFTransferRetained(retval, fpi);
171
172 errOut:
173 CFReleaseNull(fpi);
174 return retval;
175 }
176
177 bool SOSFullPeerInfoUpdateTransportType(SOSFullPeerInfoRef peer, CFStringRef transportType, CFErrorRef* error)
178 {
179 return SOSFullPeerInfoUpdate(peer, error, ^SOSPeerInfoRef(SOSPeerInfoRef peer, SecKeyRef key, CFErrorRef *error) {
180 return SOSPeerInfoSetTransportType(kCFAllocatorDefault, peer, transportType, key, error);
181 });
182 }
183
184 bool SOSFullPeerInfoUpdateDeviceID(SOSFullPeerInfoRef peer, CFStringRef deviceID, CFErrorRef* error){
185 return SOSFullPeerInfoUpdate(peer, error, ^SOSPeerInfoRef(SOSPeerInfoRef peer, SecKeyRef key, CFErrorRef *error) {
186 return SOSPeerInfoSetDeviceID(kCFAllocatorDefault, peer, deviceID, key, error);
187 });
188 }
189
190 bool SOSFullPeerInfoUpdateTransportPreference(SOSFullPeerInfoRef peer, CFBooleanRef preference, CFErrorRef* error){
191 return SOSFullPeerInfoUpdate(peer, error, ^SOSPeerInfoRef(SOSPeerInfoRef peer, SecKeyRef key, CFErrorRef *error) {
192 return SOSPeerInfoSetIDSPreference(kCFAllocatorDefault, peer, preference, key, error);
193 });
194 }
195
196 SOSFullPeerInfoRef SOSFullPeerInfoCreateCloudIdentity(CFAllocatorRef allocator, SOSPeerInfoRef peer, CFErrorRef* error) {
197 SOSFullPeerInfoRef fpi = CFTypeAllocate(SOSFullPeerInfo, struct __OpaqueSOSFullPeerInfo, allocator);
198
199 SecKeyRef pubKey = NULL;
200
201 fpi->peer_info = peer;
202 CFRetainSafe(fpi->peer_info);
203 if (fpi->peer_info == NULL) {
204 CFReleaseNull(fpi);
205 goto exit;
206 }
207
208 pubKey = SOSPeerInfoCopyPubKey(peer);
209
210 fpi->key_ref = SecKeyCreatePersistentRefToMatchingPrivateKey(pubKey, error);
211
212 if (fpi->key_ref == NULL) {
213 CFReleaseNull(fpi);
214 goto exit;
215 }
216
217 exit:
218 CFReleaseNull(pubKey);
219 return fpi;
220 }
221
222
223 SOSFullPeerInfoRef SOSFullPeerInfoCreateFromDER(CFAllocatorRef allocator, CFErrorRef* error,
224 const uint8_t** der_p, const uint8_t *der_end) {
225 SOSFullPeerInfoRef fpi = CFTypeAllocate(SOSFullPeerInfo, struct __OpaqueSOSFullPeerInfo, allocator);
226
227 const uint8_t *sequence_end;
228
229 *der_p = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &sequence_end, *der_p, der_end);
230 CFReleaseNull(fpi->peer_info);
231 fpi->peer_info = SOSPeerInfoCreateFromDER(allocator, error, der_p, der_end);
232 require_quiet(fpi->peer_info != NULL, fail);
233
234 *der_p = der_decode_data(allocator, kCFPropertyListImmutable, &fpi->key_ref, error, *der_p, sequence_end);
235 require_quiet(*der_p != NULL, fail);
236
237 return fpi;
238
239 fail:
240 CFReleaseNull(fpi);
241 return NULL;
242 }
243
244 SOSFullPeerInfoRef SOSFullPeerInfoCreateFromData(CFAllocatorRef allocator, CFDataRef fullPeerData, CFErrorRef *error)
245 {
246 if(!fullPeerData) return NULL;
247 size_t size = CFDataGetLength(fullPeerData);
248 const uint8_t *der = CFDataGetBytePtr(fullPeerData);
249 SOSFullPeerInfoRef inflated = SOSFullPeerInfoCreateFromDER(allocator, error, &der, der + size);
250 return inflated;
251 }
252
253 static void SOSFullPeerInfoDestroy(CFTypeRef aObj) {
254 SOSFullPeerInfoRef fpi = (SOSFullPeerInfoRef) aObj;
255
256 CFReleaseNull(fpi->peer_info);
257 CFReleaseNull(fpi->key_ref);
258 }
259
260 static Boolean SOSFullPeerInfoCompare(CFTypeRef lhs, CFTypeRef rhs) {
261 SOSFullPeerInfoRef lpeer = (SOSFullPeerInfoRef) lhs;
262 SOSFullPeerInfoRef rpeer = (SOSFullPeerInfoRef) rhs;
263
264 if (!CFEqual(lpeer->peer_info, rpeer->peer_info))
265 return false;
266
267 if (CFEqual(lpeer->key_ref, rpeer->key_ref))
268 return true;
269
270 SecKeyRef lpk = SOSFullPeerInfoCopyDeviceKey(lpeer, NULL);
271 SecKeyRef rpk = SOSFullPeerInfoCopyDeviceKey(rpeer, NULL);
272
273 bool match = lpk && rpk && CFEqual(lpk, rpk);
274
275 CFReleaseNull(lpk);
276 CFReleaseNull(rpk);
277
278 return match;
279 }
280
281 static CFHashCode SOSFullPeerInfoHash(CFTypeRef cf) {
282 SOSFullPeerInfoRef peer = (SOSFullPeerInfoRef) cf;
283
284 return CFHash(peer->peer_info);
285 }
286
287 static CFStringRef SOSFullPeerInfoCopyFormatDescription(CFTypeRef aObj, CFDictionaryRef formatOptions) {
288 SOSFullPeerInfoRef fpi = (SOSFullPeerInfoRef) aObj;
289
290 return CFStringCreateWithFormat(NULL, NULL, CFSTR("<SOSFullPeerInfo@%p: \"%@\">"), fpi, fpi->peer_info);
291 }
292
293 bool SOSFullPeerInfoUpdateGestalt(SOSFullPeerInfoRef peer, CFDictionaryRef gestalt, CFErrorRef* error)
294 {
295 return SOSFullPeerInfoUpdate(peer, error, ^SOSPeerInfoRef(SOSPeerInfoRef peer, SecKeyRef key, CFErrorRef *error) {
296 return SOSPeerInfoCopyWithGestaltUpdate(kCFAllocatorDefault, peer,
297 gestalt, key, error);
298 });
299 }
300
301 bool SOSFullPeerInfoUpdateBackupKey(SOSFullPeerInfoRef peer, CFDataRef backupKey, CFErrorRef* error)
302 {
303 return SOSFullPeerInfoUpdate(peer, error, ^SOSPeerInfoRef(SOSPeerInfoRef peer, SecKeyRef key, CFErrorRef *error) {
304 return SOSPeerInfoCopyWithBackupKeyUpdate(kCFAllocatorDefault, peer, backupKey, key, error);
305 });
306 }
307
308 bool SOSFullPeerInfoAddEscrowRecord(SOSFullPeerInfoRef peer, CFStringRef dsid, CFDictionaryRef escrowRecord, CFErrorRef* error)
309 {
310 return SOSFullPeerInfoUpdate(peer, error, ^SOSPeerInfoRef(SOSPeerInfoRef peer, SecKeyRef key, CFErrorRef *error) {
311 return SOSPeerInfoCopyWithEscrowRecordUpdate(kCFAllocatorDefault, peer, dsid, escrowRecord, key, error);
312 });
313 }
314
315 bool SOSFullPeerInfoReplaceEscrowRecords(SOSFullPeerInfoRef peer, CFDictionaryRef escrowRecords, CFErrorRef* error)
316 {
317 return SOSFullPeerInfoUpdate(peer, error, ^SOSPeerInfoRef(SOSPeerInfoRef peer, SecKeyRef key, CFErrorRef *error) {
318 return SOSPeerInfoCopyWithReplacedEscrowRecords(kCFAllocatorDefault, peer, escrowRecords, key, error);
319 });
320 }
321
322 SOSViewResultCode SOSFullPeerInfoUpdateViews(SOSFullPeerInfoRef peer, SOSViewActionCode action, CFStringRef viewname, CFErrorRef* error)
323 {
324 __block SOSViewResultCode retval = kSOSCCGeneralViewError;
325
326 return SOSFullPeerInfoUpdate(peer, error, ^SOSPeerInfoRef(SOSPeerInfoRef peer, SecKeyRef key, CFErrorRef *error) {
327 return SOSPeerInfoCopyWithViewsChange(kCFAllocatorDefault, peer, action, viewname, &retval, key, error);
328 }) ? retval : kSOSCCGeneralViewError;
329 }
330
331 static CFMutableSetRef SOSFullPeerInfoCopyViewUpdate(SOSFullPeerInfoRef peer, CFSetRef minimumViews, CFSetRef excludedViews) {
332 CFSetRef enabledViews = SOSPeerInfoCopyEnabledViews(peer->peer_info);
333 CFMutableSetRef newViews = SOSPeerInfoCopyEnabledViews(peer->peer_info);
334
335 if (isSet(minimumViews)) {
336 CFSetUnion(newViews, minimumViews);
337 }
338 if (isSet(excludedViews)) {
339 CFSetSubtract(newViews, excludedViews);
340 }
341
342 if (CFEqualSafe(newViews, enabledViews)) {
343 CFReleaseNull(newViews);
344 }
345
346 CFReleaseNull(enabledViews);
347 return newViews;
348 }
349
350 static bool SOSFullPeerInfoNeedsViewUpdate(SOSFullPeerInfoRef peer, CFSetRef minimumViews, CFSetRef excludedViews) {
351 CFSetRef updatedViews = SOSFullPeerInfoCopyViewUpdate(peer, minimumViews, excludedViews);
352 bool needsUpdate = (updatedViews != NULL);
353 CFReleaseNull(updatedViews);
354 return needsUpdate;
355 }
356
357 static bool sosFullPeerInfoRequiresUpdate(SOSFullPeerInfoRef peer, CFSetRef minimumViews, CFSetRef excludedViews) {
358
359 if(!SOSPeerInfoVersionIsCurrent(peer->peer_info)) return true;
360 if(!SOSPeerInfoSerialNumberIsSet(peer->peer_info)) return true;
361 if(!(SOSPeerInfoV2DictionaryHasString(peer->peer_info, sDeviceID)))return true;
362 if(!(SOSPeerInfoV2DictionaryHasString(peer->peer_info, sTransportType))) return true;
363 if(!(SOSPeerInfoV2DictionaryHasBoolean(peer->peer_info, sPreferIDS))) return true;
364 if(SOSFullPeerInfoNeedsViewUpdate(peer, minimumViews, excludedViews)) return true;
365
366 return false;
367 }
368
369 // Returning false indicates we don't need to upgrade.
370 bool SOSFullPeerInfoUpdateToCurrent(SOSFullPeerInfoRef peer, CFSetRef minimumViews, CFSetRef excludedViews) {
371 bool success = false;
372
373 CFMutableSetRef newViews = NULL;
374 CFErrorRef copyError = NULL;
375 CFErrorRef createError = NULL;
376 SecKeyRef device_key = NULL;
377
378 require_quiet(sosFullPeerInfoRequiresUpdate(peer, minimumViews, excludedViews), errOut);
379
380 newViews = SOSFullPeerInfoCopyViewUpdate(peer, minimumViews, excludedViews);
381
382 device_key = SOSFullPeerInfoCopyDeviceKey(peer, &copyError);
383 require_action_quiet(device_key, errOut,
384 secnotice("upgrade", "SOSFullPeerInfoCopyDeviceKey failed: %@", copyError));
385
386 SOSPeerInfoRef newPeer = SOSPeerInfoCreateCurrentCopy(kCFAllocatorDefault, peer->peer_info,
387 NULL, NULL, NULL, newViews,
388 device_key, &createError);
389 require_action_quiet(newPeer, errOut,
390 secnotice("upgrade", "Peer info v2 create copy failed: %@", createError));
391
392 CFTransferRetained(peer->peer_info, newPeer);
393
394 success = true;
395
396 errOut:
397 CFReleaseNull(newViews);
398 CFReleaseNull(copyError);
399 CFReleaseNull(createError);
400 CFReleaseNull(device_key);
401 return success;
402 }
403
404 SOSViewResultCode SOSFullPeerInfoViewStatus(SOSFullPeerInfoRef peer, CFStringRef viewname, CFErrorRef *error)
405 {
406 SOSPeerInfoRef pi = SOSFullPeerInfoGetPeerInfo(peer);
407 secnotice("views", "have pi %s", (pi)? "true": "false");
408 if(!pi) return kSOSCCGeneralViewError;
409 return SOSPeerInfoViewStatus(pi, viewname, error);
410 }
411
412
413 SOSSecurityPropertyResultCode SOSFullPeerInfoUpdateSecurityProperty(SOSFullPeerInfoRef peer, SOSViewActionCode action, CFStringRef property, CFErrorRef* error)
414 {
415 SOSSecurityPropertyResultCode retval = kSOSCCGeneralSecurityPropertyError;
416 SecKeyRef device_key = SOSFullPeerInfoCopyDeviceKey(peer, error);
417 require_quiet(device_key, fail);
418
419 SOSPeerInfoRef newPeer = SOSPeerInfoCopyWithSecurityPropertyChange(kCFAllocatorDefault, peer->peer_info, action, property, &retval, device_key, error);
420
421 require_quiet(newPeer, fail);
422
423 CFReleaseNull(peer->peer_info);
424 peer->peer_info = newPeer;
425 newPeer = NULL;
426
427 fail:
428 CFReleaseNull(device_key);
429 return retval;
430 }
431
432 SOSSecurityPropertyResultCode SOSFullPeerInfoSecurityPropertyStatus(SOSFullPeerInfoRef peer, CFStringRef property, CFErrorRef *error)
433 {
434 SOSPeerInfoRef pi = SOSFullPeerInfoGetPeerInfo(peer);
435 secnotice("secprop", "have pi %s", (pi)? "true": "false");
436 if(!pi) return kSOSCCGeneralSecurityPropertyError;
437 return SOSPeerInfoSecurityPropertyStatus(pi, property, error);
438 }
439
440
441 SOSPeerInfoRef SOSFullPeerInfoGetPeerInfo(SOSFullPeerInfoRef fullPeer) {
442 return fullPeer?fullPeer->peer_info:NULL;
443 }
444
445 // MARK: Private Key Retrieval and Existence
446
447 static SecKeyRef SOSFullPeerInfoCopyPubKey(SOSFullPeerInfoRef fpi) {
448 SecKeyRef retval = NULL;
449 require_quiet(fpi, errOut);
450 SOSPeerInfoRef pi = SOSFullPeerInfoGetPeerInfo(fpi);
451 require_quiet(pi, errOut);
452 retval = SOSPeerInfoCopyPubKey(pi);
453
454 errOut:
455 return retval;
456 }
457
458 static SecKeyRef SOSFullPeerInfoCopyMatchingPrivateKey(SOSFullPeerInfoRef fpi, CFErrorRef *error) {
459 SecKeyRef pub = SOSFullPeerInfoCopyPubKey(fpi);
460 SecKeyRef retval = SecKeyCopyMatchingPrivateKey(pub, error);
461 CFReleaseNull(pub);
462 return retval;
463 }
464
465 static OSStatus SOSFullPeerInfoGetMatchingPrivateKeyStatus(SOSFullPeerInfoRef fpi, CFErrorRef *error) {
466 SecKeyRef pub = SOSFullPeerInfoCopyPubKey(fpi);
467 OSStatus retval = SecKeyGetMatchingPrivateKeyStatus(pub, error);
468 CFReleaseNull(pub);
469 return retval;
470 }
471
472 bool SOSFullPeerInfoValidate(SOSFullPeerInfoRef peer, CFErrorRef* error) {
473 OSStatus result = SOSFullPeerInfoGetMatchingPrivateKeyStatus(peer, error);
474 if(result == errSecSuccess) return true;
475 return false;
476 }
477
478 bool SOSFullPeerInfoPrivKeyExists(SOSFullPeerInfoRef peer) {
479 OSStatus result = SOSFullPeerInfoGetMatchingPrivateKeyStatus(peer, NULL);
480 if(result == errSecItemNotFound || result == errSecParam) return false;
481 return true;
482 }
483
484 bool SOSFullPeerInfoPurgePersistentKey(SOSFullPeerInfoRef fpi, CFErrorRef* error) {
485 SecKeyRef pub = SOSFullPeerInfoCopyPubKey(fpi);
486 CFDictionaryRef privQuery = CreatePrivateKeyMatchingQuery(pub, false);
487 CFMutableDictionaryRef query = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, privQuery);
488 CFDictionaryAddValue(query, kSecUseTombstones, kCFBooleanFalse);
489 SecItemDelete(query);
490 CFReleaseNull(privQuery);
491 CFReleaseNull(query);
492 CFReleaseNull(pub);
493 return true;
494 }
495
496 SecKeyRef SOSFullPeerInfoCopyDeviceKey(SOSFullPeerInfoRef fullPeer, CFErrorRef* error) {
497 return SOSFullPeerInfoCopyMatchingPrivateKey(fullPeer, error);
498 }
499
500 //
501 // MARK: Encode and decode
502 //
503 size_t SOSFullPeerInfoGetDEREncodedSize(SOSFullPeerInfoRef peer, CFErrorRef *error)
504 {
505 size_t peer_size = SOSPeerInfoGetDEREncodedSize(peer->peer_info, error);
506 if (peer_size == 0)
507 return 0;
508
509 size_t ref_size = der_sizeof_data(peer->key_ref, error);
510 if (ref_size == 0)
511 return 0;
512
513 return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE,
514 peer_size + ref_size);
515 }
516
517 uint8_t* SOSFullPeerInfoEncodeToDER(SOSFullPeerInfoRef peer, CFErrorRef* error, const uint8_t* der, uint8_t* der_end)
518 {
519 return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der,
520 SOSPeerInfoEncodeToDER(peer->peer_info, error, der,
521 der_encode_data(peer->key_ref, error, der, der_end)));
522 }
523
524 CFDataRef SOSFullPeerInfoCopyEncodedData(SOSFullPeerInfoRef peer, CFAllocatorRef allocator, CFErrorRef *error)
525 {
526 size_t size = SOSFullPeerInfoGetDEREncodedSize(peer, error);
527 if (size == 0)
528 return NULL;
529 uint8_t buffer[size];
530 uint8_t* start = SOSFullPeerInfoEncodeToDER(peer, error, buffer, buffer + sizeof(buffer));
531 CFDataRef result = CFDataCreate(kCFAllocatorDefault, start, size);
532 return result;
533 }
534
535 bool SOSFullPeerInfoPromoteToApplication(SOSFullPeerInfoRef fpi, SecKeyRef user_key, CFErrorRef *error)
536 {
537 bool success = false;
538 SOSPeerInfoRef old_pi = NULL;
539
540 SecKeyRef device_key = SOSFullPeerInfoCopyDeviceKey(fpi, error);
541 require_quiet(device_key, exit);
542
543 old_pi = fpi->peer_info;
544 fpi->peer_info = SOSPeerInfoCopyAsApplication(old_pi, user_key, device_key, error);
545
546 require_action_quiet(fpi->peer_info, exit, fpi->peer_info = old_pi; old_pi = NULL);
547
548 success = true;
549
550 exit:
551 CFReleaseSafe(old_pi);
552 CFReleaseSafe(device_key);
553 return success;
554 }
555
556 bool SOSFullPeerInfoUpgradeSignatures(SOSFullPeerInfoRef fpi, SecKeyRef user_key, CFErrorRef *error)
557 {
558 bool success = false;
559 SOSPeerInfoRef old_pi = NULL;
560
561 SecKeyRef device_key = SOSFullPeerInfoCopyDeviceKey(fpi, error);
562 require_quiet(device_key, exit);
563
564 old_pi = fpi->peer_info;
565 fpi->peer_info = SOSPeerInfoUpgradeSignatures(NULL, user_key, device_key, old_pi, error);
566
567 require_action_quiet(fpi->peer_info, exit, fpi->peer_info = old_pi; old_pi = NULL);
568
569 success = true;
570
571 exit:
572 CFReleaseSafe(old_pi);
573 CFReleaseSafe(device_key);
574 return success;
575 }
576
577 //
578 //
579 //
580
581 SOSPeerInfoRef SOSFullPeerInfoPromoteToRetiredAndCopy(SOSFullPeerInfoRef fpi, CFErrorRef *error)
582 {
583 SOSPeerInfoRef peer_to_free = NULL;
584 SOSPeerInfoRef retired_peer = NULL;
585 SecKeyRef key = SOSFullPeerInfoCopyDeviceKey(fpi, error);
586 require_quiet(key, error_out);
587
588 retired_peer = SOSPeerInfoCreateRetirementTicket(NULL, key, fpi->peer_info, error);
589
590 require_quiet(retired_peer, error_out);
591
592 peer_to_free = fpi->peer_info;
593 fpi->peer_info = retired_peer;
594 CFRetainSafe(fpi->peer_info);
595
596 error_out:
597 CFReleaseNull(key);
598 CFReleaseNull(peer_to_free);
599 return retired_peer;
600 }
601
602
603 bool SOSFullPeerInfoPing(SOSFullPeerInfoRef peer, CFErrorRef* error) {
604 bool retval = false;
605 SecKeyRef device_key = SOSFullPeerInfoCopyDeviceKey(peer, error);
606 require_quiet(device_key, fail);
607 SOSPeerInfoRef newPeer = SOSPeerInfoCopyWithPing(kCFAllocatorDefault, peer->peer_info, device_key, error);
608 require_quiet(newPeer, fail);
609
610 CFReleaseNull(peer->peer_info);
611 peer->peer_info = newPeer;
612 newPeer = NULL;
613 retval = true;
614 fail:
615 CFReleaseNull(device_key);
616 return retval;
617 }
618
619