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 // MARK: Last Modifier
290 CFStringRef
SOSRingGetLastModifier(SOSRingRef ring
) {
292 assert(ring
->unSignedInformation
);
293 return CFDictionaryGetValue(ring
->unSignedInformation
, sLastPeerToModifyKey
);
296 bool SOSRingSetLastModifier(SOSRingRef ring
, CFStringRef peerID
) {
298 assert(ring
->unSignedInformation
);
299 return setValueInDict(ring
->unSignedInformation
, sLastPeerToModifyKey
, peerID
);
303 // MARK: Ring Applicants
305 CFMutableSetRef
SOSRingGetApplicants(SOSRingRef ring
) {
306 SOSRingAssertStable(ring
);
307 return (CFMutableSetRef
) CFDictionaryGetValue(ring
->unSignedInformation
, sApplicantsKey
);
310 bool SOSRingSetApplicants(SOSRingRef ring
, CFMutableSetRef applicants
) {
311 SOSRingAssertStable(ring
);
312 return setValueInDict(ring
->unSignedInformation
, sApplicantsKey
, applicants
);
315 int SOSRingCountApplicants(SOSRingRef ring
) {
316 SOSRingAssertStable(ring
);
317 return (int)CFSetGetCount(SOSRingGetApplicants(ring
));
320 bool SOSRingHasApplicant(SOSRingRef ring
, CFStringRef peerID
) {
321 SOSRingAssertStable(ring
);
322 return CFSetContainsValue(SOSRingGetApplicants(ring
), peerID
);
325 CFMutableSetRef
SOSRingCopyApplicants(SOSRingRef ring
) {
326 SOSRingAssertStable(ring
);
327 CFSetRef applicants
= SOSRingGetApplicants(ring
);
328 return CFSetCreateMutableCopy(ALLOCATOR
, 0, applicants
);
331 bool SOSRingAddApplicant(SOSRingRef ring
, CFStringRef peerid
) {
332 CFMutableSetRef applicants
= SOSRingGetApplicants(ring
);
333 CFSetAddValue(applicants
, peerid
);
337 bool SOSRingRemoveApplicant(SOSRingRef ring
, CFStringRef peerid
) {
338 CFMutableSetRef applicants
= SOSRingGetApplicants(ring
);
339 CFSetRemoveValue(applicants
, peerid
);
343 // MARK: Ring Rejections
345 static inline CFMutableSetRef
SOSRingGetRejections(SOSRingRef ring
) {
346 SOSRingAssertStable(ring
);
347 return (CFMutableSetRef
) CFDictionaryGetValue(ring
->unSignedInformation
, sRejectionsKey
);
350 static inline bool SOSRingSetRejections(SOSRingRef ring
, CFMutableSetRef rejections
) {
351 SOSRingAssertStable(ring
);
352 return setValueInDict(ring
->unSignedInformation
, sRejectionsKey
, rejections
);
355 int SOSRingCountRejections(SOSRingRef ring
) {
356 CFSetRef rejects
= SOSRingGetRejections(ring
);
357 return (int)CFSetGetCount(rejects
);
360 bool SOSRingHasRejection(SOSRingRef ring
, CFStringRef peerID
) {
361 SOSRingAssertStable(ring
);
362 return CFSetContainsValue(SOSRingGetRejections(ring
), peerID
);
365 CFMutableSetRef
SOSRingCopyRejections(SOSRingRef ring
) {
366 CFSetRef rejects
= SOSRingGetRejections(ring
);
367 return CFSetCreateMutableCopy(ALLOCATOR
, 0, rejects
);
371 bool SOSRingAddRejection(SOSRingRef ring
, CFStringRef peerid
) {
372 CFMutableSetRef rejects
= SOSRingGetRejections(ring
);
373 CFSetAddValue(rejects
, peerid
);
377 bool SOSRingRemoveRejection(SOSRingRef ring
, CFStringRef peerid
) {
378 CFMutableSetRef rejects
= SOSRingGetRejections(ring
);
379 CFSetRemoveValue(rejects
, peerid
);
383 // MARK: Ring Payload
385 CFDataRef
SOSRingGetPayload_Internal(SOSRingRef ring
) {
386 SOSRingAssertStable(ring
);
387 return (CFDataRef
) CFDictionaryGetValue(ring
->signedInformation
, sPayloadKey
);
390 bool SOSRingSetPayload_Internal(SOSRingRef ring
, CFDataRef payload
) {
391 SOSRingAssertStable(ring
);
392 return setValueInDict(ring
->signedInformation
, sPayloadKey
, payload
);
395 // MARK: Ring Backup Viewset
398 CFSetRef
SOSRingGetBackupViewset_Internal(SOSRingRef ring
) {
399 SOSRingAssertStable(ring
);
400 return (CFSetRef
) CFDictionaryGetValue(ring
->signedInformation
, sBackupViewSetKey
);
403 bool SOSRingSetBackupViewset_Internal(SOSRingRef ring
, CFSetRef viewSet
) {
404 SOSRingAssertStable(ring
);
405 return setValueInDict(ring
->signedInformation
, sBackupViewSetKey
, viewSet
);
410 // MARK: Ring PeerIDs
412 static inline CFMutableSetRef
SOSRingGetPeerIDs(SOSRingRef ring
) {
413 SOSRingAssertStable(ring
);
414 return (CFMutableSetRef
) CFDictionaryGetValue(ring
->signedInformation
, sPeerIDsKey
);
417 bool SOSRingSetPeerIDs(SOSRingRef ring
, CFMutableSetRef peers
) {
418 SOSRingAssertStable(ring
);
419 return setValueInDict(ring
->signedInformation
, sPeerIDsKey
, peers
);
422 int SOSRingCountPeerIDs(SOSRingRef ring
) {
423 CFSetRef peerIDs
= SOSRingGetPeerIDs(ring
);
424 return (int)CFSetGetCount(peerIDs
);
428 bool SOSRingHasPeerID(SOSRingRef ring
, CFStringRef peerID
) {
429 SOSRingAssertStable(ring
);
430 return CFSetContainsValue(SOSRingGetPeerIDs(ring
), peerID
);
433 CFMutableSetRef
SOSRingCopyPeerIDs(SOSRingRef ring
) {
434 CFSetRef peerIDs
= SOSRingGetPeerIDs(ring
);
435 return CFSetCreateMutableCopy(ALLOCATOR
, 0, peerIDs
);
438 void SOSRingAddAll(SOSRingRef ring
, CFSetRef peerInfosOrIDs
) {
439 CFSetForEach(peerInfosOrIDs
, ^(const void *value
) {
440 CFStringRef peerID
= value
;
442 if (isSOSPeerInfo(value
))
443 peerID
= SOSPeerInfoGetPeerID((SOSPeerInfoRef
)value
);
445 if (isString(peerID
))
446 SOSRingAddPeerID(ring
, peerID
);
450 bool SOSRingAddPeerID(SOSRingRef ring
, CFStringRef peerid
) {
451 CFMutableSetRef peerIDs
= SOSRingGetPeerIDs(ring
);
452 CFSetAddValue(peerIDs
, peerid
);
456 bool SOSRingRemovePeerID(SOSRingRef ring
, CFStringRef peerid
) {
457 CFMutableSetRef peerIDs
= SOSRingGetPeerIDs(ring
);
458 CFSetRemoveValue(peerIDs
, peerid
);
462 void SOSRingForEachPeerID(SOSRingRef ring
, void (^action
)(CFStringRef peerID
)) {
463 SOSRingAssertStable(ring
);
464 CFMutableSetRef peerIDs
= SOSRingGetPeerIDs(ring
);
466 CFSetForEach(peerIDs
, ^(const void*value
) {
467 CFStringRef peerID
= (CFStringRef
) value
;
474 SOSRingRef
SOSRingCreate_Internal(CFStringRef name
, SOSRingType type
, CFErrorRef
*error
) {
475 SOSRingRef r
= SOSRingAllocate();
476 SOSGenCountRef gen
= SOSGenerationCreate();
478 require_action_quiet(name
, errout0
,
479 SOSCreateError(kSOSErrorNoCircleName
, CFSTR("No ring name"), NULL
, error
));
480 require_action_quiet(SOSRingCheckType(type
, error
), errout0
,
481 SOSCreateError(kSOSErrorUnexpectedType
, CFSTR("Unknown ring type"), NULL
, error
));
482 require_action_quiet((r
->unSignedInformation
= CFDictionaryCreateMutableForCFTypes(ALLOCATOR
)), errout
,
483 SOSCreateError(kSOSErrorAllocationFailure
, CFSTR("Failed to allocate unsigned information area"), NULL
, error
));
484 require_action_quiet((r
->signedInformation
= CFDictionaryCreateMutableForCFTypes(ALLOCATOR
)), errout
,
485 SOSCreateError(kSOSErrorAllocationFailure
, CFSTR("Failed to allocate signed information area"), NULL
, error
));
486 require_action_quiet((r
->signatures
= CFDictionaryCreateMutableForCFTypes(ALLOCATOR
)), errout
,
487 SOSCreateError(kSOSErrorAllocationFailure
, CFSTR("Failed to allocate signature area"), NULL
, error
));
488 require_action_quiet((r
->data
= CFDictionaryCreateMutableForCFTypes(ALLOCATOR
)), errout
,
489 SOSCreateError(kSOSErrorAllocationFailure
, CFSTR("Failed to allocate data area"), NULL
, error
));
491 require_action_quiet(SOSRingSetName(r
, name
), errout
,
492 SOSCreateError(kSOSErrorAllocationFailure
, CFSTR("Failed to allocate ring name area"), NULL
, error
));
493 require_action_quiet(SOSRingSetType(r
, type
), errout
,
494 SOSCreateError(kSOSErrorAllocationFailure
, CFSTR("Failed to allocate ring type"), NULL
, error
));
495 require_action_quiet(SOSRingSetVersion(r
), errout
,
496 SOSCreateError(kSOSErrorAllocationFailure
, CFSTR("Failed to allocate ring version"), NULL
, error
));
497 require_action_quiet(SOSRingSetIdentifier(r
), errout
,
498 SOSCreateError(kSOSErrorAllocationFailure
, CFSTR("Failed to allocate ring identifier"), NULL
, error
));
500 CFMutableSetRef peerIDs
= CFSetCreateMutableForSOSPeerIDs();
501 require_action_quiet(SOSRingSetApplicants(r
, peerIDs
), errout
,
502 SOSCreateError(kSOSErrorAllocationFailure
, CFSTR("Failed to allocate applicant area"), NULL
, error
));
503 CFReleaseNull(peerIDs
);
505 CFMutableSetRef rejectedIDs
= CFSetCreateMutableForSOSPeerIDs();
506 require_action_quiet(SOSRingSetRejections(r
, rejectedIDs
), errout
,
507 SOSCreateError(kSOSErrorAllocationFailure
, CFSTR("Failed to allocate rejection area"), NULL
, error
));
508 CFReleaseNull(rejectedIDs
);
510 require_action_quiet(SOSRingSetGeneration(r
, gen
), errout
,
511 SOSCreateError(kSOSErrorAllocationFailure
, CFSTR("Failed to allocate generation count"), NULL
, error
));
513 peerIDs
= CFSetCreateMutableForSOSPeerIDs();
514 require_action_quiet(SOSRingSetPeerIDs(r
, peerIDs
), errout
,
515 SOSCreateError(kSOSErrorAllocationFailure
, CFSTR("Failed to allocate PeerID"), NULL
, error
));
517 CFReleaseNull(peerIDs
);
521 CFReleaseNull(r
->unSignedInformation
);
522 CFReleaseNull(r
->signedInformation
);
523 CFReleaseNull(r
->signatures
);
524 CFReleaseNull(r
->data
);
532 static void SOSRingDestroy(CFTypeRef aObj
) {
533 SOSRingRef c
= (SOSRingRef
) aObj
;
535 CFReleaseNull(c
->unSignedInformation
);
536 CFReleaseNull(c
->signedInformation
);
537 CFReleaseNull(c
->data
);
538 CFReleaseNull(c
->signatures
);
542 SOSRingRef
SOSRingCopyRing(SOSRingRef original
, CFErrorRef
*error
) {
543 SOSRingRef r
= CFTypeAllocate(SOSRing
, struct __OpaqueSOSRing
, ALLOCATOR
);
546 r
->unSignedInformation
= CFDictionaryCreateMutableCopy(ALLOCATOR
, 0, original
->unSignedInformation
);
547 r
->signedInformation
= CFDictionaryCreateMutableCopy(ALLOCATOR
, 0, original
->signedInformation
);
548 r
->signatures
= CFDictionaryCreateMutableCopy(ALLOCATOR
, 0, original
->signatures
);
549 r
->data
= CFDictionaryCreateMutableCopy(ALLOCATOR
, 0, original
->data
);
554 bool SOSRingIsEmpty_Internal(SOSRingRef ring
) {
555 return CFSetGetCount(SOSRingGetPeerIDs(ring
)) == 0;
558 bool SOSRingIsOffering_Internal(SOSRingRef ring
) {
559 return SOSRingCountPeers(ring
) == 1;
562 bool SOSRingResetToEmpty_Internal(SOSRingRef ring
, CFErrorRef
*error
) {
563 SOSGenCountRef gen
= NULL
;
564 CFSetRemoveAllValues(SOSRingGetApplicants(ring
));
565 CFSetRemoveAllValues(SOSRingGetRejections(ring
));
566 CFSetRemoveAllValues(SOSRingGetPeerIDs(ring
));
567 CFDictionaryRemoveAllValues(ring
->signatures
);
568 SOSRingSetGeneration(ring
, gen
= SOSGenerationCreate());
573 // MARK: PeerIDs in Ring
576 static inline bool isHiddenPeer(SOSPeerInfoRef peer
) {
577 return SOSPeerInfoIsRetirementTicket(peer
) || SOSPeerInfoIsCloudIdentity(peer
);
581 int SOSRingCountPeers(SOSRingRef ring
) {
582 SOSRingAssertStable(ring
);
583 return (int) CFSetGetCount(SOSRingGetPeerIDs(ring
));
587 bool SOSRingHasPeerWithID(SOSRingRef ring
, CFStringRef peerid
, CFErrorRef
*error
) {
588 SOSRingAssertStable(ring
);
589 return CFSetContainsValue(SOSRingGetPeerIDs(ring
), peerid
);
592 // MARK: Ring Signatures
595 static inline CFDictionaryRef
SOSRingGetSignatures(SOSRingRef ring
) {
596 return ring
->signatures
;
599 static inline CFDataRef
SOSRingGetSignatureForPeerID(SOSRingRef ring
, CFStringRef peerID
) {
600 if(!ring
|| !peerID
) return NULL
;
601 CFDataRef result
= NULL
;
602 CFTypeRef value
= (CFDataRef
)CFDictionaryGetValue(SOSRingGetSignatures(ring
), peerID
);
603 if (isData(value
)) result
= (CFDataRef
) value
;
607 static CFDataRef
SOSRingCreateHash(const struct ccdigest_info
*di
, SOSRingRef ring
, CFErrorRef
*error
) {
608 uint8_t hash_result
[di
->output_size
];
610 size_t dersize
= der_sizeof_plist(ring
->signedInformation
, error
);
614 uint8_t der
[dersize
];
615 der_encode_plist(ring
->signedInformation
, error
, der
, der
+dersize
);
617 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
SOSHashSign(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
= SOSHashSign(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
) {
684 SecKeyRef pubkey
= SOSPeerInfoCopyPubKey(peer
);
685 bool result
= SOSRingVerify(ring
, pubkey
, error
);
686 CFReleaseSafe(pubkey
);
690 static bool SOSRingEnsureRingConsistency(SOSRingRef ring
, CFErrorRef
*error
) {
691 secnotice("Development", "SOSRingEnsureRingConsistency requires ring membership and generation count consistency check", NULL
);
695 bool SOSRingGenerationSign_Internal(SOSRingRef ring
, SecKeyRef privKey
, CFErrorRef
*error
) {
696 if(!privKey
|| !ring
) return false;
698 SOSRingGenerationIncrement(ring
);
699 require_quiet(SOSRingEnsureRingConsistency(ring
, error
), fail
);
700 require_quiet(SOSRingRemoveSignatures(ring
, error
), fail
);
701 require_quiet(SOSRingSign(ring
, privKey
, error
), fail
);
709 bool SOSRingConcordanceSign_Internal(SOSRingRef ring
, SecKeyRef privKey
, CFErrorRef
*error
) {
710 if(!privKey
|| !ring
) return false;
712 require_quiet(SOSRingSign(ring
, privKey
, error
), fail
);
722 static inline void CFSetForEachPeerID(CFSetRef set
, void (^operation
)(CFStringRef peerID
)) {
723 CFSetForEach(set
, ^(const void *value
) {
724 CFStringRef peerID
= (CFStringRef
) value
;
729 static CFStringRef
CreateCommaSeparatedPeerIDs(CFSetRef peers
) {
730 CFMutableStringRef result
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
732 __block
bool addSeparator
= false;
734 CFSetForEachPeerID(peers
, ^(CFStringRef peerID
) {
736 CFStringAppendCString(result
, ", ", kCFStringEncodingUTF8
);
738 CFStringAppend(result
, peerID
);
746 CFDictionaryRef
SOSRingPeerIDList(SOSRingRef ring
) {
747 CFStringRef peerIDS
= CreateCommaSeparatedPeerIDs(SOSRingGetPeerIDs(ring
));
748 CFStringRef applicantIDs
= CreateCommaSeparatedPeerIDs(SOSRingGetApplicants(ring
));
749 CFStringRef rejectIDs
= CreateCommaSeparatedPeerIDs(SOSRingGetRejections(ring
));
750 CFDictionaryRef list
= CFDictionaryCreateForCFTypes(ALLOCATOR
,
751 CFSTR("MEMBER"), peerIDS
,
752 CFSTR("APPLICANTS"), applicantIDs
,
753 CFSTR("REJECTS"), rejectIDs
,
756 CFReleaseNull(peerIDS
);
757 CFReleaseNull(applicantIDs
);
758 CFReleaseNull(rejectIDs
);
762 CFStringRef
SOSRingSignerList(SOSRingRef ring
) {
763 __block
bool addSeparator
= false;
764 CFMutableStringRef signers
= CFStringCreateMutable(ALLOCATOR
, 0);
765 CFDictionaryForEach(ring
->signatures
, ^(const void *key
, const void *value
) {
766 CFStringRef peerID
= (CFStringRef
) key
;
768 CFStringAppendCString(signers
, ", ", kCFStringEncodingUTF8
);
769 CFStringAppend(signers
, peerID
);
775 static CFStringRef
SOSRingCopyFormatDescription(CFTypeRef aObj
, CFDictionaryRef formatOpts
) {
776 SOSRingRef ring
= (SOSRingRef
) aObj
;
778 SOSRingAssertStable(ring
);
780 CFDictionaryRef peers
= SOSRingPeerIDList(ring
);
781 CFStringRef signers
= SOSRingSignerList(ring
);
783 CFDataRef payload
= SOSRingGetPayload(ring
, NULL
);
785 CFStringRef gcString
= SOSGenerationCountCopyDescription(SOSRingGetGeneration(ring
));
787 CFMutableStringRef description
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
789 CFStringAppendFormat(description
, formatOpts
, CFSTR("<SOSRing@%p: '%@', Version %u, "), ring
, SOSRingGetName(ring
), SOSRingGetVersion(ring
));
790 CFStringAppendFormat(description
, formatOpts
, CFSTR("UUID: %@, "), SOSRingGetIdentifier(ring
));
791 SOSGenerationCountWithDescription(SOSRingGetGeneration(ring
), ^(CFStringRef gcString
) {
792 CFStringAppendFormat(description
, formatOpts
, CFSTR("Gen: %@, "), gcString
);
794 CFStringAppendFormat(description
, formatOpts
, CFSTR("Mod: %@, "), SOSRingGetLastModifier(ring
));
796 CFStringAppendFormat(description
, formatOpts
, CFSTR("D: %ld "), payload
? CFDataGetLength(payload
) : 0);
798 SOSBackupSliceKeyBagRef payloadAsBSKB
= SOSRingCopyBackupSliceKeyBag(ring
, NULL
);
801 CFStringAppendFormat(description
, formatOpts
, CFSTR("%@ "), payloadAsBSKB
);
804 CFReleaseSafe(payloadAsBSKB
);
806 CFStringAppendFormat(description
, formatOpts
, CFSTR("P: [%@], "), CFDictionaryGetValue(peers
, CFSTR("MEMBER")));
807 CFStringAppendFormat(description
, formatOpts
, CFSTR("A: [%@], "), CFDictionaryGetValue(peers
, CFSTR("APPLICANTS")));
808 CFStringAppendFormat(description
, formatOpts
, CFSTR("R: [%@], "), CFDictionaryGetValue(peers
, CFSTR("REJECTS")));
809 CFStringAppendFormat(description
, formatOpts
, CFSTR("S: [%@]>"), signers
);
811 CFReleaseNull(gcString
);
812 CFReleaseNull(peers
);
813 CFReleaseNull(signers
);
824 static CFDataRef
sosSignHash(SecKeyRef privkey
, const struct ccdigest_info
*di
, uint8_t *hbuf
) {
826 size_t siglen
= SIGLEN
;
828 if((stat
= SecKeyRawSign(privkey
, kSecPaddingNone
, hbuf
, di
->output_size
, sig
, &siglen
)) != 0) {
831 return CFDataCreate(NULL
, sig
, (CFIndex
)siglen
);
835 static void WithBufferSpace(size_t space
, void (^action
)(uint8_t *buffer
, size_t length
)) {
838 } else if (space
<= 2048) {
839 uint8_t buffer
[space
];
841 action(buffer
, space
);
843 uint8_t* buffer
= malloc(space
);
845 action(buffer
, space
);
851 static CFDataRef
CFDictionaryHashCreate(CFDictionaryRef dict
, CFErrorRef
*error
) {
853 __block CFDataRef result
= NULL
;
855 require_quiet(dict
, errOut
);
857 WithBufferSpace(der_sizeof_dictionary(dict
, error
), ^(uint8_t *der
, size_t len
) {
859 const struct ccdigest_info
*di
= ccsha256_di();
860 uint8_t hash_result
[di
->output_size
];
861 der_encode_dictionary(dict
, error
, der
, der
+len
);
863 ccdigest(di
, len
, der
, hash_result
);
864 result
= CFDataCreate(ALLOCATOR
, hash_result
, di
->output_size
);
874 signatures: CFDictionary of key = hash(pubkey), value = signature(privkey, (DER(payload))
875 payload: CFDictionary passed in
880 static CFStringRef sPayload
= CFSTR("payload");
881 static CFStringRef sSignature
= CFSTR("signature");
883 static bool SOSCFSignedDictionarySetSignature(SecKeyRef priv
, CFDictionaryRef sd
, CFErrorRef
*error
) {
884 CFDictionaryRef payload
= CFDictionaryGetValue(sd
, sPayload
);
885 CFMutableDictionaryRef signatures
= (CFMutableDictionaryRef
) CFDictionaryGetValue(sd
, sSignature
);
886 CFDataRef hash
= CFDictionaryHashCreate(payload
, error
);
887 CFDataRef signature
= SOSHashSign(priv
, hash
, error
);
889 CFStringRef pubhash
= SOSCopyIDOfKey(priv
, error
);
890 require_quiet(signature
&& pubhash
, errOut
);
891 CFDictionaryAddValue(signatures
, pubhash
, signature
);
898 static CFDictionaryRef
SOSCFSignedDictionaryCreate(SecKeyRef priv
, CFDictionaryRef payload
, CFErrorRef
*error
) {
899 CFMutableDictionaryRef signatures
= CFDictionaryCreateMutableForCFTypes(ALLOCATOR
);
900 CFMutableDictionaryRef retval
= CFDictionaryCreateMutableForCFTypes(ALLOCATOR
);
901 require_quiet(signatures
&& retval
, errOut
);
903 CFDictionaryAddValue(retval
, sSignature
, signatures
);
904 CFDictionaryAddValue(retval
, sPayload
, payload
);
905 SOSCFSignedDictionarySetSignature(priv
, retval
, error
);
908 CFReleaseNull(signatures
);
909 CFReleaseNull(retval
);
915 CFDictionaryRef
SOSRingCreateRetirementTicket(SOSFullPeerInfoRef fpi
, CFErrorRef
*error
) {
916 CFDictionaryRef retval
= NULL
;
917 CFStringRef myPeerID
= SOSPeerInfoGetPeerID(SOSFullPeerInfoGetPeerInfo(fpi
));
918 SecKeyRef priv
= SOSFullPeerInfoCopyDeviceKey(fpi
, error
);
919 CFDataRef resignationDate
= SOSDateCreate();
922 CFDataRef sig
= SOSDERAndSignStuff(priv
, keys
, values
, 2, error
);
923 retval
= CFDictionaryCreate(ALLOCATOR
, <#const void **keys#>, <#const void **values#>, <#CFIndex numValues#>, <#const CFDictionaryKeyCallBacks *keyCallBacks#>, <#const CFDictionaryValueCallBacks *valueCallBacks#>)
928 CFReleaseNull(resignationDate
);