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 "keychain/SecureObjectSync/SOSInternal.h"
32 #include "keychain/SecureObjectSync/SOSPeer.h"
33 #include "keychain/SecureObjectSync/SOSPeerInfoInternal.h"
34 #include "keychain/SecureObjectSync/SOSPeerInfoCollections.h"
35 #include "keychain/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 static bool setValueInDict(CFMutableDictionaryRef thedict
, CFStringRef key
, CFTypeRef value
) {
86 if(!value
) return false;
87 CFDictionarySetValue(thedict
, key
, value
);
91 static CFMutableSetRef
CFSetCreateMutableForSOSPeerIDs(void) {
92 return CFSetCreateMutable(ALLOCATOR
, 0, &kCFTypeSetCallBacks
);
97 SOSRingRef
SOSRingConvertAndAssertStable(CFTypeRef ringAsType
) {
98 if (CFGetTypeID(ringAsType
) != SOSRingGetTypeID())
101 SOSRingRef ring
= (SOSRingRef
) ringAsType
;
103 SOSRingAssertStable(ring
);
110 CFStringRef
SOSRingGetName(SOSRingRef ring
) {
112 assert(ring
->signedInformation
);
113 return asString(CFDictionaryGetValue(ring
->signedInformation
, sNameKey
), NULL
);
116 const char *SOSRingGetNameC(SOSRingRef ring
) {
117 CFStringRef name
= asString(SOSRingGetName(ring
), NULL
);
120 return CFStringToCString(name
);
123 static inline bool SOSRingSetName(SOSRingRef ring
, CFStringRef name
) {
125 assert(ring
->signedInformation
);
126 return setValueInDict(ring
->signedInformation
, sNameKey
, name
);
131 static bool SOSRingCheckType(SOSRingType type
, CFErrorRef
*error
) {
132 if(type
< kSOSRingTypeCount
) return true;
133 SOSCreateError(kSOSErrorUnexpectedType
, CFSTR("Bad Ring Type Specification"), (error
!= NULL
) ? *error
: NULL
, error
);
137 uint32_t SOSRingGetType(SOSRingRef ring
) {
138 uint32_t retval
= kSOSRingTypeError
; // Error return
139 SOSRingAssertStable(ring
);
140 if(!ring
->signedInformation
) return retval
;
141 CFNumberRef ringtype
= (CFNumberRef
) CFDictionaryGetValue(ring
->signedInformation
, sTypeKey
);
142 CFNumberGetValue(ringtype
, kCFNumberSInt32Type
, &retval
);
146 static inline bool SOSRingSetType(SOSRingRef ring
, uint32_t ringtype
) {
148 CFNumberRef cfrtype
= NULL
;
149 SOSRingAssertStable(ring
);
150 require_action_quiet(SOSRingCheckType(ringtype
, NULL
), errOut
, secnotice("ring", "Bad ring type specification"));
151 cfrtype
= CFNumberCreate(ALLOCATOR
, kCFNumberSInt32Type
, &ringtype
);
152 retval
= setValueInDict(ring
->signedInformation
, sTypeKey
, cfrtype
);
154 CFReleaseNull(cfrtype
);
160 uint32_t SOSRingGetVersion(SOSRingRef ring
) {
161 uint32_t version
= 0;
163 assert(ring
->signedInformation
);
164 CFNumberRef cfversion
= CFDictionaryGetValue(ring
->signedInformation
, sRingVersionKey
);
165 require_action_quiet(cfversion
, errOut
, secnotice("ring", "Could not create version number"));
166 CFNumberGetValue(cfversion
, kCFNumberSInt32Type
, &version
);
171 static inline bool SOSRingSetVersion(SOSRingRef ring
) {
173 assert(ring
->signedInformation
);
174 int32_t thisversion
= RINGVERSION
;
175 CFNumberRef version
= CFNumberCreate(ALLOCATOR
, kCFNumberSInt32Type
, &thisversion
);
176 require_action_quiet(version
, errOut
, secnotice("ring", "Could not create version number"));
177 CFDictionarySetValue(ring
->signedInformation
, sRingVersionKey
, version
);
178 CFReleaseNull(version
);
186 CFStringRef
SOSRingGetIdentifier(SOSRingRef ring
) {
188 assert(ring
->signedInformation
);
189 return CFDictionaryGetValue(ring
->signedInformation
, sIdentifierKey
);
192 static inline bool SOSRingSetIdentifier(SOSRingRef ring
) {
194 assert(ring
->signedInformation
);
196 CFStringRef identifier
= NULL
;
197 CFUUIDRef uuid
= CFUUIDCreate(ALLOCATOR
);
198 require_action_quiet(uuid
, errOut
, secnotice("ring", "Could not create ring identifier"));
199 identifier
= CFUUIDCreateString(ALLOCATOR
, uuid
);
200 CFDictionarySetValue(ring
->signedInformation
, sIdentifierKey
, identifier
);
204 CFReleaseNull(identifier
);
208 // MARK: Ring Identity
210 bool SOSRingIsSame(SOSRingRef ring1
, SOSRingRef ring2
) {
211 CFStringRef name1
= SOSRingGetName(ring1
);
212 CFStringRef name2
= SOSRingGetName(ring2
);
213 require_action_quiet(name1
&& name2
, errOut
, secnotice("ring", "Cannot get both names to consider rings the same"));
214 if(CFEqualSafe(name1
, name2
) != true) return false;
216 uint32_t type1
= SOSRingGetType(ring1
);
217 uint32_t type2
= SOSRingGetVersion(ring2
);
218 require_action_quiet(type1
&& type2
, errOut
, secnotice("ring", "Cannot get both types to consider rings the same"));
219 if(type1
!= type2
) return false;
221 CFStringRef identifier1
= SOSRingGetIdentifier(ring1
);
222 CFStringRef identifier2
= SOSRingGetIdentifier(ring2
);
223 require_action_quiet(identifier1
&& identifier2
, errOut
, secnotice("ring", "Cannot get both identifiers to consider rings the same"));
224 if(CFEqualSafe(identifier1
, identifier2
) != true) return false;
232 static Boolean
SOSRingCompare(CFTypeRef lhs
, CFTypeRef rhs
) {
233 if (CFGetTypeID(lhs
) != SOSRingGetTypeID()
234 || CFGetTypeID(rhs
) != SOSRingGetTypeID())
237 SOSRingRef left
= SOSRingConvertAndAssertStable(lhs
);
238 SOSRingRef right
= SOSRingConvertAndAssertStable(rhs
);
240 return NULL
!= left
&& NULL
!= right
241 && CFEqualSafe(left
->unSignedInformation
, right
->unSignedInformation
)
242 && CFEqualSafe(left
->signedInformation
, right
->signedInformation
)
243 && CFEqualSafe(left
->data
, right
->data
)
244 && CFEqualSafe(left
->signatures
, right
->signatures
);
248 // MARK: Ring Generation Count
250 SOSGenCountRef
SOSRingGetGeneration(SOSRingRef ring
) {
252 assert(ring
->signedInformation
);
253 return CFDictionaryGetValue(ring
->signedInformation
, sGenerationKey
);
256 static inline bool SOSRingSetGeneration(SOSRingRef ring
, SOSGenCountRef gen
) {
258 assert(ring
->signedInformation
);
259 return setValueInDict(ring
->signedInformation
, sGenerationKey
, gen
);
262 void SOSRingGenerationIncrement(SOSRingRef ring
) {
263 SOSGenCountRef gen
= SOSRingGetGeneration(ring
);
264 SOSGenCountRef newgen
= SOSGenerationIncrementAndCreate(gen
);
265 SOSRingSetGeneration(ring
, newgen
);
266 CFReleaseNull(newgen
);
269 bool SOSRingIsOlderGeneration(SOSRingRef olderRing
, SOSRingRef newerRing
) {
270 SOSGenCountRef old
= SOSRingGetGeneration(olderRing
);
271 SOSGenCountRef
new = SOSRingGetGeneration(newerRing
);
272 return SOSGenerationIsOlder(old
, new);
275 void SOSRingGenerationCreateWithBaseline(SOSRingRef newring
, SOSRingRef baseline
) {
277 SOSGenCountRef gen
= SOSGenerationCreateWithBaseline(SOSRingGetGeneration(baseline
));
278 SOSRingSetGeneration(newring
, gen
);
282 // MARK: Last Modifier
283 CFStringRef
SOSRingGetLastModifier(SOSRingRef ring
) {
285 assert(ring
->unSignedInformation
);
286 return CFDictionaryGetValue(ring
->unSignedInformation
, sLastPeerToModifyKey
);
289 bool SOSRingSetLastModifier(SOSRingRef ring
, CFStringRef peerID
) {
291 assert(ring
->unSignedInformation
);
292 return setValueInDict(ring
->unSignedInformation
, sLastPeerToModifyKey
, peerID
);
296 // MARK: Ring Applicants
298 CFMutableSetRef
SOSRingGetApplicants(SOSRingRef ring
) {
299 SOSRingAssertStable(ring
);
300 return (CFMutableSetRef
) CFDictionaryGetValue(ring
->unSignedInformation
, sApplicantsKey
);
303 bool SOSRingSetApplicants(SOSRingRef ring
, CFMutableSetRef applicants
) {
304 SOSRingAssertStable(ring
);
305 return setValueInDict(ring
->unSignedInformation
, sApplicantsKey
, applicants
);
308 int SOSRingCountApplicants(SOSRingRef ring
) {
309 SOSRingAssertStable(ring
);
310 return (int)CFSetGetCount(SOSRingGetApplicants(ring
));
313 bool SOSRingHasApplicant(SOSRingRef ring
, CFStringRef peerID
) {
314 SOSRingAssertStable(ring
);
315 return CFSetContainsValue(SOSRingGetApplicants(ring
), peerID
);
318 CFMutableSetRef
SOSRingCopyApplicants(SOSRingRef ring
) {
319 SOSRingAssertStable(ring
);
320 CFSetRef applicants
= SOSRingGetApplicants(ring
);
321 return CFSetCreateMutableCopy(ALLOCATOR
, 0, applicants
);
324 bool SOSRingAddApplicant(SOSRingRef ring
, CFStringRef peerid
) {
325 CFMutableSetRef applicants
= SOSRingGetApplicants(ring
);
326 CFSetAddValue(applicants
, peerid
);
330 bool SOSRingRemoveApplicant(SOSRingRef ring
, CFStringRef peerid
) {
331 CFMutableSetRef applicants
= SOSRingGetApplicants(ring
);
332 CFSetRemoveValue(applicants
, peerid
);
336 // MARK: Ring Rejections
338 static inline CFMutableSetRef
SOSRingGetRejections(SOSRingRef ring
) {
339 SOSRingAssertStable(ring
);
340 return (CFMutableSetRef
) CFDictionaryGetValue(ring
->unSignedInformation
, sRejectionsKey
);
343 static inline bool SOSRingSetRejections(SOSRingRef ring
, CFMutableSetRef rejections
) {
344 SOSRingAssertStable(ring
);
345 return setValueInDict(ring
->unSignedInformation
, sRejectionsKey
, rejections
);
348 int SOSRingCountRejections(SOSRingRef ring
) {
349 CFSetRef rejects
= SOSRingGetRejections(ring
);
350 return (int)CFSetGetCount(rejects
);
353 bool SOSRingHasRejection(SOSRingRef ring
, CFStringRef peerID
) {
354 SOSRingAssertStable(ring
);
355 return CFSetContainsValue(SOSRingGetRejections(ring
), peerID
);
358 CFMutableSetRef
SOSRingCopyRejections(SOSRingRef ring
) {
359 CFSetRef rejects
= SOSRingGetRejections(ring
);
360 return CFSetCreateMutableCopy(ALLOCATOR
, 0, rejects
);
364 bool SOSRingAddRejection(SOSRingRef ring
, CFStringRef peerid
) {
365 CFMutableSetRef rejects
= SOSRingGetRejections(ring
);
366 CFSetAddValue(rejects
, peerid
);
370 bool SOSRingRemoveRejection(SOSRingRef ring
, CFStringRef peerid
) {
371 CFMutableSetRef rejects
= SOSRingGetRejections(ring
);
372 CFSetRemoveValue(rejects
, peerid
);
376 // MARK: Ring Payload
378 CFDataRef
SOSRingGetPayload_Internal(SOSRingRef ring
) {
379 SOSRingAssertStable(ring
);
380 return (CFDataRef
) CFDictionaryGetValue(ring
->signedInformation
, sPayloadKey
);
383 bool SOSRingSetPayload_Internal(SOSRingRef ring
, CFDataRef payload
) {
384 SOSRingAssertStable(ring
);
385 return setValueInDict(ring
->signedInformation
, sPayloadKey
, payload
);
388 // MARK: Ring Backup Viewset
391 CFSetRef
SOSRingGetBackupViewset_Internal(SOSRingRef ring
) {
392 SOSRingAssertStable(ring
);
393 return asSet(CFDictionaryGetValue(ring
->signedInformation
, sBackupViewSetKey
), NULL
);
396 bool SOSRingSetBackupViewset_Internal(SOSRingRef ring
, CFSetRef viewSet
) {
397 SOSRingAssertStable(ring
);
398 return setValueInDict(ring
->signedInformation
, sBackupViewSetKey
, viewSet
);
403 // MARK: Ring PeerIDs
405 static inline CFMutableSetRef
SOSRingGetPeerIDs(SOSRingRef ring
) {
406 SOSRingAssertStable(ring
);
407 return (CFMutableSetRef
) asSet(CFDictionaryGetValue(ring
->signedInformation
, sPeerIDsKey
), NULL
);
410 bool SOSRingSetPeerIDs(SOSRingRef ring
, CFMutableSetRef peers
) {
411 SOSRingAssertStable(ring
);
412 return setValueInDict(ring
->signedInformation
, sPeerIDsKey
, peers
);
415 int SOSRingCountPeerIDs(SOSRingRef ring
) {
416 CFSetRef peerIDs
= SOSRingGetPeerIDs(ring
);
417 return (int)CFSetGetCount(peerIDs
);
421 bool SOSRingHasPeerID(SOSRingRef ring
, CFStringRef peerID
) {
422 SOSRingAssertStable(ring
);
423 return CFSetContainsValue(SOSRingGetPeerIDs(ring
), peerID
);
426 CFMutableSetRef
SOSRingCopyPeerIDs(SOSRingRef ring
) {
427 CFSetRef peerIDs
= SOSRingGetPeerIDs(ring
);
428 return CFSetCreateMutableCopy(ALLOCATOR
, 0, peerIDs
);
431 void SOSRingAddAll(SOSRingRef ring
, CFSetRef peerInfosOrIDs
) {
432 CFSetForEach(peerInfosOrIDs
, ^(const void *value
) {
433 CFStringRef peerID
= value
;
435 if (isSOSPeerInfo(value
))
436 peerID
= SOSPeerInfoGetPeerID((SOSPeerInfoRef
)value
);
438 if (isString(peerID
))
439 SOSRingAddPeerID(ring
, peerID
);
443 bool SOSRingAddPeerID(SOSRingRef ring
, CFStringRef peerid
) {
444 CFMutableSetRef peerIDs
= SOSRingGetPeerIDs(ring
);
445 CFSetAddValue(peerIDs
, peerid
);
449 bool SOSRingRemovePeerID(SOSRingRef ring
, CFStringRef peerid
) {
450 CFMutableSetRef peerIDs
= SOSRingGetPeerIDs(ring
);
451 CFSetRemoveValue(peerIDs
, peerid
);
455 void SOSRingForEachPeerID(SOSRingRef ring
, void (^action
)(CFStringRef peerID
)) {
456 SOSRingAssertStable(ring
);
457 CFMutableSetRef peerIDs
= SOSRingGetPeerIDs(ring
);
459 CFSetForEach(peerIDs
, ^(const void*value
) {
460 CFStringRef peerID
= (CFStringRef
) value
;
467 SOSRingRef
SOSRingCreate_Internal(CFStringRef name
, SOSRingType type
, CFErrorRef
*error
) {
468 SOSRingRef r
= SOSRingAllocate();
469 SOSGenCountRef gen
= SOSGenerationCreate();
471 require_action_quiet(name
, errout0
,
472 SOSCreateError(kSOSErrorNoCircleName
, CFSTR("No ring name"), NULL
, error
));
473 require_action_quiet(SOSRingCheckType(type
, error
), errout0
,
474 SOSCreateError(kSOSErrorUnexpectedType
, CFSTR("Unknown ring type"), NULL
, error
));
475 require_action_quiet((r
->unSignedInformation
= CFDictionaryCreateMutableForCFTypes(ALLOCATOR
)), errout
,
476 SOSCreateError(kSOSErrorAllocationFailure
, CFSTR("Failed to allocate unsigned information area"), NULL
, error
));
477 require_action_quiet((r
->signedInformation
= CFDictionaryCreateMutableForCFTypes(ALLOCATOR
)), errout
,
478 SOSCreateError(kSOSErrorAllocationFailure
, CFSTR("Failed to allocate signed information area"), NULL
, error
));
479 require_action_quiet((r
->signatures
= CFDictionaryCreateMutableForCFTypes(ALLOCATOR
)), errout
,
480 SOSCreateError(kSOSErrorAllocationFailure
, CFSTR("Failed to allocate signature area"), NULL
, error
));
481 require_action_quiet((r
->data
= CFDictionaryCreateMutableForCFTypes(ALLOCATOR
)), errout
,
482 SOSCreateError(kSOSErrorAllocationFailure
, CFSTR("Failed to allocate data area"), NULL
, error
));
484 require_action_quiet(SOSRingSetName(r
, name
), errout
,
485 SOSCreateError(kSOSErrorAllocationFailure
, CFSTR("Failed to allocate ring name area"), NULL
, error
));
486 require_action_quiet(SOSRingSetType(r
, type
), errout
,
487 SOSCreateError(kSOSErrorAllocationFailure
, CFSTR("Failed to allocate ring type"), NULL
, error
));
488 require_action_quiet(SOSRingSetVersion(r
), errout
,
489 SOSCreateError(kSOSErrorAllocationFailure
, CFSTR("Failed to allocate ring version"), NULL
, error
));
490 require_action_quiet(SOSRingSetIdentifier(r
), errout
,
491 SOSCreateError(kSOSErrorAllocationFailure
, CFSTR("Failed to allocate ring identifier"), NULL
, error
));
493 CFMutableSetRef peerIDs
= CFSetCreateMutableForSOSPeerIDs();
494 require_action_quiet(SOSRingSetApplicants(r
, peerIDs
), errout
,
495 SOSCreateError(kSOSErrorAllocationFailure
, CFSTR("Failed to allocate applicant area"), NULL
, error
));
496 CFReleaseNull(peerIDs
);
498 CFMutableSetRef rejectedIDs
= CFSetCreateMutableForSOSPeerIDs();
499 require_action_quiet(SOSRingSetRejections(r
, rejectedIDs
), errout
,
500 SOSCreateError(kSOSErrorAllocationFailure
, CFSTR("Failed to allocate rejection area"), NULL
, error
));
501 CFReleaseNull(rejectedIDs
);
503 require_action_quiet(SOSRingSetGeneration(r
, gen
), errout
,
504 SOSCreateError(kSOSErrorAllocationFailure
, CFSTR("Failed to allocate generation count"), NULL
, error
));
506 peerIDs
= CFSetCreateMutableForSOSPeerIDs();
507 require_action_quiet(SOSRingSetPeerIDs(r
, peerIDs
), errout
,
508 SOSCreateError(kSOSErrorAllocationFailure
, CFSTR("Failed to allocate PeerID"), NULL
, error
));
510 CFReleaseNull(peerIDs
);
514 CFReleaseNull(r
->unSignedInformation
);
515 CFReleaseNull(r
->signedInformation
);
516 CFReleaseNull(r
->signatures
);
517 CFReleaseNull(r
->data
);
525 static void SOSRingDestroy(CFTypeRef aObj
) {
526 SOSRingRef c
= (SOSRingRef
) aObj
;
528 CFReleaseNull(c
->unSignedInformation
);
529 CFReleaseNull(c
->signedInformation
);
530 CFReleaseNull(c
->data
);
531 CFReleaseNull(c
->signatures
);
535 SOSRingRef
SOSRingCopyRing(SOSRingRef original
, CFErrorRef
*error
) {
536 SOSRingRef r
= CFTypeAllocate(SOSRing
, struct __OpaqueSOSRing
, ALLOCATOR
);
539 r
->unSignedInformation
= CFDictionaryCreateMutableCopy(ALLOCATOR
, 0, original
->unSignedInformation
);
540 r
->signedInformation
= CFDictionaryCreateMutableCopy(ALLOCATOR
, 0, original
->signedInformation
);
541 r
->signatures
= CFDictionaryCreateMutableCopy(ALLOCATOR
, 0, original
->signatures
);
542 r
->data
= CFDictionaryCreateMutableCopy(ALLOCATOR
, 0, original
->data
);
547 bool SOSRingIsEmpty_Internal(SOSRingRef ring
) {
548 return CFSetGetCount(SOSRingGetPeerIDs(ring
)) == 0;
551 bool SOSRingIsOffering_Internal(SOSRingRef ring
) {
552 return SOSRingCountPeers(ring
) == 1;
555 bool SOSRingResetToEmpty_Internal(SOSRingRef ring
, CFErrorRef
*error
) {
556 SOSGenCountRef gen
= NULL
;
557 CFSetRemoveAllValues(SOSRingGetApplicants(ring
));
558 CFSetRemoveAllValues(SOSRingGetRejections(ring
));
559 CFSetRemoveAllValues(SOSRingGetPeerIDs(ring
));
560 CFDictionaryRemoveAllValues(ring
->signatures
);
561 SOSRingSetGeneration(ring
, gen
= SOSGenerationCreate());
566 // MARK: PeerIDs in Ring
568 int SOSRingCountPeers(SOSRingRef ring
) {
569 SOSRingAssertStable(ring
);
570 return (int) CFSetGetCount(SOSRingGetPeerIDs(ring
));
574 bool SOSRingHasPeerWithID(SOSRingRef ring
, CFStringRef peerid
, CFErrorRef
*error
) {
575 SOSRingAssertStable(ring
);
576 return CFSetContainsValue(SOSRingGetPeerIDs(ring
), peerid
);
579 // MARK: Ring Signatures
582 static inline CFDictionaryRef
SOSRingGetSignatures(SOSRingRef ring
) {
583 return ring
->signatures
;
586 static inline CFDataRef
SOSRingGetSignatureForPeerID(SOSRingRef ring
, CFStringRef peerID
) {
587 if(!ring
|| !peerID
) return NULL
;
588 CFDataRef result
= NULL
;
589 CFTypeRef value
= (CFDataRef
)CFDictionaryGetValue(SOSRingGetSignatures(ring
), peerID
);
590 if (isData(value
)) result
= (CFDataRef
) value
;
594 static CFDataRef
SOSRingCreateHash(const struct ccdigest_info
*di
, SOSRingRef ring
, CFErrorRef
*error
) {
595 uint8_t hash_result
[di
->output_size
];
597 size_t dersize
= der_sizeof_plist(ring
->signedInformation
, error
);
601 uint8_t *der
= malloc(dersize
);
605 if (der_encode_plist(ring
->signedInformation
, error
, der
, der
+dersize
) == NULL
) {
610 ccdigest(di
, dersize
, der
, hash_result
);
612 return CFDataCreate(NULL
, hash_result
, di
->output_size
);
615 static bool SOSRingSetSignature(SOSRingRef ring
, SecKeyRef privKey
, CFDataRef signature
, CFErrorRef
*error
) {
617 SecKeyRef pubkey
= SecKeyCreatePublicFromPrivate(privKey
);
618 CFStringRef pubKeyID
= SOSCopyIDOfKey(pubkey
, error
);
619 require_quiet(pubKeyID
, fail
);
620 CFDictionarySetValue(ring
->signatures
, pubKeyID
, signature
);
623 CFReleaseSafe(pubkey
);
624 CFReleaseSafe(pubKeyID
);
628 bool SOSRingRemoveSignatures(SOSRingRef ring
, CFErrorRef
*error
) {
629 CFDictionaryRemoveAllValues(ring
->signatures
);
633 static CFDataRef
SOSCopySignedHash(SecKeyRef privKey
, CFDataRef hash
, CFErrorRef
*error
) {
634 size_t siglen
= SecKeyGetSize(privKey
, kSecKeySignatureSize
)+16;
636 OSStatus stat
= SecKeyRawSign(privKey
, kSecPaddingNone
, CFDataGetBytePtr(hash
), CFDataGetLength(hash
), sig
, &siglen
);
640 return CFDataCreate(NULL
, sig
, siglen
);
643 static bool SOSRingSign(SOSRingRef ring
, SecKeyRef privKey
, CFErrorRef
*error
) {
644 if (!ring
|| !privKey
) {
645 SOSCreateError(kSOSErrorBadSignature
, CFSTR("SOSRingSign Lacking ring or private key"),
646 (error
!= NULL
) ? *error
: NULL
, error
);
649 const struct ccdigest_info
*di
= ccsha256_di();
650 CFDataRef hash
= SOSRingCreateHash(di
, ring
, error
);
651 CFDataRef signature
= SOSCopySignedHash(privKey
, hash
, error
);
652 SOSRingSetSignature(ring
, privKey
, signature
, error
);
653 CFRelease(signature
);
658 bool SOSRingVerifySignatureExists(SOSRingRef ring
, SecKeyRef pubKey
, CFErrorRef
*error
) {
659 CFStringRef pubKeyID
= SOSCopyIDOfKey(pubKey
, error
);
660 CFDataRef signature
= SOSRingGetSignatureForPeerID(ring
, pubKeyID
);
661 CFReleaseNull(pubKeyID
);
662 return NULL
!= signature
;
665 bool SOSRingVerify(SOSRingRef ring
, SecKeyRef pubKey
, CFErrorRef
*error
) {
666 CFStringRef pubKeyID
= SOSCopyIDOfKey(pubKey
, error
);
667 CFDataRef signature
= SOSRingGetSignatureForPeerID(ring
, pubKeyID
);
668 CFReleaseNull(pubKeyID
);
669 if(!signature
) return false;
670 CFDataRef hash
= SOSRingCreateHash(ccsha256_di(), ring
, error
);
671 bool success
= SecKeyRawVerify(pubKey
, kSecPaddingNone
, CFDataGetBytePtr(hash
), CFDataGetLength(hash
),
672 CFDataGetBytePtr(signature
), CFDataGetLength(signature
)) == errSecSuccess
;
677 bool SOSRingVerifyPeerSigned(SOSRingRef ring
, SOSPeerInfoRef peer
, CFErrorRef
*error
) {
679 SecKeyRef pubkey
= SOSPeerInfoCopyPubKey(peer
, error
);
680 require_quiet(pubkey
, fail
);
682 result
= SOSRingVerify(ring
, pubkey
, error
);
685 CFReleaseSafe(pubkey
);
689 static bool SOSRingEnsureRingConsistency(SOSRingRef ring
, CFErrorRef
*error
) {
690 secnotice("Development", "SOSRingEnsureRingConsistency requires ring membership and generation count consistency check", NULL
);
694 bool SOSRingGenerationSign_Internal(SOSRingRef ring
, SecKeyRef privKey
, CFErrorRef
*error
) {
695 if(!privKey
|| !ring
) return false;
697 SOSRingGenerationIncrement(ring
);
698 require_quiet(SOSRingEnsureRingConsistency(ring
, error
), fail
);
699 require_quiet(SOSRingRemoveSignatures(ring
, error
), fail
);
700 require_quiet(SOSRingSign(ring
, privKey
, error
), fail
);
708 bool SOSRingConcordanceSign_Internal(SOSRingRef ring
, SecKeyRef privKey
, CFErrorRef
*error
) {
709 if(!privKey
|| !ring
) return false;
711 require_quiet(SOSRingSign(ring
, privKey
, error
), fail
);
721 static inline void CFSetForEachPeerID(CFSetRef set
, void (^operation
)(CFStringRef peerID
)) {
722 CFSetForEach(set
, ^(const void *value
) {
723 CFStringRef peerID
= (CFStringRef
) value
;
728 static CFStringRef
CreateCommaSeparatedPeerIDs(CFSetRef peers
) {
729 CFMutableStringRef result
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
731 __block
bool addSeparator
= false;
733 CFSetForEachPeerID(peers
, ^(CFStringRef peerID
) {
735 CFStringAppendCString(result
, ", ", kCFStringEncodingUTF8
);
737 CFStringRef spid
= CFStringCreateTruncatedCopy(peerID
, 8);
738 CFStringAppend(result
, spid
);
747 CFDictionaryRef
SOSRingCopyPeerIDList(SOSRingRef ring
) {
748 CFStringRef peerIDS
= CreateCommaSeparatedPeerIDs(SOSRingGetPeerIDs(ring
));
749 CFStringRef applicantIDs
= CreateCommaSeparatedPeerIDs(SOSRingGetApplicants(ring
));
750 CFStringRef rejectIDs
= CreateCommaSeparatedPeerIDs(SOSRingGetRejections(ring
));
751 CFDictionaryRef list
= CFDictionaryCreateForCFTypes(ALLOCATOR
,
752 CFSTR("MEMBER"), peerIDS
,
753 CFSTR("APPLICANTS"), applicantIDs
,
754 CFSTR("REJECTS"), rejectIDs
,
757 CFReleaseNull(peerIDS
);
758 CFReleaseNull(applicantIDs
);
759 CFReleaseNull(rejectIDs
);
763 CFStringRef
SOSRingCopySignerList(SOSRingRef ring
) {
764 __block
bool addSeparator
= false;
765 CFMutableStringRef signers
= CFStringCreateMutable(ALLOCATOR
, 0);
766 CFDictionaryForEach(ring
->signatures
, ^(const void *key
, const void *value
) {
767 CFStringRef peerID
= (CFStringRef
) key
;
768 CFStringRef spid
= CFStringCreateTruncatedCopy(peerID
, 8);
770 CFStringAppendCString(signers
, ", ", kCFStringEncodingUTF8
);
771 CFStringAppend(signers
, spid
);
778 static CFStringRef
SOSRingCopyFormatDescription(CFTypeRef aObj
, CFDictionaryRef formatOpts
) {
779 SOSRingRef ring
= (SOSRingRef
) aObj
;
781 SOSRingAssertStable(ring
);
783 CFDictionaryRef peers
= SOSRingCopyPeerIDList(ring
);
784 CFStringRef signers
= SOSRingCopySignerList(ring
);
785 CFStringRef gcString
= SOSGenerationCountCopyDescription(SOSRingGetGeneration(ring
));
787 CFMutableStringRef description
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
789 CFStringAppendFormat(description
, formatOpts
, CFSTR("<SOSRing: '%@'"), SOSRingGetName(ring
));
790 SOSGenerationCountWithDescription(SOSRingGetGeneration(ring
), ^(CFStringRef gcString
) {
791 CFStringAppendFormat(description
, formatOpts
, CFSTR("Gen: %@, "), gcString
);
793 CFStringRef modifierID
= CFStringCreateTruncatedCopy(SOSRingGetLastModifier(ring
), 8);
794 CFStringAppendFormat(description
, formatOpts
, CFSTR("Mod: %@, "), modifierID
);
795 CFReleaseNull(modifierID
);
797 CFStringAppendFormat(description
, formatOpts
, CFSTR("P: [%@], "), CFDictionaryGetValue(peers
, CFSTR("MEMBER")));
798 CFStringAppendFormat(description
, formatOpts
, CFSTR("A: [%@], "), CFDictionaryGetValue(peers
, CFSTR("APPLICANTS")));
799 CFStringAppendFormat(description
, formatOpts
, CFSTR("R: [%@], "), CFDictionaryGetValue(peers
, CFSTR("REJECTS")));
800 CFStringAppendFormat(description
, formatOpts
, CFSTR("S: [%@]>"), signers
);
802 CFReleaseNull(gcString
);
803 CFReleaseNull(peers
);
804 CFReleaseNull(signers
);
805 CFReleaseNull(peers
);