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