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 "SecOTRDHKey.h"
13#include "SecOTRSessionPriv.h"
14#include "SecOTRPackets.h"
15#include "SecOTRPacketData.h"
16
17#include <utilities/SecCFWrappers.h>
18
19#include <CoreFoundation/CFRuntime.h>
20#include <CoreFoundation/CFString.h>
21
22#include <Security/SecBasePriv.h>
23#include <Security/SecRandom.h>
24#include <Security/SecBase64.h>
25
26#include <AssertMacros.h>
27
28#ifdef USECOMMONCRYPTO
29#include <CommonCrypto/CommonHMAC.h>
30#endif
31
32#include <corecrypto/cchmac.h>
33#include <corecrypto/ccsha2.h>
34#include <corecrypto/ccsha1.h>
35
36#include <string.h>
37#include <stdlib.h>
38
39#include <syslog.h>
40
41#include "utilities/comparison.h"
42
43CFGiblisFor(SecOTRSession);
44
45static OTRMessageType SecOTRSGetMessageType(CFDataRef message)
46{
47    OTRMessageType type = kInvalidMessage;
48
49    CFMutableDataRef decodedBytes = CFDataCreateMutable(kCFAllocatorDefault, 0);
50    SecOTRGetIncomingBytes(message, decodedBytes);
51
52    const uint8_t *bytes = CFDataGetBytePtr(decodedBytes);
53    size_t size = CFDataGetLength(decodedBytes);
54
55    require_noerr(ReadHeader(&bytes, &size, &type), fail);
56
57fail:
58    CFReleaseNull(decodedBytes);
59
60    return type;
61}
62
63const char *SecOTRPacketTypeString(CFDataRef message)
64{
65    if (!message) return "NoMessage";
66    switch (SecOTRSGetMessageType(message)) {
67        case kDHMessage:                return "DHMessage (0x02)";
68        case kDataMessage:              return "DataMessage (0x03)";
69        case kDHKeyMessage:             return "DHKeyMessage (0x0A)";
70        case kRevealSignatureMessage:   return "RevealSignatureMessage (0x11)";
71        case kSignatureMessage:         return "SignatureMessage (0x12)";
72        case kInvalidMessage:           return "InvalidMessage (0xFF)";
73        default:                        return "UnknownMessage";
74    }
75}
76
77static const char *SecOTRAuthStateString(SecOTRAuthState authState)
78{
79    switch (authState) {
80        case kIdle:                     return "Idle";
81        case kAwaitingDHKey:            return "AwaitingDHKey";
82        case kAwaitingRevealSignature:  return "AwaitingRevealSignature";
83        case kAwaitingSignature:        return "AwaitingSignature";
84        case kDone:                     return "Done";
85        default:                        return "InvalidState";
86    }
87}
88
89static CF_RETURNS_RETAINED CFStringRef SecOTRSessionCopyDescription(CFTypeRef cf) {
90    SecOTRSessionRef session = (SecOTRSessionRef)cf;
91    return CFStringCreateWithFormat(kCFAllocatorDefault,NULL,CFSTR("<%s %s%s%s%s %d:%d %s%s>"),
92                                    SecOTRAuthStateString(session->_state),
93                                    session->_me ? "F" : "-",
94                                    session->_them ? "P" : "-",
95                                    session->_receivedDHMessage ? "D" : "-",
96                                    session->_receivedDHKeyMessage ? "K" : "-",
97                                    session->_keyID,
98                                    session->_theirKeyID,
99                                    session->_theirPreviousKey ? "P" : "-",
100                                    session->_theirKey ? "T" : "-");
101}
102
103static void SecOTRSessionDestroy(CFTypeRef cf) {
104    SecOTRSessionRef session = (SecOTRSessionRef)cf;
105
106    CFReleaseNull(session->_receivedDHMessage);
107    CFReleaseNull(session->_receivedDHKeyMessage);
108
109    CFReleaseNull(session->_me);
110    CFReleaseNull(session->_myKey);
111    CFReleaseNull(session->_myNextKey);
112
113    CFReleaseNull(session->_them);
114    CFReleaseNull(session->_theirKey);
115    CFReleaseNull(session->_theirPreviousKey);
116
117    CFReleaseNull(session->_macKeysToExpose);
118
119    dispatch_release(session->_queue);
120}
121
122static void SecOTRSessionResetInternal(SecOTRSessionRef session)
123{
124    session->_state = kIdle;
125
126    CFReleaseNull(session->_receivedDHMessage);
127    CFReleaseNull(session->_receivedDHKeyMessage);
128
129    session->_keyID = 0;
130    CFReleaseNull(session->_myKey);
131    CFReleaseNull(session->_myNextKey);
132    //session->_myNextKey = SecOTRFullDHKCreate(kCFAllocatorDefault);
133    session->_theirKeyID = 0;
134    CFReleaseNull(session->_theirKey);
135    CFReleaseNull(session->_theirPreviousKey);
136    CFReleaseNull(session->_macKeysToExpose);
137    session->_macKeysToExpose = CFDataCreateMutable(kCFAllocatorDefault, 0);
138
139    bzero(session->_keyCache, sizeof(session->_keyCache));
140}
141
142void SecOTRSessionReset(SecOTRSessionRef session)
143{
144    dispatch_sync_f(session->_queue, session, (dispatch_function_t) SecOTRSessionResetInternal);
145}
146
147
148SecOTRSessionRef SecOTRSessionCreateFromID(CFAllocatorRef allocator,
149                                           SecOTRFullIdentityRef myID,
150                                           SecOTRPublicIdentityRef theirID)
151{
152    SecOTRSessionRef newID = CFTypeAllocate(SecOTRSession, struct _SecOTRSession, allocator);
153
154    newID->_queue = dispatch_queue_create("OTRSession", DISPATCH_QUEUE_SERIAL);
155
156    newID->_me = myID;
157    newID->_them = theirID;
158    newID->_receivedDHMessage = NULL;
159    newID->_receivedDHKeyMessage = NULL;
160    newID->_myKey = NULL;
161    newID->_myNextKey = NULL;
162    newID->_theirKey = NULL;
163    newID->_theirPreviousKey = NULL;
164    newID->_macKeysToExpose = NULL;
165    newID->_textOutput = false;
166
167    SecOTRSessionResetInternal(newID);
168
169    CFRetain(newID->_me);
170    CFRetain(newID->_them);
171
172    return newID;
173}
174
175SecOTRSessionRef SecOTRSessionCreateFromIDAndFlags(CFAllocatorRef allocator,
176                                           SecOTRFullIdentityRef myID,
177                                           SecOTRPublicIdentityRef theirID,
178                                           uint32_t flags)
179{
180    SecOTRSessionRef newID = SecOTRSessionCreateFromID(allocator, myID, theirID);
181    if (flags & kSecOTRSendTextMessages) {
182        newID->_textOutput = true;
183    }
184    return newID;
185}
186
187static uint64_t constant_zero = 0;
188
189static void SecOTRSFindKeysForMessage(SecOTRSessionRef session,
190                                      SecOTRFullDHKeyRef myKey,
191                                      SecOTRPublicDHKeyRef theirKey,
192                                      bool sending,
193                                      uint8_t** messageKey, uint8_t** macKey, uint64_t **counter)
194{
195    SecOTRCacheElement* emptyKeys = NULL;
196    SecOTRCacheElement* cachedKeys = NULL;
197
198    if ((NULL == myKey) || (NULL == theirKey)) {
199        if (messageKey)
200            *messageKey = NULL;
201        if (macKey)
202            *macKey = NULL;
203        if (counter)
204            *counter = &constant_zero;
205
206        return;
207    }
208
209    for(int i = 0; i < kOTRKeyCacheSize; ++i)
210    {
211        if (0 == constant_memcmp(session->_keyCache[i]._fullKeyHash, SecFDHKGetHash(myKey), CCSHA1_OUTPUT_SIZE)
212         && (0 == constant_memcmp(session->_keyCache[i]._publicKeyHash, SecPDHKGetHash(theirKey), CCSHA1_OUTPUT_SIZE))) {
213            cachedKeys = &session->_keyCache[i];
214            break;
215        }
216
217        if (emptyKeys == NULL
218         && session->_keyCache[i]._fullKey == NULL) {
219            emptyKeys = &session->_keyCache[i];
220        }
221    }
222
223    if (cachedKeys == NULL) {
224        if (emptyKeys == NULL) {
225            syslog(LOG_ERR, "SecOTRSession key cache was full. Should never happen, spooky.\n");
226            emptyKeys = &session->_keyCache[0];
227        }
228
229        // Fill in the entry.
230        emptyKeys->_fullKey = myKey;
231        memcpy(emptyKeys->_fullKeyHash, SecFDHKGetHash(myKey), CCSHA1_OUTPUT_SIZE);
232        emptyKeys->_publicKey = theirKey;
233        memcpy(emptyKeys->_publicKeyHash, SecPDHKGetHash(theirKey), CCSHA1_OUTPUT_SIZE);
234
235        emptyKeys->_counter = 0;
236        emptyKeys->_theirCounter = 0;
237
238        SecOTRDHKGenerateOTRKeys(emptyKeys->_fullKey, emptyKeys->_publicKey,
239                              emptyKeys->_sendEncryptionKey, emptyKeys->_sendMacKey,
240                              emptyKeys->_receiveEncryptionKey, emptyKeys->_receiveMacKey);
241
242        cachedKeys = emptyKeys;
243    }
244
245    if (messageKey)
246        *messageKey = sending ? cachedKeys->_sendEncryptionKey : cachedKeys->_receiveEncryptionKey;
247    if (macKey)
248        *macKey = sending ? cachedKeys->_sendMacKey : cachedKeys->_receiveMacKey;
249    if (counter)
250        *counter = sending ? &cachedKeys->_counter : &cachedKeys->_theirCounter;
251}
252
253SecOTRSessionRef SecOTRSessionCreateFromData(CFAllocatorRef allocator, CFDataRef data)
254{
255    if (data == NULL)
256        return NULL;
257
258    SecOTRSessionRef result = NULL;
259    SecOTRSessionRef session = CFTypeAllocate(SecOTRSession, struct _SecOTRSession, allocator);
260
261    const uint8_t *bytes = CFDataGetBytePtr(data);
262    size_t size = (size_t)CFDataGetLength(data);
263
264    session->_queue = dispatch_queue_create("OTRSession", DISPATCH_QUEUE_SERIAL);
265
266    session->_me = NULL;
267    session->_them = NULL;
268    session->_myKey = NULL;
269    session->_myNextKey = NULL;
270    session->_theirKey = NULL;
271    session->_theirPreviousKey = NULL;
272    session->_receivedDHMessage = NULL;
273    session->_receivedDHKeyMessage = NULL;
274    bzero(session->_keyCache, sizeof(session->_keyCache));
275
276    uint8_t version;
277    require_noerr(ReadByte(&bytes, &size, &version), fail);
278    require(version <= 3, fail);
279
280    require_noerr(ReadLong(&bytes, &size, &session->_state), fail);
281    session->_me = SecOTRFullIdentityCreateFromBytes(kCFAllocatorDefault, &bytes, &size, NULL);
282    require(session->_me != NULL, fail);
283    session->_them = SecOTRPublicIdentityCreateFromBytes(kCFAllocatorDefault, &bytes, &size, NULL);
284    require(session->_them != NULL, fail);
285
286    require(size > sizeof(session->_r), fail);
287    memcpy(session->_r, bytes, sizeof(session->_r));
288    bytes += sizeof(session->_r);
289    size -= sizeof(session->_r);
290
291    {
292        uint8_t hasMessage = false;
293        ReadByte(&bytes, &size, &hasMessage);
294        if (hasMessage) {
295            session->_receivedDHMessage = CFDataCreateMutableFromOTRDATA(kCFAllocatorDefault, &bytes, &size);
296        }
297    }
298
299    if (version >= 2) {
300        uint8_t hasMessage = false;
301        ReadByte(&bytes, &size, &hasMessage);
302        if (hasMessage) {
303            session->_receivedDHKeyMessage = CFDataCreateMutableFromOTRDATA(kCFAllocatorDefault, &bytes, &size);
304        }
305    }
306
307    if (version < 3) {
308        uint8_t ready;
309        require_noerr(ReadByte(&bytes, &size, &ready), fail);
310        if (ready && session->_state == kIdle)
311            session->_state = kDone;
312    }
313
314    require_noerr(ReadLong(&bytes, &size, &session->_keyID), fail);
315    if (session->_keyID > 0) {
316        session->_myKey = SecOTRFullDHKCreateFromBytes(kCFAllocatorDefault, &bytes, &size);
317        require(session->_myKey != NULL, fail);
318        session->_myNextKey = SecOTRFullDHKCreateFromBytes(kCFAllocatorDefault, &bytes, &size);
319        require(session->_myNextKey != NULL, fail);
320    }
321
322    require_noerr(ReadLong(&bytes, &size, &session->_theirKeyID), fail);
323    if (session->_theirKeyID > 0) {
324        if (session->_theirKeyID > 1) {
325            session->_theirPreviousKey = SecOTRPublicDHKCreateFromSerialization(kCFAllocatorDefault, &bytes, &size);
326            require(session->_theirPreviousKey != NULL, fail);
327        }
328        session->_theirKey = SecOTRPublicDHKCreateFromSerialization(kCFAllocatorDefault, &bytes, &size);
329        require(session->_theirKey != NULL, fail);
330    }
331
332    uint64_t *counter;
333    SecOTRSFindKeysForMessage(session, session->_myKey, session->_theirKey, false, NULL, NULL, &counter);
334    require_noerr(ReadLongLong(&bytes, &size, counter), fail);
335    SecOTRSFindKeysForMessage(session, session->_myKey, session->_theirKey, true, NULL, NULL, &counter);
336    require_noerr(ReadLongLong(&bytes, &size, counter), fail);
337    SecOTRSFindKeysForMessage(session, session->_myKey, session->_theirPreviousKey, false, NULL, NULL, &counter);
338    require_noerr(ReadLongLong(&bytes, &size, counter), fail);
339    SecOTRSFindKeysForMessage(session, session->_myKey, session->_theirPreviousKey, true, NULL, NULL, &counter);
340    require_noerr(ReadLongLong(&bytes, &size, counter), fail);
341    SecOTRSFindKeysForMessage(session, session->_myNextKey, session->_theirKey, false, NULL, NULL, &counter);
342    require_noerr(ReadLongLong(&bytes, &size, counter), fail);
343    SecOTRSFindKeysForMessage(session, session->_myNextKey, session->_theirKey, true, NULL, NULL, &counter);
344    require_noerr(ReadLongLong(&bytes, &size, counter), fail);
345    SecOTRSFindKeysForMessage(session, session->_myNextKey, session->_theirPreviousKey, false, NULL, NULL, &counter);
346    require_noerr(ReadLongLong(&bytes, &size, counter), fail);
347    SecOTRSFindKeysForMessage(session, session->_myNextKey, session->_theirPreviousKey, true, NULL, NULL, &counter);
348    require_noerr(ReadLongLong(&bytes, &size, counter), fail);
349
350    session->_macKeysToExpose = CFDataCreateMutableFromOTRDATA(kCFAllocatorDefault, &bytes, &size);
351    require(session->_macKeysToExpose != NULL, fail);
352
353    uint8_t textMode;
354    require_noerr(ReadByte(&bytes, &size, &textMode), fail);
355    session->_textOutput = (textMode != 0);
356
357    result = session;
358    session = NULL;
359
360fail:
361    CFReleaseNull(session);
362    return result;
363}
364
365
366OSStatus SecOTRSAppendSerialization(SecOTRSessionRef session, CFMutableDataRef serializeInto)
367{
368    __block OSStatus result  = errSecParam;
369
370    require(session, abort);
371    require(serializeInto, abort);
372
373    CFIndex start = CFDataGetLength(serializeInto);
374
375    dispatch_sync(session->_queue, ^{
376        const uint8_t version = 3;
377
378        CFDataAppendBytes(serializeInto, &version, sizeof(version));
379
380        AppendLong(serializeInto, session->_state);
381
382        result = (SecOTRFIAppendSerialization(session->_me, serializeInto, NULL)) ? errSecSuccess : errSecParam;
383
384        if (result == errSecSuccess) {
385            result = (SecOTRPIAppendSerialization(session->_them, serializeInto, NULL)) ? errSecSuccess : errSecParam;
386        }
387
388        if (result == errSecSuccess) {
389            CFDataAppendBytes(serializeInto, session->_r, sizeof(session->_r));
390
391            if (session->_receivedDHMessage == NULL) {
392                AppendByte(serializeInto, 0);
393            } else {
394                AppendByte(serializeInto, 1);
395                AppendCFDataAsDATA(serializeInto, session->_receivedDHMessage);
396            }
397
398            if (session->_receivedDHKeyMessage == NULL) {
399                AppendByte(serializeInto, 0);
400            } else {
401                AppendByte(serializeInto, 1);
402                AppendCFDataAsDATA(serializeInto, session->_receivedDHKeyMessage);
403            }
404
405            AppendLong(serializeInto, session->_keyID);
406            if (session->_keyID > 0) {
407                SecFDHKAppendSerialization(session->_myKey, serializeInto);
408                SecFDHKAppendSerialization(session->_myNextKey, serializeInto);
409            }
410
411            AppendLong(serializeInto, session->_theirKeyID);
412            if (session->_theirKeyID > 0) {
413                if (session->_theirKeyID > 1) {
414                    SecPDHKAppendSerialization(session->_theirPreviousKey, serializeInto);
415                }
416                SecPDHKAppendSerialization(session->_theirKey, serializeInto);
417            }
418
419            uint64_t *counter;
420            SecOTRSFindKeysForMessage(session, session->_myKey, session->_theirKey, false, NULL, NULL, &counter);
421            AppendLongLong(serializeInto, *counter);
422            SecOTRSFindKeysForMessage(session, session->_myKey, session->_theirKey, true, NULL, NULL, &counter);
423            AppendLongLong(serializeInto, *counter);
424            SecOTRSFindKeysForMessage(session, session->_myKey, session->_theirPreviousKey, false, NULL, NULL, &counter);
425            AppendLongLong(serializeInto, *counter);
426            SecOTRSFindKeysForMessage(session, session->_myKey, session->_theirPreviousKey, true, NULL, NULL, &counter);
427            AppendLongLong(serializeInto, *counter);
428            SecOTRSFindKeysForMessage(session, session->_myNextKey, session->_theirKey, false, NULL, NULL, &counter);
429            AppendLongLong(serializeInto, *counter);
430            SecOTRSFindKeysForMessage(session, session->_myNextKey, session->_theirKey, true, NULL, NULL, &counter);
431            AppendLongLong(serializeInto, *counter);
432            SecOTRSFindKeysForMessage(session, session->_myNextKey, session->_theirPreviousKey, false, NULL, NULL, &counter);
433            AppendLongLong(serializeInto, *counter);
434            SecOTRSFindKeysForMessage(session, session->_myNextKey, session->_theirPreviousKey, true, NULL, NULL, &counter);
435            AppendLongLong(serializeInto, *counter);
436
437            AppendCFDataAsDATA(serializeInto, session->_macKeysToExpose);
438
439            AppendByte(serializeInto, session->_textOutput ? 1 : 0);
440        }
441    });
442
443    if (result != errSecSuccess)
444        CFDataSetLength(serializeInto, start);
445
446abort:
447    return result;
448}
449
450
451bool SecOTRSGetIsReadyForMessages(SecOTRSessionRef session)
452{
453    __block bool result;
454
455    dispatch_sync(session->_queue, ^{ result = session->_state == kDone; });
456
457    return result;
458}
459
460bool SecOTRSGetIsIdle(SecOTRSessionRef session)
461{
462    __block bool result;
463
464    dispatch_sync(session->_queue, ^{ result = session->_state == kIdle; });
465
466    return result;
467}
468
469static void SecOTRSExpireCachedKeysForFullKey(SecOTRSessionRef session, SecOTRFullDHKeyRef myKey)
470{
471    for(int i = 0; i < kOTRKeyCacheSize; ++i)
472    {
473        if (0 == constant_memcmp(session->_keyCache[i]._fullKeyHash, SecFDHKGetHash(myKey), CCSHA1_OUTPUT_SIZE)) {
474            CFDataAppendBytes(session->_macKeysToExpose, session->_keyCache[i]._receiveMacKey, sizeof(session->_keyCache[i]._receiveMacKey));
475
476            bzero(&session->_keyCache[i], sizeof(session->_keyCache[i]));
477        }
478    }
479}
480
481static void SecOTRSExpireCachedKeysForPublicKey(SecOTRSessionRef session, SecOTRPublicDHKeyRef theirKey)
482{
483    for(int i = 0; i < kOTRKeyCacheSize; ++i)
484    {
485        if (0 == constant_memcmp(session->_keyCache[i]._publicKeyHash, SecPDHKGetHash(theirKey), CCSHA1_OUTPUT_SIZE)) {
486            CFDataAppendBytes(session->_macKeysToExpose, session->_keyCache[i]._receiveMacKey, sizeof(session->_keyCache[i]._receiveMacKey));
487
488            bzero(&session->_keyCache[i], sizeof(session->_keyCache[i]));
489        }
490    }
491}
492
493static void SecOTRSPrecalculateForPair(SecOTRSessionRef session,
494                                       SecOTRFullDHKeyRef myKey,
495                                       SecOTRPublicDHKeyRef theirKey)
496{
497    if (myKey == NULL || theirKey == NULL)
498        return;
499
500    SecOTRSFindKeysForMessage(session, myKey, theirKey, true, NULL, NULL, NULL);
501    SecOTRSFindKeysForMessage(session, myKey, theirKey, false, NULL, NULL, NULL);
502}
503
504static void SecOTRSPrecalculateKeysInternal(SecOTRSessionRef session)
505{
506    SecOTRSPrecalculateForPair(session, session->_myKey, session->_theirKey);
507    SecOTRSPrecalculateForPair(session, session->_myNextKey, session->_theirKey);
508    SecOTRSPrecalculateForPair(session, session->_myKey, session->_theirPreviousKey);
509    SecOTRSPrecalculateForPair(session, session->_myNextKey, session->_theirPreviousKey);
510}
511
512void SecOTRSPrecalculateKeys(SecOTRSessionRef session)
513{
514    dispatch_sync_f(session->_queue, session, (dispatch_function_t) SecOTRSPrecalculateKeysInternal);
515}
516
517enum SecOTRSMessageKind SecOTRSGetMessageKind(SecOTRSessionRef session, CFDataRef message)
518{
519    enum SecOTRSMessageKind kind = kOTRUnknownPacket;
520
521    CFMutableDataRef decodedBytes = CFDataCreateMutable(kCFAllocatorDefault, 0);
522    SecOTRGetIncomingBytes(message, decodedBytes);
523
524    const uint8_t *bytes = CFDataGetBytePtr(decodedBytes);
525    size_t size = CFDataGetLength(decodedBytes);
526
527    OTRMessageType type;
528    require_noerr(ReadHeader(&bytes, &size, &type), fail);
529
530    kind = (type == kDataMessage) ? kOTRDataPacket : kOTRNegotiationPacket;
531
532fail:
533    CFReleaseNull(decodedBytes);
534
535    return kind;
536}
537
538OSStatus SecOTRSSignAndProtectMessage(SecOTRSessionRef session,
539                                      CFDataRef sourceMessage,
540                                      CFMutableDataRef protectedMessage)
541{
542    __block OSStatus result = errSecParam;
543
544    require(session, abort);
545    require(sourceMessage, abort);
546    require(protectedMessage, abort);
547
548    dispatch_sync(session->_queue, ^{
549        if (session->_myKey == NULL ||
550            session->_theirKey == NULL) {
551            return;
552        }
553
554        CFMutableDataRef destinationMessage;
555        if (session->_textOutput) {
556            destinationMessage = CFDataCreateMutable(kCFAllocatorDefault, 0);
557        } else {
558            destinationMessage = protectedMessage;
559        }
560
561        uint8_t *messageKey;
562        uint8_t *macKey;
563        uint64_t *counter;
564
565        CFIndex start = CFDataGetLength(destinationMessage);
566
567        SecOTRSFindKeysForMessage(session, session->_myKey, session->_theirKey,
568                                  true,
569                                  &messageKey, &macKey, &counter);
570
571        AppendHeader(destinationMessage, kDataMessage);
572        AppendByte(destinationMessage, 0); // Flags, all zero
573
574        AppendLong(destinationMessage, session->_keyID);
575        AppendLong(destinationMessage, session->_theirKeyID);
576        SecFDHKAppendPublicSerialization(session->_myNextKey, destinationMessage);
577        AppendLongLong(destinationMessage, ++*counter);
578
579        CFIndex sourceSize = CFDataGetLength(sourceMessage);
580        assert(((unsigned long)sourceSize)<=UINT32_MAX); /* this is correct as long as CFIndex is a signed long */
581        AppendLong(destinationMessage, (uint32_t)sourceSize);
582        uint8_t* encryptedDataPointer = CFDataIncreaseLengthAndGetMutableBytes(destinationMessage, sourceSize);
583        AES_CTR_HighHalf_Transform(kOTRMessageKeyBytes, messageKey,
584                                   *counter,
585                                   (size_t)sourceSize, CFDataGetBytePtr(sourceMessage),
586                                   encryptedDataPointer);
587
588        CFIndex macedContentsSize = CFDataGetLength(destinationMessage) - start;
589        CFIndex macSize = CCSHA1_OUTPUT_SIZE;
590        uint8_t* macDataPointer = CFDataIncreaseLengthAndGetMutableBytes(destinationMessage, macSize);
591
592#ifdef USECOMMONCRYPTO
593        CCHmac(kCCHmacAlgSHA1,
594               macKey, kOTRMessageMacKeyBytes,
595               CFDataGetBytePtr(destinationMessage) + start, (size_t)macedContentsSize,
596               macDataPointer);
597#else
598        cchmac(ccsha1_di(),
599               kOTRMessageMacKeyBytes, macKey,
600               macedContentsSize, CFDataGetBytePtr(destinationMessage) + start,
601               macDataPointer);
602#endif
603
604        CFDataAppend(destinationMessage, session->_macKeysToExpose);
605
606        CFDataSetLength(session->_macKeysToExpose, 0);
607
608        if (session->_textOutput) {
609            SecOTRPrepareOutgoingBytes(destinationMessage, protectedMessage);
610            CFReleaseSafe(destinationMessage);
611        }
612
613        result = errSecSuccess;
614    });
615
616abort:
617    return result;
618}
619
620OSStatus SecOTRSVerifyAndExposeMessage(SecOTRSessionRef session,
621                                       CFDataRef incomingMessage,
622                                       CFMutableDataRef exposedMessageContents)
623{
624    __block SecOTRPublicDHKeyRef newKey = NULL;
625    __block OSStatus result = errSecParam;
626
627
628    require(session, abort);
629    require(incomingMessage, abort);
630    require(exposedMessageContents, abort);
631
632    dispatch_sync(session->_queue, ^{
633        const uint8_t* bytes;
634        size_t  size;
635        CFMutableDataRef decodedBytes = CFDataCreateMutable(kCFAllocatorDefault, 0);
636        SecOTRGetIncomingBytes(incomingMessage, decodedBytes);
637
638        bytes = CFDataGetBytePtr(decodedBytes);
639        size = CFDataGetLength(decodedBytes);
640
641        const uint8_t* macDataStart = bytes;
642
643        uint32_t theirID;
644        uint32_t myID;
645
646        if ((result = ReadAndVerifyHeader(&bytes, &size, kDataMessage))){
647            CFReleaseSafe(decodedBytes);
648            return;
649        }
650
651        if (size <= 0) { result = errSecDecode;  CFReleaseSafe(decodedBytes); return; }
652
653        if ((result = ReadAndVerifyByte(&bytes, &size, 0))) {  CFReleaseSafe(decodedBytes); return;} // No flags
654
655        if ((result = ReadLong(&bytes, &size, &theirID))){  CFReleaseSafe(decodedBytes); return; }
656
657        if (theirID != session->_theirKeyID &&
658            (session->_theirPreviousKey == NULL || theirID != (session->_theirKeyID - 1)))
659        {
660            result = ((theirID + 1) < session->_theirKeyID) ? errSecOTRTooOld : errSecOTRIDTooNew;
661            CFReleaseSafe(decodedBytes);
662            return;
663        };
664
665        if ((result = ReadLong(&bytes, &size, &myID))){  CFReleaseSafe(decodedBytes); return; }
666        if (myID != session->_keyID && myID != (session->_keyID + 1))
667        {
668            result = (myID < session->_keyID) ? errSecOTRTooOld : errSecOTRIDTooNew;
669            CFReleaseSafe(decodedBytes);
670            return;
671        };
672
673
674        // Choose appripriate keys for message:
675        {
676            uint8_t *messageKey;
677            uint8_t *macKey;
678            uint64_t *theirCounter;
679
680            SecOTRFullDHKeyRef myKeyForMessage = (myID == session->_keyID) ? session->_myKey : session->_myNextKey;
681            SecOTRPublicDHKeyRef theirKeyForMessage = (theirID == session->_theirKeyID) ? session->_theirKey : session->_theirPreviousKey;
682
683            SecOTRSFindKeysForMessage(session, myKeyForMessage, theirKeyForMessage, false,
684                                      &messageKey, &macKey, &theirCounter);
685
686            size_t nextKeyMPISize;
687            const uint8_t* nextKeyMPIBytes;
688            if ((result = SizeAndSkipMPI(&bytes, &size, &nextKeyMPIBytes, &nextKeyMPISize))){  CFReleaseSafe(decodedBytes); return;}
689
690            uint64_t counter;
691            if ((result = ReadLongLong(&bytes, &size, &counter))) {  CFReleaseSafe(decodedBytes); return; }
692
693            if (counter <= *theirCounter) { result = errSecOTRTooOld;  CFReleaseSafe(decodedBytes); return; };
694
695            size_t messageSize;
696            const uint8_t* messageStart;
697            if ((result = SizeAndSkipDATA(&bytes, &size, &messageStart, &messageSize))) {  CFReleaseSafe(decodedBytes); return; }
698
699            size_t macDataSize = (bytes - macDataStart) ? (size_t)(bytes - macDataStart) : 0;
700            uint8_t mac[CCSHA1_OUTPUT_SIZE];
701            if (sizeof(mac) > size) { result = errSecDecode;  CFReleaseSafe(decodedBytes); return; }
702
703#ifdef USECOMMONCRYPTO
704            CCHmac(kCCHmacAlgSHA1,
705                   macKey, kOTRMessageMacKeyBytes,
706                   macDataStart, macDataSize,
707                   mac);
708#else
709            cchmac(ccsha1_di(),
710                   kOTRMessageMacKeyBytes, macKey,
711                   macDataSize, macDataStart,
712                   mac);
713#endif
714
715            if (0 != constant_memcmp(mac, bytes, sizeof(mac))) { result = errSecAuthFailed;  CFReleaseSafe(decodedBytes); return; }
716            //if (messageSize > 65535) { result = errSecDataTooLarge;  CFReleaseSafe(decodedBytes); return; }
717            uint8_t* dataSpace = CFDataIncreaseLengthAndGetMutableBytes(exposedMessageContents, (CFIndex)messageSize);
718
719
720            AES_CTR_HighHalf_Transform(kOTRMessageKeyBytes, messageKey,
721                                       counter,
722                                       messageSize, messageStart,
723                                       dataSpace);
724
725            // Everything is good, accept the meta data.
726            *theirCounter = counter;
727
728            newKey = SecOTRPublicDHKCreateFromBytes(kCFAllocatorDefault, &nextKeyMPIBytes, &nextKeyMPISize);
729        }
730
731        SecOTRSPrecalculateKeysInternal(session);
732
733        bool acceptTheirNewKey = newKey != NULL && theirID == session->_theirKeyID;
734
735        if (acceptTheirNewKey) {
736            if (session->_theirPreviousKey) {
737                SecOTRSExpireCachedKeysForPublicKey(session, session->_theirPreviousKey);
738            }
739
740            CFReleaseNull(session->_theirPreviousKey);
741            session->_theirPreviousKey = session->_theirKey;
742            session->_theirKey = newKey;
743
744            session->_theirKeyID += 1;
745
746            newKey = NULL;
747        }
748
749        if (myID == (session->_keyID + 1)) {
750            SecOTRSExpireCachedKeysForFullKey(session, session->_myKey);
751
752            // Swap the keys so we know the current key.
753            {
754                SecOTRFullDHKeyRef oldKey = session->_myKey;
755                session->_myKey = session->_myNextKey;
756                session->_myNextKey = oldKey;
757            }
758
759            // Derive a new next key by regenerating over the old key.
760            SecFDHKNewKey(session->_myNextKey);
761
762            session->_keyID = myID;
763        }
764        CFReleaseSafe(decodedBytes);
765    });
766
767abort:
768    CFReleaseNull(newKey);
769    return result;
770}
771
772
773OSStatus SecOTRSEndSession(SecOTRSessionRef session,
774                           CFMutableDataRef messageToSend)
775{
776    return errSecUnimplemented;
777}
778