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