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