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 asString(CFDictionaryGetValue(ring
->signedInformation
, sNameKey
), NULL
);
122 const char *SOSRingGetNameC(SOSRingRef ring
) {
123 CFStringRef name
= asString(SOSRingGetName(ring
), NULL
);
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;
222 uint32_t type1
= SOSRingGetType(ring1
);
223 uint32_t type2
= SOSRingGetVersion(ring2
);
224 require_action_quiet(type1
&& type2
, errOut
, secnotice("ring", "Cannot get both types to consider rings the same"));
225 if(type1
!= type2
) return false;
227 CFStringRef identifier1
= SOSRingGetIdentifier(ring1
);
228 CFStringRef identifier2
= SOSRingGetIdentifier(ring2
);
229 require_action_quiet(identifier1
&& identifier2
, errOut
, secnotice("ring", "Cannot get both identifiers to consider rings the same"));
230 if(CFEqualSafe(identifier1
, identifier2
) != true) return false;
238 static Boolean
SOSRingCompare(CFTypeRef lhs
, CFTypeRef rhs
) {
239 if (CFGetTypeID(lhs
) != SOSRingGetTypeID()
240 || CFGetTypeID(rhs
) != SOSRingGetTypeID())
243 SOSRingRef left
= SOSRingConvertAndAssertStable(lhs
);
244 SOSRingRef right
= SOSRingConvertAndAssertStable(rhs
);
246 return NULL
!= left
&& NULL
!= right
247 && CFEqualSafe(left
->unSignedInformation
, right
->unSignedInformation
)
248 && CFEqualSafe(left
->signedInformation
, right
->signedInformation
)
249 && CFEqualSafe(left
->data
, right
->data
)
250 && CFEqualSafe(left
->signatures
, right
->signatures
);
254 // MARK: Ring Generation Count
256 SOSGenCountRef
SOSRingGetGeneration(SOSRingRef ring
) {
258 assert(ring
->signedInformation
);
259 return CFDictionaryGetValue(ring
->signedInformation
, sGenerationKey
);
262 static inline bool SOSRingSetGeneration(SOSRingRef ring
, SOSGenCountRef gen
) {
264 assert(ring
->signedInformation
);
265 return setValueInDict(ring
->signedInformation
, sGenerationKey
, gen
);
268 void SOSRingGenerationIncrement(SOSRingRef ring
) {
269 SOSGenCountRef gen
= SOSRingGetGeneration(ring
);
270 SOSGenCountRef newgen
= SOSGenerationIncrementAndCreate(gen
);
271 SOSRingSetGeneration(ring
, newgen
);
272 CFReleaseNull(newgen
);
275 bool SOSRingIsOlderGeneration(SOSRingRef olderRing
, SOSRingRef newerRing
) {
276 SOSGenCountRef old
= SOSRingGetGeneration(olderRing
);
277 SOSGenCountRef
new = SOSRingGetGeneration(newerRing
);
278 return SOSGenerationIsOlder(old
, new);
281 void SOSRingGenerationCreateWithBaseline(SOSRingRef newring
, SOSRingRef baseline
) {
283 SOSGenCountRef gen
= SOSGenerationCreateWithBaseline(SOSRingGetGeneration(baseline
));
284 SOSRingSetGeneration(newring
, gen
);
288 // MARK: Last Modifier
289 CFStringRef
SOSRingGetLastModifier(SOSRingRef ring
) {
291 assert(ring
->unSignedInformation
);
292 return CFDictionaryGetValue(ring
->unSignedInformation
, sLastPeerToModifyKey
);
295 bool SOSRingSetLastModifier(SOSRingRef ring
, CFStringRef peerID
) {
297 assert(ring
->unSignedInformation
);
298 return setValueInDict(ring
->unSignedInformation
, sLastPeerToModifyKey
, peerID
);
302 // MARK: Ring Applicants
304 CFMutableSetRef
SOSRingGetApplicants(SOSRingRef ring
) {
305 SOSRingAssertStable(ring
);
306 return (CFMutableSetRef
) CFDictionaryGetValue(ring
->unSignedInformation
, sApplicantsKey
);
309 bool SOSRingSetApplicants(SOSRingRef ring
, CFMutableSetRef applicants
) {
310 SOSRingAssertStable(ring
);
311 return setValueInDict(ring
->unSignedInformation
, sApplicantsKey
, applicants
);
314 int SOSRingCountApplicants(SOSRingRef ring
) {
315 SOSRingAssertStable(ring
);
316 return (int)CFSetGetCount(SOSRingGetApplicants(ring
));
319 bool SOSRingHasApplicant(SOSRingRef ring
, CFStringRef peerID
) {
320 SOSRingAssertStable(ring
);
321 return CFSetContainsValue(SOSRingGetApplicants(ring
), peerID
);
324 CFMutableSetRef
SOSRingCopyApplicants(SOSRingRef ring
) {
325 SOSRingAssertStable(ring
);
326 CFSetRef applicants
= SOSRingGetApplicants(ring
);
327 return CFSetCreateMutableCopy(ALLOCATOR
, 0, applicants
);
330 bool SOSRingAddApplicant(SOSRingRef ring
, CFStringRef peerid
) {
331 CFMutableSetRef applicants
= SOSRingGetApplicants(ring
);
332 CFSetAddValue(applicants
, peerid
);
336 bool SOSRingRemoveApplicant(SOSRingRef ring
, CFStringRef peerid
) {
337 CFMutableSetRef applicants
= SOSRingGetApplicants(ring
);
338 CFSetRemoveValue(applicants
, peerid
);
342 // MARK: Ring Rejections
344 static inline CFMutableSetRef
SOSRingGetRejections(SOSRingRef ring
) {
345 SOSRingAssertStable(ring
);
346 return (CFMutableSetRef
) CFDictionaryGetValue(ring
->unSignedInformation
, sRejectionsKey
);
349 static inline bool SOSRingSetRejections(SOSRingRef ring
, CFMutableSetRef rejections
) {
350 SOSRingAssertStable(ring
);
351 return setValueInDict(ring
->unSignedInformation
, sRejectionsKey
, rejections
);
354 int SOSRingCountRejections(SOSRingRef ring
) {
355 CFSetRef rejects
= SOSRingGetRejections(ring
);
356 return (int)CFSetGetCount(rejects
);
359 bool SOSRingHasRejection(SOSRingRef ring
, CFStringRef peerID
) {
360 SOSRingAssertStable(ring
);
361 return CFSetContainsValue(SOSRingGetRejections(ring
), peerID
);
364 CFMutableSetRef
SOSRingCopyRejections(SOSRingRef ring
) {
365 CFSetRef rejects
= SOSRingGetRejections(ring
);
366 return CFSetCreateMutableCopy(ALLOCATOR
, 0, rejects
);
370 bool SOSRingAddRejection(SOSRingRef ring
, CFStringRef peerid
) {
371 CFMutableSetRef rejects
= SOSRingGetRejections(ring
);
372 CFSetAddValue(rejects
, peerid
);
376 bool SOSRingRemoveRejection(SOSRingRef ring
, CFStringRef peerid
) {
377 CFMutableSetRef rejects
= SOSRingGetRejections(ring
);
378 CFSetRemoveValue(rejects
, peerid
);
382 // MARK: Ring Payload
384 CFDataRef
SOSRingGetPayload_Internal(SOSRingRef ring
) {
385 SOSRingAssertStable(ring
);
386 return (CFDataRef
) CFDictionaryGetValue(ring
->signedInformation
, sPayloadKey
);
389 bool SOSRingSetPayload_Internal(SOSRingRef ring
, CFDataRef payload
) {
390 SOSRingAssertStable(ring
);
391 return setValueInDict(ring
->signedInformation
, sPayloadKey
, payload
);
394 // MARK: Ring Backup Viewset
397 CFSetRef
SOSRingGetBackupViewset_Internal(SOSRingRef ring
) {
398 SOSRingAssertStable(ring
);
399 return asSet(CFDictionaryGetValue(ring
->signedInformation
, sBackupViewSetKey
), NULL
);
402 bool SOSRingSetBackupViewset_Internal(SOSRingRef ring
, CFSetRef viewSet
) {
403 SOSRingAssertStable(ring
);
404 return setValueInDict(ring
->signedInformation
, sBackupViewSetKey
, viewSet
);
409 // MARK: Ring PeerIDs
411 static inline CFMutableSetRef
SOSRingGetPeerIDs(SOSRingRef ring
) {
412 SOSRingAssertStable(ring
);
413 return (CFMutableSetRef
) asSet(CFDictionaryGetValue(ring
->signedInformation
, sPeerIDsKey
), NULL
);
416 bool SOSRingSetPeerIDs(SOSRingRef ring
, CFMutableSetRef peers
) {
417 SOSRingAssertStable(ring
);
418 return setValueInDict(ring
->signedInformation
, sPeerIDsKey
, peers
);
421 int SOSRingCountPeerIDs(SOSRingRef ring
) {
422 CFSetRef peerIDs
= SOSRingGetPeerIDs(ring
);
423 return (int)CFSetGetCount(peerIDs
);
427 bool SOSRingHasPeerID(SOSRingRef ring
, CFStringRef peerID
) {
428 SOSRingAssertStable(ring
);
429 return CFSetContainsValue(SOSRingGetPeerIDs(ring
), peerID
);
432 CFMutableSetRef
SOSRingCopyPeerIDs(SOSRingRef ring
) {
433 CFSetRef peerIDs
= SOSRingGetPeerIDs(ring
);
434 return CFSetCreateMutableCopy(ALLOCATOR
, 0, peerIDs
);
437 void SOSRingAddAll(SOSRingRef ring
, CFSetRef peerInfosOrIDs
) {
438 CFSetForEach(peerInfosOrIDs
, ^(const void *value
) {
439 CFStringRef peerID
= value
;
441 if (isSOSPeerInfo(value
))
442 peerID
= SOSPeerInfoGetPeerID((SOSPeerInfoRef
)value
);
444 if (isString(peerID
))
445 SOSRingAddPeerID(ring
, peerID
);
449 bool SOSRingAddPeerID(SOSRingRef ring
, CFStringRef peerid
) {
450 CFMutableSetRef peerIDs
= SOSRingGetPeerIDs(ring
);
451 CFSetAddValue(peerIDs
, peerid
);
455 bool SOSRingRemovePeerID(SOSRingRef ring
, CFStringRef peerid
) {
456 CFMutableSetRef peerIDs
= SOSRingGetPeerIDs(ring
);
457 CFSetRemoveValue(peerIDs
, peerid
);
461 void SOSRingForEachPeerID(SOSRingRef ring
, void (^action
)(CFStringRef peerID
)) {
462 SOSRingAssertStable(ring
);
463 CFMutableSetRef peerIDs
= SOSRingGetPeerIDs(ring
);
465 CFSetForEach(peerIDs
, ^(const void*value
) {
466 CFStringRef peerID
= (CFStringRef
) value
;
473 SOSRingRef
SOSRingCreate_Internal(CFStringRef name
, SOSRingType type
, CFErrorRef
*error
) {
474 SOSRingRef r
= SOSRingAllocate();
475 SOSGenCountRef gen
= SOSGenerationCreate();
477 require_action_quiet(name
, errout0
,
478 SOSCreateError(kSOSErrorNoCircleName
, CFSTR("No ring name"), NULL
, error
));
479 require_action_quiet(SOSRingCheckType(type
, error
), errout0
,
480 SOSCreateError(kSOSErrorUnexpectedType
, CFSTR("Unknown ring type"), NULL
, error
));
481 require_action_quiet((r
->unSignedInformation
= CFDictionaryCreateMutableForCFTypes(ALLOCATOR
)), errout
,
482 SOSCreateError(kSOSErrorAllocationFailure
, CFSTR("Failed to allocate unsigned information area"), NULL
, error
));
483 require_action_quiet((r
->signedInformation
= CFDictionaryCreateMutableForCFTypes(ALLOCATOR
)), errout
,
484 SOSCreateError(kSOSErrorAllocationFailure
, CFSTR("Failed to allocate signed information area"), NULL
, error
));
485 require_action_quiet((r
->signatures
= CFDictionaryCreateMutableForCFTypes(ALLOCATOR
)), errout
,
486 SOSCreateError(kSOSErrorAllocationFailure
, CFSTR("Failed to allocate signature area"), NULL
, error
));
487 require_action_quiet((r
->data
= CFDictionaryCreateMutableForCFTypes(ALLOCATOR
)), errout
,
488 SOSCreateError(kSOSErrorAllocationFailure
, CFSTR("Failed to allocate data area"), NULL
, error
));
490 require_action_quiet(SOSRingSetName(r
, name
), errout
,
491 SOSCreateError(kSOSErrorAllocationFailure
, CFSTR("Failed to allocate ring name area"), NULL
, error
));
492 require_action_quiet(SOSRingSetType(r
, type
), errout
,
493 SOSCreateError(kSOSErrorAllocationFailure
, CFSTR("Failed to allocate ring type"), NULL
, error
));
494 require_action_quiet(SOSRingSetVersion(r
), errout
,
495 SOSCreateError(kSOSErrorAllocationFailure
, CFSTR("Failed to allocate ring version"), NULL
, error
));
496 require_action_quiet(SOSRingSetIdentifier(r
), errout
,
497 SOSCreateError(kSOSErrorAllocationFailure
, CFSTR("Failed to allocate ring identifier"), NULL
, error
));
499 CFMutableSetRef peerIDs
= CFSetCreateMutableForSOSPeerIDs();
500 require_action_quiet(SOSRingSetApplicants(r
, peerIDs
), errout
,
501 SOSCreateError(kSOSErrorAllocationFailure
, CFSTR("Failed to allocate applicant area"), NULL
, error
));
502 CFReleaseNull(peerIDs
);
504 CFMutableSetRef rejectedIDs
= CFSetCreateMutableForSOSPeerIDs();
505 require_action_quiet(SOSRingSetRejections(r
, rejectedIDs
), errout
,
506 SOSCreateError(kSOSErrorAllocationFailure
, CFSTR("Failed to allocate rejection area"), NULL
, error
));
507 CFReleaseNull(rejectedIDs
);
509 require_action_quiet(SOSRingSetGeneration(r
, gen
), errout
,
510 SOSCreateError(kSOSErrorAllocationFailure
, CFSTR("Failed to allocate generation count"), NULL
, error
));
512 peerIDs
= CFSetCreateMutableForSOSPeerIDs();
513 require_action_quiet(SOSRingSetPeerIDs(r
, peerIDs
), errout
,
514 SOSCreateError(kSOSErrorAllocationFailure
, CFSTR("Failed to allocate PeerID"), NULL
, error
));
516 CFReleaseNull(peerIDs
);
520 CFReleaseNull(r
->unSignedInformation
);
521 CFReleaseNull(r
->signedInformation
);
522 CFReleaseNull(r
->signatures
);
523 CFReleaseNull(r
->data
);
531 static void SOSRingDestroy(CFTypeRef aObj
) {
532 SOSRingRef c
= (SOSRingRef
) aObj
;
534 CFReleaseNull(c
->unSignedInformation
);
535 CFReleaseNull(c
->signedInformation
);
536 CFReleaseNull(c
->data
);
537 CFReleaseNull(c
->signatures
);
541 SOSRingRef
SOSRingCopyRing(SOSRingRef original
, CFErrorRef
*error
) {
542 SOSRingRef r
= CFTypeAllocate(SOSRing
, struct __OpaqueSOSRing
, ALLOCATOR
);
545 r
->unSignedInformation
= CFDictionaryCreateMutableCopy(ALLOCATOR
, 0, original
->unSignedInformation
);
546 r
->signedInformation
= CFDictionaryCreateMutableCopy(ALLOCATOR
, 0, original
->signedInformation
);
547 r
->signatures
= CFDictionaryCreateMutableCopy(ALLOCATOR
, 0, original
->signatures
);
548 r
->data
= CFDictionaryCreateMutableCopy(ALLOCATOR
, 0, original
->data
);
553 bool SOSRingIsEmpty_Internal(SOSRingRef ring
) {
554 return CFSetGetCount(SOSRingGetPeerIDs(ring
)) == 0;
557 bool SOSRingIsOffering_Internal(SOSRingRef ring
) {
558 return SOSRingCountPeers(ring
) == 1;
561 bool SOSRingResetToEmpty_Internal(SOSRingRef ring
, CFErrorRef
*error
) {
562 SOSGenCountRef gen
= NULL
;
563 CFSetRemoveAllValues(SOSRingGetApplicants(ring
));
564 CFSetRemoveAllValues(SOSRingGetRejections(ring
));
565 CFSetRemoveAllValues(SOSRingGetPeerIDs(ring
));
566 CFDictionaryRemoveAllValues(ring
->signatures
);
567 SOSRingSetGeneration(ring
, gen
= SOSGenerationCreate());
572 // MARK: PeerIDs in Ring
574 int SOSRingCountPeers(SOSRingRef ring
) {
575 SOSRingAssertStable(ring
);
576 return (int) CFSetGetCount(SOSRingGetPeerIDs(ring
));
580 bool SOSRingHasPeerWithID(SOSRingRef ring
, CFStringRef peerid
, CFErrorRef
*error
) {
581 SOSRingAssertStable(ring
);
582 return CFSetContainsValue(SOSRingGetPeerIDs(ring
), peerid
);
585 // MARK: Ring Signatures
588 static inline CFDictionaryRef
SOSRingGetSignatures(SOSRingRef ring
) {
589 return ring
->signatures
;
592 static inline CFDataRef
SOSRingGetSignatureForPeerID(SOSRingRef ring
, CFStringRef peerID
) {
593 if(!ring
|| !peerID
) return NULL
;
594 CFDataRef result
= NULL
;
595 CFTypeRef value
= (CFDataRef
)CFDictionaryGetValue(SOSRingGetSignatures(ring
), peerID
);
596 if (isData(value
)) result
= (CFDataRef
) value
;
600 static CFDataRef
SOSRingCreateHash(const struct ccdigest_info
*di
, SOSRingRef ring
, CFErrorRef
*error
) {
601 uint8_t hash_result
[di
->output_size
];
603 size_t dersize
= der_sizeof_plist(ring
->signedInformation
, error
);
607 uint8_t *der
= malloc(dersize
);
611 if (der_encode_plist(ring
->signedInformation
, error
, der
, der
+dersize
) == NULL
) {
616 ccdigest(di
, dersize
, der
, hash_result
);
618 return CFDataCreate(NULL
, hash_result
, di
->output_size
);
621 static bool SOSRingSetSignature(SOSRingRef ring
, SecKeyRef privKey
, CFDataRef signature
, CFErrorRef
*error
) {
623 SecKeyRef pubkey
= SecKeyCreatePublicFromPrivate(privKey
);
624 CFStringRef pubKeyID
= SOSCopyIDOfKey(pubkey
, error
);
625 require_quiet(pubKeyID
, fail
);
626 CFDictionarySetValue(ring
->signatures
, pubKeyID
, signature
);
629 CFReleaseSafe(pubkey
);
630 CFReleaseSafe(pubKeyID
);
634 static bool SOSRingRemoveSignatures(SOSRingRef ring
, CFErrorRef
*error
) {
635 CFDictionaryRemoveAllValues(ring
->signatures
);
639 static CFDataRef
SOSCopySignedHash(SecKeyRef privKey
, CFDataRef hash
, CFErrorRef
*error
) {
640 size_t siglen
= SecKeyGetSize(privKey
, kSecKeySignatureSize
)+16;
642 OSStatus stat
= SecKeyRawSign(privKey
, kSecPaddingNone
, CFDataGetBytePtr(hash
), CFDataGetLength(hash
), sig
, &siglen
);
646 return CFDataCreate(NULL
, sig
, siglen
);
649 static bool SOSRingSign(SOSRingRef ring
, SecKeyRef privKey
, CFErrorRef
*error
) {
650 if (!ring
|| !privKey
) {
651 SOSCreateError(kSOSErrorBadSignature
, CFSTR("SOSRingSign Lacking ring or private key"),
652 (error
!= NULL
) ? *error
: NULL
, error
);
655 const struct ccdigest_info
*di
= ccsha256_di();
656 CFDataRef hash
= SOSRingCreateHash(di
, ring
, error
);
657 CFDataRef signature
= SOSCopySignedHash(privKey
, hash
, error
);
658 SOSRingSetSignature(ring
, privKey
, signature
, error
);
659 CFRelease(signature
);
664 bool SOSRingVerifySignatureExists(SOSRingRef ring
, SecKeyRef pubKey
, CFErrorRef
*error
) {
665 CFStringRef pubKeyID
= SOSCopyIDOfKey(pubKey
, error
);
666 CFDataRef signature
= SOSRingGetSignatureForPeerID(ring
, pubKeyID
);
667 CFReleaseNull(pubKeyID
);
668 return NULL
!= signature
;
671 bool SOSRingVerify(SOSRingRef ring
, SecKeyRef pubKey
, CFErrorRef
*error
) {
672 CFStringRef pubKeyID
= SOSCopyIDOfKey(pubKey
, error
);
673 CFDataRef signature
= SOSRingGetSignatureForPeerID(ring
, pubKeyID
);
674 CFReleaseNull(pubKeyID
);
675 if(!signature
) return false;
676 CFDataRef hash
= SOSRingCreateHash(ccsha256_di(), ring
, error
);
677 bool success
= SecKeyRawVerify(pubKey
, kSecPaddingNone
, CFDataGetBytePtr(hash
), CFDataGetLength(hash
),
678 CFDataGetBytePtr(signature
), CFDataGetLength(signature
)) == errSecSuccess
;
683 bool SOSRingVerifyPeerSigned(SOSRingRef ring
, SOSPeerInfoRef peer
, CFErrorRef
*error
) {
685 SecKeyRef pubkey
= SOSPeerInfoCopyPubKey(peer
, error
);
686 require_quiet(pubkey
, fail
);
688 result
= SOSRingVerify(ring
, pubkey
, error
);
691 CFReleaseSafe(pubkey
);
695 static bool SOSRingEnsureRingConsistency(SOSRingRef ring
, CFErrorRef
*error
) {
696 secnotice("Development", "SOSRingEnsureRingConsistency requires ring membership and generation count consistency check", NULL
);
700 bool SOSRingGenerationSign_Internal(SOSRingRef ring
, SecKeyRef privKey
, CFErrorRef
*error
) {
701 if(!privKey
|| !ring
) return false;
703 SOSRingGenerationIncrement(ring
);
704 require_quiet(SOSRingEnsureRingConsistency(ring
, error
), fail
);
705 require_quiet(SOSRingRemoveSignatures(ring
, error
), fail
);
706 require_quiet(SOSRingSign(ring
, privKey
, error
), fail
);
714 bool SOSRingConcordanceSign_Internal(SOSRingRef ring
, SecKeyRef privKey
, CFErrorRef
*error
) {
715 if(!privKey
|| !ring
) return false;
717 require_quiet(SOSRingSign(ring
, privKey
, error
), fail
);
727 static inline void CFSetForEachPeerID(CFSetRef set
, void (^operation
)(CFStringRef peerID
)) {
728 CFSetForEach(set
, ^(const void *value
) {
729 CFStringRef peerID
= (CFStringRef
) value
;
734 static CFStringRef
CreateCommaSeparatedPeerIDs(CFSetRef peers
) {
735 CFMutableStringRef result
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
737 __block
bool addSeparator
= false;
739 CFSetForEachPeerID(peers
, ^(CFStringRef peerID
) {
741 CFStringAppendCString(result
, ", ", kCFStringEncodingUTF8
);
743 CFStringAppend(result
, peerID
);
751 CFDictionaryRef
SOSRingCopyPeerIDList(SOSRingRef ring
) {
752 CFStringRef peerIDS
= CreateCommaSeparatedPeerIDs(SOSRingGetPeerIDs(ring
));
753 CFStringRef applicantIDs
= CreateCommaSeparatedPeerIDs(SOSRingGetApplicants(ring
));
754 CFStringRef rejectIDs
= CreateCommaSeparatedPeerIDs(SOSRingGetRejections(ring
));
755 CFDictionaryRef list
= CFDictionaryCreateForCFTypes(ALLOCATOR
,
756 CFSTR("MEMBER"), peerIDS
,
757 CFSTR("APPLICANTS"), applicantIDs
,
758 CFSTR("REJECTS"), rejectIDs
,
761 CFReleaseNull(peerIDS
);
762 CFReleaseNull(applicantIDs
);
763 CFReleaseNull(rejectIDs
);
767 CFStringRef
SOSRingCopySignerList(SOSRingRef ring
) {
768 __block
bool addSeparator
= false;
769 CFMutableStringRef signers
= CFStringCreateMutable(ALLOCATOR
, 0);
770 CFDictionaryForEach(ring
->signatures
, ^(const void *key
, const void *value
) {
771 CFStringRef peerID
= (CFStringRef
) key
;
773 CFStringAppendCString(signers
, ", ", kCFStringEncodingUTF8
);
774 CFStringAppend(signers
, peerID
);
780 static CFStringRef
SOSRingCopyFormatDescription(CFTypeRef aObj
, CFDictionaryRef formatOpts
) {
781 SOSRingRef ring
= (SOSRingRef
) aObj
;
783 SOSRingAssertStable(ring
);
785 CFDictionaryRef peers
= SOSRingCopyPeerIDList(ring
);
786 CFStringRef signers
= SOSRingCopySignerList(ring
);
788 CFDataRef payload
= SOSRingGetPayload(ring
, NULL
);
790 CFStringRef gcString
= SOSGenerationCountCopyDescription(SOSRingGetGeneration(ring
));
792 CFMutableStringRef description
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
794 CFStringAppendFormat(description
, formatOpts
, CFSTR("<SOSRing@%p: '%@', Version %u, "), ring
, SOSRingGetName(ring
), SOSRingGetVersion(ring
));
795 CFStringAppendFormat(description
, formatOpts
, CFSTR("UUID: %@, "), SOSRingGetIdentifier(ring
));
796 SOSGenerationCountWithDescription(SOSRingGetGeneration(ring
), ^(CFStringRef gcString
) {
797 CFStringAppendFormat(description
, formatOpts
, CFSTR("Gen: %@, "), gcString
);
799 CFStringAppendFormat(description
, formatOpts
, CFSTR("Mod: %@, "), SOSRingGetLastModifier(ring
));
801 CFStringAppendFormat(description
, formatOpts
, CFSTR("D: %ld "), payload
? CFDataGetLength(payload
) : 0);
803 SOSBackupSliceKeyBagRef payloadAsBSKB
= SOSRingCopyBackupSliceKeyBag(ring
, NULL
);
806 CFStringAppendFormat(description
, formatOpts
, CFSTR("%@ "), payloadAsBSKB
);
809 CFReleaseSafe(payloadAsBSKB
);
811 CFStringAppendFormat(description
, formatOpts
, CFSTR("P: [%@], "), CFDictionaryGetValue(peers
, CFSTR("MEMBER")));
812 CFStringAppendFormat(description
, formatOpts
, CFSTR("A: [%@], "), CFDictionaryGetValue(peers
, CFSTR("APPLICANTS")));
813 CFStringAppendFormat(description
, formatOpts
, CFSTR("R: [%@], "), CFDictionaryGetValue(peers
, CFSTR("REJECTS")));
814 CFStringAppendFormat(description
, formatOpts
, CFSTR("S: [%@]>"), signers
);
816 CFReleaseNull(gcString
);
817 CFReleaseNull(peers
);
818 CFReleaseNull(signers
);
819 CFReleaseNull(peers
);