2 // otr-30-negotiation.c
5 // Created by Mitch Adler on 6/7/11.
6 // Copyright 2011 Apple Inc. All rights reserved.
9 #include "Security_regressions.h"
11 #include <CoreFoundation/CFData.h>
12 #include <Security/SecOTRSession.h>
13 #include <Security/SecInternal.h>
14 #include <Security/SecBasePriv.h>
16 static void SecMPLogError(CFErrorRef error
) {
20 CFDictionaryRef tempDictionary
= CFErrorCopyUserInfo(error
);
21 CFIndex errorCode
= CFErrorGetCode(error
);
22 CFStringRef errorDomain
= CFErrorGetDomain(error
);
23 CFStringRef errorString
= CFDictionaryGetValue(tempDictionary
, kCFErrorDescriptionKey
);
24 CFErrorRef previousError
= (CFErrorRef
)CFDictionaryGetValue(tempDictionary
, kCFErrorUnderlyingErrorKey
);
25 if (previousError
!= NULL
) {
26 SecMPLogError(previousError
);
28 char errorDomainStr
[1024];
29 char errorStringStr
[1024];
31 CFStringGetCString(errorDomain
, errorDomainStr
, 1024, kCFStringEncodingUTF8
);
32 CFStringGetCString(errorString
, errorStringStr
, 1024, kCFStringEncodingUTF8
);
33 printf("MessageProtection: %s (%ld) -- %s\n", errorDomainStr
, errorCode
, errorStringStr
);
34 CFReleaseSafe(tempDictionary
);
37 static void serializeAndDeserialize(SecOTRSessionRef
* thisOne
)
39 CFMutableDataRef serialized
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
41 SecOTRSAppendSerialization(*thisOne
, serialized
);
42 CFReleaseNull(*thisOne
);
43 *thisOne
= SecOTRSessionCreateFromData(kCFAllocatorDefault
, serialized
);
45 CFReleaseSafe(serialized
);
50 #define sendMessagesCount(n) ((n) * 8)
51 static void sendMessages(int howMany
, SecOTRSessionRef
*bobSession
, SecOTRSessionRef
*aliceSession
, bool serialize
)
53 for(int count
= howMany
; count
> 0; --count
) {
54 const char* aliceToBob
= "aliceToBob";
55 CFDataRef rawAliceToBob
= CFDataCreate(kCFAllocatorDefault
, (const uint8_t*)aliceToBob
, (CFIndex
) strlen(aliceToBob
));
56 CFMutableDataRef protectedAliceToBob
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
57 CFMutableDataRef bobDecode
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
59 ok_status(SecOTRSSignAndProtectMessage(*aliceSession
, rawAliceToBob
, protectedAliceToBob
), "encode message");
60 ok_status(SecOTRSVerifyAndExposeMessage(*bobSession
, protectedAliceToBob
, bobDecode
), "Decode message");
63 serializeAndDeserialize(bobSession
);
64 serializeAndDeserialize(aliceSession
);
67 ok(CFDataGetLength(rawAliceToBob
) == CFDataGetLength(bobDecode
)
68 && 0 == memcmp(CFDataGetBytePtr(rawAliceToBob
), CFDataGetBytePtr(bobDecode
), (size_t)CFDataGetLength(rawAliceToBob
)), "Didn't match!");
70 CFReleaseNull(rawAliceToBob
);
71 CFReleaseNull(protectedAliceToBob
);
72 CFReleaseNull(bobDecode
);
74 const char* bobToAlice
= "i liked your silly message from me to you";
75 CFDataRef rawBobToAlice
= CFDataCreate(kCFAllocatorDefault
, (const uint8_t*)bobToAlice
, (CFIndex
) strlen(bobToAlice
));
76 CFMutableDataRef protectedBobToAlice
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
77 CFMutableDataRef aliceDecode
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
79 ok_status(SecOTRSSignAndProtectMessage(*bobSession
, rawBobToAlice
, protectedBobToAlice
), "encode reply");
80 ok_status(SecOTRSVerifyAndExposeMessage(*aliceSession
, protectedBobToAlice
, aliceDecode
), "decode reply");
83 serializeAndDeserialize(bobSession
);
84 serializeAndDeserialize(aliceSession
);
87 ok(CFDataGetLength(rawBobToAlice
) == CFDataGetLength(aliceDecode
)
88 && 0 == memcmp(CFDataGetBytePtr(rawBobToAlice
), CFDataGetBytePtr(aliceDecode
), (size_t)CFDataGetLength(rawBobToAlice
)), "reply matched");
90 CFReleaseNull(rawAliceToBob
);
91 CFReleaseNull(protectedAliceToBob
);
92 CFReleaseNull(aliceDecode
);
94 CFStringRef stateString
= CFCopyDescription(*bobSession
);
95 ok(stateString
, "getting state from bob");
96 CFReleaseNull(stateString
);
98 stateString
= CFCopyDescription(*aliceSession
);
99 ok(stateString
, "getting state from alice");
100 CFReleaseNull(stateString
);
104 #define kNegotiateTestCount (14 + sendMessagesCount(5) \
105 + 2 + sendMessagesCount(1) \
106 + 1 + sendMessagesCount(1))
107 static void negotiate(SecOTRSessionRef
* aliceSession
, SecOTRSessionRef
* bobSession
, bool serialize
)
109 // Step 1: Create a start packet for each side of the transaction
110 CFMutableDataRef bobStartPacket
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
112 ok_status(SecOTRSAppendStartPacket(*bobSession
, bobStartPacket
), "Bob start packet");
115 serializeAndDeserialize(bobSession
);
117 CFMutableDataRef aliceStartPacket
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
119 ok_status(SecOTRSAppendStartPacket(*aliceSession
, aliceStartPacket
), "Alice start packet");
122 serializeAndDeserialize(aliceSession
);
124 // Step 2: Exchange the start packets, forcing the DH commit messages to collide
125 CFMutableDataRef aliceDHKeyResponse
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
127 ok_status(SecOTRSProcessPacket(*aliceSession
, bobStartPacket
, aliceDHKeyResponse
),
128 "Bob DH packet failed");
131 serializeAndDeserialize(aliceSession
);
133 CFReleaseNull(bobStartPacket
);
135 CFMutableDataRef bobDHKeyResponse
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
137 ok_status(SecOTRSProcessPacket(*bobSession
, aliceStartPacket
, bobDHKeyResponse
),
138 "Alice DH packet failed");
141 serializeAndDeserialize(bobSession
);
143 CFReleaseNull(aliceStartPacket
);
145 // Step 3: With one "real" DH key message, and one replayed DH commit message, try to get a "reveal sig" out of one side
147 CFMutableDataRef bobRevealSigResponse
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
149 ok_status(SecOTRSProcessPacket(*bobSession
, aliceDHKeyResponse
, bobRevealSigResponse
),
150 "Alice DH Key packet failed");
153 serializeAndDeserialize(bobSession
);
155 CFReleaseNull(aliceDHKeyResponse
);
157 CFMutableDataRef aliceRevealSigResponse
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
159 ok_status(SecOTRSProcessPacket(*aliceSession
, bobDHKeyResponse
, aliceRevealSigResponse
),
160 "Bob DH Key packet failed");
163 serializeAndDeserialize(aliceSession
);
165 CFReleaseNull(bobDHKeyResponse
);
167 // Step 4: Having gotten the reveal signature, now work for the signature
169 CFMutableDataRef aliceSigResponse
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
171 ok_status(SecOTRSProcessPacket(*aliceSession
, bobRevealSigResponse
, aliceSigResponse
),
172 "Bob Reveal sig failed");
175 serializeAndDeserialize(aliceSession
);
177 CFReleaseNull(bobRevealSigResponse
);
179 CFMutableDataRef bobSigResponse
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
181 ok_status(SecOTRSProcessPacket(*bobSession
, aliceRevealSigResponse
, bobSigResponse
),
182 "Alice Reveal sig failed");
185 serializeAndDeserialize(bobSession
);
187 CFReleaseNull(aliceRevealSigResponse
);
189 // Step 5: All the messages have been sent, now deal with any replays from the collision handling
190 CFMutableDataRef bobFinalResponse
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
192 ok_status(SecOTRSProcessPacket(*bobSession
, aliceSigResponse
, bobFinalResponse
),
193 "Alice Final Sig failed");
196 serializeAndDeserialize(bobSession
);
198 CFMutableDataRef aliceFinalResponse
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
200 ok_status(SecOTRSProcessPacket(*aliceSession
, bobSigResponse
, aliceFinalResponse
),
201 "Bob Final Sig failed");
204 serializeAndDeserialize(aliceSession
);
206 is(6, CFDataGetLength(bobFinalResponse
), "Alice had nothing left to say");
207 is(6, CFDataGetLength(bobFinalResponse
), "Bob had nothing left to say");
208 ok(SecOTRSGetIsReadyForMessages(*bobSession
), "Bob is ready");
209 ok(SecOTRSGetIsReadyForMessages(*aliceSession
), "Alice is ready");
211 CFReleaseNull(aliceSigResponse
);
212 CFReleaseNull(bobFinalResponse
);
214 sendMessages(5, bobSession
, aliceSession
, serialize
);
216 const char* aliceToBob
= "deferredMessage";
217 CFDataRef rawAliceToBob
= CFDataCreate(kCFAllocatorDefault
, (const uint8_t*)aliceToBob
, (CFIndex
) strlen(aliceToBob
));
218 CFMutableDataRef protectedAliceToBob
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
219 CFMutableDataRef bobDecode
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
221 ok_status(SecOTRSSignAndProtectMessage(*aliceSession
, rawAliceToBob
, protectedAliceToBob
), "encode message");
223 sendMessages(1, bobSession
, aliceSession
, serialize
);
225 ok(errSecOTRTooOld
==SecOTRSVerifyAndExposeMessage(*bobSession
, protectedAliceToBob
, bobDecode
), "Decode old message");
227 sendMessages(1, bobSession
, aliceSession
, serialize
);
229 ok(errSecOTRTooOld
== SecOTRSVerifyAndExposeMessage(*bobSession
, protectedAliceToBob
, bobDecode
), "Fail to decode excessively old message");
231 CFReleaseNull(rawAliceToBob
);
232 CFReleaseNull(protectedAliceToBob
);
233 CFReleaseNull(bobDecode
);
237 #define kTestTestCount (7 + kNegotiateTestCount)
241 CFErrorRef testError
= NULL
;
242 SecOTRFullIdentityRef aliceID
= SecOTRFullIdentityCreate(kCFAllocatorDefault
, &testError
);
243 SecMPLogError(testError
);
244 CFReleaseNull(testError
);
246 SecOTRFullIdentityRef bobID
= SecOTRFullIdentityCreate(kCFAllocatorDefault
, &testError
);
247 SecMPLogError(testError
);
248 CFReleaseNull(testError
);
251 ok(aliceID
, "create alice ID");
252 ok(bobID
, "create bob ID");
254 SecOTRPublicIdentityRef alicePublicID
= SecOTRPublicIdentityCopyFromPrivate(kCFAllocatorDefault
, aliceID
, &testError
);
255 SecMPLogError(testError
);
256 CFReleaseNull(testError
);
257 SecOTRPublicIdentityRef bobPublicID
= SecOTRPublicIdentityCopyFromPrivate(kCFAllocatorDefault
, bobID
, &testError
);
258 SecMPLogError(testError
);
259 CFReleaseNull(testError
);
261 ok(alicePublicID
, "extract alice public");
262 ok(bobPublicID
, "extract bob public");
264 SecOTRSessionRef aliceSession
= SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault
, aliceID
, bobPublicID
, kSecOTRSendTextMessages
);
265 SecOTRSessionRef bobSession
= SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault
, bobID
, alicePublicID
, kSecOTRSendTextMessages
);
267 ok(aliceSession
, "create alice session");
268 ok(bobSession
, "create bob session");
270 // Release the IDs, sessions shouldn't need us to retain them for them.
271 CFReleaseNull(aliceID
);
272 CFReleaseNull(bobID
);
274 CFReleaseNull(alicePublicID
);
275 CFReleaseNull(bobPublicID
);
277 negotiate(&aliceSession
, &bobSession
, true);
279 /* cleanup keychain */
280 ok(SecOTRFIPurgeAllFromKeychain(&testError
),"cleanup keychain");
281 SecMPLogError(testError
);
282 CFReleaseNull(testError
);
284 CFReleaseNull(aliceSession
);
285 CFReleaseNull(bobSession
);
288 int otr_30_negotiation(int argc
, char *const *argv
)
290 plan_tests(kTestTestCount
);