SOSCoderStatus SOSCoderWrap(SOSCoderRef coder, CFDataRef message, CFMutableDataRef *codedMessage, CFStringRef clientId, CFErrorRef *error) { CFMutableStringRef action = CFStringCreateMutable(kCFAllocatorDefault, 0); SOSCoderStatus result = kSOSCoderDataReturned; CFStringRef beginState = NULL; CFMutableDataRef encoded = NULL; OSStatus otrStatus = 0; require_action_quiet(coder->sessRef, errOut, CFStringAppend(action, CFSTR("*** using null coder ***")); result = nullCoder(message, codedMessage)); beginState = CFCopyDescription(coder->sessRef); require_action_quiet(SecOTRSGetIsReadyForMessages(coder->sessRef), errOut, CFStringAppend(action, CFSTR("not ready")); result = kSOSCoderNegotiating); require_action_quiet(!coder->waitingForDataPacket, errOut, CFStringAppend(action, CFSTR("waiting for peer to send data packet first")); result = kSOSCoderNegotiating); require_action_quiet(encoded = CFDataCreateMutable(kCFAllocatorDefault, 0), errOut, SOSCreateErrorWithFormat(kSOSErrorAllocationFailure, NULL, error, NULL, CFSTR("%@ alloc failed"), clientId); result = kSOSCoderFailure); require_noerr_action_quiet(otrStatus = SecOTRSSignAndProtectMessage(coder->sessRef, message, encoded), errOut, SOSCreateErrorWithFormat(kSOSErrorEncodeFailure, (error != NULL) ? *error : NULL, error, NULL, CFSTR("%@ cannot protect message: %" PRIdOSStatus), clientId, otrStatus); CFReleaseNull(encoded); result = kSOSCoderFailure); *codedMessage = encoded; errOut: // Uber state log if (result == kSOSCoderFailure && error && *error) CFStringAppendFormat(action, NULL, CFSTR(" %@"), *error); secnotice("coder", "%@ %@ %s %@ %@ returned %s", clientId, beginState, SecOTRPacketTypeString(encoded), action, coder->sessRef, SOSCoderString(result)); CFReleaseSafe(beginState); CFRelease(action); return result; }
static void sendMessages(int howMany, SecOTRSessionRef *bobSession, SecOTRSessionRef *aliceSession, bool serialize) { for(int count = howMany; count > 0; --count) { const char* aliceToBob = "aliceToBob"; CFDataRef rawAliceToBob = CFDataCreate(kCFAllocatorDefault, (const uint8_t*)aliceToBob, (CFIndex) strlen(aliceToBob)); CFMutableDataRef protectedAliceToBob = CFDataCreateMutable(kCFAllocatorDefault, 0); CFMutableDataRef bobDecode = CFDataCreateMutable(kCFAllocatorDefault, 0); ok_status(SecOTRSSignAndProtectMessage(*aliceSession, rawAliceToBob, protectedAliceToBob), "encode message"); ok_status(SecOTRSVerifyAndExposeMessage(*bobSession, protectedAliceToBob, bobDecode), "Decode message"); if (serialize) { serializeAndDeserialize(bobSession); serializeAndDeserialize(aliceSession); } ok(CFDataGetLength(rawAliceToBob) == CFDataGetLength(bobDecode) && 0 == memcmp(CFDataGetBytePtr(rawAliceToBob), CFDataGetBytePtr(bobDecode), (size_t)CFDataGetLength(rawAliceToBob)), "Didn't match!"); CFReleaseNull(rawAliceToBob); CFReleaseNull(protectedAliceToBob); CFReleaseNull(bobDecode); const char* bobToAlice = "i liked your silly message from me to you"; CFDataRef rawBobToAlice = CFDataCreate(kCFAllocatorDefault, (const uint8_t*)bobToAlice, (CFIndex) strlen(bobToAlice)); CFMutableDataRef protectedBobToAlice = CFDataCreateMutable(kCFAllocatorDefault, 0); CFMutableDataRef aliceDecode = CFDataCreateMutable(kCFAllocatorDefault, 0); ok_status(SecOTRSSignAndProtectMessage(*aliceSession, rawBobToAlice, protectedBobToAlice), "encode reply"); ok_status(SecOTRSVerifyAndExposeMessage(*bobSession, protectedBobToAlice, aliceDecode), "decode reply"); if (serialize) { serializeAndDeserialize(bobSession); serializeAndDeserialize(aliceSession); } ok(CFDataGetLength(rawBobToAlice) == CFDataGetLength(aliceDecode) && 0 == memcmp(CFDataGetBytePtr(rawBobToAlice), CFDataGetBytePtr(aliceDecode), (size_t)CFDataGetLength(rawBobToAlice)), "reply matched"); CFReleaseNull(rawAliceToBob); CFReleaseNull(rawBobToAlice); CFReleaseNull(protectedBobToAlice); CFReleaseNull(protectedAliceToBob); CFReleaseNull(aliceDecode); rawAliceToBob = CFDataCreate(kCFAllocatorDefault, (const uint8_t*)aliceToBob, (CFIndex) strlen(aliceToBob)); protectedAliceToBob = CFDataCreateMutable(kCFAllocatorDefault, 0); bobDecode = CFDataCreateMutable(kCFAllocatorDefault, 0); ok_status(SecOTRSSignAndProtectMessage(*aliceSession, rawAliceToBob, protectedAliceToBob), "encode message"); ok_status(SecOTRSVerifyAndExposeMessage(*bobSession, protectedAliceToBob, bobDecode), "Decode message"); if (serialize) { serializeAndDeserialize(bobSession); serializeAndDeserialize(aliceSession); } ok(CFDataGetLength(rawAliceToBob) == CFDataGetLength(bobDecode) && 0 == memcmp(CFDataGetBytePtr(rawAliceToBob), CFDataGetBytePtr(bobDecode), (size_t)CFDataGetLength(rawAliceToBob)), "Didn't match!"); CFReleaseNull(rawAliceToBob); CFReleaseNull(protectedAliceToBob); CFReleaseNull(bobDecode); bobToAlice = "i liked your silly message from me to you"; rawBobToAlice = CFDataCreate(kCFAllocatorDefault, (const uint8_t*)bobToAlice, (CFIndex) strlen(bobToAlice)); protectedBobToAlice = CFDataCreateMutable(kCFAllocatorDefault, 0); aliceDecode = CFDataCreateMutable(kCFAllocatorDefault, 0); ok_status(SecOTRSSignAndProtectMessage(*aliceSession, rawBobToAlice, protectedBobToAlice), "encode reply"); ok_status(SecOTRSVerifyAndExposeMessage(*bobSession, protectedBobToAlice, aliceDecode), "decode reply"); if (serialize) { serializeAndDeserialize(bobSession); serializeAndDeserialize(aliceSession); } ok(CFDataGetLength(rawBobToAlice) == CFDataGetLength(aliceDecode) && 0 == memcmp(CFDataGetBytePtr(rawBobToAlice), CFDataGetBytePtr(aliceDecode), (size_t)CFDataGetLength(rawBobToAlice)), "reply matched"); CFReleaseNull(rawAliceToBob); CFReleaseNull(rawBobToAlice); CFReleaseNull(protectedBobToAlice); CFReleaseNull(protectedAliceToBob); CFReleaseNull(aliceDecode); CFStringRef stateString = CFCopyDescription(*bobSession); ok(stateString, "getting state from bob"); CFReleaseNull(stateString); stateString = CFCopyDescription(*aliceSession); ok(stateString, "getting state from alice"); CFReleaseNull(stateString); } }
static void negotiate(SecOTRSessionRef* aliceSession, SecOTRSessionRef* bobSession, bool serializeNegotiating, bool serializeMessaging, bool textMode, bool compact) { const int kEmptyMessageSize = textMode ? 6 : 0; // Step 1: Create a start packet for each side of the transaction CFMutableDataRef bobStartPacket = CFDataCreateMutable(kCFAllocatorDefault, 0); ok_status(SecOTRSAppendStartPacket(*bobSession, bobStartPacket), "Bob start packet"); if (serializeNegotiating) serializeAndDeserialize(bobSession); CFMutableDataRef aliceStartPacket = CFDataCreateMutable(kCFAllocatorDefault, 0); ok_status(SecOTRSAppendStartPacket(*aliceSession, aliceStartPacket), "Alice start packet"); if (serializeNegotiating) serializeAndDeserialize(aliceSession); // Step 2: Exchange the start packets, forcing the DH commit messages to collide CFMutableDataRef aliceDHKeyResponse = CFDataCreateMutable(kCFAllocatorDefault, 0); ok_status(SecOTRSProcessPacket(*aliceSession, bobStartPacket, aliceDHKeyResponse), "Bob DH packet failed"); if (serializeNegotiating) serializeAndDeserialize(aliceSession); CFReleaseNull(bobStartPacket); CFMutableDataRef bobDHKeyResponse = CFDataCreateMutable(kCFAllocatorDefault, 0); ok_status(SecOTRSProcessPacket(*bobSession, aliceStartPacket, bobDHKeyResponse), "Alice DH packet failed"); if (serializeNegotiating) serializeAndDeserialize(bobSession); CFReleaseNull(aliceStartPacket); // Step 3: With one "real" DH key message, and one replayed DH commit message, try to get a "reveal sig" out of one side CFMutableDataRef bobRevealSigResponse = CFDataCreateMutable(kCFAllocatorDefault, 0); ok_status(SecOTRSProcessPacket(*bobSession, aliceDHKeyResponse, bobRevealSigResponse), "Alice DH Key packet failed"); if (serializeNegotiating) serializeAndDeserialize(bobSession); CFReleaseNull(aliceDHKeyResponse); CFMutableDataRef aliceRevealSigResponse = CFDataCreateMutable(kCFAllocatorDefault, 0); ok_status(SecOTRSProcessPacket(*aliceSession, bobDHKeyResponse, aliceRevealSigResponse), "Bob DH Key packet failed"); if (serializeNegotiating) serializeAndDeserialize(aliceSession); CFReleaseNull(bobDHKeyResponse); // Step 4: Having gotten the reveal signature, now work for the signature CFMutableDataRef aliceSigResponse = CFDataCreateMutable(kCFAllocatorDefault, 0); ok_status(SecOTRSProcessPacket(*aliceSession, bobRevealSigResponse, aliceSigResponse), "Bob Reveal sig failed"); if (serializeNegotiating) serializeAndDeserialize(aliceSession); CFReleaseNull(bobRevealSigResponse); CFMutableDataRef bobSigResponse = CFDataCreateMutable(kCFAllocatorDefault, 0); ok_status(SecOTRSProcessPacket(*bobSession, aliceRevealSigResponse, bobSigResponse), "Alice Reveal sig failed"); if (serializeNegotiating) serializeAndDeserialize(bobSession); CFReleaseNull(aliceRevealSigResponse); // Step 5: All the messages have been sent, now deal with any replays from the collision handling CFMutableDataRef bobFinalResponse = CFDataCreateMutable(kCFAllocatorDefault, 0); ok_status(SecOTRSProcessPacket(*bobSession, aliceSigResponse, bobFinalResponse), "Alice Final Sig failed"); if (serializeNegotiating) serializeAndDeserialize(bobSession); CFMutableDataRef aliceFinalResponse = CFDataCreateMutable(kCFAllocatorDefault, 0); ok_status(SecOTRSProcessPacket(*aliceSession, bobSigResponse, aliceFinalResponse), "Bob Final Sig failed"); is(kEmptyMessageSize, CFDataGetLength(aliceFinalResponse), "Alice had nothing left to say"); CFReleaseNull(aliceFinalResponse); CFReleaseNull(bobSigResponse); if (serializeNegotiating) serializeAndDeserialize(aliceSession); is(kEmptyMessageSize, CFDataGetLength(bobFinalResponse), "Bob had nothing left to say"); ok(SecOTRSGetIsReadyForMessages(*bobSession), "Bob is ready"); ok(SecOTRSGetIsReadyForMessages(*aliceSession), "Alice is ready"); CFReleaseNull(aliceSigResponse); CFReleaseNull(bobFinalResponse); sendMessages(5, bobSession, aliceSession, serializeMessaging); const char* aliceToBob = "deferredMessage"; CFDataRef rawAliceToBob = CFDataCreate(kCFAllocatorDefault, (const uint8_t*)aliceToBob, (CFIndex) strlen(aliceToBob)); CFMutableDataRef protectedAliceToBob = CFDataCreateMutable(kCFAllocatorDefault, 0); CFMutableDataRef bobDecode = CFDataCreateMutable(kCFAllocatorDefault, 0); ok_status(SecOTRSSignAndProtectMessage(*aliceSession, rawAliceToBob, protectedAliceToBob), "encode message"); sendMessages(1, bobSession, aliceSession, serializeMessaging); is(SecOTRSVerifyAndExposeMessage(*bobSession, protectedAliceToBob, bobDecode), errSecOTRTooOld, "Decode old message"); sendMessages(1, bobSession, aliceSession, serializeMessaging); is(SecOTRSVerifyAndExposeMessage(*bobSession, protectedAliceToBob, bobDecode), errSecOTRTooOld, "Decode excessively old message"); sendMessages(3, bobSession, aliceSession, serializeMessaging); CFReleaseNull(rawAliceToBob); CFReleaseNull(protectedAliceToBob); CFReleaseNull(bobDecode); }