5 // Created by Richard Murphy on 3/3/15.
9 #include "SOSRingBackup.h"
11 #include <AssertMacros.h>
13 #include <Security/SecureObjectSync/SOSInternal.h>
14 #include <Security/SecureObjectSync/SOSPeerInfoInternal.h>
15 #include <Security/SecureObjectSync/SOSPeerInfoCollections.h>
16 #include <Security/SecureObjectSync/SOSCircle.h>
17 #include <Security/SecureObjectSync/SOSViews.h>
18 #include <Security/SecFramework.h>
20 #include <Security/SecKey.h>
21 #include <Security/SecKeyPriv.h>
22 #include <CoreFoundation/CoreFoundation.h>
24 #include <utilities/SecCFWrappers.h>
29 #include "SOSRingUtils.h"
30 #include "SOSRingTypes.h"
32 // MARK: Backup Ring Ops
34 static SOSRingRef
SOSRingCreate_Backup(CFStringRef name
, CFStringRef myPeerID
, CFErrorRef
*error
) {
35 SOSRingRef retval
= NULL
;
36 retval
= SOSRingCreate_Internal(name
, kSOSRingBackup
, error
);
37 if(!retval
) return NULL
;
38 SOSRingSetLastModifier(retval
, myPeerID
);
42 static bool SOSRingResetToEmpty_Backup(SOSRingRef ring
, CFStringRef myPeerID
, CFErrorRef
*error
) {
43 return SOSRingResetToEmpty_Internal(ring
, error
) && SOSRingSetLastModifier(ring
, myPeerID
);
46 static bool SOSRingResetToOffering_Backup(SOSRingRef ring
, SecKeyRef user_privkey
, SOSFullPeerInfoRef requestor
, CFErrorRef
*error
) {
47 CFStringRef myPeerID
= SOSPeerInfoGetPeerID(SOSFullPeerInfoGetPeerInfo(requestor
));
48 SecKeyRef priv
= SOSFullPeerInfoCopyDeviceKey(requestor
, error
);
49 bool retval
= priv
&& myPeerID
&&
50 SOSRingResetToEmpty_Internal(ring
, error
) &&
51 SOSRingAddPeerID(ring
, myPeerID
) &&
52 SOSRingSetLastModifier(ring
, myPeerID
) &&
53 SOSRingGenerationSign_Internal(ring
, priv
, error
);
54 if(user_privkey
) SOSRingConcordanceSign_Internal(ring
, user_privkey
, error
);
59 static SOSRingStatus
SOSRingDeviceIsInRing_Backup(SOSRingRef ring
, CFStringRef peerID
) {
60 if(SOSRingHasPeerID(ring
, peerID
)) return kSOSRingMember
;
61 if(SOSRingHasApplicant(ring
, peerID
)) return kSOSRingApplicant
;
62 if(SOSRingHasRejection(ring
, peerID
)) return kSOSRingReject
;
63 return kSOSRingNotInRing
;
66 static bool SOSRingApply_Backup(SOSRingRef ring
, SecKeyRef user_pubkey
, SOSFullPeerInfoRef requestor
, CFErrorRef
*error
) {
68 CFStringRef myPeerID
= SOSPeerInfoGetPeerID(SOSFullPeerInfoGetPeerInfo(requestor
));
69 SecKeyRef priv
= SOSFullPeerInfoCopyDeviceKey(requestor
, error
);
70 require_action_quiet(SOSRingDeviceIsInRing_Backup(ring
, myPeerID
) == kSOSRingNotInRing
, errOut
, secnotice("ring", "Already associated with ring"));
71 retval
= priv
&& myPeerID
&&
72 SOSRingAddPeerID(ring
, myPeerID
) &&
73 SOSRingSetLastModifier(ring
, myPeerID
) &&
74 SOSRingGenerationSign_Internal(ring
, priv
, error
);
81 static bool SOSRingWithdraw_Backup(SOSRingRef ring
, SecKeyRef user_privkey
, SOSFullPeerInfoRef requestor
, CFErrorRef
*error
) {
82 CFStringRef myPeerID
= SOSPeerInfoGetPeerID(SOSFullPeerInfoGetPeerInfo(requestor
));
83 if(SOSRingHasPeerID(ring
, myPeerID
)) {
84 SOSRingRemovePeerID(ring
, myPeerID
);
85 } else if(SOSRingHasApplicant(ring
, myPeerID
)) {
86 SOSRingRemoveApplicant(ring
, myPeerID
);
87 } else if(SOSRingHasRejection(ring
, myPeerID
)) {
88 SOSRingRemoveRejection(ring
, myPeerID
);
90 SOSCreateError(kSOSErrorPeerNotFound
, CFSTR("Not associated with Ring"), NULL
, error
);
93 SOSRingSetLastModifier(ring
, myPeerID
);
95 SecKeyRef priv
= SOSFullPeerInfoCopyDeviceKey(requestor
, error
);
96 SOSRingGenerationSign_Internal(ring
, priv
, error
);
97 if(user_privkey
) SOSRingConcordanceSign_Internal(ring
, user_privkey
, error
);
102 static bool SOSRingGenerationSign_Backup(SOSRingRef ring
, SecKeyRef user_privkey
, SOSFullPeerInfoRef requestor
, CFErrorRef
*error
) {
103 CFStringRef myPeerID
= SOSPeerInfoGetPeerID(SOSFullPeerInfoGetPeerInfo(requestor
));
104 SecKeyRef priv
= SOSFullPeerInfoCopyDeviceKey(requestor
, error
);
105 bool retval
= priv
&& myPeerID
&&
106 SOSRingSetLastModifier(ring
, myPeerID
) &&
107 SOSRingGenerationSign_Internal(ring
, priv
, error
);
108 if(user_privkey
) SOSRingConcordanceSign_Internal(ring
, user_privkey
, error
);
113 // Make sure all the peers in the ring have access to the ring views
114 static bool SOSBackupRingPeersInViews(CFSetRef peers
, SOSRingRef ring
) {
115 CFSetRef ringViews
= SOSBackupRingGetViews(ring
, NULL
);
116 if(!ringViews
) return false;
117 __block
bool retval
= true;
118 SOSRingForEachPeerID(ring
, ^(CFStringRef peerID
) {
119 SOSPeerInfoRef peerInfo
= SOSPeerInfoSetFindByID(peers
, peerID
);
121 CFSetForEach(ringViews
, ^(const void *value
) {
122 if(!SOSPeerInfoIsViewPermitted(peerInfo
, (CFStringRef
) value
)) retval
= false;
131 // Make sure that the ring includes me if I'm enabled for its view.
132 static SOSConcordanceStatus
SOSBackupRingEvaluateMyInclusion(SOSRingRef ring
, SOSFullPeerInfoRef me
) {
133 bool shouldBeInRing
= false;
134 bool amInThisRing
= false;
137 SOSPeerInfoRef pi
= SOSFullPeerInfoGetPeerInfo(me
);
138 CFStringRef peerID
= SOSPeerInfoGetPeerID(pi
);
139 CFSetRef ringViews
= SOSRingGetBackupViewset_Internal(ring
);
140 CFSetRef piViews
= SOSPeerInfoGetPermittedViews(pi
);
141 shouldBeInRing
= CFSetIsSubset(ringViews
, piViews
);
142 amInThisRing
= SOSRingHasPeerWithID(ring
, peerID
, NULL
);
145 if(shouldBeInRing
&& !amInThisRing
) return kSOSConcordanceMissingMe
;
146 if(!shouldBeInRing
&& amInThisRing
) return kSOSConcordanceImNotWorthy
;
147 return kSOSConcordanceTrusted
;
150 static SOSConcordanceStatus
SOSRingPeerKeyConcordanceTrust_Backup(SOSFullPeerInfoRef me
, CFSetRef peers
, SOSRingRef knownRing
, SOSRingRef proposedRing
,
151 __unused SecKeyRef knownPubkey
, SecKeyRef userPubkey
,
152 CFStringRef excludePeerID
, CFErrorRef
*error
) {
153 if(userPubkey
== NULL
) {
154 SOSCreateError(kSOSErrorPublicKeyAbsent
, CFSTR("Concordance with no public key - need to validate application"), NULL
, error
);
155 return kSOSConcordanceNoUserKey
;
158 if(SOSRingIsOlderGeneration(knownRing
, proposedRing
)) {
159 SOSCreateError(kSOSErrorReplay
, CFSTR("Bad generation"), NULL
, error
);
160 return kSOSConcordanceGenOld
;
164 if (SOSRingIsEmpty_Internal(proposedRing
)) {
165 return kSOSConcordanceTrusted
;
168 SOSConcordanceStatus localstatus
= SOSBackupRingEvaluateMyInclusion(proposedRing
, me
);
169 if(localstatus
== kSOSConcordanceMissingMe
) {
170 SOSCreateError(kSOSErrorReplay
, CFSTR("Improper exclusion of this peer"), NULL
, error
);
174 if(localstatus
== kSOSConcordanceImNotWorthy
) {
175 SOSCreateError(kSOSErrorReplay
, CFSTR("Improper inclusion of this peer"), NULL
, error
);
179 if(!SOSBackupRingPeersInViews(peers
, proposedRing
)) {
180 return kSOSConcordanceInvalidMembership
;
183 return GetSignersStatus_Transitive(peers
, knownRing
, proposedRing
, userPubkey
, excludePeerID
, error
);
187 static bool SOSRingConcordanceSign_Backup(SOSRingRef ring
, SOSFullPeerInfoRef requestor
, CFErrorRef
*error
) {
188 CFStringRef myPeerID
= SOSPeerInfoGetPeerID(SOSFullPeerInfoGetPeerInfo(requestor
));
189 SecKeyRef priv
= SOSFullPeerInfoCopyDeviceKey(requestor
, error
);
190 bool retval
= priv
&& myPeerID
&&
191 SOSRingSetLastModifier(ring
, myPeerID
) &&
192 SOSRingConcordanceSign_Internal(ring
, priv
, error
);
197 static bool SOSRingSetPayload_Backup(SOSRingRef ring
, SecKeyRef user_privkey
, CFDataRef payload
, SOSFullPeerInfoRef requestor
, CFErrorRef
*error
) {
198 CFStringRef myPeerID
= SOSPeerInfoGetPeerID(SOSFullPeerInfoGetPeerInfo(requestor
));
199 SecKeyRef priv
= SOSFullPeerInfoCopyDeviceKey(requestor
, error
);
200 bool retval
= priv
&& myPeerID
&&
201 SOSRingSetLastModifier(ring
, myPeerID
) &&
202 SOSRingSetPayload_Internal(ring
, payload
) &&
203 SOSRingGenerationSign_Internal(ring
, priv
, error
);
204 if(user_privkey
) SOSRingConcordanceSign_Internal(ring
, user_privkey
, error
);
209 static CFDataRef
SOSRingGetPayload_Backup(SOSRingRef ring
, CFErrorRef
*error
) {
210 return SOSRingGetPayload_Internal(ring
);
213 bool SOSBackupRingSetViews(SOSRingRef ring
, SOSFullPeerInfoRef requestor
, CFSetRef viewSet
, CFErrorRef
*error
) {
214 CFStringRef myPeerID
= SOSPeerInfoGetPeerID(SOSFullPeerInfoGetPeerInfo(requestor
));
215 SecKeyRef priv
= SOSFullPeerInfoCopyDeviceKey(requestor
, error
);
216 bool retval
= priv
&& myPeerID
&&
217 SOSRingSetLastModifier(ring
, myPeerID
) &&
218 SOSRingSetBackupViewset_Internal(ring
, viewSet
) &&
219 SOSRingGenerationSign_Internal(ring
, priv
, error
);
224 CFSetRef
SOSBackupRingGetViews(SOSRingRef ring
, CFErrorRef
*error
) {
225 return SOSRingGetBackupViewset_Internal(ring
);
228 ringFuncStruct backup
= {
231 SOSRingCreate_Backup
,
232 SOSRingResetToEmpty_Backup
,
233 SOSRingResetToOffering_Backup
,
234 SOSRingDeviceIsInRing_Backup
,
236 SOSRingWithdraw_Backup
,
237 SOSRingGenerationSign_Backup
,
238 SOSRingConcordanceSign_Backup
,
239 SOSRingPeerKeyConcordanceTrust_Backup
,
242 SOSRingSetPayload_Backup
,
243 SOSRingGetPayload_Backup
,