]> git.saurik.com Git - apple/security.git/blob - Security/sec/SOSCircle/SecureObjectSync/SOSTransport.c
Security-57031.1.35.tar.gz
[apple/security.git] / Security / sec / SOSCircle / SecureObjectSync / SOSTransport.c
1
2 #include <SecureObjectSync/SOSInternal.h>
3 #include <SecureObjectSync/SOSKVSKeys.h>
4 #include <SecureObjectSync/SOSAccountPriv.h>
5 #include <SecureObjectSync/SOSTransport.h>
6 #include <SecureObjectSync/SOSTransportKeyParameterKVS.h>
7 #include <SecureObjectSync/SOSTransportCircleKVS.h>
8 #include <SecureObjectSync/SOSTransportMessageKVS.h>
9 #include <SOSCloudKeychainClient.h>
10 #include <utilities/debugging.h>
11
12 CFStringRef kKeyParameter = CFSTR("KeyParameter");
13 CFStringRef kCircle = CFSTR("Circle");
14 CFStringRef kMessage = CFSTR("Message");
15 CFStringRef kAlwaysKeys = CFSTR("AlwaysKeys");
16 CFStringRef kFirstUnlocked = CFSTR("FirstUnlockKeys");
17 CFStringRef kUnlocked = CFSTR("UnlockedKeys");
18
19
20
21 CFStringRef SOSInterestListCopyDescription(CFArrayRef interests)
22 {
23 CFMutableStringRef description = CFStringCreateMutable(kCFAllocatorDefault, 0);
24 CFStringAppendFormat(description, NULL, CFSTR("<Interest: "));
25
26 CFArrayForEach(interests, ^(const void* string) {
27 if (isString(string))
28 CFStringAppendFormat(description, NULL, CFSTR(" '%@'"), string);
29 });
30 CFStringAppend(description, CFSTR(">"));
31
32 return description;
33 }
34
35
36 //
37 // MARK: Key Interest Processing
38 //
39
40 CFGiblisGetSingleton(CFMutableArrayRef, SOSGetTransportMessages, sTransportMessages, ^{
41 *sTransportMessages = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL);
42 });
43
44 CFGiblisGetSingleton(CFMutableArrayRef, SOSGetTransportKeyParameters, sTransportKeyParameters, ^{
45 *sTransportKeyParameters = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL);
46 });
47
48 CFGiblisGetSingleton(CFMutableArrayRef, SOSGetTransportCircles, sTransportCircles, ^{
49 *sTransportCircles = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL);
50 });
51
52
53 void SOSRegisterTransportMessage(SOSTransportMessageRef additional) {
54 CFArrayAppendValue(SOSGetTransportMessages(), additional);
55 }
56
57 void SOSUnregisterTransportMessage(SOSTransportMessageRef removal) {
58 CFArrayRemoveAllValue(SOSGetTransportMessages(), removal);
59 }
60
61 void SOSUnregisterAllTransportMessages() {
62 CFArrayRemoveAllValues(SOSGetTransportMessages());
63 }
64
65 void SOSRegisterTransportCircle(SOSTransportCircleRef additional) {
66 CFArrayAppendValue(SOSGetTransportCircles(), additional);
67 }
68
69 void SOSUnregisterTransportCircle(SOSTransportCircleRef removal) {
70 CFArrayRemoveAllValue(SOSGetTransportCircles(), removal);
71 }
72
73 void SOSUnregisterAllTransportCircles() {
74 CFArrayRemoveAllValues(SOSGetTransportCircles());
75 }
76
77 void SOSRegisterTransportKeyParameter(SOSTransportKeyParameterRef additional) {
78 CFArrayAppendValue(SOSGetTransportKeyParameters(), additional);
79 }
80
81 void SOSUnregisterTransportKeyParameter(SOSTransportKeyParameterRef removal) {
82 CFArrayRemoveAllValue(SOSGetTransportKeyParameters(), removal);
83 }
84
85 void SOSUnregisterAllTransportKeyParameters() {
86 CFArrayRemoveAllValues(SOSGetTransportKeyParameters());
87 }
88
89 //
90 // Should we be dispatching back to our queue to handle later
91 //
92 void SOSUpdateKeyInterest(void)
93 {
94 CFMutableArrayRef alwaysKeys = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
95 CFMutableArrayRef afterFirstUnlockKeys = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
96 CFMutableArrayRef whenUnlockedKeys = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
97 CFMutableDictionaryRef keyDict = CFDictionaryCreateMutableForCFTypes (kCFAllocatorDefault);
98
99 CFArrayForEach(SOSGetTransportKeyParameters(), ^(const void *value) {
100 SOSTransportKeyParameterKVSRef tkvs = (SOSTransportKeyParameterKVSRef) value;
101 CFErrorRef localError = NULL;
102
103 if (!SOSTransportKeyParameterKVSAppendKeyInterests(tkvs, alwaysKeys, afterFirstUnlockKeys, whenUnlockedKeys, &localError)) {
104 secerror("Error getting key parameters interests %@", localError);
105 }
106 CFReleaseNull(localError);
107 });
108 CFMutableDictionaryRef keyParamsDict = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
109 CFDictionarySetValue(keyParamsDict, kAlwaysKeys, alwaysKeys);
110 CFDictionarySetValue(keyParamsDict, kFirstUnlocked, afterFirstUnlockKeys);
111 CFDictionarySetValue(keyParamsDict, kUnlocked, whenUnlockedKeys);
112 CFDictionarySetValue(keyDict, kKeyParameter, keyParamsDict);
113 CFErrorRef updateError = NULL;
114 CFReleaseNull(alwaysKeys);
115 CFReleaseNull(afterFirstUnlockKeys);
116 CFReleaseNull(whenUnlockedKeys);
117 alwaysKeys = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
118 afterFirstUnlockKeys = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
119 whenUnlockedKeys = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
120
121 CFArrayForEach(SOSGetTransportCircles(), ^(const void *value) {
122 SOSTransportCircleKVSRef tkvs = (SOSTransportCircleKVSRef) value;
123 CFErrorRef localError = NULL;
124
125 if(!SOSTransportCircleKVSAppendKeyInterest(tkvs, alwaysKeys, afterFirstUnlockKeys, whenUnlockedKeys, &localError)){
126 secerror("Error getting circle interests %@", localError);
127 }
128 CFReleaseNull(localError);
129
130 });
131 CFMutableDictionaryRef circleDict = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
132 CFDictionarySetValue(circleDict, kAlwaysKeys, alwaysKeys);
133 CFDictionarySetValue(circleDict, kFirstUnlocked, afterFirstUnlockKeys);
134 CFDictionarySetValue(circleDict, kUnlocked, whenUnlockedKeys);
135 CFDictionarySetValue(keyDict, kCircle, circleDict);
136
137 CFReleaseNull(alwaysKeys);
138 CFReleaseNull(afterFirstUnlockKeys);
139 CFReleaseNull(whenUnlockedKeys);
140 alwaysKeys = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
141 afterFirstUnlockKeys = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
142 whenUnlockedKeys = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
143
144 CFArrayForEach(SOSGetTransportMessages(), ^(const void *value) {
145 SOSTransportMessageKVSRef tkvs = (SOSTransportMessageKVSRef) value;
146 CFErrorRef localError = NULL;
147
148 if(!SOSTransportMessageKVSAppendKeyInterest(tkvs, alwaysKeys, afterFirstUnlockKeys, whenUnlockedKeys, &localError)){
149 secerror("Error getting message interests %@", localError);
150 }
151 CFReleaseNull(localError);
152
153 });
154
155 CFMutableDictionaryRef messageDict = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
156 CFDictionarySetValue(messageDict, kAlwaysKeys, alwaysKeys);
157 CFDictionarySetValue(messageDict, kFirstUnlocked, afterFirstUnlockKeys);
158 CFDictionarySetValue(messageDict, kUnlocked, whenUnlockedKeys);
159 CFDictionarySetValue(keyDict, kMessage, messageDict);
160
161 CFReleaseNull(alwaysKeys);
162 CFReleaseNull(afterFirstUnlockKeys);
163 CFReleaseNull(whenUnlockedKeys);
164 alwaysKeys = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
165 afterFirstUnlockKeys = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
166 whenUnlockedKeys = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
167
168
169 if (!SOSCloudKeychainUpdateKeys(keyDict, &updateError))
170 {
171 secerror("Error updating keys: %@", updateError);
172 // TODO: propagate error(s) to callers.
173 } else {
174 if (CFArrayGetCount(whenUnlockedKeys) == 0) {
175 secnotice("sync", "Unlocked keys were empty!");
176 }
177 // This leaks 3 CFStringRefs in DEBUG builds.
178 CFStringRef alwaysKeysDesc = SOSInterestListCopyDescription(alwaysKeys);
179 CFStringRef afterFirstUnlockKeysDesc = SOSInterestListCopyDescription(afterFirstUnlockKeys);
180 CFStringRef unlockedKeysDesc = SOSInterestListCopyDescription(whenUnlockedKeys);
181 secdebug("sync", "Updating interest: always: %@,\nfirstUnlock: %@,\nunlockedKeys: %@",
182 alwaysKeysDesc,
183 afterFirstUnlockKeysDesc,
184 unlockedKeysDesc);
185 CFReleaseNull(alwaysKeysDesc);
186 CFReleaseNull(afterFirstUnlockKeysDesc);
187 CFReleaseNull(unlockedKeysDesc);
188 }
189
190 CFReleaseNull(updateError);
191 CFReleaseNull(alwaysKeys);
192 CFReleaseNull(afterFirstUnlockKeys);
193 CFReleaseNull(whenUnlockedKeys);
194 CFReleaseNull(keyParamsDict);
195 CFReleaseNull(circleDict);
196 CFReleaseNull(messageDict);
197 CFReleaseNull(keyDict);
198 }
199
200
201 static void showWhatWasHandled(CFDictionaryRef updates, CFMutableArrayRef handledKeys) {
202
203 CFMutableStringRef updateStr = CFStringCreateMutable(kCFAllocatorDefault, 0);
204 CFMutableStringRef handledKeysStr = CFStringCreateMutable(kCFAllocatorDefault, 0);
205
206 CFDictionaryForEach(updates, ^(const void *key, const void *value) {
207 if (isString(key)) {
208 CFStringAppendFormat(updateStr, NULL, CFSTR("%@ "), (CFStringRef)key);
209 }
210 });
211 CFArrayForEach(handledKeys, ^(const void *value) {
212 if (isString(value)) {
213 CFStringAppendFormat(handledKeysStr, NULL, CFSTR("%@ "), (CFStringRef)value);
214 }
215 });
216 secnotice("updates", "Updates [%ld]: %@\n", CFDictionaryGetCount(updates), updateStr);
217 secnotice("updates", "Handled [%ld]: %@\n", CFArrayGetCount(handledKeys), handledKeysStr);
218 // secnotice("updates", "Updates: %@\n", updates);
219 // secnotice("updates", "Handled: %@\n", handledKeys);
220
221 CFReleaseSafe(updateStr);
222 CFReleaseSafe(handledKeysStr);
223 }
224
225 CF_RETURNS_RETAINED
226 CFMutableArrayRef SOSTransportDispatchMessages(SOSAccountRef account, CFDictionaryRef updates, CFErrorRef *error){
227
228 CFMutableArrayRef handledKeys = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
229
230 if(CFDictionaryContainsKey(updates, kSOSKVSAccountChangedKey)){
231 // While changing accounts we may modify the key params array. To avoid stepping on ourselves we
232 // copy the list for iteration.
233 CFArrayRef originalKeyParams = CFArrayCreateCopy(kCFAllocatorDefault, SOSGetTransportKeyParameters());
234 CFArrayForEach(originalKeyParams, ^(const void *value) {
235 SOSTransportKeyParameterRef tkvs = (SOSTransportKeyParameterRef) value;
236 if( (SOSTransportKeyParameterGetAccount((SOSTransportKeyParameterRef)value), account)){
237 SOSTransportKeyParameterHandleNewAccount(tkvs);
238 }
239 });
240 CFReleaseNull(originalKeyParams);
241 CFArrayAppendValue(handledKeys, kSOSKVSAccountChangedKey);
242 }
243
244 // Iterate through keys in updates. Perform circle change update.
245 // Then instantiate circles and engines and peers for all peers that
246 // are receiving a message in updates.
247 CFMutableDictionaryRef circle_peer_messages_table = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
248 CFMutableDictionaryRef circle_circle_messages_table = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
249 CFMutableDictionaryRef circle_retirement_messages_table = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
250 __block CFDataRef newParameters = NULL;
251 __block bool initial_sync = false;
252 __block bool new_account = false;
253
254 CFDictionaryForEach(updates, ^(const void *key, const void *value) {
255 CFErrorRef localError = NULL;
256 CFStringRef circle_name = NULL;
257 CFStringRef from_name = NULL;
258 CFStringRef to_name = NULL;
259 switch (SOSKVSKeyGetKeyTypeAndParse(key, &circle_name, &from_name, &to_name)) {
260 case kCircleKey:
261 CFDictionarySetValue(circle_circle_messages_table, circle_name, value);
262 break;
263 case kInitialSyncKey:
264 initial_sync = true;
265 break;
266 case kParametersKey:
267 if (isData(value)) {
268 newParameters = (CFDataRef) CFRetainSafe(value);
269 }
270 break;
271 case kMessageKey: {
272 CFMutableDictionaryRef circle_messages = CFDictionaryEnsureCFDictionaryAndGetCurrentValue(circle_peer_messages_table, circle_name);
273 CFDictionarySetValue(circle_messages, from_name, value);
274 break;
275 }
276 case kRetirementKey: {
277 CFMutableDictionaryRef circle_retirements = CFDictionaryEnsureCFDictionaryAndGetCurrentValue(circle_retirement_messages_table, circle_name);
278 CFDictionarySetValue(circle_retirements, from_name, value);
279 break;
280 }
281 case kAccountChangedKey:
282 new_account = true;
283 break;
284
285 case kUnknownKey:
286 secnotice("updates", "Unknown key '%@', ignoring", key);
287 break;
288
289 }
290
291 CFReleaseNull(circle_name);
292 CFReleaseNull(from_name);
293 CFReleaseNull(to_name);
294
295 if (error && *error)
296 secerror("Peer message processing error for: %@ -> %@ (%@)", key, value, *error);
297 if (localError)
298 secerror("Peer message local processing error for: %@ -> %@ (%@)", key, value, localError);
299
300 CFReleaseNull(localError);
301 });
302
303
304 if (newParameters) {
305 CFArrayForEach(SOSGetTransportKeyParameters(), ^(const void *value) {
306 SOSTransportKeyParameterRef tkvs = (SOSTransportKeyParameterRef) value;
307 CFErrorRef localError = NULL;
308 if(CFEqualSafe(SOSTransportKeyParameterGetAccount(tkvs), account)){
309 if(!SOSTransportKeyParameterHandleKeyParameterChanges(tkvs, newParameters, localError))
310 secerror("Transport failed to handle new key parameters: %@", localError);
311 }
312 });
313 CFArrayAppendValue(handledKeys, kSOSKVSKeyParametersKey);
314 }
315 CFReleaseNull(newParameters);
316
317 if(initial_sync){
318 CFArrayAppendValue(handledKeys, kSOSKVSInitialSyncKey);
319 }
320
321
322 if(CFDictionaryGetCount(circle_retirement_messages_table)) {
323 CFArrayForEach(SOSGetTransportCircles(), ^(const void *value) {
324 SOSTransportCircleRef tkvs = (SOSTransportCircleRef) value;
325 if(CFEqualSafe(SOSTransportCircleGetAccount((SOSTransportCircleRef)value), account)){
326 CFErrorRef localError = NULL;
327 CFDictionaryRef handledRetirementKeys = SOSTransportCircleHandleRetirementMessages(tkvs, circle_retirement_messages_table, error);
328 if(handledRetirementKeys == NULL){
329 secerror("Transport failed to handle retirement messages: %@", localError);
330 } else {
331 CFDictionaryForEach(handledRetirementKeys, ^(const void *key, const void *value) {
332 CFStringRef circle_name = (CFStringRef)key;
333 CFArrayRef handledPeerIDs = (CFArrayRef)value;
334 CFArrayForEach(handledPeerIDs, ^(const void *value) {
335 CFStringRef peer_id = (CFStringRef)value;
336 CFStringRef keyHandled = SOSRetirementKeyCreateWithCircleNameAndPeer(circle_name, peer_id);
337 CFArrayAppendValue(handledKeys, keyHandled);
338 CFReleaseNull(keyHandled);
339 });
340 });
341 }
342 CFReleaseNull(handledRetirementKeys);
343 CFReleaseNull(localError);
344 }
345 });
346 }
347
348 if(CFDictionaryGetCount(circle_circle_messages_table)) {
349 CFArrayForEach(SOSGetTransportCircles(), ^(const void *value) {
350 SOSTransportCircleRef tkvs = (SOSTransportCircleRef) value;
351 if(CFEqualSafe(SOSTransportCircleGetAccount((SOSTransportCircleRef)value), account)){
352 CFArrayRef handleCircleMessages = SOSTransportCircleHandleCircleMessages(tkvs, circle_circle_messages_table, error);
353 CFErrorRef localError = NULL;
354 if(handleCircleMessages == NULL){
355 secerror("Transport failed to handle circle messages: %@", localError);
356 } else if(CFArrayGetCount(handleCircleMessages) == 0) {
357 if(CFDictionaryGetCount(circle_circle_messages_table) != 0) {
358 secerror("Transport failed to process all circle messages: (%ld/%ld) %@",
359 CFArrayGetCount(handleCircleMessages),
360 CFDictionaryGetCount(circle_circle_messages_table), localError);
361 } else {
362 secnotice("circle", "Transport handled no circle messages");
363 }
364 } else {
365 CFArrayForEach(handleCircleMessages, ^(const void *value) {
366 CFStringRef keyHandled = SOSCircleKeyCreateWithName((CFStringRef)value, error);
367 CFArrayAppendValue(handledKeys, keyHandled);
368 CFReleaseNull(keyHandled);
369 });
370 }
371 CFReleaseNull(localError);
372
373 if (!SOSTransportCircleFlushChanges(tkvs, &localError))
374 secerror("error flushing changes: %@", localError);
375
376 CFReleaseNull(localError);
377 CFReleaseNull(handleCircleMessages);
378 }
379
380 });
381 }
382 // TODO: These should all produce circle -> messageTypeHandled messages
383 // That probably needs to wait for separation of transport types.
384 if(CFDictionaryGetCount(circle_peer_messages_table)) {
385 CFArrayForEach(SOSGetTransportMessages(), ^(const void *value) {
386 SOSTransportMessageRef tkvs = (SOSTransportMessageRef) value;
387 if(CFEqualSafe(SOSTransportMessageGetAccount((SOSTransportMessageRef)value), account)){
388 CFErrorRef handleMessagesError = NULL;
389 CFDictionaryRef handledPeers = SOSTransportMessageHandleMessages(tkvs, circle_peer_messages_table, &handleMessagesError);
390
391 if (handledPeers) {
392 // We need to look for and send responses.
393
394 CFErrorRef syncError = NULL;
395 if (!SOSTransportMessageSyncWithPeers((SOSTransportMessageRef)tkvs, handledPeers, &syncError)) {
396 secerror("Sync with peers failed: %@", syncError);
397 }
398
399 CFDictionaryForEach(handledPeers, ^(const void *key, const void *value) {
400 if (isString(key) && isArray(value)) {
401 CFArrayForEach(value, ^(const void *value) {
402 if (isString(value)) {
403 CFStringRef peerID = (CFStringRef) value;
404
405 CFStringRef kvsHandledKey = SOSMessageKeyCreateFromPeerToTransport((SOSTransportMessageKVSRef)tkvs, peerID);
406 CFArrayAppendValue(handledKeys, kvsHandledKey);
407 CFReleaseSafe(kvsHandledKey);
408 }
409 });
410 }
411 });
412
413 CFErrorRef flushError = NULL;
414 if (!SOSTransportMessageFlushChanges((SOSTransportMessageRef)tkvs, &flushError)) {
415 secerror("Flush failed: %@", flushError);
416 }
417 }
418 else {
419 secerror("Didn't handle? : %@", handleMessagesError);
420 }
421 CFReleaseNull(handledPeers);
422 CFReleaseNull(handleMessagesError);
423 }
424 });
425 }
426 CFReleaseNull(circle_retirement_messages_table);
427 CFReleaseNull(circle_circle_messages_table);
428 CFReleaseNull(circle_peer_messages_table);
429
430
431
432 showWhatWasHandled(updates, handledKeys);
433
434 return handledKeys;
435 }
436
437