]> git.saurik.com Git - apple/security.git/blob - sec/Security/SecOTRSession.c
Security-55471.14.8.tar.gz
[apple/security.git] / sec / Security / SecOTRSession.c
1 //
2 // SecOTRSession.c
3 // libsecurity_libSecOTR
4 //
5 // Created by Mitch Adler on 2/22/11.
6 // Copyright 2011 Apple Inc. All rights reserved.
7 //
8
9 #include "SecOTRSession.h"
10
11 #include "SecOTRMath.h"
12 #include "SecOTRDHKey.h"
13 #include "SecOTRSessionPriv.h"
14 #include "SecOTRPackets.h"
15 #include "SecOTRPacketData.h"
16
17 #include <utilities/SecCFWrappers.h>
18
19 #include <CoreFoundation/CFRuntime.h>
20 #include <CoreFoundation/CFString.h>
21
22 #include <Security/SecBasePriv.h>
23 #include <Security/SecRandom.h>
24 #include <Security/SecBase64.h>
25
26 #include <AssertMacros.h>
27
28 #ifdef USECOMMONCRYPTO
29 #include <CommonCrypto/CommonHMAC.h>
30 #endif
31
32 #include <corecrypto/cchmac.h>
33 #include <corecrypto/ccsha2.h>
34 #include <corecrypto/ccsha1.h>
35
36 #include <string.h>
37 #include <stdlib.h>
38
39 #include <syslog.h>
40
41 #include "utilities/comparison.h"
42
43 CFGiblisFor(SecOTRSession);
44
45 static OTRMessageType SecOTRSGetMessageType(CFDataRef message)
46 {
47 OTRMessageType type = kInvalidMessage;
48
49 CFMutableDataRef decodedBytes = CFDataCreateMutable(kCFAllocatorDefault, 0);
50 SecOTRGetIncomingBytes(message, decodedBytes);
51
52 const uint8_t *bytes = CFDataGetBytePtr(decodedBytes);
53 size_t size = CFDataGetLength(decodedBytes);
54
55 require_noerr(ReadHeader(&bytes, &size, &type), fail);
56
57 fail:
58 CFReleaseNull(decodedBytes);
59
60 return type;
61 }
62
63 const char *SecOTRPacketTypeString(CFDataRef message)
64 {
65 if (!message) return "NoMessage";
66 switch (SecOTRSGetMessageType(message)) {
67 case kDHMessage: return "DHMessage (0x02)";
68 case kDataMessage: return "DataMessage (0x03)";
69 case kDHKeyMessage: return "DHKeyMessage (0x0A)";
70 case kRevealSignatureMessage: return "RevealSignatureMessage (0x11)";
71 case kSignatureMessage: return "SignatureMessage (0x12)";
72 case kInvalidMessage: return "InvalidMessage (0xFF)";
73 default: return "UnknownMessage";
74 }
75 }
76
77 static const char *SecOTRAuthStateString(SecOTRAuthState authState)
78 {
79 switch (authState) {
80 case kIdle: return "Idle";
81 case kAwaitingDHKey: return "AwaitingDHKey";
82 case kAwaitingRevealSignature: return "AwaitingRevealSignature";
83 case kAwaitingSignature: return "AwaitingSignature";
84 case kDone: return "Done";
85 default: return "InvalidState";
86 }
87 }
88
89 static CF_RETURNS_RETAINED CFStringRef SecOTRSessionCopyDescription(CFTypeRef cf) {
90 SecOTRSessionRef session = (SecOTRSessionRef)cf;
91 return CFStringCreateWithFormat(kCFAllocatorDefault,NULL,CFSTR("<%s %s%s%s%s %d:%d %s%s>"),
92 SecOTRAuthStateString(session->_state),
93 session->_me ? "F" : "-",
94 session->_them ? "P" : "-",
95 session->_receivedDHMessage ? "D" : "-",
96 session->_receivedDHKeyMessage ? "K" : "-",
97 session->_keyID,
98 session->_theirKeyID,
99 session->_theirPreviousKey ? "P" : "-",
100 session->_theirKey ? "T" : "-");
101 }
102
103 static void SecOTRSessionDestroy(CFTypeRef cf) {
104 SecOTRSessionRef session = (SecOTRSessionRef)cf;
105
106 CFReleaseNull(session->_receivedDHMessage);
107 CFReleaseNull(session->_receivedDHKeyMessage);
108
109 CFReleaseNull(session->_me);
110 CFReleaseNull(session->_myKey);
111 CFReleaseNull(session->_myNextKey);
112
113 CFReleaseNull(session->_them);
114 CFReleaseNull(session->_theirKey);
115 CFReleaseNull(session->_theirPreviousKey);
116
117 CFReleaseNull(session->_macKeysToExpose);
118
119 dispatch_release(session->_queue);
120 }
121
122 static void SecOTRSessionResetInternal(SecOTRSessionRef session)
123 {
124 session->_state = kIdle;
125
126 CFReleaseNull(session->_receivedDHMessage);
127 CFReleaseNull(session->_receivedDHKeyMessage);
128
129 session->_keyID = 0;
130 CFReleaseNull(session->_myKey);
131 CFReleaseNull(session->_myNextKey);
132 //session->_myNextKey = SecOTRFullDHKCreate(kCFAllocatorDefault);
133 session->_theirKeyID = 0;
134 CFReleaseNull(session->_theirKey);
135 CFReleaseNull(session->_theirPreviousKey);
136 CFReleaseNull(session->_macKeysToExpose);
137 session->_macKeysToExpose = CFDataCreateMutable(kCFAllocatorDefault, 0);
138
139 bzero(session->_keyCache, sizeof(session->_keyCache));
140 }
141
142 void SecOTRSessionReset(SecOTRSessionRef session)
143 {
144 dispatch_sync_f(session->_queue, session, (dispatch_function_t) SecOTRSessionResetInternal);
145 }
146
147
148 SecOTRSessionRef SecOTRSessionCreateFromID(CFAllocatorRef allocator,
149 SecOTRFullIdentityRef myID,
150 SecOTRPublicIdentityRef theirID)
151 {
152 SecOTRSessionRef newID = CFTypeAllocate(SecOTRSession, struct _SecOTRSession, allocator);
153
154 newID->_queue = dispatch_queue_create("OTRSession", DISPATCH_QUEUE_SERIAL);
155
156 newID->_me = myID;
157 newID->_them = theirID;
158 newID->_receivedDHMessage = NULL;
159 newID->_receivedDHKeyMessage = NULL;
160 newID->_myKey = NULL;
161 newID->_myNextKey = NULL;
162 newID->_theirKey = NULL;
163 newID->_theirPreviousKey = NULL;
164 newID->_macKeysToExpose = NULL;
165 newID->_textOutput = false;
166
167 SecOTRSessionResetInternal(newID);
168
169 CFRetain(newID->_me);
170 CFRetain(newID->_them);
171
172 return newID;
173 }
174
175 SecOTRSessionRef SecOTRSessionCreateFromIDAndFlags(CFAllocatorRef allocator,
176 SecOTRFullIdentityRef myID,
177 SecOTRPublicIdentityRef theirID,
178 uint32_t flags)
179 {
180 SecOTRSessionRef newID = SecOTRSessionCreateFromID(allocator, myID, theirID);
181 if (flags & kSecOTRSendTextMessages) {
182 newID->_textOutput = true;
183 }
184 return newID;
185 }
186
187 static uint64_t constant_zero = 0;
188
189 static void SecOTRSFindKeysForMessage(SecOTRSessionRef session,
190 SecOTRFullDHKeyRef myKey,
191 SecOTRPublicDHKeyRef theirKey,
192 bool sending,
193 uint8_t** messageKey, uint8_t** macKey, uint64_t **counter)
194 {
195 SecOTRCacheElement* emptyKeys = NULL;
196 SecOTRCacheElement* cachedKeys = NULL;
197
198 if ((NULL == myKey) || (NULL == theirKey)) {
199 if (messageKey)
200 *messageKey = NULL;
201 if (macKey)
202 *macKey = NULL;
203 if (counter)
204 *counter = &constant_zero;
205
206 return;
207 }
208
209 for(int i = 0; i < kOTRKeyCacheSize; ++i)
210 {
211 if (0 == constant_memcmp(session->_keyCache[i]._fullKeyHash, SecFDHKGetHash(myKey), CCSHA1_OUTPUT_SIZE)
212 && (0 == constant_memcmp(session->_keyCache[i]._publicKeyHash, SecPDHKGetHash(theirKey), CCSHA1_OUTPUT_SIZE))) {
213 cachedKeys = &session->_keyCache[i];
214 break;
215 }
216
217 if (emptyKeys == NULL
218 && session->_keyCache[i]._fullKey == NULL) {
219 emptyKeys = &session->_keyCache[i];
220 }
221 }
222
223 if (cachedKeys == NULL) {
224 if (emptyKeys == NULL) {
225 syslog(LOG_ERR, "SecOTRSession key cache was full. Should never happen, spooky.\n");
226 emptyKeys = &session->_keyCache[0];
227 }
228
229 // Fill in the entry.
230 emptyKeys->_fullKey = myKey;
231 memcpy(emptyKeys->_fullKeyHash, SecFDHKGetHash(myKey), CCSHA1_OUTPUT_SIZE);
232 emptyKeys->_publicKey = theirKey;
233 memcpy(emptyKeys->_publicKeyHash, SecPDHKGetHash(theirKey), CCSHA1_OUTPUT_SIZE);
234
235 emptyKeys->_counter = 0;
236 emptyKeys->_theirCounter = 0;
237
238 SecOTRDHKGenerateOTRKeys(emptyKeys->_fullKey, emptyKeys->_publicKey,
239 emptyKeys->_sendEncryptionKey, emptyKeys->_sendMacKey,
240 emptyKeys->_receiveEncryptionKey, emptyKeys->_receiveMacKey);
241
242 cachedKeys = emptyKeys;
243 }
244
245 if (messageKey)
246 *messageKey = sending ? cachedKeys->_sendEncryptionKey : cachedKeys->_receiveEncryptionKey;
247 if (macKey)
248 *macKey = sending ? cachedKeys->_sendMacKey : cachedKeys->_receiveMacKey;
249 if (counter)
250 *counter = sending ? &cachedKeys->_counter : &cachedKeys->_theirCounter;
251 }
252
253 SecOTRSessionRef SecOTRSessionCreateFromData(CFAllocatorRef allocator, CFDataRef data)
254 {
255 if (data == NULL)
256 return NULL;
257
258 SecOTRSessionRef result = NULL;
259 SecOTRSessionRef session = CFTypeAllocate(SecOTRSession, struct _SecOTRSession, allocator);
260
261 const uint8_t *bytes = CFDataGetBytePtr(data);
262 size_t size = (size_t)CFDataGetLength(data);
263
264 session->_queue = dispatch_queue_create("OTRSession", DISPATCH_QUEUE_SERIAL);
265
266 session->_me = NULL;
267 session->_them = NULL;
268 session->_myKey = NULL;
269 session->_myNextKey = NULL;
270 session->_theirKey = NULL;
271 session->_theirPreviousKey = NULL;
272 session->_receivedDHMessage = NULL;
273 session->_receivedDHKeyMessage = NULL;
274 bzero(session->_keyCache, sizeof(session->_keyCache));
275
276 uint8_t version;
277 require_noerr(ReadByte(&bytes, &size, &version), fail);
278 require(version <= 3, fail);
279
280 require_noerr(ReadLong(&bytes, &size, &session->_state), fail);
281 session->_me = SecOTRFullIdentityCreateFromBytes(kCFAllocatorDefault, &bytes, &size, NULL);
282 require(session->_me != NULL, fail);
283 session->_them = SecOTRPublicIdentityCreateFromBytes(kCFAllocatorDefault, &bytes, &size, NULL);
284 require(session->_them != NULL, fail);
285
286 require(size > sizeof(session->_r), fail);
287 memcpy(session->_r, bytes, sizeof(session->_r));
288 bytes += sizeof(session->_r);
289 size -= sizeof(session->_r);
290
291 {
292 uint8_t hasMessage = false;
293 ReadByte(&bytes, &size, &hasMessage);
294 if (hasMessage) {
295 session->_receivedDHMessage = CFDataCreateMutableFromOTRDATA(kCFAllocatorDefault, &bytes, &size);
296 }
297 }
298
299 if (version >= 2) {
300 uint8_t hasMessage = false;
301 ReadByte(&bytes, &size, &hasMessage);
302 if (hasMessage) {
303 session->_receivedDHKeyMessage = CFDataCreateMutableFromOTRDATA(kCFAllocatorDefault, &bytes, &size);
304 }
305 }
306
307 if (version < 3) {
308 uint8_t ready;
309 require_noerr(ReadByte(&bytes, &size, &ready), fail);
310 if (ready && session->_state == kIdle)
311 session->_state = kDone;
312 }
313
314 require_noerr(ReadLong(&bytes, &size, &session->_keyID), fail);
315 if (session->_keyID > 0) {
316 session->_myKey = SecOTRFullDHKCreateFromBytes(kCFAllocatorDefault, &bytes, &size);
317 require(session->_myKey != NULL, fail);
318 session->_myNextKey = SecOTRFullDHKCreateFromBytes(kCFAllocatorDefault, &bytes, &size);
319 require(session->_myNextKey != NULL, fail);
320 }
321
322 require_noerr(ReadLong(&bytes, &size, &session->_theirKeyID), fail);
323 if (session->_theirKeyID > 0) {
324 if (session->_theirKeyID > 1) {
325 session->_theirPreviousKey = SecOTRPublicDHKCreateFromSerialization(kCFAllocatorDefault, &bytes, &size);
326 require(session->_theirPreviousKey != NULL, fail);
327 }
328 session->_theirKey = SecOTRPublicDHKCreateFromSerialization(kCFAllocatorDefault, &bytes, &size);
329 require(session->_theirKey != NULL, fail);
330 }
331
332 uint64_t *counter;
333 SecOTRSFindKeysForMessage(session, session->_myKey, session->_theirKey, false, NULL, NULL, &counter);
334 require_noerr(ReadLongLong(&bytes, &size, counter), fail);
335 SecOTRSFindKeysForMessage(session, session->_myKey, session->_theirKey, true, NULL, NULL, &counter);
336 require_noerr(ReadLongLong(&bytes, &size, counter), fail);
337 SecOTRSFindKeysForMessage(session, session->_myKey, session->_theirPreviousKey, false, NULL, NULL, &counter);
338 require_noerr(ReadLongLong(&bytes, &size, counter), fail);
339 SecOTRSFindKeysForMessage(session, session->_myKey, session->_theirPreviousKey, true, NULL, NULL, &counter);
340 require_noerr(ReadLongLong(&bytes, &size, counter), fail);
341 SecOTRSFindKeysForMessage(session, session->_myNextKey, session->_theirKey, false, NULL, NULL, &counter);
342 require_noerr(ReadLongLong(&bytes, &size, counter), fail);
343 SecOTRSFindKeysForMessage(session, session->_myNextKey, session->_theirKey, true, NULL, NULL, &counter);
344 require_noerr(ReadLongLong(&bytes, &size, counter), fail);
345 SecOTRSFindKeysForMessage(session, session->_myNextKey, session->_theirPreviousKey, false, NULL, NULL, &counter);
346 require_noerr(ReadLongLong(&bytes, &size, counter), fail);
347 SecOTRSFindKeysForMessage(session, session->_myNextKey, session->_theirPreviousKey, true, NULL, NULL, &counter);
348 require_noerr(ReadLongLong(&bytes, &size, counter), fail);
349
350 session->_macKeysToExpose = CFDataCreateMutableFromOTRDATA(kCFAllocatorDefault, &bytes, &size);
351 require(session->_macKeysToExpose != NULL, fail);
352
353 uint8_t textMode;
354 require_noerr(ReadByte(&bytes, &size, &textMode), fail);
355 session->_textOutput = (textMode != 0);
356
357 result = session;
358 session = NULL;
359
360 fail:
361 CFReleaseNull(session);
362 return result;
363 }
364
365
366 OSStatus SecOTRSAppendSerialization(SecOTRSessionRef session, CFMutableDataRef serializeInto)
367 {
368 __block OSStatus result = errSecParam;
369
370 require(session, abort);
371 require(serializeInto, abort);
372
373 CFIndex start = CFDataGetLength(serializeInto);
374
375 dispatch_sync(session->_queue, ^{
376 const uint8_t version = 3;
377
378 CFDataAppendBytes(serializeInto, &version, sizeof(version));
379
380 AppendLong(serializeInto, session->_state);
381
382 result = (SecOTRFIAppendSerialization(session->_me, serializeInto, NULL)) ? errSecSuccess : errSecParam;
383
384 if (result == errSecSuccess) {
385 result = (SecOTRPIAppendSerialization(session->_them, serializeInto, NULL)) ? errSecSuccess : errSecParam;
386 }
387
388 if (result == errSecSuccess) {
389 CFDataAppendBytes(serializeInto, session->_r, sizeof(session->_r));
390
391 if (session->_receivedDHMessage == NULL) {
392 AppendByte(serializeInto, 0);
393 } else {
394 AppendByte(serializeInto, 1);
395 AppendCFDataAsDATA(serializeInto, session->_receivedDHMessage);
396 }
397
398 if (session->_receivedDHKeyMessage == NULL) {
399 AppendByte(serializeInto, 0);
400 } else {
401 AppendByte(serializeInto, 1);
402 AppendCFDataAsDATA(serializeInto, session->_receivedDHKeyMessage);
403 }
404
405 AppendLong(serializeInto, session->_keyID);
406 if (session->_keyID > 0) {
407 SecFDHKAppendSerialization(session->_myKey, serializeInto);
408 SecFDHKAppendSerialization(session->_myNextKey, serializeInto);
409 }
410
411 AppendLong(serializeInto, session->_theirKeyID);
412 if (session->_theirKeyID > 0) {
413 if (session->_theirKeyID > 1) {
414 SecPDHKAppendSerialization(session->_theirPreviousKey, serializeInto);
415 }
416 SecPDHKAppendSerialization(session->_theirKey, serializeInto);
417 }
418
419 uint64_t *counter;
420 SecOTRSFindKeysForMessage(session, session->_myKey, session->_theirKey, false, NULL, NULL, &counter);
421 AppendLongLong(serializeInto, *counter);
422 SecOTRSFindKeysForMessage(session, session->_myKey, session->_theirKey, true, NULL, NULL, &counter);
423 AppendLongLong(serializeInto, *counter);
424 SecOTRSFindKeysForMessage(session, session->_myKey, session->_theirPreviousKey, false, NULL, NULL, &counter);
425 AppendLongLong(serializeInto, *counter);
426 SecOTRSFindKeysForMessage(session, session->_myKey, session->_theirPreviousKey, true, NULL, NULL, &counter);
427 AppendLongLong(serializeInto, *counter);
428 SecOTRSFindKeysForMessage(session, session->_myNextKey, session->_theirKey, false, NULL, NULL, &counter);
429 AppendLongLong(serializeInto, *counter);
430 SecOTRSFindKeysForMessage(session, session->_myNextKey, session->_theirKey, true, NULL, NULL, &counter);
431 AppendLongLong(serializeInto, *counter);
432 SecOTRSFindKeysForMessage(session, session->_myNextKey, session->_theirPreviousKey, false, NULL, NULL, &counter);
433 AppendLongLong(serializeInto, *counter);
434 SecOTRSFindKeysForMessage(session, session->_myNextKey, session->_theirPreviousKey, true, NULL, NULL, &counter);
435 AppendLongLong(serializeInto, *counter);
436
437 AppendCFDataAsDATA(serializeInto, session->_macKeysToExpose);
438
439 AppendByte(serializeInto, session->_textOutput ? 1 : 0);
440 }
441 });
442
443 if (result != errSecSuccess)
444 CFDataSetLength(serializeInto, start);
445
446 abort:
447 return result;
448 }
449
450
451 bool SecOTRSGetIsReadyForMessages(SecOTRSessionRef session)
452 {
453 __block bool result;
454
455 dispatch_sync(session->_queue, ^{ result = session->_state == kDone; });
456
457 return result;
458 }
459
460 bool SecOTRSGetIsIdle(SecOTRSessionRef session)
461 {
462 __block bool result;
463
464 dispatch_sync(session->_queue, ^{ result = session->_state == kIdle; });
465
466 return result;
467 }
468
469 static void SecOTRSExpireCachedKeysForFullKey(SecOTRSessionRef session, SecOTRFullDHKeyRef myKey)
470 {
471 for(int i = 0; i < kOTRKeyCacheSize; ++i)
472 {
473 if (0 == constant_memcmp(session->_keyCache[i]._fullKeyHash, SecFDHKGetHash(myKey), CCSHA1_OUTPUT_SIZE)) {
474 CFDataAppendBytes(session->_macKeysToExpose, session->_keyCache[i]._receiveMacKey, sizeof(session->_keyCache[i]._receiveMacKey));
475
476 bzero(&session->_keyCache[i], sizeof(session->_keyCache[i]));
477 }
478 }
479 }
480
481 static void SecOTRSExpireCachedKeysForPublicKey(SecOTRSessionRef session, SecOTRPublicDHKeyRef theirKey)
482 {
483 for(int i = 0; i < kOTRKeyCacheSize; ++i)
484 {
485 if (0 == constant_memcmp(session->_keyCache[i]._publicKeyHash, SecPDHKGetHash(theirKey), CCSHA1_OUTPUT_SIZE)) {
486 CFDataAppendBytes(session->_macKeysToExpose, session->_keyCache[i]._receiveMacKey, sizeof(session->_keyCache[i]._receiveMacKey));
487
488 bzero(&session->_keyCache[i], sizeof(session->_keyCache[i]));
489 }
490 }
491 }
492
493 static void SecOTRSPrecalculateForPair(SecOTRSessionRef session,
494 SecOTRFullDHKeyRef myKey,
495 SecOTRPublicDHKeyRef theirKey)
496 {
497 if (myKey == NULL || theirKey == NULL)
498 return;
499
500 SecOTRSFindKeysForMessage(session, myKey, theirKey, true, NULL, NULL, NULL);
501 SecOTRSFindKeysForMessage(session, myKey, theirKey, false, NULL, NULL, NULL);
502 }
503
504 static void SecOTRSPrecalculateKeysInternal(SecOTRSessionRef session)
505 {
506 SecOTRSPrecalculateForPair(session, session->_myKey, session->_theirKey);
507 SecOTRSPrecalculateForPair(session, session->_myNextKey, session->_theirKey);
508 SecOTRSPrecalculateForPair(session, session->_myKey, session->_theirPreviousKey);
509 SecOTRSPrecalculateForPair(session, session->_myNextKey, session->_theirPreviousKey);
510 }
511
512 void SecOTRSPrecalculateKeys(SecOTRSessionRef session)
513 {
514 dispatch_sync_f(session->_queue, session, (dispatch_function_t) SecOTRSPrecalculateKeysInternal);
515 }
516
517 enum SecOTRSMessageKind SecOTRSGetMessageKind(SecOTRSessionRef session, CFDataRef message)
518 {
519 enum SecOTRSMessageKind kind = kOTRUnknownPacket;
520
521 CFMutableDataRef decodedBytes = CFDataCreateMutable(kCFAllocatorDefault, 0);
522 SecOTRGetIncomingBytes(message, decodedBytes);
523
524 const uint8_t *bytes = CFDataGetBytePtr(decodedBytes);
525 size_t size = CFDataGetLength(decodedBytes);
526
527 OTRMessageType type;
528 require_noerr(ReadHeader(&bytes, &size, &type), fail);
529
530 kind = (type == kDataMessage) ? kOTRDataPacket : kOTRNegotiationPacket;
531
532 fail:
533 CFReleaseNull(decodedBytes);
534
535 return kind;
536 }
537
538 OSStatus SecOTRSSignAndProtectMessage(SecOTRSessionRef session,
539 CFDataRef sourceMessage,
540 CFMutableDataRef protectedMessage)
541 {
542 __block OSStatus result = errSecParam;
543
544 require(session, abort);
545 require(sourceMessage, abort);
546 require(protectedMessage, abort);
547
548 dispatch_sync(session->_queue, ^{
549 if (session->_myKey == NULL ||
550 session->_theirKey == NULL) {
551 return;
552 }
553
554 CFMutableDataRef destinationMessage;
555 if (session->_textOutput) {
556 destinationMessage = CFDataCreateMutable(kCFAllocatorDefault, 0);
557 } else {
558 destinationMessage = protectedMessage;
559 }
560
561 uint8_t *messageKey;
562 uint8_t *macKey;
563 uint64_t *counter;
564
565 CFIndex start = CFDataGetLength(destinationMessage);
566
567 SecOTRSFindKeysForMessage(session, session->_myKey, session->_theirKey,
568 true,
569 &messageKey, &macKey, &counter);
570
571 AppendHeader(destinationMessage, kDataMessage);
572 AppendByte(destinationMessage, 0); // Flags, all zero
573
574 AppendLong(destinationMessage, session->_keyID);
575 AppendLong(destinationMessage, session->_theirKeyID);
576 SecFDHKAppendPublicSerialization(session->_myNextKey, destinationMessage);
577 AppendLongLong(destinationMessage, ++*counter);
578
579 CFIndex sourceSize = CFDataGetLength(sourceMessage);
580 assert(((unsigned long)sourceSize)<=UINT32_MAX); /* this is correct as long as CFIndex is a signed long */
581 AppendLong(destinationMessage, (uint32_t)sourceSize);
582 uint8_t* encryptedDataPointer = CFDataIncreaseLengthAndGetMutableBytes(destinationMessage, sourceSize);
583 AES_CTR_HighHalf_Transform(kOTRMessageKeyBytes, messageKey,
584 *counter,
585 (size_t)sourceSize, CFDataGetBytePtr(sourceMessage),
586 encryptedDataPointer);
587
588 CFIndex macedContentsSize = CFDataGetLength(destinationMessage) - start;
589 CFIndex macSize = CCSHA1_OUTPUT_SIZE;
590 uint8_t* macDataPointer = CFDataIncreaseLengthAndGetMutableBytes(destinationMessage, macSize);
591
592 #ifdef USECOMMONCRYPTO
593 CCHmac(kCCHmacAlgSHA1,
594 macKey, kOTRMessageMacKeyBytes,
595 CFDataGetBytePtr(destinationMessage) + start, (size_t)macedContentsSize,
596 macDataPointer);
597 #else
598 cchmac(ccsha1_di(),
599 kOTRMessageMacKeyBytes, macKey,
600 macedContentsSize, CFDataGetBytePtr(destinationMessage) + start,
601 macDataPointer);
602 #endif
603
604 CFDataAppend(destinationMessage, session->_macKeysToExpose);
605
606 CFDataSetLength(session->_macKeysToExpose, 0);
607
608 if (session->_textOutput) {
609 SecOTRPrepareOutgoingBytes(destinationMessage, protectedMessage);
610 CFReleaseSafe(destinationMessage);
611 }
612
613 result = errSecSuccess;
614 });
615
616 abort:
617 return result;
618 }
619
620 OSStatus SecOTRSVerifyAndExposeMessage(SecOTRSessionRef session,
621 CFDataRef incomingMessage,
622 CFMutableDataRef exposedMessageContents)
623 {
624 __block SecOTRPublicDHKeyRef newKey = NULL;
625 __block OSStatus result = errSecParam;
626
627
628 require(session, abort);
629 require(incomingMessage, abort);
630 require(exposedMessageContents, abort);
631
632 dispatch_sync(session->_queue, ^{
633 const uint8_t* bytes;
634 size_t size;
635 CFMutableDataRef decodedBytes = CFDataCreateMutable(kCFAllocatorDefault, 0);
636 SecOTRGetIncomingBytes(incomingMessage, decodedBytes);
637
638 bytes = CFDataGetBytePtr(decodedBytes);
639 size = CFDataGetLength(decodedBytes);
640
641 const uint8_t* macDataStart = bytes;
642
643 uint32_t theirID;
644 uint32_t myID;
645
646 if ((result = ReadAndVerifyHeader(&bytes, &size, kDataMessage))){
647 CFReleaseSafe(decodedBytes);
648 return;
649 }
650
651 if (size <= 0) { result = errSecDecode; CFReleaseSafe(decodedBytes); return; }
652
653 if ((result = ReadAndVerifyByte(&bytes, &size, 0))) { CFReleaseSafe(decodedBytes); return;} // No flags
654
655 if ((result = ReadLong(&bytes, &size, &theirID))){ CFReleaseSafe(decodedBytes); return; }
656
657 if (theirID != session->_theirKeyID &&
658 (session->_theirPreviousKey == NULL || theirID != (session->_theirKeyID - 1)))
659 {
660 result = ((theirID + 1) < session->_theirKeyID) ? errSecOTRTooOld : errSecOTRIDTooNew;
661 CFReleaseSafe(decodedBytes);
662 return;
663 };
664
665 if ((result = ReadLong(&bytes, &size, &myID))){ CFReleaseSafe(decodedBytes); return; }
666 if (myID != session->_keyID && myID != (session->_keyID + 1))
667 {
668 result = (myID < session->_keyID) ? errSecOTRTooOld : errSecOTRIDTooNew;
669 CFReleaseSafe(decodedBytes);
670 return;
671 };
672
673
674 // Choose appripriate keys for message:
675 {
676 uint8_t *messageKey;
677 uint8_t *macKey;
678 uint64_t *theirCounter;
679
680 SecOTRFullDHKeyRef myKeyForMessage = (myID == session->_keyID) ? session->_myKey : session->_myNextKey;
681 SecOTRPublicDHKeyRef theirKeyForMessage = (theirID == session->_theirKeyID) ? session->_theirKey : session->_theirPreviousKey;
682
683 SecOTRSFindKeysForMessage(session, myKeyForMessage, theirKeyForMessage, false,
684 &messageKey, &macKey, &theirCounter);
685
686 size_t nextKeyMPISize;
687 const uint8_t* nextKeyMPIBytes;
688 if ((result = SizeAndSkipMPI(&bytes, &size, &nextKeyMPIBytes, &nextKeyMPISize))){ CFReleaseSafe(decodedBytes); return;}
689
690 uint64_t counter;
691 if ((result = ReadLongLong(&bytes, &size, &counter))) { CFReleaseSafe(decodedBytes); return; }
692
693 if (counter <= *theirCounter) { result = errSecOTRTooOld; CFReleaseSafe(decodedBytes); return; };
694
695 size_t messageSize;
696 const uint8_t* messageStart;
697 if ((result = SizeAndSkipDATA(&bytes, &size, &messageStart, &messageSize))) { CFReleaseSafe(decodedBytes); return; }
698
699 size_t macDataSize = (bytes - macDataStart) ? (size_t)(bytes - macDataStart) : 0;
700 uint8_t mac[CCSHA1_OUTPUT_SIZE];
701 if (sizeof(mac) > size) { result = errSecDecode; CFReleaseSafe(decodedBytes); return; }
702
703 #ifdef USECOMMONCRYPTO
704 CCHmac(kCCHmacAlgSHA1,
705 macKey, kOTRMessageMacKeyBytes,
706 macDataStart, macDataSize,
707 mac);
708 #else
709 cchmac(ccsha1_di(),
710 kOTRMessageMacKeyBytes, macKey,
711 macDataSize, macDataStart,
712 mac);
713 #endif
714
715 if (0 != constant_memcmp(mac, bytes, sizeof(mac))) { result = errSecAuthFailed; CFReleaseSafe(decodedBytes); return; }
716 //if (messageSize > 65535) { result = errSecDataTooLarge; CFReleaseSafe(decodedBytes); return; }
717 uint8_t* dataSpace = CFDataIncreaseLengthAndGetMutableBytes(exposedMessageContents, (CFIndex)messageSize);
718
719
720 AES_CTR_HighHalf_Transform(kOTRMessageKeyBytes, messageKey,
721 counter,
722 messageSize, messageStart,
723 dataSpace);
724
725 // Everything is good, accept the meta data.
726 *theirCounter = counter;
727
728 newKey = SecOTRPublicDHKCreateFromBytes(kCFAllocatorDefault, &nextKeyMPIBytes, &nextKeyMPISize);
729 }
730
731 SecOTRSPrecalculateKeysInternal(session);
732
733 bool acceptTheirNewKey = newKey != NULL && theirID == session->_theirKeyID;
734
735 if (acceptTheirNewKey) {
736 if (session->_theirPreviousKey) {
737 SecOTRSExpireCachedKeysForPublicKey(session, session->_theirPreviousKey);
738 }
739
740 CFReleaseNull(session->_theirPreviousKey);
741 session->_theirPreviousKey = session->_theirKey;
742 session->_theirKey = newKey;
743
744 session->_theirKeyID += 1;
745
746 newKey = NULL;
747 }
748
749 if (myID == (session->_keyID + 1)) {
750 SecOTRSExpireCachedKeysForFullKey(session, session->_myKey);
751
752 // Swap the keys so we know the current key.
753 {
754 SecOTRFullDHKeyRef oldKey = session->_myKey;
755 session->_myKey = session->_myNextKey;
756 session->_myNextKey = oldKey;
757 }
758
759 // Derive a new next key by regenerating over the old key.
760 SecFDHKNewKey(session->_myNextKey);
761
762 session->_keyID = myID;
763 }
764 CFReleaseSafe(decodedBytes);
765 });
766
767 abort:
768 CFReleaseNull(newKey);
769 return result;
770 }
771
772
773 OSStatus SecOTRSEndSession(SecOTRSessionRef session,
774 CFMutableDataRef messageToSend)
775 {
776 return errSecUnimplemented;
777 }