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