2 * Copyright (c) 2011-2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
25 #include "Security_regressions.h"
27 #include <CoreFoundation/CFData.h>
28 #include <Security/SecOTRSession.h>
29 #include <Security/SecInternal.h>
30 #include <Security/SecBasePriv.h>
32 static void SecMPLogError(CFErrorRef error
) {
36 CFDictionaryRef tempDictionary
= CFErrorCopyUserInfo(error
);
37 CFIndex errorCode
= CFErrorGetCode(error
);
38 CFStringRef errorDomain
= CFErrorGetDomain(error
);
39 CFStringRef errorString
= CFDictionaryGetValue(tempDictionary
, kCFErrorDescriptionKey
);
40 CFErrorRef previousError
= (CFErrorRef
)CFDictionaryGetValue(tempDictionary
, kCFErrorUnderlyingErrorKey
);
41 if (previousError
!= NULL
) {
42 SecMPLogError(previousError
);
44 char errorDomainStr
[1024];
45 char errorStringStr
[1024];
47 CFStringGetCString(errorDomain
, errorDomainStr
, 1024, kCFStringEncodingUTF8
);
48 CFStringGetCString(errorString
, errorStringStr
, 1024, kCFStringEncodingUTF8
);
49 printf("MessageProtection: %s (%ld) -- %s\n", errorDomainStr
, errorCode
, errorStringStr
);
50 CFReleaseSafe(tempDictionary
);
53 static void serializeAndDeserialize(SecOTRSessionRef
* thisOne
)
55 CFMutableDataRef serialized
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
57 SecOTRSAppendSerialization(*thisOne
, serialized
);
58 CFReleaseNull(*thisOne
);
59 *thisOne
= SecOTRSessionCreateFromData(kCFAllocatorDefault
, serialized
);
61 CFReleaseSafe(serialized
);
64 #define renegotiateTests 9
66 static void renegotiate(SecOTRSessionRef
*bobSession
, SecOTRSessionRef
*aliceSession
, bool serializeNegotiating
, CFDataRef messageDuringNegotiation
){
68 CFMutableDataRef aliceRestartPacket
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
69 CFMutableDataRef bobDHKeyPacket
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
71 CFDataRef empty
= CFDataCreate(kCFAllocatorDefault
, NULL
, 0);
73 CFMutableDataRef hopefullyNothing
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
75 //send a restart packet after session has successfully sent messages
76 ok_status(SecOTRSAppendRestartPacket(*aliceSession
, aliceRestartPacket
), "Alice restart packet");
78 if(serializeNegotiating
)
79 serializeAndDeserialize(aliceSession
);
82 skip("No messageDuringNegotiation", 1, messageDuringNegotiation
);
83 is(SecOTRSVerifyAndExposeMessage(*aliceSession
, messageDuringNegotiation
, hopefullyNothing
), errSecOTRNotReady
, "Message during negotiation");
86 if(serializeNegotiating
)
87 serializeAndDeserialize(aliceSession
);
89 ok_status(SecOTRSProcessPacket(*bobSession
, aliceRestartPacket
, bobDHKeyPacket
),
90 "Bob DH packet failed");
92 if (serializeNegotiating
)
93 serializeAndDeserialize(bobSession
);
95 // Step 3: With one "real" DH key message, and one replayed DH commit message, try to get a "reveal sig" out of one side
97 CFMutableDataRef aliceRevealSigPacket
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
99 ok_status(SecOTRSProcessPacket(*aliceSession
, bobDHKeyPacket
, aliceRevealSigPacket
),
100 "Alice DH Key packet failed");
102 if (serializeNegotiating
)
103 serializeAndDeserialize(aliceSession
);
105 CFMutableDataRef bobRevealSigResponse
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
107 ok_status(SecOTRSProcessPacket(*bobSession
, aliceRevealSigPacket
, bobRevealSigResponse
),
108 "Bob DH Key packet failed");
110 if (serializeNegotiating
)
111 serializeAndDeserialize(bobSession
);
113 // Step 4: Having gotten the reveal signature, now work for the signature
115 CFMutableDataRef aliceSigPacket
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
117 ok_status(SecOTRSProcessPacket(*aliceSession
, bobRevealSigResponse
, aliceSigPacket
),
118 "Bob Reveal sig failed");
120 if (serializeNegotiating
)
121 serializeAndDeserialize(aliceSession
);
124 ok(SecOTRSGetIsReadyForMessages(*bobSession
), "Bob is ready");
125 ok(SecOTRSGetIsReadyForMessages(*aliceSession
), "Alice is ready");
127 CFReleaseNull(aliceRestartPacket
);
128 CFReleaseNull(aliceRevealSigPacket
);
129 CFReleaseNull(aliceSigPacket
);
131 CFReleaseNull(bobDHKeyPacket
);
132 CFReleaseNull(bobRevealSigResponse
);
134 CFReleaseNull(hopefullyNothing
);
135 CFReleaseNull(empty
);
140 #define sendMessagesCount(n) ((n) * 14)
141 static void sendMessages(int howMany
, SecOTRSessionRef
*bobSession
, SecOTRSessionRef
*aliceSession
, bool serialize
)
143 for(int count
= howMany
; count
> 0; --count
) {
144 const char* aliceToBob
= "aliceToBob";
145 CFDataRef rawAliceToBob
= CFDataCreate(kCFAllocatorDefault
, (const uint8_t*)aliceToBob
, (CFIndex
) strlen(aliceToBob
));
146 CFMutableDataRef protectedAliceToBob
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
147 CFMutableDataRef bobDecode
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
149 ok_status(SecOTRSSignAndProtectMessage(*aliceSession
, rawAliceToBob
, protectedAliceToBob
), "encode message");
150 ok_status(SecOTRSVerifyAndExposeMessage(*bobSession
, protectedAliceToBob
, bobDecode
), "Decode message");
154 serializeAndDeserialize(bobSession
);
155 serializeAndDeserialize(aliceSession
);
158 ok(CFDataGetLength(rawAliceToBob
) == CFDataGetLength(bobDecode
)
159 && 0 == memcmp(CFDataGetBytePtr(rawAliceToBob
), CFDataGetBytePtr(bobDecode
), (size_t)CFDataGetLength(rawAliceToBob
)), "Didn't match!");
161 CFReleaseNull(rawAliceToBob
);
162 CFReleaseNull(protectedAliceToBob
);
163 CFReleaseNull(bobDecode
);
165 const char* bobToAlice
= "i liked your silly message from me to you";
166 CFDataRef rawBobToAlice
= CFDataCreate(kCFAllocatorDefault
, (const uint8_t*)bobToAlice
, (CFIndex
) strlen(bobToAlice
));
167 CFMutableDataRef protectedBobToAlice
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
168 CFMutableDataRef aliceDecode
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
170 ok_status(SecOTRSSignAndProtectMessage(*aliceSession
, rawBobToAlice
, protectedBobToAlice
), "encode reply");
171 ok_status(SecOTRSVerifyAndExposeMessage(*bobSession
, protectedBobToAlice
, aliceDecode
), "decode reply");
174 serializeAndDeserialize(bobSession
);
175 serializeAndDeserialize(aliceSession
);
178 ok(CFDataGetLength(rawBobToAlice
) == CFDataGetLength(aliceDecode
)
179 && 0 == memcmp(CFDataGetBytePtr(rawBobToAlice
), CFDataGetBytePtr(aliceDecode
), (size_t)CFDataGetLength(rawBobToAlice
)), "reply matched");
181 CFReleaseNull(rawAliceToBob
);
182 CFReleaseNull(rawBobToAlice
);
183 CFReleaseNull(protectedBobToAlice
);
184 CFReleaseNull(protectedAliceToBob
);
185 CFReleaseNull(aliceDecode
);
187 rawAliceToBob
= CFDataCreate(kCFAllocatorDefault
, (const uint8_t*)aliceToBob
, (CFIndex
) strlen(aliceToBob
));
188 protectedAliceToBob
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
189 bobDecode
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
191 ok_status(SecOTRSSignAndProtectMessage(*aliceSession
, rawAliceToBob
, protectedAliceToBob
), "encode message");
192 ok_status(SecOTRSVerifyAndExposeMessage(*bobSession
, protectedAliceToBob
, bobDecode
), "Decode message");
195 serializeAndDeserialize(bobSession
);
196 serializeAndDeserialize(aliceSession
);
199 ok(CFDataGetLength(rawAliceToBob
) == CFDataGetLength(bobDecode
)
200 && 0 == memcmp(CFDataGetBytePtr(rawAliceToBob
), CFDataGetBytePtr(bobDecode
), (size_t)CFDataGetLength(rawAliceToBob
)), "Didn't match!");
202 CFReleaseNull(rawAliceToBob
);
203 CFReleaseNull(protectedAliceToBob
);
204 CFReleaseNull(bobDecode
);
206 bobToAlice
= "i liked your silly message from me to you";
207 rawBobToAlice
= CFDataCreate(kCFAllocatorDefault
, (const uint8_t*)bobToAlice
, (CFIndex
) strlen(bobToAlice
));
208 protectedBobToAlice
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
209 aliceDecode
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
211 ok_status(SecOTRSSignAndProtectMessage(*aliceSession
, rawBobToAlice
, protectedBobToAlice
), "encode reply");
212 ok_status(SecOTRSVerifyAndExposeMessage(*bobSession
, protectedBobToAlice
, aliceDecode
), "decode reply");
215 serializeAndDeserialize(bobSession
);
216 serializeAndDeserialize(aliceSession
);
219 ok(CFDataGetLength(rawBobToAlice
) == CFDataGetLength(aliceDecode
)
220 && 0 == memcmp(CFDataGetBytePtr(rawBobToAlice
), CFDataGetBytePtr(aliceDecode
), (size_t)CFDataGetLength(rawBobToAlice
)), "reply matched");
222 CFReleaseNull(rawAliceToBob
);
223 CFReleaseNull(rawBobToAlice
);
224 CFReleaseNull(protectedBobToAlice
);
225 CFReleaseNull(protectedAliceToBob
);
226 CFReleaseNull(aliceDecode
);
230 CFStringRef stateString
= CFCopyDescription(*bobSession
);
231 ok(stateString
, "getting state from bob");
232 CFReleaseNull(stateString
);
234 stateString
= CFCopyDescription(*aliceSession
);
235 ok(stateString
, "getting state from alice");
236 CFReleaseNull(stateString
);
240 #define kNegotiateTestCount (14 + sendMessagesCount(1) * 4 \
243 static void negotiate(SecOTRSessionRef
* aliceSession
, SecOTRSessionRef
* bobSession
, SecOTRSessionRef
*brandNewBobSession
, bool serializeNegotiating
, bool serializeMessaging
, bool textMode
, bool compact
)
245 const int kEmptyMessageSize
= textMode
? 6 : 0;
247 // Step 1: Create a start packet for each side of the transaction
248 CFMutableDataRef bobStartPacket
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
250 ok_status(SecOTRSAppendStartPacket(*bobSession
, bobStartPacket
), "Bob start packet");
252 if (serializeNegotiating
)
253 serializeAndDeserialize(bobSession
);
255 CFMutableDataRef aliceStartPacket
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
257 ok_status(SecOTRSAppendStartPacket(*aliceSession
, aliceStartPacket
), "Alice start packet");
259 if (serializeNegotiating
)
260 serializeAndDeserialize(aliceSession
);
262 // Step 2: Exchange the start packets, forcing the DH commit messages to collide
263 CFMutableDataRef aliceDHKeyResponse
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
265 ok_status(SecOTRSProcessPacket(*aliceSession
, bobStartPacket
, aliceDHKeyResponse
),
266 "Bob DH packet failed");
268 if (serializeNegotiating
)
269 serializeAndDeserialize(aliceSession
);
271 CFReleaseNull(bobStartPacket
);
273 CFMutableDataRef bobDHKeyResponse
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
275 ok_status(SecOTRSProcessPacket(*bobSession
, aliceStartPacket
, bobDHKeyResponse
),
276 "Alice DH packet failed");
278 if (serializeNegotiating
)
279 serializeAndDeserialize(bobSession
);
281 CFReleaseNull(aliceStartPacket
);
283 // Step 3: With one "real" DH key message, and one replayed DH commit message, try to get a "reveal sig" out of one side
285 CFMutableDataRef bobRevealSigResponse
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
287 ok_status(SecOTRSProcessPacket(*bobSession
, aliceDHKeyResponse
, bobRevealSigResponse
),
288 "Alice DH Key packet failed");
290 if (serializeNegotiating
)
291 serializeAndDeserialize(bobSession
);
293 CFReleaseNull(aliceDHKeyResponse
);
295 CFMutableDataRef aliceRevealSigResponse
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
297 ok_status(SecOTRSProcessPacket(*aliceSession
, bobDHKeyResponse
, aliceRevealSigResponse
),
298 "Bob DH Key packet failed");
300 if (serializeNegotiating
)
301 serializeAndDeserialize(aliceSession
);
303 CFReleaseNull(bobDHKeyResponse
);
305 // Step 4: Having gotten the reveal signature, now work for the signature
307 CFMutableDataRef aliceSigResponse
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
309 ok_status(SecOTRSProcessPacket(*aliceSession
, bobRevealSigResponse
, aliceSigResponse
),
310 "Bob Reveal sig failed");
312 if (serializeNegotiating
)
313 serializeAndDeserialize(aliceSession
);
315 CFReleaseNull(bobRevealSigResponse
);
317 CFMutableDataRef bobSigResponse
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
319 ok_status(SecOTRSProcessPacket(*bobSession
, aliceRevealSigResponse
, bobSigResponse
),
320 "Alice Reveal sig failed");
322 if (serializeNegotiating
)
323 serializeAndDeserialize(bobSession
);
325 CFReleaseNull(aliceRevealSigResponse
);
327 // Step 5: All the messages have been sent, now deal with any replays from the collision handling
328 CFMutableDataRef bobFinalResponse
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
330 ok_status(SecOTRSProcessPacket(*bobSession
, aliceSigResponse
, bobFinalResponse
),
331 "Alice Final Sig failed");
333 if (serializeNegotiating
)
334 serializeAndDeserialize(bobSession
);
336 CFMutableDataRef aliceFinalResponse
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
338 ok_status(SecOTRSProcessPacket(*aliceSession
, bobSigResponse
, aliceFinalResponse
),
339 "Bob Final Sig failed");
341 is(kEmptyMessageSize
, CFDataGetLength(aliceFinalResponse
), "Alice had nothing left to say");
342 CFReleaseNull(aliceFinalResponse
);
343 CFReleaseNull(bobSigResponse
);
345 if (serializeNegotiating
)
346 serializeAndDeserialize(aliceSession
);
348 is(kEmptyMessageSize
, CFDataGetLength(bobFinalResponse
), "Bob had nothing left to say");
349 ok(SecOTRSGetIsReadyForMessages(*bobSession
), "Bob is ready");
350 ok(SecOTRSGetIsReadyForMessages(*aliceSession
), "Alice is ready");
352 CFReleaseNull(aliceSigResponse
);
353 CFReleaseNull(bobFinalResponse
);
355 sendMessages(1, bobSession
, aliceSession
, serializeMessaging
);
356 sendMessages(1, aliceSession
, bobSession
, serializeMessaging
);
357 sendMessages(1, bobSession
, aliceSession
, serializeMessaging
);
358 sendMessages(1, aliceSession
, bobSession
, serializeMessaging
);
360 const char *bobToAlice
= "i liked your silly message from me to you";
361 CFDataRef rawBobToAlice
= CFDataCreate(kCFAllocatorDefault
, (const uint8_t*)bobToAlice
, (CFIndex
) strlen(bobToAlice
));
362 CFMutableDataRef protectedBobToAlice
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
364 ok_status(SecOTRSSignAndProtectMessage(*bobSession
, rawBobToAlice
, protectedBobToAlice
), "protected bob to alice message");
366 CFReleaseNull(rawBobToAlice
);
368 renegotiate(brandNewBobSession
, aliceSession
, serializeNegotiating
, protectedBobToAlice
);
370 CFReleaseNull(protectedBobToAlice
);
374 #define kEdgeCaseTestCount (10 + kNegotiateTestCount * 2)
376 static void tryEdgeCases(uint32_t flags
)
378 CFErrorRef testError
= NULL
;
379 SecOTRFullIdentityRef aliceID
= SecOTRFullIdentityCreate(kCFAllocatorDefault
, &testError
);
380 SecMPLogError(testError
);
381 CFReleaseNull(testError
);
383 SecOTRFullIdentityRef bobID
= SecOTRFullIdentityCreate(kCFAllocatorDefault
, &testError
);
384 SecMPLogError(testError
);
385 CFReleaseNull(testError
);
388 ok(aliceID
, "create alice ID");
389 ok(bobID
, "create bob ID");
391 SecOTRPublicIdentityRef alicePublicID
= SecOTRPublicIdentityCopyFromPrivate(kCFAllocatorDefault
, aliceID
, &testError
);
392 SecMPLogError(testError
);
393 CFReleaseNull(testError
);
394 SecOTRPublicIdentityRef bobPublicID
= SecOTRPublicIdentityCopyFromPrivate(kCFAllocatorDefault
, bobID
, &testError
);
395 SecMPLogError(testError
);
396 CFReleaseNull(testError
);
398 ok(alicePublicID
, "extract alice public");
399 ok(bobPublicID
, "extract bob public");
401 SecOTRSessionRef aliceSession
= SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault
, aliceID
, bobPublicID
, flags
);
402 SecOTRSessionRef bobSession
= SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault
, bobID
, alicePublicID
, flags
);
403 SecOTRSessionRef brandNewBobSession
= SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault
, bobID
, alicePublicID
, flags
);
404 SecOTRSessionRef brandNewBobSession2
= SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault
, bobID
, alicePublicID
, flags
);
405 SecOTRSessionRef brandNewBobSession3
= SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault
, bobID
, alicePublicID
, flags
);
407 ok(aliceSession
, "create alice session");
408 ok(bobSession
, "create bob session");
409 ok(brandNewBobSession
, "create new bob session");
412 // Release the IDs, sessions shouldn't need us to retain them for them.
413 CFReleaseNull(aliceID
);
414 CFReleaseNull(bobID
);
416 CFReleaseNull(alicePublicID
);
417 CFReleaseNull(bobPublicID
);
419 negotiate(&aliceSession
, &bobSession
, &brandNewBobSession
, true, true, false, flags
& kSecOTRUseAppleCustomMessageFormat
);
421 negotiate(&aliceSession
, &bobSession
, &brandNewBobSession2
, true, false, false, flags
& kSecOTRUseAppleCustomMessageFormat
);
424 const char * testMessageString
= "i liked your silly message from me to you";
425 CFDataRef testMessage
= CFDataCreate(kCFAllocatorDefault
, (const uint8_t*)testMessageString
, (CFIndex
) strlen(testMessageString
));
426 CFMutableDataRef protectedTestMessage
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
428 ok_status(SecOTRSSignAndProtectMessage(aliceSession
, testMessage
, protectedTestMessage
), "Make message");
430 CFMutableDataRef hopefullyNothing
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
432 is(SecOTRSVerifyAndExposeMessage(brandNewBobSession3
, protectedTestMessage
, hopefullyNothing
), errSecOTRNotReady
, "Message Before Negotiating");
434 /* cleanup keychain */
435 ok(SecOTRFIPurgeAllFromKeychain(&testError
),"cleanup keychain");
436 SecMPLogError(testError
);
437 CFReleaseNull(testError
);
439 CFReleaseNull(aliceSession
);
440 CFReleaseNull(bobSession
);
442 CFReleaseNull(brandNewBobSession
);
443 CFReleaseNull(brandNewBobSession2
);
444 CFReleaseNull(brandNewBobSession3
);
445 CFReleaseNull(testMessage
);
446 CFReleaseNull(protectedTestMessage
);
447 CFReleaseNull(hopefullyNothing
);
451 #define kTestTestCount (2 * kEdgeCaseTestCount)
456 tryEdgeCases(kSecOTRUseAppleCustomMessageFormat
);
459 int otr_40_edgecases(int argc
, char *const *argv
)
461 plan_tests(kTestTestCount
);