]> git.saurik.com Git - apple/security.git/blob - Security/sec/SOSCircle/SecureObjectSync/SOSFullPeerInfo.c
Security-57031.20.26.tar.gz
[apple/security.git] / Security / 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 <SecureObjectSync/SOSFullPeerInfo.h>
28 #include <SecureObjectSync/SOSCircle.h>
29
30 #include <SecureObjectSync/SOSInternal.h>
31
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>
37
38 #include <stdlib.h>
39 #include <assert.h>
40
41 #include <utilities/SecCFWrappers.h>
42 #include <utilities/SecCFRelease.h>
43
44 #include <utilities/der_plist.h>
45 #include <utilities/der_plist_internal.h>
46 #include <corecrypto/ccder.h>
47
48 #include <CommonCrypto/CommonDigest.h>
49 #include <CommonCrypto/CommonDigestSPI.h>
50
51 #include <CoreFoundation/CoreFoundation.h>
52
53 #include "utilities/iOSforOSX.h"
54
55 #include <AssertMacros.h>
56
57 #include <utilities/SecCFError.h>
58
59 // for OS X
60 #ifdef __cplusplus
61 extern "C" {
62 #endif
63
64 //---- missing
65
66 extern OSStatus SecKeyCopyPublicBytes(SecKeyRef key, CFDataRef* publicBytes);
67 extern SecKeyRef SecKeyCreatePublicFromPrivate(SecKeyRef privateKey);
68 #ifdef __cplusplus
69 }
70 #endif
71
72 struct __OpaqueSOSFullPeerInfo {
73 CFRuntimeBase _base;
74
75 SOSPeerInfoRef peer_info;
76 CFDataRef key_ref;
77 };
78
79 CFGiblisWithHashFor(SOSFullPeerInfo);
80
81
82 static CFStringRef sPublicKeyKey = CFSTR("PublicSigningKey");
83 static CFStringRef sNameKey = CFSTR("DeviceName");
84 static CFStringRef sVersionKey = CFSTR("ConflictVersion");
85
86 CFStringRef kSOSFullPeerInfoDescriptionKey = CFSTR("SOSFullPeerInfoDescription");
87 CFStringRef kSOSFullPeerInfoSignatureKey = CFSTR("SOSFullPeerInfoSignature");
88 CFStringRef kSOSFullPeerInfoNameKey = CFSTR("SOSFullPeerInfoName");
89
90 SOSFullPeerInfoRef SOSFullPeerInfoCreate(CFAllocatorRef allocator, CFDictionaryRef gestalt, SecKeyRef signingKey, CFErrorRef* error) {
91 SOSFullPeerInfoRef fpi = CFTypeAllocate(SOSFullPeerInfo, struct __OpaqueSOSFullPeerInfo, allocator);
92
93 fpi->peer_info = SOSPeerInfoCreate(allocator, gestalt, signingKey, error);
94 if (fpi->peer_info == NULL) {
95 CFReleaseNull(fpi);
96 goto exit;
97 }
98
99 OSStatus result = SecKeyCopyPersistentRef(signingKey, &fpi->key_ref);
100
101 if (result != errSecSuccess) {
102 CFReleaseNull(fpi);
103 goto exit;
104 }
105
106 exit:
107 return fpi;
108 }
109
110
111
112 SOSFullPeerInfoRef SOSFullPeerInfoCreateCloudIdentity(CFAllocatorRef allocator, SOSPeerInfoRef peer, CFErrorRef* error) {
113 SOSFullPeerInfoRef fpi = CFTypeAllocate(SOSFullPeerInfo, struct __OpaqueSOSFullPeerInfo, allocator);
114
115 SecKeyRef pubKey = NULL;
116
117 fpi->peer_info = peer;
118 CFRetainSafe(fpi->peer_info);
119 if (fpi->peer_info == NULL) {
120 CFReleaseNull(fpi);
121 goto exit;
122 }
123
124 pubKey = SOSPeerInfoCopyPubKey(peer);
125
126 fpi->key_ref = SecKeyCreatePersistentRefToMatchingPrivateKey(pubKey, error);
127
128 if (fpi->key_ref == NULL) {
129 CFReleaseNull(fpi);
130 goto exit;
131 }
132
133 exit:
134 CFReleaseNull(pubKey);
135 return fpi;
136 }
137
138
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
143 const uint8_t *sequence_end;
144
145 *der_p = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &sequence_end, *der_p, der_end);
146
147 fpi->peer_info = SOSPeerInfoCreateFromDER(allocator, error, der_p, der_end);
148 require_quiet(fpi->peer_info != NULL, fail);
149
150 *der_p = der_decode_data(allocator, kCFPropertyListImmutable, &fpi->key_ref, error, *der_p, sequence_end);
151 require_quiet(*der_p != NULL, fail);
152
153 return fpi;
154
155 fail:
156 CFReleaseNull(fpi);
157 return NULL;
158 }
159
160 SOSFullPeerInfoRef SOSFullPeerInfoCreateFromData(CFAllocatorRef allocator, CFDataRef fullPeerData, CFErrorRef *error)
161 {
162 size_t size = CFDataGetLength(fullPeerData);
163 const uint8_t *der = CFDataGetBytePtr(fullPeerData);
164 SOSFullPeerInfoRef inflated = SOSFullPeerInfoCreateFromDER(allocator, error, &der, der + size);
165 return inflated;
166 }
167
168 static void SOSFullPeerInfoDestroy(CFTypeRef aObj) {
169 SOSFullPeerInfoRef fpi = (SOSFullPeerInfoRef) aObj;
170
171 CFReleaseNull(fpi->peer_info);
172 CFReleaseNull(fpi->key_ref);
173 }
174
175 static Boolean SOSFullPeerInfoCompare(CFTypeRef lhs, CFTypeRef rhs) {
176 SOSFullPeerInfoRef lpeer = (SOSFullPeerInfoRef) lhs;
177 SOSFullPeerInfoRef rpeer = (SOSFullPeerInfoRef) rhs;
178
179 if (!CFEqual(lpeer->peer_info, rpeer->peer_info))
180 return false;
181
182 if (CFEqual(lpeer->key_ref, rpeer->key_ref))
183 return true;
184
185 SecKeyRef lpk = SOSFullPeerInfoCopyDeviceKey(lpeer, NULL);
186 SecKeyRef rpk = SOSFullPeerInfoCopyDeviceKey(rpeer, NULL);
187
188 bool match = lpk && rpk && CFEqual(lpk, rpk);
189
190 CFReleaseNull(lpk);
191 CFReleaseNull(rpk);
192
193 return match;
194 }
195
196 static CFHashCode SOSFullPeerInfoHash(CFTypeRef cf) {
197 SOSFullPeerInfoRef peer = (SOSFullPeerInfoRef) cf;
198
199 return CFHash(peer->peer_info);
200 }
201
202 static CFStringRef SOSFullPeerInfoCopyFormatDescription(CFTypeRef aObj, CFDictionaryRef formatOptions) {
203 SOSFullPeerInfoRef fpi = (SOSFullPeerInfoRef) aObj;
204
205 return CFStringCreateWithFormat(NULL, NULL, CFSTR("<SOSFullPeerInfo@%p: \"%@\">"), fpi, fpi->peer_info);
206 }
207
208 bool SOSFullPeerInfoUpdateGestalt(SOSFullPeerInfoRef peer, CFDictionaryRef gestalt, CFErrorRef* error)
209 {
210 SecKeyRef device_key = SOSFullPeerInfoCopyDeviceKey(peer, error);
211 require_quiet(device_key, fail);
212
213 SOSPeerInfoRef newPeer = SOSPeerInfoCopyWithGestaltUpdate(kCFAllocatorDefault, peer->peer_info,
214 gestalt, device_key, error);
215
216 require_quiet(newPeer, fail);
217
218 CFReleaseNull(peer->peer_info);
219 peer->peer_info = newPeer;
220 newPeer = NULL;
221
222 CFReleaseNull(device_key);
223 return true;
224
225 fail:
226 CFReleaseNull(device_key);
227 return false;
228 }
229
230
231 bool SOSFullPeerInfoValidate(SOSFullPeerInfoRef peer, CFErrorRef* error) {
232 SecKeyRef device_key = NULL;
233 OSStatus result = SecKeyFindWithPersistentRef(peer->key_ref, &device_key);
234 CFReleaseNull(device_key);
235 if(result == errSecSuccess) return true;
236 return false;
237 }
238
239 bool SOSFullPeerInfoPurgePersistentKey(SOSFullPeerInfoRef fullPeer, CFErrorRef* error) {
240 CFDictionaryRef query = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
241 kSecValuePersistentRef, fullPeer->key_ref,
242 kSecUseTombstones, kCFBooleanFalse,
243 NULL);
244 SecItemDelete(query);
245 CFReleaseNull(query);
246 CFReleaseNull(fullPeer->key_ref);
247
248 return true;
249 }
250
251 SOSPeerInfoRef SOSFullPeerInfoGetPeerInfo(SOSFullPeerInfoRef fullPeer)
252 {
253 return fullPeer?fullPeer->peer_info:NULL;
254 }
255
256 SecKeyRef SOSFullPeerInfoCopyDeviceKey(SOSFullPeerInfoRef fullPeer, CFErrorRef* error)
257 {
258 SecKeyRef device_key = NULL;
259
260 require(fullPeer && fullPeer->key_ref, fail);
261
262 OSStatus result = SecKeyFindWithPersistentRef(fullPeer->key_ref, &device_key);
263
264 require_action_quiet(result == errSecSuccess, fail, SecError(result, error, CFSTR("Finding Persistent Ref")));
265
266 return device_key;
267
268 fail:
269 CFReleaseNull(device_key);
270 return NULL;
271 }
272
273 //
274 // MARK: Encode and decode
275 //
276 size_t SOSFullPeerInfoGetDEREncodedSize(SOSFullPeerInfoRef peer, CFErrorRef *error)
277 {
278 size_t peer_size = SOSPeerInfoGetDEREncodedSize(peer->peer_info, error);
279 if (peer_size == 0)
280 return 0;
281
282 size_t ref_size = der_sizeof_data(peer->key_ref, error);
283 if (ref_size == 0)
284 return 0;
285
286 return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE,
287 peer_size + ref_size);
288 }
289
290 uint8_t* SOSFullPeerInfoEncodeToDER(SOSFullPeerInfoRef peer, CFErrorRef* error, const uint8_t* der, uint8_t* der_end)
291 {
292 return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der,
293 SOSPeerInfoEncodeToDER(peer->peer_info, error, der,
294 der_encode_data(peer->key_ref, error, der, der_end)));
295 }
296
297 CFDataRef SOSFullPeerInfoCopyEncodedData(SOSFullPeerInfoRef peer, CFAllocatorRef allocator, CFErrorRef *error)
298 {
299 size_t size = SOSFullPeerInfoGetDEREncodedSize(peer, error);
300 if (size == 0)
301 return NULL;
302 uint8_t buffer[size];
303 uint8_t* start = SOSFullPeerInfoEncodeToDER(peer, error, buffer, buffer + sizeof(buffer));
304 CFDataRef result = CFDataCreate(kCFAllocatorDefault, start, size);
305 return result;
306 }
307
308 bool SOSFullPeerInfoPromoteToApplication(SOSFullPeerInfoRef fpi, SecKeyRef user_key, CFErrorRef *error)
309 {
310 bool success = false;
311 SOSPeerInfoRef old_pi = NULL;
312
313 SecKeyRef device_key = SOSFullPeerInfoCopyDeviceKey(fpi, error);
314 require_quiet(device_key, exit);
315
316 old_pi = fpi->peer_info;
317 fpi->peer_info = SOSPeerInfoCopyAsApplication(old_pi, user_key, device_key, error);
318
319 require_action_quiet(fpi->peer_info, exit, fpi->peer_info = old_pi; old_pi = NULL);
320
321 success = true;
322
323 exit:
324 CFReleaseSafe(old_pi);
325 CFReleaseSafe(device_key);
326 return success;
327 }
328
329 bool SOSFullPeerInfoUpgradeSignatures(SOSFullPeerInfoRef fpi, SecKeyRef user_key, CFErrorRef *error)
330 {
331 bool success = false;
332 SOSPeerInfoRef old_pi = NULL;
333
334 SecKeyRef device_key = SOSFullPeerInfoCopyDeviceKey(fpi, error);
335 require_quiet(device_key, exit);
336
337 old_pi = fpi->peer_info;
338 fpi->peer_info = SOSPeerInfoUpgradeSignatures(NULL, user_key, device_key, old_pi, error);
339
340 require_action_quiet(fpi->peer_info, exit, fpi->peer_info = old_pi; old_pi = NULL);
341
342 success = true;
343
344 exit:
345 CFReleaseSafe(old_pi);
346 CFReleaseSafe(device_key);
347 return success;
348 }
349
350 //
351 //
352 //
353
354 SOSPeerInfoRef SOSFullPeerInfoPromoteToRetiredAndCopy(SOSFullPeerInfoRef fpi, CFErrorRef *error)
355 {
356 SOSPeerInfoRef peer_to_free = NULL;
357 SOSPeerInfoRef retired_peer = NULL;
358 SecKeyRef key = SOSFullPeerInfoCopyDeviceKey(fpi, error);
359 require_quiet(key, error_out);
360
361 retired_peer = SOSPeerInfoCreateRetirementTicket(NULL, key, fpi->peer_info, error);
362
363 require_quiet(retired_peer, error_out);
364
365 peer_to_free = fpi->peer_info;
366 fpi->peer_info = retired_peer;
367 CFRetainSafe(fpi->peer_info);
368
369 error_out:
370 CFReleaseNull(key);
371 CFReleaseNull(peer_to_free);
372 return retired_peer;
373 }
374
375
376