]> git.saurik.com Git - apple/security.git/blob - OSX/sec/SOSCircle/SecureObjectSync/SOSCoder.c
Security-57740.31.2.tar.gz
[apple/security.git] / OSX / sec / SOSCircle / SecureObjectSync / SOSCoder.c
1 /*
2 * Copyright (c) 2013-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 #include <stdlib.h>
25
26 #include <CoreFoundation/CFBase.h>
27 #include <CoreFoundation/CFError.h>
28
29 #include <Security/SecBasePriv.h>
30 #include <Security/SecOTR.h>
31 #include <Security/SecOTRSession.h>
32 #include <Security/SecureObjectSync/SOSInternal.h>
33 #include <Security/SecureObjectSync/SOSFullPeerInfo.h>
34 #include <Security/SecureObjectSync/SOSPeerInfo.h>
35 #include <Security/SecureObjectSync/SOSPeer.h>
36 #include <Security/SecureObjectSync/SOSCoder.h>
37
38 #include <utilities/SecCFRelease.h>
39 #include <utilities/SecCFWrappers.h>
40 #include <utilities/SecIOFormat.h>
41 #include <utilities/SecCFError.h>
42 #include <utilities/SecCoreCrypto.h>
43 #include <utilities/debugging.h>
44
45 #include <utilities/der_plist.h>
46 #include <utilities/der_plist_internal.h>
47
48 #include <corecrypto/ccder.h>
49 #include <utilities/iCloudKeychainTrace.h>
50
51 #include "AssertMacros.h"
52
53 struct __OpaqueSOSCoder {
54 CFRuntimeBase _base;
55
56 CFStringRef peer_id;
57 SecOTRSessionRef sessRef;
58 bool waitingForDataPacket;
59 CFDataRef pendingResponse;
60
61 CFDataRef hashOfLastReceived;
62 bool lastReceivedWasOld;
63 };
64
65 #define lastReceived_di ccsha1_di
66
67 CFGiblisWithCompareFor(SOSCoder)
68
69 static CFStringRef SOSCoderCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
70 SOSCoderRef coder = (SOSCoderRef)cf;
71 if(coder){
72 CFStringRef desc = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("<Coder %@ %@ %s%s>"),
73 coder->sessRef,
74 coder->hashOfLastReceived,
75 coder->waitingForDataPacket ? "W" : "w",
76 coder->lastReceivedWasOld ? "O" : "o"
77 );
78 return desc;
79 }
80 else
81 return CFSTR("NULL");
82 }
83
84 static Boolean SOSCoderCompare(CFTypeRef cfA, CFTypeRef cfB) {
85 SOSCoderRef coderA = (SOSCoderRef)cfA, coderB = (SOSCoderRef)cfB;
86 // Use mainly to see if peerB is actually this device (peerA)
87 return CFStringCompare(coderA->peer_id, coderB->peer_id, 0) == kCFCompareEqualTo;
88 }
89
90
91 static const char *SOSCoderString(SOSCoderStatus coderStatus) {
92 switch (coderStatus) {
93 case kSOSCoderDataReturned: return "DataReturned";
94 case kSOSCoderNegotiating: return "Negotiating";
95 case kSOSCoderNegotiationCompleted: return "NegotiationCompleted";
96 case kSOSCoderFailure: return "Failure";
97 case kSOSCoderStaleEvent: return "StaleEvent";
98 case kSOSCoderTooNew: return "TooNew";
99 default: return "StatusUnknown";
100 }
101 }
102
103 /*
104 static void logRawCoderMessage(const uint8_t* der, uint8_t* der_end, bool encoding)
105 {
106 #ifndef NDEBUG
107 CFStringRef hexMessage = NULL;
108 if (der && der_end) {
109 CFIndex length = der_end - der;
110 CFDataRef message = CFDataCreate(kCFAllocatorDefault, der, length);
111 hexMessage = CFDataCopyHexString(message);
112 secnoticeq("coder", "%s RAW [%ld] %@", encoding ? "encode" : "decode", length, hexMessage);
113 CFReleaseSafe(message);
114 }
115 CFReleaseSafe(hexMessage);
116 #endif
117 }
118 */
119
120 static CFMutableDataRef sessSerialized(SOSCoderRef coder, CFErrorRef *error) {
121 CFMutableDataRef otr_state = NULL;
122
123 if(!coder || !coder->sessRef) {
124 SOSCreateErrorWithFormat(kSOSErrorUnexpectedType, NULL, error, 0, CFSTR("No session reference."));
125 return NULL;
126 }
127
128 if ((otr_state = CFDataCreateMutable(NULL, 0)) == NULL) {
129 SOSCreateErrorWithFormat(kSOSErrorAllocationFailure, NULL, error, 0, CFSTR("Mutable Data allocation failed."));
130 return NULL;
131 }
132
133 if (errSecSuccess != SecOTRSAppendSerialization(coder->sessRef, otr_state)) {
134 SOSCreateErrorWithFormat(kSOSErrorEncodeFailure, NULL, error, 0, CFSTR("Append Serialization failed."));
135 CFReleaseSafe(otr_state);
136 return NULL;
137 }
138
139 return otr_state;
140
141 }
142
143 static size_t der_sizeof_optional_data(CFDataRef data) {
144 return data ? der_sizeof_data(data, NULL) : 0;
145 }
146
147 static uint8_t* der_encode_optional_data(CFDataRef data, CFErrorRef *error, const uint8_t* der, uint8_t* der_end) {
148 return data ? der_encode_data(data, error, der, der_end) : der_end;
149 }
150
151
152
153 static size_t SOSCoderGetDEREncodedSize(SOSCoderRef coder, CFErrorRef *error) {
154 size_t encoded_size = 0;
155 CFMutableDataRef otr_state = sessSerialized(coder, error);
156
157 if (otr_state) {
158 size_t data_size = der_sizeof_data(otr_state, error);
159 size_t waiting_size = ccder_sizeof_bool(coder->waitingForDataPacket, error);
160 size_t pending_size = der_sizeof_optional_data(coder->pendingResponse);
161
162 if ((data_size != 0) && (waiting_size != 0))
163 {
164 encoded_size = ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, data_size + waiting_size + pending_size);
165 }
166 CFReleaseSafe(otr_state);
167 }
168 return encoded_size;
169 }
170
171
172 static uint8_t* SOSCoderEncodeToDER(SOSCoderRef coder, CFErrorRef* error, const uint8_t* der, uint8_t* der_end) {
173 if(!der_end) return NULL;
174 uint8_t* result = NULL;
175 CFMutableDataRef otr_state = sessSerialized(coder, error);
176
177 if(otr_state) {
178 result = ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der,
179 der_encode_data(otr_state, error, der,
180 ccder_encode_bool(coder->waitingForDataPacket, der,
181 der_encode_optional_data(coder->pendingResponse, error, der, der_end))));
182 CFReleaseSafe(otr_state);
183 }
184 return result;
185 }
186
187
188 CFDataRef SOSCoderCopyDER(SOSCoderRef coder, CFErrorRef* error) {
189 CFMutableDataRef encoded = NULL;
190 size_t encoded_size = SOSCoderGetDEREncodedSize(coder, error);
191
192 if (encoded_size > 0) {
193 encoded = CFDataCreateMutable(NULL, encoded_size);
194 if (encoded) {
195 CFDataSetLength(encoded, encoded_size);
196 uint8_t * der = CFDataGetMutableBytePtr(encoded);
197 uint8_t * der_end = der + encoded_size;
198 if (!SOSCoderEncodeToDER(coder, error, der, der_end)) {
199 CFReleaseNull(encoded);
200 encoded = NULL;
201 }
202 }
203 }
204 return encoded;
205 }
206
207 static SOSCoderRef SOSCoderCreate_internal() {
208 SOSCoderRef p = CFTypeAllocate(SOSCoder, struct __OpaqueSOSCoder, kCFAllocatorDefault);
209
210 p->peer_id = NULL;
211 p->sessRef = NULL;
212 p->pendingResponse = NULL;
213 p->waitingForDataPacket = false;
214
215 p->hashOfLastReceived = NULL;
216 p->lastReceivedWasOld = false;
217
218 return p;
219
220 }
221
222 // 0 - Type not understood
223 // 1 - OCTET_STRING, just stored the data for OTR
224 // 2 - SEQUENCE with no version value
225 // 3 - SEQUENCE with version value we pull out of the CCDER_INTEGER
226
227 typedef enum coderExportFormatVersion {
228 kNotUnderstood = 0,
229 kCoderAsOTRDataOnly = 1,
230 kCoderAsSequence = 2,
231 kCoderAsVersionedSequence = 3,
232
233 kCurrentCoderExportVersion = kCoderAsVersionedSequence
234 } CoderExportFormatVersion;
235
236 static uint64_t SOSCoderGetExportedVersion(const uint8_t *der, const uint8_t *der_end) {
237 ccder_tag tag;
238 uint64_t result = kNotUnderstood;
239 require(ccder_decode_tag(&tag, der, der_end),xit);
240 switch (tag) {
241 case CCDER_OCTET_STRING: // TODO: this code is safe to delete?
242 result = kCoderAsOTRDataOnly;
243 break;
244
245 case CCDER_CONSTRUCTED_SEQUENCE:
246 {
247 const uint8_t *sequence_end = NULL;
248 der = ccder_decode_sequence_tl(&sequence_end, der, der_end);
249 ccder_tag firstSequenceTag;
250 require(ccder_decode_tag(&firstSequenceTag, der, der_end),xit);
251
252 switch (firstSequenceTag) {
253 case CCDER_OCTET_STRING:
254 result = kCoderAsSequence;
255 break;
256 case CCDER_INTEGER:
257 der = ccder_decode_uint64(NULL, der, sequence_end);
258 if (der == NULL) {
259 result = kNotUnderstood;
260 } else {
261 result = kCoderAsVersionedSequence;
262 }
263 break;
264 }
265 }
266 }
267 xit:
268 return result;
269
270 }
271
272 SOSCoderRef SOSCoderCreateFromData(CFDataRef exportedData, CFErrorRef *error) {
273 // TODO: fill in errors for all failure cases
274 //require_action_quiet(coder, xit, SOSCreateError(kSOSErrorSendFailure, CFSTR("No coder for peer"), NULL, error));
275
276 SOSCoderRef p = SOSCoderCreate_internal();
277
278 const uint8_t *der = CFDataGetBytePtr(exportedData);
279 const uint8_t *der_end = der + CFDataGetLength(exportedData);
280
281 CFDataRef otr_data = NULL;
282
283 switch (SOSCoderGetExportedVersion(der, der_end)) {
284 case kCoderAsOTRDataOnly:
285 der = der_decode_data(kCFAllocatorDefault, 0, &otr_data, error, der, der_end);
286 p->waitingForDataPacket = false;
287 break;
288
289 case kCoderAsSequence:
290 {
291 const uint8_t *sequence_end = NULL;
292 der = ccder_decode_sequence_tl(&sequence_end, der, der_end);
293
294 require_action_quiet(sequence_end == der_end, fail, SecCFDERCreateError(kSOSErrorDecodeFailure, CFSTR("Extra data in SOS coder"), NULL, error));
295
296 der = der_decode_data(kCFAllocatorDefault, 0, &otr_data, error, der, sequence_end);
297 der = ccder_decode_bool(&p->waitingForDataPacket, der, sequence_end);
298 if (der != sequence_end) { // optionally a pending response
299 der = der_decode_data(kCFAllocatorDefault, 0, &p->pendingResponse, error, der, sequence_end);
300 }
301 }
302 break;
303
304 case kCoderAsVersionedSequence:
305 {
306 const uint8_t *sequence_end = NULL;
307 der = ccder_decode_sequence_tl(&sequence_end, der, der_end);
308
309 require_action_quiet(sequence_end == der_end, fail, SecCFDERCreateError(kSOSErrorDecodeFailure, CFSTR("Extra data in SOS coder"), NULL, error));
310
311 uint64_t version;
312 der = ccder_decode_uint64(&version, der, sequence_end);
313 if (version != kCoderAsVersionedSequence) {
314 SOSErrorCreate(kSOSErrorDecodeFailure, error, NULL, CFSTR("Unsupported Sequence Version: %lld"), version);
315 goto fail;
316 }
317
318 der = der_decode_data(kCFAllocatorDefault, 0, &otr_data, error, der, sequence_end);
319 der = ccder_decode_bool(&p->waitingForDataPacket, der, sequence_end);
320 der = ccder_decode_bool(&p->lastReceivedWasOld, der, sequence_end);
321 der = der_decode_data(kCFAllocatorDefault, 0, &p->hashOfLastReceived, error, der, sequence_end);
322 if (der != sequence_end) { // optionally a pending response
323 der = der_decode_data(kCFAllocatorDefault, 0, &p->pendingResponse, error, der, sequence_end);
324 }
325 }
326 break;
327
328 default:
329 SOSErrorCreate(kSOSErrorDecodeFailure, error, NULL, CFSTR("Unsupported SOS Coder DER"));
330 goto fail;
331 }
332
333 require(der, fail);
334
335 p->sessRef = SecOTRSessionCreateFromData(NULL, otr_data);
336 require(p->sessRef, fail);
337
338 if (p->hashOfLastReceived == NULL)
339 p->hashOfLastReceived = CFDataCreateMutableWithScratch(kCFAllocatorDefault, lastReceived_di()->output_size);
340
341 CFReleaseSafe(otr_data);
342 return p;
343
344 fail:
345 CFReleaseNull(p);
346 CFReleaseSafe(otr_data);
347 return NULL;
348 }
349
350
351 SOSCoderRef SOSCoderCreate(SOSPeerInfoRef peerInfo, SOSFullPeerInfoRef myPeerInfo, CFBooleanRef useCompact, CFErrorRef *error) {
352 CFAllocatorRef allocator = CFGetAllocator(peerInfo);
353
354 SOSCoderRef coder = SOSCoderCreate_internal();
355
356 CFErrorRef localError = NULL;
357
358 SecOTRFullIdentityRef myRef = NULL;
359 SecOTRPublicIdentityRef peerRef = NULL;
360 SecKeyRef privateKey = NULL;
361 SecKeyRef publicKey = NULL;
362
363 if (myPeerInfo && peerInfo) {
364 privateKey = SOSFullPeerInfoCopyDeviceKey(myPeerInfo, &localError);
365 require_quiet(privateKey, errOut);
366
367 myRef = SecOTRFullIdentityCreateFromSecKeyRef(allocator, privateKey, &localError);
368 require_quiet(myRef, errOut);
369
370 CFReleaseNull(privateKey);
371
372 publicKey = SOSPeerInfoCopyPubKey(peerInfo, &localError);
373 require(publicKey, errOut);
374
375 peerRef = SecOTRPublicIdentityCreateFromSecKeyRef(allocator, publicKey, &localError);
376 require_quiet(peerRef, errOut);
377
378 if(useCompact == kCFBooleanTrue)
379 coder->sessRef = SecOTRSessionCreateFromIDAndFlags(allocator, myRef, peerRef, kSecOTRUseAppleCustomMessageFormat);
380
381 else
382 coder->sessRef = SecOTRSessionCreateFromID(allocator, myRef, peerRef);
383
384 require(coder->sessRef, errOut);
385
386 coder->waitingForDataPacket = false;
387 coder->pendingResponse = NULL;
388
389 CFReleaseNull(publicKey);
390 CFReleaseNull(privateKey);
391 CFReleaseNull(myRef);
392 CFReleaseNull(peerRef);
393 } else {
394 secnotice("coder", "NULL Coder requested, no transport security");
395 }
396
397 coder->hashOfLastReceived = CFDataCreateMutableWithScratch(kCFAllocatorDefault, lastReceived_di()->output_size);
398 coder->lastReceivedWasOld = false;
399
400 SOSCoderStart(coder, NULL);
401
402 return coder;
403
404 errOut:
405 secerror("Coder create failed: %@\n", localError ? localError : (CFTypeRef)CFSTR("No local error in SOSCoderCreate"));
406 secerror("Coder create failed: %@\n", error ? *error : (CFTypeRef)CFSTR("WTF NULL?"));
407 CFReleaseNull(myRef);
408 CFReleaseNull(peerRef);
409 CFReleaseNull(publicKey);
410 CFReleaseNull(privateKey);
411
412 CFReleaseNull(coder);
413 return NULL;
414 }
415
416 static void SOSCoderDestroy(CFTypeRef cf)
417 {
418 SOSCoderRef coder = (SOSCoderRef) cf;
419 if (coder) {
420 CFReleaseNull(coder->sessRef);
421 CFReleaseNull(coder->pendingResponse);
422 CFReleaseNull(coder->hashOfLastReceived);
423 }
424 }
425
426 void SOSCoderReset(SOSCoderRef coder)
427 {
428 SecOTRSessionReset(coder->sessRef);
429 coder->waitingForDataPacket = false;
430 CFReleaseNull(coder->pendingResponse);
431
432 coder->lastReceivedWasOld = false;
433 CFReleaseNull(coder->hashOfLastReceived);
434 coder->hashOfLastReceived = CFDataCreateMutableWithScratch(kCFAllocatorDefault, lastReceived_di()->output_size);
435 }
436
437 bool SOSCoderIsFor(SOSCoderRef coder, SOSPeerInfoRef peerInfo, SOSFullPeerInfoRef myPeerInfo) {
438 SecKeyRef theirPublicKey = NULL;
439 SecKeyRef myPublicKey = NULL;
440 bool isForThisPair = false;
441 CFErrorRef localError = NULL;
442
443 myPublicKey = SOSPeerInfoCopyPubKey(SOSFullPeerInfoGetPeerInfo(myPeerInfo), &localError);
444 require(myPublicKey, errOut);
445
446 theirPublicKey = SOSPeerInfoCopyPubKey(peerInfo, &localError);
447 require(theirPublicKey, errOut);
448
449 isForThisPair = SecOTRSIsForKeys(coder->sessRef, myPublicKey, theirPublicKey);
450
451 errOut:
452 if (localError) {
453 secerror("SOSCoderIsFor failed: %@\n", localError ? localError : (CFTypeRef)CFSTR("No local error in SOSCoderCreate"));
454 }
455
456 CFReleaseNull(myPublicKey);
457 CFReleaseNull(theirPublicKey);
458 CFReleaseNull(localError);
459 return isForThisPair;
460 }
461
462 CFDataRef SOSCoderCopyPendingResponse(SOSCoderRef coder)
463 {
464 return coder->pendingResponse ? CFDataCreateCopy(kCFAllocatorDefault, coder->pendingResponse) : NULL;
465 }
466
467 void SOSCoderConsumeResponse(SOSCoderRef coder)
468 {
469 CFReleaseNull(coder->pendingResponse);
470 }
471
472 static bool SOSOTRSAppendStartPacket(SecOTRSessionRef session, CFMutableDataRef appendPacket, CFErrorRef *error) {
473 OSStatus otrStatus = SecOTRSAppendStartPacket(session, appendPacket);
474 if (otrStatus != errSecSuccess) {
475 SOSCreateErrorWithFormat(kSOSErrorEncodeFailure, (error != NULL) ? *error : NULL, error, NULL, CFSTR("append start packet returned: %" PRIdOSStatus), otrStatus);
476 }
477 return otrStatus == errSecSuccess;
478 }
479
480 // Start OTR negotiation if we haven't already done so.
481 SOSCoderStatus
482 SOSCoderStart(SOSCoderRef coder, CFErrorRef *error) {
483 CFMutableStringRef action = CFStringCreateMutable(kCFAllocatorDefault, 0);
484 CFStringRef beginState = NULL;
485 SOSCoderStatus result = kSOSCoderFailure;
486 CFMutableDataRef startPacket = NULL;
487
488 require_action_quiet(coder->sessRef, coderFailure, CFStringAppend(action, CFSTR("*** no otr session ***")));
489 beginState = CFCopyDescription(coder->sessRef);
490 require_action_quiet(!coder->waitingForDataPacket, negotiatingOut, CFStringAppend(action, CFSTR("waiting for peer to send first data packet")));
491 require_action_quiet(!SecOTRSGetIsReadyForMessages(coder->sessRef), coderFailure, CFStringAppend(action, CFSTR("otr session ready"));
492 result = kSOSCoderDataReturned);
493 require_action_quiet(SecOTRSGetIsIdle(coder->sessRef), negotiatingOut, CFStringAppend(action, CFSTR("otr negotiating already")));
494 require_action_quiet(startPacket = CFDataCreateMutable(kCFAllocatorDefault, 0), coderFailure, SOSCreateError(kSOSErrorAllocationFailure, CFSTR("alloc failed"), NULL, error));
495 require_quiet(SOSOTRSAppendStartPacket(coder->sessRef, startPacket, error), coderFailure);
496 CFRetainAssign(coder->pendingResponse, startPacket);
497
498 negotiatingOut:
499 result = kSOSCoderNegotiating;
500 coderFailure:
501 // Uber state log
502 if (result == kSOSCoderFailure && error && *error)
503 CFStringAppendFormat(action, NULL, CFSTR(" %@"), *error);
504 secinfo("coder", "%@ %s %@ %@ returned %s", beginState,
505 SecOTRPacketTypeString(startPacket), action, coder->sessRef, SOSCoderString(result));
506 CFReleaseNull(startPacket);
507 CFReleaseSafe(beginState);
508 CFRelease(action);
509
510 return result;
511
512 }
513
514 SOSCoderStatus
515 SOSCoderResendDH(SOSCoderRef coder, CFErrorRef *error) {
516 if(coder->sessRef == NULL) return kSOSCoderDataReturned;
517 CFMutableDataRef startPacket = CFDataCreateMutable(kCFAllocatorDefault, 0);
518 SOSCoderStatus result = kSOSCoderFailure;
519 require_noerr_quiet(SecOTRSAppendRestartPacket(coder->sessRef, startPacket), exit);
520 secnotice("coder", "Resending OTR Start %@", startPacket);
521 CFRetainAssign(coder->pendingResponse, startPacket);
522 result = kSOSCoderNegotiating;
523 exit:
524 CFReleaseNull(startPacket);
525 return result;
526 }
527
528
529 static SOSCoderStatus nullCoder(CFDataRef from, CFMutableDataRef *to) {
530 *to = CFDataCreateMutableCopy(NULL, CFDataGetLength(from), from);
531 return kSOSCoderDataReturned;
532 }
533
534 SOSCoderStatus SOSCoderUnwrap(SOSCoderRef coder, CFDataRef codedMessage, CFMutableDataRef *message,
535 CFStringRef clientId, CFErrorRef *error) {
536 if(codedMessage == NULL) return kSOSCoderDataReturned;
537 if(coder->sessRef == NULL) return nullCoder(codedMessage, message);
538 CFMutableStringRef action = CFStringCreateMutable(kCFAllocatorDefault, 0);
539 /* This should be the "normal" case. We just use OTR to unwrap the received message. */
540 SOSCoderStatus result = kSOSCoderFailure;
541
542 CFStringRef beginState = CFCopyDescription(coder->sessRef);
543 enum SecOTRSMessageKind kind = SecOTRSGetMessageKind(coder->sessRef, codedMessage);
544
545
546 switch (kind) {
547 case kOTRNegotiationPacket: {
548 /* If we're in here we haven't completed negotiating a session. Use SecOTRSProcessPacket() to go through
549 the negotiation steps and immediately send a reply back if necessary using the sendBlock. This
550 assumes the sendBlock is still available.
551 */
552 CFMutableDataRef response = CFDataCreateMutable(kCFAllocatorDefault, 0);
553 OSStatus ppstatus = errSecSuccess;
554 if (response) {
555 switch (ppstatus = SecOTRSProcessPacket(coder->sessRef, codedMessage, response)) {
556 case errSecSuccess:
557 if (CFDataGetLength(response) > 1) {
558 CFStringAppendFormat(action, NULL, CFSTR("Sending OTR Response %s"), SecOTRPacketTypeString(response));
559 CFRetainAssign(coder->pendingResponse, response);
560 result = kSOSCoderNegotiating;
561 if (SecOTRSGetIsReadyForMessages(coder->sessRef)) {
562 CFStringAppend(action, CFSTR(" begin waiting for data packet"));
563 coder->waitingForDataPacket = true;
564 }
565 } else if(!SecOTRSGetIsReadyForMessages(coder->sessRef)) {
566 CFStringAppend(action, CFSTR("stuck?"));
567 result = kSOSCoderNegotiating;
568 } else {
569 CFStringAppend(action, CFSTR("completed negotiation"));
570 result = kSOSCoderNegotiationCompleted;
571 coder->waitingForDataPacket = false;
572 }
573 break;
574 case errSecDecode:
575 CFStringAppend(action, CFSTR("resending dh"));
576 result = SOSCoderResendDH(coder, error);
577 break;
578 default:
579 SOSCreateErrorWithFormat(kSOSErrorEncodeFailure, (error != NULL) ? *error : NULL, error, NULL, CFSTR("%@ Cannot negotiate session (%ld)"), clientId, (long)ppstatus);
580 result = kSOSCoderFailure;
581 break;
582 };
583 } else {
584 SOSCreateErrorWithFormat(kSOSErrorAllocationFailure, (error != NULL) ? *error : NULL, error, NULL, CFSTR("%@ Cannot allocate CFData"), clientId);
585 result = kSOSCoderFailure;
586 }
587
588 CFReleaseNull(response);
589
590 break;
591 }
592
593 case kOTRDataPacket:
594 {
595 CFDataRef previousMessageHash = coder->hashOfLastReceived;
596 coder->hashOfLastReceived = CFDataCreateWithHash(kCFAllocatorDefault, lastReceived_di(), CFDataGetBytePtr(codedMessage), CFDataGetLength(codedMessage));
597 bool lastWasOld = coder->lastReceivedWasOld;
598 coder->lastReceivedWasOld = false;
599
600 if(!SecOTRSGetIsReadyForMessages(coder->sessRef)) {
601 CFStringAppend(action, CFSTR("not ready for data; resending DH packet"));
602 SetCloudKeychainTraceValueForKey(kCloudKeychainNumberOfTimesSyncFailed, 1);
603 result = SOSCoderResendDH(coder, error);
604 } else {
605 if (coder->waitingForDataPacket) {
606 CFStringAppend(action, CFSTR("got data packet we were waiting for "));
607 coder->waitingForDataPacket = false;
608 }
609 CFMutableDataRef exposed = CFDataCreateMutable(0, 0);
610 OSStatus otrResult = SecOTRSVerifyAndExposeMessage(coder->sessRef, codedMessage, exposed);
611 CFStringAppend(action, CFSTR("verify and expose message"));
612 switch(otrResult) {
613 case errSecSuccess:
614 CFStringAppend(action, CFSTR("decoded OTR protected packet"));
615 CFTransferRetained(*message, exposed);
616 result = kSOSCoderDataReturned;
617 break;
618 case errSecOTRTooOld:
619 if (CFEqualSafe(previousMessageHash, coder->hashOfLastReceived)) {
620 CFStringAppend(action, CFSTR(" repeated"));
621 result = kSOSCoderStaleEvent;
622 } else {
623 coder->lastReceivedWasOld = true;
624 if (lastWasOld) {
625 CFStringAppend(action, CFSTR(" too old, repeated renegotiating"));
626 // Fail so we will renegotiate
627 result = kSOSCoderFailure;
628 } else {
629 CFStringAppend(action, CFSTR(" too old, forcing message"));
630 // Force message send.
631 result = kSOSCoderForceMessage;
632 }
633 }
634 break;
635 case errSecOTRIDTooNew:
636 CFStringAppend(action, CFSTR(" too new"));
637 result = kSOSCoderTooNew;
638 break;
639 default:
640 SecError(otrResult, error, CFSTR("%@ Cannot expose message: %" PRIdOSStatus), clientId, otrResult);
641 secerror("%@ Decode OTR Protected Packet: %@", clientId, error ? *error : NULL);
642 result = kSOSCoderFailure;
643 break;
644 }
645
646 CFReleaseNull(exposed);
647 }
648 CFReleaseNull(previousMessageHash);
649 }
650 break;
651
652 default:
653 secerror("%@ Unknown packet type: %@", clientId, codedMessage);
654 SOSCreateError(kSOSErrorDecodeFailure, CFSTR("Unknown packet type"), (error != NULL) ? *error : NULL, error);
655 result = kSOSCoderFailure;
656 break;
657 };
658
659 // Uber state log
660 if (result == kSOSCoderFailure && error && *error)
661 CFStringAppendFormat(action, NULL, CFSTR(" %@"), *error);
662 secnotice("coder", "%@ %@ %s %@ %@ returned %s", clientId, beginState,
663 SecOTRPacketTypeString(codedMessage), action, coder->sessRef, SOSCoderString(result));
664 CFReleaseSafe(beginState);
665 CFRelease(action);
666
667 return result;
668 }
669
670
671 SOSCoderStatus SOSCoderWrap(SOSCoderRef coder, CFDataRef message, CFMutableDataRef *codedMessage, CFStringRef clientId, CFErrorRef *error) {
672 CFMutableStringRef action = CFStringCreateMutable(kCFAllocatorDefault, 0);
673 SOSCoderStatus result = kSOSCoderDataReturned;
674 CFStringRef beginState = NULL;
675 CFMutableDataRef encoded = NULL;
676 OSStatus otrStatus = 0;
677
678 require_action_quiet(coder->sessRef, errOut,
679 CFStringAppend(action, CFSTR("*** using null coder ***"));
680 result = nullCoder(message, codedMessage));
681 beginState = CFCopyDescription(coder->sessRef);
682 require_action_quiet(SecOTRSGetIsReadyForMessages(coder->sessRef), errOut,
683 CFStringAppend(action, CFSTR("not ready"));
684 result = kSOSCoderNegotiating);
685 require_action_quiet(!coder->waitingForDataPacket, errOut,
686 CFStringAppend(action, CFSTR("waiting for peer to send data packet first"));
687 result = kSOSCoderNegotiating);
688 require_action_quiet(encoded = CFDataCreateMutable(kCFAllocatorDefault, 0), errOut,
689 SOSCreateErrorWithFormat(kSOSErrorAllocationFailure, NULL, error, NULL, CFSTR("%@ alloc failed"), clientId);
690 result = kSOSCoderFailure);
691 require_noerr_action_quiet(otrStatus = SecOTRSSignAndProtectMessage(coder->sessRef, message, encoded), errOut,
692 SOSCreateErrorWithFormat(kSOSErrorEncodeFailure, (error != NULL) ? *error : NULL, error, NULL, CFSTR("%@ cannot protect message: %" PRIdOSStatus), clientId, otrStatus);
693 CFReleaseNull(encoded);
694 result = kSOSCoderFailure);
695 *codedMessage = encoded;
696
697 errOut:
698 // Uber state log
699 if (result == kSOSCoderFailure && error && *error)
700 CFStringAppendFormat(action, NULL, CFSTR(" %@"), *error);
701 secinfo("coder", "%@ %@ %s %@ %@ returned %s", clientId, beginState,
702 SecOTRPacketTypeString(encoded), action, coder->sessRef, SOSCoderString(result));
703 CFReleaseSafe(beginState);
704 CFRelease(action);
705
706 return result;
707 }
708
709 bool SOSCoderCanWrap(SOSCoderRef coder) {
710 return coder->sessRef && SecOTRSGetIsReadyForMessages(coder->sessRef) && !coder->waitingForDataPacket;
711 }