]> git.saurik.com Git - apple/security.git/blob - keychain/SecureObjectSync/SOSTransportCircleKVS.m
Security-59754.41.1.tar.gz
[apple/security.git] / keychain / SecureObjectSync / SOSTransportCircleKVS.m
1 //
2 // SOSTransportCircleKVS.c
3 // sec
4 //
5 #include "keychain/SecureObjectSync/SOSTransport.h"
6 #include "keychain/SecureObjectSync/SOSTransportCircle.h"
7 #include "keychain/SecureObjectSync/SOSTransportCircleKVS.h"
8 #include "keychain/SecureObjectSync/SOSKVSKeys.h"
9 #include "keychain/SecureObjectSync/SOSInternal.h"
10 #include "keychain/SecureObjectSync/CKBridge/SOSCloudKeychainClient.h"
11 #include <utilities/SecCFWrappers.h>
12 #import "keychain/SecureObjectSync/SOSAccountTrustClassic.h"
13
14
15 @implementation SOSKVSCircleStorageTransport
16
17 @synthesize pending_changes = pending_changes;
18 @synthesize circleName = circleName;
19 extern CFStringRef kSOSAccountDebugScope;
20
21 -(id)init
22 {
23 return [super init];
24 }
25
26 -(id)initWithAccount:(SOSAccount*)acct andCircleName:(NSString*)name
27 {
28 if ((self = [super init])) {
29 self.pending_changes = [NSMutableDictionary dictionary];
30 self.circleName = [[NSString alloc] initWithString:name];
31 self.account = acct;
32 SOSRegisterTransportCircle(self);
33 }
34 return self;
35 }
36
37 -(NSString*) getCircleName
38 {
39 return self.circleName;
40 }
41
42 -(CFIndex) getTransportType{
43 return kKVS;
44 }
45
46 static bool SOSTransportCircleKVSUpdateKVS(NSDictionary *changes, CFErrorRef *error)
47 {
48 CloudKeychainReplyBlock log_error = ^(CFDictionaryRef returnedValues __unused, CFErrorRef block_error) {
49 if (block_error) {
50 secerror("Error putting: %@", block_error);
51 }
52 };
53
54 SOSCloudKeychainPutObjectsInCloud((__bridge CFDictionaryRef)(changes), dispatch_get_global_queue(SOS_TRANSPORT_PRIORITY, 0), log_error);
55 return true;
56 }
57
58 -(bool)kvsSendPendingChanges:(CFErrorRef *)error
59 {
60 CFErrorRef changeError = NULL;
61
62 if (self.pending_changes == NULL || [self.pending_changes count] == 0) {
63 return true;
64 }
65
66 CFTypeRef dsid = SOSAccountGetValue(account, kSOSDSIDKey, error);
67 if(dsid == NULL)
68 dsid = kCFNull;
69
70 [self.pending_changes setObject:(__bridge id _Nonnull)((void*)(dsid)) forKey:(__bridge NSString*)kSOSKVSRequiredKey];
71
72 bool success = SOSTransportCircleKVSUpdateKVS(self.pending_changes, &changeError);
73 if (success) {
74 [self.pending_changes removeAllObjects];
75 } else {
76 SOSCreateErrorWithFormat(kSOSErrorSendFailure, changeError, error, NULL,
77 CFSTR("Send changes block failed [%@]"), self.pending_changes);
78 }
79
80 return success;
81 }
82
83 -(void)kvsAddToPendingChanges:(CFStringRef) message_key data:(CFDataRef)message_data
84 {
85 if (self.pending_changes == NULL) {
86 self.pending_changes = [NSMutableDictionary dictionary];
87 }
88 if (message_data == NULL) {
89 [self.pending_changes setObject:[NSNull null] forKey:(__bridge NSString*)message_key];
90 } else {
91 [self.pending_changes setObject:(__bridge NSData*)message_data forKey:(__bridge NSString*)message_key];
92 }
93 }
94
95 static bool SOSTransportCircleKVSUpdateRetirementRecords(CFDictionaryRef updates, CFErrorRef* error){
96 CFErrorRef updateError = NULL;
97 bool success = false;
98 if (SOSTransportCircleKVSUpdateKVS((__bridge NSDictionary*)updates, &updateError)){
99 success = true;
100 } else {
101 SOSCreateErrorWithFormat(kSOSErrorSendFailure, updateError, error, NULL,
102 CFSTR("update parameters key failed [%@]"), updates);
103 }
104 return success;
105 }
106 -(bool) expireRetirementRecords:(CFDictionaryRef) retirements err:(CFErrorRef *)error
107 {
108 bool success = true;
109 CFMutableDictionaryRef keysToWrite = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
110
111 CFDictionaryForEach(retirements, ^(const void *key, const void *value) {
112 if (isString(key) && isArray(value)) {
113 CFStringRef circle_name = (CFStringRef) key;
114 CFArrayRef retirees = (CFArrayRef) value;
115
116 CFArrayForEach(retirees, ^(const void *value) {
117 if (isString(value)) {
118 CFStringRef retiree_id = (CFStringRef) value;
119
120 CFStringRef kvsKey = SOSRetirementKeyCreateWithCircleNameAndPeer(circle_name, retiree_id);
121
122 CFDictionaryAddValue(keysToWrite, kvsKey, kCFNull);
123
124 CFReleaseSafe(kvsKey);
125 }
126 });
127 }
128 });
129
130 if(CFDictionaryGetCount(keysToWrite)) {
131 success = SOSTransportCircleKVSUpdateRetirementRecords(keysToWrite, error);
132 }
133 CFReleaseNull(keysToWrite);
134
135 return success;
136 }
137
138 -(bool) flushChanges:(CFErrorRef *)error
139 {
140 return [self kvsSendPendingChanges:error];
141
142 }
143
144 -(bool) postCircle:(CFStringRef)name circleData:(CFDataRef)circle_data err:(CFErrorRef *)error
145 {
146 CFStringRef circle_key = SOSCircleKeyCreateWithName(name, error);
147 if (circle_key)
148 [self kvsAddToPendingChanges:circle_key data:circle_data];
149
150 CFReleaseNull(circle_key);
151
152 return true;
153 }
154
155 -(CFDictionaryRef)CF_RETURNS_RETAINED handleRetirementMessages:(CFMutableDictionaryRef) circle_retirement_messages_table err:(CFErrorRef *)error
156 {
157 return SOSAccountHandleRetirementMessages(self.account, circle_retirement_messages_table, error);
158 }
159
160 -(CFArrayRef)CF_RETURNS_RETAINED handleCircleMessagesAndReturnHandledCopy:(CFMutableDictionaryRef) circle_circle_messages_table err:(CFErrorRef *)error
161 {
162 CFMutableArrayRef handledKeys = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
163 CFDictionaryForEach(circle_circle_messages_table, ^(const void *key, const void *value) {
164 CFErrorRef circleMessageError = NULL;
165 if(!isString(key) || !isData(value)) {
166 secerror("Error, Key-Value for CircleMessage was not CFString/CFData");
167 } if (!SOSAccountHandleCircleMessage(self.account, key, value, &circleMessageError)) {
168 secerror("Error handling circle message %@ (%@): %@", key, value, circleMessageError);
169 } else{
170 CFStringRef circle_id = (CFStringRef) key;
171 CFArrayAppendValue(handledKeys, circle_id);
172 }
173 CFReleaseNull(circleMessageError);
174 });
175
176 return handledKeys;
177 }
178
179 -(bool)kvsAppendKeyInterest:(CFMutableArrayRef) alwaysKeys firstUnlock:(CFMutableArrayRef) afterFirstUnlockKeys unlocked:(CFMutableArrayRef)unlockedKeys err:(CFErrorRef *)error
180 {
181 CFStringRef circle_name = NULL;
182 CFStringRef circle_key = NULL;
183
184 if(SOSAccountHasPublicKey(self.account, NULL)){
185 require_quiet(circle_name = (__bridge CFStringRef)self.circleName, fail);
186 require_quiet(circle_key = SOSCircleKeyCreateWithName(circle_name, error), fail);
187
188 require_quiet(account, fail);
189 SOSAccountTrustClassic *trust = account.trust;
190 SOSCircleRef circle = trust.trustedCircle;
191 require_quiet(circle && CFEqualSafe(circle_name, SOSCircleGetName(circle)), fail);
192
193 SOSCircleForEachActivePeer(circle, ^(SOSPeerInfoRef peer) {
194 CFStringRef retirement_key = SOSRetirementKeyCreateWithCircleNameAndPeer(circle_name, SOSPeerInfoGetPeerID(peer));
195 CFArrayAppendValue(alwaysKeys, retirement_key);
196 CFReleaseNull(retirement_key);
197 });
198
199 CFArrayAppendValue(unlockedKeys, circle_key); // This is where circle interest is handled
200
201 CFReleaseNull(circle_key);
202 }
203 return true;
204
205 fail:
206 CFReleaseNull(circle_key);
207 return false;
208 }
209
210 //register ring key
211 -(bool)kvsAppendRingKeyInterest:(CFMutableArrayRef) alwaysKeys firstUnlock:(CFMutableArrayRef)afterFirstUnlockKeys unlocked:(CFMutableArrayRef) unlockedKeys err:(CFErrorRef *)error
212 {
213 if(SOSAccountHasPublicKey(self.account, NULL)){
214 require_quiet(account, fail);
215 SOSAccountTrustClassic *trust = account.trust;
216 SOSCircleRef circle = trust.trustedCircle;
217 require_quiet(circle, fail);
218
219 // Always interested in backup rings:
220 SOSAccountForEachRingName(account, ^(CFStringRef ringName) {
221 CFStringRef ring_key = SOSRingKeyCreateWithRingName(ringName);
222 CFArrayAppendValue(unlockedKeys, ring_key);
223 CFReleaseNull(ring_key);
224 });
225 }
226 return true;
227 fail:
228 return false;
229 }
230
231 //register debug scope key
232 -(bool)kvsAppendDebugKeyInterest:(CFMutableArrayRef) alwaysKeys firstUnlock:(CFMutableArrayRef)afterFirstUnlockKeys unlocked:(CFMutableArrayRef) unlockedKeys err:(CFErrorRef *)error
233 {
234 CFStringRef key = SOSDebugInfoKeyCreateWithTypeName(kSOSAccountDebugScope);
235 CFArrayAppendValue(alwaysKeys, key);
236 CFReleaseNull(key);
237 return true;
238 }
239
240 //send debug info over KVS
241 -(bool) kvssendDebugInfo:(CFStringRef) type debug:(CFTypeRef) debugInfo err:(CFErrorRef *)error
242 {
243 CFStringRef key = SOSDebugInfoKeyCreateWithTypeName(type);
244 NSDictionary *changes = @{(__bridge NSString*)key:(__bridge id _Nonnull)debugInfo};
245
246 CFReleaseNull(key);
247 bool success = SOSTransportCircleKVSUpdateKVS(changes, error);
248
249 return success;
250 }
251
252 -(bool) kvsSendAccountChangedWithDSID:(CFStringRef) dsid err:(CFErrorRef *)error
253 {
254 NSDictionary *changes = @{(__bridge NSString*)kSOSKVSAccountChangedKey:(__bridge NSString*)dsid};
255
256 bool success = SOSTransportCircleKVSUpdateKVS(changes, error);
257
258
259 return success;
260 }
261
262 //send the Ring over KVS
263 -(bool) kvsRingPostRing:(CFStringRef) ringName ring:(CFDataRef) ring err:(CFErrorRef *)error
264 {
265 CFStringRef ringKey = SOSRingKeyCreateWithName(ringName, error);
266
267 if(ringKey)
268 [self kvsAddToPendingChanges:ringKey data:ring];
269
270 CFReleaseNull(ringKey);
271
272 return true;
273 }
274
275 -(bool) kvsRingFlushChanges:(CFErrorRef*) error
276 {
277 return [self kvsSendPendingChanges:error];
278 }
279
280 -(bool) kvsSendOfficialDSID:(CFStringRef) dsid err:(CFErrorRef *)error
281 {
282 NSDictionary *changes = @{(__bridge NSString*)kSOSKVSOfficialDSIDKey : (__bridge NSString*)dsid};
283 bool success = SOSTransportCircleKVSUpdateKVS(changes, error);
284 return success;
285 }
286
287 -(bool) postRetirement:(CFStringRef)circleName peer:(SOSPeerInfoRef)peer err:(CFErrorRef *)error
288 {
289 CFDataRef retirement_data = SOSPeerInfoCopyEncodedData(peer, kCFAllocatorDefault, error);
290
291 require_quiet(retirement_data, fail);
292
293 CFStringRef retirement_key = SOSRetirementKeyCreateWithCircleNameAndPeer((__bridge CFStringRef)(self.circleName), SOSPeerInfoGetPeerID(peer));
294 if (retirement_key)
295 [self kvsAddToPendingChanges:retirement_key data:retirement_data];
296
297 CFReleaseNull(retirement_key);
298 CFReleaseNull(retirement_data);
299 return true;
300 fail:
301 CFReleaseNull(retirement_data);
302 return true;
303 }
304 @end
305