]> git.saurik.com Git - apple/security.git/blob - OSX/sec/Security/SecOTRSession.c
Security-57336.1.9.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 SecOTRSessionRef SecOTRSessionCreateFromID(CFAllocatorRef allocator,
318 SecOTRFullIdentityRef myID,
319 SecOTRPublicIdentityRef theirID)
320 {
321 SecOTRSessionRef newID = CFTypeAllocate(SecOTRSession, struct _SecOTRSession, allocator);
322
323 (void)SecOTRGetDefaultsWriteSeconds();
324 newID->_queue = dispatch_queue_create("OTRSession", DISPATCH_QUEUE_SERIAL);
325
326 newID->_me = myID;
327 newID->_them = theirID;
328 newID->_receivedDHMessage = NULL;
329 newID->_receivedDHKeyMessage = NULL;
330 newID->_myKey = NULL;
331 newID->_myNextKey = NULL;
332 newID->_theirKey = NULL;
333 newID->_theirPreviousKey = NULL;
334 newID->_macKeysToExpose = NULL;
335 newID->_textOutput = false;
336 newID->_compactAppleMessages = false;
337 newID->_includeHashes = false;
338
339 newID->_timeToRoll = 0;
340 newID->_stallingTheirRoll = false;
341 newID->_stallSeconds = 0;
342 newID->_missedAck = true;
343 newID->_receivedAck = false;
344
345 SecOTRSessionResetInternal(newID);
346
347 CFRetain(newID->_me);
348 CFRetain(newID->_them);
349
350 return newID;
351 }
352
353 SecOTRSessionRef SecOTRSessionCreateFromIDAndFlags(CFAllocatorRef allocator,
354 SecOTRFullIdentityRef myID,
355 SecOTRPublicIdentityRef theirID,
356 uint32_t flags)
357 {
358
359 uint64_t seconds = SecOTRGetDefaultsWriteSeconds();
360
361 SecOTRSessionRef newID = SecOTRSessionCreateFromID(allocator, myID, theirID);
362 if (flags & kSecOTRSendTextMessages) {
363 newID->_textOutput = true;
364 }
365 if (flags & kSecOTRUseAppleCustomMessageFormat) {
366 newID->_compactAppleMessages = true;
367 }
368 if(flags & kSecOTRIncludeHashesInMessages)
369 {
370 newID->_includeHashes = true;
371 }
372 if(flags & kSecOTRSlowRoll)
373 {
374 newID->_stallSeconds = seconds;
375 }
376
377 return newID;
378 }
379
380 static uint64_t constant_zero = 0;
381
382 static bool hashIsZero(uint8_t hash[CCSHA1_OUTPUT_SIZE])
383 {
384 bool isZero = true;
385 for(size_t byte = 0; isZero && byte < CCSHA1_OUTPUT_SIZE; ++byte)
386 isZero = (0 == hash[byte]);
387
388 return isZero;
389 }
390
391 static bool SOSOTRSCacheEntryIsEmpty(SecOTRCacheElement *element)
392 {
393 return hashIsZero(element->_fullKeyHash) && hashIsZero(element->_publicKeyHash);
394 }
395
396 #if DEBUG
397
398 static void WithCacheDescription(SecOTRSessionRef session, void (^operation)(CFStringRef cacheDescription)) {
399 CFStringRef description = NULL;
400
401 CFStringRef keyCache0Description = SecOTRCacheElementCopyDescription(&session->_keyCache[0]);
402 CFStringRef keyCache1Description = SecOTRCacheElementCopyDescription(&session->_keyCache[1]);
403 CFStringRef keyCache2Description = SecOTRCacheElementCopyDescription(&session->_keyCache[2]);
404 CFStringRef keyCache3Description = SecOTRCacheElementCopyDescription(&session->_keyCache[3]);
405
406 description = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("{%@, %@, %@, %@}"), keyCache0Description, keyCache1Description, keyCache2Description, keyCache3Description);
407
408 operation(description);
409
410 CFReleaseNull(keyCache0Description);
411 CFReleaseNull(keyCache1Description);
412 CFReleaseNull(keyCache2Description);
413 CFReleaseNull(keyCache3Description);
414 CFReleaseNull(description);
415 }
416
417 #endif
418
419 static void SecOTRSFindKeysForMessage(SecOTRSessionRef session,
420 SecOTRFullDHKeyRef myKey,
421 SecOTRPublicDHKeyRef theirKey,
422 bool sending,
423 uint8_t** messageKey, uint8_t** macKey, uint64_t **counter)
424 {
425 SecOTRCacheElement* emptyKeys = NULL;
426 SecOTRCacheElement* cachedKeys = NULL;
427 #if DEBUG
428 int emptyPosition = kOTRKeyCacheSize;
429 #endif
430
431 if ((NULL == myKey) || (NULL == theirKey)) {
432 if (messageKey)
433 *messageKey = NULL;
434 if (macKey)
435 *macKey = NULL;
436 if (counter)
437 *counter = &constant_zero;
438
439 return;
440 }
441
442 for(int i = 0; i < kOTRKeyCacheSize; ++i)
443 {
444 if (0 == constant_memcmp(session->_keyCache[i]._fullKeyHash, SecFDHKGetHash(myKey), CCSHA1_OUTPUT_SIZE)
445 && (0 == constant_memcmp(session->_keyCache[i]._publicKeyHash, SecPDHKGetHash(theirKey), CCSHA1_OUTPUT_SIZE))) {
446 cachedKeys = &session->_keyCache[i];
447 #if DEBUG
448 secdebug("OTR","session@[%p] found key match: mk: %@, tk: %@", session, myKey, theirKey);
449 #endif
450 break;
451 }
452
453 if (emptyKeys == NULL && SOSOTRSCacheEntryIsEmpty(&(session->_keyCache[i]))) {
454 #if DEBUG
455 emptyPosition = i;
456 #endif
457
458 emptyKeys = &session->_keyCache[i];
459 }
460 }
461
462 if (cachedKeys == NULL) {
463 if (emptyKeys == NULL) {
464 #if DEBUG
465 WithCacheDescription(session, ^(CFStringRef cacheDescription) {
466 secdebug("OTR","session@[%p] Cache miss, spooky for mk: %@, tk: %@ cache: %@", session, myKey, theirKey, cacheDescription);
467 });
468 emptyPosition = 0;
469 #endif
470
471 emptyKeys = &session->_keyCache[0];
472
473 }
474
475 // Fill in the entry.
476 memcpy(emptyKeys->_fullKeyHash, SecFDHKGetHash(myKey), CCSHA1_OUTPUT_SIZE);
477 memcpy(emptyKeys->_publicKeyHash, SecPDHKGetHash(theirKey), CCSHA1_OUTPUT_SIZE);
478
479 emptyKeys->_counter = 0;
480 emptyKeys->_theirCounter = 0;
481
482 SecOTRDHKGenerateOTRKeys(myKey, theirKey,
483 emptyKeys->_sendEncryptionKey, emptyKeys->_sendMacKey,
484 emptyKeys->_receiveEncryptionKey, emptyKeys->_receiveMacKey);
485
486 cachedKeys = emptyKeys;
487 #if DEBUG
488 WithCacheDescription(session, ^(CFStringRef cacheDescription) {
489 secdebug("OTR","mk %@, th: %@ session@[%p] new key cache state added key@[%d]: %@", myKey, theirKey, session, emptyPosition, cacheDescription);
490 });
491 #endif
492
493 }
494
495 if (messageKey)
496 *messageKey = sending ? cachedKeys->_sendEncryptionKey : cachedKeys->_receiveEncryptionKey;
497 if (macKey)
498 *macKey = sending ? cachedKeys->_sendMacKey : cachedKeys->_receiveMacKey;
499 if (counter)
500 *counter = sending ? &cachedKeys->_counter : &cachedKeys->_theirCounter;
501 }
502
503 SecOTRSessionRef SecOTRSessionCreateFromData(CFAllocatorRef allocator, CFDataRef data)
504 {
505 if (data == NULL)
506 return NULL;
507
508 SecOTRSessionRef result = NULL;
509 SecOTRSessionRef session = CFTypeAllocate(SecOTRSession, struct _SecOTRSession, allocator);
510
511 uint8_t numberOfKeys;
512 uint64_t timeToRoll;
513
514 const uint8_t *bytes = CFDataGetBytePtr(data);
515 size_t size = (size_t)CFDataGetLength(data);
516
517 (void)SecOTRGetDefaultsWriteSeconds();
518
519 session->_queue = dispatch_queue_create("OTRSession", DISPATCH_QUEUE_SERIAL);
520
521 session->_me = NULL;
522 session->_them = NULL;
523 session->_myKey = NULL;
524 session->_myNextKey = NULL;
525 session->_theirKey = NULL;
526 session->_theirPreviousKey = NULL;
527 session->_receivedDHMessage = NULL;
528 session->_receivedDHKeyMessage = NULL;
529 session->_textOutput = false;
530 session->_compactAppleMessages = false;
531 session->_timeToRoll = 0;
532 session->_stallingTheirRoll = false;
533 session->_stallSeconds = 0;
534 session->_missedAck = true;
535 session->_receivedAck = false;
536
537 bzero(session->_keyCache, sizeof(session->_keyCache));
538
539 uint8_t version;
540 require_noerr(ReadByte(&bytes, &size, &version), fail);
541 require(version <= 6, fail);
542
543 require_noerr(ReadLong(&bytes, &size, &session->_state), fail);
544 session->_me = SecOTRFullIdentityCreateFromBytes(kCFAllocatorDefault, &bytes, &size, NULL);
545 require(session->_me != NULL, fail);
546 session->_them = SecOTRPublicIdentityCreateFromBytes(kCFAllocatorDefault, &bytes, &size, NULL);
547 require(session->_them != NULL, fail);
548
549 require(size > sizeof(session->_r), fail);
550 memcpy(session->_r, bytes, sizeof(session->_r));
551 bytes += sizeof(session->_r);
552 size -= sizeof(session->_r);
553
554 {
555 uint8_t hasMessage = false;
556 ReadByte(&bytes, &size, &hasMessage);
557 if (hasMessage) {
558 session->_receivedDHMessage = CFDataCreateMutableFromOTRDATA(kCFAllocatorDefault, &bytes, &size);
559 }
560 }
561
562 if (version >= 2) {
563 uint8_t hasMessage = false;
564 ReadByte(&bytes, &size, &hasMessage);
565 if (hasMessage) {
566 session->_receivedDHKeyMessage = CFDataCreateMutableFromOTRDATA(kCFAllocatorDefault, &bytes, &size);
567 }
568 }
569
570 if (version < 3) {
571 uint8_t ready;
572 require_noerr(ReadByte(&bytes, &size, &ready), fail);
573 if (ready && session->_state == kIdle)
574 session->_state = kDone;
575 }
576
577
578 require_noerr(ReadLong(&bytes, &size, &session->_keyID), fail);
579 if (session->_keyID > 0) {
580 session->_myKey = SecOTRFullDHKCreateFromBytes(kCFAllocatorDefault, &bytes, &size);
581 require(session->_myKey != NULL, fail);
582 session->_myNextKey = SecOTRFullDHKCreateFromBytes(kCFAllocatorDefault, &bytes, &size);
583 require(session->_myNextKey != NULL, fail);
584 }
585
586
587 require_noerr(ReadByte(&bytes, &size, &numberOfKeys), fail);
588
589 require_noerr(ReadLong(&bytes, &size, &session->_theirKeyID), fail);
590 if (version < 5) {
591 if (session->_theirKeyID > 0) {
592 if (session->_theirKeyID > 1) {
593 session->_theirPreviousKey = SecOTRPublicDHKCreateFromSerialization(kCFAllocatorDefault, &bytes, &size);
594 require(session->_theirPreviousKey != NULL, fail);
595 }
596 session->_theirKey = SecOTRPublicDHKCreateFromSerialization(kCFAllocatorDefault, &bytes, &size);
597 require(session->_theirKey != NULL, fail);
598 }
599 }
600 else {
601 if(numberOfKeys >= 1){
602 if (numberOfKeys >= 2) {
603 session->_theirPreviousKey = SecOTRPublicDHKCreateFromSerialization(kCFAllocatorDefault, &bytes, &size);
604 require(session->_theirPreviousKey != NULL, fail);
605 }
606 session->_theirKey = SecOTRPublicDHKCreateFromSerialization(kCFAllocatorDefault, &bytes, &size);
607 require(session->_theirKey != NULL, fail);
608 }
609 }
610
611
612 uint64_t *counter;
613 SecOTRSFindKeysForMessage(session, session->_myKey, session->_theirKey, false, NULL, NULL, &counter);
614 require_noerr(ReadLongLong(&bytes, &size, counter), fail);
615 SecOTRSFindKeysForMessage(session, session->_myKey, session->_theirKey, true, NULL, NULL, &counter);
616 require_noerr(ReadLongLong(&bytes, &size, counter), fail);
617 SecOTRSFindKeysForMessage(session, session->_myKey, session->_theirPreviousKey, false, NULL, NULL, &counter);
618 require_noerr(ReadLongLong(&bytes, &size, counter), fail);
619 SecOTRSFindKeysForMessage(session, session->_myKey, session->_theirPreviousKey, true, NULL, NULL, &counter);
620 require_noerr(ReadLongLong(&bytes, &size, counter), fail);
621 SecOTRSFindKeysForMessage(session, session->_myNextKey, session->_theirKey, false, NULL, NULL, &counter);
622 require_noerr(ReadLongLong(&bytes, &size, counter), fail);
623 SecOTRSFindKeysForMessage(session, session->_myNextKey, session->_theirKey, true, NULL, NULL, &counter);
624 require_noerr(ReadLongLong(&bytes, &size, counter), fail);
625 SecOTRSFindKeysForMessage(session, session->_myNextKey, session->_theirPreviousKey, false, NULL, NULL, &counter);
626 require_noerr(ReadLongLong(&bytes, &size, counter), fail);
627 SecOTRSFindKeysForMessage(session, session->_myNextKey, session->_theirPreviousKey, true, NULL, NULL, &counter);
628 require_noerr(ReadLongLong(&bytes, &size, counter), fail);
629
630 session->_macKeysToExpose = CFDataCreateMutableFromOTRDATA(kCFAllocatorDefault, &bytes, &size);
631 require(session->_macKeysToExpose != NULL, fail);
632
633 require_noerr(ReadByteAsBool(&bytes, &size, &session->_textOutput), fail);
634
635 if (version >= 4) {
636 require_noerr(ReadByteAsBool(&bytes, &size, &session->_compactAppleMessages), fail);
637 }
638 if (version >= 5) {
639 require_noerr(ReadByteAsBool(&bytes, &size, &session->_includeHashes), fail);
640 }
641 if (version >= 6) {
642 require_noerr(ReadLongLong(&bytes, &size, &session->_stallSeconds), fail);
643 require_noerr(ReadByteAsBool(&bytes, &size, &session->_stallingTheirRoll), fail);
644 require_noerr(ReadLongLong(&bytes, &size, &timeToRoll), fail);
645 require_noerr(ReadByteAsBool(&bytes, &size, &session->_missedAck), fail);
646 require_noerr(ReadByteAsBool(&bytes, &size, &session->_receivedAck), fail);
647 session->_timeToRoll = timeToRoll;
648 }
649 result = session;
650 session = NULL;
651
652 fail:
653 CFReleaseNull(session);
654 return result;
655 }
656
657
658 OSStatus SecOTRSAppendSerialization(SecOTRSessionRef session, CFMutableDataRef serializeInto)
659 {
660 __block OSStatus result = errSecParam;
661
662 require(session, abort);
663 require(serializeInto, abort);
664
665 CFIndex start = CFDataGetLength(serializeInto);
666
667 dispatch_sync(session->_queue, ^{
668 const uint8_t version = 6;
669 uint8_t numberOfKeys = 0;
670 CFDataAppendBytes(serializeInto, &version, sizeof(version));
671
672 AppendLong(serializeInto, session->_state);
673
674 result = (SecOTRFIAppendSerialization(session->_me, serializeInto, NULL)) ? errSecSuccess : errSecParam;
675
676 if (result == errSecSuccess) {
677 result = (SecOTRPIAppendSerialization(session->_them, serializeInto, NULL)) ? errSecSuccess : errSecParam;
678 }
679
680 if (result == errSecSuccess) {
681 CFDataAppendBytes(serializeInto, session->_r, sizeof(session->_r));
682
683 if (session->_receivedDHMessage == NULL) {
684 AppendByte(serializeInto, 0);
685 } else {
686 AppendByte(serializeInto, 1);
687 AppendCFDataAsDATA(serializeInto, session->_receivedDHMessage);
688 }
689
690 if (session->_receivedDHKeyMessage == NULL) {
691 AppendByte(serializeInto, 0);
692 } else {
693 AppendByte(serializeInto, 1);
694 AppendCFDataAsDATA(serializeInto, session->_receivedDHKeyMessage);
695 }
696
697 AppendLong(serializeInto, session->_keyID);
698 if (session->_keyID > 0) {
699 SecFDHKAppendSerialization(session->_myKey, serializeInto);
700 SecFDHKAppendSerialization(session->_myNextKey, serializeInto);
701 }
702
703 if(session->_theirPreviousKey != NULL)
704 numberOfKeys++;
705 if(session->_theirKey != NULL)
706 numberOfKeys++;
707
708 AppendByte(serializeInto, numberOfKeys);
709
710 AppendLong(serializeInto, session->_theirKeyID);
711
712 if (session->_theirPreviousKey != NULL)
713 SecPDHKAppendSerialization(session->_theirPreviousKey, serializeInto);
714
715 if (session->_theirKey != NULL )
716 SecPDHKAppendSerialization(session->_theirKey, serializeInto);
717
718
719 uint64_t *counter;
720 SecOTRSFindKeysForMessage(session, session->_myKey, session->_theirKey, false, NULL, NULL, &counter);
721 AppendLongLong(serializeInto, *counter);
722 SecOTRSFindKeysForMessage(session, session->_myKey, session->_theirKey, true, NULL, NULL, &counter);
723 AppendLongLong(serializeInto, *counter);
724 SecOTRSFindKeysForMessage(session, session->_myKey, session->_theirPreviousKey, false, NULL, NULL, &counter);
725 AppendLongLong(serializeInto, *counter);
726 SecOTRSFindKeysForMessage(session, session->_myKey, session->_theirPreviousKey, true, NULL, NULL, &counter);
727 AppendLongLong(serializeInto, *counter);
728 SecOTRSFindKeysForMessage(session, session->_myNextKey, session->_theirKey, false, NULL, NULL, &counter);
729 AppendLongLong(serializeInto, *counter);
730 SecOTRSFindKeysForMessage(session, session->_myNextKey, session->_theirKey, true, NULL, NULL, &counter);
731 AppendLongLong(serializeInto, *counter);
732 SecOTRSFindKeysForMessage(session, session->_myNextKey, session->_theirPreviousKey, false, NULL, NULL, &counter);
733 AppendLongLong(serializeInto, *counter);
734 SecOTRSFindKeysForMessage(session, session->_myNextKey, session->_theirPreviousKey, true, NULL, NULL, &counter);
735 AppendLongLong(serializeInto, *counter);
736
737 AppendCFDataAsDATA(serializeInto, session->_macKeysToExpose);
738
739 AppendByte(serializeInto, session->_textOutput ? 1 : 0);
740 AppendByte(serializeInto, session->_compactAppleMessages ? 1 : 0);
741 AppendByte(serializeInto, session->_includeHashes ? 1 : 0);
742
743 AppendLongLong(serializeInto, session->_stallSeconds ? session->_stallSeconds : constant_zero);
744
745 AppendByte(serializeInto, session->_stallingTheirRoll ? 1 : 0);
746 AppendLongLong(serializeInto, (uint64_t)session->_timeToRoll);
747 AppendByte(serializeInto, session->_missedAck ? 1 : 0);
748 AppendByte(serializeInto, session->_receivedAck ? 1 : 0);
749
750 }
751 });
752
753 if (result != errSecSuccess)
754 CFDataSetLength(serializeInto, start);
755
756 abort:
757 return result;
758 }
759
760
761 bool SecOTRSGetIsReadyForMessages(SecOTRSessionRef session)
762 {
763 __block bool result;
764
765 dispatch_sync(session->_queue, ^{ result = session->_state == kDone; });
766
767 return result;
768 }
769
770 bool SecOTRSGetIsIdle(SecOTRSessionRef session)
771 {
772 __block bool result;
773
774 dispatch_sync(session->_queue, ^{ result = session->_state == kIdle; });
775
776 return result;
777 }
778
779 static void SecOTRSPrecalculateForPair(SecOTRSessionRef session,
780 SecOTRFullDHKeyRef myKey,
781 SecOTRPublicDHKeyRef theirKey)
782 {
783 if (myKey == NULL || theirKey == NULL)
784 return;
785
786 SecOTRSFindKeysForMessage(session, myKey, theirKey, true, NULL, NULL, NULL);
787 SecOTRSFindKeysForMessage(session, myKey, theirKey, false, NULL, NULL, NULL);
788 }
789
790 static void SecOTRSPrecalculateKeysInternal(SecOTRSessionRef session)
791 {
792 SecOTRSPrecalculateForPair(session, session->_myKey, session->_theirKey);
793 SecOTRSPrecalculateForPair(session, session->_myNextKey, session->_theirKey);
794 SecOTRSPrecalculateForPair(session, session->_myKey, session->_theirPreviousKey);
795 SecOTRSPrecalculateForPair(session, session->_myNextKey, session->_theirPreviousKey);
796 }
797
798 static void SecOTRSPrecalculateNextKeysInternal(SecOTRSessionRef session)
799 {
800 SecOTRSPrecalculateForPair(session, session->_myKey, session->_theirKey);
801 }
802
803 void SecOTRSPrecalculateKeys(SecOTRSessionRef session)
804 {
805 dispatch_sync_f(session->_queue, session, (dispatch_function_t) SecOTRSPrecalculateKeysInternal);
806 }
807
808 enum SecOTRSMessageKind SecOTRSGetMessageKind(SecOTRSessionRef session, CFDataRef message)
809 {
810 OTRMessageType type = SecOTRSGetMessageType(message);
811
812 enum SecOTRSMessageKind kind;
813
814 switch (type) {
815 case kDataMessage:
816 case kEvenCompactDataMessage:
817 case kOddCompactDataMessage:
818 case kEvenCompactDataMessageWithHashes:
819 case kOddCompactDataMessageWithHashes:
820 kind = kOTRDataPacket;
821 break;
822 case kDHMessage:
823 case kDHKeyMessage:
824 case kRevealSignatureMessage:
825 case kSignatureMessage:
826 kind = kOTRNegotiationPacket;
827 break;
828 case kInvalidMessage:
829 default:
830 kind = kOTRUnknownPacket;
831 break;
832 }
833
834 return kind;
835 }
836
837 static OSStatus SecOTRSSignAndProtectRaw_locked(SecOTRSessionRef session,
838 CFDataRef sourceMessage, CFMutableDataRef destinationMessage,
839 uint8_t* messageKey, uint8_t* macKey, uint64_t* counter, uint32_t theirKeyID, SecOTRPublicDHKeyRef theirKey)
840 {
841 CFIndex start = CFDataGetLength(destinationMessage);
842
843 AppendHeader(destinationMessage, kDataMessage);
844 AppendByte(destinationMessage, 0); // Flags, all zero
845
846 AppendLong(destinationMessage, session->_keyID);
847 AppendLong(destinationMessage, theirKeyID);
848 SecFDHKAppendPublicSerialization(session->_myNextKey, destinationMessage);
849 AppendLongLong(destinationMessage, ++*counter);
850
851 CFIndex sourceSize = CFDataGetLength(sourceMessage);
852 assert(((unsigned long)sourceSize)<=UINT32_MAX); /* this is correct as long as CFIndex is a signed long */
853 AppendLong(destinationMessage, (uint32_t)sourceSize);
854 uint8_t* encryptedDataPointer = CFDataIncreaseLengthAndGetMutableBytes(destinationMessage, sourceSize);
855 AES_CTR_HighHalf_Transform(kOTRMessageKeyBytes, messageKey,
856 *counter,
857 (size_t)sourceSize, CFDataGetBytePtr(sourceMessage),
858 encryptedDataPointer);
859
860 CFIndex macedContentsSize = CFDataGetLength(destinationMessage) - start;
861 CFIndex macSize = CCSHA1_OUTPUT_SIZE;
862 uint8_t* macDataPointer = CFDataIncreaseLengthAndGetMutableBytes(destinationMessage, macSize);
863
864 cchmac(ccsha1_di(),
865 kOTRMessageMacKeyBytes, macKey,
866 macedContentsSize, CFDataGetBytePtr(destinationMessage) + start,
867 macDataPointer);
868
869 CFDataAppend(destinationMessage, session->_macKeysToExpose);
870
871 return errSecSuccess;
872 }
873
874 const size_t kCompactMessageMACSize = 16;
875
876 static OSStatus SecOTRSSignAndProtectCompact_locked(SecOTRSessionRef session,
877 CFDataRef sourceMessage, CFMutableDataRef destinationMessage,
878 uint8_t* messageKey, uint8_t* macKey, uint64_t* counter, uint32_t theirKeyID, SecOTRPublicDHKeyRef theirKey)
879 {
880 CFIndex start = CFDataGetLength(destinationMessage);
881 bool sendHashes = session->_includeHashes;
882
883 const uint8_t messageType = sendHashes ? ((theirKeyID & 0x1) ? kOddCompactDataMessageWithHashes : kEvenCompactDataMessageWithHashes)
884 : ((theirKeyID & 0x1) ? kOddCompactDataMessage : kEvenCompactDataMessage);
885
886 AppendByte(destinationMessage, messageType);
887
888 SecFDHKAppendCompactPublicSerialization(session->_myNextKey, destinationMessage);
889 AppendLongLongCompact(destinationMessage, ++*counter);
890
891 CFIndex sourceSize = CFDataGetLength(sourceMessage);
892 assert(((unsigned long)sourceSize)<=UINT32_MAX); /* this is correct as long as CFIndex is a signed long */
893 uint8_t* encryptedDataPointer = CFDataIncreaseLengthAndGetMutableBytes(destinationMessage, sourceSize);
894 AES_CTR_HighHalf_Transform(kOTRMessageKeyBytes, messageKey,
895 *counter,
896 (size_t)sourceSize, CFDataGetBytePtr(sourceMessage),
897 encryptedDataPointer);
898
899 if (sendHashes) {
900 uint8_t *senderHashPtr = CFDataIncreaseLengthAndGetMutableBytes(destinationMessage, kSecDHKHashSize);
901
902 memcpy(senderHashPtr, SecFDHKGetHash(session->_myKey), kSecDHKHashSize);
903
904 uint8_t *receiverHashPtr = CFDataIncreaseLengthAndGetMutableBytes(destinationMessage, kSecDHKHashSize);
905
906 memcpy(receiverHashPtr, SecPDHKGetHash(theirKey), kSecDHKHashSize);
907 }
908
909
910 CFIndex macedContentsSize = CFDataGetLength(destinationMessage) - start;
911 CFIndex macSize = CCSHA1_OUTPUT_SIZE;
912 uint8_t mac[macSize];
913 cchmac(ccsha1_di(),
914 kOTRMessageMacKeyBytes, macKey,
915 macedContentsSize, CFDataGetBytePtr(destinationMessage) + start,
916 mac);
917
918 CFDataAppendBytes(destinationMessage, mac, kCompactMessageMACSize);
919
920 return errSecSuccess;
921 }
922
923 OSStatus SecOTRSSignAndProtectMessage(SecOTRSessionRef session,
924 CFDataRef sourceMessage,
925 CFMutableDataRef protectedMessage)
926 {
927 __block OSStatus result = errSecParam;
928
929 require(session, abort);
930 require(sourceMessage, abort);
931 require(protectedMessage, abort);
932
933 if(session->_state != kDone){
934 secdebug("OTR", "Cannot sign and protect messages, we are not done negotiating sesion[%p]", session);
935 require_quiet( session->_state == kDone, abort);
936 }
937
938 dispatch_sync(session->_queue, ^{
939 if (session->_myKey == NULL ||
940 session->_theirKey == NULL) {
941 return;
942 }
943
944 uint8_t *messageKey;
945 uint8_t *macKey;
946 uint64_t *counter;
947 uint32_t theirKeyID = session->_theirKeyID;
948
949 SecOTRPublicDHKeyRef theirKeyToUse = session->_theirKey;
950
951 SecOTRSRollIfTime(session);
952
953 if(session->_stallingTheirRoll && session->_theirPreviousKey){
954 theirKeyToUse = session->_theirPreviousKey;
955 theirKeyID = session->_theirKeyID - 1;
956 }
957
958 SecOTRSFindKeysForMessage(session, session->_myKey, theirKeyToUse,
959 true,
960 &messageKey, &macKey, &counter);
961 // 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.
962 CFMutableDataRef destinationMessage = session->_textOutput || !protectedMessage ? CFDataCreateMutable(kCFAllocatorDefault, 0) : CFRetainSafe(protectedMessage);
963
964 result = session->_compactAppleMessages ? SecOTRSSignAndProtectCompact_locked(session, sourceMessage, destinationMessage, messageKey, macKey, counter, theirKeyID, theirKeyToUse)
965 : SecOTRSSignAndProtectRaw_locked(session, sourceMessage, destinationMessage, messageKey, macKey, counter, theirKeyID, theirKeyToUse);
966
967 if (result == errSecSuccess) {
968 if (session->_textOutput) {
969 SecOTRPrepareOutgoingBytes(destinationMessage, protectedMessage);
970 }
971
972 CFDataSetLength(session->_macKeysToExpose, 0);
973 }
974
975 CFReleaseSafe(destinationMessage);
976
977 result = errSecSuccess;
978 });
979
980 abort:
981 return result;
982 }
983
984 void SecOTRSKickTimeToRoll(SecOTRSessionRef session){
985 session->_timeToRoll = CFAbsoluteTimeGetCurrent();
986 }
987
988 static void SecOTRAcceptNewRemoteKey(SecOTRSessionRef session, SecOTRPublicDHKeyRef newKey)
989 {
990 if (session->_theirPreviousKey) {
991 SecOTRSExpireCachedKeysForPublicKey(session, session->_theirPreviousKey);
992 }
993
994 CFReleaseNull(session->_theirPreviousKey);
995 session->_theirPreviousKey = session->_theirKey;
996 session->_theirKey = CFRetainSafe(newKey);
997 session->_stallingTheirRoll = true;
998
999 session->_theirKeyID += 1;
1000
1001 SecOTRSEnableTimeToRoll(session);
1002 }
1003
1004 OSStatus SecOTRSetupInitialRemoteKey(SecOTRSessionRef session, SecOTRPublicDHKeyRef initialKey) {
1005
1006 bzero(session->_keyCache, sizeof(session->_keyCache));
1007
1008 CFReleaseNull(session->_theirPreviousKey);
1009 CFAssignRetained(session->_theirKey, initialKey);
1010 session->_theirKeyID = 1;
1011
1012 return errSecSuccess;
1013 }
1014
1015 ///
1016 /// MARK: SLOW ROLLING
1017 ///
1018
1019 void SOSOTRSRoll(SecOTRSessionRef session){
1020
1021 session->_stallingTheirRoll = false;
1022
1023 //receiving side roll
1024 if(session->_receivedAck){
1025 SecOTRGenerateNewProposedKey(session);
1026 session->_missedAck = false;
1027 session->_receivedAck = false;
1028 }
1029 else{
1030 session->_missedAck = true;
1031 }
1032 }
1033
1034 static OSStatus SecOTRVerifyAndExposeRaw_locked(SecOTRSessionRef session,
1035 CFDataRef decodedBytes,
1036 CFMutableDataRef exposedMessageContents)
1037 {
1038 OSStatus result = errSecDecode;
1039
1040 SecOTRPublicDHKeyRef newKey = NULL;
1041 const uint8_t* bytes;
1042 size_t size;
1043
1044 bytes = CFDataGetBytePtr(decodedBytes);
1045 size = CFDataGetLength(decodedBytes);
1046
1047 const uint8_t* macDataStart = bytes;
1048
1049 uint32_t theirID;
1050 uint32_t myID;
1051
1052 require_noerr_quiet(result = ReadAndVerifyHeader(&bytes, &size, kDataMessage), fail);
1053 require_action_quiet(size > 0, fail, result = errSecDecode);
1054
1055 require_noerr_quiet(result = ReadAndVerifyByte(&bytes, &size, 0), fail); // Flags, always zero
1056
1057 require_noerr_quiet(result = ReadLong(&bytes, &size, &theirID), fail);
1058
1059 require_action_quiet(theirID == session->_theirKeyID || (theirID == (session->_theirKeyID - 1) && session->_theirPreviousKey != NULL),
1060 fail,
1061 result = ((theirID + 1) < session->_theirKeyID) ? errSecOTRTooOld : errSecOTRIDTooNew);
1062
1063 require_noerr_quiet(result = ReadLong(&bytes, &size, &myID), fail);
1064
1065 require_action_quiet(myID == session->_keyID || (myID == session->_keyID + 1 && session->_myNextKey != NULL),
1066 fail,
1067 result = (myID < session->_keyID) ? errSecOTRTooOld : errSecOTRIDTooNew);
1068
1069
1070 // Choose appripriate keys for message:
1071 {
1072 uint8_t *messageKey;
1073 uint8_t *macKey;
1074 uint64_t *theirCounter;
1075
1076 SecOTRFullDHKeyRef myKeyForMessage = (myID == session->_keyID) ? session->_myKey : session->_myNextKey;
1077 SecOTRPublicDHKeyRef theirKeyForMessage = (theirID == session->_theirKeyID) ? session->_theirKey : session->_theirPreviousKey;
1078
1079 SecOTRSFindKeysForMessage(session, myKeyForMessage, theirKeyForMessage, false,
1080 &messageKey, &macKey, &theirCounter);
1081
1082 size_t nextKeyMPISize;
1083 const uint8_t* nextKeyMPIBytes;
1084 require_noerr_quiet(result = SizeAndSkipMPI(&bytes, &size, &nextKeyMPIBytes, &nextKeyMPISize), fail);
1085
1086 uint64_t counter;
1087 require_noerr_quiet(result = ReadLongLong(&bytes, &size, &counter), fail);
1088 require_action_quiet(counter > *theirCounter, fail, result = errSecOTRTooOld);
1089
1090 size_t messageSize;
1091 const uint8_t* messageStart;
1092 require_noerr_quiet(result = SizeAndSkipDATA(&bytes, &size, &messageStart, &messageSize), fail);
1093
1094 size_t macDataSize = (bytes - macDataStart) ? (size_t)(bytes - macDataStart) : 0;
1095 uint8_t mac[CCSHA1_OUTPUT_SIZE];
1096 require_action_quiet(sizeof(mac) <= size, fail, result = errSecDecode);
1097
1098 cchmac(ccsha1_di(),
1099 kOTRMessageMacKeyBytes, macKey,
1100 macDataSize, macDataStart,
1101 mac);
1102
1103 require_noerr_action_quiet(constant_memcmp(mac, bytes, sizeof(mac)), fail, result = errSecAuthFailed);
1104
1105 uint8_t* dataSpace = CFDataIncreaseLengthAndGetMutableBytes(exposedMessageContents, (CFIndex)messageSize);
1106
1107 AES_CTR_HighHalf_Transform(kOTRMessageKeyBytes, messageKey,
1108 counter,
1109 messageSize, messageStart,
1110 dataSpace);
1111
1112 // Everything is good, accept the meta data.
1113 *theirCounter = counter;
1114
1115 newKey = SecOTRPublicDHKCreateFromBytes(kCFAllocatorDefault, &nextKeyMPIBytes, &nextKeyMPISize);
1116 }
1117
1118 bool acceptTheirNewKey = newKey != NULL && theirID == session->_theirKeyID;
1119
1120 if (acceptTheirNewKey) {
1121 SecOTRAcceptNewRemoteKey(session, newKey);
1122 }
1123
1124 if (myID == (session->_keyID + 1)) {
1125 SecOTRSHandleProposalAcknowledge(session);
1126 }
1127
1128 SecOTRSRollIfTime(session);
1129
1130 SecOTRSPrecalculateNextKeysInternal(session);
1131
1132 fail:
1133 CFReleaseNull(newKey);
1134 return result;
1135 }
1136
1137 static OSStatus SecOTRVerifyAndExposeRawCompact_locked(SecOTRSessionRef session,
1138 CFDataRef decodedBytes,
1139 CFMutableDataRef exposedMessageContents)
1140 {
1141 SecOTRPublicDHKeyRef theirProposal = NULL;
1142 OSStatus result = errSecDecode;
1143 const uint8_t* bytes;
1144 size_t size;
1145 SecOTRPublicDHKeyRef theirKeyForMessage = NULL;
1146 bytes = CFDataGetBytePtr(decodedBytes);
1147 size = CFDataGetLength(decodedBytes);
1148 SecOTRFullDHKeyRef myKeyForMessage = NULL;
1149 const uint8_t* macDataStart = bytes;
1150 bool useEvenKey = false;
1151 bool useCurrentKey = false;
1152 bool sentHashes = false;
1153 uint64_t counter = 0;
1154
1155 uint8_t type_byte = 0;
1156 require_noerr_quiet(result = ReadByte(&bytes, &size, &type_byte), fail);
1157 require_action_quiet(type_byte == kOddCompactDataMessage || type_byte == kEvenCompactDataMessage
1158 || type_byte == kOddCompactDataMessageWithHashes || type_byte == kEvenCompactDataMessageWithHashes, fail, result = errSecDecode);
1159
1160 useEvenKey = (type_byte == kEvenCompactDataMessage || type_byte == kEvenCompactDataMessageWithHashes);
1161 sentHashes = (type_byte == kOddCompactDataMessageWithHashes || type_byte == kEvenCompactDataMessageWithHashes);
1162
1163 useCurrentKey = useEvenKey ^ (session->_keyID & 1);
1164 myKeyForMessage = useCurrentKey ? session->_myKey : session->_myNextKey;
1165
1166 require_action_quiet(myKeyForMessage, fail, result = errSecDecode);
1167
1168 theirProposal = SecOTRPublicDHKCreateFromCompactSerialization(kCFAllocatorDefault, &bytes, &size);
1169
1170 require_action_quiet(theirProposal, fail, result = errSecDecode);
1171
1172 bool proposalIsNew = !CFEqualSafe(theirProposal, session->_theirKey);
1173 theirKeyForMessage = proposalIsNew ? session->_theirKey : session->_theirPreviousKey;
1174
1175 require_action_quiet(theirKeyForMessage, fail, result = errSecDecode);
1176
1177 uint8_t *messageKey;
1178 uint8_t *macKey;
1179 uint64_t *theirCounter;
1180
1181
1182 SecOTRSFindKeysForMessage(session, myKeyForMessage, theirKeyForMessage, false, &messageKey, &macKey, &theirCounter);
1183
1184 require_noerr_quiet(result = ReadLongLongCompact(&bytes, &size, &counter), fail);
1185 require_action_quiet(counter > *theirCounter, fail, result = errSecOTRTooOld);
1186
1187 size_t messageSize = size - kCompactMessageMACSize - (sentHashes ? 2 * kSecDHKHashSize : 0); // It's all message except for the MAC and maybe hashes
1188 const uint8_t* messageStart = bytes;
1189
1190 bytes += messageSize;
1191 size -= messageSize;
1192
1193 if (sentHashes) {
1194 // Sender then receiver keys
1195
1196 if (memcmp(SecPDHKGetHash(theirKeyForMessage), bytes, kSecDHKHashSize) != 0) {
1197 // Wrong sender key WTF.
1198 #if DEBUG
1199 BufferPerformWithHexString(bytes, kSecDHKHashSize, ^(CFStringRef dataString) {
1200 secdebug("OTR","session[%p] Sender key hash doesn't match: %@ != %@", session, theirKeyForMessage, dataString);
1201 });
1202 #endif
1203 }
1204
1205 bytes += kSecDHKHashSize;
1206 size -= kSecDHKHashSize;
1207
1208 if (memcmp(SecFDHKGetHash(myKeyForMessage), bytes, kSecDHKHashSize) != 0) {
1209 // Wrong sender key WTF.
1210 #if DEBUG
1211 BufferPerformWithHexString(bytes, kSecDHKHashSize, ^(CFStringRef dataString) {
1212 secdebug("OTR","session[%p] Receiver key hash doesn't match: %@ != %@", session, myKeyForMessage, dataString);
1213 });
1214 #endif
1215 }
1216
1217 bytes += kSecDHKHashSize;
1218 size -= kSecDHKHashSize;
1219
1220 }
1221
1222 uint8_t mac[CCSHA1_OUTPUT_SIZE];
1223 require_action_quiet(kCompactMessageMACSize == size, fail, result = errSecDecode); // require space for the mac and some bytes
1224
1225 size_t macDataSize = (size_t)(bytes - macDataStart);
1226
1227 cchmac(ccsha1_di(),
1228 kOTRMessageMacKeyBytes, macKey,
1229 macDataSize, macDataStart,
1230 mac);
1231
1232 require_noerr_action_quiet(constant_memcmp(mac, bytes, kCompactMessageMACSize), fail, result = errSecAuthFailed);
1233
1234 uint8_t* dataSpace = CFDataIncreaseLengthAndGetMutableBytes(exposedMessageContents, (CFIndex)messageSize);
1235
1236 AES_CTR_HighHalf_Transform(kOTRMessageKeyBytes, messageKey,
1237 counter,
1238 messageSize, messageStart,
1239 dataSpace);
1240
1241 // Everything is good, accept the meta data.
1242 *theirCounter = counter;
1243
1244 if (proposalIsNew) {
1245 SecOTRAcceptNewRemoteKey(session, theirProposal);
1246 }
1247
1248 if (!useCurrentKey) {
1249 SecOTRSHandleProposalAcknowledge(session);
1250 }
1251 SecOTRSRollIfTime(session);
1252
1253 SecOTRSPrecalculateNextKeysInternal(session);
1254
1255 fail:
1256 #if DEBUG
1257 if(result != errSecSuccess){
1258 CFDataPerformWithHexString(decodedBytes, ^(CFStringRef decodedBytesString) {
1259 secdebug("OTR","session[%p] failed to decrypt, session: %@, mk: %@, mpk: %@, tpk: %@, tk: %@, chose tktu: %@, mktu: %@, m: %@, tP: %@, tb: %hhx", session, session,
1260 session->_myKey, session->_myNextKey, session->_theirPreviousKey, session->_theirKey, theirKeyForMessage, myKeyForMessage, decodedBytesString, theirProposal, type_byte);
1261 });
1262 }
1263 #endif
1264 CFReleaseNull(theirProposal);
1265 return result;
1266 }
1267
1268
1269 OSStatus SecOTRSVerifyAndExposeMessage(SecOTRSessionRef session,
1270 CFDataRef incomingMessage,
1271 CFMutableDataRef exposedMessageContents)
1272 {
1273 __block OSStatus result = errSecParam;
1274
1275
1276 require(session, abort);
1277 require(incomingMessage, abort);
1278 require(exposedMessageContents, abort);
1279
1280 if(session->_state == kDone){
1281 dispatch_sync(session->_queue, ^{
1282 CFDataRef decodedBytes = SecOTRCopyIncomingBytes(incomingMessage);
1283
1284 OTRMessageType messageType = SecOTRSGetMessageType(decodedBytes);
1285
1286 switch (messageType) {
1287 case kDataMessage:
1288 result = SecOTRVerifyAndExposeRaw_locked(session, decodedBytes, exposedMessageContents);
1289 break;
1290
1291 case kOddCompactDataMessage:
1292 case kEvenCompactDataMessage:
1293 case kOddCompactDataMessageWithHashes:
1294 case kEvenCompactDataMessageWithHashes:
1295 result = SecOTRVerifyAndExposeRawCompact_locked(session, decodedBytes, exposedMessageContents);
1296 break;
1297
1298 default:
1299 result = errSecUnsupportedFormat;
1300 break;
1301 }
1302
1303 CFReleaseSafe(decodedBytes);
1304 });
1305 }
1306 else{
1307 secnotice("OTR", "session[%p]Cannot process message:%@, session is not done negotiating, session state: %@", session, incomingMessage, session);
1308 result = errSecOTRNotReady;
1309 }
1310 abort:
1311 return result;
1312 }
1313
1314
1315 OSStatus SecOTRSEndSession(SecOTRSessionRef session,
1316 CFMutableDataRef messageToSend)
1317 {
1318 return errSecUnimplemented;
1319 }
1320
1321 static CFDataRef data_to_data_error_request(enum SecXPCOperation op, CFDataRef publicPeerId, CFErrorRef *error) {
1322 __block CFDataRef result = NULL;
1323 securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) {
1324 return SecXPCDictionarySetDataOptional(message, kSecXPCPublicPeerId, publicPeerId, error);
1325 }, ^bool(xpc_object_t response, CFErrorRef *error) {
1326 return (result = SecXPCDictionaryCopyData(response, kSecXPCKeyResult, error));
1327 });
1328 return result;
1329 }
1330
1331 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) {
1332 __block CFDataRef tempOutputSessionData = NULL;
1333 __block CFDataRef tempOutputPacket = NULL;
1334 __block bool tempReadyForMessages = false;
1335
1336 bool result = securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) {
1337 return SecXPCDictionarySetDataOptional(message, kSecXPCOTRSession, sessionData, error)
1338 && SecXPCDictionarySetDataOptional(message, kSecXPCData, inputPacket, error);
1339 }, ^bool(xpc_object_t response, CFErrorRef *error) {
1340 if (xpc_dictionary_get_bool(response, kSecXPCKeyResult)) {
1341 tempOutputSessionData = SecXPCDictionaryCopyData(response, kSecXPCOTRSession, error);
1342 tempOutputPacket = SecXPCDictionaryCopyData(response, kSecXPCData, error);
1343 tempReadyForMessages = xpc_dictionary_get_bool(response, kSecXPCOTRReady);
1344 return true;
1345 } else {
1346 return false;
1347 }
1348
1349 });
1350
1351 *outputSessionData = tempOutputSessionData;
1352 *outputPacket = tempOutputPacket;
1353 *readyForMessages = tempReadyForMessages;
1354
1355 return result;
1356 }
1357
1358
1359 CFDataRef SecOTRSessionCreateRemote(CFDataRef publicPeerId, CFErrorRef *error) {
1360 __block CFDataRef result;
1361 os_activity_initiate("SecOTRSessionCreateRemote", OS_ACTIVITY_FLAG_DEFAULT, ^{
1362 (void)SecOTRGetDefaultsWriteSeconds();
1363 result = SECURITYD_XPC(sec_otr_session_create_remote, data_to_data_error_request, publicPeerId, error);
1364 });
1365 return result;
1366 }
1367
1368 bool SecOTRSessionProcessPacketRemote(CFDataRef sessionData, CFDataRef inputPacket, CFDataRef* outputSessionData, CFDataRef* outputPacket, bool *readyForMessages, CFErrorRef *error) {
1369 __block bool result;
1370 os_activity_initiate("SecOTRSessionProcessPacketRemote", OS_ACTIVITY_FLAG_DEFAULT, ^{
1371 result = SECURITYD_XPC(sec_otr_session_process_packet_remote, data_data_to_data_data_bool_error_request, sessionData, inputPacket, outputSessionData, outputPacket, readyForMessages, error);
1372 });
1373 return result;
1374 }