]> git.saurik.com Git - apple/security.git/blob - Security/sec/SOSCircle/SecureObjectSync/SOSTransport.c
Security-57031.10.10.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 secnotice("accountChange", "SOSTransportDispatchMessages received kSOSKVSAccountChangedKey");
232 // While changing accounts we may modify the key params array. To avoid stepping on ourselves we
233 // copy the list for iteration.
234 CFArrayRef originalKeyParams = CFArrayCreateCopy(kCFAllocatorDefault, SOSGetTransportKeyParameters());
235 CFArrayForEach(originalKeyParams, ^(const void *value) {
236 SOSTransportKeyParameterRef tkvs = (SOSTransportKeyParameterRef) value;
237 if( (SOSTransportKeyParameterGetAccount((SOSTransportKeyParameterRef)value), account)){
238 SOSTransportKeyParameterHandleNewAccount(tkvs);
239 }
240 });
241 CFReleaseNull(originalKeyParams);
242 CFArrayAppendValue(handledKeys, kSOSKVSAccountChangedKey);
243 }
244
245 // Iterate through keys in updates. Perform circle change update.
246 // Then instantiate circles and engines and peers for all peers that
247 // are receiving a message in updates.
248 CFMutableDictionaryRef circle_peer_messages_table = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
249 CFMutableDictionaryRef circle_circle_messages_table = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
250 CFMutableDictionaryRef circle_retirement_messages_table = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
251 __block CFDataRef newParameters = NULL;
252 __block bool initial_sync = false;
253 __block bool new_account = false;
254
255 CFDictionaryForEach(updates, ^(const void *key, const void *value) {
256 CFErrorRef localError = NULL;
257 CFStringRef circle_name = NULL;
258 CFStringRef from_name = NULL;
259 CFStringRef to_name = NULL;
260 switch (SOSKVSKeyGetKeyTypeAndParse(key, &circle_name, &from_name, &to_name)) {
261 case kCircleKey:
262 CFDictionarySetValue(circle_circle_messages_table, circle_name, value);
263 break;
264 case kInitialSyncKey:
265 initial_sync = true;
266 break;
267 case kParametersKey:
268 if (isData(value)) {
269 newParameters = (CFDataRef) CFRetainSafe(value);
270 }
271 break;
272 case kMessageKey: {
273 CFMutableDictionaryRef circle_messages = CFDictionaryEnsureCFDictionaryAndGetCurrentValue(circle_peer_messages_table, circle_name);
274 CFDictionarySetValue(circle_messages, from_name, value);
275 break;
276 }
277 case kRetirementKey: {
278 CFMutableDictionaryRef circle_retirements = CFDictionaryEnsureCFDictionaryAndGetCurrentValue(circle_retirement_messages_table, circle_name);
279 CFDictionarySetValue(circle_retirements, from_name, value);
280 break;
281 }
282 case kAccountChangedKey:
283 new_account = true;
284 break;
285
286 case kUnknownKey:
287 secnotice("updates", "Unknown key '%@', ignoring", key);
288 break;
289
290 }
291
292 CFReleaseNull(circle_name);
293 CFReleaseNull(from_name);
294 CFReleaseNull(to_name);
295
296 if (error && *error)
297 secerror("Peer message processing error for: %@ -> %@ (%@)", key, value, *error);
298 if (localError)
299 secerror("Peer message local processing error for: %@ -> %@ (%@)", key, value, localError);
300
301 CFReleaseNull(localError);
302 });
303
304
305 if (newParameters) {
306 CFArrayForEach(SOSGetTransportKeyParameters(), ^(const void *value) {
307 SOSTransportKeyParameterRef tkvs = (SOSTransportKeyParameterRef) value;
308 CFErrorRef localError = NULL;
309 if(CFEqualSafe(SOSTransportKeyParameterGetAccount(tkvs), account)){
310 if(!SOSTransportKeyParameterHandleKeyParameterChanges(tkvs, newParameters, localError))
311 secerror("Transport failed to handle new key parameters: %@", localError);
312 }
313 });
314 CFArrayAppendValue(handledKeys, kSOSKVSKeyParametersKey);
315 }
316 CFReleaseNull(newParameters);
317
318 if(initial_sync){
319 CFArrayAppendValue(handledKeys, kSOSKVSInitialSyncKey);
320 }
321
322
323 if(CFDictionaryGetCount(circle_retirement_messages_table)) {
324 CFArrayForEach(SOSGetTransportCircles(), ^(const void *value) {
325 SOSTransportCircleRef tkvs = (SOSTransportCircleRef) value;
326 if(CFEqualSafe(SOSTransportCircleGetAccount((SOSTransportCircleRef)value), account)){
327 CFErrorRef localError = NULL;
328 CFDictionaryRef handledRetirementKeys = SOSTransportCircleHandleRetirementMessages(tkvs, circle_retirement_messages_table, error);
329 if(handledRetirementKeys == NULL){
330 secerror("Transport failed to handle retirement messages: %@", localError);
331 } else {
332 CFDictionaryForEach(handledRetirementKeys, ^(const void *key, const void *value) {
333 CFStringRef circle_name = (CFStringRef)key;
334 CFArrayRef handledPeerIDs = (CFArrayRef)value;
335 CFArrayForEach(handledPeerIDs, ^(const void *value) {
336 CFStringRef peer_id = (CFStringRef)value;
337 CFStringRef keyHandled = SOSRetirementKeyCreateWithCircleNameAndPeer(circle_name, peer_id);
338 CFArrayAppendValue(handledKeys, keyHandled);
339 CFReleaseNull(keyHandled);
340 });
341 });
342 }
343 CFReleaseNull(handledRetirementKeys);
344 CFReleaseNull(localError);
345 }
346 });
347 }
348
349 if(CFDictionaryGetCount(circle_circle_messages_table)) {
350 CFArrayForEach(SOSGetTransportCircles(), ^(const void *value) {
351 SOSTransportCircleRef tkvs = (SOSTransportCircleRef) value;
352 if(CFEqualSafe(SOSTransportCircleGetAccount((SOSTransportCircleRef)value), account)){
353 CFArrayRef handleCircleMessages = SOSTransportCircleHandleCircleMessages(tkvs, circle_circle_messages_table, error);
354 CFErrorRef localError = NULL;
355 if(handleCircleMessages == NULL){
356 secerror("Transport failed to handle circle messages: %@", localError);
357 } else if(CFArrayGetCount(handleCircleMessages) == 0) {
358 if(CFDictionaryGetCount(circle_circle_messages_table) != 0) {
359 secerror("Transport failed to process all circle messages: (%ld/%ld) %@",
360 CFArrayGetCount(handleCircleMessages),
361 CFDictionaryGetCount(circle_circle_messages_table), localError);
362 } else {
363 secnotice("circle", "Transport handled no circle messages");
364 }
365 } else {
366 CFArrayForEach(handleCircleMessages, ^(const void *value) {
367 CFStringRef keyHandled = SOSCircleKeyCreateWithName((CFStringRef)value, error);
368 CFArrayAppendValue(handledKeys, keyHandled);
369 CFReleaseNull(keyHandled);
370 });
371 }
372 CFReleaseNull(localError);
373
374 if (!SOSTransportCircleFlushChanges(tkvs, &localError))
375 secerror("error flushing changes: %@", localError);
376
377 CFReleaseNull(localError);
378 CFReleaseNull(handleCircleMessages);
379 }
380
381 });
382 }
383 // TODO: These should all produce circle -> messageTypeHandled messages
384 // That probably needs to wait for separation of transport types.
385 if(CFDictionaryGetCount(circle_peer_messages_table)) {
386 CFArrayForEach(SOSGetTransportMessages(), ^(const void *value) {
387 SOSTransportMessageRef tkvs = (SOSTransportMessageRef) value;
388 if(CFEqualSafe(SOSTransportMessageGetAccount((SOSTransportMessageRef)value), account)){
389 CFErrorRef handleMessagesError = NULL;
390 CFDictionaryRef handledPeers = SOSTransportMessageHandleMessages(tkvs, circle_peer_messages_table, &handleMessagesError);
391
392 if (handledPeers) {
393 // We need to look for and send responses.
394
395 CFErrorRef syncError = NULL;
396 if (!SOSTransportMessageSyncWithPeers((SOSTransportMessageRef)tkvs, handledPeers, &syncError)) {
397 secerror("Sync with peers failed: %@", syncError);
398 }
399
400 CFDictionaryForEach(handledPeers, ^(const void *key, const void *value) {
401 if (isString(key) && isArray(value)) {
402 CFArrayForEach(value, ^(const void *value) {
403 if (isString(value)) {
404 CFStringRef peerID = (CFStringRef) value;
405
406 CFStringRef kvsHandledKey = SOSMessageKeyCreateFromPeerToTransport((SOSTransportMessageKVSRef)tkvs, peerID);
407 CFArrayAppendValue(handledKeys, kvsHandledKey);
408 CFReleaseSafe(kvsHandledKey);
409 }
410 });
411 }
412 });
413
414 CFErrorRef flushError = NULL;
415 if (!SOSTransportMessageFlushChanges((SOSTransportMessageRef)tkvs, &flushError)) {
416 secerror("Flush failed: %@", flushError);
417 }
418 }
419 else {
420 secerror("Didn't handle? : %@", handleMessagesError);
421 }
422 CFReleaseNull(handledPeers);
423 CFReleaseNull(handleMessagesError);
424 }
425 });
426 }
427 CFReleaseNull(circle_retirement_messages_table);
428 CFReleaseNull(circle_circle_messages_table);
429 CFReleaseNull(circle_peer_messages_table);
430
431
432
433 showWhatWasHandled(updates, handledKeys);
434
435 return handledKeys;
436 }
437
438