3 // libsecurity_libSecOTR
5 // Created by Mitch Adler on 2/22/11.
6 // Copyright 2011 Apple Inc. All rights reserved.
9 #include "SecOTRSession.h"
11 #include "SecOTRMath.h"
12 #include "SecOTRDHKey.h"
13 #include "SecOTRSessionPriv.h"
14 #include "SecOTRPackets.h"
15 #include "SecOTRPacketData.h"
17 #include <utilities/SecCFWrappers.h>
19 #include <CoreFoundation/CFRuntime.h>
20 #include <CoreFoundation/CFString.h>
22 #include <Security/SecBasePriv.h>
23 #include <Security/SecRandom.h>
24 #include <Security/SecBase64.h>
26 #include <AssertMacros.h>
28 #ifdef USECOMMONCRYPTO
29 #include <CommonCrypto/CommonHMAC.h>
32 #include <corecrypto/cchmac.h>
33 #include <corecrypto/ccsha2.h>
34 #include <corecrypto/ccsha1.h>
41 #include "utilities/comparison.h"
43 CFGiblisFor(SecOTRSession
);
45 static OTRMessageType
SecOTRSGetMessageType(CFDataRef message
)
47 OTRMessageType type
= kInvalidMessage
;
49 CFMutableDataRef decodedBytes
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
50 SecOTRGetIncomingBytes(message
, decodedBytes
);
52 const uint8_t *bytes
= CFDataGetBytePtr(decodedBytes
);
53 size_t size
= CFDataGetLength(decodedBytes
);
55 require_noerr(ReadHeader(&bytes
, &size
, &type
), fail
);
58 CFReleaseNull(decodedBytes
);
63 const char *SecOTRPacketTypeString(CFDataRef message
)
65 if (!message
) return "NoMessage";
66 switch (SecOTRSGetMessageType(message
)) {
67 case kDHMessage
: return "DHMessage (0x02)";
68 case kDataMessage
: return "DataMessage (0x03)";
69 case kDHKeyMessage
: return "DHKeyMessage (0x0A)";
70 case kRevealSignatureMessage
: return "RevealSignatureMessage (0x11)";
71 case kSignatureMessage
: return "SignatureMessage (0x12)";
72 case kInvalidMessage
: return "InvalidMessage (0xFF)";
73 default: return "UnknownMessage";
77 static const char *SecOTRAuthStateString(SecOTRAuthState authState
)
80 case kIdle
: return "Idle";
81 case kAwaitingDHKey
: return "AwaitingDHKey";
82 case kAwaitingRevealSignature
: return "AwaitingRevealSignature";
83 case kAwaitingSignature
: return "AwaitingSignature";
84 case kDone
: return "Done";
85 default: return "InvalidState";
89 static CF_RETURNS_RETAINED CFStringRef
SecOTRSessionCopyDescription(CFTypeRef cf
) {
90 SecOTRSessionRef session
= (SecOTRSessionRef
)cf
;
91 return CFStringCreateWithFormat(kCFAllocatorDefault
,NULL
,CFSTR("<%s %s%s%s%s %d:%d %s%s>"),
92 SecOTRAuthStateString(session
->_state
),
93 session
->_me
? "F" : "-",
94 session
->_them
? "P" : "-",
95 session
->_receivedDHMessage
? "D" : "-",
96 session
->_receivedDHKeyMessage
? "K" : "-",
99 session
->_theirPreviousKey
? "P" : "-",
100 session
->_theirKey
? "T" : "-");
103 static void SecOTRSessionDestroy(CFTypeRef cf
) {
104 SecOTRSessionRef session
= (SecOTRSessionRef
)cf
;
106 CFReleaseNull(session
->_receivedDHMessage
);
107 CFReleaseNull(session
->_receivedDHKeyMessage
);
109 CFReleaseNull(session
->_me
);
110 CFReleaseNull(session
->_myKey
);
111 CFReleaseNull(session
->_myNextKey
);
113 CFReleaseNull(session
->_them
);
114 CFReleaseNull(session
->_theirKey
);
115 CFReleaseNull(session
->_theirPreviousKey
);
117 CFReleaseNull(session
->_macKeysToExpose
);
119 dispatch_release(session
->_queue
);
122 static void SecOTRSessionResetInternal(SecOTRSessionRef session
)
124 session
->_state
= kIdle
;
126 CFReleaseNull(session
->_receivedDHMessage
);
127 CFReleaseNull(session
->_receivedDHKeyMessage
);
130 CFReleaseNull(session
->_myKey
);
131 CFReleaseNull(session
->_myNextKey
);
132 //session->_myNextKey = SecOTRFullDHKCreate(kCFAllocatorDefault);
133 session
->_theirKeyID
= 0;
134 CFReleaseNull(session
->_theirKey
);
135 CFReleaseNull(session
->_theirPreviousKey
);
136 CFReleaseNull(session
->_macKeysToExpose
);
137 session
->_macKeysToExpose
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
139 bzero(session
->_keyCache
, sizeof(session
->_keyCache
));
142 void SecOTRSessionReset(SecOTRSessionRef session
)
144 dispatch_sync_f(session
->_queue
, session
, (dispatch_function_t
) SecOTRSessionResetInternal
);
148 SecOTRSessionRef
SecOTRSessionCreateFromID(CFAllocatorRef allocator
,
149 SecOTRFullIdentityRef myID
,
150 SecOTRPublicIdentityRef theirID
)
152 SecOTRSessionRef newID
= CFTypeAllocate(SecOTRSession
, struct _SecOTRSession
, allocator
);
154 newID
->_queue
= dispatch_queue_create("OTRSession", DISPATCH_QUEUE_SERIAL
);
157 newID
->_them
= theirID
;
158 newID
->_receivedDHMessage
= NULL
;
159 newID
->_receivedDHKeyMessage
= NULL
;
160 newID
->_myKey
= NULL
;
161 newID
->_myNextKey
= NULL
;
162 newID
->_theirKey
= NULL
;
163 newID
->_theirPreviousKey
= NULL
;
164 newID
->_macKeysToExpose
= NULL
;
165 newID
->_textOutput
= false;
167 SecOTRSessionResetInternal(newID
);
169 CFRetain(newID
->_me
);
170 CFRetain(newID
->_them
);
175 SecOTRSessionRef
SecOTRSessionCreateFromIDAndFlags(CFAllocatorRef allocator
,
176 SecOTRFullIdentityRef myID
,
177 SecOTRPublicIdentityRef theirID
,
180 SecOTRSessionRef newID
= SecOTRSessionCreateFromID(allocator
, myID
, theirID
);
181 if (flags
& kSecOTRSendTextMessages
) {
182 newID
->_textOutput
= true;
187 static uint64_t constant_zero
= 0;
189 static void SecOTRSFindKeysForMessage(SecOTRSessionRef session
,
190 SecOTRFullDHKeyRef myKey
,
191 SecOTRPublicDHKeyRef theirKey
,
193 uint8_t** messageKey
, uint8_t** macKey
, uint64_t **counter
)
195 SecOTRCacheElement
* emptyKeys
= NULL
;
196 SecOTRCacheElement
* cachedKeys
= NULL
;
198 if ((NULL
== myKey
) || (NULL
== theirKey
)) {
204 *counter
= &constant_zero
;
209 for(int i
= 0; i
< kOTRKeyCacheSize
; ++i
)
211 if (0 == constant_memcmp(session
->_keyCache
[i
]._fullKeyHash
, SecFDHKGetHash(myKey
), CCSHA1_OUTPUT_SIZE
)
212 && (0 == constant_memcmp(session
->_keyCache
[i
]._publicKeyHash
, SecPDHKGetHash(theirKey
), CCSHA1_OUTPUT_SIZE
))) {
213 cachedKeys
= &session
->_keyCache
[i
];
217 if (emptyKeys
== NULL
218 && session
->_keyCache
[i
]._fullKey
== NULL
) {
219 emptyKeys
= &session
->_keyCache
[i
];
223 if (cachedKeys
== NULL
) {
224 if (emptyKeys
== NULL
) {
225 syslog(LOG_ERR
, "SecOTRSession key cache was full. Should never happen, spooky.\n");
226 emptyKeys
= &session
->_keyCache
[0];
229 // Fill in the entry.
230 emptyKeys
->_fullKey
= myKey
;
231 memcpy(emptyKeys
->_fullKeyHash
, SecFDHKGetHash(myKey
), CCSHA1_OUTPUT_SIZE
);
232 emptyKeys
->_publicKey
= theirKey
;
233 memcpy(emptyKeys
->_publicKeyHash
, SecPDHKGetHash(theirKey
), CCSHA1_OUTPUT_SIZE
);
235 emptyKeys
->_counter
= 0;
236 emptyKeys
->_theirCounter
= 0;
238 SecOTRDHKGenerateOTRKeys(emptyKeys
->_fullKey
, emptyKeys
->_publicKey
,
239 emptyKeys
->_sendEncryptionKey
, emptyKeys
->_sendMacKey
,
240 emptyKeys
->_receiveEncryptionKey
, emptyKeys
->_receiveMacKey
);
242 cachedKeys
= emptyKeys
;
246 *messageKey
= sending
? cachedKeys
->_sendEncryptionKey
: cachedKeys
->_receiveEncryptionKey
;
248 *macKey
= sending
? cachedKeys
->_sendMacKey
: cachedKeys
->_receiveMacKey
;
250 *counter
= sending
? &cachedKeys
->_counter
: &cachedKeys
->_theirCounter
;
253 SecOTRSessionRef
SecOTRSessionCreateFromData(CFAllocatorRef allocator
, CFDataRef data
)
258 SecOTRSessionRef result
= NULL
;
259 SecOTRSessionRef session
= CFTypeAllocate(SecOTRSession
, struct _SecOTRSession
, allocator
);
261 const uint8_t *bytes
= CFDataGetBytePtr(data
);
262 size_t size
= (size_t)CFDataGetLength(data
);
264 session
->_queue
= dispatch_queue_create("OTRSession", DISPATCH_QUEUE_SERIAL
);
267 session
->_them
= NULL
;
268 session
->_myKey
= NULL
;
269 session
->_myNextKey
= NULL
;
270 session
->_theirKey
= NULL
;
271 session
->_theirPreviousKey
= NULL
;
272 session
->_receivedDHMessage
= NULL
;
273 session
->_receivedDHKeyMessage
= NULL
;
274 bzero(session
->_keyCache
, sizeof(session
->_keyCache
));
277 require_noerr(ReadByte(&bytes
, &size
, &version
), fail
);
278 require(version
<= 3, fail
);
280 require_noerr(ReadLong(&bytes
, &size
, &session
->_state
), fail
);
281 session
->_me
= SecOTRFullIdentityCreateFromBytes(kCFAllocatorDefault
, &bytes
, &size
, NULL
);
282 require(session
->_me
!= NULL
, fail
);
283 session
->_them
= SecOTRPublicIdentityCreateFromBytes(kCFAllocatorDefault
, &bytes
, &size
, NULL
);
284 require(session
->_them
!= NULL
, fail
);
286 require(size
> sizeof(session
->_r
), fail
);
287 memcpy(session
->_r
, bytes
, sizeof(session
->_r
));
288 bytes
+= sizeof(session
->_r
);
289 size
-= sizeof(session
->_r
);
292 uint8_t hasMessage
= false;
293 ReadByte(&bytes
, &size
, &hasMessage
);
295 session
->_receivedDHMessage
= CFDataCreateMutableFromOTRDATA(kCFAllocatorDefault
, &bytes
, &size
);
300 uint8_t hasMessage
= false;
301 ReadByte(&bytes
, &size
, &hasMessage
);
303 session
->_receivedDHKeyMessage
= CFDataCreateMutableFromOTRDATA(kCFAllocatorDefault
, &bytes
, &size
);
309 require_noerr(ReadByte(&bytes
, &size
, &ready
), fail
);
310 if (ready
&& session
->_state
== kIdle
)
311 session
->_state
= kDone
;
314 require_noerr(ReadLong(&bytes
, &size
, &session
->_keyID
), fail
);
315 if (session
->_keyID
> 0) {
316 session
->_myKey
= SecOTRFullDHKCreateFromBytes(kCFAllocatorDefault
, &bytes
, &size
);
317 require(session
->_myKey
!= NULL
, fail
);
318 session
->_myNextKey
= SecOTRFullDHKCreateFromBytes(kCFAllocatorDefault
, &bytes
, &size
);
319 require(session
->_myNextKey
!= NULL
, fail
);
322 require_noerr(ReadLong(&bytes
, &size
, &session
->_theirKeyID
), fail
);
323 if (session
->_theirKeyID
> 0) {
324 if (session
->_theirKeyID
> 1) {
325 session
->_theirPreviousKey
= SecOTRPublicDHKCreateFromSerialization(kCFAllocatorDefault
, &bytes
, &size
);
326 require(session
->_theirPreviousKey
!= NULL
, fail
);
328 session
->_theirKey
= SecOTRPublicDHKCreateFromSerialization(kCFAllocatorDefault
, &bytes
, &size
);
329 require(session
->_theirKey
!= NULL
, fail
);
333 SecOTRSFindKeysForMessage(session
, session
->_myKey
, session
->_theirKey
, false, NULL
, NULL
, &counter
);
334 require_noerr(ReadLongLong(&bytes
, &size
, counter
), fail
);
335 SecOTRSFindKeysForMessage(session
, session
->_myKey
, session
->_theirKey
, true, NULL
, NULL
, &counter
);
336 require_noerr(ReadLongLong(&bytes
, &size
, counter
), fail
);
337 SecOTRSFindKeysForMessage(session
, session
->_myKey
, session
->_theirPreviousKey
, false, NULL
, NULL
, &counter
);
338 require_noerr(ReadLongLong(&bytes
, &size
, counter
), fail
);
339 SecOTRSFindKeysForMessage(session
, session
->_myKey
, session
->_theirPreviousKey
, true, NULL
, NULL
, &counter
);
340 require_noerr(ReadLongLong(&bytes
, &size
, counter
), fail
);
341 SecOTRSFindKeysForMessage(session
, session
->_myNextKey
, session
->_theirKey
, false, NULL
, NULL
, &counter
);
342 require_noerr(ReadLongLong(&bytes
, &size
, counter
), fail
);
343 SecOTRSFindKeysForMessage(session
, session
->_myNextKey
, session
->_theirKey
, true, NULL
, NULL
, &counter
);
344 require_noerr(ReadLongLong(&bytes
, &size
, counter
), fail
);
345 SecOTRSFindKeysForMessage(session
, session
->_myNextKey
, session
->_theirPreviousKey
, false, NULL
, NULL
, &counter
);
346 require_noerr(ReadLongLong(&bytes
, &size
, counter
), fail
);
347 SecOTRSFindKeysForMessage(session
, session
->_myNextKey
, session
->_theirPreviousKey
, true, NULL
, NULL
, &counter
);
348 require_noerr(ReadLongLong(&bytes
, &size
, counter
), fail
);
350 session
->_macKeysToExpose
= CFDataCreateMutableFromOTRDATA(kCFAllocatorDefault
, &bytes
, &size
);
351 require(session
->_macKeysToExpose
!= NULL
, fail
);
354 require_noerr(ReadByte(&bytes
, &size
, &textMode
), fail
);
355 session
->_textOutput
= (textMode
!= 0);
361 CFReleaseNull(session
);
366 OSStatus
SecOTRSAppendSerialization(SecOTRSessionRef session
, CFMutableDataRef serializeInto
)
368 __block OSStatus result
= errSecParam
;
370 require(session
, abort
);
371 require(serializeInto
, abort
);
373 CFIndex start
= CFDataGetLength(serializeInto
);
375 dispatch_sync(session
->_queue
, ^{
376 const uint8_t version
= 3;
378 CFDataAppendBytes(serializeInto
, &version
, sizeof(version
));
380 AppendLong(serializeInto
, session
->_state
);
382 result
= (SecOTRFIAppendSerialization(session
->_me
, serializeInto
, NULL
)) ? errSecSuccess
: errSecParam
;
384 if (result
== errSecSuccess
) {
385 result
= (SecOTRPIAppendSerialization(session
->_them
, serializeInto
, NULL
)) ? errSecSuccess
: errSecParam
;
388 if (result
== errSecSuccess
) {
389 CFDataAppendBytes(serializeInto
, session
->_r
, sizeof(session
->_r
));
391 if (session
->_receivedDHMessage
== NULL
) {
392 AppendByte(serializeInto
, 0);
394 AppendByte(serializeInto
, 1);
395 AppendCFDataAsDATA(serializeInto
, session
->_receivedDHMessage
);
398 if (session
->_receivedDHKeyMessage
== NULL
) {
399 AppendByte(serializeInto
, 0);
401 AppendByte(serializeInto
, 1);
402 AppendCFDataAsDATA(serializeInto
, session
->_receivedDHKeyMessage
);
405 AppendLong(serializeInto
, session
->_keyID
);
406 if (session
->_keyID
> 0) {
407 SecFDHKAppendSerialization(session
->_myKey
, serializeInto
);
408 SecFDHKAppendSerialization(session
->_myNextKey
, serializeInto
);
411 AppendLong(serializeInto
, session
->_theirKeyID
);
412 if (session
->_theirKeyID
> 0) {
413 if (session
->_theirKeyID
> 1) {
414 SecPDHKAppendSerialization(session
->_theirPreviousKey
, serializeInto
);
416 SecPDHKAppendSerialization(session
->_theirKey
, serializeInto
);
420 SecOTRSFindKeysForMessage(session
, session
->_myKey
, session
->_theirKey
, false, NULL
, NULL
, &counter
);
421 AppendLongLong(serializeInto
, *counter
);
422 SecOTRSFindKeysForMessage(session
, session
->_myKey
, session
->_theirKey
, true, NULL
, NULL
, &counter
);
423 AppendLongLong(serializeInto
, *counter
);
424 SecOTRSFindKeysForMessage(session
, session
->_myKey
, session
->_theirPreviousKey
, false, NULL
, NULL
, &counter
);
425 AppendLongLong(serializeInto
, *counter
);
426 SecOTRSFindKeysForMessage(session
, session
->_myKey
, session
->_theirPreviousKey
, true, NULL
, NULL
, &counter
);
427 AppendLongLong(serializeInto
, *counter
);
428 SecOTRSFindKeysForMessage(session
, session
->_myNextKey
, session
->_theirKey
, false, NULL
, NULL
, &counter
);
429 AppendLongLong(serializeInto
, *counter
);
430 SecOTRSFindKeysForMessage(session
, session
->_myNextKey
, session
->_theirKey
, true, NULL
, NULL
, &counter
);
431 AppendLongLong(serializeInto
, *counter
);
432 SecOTRSFindKeysForMessage(session
, session
->_myNextKey
, session
->_theirPreviousKey
, false, NULL
, NULL
, &counter
);
433 AppendLongLong(serializeInto
, *counter
);
434 SecOTRSFindKeysForMessage(session
, session
->_myNextKey
, session
->_theirPreviousKey
, true, NULL
, NULL
, &counter
);
435 AppendLongLong(serializeInto
, *counter
);
437 AppendCFDataAsDATA(serializeInto
, session
->_macKeysToExpose
);
439 AppendByte(serializeInto
, session
->_textOutput
? 1 : 0);
443 if (result
!= errSecSuccess
)
444 CFDataSetLength(serializeInto
, start
);
451 bool SecOTRSGetIsReadyForMessages(SecOTRSessionRef session
)
455 dispatch_sync(session
->_queue
, ^{ result
= session
->_state
== kDone
; });
460 bool SecOTRSGetIsIdle(SecOTRSessionRef session
)
464 dispatch_sync(session
->_queue
, ^{ result
= session
->_state
== kIdle
; });
469 static void SecOTRSExpireCachedKeysForFullKey(SecOTRSessionRef session
, SecOTRFullDHKeyRef myKey
)
471 for(int i
= 0; i
< kOTRKeyCacheSize
; ++i
)
473 if (0 == constant_memcmp(session
->_keyCache
[i
]._fullKeyHash
, SecFDHKGetHash(myKey
), CCSHA1_OUTPUT_SIZE
)) {
474 CFDataAppendBytes(session
->_macKeysToExpose
, session
->_keyCache
[i
]._receiveMacKey
, sizeof(session
->_keyCache
[i
]._receiveMacKey
));
476 bzero(&session
->_keyCache
[i
], sizeof(session
->_keyCache
[i
]));
481 static void SecOTRSExpireCachedKeysForPublicKey(SecOTRSessionRef session
, SecOTRPublicDHKeyRef theirKey
)
483 for(int i
= 0; i
< kOTRKeyCacheSize
; ++i
)
485 if (0 == constant_memcmp(session
->_keyCache
[i
]._publicKeyHash
, SecPDHKGetHash(theirKey
), CCSHA1_OUTPUT_SIZE
)) {
486 CFDataAppendBytes(session
->_macKeysToExpose
, session
->_keyCache
[i
]._receiveMacKey
, sizeof(session
->_keyCache
[i
]._receiveMacKey
));
488 bzero(&session
->_keyCache
[i
], sizeof(session
->_keyCache
[i
]));
493 static void SecOTRSPrecalculateForPair(SecOTRSessionRef session
,
494 SecOTRFullDHKeyRef myKey
,
495 SecOTRPublicDHKeyRef theirKey
)
497 if (myKey
== NULL
|| theirKey
== NULL
)
500 SecOTRSFindKeysForMessage(session
, myKey
, theirKey
, true, NULL
, NULL
, NULL
);
501 SecOTRSFindKeysForMessage(session
, myKey
, theirKey
, false, NULL
, NULL
, NULL
);
504 static void SecOTRSPrecalculateKeysInternal(SecOTRSessionRef session
)
506 SecOTRSPrecalculateForPair(session
, session
->_myKey
, session
->_theirKey
);
507 SecOTRSPrecalculateForPair(session
, session
->_myNextKey
, session
->_theirKey
);
508 SecOTRSPrecalculateForPair(session
, session
->_myKey
, session
->_theirPreviousKey
);
509 SecOTRSPrecalculateForPair(session
, session
->_myNextKey
, session
->_theirPreviousKey
);
512 void SecOTRSPrecalculateKeys(SecOTRSessionRef session
)
514 dispatch_sync_f(session
->_queue
, session
, (dispatch_function_t
) SecOTRSPrecalculateKeysInternal
);
517 enum SecOTRSMessageKind
SecOTRSGetMessageKind(SecOTRSessionRef session
, CFDataRef message
)
519 enum SecOTRSMessageKind kind
= kOTRUnknownPacket
;
521 CFMutableDataRef decodedBytes
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
522 SecOTRGetIncomingBytes(message
, decodedBytes
);
524 const uint8_t *bytes
= CFDataGetBytePtr(decodedBytes
);
525 size_t size
= CFDataGetLength(decodedBytes
);
528 require_noerr(ReadHeader(&bytes
, &size
, &type
), fail
);
530 kind
= (type
== kDataMessage
) ? kOTRDataPacket
: kOTRNegotiationPacket
;
533 CFReleaseNull(decodedBytes
);
538 OSStatus
SecOTRSSignAndProtectMessage(SecOTRSessionRef session
,
539 CFDataRef sourceMessage
,
540 CFMutableDataRef protectedMessage
)
542 __block OSStatus result
= errSecParam
;
544 require(session
, abort
);
545 require(sourceMessage
, abort
);
546 require(protectedMessage
, abort
);
548 dispatch_sync(session
->_queue
, ^{
549 if (session
->_myKey
== NULL
||
550 session
->_theirKey
== NULL
) {
554 CFMutableDataRef destinationMessage
;
555 if (session
->_textOutput
) {
556 destinationMessage
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
558 destinationMessage
= protectedMessage
;
565 CFIndex start
= CFDataGetLength(destinationMessage
);
567 SecOTRSFindKeysForMessage(session
, session
->_myKey
, session
->_theirKey
,
569 &messageKey
, &macKey
, &counter
);
571 AppendHeader(destinationMessage
, kDataMessage
);
572 AppendByte(destinationMessage
, 0); // Flags, all zero
574 AppendLong(destinationMessage
, session
->_keyID
);
575 AppendLong(destinationMessage
, session
->_theirKeyID
);
576 SecFDHKAppendPublicSerialization(session
->_myNextKey
, destinationMessage
);
577 AppendLongLong(destinationMessage
, ++*counter
);
579 CFIndex sourceSize
= CFDataGetLength(sourceMessage
);
580 assert(((unsigned long)sourceSize
)<=UINT32_MAX
); /* this is correct as long as CFIndex is a signed long */
581 AppendLong(destinationMessage
, (uint32_t)sourceSize
);
582 uint8_t* encryptedDataPointer
= CFDataIncreaseLengthAndGetMutableBytes(destinationMessage
, sourceSize
);
583 AES_CTR_HighHalf_Transform(kOTRMessageKeyBytes
, messageKey
,
585 (size_t)sourceSize
, CFDataGetBytePtr(sourceMessage
),
586 encryptedDataPointer
);
588 CFIndex macedContentsSize
= CFDataGetLength(destinationMessage
) - start
;
589 CFIndex macSize
= CCSHA1_OUTPUT_SIZE
;
590 uint8_t* macDataPointer
= CFDataIncreaseLengthAndGetMutableBytes(destinationMessage
, macSize
);
592 #ifdef USECOMMONCRYPTO
593 CCHmac(kCCHmacAlgSHA1
,
594 macKey
, kOTRMessageMacKeyBytes
,
595 CFDataGetBytePtr(destinationMessage
) + start
, (size_t)macedContentsSize
,
599 kOTRMessageMacKeyBytes
, macKey
,
600 macedContentsSize
, CFDataGetBytePtr(destinationMessage
) + start
,
604 CFDataAppend(destinationMessage
, session
->_macKeysToExpose
);
606 CFDataSetLength(session
->_macKeysToExpose
, 0);
608 if (session
->_textOutput
) {
609 SecOTRPrepareOutgoingBytes(destinationMessage
, protectedMessage
);
610 CFReleaseSafe(destinationMessage
);
613 result
= errSecSuccess
;
620 OSStatus
SecOTRSVerifyAndExposeMessage(SecOTRSessionRef session
,
621 CFDataRef incomingMessage
,
622 CFMutableDataRef exposedMessageContents
)
624 __block SecOTRPublicDHKeyRef newKey
= NULL
;
625 __block OSStatus result
= errSecParam
;
628 require(session
, abort
);
629 require(incomingMessage
, abort
);
630 require(exposedMessageContents
, abort
);
632 dispatch_sync(session
->_queue
, ^{
633 const uint8_t* bytes
;
635 CFMutableDataRef decodedBytes
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
636 SecOTRGetIncomingBytes(incomingMessage
, decodedBytes
);
638 bytes
= CFDataGetBytePtr(decodedBytes
);
639 size
= CFDataGetLength(decodedBytes
);
641 const uint8_t* macDataStart
= bytes
;
646 if ((result
= ReadAndVerifyHeader(&bytes
, &size
, kDataMessage
))){
647 CFReleaseSafe(decodedBytes
);
651 if (size
<= 0) { result
= errSecDecode
; CFReleaseSafe(decodedBytes
); return; }
653 if ((result
= ReadAndVerifyByte(&bytes
, &size
, 0))) { CFReleaseSafe(decodedBytes
); return;} // No flags
655 if ((result
= ReadLong(&bytes
, &size
, &theirID
))){ CFReleaseSafe(decodedBytes
); return; }
657 if (theirID
!= session
->_theirKeyID
&&
658 (session
->_theirPreviousKey
== NULL
|| theirID
!= (session
->_theirKeyID
- 1)))
660 result
= ((theirID
+ 1) < session
->_theirKeyID
) ? errSecOTRTooOld
: errSecOTRIDTooNew
;
661 CFReleaseSafe(decodedBytes
);
665 if ((result
= ReadLong(&bytes
, &size
, &myID
))){ CFReleaseSafe(decodedBytes
); return; }
666 if (myID
!= session
->_keyID
&& myID
!= (session
->_keyID
+ 1))
668 result
= (myID
< session
->_keyID
) ? errSecOTRTooOld
: errSecOTRIDTooNew
;
669 CFReleaseSafe(decodedBytes
);
674 // Choose appripriate keys for message:
678 uint64_t *theirCounter
;
680 SecOTRFullDHKeyRef myKeyForMessage
= (myID
== session
->_keyID
) ? session
->_myKey
: session
->_myNextKey
;
681 SecOTRPublicDHKeyRef theirKeyForMessage
= (theirID
== session
->_theirKeyID
) ? session
->_theirKey
: session
->_theirPreviousKey
;
683 SecOTRSFindKeysForMessage(session
, myKeyForMessage
, theirKeyForMessage
, false,
684 &messageKey
, &macKey
, &theirCounter
);
686 size_t nextKeyMPISize
;
687 const uint8_t* nextKeyMPIBytes
;
688 if ((result
= SizeAndSkipMPI(&bytes
, &size
, &nextKeyMPIBytes
, &nextKeyMPISize
))){ CFReleaseSafe(decodedBytes
); return;}
691 if ((result
= ReadLongLong(&bytes
, &size
, &counter
))) { CFReleaseSafe(decodedBytes
); return; }
693 if (counter
<= *theirCounter
) { result
= errSecOTRTooOld
; CFReleaseSafe(decodedBytes
); return; };
696 const uint8_t* messageStart
;
697 if ((result
= SizeAndSkipDATA(&bytes
, &size
, &messageStart
, &messageSize
))) { CFReleaseSafe(decodedBytes
); return; }
699 size_t macDataSize
= (bytes
- macDataStart
) ? (size_t)(bytes
- macDataStart
) : 0;
700 uint8_t mac
[CCSHA1_OUTPUT_SIZE
];
701 if (sizeof(mac
) > size
) { result
= errSecDecode
; CFReleaseSafe(decodedBytes
); return; }
703 #ifdef USECOMMONCRYPTO
704 CCHmac(kCCHmacAlgSHA1
,
705 macKey
, kOTRMessageMacKeyBytes
,
706 macDataStart
, macDataSize
,
710 kOTRMessageMacKeyBytes
, macKey
,
711 macDataSize
, macDataStart
,
715 if (0 != constant_memcmp(mac
, bytes
, sizeof(mac
))) { result
= errSecAuthFailed
; CFReleaseSafe(decodedBytes
); return; }
716 //if (messageSize > 65535) { result = errSecDataTooLarge; CFReleaseSafe(decodedBytes); return; }
717 uint8_t* dataSpace
= CFDataIncreaseLengthAndGetMutableBytes(exposedMessageContents
, (CFIndex
)messageSize
);
720 AES_CTR_HighHalf_Transform(kOTRMessageKeyBytes
, messageKey
,
722 messageSize
, messageStart
,
725 // Everything is good, accept the meta data.
726 *theirCounter
= counter
;
728 newKey
= SecOTRPublicDHKCreateFromBytes(kCFAllocatorDefault
, &nextKeyMPIBytes
, &nextKeyMPISize
);
731 SecOTRSPrecalculateKeysInternal(session
);
733 bool acceptTheirNewKey
= newKey
!= NULL
&& theirID
== session
->_theirKeyID
;
735 if (acceptTheirNewKey
) {
736 if (session
->_theirPreviousKey
) {
737 SecOTRSExpireCachedKeysForPublicKey(session
, session
->_theirPreviousKey
);
740 CFReleaseNull(session
->_theirPreviousKey
);
741 session
->_theirPreviousKey
= session
->_theirKey
;
742 session
->_theirKey
= newKey
;
744 session
->_theirKeyID
+= 1;
749 if (myID
== (session
->_keyID
+ 1)) {
750 SecOTRSExpireCachedKeysForFullKey(session
, session
->_myKey
);
752 // Swap the keys so we know the current key.
754 SecOTRFullDHKeyRef oldKey
= session
->_myKey
;
755 session
->_myKey
= session
->_myNextKey
;
756 session
->_myNextKey
= oldKey
;
759 // Derive a new next key by regenerating over the old key.
760 SecFDHKNewKey(session
->_myNextKey
);
762 session
->_keyID
= myID
;
764 CFReleaseSafe(decodedBytes
);
768 CFReleaseNull(newKey
);
773 OSStatus
SecOTRSEndSession(SecOTRSessionRef session
,
774 CFMutableDataRef messageToSend
)
776 return errSecUnimplemented
;