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