X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/ce3c8656732c924baf7e88df75eab50891bdc471..fa7225c82381bac4432a6edf16f53b5370238d85:/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportMessageIDS.c diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportMessageIDS.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportMessageIDS.c index 9111aa48..9e2d7747 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportMessageIDS.c +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportMessageIDS.c @@ -25,16 +25,17 @@ struct __OpaqueSOSTransportMessageIDS { struct __OpaqueSOSTransportMessage m; - + CFBooleanRef useFragmentation; }; const CFStringRef kSecIDSErrorDomain = CFSTR("com.apple.security.ids.error"); - +const CFStringRef kIDSOperationType = CFSTR("IDSMessageOperation"); +const CFStringRef kIDSMessageToSendKey = CFSTR("MessageToSendKey"); // // V-table implementation forward declarations // -static bool sendToPeer(SOSTransportMessageRef transport, CFStringRef circleName, CFStringRef deviceID, CFStringRef peerID, CFDictionaryRef message, CFErrorRef *error); +static bool sendToPeer(SOSTransportMessageRef transport, CFStringRef circleName, CFStringRef deviceID, CFStringRef peerID,CFDictionaryRef message, CFErrorRef *error); static bool syncWithPeers(SOSTransportMessageRef transport, CFDictionaryRef circleToPeerIDs, CFErrorRef *error); static bool sendMessages(SOSTransportMessageRef transport, CFDictionaryRef circleToPeersToMessage, CFErrorRef *error); static void destroy(SOSTransportMessageRef transport); @@ -46,6 +47,16 @@ static inline CFIndex getTransportType(SOSTransportMessageRef transport, CFError return kIDS; } +void SOSTransportMessageIDSSetFragmentationPreference(SOSTransportMessageRef transport, CFBooleanRef preference){ + SOSTransportMessageIDSRef t = (SOSTransportMessageIDSRef)transport; + t->useFragmentation = preference; +} + +CFBooleanRef SOSTransportMessageIDSGetFragmentationPreference(SOSTransportMessageRef transport){ + SOSTransportMessageIDSRef t = (SOSTransportMessageIDSRef)transport; + return t->useFragmentation; + } + SOSTransportMessageIDSRef SOSTransportMessageIDSCreate(SOSAccountRef account, CFStringRef circleName, CFErrorRef *error) { SOSTransportMessageIDSRef ids = (SOSTransportMessageIDSRef) SOSTransportMessageCreateForSubclass(sizeof(struct __OpaqueSOSTransportMessageIDS) - sizeof(CFRuntimeBase), account, circleName, error); @@ -73,75 +84,116 @@ static void destroy(SOSTransportMessageRef transport){ } static CF_RETURNS_RETAINED CFDictionaryRef handleMessages(SOSTransportMessageRef transport, CFMutableDictionaryRef circle_peer_messages_table, CFErrorRef *error) { - // TODO: This might need to be: return CFDictionaryCreateForCFTypes(kCFAllocatorDefault, NULL); - return CFDictionaryCreateForCFTypes(kCFAllocatorDefault); + return CFDictionaryCreateForCFTypes(kCFAllocatorDefault, NULL); +} + +static HandleIDSMessageReason checkMessageValidity(SOSAccountRef account, CFStringRef fromDeviceID, CFStringRef fromPeerID, CFStringRef *peerID, SOSPeerInfoRef *theirPeerInfo){ + + __block HandleIDSMessageReason reason = kHandleIDSMessageDontHandle; + + SOSCircleForEachPeer(account->trusted_circle, ^(SOSPeerInfoRef peer) { + CFStringRef deviceID = SOSPeerInfoCopyDeviceID(peer); + CFStringRef pID = SOSPeerInfoGetPeerID(peer); + + if( deviceID && pID && fromPeerID && fromDeviceID && CFStringGetLength(fromPeerID) != 0 ){ + if(CFStringCompare(pID, fromPeerID, 0) == 0){ + if(CFStringGetLength(deviceID) == 0){ + secnotice("ids transport", "device ID was empty in the peer list, holding on to message"); + CFReleaseNull(deviceID); + reason = kHandleIDSMessageNotReady; + return; + } + else if(CFStringCompare(fromDeviceID, deviceID, 0) != 0){ //IDSids do not match, ghost + reason = kHandleIDSmessageDeviceIDMismatch; + CFReleaseNull(deviceID); + return; + } + else if(CFStringCompare(deviceID, fromDeviceID, 0) == 0){ + *peerID = pID; + *theirPeerInfo = peer; + CFReleaseNull(deviceID); + reason = kHandleIDSMessageSuccess; + return; + } + } + } + CFReleaseNull(deviceID); + }); + + return reason; } HandleIDSMessageReason SOSTransportMessageIDSHandleMessage(SOSAccountRef account, CFDictionaryRef message, CFErrorRef *error) { - secdebug("IDS Transport", "SOSTransportMessageIDSHandleMessage!"); + secnotice("IDS Transport", "SOSTransportMessageIDSHandleMessage!"); CFStringRef dataKey = CFStringCreateWithCString(kCFAllocatorDefault, kMessageKeyIDSDataMessage, kCFStringEncodingASCII); CFStringRef deviceIDKey = CFStringCreateWithCString(kCFAllocatorDefault, kMessageKeyDeviceID, kCFStringEncodingASCII); - - CFDataRef messageData = (CFDataRef)CFDictionaryGetValue(message, dataKey); - CFStringRef fromID = (CFStringRef)CFDictionaryGetValue(message, deviceIDKey); - - SOSPeerInfoRef myPeer = SOSAccountGetMyPeerInfo(account); + CFStringRef sendersPeerIDKey = CFStringCreateWithCString(kCFAllocatorDefault, kMessageKeySendersPeerID, kCFStringEncodingASCII); - if(!myPeer) { - CFReleaseNull(deviceIDKey); - CFReleaseNull(dataKey); - if(!SOSAccountHasFullPeerInfo(account, error)) - return kHandleIDSMessageOtherFail; - } + HandleIDSMessageReason result = kHandleIDSMessageSuccess; - __block CFStringRef peerID = NULL; - - SOSCircleForEachPeer(account->trusted_circle, ^(SOSPeerInfoRef peer) { - CFStringRef deviceID = SOSPeerInfoCopyDeviceID(peer); - if(deviceID && CFStringCompare(deviceID, fromID, 0) == 0) - peerID = SOSPeerInfoGetPeerID(peer); - CFReleaseNull(deviceID); - }); - if(!peerID){ - secerror("Could not find peer matching the IDS device ID, dropping message"); - CFReleaseNull(dataKey); - CFReleaseNull(deviceIDKey); - return kHandleIDSMessageNotReady; - } + CFDataRef messageData = asData(CFDictionaryGetValue(message, dataKey), NULL); + __block CFStringRef fromDeviceID = asString(CFDictionaryGetValue(message, deviceIDKey), NULL); + __block CFStringRef fromPeerID = (CFStringRef)CFDictionaryGetValue(message, sendersPeerIDKey); - if(messageData != NULL && CFDataGetLength(messageData) > 0){ + CFStringRef peerID = NULL; + SOSPeerInfoRef theirPeer = NULL; + + require_action_quiet(fromDeviceID, exit, result = kHandleIDSMessageDontHandle); + require_action_quiet(fromPeerID, exit, result = kHandleIDSMessageDontHandle); + require_action_quiet(messageData && CFDataGetLength(messageData) != 0, exit, result = kHandleIDSMessageDontHandle); + require_action_quiet(SOSAccountHasFullPeerInfo(account, error), exit, result = kHandleIDSMessageNotReady); + + require_quiet((result = checkMessageValidity( account, fromDeviceID, fromPeerID, &peerID, &theirPeer)) == kHandleIDSMessageSuccess, exit); + + if (SOSTransportMessageHandlePeerMessage(account->ids_message_transport, peerID, messageData, error)) { + CFMutableDictionaryRef peersToSyncWith = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + CFMutableArrayRef peerIDs = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); + CFArrayAppendValue(peerIDs, peerID); + CFDictionaryAddValue(peersToSyncWith, SOSCircleGetName(account->trusted_circle), peerIDs); - if (SOSTransportMessageHandlePeerMessage(account->ids_message_transport, peerID, messageData, error)) { - CFMutableDictionaryRef peersToSyncWith = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - CFMutableArrayRef peerIDs = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); - CFArrayAppendValue(peerIDs, peerID); - CFDictionaryAddValue(peersToSyncWith, SOSCircleGetName(account->trusted_circle), peerIDs); - - if(!SOSTransportMessageSyncWithPeers(account->ids_message_transport, peersToSyncWith, error)) - { - secerror("SOSTransportMessageIDSHandleMessage Could not sync with all peers: %@", *error); - } - else{ - secdebug("IDS Transport", "Synced with all peers!"); - CFReleaseNull(dataKey); - CFReleaseNull(deviceIDKey); - return kHandleIDSMessageSuccess; - } - + //sync using fragmentation? + if(SOSPeerInfoShouldUseIDSMessageFragmentation(SOSFullPeerInfoGetPeerInfo(account->my_identity), theirPeer)){ + //set useFragmentation bit + SOSTransportMessageIDSSetFragmentationPreference(account->ids_message_transport, kCFBooleanTrue); } else{ - CFReleaseNull(dataKey); - CFReleaseNull(deviceIDKey); + SOSTransportMessageIDSSetFragmentationPreference(account->ids_message_transport, kCFBooleanFalse); + } + + if(!SOSTransportMessageSyncWithPeers(account->ids_message_transport, peersToSyncWith, error)){ + secerror("SOSTransportMessageIDSHandleMessage Could not sync with all peers: %@", *error); + }else{ + secnotice("IDS Transport", "Synced with all peers!"); + } + + CFReleaseNull(peersToSyncWith); + CFReleaseNull(peerIDs); + }else{ + if(error && *error != NULL){ + CFStringRef errorMessage = CFErrorCopyDescription(*error); + if (-25308 == CFErrorGetCode(*error)) { // tell IDSKeychainSyncingProxy to call us back when device unlocks + result = kHandleIDSMessageLocked; + }else{ //else drop it, couldn't handle the message + result = kHandleIDSMessageDontHandle; + } + secerror("IDS Transport Could not handle message: %@, %@", messageData, *error); + CFReleaseNull(errorMessage); + + } + else{ //no error but failed? drop it, log message secerror("IDS Transport Could not handle message: %@", messageData); - return kHandleIDSMessageOtherFail; + result = kHandleIDSMessageDontHandle; + } } - secerror("Data doesn't exist: %@", messageData); + +exit: + CFReleaseNull(sendersPeerIDKey); CFReleaseNull(deviceIDKey); CFReleaseNull(dataKey); - return kHandleIDSMessageOtherFail; + return result; } @@ -155,15 +207,33 @@ static bool sendToPeer(SOSTransportMessageRef transport, CFStringRef circleName, CFMutableDataRef mutableData = NULL; SOSAccountRef account = SOSTransportMessageGetAccount(transport); CFStringRef ourPeerID = SOSPeerInfoGetPeerID(SOSAccountGetMyPeerInfo(account)); + CFStringRef operationToString = NULL; + + CFDictionaryRef messagetoSend = NULL; require_action_quiet((deviceID != NULL && CFStringGetLength(deviceID) >0), fail, errorMessage = CFSTR("Need an IDS Device ID to sync")); + if(CFDictionaryGetValue(message, kIDSOperationType) == NULL && SOSTransportMessageIDSGetFragmentationPreference(transport) == kCFBooleanTrue){ + //otherwise handle a keychain data blob using fragmentation! + secnotice("IDS Transport","sendToPeer: using fragmentation!"); + char *messageCharStar; + asprintf(&messageCharStar, "%d", kIDSKeychainSyncIDSFragmentation); + operationToString = CFStringCreateWithCString(kCFAllocatorDefault, messageCharStar, kCFStringEncodingUTF8); + free(messageCharStar); + + messagetoSend = CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault, kIDSOperationType, operationToString, kIDSMessageToSendKey, message, NULL); + } + else{ //otherhandle handle the test message without fragmentation + messagetoSend = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, CFDictionaryGetCount(message), message); + secnotice("IDS Transport","sendToPeer: not going to fragment message"); + } + dispatch_semaphore_t wait_for = dispatch_semaphore_create(0); dispatch_retain(wait_for); // Both this scope and the block own it. secnotice("ids transport", "Starting"); - SOSCloudKeychainSendIDSMessage(message, deviceID, ourPeerID, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(CFDictionaryRef returnedValues, CFErrorRef sync_error) { + SOSCloudKeychainSendIDSMessage(messagetoSend, deviceID, ourPeerID, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), SOSTransportMessageIDSGetFragmentationPreference(transport), ^(CFDictionaryRef returnedValues, CFErrorRef sync_error) { success = (sync_error == NULL); if (sync_error && error) { CFRetainAssign(*error, sync_error); @@ -183,13 +253,14 @@ static bool sendToPeer(SOSTransportMessageRef transport, CFStringRef circleName, secerror("Failed to send message to peer"); } else{ - secdebug("IDS Transport", "Sent message to peer!"); + secnotice("IDS Transport", "Sent message to peer!"); } - + + CFReleaseNull(messagetoSend); CFReleaseNull(operation); CFReleaseNull(operationData); CFReleaseNull(mutableData); - + CFReleaseNull(operationToString); return success; fail: @@ -198,14 +269,17 @@ fail: *error =CFErrorCreate(kCFAllocatorDefault, CFSTR("com.apple.security.ids.error"), kSecIDSErrorNoDeviceID, userInfo); secerror("%@", *error); } + CFReleaseNull(messagetoSend); CFReleaseNull(operation); CFReleaseNull(operationData); CFReleaseNull(mutableData); CFReleaseNull(userInfo); + CFReleaseNull(operationToString); return success; } + static bool syncWithPeers(SOSTransportMessageRef transport, CFDictionaryRef circleToPeerIDs, CFErrorRef *error) { // Each entry is keyed by circle name and contains a list of peerIDs __block bool result = true; @@ -249,6 +323,13 @@ static bool sendMessages(SOSTransportMessageRef transport, CFDictionaryRef circl } SOSCircleForEachPeer(circle, ^(SOSPeerInfoRef peer) { if(!CFEqualSafe(myPeer, peer)){ + if(SOSPeerInfoShouldUseIDSMessageFragmentation(myPeer, peer)){ + SOSTransportMessageIDSSetFragmentationPreference(transport, kCFBooleanTrue); + } + else{ + SOSTransportMessageIDSSetFragmentationPreference(transport, kCFBooleanFalse); + } + CFStringRef deviceID = SOSPeerInfoCopyDeviceID(peer); if(CFStringCompare(SOSPeerInfoGetPeerID(peer), peerID, 0) == 0){ bool rx = false; @@ -261,10 +342,13 @@ static bool sendMessages(SOSTransportMessageRef transport, CFDictionaryRef circl }); } }); + fail: + CFReleaseNull(message); return result; } + static bool flushChanges(SOSTransportMessageRef transport, CFErrorRef *error) { return true; @@ -285,7 +369,7 @@ void SOSTransportMessageIDSGetIDSDeviceID(SOSAccountRef account){ secerror("Could not ask IDSKeychainSyncingProxy for Device ID: %@", sync_error); } else{ - secdebug("IDS Transport", "Successfully attempting to retrieve the IDS Device ID"); + secnotice("IDS Transport", "Successfully attempting to retrieve the IDS Device ID"); } }); }