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