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