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 <SecureObjectSync/SOSFullPeerInfo.h>
28 #include <SecureObjectSync/SOSCircle.h>
30 #include <SecureObjectSync/SOSInternal.h>
32 #include <Security/SecKeyPriv.h>
33 #include <Security/SecItemPriv.h>
34 #include <Security/SecOTR.h>
35 #include <CoreFoundation/CFArray.h>
36 #include <dispatch/dispatch.h>
41 #include <utilities/SecCFWrappers.h>
42 #include <utilities/SecCFRelease.h>
44 #include <utilities/der_plist.h>
45 #include <utilities/der_plist_internal.h>
46 #include <corecrypto/ccder.h>
48 #include <CommonCrypto/CommonDigest.h>
49 #include <CommonCrypto/CommonDigestSPI.h>
51 #include <CoreFoundation/CoreFoundation.h>
53 #include "utilities/iOSforOSX.h"
55 #include <AssertMacros.h>
57 #include <utilities/SecCFError.h>
66 extern OSStatus
SecKeyCopyPublicBytes(SecKeyRef key
, CFDataRef
* publicBytes
);
67 extern SecKeyRef
SecKeyCreatePublicFromPrivate(SecKeyRef privateKey
);
72 struct __OpaqueSOSFullPeerInfo
{
75 SOSPeerInfoRef peer_info
;
79 CFGiblisWithHashFor(SOSFullPeerInfo
);
82 static CFStringRef sPublicKeyKey
= CFSTR("PublicSigningKey");
83 static CFStringRef sNameKey
= CFSTR("DeviceName");
84 static CFStringRef sVersionKey
= CFSTR("ConflictVersion");
86 CFStringRef kSOSFullPeerInfoDescriptionKey
= CFSTR("SOSFullPeerInfoDescription");
87 CFStringRef kSOSFullPeerInfoSignatureKey
= CFSTR("SOSFullPeerInfoSignature");
88 CFStringRef kSOSFullPeerInfoNameKey
= CFSTR("SOSFullPeerInfoName");
90 SOSFullPeerInfoRef
SOSFullPeerInfoCreate(CFAllocatorRef allocator
, CFDictionaryRef gestalt
, SecKeyRef signingKey
, CFErrorRef
* error
) {
91 SOSFullPeerInfoRef fpi
= CFTypeAllocate(SOSFullPeerInfo
, struct __OpaqueSOSFullPeerInfo
, allocator
);
93 fpi
->peer_info
= SOSPeerInfoCreate(allocator
, gestalt
, signingKey
, error
);
94 if (fpi
->peer_info
== NULL
) {
99 OSStatus result
= SecKeyCopyPersistentRef(signingKey
, &fpi
->key_ref
);
101 if (result
!= errSecSuccess
) {
112 SOSFullPeerInfoRef
SOSFullPeerInfoCreateCloudIdentity(CFAllocatorRef allocator
, SOSPeerInfoRef peer
, CFErrorRef
* error
) {
113 SOSFullPeerInfoRef fpi
= CFTypeAllocate(SOSFullPeerInfo
, struct __OpaqueSOSFullPeerInfo
, allocator
);
115 SecKeyRef pubKey
= NULL
;
117 fpi
->peer_info
= peer
;
118 CFRetainSafe(fpi
->peer_info
);
119 if (fpi
->peer_info
== NULL
) {
124 pubKey
= SOSPeerInfoCopyPubKey(peer
);
126 fpi
->key_ref
= SecKeyCreatePersistentRefToMatchingPrivateKey(pubKey
, error
);
128 if (fpi
->key_ref
== NULL
) {
134 CFReleaseNull(pubKey
);
139 SOSFullPeerInfoRef
SOSFullPeerInfoCreateFromDER(CFAllocatorRef allocator
, CFErrorRef
* error
,
140 const uint8_t** der_p
, const uint8_t *der_end
) {
141 SOSFullPeerInfoRef fpi
= CFTypeAllocate(SOSFullPeerInfo
, struct __OpaqueSOSFullPeerInfo
, allocator
);
142 SecKeyRef device_key
= NULL
;
144 const uint8_t *sequence_end
;
146 *der_p
= ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
, &sequence_end
, *der_p
, der_end
);
148 fpi
->peer_info
= SOSPeerInfoCreateFromDER(allocator
, error
, der_p
, der_end
);
149 require_quiet(fpi
->peer_info
!= NULL
, fail
);
151 *der_p
= der_decode_data(allocator
, kCFPropertyListImmutable
, &fpi
->key_ref
, error
, *der_p
, sequence_end
);
153 OSStatus result
= SecKeyFindWithPersistentRef(fpi
->key_ref
, &device_key
);
155 require_quiet(result
== errSecSuccess
, fail
);
156 require_quiet(*der_p
!= NULL
, fail
);
158 CFReleaseNull(device_key
);
163 CFReleaseNull(device_key
);
167 SOSFullPeerInfoRef
SOSFullPeerInfoCreateFromData(CFAllocatorRef allocator
, CFDataRef fullPeerData
, CFErrorRef
*error
)
169 size_t size
= CFDataGetLength(fullPeerData
);
170 const uint8_t *der
= CFDataGetBytePtr(fullPeerData
);
171 SOSFullPeerInfoRef inflated
= SOSFullPeerInfoCreateFromDER(allocator
, error
, &der
, der
+ size
);
175 static void SOSFullPeerInfoDestroy(CFTypeRef aObj
) {
176 SOSFullPeerInfoRef fpi
= (SOSFullPeerInfoRef
) aObj
;
178 CFReleaseNull(fpi
->peer_info
);
179 CFReleaseNull(fpi
->key_ref
);
182 static Boolean
SOSFullPeerInfoCompare(CFTypeRef lhs
, CFTypeRef rhs
) {
183 SOSFullPeerInfoRef lpeer
= (SOSFullPeerInfoRef
) lhs
;
184 SOSFullPeerInfoRef rpeer
= (SOSFullPeerInfoRef
) rhs
;
186 if (!CFEqual(lpeer
->peer_info
, rpeer
->peer_info
))
189 if (CFEqual(lpeer
->key_ref
, rpeer
->key_ref
))
192 SecKeyRef lpk
= SOSFullPeerInfoCopyDeviceKey(lpeer
, NULL
);
193 SecKeyRef rpk
= SOSFullPeerInfoCopyDeviceKey(rpeer
, NULL
);
195 bool match
= lpk
&& rpk
&& CFEqual(lpk
, rpk
);
203 static CFHashCode
SOSFullPeerInfoHash(CFTypeRef cf
) {
204 SOSFullPeerInfoRef peer
= (SOSFullPeerInfoRef
) cf
;
206 return CFHash(peer
->peer_info
);
209 static CFStringRef
SOSFullPeerInfoCopyDescription(CFTypeRef aObj
) {
210 SOSFullPeerInfoRef fpi
= (SOSFullPeerInfoRef
) aObj
;
212 return CFStringCreateWithFormat(NULL
, NULL
, CFSTR("<SOSFullPeerInfo@%p: \"%@\">"), fpi
, fpi
->peer_info
);
215 bool SOSFullPeerInfoUpdateGestalt(SOSFullPeerInfoRef peer
, CFDictionaryRef gestalt
, CFErrorRef
* error
)
217 SecKeyRef device_key
= SOSFullPeerInfoCopyDeviceKey(peer
, error
);
218 require_quiet(device_key
, fail
);
220 SOSPeerInfoRef newPeer
= SOSPeerInfoCopyWithGestaltUpdate(kCFAllocatorDefault
, peer
->peer_info
,
221 gestalt
, device_key
, error
);
223 require_quiet(newPeer
, fail
);
225 CFReleaseNull(peer
->peer_info
);
226 peer
->peer_info
= newPeer
;
229 CFReleaseNull(device_key
);
233 CFReleaseNull(device_key
);
238 bool SOSFullPeerInfoValidate(SOSFullPeerInfoRef peer
, CFErrorRef
* error
) {
242 bool SOSFullPeerInfoPurgePersistentKey(SOSFullPeerInfoRef fullPeer
, CFErrorRef
* error
) {
243 CFDictionaryRef query
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
244 kSecValuePersistentRef
, fullPeer
->key_ref
,
245 kSecUseTombstones
, kCFBooleanFalse
,
247 SecItemDelete(query
);
248 CFReleaseNull(query
);
249 CFReleaseNull(fullPeer
->key_ref
);
254 SOSPeerInfoRef
SOSFullPeerInfoGetPeerInfo(SOSFullPeerInfoRef fullPeer
)
256 return fullPeer
?fullPeer
->peer_info
:NULL
;
259 SecKeyRef
SOSFullPeerInfoCopyDeviceKey(SOSFullPeerInfoRef fullPeer
, CFErrorRef
* error
)
261 SecKeyRef device_key
= NULL
;
263 require(fullPeer
&& fullPeer
->key_ref
, fail
);
265 OSStatus result
= SecKeyFindWithPersistentRef(fullPeer
->key_ref
, &device_key
);
267 require_action_quiet(result
== errSecSuccess
, fail
, SecError(result
, error
, CFSTR("Finding Persistent Ref")));
272 CFReleaseNull(device_key
);
277 // MARK: Encode and decode
279 size_t SOSFullPeerInfoGetDEREncodedSize(SOSFullPeerInfoRef peer
, CFErrorRef
*error
)
281 size_t peer_size
= SOSPeerInfoGetDEREncodedSize(peer
->peer_info
, error
);
285 size_t ref_size
= der_sizeof_data(peer
->key_ref
, error
);
289 return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE
,
290 peer_size
+ ref_size
);
293 uint8_t* SOSFullPeerInfoEncodeToDER(SOSFullPeerInfoRef peer
, CFErrorRef
* error
, const uint8_t* der
, uint8_t* der_end
)
295 return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
, der_end
, der
,
296 SOSPeerInfoEncodeToDER(peer
->peer_info
, error
, der
,
297 der_encode_data(peer
->key_ref
, error
, der
, der_end
)));
300 CFDataRef
SOSFullPeerInfoCopyEncodedData(SOSFullPeerInfoRef peer
, CFAllocatorRef allocator
, CFErrorRef
*error
)
302 size_t size
= SOSFullPeerInfoGetDEREncodedSize(peer
, error
);
305 uint8_t buffer
[size
];
306 uint8_t* start
= SOSFullPeerInfoEncodeToDER(peer
, error
, buffer
, buffer
+ sizeof(buffer
));
307 CFDataRef result
= CFDataCreate(kCFAllocatorDefault
, start
, size
);
311 bool SOSFullPeerInfoPromoteToApplication(SOSFullPeerInfoRef fpi
, SecKeyRef user_key
, CFErrorRef
*error
)
313 bool success
= false;
314 SOSPeerInfoRef old_pi
= NULL
;
316 SecKeyRef device_key
= SOSFullPeerInfoCopyDeviceKey(fpi
, error
);
317 require_quiet(device_key
, exit
);
319 old_pi
= fpi
->peer_info
;
320 fpi
->peer_info
= SOSPeerInfoCopyAsApplication(old_pi
, user_key
, device_key
, error
);
322 require_action_quiet(fpi
->peer_info
, exit
, fpi
->peer_info
= old_pi
; old_pi
= NULL
);
327 CFReleaseSafe(old_pi
);
328 CFReleaseSafe(device_key
);
332 bool SOSFullPeerInfoUpgradeSignatures(SOSFullPeerInfoRef fpi
, SecKeyRef user_key
, CFErrorRef
*error
)
334 bool success
= false;
335 SOSPeerInfoRef old_pi
= NULL
;
337 SecKeyRef device_key
= SOSFullPeerInfoCopyDeviceKey(fpi
, error
);
338 require_quiet(device_key
, exit
);
340 old_pi
= fpi
->peer_info
;
341 fpi
->peer_info
= SOSPeerInfoUpgradeSignatures(NULL
, user_key
, device_key
, old_pi
, error
);
343 require_action_quiet(fpi
->peer_info
, exit
, fpi
->peer_info
= old_pi
; old_pi
= NULL
);
348 CFReleaseSafe(old_pi
);
349 CFReleaseSafe(device_key
);
357 SOSPeerInfoRef
SOSFullPeerInfoPromoteToRetiredAndCopy(SOSFullPeerInfoRef fpi
, CFErrorRef
*error
)
359 SOSPeerInfoRef peer_to_free
= NULL
;
360 SOSPeerInfoRef retired_peer
= NULL
;
361 SecKeyRef key
= SOSFullPeerInfoCopyDeviceKey(fpi
, error
);
362 require_quiet(key
, error_out
);
364 retired_peer
= SOSPeerInfoCreateRetirementTicket(NULL
, key
, fpi
->peer_info
, error
);
366 require_quiet(retired_peer
, error_out
);
368 peer_to_free
= fpi
->peer_info
;
369 fpi
->peer_info
= retired_peer
;
370 CFRetainSafe(fpi
->peer_info
);
374 CFReleaseNull(peer_to_free
);