]> git.saurik.com Git - apple/security.git/blob - OSX/sec/SOSCircle/SecureObjectSync/SOSFullPeerInfo.c
Security-57740.31.2.tar.gz
[apple/security.git] / OSX / 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 <Security/SecureObjectSync/SOSFullPeerInfo.h>
28 #include <Security/SecureObjectSync/SOSPeerInfoV2.h>
29
30 #include <Security/SecureObjectSync/SOSCircle.h>
31
32 #include <Security/SecureObjectSync/SOSInternal.h>
33 #include <Security/SecureObjectSync/SOSAccountPriv.h>
34
35 #include <Security/SecKeyPriv.h>
36 #include <Security/SecItemPriv.h>
37 #include <Security/SecOTR.h>
38 #include <CoreFoundation/CFArray.h>
39 #include <dispatch/dispatch.h>
40 #include <SOSPeerInfoDER.h>
41 #include <Security/SecFramework.h>
42
43 #include <stdlib.h>
44 #include <assert.h>
45
46 #include <utilities/SecCFWrappers.h>
47 #include <utilities/SecCFRelease.h>
48
49 #include <utilities/der_plist.h>
50 #include <utilities/der_plist_internal.h>
51 #include <corecrypto/ccder.h>
52
53 #include <CommonCrypto/CommonDigest.h>
54 #include <CommonCrypto/CommonDigestSPI.h>
55
56 #include <CoreFoundation/CoreFoundation.h>
57
58 #include "utilities/iOSforOSX.h"
59
60 #include <AssertMacros.h>
61
62 #include <utilities/SecCFError.h>
63
64 // for OS X
65 #ifdef __cplusplus
66 extern "C" {
67 #endif
68
69 //---- missing
70
71 extern OSStatus SecKeyCopyPublicBytes(SecKeyRef key, CFDataRef* publicBytes);
72 extern SecKeyRef SecKeyCreatePublicFromPrivate(SecKeyRef privateKey);
73 #ifdef __cplusplus
74 }
75 #endif
76
77 struct __OpaqueSOSFullPeerInfo {
78 CFRuntimeBase _base;
79
80 SOSPeerInfoRef peer_info;
81 CFDataRef key_ref;
82 };
83
84 CFGiblisWithHashFor(SOSFullPeerInfo);
85
86
87
88 CFStringRef kSOSFullPeerInfoDescriptionKey = CFSTR("SOSFullPeerInfoDescription");
89 CFStringRef kSOSFullPeerInfoSignatureKey = CFSTR("SOSFullPeerInfoSignature");
90 CFStringRef kSOSFullPeerInfoNameKey = CFSTR("SOSFullPeerInfoName");
91
92
93 static bool SOSFullPeerInfoUpdate(SOSFullPeerInfoRef peer, CFErrorRef *error, SOSPeerInfoRef (^create_modification)(SOSPeerInfoRef peer, SecKeyRef key, CFErrorRef *error)) {
94 bool result = false;
95
96 SOSPeerInfoRef newPeer = NULL;
97 SecKeyRef device_key = SOSFullPeerInfoCopyDeviceKey(peer, error);
98 require_quiet(device_key, fail);
99
100 newPeer = create_modification(peer->peer_info, device_key, error);
101 require_quiet(newPeer, fail);
102
103 CFTransferRetained(peer->peer_info, newPeer);
104
105 result = true;
106
107 fail:
108 CFReleaseNull(device_key);
109 CFReleaseNull(newPeer);
110 return result;
111 }
112
113 bool SOSFullPeerInfoUpdateToThisPeer(SOSFullPeerInfoRef peer, SOSPeerInfoRef pi, CFErrorRef *error) {
114 return SOSFullPeerInfoUpdate(peer, error, ^SOSPeerInfoRef(SOSPeerInfoRef peer, SecKeyRef key, CFErrorRef *error) {
115 return SOSPeerInfoSign(key, pi, error) ? CFRetainSafe(pi): NULL;
116 });
117 }
118
119 SOSFullPeerInfoRef SOSFullPeerInfoCreate(CFAllocatorRef allocator, CFDictionaryRef gestalt,
120 CFDataRef backupKey, SecKeyRef signingKey,
121 CFErrorRef* error) {
122 return SOSFullPeerInfoCreateWithViews(allocator, gestalt, backupKey, NULL, signingKey, error);
123 }
124
125 SOSFullPeerInfoRef SOSFullPeerInfoCreateWithViews(CFAllocatorRef allocator,
126 CFDictionaryRef gestalt, CFDataRef backupKey, CFSetRef initialViews,
127 SecKeyRef signingKey, CFErrorRef* error) {
128
129 SOSFullPeerInfoRef result = NULL;
130 SOSFullPeerInfoRef fpi = CFTypeAllocate(SOSFullPeerInfo, struct __OpaqueSOSFullPeerInfo, allocator);
131
132 CFStringRef IDSID = CFSTR("");
133 CFStringRef transportType =SOSTransportMessageTypeIDSV2;
134 CFBooleanRef preferIDS = kCFBooleanFalse;
135 CFBooleanRef preferIDSFragmentation = kCFBooleanTrue;
136
137 fpi->peer_info = SOSPeerInfoCreateWithTransportAndViews(allocator, gestalt, backupKey,
138 IDSID, transportType, preferIDS,
139 preferIDSFragmentation, initialViews,
140 signingKey, error);
141 require_quiet(fpi->peer_info, exit);
142
143 OSStatus status = SecKeyCopyPersistentRef(signingKey, &fpi->key_ref);
144 require_quiet(SecError(status, error, CFSTR("Inflating persistent ref")), exit);
145
146 CFTransferRetained(result, fpi);
147
148 exit:
149 CFReleaseNull(fpi);
150 return result;
151 }
152
153 SOSFullPeerInfoRef SOSFullPeerInfoCopyFullPeerInfo(SOSFullPeerInfoRef toCopy) {
154 SOSFullPeerInfoRef retval = NULL;
155 SOSFullPeerInfoRef fpi = CFTypeAllocate(SOSFullPeerInfo, struct __OpaqueSOSFullPeerInfo, kCFAllocatorDefault);
156 SOSPeerInfoRef piToCopy = SOSFullPeerInfoGetPeerInfo(toCopy);
157
158 require_quiet(piToCopy, errOut);
159 require_quiet(fpi, errOut);
160 fpi->peer_info = SOSPeerInfoCreateCopy(kCFAllocatorDefault, piToCopy, NULL);
161 require_quiet(fpi->peer_info, errOut);
162 fpi->key_ref = toCopy->key_ref;
163 CFTransferRetained(retval, fpi);
164
165 errOut:
166 CFReleaseNull(fpi);
167 return retval;
168 }
169
170 bool SOSFullPeerInfoUpdateTransportType(SOSFullPeerInfoRef peer, CFStringRef transportType, CFErrorRef* error)
171 {
172 return SOSFullPeerInfoUpdate(peer, error, ^SOSPeerInfoRef(SOSPeerInfoRef peer, SecKeyRef key, CFErrorRef *error) {
173 return SOSPeerInfoSetTransportType(kCFAllocatorDefault, peer, transportType, key, error);
174 });
175 }
176
177 bool SOSFullPeerInfoUpdateDeviceID(SOSFullPeerInfoRef peer, CFStringRef deviceID, CFErrorRef* error){
178 return SOSFullPeerInfoUpdate(peer, error, ^SOSPeerInfoRef(SOSPeerInfoRef peer, SecKeyRef key, CFErrorRef *error) {
179 return SOSPeerInfoSetDeviceID(kCFAllocatorDefault, peer, deviceID, key, error);
180 });
181 }
182
183 bool SOSFullPeerInfoUpdateTransportPreference(SOSFullPeerInfoRef peer, CFBooleanRef preference, CFErrorRef* error){
184 return SOSFullPeerInfoUpdate(peer, error, ^SOSPeerInfoRef(SOSPeerInfoRef peer, SecKeyRef key, CFErrorRef *error) {
185 return SOSPeerInfoSetIDSPreference(kCFAllocatorDefault, peer, preference, key, error);
186 });
187 }
188
189 bool SOSFullPeerInfoUpdateTransportFragmentationPreference(SOSFullPeerInfoRef peer, CFBooleanRef preference, CFErrorRef* error){
190 return SOSFullPeerInfoUpdate(peer, error, ^SOSPeerInfoRef(SOSPeerInfoRef peer, SecKeyRef key, CFErrorRef *error) {
191 return SOSPeerInfoSetIDSFragmentationPreference(kCFAllocatorDefault, peer, preference, key, error);
192 });
193 }
194
195
196 SOSFullPeerInfoRef SOSFullPeerInfoCreateCloudIdentity(CFAllocatorRef allocator, SOSPeerInfoRef peer, CFErrorRef* error) {
197 SOSFullPeerInfoRef fpi = CFTypeAllocate(SOSFullPeerInfo, struct __OpaqueSOSFullPeerInfo, allocator);
198
199 SecKeyRef pubKey = NULL;
200
201 fpi->peer_info = peer;
202 CFRetainSafe(fpi->peer_info);
203 if (fpi->peer_info == NULL) {
204 CFReleaseNull(fpi);
205 goto exit;
206 }
207
208 pubKey = SOSPeerInfoCopyPubKey(peer, error);
209 require_quiet(pubKey, exit);
210
211 fpi->key_ref = SecKeyCreatePersistentRefToMatchingPrivateKey(pubKey, error);
212
213 if (fpi->key_ref == NULL) {
214 CFReleaseNull(fpi);
215 goto exit;
216 }
217
218 exit:
219 CFReleaseNull(pubKey);
220 return fpi;
221 }
222
223
224 SOSFullPeerInfoRef SOSFullPeerInfoCreateFromDER(CFAllocatorRef allocator, CFErrorRef* error,
225 const uint8_t** der_p, const uint8_t *der_end) {
226 SOSFullPeerInfoRef fpi = CFTypeAllocate(SOSFullPeerInfo, struct __OpaqueSOSFullPeerInfo, allocator);
227
228 const uint8_t *sequence_end;
229
230 *der_p = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &sequence_end, *der_p, der_end);
231 CFReleaseNull(fpi->peer_info);
232 fpi->peer_info = SOSPeerInfoCreateFromDER(allocator, error, der_p, der_end);
233 require_quiet(fpi->peer_info != NULL, fail);
234
235 *der_p = der_decode_data(allocator, kCFPropertyListImmutable, &fpi->key_ref, error, *der_p, sequence_end);
236 require_quiet(*der_p != NULL, fail);
237
238 return fpi;
239
240 fail:
241 CFReleaseNull(fpi);
242 return NULL;
243 }
244
245 SOSFullPeerInfoRef SOSFullPeerInfoCreateFromData(CFAllocatorRef allocator, CFDataRef fullPeerData, CFErrorRef *error)
246 {
247 if(!fullPeerData) return NULL;
248 size_t size = CFDataGetLength(fullPeerData);
249 const uint8_t *der = CFDataGetBytePtr(fullPeerData);
250 SOSFullPeerInfoRef inflated = SOSFullPeerInfoCreateFromDER(allocator, error, &der, der + size);
251 return inflated;
252 }
253
254 static void SOSFullPeerInfoDestroy(CFTypeRef aObj) {
255 SOSFullPeerInfoRef fpi = (SOSFullPeerInfoRef) aObj;
256
257 CFReleaseNull(fpi->peer_info);
258 CFReleaseNull(fpi->key_ref);
259 }
260
261 static Boolean SOSFullPeerInfoCompare(CFTypeRef lhs, CFTypeRef rhs) {
262 SOSFullPeerInfoRef lpeer = (SOSFullPeerInfoRef) lhs;
263 SOSFullPeerInfoRef rpeer = (SOSFullPeerInfoRef) rhs;
264
265 if (!CFEqual(lpeer->peer_info, rpeer->peer_info))
266 return false;
267
268 if (CFEqual(lpeer->key_ref, rpeer->key_ref))
269 return true;
270
271 SecKeyRef lpk = SOSFullPeerInfoCopyDeviceKey(lpeer, NULL);
272 SecKeyRef rpk = SOSFullPeerInfoCopyDeviceKey(rpeer, NULL);
273
274 bool match = lpk && rpk && CFEqual(lpk, rpk);
275
276 CFReleaseNull(lpk);
277 CFReleaseNull(rpk);
278
279 return match;
280 }
281
282 static CFHashCode SOSFullPeerInfoHash(CFTypeRef cf) {
283 SOSFullPeerInfoRef peer = (SOSFullPeerInfoRef) cf;
284
285 return CFHash(peer->peer_info);
286 }
287
288 static CFStringRef SOSFullPeerInfoCopyFormatDescription(CFTypeRef aObj, CFDictionaryRef formatOptions) {
289 SOSFullPeerInfoRef fpi = (SOSFullPeerInfoRef) aObj;
290
291 return CFStringCreateWithFormat(NULL, NULL, CFSTR("<SOSFullPeerInfo@%p: \"%@\">"), fpi, fpi->peer_info);
292 }
293
294 bool SOSFullPeerInfoUpdateGestalt(SOSFullPeerInfoRef peer, CFDictionaryRef gestalt, CFErrorRef* error)
295 {
296 return SOSFullPeerInfoUpdate(peer, error, ^SOSPeerInfoRef(SOSPeerInfoRef peer, SecKeyRef key, CFErrorRef *error) {
297 return SOSPeerInfoCopyWithGestaltUpdate(kCFAllocatorDefault, peer,
298 gestalt, key, error);
299 });
300 }
301
302 bool SOSFullPeerInfoUpdateBackupKey(SOSFullPeerInfoRef peer, CFDataRef backupKey, CFErrorRef* error)
303 {
304 return SOSFullPeerInfoUpdate(peer, error, ^SOSPeerInfoRef(SOSPeerInfoRef peer, SecKeyRef key, CFErrorRef *error) {
305 return SOSPeerInfoCopyWithBackupKeyUpdate(kCFAllocatorDefault, peer, backupKey, key, error);
306 });
307 }
308
309 bool SOSFullPeerInfoAddEscrowRecord(SOSFullPeerInfoRef peer, CFStringRef dsid, CFDictionaryRef escrowRecord, CFErrorRef* error)
310 {
311 return SOSFullPeerInfoUpdate(peer, error, ^SOSPeerInfoRef(SOSPeerInfoRef peer, SecKeyRef key, CFErrorRef *error) {
312 return SOSPeerInfoCopyWithEscrowRecordUpdate(kCFAllocatorDefault, peer, dsid, escrowRecord, key, error);
313 });
314 }
315
316 bool SOSFullPeerInfoReplaceEscrowRecords(SOSFullPeerInfoRef peer, CFDictionaryRef escrowRecords, CFErrorRef* error)
317 {
318 return SOSFullPeerInfoUpdate(peer, error, ^SOSPeerInfoRef(SOSPeerInfoRef peer, SecKeyRef key, CFErrorRef *error) {
319 return SOSPeerInfoCopyWithReplacedEscrowRecords(kCFAllocatorDefault, peer, escrowRecords, key, error);
320 });
321 }
322
323 SOSViewResultCode SOSFullPeerInfoUpdateViews(SOSFullPeerInfoRef peer, SOSViewActionCode action, CFStringRef viewname, CFErrorRef* error)
324 {
325 __block SOSViewResultCode retval = kSOSCCGeneralViewError;
326
327 secnotice("viewChange", "%s view %@", SOSViewsXlateAction(action), viewname);
328
329 return SOSFullPeerInfoUpdate(peer, error, ^SOSPeerInfoRef(SOSPeerInfoRef peer, SecKeyRef key, CFErrorRef *error) {
330 return SOSPeerInfoCopyWithViewsChange(kCFAllocatorDefault, peer, action, viewname, &retval, key, error);
331 }) ? retval : kSOSCCGeneralViewError;
332 }
333
334 static CFMutableSetRef SOSFullPeerInfoCopyViewUpdate(SOSFullPeerInfoRef peer, CFSetRef minimumViews, CFSetRef excludedViews) {
335 CFSetRef enabledViews = SOSPeerInfoCopyEnabledViews(peer->peer_info);
336 CFMutableSetRef newViews = SOSPeerInfoCopyEnabledViews(peer->peer_info);
337
338 if (isSet(minimumViews)) {
339 CFSetUnion(newViews, minimumViews);
340 }
341 if (isSet(excludedViews)) {
342 CFSetSubtract(newViews, excludedViews);
343 }
344
345 if (CFEqualSafe(newViews, enabledViews)) {
346 CFReleaseNull(newViews);
347 }
348
349 CFReleaseNull(enabledViews);
350 return newViews;
351 }
352
353 static bool SOSFullPeerInfoNeedsViewUpdate(SOSFullPeerInfoRef peer, CFSetRef minimumViews, CFSetRef excludedViews) {
354 CFSetRef updatedViews = SOSFullPeerInfoCopyViewUpdate(peer, minimumViews, excludedViews);
355 bool needsUpdate = (updatedViews != NULL);
356 CFReleaseNull(updatedViews);
357 return needsUpdate;
358 }
359
360 static bool sosFullPeerInfoRequiresUpdate(SOSFullPeerInfoRef peer, CFSetRef minimumViews, CFSetRef excludedViews) {
361
362 if(!SOSPeerInfoVersionIsCurrent(peer->peer_info)) return true;
363 if(!SOSPeerInfoSerialNumberIsSet(peer->peer_info)) return true;
364 if(!(SOSPeerInfoV2DictionaryHasString(peer->peer_info, sDeviceID)))return true;
365 if(!(SOSPeerInfoV2DictionaryHasString(peer->peer_info, sTransportType))) return true;
366 if(!(SOSPeerInfoV2DictionaryHasBoolean(peer->peer_info, sPreferIDS))) return true;
367 if(!(SOSPeerInfoV2DictionaryHasBoolean(peer->peer_info, sPreferIDSFragmentation))) return true;
368 if(SOSFullPeerInfoNeedsViewUpdate(peer, minimumViews, excludedViews)) return true;
369
370 return false;
371 }
372
373 // Returning false indicates we don't need to upgrade.
374 bool SOSFullPeerInfoUpdateToCurrent(SOSFullPeerInfoRef peer, CFSetRef minimumViews, CFSetRef excludedViews) {
375 bool success = false;
376
377 CFMutableSetRef newViews = NULL;
378 CFErrorRef copyError = NULL;
379 CFErrorRef createError = NULL;
380 SecKeyRef device_key = NULL;
381
382 require_quiet(sosFullPeerInfoRequiresUpdate(peer, minimumViews, excludedViews), errOut);
383
384 newViews = SOSFullPeerInfoCopyViewUpdate(peer, minimumViews, excludedViews);
385
386 device_key = SOSFullPeerInfoCopyDeviceKey(peer, &copyError);
387 require_action_quiet(device_key, errOut,
388 secnotice("upgrade", "SOSFullPeerInfoCopyDeviceKey failed: %@", copyError));
389
390 SOSPeerInfoRef newPeer = SOSPeerInfoCreateCurrentCopy(kCFAllocatorDefault, peer->peer_info,
391 NULL, NULL, kCFBooleanFalse, kCFBooleanTrue, newViews,
392 device_key, &createError);
393 require_action_quiet(newPeer, errOut,
394 secnotice("upgrade", "Peer info v2 create copy failed: %@", createError));
395
396 CFTransferRetained(peer->peer_info, newPeer);
397
398 success = true;
399
400 errOut:
401 CFReleaseNull(newViews);
402 CFReleaseNull(copyError);
403 CFReleaseNull(createError);
404 CFReleaseNull(device_key);
405 return success;
406 }
407
408 SOSViewResultCode SOSFullPeerInfoViewStatus(SOSFullPeerInfoRef peer, CFStringRef viewname, CFErrorRef *error)
409 {
410 SOSPeerInfoRef pi = SOSFullPeerInfoGetPeerInfo(peer);
411 if(!pi) return kSOSCCGeneralViewError;
412 return SOSPeerInfoViewStatus(pi, viewname, error);
413 }
414
415
416 SOSSecurityPropertyResultCode SOSFullPeerInfoUpdateSecurityProperty(SOSFullPeerInfoRef peer, SOSViewActionCode action, CFStringRef property, CFErrorRef* error)
417 {
418 SOSSecurityPropertyResultCode retval = kSOSCCGeneralSecurityPropertyError;
419 SecKeyRef device_key = SOSFullPeerInfoCopyDeviceKey(peer, error);
420 require_quiet(device_key, fail);
421
422 SOSPeerInfoRef newPeer = SOSPeerInfoCopyWithSecurityPropertyChange(kCFAllocatorDefault, peer->peer_info, action, property, &retval, device_key, error);
423
424 require_quiet(newPeer, fail);
425
426 CFReleaseNull(peer->peer_info);
427 peer->peer_info = newPeer;
428 newPeer = NULL;
429
430 fail:
431 CFReleaseNull(device_key);
432 return retval;
433 }
434
435 SOSSecurityPropertyResultCode SOSFullPeerInfoSecurityPropertyStatus(SOSFullPeerInfoRef peer, CFStringRef property, CFErrorRef *error)
436 {
437 SOSPeerInfoRef pi = SOSFullPeerInfoGetPeerInfo(peer);
438 secnotice("secprop", "have pi %s", (pi)? "true": "false");
439 if(!pi) return kSOSCCGeneralSecurityPropertyError;
440 return SOSPeerInfoSecurityPropertyStatus(pi, property, error);
441 }
442
443
444 SOSPeerInfoRef SOSFullPeerInfoGetPeerInfo(SOSFullPeerInfoRef fullPeer) {
445 return fullPeer?fullPeer->peer_info:NULL;
446 }
447
448 // MARK: Private Key Retrieval and Existence
449
450 static SecKeyRef SOSFullPeerInfoCopyPubKey(SOSFullPeerInfoRef fpi, CFErrorRef *error) {
451 SecKeyRef retval = NULL;
452 require_quiet(fpi, errOut);
453 SOSPeerInfoRef pi = SOSFullPeerInfoGetPeerInfo(fpi);
454 require_quiet(pi, errOut);
455 retval = SOSPeerInfoCopyPubKey(pi, error);
456
457 errOut:
458 return retval;
459 }
460
461 static SecKeyRef SOSFullPeerInfoCopyMatchingPrivateKey(SOSFullPeerInfoRef fpi, CFErrorRef *error) {
462 SecKeyRef retval = NULL;
463
464 SecKeyRef pub = SOSFullPeerInfoCopyPubKey(fpi, error);
465 require_quiet(pub, exit);
466 retval = SecKeyCopyMatchingPrivateKey(pub, error);
467 exit:
468 CFReleaseNull(pub);
469 return retval;
470 }
471
472 static OSStatus SOSFullPeerInfoGetMatchingPrivateKeyStatus(SOSFullPeerInfoRef fpi, CFErrorRef *error) {
473 OSStatus retval = errSecParam;
474 SecKeyRef pub = SOSFullPeerInfoCopyPubKey(fpi, error);
475 require_quiet(pub, exit);
476 retval = SecKeyGetMatchingPrivateKeyStatus(pub, error);
477
478 exit:
479 CFReleaseNull(pub);
480 return retval;
481 }
482
483 bool SOSFullPeerInfoValidate(SOSFullPeerInfoRef peer, CFErrorRef* error) {
484 OSStatus result = SOSFullPeerInfoGetMatchingPrivateKeyStatus(peer, error);
485 if(result == errSecSuccess) return true;
486 return false;
487 }
488
489 bool SOSFullPeerInfoPrivKeyExists(SOSFullPeerInfoRef peer) {
490 OSStatus result = SOSFullPeerInfoGetMatchingPrivateKeyStatus(peer, NULL);
491 if(result == errSecItemNotFound || result == errSecParam) return false;
492 return true;
493 }
494
495 bool SOSFullPeerInfoPurgePersistentKey(SOSFullPeerInfoRef fpi, CFErrorRef* error) {
496 bool result = false;
497 CFDictionaryRef privQuery = NULL;
498 CFMutableDictionaryRef query = NULL;
499
500 SecKeyRef pub = SOSFullPeerInfoCopyPubKey(fpi, error);
501 require_quiet(pub, fail);
502
503 privQuery = CreatePrivateKeyMatchingQuery(pub, false);
504 query = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, privQuery);
505 CFDictionaryAddValue(query, kSecUseTombstones, kCFBooleanFalse);
506
507 result = SecError(SecItemDelete(query), error, CFSTR("Deleting while purging"));
508
509 fail:
510 CFReleaseNull(privQuery);
511 CFReleaseNull(query);
512 CFReleaseNull(pub);
513 return result;
514 }
515
516 SecKeyRef SOSFullPeerInfoCopyDeviceKey(SOSFullPeerInfoRef fullPeer, CFErrorRef* error) {
517 return SOSFullPeerInfoCopyMatchingPrivateKey(fullPeer, error);
518 }
519
520 //
521 // MARK: Encode and decode
522 //
523 size_t SOSFullPeerInfoGetDEREncodedSize(SOSFullPeerInfoRef peer, CFErrorRef *error)
524 {
525 size_t peer_size = SOSPeerInfoGetDEREncodedSize(peer->peer_info, error);
526 if (peer_size == 0)
527 return 0;
528
529 size_t ref_size = der_sizeof_data(peer->key_ref, error);
530 if (ref_size == 0)
531 return 0;
532
533 return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE,
534 peer_size + ref_size);
535 }
536
537 uint8_t* SOSFullPeerInfoEncodeToDER(SOSFullPeerInfoRef peer, CFErrorRef* error, const uint8_t* der, uint8_t* der_end)
538 {
539 return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der,
540 SOSPeerInfoEncodeToDER(peer->peer_info, error, der,
541 der_encode_data(peer->key_ref, error, der, der_end)));
542 }
543
544 CFDataRef SOSFullPeerInfoCopyEncodedData(SOSFullPeerInfoRef peer, CFAllocatorRef allocator, CFErrorRef *error)
545 {
546 size_t size = SOSFullPeerInfoGetDEREncodedSize(peer, error);
547 if (size == 0)
548 return NULL;
549 uint8_t buffer[size];
550 uint8_t* start = SOSFullPeerInfoEncodeToDER(peer, error, buffer, buffer + sizeof(buffer));
551 CFDataRef result = CFDataCreate(kCFAllocatorDefault, start, size);
552 return result;
553 }
554
555 bool SOSFullPeerInfoPromoteToApplication(SOSFullPeerInfoRef fpi, SecKeyRef user_key, CFErrorRef *error)
556 {
557 bool success = false;
558 SOSPeerInfoRef old_pi = NULL;
559
560 SecKeyRef device_key = SOSFullPeerInfoCopyDeviceKey(fpi, error);
561 require_quiet(device_key, exit);
562
563 old_pi = fpi->peer_info;
564 fpi->peer_info = SOSPeerInfoCopyAsApplication(old_pi, user_key, device_key, error);
565
566 require_action_quiet(fpi->peer_info, exit, fpi->peer_info = old_pi; old_pi = NULL);
567
568 success = true;
569
570 exit:
571 CFReleaseSafe(old_pi);
572 CFReleaseSafe(device_key);
573 return success;
574 }
575
576 bool SOSFullPeerInfoUpgradeSignatures(SOSFullPeerInfoRef fpi, SecKeyRef user_key, CFErrorRef *error)
577 {
578 bool success = false;
579 SOSPeerInfoRef old_pi = NULL;
580
581 SecKeyRef device_key = SOSFullPeerInfoCopyDeviceKey(fpi, error);
582 require_quiet(device_key, exit);
583
584 old_pi = fpi->peer_info;
585 fpi->peer_info = SOSPeerInfoUpgradeSignatures(NULL, user_key, device_key, old_pi, error);
586
587 require_action_quiet(fpi->peer_info, exit, fpi->peer_info = old_pi; old_pi = NULL);
588
589 success = true;
590
591 exit:
592 CFReleaseSafe(old_pi);
593 CFReleaseSafe(device_key);
594 return success;
595 }
596
597 //
598 //
599 //
600
601 SOSPeerInfoRef SOSFullPeerInfoPromoteToRetiredAndCopy(SOSFullPeerInfoRef fpi, CFErrorRef *error)
602 {
603 SOSPeerInfoRef peer_to_free = NULL;
604 SOSPeerInfoRef retired_peer = NULL;
605 SecKeyRef key = SOSFullPeerInfoCopyDeviceKey(fpi, error);
606 require_quiet(key, error_out);
607
608 retired_peer = SOSPeerInfoCreateRetirementTicket(NULL, key, fpi->peer_info, error);
609
610 require_quiet(retired_peer, error_out);
611
612 peer_to_free = fpi->peer_info;
613 fpi->peer_info = retired_peer;
614 CFRetainSafe(fpi->peer_info);
615
616 error_out:
617 CFReleaseNull(key);
618 CFReleaseNull(peer_to_free);
619 return retired_peer;
620 }
621
622
623 bool SOSFullPeerInfoPing(SOSFullPeerInfoRef peer, CFErrorRef* error) {
624 bool retval = false;
625 SecKeyRef device_key = SOSFullPeerInfoCopyDeviceKey(peer, error);
626 require_quiet(device_key, fail);
627 SOSPeerInfoRef newPeer = SOSPeerInfoCopyWithPing(kCFAllocatorDefault, peer->peer_info, device_key, error);
628 require_quiet(newPeer, fail);
629
630 CFReleaseNull(peer->peer_info);
631 peer->peer_info = newPeer;
632 newPeer = NULL;
633 retval = true;
634 fail:
635 CFReleaseNull(device_key);
636 return retval;
637 }
638
639