]> git.saurik.com Git - apple/security.git/blob - OSX/sec/SOSCircle/SecureObjectSync/SOSRingBackup.c
Security-57337.40.85.tar.gz
[apple/security.git] / OSX / sec / SOSCircle / SecureObjectSync / SOSRingBackup.c
1 //
2 // SOSRingBasic.c
3 // sec
4 //
5 // Created by Richard Murphy on 3/3/15.
6 //
7 //
8
9 #include "SOSRingBackup.h"
10
11 #include <AssertMacros.h>
12
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>
19
20 #include <Security/SecKey.h>
21 #include <Security/SecKeyPriv.h>
22 #include <CoreFoundation/CoreFoundation.h>
23
24 #include <utilities/SecCFWrappers.h>
25
26 #include <stdlib.h>
27 #include <assert.h>
28
29 #include "SOSRingUtils.h"
30 #include "SOSRingTypes.h"
31
32 // MARK: Backup Ring Ops
33
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);
39 return retval;
40 }
41
42 static bool SOSRingResetToEmpty_Backup(SOSRingRef ring, CFStringRef myPeerID, CFErrorRef *error) {
43 return SOSRingResetToEmpty_Internal(ring, error) && SOSRingSetLastModifier(ring, myPeerID);
44 }
45
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);
55 CFReleaseNull(priv);
56 return retval;
57 }
58
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;
64 }
65
66 static bool SOSRingApply_Backup(SOSRingRef ring, SecKeyRef user_pubkey, SOSFullPeerInfoRef requestor, CFErrorRef *error) {
67 bool retval = false;
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);
75 CFReleaseNull(priv);
76 errOut:
77 return retval;
78
79 }
80
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);
89 } else {
90 SOSCreateError(kSOSErrorPeerNotFound, CFSTR("Not associated with Ring"), NULL, error);
91 return false;
92 }
93 SOSRingSetLastModifier(ring, myPeerID);
94
95 SecKeyRef priv = SOSFullPeerInfoCopyDeviceKey(requestor, error);
96 SOSRingGenerationSign_Internal(ring, priv, error);
97 if(user_privkey) SOSRingConcordanceSign_Internal(ring, user_privkey, error);
98 CFReleaseNull(priv);
99 return true;
100 }
101
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);
109 CFReleaseNull(priv);
110 return retval;
111 }
112
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);
120 if(peerInfo) {
121 CFSetForEach(ringViews, ^(const void *value) {
122 if(!SOSPeerInfoIsViewPermitted(peerInfo, (CFStringRef) value)) retval = false;
123 });
124 } else {
125 retval = false;
126 }
127 });
128 return retval;
129 }
130
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;
135
136 if (me) {
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);
143 }
144
145 if(shouldBeInRing && !amInThisRing) return kSOSConcordanceMissingMe;
146 if(!shouldBeInRing && amInThisRing) return kSOSConcordanceImNotWorthy;
147 return kSOSConcordanceTrusted;
148 }
149
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;
156 }
157
158 if(SOSRingIsOlderGeneration(knownRing, proposedRing)) {
159 SOSCreateError(kSOSErrorReplay, CFSTR("Bad generation"), NULL, error);
160 return kSOSConcordanceGenOld;
161 }
162
163
164 if (SOSRingIsEmpty_Internal(proposedRing)) {
165 return kSOSConcordanceTrusted;
166 }
167
168 SOSConcordanceStatus localstatus = SOSBackupRingEvaluateMyInclusion(proposedRing, me);
169 if(localstatus == kSOSConcordanceMissingMe) {
170 SOSCreateError(kSOSErrorReplay, CFSTR("Improper exclusion of this peer"), NULL, error);
171 return localstatus;
172 }
173
174 if(localstatus == kSOSConcordanceImNotWorthy) {
175 SOSCreateError(kSOSErrorReplay, CFSTR("Improper inclusion of this peer"), NULL, error);
176 return localstatus;
177 }
178
179 if(!SOSBackupRingPeersInViews(peers, proposedRing)) {
180 return kSOSConcordanceInvalidMembership;
181 }
182
183 return GetSignersStatus_Transitive(peers, knownRing, proposedRing, userPubkey, excludePeerID, error);
184 }
185
186
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);
193 CFReleaseNull(priv);
194 return retval;
195 }
196
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);
205 CFReleaseNull(priv);
206 return retval;
207 }
208
209 static CFDataRef SOSRingGetPayload_Backup(SOSRingRef ring, CFErrorRef *error) {
210 return SOSRingGetPayload_Internal(ring);
211 }
212
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);
220 CFReleaseNull(priv);
221 return retval;
222 }
223
224 CFSetRef SOSBackupRingGetViews(SOSRingRef ring, CFErrorRef *error) {
225 return SOSRingGetBackupViewset_Internal(ring);
226 }
227
228 ringFuncStruct backup = {
229 "Backup",
230 1,
231 SOSRingCreate_Backup,
232 SOSRingResetToEmpty_Backup,
233 SOSRingResetToOffering_Backup,
234 SOSRingDeviceIsInRing_Backup,
235 SOSRingApply_Backup,
236 SOSRingWithdraw_Backup,
237 SOSRingGenerationSign_Backup,
238 SOSRingConcordanceSign_Backup,
239 SOSRingPeerKeyConcordanceTrust_Backup,
240 NULL,
241 NULL,
242 SOSRingSetPayload_Backup,
243 SOSRingGetPayload_Backup,
244 };