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