SOSCoder.c
1 /* 2 * Copyright (c) 2013-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 #include <stdlib.h> 25 26 #include <CoreFoundation/CFBase.h> 27 #include <CoreFoundation/CFError.h> 28 29 #include <Security/SecBasePriv.h> 30 #include <Security/SecOTR.h> 31 #include <Security/SecOTRSession.h> 32 #include <Security/SecOTRSessionPriv.h> 33 #include "keychain/SecureObjectSync/SOSInternal.h" 34 #include "keychain/SecureObjectSync/SOSFullPeerInfo.h" 35 #include <Security/SecureObjectSync/SOSPeerInfo.h> 36 #include "keychain/SecureObjectSync/SOSPeer.h" 37 #include "keychain/SecureObjectSync/SOSCoder.h" 38 39 #include <utilities/SecCFRelease.h> 40 #include <utilities/SecCFWrappers.h> 41 #include <utilities/SecIOFormat.h> 42 #include <utilities/SecCFError.h> 43 #include <utilities/SecCoreCrypto.h> 44 #include <utilities/debugging.h> 45 46 #include <utilities/der_plist.h> 47 #include <utilities/der_plist_internal.h> 48 49 #include <corecrypto/ccder.h> 50 #include <utilities/iCloudKeychainTrace.h> 51 52 #include "AssertMacros.h" 53 54 struct __OpaqueSOSCoder { 55 CFRuntimeBase _base; 56 57 CFStringRef peer_id; 58 SecOTRSessionRef sessRef; 59 bool waitingForDataPacket; 60 CFDataRef pendingResponse; 61 62 CFDataRef hashOfLastReceived; 63 bool lastReceivedWasOld; 64 }; 65 66 #define lastReceived_di ccsha1_di 67 68 CFGiblisWithCompareFor(SOSCoder) 69 70 static CFStringRef SOSCoderCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions) { 71 SOSCoderRef coder = (SOSCoderRef)cf; 72 if(coder){ 73 __block CFStringRef desc = NULL; 74 CFDataPerformWithHexString(coder->hashOfLastReceived, ^(CFStringRef dataString) { 75 desc = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("<Coder %@ %@ %s%s>"), 76 coder->sessRef, 77 dataString, 78 coder->waitingForDataPacket ? "W" : "w", 79 coder->lastReceivedWasOld ? "O" : "o" 80 ); 81 82 }); 83 return desc; 84 } 85 else 86 return CFSTR("NULL"); 87 } 88 89 static Boolean SOSCoderCompare(CFTypeRef cfA, CFTypeRef cfB) { 90 SOSCoderRef coderA = (SOSCoderRef)cfA, coderB = (SOSCoderRef)cfB; 91 // Use mainly to see if peerB is actually this device (peerA) 92 return CFStringCompare(coderA->peer_id, coderB->peer_id, 0) == kCFCompareEqualTo; 93 } 94 95 96 static const char *SOSCoderString(SOSCoderStatus coderStatus) { 97 switch (coderStatus) { 98 case kSOSCoderDataReturned: return "DataReturned"; 99 case kSOSCoderNegotiating: return "Negotiating"; 100 case kSOSCoderNegotiationCompleted: return "NegotiationCompleted"; 101 case kSOSCoderFailure: return "Failure"; 102 case kSOSCoderStaleEvent: return "StaleEvent"; 103 case kSOSCoderTooNew: return "TooNew"; 104 default: return "StatusUnknown"; 105 } 106 } 107 108 static CFMutableDataRef sessSerializedCreate(SOSCoderRef coder, CFErrorRef *error) { 109 CFMutableDataRef otr_state = NULL; 110 111 if(!coder || !coder->sessRef) { 112 SOSCreateErrorWithFormat(kSOSErrorUnexpectedType, NULL, error, 0, CFSTR("No session reference.")); 113 return NULL; 114 } 115 116 if ((otr_state = CFDataCreateMutable(NULL, 0)) == NULL) { 117 SOSCreateErrorWithFormat(kSOSErrorAllocationFailure, NULL, error, 0, CFSTR("Mutable Data allocation failed.")); 118 return NULL; 119 } 120 121 if (errSecSuccess != SecOTRSAppendSerialization(coder->sessRef, otr_state)) { 122 SOSCreateErrorWithFormat(kSOSErrorEncodeFailure, NULL, error, 0, CFSTR("Append Serialization failed.")); 123 CFReleaseSafe(otr_state); 124 return NULL; 125 } 126 127 return otr_state; 128 129 } 130 131 static size_t der_sizeof_optional_data(CFDataRef data) { 132 return data ? der_sizeof_data(data, NULL) : 0; 133 } 134 135 static uint8_t* der_encode_optional_data(CFDataRef data, CFErrorRef *error, const uint8_t* der, uint8_t* der_end) { 136 return data ? der_encode_data(data, error, der, der_end) : der_end; 137 } 138 139 140 141 static size_t SOSCoderGetDEREncodedSize(SOSCoderRef coder, CFErrorRef *error) { 142 size_t encoded_size = 0; 143 CFMutableDataRef otr_state = sessSerializedCreate(coder, error); 144 145 if (otr_state) { 146 size_t data_size = der_sizeof_data(otr_state, error); 147 size_t waiting_size = ccder_sizeof_bool(coder->waitingForDataPacket, error); 148 size_t pending_size = der_sizeof_optional_data(coder->pendingResponse); 149 150 if ((data_size != 0) && (waiting_size != 0)) 151 { 152 encoded_size = ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, data_size + waiting_size + pending_size); 153 } 154 CFReleaseSafe(otr_state); 155 } 156 return encoded_size; 157 } 158 159 160 static uint8_t* SOSCoderEncodeToDER(SOSCoderRef coder, CFErrorRef* error, const uint8_t* der, uint8_t* der_end) { 161 if(!der_end) return NULL; 162 uint8_t* result = NULL; 163 CFMutableDataRef otr_state = sessSerializedCreate(coder, error); 164 165 if(otr_state) { 166 result = ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der, 167 der_encode_data(otr_state, error, der, 168 ccder_encode_bool(coder->waitingForDataPacket, der, 169 der_encode_optional_data(coder->pendingResponse, error, der, der_end)))); 170 CFReleaseSafe(otr_state); 171 } 172 return result; 173 } 174 175 bool SOSCoderIsCoderInAwaitingState(SOSCoderRef coder){ 176 return SecOTRSessionIsSessionInAwaitingState(coder->sessRef); 177 } 178 179 CFDataRef SOSCoderCopyDER(SOSCoderRef coder, CFErrorRef* error) { 180 CFMutableDataRef encoded = NULL; 181 size_t encoded_size = SOSCoderGetDEREncodedSize(coder, error); 182 183 if (encoded_size > 0) { 184 encoded = CFDataCreateMutable(NULL, encoded_size); 185 if (encoded) { 186 CFDataSetLength(encoded, encoded_size); 187 uint8_t * der = CFDataGetMutableBytePtr(encoded); 188 uint8_t * der_end = der + encoded_size; 189 if (!SOSCoderEncodeToDER(coder, error, der, der_end)) { 190 CFReleaseNull(encoded); 191 encoded = NULL; 192 } 193 } 194 } 195 return encoded; 196 } 197 198 static SOSCoderRef SOSCoderCreate_internal() { 199 SOSCoderRef p = CFTypeAllocate(SOSCoder, struct __OpaqueSOSCoder, kCFAllocatorDefault); 200 201 p->peer_id = NULL; 202 p->sessRef = NULL; 203 p->pendingResponse = NULL; 204 p->waitingForDataPacket = false; 205 206 p->hashOfLastReceived = NULL; 207 p->lastReceivedWasOld = false; 208 209 return p; 210 211 } 212 213 // 0 - Type not understood 214 // 1 - OCTET_STRING, just stored the data for OTR 215 // 2 - SEQUENCE with no version value 216 // 3 - SEQUENCE with version value we pull out of the CCDER_INTEGER 217 218 typedef enum coderExportFormatVersion { 219 kNotUnderstood = 0, 220 kCoderAsOTRDataOnly = 1, 221 kCoderAsSequence = 2, 222 kCoderAsVersionedSequence = 3, 223 224 kCurrentCoderExportVersion = kCoderAsVersionedSequence 225 } CoderExportFormatVersion; 226 227 static uint64_t SOSCoderGetExportedVersion(const uint8_t *der, const uint8_t *der_end) { 228 ccder_tag tag; 229 uint64_t result = kNotUnderstood; 230 require(ccder_decode_tag(&tag, der, der_end),xit); 231 switch (tag) { 232 case CCDER_OCTET_STRING: // TODO: this code is safe to delete? 233 result = kCoderAsOTRDataOnly; 234 break; 235 236 case CCDER_CONSTRUCTED_SEQUENCE: 237 { 238 const uint8_t *sequence_end = NULL; 239 der = ccder_decode_sequence_tl(&sequence_end, der, der_end); 240 ccder_tag firstSequenceTag; 241 require(ccder_decode_tag(&firstSequenceTag, der, der_end),xit); 242 243 switch (firstSequenceTag) { 244 case CCDER_OCTET_STRING: 245 result = kCoderAsSequence; 246 break; 247 case CCDER_INTEGER: 248 der = ccder_decode_uint64(NULL, der, sequence_end); 249 if (der == NULL) { 250 result = kNotUnderstood; 251 } else { 252 result = kCoderAsVersionedSequence; 253 } 254 break; 255 } 256 } 257 } 258 xit: 259 return result; 260 261 } 262 263 SOSCoderRef SOSCoderCreateFromData(CFDataRef exportedData, CFErrorRef *error) { 264 // TODO: fill in errors for all failure cases 265 //require_action_quiet(coder, xit, SOSCreateError(kSOSErrorSendFailure, CFSTR("No coder for peer"), NULL, error)); 266 267 SOSCoderRef p = SOSCoderCreate_internal(); 268 269 const uint8_t *der = CFDataGetBytePtr(exportedData); 270 const uint8_t *der_end = der + CFDataGetLength(exportedData); 271 272 CFDataRef otr_data = NULL; 273 274 switch (SOSCoderGetExportedVersion(der, der_end)) { 275 case kCoderAsOTRDataOnly: 276 der = der_decode_data(kCFAllocatorDefault, &otr_data, error, der, der_end); 277 p->waitingForDataPacket = false; 278 break; 279 280 case kCoderAsSequence: 281 { 282 const uint8_t *sequence_end = NULL; 283 der = ccder_decode_sequence_tl(&sequence_end, der, der_end); 284 285 require_action_quiet(sequence_end == der_end, fail, SecCFDERCreateError(kSOSErrorDecodeFailure, CFSTR("Extra data in SOS coder"), NULL, error)); 286 287 der = der_decode_data(kCFAllocatorDefault, &otr_data, error, der, sequence_end); 288 der = ccder_decode_bool(&p->waitingForDataPacket, der, sequence_end); 289 if (der != sequence_end) { // optionally a pending response 290 der = der_decode_data(kCFAllocatorDefault, &p->pendingResponse, error, der, sequence_end); 291 } 292 } 293 break; 294 295 case kCoderAsVersionedSequence: 296 { 297 const uint8_t *sequence_end = NULL; 298 der = ccder_decode_sequence_tl(&sequence_end, der, der_end); 299 300 require_action_quiet(sequence_end == der_end, fail, SecCFDERCreateError(kSOSErrorDecodeFailure, CFSTR("Extra data in SOS coder"), NULL, error)); 301 302 uint64_t version; 303 der = ccder_decode_uint64(&version, der, sequence_end); 304 if (version != kCoderAsVersionedSequence) { 305 SOSErrorCreate(kSOSErrorDecodeFailure, error, NULL, CFSTR("Unsupported Sequence Version: %lld"), version); 306 goto fail; 307 } 308 309 der = der_decode_data(kCFAllocatorDefault, &otr_data, error, der, sequence_end); 310 der = ccder_decode_bool(&p->waitingForDataPacket, der, sequence_end); 311 der = ccder_decode_bool(&p->lastReceivedWasOld, der, sequence_end); 312 der = der_decode_data(kCFAllocatorDefault, &p->hashOfLastReceived, error, der, sequence_end); 313 if (der != sequence_end) { // optionally a pending response 314 der = der_decode_data(kCFAllocatorDefault, &p->pendingResponse, error, der, sequence_end); 315 } 316 } 317 break; 318 319 default: 320 SOSErrorCreate(kSOSErrorDecodeFailure, error, NULL, CFSTR("Unsupported SOS Coder DER")); 321 goto fail; 322 } 323 324 require(der, fail); 325 326 p->sessRef = SecOTRSessionCreateFromData(NULL, otr_data); 327 require(p->sessRef, fail); 328 329 if (p->hashOfLastReceived == NULL) 330 p->hashOfLastReceived = CFDataCreateMutableWithScratch(kCFAllocatorDefault, lastReceived_di()->output_size); 331 332 CFReleaseSafe(otr_data); 333 return p; 334 335 fail: 336 CFReleaseNull(p); 337 CFReleaseSafe(otr_data); 338 return NULL; 339 } 340 341 342 SOSCoderRef SOSCoderCreate(SOSPeerInfoRef peerInfo, SOSFullPeerInfoRef myPeerInfo, CFBooleanRef useCompact, CFErrorRef *error) { 343 CFAllocatorRef allocator = CFGetAllocator(peerInfo); 344 345 SOSCoderRef coder = SOSCoderCreate_internal(); 346 347 CFErrorRef localError = NULL; 348 349 SecOTRFullIdentityRef myRef = NULL; 350 SecOTRPublicIdentityRef peerRef = NULL; 351 SecKeyRef privateKey = NULL; 352 SecKeyRef publicKey = NULL; 353 354 if (myPeerInfo && peerInfo) { 355 privateKey = SOSFullPeerInfoCopyDeviceKey(myPeerInfo, &localError); 356 require_quiet(privateKey, errOut); 357 358 myRef = SecOTRFullIdentityCreateFromSecKeyRefSOS(allocator, privateKey, &localError); 359 require_quiet(myRef, errOut); 360 361 CFReleaseNull(privateKey); 362 363 publicKey = SOSPeerInfoCopyPubKey(peerInfo, &localError); 364 require(publicKey, errOut); 365 366 peerRef = SecOTRPublicIdentityCreateFromSecKeyRef(allocator, publicKey, &localError); 367 require_quiet(peerRef, errOut); 368 369 if(useCompact == kCFBooleanTrue) 370 coder->sessRef = SecOTRSessionCreateFromIDAndFlags(allocator, myRef, peerRef, kSecOTRUseAppleCustomMessageFormat); 371 372 else 373 coder->sessRef = SecOTRSessionCreateFromID(allocator, myRef, peerRef); 374 375 require(coder->sessRef, errOut); 376 377 coder->waitingForDataPacket = false; 378 coder->pendingResponse = NULL; 379 380 CFReleaseNull(publicKey); 381 CFReleaseNull(privateKey); 382 CFReleaseNull(myRef); 383 CFReleaseNull(peerRef); 384 } else { 385 secnotice("coder", "NULL Coder requested, no transport security"); 386 } 387 388 coder->hashOfLastReceived = CFDataCreateMutableWithScratch(kCFAllocatorDefault, lastReceived_di()->output_size); 389 coder->lastReceivedWasOld = false; 390 391 SOSCoderStart(coder, NULL); 392 393 return coder; 394 395 errOut: 396 secerror("Coder create failed: %@\n", localError ? localError : (CFTypeRef)CFSTR("No local error in SOSCoderCreate")); 397 secerror("Coder create failed: %@\n", error ? *error : (CFTypeRef)CFSTR("WTF NULL?")); 398 CFReleaseNull(myRef); 399 CFReleaseNull(peerRef); 400 CFReleaseNull(publicKey); 401 CFReleaseNull(privateKey); 402 403 CFReleaseNull(coder); 404 return NULL; 405 } 406 407 static void SOSCoderDestroy(CFTypeRef cf) 408 { 409 SOSCoderRef coder = (SOSCoderRef) cf; 410 if (coder) { 411 CFReleaseNull(coder->sessRef); 412 CFReleaseNull(coder->pendingResponse); 413 CFReleaseNull(coder->hashOfLastReceived); 414 } 415 } 416 417 void SOSCoderReset(SOSCoderRef coder) 418 { 419 SecOTRSessionReset(coder->sessRef); 420 coder->waitingForDataPacket = false; 421 CFReleaseNull(coder->pendingResponse); 422 423 coder->lastReceivedWasOld = false; 424 CFReleaseNull(coder->hashOfLastReceived); 425 coder->hashOfLastReceived = CFDataCreateMutableWithScratch(kCFAllocatorDefault, lastReceived_di()->output_size); 426 } 427 428 bool SOSCoderIsFor(SOSCoderRef coder, SOSPeerInfoRef peerInfo, SOSFullPeerInfoRef myPeerInfo) { 429 SecKeyRef theirPublicKey = NULL; 430 SecKeyRef myPublicKey = NULL; 431 bool isForThisPair = false; 432 CFErrorRef localError = NULL; 433 434 myPublicKey = SOSPeerInfoCopyPubKey(SOSFullPeerInfoGetPeerInfo(myPeerInfo), &localError); 435 require(myPublicKey, errOut); 436 437 theirPublicKey = SOSPeerInfoCopyPubKey(peerInfo, &localError); 438 require(theirPublicKey, errOut); 439 440 isForThisPair = SecOTRSIsForKeys(coder->sessRef, myPublicKey, theirPublicKey); 441 442 errOut: 443 if (localError) { 444 secerror("SOSCoderIsFor failed: %@\n", localError ? localError : (CFTypeRef)CFSTR("No local error in SOSCoderCreate")); 445 } 446 447 CFReleaseNull(myPublicKey); 448 CFReleaseNull(theirPublicKey); 449 CFReleaseNull(localError); 450 return isForThisPair; 451 } 452 453 CFDataRef SOSCoderCopyPendingResponse(SOSCoderRef coder) 454 { 455 return coder->pendingResponse ? CFDataCreateCopy(kCFAllocatorDefault, coder->pendingResponse) : NULL; 456 } 457 458 void SOSCoderConsumeResponse(SOSCoderRef coder) 459 { 460 CFReleaseNull(coder->pendingResponse); 461 } 462 463 static bool SOSOTRSAppendStartPacket(SecOTRSessionRef session, CFMutableDataRef appendPacket, CFErrorRef *error) { 464 OSStatus otrStatus = SecOTRSAppendStartPacket(session, appendPacket); 465 if (otrStatus != errSecSuccess) { 466 SOSCreateErrorWithFormat(kSOSErrorEncodeFailure, (error != NULL) ? *error : NULL, error, NULL, CFSTR("append start packet returned: %" PRIdOSStatus), otrStatus); 467 } 468 return otrStatus == errSecSuccess; 469 } 470 471 // Start OTR negotiation if we haven't already done so. 472 SOSCoderStatus 473 SOSCoderStart(SOSCoderRef coder, CFErrorRef *error) { 474 CFMutableStringRef action = CFStringCreateMutable(kCFAllocatorDefault, 0); 475 CFStringRef beginState = NULL; 476 SOSCoderStatus result = kSOSCoderFailure; 477 CFMutableDataRef startPacket = NULL; 478 479 require_action_quiet(coder->sessRef, coderFailure, CFStringAppend(action, CFSTR("*** no otr session ***"))); 480 beginState = CFCopyDescription(coder->sessRef); 481 require_action_quiet(!coder->waitingForDataPacket, negotiatingOut, CFStringAppend(action, CFSTR("waiting for peer to send first data packet"))); 482 require_action_quiet(!SecOTRSGetIsReadyForMessages(coder->sessRef), coderFailure, CFStringAppend(action, CFSTR("otr session ready")); 483 result = kSOSCoderDataReturned); 484 require_action_quiet(SecOTRSGetIsIdle(coder->sessRef), negotiatingOut, CFStringAppend(action, CFSTR("otr negotiating already"))); 485 require_action_quiet(startPacket = CFDataCreateMutable(kCFAllocatorDefault, 0), coderFailure, SOSCreateError(kSOSErrorAllocationFailure, CFSTR("alloc failed"), NULL, error)); 486 require_quiet(SOSOTRSAppendStartPacket(coder->sessRef, startPacket, error), coderFailure); 487 CFRetainAssign(coder->pendingResponse, startPacket); 488 489 negotiatingOut: 490 result = kSOSCoderNegotiating; 491 coderFailure: 492 // Uber state log 493 if (result == kSOSCoderFailure && error && *error) 494 CFStringAppendFormat(action, NULL, CFSTR(" %@"), *error); 495 secinfo("coder", "%@ %s %@ %@ returned %s", beginState, 496 SecOTRPacketTypeString(startPacket), action, coder->sessRef, SOSCoderString(result)); 497 CFReleaseNull(startPacket); 498 CFReleaseSafe(beginState); 499 CFRelease(action); 500 501 return result; 502 503 } 504 505 SOSCoderStatus 506 SOSCoderResendDH(SOSCoderRef coder, CFErrorRef *error) { 507 if(coder->sessRef == NULL) return kSOSCoderDataReturned; 508 CFMutableDataRef startPacket = CFDataCreateMutable(kCFAllocatorDefault, 0); 509 SOSCoderStatus result = kSOSCoderFailure; 510 require_noerr_quiet(SecOTRSAppendRestartPacket(coder->sessRef, startPacket), exit); 511 secnotice("coder", "Resending OTR Start %@", startPacket); 512 CFRetainAssign(coder->pendingResponse, startPacket); 513 result = kSOSCoderNegotiating; 514 exit: 515 CFReleaseNull(startPacket); 516 return result; 517 } 518 519 520 static SOSCoderStatus nullCoder(CFDataRef from, CFMutableDataRef *to) { 521 *to = CFDataCreateMutableCopy(NULL, CFDataGetLength(from), from); 522 return kSOSCoderDataReturned; 523 } 524 525 SOSCoderStatus SOSCoderUnwrap(SOSCoderRef coder, CFDataRef codedMessage, CFMutableDataRef *message, 526 CFStringRef clientId, CFErrorRef *error) { 527 if(codedMessage == NULL) return kSOSCoderDataReturned; 528 if(coder->sessRef == NULL) return nullCoder(codedMessage, message); 529 CFMutableStringRef action = CFStringCreateMutable(kCFAllocatorDefault, 0); 530 /* This should be the "normal" case. We just use OTR to unwrap the received message. */ 531 SOSCoderStatus result = kSOSCoderFailure; 532 533 CFStringRef beginState = CFCopyDescription(coder->sessRef); 534 enum SecOTRSMessageKind kind = SecOTRSGetMessageKind(coder->sessRef, codedMessage); 535 536 537 switch (kind) { 538 case kOTRNegotiationPacket: { 539 /* If we're in here we haven't completed negotiating a session. Use SecOTRSProcessPacket() to go through 540 the negotiation steps and immediately send a reply back if necessary using the sendBlock. This 541 assumes the sendBlock is still available. 542 */ 543 CFMutableDataRef response = CFDataCreateMutable(kCFAllocatorDefault, 0); 544 OSStatus ppstatus = errSecSuccess; 545 if (response) { 546 switch (ppstatus = SecOTRSProcessPacket(coder->sessRef, codedMessage, response)) { 547 case errSecSuccess: 548 if (CFDataGetLength(response) > 1) { 549 CFStringAppendFormat(action, NULL, CFSTR("Sending OTR Response %s"), SecOTRPacketTypeString(response)); 550 CFRetainAssign(coder->pendingResponse, response); 551 result = kSOSCoderNegotiating; 552 if (SecOTRSGetIsReadyForMessages(coder->sessRef)) { 553 CFStringAppend(action, CFSTR(" begin waiting for data packet")); 554 coder->waitingForDataPacket = true; 555 } 556 } else if(!SecOTRSGetIsReadyForMessages(coder->sessRef)) { 557 CFStringAppend(action, CFSTR("stuck?")); 558 result = kSOSCoderNegotiating; 559 } else { 560 CFStringAppend(action, CFSTR("completed negotiation")); 561 result = kSOSCoderNegotiationCompleted; 562 coder->waitingForDataPacket = false; 563 } 564 break; 565 case errSecDecode: 566 CFStringAppend(action, CFSTR("resending dh")); 567 result = SOSCoderResendDH(coder, error); 568 break; 569 default: 570 SOSCreateErrorWithFormat(kSOSErrorEncodeFailure, (error != NULL) ? *error : NULL, error, NULL, CFSTR("%@ Cannot negotiate session (%ld)"), clientId, (long)ppstatus); 571 result = kSOSCoderFailure; 572 break; 573 }; 574 } else { 575 SOSCreateErrorWithFormat(kSOSErrorAllocationFailure, (error != NULL) ? *error : NULL, error, NULL, CFSTR("%@ Cannot allocate CFData"), clientId); 576 result = kSOSCoderFailure; 577 } 578 579 CFReleaseNull(response); 580 581 break; 582 } 583 584 case kOTRDataPacket: 585 { 586 CFDataRef previousMessageHash = coder->hashOfLastReceived; 587 coder->hashOfLastReceived = CFDataCreateWithHash(kCFAllocatorDefault, lastReceived_di(), CFDataGetBytePtr(codedMessage), CFDataGetLength(codedMessage)); 588 bool lastWasOld = coder->lastReceivedWasOld; 589 coder->lastReceivedWasOld = false; 590 591 if(!SecOTRSGetIsReadyForMessages(coder->sessRef)) { 592 CFStringAppend(action, CFSTR("not ready for data; resending DH packet")); 593 result = SOSCoderResendDH(coder, error); 594 } else { 595 if (coder->waitingForDataPacket) { 596 CFStringAppend(action, CFSTR("got data packet we were waiting for ")); 597 coder->waitingForDataPacket = false; 598 } 599 CFMutableDataRef exposed = CFDataCreateMutable(0, 0); 600 OSStatus otrResult = SecOTRSVerifyAndExposeMessage(coder->sessRef, codedMessage, exposed); 601 CFStringAppend(action, CFSTR("verify and expose message")); 602 switch(otrResult) { 603 case errSecSuccess: 604 CFStringAppend(action, CFSTR("decoded OTR protected packet")); 605 CFTransferRetained(*message, exposed); 606 result = kSOSCoderDataReturned; 607 break; 608 case errSecOTRTooOld: 609 if (CFEqualSafe(previousMessageHash, coder->hashOfLastReceived)) { 610 CFStringAppend(action, CFSTR(" repeated")); 611 result = kSOSCoderStaleEvent; 612 } else { 613 coder->lastReceivedWasOld = true; 614 if (lastWasOld) { 615 CFStringAppend(action, CFSTR(" too old, repeated renegotiating")); 616 // Fail so we will renegotiate 617 result = kSOSCoderFailure; 618 } else { 619 CFStringAppend(action, CFSTR(" too old, forcing message")); 620 // Force message send. 621 result = kSOSCoderForceMessage; 622 } 623 } 624 break; 625 case errSecOTRIDTooNew: 626 CFStringAppend(action, CFSTR(" too new")); 627 result = kSOSCoderTooNew; 628 break; 629 default: 630 SecError(otrResult, error, CFSTR("%@ Cannot expose message: %" PRIdOSStatus), clientId, otrResult); 631 secerror("%@ Decode OTR Protected Packet: %@", clientId, error ? *error : NULL); 632 result = kSOSCoderFailure; 633 break; 634 } 635 636 CFReleaseNull(exposed); 637 } 638 CFReleaseNull(previousMessageHash); 639 } 640 break; 641 642 default: 643 secerror("%@ Unknown packet type: %@", clientId, codedMessage); 644 SOSCreateError(kSOSErrorDecodeFailure, CFSTR("Unknown packet type"), (error != NULL) ? *error : NULL, error); 645 result = kSOSCoderFailure; 646 break; 647 }; 648 649 // Uber state log 650 if (result == kSOSCoderFailure && error && *error) 651 CFStringAppendFormat(action, NULL, CFSTR(" %@"), *error); 652 secnotice("coder", "%@ %@ %s %@ %@ returned %s", clientId, beginState, 653 SecOTRPacketTypeString(codedMessage), action, coder->sessRef, SOSCoderString(result)); 654 CFReleaseSafe(beginState); 655 CFRelease(action); 656 657 return result; 658 } 659 660 661 SOSCoderStatus SOSCoderWrap(SOSCoderRef coder, CFDataRef message, CFMutableDataRef *codedMessage, CFStringRef clientId, CFErrorRef *error) { 662 CFMutableStringRef action = CFStringCreateMutable(kCFAllocatorDefault, 0); 663 SOSCoderStatus result = kSOSCoderDataReturned; 664 CFStringRef beginState = NULL; 665 CFMutableDataRef encoded = NULL; 666 OSStatus otrStatus = 0; 667 668 require_action_quiet(coder->sessRef, errOut, 669 CFStringAppend(action, CFSTR("*** using null coder ***")); 670 result = nullCoder(message, codedMessage)); 671 beginState = CFCopyDescription(coder->sessRef); 672 require_action_quiet(SecOTRSGetIsReadyForMessages(coder->sessRef), errOut, 673 CFStringAppend(action, CFSTR("not ready")); 674 result = kSOSCoderNegotiating); 675 require_action_quiet(!coder->waitingForDataPacket, errOut, 676 CFStringAppend(action, CFSTR("waiting for peer to send data packet first")); 677 result = kSOSCoderNegotiating); 678 require_action_quiet(encoded = CFDataCreateMutable(kCFAllocatorDefault, 0), errOut, 679 SOSCreateErrorWithFormat(kSOSErrorAllocationFailure, NULL, error, NULL, CFSTR("%@ alloc failed"), clientId); 680 result = kSOSCoderFailure); 681 require_noerr_action_quiet(otrStatus = SecOTRSSignAndProtectMessage(coder->sessRef, message, encoded), errOut, 682 SOSCreateErrorWithFormat(kSOSErrorEncodeFailure, (error != NULL) ? *error : NULL, error, NULL, CFSTR("%@ cannot protect message: %" PRIdOSStatus), clientId, otrStatus); 683 CFReleaseNull(encoded); 684 result = kSOSCoderFailure); 685 *codedMessage = encoded; 686 687 errOut: 688 // Uber state log 689 if (result == kSOSCoderFailure && error && *error) 690 CFStringAppendFormat(action, NULL, CFSTR(" %@"), *error); 691 secinfo("coder", "%@ %@ %s %@ %@ returned %s", clientId, beginState, 692 SecOTRPacketTypeString(encoded), action, coder->sessRef, SOSCoderString(result)); 693 CFReleaseSafe(beginState); 694 CFRelease(action); 695 696 return result; 697 } 698 699 bool SOSCoderCanWrap(SOSCoderRef coder) { 700 return coder->sessRef && SecOTRSGetIsReadyForMessages(coder->sessRef) && !coder->waitingForDataPacket; 701 }