2 * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 #include <AssertMacros.h>
27 #include <Security/SecureObjectSync/SOSFullPeerInfo.h>
28 #include <Security/SecureObjectSync/SOSPeerInfoV2.h>
29 #include <Security/SecureObjectSync/SOSPeerInfoDER.h>
31 #include <Security/SecureObjectSync/SOSCircle.h>
33 #include <Security/SecureObjectSync/SOSInternal.h>
34 #include <Security/SecureObjectSync/SOSAccountPriv.h>
35 #include <Security/SecureObjectSync/SOSPeerInfoDER.h>
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>
47 #include <utilities/SecCFWrappers.h>
48 #include <utilities/SecCFRelease.h>
50 #include <utilities/der_plist.h>
51 #include <utilities/der_plist_internal.h>
52 #include <corecrypto/ccder.h>
54 #include <CommonCrypto/CommonDigest.h>
55 #include <CommonCrypto/CommonDigestSPI.h>
57 #include <CoreFoundation/CoreFoundation.h>
59 #include "utilities/iOSforOSX.h"
61 #include <AssertMacros.h>
63 #include <utilities/SecCFError.h>
72 extern OSStatus
SecKeyCopyPublicBytes(SecKeyRef key
, CFDataRef
* publicBytes
);
73 extern SecKeyRef
SecKeyCreatePublicFromPrivate(SecKeyRef privateKey
);
78 struct __OpaqueSOSFullPeerInfo
{
81 SOSPeerInfoRef peer_info
;
85 CFGiblisWithHashFor(SOSFullPeerInfo
);
89 CFStringRef kSOSFullPeerInfoDescriptionKey
= CFSTR("SOSFullPeerInfoDescription");
90 CFStringRef kSOSFullPeerInfoSignatureKey
= CFSTR("SOSFullPeerInfoSignature");
91 CFStringRef kSOSFullPeerInfoNameKey
= CFSTR("SOSFullPeerInfoName");
94 static bool SOSFullPeerInfoUpdate(SOSFullPeerInfoRef peer
, CFErrorRef
*error
, SOSPeerInfoRef (^create_modification
)(SOSPeerInfoRef peer
, SecKeyRef key
, CFErrorRef
*error
)) {
97 SOSPeerInfoRef newPeer
= NULL
;
98 SecKeyRef device_key
= SOSFullPeerInfoCopyDeviceKey(peer
, error
);
99 require_quiet(device_key
, fail
);
101 newPeer
= create_modification(peer
->peer_info
, device_key
, error
);
102 require_quiet(newPeer
, fail
);
104 CFTransferRetained(peer
->peer_info
, newPeer
);
109 CFReleaseNull(device_key
);
110 CFReleaseNull(newPeer
);
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
) ? CFRetainSafe(pi
): NULL
;
120 SOSFullPeerInfoRef
SOSFullPeerInfoCreate(CFAllocatorRef allocator
, CFDictionaryRef gestalt
,
121 CFDataRef backupKey
, SecKeyRef signingKey
,
123 return SOSFullPeerInfoCreateWithViews(allocator
, gestalt
, backupKey
, NULL
, signingKey
, error
);
126 SOSFullPeerInfoRef
SOSFullPeerInfoCreateWithViews(CFAllocatorRef allocator
,
127 CFDictionaryRef gestalt
, CFDataRef backupKey
, CFSetRef initialViews
,
128 SecKeyRef signingKey
, CFErrorRef
* error
) {
130 SOSFullPeerInfoRef result
= NULL
;
131 SOSFullPeerInfoRef fpi
= CFTypeAllocate(SOSFullPeerInfo
, struct __OpaqueSOSFullPeerInfo
, allocator
);
133 CFStringRef IDSID
= CFSTR("");
134 CFStringRef transportType
=SOSTransportMessageTypeIDSV2
;
135 CFBooleanRef preferIDS
= kCFBooleanFalse
;
136 CFBooleanRef preferIDSFragmentation
= kCFBooleanTrue
;
137 CFBooleanRef preferACKModel
= kCFBooleanTrue
;
139 fpi
->peer_info
= SOSPeerInfoCreateWithTransportAndViews(allocator
, gestalt
, backupKey
,
140 IDSID
, transportType
, preferIDS
,
141 preferIDSFragmentation
, preferACKModel
, initialViews
,
143 require_quiet(fpi
->peer_info
, exit
);
145 OSStatus status
= SecKeyCopyPersistentRef(signingKey
, &fpi
->key_ref
);
146 require_quiet(SecError(status
, error
, CFSTR("Inflating persistent ref")), exit
);
148 CFTransferRetained(result
, fpi
);
155 SOSFullPeerInfoRef
SOSFullPeerInfoCopyFullPeerInfo(SOSFullPeerInfoRef toCopy
) {
156 SOSFullPeerInfoRef retval
= NULL
;
157 SOSFullPeerInfoRef fpi
= CFTypeAllocate(SOSFullPeerInfo
, struct __OpaqueSOSFullPeerInfo
, kCFAllocatorDefault
);
158 SOSPeerInfoRef piToCopy
= SOSFullPeerInfoGetPeerInfo(toCopy
);
160 require_quiet(piToCopy
, errOut
);
161 require_quiet(fpi
, errOut
);
162 fpi
->peer_info
= SOSPeerInfoCreateCopy(kCFAllocatorDefault
, piToCopy
, NULL
);
163 require_quiet(fpi
->peer_info
, errOut
);
164 fpi
->key_ref
= toCopy
->key_ref
;
165 CFTransferRetained(retval
, fpi
);
172 bool SOSFullPeerInfoUpdateTransportType(SOSFullPeerInfoRef peer
, CFStringRef transportType
, CFErrorRef
* error
)
174 return SOSFullPeerInfoUpdate(peer
, error
, ^SOSPeerInfoRef(SOSPeerInfoRef peer
, SecKeyRef key
, CFErrorRef
*error
) {
175 return SOSPeerInfoSetTransportType(kCFAllocatorDefault
, peer
, transportType
, key
, error
);
179 bool SOSFullPeerInfoUpdateDeviceID(SOSFullPeerInfoRef peer
, CFStringRef deviceID
, CFErrorRef
* error
){
180 return SOSFullPeerInfoUpdate(peer
, error
, ^SOSPeerInfoRef(SOSPeerInfoRef peer
, SecKeyRef key
, CFErrorRef
*error
) {
181 return SOSPeerInfoSetDeviceID(kCFAllocatorDefault
, peer
, deviceID
, key
, error
);
185 bool SOSFullPeerInfoUpdateTransportPreference(SOSFullPeerInfoRef peer
, CFBooleanRef preference
, CFErrorRef
* error
){
186 return SOSFullPeerInfoUpdate(peer
, error
, ^SOSPeerInfoRef(SOSPeerInfoRef peer
, SecKeyRef key
, CFErrorRef
*error
) {
187 return SOSPeerInfoSetIDSPreference(kCFAllocatorDefault
, peer
, preference
, key
, error
);
191 bool SOSFullPeerInfoUpdateTransportFragmentationPreference(SOSFullPeerInfoRef peer
, CFBooleanRef preference
, CFErrorRef
* error
){
192 return SOSFullPeerInfoUpdate(peer
, error
, ^SOSPeerInfoRef(SOSPeerInfoRef peer
, SecKeyRef key
, CFErrorRef
*error
) {
193 return SOSPeerInfoSetIDSFragmentationPreference(kCFAllocatorDefault
, peer
, preference
, key
, error
);
197 bool SOSFullPeerInfoUpdateTransportAckModelPreference(SOSFullPeerInfoRef peer
, CFBooleanRef preference
, CFErrorRef
* error
){
198 return SOSFullPeerInfoUpdate(peer
, error
, ^SOSPeerInfoRef(SOSPeerInfoRef peer
, SecKeyRef key
, CFErrorRef
*error
) {
199 return SOSPeerInfoSetIDSACKModelPreference(kCFAllocatorDefault
, peer
, preference
, key
, error
);
203 SOSFullPeerInfoRef
SOSFullPeerInfoCreateCloudIdentity(CFAllocatorRef allocator
, SOSPeerInfoRef peer
, CFErrorRef
* error
) {
204 SOSFullPeerInfoRef fpi
= CFTypeAllocate(SOSFullPeerInfo
, struct __OpaqueSOSFullPeerInfo
, allocator
);
206 SecKeyRef pubKey
= NULL
;
208 fpi
->peer_info
= peer
;
209 CFRetainSafe(fpi
->peer_info
);
210 if (fpi
->peer_info
== NULL
) {
215 pubKey
= SOSPeerInfoCopyPubKey(peer
, error
);
216 require_quiet(pubKey
, exit
);
218 fpi
->key_ref
= SecKeyCreatePersistentRefToMatchingPrivateKey(pubKey
, error
);
220 if (fpi
->key_ref
== NULL
) {
226 CFReleaseNull(pubKey
);
231 SOSFullPeerInfoRef
SOSFullPeerInfoCreateFromDER(CFAllocatorRef allocator
, CFErrorRef
* error
,
232 const uint8_t** der_p
, const uint8_t *der_end
) {
233 SOSFullPeerInfoRef fpi
= CFTypeAllocate(SOSFullPeerInfo
, struct __OpaqueSOSFullPeerInfo
, allocator
);
235 const uint8_t *sequence_end
;
237 *der_p
= ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
, &sequence_end
, *der_p
, der_end
);
238 CFReleaseNull(fpi
->peer_info
);
239 fpi
->peer_info
= SOSPeerInfoCreateFromDER(allocator
, error
, der_p
, der_end
);
240 require_quiet(fpi
->peer_info
!= NULL
, fail
);
242 *der_p
= der_decode_data(allocator
, kCFPropertyListImmutable
, &fpi
->key_ref
, error
, *der_p
, sequence_end
);
243 require_quiet(*der_p
!= NULL
, fail
);
252 SOSFullPeerInfoRef
SOSFullPeerInfoCreateFromData(CFAllocatorRef allocator
, CFDataRef fullPeerData
, CFErrorRef
*error
)
254 if(!fullPeerData
) return NULL
;
255 size_t size
= CFDataGetLength(fullPeerData
);
256 const uint8_t *der
= CFDataGetBytePtr(fullPeerData
);
257 SOSFullPeerInfoRef inflated
= SOSFullPeerInfoCreateFromDER(allocator
, error
, &der
, der
+ size
);
261 static void SOSFullPeerInfoDestroy(CFTypeRef aObj
) {
262 SOSFullPeerInfoRef fpi
= (SOSFullPeerInfoRef
) aObj
;
264 CFReleaseNull(fpi
->peer_info
);
265 CFReleaseNull(fpi
->key_ref
);
268 static Boolean
SOSFullPeerInfoCompare(CFTypeRef lhs
, CFTypeRef rhs
) {
269 SOSFullPeerInfoRef lpeer
= (SOSFullPeerInfoRef
) lhs
;
270 SOSFullPeerInfoRef rpeer
= (SOSFullPeerInfoRef
) rhs
;
272 if (!CFEqual(lpeer
->peer_info
, rpeer
->peer_info
))
275 if (CFEqual(lpeer
->key_ref
, rpeer
->key_ref
))
278 SecKeyRef lpk
= SOSFullPeerInfoCopyDeviceKey(lpeer
, NULL
);
279 SecKeyRef rpk
= SOSFullPeerInfoCopyDeviceKey(rpeer
, NULL
);
281 bool match
= lpk
&& rpk
&& CFEqual(lpk
, rpk
);
289 static CFHashCode
SOSFullPeerInfoHash(CFTypeRef cf
) {
290 SOSFullPeerInfoRef peer
= (SOSFullPeerInfoRef
) cf
;
292 return CFHash(peer
->peer_info
);
295 static CFStringRef
SOSFullPeerInfoCopyFormatDescription(CFTypeRef aObj
, CFDictionaryRef formatOptions
) {
296 SOSFullPeerInfoRef fpi
= (SOSFullPeerInfoRef
) aObj
;
298 return CFStringCreateWithFormat(NULL
, NULL
, CFSTR("<SOSFullPeerInfo@%p: \"%@\">"), fpi
, fpi
->peer_info
);
301 bool SOSFullPeerInfoUpdateGestalt(SOSFullPeerInfoRef peer
, CFDictionaryRef gestalt
, CFErrorRef
* error
)
303 return SOSFullPeerInfoUpdate(peer
, error
, ^SOSPeerInfoRef(SOSPeerInfoRef peer
, SecKeyRef key
, CFErrorRef
*error
) {
304 return SOSPeerInfoCopyWithGestaltUpdate(kCFAllocatorDefault
, peer
,
305 gestalt
, key
, error
);
309 bool SOSFullPeerInfoUpdateV2Dictionary(SOSFullPeerInfoRef peer
, CFDictionaryRef newv2dict
, CFErrorRef
* error
)
311 return SOSFullPeerInfoUpdate(peer
, error
, ^SOSPeerInfoRef(SOSPeerInfoRef peer
, SecKeyRef key
, CFErrorRef
*error
) {
312 return SOSPeerInfoCopyWithV2DictionaryUpdate(kCFAllocatorDefault
, peer
,
313 newv2dict
, key
, error
);
317 bool SOSFullPeerInfoUpdateBackupKey(SOSFullPeerInfoRef peer
, CFDataRef backupKey
, CFErrorRef
* error
)
319 return SOSFullPeerInfoUpdate(peer
, error
, ^SOSPeerInfoRef(SOSPeerInfoRef peer
, SecKeyRef key
, CFErrorRef
*error
) {
320 return SOSPeerInfoCopyWithBackupKeyUpdate(kCFAllocatorDefault
, peer
, backupKey
, key
, error
);
324 bool SOSFullPeerInfoAddEscrowRecord(SOSFullPeerInfoRef peer
, CFStringRef dsid
, CFDictionaryRef escrowRecord
, CFErrorRef
* error
)
326 return SOSFullPeerInfoUpdate(peer
, error
, ^SOSPeerInfoRef(SOSPeerInfoRef peer
, SecKeyRef key
, CFErrorRef
*error
) {
327 return SOSPeerInfoCopyWithEscrowRecordUpdate(kCFAllocatorDefault
, peer
, dsid
, escrowRecord
, key
, error
);
331 bool SOSFullPeerInfoReplaceEscrowRecords(SOSFullPeerInfoRef peer
, CFDictionaryRef escrowRecords
, CFErrorRef
* error
)
333 return SOSFullPeerInfoUpdate(peer
, error
, ^SOSPeerInfoRef(SOSPeerInfoRef peer
, SecKeyRef key
, CFErrorRef
*error
) {
334 return SOSPeerInfoCopyWithReplacedEscrowRecords(kCFAllocatorDefault
, peer
, escrowRecords
, key
, error
);
338 SOSViewResultCode
SOSFullPeerInfoUpdateViews(SOSFullPeerInfoRef peer
, SOSViewActionCode action
, CFStringRef viewname
, CFErrorRef
* error
)
340 __block SOSViewResultCode retval
= kSOSCCGeneralViewError
;
342 secnotice("viewChange", "%s view %@", SOSViewsXlateAction(action
), viewname
);
344 return SOSFullPeerInfoUpdate(peer
, error
, ^SOSPeerInfoRef(SOSPeerInfoRef peer
, SecKeyRef key
, CFErrorRef
*error
) {
345 return SOSPeerInfoCopyWithViewsChange(kCFAllocatorDefault
, peer
, action
, viewname
, &retval
, key
, error
);
346 }) ? retval
: kSOSCCGeneralViewError
;
349 static CFMutableSetRef
SOSFullPeerInfoCopyViewUpdate(SOSFullPeerInfoRef peer
, CFSetRef minimumViews
, CFSetRef excludedViews
) {
350 CFSetRef enabledViews
= SOSPeerInfoCopyEnabledViews(peer
->peer_info
);
351 CFMutableSetRef newViews
= SOSPeerInfoCopyEnabledViews(peer
->peer_info
);
353 if (isSet(minimumViews
)) {
354 CFSetUnion(newViews
, minimumViews
);
356 if (isSet(excludedViews
)) {
357 CFSetSubtract(newViews
, excludedViews
);
360 if (CFEqualSafe(newViews
, enabledViews
)) {
361 CFReleaseNull(newViews
);
364 CFReleaseNull(enabledViews
);
368 static bool SOSFullPeerInfoNeedsViewUpdate(SOSFullPeerInfoRef peer
, CFSetRef minimumViews
, CFSetRef excludedViews
) {
369 CFSetRef updatedViews
= SOSFullPeerInfoCopyViewUpdate(peer
, minimumViews
, excludedViews
);
370 bool needsUpdate
= (updatedViews
!= NULL
);
371 CFReleaseNull(updatedViews
);
375 static bool sosFullPeerInfoRequiresUpdate(SOSFullPeerInfoRef peer
, CFSetRef minimumViews
, CFSetRef excludedViews
) {
377 if(!SOSPeerInfoVersionIsCurrent(peer
->peer_info
)) return true;
378 if(!SOSPeerInfoSerialNumberIsSet(peer
->peer_info
)) return true;
379 if(!(SOSPeerInfoV2DictionaryHasString(peer
->peer_info
, sDeviceID
)))return true;
380 if(!(SOSPeerInfoV2DictionaryHasString(peer
->peer_info
, sTransportType
))) return true;
381 if(!(SOSPeerInfoV2DictionaryHasBoolean(peer
->peer_info
, sPreferIDS
))) return true;
382 if(!(SOSPeerInfoV2DictionaryHasBoolean(peer
->peer_info
, sPreferIDSFragmentation
))) return true;
383 if(!(SOSPeerInfoV2DictionaryHasBoolean(peer
->peer_info
, sPreferIDSACKModel
))) return true;
384 if(SOSFullPeerInfoNeedsViewUpdate(peer
, minimumViews
, excludedViews
)) return true;
389 // Returning false indicates we don't need to upgrade.
390 bool SOSFullPeerInfoUpdateToCurrent(SOSFullPeerInfoRef peer
, CFSetRef minimumViews
, CFSetRef excludedViews
) {
391 bool success
= false;
393 CFMutableSetRef newViews
= NULL
;
394 CFErrorRef copyError
= NULL
;
395 CFErrorRef createError
= NULL
;
396 SecKeyRef device_key
= NULL
;
398 require_quiet(sosFullPeerInfoRequiresUpdate(peer
, minimumViews
, excludedViews
), errOut
);
400 newViews
= SOSFullPeerInfoCopyViewUpdate(peer
, minimumViews
, excludedViews
);
402 device_key
= SOSFullPeerInfoCopyDeviceKey(peer
, ©Error
);
403 require_action_quiet(device_key
, errOut
,
404 secnotice("upgrade", "SOSFullPeerInfoCopyDeviceKey failed: %@", copyError
));
406 SOSPeerInfoRef newPeer
= SOSPeerInfoCreateCurrentCopy(kCFAllocatorDefault
, peer
->peer_info
,
407 NULL
, NULL
, kCFBooleanFalse
, kCFBooleanTrue
, kCFBooleanTrue
, newViews
,
408 device_key
, &createError
);
409 require_action_quiet(newPeer
, errOut
,
410 secnotice("upgrade", "Peer info v2 create copy failed: %@", createError
));
412 CFTransferRetained(peer
->peer_info
, newPeer
);
417 CFReleaseNull(newViews
);
418 CFReleaseNull(copyError
);
419 CFReleaseNull(createError
);
420 CFReleaseNull(device_key
);
424 SOSViewResultCode
SOSFullPeerInfoViewStatus(SOSFullPeerInfoRef peer
, CFStringRef viewname
, CFErrorRef
*error
)
426 SOSPeerInfoRef pi
= SOSFullPeerInfoGetPeerInfo(peer
);
427 if(!pi
) return kSOSCCGeneralViewError
;
428 return SOSPeerInfoViewStatus(pi
, viewname
, error
);
432 SOSSecurityPropertyResultCode
SOSFullPeerInfoUpdateSecurityProperty(SOSFullPeerInfoRef peer
, SOSViewActionCode action
, CFStringRef property
, CFErrorRef
* error
)
434 SOSSecurityPropertyResultCode retval
= kSOSCCGeneralSecurityPropertyError
;
435 SecKeyRef device_key
= SOSFullPeerInfoCopyDeviceKey(peer
, error
);
436 require_quiet(device_key
, fail
);
438 SOSPeerInfoRef newPeer
= SOSPeerInfoCopyWithSecurityPropertyChange(kCFAllocatorDefault
, peer
->peer_info
, action
, property
, &retval
, device_key
, error
);
440 require_quiet(newPeer
, fail
);
442 CFReleaseNull(peer
->peer_info
);
443 peer
->peer_info
= newPeer
;
447 CFReleaseNull(device_key
);
451 SOSSecurityPropertyResultCode
SOSFullPeerInfoSecurityPropertyStatus(SOSFullPeerInfoRef peer
, CFStringRef property
, CFErrorRef
*error
)
453 SOSPeerInfoRef pi
= SOSFullPeerInfoGetPeerInfo(peer
);
454 secnotice("secprop", "have pi %s", (pi
)? "true": "false");
455 if(!pi
) return kSOSCCGeneralSecurityPropertyError
;
456 return SOSPeerInfoSecurityPropertyStatus(pi
, property
, error
);
460 SOSPeerInfoRef
SOSFullPeerInfoGetPeerInfo(SOSFullPeerInfoRef fullPeer
) {
461 return fullPeer
?fullPeer
->peer_info
:NULL
;
464 // MARK: Private Key Retrieval and Existence
466 static SecKeyRef
SOSFullPeerInfoCopyPubKey(SOSFullPeerInfoRef fpi
, CFErrorRef
*error
) {
467 SecKeyRef retval
= NULL
;
468 require_quiet(fpi
, errOut
);
469 SOSPeerInfoRef pi
= SOSFullPeerInfoGetPeerInfo(fpi
);
470 require_quiet(pi
, errOut
);
471 retval
= SOSPeerInfoCopyPubKey(pi
, error
);
477 static SecKeyRef
SOSFullPeerInfoCopyMatchingPrivateKey(SOSFullPeerInfoRef fpi
, CFErrorRef
*error
) {
478 SecKeyRef retval
= NULL
;
480 SecKeyRef pub
= SOSFullPeerInfoCopyPubKey(fpi
, error
);
481 require_quiet(pub
, exit
);
482 retval
= SecKeyCopyMatchingPrivateKey(pub
, error
);
488 static OSStatus
SOSFullPeerInfoGetMatchingPrivateKeyStatus(SOSFullPeerInfoRef fpi
, CFErrorRef
*error
) {
489 OSStatus retval
= errSecParam
;
490 SecKeyRef pub
= SOSFullPeerInfoCopyPubKey(fpi
, error
);
491 require_quiet(pub
, exit
);
492 retval
= SecKeyGetMatchingPrivateKeyStatus(pub
, error
);
499 bool SOSFullPeerInfoValidate(SOSFullPeerInfoRef peer
, CFErrorRef
* error
) {
500 OSStatus result
= SOSFullPeerInfoGetMatchingPrivateKeyStatus(peer
, error
);
501 if(result
== errSecSuccess
) return true;
505 bool SOSFullPeerInfoPrivKeyExists(SOSFullPeerInfoRef peer
) {
506 OSStatus result
= SOSFullPeerInfoGetMatchingPrivateKeyStatus(peer
, NULL
);
507 if(result
== errSecItemNotFound
|| result
== errSecParam
) return false;
511 bool SOSFullPeerInfoPurgePersistentKey(SOSFullPeerInfoRef fpi
, CFErrorRef
* error
) {
513 CFDictionaryRef privQuery
= NULL
;
514 CFMutableDictionaryRef query
= NULL
;
516 SecKeyRef pub
= SOSFullPeerInfoCopyPubKey(fpi
, error
);
517 require_quiet(pub
, fail
);
519 privQuery
= CreatePrivateKeyMatchingQuery(pub
, false);
520 query
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, privQuery
);
521 CFDictionaryAddValue(query
, kSecUseTombstones
, kCFBooleanFalse
);
523 result
= SecError(SecItemDelete(query
), error
, CFSTR("Deleting while purging"));
526 CFReleaseNull(privQuery
);
527 CFReleaseNull(query
);
532 SecKeyRef
SOSFullPeerInfoCopyDeviceKey(SOSFullPeerInfoRef fullPeer
, CFErrorRef
* error
) {
533 return SOSFullPeerInfoCopyMatchingPrivateKey(fullPeer
, error
);
537 // MARK: Encode and decode
539 size_t SOSFullPeerInfoGetDEREncodedSize(SOSFullPeerInfoRef peer
, CFErrorRef
*error
)
541 size_t peer_size
= SOSPeerInfoGetDEREncodedSize(peer
->peer_info
, error
);
545 size_t ref_size
= der_sizeof_data(peer
->key_ref
, error
);
549 return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE
,
550 peer_size
+ ref_size
);
553 uint8_t* SOSFullPeerInfoEncodeToDER(SOSFullPeerInfoRef peer
, CFErrorRef
* error
, const uint8_t* der
, uint8_t* der_end
)
555 return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
, der_end
, der
,
556 SOSPeerInfoEncodeToDER(peer
->peer_info
, error
, der
,
557 der_encode_data(peer
->key_ref
, error
, der
, der_end
)));
560 CFDataRef
SOSFullPeerInfoCopyEncodedData(SOSFullPeerInfoRef peer
, CFAllocatorRef allocator
, CFErrorRef
*error
)
562 size_t size
= SOSFullPeerInfoGetDEREncodedSize(peer
, error
);
565 uint8_t buffer
[size
];
566 uint8_t* start
= SOSFullPeerInfoEncodeToDER(peer
, error
, buffer
, buffer
+ sizeof(buffer
));
567 CFDataRef result
= CFDataCreate(kCFAllocatorDefault
, start
, size
);
571 bool SOSFullPeerInfoPromoteToApplication(SOSFullPeerInfoRef fpi
, SecKeyRef user_key
, CFErrorRef
*error
)
573 bool success
= false;
574 SOSPeerInfoRef old_pi
= NULL
;
576 SecKeyRef device_key
= SOSFullPeerInfoCopyDeviceKey(fpi
, error
);
577 require_quiet(device_key
, exit
);
579 old_pi
= fpi
->peer_info
;
580 fpi
->peer_info
= SOSPeerInfoCopyAsApplication(old_pi
, user_key
, device_key
, error
);
582 require_action_quiet(fpi
->peer_info
, exit
, fpi
->peer_info
= old_pi
; old_pi
= NULL
);
587 CFReleaseSafe(old_pi
);
588 CFReleaseSafe(device_key
);
592 bool SOSFullPeerInfoUpgradeSignatures(SOSFullPeerInfoRef fpi
, SecKeyRef user_key
, CFErrorRef
*error
)
594 bool success
= false;
595 SOSPeerInfoRef old_pi
= NULL
;
597 SecKeyRef device_key
= SOSFullPeerInfoCopyDeviceKey(fpi
, error
);
598 require_quiet(device_key
, exit
);
600 old_pi
= fpi
->peer_info
;
601 fpi
->peer_info
= SOSPeerInfoUpgradeSignatures(NULL
, user_key
, device_key
, old_pi
, error
);
603 require_action_quiet(fpi
->peer_info
, exit
, fpi
->peer_info
= old_pi
; old_pi
= NULL
);
608 CFReleaseSafe(old_pi
);
609 CFReleaseSafe(device_key
);
617 SOSPeerInfoRef
SOSFullPeerInfoPromoteToRetiredAndCopy(SOSFullPeerInfoRef fpi
, CFErrorRef
*error
)
619 SOSPeerInfoRef peer_to_free
= NULL
;
620 SOSPeerInfoRef retired_peer
= NULL
;
621 SecKeyRef key
= SOSFullPeerInfoCopyDeviceKey(fpi
, error
);
622 require_quiet(key
, error_out
);
624 retired_peer
= SOSPeerInfoCreateRetirementTicket(NULL
, key
, fpi
->peer_info
, error
);
626 require_quiet(retired_peer
, error_out
);
628 peer_to_free
= fpi
->peer_info
;
629 fpi
->peer_info
= retired_peer
;
630 CFRetainSafe(fpi
->peer_info
);
634 CFReleaseNull(peer_to_free
);
639 bool SOSFullPeerInfoPing(SOSFullPeerInfoRef peer
, CFErrorRef
* error
) {
641 SecKeyRef device_key
= SOSFullPeerInfoCopyDeviceKey(peer
, error
);
642 require_quiet(device_key
, fail
);
643 SOSPeerInfoRef newPeer
= SOSPeerInfoCopyWithPing(kCFAllocatorDefault
, peer
->peer_info
, device_key
, error
);
644 require_quiet(newPeer
, fail
);
646 CFReleaseNull(peer
->peer_info
);
647 peer
->peer_info
= newPeer
;
651 CFReleaseNull(device_key
);