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