+++ /dev/null
-//
-// SecOTRSession.c
-// libsecurity_libSecOTR
-//
-// Created by Mitch Adler on 2/22/11.
-// Copyright 2011 Apple Inc. All rights reserved.
-//
-
-#include "SecOTRSession.h"
-
-#include "SecOTRMath.h"
-#include "SecOTRDHKey.h"
-#include "SecOTRSessionPriv.h"
-#include "SecOTRPackets.h"
-#include "SecOTRPacketData.h"
-
-#include <utilities/SecCFWrappers.h>
-
-#include <CoreFoundation/CFRuntime.h>
-#include <CoreFoundation/CFString.h>
-
-#include <Security/SecBasePriv.h>
-#include <Security/SecRandom.h>
-#include <Security/SecBase64.h>
-
-#include <AssertMacros.h>
-
-#ifdef USECOMMONCRYPTO
-#include <CommonCrypto/CommonHMAC.h>
-#endif
-
-#include <corecrypto/cchmac.h>
-#include <corecrypto/ccsha2.h>
-#include <corecrypto/ccsha1.h>
-
-#include <string.h>
-#include <stdlib.h>
-
-#include <syslog.h>
-
-#include "utilities/comparison.h"
-
-CFGiblisFor(SecOTRSession);
-
-static OTRMessageType SecOTRSGetMessageType(CFDataRef message)
-{
- OTRMessageType type = kInvalidMessage;
-
- CFMutableDataRef decodedBytes = CFDataCreateMutable(kCFAllocatorDefault, 0);
- SecOTRGetIncomingBytes(message, decodedBytes);
-
- const uint8_t *bytes = CFDataGetBytePtr(decodedBytes);
- size_t size = CFDataGetLength(decodedBytes);
-
- require_noerr(ReadHeader(&bytes, &size, &type), fail);
-
-fail:
- CFReleaseNull(decodedBytes);
-
- return type;
-}
-
-const char *SecOTRPacketTypeString(CFDataRef message)
-{
- if (!message) return "NoMessage";
- switch (SecOTRSGetMessageType(message)) {
- case kDHMessage: return "DHMessage (0x02)";
- case kDataMessage: return "DataMessage (0x03)";
- case kDHKeyMessage: return "DHKeyMessage (0x0A)";
- case kRevealSignatureMessage: return "RevealSignatureMessage (0x11)";
- case kSignatureMessage: return "SignatureMessage (0x12)";
- case kInvalidMessage: return "InvalidMessage (0xFF)";
- default: return "UnknownMessage";
- }
-}
-
-static const char *SecOTRAuthStateString(SecOTRAuthState authState)
-{
- switch (authState) {
- case kIdle: return "Idle";
- case kAwaitingDHKey: return "AwaitingDHKey";
- case kAwaitingRevealSignature: return "AwaitingRevealSignature";
- case kAwaitingSignature: return "AwaitingSignature";
- case kDone: return "Done";
- default: return "InvalidState";
- }
-}
-
-static CF_RETURNS_RETAINED CFStringRef SecOTRSessionCopyDescription(CFTypeRef cf) {
- SecOTRSessionRef session = (SecOTRSessionRef)cf;
- return CFStringCreateWithFormat(kCFAllocatorDefault,NULL,CFSTR("<%s %s%s%s%s %d:%d %s%s>"),
- SecOTRAuthStateString(session->_state),
- session->_me ? "F" : "-",
- session->_them ? "P" : "-",
- session->_receivedDHMessage ? "D" : "-",
- session->_receivedDHKeyMessage ? "K" : "-",
- session->_keyID,
- session->_theirKeyID,
- session->_theirPreviousKey ? "P" : "-",
- session->_theirKey ? "T" : "-");
-}
-
-static void SecOTRSessionDestroy(CFTypeRef cf) {
- SecOTRSessionRef session = (SecOTRSessionRef)cf;
-
- CFReleaseNull(session->_receivedDHMessage);
- CFReleaseNull(session->_receivedDHKeyMessage);
-
- CFReleaseNull(session->_me);
- CFReleaseNull(session->_myKey);
- CFReleaseNull(session->_myNextKey);
-
- CFReleaseNull(session->_them);
- CFReleaseNull(session->_theirKey);
- CFReleaseNull(session->_theirPreviousKey);
-
- CFReleaseNull(session->_macKeysToExpose);
-
- dispatch_release(session->_queue);
-}
-
-static void SecOTRSessionResetInternal(SecOTRSessionRef session)
-{
- session->_state = kIdle;
-
- CFReleaseNull(session->_receivedDHMessage);
- CFReleaseNull(session->_receivedDHKeyMessage);
-
- session->_keyID = 0;
- CFReleaseNull(session->_myKey);
- CFReleaseNull(session->_myNextKey);
- //session->_myNextKey = SecOTRFullDHKCreate(kCFAllocatorDefault);
- session->_theirKeyID = 0;
- CFReleaseNull(session->_theirKey);
- CFReleaseNull(session->_theirPreviousKey);
- CFReleaseNull(session->_macKeysToExpose);
- session->_macKeysToExpose = CFDataCreateMutable(kCFAllocatorDefault, 0);
-
- bzero(session->_keyCache, sizeof(session->_keyCache));
-}
-
-void SecOTRSessionReset(SecOTRSessionRef session)
-{
- dispatch_sync_f(session->_queue, session, (dispatch_function_t) SecOTRSessionResetInternal);
-}
-
-
-SecOTRSessionRef SecOTRSessionCreateFromID(CFAllocatorRef allocator,
- SecOTRFullIdentityRef myID,
- SecOTRPublicIdentityRef theirID)
-{
- SecOTRSessionRef newID = CFTypeAllocate(SecOTRSession, struct _SecOTRSession, allocator);
-
- newID->_queue = dispatch_queue_create("OTRSession", DISPATCH_QUEUE_SERIAL);
-
- newID->_me = myID;
- newID->_them = theirID;
- newID->_receivedDHMessage = NULL;
- newID->_receivedDHKeyMessage = NULL;
- newID->_myKey = NULL;
- newID->_myNextKey = NULL;
- newID->_theirKey = NULL;
- newID->_theirPreviousKey = NULL;
- newID->_macKeysToExpose = NULL;
- newID->_textOutput = false;
-
- SecOTRSessionResetInternal(newID);
-
- CFRetain(newID->_me);
- CFRetain(newID->_them);
-
- return newID;
-}
-
-SecOTRSessionRef SecOTRSessionCreateFromIDAndFlags(CFAllocatorRef allocator,
- SecOTRFullIdentityRef myID,
- SecOTRPublicIdentityRef theirID,
- uint32_t flags)
-{
- SecOTRSessionRef newID = SecOTRSessionCreateFromID(allocator, myID, theirID);
- if (flags & kSecOTRSendTextMessages) {
- newID->_textOutput = true;
- }
- return newID;
-}
-
-static uint64_t constant_zero = 0;
-
-static void SecOTRSFindKeysForMessage(SecOTRSessionRef session,
- SecOTRFullDHKeyRef myKey,
- SecOTRPublicDHKeyRef theirKey,
- bool sending,
- uint8_t** messageKey, uint8_t** macKey, uint64_t **counter)
-{
- SecOTRCacheElement* emptyKeys = NULL;
- SecOTRCacheElement* cachedKeys = NULL;
-
- if ((NULL == myKey) || (NULL == theirKey)) {
- if (messageKey)
- *messageKey = NULL;
- if (macKey)
- *macKey = NULL;
- if (counter)
- *counter = &constant_zero;
-
- return;
- }
-
- for(int i = 0; i < kOTRKeyCacheSize; ++i)
- {
- if (0 == constant_memcmp(session->_keyCache[i]._fullKeyHash, SecFDHKGetHash(myKey), CCSHA1_OUTPUT_SIZE)
- && (0 == constant_memcmp(session->_keyCache[i]._publicKeyHash, SecPDHKGetHash(theirKey), CCSHA1_OUTPUT_SIZE))) {
- cachedKeys = &session->_keyCache[i];
- break;
- }
-
- if (emptyKeys == NULL
- && session->_keyCache[i]._fullKey == NULL) {
- emptyKeys = &session->_keyCache[i];
- }
- }
-
- if (cachedKeys == NULL) {
- if (emptyKeys == NULL) {
- syslog(LOG_ERR, "SecOTRSession key cache was full. Should never happen, spooky.\n");
- emptyKeys = &session->_keyCache[0];
- }
-
- // Fill in the entry.
- emptyKeys->_fullKey = myKey;
- memcpy(emptyKeys->_fullKeyHash, SecFDHKGetHash(myKey), CCSHA1_OUTPUT_SIZE);
- emptyKeys->_publicKey = theirKey;
- memcpy(emptyKeys->_publicKeyHash, SecPDHKGetHash(theirKey), CCSHA1_OUTPUT_SIZE);
-
- emptyKeys->_counter = 0;
- emptyKeys->_theirCounter = 0;
-
- SecOTRDHKGenerateOTRKeys(emptyKeys->_fullKey, emptyKeys->_publicKey,
- emptyKeys->_sendEncryptionKey, emptyKeys->_sendMacKey,
- emptyKeys->_receiveEncryptionKey, emptyKeys->_receiveMacKey);
-
- cachedKeys = emptyKeys;
- }
-
- if (messageKey)
- *messageKey = sending ? cachedKeys->_sendEncryptionKey : cachedKeys->_receiveEncryptionKey;
- if (macKey)
- *macKey = sending ? cachedKeys->_sendMacKey : cachedKeys->_receiveMacKey;
- if (counter)
- *counter = sending ? &cachedKeys->_counter : &cachedKeys->_theirCounter;
-}
-
-SecOTRSessionRef SecOTRSessionCreateFromData(CFAllocatorRef allocator, CFDataRef data)
-{
- if (data == NULL)
- return NULL;
-
- SecOTRSessionRef result = NULL;
- SecOTRSessionRef session = CFTypeAllocate(SecOTRSession, struct _SecOTRSession, allocator);
-
- const uint8_t *bytes = CFDataGetBytePtr(data);
- size_t size = (size_t)CFDataGetLength(data);
-
- session->_queue = dispatch_queue_create("OTRSession", DISPATCH_QUEUE_SERIAL);
-
- session->_me = NULL;
- session->_them = NULL;
- session->_myKey = NULL;
- session->_myNextKey = NULL;
- session->_theirKey = NULL;
- session->_theirPreviousKey = NULL;
- session->_receivedDHMessage = NULL;
- session->_receivedDHKeyMessage = NULL;
- bzero(session->_keyCache, sizeof(session->_keyCache));
-
- uint8_t version;
- require_noerr(ReadByte(&bytes, &size, &version), fail);
- require(version <= 3, fail);
-
- require_noerr(ReadLong(&bytes, &size, &session->_state), fail);
- session->_me = SecOTRFullIdentityCreateFromBytes(kCFAllocatorDefault, &bytes, &size, NULL);
- require(session->_me != NULL, fail);
- session->_them = SecOTRPublicIdentityCreateFromBytes(kCFAllocatorDefault, &bytes, &size, NULL);
- require(session->_them != NULL, fail);
-
- require(size > sizeof(session->_r), fail);
- memcpy(session->_r, bytes, sizeof(session->_r));
- bytes += sizeof(session->_r);
- size -= sizeof(session->_r);
-
- {
- uint8_t hasMessage = false;
- ReadByte(&bytes, &size, &hasMessage);
- if (hasMessage) {
- session->_receivedDHMessage = CFDataCreateMutableFromOTRDATA(kCFAllocatorDefault, &bytes, &size);
- }
- }
-
- if (version >= 2) {
- uint8_t hasMessage = false;
- ReadByte(&bytes, &size, &hasMessage);
- if (hasMessage) {
- session->_receivedDHKeyMessage = CFDataCreateMutableFromOTRDATA(kCFAllocatorDefault, &bytes, &size);
- }
- }
-
- if (version < 3) {
- uint8_t ready;
- require_noerr(ReadByte(&bytes, &size, &ready), fail);
- if (ready && session->_state == kIdle)
- session->_state = kDone;
- }
-
- require_noerr(ReadLong(&bytes, &size, &session->_keyID), fail);
- if (session->_keyID > 0) {
- session->_myKey = SecOTRFullDHKCreateFromBytes(kCFAllocatorDefault, &bytes, &size);
- require(session->_myKey != NULL, fail);
- session->_myNextKey = SecOTRFullDHKCreateFromBytes(kCFAllocatorDefault, &bytes, &size);
- require(session->_myNextKey != NULL, fail);
- }
-
- require_noerr(ReadLong(&bytes, &size, &session->_theirKeyID), fail);
- if (session->_theirKeyID > 0) {
- if (session->_theirKeyID > 1) {
- session->_theirPreviousKey = SecOTRPublicDHKCreateFromSerialization(kCFAllocatorDefault, &bytes, &size);
- require(session->_theirPreviousKey != NULL, fail);
- }
- session->_theirKey = SecOTRPublicDHKCreateFromSerialization(kCFAllocatorDefault, &bytes, &size);
- require(session->_theirKey != NULL, fail);
- }
-
- uint64_t *counter;
- SecOTRSFindKeysForMessage(session, session->_myKey, session->_theirKey, false, NULL, NULL, &counter);
- require_noerr(ReadLongLong(&bytes, &size, counter), fail);
- SecOTRSFindKeysForMessage(session, session->_myKey, session->_theirKey, true, NULL, NULL, &counter);
- require_noerr(ReadLongLong(&bytes, &size, counter), fail);
- SecOTRSFindKeysForMessage(session, session->_myKey, session->_theirPreviousKey, false, NULL, NULL, &counter);
- require_noerr(ReadLongLong(&bytes, &size, counter), fail);
- SecOTRSFindKeysForMessage(session, session->_myKey, session->_theirPreviousKey, true, NULL, NULL, &counter);
- require_noerr(ReadLongLong(&bytes, &size, counter), fail);
- SecOTRSFindKeysForMessage(session, session->_myNextKey, session->_theirKey, false, NULL, NULL, &counter);
- require_noerr(ReadLongLong(&bytes, &size, counter), fail);
- SecOTRSFindKeysForMessage(session, session->_myNextKey, session->_theirKey, true, NULL, NULL, &counter);
- require_noerr(ReadLongLong(&bytes, &size, counter), fail);
- SecOTRSFindKeysForMessage(session, session->_myNextKey, session->_theirPreviousKey, false, NULL, NULL, &counter);
- require_noerr(ReadLongLong(&bytes, &size, counter), fail);
- SecOTRSFindKeysForMessage(session, session->_myNextKey, session->_theirPreviousKey, true, NULL, NULL, &counter);
- require_noerr(ReadLongLong(&bytes, &size, counter), fail);
-
- session->_macKeysToExpose = CFDataCreateMutableFromOTRDATA(kCFAllocatorDefault, &bytes, &size);
- require(session->_macKeysToExpose != NULL, fail);
-
- uint8_t textMode;
- require_noerr(ReadByte(&bytes, &size, &textMode), fail);
- session->_textOutput = (textMode != 0);
-
- result = session;
- session = NULL;
-
-fail:
- CFReleaseNull(session);
- return result;
-}
-
-
-OSStatus SecOTRSAppendSerialization(SecOTRSessionRef session, CFMutableDataRef serializeInto)
-{
- __block OSStatus result = errSecParam;
-
- require(session, abort);
- require(serializeInto, abort);
-
- CFIndex start = CFDataGetLength(serializeInto);
-
- dispatch_sync(session->_queue, ^{
- const uint8_t version = 3;
-
- CFDataAppendBytes(serializeInto, &version, sizeof(version));
-
- AppendLong(serializeInto, session->_state);
-
- result = (SecOTRFIAppendSerialization(session->_me, serializeInto, NULL)) ? errSecSuccess : errSecParam;
-
- if (result == errSecSuccess) {
- result = (SecOTRPIAppendSerialization(session->_them, serializeInto, NULL)) ? errSecSuccess : errSecParam;
- }
-
- if (result == errSecSuccess) {
- CFDataAppendBytes(serializeInto, session->_r, sizeof(session->_r));
-
- if (session->_receivedDHMessage == NULL) {
- AppendByte(serializeInto, 0);
- } else {
- AppendByte(serializeInto, 1);
- AppendCFDataAsDATA(serializeInto, session->_receivedDHMessage);
- }
-
- if (session->_receivedDHKeyMessage == NULL) {
- AppendByte(serializeInto, 0);
- } else {
- AppendByte(serializeInto, 1);
- AppendCFDataAsDATA(serializeInto, session->_receivedDHKeyMessage);
- }
-
- AppendLong(serializeInto, session->_keyID);
- if (session->_keyID > 0) {
- SecFDHKAppendSerialization(session->_myKey, serializeInto);
- SecFDHKAppendSerialization(session->_myNextKey, serializeInto);
- }
-
- AppendLong(serializeInto, session->_theirKeyID);
- if (session->_theirKeyID > 0) {
- if (session->_theirKeyID > 1) {
- SecPDHKAppendSerialization(session->_theirPreviousKey, serializeInto);
- }
- SecPDHKAppendSerialization(session->_theirKey, serializeInto);
- }
-
- uint64_t *counter;
- SecOTRSFindKeysForMessage(session, session->_myKey, session->_theirKey, false, NULL, NULL, &counter);
- AppendLongLong(serializeInto, *counter);
- SecOTRSFindKeysForMessage(session, session->_myKey, session->_theirKey, true, NULL, NULL, &counter);
- AppendLongLong(serializeInto, *counter);
- SecOTRSFindKeysForMessage(session, session->_myKey, session->_theirPreviousKey, false, NULL, NULL, &counter);
- AppendLongLong(serializeInto, *counter);
- SecOTRSFindKeysForMessage(session, session->_myKey, session->_theirPreviousKey, true, NULL, NULL, &counter);
- AppendLongLong(serializeInto, *counter);
- SecOTRSFindKeysForMessage(session, session->_myNextKey, session->_theirKey, false, NULL, NULL, &counter);
- AppendLongLong(serializeInto, *counter);
- SecOTRSFindKeysForMessage(session, session->_myNextKey, session->_theirKey, true, NULL, NULL, &counter);
- AppendLongLong(serializeInto, *counter);
- SecOTRSFindKeysForMessage(session, session->_myNextKey, session->_theirPreviousKey, false, NULL, NULL, &counter);
- AppendLongLong(serializeInto, *counter);
- SecOTRSFindKeysForMessage(session, session->_myNextKey, session->_theirPreviousKey, true, NULL, NULL, &counter);
- AppendLongLong(serializeInto, *counter);
-
- AppendCFDataAsDATA(serializeInto, session->_macKeysToExpose);
-
- AppendByte(serializeInto, session->_textOutput ? 1 : 0);
- }
- });
-
- if (result != errSecSuccess)
- CFDataSetLength(serializeInto, start);
-
-abort:
- return result;
-}
-
-
-bool SecOTRSGetIsReadyForMessages(SecOTRSessionRef session)
-{
- __block bool result;
-
- dispatch_sync(session->_queue, ^{ result = session->_state == kDone; });
-
- return result;
-}
-
-bool SecOTRSGetIsIdle(SecOTRSessionRef session)
-{
- __block bool result;
-
- dispatch_sync(session->_queue, ^{ result = session->_state == kIdle; });
-
- return result;
-}
-
-static void SecOTRSExpireCachedKeysForFullKey(SecOTRSessionRef session, SecOTRFullDHKeyRef myKey)
-{
- for(int i = 0; i < kOTRKeyCacheSize; ++i)
- {
- if (0 == constant_memcmp(session->_keyCache[i]._fullKeyHash, SecFDHKGetHash(myKey), CCSHA1_OUTPUT_SIZE)) {
- CFDataAppendBytes(session->_macKeysToExpose, session->_keyCache[i]._receiveMacKey, sizeof(session->_keyCache[i]._receiveMacKey));
-
- bzero(&session->_keyCache[i], sizeof(session->_keyCache[i]));
- }
- }
-}
-
-static void SecOTRSExpireCachedKeysForPublicKey(SecOTRSessionRef session, SecOTRPublicDHKeyRef theirKey)
-{
- for(int i = 0; i < kOTRKeyCacheSize; ++i)
- {
- if (0 == constant_memcmp(session->_keyCache[i]._publicKeyHash, SecPDHKGetHash(theirKey), CCSHA1_OUTPUT_SIZE)) {
- CFDataAppendBytes(session->_macKeysToExpose, session->_keyCache[i]._receiveMacKey, sizeof(session->_keyCache[i]._receiveMacKey));
-
- bzero(&session->_keyCache[i], sizeof(session->_keyCache[i]));
- }
- }
-}
-
-static void SecOTRSPrecalculateForPair(SecOTRSessionRef session,
- SecOTRFullDHKeyRef myKey,
- SecOTRPublicDHKeyRef theirKey)
-{
- if (myKey == NULL || theirKey == NULL)
- return;
-
- SecOTRSFindKeysForMessage(session, myKey, theirKey, true, NULL, NULL, NULL);
- SecOTRSFindKeysForMessage(session, myKey, theirKey, false, NULL, NULL, NULL);
-}
-
-static void SecOTRSPrecalculateKeysInternal(SecOTRSessionRef session)
-{
- SecOTRSPrecalculateForPair(session, session->_myKey, session->_theirKey);
- SecOTRSPrecalculateForPair(session, session->_myNextKey, session->_theirKey);
- SecOTRSPrecalculateForPair(session, session->_myKey, session->_theirPreviousKey);
- SecOTRSPrecalculateForPair(session, session->_myNextKey, session->_theirPreviousKey);
-}
-
-void SecOTRSPrecalculateKeys(SecOTRSessionRef session)
-{
- dispatch_sync_f(session->_queue, session, (dispatch_function_t) SecOTRSPrecalculateKeysInternal);
-}
-
-enum SecOTRSMessageKind SecOTRSGetMessageKind(SecOTRSessionRef session, CFDataRef message)
-{
- enum SecOTRSMessageKind kind = kOTRUnknownPacket;
-
- CFMutableDataRef decodedBytes = CFDataCreateMutable(kCFAllocatorDefault, 0);
- SecOTRGetIncomingBytes(message, decodedBytes);
-
- const uint8_t *bytes = CFDataGetBytePtr(decodedBytes);
- size_t size = CFDataGetLength(decodedBytes);
-
- OTRMessageType type;
- require_noerr(ReadHeader(&bytes, &size, &type), fail);
-
- kind = (type == kDataMessage) ? kOTRDataPacket : kOTRNegotiationPacket;
-
-fail:
- CFReleaseNull(decodedBytes);
-
- return kind;
-}
-
-OSStatus SecOTRSSignAndProtectMessage(SecOTRSessionRef session,
- CFDataRef sourceMessage,
- CFMutableDataRef protectedMessage)
-{
- __block OSStatus result = errSecParam;
-
- require(session, abort);
- require(sourceMessage, abort);
- require(protectedMessage, abort);
-
- dispatch_sync(session->_queue, ^{
- if (session->_myKey == NULL ||
- session->_theirKey == NULL) {
- return;
- }
-
- CFMutableDataRef destinationMessage;
- if (session->_textOutput) {
- destinationMessage = CFDataCreateMutable(kCFAllocatorDefault, 0);
- } else {
- destinationMessage = protectedMessage;
- }
-
- uint8_t *messageKey;
- uint8_t *macKey;
- uint64_t *counter;
-
- CFIndex start = CFDataGetLength(destinationMessage);
-
- SecOTRSFindKeysForMessage(session, session->_myKey, session->_theirKey,
- true,
- &messageKey, &macKey, &counter);
-
- AppendHeader(destinationMessage, kDataMessage);
- AppendByte(destinationMessage, 0); // Flags, all zero
-
- AppendLong(destinationMessage, session->_keyID);
- AppendLong(destinationMessage, session->_theirKeyID);
- SecFDHKAppendPublicSerialization(session->_myNextKey, destinationMessage);
- AppendLongLong(destinationMessage, ++*counter);
-
- CFIndex sourceSize = CFDataGetLength(sourceMessage);
- assert(((unsigned long)sourceSize)<=UINT32_MAX); /* this is correct as long as CFIndex is a signed long */
- AppendLong(destinationMessage, (uint32_t)sourceSize);
- uint8_t* encryptedDataPointer = CFDataIncreaseLengthAndGetMutableBytes(destinationMessage, sourceSize);
- AES_CTR_HighHalf_Transform(kOTRMessageKeyBytes, messageKey,
- *counter,
- (size_t)sourceSize, CFDataGetBytePtr(sourceMessage),
- encryptedDataPointer);
-
- CFIndex macedContentsSize = CFDataGetLength(destinationMessage) - start;
- CFIndex macSize = CCSHA1_OUTPUT_SIZE;
- uint8_t* macDataPointer = CFDataIncreaseLengthAndGetMutableBytes(destinationMessage, macSize);
-
-#ifdef USECOMMONCRYPTO
- CCHmac(kCCHmacAlgSHA1,
- macKey, kOTRMessageMacKeyBytes,
- CFDataGetBytePtr(destinationMessage) + start, (size_t)macedContentsSize,
- macDataPointer);
-#else
- cchmac(ccsha1_di(),
- kOTRMessageMacKeyBytes, macKey,
- macedContentsSize, CFDataGetBytePtr(destinationMessage) + start,
- macDataPointer);
-#endif
-
- CFDataAppend(destinationMessage, session->_macKeysToExpose);
-
- CFDataSetLength(session->_macKeysToExpose, 0);
-
- if (session->_textOutput) {
- SecOTRPrepareOutgoingBytes(destinationMessage, protectedMessage);
- CFReleaseSafe(destinationMessage);
- }
-
- result = errSecSuccess;
- });
-
-abort:
- return result;
-}
-
-OSStatus SecOTRSVerifyAndExposeMessage(SecOTRSessionRef session,
- CFDataRef incomingMessage,
- CFMutableDataRef exposedMessageContents)
-{
- __block SecOTRPublicDHKeyRef newKey = NULL;
- __block OSStatus result = errSecParam;
-
-
- require(session, abort);
- require(incomingMessage, abort);
- require(exposedMessageContents, abort);
-
- dispatch_sync(session->_queue, ^{
- const uint8_t* bytes;
- size_t size;
- CFMutableDataRef decodedBytes = CFDataCreateMutable(kCFAllocatorDefault, 0);
- SecOTRGetIncomingBytes(incomingMessage, decodedBytes);
-
- bytes = CFDataGetBytePtr(decodedBytes);
- size = CFDataGetLength(decodedBytes);
-
- const uint8_t* macDataStart = bytes;
-
- uint32_t theirID;
- uint32_t myID;
-
- if ((result = ReadAndVerifyHeader(&bytes, &size, kDataMessage))){
- CFReleaseSafe(decodedBytes);
- return;
- }
-
- if (size <= 0) { result = errSecDecode; CFReleaseSafe(decodedBytes); return; }
-
- if ((result = ReadAndVerifyByte(&bytes, &size, 0))) { CFReleaseSafe(decodedBytes); return;} // No flags
-
- if ((result = ReadLong(&bytes, &size, &theirID))){ CFReleaseSafe(decodedBytes); return; }
-
- if (theirID != session->_theirKeyID &&
- (session->_theirPreviousKey == NULL || theirID != (session->_theirKeyID - 1)))
- {
- result = ((theirID + 1) < session->_theirKeyID) ? errSecOTRTooOld : errSecOTRIDTooNew;
- CFReleaseSafe(decodedBytes);
- return;
- };
-
- if ((result = ReadLong(&bytes, &size, &myID))){ CFReleaseSafe(decodedBytes); return; }
- if (myID != session->_keyID && myID != (session->_keyID + 1))
- {
- result = (myID < session->_keyID) ? errSecOTRTooOld : errSecOTRIDTooNew;
- CFReleaseSafe(decodedBytes);
- return;
- };
-
-
- // Choose appripriate keys for message:
- {
- uint8_t *messageKey;
- uint8_t *macKey;
- uint64_t *theirCounter;
-
- SecOTRFullDHKeyRef myKeyForMessage = (myID == session->_keyID) ? session->_myKey : session->_myNextKey;
- SecOTRPublicDHKeyRef theirKeyForMessage = (theirID == session->_theirKeyID) ? session->_theirKey : session->_theirPreviousKey;
-
- SecOTRSFindKeysForMessage(session, myKeyForMessage, theirKeyForMessage, false,
- &messageKey, &macKey, &theirCounter);
-
- size_t nextKeyMPISize;
- const uint8_t* nextKeyMPIBytes;
- if ((result = SizeAndSkipMPI(&bytes, &size, &nextKeyMPIBytes, &nextKeyMPISize))){ CFReleaseSafe(decodedBytes); return;}
-
- uint64_t counter;
- if ((result = ReadLongLong(&bytes, &size, &counter))) { CFReleaseSafe(decodedBytes); return; }
-
- if (counter <= *theirCounter) { result = errSecOTRTooOld; CFReleaseSafe(decodedBytes); return; };
-
- size_t messageSize;
- const uint8_t* messageStart;
- if ((result = SizeAndSkipDATA(&bytes, &size, &messageStart, &messageSize))) { CFReleaseSafe(decodedBytes); return; }
-
- size_t macDataSize = (bytes - macDataStart) ? (size_t)(bytes - macDataStart) : 0;
- uint8_t mac[CCSHA1_OUTPUT_SIZE];
- if (sizeof(mac) > size) { result = errSecDecode; CFReleaseSafe(decodedBytes); return; }
-
-#ifdef USECOMMONCRYPTO
- CCHmac(kCCHmacAlgSHA1,
- macKey, kOTRMessageMacKeyBytes,
- macDataStart, macDataSize,
- mac);
-#else
- cchmac(ccsha1_di(),
- kOTRMessageMacKeyBytes, macKey,
- macDataSize, macDataStart,
- mac);
-#endif
-
- if (0 != constant_memcmp(mac, bytes, sizeof(mac))) { result = errSecAuthFailed; CFReleaseSafe(decodedBytes); return; }
- //if (messageSize > 65535) { result = errSecDataTooLarge; CFReleaseSafe(decodedBytes); return; }
- uint8_t* dataSpace = CFDataIncreaseLengthAndGetMutableBytes(exposedMessageContents, (CFIndex)messageSize);
-
-
- AES_CTR_HighHalf_Transform(kOTRMessageKeyBytes, messageKey,
- counter,
- messageSize, messageStart,
- dataSpace);
-
- // Everything is good, accept the meta data.
- *theirCounter = counter;
-
- newKey = SecOTRPublicDHKCreateFromBytes(kCFAllocatorDefault, &nextKeyMPIBytes, &nextKeyMPISize);
- }
-
- SecOTRSPrecalculateKeysInternal(session);
-
- bool acceptTheirNewKey = newKey != NULL && theirID == session->_theirKeyID;
-
- if (acceptTheirNewKey) {
- if (session->_theirPreviousKey) {
- SecOTRSExpireCachedKeysForPublicKey(session, session->_theirPreviousKey);
- }
-
- CFReleaseNull(session->_theirPreviousKey);
- session->_theirPreviousKey = session->_theirKey;
- session->_theirKey = newKey;
-
- session->_theirKeyID += 1;
-
- newKey = NULL;
- }
-
- if (myID == (session->_keyID + 1)) {
- SecOTRSExpireCachedKeysForFullKey(session, session->_myKey);
-
- // Swap the keys so we know the current key.
- {
- SecOTRFullDHKeyRef oldKey = session->_myKey;
- session->_myKey = session->_myNextKey;
- session->_myNextKey = oldKey;
- }
-
- // Derive a new next key by regenerating over the old key.
- SecFDHKNewKey(session->_myNextKey);
-
- session->_keyID = myID;
- }
- CFReleaseSafe(decodedBytes);
- });
-
-abort:
- CFReleaseNull(newKey);
- return result;
-}
-
-
-OSStatus SecOTRSEndSession(SecOTRSessionRef session,
- CFMutableDataRef messageToSend)
-{
- return errSecUnimplemented;
-}