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/SecOTRSessionPriv.h>
30 #include <Security/SecInternal.h>
31 #include <Security/SecBasePriv.h>
33 static void SecMPLogError(CFErrorRef error
) {
37 CFDictionaryRef tempDictionary
= CFErrorCopyUserInfo(error
);
38 CFIndex errorCode
= CFErrorGetCode(error
);
39 CFStringRef errorDomain
= CFErrorGetDomain(error
);
40 CFStringRef errorString
= CFDictionaryGetValue(tempDictionary
, kCFErrorDescriptionKey
);
41 CFErrorRef previousError
= (CFErrorRef
)CFDictionaryGetValue(tempDictionary
, kCFErrorUnderlyingErrorKey
);
42 if (previousError
!= NULL
) {
43 SecMPLogError(previousError
);
45 char errorDomainStr
[1024];
46 char errorStringStr
[1024];
48 CFStringGetCString(errorDomain
, errorDomainStr
, 1024, kCFStringEncodingUTF8
);
49 CFStringGetCString(errorString
, errorStringStr
, 1024, kCFStringEncodingUTF8
);
50 printf("MessageProtection: %s (%ld) -- %s\n", errorDomainStr
, errorCode
, errorStringStr
);
51 CFReleaseSafe(tempDictionary
);
54 static void serializeAndDeserialize(SecOTRSessionRef
* thisOne
)
56 CFMutableDataRef serialized
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
58 SecOTRSAppendSerialization(*thisOne
, serialized
);
59 CFReleaseNull(*thisOne
);
60 *thisOne
= SecOTRSessionCreateFromData(kCFAllocatorDefault
, serialized
);
62 CFReleaseSafe(serialized
);
67 #define sendMessagesCount(n) ((n) * 5)
68 static void sendMessages(int howMany
, SecOTRSessionRef
*bobSession
, SecOTRSessionRef
*aliceSession
, bool serialize
)
70 for(int count
= howMany
; count
> 0; --count
) {
71 const char* aliceToBob
= "aliceToBob";
72 CFDataRef rawAliceToBob
= CFDataCreate(kCFAllocatorDefault
, (const uint8_t*)aliceToBob
, (CFIndex
) strlen(aliceToBob
));
73 CFMutableDataRef protectedAliceToBob
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
74 CFMutableDataRef bobDecode
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
76 ok_status(SecOTRSSignAndProtectMessage(*aliceSession
, rawAliceToBob
, protectedAliceToBob
), "encode message");
77 ok_status(SecOTRSVerifyAndExposeMessage(*bobSession
, protectedAliceToBob
, bobDecode
), "Decode message");
81 serializeAndDeserialize(bobSession
);
82 serializeAndDeserialize(aliceSession
);
85 ok(CFDataGetLength(rawAliceToBob
) == CFDataGetLength(bobDecode
)
86 && 0 == memcmp(CFDataGetBytePtr(rawAliceToBob
), CFDataGetBytePtr(bobDecode
), (size_t)CFDataGetLength(rawAliceToBob
)), "Didn't match!");
88 CFReleaseNull(rawAliceToBob
);
89 CFReleaseNull(protectedAliceToBob
);
90 CFReleaseNull(bobDecode
);
92 CFStringRef stateString
= CFCopyDescription(*bobSession
);
93 ok(stateString
, "getting state from bob");
94 CFReleaseNull(stateString
);
96 stateString
= CFCopyDescription(*aliceSession
);
97 ok(stateString
, "getting state from alice");
98 CFReleaseNull(stateString
);
102 #define kNegotiateTestCount (14 \
103 + 60 + (69 * sendMessagesCount(1)))
104 static void negotiate(SecOTRSessionRef
* aliceSession
, SecOTRSessionRef
* bobSession
, bool serializeNegotiating
, bool serializeMessaging
, bool textMode
, bool compact
)
106 const int kEmptyMessageSize
= textMode
? 6 : 0;
108 // Step 1: Create a start packet for each side of the transaction
109 CFMutableDataRef bobStartPacket
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
111 ok_status(SecOTRSAppendStartPacket(*bobSession
, bobStartPacket
), "Bob start packet");
113 if (serializeNegotiating
)
114 serializeAndDeserialize(bobSession
);
116 CFMutableDataRef aliceStartPacket
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
118 ok_status(SecOTRSAppendStartPacket(*aliceSession
, aliceStartPacket
), "Alice start packet");
120 if (serializeNegotiating
)
121 serializeAndDeserialize(aliceSession
);
123 // Step 2: Exchange the start packets, forcing the DH commit messages to collide
124 CFMutableDataRef aliceDHKeyResponse
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
126 ok_status(SecOTRSProcessPacket(*aliceSession
, bobStartPacket
, aliceDHKeyResponse
),
127 "Bob DH packet failed");
129 if (serializeNegotiating
)
130 serializeAndDeserialize(aliceSession
);
132 CFReleaseNull(bobStartPacket
);
134 CFMutableDataRef bobDHKeyResponse
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
136 ok_status(SecOTRSProcessPacket(*bobSession
, aliceStartPacket
, bobDHKeyResponse
),
137 "Alice DH packet failed");
139 if (serializeNegotiating
)
140 serializeAndDeserialize(bobSession
);
142 CFReleaseNull(aliceStartPacket
);
144 // Step 3: With one "real" DH key message, and one replayed DH commit message, try to get a "reveal sig" out of one side
146 CFMutableDataRef bobRevealSigResponse
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
148 ok_status(SecOTRSProcessPacket(*bobSession
, aliceDHKeyResponse
, bobRevealSigResponse
),
149 "Alice DH Key packet failed");
151 if (serializeNegotiating
)
152 serializeAndDeserialize(bobSession
);
154 CFReleaseNull(aliceDHKeyResponse
);
156 CFMutableDataRef aliceRevealSigResponse
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
158 ok_status(SecOTRSProcessPacket(*aliceSession
, bobDHKeyResponse
, aliceRevealSigResponse
),
159 "Bob DH Key packet failed");
161 if (serializeNegotiating
)
162 serializeAndDeserialize(aliceSession
);
164 CFReleaseNull(bobDHKeyResponse
);
166 // Step 4: Having gotten the reveal signature, now work for the signature
168 CFMutableDataRef aliceSigResponse
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
170 ok_status(SecOTRSProcessPacket(*aliceSession
, bobRevealSigResponse
, aliceSigResponse
),
171 "Bob Reveal sig failed");
173 if (serializeNegotiating
)
174 serializeAndDeserialize(aliceSession
);
176 CFReleaseNull(bobRevealSigResponse
);
178 CFMutableDataRef bobSigResponse
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
180 ok_status(SecOTRSProcessPacket(*bobSession
, aliceRevealSigResponse
, bobSigResponse
),
181 "Alice Reveal sig failed");
183 if (serializeNegotiating
)
184 serializeAndDeserialize(bobSession
);
186 CFReleaseNull(aliceRevealSigResponse
);
188 // Step 5: All the messages have been sent, now deal with any replays from the collision handling
189 CFMutableDataRef bobFinalResponse
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
191 ok_status(SecOTRSProcessPacket(*bobSession
, aliceSigResponse
, bobFinalResponse
),
192 "Alice Final Sig failed");
194 if (serializeNegotiating
)
195 serializeAndDeserialize(bobSession
);
197 CFMutableDataRef aliceFinalResponse
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
199 ok_status(SecOTRSProcessPacket(*aliceSession
, bobSigResponse
, aliceFinalResponse
),
200 "Bob Final Sig failed");
202 is(kEmptyMessageSize
, CFDataGetLength(aliceFinalResponse
), "Alice had nothing left to say");
203 CFReleaseNull(aliceFinalResponse
);
204 CFReleaseNull(bobSigResponse
);
206 if (serializeNegotiating
)
207 serializeAndDeserialize(aliceSession
);
209 is(kEmptyMessageSize
, CFDataGetLength(bobFinalResponse
), "Bob had nothing left to say");
210 ok(SecOTRSGetIsReadyForMessages(*bobSession
), "Bob is ready");
211 ok(SecOTRSGetIsReadyForMessages(*aliceSession
), "Alice is ready");
213 CFReleaseNull(aliceSigResponse
);
214 CFReleaseNull(bobFinalResponse
);
217 //both sessions are kicked to roll
219 SecOTRSKickTimeToRoll(*aliceSession
);
220 SecOTRSKickTimeToRoll(*bobSession
);
222 sendMessages(1, aliceSession
, bobSession
, serializeMessaging
);
223 sendMessages(1, bobSession
, aliceSession
, serializeMessaging
);
224 sendMessages(1, aliceSession
, bobSession
, serializeMessaging
);
226 //now we make sure keys do not roll for 10 iterations
227 int aliceKeyID
= SecOTRSGetKeyID(*aliceSession
);
228 int bobKeyID
= SecOTRSGetKeyID(*bobSession
);
230 for(int i
= 0; i
< 10; i
++){
231 sendMessages(1, bobSession
, aliceSession
, serializeMessaging
);
232 sendMessages(1, aliceSession
, bobSession
, serializeMessaging
);
234 ok(SecOTRSGetKeyID(*aliceSession
) == aliceKeyID
);
235 ok(SecOTRSGetKeyID(*bobSession
) == bobKeyID
);
239 //kicking sending side
242 SecOTRSKickTimeToRoll(*aliceSession
);
243 sendMessages(1, aliceSession
, bobSession
, serializeMessaging
);
245 sendMessages(1, bobSession
, aliceSession
, serializeMessaging
);
246 sendMessages(1, aliceSession
, bobSession
, serializeMessaging
);
248 //now we make sure keys do not roll for 10 iterations
249 aliceKeyID
= SecOTRSGetKeyID(*aliceSession
);
250 bobKeyID
= SecOTRSGetKeyID(*bobSession
);
252 for(int i
= 0; i
< 10; i
++){
253 sendMessages(1, aliceSession
, bobSession
, serializeMessaging
);
254 sendMessages(1, bobSession
, aliceSession
, serializeMessaging
);
256 ok(SecOTRSGetKeyID(*aliceSession
) == aliceKeyID
);
257 ok(SecOTRSGetKeyID(*bobSession
) == bobKeyID
);
260 //kicking receiving side
262 SecOTRSKickTimeToRoll(*bobSession
);
263 sendMessages(1, bobSession
, aliceSession
, serializeMessaging
);
265 sendMessages(1, aliceSession
, bobSession
, serializeMessaging
);
266 sendMessages(1, bobSession
, aliceSession
, serializeMessaging
);
268 aliceKeyID
= SecOTRSGetKeyID(*aliceSession
);
269 bobKeyID
= SecOTRSGetKeyID(*bobSession
);
271 for(int i
= 0; i
< 10; i
++){
272 sendMessages(1, aliceSession
, bobSession
, serializeMessaging
);
273 sendMessages(1, bobSession
, aliceSession
, serializeMessaging
);
275 ok(SecOTRSGetKeyID(*aliceSession
) == aliceKeyID
);
276 ok(SecOTRSGetKeyID(*bobSession
) == bobKeyID
);
282 #define kTestTestCount (11 + kNegotiateTestCount * 6)
286 CFErrorRef testError
= NULL
;
287 SecOTRFullIdentityRef aliceID
= SecOTRFullIdentityCreate(kCFAllocatorDefault
, &testError
);
288 SecMPLogError(testError
);
289 CFReleaseNull(testError
);
291 SecOTRFullIdentityRef bobID
= SecOTRFullIdentityCreate(kCFAllocatorDefault
, &testError
);
292 SecMPLogError(testError
);
293 CFReleaseNull(testError
);
296 ok(aliceID
, "create alice ID");
297 ok(bobID
, "create bob ID");
299 SecOTRPublicIdentityRef alicePublicID
= SecOTRPublicIdentityCopyFromPrivate(kCFAllocatorDefault
, aliceID
, &testError
);
300 SecMPLogError(testError
);
301 CFReleaseNull(testError
);
302 SecOTRPublicIdentityRef bobPublicID
= SecOTRPublicIdentityCopyFromPrivate(kCFAllocatorDefault
, bobID
, &testError
);
303 SecMPLogError(testError
);
304 CFReleaseNull(testError
);
306 ok(alicePublicID
, "extract alice public");
307 ok(bobPublicID
, "extract bob public");
309 SecOTRSessionRef aliceSession
= SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault
, aliceID
, bobPublicID
, kSecOTRSendTextMessages
| kSecOTRSlowRoll
);
310 SecOTRSessionRef bobSession
= SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault
, bobID
, alicePublicID
, kSecOTRSendTextMessages
| kSecOTRSlowRoll
);
312 ok(aliceSession
, "create alice session");
313 ok(bobSession
, "create bob session");
315 SecOTRSessionRef aliceCompactSession
= SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault
, aliceID
, bobPublicID
, kSecOTRUseAppleCustomMessageFormat
| kSecOTRSlowRoll
);
316 SecOTRSessionRef bobCompactSession
= SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault
, bobID
, alicePublicID
, kSecOTRUseAppleCustomMessageFormat
| kSecOTRSlowRoll
);
318 ok(aliceCompactSession
, "create alice compact session");
319 ok(bobCompactSession
, "create bob compact session");
321 SecOTRSessionRef aliceCompactHashesSession
= SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault
, aliceID
, bobPublicID
, kSecOTRUseAppleCustomMessageFormat
|kSecOTRIncludeHashesInMessages
| kSecOTRSlowRoll
);
322 SecOTRSessionRef bobCompactHashesSession
= SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault
, bobID
, alicePublicID
, kSecOTRUseAppleCustomMessageFormat
|kSecOTRIncludeHashesInMessages
| kSecOTRSlowRoll
);
324 ok(aliceCompactHashesSession
, "create alice compact session with hashes");
325 ok(bobCompactHashesSession
, "create bob compact session with hashes");
327 // Release the IDs, sessions shouldn't need us to retain them for them.
328 CFReleaseNull(aliceID
);
329 CFReleaseNull(bobID
);
331 CFReleaseNull(alicePublicID
);
332 CFReleaseNull(bobPublicID
);
334 negotiate(&aliceSession
, &bobSession
, true, true, true, false);
336 negotiate(&aliceSession
, &bobSession
, true, false, true, false);
338 negotiate(&aliceCompactSession
, &bobCompactSession
, true, true, false, true);
340 negotiate(&aliceCompactSession
, &bobCompactSession
, true, false, false, true);
342 negotiate(&aliceCompactHashesSession
, &bobCompactHashesSession
, true, true, false, true);
344 negotiate(&aliceCompactHashesSession
, &bobCompactHashesSession
, true, false, false, true);
346 /* cleanup keychain */
347 ok(SecOTRFIPurgeAllFromKeychain(&testError
),"cleanup keychain");
348 SecMPLogError(testError
);
349 CFReleaseNull(testError
);
351 CFReleaseNull(aliceSession
);
352 CFReleaseNull(bobSession
);
354 CFReleaseNull(aliceCompactSession
);
355 CFReleaseNull(bobCompactSession
);
357 CFReleaseNull(aliceCompactHashesSession
);
358 CFReleaseNull(bobCompactHashesSession
);
361 int otr_60_slowroll(int argc
, char *const *argv
)
363 plan_tests(kTestTestCount
);