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 <stdint.h>
26#include <sys/types.h>
27#include "utilities/comparison.h"
28
29#include "SecOTRSession.h"
30
31#include "SecOTRMath.h"
32#include "SecOTRDHKey.h"
33#include "SecOTRSessionPriv.h"
34#include "SecOTRPackets.h"
35#include "SecOTRPacketData.h"
36#include "SecOTRIdentityPriv.h"
37
38#include <utilities/SecCFWrappers.h>
39
40#include <CoreFoundation/CFRuntime.h>
41#include <CoreFoundation/CFString.h>
42
43#include <Security/SecBasePriv.h>
44#include <Security/SecRandom.h>
45#include <Security/SecBase64.h>
46#include <Security/SecKeyPriv.h>
47
48#include <SecureObjectSync/SOSPeerInfo.h>
49#include <SecureObjectSync/SOSCircle.h>
50#include <SecureObjectSync/SOSCloudCircle.h>
51#include <SecureObjectSync/SOSInternal.h>
52#include <SecureObjectSync/SOSUserKeygen.h>
53
54#include <AssertMacros.h>
55
56#include <corecrypto/cchmac.h>
57#include <corecrypto/ccsha2.h>
58#include <corecrypto/ccsha1.h>
59
60#include <string.h>
61#include <stdlib.h>
62
63#include <syslog.h>
64
65#include <utilities/array_size.h>
66
67#include <ipc/securityd_client.h>
68#include <Security/SecuritydXPC.h>
69
70CFGiblisFor(SecOTRSession);
71
72static OTRMessageType SecOTRSGetMessageType(CFDataRef message)
73{
74    OTRMessageType type = kInvalidMessage;
75
76    CFDataRef decodedBytes = SecOTRCopyIncomingBytes(message);
77
78    const uint8_t *bytes = CFDataGetBytePtr(decodedBytes);
79    size_t size = CFDataGetLength(decodedBytes);
80
81    if (noErr != ReadHeader(&bytes, &size, &type)) {
82        uint8_t firstByte = *CFDataGetBytePtr(decodedBytes);
83        switch (firstByte) {
84            case kOddCompactDataMessage:
85            case kEvenCompactDataMessage:
86                type = firstByte;
87                break;
88
89            default:
90                break;
91        }
92    }
93
94    CFReleaseNull(decodedBytes);
95
96    return type;
97}
98
99const char *SecOTRPacketTypeString(CFDataRef message)
100{
101    if (!message) return "NoMessage";
102    switch (SecOTRSGetMessageType(message)) {
103        case kDHMessage:                return "DHMessage (0x02)";
104        case kDataMessage:              return "DataMessage (0x03)";
105        case kDHKeyMessage:             return "DHKeyMessage (0x0A)";
106        case kRevealSignatureMessage:   return "RevealSignatureMessage (0x11)";
107        case kSignatureMessage:         return "SignatureMessage (0x12)";
108        case kEvenCompactDataMessage:   return "kEvenCompactDatamessage (0x20)";
109        case kOddCompactDataMessage:    return "kOddCompactDataMessage (0x21)";
110        case kInvalidMessage:           return "InvalidMessage (0xFF)";
111        default:                        return "UnknownMessage";
112    }
113}
114
115static const char *SecOTRAuthStateString(SecOTRAuthState authState)
116{
117    switch (authState) {
118        case kIdle:                     return "Idle";
119        case kAwaitingDHKey:            return "AwaitingDHKey";
120        case kAwaitingRevealSignature:  return "AwaitingRevealSignature";
121        case kAwaitingSignature:        return "AwaitingSignature";
122        case kDone:                     return "Done";
123        default:                        return "InvalidState";
124    }
125}
126
127static CF_RETURNS_RETAINED CFStringRef SecOTRSessionCopyDescription(CFTypeRef cf) {
128    SecOTRSessionRef session = (SecOTRSessionRef)cf;
129    return CFStringCreateWithFormat(kCFAllocatorDefault,NULL,CFSTR("<%s %s %s%s%s%s %d:%d %s%s>"),
130                                    SecOTRAuthStateString(session->_state),
131                                    session->_compactAppleMessages ? "C" :"c",
132                                    session->_me ? "F" : "f",
133                                    session->_them ? "P" : "p",
134                                    session->_receivedDHMessage ? "D" : "d",
135                                    session->_receivedDHKeyMessage ? "K" : "k",
136                                    session->_keyID,
137                                    session->_theirKeyID,
138                                    session->_theirPreviousKey ? "P" : "p",
139                                    session->_theirKey ? "T" : "t");
140}
141
142static void SecOTRSessionDestroy(CFTypeRef cf) {
143    SecOTRSessionRef session = (SecOTRSessionRef)cf;
144
145    CFReleaseNull(session->_receivedDHMessage);
146    CFReleaseNull(session->_receivedDHKeyMessage);
147
148    CFReleaseNull(session->_me);
149    CFReleaseNull(session->_myKey);
150    CFReleaseNull(session->_myNextKey);
151
152    CFReleaseNull(session->_them);
153    CFReleaseNull(session->_theirKey);
154    CFReleaseNull(session->_theirPreviousKey);
155
156    CFReleaseNull(session->_macKeysToExpose);
157
158    dispatch_release(session->_queue);
159}
160
161static void SecOTRSessionResetInternal(SecOTRSessionRef session)
162{
163    session->_state = kIdle;
164
165    CFReleaseNull(session->_receivedDHMessage);
166    CFReleaseNull(session->_receivedDHKeyMessage);
167
168    session->_keyID = 0;
169    CFReleaseNull(session->_myKey);
170    CFReleaseNull(session->_myNextKey);
171    //session->_myNextKey = SecOTRFullDHKCreate(kCFAllocatorDefault);
172    session->_theirKeyID = 0;
173    CFReleaseNull(session->_theirKey);
174    CFReleaseNull(session->_theirPreviousKey);
175    CFReleaseNull(session->_macKeysToExpose);
176    session->_macKeysToExpose = CFDataCreateMutable(kCFAllocatorDefault, 0);
177
178    bzero(session->_keyCache, sizeof(session->_keyCache));
179}
180
181void SecOTRSessionReset(SecOTRSessionRef session)
182{
183    dispatch_sync_f(session->_queue, session, (dispatch_function_t) SecOTRSessionResetInternal);
184}
185
186
187SecOTRSessionRef SecOTRSessionCreateFromID(CFAllocatorRef allocator,
188                                           SecOTRFullIdentityRef myID,
189                                           SecOTRPublicIdentityRef theirID)
190{
191    SecOTRSessionRef newID = CFTypeAllocate(SecOTRSession, struct _SecOTRSession, allocator);
192
193    newID->_queue = dispatch_queue_create("OTRSession", DISPATCH_QUEUE_SERIAL);
194
195    newID->_me = myID;
196    newID->_them = theirID;
197    newID->_receivedDHMessage = NULL;
198    newID->_receivedDHKeyMessage = NULL;
199    newID->_myKey = NULL;
200    newID->_myNextKey = NULL;
201    newID->_theirKey = NULL;
202    newID->_theirPreviousKey = NULL;
203    newID->_macKeysToExpose = NULL;
204    newID->_textOutput = false;
205    newID->_compactAppleMessages = false;
206
207    SecOTRSessionResetInternal(newID);
208
209    CFRetain(newID->_me);
210    CFRetain(newID->_them);
211
212    return newID;
213}
214
215SecOTRSessionRef SecOTRSessionCreateFromIDAndFlags(CFAllocatorRef allocator,
216                                           SecOTRFullIdentityRef myID,
217                                           SecOTRPublicIdentityRef theirID,
218                                           uint32_t flags)
219{
220    SecOTRSessionRef newID = SecOTRSessionCreateFromID(allocator, myID, theirID);
221    if (flags & kSecOTRSendTextMessages) {
222        newID->_textOutput = true;
223    }
224    if (flags & kSecOTRUseAppleCustomMessageFormat) {
225        newID->_compactAppleMessages = true;
226    }
227    return newID;
228}
229
230static uint64_t constant_zero = 0;
231
232static bool hashIsZero(uint8_t hash[CCSHA1_OUTPUT_SIZE])
233{
234    bool isZero = true;
235    for(size_t byte = 0; isZero && byte < CCSHA1_OUTPUT_SIZE; ++byte)
236        isZero = (0 == hash[byte]);
237
238    return isZero;
239}
240
241
242static bool SOSOTRSCacheEntryIsEmpty(SecOTRCacheElement *element)
243{
244    return hashIsZero(element->_fullKeyHash) && hashIsZero(element->_publicKeyHash);
245}
246
247static void SecOTRSFindKeysForMessage(SecOTRSessionRef session,
248                                      SecOTRFullDHKeyRef myKey,
249                                      SecOTRPublicDHKeyRef theirKey,
250                                      bool sending,
251                                      uint8_t** messageKey, uint8_t** macKey, uint64_t **counter)
252{
253    SecOTRCacheElement* emptyKeys = NULL;
254    SecOTRCacheElement* cachedKeys = NULL;
255
256    if ((NULL == myKey) || (NULL == theirKey)) {
257        if (messageKey)
258            *messageKey = NULL;
259        if (macKey)
260            *macKey = NULL;
261        if (counter)
262            *counter = &constant_zero;
263
264        return;
265    }
266
267    for(int i = 0; i < kOTRKeyCacheSize; ++i)
268    {
269        if (0 == constant_memcmp(session->_keyCache[i]._fullKeyHash, SecFDHKGetHash(myKey), CCSHA1_OUTPUT_SIZE)
270         && (0 == constant_memcmp(session->_keyCache[i]._publicKeyHash, SecPDHKGetHash(theirKey), CCSHA1_OUTPUT_SIZE))) {
271            cachedKeys = &session->_keyCache[i];
272            break;
273        }
274
275        if (emptyKeys == NULL && SOSOTRSCacheEntryIsEmpty(&(session->_keyCache[i]))) {
276            emptyKeys = &session->_keyCache[i];
277        }
278    }
279
280    if (cachedKeys == NULL) {
281        if (emptyKeys == NULL) {
282            secerror("SecOTRSession key cache was full. Should never happen, spooky.\n");
283            emptyKeys = &session->_keyCache[0];
284        }
285
286        // Fill in the entry.
287        memcpy(emptyKeys->_fullKeyHash, SecFDHKGetHash(myKey), CCSHA1_OUTPUT_SIZE);
288        memcpy(emptyKeys->_publicKeyHash, SecPDHKGetHash(theirKey), CCSHA1_OUTPUT_SIZE);
289
290        emptyKeys->_counter = 0;
291        emptyKeys->_theirCounter = 0;
292
293        SecOTRDHKGenerateOTRKeys(myKey, theirKey,
294                              emptyKeys->_sendEncryptionKey, emptyKeys->_sendMacKey,
295                              emptyKeys->_receiveEncryptionKey, emptyKeys->_receiveMacKey);
296
297        cachedKeys = emptyKeys;
298    }
299
300    if (messageKey)
301        *messageKey = sending ? cachedKeys->_sendEncryptionKey : cachedKeys->_receiveEncryptionKey;
302    if (macKey)
303        *macKey = sending ? cachedKeys->_sendMacKey : cachedKeys->_receiveMacKey;
304    if (counter)
305        *counter = sending ? &cachedKeys->_counter : &cachedKeys->_theirCounter;
306}
307
308SecOTRSessionRef SecOTRSessionCreateFromData(CFAllocatorRef allocator, CFDataRef data)
309{
310    if (data == NULL)
311        return NULL;
312
313    SecOTRSessionRef result = NULL;
314    SecOTRSessionRef session = CFTypeAllocate(SecOTRSession, struct _SecOTRSession, allocator);
315
316    const uint8_t *bytes = CFDataGetBytePtr(data);
317    size_t size = (size_t)CFDataGetLength(data);
318
319    session->_queue = dispatch_queue_create("OTRSession", DISPATCH_QUEUE_SERIAL);
320
321    session->_me = NULL;
322    session->_them = NULL;
323    session->_myKey = NULL;
324    session->_myNextKey = NULL;
325    session->_theirKey = NULL;
326    session->_theirPreviousKey = NULL;
327    session->_receivedDHMessage = NULL;
328    session->_receivedDHKeyMessage = NULL;
329    session->_textOutput = false;
330    session->_compactAppleMessages = false;
331
332    bzero(session->_keyCache, sizeof(session->_keyCache));
333
334    uint8_t version;
335    require_noerr(ReadByte(&bytes, &size, &version), fail);
336    require(version <= 4, fail);
337
338    require_noerr(ReadLong(&bytes, &size, &session->_state), fail);
339    session->_me = SecOTRFullIdentityCreateFromBytes(kCFAllocatorDefault, &bytes, &size, NULL);
340    require(session->_me != NULL, fail);
341    session->_them = SecOTRPublicIdentityCreateFromBytes(kCFAllocatorDefault, &bytes, &size, NULL);
342    require(session->_them != NULL, fail);
343
344    require(size > sizeof(session->_r), fail);
345    memcpy(session->_r, bytes, sizeof(session->_r));
346    bytes += sizeof(session->_r);
347    size -= sizeof(session->_r);
348
349    {
350        uint8_t hasMessage = false;
351        ReadByte(&bytes, &size, &hasMessage);
352        if (hasMessage) {
353            session->_receivedDHMessage = CFDataCreateMutableFromOTRDATA(kCFAllocatorDefault, &bytes, &size);
354        }
355    }
356
357    if (version >= 2) {
358        uint8_t hasMessage = false;
359        ReadByte(&bytes, &size, &hasMessage);
360        if (hasMessage) {
361            session->_receivedDHKeyMessage = CFDataCreateMutableFromOTRDATA(kCFAllocatorDefault, &bytes, &size);
362        }
363    }
364
365    if (version < 3) {
366        uint8_t ready;
367        require_noerr(ReadByte(&bytes, &size, &ready), fail);
368        if (ready && session->_state == kIdle)
369            session->_state = kDone;
370    }
371
372    require_noerr(ReadLong(&bytes, &size, &session->_keyID), fail);
373    if (session->_keyID > 0) {
374        session->_myKey = SecOTRFullDHKCreateFromBytes(kCFAllocatorDefault, &bytes, &size);
375        require(session->_myKey != NULL, fail);
376        session->_myNextKey = SecOTRFullDHKCreateFromBytes(kCFAllocatorDefault, &bytes, &size);
377        require(session->_myNextKey != NULL, fail);
378    }
379
380    require_noerr(ReadLong(&bytes, &size, &session->_theirKeyID), fail);
381    if (session->_theirKeyID > 0) {
382        if (session->_theirKeyID > 1) {
383            session->_theirPreviousKey = SecOTRPublicDHKCreateFromSerialization(kCFAllocatorDefault, &bytes, &size);
384            require(session->_theirPreviousKey != NULL, fail);
385        }
386        session->_theirKey = SecOTRPublicDHKCreateFromSerialization(kCFAllocatorDefault, &bytes, &size);
387        require(session->_theirKey != NULL, fail);
388    }
389
390    uint64_t *counter;
391    SecOTRSFindKeysForMessage(session, session->_myKey, session->_theirKey, false, NULL, NULL, &counter);
392    require_noerr(ReadLongLong(&bytes, &size, counter), fail);
393    SecOTRSFindKeysForMessage(session, session->_myKey, session->_theirKey, true, NULL, NULL, &counter);
394    require_noerr(ReadLongLong(&bytes, &size, counter), fail);
395    SecOTRSFindKeysForMessage(session, session->_myKey, session->_theirPreviousKey, false, NULL, NULL, &counter);
396    require_noerr(ReadLongLong(&bytes, &size, counter), fail);
397    SecOTRSFindKeysForMessage(session, session->_myKey, session->_theirPreviousKey, true, NULL, NULL, &counter);
398    require_noerr(ReadLongLong(&bytes, &size, counter), fail);
399    SecOTRSFindKeysForMessage(session, session->_myNextKey, session->_theirKey, false, NULL, NULL, &counter);
400    require_noerr(ReadLongLong(&bytes, &size, counter), fail);
401    SecOTRSFindKeysForMessage(session, session->_myNextKey, session->_theirKey, true, NULL, NULL, &counter);
402    require_noerr(ReadLongLong(&bytes, &size, counter), fail);
403    SecOTRSFindKeysForMessage(session, session->_myNextKey, session->_theirPreviousKey, false, NULL, NULL, &counter);
404    require_noerr(ReadLongLong(&bytes, &size, counter), fail);
405    SecOTRSFindKeysForMessage(session, session->_myNextKey, session->_theirPreviousKey, true, NULL, NULL, &counter);
406    require_noerr(ReadLongLong(&bytes, &size, counter), fail);
407
408    session->_macKeysToExpose = CFDataCreateMutableFromOTRDATA(kCFAllocatorDefault, &bytes, &size);
409    require(session->_macKeysToExpose != NULL, fail);
410
411    require_noerr(ReadByteAsBool(&bytes, &size, &session->_textOutput), fail);
412
413    if (version >= 4) {
414        require_noerr(ReadByteAsBool(&bytes, &size, &session->_compactAppleMessages), fail);
415    }
416
417    result = session;
418    session = NULL;
419
420fail:
421    CFReleaseNull(session);
422    return result;
423}
424
425
426OSStatus SecOTRSAppendSerialization(SecOTRSessionRef session, CFMutableDataRef serializeInto)
427{
428    __block OSStatus result  = errSecParam;
429
430    require(session, abort);
431    require(serializeInto, abort);
432
433    CFIndex start = CFDataGetLength(serializeInto);
434
435    dispatch_sync(session->_queue, ^{
436        const uint8_t version = 4;
437
438        CFDataAppendBytes(serializeInto, &version, sizeof(version));
439
440        AppendLong(serializeInto, session->_state);
441
442        result = (SecOTRFIAppendSerialization(session->_me, serializeInto, NULL)) ? errSecSuccess : errSecParam;
443
444        if (result == errSecSuccess) {
445            result = (SecOTRPIAppendSerialization(session->_them, serializeInto, NULL)) ? errSecSuccess : errSecParam;
446        }
447
448        if (result == errSecSuccess) {
449            CFDataAppendBytes(serializeInto, session->_r, sizeof(session->_r));
450
451            if (session->_receivedDHMessage == NULL) {
452                AppendByte(serializeInto, 0);
453            } else {
454                AppendByte(serializeInto, 1);
455                AppendCFDataAsDATA(serializeInto, session->_receivedDHMessage);
456            }
457
458            if (session->_receivedDHKeyMessage == NULL) {
459                AppendByte(serializeInto, 0);
460            } else {
461                AppendByte(serializeInto, 1);
462                AppendCFDataAsDATA(serializeInto, session->_receivedDHKeyMessage);
463            }
464
465            AppendLong(serializeInto, session->_keyID);
466            if (session->_keyID > 0) {
467                SecFDHKAppendSerialization(session->_myKey, serializeInto);
468                SecFDHKAppendSerialization(session->_myNextKey, serializeInto);
469            }
470
471            AppendLong(serializeInto, session->_theirKeyID);
472            if (session->_theirKeyID > 0) {
473                if (session->_theirKeyID > 1) {
474                    SecPDHKAppendSerialization(session->_theirPreviousKey, serializeInto);
475                }
476                SecPDHKAppendSerialization(session->_theirKey, serializeInto);
477            }
478
479            uint64_t *counter;
480            SecOTRSFindKeysForMessage(session, session->_myKey, session->_theirKey, false, NULL, NULL, &counter);
481            AppendLongLong(serializeInto, *counter);
482            SecOTRSFindKeysForMessage(session, session->_myKey, session->_theirKey, true, NULL, NULL, &counter);
483            AppendLongLong(serializeInto, *counter);
484            SecOTRSFindKeysForMessage(session, session->_myKey, session->_theirPreviousKey, false, NULL, NULL, &counter);
485            AppendLongLong(serializeInto, *counter);
486            SecOTRSFindKeysForMessage(session, session->_myKey, session->_theirPreviousKey, true, NULL, NULL, &counter);
487            AppendLongLong(serializeInto, *counter);
488            SecOTRSFindKeysForMessage(session, session->_myNextKey, session->_theirKey, false, NULL, NULL, &counter);
489            AppendLongLong(serializeInto, *counter);
490            SecOTRSFindKeysForMessage(session, session->_myNextKey, session->_theirKey, true, NULL, NULL, &counter);
491            AppendLongLong(serializeInto, *counter);
492            SecOTRSFindKeysForMessage(session, session->_myNextKey, session->_theirPreviousKey, false, NULL, NULL, &counter);
493            AppendLongLong(serializeInto, *counter);
494            SecOTRSFindKeysForMessage(session, session->_myNextKey, session->_theirPreviousKey, true, NULL, NULL, &counter);
495            AppendLongLong(serializeInto, *counter);
496
497            AppendCFDataAsDATA(serializeInto, session->_macKeysToExpose);
498
499            AppendByte(serializeInto, session->_textOutput ? 1 : 0);
500            AppendByte(serializeInto, session->_compactAppleMessages ? 1 : 0);
501        }
502    });
503
504    if (result != errSecSuccess)
505        CFDataSetLength(serializeInto, start);
506
507abort:
508    return result;
509}
510
511
512bool SecOTRSGetIsReadyForMessages(SecOTRSessionRef session)
513{
514    __block bool result;
515
516    dispatch_sync(session->_queue, ^{ result = session->_state == kDone; });
517
518    return result;
519}
520
521bool SecOTRSGetIsIdle(SecOTRSessionRef session)
522{
523    __block bool result;
524
525    dispatch_sync(session->_queue, ^{ result = session->_state == kIdle; });
526
527    return result;
528}
529
530static void SecOTRSExpireCachedKeysForFullKey(SecOTRSessionRef session, SecOTRFullDHKeyRef myKey)
531{
532    for(int i = 0; i < kOTRKeyCacheSize; ++i)
533    {
534        if (0 == constant_memcmp(session->_keyCache[i]._fullKeyHash, SecFDHKGetHash(myKey), CCSHA1_OUTPUT_SIZE)) {
535            CFDataAppendBytes(session->_macKeysToExpose, session->_keyCache[i]._receiveMacKey, sizeof(session->_keyCache[i]._receiveMacKey));
536
537            bzero(&session->_keyCache[i], sizeof(session->_keyCache[i]));
538        }
539    }
540}
541
542static void SecOTRSExpireCachedKeysForPublicKey(SecOTRSessionRef session, SecOTRPublicDHKeyRef theirKey)
543{
544    for(int i = 0; i < kOTRKeyCacheSize; ++i)
545    {
546        if (0 == constant_memcmp(session->_keyCache[i]._publicKeyHash, SecPDHKGetHash(theirKey), CCSHA1_OUTPUT_SIZE)) {
547            CFDataAppendBytes(session->_macKeysToExpose, session->_keyCache[i]._receiveMacKey, sizeof(session->_keyCache[i]._receiveMacKey));
548
549            bzero(&session->_keyCache[i], sizeof(session->_keyCache[i]));
550        }
551    }
552}
553
554static void SecOTRSPrecalculateForPair(SecOTRSessionRef session,
555                                       SecOTRFullDHKeyRef myKey,
556                                       SecOTRPublicDHKeyRef theirKey)
557{
558    if (myKey == NULL || theirKey == NULL)
559        return;
560
561    SecOTRSFindKeysForMessage(session, myKey, theirKey, true, NULL, NULL, NULL);
562    SecOTRSFindKeysForMessage(session, myKey, theirKey, false, NULL, NULL, NULL);
563}
564
565static void SecOTRSPrecalculateKeysInternal(SecOTRSessionRef session)
566{
567    SecOTRSPrecalculateForPair(session, session->_myKey, session->_theirKey);
568    SecOTRSPrecalculateForPair(session, session->_myNextKey, session->_theirKey);
569    SecOTRSPrecalculateForPair(session, session->_myKey, session->_theirPreviousKey);
570    SecOTRSPrecalculateForPair(session, session->_myNextKey, session->_theirPreviousKey);
571}
572
573void SecOTRSPrecalculateKeys(SecOTRSessionRef session)
574{
575    dispatch_sync_f(session->_queue, session, (dispatch_function_t) SecOTRSPrecalculateKeysInternal);
576}
577
578enum SecOTRSMessageKind SecOTRSGetMessageKind(SecOTRSessionRef session, CFDataRef message)
579{
580    OTRMessageType type = SecOTRSGetMessageType(message);
581
582    enum SecOTRSMessageKind kind;
583
584    switch (type) {
585        case kDataMessage:
586        case kEvenCompactDataMessage:
587        case kOddCompactDataMessage:
588            kind = kOTRDataPacket;
589            break;
590        case kDHMessage:
591        case kDHKeyMessage:
592        case kRevealSignatureMessage:
593        case kSignatureMessage:
594            kind = kOTRNegotiationPacket;
595            break;
596        case kInvalidMessage:
597        default:
598            kind = kOTRUnknownPacket;
599            break;
600    }
601
602    return kind;
603}
604
605static OSStatus SecOTRSSignAndProtectRaw_locked(SecOTRSessionRef session,
606                                                CFDataRef sourceMessage, CFMutableDataRef destinationMessage,
607                                                uint8_t* messageKey, uint8_t* macKey, uint64_t* counter)
608{
609    CFIndex start = CFDataGetLength(destinationMessage);
610
611    AppendHeader(destinationMessage, kDataMessage);
612    AppendByte(destinationMessage, 0); // Flags, all zero
613
614    AppendLong(destinationMessage, session->_keyID);
615    AppendLong(destinationMessage, session->_theirKeyID);
616    SecFDHKAppendPublicSerialization(session->_myNextKey, destinationMessage);
617    AppendLongLong(destinationMessage, ++*counter);
618
619    CFIndex sourceSize = CFDataGetLength(sourceMessage);
620    assert(((unsigned long)sourceSize)<=UINT32_MAX); /* this is correct as long as CFIndex is a signed long */
621    AppendLong(destinationMessage, (uint32_t)sourceSize);
622    uint8_t* encryptedDataPointer = CFDataIncreaseLengthAndGetMutableBytes(destinationMessage, sourceSize);
623    AES_CTR_HighHalf_Transform(kOTRMessageKeyBytes, messageKey,
624                               *counter,
625                               (size_t)sourceSize, CFDataGetBytePtr(sourceMessage),
626                               encryptedDataPointer);
627
628    CFIndex macedContentsSize = CFDataGetLength(destinationMessage) - start;
629    CFIndex macSize = CCSHA1_OUTPUT_SIZE;
630    uint8_t* macDataPointer = CFDataIncreaseLengthAndGetMutableBytes(destinationMessage, macSize);
631
632    cchmac(ccsha1_di(),
633           kOTRMessageMacKeyBytes, macKey,
634           macedContentsSize, CFDataGetBytePtr(destinationMessage) + start,
635           macDataPointer);
636
637    CFDataAppend(destinationMessage, session->_macKeysToExpose);
638
639    return errSecSuccess;
640}
641
642const size_t kCompactMessageMACSize = 16;
643
644static OSStatus SecOTRSSignAndProtectCompact_locked(SecOTRSessionRef session,
645                                                    CFDataRef sourceMessage, CFMutableDataRef destinationMessage,
646                                                    uint8_t* messageKey, uint8_t* macKey, uint64_t* counter)
647{
648    CFIndex start = CFDataGetLength(destinationMessage);
649
650    AppendByte(destinationMessage, (session->_theirKeyID & 0x1) ? kOddCompactDataMessage : kEvenCompactDataMessage);
651
652    SecFDHKAppendCompactPublicSerialization(session->_myNextKey, destinationMessage);
653    AppendLongLongCompact(destinationMessage, ++*counter);
654
655    CFIndex sourceSize = CFDataGetLength(sourceMessage);
656    assert(((unsigned long)sourceSize)<=UINT32_MAX); /* this is correct as long as CFIndex is a signed long */
657    uint8_t* encryptedDataPointer = CFDataIncreaseLengthAndGetMutableBytes(destinationMessage, sourceSize);
658    AES_CTR_HighHalf_Transform(kOTRMessageKeyBytes, messageKey,
659                               *counter,
660                               (size_t)sourceSize, CFDataGetBytePtr(sourceMessage),
661                               encryptedDataPointer);
662
663    CFIndex macedContentsSize = CFDataGetLength(destinationMessage) - start;
664    CFIndex macSize = CCSHA1_OUTPUT_SIZE;
665    uint8_t mac[macSize];
666    cchmac(ccsha1_di(),
667           kOTRMessageMacKeyBytes, macKey,
668           macedContentsSize, CFDataGetBytePtr(destinationMessage) + start,
669           mac);
670
671    CFDataAppendBytes(destinationMessage, mac, kCompactMessageMACSize);
672
673    return errSecSuccess;
674}
675
676OSStatus SecOTRSSignAndProtectMessage(SecOTRSessionRef session,
677                                      CFDataRef sourceMessage,
678                                      CFMutableDataRef protectedMessage)
679{
680    __block OSStatus result = errSecParam;
681
682    require(session, abort);
683    require(sourceMessage, abort);
684    require(protectedMessage, abort);
685
686    dispatch_sync(session->_queue, ^{
687        if (session->_myKey == NULL ||
688            session->_theirKey == NULL) {
689            return;
690        }
691
692        uint8_t *messageKey;
693        uint8_t *macKey;
694        uint64_t *counter;
695
696        SecOTRSFindKeysForMessage(session, session->_myKey, session->_theirKey,
697                                  true,
698                                  &messageKey, &macKey, &counter);
699
700
701        CFMutableDataRef destinationMessage = session->_textOutput ? CFDataCreateMutable(kCFAllocatorDefault, 0) : CFRetainSafe(protectedMessage);
702
703        result = session->_compactAppleMessages ? SecOTRSSignAndProtectCompact_locked(session, sourceMessage, destinationMessage, messageKey, macKey, counter)
704        : SecOTRSSignAndProtectRaw_locked(session, sourceMessage, destinationMessage, messageKey, macKey, counter);
705
706        if (result == errSecSuccess) {
707            if (session->_textOutput) {
708                SecOTRPrepareOutgoingBytes(destinationMessage, protectedMessage);
709            }
710
711            CFDataSetLength(session->_macKeysToExpose, 0);
712        }
713
714        CFReleaseSafe(destinationMessage);
715
716        result = errSecSuccess;
717    });
718
719abort:
720    return result;
721}
722
723static void SecOTRAcceptNewRemoteKey(SecOTRSessionRef session, SecOTRPublicDHKeyRef newKey)
724{
725    if (session->_theirPreviousKey) {
726        SecOTRSExpireCachedKeysForPublicKey(session, session->_theirPreviousKey);
727    }
728
729    CFReleaseNull(session->_theirPreviousKey);
730    session->_theirPreviousKey = session->_theirKey;
731    session->_theirKey = CFRetainSafe(newKey);
732
733    session->_theirKeyID += 1;
734}
735
736static void SecOTRGenerateNewProposedKey(SecOTRSessionRef session)
737{
738    SecOTRSExpireCachedKeysForFullKey(session, session->_myKey);
739
740    // Swap the keys so we know the current key.
741    {
742        SecOTRFullDHKeyRef oldKey = session->_myKey;
743        session->_myKey = session->_myNextKey;
744        session->_myNextKey = oldKey;
745    }
746
747    // Derive a new next key by regenerating over the old key.
748    SecFDHKNewKey(session->_myNextKey);
749
750    session->_keyID += 1;
751}
752
753static OSStatus SecOTRVerifyAndExposeRaw_locked(SecOTRSessionRef session,
754                                                CFDataRef decodedBytes,
755                                                CFMutableDataRef exposedMessageContents)
756{
757    OSStatus result = errSecDecode;
758
759    SecOTRPublicDHKeyRef newKey = NULL;
760    const uint8_t* bytes;
761    size_t  size;
762
763    bytes = CFDataGetBytePtr(decodedBytes);
764    size = CFDataGetLength(decodedBytes);
765
766    const uint8_t* macDataStart = bytes;
767
768    uint32_t theirID;
769    uint32_t myID;
770
771    require_noerr_quiet(result = ReadAndVerifyHeader(&bytes, &size, kDataMessage), fail);
772    require_action_quiet(size > 0, fail, result = errSecDecode);
773
774    require_noerr_quiet(result = ReadAndVerifyByte(&bytes, &size, 0), fail); // Flags, always zero
775
776    require_noerr_quiet(result = ReadLong(&bytes, &size, &theirID), fail);
777
778    require_action_quiet(theirID == session->_theirKeyID || (theirID == (session->_theirKeyID - 1) && session->_theirPreviousKey != NULL),
779                         fail,
780                         result = ((theirID + 1) < session->_theirKeyID) ? errSecOTRTooOld : errSecOTRIDTooNew);
781
782    require_noerr_quiet(result = ReadLong(&bytes, &size, &myID), fail);
783
784    require_action_quiet(myID == session->_keyID || (myID == session->_keyID + 1 && session->_myNextKey != NULL),
785                         fail,
786                         result = (myID < session->_keyID) ? errSecOTRTooOld : errSecOTRIDTooNew);
787
788
789    // Choose appripriate keys for message:
790    {
791        uint8_t *messageKey;
792        uint8_t *macKey;
793        uint64_t *theirCounter;
794
795        SecOTRFullDHKeyRef myKeyForMessage = (myID == session->_keyID) ? session->_myKey : session->_myNextKey;
796        SecOTRPublicDHKeyRef theirKeyForMessage = (theirID == session->_theirKeyID) ? session->_theirKey : session->_theirPreviousKey;
797
798        SecOTRSFindKeysForMessage(session, myKeyForMessage, theirKeyForMessage, false,
799                                  &messageKey, &macKey, &theirCounter);
800
801        size_t nextKeyMPISize;
802        const uint8_t* nextKeyMPIBytes;
803        require_noerr_quiet(result = SizeAndSkipMPI(&bytes, &size, &nextKeyMPIBytes, &nextKeyMPISize), fail);
804
805        uint64_t counter;
806        require_noerr_quiet(result = ReadLongLong(&bytes, &size, &counter), fail);
807        require_action_quiet(counter > *theirCounter, fail, result = errSecOTRTooOld);
808
809        size_t messageSize;
810        const uint8_t* messageStart;
811        require_noerr_quiet(result = SizeAndSkipDATA(&bytes, &size, &messageStart, &messageSize), fail);
812
813        size_t macDataSize = (bytes - macDataStart) ? (size_t)(bytes - macDataStart) : 0;
814        uint8_t mac[CCSHA1_OUTPUT_SIZE];
815        require_action_quiet(sizeof(mac) <= size, fail, result = errSecDecode);
816
817        cchmac(ccsha1_di(),
818               kOTRMessageMacKeyBytes, macKey,
819               macDataSize, macDataStart,
820               mac);
821
822        require_noerr_action_quiet(constant_memcmp(mac, bytes, sizeof(mac)), fail, result = errSecAuthFailed);
823
824        uint8_t* dataSpace = CFDataIncreaseLengthAndGetMutableBytes(exposedMessageContents, (CFIndex)messageSize);
825
826        AES_CTR_HighHalf_Transform(kOTRMessageKeyBytes, messageKey,
827                                   counter,
828                                   messageSize, messageStart,
829                                   dataSpace);
830
831        // Everything is good, accept the meta data.
832        *theirCounter = counter;
833
834        newKey = SecOTRPublicDHKCreateFromBytes(kCFAllocatorDefault, &nextKeyMPIBytes, &nextKeyMPISize);
835    }
836
837    bool acceptTheirNewKey = newKey != NULL && theirID == session->_theirKeyID;
838
839    if (acceptTheirNewKey) {
840        SecOTRAcceptNewRemoteKey(session, newKey);
841    }
842
843    if (myID == (session->_keyID + 1)) {
844        SecOTRGenerateNewProposedKey(session);
845    }
846
847    SecOTRSPrecalculateKeysInternal(session);
848
849fail:
850    CFReleaseNull(newKey);
851    return result;
852}
853
854static OSStatus SecOTRVerifyAndExposeRawCompact_locked(SecOTRSessionRef session,
855                                                CFDataRef decodedBytes,
856                                                CFMutableDataRef exposedMessageContents)
857{
858    SecOTRPublicDHKeyRef theirProposal = NULL;
859    OSStatus result = errSecDecode;
860    const uint8_t* bytes;
861    size_t  size;
862
863    bytes = CFDataGetBytePtr(decodedBytes);
864    size = CFDataGetLength(decodedBytes);
865
866    const uint8_t* macDataStart = bytes;
867
868    uint8_t type_byte;
869    require_noerr_quiet(result = ReadByte(&bytes, &size, &type_byte), fail);
870    require_action_quiet(type_byte == kOddCompactDataMessage || type_byte == kEvenCompactDataMessage, fail, result = errSecDecode);
871
872    bool useEvenKey = (type_byte == kEvenCompactDataMessage);
873
874    bool useCurrentKey = useEvenKey ^ (session->_keyID & 1);
875    SecOTRFullDHKeyRef myKeyForMessage =  useCurrentKey ? session->_myKey : session->_myNextKey;
876
877    theirProposal = SecOTRPublicDHKCreateFromCompactSerialization(kCFAllocatorDefault, &bytes, &size);
878
879    require_action_quiet(theirProposal, fail, result = errSecDecode);
880
881    bool proposalIsNew = !CFEqualSafe(theirProposal, session->_theirKey);
882    SecOTRPublicDHKeyRef theirKeyForMessage = proposalIsNew ? session->_theirKey : session->_theirPreviousKey;
883
884    uint8_t *messageKey;
885    uint8_t *macKey;
886    uint64_t *theirCounter;
887
888    SecOTRSFindKeysForMessage(session, myKeyForMessage, theirKeyForMessage, false, &messageKey, &macKey, &theirCounter);
889
890    uint64_t counter;
891    require_noerr_quiet(result = ReadLongLongCompact(&bytes, &size, &counter), fail);
892    require_action_quiet(counter > *theirCounter, fail, result = errSecOTRTooOld);
893
894    uint8_t mac[CCSHA1_OUTPUT_SIZE];
895    require_action_quiet(sizeof(mac) < size, fail, result = errSecDecode); // require space for the mac and some bytes
896
897    size_t messageSize = size - kCompactMessageMACSize; // It's all message except for the MAC
898    const uint8_t* messageStart = bytes;
899
900    bytes += messageSize;
901
902    size_t macDataSize = (size_t)(bytes - macDataStart);
903
904    cchmac(ccsha1_di(),
905           kOTRMessageMacKeyBytes, macKey,
906           macDataSize, macDataStart,
907           mac);
908
909    require_noerr_action_quiet(constant_memcmp(mac, bytes, kCompactMessageMACSize), fail, result = errSecAuthFailed);
910
911    uint8_t* dataSpace = CFDataIncreaseLengthAndGetMutableBytes(exposedMessageContents, (CFIndex)messageSize);
912
913    AES_CTR_HighHalf_Transform(kOTRMessageKeyBytes, messageKey,
914                               counter,
915                               messageSize, messageStart,
916                               dataSpace);
917
918    // Everything is good, accept the meta data.
919    *theirCounter = counter;
920
921    if (proposalIsNew) {
922        SecOTRAcceptNewRemoteKey(session, theirProposal);
923    }
924
925    if (!useCurrentKey) {
926        SecOTRGenerateNewProposedKey(session);
927    }
928
929    SecOTRSPrecalculateKeysInternal(session);
930
931fail:
932    CFReleaseNull(theirProposal);
933    return result;
934}
935
936
937OSStatus SecOTRSVerifyAndExposeMessage(SecOTRSessionRef session,
938                                       CFDataRef incomingMessage,
939                                       CFMutableDataRef exposedMessageContents)
940{
941    __block OSStatus result = errSecParam;
942
943
944    require(session, abort);
945    require(incomingMessage, abort);
946    require(exposedMessageContents, abort);
947
948    dispatch_sync(session->_queue, ^{
949        CFDataRef decodedBytes = SecOTRCopyIncomingBytes(incomingMessage);
950
951        OTRMessageType messageType = SecOTRSGetMessageType(decodedBytes);
952
953        switch (messageType) {
954            case kDataMessage:
955                result = SecOTRVerifyAndExposeRaw_locked(session, decodedBytes, exposedMessageContents);
956                break;
957
958            case kOddCompactDataMessage:
959            case kEvenCompactDataMessage:
960                result = SecOTRVerifyAndExposeRawCompact_locked(session, decodedBytes, exposedMessageContents);
961                break;
962
963            default:
964                result = errSecUnsupportedFormat;
965                break;
966        }
967
968        CFReleaseSafe(decodedBytes);
969    });
970
971abort:
972    return result;
973}
974
975
976OSStatus SecOTRSEndSession(SecOTRSessionRef session,
977                           CFMutableDataRef messageToSend)
978{
979    return errSecUnimplemented;
980}
981
982static CFDataRef data_to_data_error_request(enum SecXPCOperation op, CFDataRef publicPeerId, CFErrorRef *error) {
983    __block CFDataRef result = NULL;
984    securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) {
985        return SecXPCDictionarySetDataOptional(message, kSecXPCPublicPeerId, publicPeerId, error);
986    }, ^bool(xpc_object_t response, CFErrorRef *error) {
987        return (result = SecXPCDictionaryCopyData(response, kSecXPCKeyResult, error));
988    });
989    return result;
990}
991
992static bool data_data_to_data_data_bool_error_request(enum SecXPCOperation op, CFDataRef sessionData, CFDataRef inputPacket, CFDataRef* outputSessionData, CFDataRef* outputPacket, bool *readyForMessages, CFErrorRef *error) {
993    __block CFDataRef tempOutputSessionData = NULL;
994    __block CFDataRef tempOutputPacket = NULL;
995    __block bool tempReadyForMessages = false;
996
997    bool result = securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) {
998        return SecXPCDictionarySetDataOptional(message, kSecXPCOTRSession, sessionData, error)
999        && SecXPCDictionarySetDataOptional(message, kSecXPCData, inputPacket, error);
1000    }, ^bool(xpc_object_t response, CFErrorRef *error) {
1001        if (xpc_dictionary_get_bool(response, kSecXPCKeyResult)) {
1002            tempOutputSessionData = SecXPCDictionaryCopyData(response, kSecXPCOTRSession, error);
1003            tempOutputPacket = SecXPCDictionaryCopyData(response, kSecXPCData, error);
1004            tempReadyForMessages = xpc_dictionary_get_bool(response, kSecXPCOTRReady);
1005            return true;
1006        } else {
1007            return false;
1008        }
1009
1010    });
1011
1012    *outputSessionData = tempOutputSessionData;
1013    *outputPacket = tempOutputPacket;
1014    *readyForMessages = tempReadyForMessages;
1015
1016    return result;
1017}
1018
1019
1020CFDataRef SecOTRSessionCreateRemote(CFDataRef publicPeerId, CFErrorRef *error) {
1021
1022    CFDataRef otrSession = SECURITYD_XPC(sec_otr_session_create_remote, data_to_data_error_request, publicPeerId, error);
1023    return otrSession;
1024
1025}
1026
1027bool SecOTRSessionProcessPacketRemote(CFDataRef sessionData, CFDataRef inputPacket, CFDataRef* outputSessionData, CFDataRef* outputPacket, bool *readyForMessages, CFErrorRef *error) {
1028
1029    return SECURITYD_XPC(sec_otr_session_process_packet_remote, data_data_to_data_data_bool_error_request, sessionData, inputPacket, outputSessionData, outputPacket, readyForMessages, error);
1030}
1031