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