]>
Commit | Line | Data |
---|---|---|
427c49bc A |
1 | // |
2 | // SecOTRSession.c | |
3 | // libsecurity_libSecOTR | |
4 | // | |
5 | // Created by Mitch Adler on 2/22/11. | |
6 | // Copyright 2011 Apple Inc. All rights reserved. | |
7 | // | |
8 | ||
9 | #include "SecOTRSession.h" | |
10 | ||
11 | #include "SecOTRMath.h" | |
12 | #include "SecOTRIdentityPriv.h" | |
13 | #include "SecOTRSessionPriv.h" | |
14 | #include "SecOTRPackets.h" | |
15 | #include "SecOTRPacketData.h" | |
16 | #include "SecOTRDHKey.h" | |
17 | ||
18 | #include <utilities/SecCFWrappers.h> | |
19 | ||
20 | #include <CoreFoundation/CFRuntime.h> | |
21 | #include <CoreFoundation/CFString.h> | |
22 | ||
23 | #include <Security/SecBase.h> | |
24 | #include <Security/SecRandom.h> | |
25 | ||
26 | #include <AssertMacros.h> | |
27 | ||
28 | #include <corecrypto/cchmac.h> | |
29 | #include <corecrypto/ccsha2.h> | |
30 | ||
31 | #include <string.h> | |
32 | ||
33 | static void SecOTRInitMyDHKeys(SecOTRSessionRef session) | |
34 | { | |
35 | CFReleaseNull(session->_myKey); | |
36 | session->_myKey = SecOTRFullDHKCreate(kCFAllocatorDefault); | |
37 | CFReleaseNull(session->_myNextKey); | |
38 | session->_myNextKey = SecOTRFullDHKCreate(kCFAllocatorDefault); | |
39 | session->_keyID = 1; | |
40 | ||
41 | bzero(session->_keyCache, sizeof(session->_keyCache)); | |
42 | } | |
43 | ||
44 | OSStatus SecOTRSAppendStartPacket(SecOTRSessionRef session, CFMutableDataRef appendPacket) | |
45 | { | |
46 | __block OSStatus result = errSecSuccess; | |
47 | ||
48 | dispatch_sync(session->_queue, ^{ | |
49 | session->_state = kAwaitingDHKey; | |
50 | ||
51 | // Generate r and x and calculate gx: | |
52 | SecOTRInitMyDHKeys(session); | |
53 | ||
54 | CFMutableDataRef destinationMessage; | |
55 | if (session->_textOutput) { | |
56 | destinationMessage = CFDataCreateMutable(kCFAllocatorDefault, 0); | |
57 | } else { | |
58 | destinationMessage = appendPacket; | |
59 | } | |
60 | ||
61 | ||
62 | result = SecRandomCopyBytes(kSecRandomDefault, sizeof(session->_r), session->_r); | |
63 | if (result == errSecSuccess) { | |
64 | SecOTRAppendDHMessage(session, destinationMessage); | |
65 | if (session->_textOutput) { | |
66 | SecOTRPrepareOutgoingBytes(destinationMessage, appendPacket); | |
67 | CFReleaseSafe(destinationMessage); | |
68 | } | |
69 | } | |
70 | }); | |
71 | ||
72 | return result; | |
73 | } | |
74 | ||
75 | OSStatus SecOTRSAppendRestartPacket(SecOTRSessionRef session, CFMutableDataRef appendPacket) | |
76 | { | |
77 | __block OSStatus result = errSecSuccess; | |
78 | ||
79 | dispatch_sync(session->_queue, ^{ | |
80 | if (!session->_myKey) { | |
81 | secerror("_myKey is NULL, avoiding crash"); | |
82 | result = errSecDecode; | |
83 | return; | |
84 | } | |
85 | CFMutableDataRef destinationMessage; | |
86 | if (session->_textOutput) { | |
87 | destinationMessage = CFDataCreateMutable(kCFAllocatorDefault, 0); | |
88 | } else { | |
89 | destinationMessage = appendPacket; | |
90 | } | |
91 | ||
92 | session->_state = kAwaitingDHKey; | |
93 | CFReleaseNull(session->_receivedDHMessage); | |
94 | CFReleaseNull(session->_receivedDHKeyMessage); | |
95 | ||
96 | SecOTRAppendDHMessage(session, destinationMessage); | |
97 | if (session->_textOutput) { | |
98 | SecOTRPrepareOutgoingBytes(destinationMessage, appendPacket); | |
99 | CFReleaseSafe(destinationMessage); | |
100 | } | |
101 | }); | |
102 | ||
103 | return result; | |
104 | } | |
105 | ||
106 | static const uint8_t* FindGXHash(CFDataRef dhPacket) | |
107 | { | |
108 | const uint8_t* messageBytes = CFDataGetBytePtr(dhPacket); | |
109 | size_t remainingBytes = (size_t)CFDataGetLength(dhPacket); | |
110 | ||
111 | OTRMessageType messageType; | |
112 | ||
113 | require_noerr(ReadHeader(&messageBytes, &remainingBytes, &messageType), fail); | |
114 | require(messageType == kDHMessage, fail); | |
115 | ||
116 | uint32_t egxiLength = 0; | |
117 | require_noerr(ReadLong(&messageBytes, &remainingBytes, & egxiLength), fail); | |
118 | require(egxiLength <= remainingBytes, fail); | |
119 | messageBytes += egxiLength; | |
120 | remainingBytes -= egxiLength; | |
121 | ||
122 | uint32_t dataLength = 0; | |
123 | require_noerr(ReadLong(&messageBytes, &remainingBytes, &dataLength), fail); | |
124 | require(dataLength <= remainingBytes, fail); | |
125 | require(dataLength == CCSHA256_OUTPUT_SIZE, fail); | |
126 | ||
127 | return messageBytes; | |
128 | ||
129 | fail: | |
130 | return NULL; | |
131 | } | |
132 | ||
133 | static bool SecOTRMyGXHashIsBigger(SecOTRSessionRef session, CFDataRef dhCommitMessage) | |
134 | { | |
135 | bool mineIsBigger = false; | |
136 | ||
137 | CFMutableDataRef myDHCommitMessage = CFDataCreateMutable(kCFAllocatorDefault, 0); | |
138 | ||
139 | SecOTRAppendDHMessage(session, myDHCommitMessage); | |
140 | ||
141 | const uint8_t* myHash = FindGXHash(myDHCommitMessage); | |
142 | const uint8_t* theirHash = FindGXHash(dhCommitMessage); | |
143 | ||
144 | require(myHash, fail); | |
145 | require(theirHash, fail); | |
146 | ||
147 | mineIsBigger = 0 < memcmp(myHash, theirHash, CCSHA256_OUTPUT_SIZE); | |
148 | ||
149 | fail: | |
150 | CFReleaseNull(myDHCommitMessage); | |
151 | return mineIsBigger; | |
152 | } | |
153 | ||
154 | static OSStatus SecOTRSProcessDHMessage(SecOTRSessionRef session, | |
155 | CFDataRef incomingPacket, | |
156 | CFMutableDataRef negotiationResponse) | |
157 | { | |
158 | OSStatus result = errSecParam; | |
159 | ||
160 | switch (session->_state) { | |
161 | case kAwaitingDHKey: | |
162 | // Compare hash values. | |
163 | if (SecOTRMyGXHashIsBigger(session, incomingPacket)) { | |
164 | // If we're bigger we resend to force them to deal. | |
165 | CFReleaseNull(session->_receivedDHMessage); | |
166 | SecOTRAppendDHMessage(session, negotiationResponse); | |
167 | result = errSecSuccess; | |
168 | break; | |
169 | } // Else intentionally fall through to idle | |
170 | case kAwaitingSignature: | |
171 | case kIdle: | |
172 | case kDone: | |
173 | // Generate a new X and GX.. | |
174 | SecOTRInitMyDHKeys(session); | |
175 | // If we were already waiting on reveal, then just send the packet again | |
176 | case kAwaitingRevealSignature: | |
177 | SecOTRAppendDHKeyMessage(session, negotiationResponse); | |
178 | ||
179 | // Keep the packet for use later. | |
180 | CFReleaseNull(session->_receivedDHMessage); | |
181 | session->_receivedDHMessage = CFDataCreateCopy(kCFAllocatorDefault, incomingPacket); | |
182 | ||
183 | session->_state = kAwaitingRevealSignature; | |
184 | result = errSecSuccess; | |
185 | break; | |
186 | default: | |
187 | result = errSecInteractionNotAllowed; | |
188 | break; | |
189 | } | |
190 | ||
191 | return result; | |
192 | } | |
193 | ||
194 | static OSStatus SecOTRSetupTheirKeyFrom(SecOTRSessionRef session, const uint8_t**data, size_t*size) | |
195 | { | |
196 | SecOTRPublicDHKeyRef tempKey = SecOTRPublicDHKCreateFromSerialization(kCFAllocatorDefault, data, size); | |
197 | require(tempKey != NULL, fail); | |
198 | session->_theirKey = tempKey; | |
199 | session->_theirKeyID = 1; | |
200 | ||
201 | return errSecSuccess; | |
202 | ||
203 | fail: | |
204 | return errSecDecode; | |
205 | } | |
206 | ||
207 | static OSStatus SecOTRSExtractTheirPublicDHKey(SecOTRSessionRef session, CFDataRef dhPacket) | |
208 | { | |
209 | OSStatus result = errSecParam; | |
210 | ||
211 | const uint8_t *messageBytes = CFDataGetBytePtr(dhPacket); | |
212 | size_t messageSize = (size_t)CFDataGetLength(dhPacket); | |
213 | OTRMessageType messageType = kDHMessage; // Suppress warning. | |
214 | ||
215 | ReadHeader(&messageBytes, &messageSize, &messageType); | |
216 | require(messageType == kDHKeyMessage, exit); | |
217 | ||
218 | result = SecOTRSetupTheirKeyFrom(session, &messageBytes, &messageSize); | |
219 | ||
220 | exit: | |
221 | return result; | |
222 | } | |
223 | ||
224 | ||
225 | static OSStatus SecOTRSProcessDHKeyMessage(SecOTRSessionRef session, | |
226 | CFDataRef incomingPacket, | |
227 | CFMutableDataRef negotiationResponse) | |
228 | { | |
229 | OSStatus result = errSecUnimplemented; | |
230 | ||
231 | result = SecOTRSExtractTheirPublicDHKey(session, incomingPacket); | |
232 | require_noerr(result, exit); | |
233 | ||
234 | switch (session->_state) { | |
235 | case kAwaitingDHKey: | |
236 | CFReleaseNull(session->_receivedDHKeyMessage); | |
237 | SecOTRAppendRevealSignatureMessage(session, negotiationResponse); | |
238 | session->_state = kAwaitingSignature; | |
239 | session->_receivedDHKeyMessage = CFDataCreateCopy(kCFAllocatorDefault, incomingPacket); | |
240 | CFRetain(incomingPacket); | |
241 | result = errSecSuccess; | |
242 | break; | |
243 | case kAwaitingSignature: | |
244 | if (CFEqualSafe(incomingPacket, session->_receivedDHKeyMessage)) | |
245 | SecOTRAppendRevealSignatureMessage(session, negotiationResponse); | |
246 | result = errSecSuccess; | |
247 | break; | |
248 | case kIdle: | |
249 | case kDone: | |
250 | case kAwaitingRevealSignature: | |
251 | result = errSecSuccess; | |
252 | break; | |
253 | default: | |
254 | result = errSecInteractionNotAllowed; | |
255 | break; | |
256 | } | |
257 | ||
258 | exit: | |
259 | return result; | |
260 | } | |
261 | ||
262 | ||
263 | static OSStatus SecOTRSExtractR(SecOTRSessionRef session, | |
264 | const uint8_t **messageBytes, | |
265 | size_t *messageSize) | |
266 | { | |
267 | OSStatus result = errSecDecode; | |
268 | ||
269 | OTRMessageType messageType = kDHMessage; // Suppress warning | |
270 | ||
271 | ReadHeader(messageBytes, messageSize, &messageType); | |
272 | require(messageType == kRevealSignatureMessage, exit); | |
273 | ||
274 | { | |
275 | uint32_t rSize = 0; | |
276 | ReadLong(messageBytes, messageSize, &rSize); | |
277 | require(rSize == kOTRAuthKeyBytes, exit); | |
278 | } | |
279 | ||
280 | memcpy(session->_r, *messageBytes, kOTRAuthKeyBytes); | |
281 | ||
282 | *messageBytes += kOTRAuthKeyBytes; | |
283 | *messageSize -= kOTRAuthKeyBytes; | |
284 | ||
285 | result = errSecSuccess; | |
286 | exit: | |
287 | return result; | |
288 | } | |
289 | ||
290 | static OSStatus FindEncGYInDHPacket(SecOTRSessionRef session, | |
291 | const uint8_t **dhMessageBytesPtr, | |
292 | size_t *messageSizePtr, | |
293 | size_t* encGYBufferSize) | |
294 | { | |
295 | OSStatus result = errSecParam; | |
296 | require_action(*encGYBufferSize >= kExponentiationBytes + 4, exit, result = errSecParam); | |
297 | ||
298 | OTRMessageType messageType; | |
299 | result = ReadHeader(dhMessageBytesPtr, messageSizePtr, &messageType); | |
300 | require_noerr(result, exit); | |
301 | require_action(messageType == kDHMessage, exit, result = errSecDecode); | |
302 | ||
303 | uint32_t readEncSize; | |
304 | result = ReadLong(dhMessageBytesPtr, messageSizePtr, &readEncSize); | |
305 | require_noerr(result, exit); | |
306 | ||
307 | *encGYBufferSize = readEncSize; | |
308 | exit: | |
309 | // Don't bother erasing the public gy decrypted, it's public after all. | |
310 | return result; | |
311 | ||
312 | } | |
313 | ||
314 | static OSStatus SecOTRSExtractRAndTheirDHKey(SecOTRSessionRef session, | |
315 | const uint8_t **messageBytes, | |
316 | size_t *messageSize) | |
317 | { | |
318 | OSStatus result = errSecDecode; | |
319 | ||
320 | require(session->_receivedDHMessage != NULL, exit); | |
321 | result = SecOTRSExtractR(session, messageBytes, messageSize); | |
322 | require_noerr(result, exit); | |
323 | ||
324 | uint8_t gxiDecrypted[kExponentiationBytes + 4]; | |
325 | const uint8_t *gxiDecryptedBuffer = gxiDecrypted; | |
326 | ||
327 | const uint8_t* dhMessageBytes = CFDataGetBytePtr(session->_receivedDHMessage); | |
328 | size_t dhMessageSize = (size_t)CFDataGetLength(session->_receivedDHMessage); | |
329 | ||
330 | size_t encGYSize = sizeof(gxiDecrypted); | |
331 | result = FindEncGYInDHPacket(session, &dhMessageBytes, &dhMessageSize, &encGYSize); | |
332 | require_noerr(result, exit); | |
333 | require_action(encGYSize <= kExponentiationBytes + 4, exit, result = errSecDecode); | |
334 | ||
335 | AES_CTR_IV0_Transform(sizeof(session->_r), session->_r, encGYSize, dhMessageBytes, gxiDecrypted); | |
336 | ||
337 | result = SecOTRSetupTheirKeyFrom(session, &gxiDecryptedBuffer, &encGYSize); | |
338 | ||
339 | exit: | |
340 | // Don't bother erasing the public gy decrypted, it's public after all. | |
341 | return result; | |
342 | } | |
343 | ||
344 | static OSStatus SecVerifySignatureAndMac(SecOTRSessionRef session, | |
345 | bool usePrimes, | |
346 | const uint8_t **signatureAndMacBytes, | |
347 | size_t *signatureAndMacSize) | |
348 | { | |
349 | OSStatus result = errSecDecode; | |
350 | ||
351 | uint8_t m1[kOTRAuthMACKeyBytes]; | |
352 | uint8_t m2[kOTRAuthMACKeyBytes]; | |
353 | uint8_t c[kOTRAuthKeyBytes]; | |
354 | ||
355 | { | |
356 | cc_unit s[kExponentiationUnits]; | |
357 | ||
358 | SecPDHKeyGenerateS(session->_myKey, session->_theirKey, s); | |
359 | // Derive M1, M2 and C, either prime or normal versions. | |
360 | DeriveOTR256BitsFromS(usePrimes ? kM1Prime : kM1, | |
361 | kExponentiationUnits, s, sizeof(m1), m1); | |
362 | DeriveOTR256BitsFromS(usePrimes ? kM2Prime : kM2, | |
363 | kExponentiationUnits, s, sizeof(m2), m2); | |
364 | DeriveOTR128BitPairFromS(kCs, | |
365 | kExponentiationUnits, s, | |
366 | sizeof(c),usePrimes ? NULL : c, | |
367 | sizeof(c), usePrimes ? c : NULL); | |
368 | bzero(s, sizeof(s)); | |
369 | } | |
370 | ||
371 | cchmac_di_decl(ccsha256_di(), mBContext); | |
372 | ||
373 | cchmac_init(ccsha256_di(), mBContext, sizeof(m1), m1); | |
374 | ||
375 | { | |
376 | CFMutableDataRef toHash = CFDataCreateMutable(kCFAllocatorDefault, 0); | |
377 | ||
378 | SecPDHKAppendSerialization(session->_theirKey, toHash); | |
379 | SecFDHKAppendPublicSerialization(session->_myKey, toHash); | |
380 | ||
381 | cchmac_update(ccsha256_di(), mBContext, (size_t)CFDataGetLength(toHash), CFDataGetBytePtr(toHash)); | |
382 | ||
383 | CFReleaseNull(toHash); | |
384 | } | |
385 | ||
386 | const uint8_t* encSigDataBlobStart = *signatureAndMacBytes; | |
387 | ||
388 | uint32_t xbSize = 0; | |
389 | result = ReadLong(signatureAndMacBytes, signatureAndMacSize, &xbSize); | |
390 | require_noerr(result, exit); | |
391 | require(xbSize > 4, exit); | |
392 | require(xbSize <= *signatureAndMacSize, exit); | |
393 | ||
394 | uint8_t signatureMac[CCSHA256_OUTPUT_SIZE]; | |
395 | cchmac(ccsha256_di(), sizeof(m2), m2, xbSize + 4, encSigDataBlobStart, signatureMac); | |
396 | ||
397 | require(xbSize + kSHA256HMAC160Bytes <= *signatureAndMacSize, exit); | |
398 | const uint8_t *macStart = *signatureAndMacBytes + xbSize; | |
399 | ||
400 | // check the outer hmac | |
401 | require(0 == memcmp(macStart, signatureMac, kSHA256HMAC160Bytes), exit); | |
402 | ||
403 | ||
404 | { | |
405 | uint8_t xb[xbSize]; | |
406 | // Decrypt and copy the signature block | |
407 | AES_CTR_IV0_Transform(sizeof(c), c, xbSize, *signatureAndMacBytes, xb); | |
408 | ||
409 | const uint8_t* signaturePacket = xb; | |
410 | size_t signaturePacketSize = xbSize; | |
411 | ||
412 | uint16_t pubKeyType; | |
413 | result = ReadShort(&signaturePacket, &signaturePacketSize, &pubKeyType); | |
414 | require_noerr(result, exit); | |
415 | require_action(pubKeyType == 0xF000, exit, result = errSecUnimplemented); | |
416 | ||
417 | uint32_t pubKeySize; | |
418 | result = ReadLong(&signaturePacket, &signaturePacketSize, &pubKeySize); | |
419 | require_noerr(result, exit); | |
420 | require_action(pubKeySize <= signaturePacketSize, exit, result = errSecDecode); | |
421 | require(((CFIndex)pubKeySize) >= 0, exit); | |
422 | ||
423 | // Add the signature and keyid to the hash. | |
424 | // PUBKEY of our type is 2 bytes of type, 2 bytes of size and size bytes. | |
425 | // Key ID is 4 bytes. | |
426 | cchmac_update(ccsha256_di(), mBContext, 2 + 4 + pubKeySize + 4, xb); | |
427 | ||
428 | uint8_t mb[CCSHA256_OUTPUT_SIZE]; | |
429 | cchmac_final(ccsha256_di(), mBContext, mb); | |
430 | ||
431 | // Make reference to the deflated key | |
432 | require_action(SecOTRPIEqualToBytes(session->_them, signaturePacket, (CFIndex)pubKeySize), exit, result = errSecAuthFailed); | |
433 | ||
434 | signaturePacket += pubKeySize; | |
435 | signaturePacketSize -= pubKeySize; | |
436 | ||
437 | result = ReadLong(&signaturePacket, &signaturePacketSize, &session->_theirKeyID); | |
438 | require_noerr(result, exit); | |
439 | ||
440 | uint32_t sigSize; | |
441 | result = ReadLong(&signaturePacket, &signaturePacketSize, &sigSize); | |
442 | require_noerr(result, exit); | |
443 | require_action(sigSize <= signaturePacketSize, exit, result = errSecDecode); | |
444 | ||
445 | bool bresult = SecOTRPIVerifySignature(session->_them, mb, sizeof(mb), signaturePacket, sigSize, NULL); | |
446 | result = bresult ? errSecSuccess : errSecDecode; | |
447 | require_noerr(result, exit); | |
448 | ||
449 | } | |
450 | ||
451 | exit: | |
452 | bzero(m1, sizeof(m1)); | |
453 | bzero(m2, sizeof(m2)); | |
454 | bzero(c, sizeof(c)); | |
455 | ||
456 | return result; | |
457 | } | |
458 | ||
459 | static OSStatus SecOTRSProcessRevealSignatureMessage(SecOTRSessionRef session, | |
460 | CFDataRef incomingPacket, | |
461 | CFMutableDataRef negotiationResponse) | |
462 | { | |
463 | OSStatus result = errSecParam; | |
464 | ||
465 | require_action_quiet(session->_state == kAwaitingRevealSignature, exit, result = errSecSuccess); | |
466 | ||
467 | const uint8_t *messageBytes = CFDataGetBytePtr(incomingPacket); | |
468 | size_t messageSize = (size_t)CFDataGetLength(incomingPacket); | |
469 | ||
470 | result = SecOTRSExtractRAndTheirDHKey(session, &messageBytes, &messageSize); | |
471 | require_noerr(result, exit); | |
472 | ||
473 | result = SecVerifySignatureAndMac(session, false, &messageBytes, &messageSize); | |
474 | require_noerr(result, exit); | |
475 | ||
476 | SecOTRAppendSignatureMessage(session, negotiationResponse); | |
477 | ||
478 | session->_state = kDone; | |
479 | result = errSecSuccess; | |
480 | exit: | |
481 | return result; | |
482 | } | |
483 | ||
484 | static OSStatus SecOTRSProcessSignatureMessage(SecOTRSessionRef session, | |
485 | CFDataRef incomingPacket, | |
486 | CFMutableDataRef negotiationResponse) | |
487 | { | |
488 | OSStatus result = errSecParam; | |
489 | ||
490 | require_action_quiet(session->_state == kAwaitingSignature, exit, result = errSecSuccess); | |
491 | ||
492 | const uint8_t *messageBytes = CFDataGetBytePtr(incomingPacket); | |
493 | size_t messageSize = (size_t)CFDataGetLength(incomingPacket); | |
494 | ||
495 | OTRMessageType messageType; | |
496 | result = ReadHeader(&messageBytes, &messageSize, &messageType); | |
497 | require_noerr(result, exit); | |
498 | require_action(messageType == kSignatureMessage, exit, result = errSecDecode); | |
499 | ||
500 | result = SecVerifySignatureAndMac(session, true, &messageBytes, &messageSize); | |
501 | require_noerr(result, exit); | |
502 | ||
503 | CFReleaseNull(session->_receivedDHKeyMessage); | |
504 | session->_state = kDone; | |
505 | ||
506 | result = errSecSuccess; | |
507 | exit: | |
508 | return result; | |
509 | } | |
510 | ||
511 | OSStatus SecOTRSProcessPacket(SecOTRSessionRef session, | |
512 | CFDataRef incomingPacket, | |
513 | CFMutableDataRef negotiationResponse) | |
514 | { | |
515 | __block OSStatus result = errSecParam; | |
516 | ||
517 | require(CFDataGetLength(incomingPacket) > 0, fail); | |
518 | dispatch_sync(session->_queue, ^{ | |
519 | CFMutableDataRef decodedBytes = CFDataCreateMutable(kCFAllocatorDefault, 0); | |
520 | SecOTRGetIncomingBytes(incomingPacket, decodedBytes); | |
521 | ||
522 | const uint8_t* bytes = CFDataGetBytePtr(decodedBytes); | |
523 | size_t size = CFDataGetLength(decodedBytes); | |
524 | ||
525 | OTRMessageType packetType = kInvalidMessage; | |
526 | if (ReadHeader(&bytes, &size, &packetType)) | |
527 | packetType = kInvalidMessage; | |
528 | ||
529 | CFMutableDataRef destinationMessage; | |
530 | if (session->_textOutput) { | |
531 | destinationMessage = CFDataCreateMutable(kCFAllocatorDefault, 0); | |
532 | } else { | |
533 | destinationMessage = negotiationResponse; | |
534 | } | |
535 | ||
536 | switch (packetType) { | |
537 | case kDHMessage: | |
538 | result = SecOTRSProcessDHMessage(session, decodedBytes, destinationMessage); | |
539 | break; | |
540 | case kDHKeyMessage: | |
541 | result = SecOTRSProcessDHKeyMessage(session, decodedBytes, destinationMessage); | |
542 | break; | |
543 | case kRevealSignatureMessage: | |
544 | result = SecOTRSProcessRevealSignatureMessage(session, decodedBytes, destinationMessage); | |
545 | break; | |
546 | case kSignatureMessage: | |
547 | result = SecOTRSProcessSignatureMessage(session, decodedBytes, destinationMessage); | |
548 | break; | |
549 | default: | |
550 | result = errSecDecode; | |
551 | break; | |
552 | }; | |
553 | ||
554 | if (result != errSecSuccess) { | |
555 | secnotice("session", "Error %d processing packet type %d, session state %d, keyid %d, myKey %p, myNextKey %p, theirKeyId %d, theirKey %p, theirPreviousKey %p, bytes %@", (int)result, packetType, session->_state, session->_keyID, session->_myKey, session->_myNextKey, session->_theirKeyID, session->_theirKey, session->_theirPreviousKey, decodedBytes); | |
556 | } | |
557 | ||
558 | if (session->_textOutput) { | |
559 | SecOTRPrepareOutgoingBytes(destinationMessage, negotiationResponse); | |
560 | CFReleaseSafe(destinationMessage); | |
561 | } | |
562 | CFReleaseSafe(decodedBytes); | |
563 | }); | |
564 | ||
565 | fail: | |
566 | return result; | |
567 | } |