2  * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. 
   4  * @APPLE_LICENSE_HEADER_START@ 
   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 
  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. 
  21  * @APPLE_LICENSE_HEADER_END@ 
  26 #include <CoreFoundation/CFBase.h> 
  27 #include <CoreFoundation/CFError.h> 
  29 #include <Security/SecBasePriv.h> 
  30 #include <Security/SecOTR.h> 
  31 #include <Security/SecOTRSession.h> 
  32 #include <Security/SecureObjectSync/SOSInternal.h> 
  33 #include <Security/SecureObjectSync/SOSFullPeerInfo.h> 
  34 #include <Security/SecureObjectSync/SOSPeerInfo.h> 
  35 #include <Security/SecureObjectSync/SOSPeer.h> 
  36 #include <Security/SecureObjectSync/SOSCoder.h> 
  38 #include <utilities/SecCFRelease.h> 
  39 #include <utilities/SecCFWrappers.h> 
  40 #include <utilities/SecIOFormat.h> 
  41 #include <utilities/SecCFError.h> 
  42 #include <utilities/SecCoreCrypto.h> 
  43 #include <utilities/debugging.h> 
  45 #include <utilities/der_plist.h> 
  46 #include <utilities/der_plist_internal.h> 
  48 #include <corecrypto/ccder.h> 
  49 #include <utilities/iCloudKeychainTrace.h> 
  51 #include "AssertMacros.h" 
  53 struct __OpaqueSOSCoder 
{ 
  57     SecOTRSessionRef sessRef
; 
  58     bool waitingForDataPacket
; 
  59     CFDataRef pendingResponse
; 
  61     CFDataRef hashOfLastReceived
; 
  62     bool      lastReceivedWasOld
; 
  65 #define lastReceived_di ccsha1_di 
  67 CFGiblisWithCompareFor(SOSCoder
) 
  69 static CFStringRef 
SOSCoderCopyFormatDescription(CFTypeRef cf
, CFDictionaryRef formatOptions
) { 
  70     SOSCoderRef coder 
= (SOSCoderRef
)cf
; 
  72         __block CFStringRef desc 
= NULL
; 
  73         CFDataPerformWithHexString(coder
->hashOfLastReceived
, ^(CFStringRef dataString
) { 
  74             desc 
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("<Coder %@ %@ %s%s>"), 
  77                                             coder
->waitingForDataPacket 
? "W" : "w", 
  78                                             coder
->lastReceivedWasOld 
? "O" : "o" 
  88 static Boolean 
SOSCoderCompare(CFTypeRef cfA
, CFTypeRef cfB
) { 
  89     SOSCoderRef coderA 
= (SOSCoderRef
)cfA
, coderB 
= (SOSCoderRef
)cfB
; 
  90     // Use mainly to see if peerB is actually this device (peerA) 
  91     return CFStringCompare(coderA
->peer_id
, coderB
->peer_id
, 0) == kCFCompareEqualTo
; 
  95 static const char *SOSCoderString(SOSCoderStatus coderStatus
) { 
  96     switch (coderStatus
) { 
  97         case kSOSCoderDataReturned
: return "DataReturned"; 
  98         case kSOSCoderNegotiating
: return "Negotiating"; 
  99         case kSOSCoderNegotiationCompleted
: return "NegotiationCompleted"; 
 100         case kSOSCoderFailure
: return "Failure"; 
 101         case kSOSCoderStaleEvent
: return "StaleEvent"; 
 102         case kSOSCoderTooNew
: return "TooNew"; 
 103         default: return "StatusUnknown"; 
 108  static void logRawCoderMessage(const uint8_t* der, uint8_t* der_end, bool encoding) 
 111     CFStringRef hexMessage = NULL; 
 112     if (der && der_end) { 
 113         CFIndex length = der_end - der; 
 114         CFDataRef message = CFDataCreate(kCFAllocatorDefault, der, length); 
 115         hexMessage = CFDataCopyHexString(message); 
 116         secnoticeq("coder", "%s RAW [%ld] %@", encoding ? "encode" : "decode", length, hexMessage); 
 117         CFReleaseSafe(message); 
 119     CFReleaseSafe(hexMessage); 
 124 static CFMutableDataRef 
sessSerializedCreate(SOSCoderRef coder
, CFErrorRef 
*error
) { 
 125     CFMutableDataRef otr_state 
= NULL
; 
 127     if(!coder 
|| !coder
->sessRef
) { 
 128         SOSCreateErrorWithFormat(kSOSErrorUnexpectedType
, NULL
, error
, 0, CFSTR("No session reference.")); 
 132     if ((otr_state 
= CFDataCreateMutable(NULL
, 0)) == NULL
) { 
 133         SOSCreateErrorWithFormat(kSOSErrorAllocationFailure
, NULL
, error
, 0, CFSTR("Mutable Data allocation failed.")); 
 137     if (errSecSuccess 
!= SecOTRSAppendSerialization(coder
->sessRef
, otr_state
)) { 
 138         SOSCreateErrorWithFormat(kSOSErrorEncodeFailure
, NULL
, error
, 0, CFSTR("Append Serialization failed.")); 
 139         CFReleaseSafe(otr_state
); 
 147 static size_t der_sizeof_optional_data(CFDataRef data
) { 
 148     return data 
? der_sizeof_data(data
, NULL
) : 0; 
 151 static uint8_t* der_encode_optional_data(CFDataRef data
, CFErrorRef 
*error
, const uint8_t* der
, uint8_t* der_end
) { 
 152     return data 
? der_encode_data(data
, error
, der
, der_end
) : der_end
; 
 157 static size_t SOSCoderGetDEREncodedSize(SOSCoderRef coder
, CFErrorRef 
*error
) { 
 158     size_t encoded_size 
= 0; 
 159     CFMutableDataRef otr_state 
= sessSerializedCreate(coder
, error
); 
 162         size_t data_size 
= der_sizeof_data(otr_state
, error
); 
 163         size_t waiting_size 
= ccder_sizeof_bool(coder
->waitingForDataPacket
, error
); 
 164         size_t pending_size 
= der_sizeof_optional_data(coder
->pendingResponse
); 
 166         if ((data_size 
!= 0) && (waiting_size 
!= 0)) 
 168             encoded_size 
= ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE
, data_size 
+ waiting_size 
+ pending_size
); 
 170         CFReleaseSafe(otr_state
); 
 176 static uint8_t* SOSCoderEncodeToDER(SOSCoderRef coder
, CFErrorRef
* error
, const uint8_t* der
, uint8_t* der_end
) { 
 177     if(!der_end
) return NULL
; 
 178     uint8_t* result 
= NULL
; 
 179     CFMutableDataRef otr_state 
= sessSerializedCreate(coder
, error
); 
 182         result 
= ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
, der_end
, der
, 
 183                                              der_encode_data(otr_state
, error
, der
, 
 184                                              ccder_encode_bool(coder
->waitingForDataPacket
, der
, 
 185                                              der_encode_optional_data(coder
->pendingResponse
, error
, der
, der_end
)))); 
 186         CFReleaseSafe(otr_state
); 
 192 CFDataRef 
SOSCoderCopyDER(SOSCoderRef coder
, CFErrorRef
* error
) { 
 193     CFMutableDataRef encoded 
= NULL
; 
 194     size_t encoded_size 
= SOSCoderGetDEREncodedSize(coder
, error
); 
 196     if (encoded_size 
> 0) { 
 197         encoded 
= CFDataCreateMutable(NULL
, encoded_size
); 
 199             CFDataSetLength(encoded
, encoded_size
); 
 200             uint8_t * der 
= CFDataGetMutableBytePtr(encoded
); 
 201             uint8_t * der_end 
= der 
+ encoded_size
; 
 202             if (!SOSCoderEncodeToDER(coder
, error
, der
, der_end
)) { 
 203                 CFReleaseNull(encoded
); 
 211 static SOSCoderRef 
SOSCoderCreate_internal() { 
 212     SOSCoderRef p 
= CFTypeAllocate(SOSCoder
, struct __OpaqueSOSCoder
, kCFAllocatorDefault
); 
 216     p
->pendingResponse 
= NULL
; 
 217     p
->waitingForDataPacket 
= false; 
 219     p
->hashOfLastReceived 
= NULL
; 
 220     p
->lastReceivedWasOld 
= false; 
 226 // 0 - Type not understood 
 227 // 1 - OCTET_STRING, just stored the data for OTR 
 228 // 2 - SEQUENCE with no version value 
 229 // 3 - SEQUENCE with version value we pull out of the CCDER_INTEGER 
 231 typedef enum coderExportFormatVersion 
{ 
 233     kCoderAsOTRDataOnly 
= 1, 
 234     kCoderAsSequence 
= 2, 
 235     kCoderAsVersionedSequence 
= 3, 
 237     kCurrentCoderExportVersion 
= kCoderAsVersionedSequence
 
 238 } CoderExportFormatVersion
; 
 240 static uint64_t SOSCoderGetExportedVersion(const uint8_t *der
, const uint8_t *der_end
) { 
 242     uint64_t result 
= kNotUnderstood
; 
 243     require(ccder_decode_tag(&tag
, der
, der_end
),xit
); 
 245         case CCDER_OCTET_STRING
: // TODO: this code is safe to delete? 
 246             result 
= kCoderAsOTRDataOnly
; 
 249         case CCDER_CONSTRUCTED_SEQUENCE
: 
 251             const uint8_t *sequence_end 
= NULL
; 
 252             der 
= ccder_decode_sequence_tl(&sequence_end
, der
, der_end
); 
 253             ccder_tag firstSequenceTag
; 
 254             require(ccder_decode_tag(&firstSequenceTag
, der
, der_end
),xit
); 
 256             switch (firstSequenceTag
) { 
 257                 case CCDER_OCTET_STRING
: 
 258                     result 
= kCoderAsSequence
; 
 261                     der 
= ccder_decode_uint64(NULL
, der
, sequence_end
); 
 263                         result 
= kNotUnderstood
; 
 265                         result 
= kCoderAsVersionedSequence
; 
 276 SOSCoderRef 
SOSCoderCreateFromData(CFDataRef exportedData
, CFErrorRef 
*error
) { 
 277     // TODO: fill in errors for all failure cases 
 278     //require_action_quiet(coder, xit, SOSCreateError(kSOSErrorSendFailure, CFSTR("No coder for peer"), NULL, error)); 
 280     SOSCoderRef p 
= SOSCoderCreate_internal(); 
 282     const uint8_t *der 
= CFDataGetBytePtr(exportedData
); 
 283     const uint8_t *der_end 
= der 
+ CFDataGetLength(exportedData
); 
 285     CFDataRef otr_data 
= NULL
; 
 287     switch (SOSCoderGetExportedVersion(der
, der_end
)) { 
 288         case kCoderAsOTRDataOnly
: 
 289             der 
= der_decode_data(kCFAllocatorDefault
, 0, &otr_data
, error
, der
, der_end
); 
 290             p
->waitingForDataPacket 
= false; 
 293         case kCoderAsSequence
: 
 295             const uint8_t *sequence_end 
= NULL
; 
 296             der 
= ccder_decode_sequence_tl(&sequence_end
, der
, der_end
); 
 298             require_action_quiet(sequence_end 
== der_end
, fail
, SecCFDERCreateError(kSOSErrorDecodeFailure
, CFSTR("Extra data in SOS coder"), NULL
, error
)); 
 300             der 
= der_decode_data(kCFAllocatorDefault
, 0, &otr_data
, error
, der
, sequence_end
); 
 301             der 
= ccder_decode_bool(&p
->waitingForDataPacket
, der
, sequence_end
); 
 302             if (der 
!= sequence_end
) { // optionally a pending response 
 303                 der 
= der_decode_data(kCFAllocatorDefault
, 0, &p
->pendingResponse
, error
, der
, sequence_end
); 
 308         case kCoderAsVersionedSequence
: 
 310             const uint8_t *sequence_end 
= NULL
; 
 311             der 
= ccder_decode_sequence_tl(&sequence_end
, der
, der_end
); 
 313             require_action_quiet(sequence_end 
== der_end
, fail
, SecCFDERCreateError(kSOSErrorDecodeFailure
, CFSTR("Extra data in SOS coder"), NULL
, error
)); 
 316             der 
= ccder_decode_uint64(&version
, der
, sequence_end
); 
 317             if (version 
!= kCoderAsVersionedSequence
) { 
 318                 SOSErrorCreate(kSOSErrorDecodeFailure
, error
, NULL
, CFSTR("Unsupported Sequence Version: %lld"), version
); 
 322             der 
= der_decode_data(kCFAllocatorDefault
, 0, &otr_data
, error
, der
, sequence_end
); 
 323             der 
= ccder_decode_bool(&p
->waitingForDataPacket
, der
, sequence_end
); 
 324             der 
= ccder_decode_bool(&p
->lastReceivedWasOld
, der
, sequence_end
); 
 325             der 
= der_decode_data(kCFAllocatorDefault
, 0, &p
->hashOfLastReceived
, error
, der
, sequence_end
); 
 326             if (der 
!= sequence_end
) { // optionally a pending response 
 327                 der 
= der_decode_data(kCFAllocatorDefault
, 0, &p
->pendingResponse
, error
, der
, sequence_end
); 
 333             SOSErrorCreate(kSOSErrorDecodeFailure
, error
, NULL
, CFSTR("Unsupported SOS Coder DER")); 
 339     p
->sessRef 
= SecOTRSessionCreateFromData(NULL
, otr_data
); 
 340     require(p
->sessRef
, fail
); 
 342     if (p
->hashOfLastReceived 
== NULL
) 
 343         p
->hashOfLastReceived 
= CFDataCreateMutableWithScratch(kCFAllocatorDefault
, lastReceived_di()->output_size
); 
 345     CFReleaseSafe(otr_data
); 
 350     CFReleaseSafe(otr_data
); 
 355 SOSCoderRef 
SOSCoderCreate(SOSPeerInfoRef peerInfo
, SOSFullPeerInfoRef myPeerInfo
, CFBooleanRef useCompact
, CFErrorRef 
*error
) { 
 356     CFAllocatorRef allocator 
= CFGetAllocator(peerInfo
); 
 358     SOSCoderRef coder 
= SOSCoderCreate_internal(); 
 360     CFErrorRef localError 
= NULL
; 
 362     SecOTRFullIdentityRef myRef 
= NULL
; 
 363     SecOTRPublicIdentityRef peerRef 
= NULL
; 
 364     SecKeyRef privateKey 
= NULL
; 
 365     SecKeyRef publicKey 
= NULL
; 
 367     if (myPeerInfo 
&& peerInfo
) { 
 368         privateKey 
= SOSFullPeerInfoCopyDeviceKey(myPeerInfo
, &localError
); 
 369         require_quiet(privateKey
, errOut
); 
 371         myRef 
= SecOTRFullIdentityCreateFromSecKeyRef(allocator
, privateKey
, &localError
); 
 372         require_quiet(myRef
, errOut
); 
 374         CFReleaseNull(privateKey
); 
 376         publicKey 
= SOSPeerInfoCopyPubKey(peerInfo
, &localError
); 
 377         require(publicKey
, errOut
); 
 379         peerRef 
= SecOTRPublicIdentityCreateFromSecKeyRef(allocator
, publicKey
, &localError
); 
 380         require_quiet(peerRef
, errOut
); 
 382         if(useCompact 
== kCFBooleanTrue
) 
 383             coder
->sessRef 
= SecOTRSessionCreateFromIDAndFlags(allocator
, myRef
, peerRef
, kSecOTRUseAppleCustomMessageFormat
); 
 386             coder
->sessRef 
= SecOTRSessionCreateFromID(allocator
, myRef
, peerRef
); 
 388         require(coder
->sessRef
, errOut
); 
 390         coder
->waitingForDataPacket 
= false; 
 391         coder
->pendingResponse 
= NULL
; 
 393         CFReleaseNull(publicKey
); 
 394         CFReleaseNull(privateKey
); 
 395         CFReleaseNull(myRef
); 
 396         CFReleaseNull(peerRef
); 
 398         secnotice("coder", "NULL Coder requested, no transport security"); 
 401     coder
->hashOfLastReceived 
= CFDataCreateMutableWithScratch(kCFAllocatorDefault
, lastReceived_di()->output_size
); 
 402     coder
->lastReceivedWasOld 
= false; 
 404     SOSCoderStart(coder
, NULL
); 
 409     secerror("Coder create failed: %@\n", localError 
? localError 
: (CFTypeRef
)CFSTR("No local error in SOSCoderCreate")); 
 410     secerror("Coder create failed: %@\n", error 
? *error 
: (CFTypeRef
)CFSTR("WTF NULL?")); 
 411     CFReleaseNull(myRef
); 
 412     CFReleaseNull(peerRef
); 
 413     CFReleaseNull(publicKey
); 
 414     CFReleaseNull(privateKey
); 
 416     CFReleaseNull(coder
); 
 420 static void SOSCoderDestroy(CFTypeRef cf
) 
 422     SOSCoderRef coder 
= (SOSCoderRef
) cf
; 
 424         CFReleaseNull(coder
->sessRef
); 
 425         CFReleaseNull(coder
->pendingResponse
); 
 426         CFReleaseNull(coder
->hashOfLastReceived
); 
 430 void SOSCoderReset(SOSCoderRef coder
) 
 432     SecOTRSessionReset(coder
->sessRef
); 
 433     coder
->waitingForDataPacket 
= false; 
 434     CFReleaseNull(coder
->pendingResponse
); 
 436     coder
->lastReceivedWasOld 
= false; 
 437     CFReleaseNull(coder
->hashOfLastReceived
); 
 438     coder
->hashOfLastReceived 
= CFDataCreateMutableWithScratch(kCFAllocatorDefault
, lastReceived_di()->output_size
); 
 441 bool SOSCoderIsFor(SOSCoderRef coder
, SOSPeerInfoRef peerInfo
, SOSFullPeerInfoRef myPeerInfo
) { 
 442     SecKeyRef theirPublicKey 
= NULL
; 
 443     SecKeyRef myPublicKey 
= NULL
; 
 444     bool isForThisPair 
= false; 
 445     CFErrorRef localError 
= NULL
; 
 447     myPublicKey 
= SOSPeerInfoCopyPubKey(SOSFullPeerInfoGetPeerInfo(myPeerInfo
), &localError
); 
 448     require(myPublicKey
, errOut
); 
 450     theirPublicKey 
= SOSPeerInfoCopyPubKey(peerInfo
, &localError
); 
 451     require(theirPublicKey
, errOut
); 
 453     isForThisPair 
= SecOTRSIsForKeys(coder
->sessRef
, myPublicKey
, theirPublicKey
); 
 457         secerror("SOSCoderIsFor failed: %@\n", localError 
? localError 
: (CFTypeRef
)CFSTR("No local error in SOSCoderCreate")); 
 460     CFReleaseNull(myPublicKey
); 
 461     CFReleaseNull(theirPublicKey
); 
 462     CFReleaseNull(localError
); 
 463     return isForThisPair
; 
 466 CFDataRef 
SOSCoderCopyPendingResponse(SOSCoderRef coder
) 
 468     return coder
->pendingResponse 
? CFDataCreateCopy(kCFAllocatorDefault
, coder
->pendingResponse
) : NULL
; 
 471 void SOSCoderConsumeResponse(SOSCoderRef coder
) 
 473     CFReleaseNull(coder
->pendingResponse
); 
 476 static bool SOSOTRSAppendStartPacket(SecOTRSessionRef session
, CFMutableDataRef appendPacket
, CFErrorRef 
*error
) { 
 477     OSStatus otrStatus 
= SecOTRSAppendStartPacket(session
, appendPacket
); 
 478     if (otrStatus 
!= errSecSuccess
) { 
 479         SOSCreateErrorWithFormat(kSOSErrorEncodeFailure
, (error 
!= NULL
) ? *error 
: NULL
, error
, NULL
, CFSTR("append start packet returned: %" PRIdOSStatus
), otrStatus
); 
 481     return otrStatus 
== errSecSuccess
; 
 484 // Start OTR negotiation if we haven't already done so. 
 486 SOSCoderStart(SOSCoderRef coder
, CFErrorRef 
*error
) { 
 487     CFMutableStringRef action 
= CFStringCreateMutable(kCFAllocatorDefault
, 0); 
 488     CFStringRef beginState 
= NULL
; 
 489     SOSCoderStatus result 
= kSOSCoderFailure
; 
 490     CFMutableDataRef startPacket 
= NULL
; 
 492     require_action_quiet(coder
->sessRef
, coderFailure
, CFStringAppend(action
, CFSTR("*** no otr session ***"))); 
 493     beginState 
= CFCopyDescription(coder
->sessRef
); 
 494     require_action_quiet(!coder
->waitingForDataPacket
, negotiatingOut
, CFStringAppend(action
, CFSTR("waiting for peer to send first data packet"))); 
 495     require_action_quiet(!SecOTRSGetIsReadyForMessages(coder
->sessRef
), coderFailure
, CFStringAppend(action
, CFSTR("otr session ready")); 
 496                          result 
= kSOSCoderDataReturned
); 
 497     require_action_quiet(SecOTRSGetIsIdle(coder
->sessRef
), negotiatingOut
, CFStringAppend(action
, CFSTR("otr negotiating already"))); 
 498     require_action_quiet(startPacket 
= CFDataCreateMutable(kCFAllocatorDefault
, 0), coderFailure
, SOSCreateError(kSOSErrorAllocationFailure
, CFSTR("alloc failed"), NULL
, error
)); 
 499     require_quiet(SOSOTRSAppendStartPacket(coder
->sessRef
, startPacket
, error
), coderFailure
); 
 500     CFRetainAssign(coder
->pendingResponse
, startPacket
); 
 503     result 
= kSOSCoderNegotiating
; 
 506     if (result 
== kSOSCoderFailure 
&& error 
&& *error
) 
 507         CFStringAppendFormat(action
, NULL
, CFSTR(" %@"), *error
); 
 508     secinfo("coder", "%@ %s %@ %@ returned %s", beginState
, 
 509               SecOTRPacketTypeString(startPacket
), action
, coder
->sessRef
, SOSCoderString(result
)); 
 510     CFReleaseNull(startPacket
); 
 511     CFReleaseSafe(beginState
); 
 519 SOSCoderResendDH(SOSCoderRef coder
, CFErrorRef 
*error
) { 
 520     if(coder
->sessRef 
== NULL
) return kSOSCoderDataReturned
; 
 521     CFMutableDataRef startPacket 
= CFDataCreateMutable(kCFAllocatorDefault
, 0); 
 522     SOSCoderStatus result 
= kSOSCoderFailure
; 
 523     require_noerr_quiet(SecOTRSAppendRestartPacket(coder
->sessRef
, startPacket
), exit
); 
 524     secnotice("coder", "Resending OTR Start %@", startPacket
); 
 525     CFRetainAssign(coder
->pendingResponse
, startPacket
); 
 526     result 
= kSOSCoderNegotiating
; 
 528     CFReleaseNull(startPacket
); 
 533 static SOSCoderStatus 
nullCoder(CFDataRef from
, CFMutableDataRef 
*to
) { 
 534     *to 
= CFDataCreateMutableCopy(NULL
, CFDataGetLength(from
), from
); 
 535     return kSOSCoderDataReturned
; 
 538 SOSCoderStatus 
SOSCoderUnwrap(SOSCoderRef coder
, CFDataRef codedMessage
, CFMutableDataRef 
*message
, 
 539                               CFStringRef clientId
, CFErrorRef 
*error
) { 
 540     if(codedMessage 
== NULL
) return kSOSCoderDataReturned
; 
 541     if(coder
->sessRef 
== NULL
) return nullCoder(codedMessage
, message
); 
 542     CFMutableStringRef action 
= CFStringCreateMutable(kCFAllocatorDefault
, 0); 
 543     /* This should be the "normal" case.  We just use OTR to unwrap the received message. */ 
 544     SOSCoderStatus result 
= kSOSCoderFailure
; 
 546     CFStringRef beginState 
= CFCopyDescription(coder
->sessRef
); 
 547     enum SecOTRSMessageKind kind 
= SecOTRSGetMessageKind(coder
->sessRef
, codedMessage
); 
 551         case kOTRNegotiationPacket
: { 
 552             /* If we're in here we haven't completed negotiating a session.  Use SecOTRSProcessPacket() to go through 
 553              the negotiation steps and immediately send a reply back if necessary using the sendBlock.  This 
 554              assumes the sendBlock is still available. 
 556             CFMutableDataRef response 
= CFDataCreateMutable(kCFAllocatorDefault
, 0); 
 557             OSStatus ppstatus 
= errSecSuccess
; 
 559                 switch (ppstatus 
= SecOTRSProcessPacket(coder
->sessRef
, codedMessage
, response
)) { 
 561                         if (CFDataGetLength(response
) > 1) { 
 562                             CFStringAppendFormat(action
, NULL
, CFSTR("Sending OTR Response %s"), SecOTRPacketTypeString(response
)); 
 563                             CFRetainAssign(coder
->pendingResponse
, response
); 
 564                             result 
= kSOSCoderNegotiating
; 
 565                             if (SecOTRSGetIsReadyForMessages(coder
->sessRef
)) { 
 566                                 CFStringAppend(action
, CFSTR(" begin waiting for data packet")); 
 567                                 coder
->waitingForDataPacket 
= true; 
 569                         } else if(!SecOTRSGetIsReadyForMessages(coder
->sessRef
)) { 
 570                             CFStringAppend(action
, CFSTR("stuck?")); 
 571                             result 
= kSOSCoderNegotiating
; 
 573                             CFStringAppend(action
, CFSTR("completed negotiation")); 
 574                             result 
= kSOSCoderNegotiationCompleted
; 
 575                             coder
->waitingForDataPacket 
= false; 
 579                         CFStringAppend(action
, CFSTR("resending dh")); 
 580                         result 
= SOSCoderResendDH(coder
, error
); 
 583                         SOSCreateErrorWithFormat(kSOSErrorEncodeFailure
, (error 
!= NULL
) ? *error 
: NULL
, error
, NULL
, CFSTR("%@ Cannot negotiate session (%ld)"), clientId
, (long)ppstatus
); 
 584                         result 
= kSOSCoderFailure
; 
 588                 SOSCreateErrorWithFormat(kSOSErrorAllocationFailure
, (error 
!= NULL
) ? *error 
: NULL
, error
, NULL
, CFSTR("%@ Cannot allocate CFData"), clientId
); 
 589                 result 
= kSOSCoderFailure
; 
 592             CFReleaseNull(response
); 
 599             CFDataRef previousMessageHash 
= coder
->hashOfLastReceived
; 
 600             coder
->hashOfLastReceived 
= CFDataCreateWithHash(kCFAllocatorDefault
, lastReceived_di(), CFDataGetBytePtr(codedMessage
), CFDataGetLength(codedMessage
)); 
 601             bool lastWasOld 
= coder
->lastReceivedWasOld
; 
 602             coder
->lastReceivedWasOld 
= false; 
 604             if(!SecOTRSGetIsReadyForMessages(coder
->sessRef
)) { 
 605                 CFStringAppend(action
, CFSTR("not ready for data; resending DH packet")); 
 606                                 SetCloudKeychainTraceValueForKey(kCloudKeychainNumberOfTimesSyncFailed
, 1); 
 607                 result 
= SOSCoderResendDH(coder
, error
); 
 609                 if (coder
->waitingForDataPacket
) { 
 610                     CFStringAppend(action
, CFSTR("got data packet we were waiting for ")); 
 611                     coder
->waitingForDataPacket 
= false; 
 613                 CFMutableDataRef exposed 
= CFDataCreateMutable(0, 0); 
 614                 OSStatus otrResult 
= SecOTRSVerifyAndExposeMessage(coder
->sessRef
, codedMessage
, exposed
); 
 615                 CFStringAppend(action
, CFSTR("verify and expose message")); 
 618                         CFStringAppend(action
, CFSTR("decoded OTR protected packet")); 
 619                         CFTransferRetained(*message
, exposed
); 
 620                         result 
= kSOSCoderDataReturned
; 
 622                     case errSecOTRTooOld
: 
 623                         if (CFEqualSafe(previousMessageHash
, coder
->hashOfLastReceived
)) { 
 624                             CFStringAppend(action
, CFSTR(" repeated")); 
 625                             result 
= kSOSCoderStaleEvent
; 
 627                             coder
->lastReceivedWasOld 
= true; 
 629                                 CFStringAppend(action
, CFSTR(" too old, repeated renegotiating")); 
 630                                 // Fail so we will renegotiate 
 631                                 result 
= kSOSCoderFailure
; 
 633                                 CFStringAppend(action
, CFSTR(" too old, forcing message")); 
 634                                 // Force message send. 
 635                                 result 
= kSOSCoderForceMessage
; 
 639                     case errSecOTRIDTooNew
: 
 640                         CFStringAppend(action
, CFSTR(" too new")); 
 641                         result 
= kSOSCoderTooNew
; 
 644                         SecError(otrResult
, error
, CFSTR("%@ Cannot expose message: %" PRIdOSStatus
), clientId
, otrResult
); 
 645                         secerror("%@ Decode OTR Protected Packet: %@", clientId
, error 
? *error 
: NULL
); 
 646                         result 
= kSOSCoderFailure
; 
 650                 CFReleaseNull(exposed
); 
 652             CFReleaseNull(previousMessageHash
); 
 657             secerror("%@ Unknown packet type: %@", clientId
, codedMessage
); 
 658             SOSCreateError(kSOSErrorDecodeFailure
, CFSTR("Unknown packet type"), (error 
!= NULL
) ? *error 
: NULL
, error
); 
 659             result 
= kSOSCoderFailure
; 
 664     if (result 
== kSOSCoderFailure 
&& error 
&& *error
) 
 665         CFStringAppendFormat(action
, NULL
, CFSTR(" %@"), *error
); 
 666     secnotice("coder", "%@ %@ %s %@ %@ returned %s", clientId
, beginState
, 
 667               SecOTRPacketTypeString(codedMessage
), action
, coder
->sessRef
, SOSCoderString(result
)); 
 668     CFReleaseSafe(beginState
); 
 675 SOSCoderStatus 
SOSCoderWrap(SOSCoderRef coder
, CFDataRef message
, CFMutableDataRef 
*codedMessage
, CFStringRef clientId
, CFErrorRef 
*error
) { 
 676     CFMutableStringRef action 
= CFStringCreateMutable(kCFAllocatorDefault
, 0); 
 677     SOSCoderStatus result 
= kSOSCoderDataReturned
; 
 678     CFStringRef beginState 
= NULL
; 
 679     CFMutableDataRef encoded 
= NULL
; 
 680     OSStatus otrStatus 
= 0; 
 682     require_action_quiet(coder
->sessRef
, errOut
, 
 683                          CFStringAppend(action
, CFSTR("*** using null coder ***")); 
 684                          result 
= nullCoder(message
, codedMessage
)); 
 685     beginState 
= CFCopyDescription(coder
->sessRef
); 
 686     require_action_quiet(SecOTRSGetIsReadyForMessages(coder
->sessRef
), errOut
, 
 687                          CFStringAppend(action
, CFSTR("not ready")); 
 688                          result 
= kSOSCoderNegotiating
); 
 689     require_action_quiet(!coder
->waitingForDataPacket
, errOut
, 
 690                          CFStringAppend(action
, CFSTR("waiting for peer to send data packet first")); 
 691                          result 
= kSOSCoderNegotiating
); 
 692     require_action_quiet(encoded 
= CFDataCreateMutable(kCFAllocatorDefault
, 0), errOut
, 
 693                          SOSCreateErrorWithFormat(kSOSErrorAllocationFailure
, NULL
, error
, NULL
, CFSTR("%@ alloc failed"), clientId
); 
 694                          result 
= kSOSCoderFailure
); 
 695     require_noerr_action_quiet(otrStatus 
= SecOTRSSignAndProtectMessage(coder
->sessRef
, message
, encoded
), errOut
, 
 696                                SOSCreateErrorWithFormat(kSOSErrorEncodeFailure
, (error 
!= NULL
) ? *error 
: NULL
, error
, NULL
, CFSTR("%@ cannot protect message: %" PRIdOSStatus
), clientId
, otrStatus
); 
 697                                CFReleaseNull(encoded
); 
 698                                result 
= kSOSCoderFailure
); 
 699     *codedMessage 
= encoded
; 
 703     if (result 
== kSOSCoderFailure 
&& error 
&& *error
) 
 704         CFStringAppendFormat(action
, NULL
, CFSTR(" %@"), *error
); 
 705     secinfo("coder", "%@ %@ %s %@ %@ returned %s", clientId
, beginState
, 
 706               SecOTRPacketTypeString(encoded
), action
, coder
->sessRef
, SOSCoderString(result
)); 
 707     CFReleaseSafe(beginState
); 
 713 bool SOSCoderCanWrap(SOSCoderRef coder
) { 
 714     return coder
->sessRef 
&& SecOTRSGetIsReadyForMessages(coder
->sessRef
) && !coder
->waitingForDataPacket
;