]> git.saurik.com Git - apple/security.git/blob - OSX/sec/ProjectHeaders/Security/SecureObjectSync/SOSRingBackup.c
Security-57336.1.9.tar.gz
[apple/security.git] / OSX / sec / ProjectHeaders / Security / 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 static bool CFSetIsSubset(CFSetRef little, CFSetRef big) {
132 __block bool retval = true;
133 CFSetForEach(little, ^(const void *value) {
134 if(!CFSetContainsValue(big, value)) retval = false;
135 });
136 return retval;
137 }
138
139 // Make sure that the ring includes me if I'm enabled for its view.
140 static SOSConcordanceStatus SOSBackupRingEvaluateMyInclusion(SOSRingRef ring, SOSFullPeerInfoRef me) {
141 bool shouldBeInRing = false;
142 bool amInThisRing = false;
143
144 if (me) {
145 SOSPeerInfoRef pi = SOSFullPeerInfoGetPeerInfo(me);
146 CFStringRef peerID = SOSPeerInfoGetPeerID(pi);
147 CFSetRef ringViews = SOSRingGetBackupViewset_Internal(ring);
148 CFSetRef piViews = SOSPeerInfoGetPermittedViews(pi);
149 shouldBeInRing = CFSetIsSubset(ringViews, piViews);
150 amInThisRing = SOSRingHasPeerWithID(ring, peerID, NULL);
151 }
152
153 if(shouldBeInRing && !amInThisRing) return kSOSConcordanceMissingMe;
154 if(!shouldBeInRing && amInThisRing) return kSOSConcordanceImNotWorthy;
155 return kSOSConcordanceTrusted;
156 }
157
158 static SOSConcordanceStatus SOSRingPeerKeyConcordanceTrust_Backup(SOSFullPeerInfoRef me, CFSetRef peers, SOSRingRef knownRing, SOSRingRef proposedRing,
159 __unused SecKeyRef knownPubkey, SecKeyRef userPubkey,
160 CFStringRef excludePeerID, CFErrorRef *error) {
161 if(userPubkey == NULL) {
162 SOSCreateError(kSOSErrorPublicKeyAbsent, CFSTR("Concordance with no public key - need to validate application"), NULL, error);
163 return kSOSConcordanceNoUserKey;
164 }
165
166 if(SOSRingIsOlderGeneration(knownRing, proposedRing)) {
167 SOSCreateError(kSOSErrorReplay, CFSTR("Bad generation"), NULL, error);
168 return kSOSConcordanceGenOld;
169 }
170
171 SOSConcordanceStatus localstatus = SOSBackupRingEvaluateMyInclusion(proposedRing, me);
172 if(localstatus == kSOSConcordanceMissingMe) {
173 SOSCreateError(kSOSErrorReplay, CFSTR("Improper exclusion of this peer"), NULL, error);
174 return localstatus;
175 }
176
177 if(localstatus == kSOSConcordanceImNotWorthy) {
178 SOSCreateError(kSOSErrorReplay, CFSTR("Improper inclusion of this peer"), NULL, error);
179 return localstatus;
180 }
181
182 if (SOSRingIsEmpty_Internal(proposedRing)) {
183 return kSOSConcordanceTrusted;
184 }
185
186 if(!SOSBackupRingPeersInViews(peers, proposedRing)) {
187 return kSOSConcordanceInvalidMembership;
188 }
189
190 return GetSignersStatus_Transitive(peers, knownRing, proposedRing, userPubkey, excludePeerID, error);
191 }
192
193
194 static bool SOSRingConcordanceSign_Backup(SOSRingRef ring, SOSFullPeerInfoRef requestor, CFErrorRef *error) {
195 CFStringRef myPeerID = SOSPeerInfoGetPeerID(SOSFullPeerInfoGetPeerInfo(requestor));
196 SecKeyRef priv = SOSFullPeerInfoCopyDeviceKey(requestor, error);
197 bool retval = priv && myPeerID &&
198 SOSRingSetLastModifier(ring, myPeerID) &&
199 SOSRingConcordanceSign_Internal(ring, priv, error);
200 CFReleaseNull(priv);
201 return retval;
202 }
203
204 static bool SOSRingSetPayload_Backup(SOSRingRef ring, SecKeyRef user_privkey, CFDataRef payload, SOSFullPeerInfoRef requestor, CFErrorRef *error) {
205 CFStringRef myPeerID = SOSPeerInfoGetPeerID(SOSFullPeerInfoGetPeerInfo(requestor));
206 SecKeyRef priv = SOSFullPeerInfoCopyDeviceKey(requestor, error);
207 bool retval = priv && myPeerID &&
208 SOSRingSetLastModifier(ring, myPeerID) &&
209 SOSRingSetPayload_Internal(ring, payload) &&
210 SOSRingGenerationSign_Internal(ring, priv, error);
211 if(user_privkey) SOSRingConcordanceSign_Internal(ring, user_privkey, error);
212 CFReleaseNull(priv);
213 return retval;
214 }
215
216 static CFDataRef SOSRingGetPayload_Backup(SOSRingRef ring, CFErrorRef *error) {
217 return SOSRingGetPayload_Internal(ring);
218 }
219
220 bool SOSBackupRingSetViews(SOSRingRef ring, SOSFullPeerInfoRef requestor, CFSetRef viewSet, CFErrorRef *error) {
221 CFStringRef myPeerID = SOSPeerInfoGetPeerID(SOSFullPeerInfoGetPeerInfo(requestor));
222 SecKeyRef priv = SOSFullPeerInfoCopyDeviceKey(requestor, error);
223 bool retval = priv && myPeerID &&
224 SOSRingSetLastModifier(ring, myPeerID) &&
225 SOSRingSetBackupViewset_Internal(ring, viewSet) &&
226 SOSRingGenerationSign_Internal(ring, priv, error);
227 CFReleaseNull(priv);
228 return retval;
229 }
230
231 CFSetRef SOSBackupRingGetViews(SOSRingRef ring, CFErrorRef *error) {
232 return SOSRingGetBackupViewset_Internal(ring);
233 }
234
235 ringFuncStruct backup = {
236 "Backup",
237 1,
238 SOSRingCreate_Backup,
239 SOSRingResetToEmpty_Backup,
240 SOSRingResetToOffering_Backup,
241 SOSRingDeviceIsInRing_Backup,
242 SOSRingApply_Backup,
243 SOSRingWithdraw_Backup,
244 SOSRingGenerationSign_Backup,
245 SOSRingConcordanceSign_Backup,
246 SOSRingPeerKeyConcordanceTrust_Backup,
247 NULL,
248 NULL,
249 SOSRingSetPayload_Backup,
250 SOSRingGetPayload_Backup,
251 };