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
);
66 #define sendMessagesCount(n) ((n) * 14)
67 static void sendMessages(int howMany
, SecOTRSessionRef
*bobSession
, SecOTRSessionRef
*aliceSession
, bool serialize
)
69 for(int count
= howMany
; count
> 0; --count
) {
70 const char* aliceToBob
= "aliceToBob";
71 CFDataRef rawAliceToBob
= CFDataCreate(kCFAllocatorDefault
, (const uint8_t*)aliceToBob
, (CFIndex
) strlen(aliceToBob
));
72 CFMutableDataRef protectedAliceToBob
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
73 CFMutableDataRef bobDecode
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
75 ok_status(SecOTRSSignAndProtectMessage(*aliceSession
, rawAliceToBob
, protectedAliceToBob
), "encode message");
76 ok_status(SecOTRSVerifyAndExposeMessage(*bobSession
, protectedAliceToBob
, bobDecode
), "Decode message");
80 serializeAndDeserialize(bobSession
);
81 serializeAndDeserialize(aliceSession
);
84 ok(CFDataGetLength(rawAliceToBob
) == CFDataGetLength(bobDecode
)
85 && 0 == memcmp(CFDataGetBytePtr(rawAliceToBob
), CFDataGetBytePtr(bobDecode
), (size_t)CFDataGetLength(rawAliceToBob
)), "Didn't match!");
87 CFReleaseNull(rawAliceToBob
);
88 CFReleaseNull(protectedAliceToBob
);
89 CFReleaseNull(bobDecode
);
91 const char* bobToAlice
= "i liked your silly message from me to you";
92 CFDataRef rawBobToAlice
= CFDataCreate(kCFAllocatorDefault
, (const uint8_t*)bobToAlice
, (CFIndex
) strlen(bobToAlice
));
93 CFMutableDataRef protectedBobToAlice
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
94 CFMutableDataRef aliceDecode
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
96 ok_status(SecOTRSSignAndProtectMessage(*aliceSession
, rawBobToAlice
, protectedBobToAlice
), "encode reply");
97 ok_status(SecOTRSVerifyAndExposeMessage(*bobSession
, protectedBobToAlice
, aliceDecode
), "decode reply");
100 serializeAndDeserialize(bobSession
);
101 serializeAndDeserialize(aliceSession
);
104 ok(CFDataGetLength(rawBobToAlice
) == CFDataGetLength(aliceDecode
)
105 && 0 == memcmp(CFDataGetBytePtr(rawBobToAlice
), CFDataGetBytePtr(aliceDecode
), (size_t)CFDataGetLength(rawBobToAlice
)), "reply matched");
107 CFReleaseNull(rawAliceToBob
);
108 CFReleaseNull(rawBobToAlice
);
109 CFReleaseNull(protectedBobToAlice
);
110 CFReleaseNull(protectedAliceToBob
);
111 CFReleaseNull(aliceDecode
);
113 rawAliceToBob
= CFDataCreate(kCFAllocatorDefault
, (const uint8_t*)aliceToBob
, (CFIndex
) strlen(aliceToBob
));
114 protectedAliceToBob
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
115 bobDecode
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
117 ok_status(SecOTRSSignAndProtectMessage(*aliceSession
, rawAliceToBob
, protectedAliceToBob
), "encode message");
118 ok_status(SecOTRSVerifyAndExposeMessage(*bobSession
, protectedAliceToBob
, bobDecode
), "Decode message");
121 serializeAndDeserialize(bobSession
);
122 serializeAndDeserialize(aliceSession
);
125 ok(CFDataGetLength(rawAliceToBob
) == CFDataGetLength(bobDecode
)
126 && 0 == memcmp(CFDataGetBytePtr(rawAliceToBob
), CFDataGetBytePtr(bobDecode
), (size_t)CFDataGetLength(rawAliceToBob
)), "Didn't match!");
128 CFReleaseNull(rawAliceToBob
);
129 CFReleaseNull(protectedAliceToBob
);
130 CFReleaseNull(bobDecode
);
132 bobToAlice
= "i liked your silly message from me to you";
133 rawBobToAlice
= CFDataCreate(kCFAllocatorDefault
, (const uint8_t*)bobToAlice
, (CFIndex
) strlen(bobToAlice
));
134 protectedBobToAlice
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
135 aliceDecode
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
137 ok_status(SecOTRSSignAndProtectMessage(*aliceSession
, rawBobToAlice
, protectedBobToAlice
), "encode reply");
138 ok_status(SecOTRSVerifyAndExposeMessage(*bobSession
, protectedBobToAlice
, aliceDecode
), "decode reply");
141 serializeAndDeserialize(bobSession
);
142 serializeAndDeserialize(aliceSession
);
145 ok(CFDataGetLength(rawBobToAlice
) == CFDataGetLength(aliceDecode
)
146 && 0 == memcmp(CFDataGetBytePtr(rawBobToAlice
), CFDataGetBytePtr(aliceDecode
), (size_t)CFDataGetLength(rawBobToAlice
)), "reply matched");
148 CFReleaseNull(rawAliceToBob
);
149 CFReleaseNull(rawBobToAlice
);
150 CFReleaseNull(protectedBobToAlice
);
151 CFReleaseNull(protectedAliceToBob
);
152 CFReleaseNull(aliceDecode
);
156 CFStringRef stateString
= CFCopyDescription(*bobSession
);
157 ok(stateString
, "getting state from bob");
158 CFReleaseNull(stateString
);
160 stateString
= CFCopyDescription(*aliceSession
);
161 ok(stateString
, "getting state from alice");
162 CFReleaseNull(stateString
);
166 #define kNegotiateTestCount (14 + sendMessagesCount(5) \
167 + 2 + sendMessagesCount(1) \
168 + 1 + sendMessagesCount(1) \
169 + sendMessagesCount(3))
170 static void negotiate(SecOTRSessionRef
* aliceSession
, SecOTRSessionRef
* bobSession
, bool serializeNegotiating
, bool serializeMessaging
, bool textMode
, bool compact
)
172 const int kEmptyMessageSize
= textMode
? 6 : 0;
174 // Step 1: Create a start packet for each side of the transaction
175 CFMutableDataRef bobStartPacket
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
177 ok_status(SecOTRSAppendStartPacket(*bobSession
, bobStartPacket
), "Bob start packet");
179 if (serializeNegotiating
)
180 serializeAndDeserialize(bobSession
);
182 CFMutableDataRef aliceStartPacket
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
184 ok_status(SecOTRSAppendStartPacket(*aliceSession
, aliceStartPacket
), "Alice start packet");
186 if (serializeNegotiating
)
187 serializeAndDeserialize(aliceSession
);
189 // Step 2: Exchange the start packets, forcing the DH commit messages to collide
190 CFMutableDataRef aliceDHKeyResponse
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
192 ok_status(SecOTRSProcessPacket(*aliceSession
, bobStartPacket
, aliceDHKeyResponse
),
193 "Bob DH packet failed");
195 if (serializeNegotiating
)
196 serializeAndDeserialize(aliceSession
);
198 CFReleaseNull(bobStartPacket
);
200 CFMutableDataRef bobDHKeyResponse
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
202 ok_status(SecOTRSProcessPacket(*bobSession
, aliceStartPacket
, bobDHKeyResponse
),
203 "Alice DH packet failed");
205 if (serializeNegotiating
)
206 serializeAndDeserialize(bobSession
);
208 CFReleaseNull(aliceStartPacket
);
210 // Step 3: With one "real" DH key message, and one replayed DH commit message, try to get a "reveal sig" out of one side
212 CFMutableDataRef bobRevealSigResponse
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
214 ok_status(SecOTRSProcessPacket(*bobSession
, aliceDHKeyResponse
, bobRevealSigResponse
),
215 "Alice DH Key packet failed");
217 if (serializeNegotiating
)
218 serializeAndDeserialize(bobSession
);
220 CFReleaseNull(aliceDHKeyResponse
);
222 CFMutableDataRef aliceRevealSigResponse
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
224 ok_status(SecOTRSProcessPacket(*aliceSession
, bobDHKeyResponse
, aliceRevealSigResponse
),
225 "Bob DH Key packet failed");
227 if (serializeNegotiating
)
228 serializeAndDeserialize(aliceSession
);
230 CFReleaseNull(bobDHKeyResponse
);
232 // Step 4: Having gotten the reveal signature, now work for the signature
234 CFMutableDataRef aliceSigResponse
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
236 ok_status(SecOTRSProcessPacket(*aliceSession
, bobRevealSigResponse
, aliceSigResponse
),
237 "Bob Reveal sig failed");
239 if (serializeNegotiating
)
240 serializeAndDeserialize(aliceSession
);
242 CFReleaseNull(bobRevealSigResponse
);
244 CFMutableDataRef bobSigResponse
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
246 ok_status(SecOTRSProcessPacket(*bobSession
, aliceRevealSigResponse
, bobSigResponse
),
247 "Alice Reveal sig failed");
249 if (serializeNegotiating
)
250 serializeAndDeserialize(bobSession
);
252 CFReleaseNull(aliceRevealSigResponse
);
254 // Step 5: All the messages have been sent, now deal with any replays from the collision handling
255 CFMutableDataRef bobFinalResponse
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
257 ok_status(SecOTRSProcessPacket(*bobSession
, aliceSigResponse
, bobFinalResponse
),
258 "Alice Final Sig failed");
260 if (serializeNegotiating
)
261 serializeAndDeserialize(bobSession
);
263 CFMutableDataRef aliceFinalResponse
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
265 ok_status(SecOTRSProcessPacket(*aliceSession
, bobSigResponse
, aliceFinalResponse
),
266 "Bob Final Sig failed");
268 is(kEmptyMessageSize
, CFDataGetLength(aliceFinalResponse
), "Alice had nothing left to say");
269 CFReleaseNull(aliceFinalResponse
);
270 CFReleaseNull(bobSigResponse
);
272 if (serializeNegotiating
)
273 serializeAndDeserialize(aliceSession
);
275 is(kEmptyMessageSize
, CFDataGetLength(bobFinalResponse
), "Bob had nothing left to say");
276 ok(SecOTRSGetIsReadyForMessages(*bobSession
), "Bob is ready");
277 ok(SecOTRSGetIsReadyForMessages(*aliceSession
), "Alice is ready");
279 CFReleaseNull(aliceSigResponse
);
280 CFReleaseNull(bobFinalResponse
);
282 sendMessages(5, bobSession
, aliceSession
, serializeMessaging
);
284 const char* aliceToBob
= "deferredMessage";
285 CFDataRef rawAliceToBob
= CFDataCreate(kCFAllocatorDefault
, (const uint8_t*)aliceToBob
, (CFIndex
) strlen(aliceToBob
));
286 CFMutableDataRef protectedAliceToBob
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
287 CFMutableDataRef bobDecode
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
289 ok_status(SecOTRSSignAndProtectMessage(*aliceSession
, rawAliceToBob
, protectedAliceToBob
), "encode message");
292 sendMessages(1, bobSession
, aliceSession
, serializeMessaging
);
294 is(SecOTRSVerifyAndExposeMessage(*bobSession
, protectedAliceToBob
, bobDecode
), errSecOTRTooOld
, "Decode old message");
296 sendMessages(1, bobSession
, aliceSession
, serializeMessaging
);
298 is(SecOTRSVerifyAndExposeMessage(*bobSession
, protectedAliceToBob
, bobDecode
), errSecOTRTooOld
, "Decode excessively old message");
300 sendMessages(3, bobSession
, aliceSession
, serializeMessaging
);
302 CFReleaseNull(rawAliceToBob
);
303 CFReleaseNull(protectedAliceToBob
);
304 CFReleaseNull(bobDecode
);
308 #define kTestTestCount (11 + kNegotiateTestCount * 6)
312 CFErrorRef testError
= NULL
;
313 SecOTRFullIdentityRef aliceID
= SecOTRFullIdentityCreate(kCFAllocatorDefault
, &testError
);
314 SecMPLogError(testError
);
315 CFReleaseNull(testError
);
317 SecOTRFullIdentityRef bobID
= SecOTRFullIdentityCreate(kCFAllocatorDefault
, &testError
);
318 SecMPLogError(testError
);
319 CFReleaseNull(testError
);
322 ok(aliceID
, "create alice ID");
323 ok(bobID
, "create bob ID");
325 SecOTRPublicIdentityRef alicePublicID
= SecOTRPublicIdentityCopyFromPrivate(kCFAllocatorDefault
, aliceID
, &testError
);
326 SecMPLogError(testError
);
327 CFReleaseNull(testError
);
328 SecOTRPublicIdentityRef bobPublicID
= SecOTRPublicIdentityCopyFromPrivate(kCFAllocatorDefault
, bobID
, &testError
);
329 SecMPLogError(testError
);
330 CFReleaseNull(testError
);
332 ok(alicePublicID
, "extract alice public");
333 ok(bobPublicID
, "extract bob public");
335 SecOTRSessionRef aliceSession
= SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault
, aliceID
, bobPublicID
, kSecOTRSendTextMessages
);
336 SecOTRSessionRef bobSession
= SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault
, bobID
, alicePublicID
, kSecOTRSendTextMessages
);
338 ok(aliceSession
, "create alice session");
339 ok(bobSession
, "create bob session");
341 SecOTRSessionRef aliceCompactSession
= SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault
, aliceID
, bobPublicID
, kSecOTRUseAppleCustomMessageFormat
);
342 SecOTRSessionRef bobCompactSession
= SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault
, bobID
, alicePublicID
, kSecOTRUseAppleCustomMessageFormat
);
344 ok(aliceCompactSession
, "create alice compact session");
345 ok(bobCompactSession
, "create bob compact session");
347 SecOTRSessionRef aliceCompactHashesSession
= SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault
, aliceID
, bobPublicID
, kSecOTRUseAppleCustomMessageFormat
|kSecOTRIncludeHashesInMessages
);
348 SecOTRSessionRef bobCompactHashesSession
= SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault
, bobID
, alicePublicID
, kSecOTRUseAppleCustomMessageFormat
|kSecOTRIncludeHashesInMessages
);
350 ok(aliceCompactHashesSession
, "create alice compact session with hashes");
351 ok(bobCompactHashesSession
, "create bob compact session with hashes");
353 // Release the IDs, sessions shouldn't need us to retain them for them.
354 CFReleaseNull(aliceID
);
355 CFReleaseNull(bobID
);
357 CFReleaseNull(alicePublicID
);
358 CFReleaseNull(bobPublicID
);
360 negotiate(&aliceSession
, &bobSession
, true, true, true, false);
362 negotiate(&aliceSession
, &bobSession
, true, false, true, false);
364 negotiate(&aliceCompactSession
, &bobCompactSession
, true, true, false, true);
366 negotiate(&aliceCompactSession
, &bobCompactSession
, true, false, false, true);
368 negotiate(&aliceCompactHashesSession
, &bobCompactHashesSession
, true, true, false, true);
370 negotiate(&aliceCompactHashesSession
, &bobCompactHashesSession
, true, false, false, true);
372 /* cleanup keychain */
373 ok(SecOTRFIPurgeAllFromKeychain(&testError
),"cleanup keychain");
374 SecMPLogError(testError
);
375 CFReleaseNull(testError
);
377 CFReleaseNull(aliceSession
);
378 CFReleaseNull(bobSession
);
380 CFReleaseNull(aliceCompactSession
);
381 CFReleaseNull(bobCompactSession
);
383 CFReleaseNull(aliceCompactHashesSession
);
384 CFReleaseNull(bobCompactHashesSession
);
387 int otr_30_negotiation(int argc
, char *const *argv
)
389 plan_tests(kTestTestCount
);