SecOTRSession.c
1 /* 2 * Copyright (c) 2011-2014 Apple Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24 25 #include <stdint.h> 26 #include <sys/types.h> 27 #include <CoreFoundation/CFDate.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 <Security/SecureObjectSync/SOSPeerInfo.h> 49 #include "keychain/SecureObjectSync/SOSCircle.h" 50 #include <Security/SecureObjectSync/SOSCloudCircle.h> 51 #include "keychain/SecureObjectSync/SOSInternal.h" 52 #include "keychain/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 #include <os/activity.h> 65 66 #include <utilities/array_size.h> 67 68 #include <ipc/securityd_client.h> 69 #include <Security/SecuritydXPC.h> 70 71 CFGiblisFor(SecOTRSession); 72 73 static uint64_t setup_defaults_settings(){ 74 75 Boolean keyExistsAndHasValue = false; 76 uint64_t seconds; 77 seconds = CFPreferencesGetAppIntegerValue(CFSTR("OTR"), CFSTR("com.apple.security"), &keyExistsAndHasValue); 78 secdebug("OTR", "Retrieving OTR default settings was success? %d value retrieved: %llu", keyExistsAndHasValue, seconds); 79 return keyExistsAndHasValue ? seconds : (kSecondsPerMinute * 15); //15 minutes by default 80 } 81 82 static uint64_t SecOTRGetDefaultsWriteSeconds(void) { 83 static dispatch_once_t sdOnceToken; 84 static uint64_t seconds; 85 86 dispatch_once(&sdOnceToken, ^{ 87 seconds = setup_defaults_settings(); 88 }); 89 90 return seconds; 91 } 92 93 static void SecOTRSEnableTimeToRoll(SecOTRSessionRef session){ 94 CFAbsoluteTime now = CFAbsoluteTimeGetCurrent(); 95 CFAbsoluteTime nextTimeToRoll = now + session->_stallSeconds; 96 97 if(session->_timeToRoll == 0 || session->_timeToRoll > nextTimeToRoll){ 98 session->_timeToRoll = nextTimeToRoll; 99 } 100 } 101 102 static void SecOTRSExpireCachedKeysForFullKey(SecOTRSessionRef session, SecOTRFullDHKeyRef myKey) 103 { 104 for(int i = 0; i < kOTRKeyCacheSize; ++i) 105 { 106 if (0 == timingsafe_bcmp(session->_keyCache[i]._fullKeyHash, SecFDHKGetHash(myKey), CCSHA1_OUTPUT_SIZE)) { 107 CFDataAppendBytes(session->_macKeysToExpose, session->_keyCache[i]._receiveMacKey, sizeof(session->_keyCache[i]._receiveMacKey)); 108 bzero(&session->_keyCache[i], sizeof(session->_keyCache[i])); 109 } 110 } 111 } 112 113 static void SecOTRSExpireCachedKeysForPublicKey(SecOTRSessionRef session, SecOTRPublicDHKeyRef theirKey) 114 { 115 for(int i = 0; i < kOTRKeyCacheSize; ++i) 116 { 117 if (0 == timingsafe_bcmp(session->_keyCache[i]._publicKeyHash, SecPDHKGetHash(theirKey), CCSHA1_OUTPUT_SIZE)) { 118 CFDataAppendBytes(session->_macKeysToExpose, session->_keyCache[i]._receiveMacKey, sizeof(session->_keyCache[i]._receiveMacKey)); 119 120 bzero(&session->_keyCache[i], sizeof(session->_keyCache[i])); 121 } 122 } 123 } 124 125 static OSStatus SecOTRGenerateNewProposedKey(SecOTRSessionRef session) 126 { 127 SecOTRSExpireCachedKeysForFullKey(session, session->_myKey); 128 129 // Swap the keys so we know the current key. 130 { 131 SecOTRFullDHKeyRef oldKey = session->_myKey; 132 session->_myKey = session->_myNextKey; 133 session->_myNextKey = oldKey; 134 } 135 136 // Derive a new next key by regenerating over the old key. 137 OSStatus ret = SecFDHKNewKey(session->_myNextKey); 138 139 session->_keyID += 1; 140 141 return ret; 142 } 143 144 145 static void SecOTRSHandleProposalAcknowledge(SecOTRSessionRef session){ 146 if(session->_missedAck){ 147 SecOTRGenerateNewProposedKey(session); 148 session->_missedAck = false; 149 } 150 else{ 151 session->_receivedAck = true; 152 SecOTRSEnableTimeToRoll(session); 153 } 154 } 155 156 static void SecOTRSRollIfTime(SecOTRSessionRef session){ 157 158 CFAbsoluteTime now = CFAbsoluteTimeGetCurrent(); 159 CFAbsoluteTime longestTimeToRoll = now + session->_stallSeconds; 160 161 //in case time to roll becomes too large we're going to roll now! 162 if(session->_timeToRoll < now || session->_timeToRoll > longestTimeToRoll){ 163 SOSOTRSRoll(session); 164 session->_timeToRoll = 0; 165 } 166 } 167 168 169 static OTRMessageType SecOTRSGetMessageType(CFDataRef message) 170 { 171 OTRMessageType type = kInvalidMessage; 172 173 CFDataRef decodedBytes = SecOTRCopyIncomingBytes(message); 174 175 const uint8_t *bytes = CFDataGetBytePtr(decodedBytes); 176 size_t size = CFDataGetLength(decodedBytes); 177 178 if (noErr != ReadHeader(&bytes, &size, &type)) { 179 uint8_t firstByte = *CFDataGetBytePtr(decodedBytes); 180 switch (firstByte) { 181 case kOddCompactDataMessage: 182 case kEvenCompactDataMessage: 183 case kOddCompactDataMessageWithHashes: 184 case kEvenCompactDataMessageWithHashes: 185 type = firstByte; 186 break; 187 188 default: 189 break; 190 } 191 } 192 193 CFReleaseNull(decodedBytes); 194 195 return type; 196 } 197 198 #if DEBUG 199 200 static CFStringRef SecOTRCacheElementCopyDescription(SecOTRCacheElement *keyCache){ 201 __block CFStringRef description = NULL; 202 BufferPerformWithHexString(keyCache->_fullKeyHash, sizeof(keyCache->_fullKeyHash), ^(CFStringRef fullKeyHashString) { 203 BufferPerformWithHexString(keyCache->_publicKeyHash,sizeof(keyCache->_publicKeyHash), ^(CFStringRef publicKeyHashString) { 204 description = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("fkh: [%@], pkh: [%@], c: %llu tc: %llu"), fullKeyHashString, publicKeyHashString, keyCache->_counter, keyCache->_theirCounter); 205 }); 206 }); 207 return description; 208 } 209 210 #endif 211 const char *SecOTRPacketTypeString(CFDataRef message) 212 { 213 if (!message) return "NoMessage"; 214 switch (SecOTRSGetMessageType(message)) { 215 case kDHMessage: return "DHMessage (0x02)"; 216 case kDataMessage: return "DataMessage (0x03)"; 217 case kDHKeyMessage: return "DHKeyMessage (0x0A)"; 218 case kRevealSignatureMessage: return "RevealSignatureMessage (0x11)"; 219 case kSignatureMessage: return "SignatureMessage (0x12)"; 220 case kEvenCompactDataMessage: return "kEvenCompactDatamessage (0x20)"; 221 case kOddCompactDataMessage: return "kOddCompactDataMessage (0x21)"; 222 case kEvenCompactDataMessageWithHashes: return "kEvenCompactDatamessage (0x30)"; 223 case kOddCompactDataMessageWithHashes: return "kOddCompactDataMessage (0x31)"; 224 case kInvalidMessage: return "InvalidMessage (0xFF)"; 225 default: return "UnknownMessage"; 226 } 227 } 228 229 static const char *SecOTRAuthStateString(SecOTRAuthState authState) 230 { 231 switch (authState) { 232 case kIdle: return "Idle"; 233 case kAwaitingDHKey: return "AwaitingDHKey"; 234 case kAwaitingRevealSignature: return "AwaitingRevealSignature"; 235 case kAwaitingSignature: return "AwaitingSignature"; 236 case kDone: return "Done"; 237 default: return "InvalidState"; 238 } 239 } 240 241 static CF_RETURNS_RETAINED CFStringRef SecOTRSessionCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions) { 242 SecOTRSessionRef session = (SecOTRSessionRef)cf; 243 244 CFAbsoluteTime now = CFAbsoluteTimeGetCurrent(); 245 246 return CFStringCreateWithFormat(kCFAllocatorDefault,NULL,CFSTR("<%s %s %s %s%s%s%s %d:%d %s%s %llu %s%s%s%s>"), 247 SecOTRAuthStateString(session->_state), 248 session->_compactAppleMessages ? "C" :"c", 249 session->_includeHashes ? "I" : "i", 250 session->_me ? "F" : "f", 251 session->_them ? "P" : "p", 252 session->_receivedDHMessage ? "D" : "d", 253 session->_receivedDHKeyMessage ? "K" : "k", 254 session->_keyID, 255 session->_theirKeyID, 256 session->_theirPreviousKey ? "P" : "p", 257 session->_theirKey ? "T" : "t", 258 session->_stallSeconds, 259 session->_missedAck ? "M" : "m", 260 session->_receivedAck ? "R" : "r", 261 session->_stallingTheirRoll ? "S" : "s", 262 (session->_timeToRoll > now && session->_timeToRoll != 0) ? "E" : "e"); 263 } 264 265 static void SecOTRSessionDestroy(CFTypeRef cf) { 266 SecOTRSessionRef session = (SecOTRSessionRef)cf; 267 268 CFReleaseNull(session->_receivedDHMessage); 269 CFReleaseNull(session->_receivedDHKeyMessage); 270 271 CFReleaseNull(session->_me); 272 CFReleaseNull(session->_myKey); 273 CFReleaseNull(session->_myNextKey); 274 275 CFReleaseNull(session->_them); 276 CFReleaseNull(session->_theirKey); 277 CFReleaseNull(session->_theirPreviousKey); 278 279 CFReleaseNull(session->_macKeysToExpose); 280 281 dispatch_release(session->_queue); 282 } 283 284 static void SecOTRSessionResetInternal(SecOTRSessionRef session) 285 { 286 session->_state = kIdle; 287 288 CFReleaseNull(session->_receivedDHMessage); 289 CFReleaseNull(session->_receivedDHKeyMessage); 290 291 session->_keyID = 0; 292 CFReleaseNull(session->_myKey); 293 CFReleaseNull(session->_myNextKey); 294 //session->_myNextKey = SecOTRFullDHKCreate(kCFAllocatorDefault); 295 session->_theirKeyID = 0; 296 CFReleaseNull(session->_theirKey); 297 CFReleaseNull(session->_theirPreviousKey); 298 CFReleaseNull(session->_macKeysToExpose); 299 session->_macKeysToExpose = CFDataCreateMutable(kCFAllocatorDefault, 0); 300 301 bzero(session->_keyCache, sizeof(session->_keyCache)); 302 } 303 304 int SecOTRSGetKeyID(SecOTRSessionRef session){ 305 return session->_keyID; 306 } 307 308 int SecOTRSGetTheirKeyID(SecOTRSessionRef session){ 309 return session->_theirKeyID; 310 } 311 312 void SecOTRSessionReset(SecOTRSessionRef session) 313 { 314 dispatch_sync_f(session->_queue, session, (dispatch_function_t) SecOTRSessionResetInternal); 315 } 316 317 318 static void SecOTRPIPerformWithSerializationString(SecOTRPublicIdentityRef id, void (^action)(CFStringRef string)) { 319 CFMutableDataRef idData = CFDataCreateMutable(kCFAllocatorDefault, 0); 320 SecOTRPIAppendSerialization(id, idData, NULL); 321 CFDataPerformWithHexString(idData, action); 322 CFReleaseNull(idData); 323 } 324 325 SecOTRSessionRef SecOTRSessionCreateFromID(CFAllocatorRef allocator, 326 SecOTRFullIdentityRef myID, 327 SecOTRPublicIdentityRef theirID) 328 { 329 SecOTRSessionRef newID = CFTypeAllocate(SecOTRSession, struct _SecOTRSession, allocator); 330 331 (void)SecOTRGetDefaultsWriteSeconds(); 332 newID->_queue = dispatch_queue_create("OTRSession", DISPATCH_QUEUE_SERIAL); 333 334 newID->_me = CFRetainSafe(myID); 335 newID->_them = CFRetainSafe(theirID); 336 newID->_receivedDHMessage = NULL; 337 newID->_receivedDHKeyMessage = NULL; 338 newID->_myKey = NULL; 339 newID->_myNextKey = NULL; 340 newID->_theirKey = NULL; 341 newID->_theirPreviousKey = NULL; 342 newID->_macKeysToExpose = NULL; 343 newID->_textOutput = false; 344 newID->_compactAppleMessages = false; 345 newID->_includeHashes = false; 346 347 newID->_timeToRoll = 0; 348 newID->_stallingTheirRoll = false; 349 newID->_stallSeconds = 0; 350 newID->_missedAck = true; 351 newID->_receivedAck = false; 352 353 SecOTRSessionResetInternal(newID); 354 355 { 356 SecOTRPublicIdentityRef myPublicID = SecOTRPublicIdentityCopyFromPrivate(kCFAllocatorDefault, newID->_me, NULL); 357 SecOTRPIPerformWithSerializationString(myPublicID, ^(CFStringRef myIDString) { 358 SecOTRPIPerformWithSerializationString(newID->_them, ^(CFStringRef theirIDString) { 359 secnotice("otr", "%@ Creating with M: %@, T: %@", newID, myIDString, theirIDString); 360 }); 361 }); 362 CFReleaseNull(myPublicID); 363 } 364 365 return newID; 366 } 367 368 SecOTRSessionRef SecOTRSessionCreateFromIDAndFlags(CFAllocatorRef allocator, 369 SecOTRFullIdentityRef myID, 370 SecOTRPublicIdentityRef theirID, 371 uint32_t flags) 372 { 373 374 uint64_t seconds = SecOTRGetDefaultsWriteSeconds(); 375 376 SecOTRSessionRef newID = SecOTRSessionCreateFromID(allocator, myID, theirID); 377 if (flags & kSecOTRSendTextMessages) { 378 newID->_textOutput = true; 379 } 380 if (flags & kSecOTRUseAppleCustomMessageFormat) { 381 newID->_compactAppleMessages = true; 382 } 383 if(flags & kSecOTRIncludeHashesInMessages) 384 { 385 newID->_includeHashes = true; 386 } 387 if(flags & kSecOTRSlowRoll) 388 { 389 newID->_stallSeconds = seconds; 390 } 391 392 return newID; 393 } 394 395 static uint64_t constant_zero = 0; 396 397 static bool hashIsZero(uint8_t hash[CCSHA1_OUTPUT_SIZE]) 398 { 399 bool isZero = true; 400 for(size_t byte = 0; isZero && byte < CCSHA1_OUTPUT_SIZE; ++byte) 401 isZero = (0 == hash[byte]); 402 403 return isZero; 404 } 405 406 static bool SOSOTRSCacheEntryIsEmpty(SecOTRCacheElement *element) 407 { 408 return hashIsZero(element->_fullKeyHash) && hashIsZero(element->_publicKeyHash); 409 } 410 411 #if DEBUG 412 413 static void WithCacheDescription(SecOTRSessionRef session, void (^operation)(CFStringRef cacheDescription)) { 414 CFStringRef description = NULL; 415 416 CFStringRef keyCache0Description = SecOTRCacheElementCopyDescription(&session->_keyCache[0]); 417 CFStringRef keyCache1Description = SecOTRCacheElementCopyDescription(&session->_keyCache[1]); 418 CFStringRef keyCache2Description = SecOTRCacheElementCopyDescription(&session->_keyCache[2]); 419 CFStringRef keyCache3Description = SecOTRCacheElementCopyDescription(&session->_keyCache[3]); 420 421 description = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("{%@, %@, %@, %@}"), keyCache0Description, keyCache1Description, keyCache2Description, keyCache3Description); 422 423 operation(description); 424 425 CFReleaseNull(keyCache0Description); 426 CFReleaseNull(keyCache1Description); 427 CFReleaseNull(keyCache2Description); 428 CFReleaseNull(keyCache3Description); 429 CFReleaseNull(description); 430 } 431 432 #endif 433 434 static void SecOTRSFindKeysForMessage(SecOTRSessionRef session, 435 SecOTRFullDHKeyRef myKey, 436 SecOTRPublicDHKeyRef theirKey, 437 bool sending, 438 uint8_t** messageKey, uint8_t** macKey, uint64_t **counter) 439 { 440 SecOTRCacheElement* emptyKeys = NULL; 441 SecOTRCacheElement* cachedKeys = NULL; 442 #if DEBUG 443 int emptyPosition = kOTRKeyCacheSize; 444 #endif 445 446 if ((NULL == myKey) || (NULL == theirKey)) { 447 if (messageKey) 448 *messageKey = NULL; 449 if (macKey) 450 *macKey = NULL; 451 if (counter) 452 *counter = &constant_zero; 453 454 return; 455 } 456 457 for(int i = 0; i < kOTRKeyCacheSize; ++i) 458 { 459 if (0 == timingsafe_bcmp(session->_keyCache[i]._fullKeyHash, SecFDHKGetHash(myKey), CCSHA1_OUTPUT_SIZE) 460 && (0 == timingsafe_bcmp(session->_keyCache[i]._publicKeyHash, SecPDHKGetHash(theirKey), CCSHA1_OUTPUT_SIZE))) { 461 cachedKeys = &session->_keyCache[i]; 462 #if DEBUG 463 secdebug("OTR","session@[%p] found key match: mk: %@, tk: %@", session, myKey, theirKey); 464 #endif 465 break; 466 } 467 468 if (emptyKeys == NULL && SOSOTRSCacheEntryIsEmpty(&(session->_keyCache[i]))) { 469 #if DEBUG 470 emptyPosition = i; 471 #endif 472 473 emptyKeys = &session->_keyCache[i]; 474 } 475 } 476 477 if (cachedKeys == NULL) { 478 if (emptyKeys == NULL) { 479 #if DEBUG 480 WithCacheDescription(session, ^(CFStringRef cacheDescription) { 481 secdebug("OTR","session@[%p] Cache miss, spooky for mk: %@, tk: %@ cache: %@", session, myKey, theirKey, cacheDescription); 482 }); 483 emptyPosition = 0; 484 #endif 485 486 emptyKeys = &session->_keyCache[0]; 487 488 } 489 assert(emptyKeys); 490 491 // Fill in the entry. 492 memcpy(emptyKeys->_fullKeyHash, SecFDHKGetHash(myKey), CCSHA1_OUTPUT_SIZE); 493 memcpy(emptyKeys->_publicKeyHash, SecPDHKGetHash(theirKey), CCSHA1_OUTPUT_SIZE); 494 495 emptyKeys->_counter = 0; 496 emptyKeys->_theirCounter = 0; 497 498 SecOTRDHKGenerateOTRKeys(myKey, theirKey, 499 emptyKeys->_sendEncryptionKey, emptyKeys->_sendMacKey, 500 emptyKeys->_receiveEncryptionKey, emptyKeys->_receiveMacKey); 501 502 cachedKeys = emptyKeys; 503 #if DEBUG 504 WithCacheDescription(session, ^(CFStringRef cacheDescription) { 505 secdebug("OTR","mk %@, th: %@ session@[%p] new key cache state added key@[%d]: %@", myKey, theirKey, session, emptyPosition, cacheDescription); 506 }); 507 #endif 508 509 } 510 511 if (messageKey) 512 *messageKey = sending ? cachedKeys->_sendEncryptionKey : cachedKeys->_receiveEncryptionKey; 513 if (macKey) 514 *macKey = sending ? cachedKeys->_sendMacKey : cachedKeys->_receiveMacKey; 515 if (counter) 516 *counter = sending ? &cachedKeys->_counter : &cachedKeys->_theirCounter; 517 } 518 519 SecOTRSessionRef SecOTRSessionCreateFromData(CFAllocatorRef allocator, CFDataRef data) 520 { 521 if (data == NULL) 522 return NULL; 523 524 SecOTRSessionRef result = NULL; 525 SecOTRSessionRef session = CFTypeAllocate(SecOTRSession, struct _SecOTRSession, allocator); 526 527 uint8_t numberOfKeys; 528 uint64_t timeToRoll; 529 530 const uint8_t *bytes = CFDataGetBytePtr(data); 531 size_t size = (size_t)CFDataGetLength(data); 532 533 (void)SecOTRGetDefaultsWriteSeconds(); 534 535 session->_queue = dispatch_queue_create("OTRSession", DISPATCH_QUEUE_SERIAL); 536 537 session->_me = NULL; 538 session->_them = NULL; 539 session->_myKey = NULL; 540 session->_myNextKey = NULL; 541 session->_theirKey = NULL; 542 session->_theirPreviousKey = NULL; 543 session->_receivedDHMessage = NULL; 544 session->_receivedDHKeyMessage = NULL; 545 session->_textOutput = false; 546 session->_compactAppleMessages = false; 547 session->_timeToRoll = 0; 548 session->_stallingTheirRoll = false; 549 session->_stallSeconds = 0; 550 session->_missedAck = true; 551 session->_receivedAck = false; 552 553 bzero(session->_keyCache, sizeof(session->_keyCache)); 554 555 uint8_t version; 556 require_noerr(ReadByte(&bytes, &size, &version), fail); 557 require(version <= 6, fail); 558 559 require_noerr(ReadLong(&bytes, &size, &session->_state), fail); 560 session->_me = SecOTRFullIdentityCreateFromBytes(kCFAllocatorDefault, &bytes, &size, NULL); 561 require(session->_me != NULL, fail); 562 session->_them = SecOTRPublicIdentityCreateFromBytes(kCFAllocatorDefault, &bytes, &size, NULL); 563 require(session->_them != NULL, fail); 564 565 require(size > sizeof(session->_r), fail); 566 memcpy(session->_r, bytes, sizeof(session->_r)); 567 bytes += sizeof(session->_r); 568 size -= sizeof(session->_r); 569 570 { 571 uint8_t hasMessage = false; 572 ReadByte(&bytes, &size, &hasMessage); 573 if (hasMessage) { 574 session->_receivedDHMessage = CFDataCreateMutableFromOTRDATA(kCFAllocatorDefault, &bytes, &size); 575 } 576 } 577 578 if (version >= 2) { 579 uint8_t hasMessage = false; 580 ReadByte(&bytes, &size, &hasMessage); 581 if (hasMessage) { 582 session->_receivedDHKeyMessage = CFDataCreateMutableFromOTRDATA(kCFAllocatorDefault, &bytes, &size); 583 } 584 } 585 586 if (version < 3) { 587 uint8_t ready; 588 require_noerr(ReadByte(&bytes, &size, &ready), fail); 589 if (ready && session->_state == kIdle) 590 session->_state = kDone; 591 } 592 593 594 require_noerr(ReadLong(&bytes, &size, &session->_keyID), fail); 595 if (session->_keyID > 0) { 596 session->_myKey = SecOTRFullDHKCreateFromBytes(kCFAllocatorDefault, &bytes, &size); 597 require(session->_myKey != NULL, fail); 598 session->_myNextKey = SecOTRFullDHKCreateFromBytes(kCFAllocatorDefault, &bytes, &size); 599 require(session->_myNextKey != NULL, fail); 600 } 601 602 603 require_noerr(ReadByte(&bytes, &size, &numberOfKeys), fail); 604 605 require_noerr(ReadLong(&bytes, &size, &session->_theirKeyID), fail); 606 if (version < 5) { 607 if (session->_theirKeyID > 0) { 608 if (session->_theirKeyID > 1) { 609 session->_theirPreviousKey = SecOTRPublicDHKCreateFromSerialization(kCFAllocatorDefault, &bytes, &size); 610 require(session->_theirPreviousKey != NULL, fail); 611 } 612 session->_theirKey = SecOTRPublicDHKCreateFromSerialization(kCFAllocatorDefault, &bytes, &size); 613 require(session->_theirKey != NULL, fail); 614 } 615 } 616 else { 617 if(numberOfKeys >= 1){ 618 if (numberOfKeys >= 2) { 619 session->_theirPreviousKey = SecOTRPublicDHKCreateFromSerialization(kCFAllocatorDefault, &bytes, &size); 620 require(session->_theirPreviousKey != NULL, fail); 621 } 622 session->_theirKey = SecOTRPublicDHKCreateFromSerialization(kCFAllocatorDefault, &bytes, &size); 623 require(session->_theirKey != NULL, fail); 624 } 625 } 626 627 628 uint64_t *counter; 629 SecOTRSFindKeysForMessage(session, session->_myKey, session->_theirKey, false, NULL, NULL, &counter); 630 require_noerr(ReadLongLong(&bytes, &size, counter), fail); 631 SecOTRSFindKeysForMessage(session, session->_myKey, session->_theirKey, true, NULL, NULL, &counter); 632 require_noerr(ReadLongLong(&bytes, &size, counter), fail); 633 SecOTRSFindKeysForMessage(session, session->_myKey, session->_theirPreviousKey, false, NULL, NULL, &counter); 634 require_noerr(ReadLongLong(&bytes, &size, counter), fail); 635 SecOTRSFindKeysForMessage(session, session->_myKey, session->_theirPreviousKey, true, NULL, NULL, &counter); 636 require_noerr(ReadLongLong(&bytes, &size, counter), fail); 637 SecOTRSFindKeysForMessage(session, session->_myNextKey, session->_theirKey, false, NULL, NULL, &counter); 638 require_noerr(ReadLongLong(&bytes, &size, counter), fail); 639 SecOTRSFindKeysForMessage(session, session->_myNextKey, session->_theirKey, true, NULL, NULL, &counter); 640 require_noerr(ReadLongLong(&bytes, &size, counter), fail); 641 SecOTRSFindKeysForMessage(session, session->_myNextKey, session->_theirPreviousKey, false, NULL, NULL, &counter); 642 require_noerr(ReadLongLong(&bytes, &size, counter), fail); 643 SecOTRSFindKeysForMessage(session, session->_myNextKey, session->_theirPreviousKey, true, NULL, NULL, &counter); 644 require_noerr(ReadLongLong(&bytes, &size, counter), fail); 645 646 session->_macKeysToExpose = CFDataCreateMutableFromOTRDATA(kCFAllocatorDefault, &bytes, &size); 647 require(session->_macKeysToExpose != NULL, fail); 648 649 require_noerr(ReadByteAsBool(&bytes, &size, &session->_textOutput), fail); 650 651 if (version >= 4) { 652 require_noerr(ReadByteAsBool(&bytes, &size, &session->_compactAppleMessages), fail); 653 } 654 if (version >= 5) { 655 require_noerr(ReadByteAsBool(&bytes, &size, &session->_includeHashes), fail); 656 } 657 if (version >= 6) { 658 require_noerr(ReadLongLong(&bytes, &size, &session->_stallSeconds), fail); 659 require_noerr(ReadByteAsBool(&bytes, &size, &session->_stallingTheirRoll), fail); 660 require_noerr(ReadLongLong(&bytes, &size, &timeToRoll), fail); 661 require_noerr(ReadByteAsBool(&bytes, &size, &session->_missedAck), fail); 662 require_noerr(ReadByteAsBool(&bytes, &size, &session->_receivedAck), fail); 663 session->_timeToRoll = timeToRoll; 664 } 665 result = session; 666 session = NULL; 667 668 fail: 669 CFReleaseNull(session); 670 return result; 671 } 672 673 674 OSStatus SecOTRSAppendSerialization(SecOTRSessionRef session, CFMutableDataRef serializeInto) 675 { 676 __block OSStatus result = errSecParam; 677 678 require(session, abort); 679 require(serializeInto, abort); 680 681 CFIndex start = CFDataGetLength(serializeInto); 682 683 dispatch_sync(session->_queue, ^{ 684 const uint8_t version = 6; 685 uint8_t numberOfKeys = 0; 686 CFDataAppendBytes(serializeInto, &version, sizeof(version)); 687 688 AppendLong(serializeInto, session->_state); 689 690 result = (SecOTRFIAppendSerialization(session->_me, serializeInto, NULL)) ? errSecSuccess : errSecParam; 691 692 if (result == errSecSuccess) { 693 result = (SecOTRPIAppendSerialization(session->_them, serializeInto, NULL)) ? errSecSuccess : errSecParam; 694 } 695 696 if (result == errSecSuccess) { 697 CFDataAppendBytes(serializeInto, session->_r, sizeof(session->_r)); 698 699 if (session->_receivedDHMessage == NULL) { 700 AppendByte(serializeInto, 0); 701 } else { 702 AppendByte(serializeInto, 1); 703 AppendCFDataAsDATA(serializeInto, session->_receivedDHMessage); 704 } 705 706 if (session->_receivedDHKeyMessage == NULL) { 707 AppendByte(serializeInto, 0); 708 } else { 709 AppendByte(serializeInto, 1); 710 AppendCFDataAsDATA(serializeInto, session->_receivedDHKeyMessage); 711 } 712 713 AppendLong(serializeInto, session->_keyID); 714 if (session->_keyID > 0) { 715 SecFDHKAppendSerialization(session->_myKey, serializeInto); 716 SecFDHKAppendSerialization(session->_myNextKey, serializeInto); 717 } 718 719 if(session->_theirPreviousKey != NULL) 720 numberOfKeys++; 721 if(session->_theirKey != NULL) 722 numberOfKeys++; 723 724 AppendByte(serializeInto, numberOfKeys); 725 726 AppendLong(serializeInto, session->_theirKeyID); 727 728 if (session->_theirPreviousKey != NULL) 729 SecPDHKAppendSerialization(session->_theirPreviousKey, serializeInto); 730 731 if (session->_theirKey != NULL ) 732 SecPDHKAppendSerialization(session->_theirKey, serializeInto); 733 734 735 uint64_t *counter; 736 SecOTRSFindKeysForMessage(session, session->_myKey, session->_theirKey, false, NULL, NULL, &counter); 737 AppendLongLong(serializeInto, *counter); 738 SecOTRSFindKeysForMessage(session, session->_myKey, session->_theirKey, true, NULL, NULL, &counter); 739 AppendLongLong(serializeInto, *counter); 740 SecOTRSFindKeysForMessage(session, session->_myKey, session->_theirPreviousKey, false, NULL, NULL, &counter); 741 AppendLongLong(serializeInto, *counter); 742 SecOTRSFindKeysForMessage(session, session->_myKey, session->_theirPreviousKey, true, NULL, NULL, &counter); 743 AppendLongLong(serializeInto, *counter); 744 SecOTRSFindKeysForMessage(session, session->_myNextKey, session->_theirKey, false, NULL, NULL, &counter); 745 AppendLongLong(serializeInto, *counter); 746 SecOTRSFindKeysForMessage(session, session->_myNextKey, session->_theirKey, true, NULL, NULL, &counter); 747 AppendLongLong(serializeInto, *counter); 748 SecOTRSFindKeysForMessage(session, session->_myNextKey, session->_theirPreviousKey, false, NULL, NULL, &counter); 749 AppendLongLong(serializeInto, *counter); 750 SecOTRSFindKeysForMessage(session, session->_myNextKey, session->_theirPreviousKey, true, NULL, NULL, &counter); 751 AppendLongLong(serializeInto, *counter); 752 753 AppendCFDataAsDATA(serializeInto, session->_macKeysToExpose); 754 755 AppendByte(serializeInto, session->_textOutput ? 1 : 0); 756 AppendByte(serializeInto, session->_compactAppleMessages ? 1 : 0); 757 AppendByte(serializeInto, session->_includeHashes ? 1 : 0); 758 759 AppendLongLong(serializeInto, session->_stallSeconds ? session->_stallSeconds : constant_zero); 760 761 AppendByte(serializeInto, session->_stallingTheirRoll ? 1 : 0); 762 AppendLongLong(serializeInto, (uint64_t)session->_timeToRoll); 763 AppendByte(serializeInto, session->_missedAck ? 1 : 0); 764 AppendByte(serializeInto, session->_receivedAck ? 1 : 0); 765 766 } 767 }); 768 769 if (result != errSecSuccess) 770 CFDataSetLength(serializeInto, start); 771 772 abort: 773 return result; 774 } 775 776 777 bool SecOTRSIsForKeys(SecOTRSessionRef session, SecKeyRef myPublic, SecKeyRef theirPublic) 778 { 779 __block bool isForKeys = false; 780 781 dispatch_sync(session->_queue, ^{ 782 isForKeys = SecOTRFICompareToPublicKey(session->_me, myPublic) && 783 SecOTRPICompareToPublicKey(session->_them, theirPublic); 784 }); 785 786 return isForKeys; 787 } 788 789 bool SecOTRSGetIsReadyForMessages(SecOTRSessionRef session) 790 { 791 __block bool result; 792 793 dispatch_sync(session->_queue, ^{ result = session->_state == kDone; }); 794 795 return result; 796 } 797 798 bool SecOTRSGetIsIdle(SecOTRSessionRef session) 799 { 800 __block bool result; 801 802 dispatch_sync(session->_queue, ^{ result = session->_state == kIdle; }); 803 804 return result; 805 } 806 807 static void SecOTRSPrecalculateForPair(SecOTRSessionRef session, 808 SecOTRFullDHKeyRef myKey, 809 SecOTRPublicDHKeyRef theirKey) 810 { 811 if (myKey == NULL || theirKey == NULL) 812 return; 813 814 SecOTRSFindKeysForMessage(session, myKey, theirKey, true, NULL, NULL, NULL); 815 SecOTRSFindKeysForMessage(session, myKey, theirKey, false, NULL, NULL, NULL); 816 } 817 818 static void SecOTRSPrecalculateKeysInternal(SecOTRSessionRef session) 819 { 820 SecOTRSPrecalculateForPair(session, session->_myKey, session->_theirKey); 821 SecOTRSPrecalculateForPair(session, session->_myNextKey, session->_theirKey); 822 SecOTRSPrecalculateForPair(session, session->_myKey, session->_theirPreviousKey); 823 SecOTRSPrecalculateForPair(session, session->_myNextKey, session->_theirPreviousKey); 824 } 825 826 static void SecOTRSPrecalculateNextKeysInternal(SecOTRSessionRef session) 827 { 828 SecOTRSPrecalculateForPair(session, session->_myKey, session->_theirKey); 829 } 830 831 void SecOTRSPrecalculateKeys(SecOTRSessionRef session) 832 { 833 dispatch_sync_f(session->_queue, session, (dispatch_function_t) SecOTRSPrecalculateKeysInternal); 834 } 835 836 enum SecOTRSMessageKind SecOTRSGetMessageKind(SecOTRSessionRef session, CFDataRef message) 837 { 838 OTRMessageType type = SecOTRSGetMessageType(message); 839 840 enum SecOTRSMessageKind kind; 841 842 switch (type) { 843 case kDataMessage: 844 case kEvenCompactDataMessage: 845 case kOddCompactDataMessage: 846 case kEvenCompactDataMessageWithHashes: 847 case kOddCompactDataMessageWithHashes: 848 kind = kOTRDataPacket; 849 break; 850 case kDHMessage: 851 case kDHKeyMessage: 852 case kRevealSignatureMessage: 853 case kSignatureMessage: 854 kind = kOTRNegotiationPacket; 855 break; 856 case kInvalidMessage: 857 default: 858 kind = kOTRUnknownPacket; 859 break; 860 } 861 862 return kind; 863 } 864 865 static OSStatus SecOTRSSignAndProtectRaw_locked(SecOTRSessionRef session, 866 CFDataRef sourceMessage, CFMutableDataRef destinationMessage, 867 uint8_t* messageKey, uint8_t* macKey, uint64_t* counter, uint32_t theirKeyID, SecOTRPublicDHKeyRef theirKey) 868 { 869 CFIndex start = CFDataGetLength(destinationMessage); 870 871 AppendHeader(destinationMessage, kDataMessage); 872 AppendByte(destinationMessage, 0); // Flags, all zero 873 874 AppendLong(destinationMessage, session->_keyID); 875 AppendLong(destinationMessage, theirKeyID); 876 SecFDHKAppendPublicSerialization(session->_myNextKey, destinationMessage); 877 AppendLongLong(destinationMessage, ++*counter); 878 879 CFIndex sourceSize = CFDataGetLength(sourceMessage); 880 assert(((unsigned long)sourceSize)<=UINT32_MAX); /* this is correct as long as CFIndex is a signed long */ 881 AppendLong(destinationMessage, (uint32_t)sourceSize); 882 uint8_t* encryptedDataPointer = CFDataIncreaseLengthAndGetMutableBytes(destinationMessage, sourceSize); 883 AES_CTR_HighHalf_Transform(kOTRMessageKeyBytes, messageKey, 884 *counter, 885 (size_t)sourceSize, CFDataGetBytePtr(sourceMessage), 886 encryptedDataPointer); 887 888 CFIndex macedContentsSize = CFDataGetLength(destinationMessage) - start; 889 CFIndex macSize = CCSHA1_OUTPUT_SIZE; 890 uint8_t* macDataPointer = CFDataIncreaseLengthAndGetMutableBytes(destinationMessage, macSize); 891 892 cchmac(ccsha1_di(), 893 kOTRMessageMacKeyBytes, macKey, 894 macedContentsSize, CFDataGetBytePtr(destinationMessage) + start, 895 macDataPointer); 896 897 CFDataAppend(destinationMessage, session->_macKeysToExpose); 898 899 return errSecSuccess; 900 } 901 902 const size_t kCompactMessageMACSize = 16; 903 904 static OSStatus SecOTRSSignAndProtectCompact_locked(SecOTRSessionRef session, 905 CFDataRef sourceMessage, CFMutableDataRef destinationMessage, 906 uint8_t* messageKey, uint8_t* macKey, uint64_t* counter, uint32_t theirKeyID, SecOTRPublicDHKeyRef theirKey) 907 { 908 CFIndex start = CFDataGetLength(destinationMessage); 909 bool sendHashes = session->_includeHashes; 910 911 const uint8_t messageType = sendHashes ? ((theirKeyID & 0x1) ? kOddCompactDataMessageWithHashes : kEvenCompactDataMessageWithHashes) 912 : ((theirKeyID & 0x1) ? kOddCompactDataMessage : kEvenCompactDataMessage); 913 914 AppendByte(destinationMessage, messageType); 915 916 SecFDHKAppendCompactPublicSerialization(session->_myNextKey, destinationMessage); 917 AppendLongLongCompact(destinationMessage, ++*counter); 918 919 CFIndex sourceSize = CFDataGetLength(sourceMessage); 920 assert(((unsigned long)sourceSize)<=UINT32_MAX); /* this is correct as long as CFIndex is a signed long */ 921 uint8_t* encryptedDataPointer = CFDataIncreaseLengthAndGetMutableBytes(destinationMessage, sourceSize); 922 AES_CTR_HighHalf_Transform(kOTRMessageKeyBytes, messageKey, 923 *counter, 924 (size_t)sourceSize, CFDataGetBytePtr(sourceMessage), 925 encryptedDataPointer); 926 927 if (sendHashes) { 928 uint8_t *senderHashPtr = CFDataIncreaseLengthAndGetMutableBytes(destinationMessage, kSecDHKHashSize); 929 930 memcpy(senderHashPtr, SecFDHKGetHash(session->_myKey), kSecDHKHashSize); 931 932 uint8_t *receiverHashPtr = CFDataIncreaseLengthAndGetMutableBytes(destinationMessage, kSecDHKHashSize); 933 934 memcpy(receiverHashPtr, SecPDHKGetHash(theirKey), kSecDHKHashSize); 935 } 936 937 938 CFIndex macedContentsSize = CFDataGetLength(destinationMessage) - start; 939 CFIndex macSize = CCSHA1_OUTPUT_SIZE; 940 uint8_t mac[macSize]; 941 cchmac(ccsha1_di(), 942 kOTRMessageMacKeyBytes, macKey, 943 macedContentsSize, CFDataGetBytePtr(destinationMessage) + start, 944 mac); 945 946 CFDataAppendBytes(destinationMessage, mac, kCompactMessageMACSize); 947 948 return errSecSuccess; 949 } 950 951 OSStatus SecOTRSSignAndProtectMessage(SecOTRSessionRef session, 952 CFDataRef sourceMessage, 953 CFMutableDataRef protectedMessage) 954 { 955 __block OSStatus result = errSecParam; 956 957 require(session, abort); 958 require(sourceMessage, abort); 959 require(protectedMessage, abort); 960 961 if(session->_state != kDone){ 962 secdebug("OTR", "Cannot sign and protect messages, we are not done negotiating sesion[%p]", session); 963 require_quiet( session->_state == kDone, abort); 964 } 965 966 dispatch_sync(session->_queue, ^{ 967 if (session->_myKey == NULL || 968 session->_theirKey == NULL) { 969 return; 970 } 971 972 uint8_t *messageKey; 973 uint8_t *macKey; 974 uint64_t *counter; 975 uint32_t theirKeyID = session->_theirKeyID; 976 977 SecOTRPublicDHKeyRef theirKeyToUse = session->_theirKey; 978 979 SecOTRSRollIfTime(session); 980 981 if(session->_stallingTheirRoll && session->_theirPreviousKey){ 982 theirKeyToUse = session->_theirPreviousKey; 983 theirKeyID = session->_theirKeyID - 1; 984 } 985 986 SecOTRSFindKeysForMessage(session, session->_myKey, theirKeyToUse, 987 true, 988 &messageKey, &macKey, &counter); 989 // The || !protectedMessage below is only here to shut the static analyzer up, the require(protectedMessage, abort) outside the block already ensures this new term is never true. 990 CFMutableDataRef destinationMessage = session->_textOutput || !protectedMessage ? CFDataCreateMutable(kCFAllocatorDefault, 0) : CFRetainSafe(protectedMessage); 991 992 result = session->_compactAppleMessages ? SecOTRSSignAndProtectCompact_locked(session, sourceMessage, destinationMessage, messageKey, macKey, counter, theirKeyID, theirKeyToUse) 993 : SecOTRSSignAndProtectRaw_locked(session, sourceMessage, destinationMessage, messageKey, macKey, counter, theirKeyID, theirKeyToUse); 994 995 if (result == errSecSuccess) { 996 if (session->_textOutput) { 997 SecOTRPrepareOutgoingBytes(destinationMessage, protectedMessage); 998 } 999 1000 CFDataSetLength(session->_macKeysToExpose, 0); 1001 } 1002 1003 CFReleaseSafe(destinationMessage); 1004 1005 result = errSecSuccess; 1006 }); 1007 1008 abort: 1009 return result; 1010 } 1011 1012 void SecOTRSKickTimeToRoll(SecOTRSessionRef session){ 1013 session->_timeToRoll = CFAbsoluteTimeGetCurrent(); 1014 } 1015 1016 static void SecOTRAcceptNewRemoteKey(SecOTRSessionRef session, SecOTRPublicDHKeyRef newKey) 1017 { 1018 if (session->_theirPreviousKey) { 1019 SecOTRSExpireCachedKeysForPublicKey(session, session->_theirPreviousKey); 1020 } 1021 1022 CFReleaseNull(session->_theirPreviousKey); 1023 session->_theirPreviousKey = session->_theirKey; 1024 session->_theirKey = CFRetainSafe(newKey); 1025 session->_stallingTheirRoll = true; 1026 1027 session->_theirKeyID += 1; 1028 1029 SecOTRSEnableTimeToRoll(session); 1030 } 1031 1032 OSStatus SecOTRSetupInitialRemoteKey(SecOTRSessionRef session, SecOTRPublicDHKeyRef CF_CONSUMED initialKey) { 1033 1034 bzero(session->_keyCache, sizeof(session->_keyCache)); 1035 1036 CFReleaseNull(session->_theirPreviousKey); 1037 CFAssignRetained(session->_theirKey, initialKey); 1038 session->_theirKeyID = 1; 1039 1040 return errSecSuccess; 1041 } 1042 1043 /// 1044 /// MARK: SLOW ROLLING 1045 /// 1046 1047 void SOSOTRSRoll(SecOTRSessionRef session){ 1048 1049 session->_stallingTheirRoll = false; 1050 1051 //receiving side roll 1052 if(session->_receivedAck){ 1053 SecOTRGenerateNewProposedKey(session); 1054 session->_missedAck = false; 1055 session->_receivedAck = false; 1056 } 1057 else{ 1058 session->_missedAck = true; 1059 } 1060 } 1061 1062 static OSStatus SecOTRVerifyAndExposeRaw_locked(SecOTRSessionRef session, 1063 CFDataRef decodedBytes, 1064 CFMutableDataRef exposedMessageContents) 1065 { 1066 OSStatus result = errSecDecode; 1067 1068 SecOTRPublicDHKeyRef newKey = NULL; 1069 const uint8_t* bytes; 1070 size_t size; 1071 SecOTRFullDHKeyRef myKeyForMessage = NULL; 1072 SecOTRPublicDHKeyRef theirKeyForMessage = NULL; 1073 bytes = CFDataGetBytePtr(decodedBytes); 1074 size = CFDataGetLength(decodedBytes); 1075 1076 const uint8_t* macDataStart = bytes; 1077 1078 uint32_t theirID; 1079 uint32_t myID; 1080 1081 require_noerr_quiet(result = ReadAndVerifyHeader(&bytes, &size, kDataMessage), fail); 1082 require_action_quiet(size > 0, fail, result = errSecDecode); 1083 1084 require_noerr_quiet(result = ReadAndVerifyByte(&bytes, &size, 0), fail); // Flags, always zero 1085 1086 require_noerr_quiet(result = ReadLong(&bytes, &size, &theirID), fail); 1087 1088 require_action_quiet(theirID == session->_theirKeyID || (theirID == (session->_theirKeyID - 1) && session->_theirPreviousKey != NULL), 1089 fail, 1090 result = ((theirID + 1) < session->_theirKeyID) ? errSecOTRTooOld : errSecOTRIDTooNew); 1091 1092 require_noerr_quiet(result = ReadLong(&bytes, &size, &myID), fail); 1093 1094 require_action_quiet(myID == session->_keyID || (myID == session->_keyID + 1 && session->_myNextKey != NULL), 1095 fail, 1096 result = (myID < session->_keyID) ? errSecOTRTooOld : errSecOTRIDTooNew); 1097 1098 1099 // Choose appripriate keys for message: 1100 { 1101 uint8_t *messageKey; 1102 uint8_t *macKey; 1103 uint64_t *theirCounter; 1104 1105 myKeyForMessage = (myID == session->_keyID) ? session->_myKey : session->_myNextKey; 1106 theirKeyForMessage = (theirID == session->_theirKeyID) ? session->_theirKey : session->_theirPreviousKey; 1107 1108 SecOTRSFindKeysForMessage(session, myKeyForMessage, theirKeyForMessage, false, 1109 &messageKey, &macKey, &theirCounter); 1110 1111 size_t nextKeyMPISize; 1112 const uint8_t* nextKeyMPIBytes; 1113 require_noerr_quiet(result = SizeAndSkipMPI(&bytes, &size, &nextKeyMPIBytes, &nextKeyMPISize), fail); 1114 1115 uint64_t counter; 1116 require_noerr_quiet(result = ReadLongLong(&bytes, &size, &counter), fail); 1117 require_action_quiet(counter > *theirCounter, fail, result = errSecOTRTooOld); 1118 1119 size_t messageSize; 1120 const uint8_t* messageStart; 1121 require_noerr_quiet(result = SizeAndSkipDATA(&bytes, &size, &messageStart, &messageSize), fail); 1122 1123 size_t macDataSize = (bytes - macDataStart) ? (size_t)(bytes - macDataStart) : 0; 1124 uint8_t mac[CCSHA1_OUTPUT_SIZE]; 1125 require_action_quiet(sizeof(mac) <= size, fail, result = errSecDecode); 1126 1127 cchmac(ccsha1_di(), 1128 kOTRMessageMacKeyBytes, macKey, 1129 macDataSize, macDataStart, 1130 mac); 1131 1132 require_noerr_action_quiet(timingsafe_bcmp(mac, bytes, sizeof(mac)), fail, result = errSecAuthFailed); 1133 1134 uint8_t* dataSpace = CFDataIncreaseLengthAndGetMutableBytes(exposedMessageContents, (CFIndex)messageSize); 1135 1136 AES_CTR_HighHalf_Transform(kOTRMessageKeyBytes, messageKey, 1137 counter, 1138 messageSize, messageStart, 1139 dataSpace); 1140 1141 // Everything is good, accept the meta data. 1142 *theirCounter = counter; 1143 1144 newKey = SecOTRPublicDHKCreateFromBytes(kCFAllocatorDefault, &nextKeyMPIBytes, &nextKeyMPISize); 1145 } 1146 1147 bool acceptTheirNewKey = newKey != NULL && theirID == session->_theirKeyID; 1148 1149 if (acceptTheirNewKey) { 1150 SecOTRAcceptNewRemoteKey(session, newKey); 1151 } 1152 1153 if (myID == (session->_keyID + 1)) { 1154 SecOTRSHandleProposalAcknowledge(session); 1155 } 1156 1157 SecOTRSRollIfTime(session); 1158 1159 SecOTRSPrecalculateNextKeysInternal(session); 1160 1161 fail: 1162 if(result != errSecSuccess){ 1163 CFDataPerformWithHexString(decodedBytes, ^(CFStringRef decodedBytesString) { 1164 SecOTRPublicIdentityRef myPublicID = SecOTRPublicIdentityCopyFromPrivate(kCFAllocatorDefault, session->_me, NULL); 1165 SecOTRPIPerformWithSerializationString(myPublicID, ^(CFStringRef myIDString) { 1166 SecOTRPIPerformWithSerializationString(session->_them, ^(CFStringRef theirIDString) { 1167 secnotice("OTR","session[%p] failed to decrypt, session: %@, mk: %@, mpk: %@, tpk: %@, tk: %@, chose tktu: %@", session, session, 1168 session->_myKey, session->_myNextKey, session->_theirPreviousKey, session->_theirKey, theirKeyForMessage); 1169 secnotice("OTR","session[%p] failed to decrypt, mktu: %@, mpi: %@, tpi: %@, m: %@", session, myKeyForMessage, myIDString, theirIDString, decodedBytesString); 1170 }); 1171 }); 1172 CFReleaseNull(myPublicID); 1173 }); 1174 } 1175 CFReleaseNull(newKey); 1176 return result; 1177 } 1178 1179 static OSStatus SecOTRVerifyAndExposeRawCompact_locked(SecOTRSessionRef session, 1180 CFDataRef decodedBytes, 1181 CFMutableDataRef exposedMessageContents) 1182 { 1183 SecOTRPublicDHKeyRef theirProposal = NULL; 1184 OSStatus result = errSecDecode; 1185 const uint8_t* bytes; 1186 size_t size; 1187 SecOTRPublicDHKeyRef theirKeyForMessage = NULL; 1188 bytes = CFDataGetBytePtr(decodedBytes); 1189 size = CFDataGetLength(decodedBytes); 1190 SecOTRFullDHKeyRef myKeyForMessage = NULL; 1191 const uint8_t* macDataStart = bytes; 1192 bool useEvenKey = false; 1193 bool useCurrentKey = false; 1194 bool sentHashes = false; 1195 uint64_t counter = 0; 1196 1197 uint8_t type_byte = 0; 1198 require_noerr_quiet(result = ReadByte(&bytes, &size, &type_byte), fail); 1199 require_action_quiet(type_byte == kOddCompactDataMessage || type_byte == kEvenCompactDataMessage 1200 || type_byte == kOddCompactDataMessageWithHashes || type_byte == kEvenCompactDataMessageWithHashes, fail, result = errSecDecode); 1201 1202 useEvenKey = (type_byte == kEvenCompactDataMessage || type_byte == kEvenCompactDataMessageWithHashes); 1203 sentHashes = (type_byte == kOddCompactDataMessageWithHashes || type_byte == kEvenCompactDataMessageWithHashes); 1204 1205 useCurrentKey = useEvenKey ^ (session->_keyID & 1); 1206 myKeyForMessage = useCurrentKey ? session->_myKey : session->_myNextKey; 1207 1208 require_action_quiet(myKeyForMessage, fail, result = errSecDecode); 1209 1210 theirProposal = SecOTRPublicDHKCreateFromCompactSerialization(kCFAllocatorDefault, &bytes, &size); 1211 1212 require_action_quiet(theirProposal, fail, result = errSecDecode); 1213 1214 bool proposalIsNew = !CFEqualSafe(theirProposal, session->_theirKey); 1215 theirKeyForMessage = proposalIsNew ? session->_theirKey : session->_theirPreviousKey; 1216 1217 require_action_quiet(theirKeyForMessage, fail, result = errSecDecode); 1218 1219 uint8_t *messageKey; 1220 uint8_t *macKey; 1221 uint64_t *theirCounter; 1222 1223 1224 SecOTRSFindKeysForMessage(session, myKeyForMessage, theirKeyForMessage, false, &messageKey, &macKey, &theirCounter); 1225 1226 require_noerr_quiet(result = ReadLongLongCompact(&bytes, &size, &counter), fail); 1227 require_action_quiet(counter > *theirCounter, fail, result = errSecOTRTooOld); 1228 1229 size_t messageSize = size - kCompactMessageMACSize - (sentHashes ? 2 * kSecDHKHashSize : 0); // It's all message except for the MAC and maybe hashes 1230 const uint8_t* messageStart = bytes; 1231 1232 bytes += messageSize; 1233 size -= messageSize; 1234 1235 if (sentHashes) { 1236 // Sender then receiver keys 1237 1238 if (memcmp(SecPDHKGetHash(theirKeyForMessage), bytes, kSecDHKHashSize) != 0) { 1239 // Wrong sender key WTF. 1240 #if DEBUG 1241 BufferPerformWithHexString(bytes, kSecDHKHashSize, ^(CFStringRef dataString) { 1242 secdebug("OTR","session[%p] Sender key hash doesn't match: %@ != %@", session, theirKeyForMessage, dataString); 1243 }); 1244 #endif 1245 } 1246 1247 bytes += kSecDHKHashSize; 1248 size -= kSecDHKHashSize; 1249 1250 if (memcmp(SecFDHKGetHash(myKeyForMessage), bytes, kSecDHKHashSize) != 0) { 1251 // Wrong sender key WTF. 1252 #if DEBUG 1253 BufferPerformWithHexString(bytes, kSecDHKHashSize, ^(CFStringRef dataString) { 1254 secdebug("OTR","session[%p] Receiver key hash doesn't match: %@ != %@", session, myKeyForMessage, dataString); 1255 }); 1256 #endif 1257 } 1258 1259 bytes += kSecDHKHashSize; 1260 size -= kSecDHKHashSize; 1261 1262 } 1263 1264 uint8_t mac[CCSHA1_OUTPUT_SIZE]; 1265 require_action_quiet(kCompactMessageMACSize == size, fail, result = errSecDecode); // require space for the mac and some bytes 1266 1267 size_t macDataSize = (size_t)(bytes - macDataStart); 1268 1269 cchmac(ccsha1_di(), 1270 kOTRMessageMacKeyBytes, macKey, 1271 macDataSize, macDataStart, 1272 mac); 1273 1274 require_noerr_action_quiet(timingsafe_bcmp(mac, bytes, kCompactMessageMACSize), fail, result = errSecAuthFailed); 1275 1276 uint8_t* dataSpace = CFDataIncreaseLengthAndGetMutableBytes(exposedMessageContents, (CFIndex)messageSize); 1277 1278 AES_CTR_HighHalf_Transform(kOTRMessageKeyBytes, messageKey, 1279 counter, 1280 messageSize, messageStart, 1281 dataSpace); 1282 1283 // Everything is good, accept the meta data. 1284 *theirCounter = counter; 1285 1286 if (proposalIsNew) { 1287 SecOTRAcceptNewRemoteKey(session, theirProposal); 1288 } 1289 1290 if (!useCurrentKey) { 1291 SecOTRSHandleProposalAcknowledge(session); 1292 } 1293 SecOTRSRollIfTime(session); 1294 1295 SecOTRSPrecalculateNextKeysInternal(session); 1296 1297 fail: 1298 if(result != errSecSuccess){ 1299 CFDataPerformWithHexString(decodedBytes, ^(CFStringRef decodedBytesString) { 1300 SecOTRPublicIdentityRef myPublicID = SecOTRPublicIdentityCopyFromPrivate(kCFAllocatorDefault, session->_me, NULL); 1301 SecOTRPIPerformWithSerializationString(myPublicID, ^(CFStringRef myIDString) { 1302 SecOTRPIPerformWithSerializationString(session->_them, ^(CFStringRef theirIDString) { 1303 secnotice("OTR","session[%p] failed to decrypt, session: %@, mk: %@, mpk: %@, tpk: %@, tk: %@, chose tktu: %@", session, session, 1304 session->_myKey, session->_myNextKey, session->_theirPreviousKey, session->_theirKey, theirKeyForMessage); 1305 secnotice("OTR","session[%p] failed to decrypt, mktu: %@, mpi: %@, tpi: %@, m: %@, tP: %@, tb: %hhx", session, myKeyForMessage, myIDString, theirIDString, decodedBytesString, theirProposal, type_byte); 1306 }); 1307 }); 1308 CFReleaseNull(myPublicID); 1309 }); 1310 } 1311 CFReleaseNull(theirProposal); 1312 return result; 1313 } 1314 1315 1316 OSStatus SecOTRSVerifyAndExposeMessage(SecOTRSessionRef session, 1317 CFDataRef incomingMessage, 1318 CFMutableDataRef exposedMessageContents) 1319 { 1320 __block OSStatus result = errSecParam; 1321 1322 1323 require(session, abort); 1324 require(incomingMessage, abort); 1325 require(exposedMessageContents, abort); 1326 1327 if(session->_state == kDone){ 1328 dispatch_sync(session->_queue, ^{ 1329 CFDataRef decodedBytes = SecOTRCopyIncomingBytes(incomingMessage); 1330 1331 OTRMessageType messageType = SecOTRSGetMessageType(decodedBytes); 1332 1333 switch (messageType) { 1334 case kDataMessage: 1335 result = SecOTRVerifyAndExposeRaw_locked(session, decodedBytes, exposedMessageContents); 1336 break; 1337 1338 case kOddCompactDataMessage: 1339 case kEvenCompactDataMessage: 1340 case kOddCompactDataMessageWithHashes: 1341 case kEvenCompactDataMessageWithHashes: 1342 result = SecOTRVerifyAndExposeRawCompact_locked(session, decodedBytes, exposedMessageContents); 1343 break; 1344 1345 default: 1346 result = errSecUnsupportedFormat; 1347 break; 1348 } 1349 1350 CFReleaseSafe(decodedBytes); 1351 }); 1352 } 1353 else{ 1354 secnotice("OTR", "session[%p]Cannot process message:%@, session is not done negotiating, session state: %@", session, incomingMessage, session); 1355 result = errSecOTRNotReady; 1356 } 1357 abort: 1358 return result; 1359 } 1360 1361 1362 static CFDataRef data_to_data_error_request(enum SecXPCOperation op, CFDataRef publicPeerId, CFErrorRef *error) { 1363 __block CFDataRef result = NULL; 1364 securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) { 1365 return SecXPCDictionarySetDataOptional(message, kSecXPCPublicPeerId, publicPeerId, error); 1366 }, ^bool(xpc_object_t response, CFErrorRef *error) { 1367 return (result = SecXPCDictionaryCopyData(response, kSecXPCKeyResult, error)); 1368 }); 1369 return result; 1370 } 1371 1372 static bool data_data_to_data_data_bool_error_request(enum SecXPCOperation op, CFDataRef sessionData, CFDataRef inputPacket, CFDataRef* outputSessionData, CFDataRef* outputPacket, bool *readyForMessages, CFErrorRef *error) { 1373 __block CFDataRef tempOutputSessionData = NULL; 1374 __block CFDataRef tempOutputPacket = NULL; 1375 __block bool tempReadyForMessages = false; 1376 1377 bool result = securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) { 1378 return SecXPCDictionarySetDataOptional(message, kSecXPCOTRSession, sessionData, error) 1379 && SecXPCDictionarySetDataOptional(message, kSecXPCData, inputPacket, error); 1380 }, ^bool(xpc_object_t response, CFErrorRef *error) { 1381 if (xpc_dictionary_get_bool(response, kSecXPCKeyResult)) { 1382 tempOutputSessionData = SecXPCDictionaryCopyData(response, kSecXPCOTRSession, error); 1383 tempOutputPacket = SecXPCDictionaryCopyData(response, kSecXPCData, error); 1384 tempReadyForMessages = xpc_dictionary_get_bool(response, kSecXPCOTRReady); 1385 return true; 1386 } else { 1387 return false; 1388 } 1389 1390 }); 1391 1392 *outputSessionData = tempOutputSessionData; 1393 *outputPacket = tempOutputPacket; 1394 *readyForMessages = tempReadyForMessages; 1395 1396 return result; 1397 } 1398 1399 1400 CFDataRef SecOTRSessionCreateRemote(CFDataRef publicPeerId, CFErrorRef *error) { 1401 __block CFDataRef result; 1402 os_activity_initiate("SecOTRSessionCreateRemote", OS_ACTIVITY_FLAG_DEFAULT, ^{ 1403 (void)SecOTRGetDefaultsWriteSeconds(); 1404 result = SECURITYD_XPC(sec_otr_session_create_remote, data_to_data_error_request, publicPeerId, error); 1405 }); 1406 return result; 1407 } 1408 1409 bool SecOTRSessionProcessPacketRemote(CFDataRef sessionData, CFDataRef inputPacket, CFDataRef* outputSessionData, CFDataRef* outputPacket, bool *readyForMessages, CFErrorRef *error) { 1410 __block bool result; 1411 os_activity_initiate("SecOTRSessionProcessPacketRemote", OS_ACTIVITY_FLAG_DEFAULT, ^{ 1412 result = SECURITYD_XPC(sec_otr_session_process_packet_remote, data_data_to_data_data_bool_error_request, sessionData, inputPacket, outputSessionData, outputPacket, readyForMessages, error); 1413 }); 1414 return result; 1415 } 1416