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