]> git.saurik.com Git - apple/security.git/blob - Security/sec/Security/Regressions/otr/otr-30-negotiation.c
5b09d0e510c17c464cf9dcfddd8d7440c7ddc845
[apple/security.git] / Security / 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) * 8)
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 if (serialize) {
79 serializeAndDeserialize(bobSession);
80 serializeAndDeserialize(aliceSession);
81 }
82
83 ok(CFDataGetLength(rawAliceToBob) == CFDataGetLength(bobDecode)
84 && 0 == memcmp(CFDataGetBytePtr(rawAliceToBob), CFDataGetBytePtr(bobDecode), (size_t)CFDataGetLength(rawAliceToBob)), "Didn't match!");
85
86 CFReleaseNull(rawAliceToBob);
87 CFReleaseNull(protectedAliceToBob);
88 CFReleaseNull(bobDecode);
89
90 const char* bobToAlice = "i liked your silly message from me to you";
91 CFDataRef rawBobToAlice = CFDataCreate(kCFAllocatorDefault, (const uint8_t*)bobToAlice, (CFIndex) strlen(bobToAlice));
92 CFMutableDataRef protectedBobToAlice = CFDataCreateMutable(kCFAllocatorDefault, 0);
93 CFMutableDataRef aliceDecode = CFDataCreateMutable(kCFAllocatorDefault, 0);
94
95 ok_status(SecOTRSSignAndProtectMessage(*bobSession, rawBobToAlice, protectedBobToAlice), "encode reply");
96 ok_status(SecOTRSVerifyAndExposeMessage(*aliceSession, protectedBobToAlice, aliceDecode), "decode reply");
97
98 if (serialize) {
99 serializeAndDeserialize(bobSession);
100 serializeAndDeserialize(aliceSession);
101 }
102
103 ok(CFDataGetLength(rawBobToAlice) == CFDataGetLength(aliceDecode)
104 && 0 == memcmp(CFDataGetBytePtr(rawBobToAlice), CFDataGetBytePtr(aliceDecode), (size_t)CFDataGetLength(rawBobToAlice)), "reply matched");
105
106 CFReleaseNull(rawAliceToBob);
107 CFReleaseNull(rawBobToAlice);
108 CFReleaseNull(protectedBobToAlice);
109 CFReleaseNull(protectedAliceToBob);
110 CFReleaseNull(aliceDecode);
111
112 CFStringRef stateString = CFCopyDescription(*bobSession);
113 ok(stateString, "getting state from bob");
114 CFReleaseNull(stateString);
115
116 stateString = CFCopyDescription(*aliceSession);
117 ok(stateString, "getting state from alice");
118 CFReleaseNull(stateString);
119 }
120 }
121
122 #define kNegotiateTestCount (14 + sendMessagesCount(5) \
123 + 2 + sendMessagesCount(1) \
124 + 1 + sendMessagesCount(1) \
125 + sendMessagesCount(3))
126 static void negotiate(SecOTRSessionRef* aliceSession, SecOTRSessionRef* bobSession, bool serialize, bool textMode, bool compact)
127 {
128 const int kEmptyMessageSize = textMode ? 6 : 0;
129
130 // Step 1: Create a start packet for each side of the transaction
131 CFMutableDataRef bobStartPacket = CFDataCreateMutable(kCFAllocatorDefault, 0);
132
133 ok_status(SecOTRSAppendStartPacket(*bobSession, bobStartPacket), "Bob start packet");
134
135 if (serialize)
136 serializeAndDeserialize(bobSession);
137
138 CFMutableDataRef aliceStartPacket = CFDataCreateMutable(kCFAllocatorDefault, 0);
139
140 ok_status(SecOTRSAppendStartPacket(*aliceSession, aliceStartPacket), "Alice start packet");
141
142 if (serialize)
143 serializeAndDeserialize(aliceSession);
144
145 // Step 2: Exchange the start packets, forcing the DH commit messages to collide
146 CFMutableDataRef aliceDHKeyResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
147
148 ok_status(SecOTRSProcessPacket(*aliceSession, bobStartPacket, aliceDHKeyResponse),
149 "Bob DH packet failed");
150
151 if (serialize)
152 serializeAndDeserialize(aliceSession);
153
154 CFReleaseNull(bobStartPacket);
155
156 CFMutableDataRef bobDHKeyResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
157
158 ok_status(SecOTRSProcessPacket(*bobSession, aliceStartPacket, bobDHKeyResponse),
159 "Alice DH packet failed");
160
161 if (serialize)
162 serializeAndDeserialize(bobSession);
163
164 CFReleaseNull(aliceStartPacket);
165
166 // Step 3: With one "real" DH key message, and one replayed DH commit message, try to get a "reveal sig" out of one side
167
168 CFMutableDataRef bobRevealSigResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
169
170 ok_status(SecOTRSProcessPacket(*bobSession, aliceDHKeyResponse, bobRevealSigResponse),
171 "Alice DH Key packet failed");
172
173 if (serialize)
174 serializeAndDeserialize(bobSession);
175
176 CFReleaseNull(aliceDHKeyResponse);
177
178 CFMutableDataRef aliceRevealSigResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
179
180 ok_status(SecOTRSProcessPacket(*aliceSession, bobDHKeyResponse, aliceRevealSigResponse),
181 "Bob DH Key packet failed");
182
183 if (serialize)
184 serializeAndDeserialize(aliceSession);
185
186 CFReleaseNull(bobDHKeyResponse);
187
188 // Step 4: Having gotten the reveal signature, now work for the signature
189
190 CFMutableDataRef aliceSigResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
191
192 ok_status(SecOTRSProcessPacket(*aliceSession, bobRevealSigResponse, aliceSigResponse),
193 "Bob Reveal sig failed");
194
195 if (serialize)
196 serializeAndDeserialize(aliceSession);
197
198 CFReleaseNull(bobRevealSigResponse);
199
200 CFMutableDataRef bobSigResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
201
202 ok_status(SecOTRSProcessPacket(*bobSession, aliceRevealSigResponse, bobSigResponse),
203 "Alice Reveal sig failed");
204
205 if (serialize)
206 serializeAndDeserialize(bobSession);
207
208 CFReleaseNull(aliceRevealSigResponse);
209
210 // Step 5: All the messages have been sent, now deal with any replays from the collision handling
211 CFMutableDataRef bobFinalResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
212
213 ok_status(SecOTRSProcessPacket(*bobSession, aliceSigResponse, bobFinalResponse),
214 "Alice Final Sig failed");
215
216 if (serialize)
217 serializeAndDeserialize(bobSession);
218
219 CFMutableDataRef aliceFinalResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
220
221 ok_status(SecOTRSProcessPacket(*aliceSession, bobSigResponse, aliceFinalResponse),
222 "Bob Final Sig failed");
223
224 is(kEmptyMessageSize, CFDataGetLength(aliceFinalResponse), "Alice had nothing left to say");
225 CFReleaseNull(aliceFinalResponse);
226 CFReleaseNull(bobSigResponse);
227
228 if (serialize)
229 serializeAndDeserialize(aliceSession);
230
231 is(kEmptyMessageSize, CFDataGetLength(bobFinalResponse), "Bob had nothing left to say");
232 ok(SecOTRSGetIsReadyForMessages(*bobSession), "Bob is ready");
233 ok(SecOTRSGetIsReadyForMessages(*aliceSession), "Alice is ready");
234
235 CFReleaseNull(aliceSigResponse);
236 CFReleaseNull(bobFinalResponse);
237
238 sendMessages(5, bobSession, aliceSession, serialize);
239
240 const char* aliceToBob = "deferredMessage";
241 CFDataRef rawAliceToBob = CFDataCreate(kCFAllocatorDefault, (const uint8_t*)aliceToBob, (CFIndex) strlen(aliceToBob));
242 CFMutableDataRef protectedAliceToBob = CFDataCreateMutable(kCFAllocatorDefault, 0);
243 CFMutableDataRef bobDecode = CFDataCreateMutable(kCFAllocatorDefault, 0);
244
245 ok_status(SecOTRSSignAndProtectMessage(*aliceSession, rawAliceToBob, protectedAliceToBob), "encode message");
246
247
248 const OSStatus expectedError = compact ? errSecAuthFailed : errSecOTRTooOld;
249
250 sendMessages(1, bobSession, aliceSession, serialize);
251
252 is(SecOTRSVerifyAndExposeMessage(*bobSession, protectedAliceToBob, bobDecode), expectedError, "Decode old message");
253
254 sendMessages(1, bobSession, aliceSession, serialize);
255
256 is(SecOTRSVerifyAndExposeMessage(*bobSession, protectedAliceToBob, bobDecode), expectedError, "Decode excessively old message");
257
258 sendMessages(3, bobSession, aliceSession, serialize);
259
260 CFReleaseNull(rawAliceToBob);
261 CFReleaseNull(protectedAliceToBob);
262 CFReleaseNull(bobDecode);
263 }
264
265
266 #define kTestTestCount (9 + kNegotiateTestCount * 2)
267
268 static void tests()
269 {
270 CFErrorRef testError = NULL;
271 SecOTRFullIdentityRef aliceID = SecOTRFullIdentityCreate(kCFAllocatorDefault, &testError);
272 SecMPLogError(testError);
273 CFReleaseNull(testError);
274 testError = NULL;
275 SecOTRFullIdentityRef bobID = SecOTRFullIdentityCreate(kCFAllocatorDefault, &testError);
276 SecMPLogError(testError);
277 CFReleaseNull(testError);
278 testError = NULL;
279
280 ok(aliceID, "create alice ID");
281 ok(bobID, "create bob ID");
282
283 SecOTRPublicIdentityRef alicePublicID = SecOTRPublicIdentityCopyFromPrivate(kCFAllocatorDefault, aliceID, &testError);
284 SecMPLogError(testError);
285 CFReleaseNull(testError);
286 SecOTRPublicIdentityRef bobPublicID = SecOTRPublicIdentityCopyFromPrivate(kCFAllocatorDefault, bobID, &testError);
287 SecMPLogError(testError);
288 CFReleaseNull(testError);
289
290 ok(alicePublicID, "extract alice public");
291 ok(bobPublicID, "extract bob public");
292
293 SecOTRSessionRef aliceSession = SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault, aliceID, bobPublicID, kSecOTRSendTextMessages);
294 SecOTRSessionRef bobSession = SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault, bobID, alicePublicID, kSecOTRSendTextMessages);
295
296 ok(aliceSession, "create alice session");
297 ok(bobSession, "create bob session");
298
299 SecOTRSessionRef aliceCompactSession = SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault, aliceID, bobPublicID, kSecOTRUseAppleCustomMessageFormat);
300 SecOTRSessionRef bobCompactSession = SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault, bobID, alicePublicID, kSecOTRUseAppleCustomMessageFormat);
301
302 ok(aliceCompactSession, "create alice compact session");
303 ok(bobCompactSession, "create bob compact session");
304
305 // Release the IDs, sessions shouldn't need us to retain them for them.
306 CFReleaseNull(aliceID);
307 CFReleaseNull(bobID);
308
309 CFReleaseNull(alicePublicID);
310 CFReleaseNull(bobPublicID);
311
312 negotiate(&aliceSession, &bobSession, true, true, false);
313
314 negotiate(&aliceCompactSession, &bobCompactSession, true, false, true);
315
316 /* cleanup keychain */
317 ok(SecOTRFIPurgeAllFromKeychain(&testError),"cleanup keychain");
318 SecMPLogError(testError);
319 CFReleaseNull(testError);
320
321 CFReleaseNull(aliceSession);
322 CFReleaseNull(bobSession);
323 }
324
325 int otr_30_negotiation(int argc, char *const *argv)
326 {
327 plan_tests(kTestTestCount);
328
329 tests();
330
331 return 0;
332 }