]> git.saurik.com Git - apple/security.git/blob - OSX/sec/Security/Regressions/otr/otr-30-negotiation.c
Security-57336.1.9.tar.gz
[apple/security.git] / OSX / sec / Security / Regressions / otr / otr-30-negotiation.c
1 /*
2 * Copyright (c) 2011-2014 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25 #include "Security_regressions.h"
26
27 #include <CoreFoundation/CFData.h>
28 #include <Security/SecOTRSession.h>
29 #include <Security/SecInternal.h>
30 #include <Security/SecBasePriv.h>
31
32 static void SecMPLogError(CFErrorRef error) {
33 if (error == NULL) {
34 return;
35 }
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);
43 }
44 char errorDomainStr[1024];
45 char errorStringStr[1024];
46
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);
51 }
52
53 static void serializeAndDeserialize(SecOTRSessionRef* thisOne)
54 {
55 CFMutableDataRef serialized = CFDataCreateMutable(kCFAllocatorDefault, 0);
56
57 SecOTRSAppendSerialization(*thisOne, serialized);
58 CFReleaseNull(*thisOne);
59 *thisOne = SecOTRSessionCreateFromData(kCFAllocatorDefault, serialized);
60
61 CFReleaseSafe(serialized);
62 }
63
64
65
66 #define sendMessagesCount(n) ((n) * 14)
67 static void sendMessages(int howMany, SecOTRSessionRef *bobSession, SecOTRSessionRef *aliceSession, bool serialize)
68 {
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);
74
75 ok_status(SecOTRSSignAndProtectMessage(*aliceSession, rawAliceToBob, protectedAliceToBob), "encode message");
76 ok_status(SecOTRSVerifyAndExposeMessage(*bobSession, protectedAliceToBob, bobDecode), "Decode message");
77
78
79 if (serialize) {
80 serializeAndDeserialize(bobSession);
81 serializeAndDeserialize(aliceSession);
82 }
83
84 ok(CFDataGetLength(rawAliceToBob) == CFDataGetLength(bobDecode)
85 && 0 == memcmp(CFDataGetBytePtr(rawAliceToBob), CFDataGetBytePtr(bobDecode), (size_t)CFDataGetLength(rawAliceToBob)), "Didn't match!");
86
87 CFReleaseNull(rawAliceToBob);
88 CFReleaseNull(protectedAliceToBob);
89 CFReleaseNull(bobDecode);
90
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);
95
96 ok_status(SecOTRSSignAndProtectMessage(*aliceSession, rawBobToAlice, protectedBobToAlice), "encode reply");
97 ok_status(SecOTRSVerifyAndExposeMessage(*bobSession, protectedBobToAlice, aliceDecode), "decode reply");
98
99 if (serialize) {
100 serializeAndDeserialize(bobSession);
101 serializeAndDeserialize(aliceSession);
102 }
103
104 ok(CFDataGetLength(rawBobToAlice) == CFDataGetLength(aliceDecode)
105 && 0 == memcmp(CFDataGetBytePtr(rawBobToAlice), CFDataGetBytePtr(aliceDecode), (size_t)CFDataGetLength(rawBobToAlice)), "reply matched");
106
107 CFReleaseNull(rawAliceToBob);
108 CFReleaseNull(rawBobToAlice);
109 CFReleaseNull(protectedBobToAlice);
110 CFReleaseNull(protectedAliceToBob);
111 CFReleaseNull(aliceDecode);
112
113 rawAliceToBob = CFDataCreate(kCFAllocatorDefault, (const uint8_t*)aliceToBob, (CFIndex) strlen(aliceToBob));
114 protectedAliceToBob = CFDataCreateMutable(kCFAllocatorDefault, 0);
115 bobDecode = CFDataCreateMutable(kCFAllocatorDefault, 0);
116
117 ok_status(SecOTRSSignAndProtectMessage(*aliceSession, rawAliceToBob, protectedAliceToBob), "encode message");
118 ok_status(SecOTRSVerifyAndExposeMessage(*bobSession, protectedAliceToBob, bobDecode), "Decode message");
119
120 if (serialize) {
121 serializeAndDeserialize(bobSession);
122 serializeAndDeserialize(aliceSession);
123 }
124
125 ok(CFDataGetLength(rawAliceToBob) == CFDataGetLength(bobDecode)
126 && 0 == memcmp(CFDataGetBytePtr(rawAliceToBob), CFDataGetBytePtr(bobDecode), (size_t)CFDataGetLength(rawAliceToBob)), "Didn't match!");
127
128 CFReleaseNull(rawAliceToBob);
129 CFReleaseNull(protectedAliceToBob);
130 CFReleaseNull(bobDecode);
131
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);
136
137 ok_status(SecOTRSSignAndProtectMessage(*aliceSession, rawBobToAlice, protectedBobToAlice), "encode reply");
138 ok_status(SecOTRSVerifyAndExposeMessage(*bobSession, protectedBobToAlice, aliceDecode), "decode reply");
139
140 if (serialize) {
141 serializeAndDeserialize(bobSession);
142 serializeAndDeserialize(aliceSession);
143 }
144
145 ok(CFDataGetLength(rawBobToAlice) == CFDataGetLength(aliceDecode)
146 && 0 == memcmp(CFDataGetBytePtr(rawBobToAlice), CFDataGetBytePtr(aliceDecode), (size_t)CFDataGetLength(rawBobToAlice)), "reply matched");
147
148 CFReleaseNull(rawAliceToBob);
149 CFReleaseNull(rawBobToAlice);
150 CFReleaseNull(protectedBobToAlice);
151 CFReleaseNull(protectedAliceToBob);
152 CFReleaseNull(aliceDecode);
153
154
155
156 CFStringRef stateString = CFCopyDescription(*bobSession);
157 ok(stateString, "getting state from bob");
158 CFReleaseNull(stateString);
159
160 stateString = CFCopyDescription(*aliceSession);
161 ok(stateString, "getting state from alice");
162 CFReleaseNull(stateString);
163 }
164 }
165
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)
171 {
172 const int kEmptyMessageSize = textMode ? 6 : 0;
173
174 // Step 1: Create a start packet for each side of the transaction
175 CFMutableDataRef bobStartPacket = CFDataCreateMutable(kCFAllocatorDefault, 0);
176
177 ok_status(SecOTRSAppendStartPacket(*bobSession, bobStartPacket), "Bob start packet");
178
179 if (serializeNegotiating)
180 serializeAndDeserialize(bobSession);
181
182 CFMutableDataRef aliceStartPacket = CFDataCreateMutable(kCFAllocatorDefault, 0);
183
184 ok_status(SecOTRSAppendStartPacket(*aliceSession, aliceStartPacket), "Alice start packet");
185
186 if (serializeNegotiating)
187 serializeAndDeserialize(aliceSession);
188
189 // Step 2: Exchange the start packets, forcing the DH commit messages to collide
190 CFMutableDataRef aliceDHKeyResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
191
192 ok_status(SecOTRSProcessPacket(*aliceSession, bobStartPacket, aliceDHKeyResponse),
193 "Bob DH packet failed");
194
195 if (serializeNegotiating)
196 serializeAndDeserialize(aliceSession);
197
198 CFReleaseNull(bobStartPacket);
199
200 CFMutableDataRef bobDHKeyResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
201
202 ok_status(SecOTRSProcessPacket(*bobSession, aliceStartPacket, bobDHKeyResponse),
203 "Alice DH packet failed");
204
205 if (serializeNegotiating)
206 serializeAndDeserialize(bobSession);
207
208 CFReleaseNull(aliceStartPacket);
209
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
211
212 CFMutableDataRef bobRevealSigResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
213
214 ok_status(SecOTRSProcessPacket(*bobSession, aliceDHKeyResponse, bobRevealSigResponse),
215 "Alice DH Key packet failed");
216
217 if (serializeNegotiating)
218 serializeAndDeserialize(bobSession);
219
220 CFReleaseNull(aliceDHKeyResponse);
221
222 CFMutableDataRef aliceRevealSigResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
223
224 ok_status(SecOTRSProcessPacket(*aliceSession, bobDHKeyResponse, aliceRevealSigResponse),
225 "Bob DH Key packet failed");
226
227 if (serializeNegotiating)
228 serializeAndDeserialize(aliceSession);
229
230 CFReleaseNull(bobDHKeyResponse);
231
232 // Step 4: Having gotten the reveal signature, now work for the signature
233
234 CFMutableDataRef aliceSigResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
235
236 ok_status(SecOTRSProcessPacket(*aliceSession, bobRevealSigResponse, aliceSigResponse),
237 "Bob Reveal sig failed");
238
239 if (serializeNegotiating)
240 serializeAndDeserialize(aliceSession);
241
242 CFReleaseNull(bobRevealSigResponse);
243
244 CFMutableDataRef bobSigResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
245
246 ok_status(SecOTRSProcessPacket(*bobSession, aliceRevealSigResponse, bobSigResponse),
247 "Alice Reveal sig failed");
248
249 if (serializeNegotiating)
250 serializeAndDeserialize(bobSession);
251
252 CFReleaseNull(aliceRevealSigResponse);
253
254 // Step 5: All the messages have been sent, now deal with any replays from the collision handling
255 CFMutableDataRef bobFinalResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
256
257 ok_status(SecOTRSProcessPacket(*bobSession, aliceSigResponse, bobFinalResponse),
258 "Alice Final Sig failed");
259
260 if (serializeNegotiating)
261 serializeAndDeserialize(bobSession);
262
263 CFMutableDataRef aliceFinalResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
264
265 ok_status(SecOTRSProcessPacket(*aliceSession, bobSigResponse, aliceFinalResponse),
266 "Bob Final Sig failed");
267
268 is(kEmptyMessageSize, CFDataGetLength(aliceFinalResponse), "Alice had nothing left to say");
269 CFReleaseNull(aliceFinalResponse);
270 CFReleaseNull(bobSigResponse);
271
272 if (serializeNegotiating)
273 serializeAndDeserialize(aliceSession);
274
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");
278
279 CFReleaseNull(aliceSigResponse);
280 CFReleaseNull(bobFinalResponse);
281
282 sendMessages(5, bobSession, aliceSession, serializeMessaging);
283
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);
288
289 ok_status(SecOTRSSignAndProtectMessage(*aliceSession, rawAliceToBob, protectedAliceToBob), "encode message");
290
291
292 sendMessages(1, bobSession, aliceSession, serializeMessaging);
293
294 is(SecOTRSVerifyAndExposeMessage(*bobSession, protectedAliceToBob, bobDecode), errSecOTRTooOld, "Decode old message");
295
296 sendMessages(1, bobSession, aliceSession, serializeMessaging);
297
298 is(SecOTRSVerifyAndExposeMessage(*bobSession, protectedAliceToBob, bobDecode), errSecOTRTooOld, "Decode excessively old message");
299
300 sendMessages(3, bobSession, aliceSession, serializeMessaging);
301
302 CFReleaseNull(rawAliceToBob);
303 CFReleaseNull(protectedAliceToBob);
304 CFReleaseNull(bobDecode);
305 }
306
307
308 #define kTestTestCount (11 + kNegotiateTestCount * 6)
309
310 static void tests()
311 {
312 CFErrorRef testError = NULL;
313 SecOTRFullIdentityRef aliceID = SecOTRFullIdentityCreate(kCFAllocatorDefault, &testError);
314 SecMPLogError(testError);
315 CFReleaseNull(testError);
316 testError = NULL;
317 SecOTRFullIdentityRef bobID = SecOTRFullIdentityCreate(kCFAllocatorDefault, &testError);
318 SecMPLogError(testError);
319 CFReleaseNull(testError);
320 testError = NULL;
321
322 ok(aliceID, "create alice ID");
323 ok(bobID, "create bob ID");
324
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);
331
332 ok(alicePublicID, "extract alice public");
333 ok(bobPublicID, "extract bob public");
334
335 SecOTRSessionRef aliceSession = SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault, aliceID, bobPublicID, kSecOTRSendTextMessages);
336 SecOTRSessionRef bobSession = SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault, bobID, alicePublicID, kSecOTRSendTextMessages);
337
338 ok(aliceSession, "create alice session");
339 ok(bobSession, "create bob session");
340
341 SecOTRSessionRef aliceCompactSession = SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault, aliceID, bobPublicID, kSecOTRUseAppleCustomMessageFormat);
342 SecOTRSessionRef bobCompactSession = SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault, bobID, alicePublicID, kSecOTRUseAppleCustomMessageFormat);
343
344 ok(aliceCompactSession, "create alice compact session");
345 ok(bobCompactSession, "create bob compact session");
346
347 SecOTRSessionRef aliceCompactHashesSession = SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault, aliceID, bobPublicID, kSecOTRUseAppleCustomMessageFormat|kSecOTRIncludeHashesInMessages);
348 SecOTRSessionRef bobCompactHashesSession = SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault, bobID, alicePublicID, kSecOTRUseAppleCustomMessageFormat|kSecOTRIncludeHashesInMessages);
349
350 ok(aliceCompactHashesSession, "create alice compact session with hashes");
351 ok(bobCompactHashesSession, "create bob compact session with hashes");
352
353 // Release the IDs, sessions shouldn't need us to retain them for them.
354 CFReleaseNull(aliceID);
355 CFReleaseNull(bobID);
356
357 CFReleaseNull(alicePublicID);
358 CFReleaseNull(bobPublicID);
359
360 negotiate(&aliceSession, &bobSession, true, true, true, false);
361
362 negotiate(&aliceSession, &bobSession, true, false, true, false);
363
364 negotiate(&aliceCompactSession, &bobCompactSession, true, true, false, true);
365
366 negotiate(&aliceCompactSession, &bobCompactSession, true, false, false, true);
367
368 negotiate(&aliceCompactHashesSession, &bobCompactHashesSession, true, true, false, true);
369
370 negotiate(&aliceCompactHashesSession, &bobCompactHashesSession, true, false, false, true);
371
372 /* cleanup keychain */
373 ok(SecOTRFIPurgeAllFromKeychain(&testError),"cleanup keychain");
374 SecMPLogError(testError);
375 CFReleaseNull(testError);
376
377 CFReleaseNull(aliceSession);
378 CFReleaseNull(bobSession);
379
380 CFReleaseNull(aliceCompactSession);
381 CFReleaseNull(bobCompactSession);
382
383 CFReleaseNull(aliceCompactHashesSession);
384 CFReleaseNull(bobCompactHashesSession);
385 }
386
387 int otr_30_negotiation(int argc, char *const *argv)
388 {
389 plan_tests(kTestTestCount);
390
391 tests();
392
393 return 0;
394 }