]> git.saurik.com Git - apple/security.git/blob - Security/sec/SOSCircle/SecureObjectSync/SOSFullPeerInfo.c
Security-57031.1.35.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 SecKeyRef device_key = NULL;
143
144 const uint8_t *sequence_end;
145
146 *der_p = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &sequence_end, *der_p, der_end);
147
148 fpi->peer_info = SOSPeerInfoCreateFromDER(allocator, error, der_p, der_end);
149 require_quiet(fpi->peer_info != NULL, fail);
150
151 *der_p = der_decode_data(allocator, kCFPropertyListImmutable, &fpi->key_ref, error, *der_p, sequence_end);
152
153 OSStatus result = SecKeyFindWithPersistentRef(fpi->key_ref, &device_key);
154
155 require_quiet(result == errSecSuccess, fail);
156 require_quiet(*der_p != NULL, fail);
157
158 CFReleaseNull(device_key);
159 return fpi;
160
161 fail:
162 CFReleaseNull(fpi);
163 CFReleaseNull(device_key);
164 return NULL;
165 }
166
167 SOSFullPeerInfoRef SOSFullPeerInfoCreateFromData(CFAllocatorRef allocator, CFDataRef fullPeerData, CFErrorRef *error)
168 {
169 size_t size = CFDataGetLength(fullPeerData);
170 const uint8_t *der = CFDataGetBytePtr(fullPeerData);
171 SOSFullPeerInfoRef inflated = SOSFullPeerInfoCreateFromDER(allocator, error, &der, der + size);
172 return inflated;
173 }
174
175 static void SOSFullPeerInfoDestroy(CFTypeRef aObj) {
176 SOSFullPeerInfoRef fpi = (SOSFullPeerInfoRef) aObj;
177
178 CFReleaseNull(fpi->peer_info);
179 CFReleaseNull(fpi->key_ref);
180 }
181
182 static Boolean SOSFullPeerInfoCompare(CFTypeRef lhs, CFTypeRef rhs) {
183 SOSFullPeerInfoRef lpeer = (SOSFullPeerInfoRef) lhs;
184 SOSFullPeerInfoRef rpeer = (SOSFullPeerInfoRef) rhs;
185
186 if (!CFEqual(lpeer->peer_info, rpeer->peer_info))
187 return false;
188
189 if (CFEqual(lpeer->key_ref, rpeer->key_ref))
190 return true;
191
192 SecKeyRef lpk = SOSFullPeerInfoCopyDeviceKey(lpeer, NULL);
193 SecKeyRef rpk = SOSFullPeerInfoCopyDeviceKey(rpeer, NULL);
194
195 bool match = lpk && rpk && CFEqual(lpk, rpk);
196
197 CFReleaseNull(lpk);
198 CFReleaseNull(rpk);
199
200 return match;
201 }
202
203 static CFHashCode SOSFullPeerInfoHash(CFTypeRef cf) {
204 SOSFullPeerInfoRef peer = (SOSFullPeerInfoRef) cf;
205
206 return CFHash(peer->peer_info);
207 }
208
209 static CFStringRef SOSFullPeerInfoCopyDescription(CFTypeRef aObj) {
210 SOSFullPeerInfoRef fpi = (SOSFullPeerInfoRef) aObj;
211
212 return CFStringCreateWithFormat(NULL, NULL, CFSTR("<SOSFullPeerInfo@%p: \"%@\">"), fpi, fpi->peer_info);
213 }
214
215 bool SOSFullPeerInfoUpdateGestalt(SOSFullPeerInfoRef peer, CFDictionaryRef gestalt, CFErrorRef* error)
216 {
217 SecKeyRef device_key = SOSFullPeerInfoCopyDeviceKey(peer, error);
218 require_quiet(device_key, fail);
219
220 SOSPeerInfoRef newPeer = SOSPeerInfoCopyWithGestaltUpdate(kCFAllocatorDefault, peer->peer_info,
221 gestalt, device_key, error);
222
223 require_quiet(newPeer, fail);
224
225 CFReleaseNull(peer->peer_info);
226 peer->peer_info = newPeer;
227 newPeer = NULL;
228
229 CFReleaseNull(device_key);
230 return true;
231
232 fail:
233 CFReleaseNull(device_key);
234 return false;
235 }
236
237
238 bool SOSFullPeerInfoValidate(SOSFullPeerInfoRef peer, CFErrorRef* error) {
239 return true;
240 }
241
242 bool SOSFullPeerInfoPurgePersistentKey(SOSFullPeerInfoRef fullPeer, CFErrorRef* error) {
243 CFDictionaryRef query = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
244 kSecValuePersistentRef, fullPeer->key_ref,
245 kSecUseTombstones, kCFBooleanFalse,
246 NULL);
247 SecItemDelete(query);
248 CFReleaseNull(query);
249 CFReleaseNull(fullPeer->key_ref);
250
251 return true;
252 }
253
254 SOSPeerInfoRef SOSFullPeerInfoGetPeerInfo(SOSFullPeerInfoRef fullPeer)
255 {
256 return fullPeer?fullPeer->peer_info:NULL;
257 }
258
259 SecKeyRef SOSFullPeerInfoCopyDeviceKey(SOSFullPeerInfoRef fullPeer, CFErrorRef* error)
260 {
261 SecKeyRef device_key = NULL;
262
263 require(fullPeer && fullPeer->key_ref, fail);
264
265 OSStatus result = SecKeyFindWithPersistentRef(fullPeer->key_ref, &device_key);
266
267 require_action_quiet(result == errSecSuccess, fail, SecError(result, error, CFSTR("Finding Persistent Ref")));
268
269 return device_key;
270
271 fail:
272 CFReleaseNull(device_key);
273 return NULL;
274 }
275
276 //
277 // MARK: Encode and decode
278 //
279 size_t SOSFullPeerInfoGetDEREncodedSize(SOSFullPeerInfoRef peer, CFErrorRef *error)
280 {
281 size_t peer_size = SOSPeerInfoGetDEREncodedSize(peer->peer_info, error);
282 if (peer_size == 0)
283 return 0;
284
285 size_t ref_size = der_sizeof_data(peer->key_ref, error);
286 if (ref_size == 0)
287 return 0;
288
289 return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE,
290 peer_size + ref_size);
291 }
292
293 uint8_t* SOSFullPeerInfoEncodeToDER(SOSFullPeerInfoRef peer, CFErrorRef* error, const uint8_t* der, uint8_t* der_end)
294 {
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)));
298 }
299
300 CFDataRef SOSFullPeerInfoCopyEncodedData(SOSFullPeerInfoRef peer, CFAllocatorRef allocator, CFErrorRef *error)
301 {
302 size_t size = SOSFullPeerInfoGetDEREncodedSize(peer, error);
303 if (size == 0)
304 return NULL;
305 uint8_t buffer[size];
306 uint8_t* start = SOSFullPeerInfoEncodeToDER(peer, error, buffer, buffer + sizeof(buffer));
307 CFDataRef result = CFDataCreate(kCFAllocatorDefault, start, size);
308 return result;
309 }
310
311 bool SOSFullPeerInfoPromoteToApplication(SOSFullPeerInfoRef fpi, SecKeyRef user_key, CFErrorRef *error)
312 {
313 bool success = false;
314 SOSPeerInfoRef old_pi = NULL;
315
316 SecKeyRef device_key = SOSFullPeerInfoCopyDeviceKey(fpi, error);
317 require_quiet(device_key, exit);
318
319 old_pi = fpi->peer_info;
320 fpi->peer_info = SOSPeerInfoCopyAsApplication(old_pi, user_key, device_key, error);
321
322 require_action_quiet(fpi->peer_info, exit, fpi->peer_info = old_pi; old_pi = NULL);
323
324 success = true;
325
326 exit:
327 CFReleaseSafe(old_pi);
328 CFReleaseSafe(device_key);
329 return success;
330 }
331
332 bool SOSFullPeerInfoUpgradeSignatures(SOSFullPeerInfoRef fpi, SecKeyRef user_key, CFErrorRef *error)
333 {
334 bool success = false;
335 SOSPeerInfoRef old_pi = NULL;
336
337 SecKeyRef device_key = SOSFullPeerInfoCopyDeviceKey(fpi, error);
338 require_quiet(device_key, exit);
339
340 old_pi = fpi->peer_info;
341 fpi->peer_info = SOSPeerInfoUpgradeSignatures(NULL, user_key, device_key, old_pi, error);
342
343 require_action_quiet(fpi->peer_info, exit, fpi->peer_info = old_pi; old_pi = NULL);
344
345 success = true;
346
347 exit:
348 CFReleaseSafe(old_pi);
349 CFReleaseSafe(device_key);
350 return success;
351 }
352
353 //
354 //
355 //
356
357 SOSPeerInfoRef SOSFullPeerInfoPromoteToRetiredAndCopy(SOSFullPeerInfoRef fpi, CFErrorRef *error)
358 {
359 SOSPeerInfoRef peer_to_free = NULL;
360 SOSPeerInfoRef retired_peer = NULL;
361 SecKeyRef key = SOSFullPeerInfoCopyDeviceKey(fpi, error);
362 require_quiet(key, error_out);
363
364 retired_peer = SOSPeerInfoCreateRetirementTicket(NULL, key, fpi->peer_info, error);
365
366 require_quiet(retired_peer, error_out);
367
368 peer_to_free = fpi->peer_info;
369 fpi->peer_info = retired_peer;
370 CFRetainSafe(fpi->peer_info);
371
372 error_out:
373 CFReleaseNull(key);
374 CFReleaseNull(peer_to_free);
375 return retired_peer;
376 }
377
378
379