2 * Copyright (c) 2015 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
26 * SOSRingUtils.c - Functions for building rings
29 #include <AssertMacros.h>
31 #include <Security/SecureObjectSync/SOSInternal.h>
32 #include <Security/SecureObjectSync/SOSPeer.h>
33 #include <Security/SecureObjectSync/SOSPeerInfoInternal.h>
34 #include <Security/SecureObjectSync/SOSPeerInfoCollections.h>
35 #include <Security/SecureObjectSync/SOSCircle.h>
36 #include <Security/SecFramework.h>
38 #include <Security/SecKey.h>
39 #include <Security/SecKeyPriv.h>
40 #include <CoreFoundation/CoreFoundation.h>
42 #include <utilities/SecCFWrappers.h>
44 //#include "ckdUtilities.h"
46 #include <corecrypto/ccder.h>
47 #include <corecrypto/ccdigest.h>
48 #include <corecrypto/ccsha2.h>
51 #include <utilities/der_plist.h>
52 #include <utilities/der_plist_internal.h>
53 #include <corecrypto/ccder.h>
54 #include <utilities/der_date.h>
60 #include "SOSRingUtils.h"
62 CFGiblisWithCompareFor(SOSRing
);
64 /* unSignedInformation Dictionary Keys */
65 CFStringRef sApplicantsKey
= CFSTR("Applicants");
66 CFStringRef sRejectionsKey
= CFSTR("Rejections");
67 CFStringRef sLastPeerToModifyKey
= CFSTR("LastModifier");
69 /* signedInformation Dictionary Keys */
70 CFStringRef sPeerIDsKey
= CFSTR("PeerIDs");
71 CFStringRef sPayloadKey
= CFSTR("Payload");
72 CFStringRef sBackupViewSetKey
= CFSTR("BackupViews");
73 CFStringRef sGenerationKey
= CFSTR("Generation");
74 CFStringRef sNameKey
= CFSTR("RingName");
75 CFStringRef sTypeKey
= CFSTR("RingType");
76 CFStringRef sIdentifierKey
= CFSTR("Identifier");
77 CFStringRef sRingVersionKey
= CFSTR("RingVersion");
81 SOSRingRef
SOSRingAllocate(void) {
82 return (SOSRingRef
) CFTypeAllocate(SOSRing
, struct __OpaqueSOSRing
, ALLOCATOR
);
85 __unused
static bool addValueToDict(CFMutableDictionaryRef thedict
, CFStringRef key
, CFTypeRef value
) {
86 if(!value
) return false;
87 CFDictionaryAddValue(thedict
, key
, value
);
91 static bool setValueInDict(CFMutableDictionaryRef thedict
, CFStringRef key
, CFTypeRef value
) {
92 if(!value
) return false;
93 CFDictionarySetValue(thedict
, key
, value
);
97 static CFMutableSetRef
CFSetCreateMutableForSOSPeerIDs(void) {
98 return CFSetCreateMutable(ALLOCATOR
, 0, &kCFTypeSetCallBacks
);
103 SOSRingRef
SOSRingConvertAndAssertStable(CFTypeRef ringAsType
) {
104 if (CFGetTypeID(ringAsType
) != SOSRingGetTypeID())
107 SOSRingRef ring
= (SOSRingRef
) ringAsType
;
109 SOSRingAssertStable(ring
);
116 CFStringRef
SOSRingGetName(SOSRingRef ring
) {
118 assert(ring
->signedInformation
);
119 return CFDictionaryGetValue(ring
->signedInformation
, sNameKey
);
122 const char *SOSRingGetNameC(SOSRingRef ring
) {
123 CFStringRef name
= SOSRingGetName(ring
);
126 return CFStringToCString(name
);
129 static inline bool SOSRingSetName(SOSRingRef ring
, CFStringRef name
) {
131 assert(ring
->signedInformation
);
132 return setValueInDict(ring
->signedInformation
, sNameKey
, name
);
137 static bool SOSRingCheckType(SOSRingType type
, CFErrorRef
*error
) {
138 if(type
< kSOSRingTypeCount
) return true;
139 SOSCreateError(kSOSErrorUnexpectedType
, CFSTR("Bad Ring Type Specification"), (error
!= NULL
) ? *error
: NULL
, error
);
143 uint32_t SOSRingGetType(SOSRingRef ring
) {
144 uint32_t retval
= kSOSRingTypeError
; // Error return
145 SOSRingAssertStable(ring
);
146 if(!ring
->signedInformation
) return retval
;
147 CFNumberRef ringtype
= (CFNumberRef
) CFDictionaryGetValue(ring
->signedInformation
, sTypeKey
);
148 CFNumberGetValue(ringtype
, kCFNumberSInt32Type
, &retval
);
152 static inline bool SOSRingSetType(SOSRingRef ring
, uint32_t ringtype
) {
154 CFNumberRef cfrtype
= NULL
;
155 SOSRingAssertStable(ring
);
156 require_action_quiet(SOSRingCheckType(ringtype
, NULL
), errOut
, secnotice("ring", "Bad ring type specification"));
157 cfrtype
= CFNumberCreate(ALLOCATOR
, kCFNumberSInt32Type
, &ringtype
);
158 retval
= setValueInDict(ring
->signedInformation
, sTypeKey
, cfrtype
);
160 CFReleaseNull(cfrtype
);
166 uint32_t SOSRingGetVersion(SOSRingRef ring
) {
167 uint32_t version
= 0;
169 assert(ring
->signedInformation
);
170 CFNumberRef cfversion
= CFDictionaryGetValue(ring
->signedInformation
, sRingVersionKey
);
171 require_action_quiet(cfversion
, errOut
, secnotice("ring", "Could not create version number"));
172 CFNumberGetValue(cfversion
, kCFNumberSInt32Type
, &version
);
177 static inline bool SOSRingSetVersion(SOSRingRef ring
) {
179 assert(ring
->signedInformation
);
180 int32_t thisversion
= RINGVERSION
;
181 CFNumberRef version
= CFNumberCreate(ALLOCATOR
, kCFNumberSInt32Type
, &thisversion
);
182 require_action_quiet(version
, errOut
, secnotice("ring", "Could not create version number"));
183 CFDictionarySetValue(ring
->signedInformation
, sRingVersionKey
, version
);
184 CFReleaseNull(version
);
192 CFStringRef
SOSRingGetIdentifier(SOSRingRef ring
) {
194 assert(ring
->signedInformation
);
195 return CFDictionaryGetValue(ring
->signedInformation
, sIdentifierKey
);
198 static inline bool SOSRingSetIdentifier(SOSRingRef ring
) {
200 assert(ring
->signedInformation
);
202 CFStringRef identifier
= NULL
;
203 CFUUIDRef uuid
= CFUUIDCreate(ALLOCATOR
);
204 require_action_quiet(uuid
, errOut
, secnotice("ring", "Could not create ring identifier"));
205 identifier
= CFUUIDCreateString(ALLOCATOR
, uuid
);
206 CFDictionarySetValue(ring
->signedInformation
, sIdentifierKey
, identifier
);
210 CFReleaseNull(identifier
);
214 // MARK: Ring Identity
216 bool SOSRingIsSame(SOSRingRef ring1
, SOSRingRef ring2
) {
217 CFStringRef name1
= SOSRingGetName(ring1
);
218 CFStringRef name2
= SOSRingGetName(ring2
);
219 require_action_quiet(name1
&& name2
, errOut
, secnotice("ring", "Cannot get both names to consider rings the same"));
220 if(CFEqualSafe(name1
, name2
) != true) return false;
223 // Not considering this for now - upgraded version can still be the "same ring".
224 uint32_t version1
= SOSRingGetVersion(ring1
);
225 uint32_t version2
= SOSRingGetVersion(ring2
);
226 require_action_quiet(version1
&& version2
, errOut
, secnotice("ring", "Cannot get both versions to consider rings the same"));
227 if(version1
!= version2
) return false;
230 uint32_t type1
= SOSRingGetType(ring1
);
231 uint32_t type2
= SOSRingGetVersion(ring2
);
232 require_action_quiet(type1
&& type2
, errOut
, secnotice("ring", "Cannot get both types to consider rings the same"));
233 if(type1
!= type2
) return false;
235 CFStringRef identifier1
= SOSRingGetIdentifier(ring1
);
236 CFStringRef identifier2
= SOSRingGetIdentifier(ring2
);
237 require_action_quiet(identifier1
&& identifier2
, errOut
, secnotice("ring", "Cannot get both identifiers to consider rings the same"));
238 if(CFEqualSafe(identifier1
, identifier2
) != true) return false;
246 static Boolean
SOSRingCompare(CFTypeRef lhs
, CFTypeRef rhs
) {
247 if (CFGetTypeID(lhs
) != SOSRingGetTypeID()
248 || CFGetTypeID(rhs
) != SOSRingGetTypeID())
251 SOSRingRef left
= SOSRingConvertAndAssertStable(lhs
);
252 SOSRingRef right
= SOSRingConvertAndAssertStable(rhs
);
254 return NULL
!= left
&& NULL
!= right
255 && CFEqualSafe(left
->unSignedInformation
, right
->unSignedInformation
)
256 && CFEqualSafe(left
->signedInformation
, right
->signedInformation
)
257 && CFEqualSafe(left
->data
, right
->data
)
258 && CFEqualSafe(left
->signatures
, right
->signatures
);
262 // MARK: Ring Generation Count
264 SOSGenCountRef
SOSRingGetGeneration(SOSRingRef ring
) {
266 assert(ring
->signedInformation
);
267 return CFDictionaryGetValue(ring
->signedInformation
, sGenerationKey
);
270 static inline bool SOSRingSetGeneration(SOSRingRef ring
, SOSGenCountRef gen
) {
272 assert(ring
->signedInformation
);
273 return setValueInDict(ring
->signedInformation
, sGenerationKey
, gen
);
276 void SOSRingGenerationIncrement(SOSRingRef ring
) {
277 SOSGenCountRef gen
= SOSRingGetGeneration(ring
);
278 SOSGenCountRef newgen
= SOSGenerationIncrementAndCreate(gen
);
279 SOSRingSetGeneration(ring
, newgen
);
280 CFReleaseNull(newgen
);
283 bool SOSRingIsOlderGeneration(SOSRingRef olderRing
, SOSRingRef newerRing
) {
284 SOSGenCountRef old
= SOSRingGetGeneration(olderRing
);
285 SOSGenCountRef
new = SOSRingGetGeneration(newerRing
);
286 return SOSGenerationIsOlder(old
, new);
289 void SOSRingGenerationCreateWithBaseline(SOSRingRef newring
, SOSRingRef baseline
) {
291 SOSGenCountRef gen
= SOSGenerationCreateWithBaseline(SOSRingGetGeneration(baseline
));
292 SOSRingSetGeneration(newring
, gen
);
296 // MARK: Last Modifier
297 CFStringRef
SOSRingGetLastModifier(SOSRingRef ring
) {
299 assert(ring
->unSignedInformation
);
300 return CFDictionaryGetValue(ring
->unSignedInformation
, sLastPeerToModifyKey
);
303 bool SOSRingSetLastModifier(SOSRingRef ring
, CFStringRef peerID
) {
305 assert(ring
->unSignedInformation
);
306 return setValueInDict(ring
->unSignedInformation
, sLastPeerToModifyKey
, peerID
);
310 // MARK: Ring Applicants
312 CFMutableSetRef
SOSRingGetApplicants(SOSRingRef ring
) {
313 SOSRingAssertStable(ring
);
314 return (CFMutableSetRef
) CFDictionaryGetValue(ring
->unSignedInformation
, sApplicantsKey
);
317 bool SOSRingSetApplicants(SOSRingRef ring
, CFMutableSetRef applicants
) {
318 SOSRingAssertStable(ring
);
319 return setValueInDict(ring
->unSignedInformation
, sApplicantsKey
, applicants
);
322 int SOSRingCountApplicants(SOSRingRef ring
) {
323 SOSRingAssertStable(ring
);
324 return (int)CFSetGetCount(SOSRingGetApplicants(ring
));
327 bool SOSRingHasApplicant(SOSRingRef ring
, CFStringRef peerID
) {
328 SOSRingAssertStable(ring
);
329 return CFSetContainsValue(SOSRingGetApplicants(ring
), peerID
);
332 CFMutableSetRef
SOSRingCopyApplicants(SOSRingRef ring
) {
333 SOSRingAssertStable(ring
);
334 CFSetRef applicants
= SOSRingGetApplicants(ring
);
335 return CFSetCreateMutableCopy(ALLOCATOR
, 0, applicants
);
338 bool SOSRingAddApplicant(SOSRingRef ring
, CFStringRef peerid
) {
339 CFMutableSetRef applicants
= SOSRingGetApplicants(ring
);
340 CFSetAddValue(applicants
, peerid
);
344 bool SOSRingRemoveApplicant(SOSRingRef ring
, CFStringRef peerid
) {
345 CFMutableSetRef applicants
= SOSRingGetApplicants(ring
);
346 CFSetRemoveValue(applicants
, peerid
);
350 // MARK: Ring Rejections
352 static inline CFMutableSetRef
SOSRingGetRejections(SOSRingRef ring
) {
353 SOSRingAssertStable(ring
);
354 return (CFMutableSetRef
) CFDictionaryGetValue(ring
->unSignedInformation
, sRejectionsKey
);
357 static inline bool SOSRingSetRejections(SOSRingRef ring
, CFMutableSetRef rejections
) {
358 SOSRingAssertStable(ring
);
359 return setValueInDict(ring
->unSignedInformation
, sRejectionsKey
, rejections
);
362 int SOSRingCountRejections(SOSRingRef ring
) {
363 CFSetRef rejects
= SOSRingGetRejections(ring
);
364 return (int)CFSetGetCount(rejects
);
367 bool SOSRingHasRejection(SOSRingRef ring
, CFStringRef peerID
) {
368 SOSRingAssertStable(ring
);
369 return CFSetContainsValue(SOSRingGetRejections(ring
), peerID
);
372 CFMutableSetRef
SOSRingCopyRejections(SOSRingRef ring
) {
373 CFSetRef rejects
= SOSRingGetRejections(ring
);
374 return CFSetCreateMutableCopy(ALLOCATOR
, 0, rejects
);
378 bool SOSRingAddRejection(SOSRingRef ring
, CFStringRef peerid
) {
379 CFMutableSetRef rejects
= SOSRingGetRejections(ring
);
380 CFSetAddValue(rejects
, peerid
);
384 bool SOSRingRemoveRejection(SOSRingRef ring
, CFStringRef peerid
) {
385 CFMutableSetRef rejects
= SOSRingGetRejections(ring
);
386 CFSetRemoveValue(rejects
, peerid
);
390 // MARK: Ring Payload
392 CFDataRef
SOSRingGetPayload_Internal(SOSRingRef ring
) {
393 SOSRingAssertStable(ring
);
394 return (CFDataRef
) CFDictionaryGetValue(ring
->signedInformation
, sPayloadKey
);
397 bool SOSRingSetPayload_Internal(SOSRingRef ring
, CFDataRef payload
) {
398 SOSRingAssertStable(ring
);
399 return setValueInDict(ring
->signedInformation
, sPayloadKey
, payload
);
402 // MARK: Ring Backup Viewset
405 CFSetRef
SOSRingGetBackupViewset_Internal(SOSRingRef ring
) {
406 SOSRingAssertStable(ring
);
407 return (CFSetRef
) CFDictionaryGetValue(ring
->signedInformation
, sBackupViewSetKey
);
410 bool SOSRingSetBackupViewset_Internal(SOSRingRef ring
, CFSetRef viewSet
) {
411 SOSRingAssertStable(ring
);
412 return setValueInDict(ring
->signedInformation
, sBackupViewSetKey
, viewSet
);
417 // MARK: Ring PeerIDs
419 static inline CFMutableSetRef
SOSRingGetPeerIDs(SOSRingRef ring
) {
420 SOSRingAssertStable(ring
);
421 return (CFMutableSetRef
) CFDictionaryGetValue(ring
->signedInformation
, sPeerIDsKey
);
424 bool SOSRingSetPeerIDs(SOSRingRef ring
, CFMutableSetRef peers
) {
425 SOSRingAssertStable(ring
);
426 return setValueInDict(ring
->signedInformation
, sPeerIDsKey
, peers
);
429 int SOSRingCountPeerIDs(SOSRingRef ring
) {
430 CFSetRef peerIDs
= SOSRingGetPeerIDs(ring
);
431 return (int)CFSetGetCount(peerIDs
);
435 bool SOSRingHasPeerID(SOSRingRef ring
, CFStringRef peerID
) {
436 SOSRingAssertStable(ring
);
437 return CFSetContainsValue(SOSRingGetPeerIDs(ring
), peerID
);
440 CFMutableSetRef
SOSRingCopyPeerIDs(SOSRingRef ring
) {
441 CFSetRef peerIDs
= SOSRingGetPeerIDs(ring
);
442 return CFSetCreateMutableCopy(ALLOCATOR
, 0, peerIDs
);
445 void SOSRingAddAll(SOSRingRef ring
, CFSetRef peerInfosOrIDs
) {
446 CFSetForEach(peerInfosOrIDs
, ^(const void *value
) {
447 CFStringRef peerID
= value
;
449 if (isSOSPeerInfo(value
))
450 peerID
= SOSPeerInfoGetPeerID((SOSPeerInfoRef
)value
);
452 if (isString(peerID
))
453 SOSRingAddPeerID(ring
, peerID
);
457 bool SOSRingAddPeerID(SOSRingRef ring
, CFStringRef peerid
) {
458 CFMutableSetRef peerIDs
= SOSRingGetPeerIDs(ring
);
459 CFSetAddValue(peerIDs
, peerid
);
463 bool SOSRingRemovePeerID(SOSRingRef ring
, CFStringRef peerid
) {
464 CFMutableSetRef peerIDs
= SOSRingGetPeerIDs(ring
);
465 CFSetRemoveValue(peerIDs
, peerid
);
469 void SOSRingForEachPeerID(SOSRingRef ring
, void (^action
)(CFStringRef peerID
)) {
470 SOSRingAssertStable(ring
);
471 CFMutableSetRef peerIDs
= SOSRingGetPeerIDs(ring
);
473 CFSetForEach(peerIDs
, ^(const void*value
) {
474 CFStringRef peerID
= (CFStringRef
) value
;
481 SOSRingRef
SOSRingCreate_Internal(CFStringRef name
, SOSRingType type
, CFErrorRef
*error
) {
482 SOSRingRef r
= SOSRingAllocate();
483 SOSGenCountRef gen
= SOSGenerationCreate();
485 require_action_quiet(name
, errout0
,
486 SOSCreateError(kSOSErrorNoCircleName
, CFSTR("No ring name"), NULL
, error
));
487 require_action_quiet(SOSRingCheckType(type
, error
), errout0
,
488 SOSCreateError(kSOSErrorUnexpectedType
, CFSTR("Unknown ring type"), NULL
, error
));
489 require_action_quiet((r
->unSignedInformation
= CFDictionaryCreateMutableForCFTypes(ALLOCATOR
)), errout
,
490 SOSCreateError(kSOSErrorAllocationFailure
, CFSTR("Failed to allocate unsigned information area"), NULL
, error
));
491 require_action_quiet((r
->signedInformation
= CFDictionaryCreateMutableForCFTypes(ALLOCATOR
)), errout
,
492 SOSCreateError(kSOSErrorAllocationFailure
, CFSTR("Failed to allocate signed information area"), NULL
, error
));
493 require_action_quiet((r
->signatures
= CFDictionaryCreateMutableForCFTypes(ALLOCATOR
)), errout
,
494 SOSCreateError(kSOSErrorAllocationFailure
, CFSTR("Failed to allocate signature area"), NULL
, error
));
495 require_action_quiet((r
->data
= CFDictionaryCreateMutableForCFTypes(ALLOCATOR
)), errout
,
496 SOSCreateError(kSOSErrorAllocationFailure
, CFSTR("Failed to allocate data area"), NULL
, error
));
498 require_action_quiet(SOSRingSetName(r
, name
), errout
,
499 SOSCreateError(kSOSErrorAllocationFailure
, CFSTR("Failed to allocate ring name area"), NULL
, error
));
500 require_action_quiet(SOSRingSetType(r
, type
), errout
,
501 SOSCreateError(kSOSErrorAllocationFailure
, CFSTR("Failed to allocate ring type"), NULL
, error
));
502 require_action_quiet(SOSRingSetVersion(r
), errout
,
503 SOSCreateError(kSOSErrorAllocationFailure
, CFSTR("Failed to allocate ring version"), NULL
, error
));
504 require_action_quiet(SOSRingSetIdentifier(r
), errout
,
505 SOSCreateError(kSOSErrorAllocationFailure
, CFSTR("Failed to allocate ring identifier"), NULL
, error
));
507 CFMutableSetRef peerIDs
= CFSetCreateMutableForSOSPeerIDs();
508 require_action_quiet(SOSRingSetApplicants(r
, peerIDs
), errout
,
509 SOSCreateError(kSOSErrorAllocationFailure
, CFSTR("Failed to allocate applicant area"), NULL
, error
));
510 CFReleaseNull(peerIDs
);
512 CFMutableSetRef rejectedIDs
= CFSetCreateMutableForSOSPeerIDs();
513 require_action_quiet(SOSRingSetRejections(r
, rejectedIDs
), errout
,
514 SOSCreateError(kSOSErrorAllocationFailure
, CFSTR("Failed to allocate rejection area"), NULL
, error
));
515 CFReleaseNull(rejectedIDs
);
517 require_action_quiet(SOSRingSetGeneration(r
, gen
), errout
,
518 SOSCreateError(kSOSErrorAllocationFailure
, CFSTR("Failed to allocate generation count"), NULL
, error
));
520 peerIDs
= CFSetCreateMutableForSOSPeerIDs();
521 require_action_quiet(SOSRingSetPeerIDs(r
, peerIDs
), errout
,
522 SOSCreateError(kSOSErrorAllocationFailure
, CFSTR("Failed to allocate PeerID"), NULL
, error
));
524 CFReleaseNull(peerIDs
);
528 CFReleaseNull(r
->unSignedInformation
);
529 CFReleaseNull(r
->signedInformation
);
530 CFReleaseNull(r
->signatures
);
531 CFReleaseNull(r
->data
);
539 static void SOSRingDestroy(CFTypeRef aObj
) {
540 SOSRingRef c
= (SOSRingRef
) aObj
;
542 CFReleaseNull(c
->unSignedInformation
);
543 CFReleaseNull(c
->signedInformation
);
544 CFReleaseNull(c
->data
);
545 CFReleaseNull(c
->signatures
);
549 SOSRingRef
SOSRingCopyRing(SOSRingRef original
, CFErrorRef
*error
) {
550 SOSRingRef r
= CFTypeAllocate(SOSRing
, struct __OpaqueSOSRing
, ALLOCATOR
);
553 r
->unSignedInformation
= CFDictionaryCreateMutableCopy(ALLOCATOR
, 0, original
->unSignedInformation
);
554 r
->signedInformation
= CFDictionaryCreateMutableCopy(ALLOCATOR
, 0, original
->signedInformation
);
555 r
->signatures
= CFDictionaryCreateMutableCopy(ALLOCATOR
, 0, original
->signatures
);
556 r
->data
= CFDictionaryCreateMutableCopy(ALLOCATOR
, 0, original
->data
);
561 bool SOSRingIsEmpty_Internal(SOSRingRef ring
) {
562 return CFSetGetCount(SOSRingGetPeerIDs(ring
)) == 0;
565 bool SOSRingIsOffering_Internal(SOSRingRef ring
) {
566 return SOSRingCountPeers(ring
) == 1;
569 bool SOSRingResetToEmpty_Internal(SOSRingRef ring
, CFErrorRef
*error
) {
570 SOSGenCountRef gen
= NULL
;
571 CFSetRemoveAllValues(SOSRingGetApplicants(ring
));
572 CFSetRemoveAllValues(SOSRingGetRejections(ring
));
573 CFSetRemoveAllValues(SOSRingGetPeerIDs(ring
));
574 CFDictionaryRemoveAllValues(ring
->signatures
);
575 SOSRingSetGeneration(ring
, gen
= SOSGenerationCreate());
580 // MARK: PeerIDs in Ring
583 static inline bool isHiddenPeer(SOSPeerInfoRef peer
) {
584 return SOSPeerInfoIsRetirementTicket(peer
) || SOSPeerInfoIsCloudIdentity(peer
);
588 int SOSRingCountPeers(SOSRingRef ring
) {
589 SOSRingAssertStable(ring
);
590 return (int) CFSetGetCount(SOSRingGetPeerIDs(ring
));
594 bool SOSRingHasPeerWithID(SOSRingRef ring
, CFStringRef peerid
, CFErrorRef
*error
) {
595 SOSRingAssertStable(ring
);
596 return CFSetContainsValue(SOSRingGetPeerIDs(ring
), peerid
);
599 // MARK: Ring Signatures
602 static inline CFDictionaryRef
SOSRingGetSignatures(SOSRingRef ring
) {
603 return ring
->signatures
;
606 static inline CFDataRef
SOSRingGetSignatureForPeerID(SOSRingRef ring
, CFStringRef peerID
) {
607 if(!ring
|| !peerID
) return NULL
;
608 CFDataRef result
= NULL
;
609 CFTypeRef value
= (CFDataRef
)CFDictionaryGetValue(SOSRingGetSignatures(ring
), peerID
);
610 if (isData(value
)) result
= (CFDataRef
) value
;
614 static CFDataRef
SOSRingCreateHash(const struct ccdigest_info
*di
, SOSRingRef ring
, CFErrorRef
*error
) {
615 uint8_t hash_result
[di
->output_size
];
617 size_t dersize
= der_sizeof_plist(ring
->signedInformation
, error
);
621 uint8_t der
[dersize
];
622 der_encode_plist(ring
->signedInformation
, error
, der
, der
+dersize
);
624 ccdigest(di
, dersize
, der
, hash_result
);
625 return CFDataCreate(NULL
, hash_result
, di
->output_size
);
628 static bool SOSRingSetSignature(SOSRingRef ring
, SecKeyRef privKey
, CFDataRef signature
, CFErrorRef
*error
) {
630 SecKeyRef pubkey
= SecKeyCreatePublicFromPrivate(privKey
);
631 CFStringRef pubKeyID
= SOSCopyIDOfKey(pubkey
, error
);
632 require_quiet(pubKeyID
, fail
);
633 CFDictionarySetValue(ring
->signatures
, pubKeyID
, signature
);
636 CFReleaseSafe(pubkey
);
637 CFReleaseSafe(pubKeyID
);
641 static bool SOSRingRemoveSignatures(SOSRingRef ring
, CFErrorRef
*error
) {
642 CFDictionaryRemoveAllValues(ring
->signatures
);
646 static CFDataRef
SOSHashSign(SecKeyRef privKey
, CFDataRef hash
, CFErrorRef
*error
) {
647 size_t siglen
= SecKeyGetSize(privKey
, kSecKeySignatureSize
)+16;
649 OSStatus stat
= SecKeyRawSign(privKey
, kSecPaddingNone
, CFDataGetBytePtr(hash
), CFDataGetLength(hash
), sig
, &siglen
);
653 return CFDataCreate(NULL
, sig
, siglen
);
656 static bool SOSRingSign(SOSRingRef ring
, SecKeyRef privKey
, CFErrorRef
*error
) {
657 if (!ring
|| !privKey
) {
658 SOSCreateError(kSOSErrorBadSignature
, CFSTR("SOSRingSign Lacking ring or private key"),
659 (error
!= NULL
) ? *error
: NULL
, error
);
662 const struct ccdigest_info
*di
= ccsha256_di();
663 CFDataRef hash
= SOSRingCreateHash(di
, ring
, error
);
664 CFDataRef signature
= SOSHashSign(privKey
, hash
, error
);
665 SOSRingSetSignature(ring
, privKey
, signature
, error
);
666 CFRelease(signature
);
671 bool SOSRingVerifySignatureExists(SOSRingRef ring
, SecKeyRef pubKey
, CFErrorRef
*error
) {
672 CFStringRef pubKeyID
= SOSCopyIDOfKey(pubKey
, error
);
673 CFDataRef signature
= SOSRingGetSignatureForPeerID(ring
, pubKeyID
);
674 CFReleaseNull(pubKeyID
);
675 return NULL
!= signature
;
678 bool SOSRingVerify(SOSRingRef ring
, SecKeyRef pubKey
, CFErrorRef
*error
) {
679 CFStringRef pubKeyID
= SOSCopyIDOfKey(pubKey
, error
);
680 CFDataRef signature
= SOSRingGetSignatureForPeerID(ring
, pubKeyID
);
681 CFReleaseNull(pubKeyID
);
682 if(!signature
) return false;
683 CFDataRef hash
= SOSRingCreateHash(ccsha256_di(), ring
, error
);
684 bool success
= SecKeyRawVerify(pubKey
, kSecPaddingNone
, CFDataGetBytePtr(hash
), CFDataGetLength(hash
),
685 CFDataGetBytePtr(signature
), CFDataGetLength(signature
)) == errSecSuccess
;
690 bool SOSRingVerifyPeerSigned(SOSRingRef ring
, SOSPeerInfoRef peer
, CFErrorRef
*error
) {
691 SecKeyRef pubkey
= SOSPeerInfoCopyPubKey(peer
);
692 bool result
= SOSRingVerify(ring
, pubkey
, error
);
693 CFReleaseSafe(pubkey
);
697 static bool SOSRingEnsureRingConsistency(SOSRingRef ring
, CFErrorRef
*error
) {
698 secnotice("Development", "SOSRingEnsureRingConsistency requires ring membership and generation count consistency check", NULL
);
702 bool SOSRingGenerationSign_Internal(SOSRingRef ring
, SecKeyRef privKey
, CFErrorRef
*error
) {
703 if(!privKey
|| !ring
) return false;
705 SOSRingGenerationIncrement(ring
);
706 require_quiet(SOSRingEnsureRingConsistency(ring
, error
), fail
);
707 require_quiet(SOSRingRemoveSignatures(ring
, error
), fail
);
708 require_quiet(SOSRingSign(ring
, privKey
, error
), fail
);
716 bool SOSRingConcordanceSign_Internal(SOSRingRef ring
, SecKeyRef privKey
, CFErrorRef
*error
) {
717 if(!privKey
|| !ring
) return false;
719 require_quiet(SOSRingSign(ring
, privKey
, error
), fail
);
729 static inline void CFSetForEachPeerID(CFSetRef set
, void (^operation
)(CFStringRef peerID
)) {
730 CFSetForEach(set
, ^(const void *value
) {
731 CFStringRef peerID
= (CFStringRef
) value
;
736 static CFStringRef
CreateCommaSeparatedPeerIDs(CFSetRef peers
) {
737 CFMutableStringRef result
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
739 __block
bool addSeparator
= false;
741 CFSetForEachPeerID(peers
, ^(CFStringRef peerID
) {
743 CFStringAppendCString(result
, ", ", kCFStringEncodingUTF8
);
745 CFStringAppend(result
, peerID
);
753 CFDictionaryRef
SOSRingCopyPeerIDList(SOSRingRef ring
) {
754 CFStringRef peerIDS
= CreateCommaSeparatedPeerIDs(SOSRingGetPeerIDs(ring
));
755 CFStringRef applicantIDs
= CreateCommaSeparatedPeerIDs(SOSRingGetApplicants(ring
));
756 CFStringRef rejectIDs
= CreateCommaSeparatedPeerIDs(SOSRingGetRejections(ring
));
757 CFDictionaryRef list
= CFDictionaryCreateForCFTypes(ALLOCATOR
,
758 CFSTR("MEMBER"), peerIDS
,
759 CFSTR("APPLICANTS"), applicantIDs
,
760 CFSTR("REJECTS"), rejectIDs
,
763 CFReleaseNull(peerIDS
);
764 CFReleaseNull(applicantIDs
);
765 CFReleaseNull(rejectIDs
);
769 CFStringRef
SOSRingCopySignerList(SOSRingRef ring
) {
770 __block
bool addSeparator
= false;
771 CFMutableStringRef signers
= CFStringCreateMutable(ALLOCATOR
, 0);
772 CFDictionaryForEach(ring
->signatures
, ^(const void *key
, const void *value
) {
773 CFStringRef peerID
= (CFStringRef
) key
;
775 CFStringAppendCString(signers
, ", ", kCFStringEncodingUTF8
);
776 CFStringAppend(signers
, peerID
);
782 static CFStringRef
SOSRingCopyFormatDescription(CFTypeRef aObj
, CFDictionaryRef formatOpts
) {
783 SOSRingRef ring
= (SOSRingRef
) aObj
;
785 SOSRingAssertStable(ring
);
787 CFDictionaryRef peers
= SOSRingCopyPeerIDList(ring
);
788 CFStringRef signers
= SOSRingCopySignerList(ring
);
790 CFDataRef payload
= SOSRingGetPayload(ring
, NULL
);
792 CFStringRef gcString
= SOSGenerationCountCopyDescription(SOSRingGetGeneration(ring
));
794 CFMutableStringRef description
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
796 CFStringAppendFormat(description
, formatOpts
, CFSTR("<SOSRing@%p: '%@', Version %u, "), ring
, SOSRingGetName(ring
), SOSRingGetVersion(ring
));
797 CFStringAppendFormat(description
, formatOpts
, CFSTR("UUID: %@, "), SOSRingGetIdentifier(ring
));
798 SOSGenerationCountWithDescription(SOSRingGetGeneration(ring
), ^(CFStringRef gcString
) {
799 CFStringAppendFormat(description
, formatOpts
, CFSTR("Gen: %@, "), gcString
);
801 CFStringAppendFormat(description
, formatOpts
, CFSTR("Mod: %@, "), SOSRingGetLastModifier(ring
));
803 CFStringAppendFormat(description
, formatOpts
, CFSTR("D: %ld "), payload
? CFDataGetLength(payload
) : 0);
805 SOSBackupSliceKeyBagRef payloadAsBSKB
= SOSRingCopyBackupSliceKeyBag(ring
, NULL
);
808 CFStringAppendFormat(description
, formatOpts
, CFSTR("%@ "), payloadAsBSKB
);
811 CFReleaseSafe(payloadAsBSKB
);
813 CFStringAppendFormat(description
, formatOpts
, CFSTR("P: [%@], "), CFDictionaryGetValue(peers
, CFSTR("MEMBER")));
814 CFStringAppendFormat(description
, formatOpts
, CFSTR("A: [%@], "), CFDictionaryGetValue(peers
, CFSTR("APPLICANTS")));
815 CFStringAppendFormat(description
, formatOpts
, CFSTR("R: [%@], "), CFDictionaryGetValue(peers
, CFSTR("REJECTS")));
816 CFStringAppendFormat(description
, formatOpts
, CFSTR("S: [%@]>"), signers
);
818 CFReleaseNull(gcString
);
819 CFReleaseNull(peers
);
820 CFReleaseNull(signers
);
821 CFReleaseNull(peers
);
832 static CFDataRef
sosSignHash(SecKeyRef privkey
, const struct ccdigest_info
*di
, uint8_t *hbuf
) {
834 size_t siglen
= SIGLEN
;
836 if((stat
= SecKeyRawSign(privkey
, kSecPaddingNone
, hbuf
, di
->output_size
, sig
, &siglen
)) != 0) {
839 return CFDataCreate(NULL
, sig
, (CFIndex
)siglen
);
843 static void WithBufferSpace(size_t space
, void (^action
)(uint8_t *buffer
, size_t length
)) {
846 } else if (space
<= 2048) {
847 uint8_t buffer
[space
];
849 action(buffer
, space
);
851 uint8_t* buffer
= malloc(space
);
853 action(buffer
, space
);
859 static CFDataRef
CFDictionaryHashCreate(CFDictionaryRef dict
, CFErrorRef
*error
) {
861 __block CFDataRef result
= NULL
;
863 require_quiet(dict
, errOut
);
865 WithBufferSpace(der_sizeof_dictionary(dict
, error
), ^(uint8_t *der
, size_t len
) {
867 const struct ccdigest_info
*di
= ccsha256_di();
868 uint8_t hash_result
[di
->output_size
];
869 der_encode_dictionary(dict
, error
, der
, der
+len
);
871 ccdigest(di
, len
, der
, hash_result
);
872 result
= CFDataCreate(ALLOCATOR
, hash_result
, di
->output_size
);
882 signatures: CFDictionary of key = hash(pubkey), value = signature(privkey, (DER(payload))
883 payload: CFDictionary passed in
888 static CFStringRef sPayload
= CFSTR("payload");
889 static CFStringRef sSignature
= CFSTR("signature");
891 static bool SOSCFSignedDictionarySetSignature(SecKeyRef priv
, CFDictionaryRef sd
, CFErrorRef
*error
) {
892 CFDictionaryRef payload
= CFDictionaryGetValue(sd
, sPayload
);
893 CFMutableDictionaryRef signatures
= (CFMutableDictionaryRef
) CFDictionaryGetValue(sd
, sSignature
);
894 CFDataRef hash
= CFDictionaryHashCreate(payload
, error
);
895 CFDataRef signature
= SOSHashSign(priv
, hash
, error
);
897 CFStringRef pubhash
= SOSCopyIDOfKey(priv
, error
);
898 require_quiet(signature
&& pubhash
, errOut
);
899 CFDictionaryAddValue(signatures
, pubhash
, signature
);
906 static CFDictionaryRef
SOSCFSignedDictionaryCreate(SecKeyRef priv
, CFDictionaryRef payload
, CFErrorRef
*error
) {
907 CFMutableDictionaryRef signatures
= CFDictionaryCreateMutableForCFTypes(ALLOCATOR
);
908 CFMutableDictionaryRef retval
= CFDictionaryCreateMutableForCFTypes(ALLOCATOR
);
909 require_quiet(signatures
&& retval
, errOut
);
911 CFDictionaryAddValue(retval
, sSignature
, signatures
);
912 CFDictionaryAddValue(retval
, sPayload
, payload
);
913 SOSCFSignedDictionarySetSignature(priv
, retval
, error
);
916 CFReleaseNull(signatures
);
917 CFReleaseNull(retval
);
923 CFDictionaryRef
SOSRingCreateRetirementTicket(SOSFullPeerInfoRef fpi
, CFErrorRef
*error
) {
924 CFDictionaryRef retval
= NULL
;
925 CFStringRef myPeerID
= SOSPeerInfoGetPeerID(SOSFullPeerInfoGetPeerInfo(fpi
));
926 SecKeyRef priv
= SOSFullPeerInfoCopyDeviceKey(fpi
, error
);
927 CFDataRef resignationDate
= SOSDateCreate();
930 CFDataRef sig
= SOSDERAndSignStuff(priv
, keys
, values
, 2, error
);
931 retval
= CFDictionaryCreate(ALLOCATOR
, <#const void **keys#>, <#const void **values#>, <#CFIndex numValues#>, <#const CFDictionaryKeyCallBacks *keyCallBacks#>, <#const CFDictionaryValueCallBacks *valueCallBacks#>)
936 CFReleaseNull(resignationDate
);