Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(681)

Side by Side Diff: runtime/bin/secure_socket_macos.cc

Issue 1721283002: Implements secure sockets on Mac OS with SecureTransport API (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Address comments Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « runtime/bin/secure_socket_macos.h ('k') | runtime/bin/secure_socket_patch.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 #include "platform/globals.h"
6 #if defined(TARGET_OS_MACOS)
7
8 #include "bin/secure_socket.h"
9 #include "bin/secure_socket_macos.h"
10
11 #include <errno.h>
12 #include <fcntl.h>
13 #include <sys/stat.h>
14 #include <sys/syslimits.h>
15 #include <stdio.h>
16 #include <string.h>
17
18 #include <CoreFoundation/CoreFoundation.h>
19 #include <Security/SecureTransport.h>
20 #include <Security/Security.h>
21
22 #include "bin/builtin.h"
23 #include "bin/dartutils.h"
24 #include "bin/lockers.h"
25 #include "bin/log.h"
26 #include "bin/socket.h"
27 #include "bin/thread.h"
28 #include "bin/utils.h"
29
30 #include "platform/text_buffer.h"
31 #include "platform/utils.h"
32
33 #include "include/dart_api.h"
34
35 // Return the error from the containing function if handle is an error handle.
36 #define RETURN_IF_ERROR(handle) \
37 { \
38 Dart_Handle __handle = handle; \
39 if (Dart_IsError((__handle))) { \
40 return __handle; \
41 } \
42 }
43
44 // We need to access this private API function to create a SecIdentityRef
45 // without writing a custom keychain to the filesystem. This is the approach
46 // taken in WebKit:
47 // https://webkit.googlesource.com/WebKit/+/master/Source/WebKit2/Shared/cf/Argu mentCodersCF.cpp
48 extern "C" {
49 SecIdentityRef SecIdentityCreate(CFAllocatorRef allocator,
50 SecCertificateRef certificate,
51 SecKeyRef private_key);
52 }
53
54 namespace dart {
55 namespace bin {
56
57 // SSLCertContext wraps the certificates needed for a SecureTransport
58 // connection. Fields are protected by the mutex_ field, and may only be set
59 // once. This is to allow access by both the Dart thread and the IOService
60 // thread. Setters return false if the field was already set.
61 class SSLCertContext {
62 public:
63 SSLCertContext() :
64 mutex_(new Mutex()),
65 private_key_(NULL),
66 keychain_(NULL),
67 cert_chain_(NULL),
68 trusted_certs_(NULL),
69 cert_authorities_(NULL),
70 trust_builtin_(false) {}
71
72 ~SSLCertContext() {
73 if (private_key_ != NULL) {
74 CFRelease(private_key_);
75 }
76 if (keychain_ != NULL) {
77 SecKeychainDelete(keychain_);
78 CFRelease(keychain_);
79 }
80 if (cert_chain_ != NULL) {
81 CFRelease(cert_chain_);
82 }
83 if (trusted_certs_ != NULL) {
84 CFRelease(trusted_certs_);
85 }
86 if (cert_authorities_ != NULL) {
87 CFRelease(cert_authorities_);
88 }
89 delete mutex_;
90 }
91
92 SecKeyRef private_key() {
93 MutexLocker m(mutex_);
94 return private_key_;
95 }
96 bool set_private_key(SecKeyRef private_key) {
97 MutexLocker m(mutex_);
98 if (private_key_ != NULL) {
99 return false;
100 }
101 private_key_ = private_key;
102 return true;
103 }
104
105 SecKeychainRef keychain() {
106 MutexLocker m(mutex_);
107 return keychain_;
108 }
109 bool set_keychain(SecKeychainRef keychain) {
110 MutexLocker m(mutex_);
111 if (keychain_ != NULL) {
112 return false;
113 }
114 keychain_ = keychain;
115 return true;
116 }
117
118 CFArrayRef cert_chain() {
119 MutexLocker m(mutex_);
120 return cert_chain_;
121 }
122 bool set_cert_chain(CFArrayRef cert_chain) {
123 MutexLocker m(mutex_);
124 if (cert_chain_ != NULL) {
125 return false;
126 }
127 cert_chain_ = cert_chain;
128 return true;
129 }
130
131 CFArrayRef trusted_certs() {
132 MutexLocker m(mutex_);
133 return trusted_certs_;
134 }
135 bool set_trusted_certs(CFArrayRef trusted_certs) {
136 MutexLocker m(mutex_);
137 if (trusted_certs_ != NULL) {
138 return false;
139 }
140 trusted_certs_ = trusted_certs;
141 return true;
142 }
143
144 CFArrayRef cert_authorities() {
145 MutexLocker m(mutex_);
146 return cert_authorities_;
147 }
148 bool set_cert_authorities(CFArrayRef cert_authorities) {
149 MutexLocker m(mutex_);
150 if (cert_authorities_ != NULL) {
151 return false;
152 }
153 cert_authorities_ = cert_authorities;
154 return true;
155 }
156
157 bool trust_builtin() {
158 MutexLocker m(mutex_);
159 return trust_builtin_;
160 }
161 void set_trust_builtin(bool trust_builtin) {
162 MutexLocker m(mutex_);
163 trust_builtin_ = trust_builtin;
164 }
165
166 private:
167 // The context is accessed both by Dart code and the IOService. This mutex
168 // protects all fields.
169 Mutex* mutex_;
170
171 SecKeyRef private_key_;
172 SecKeychainRef keychain_;
173
174 // CFArrays of SecCertificateRef.
175 CFArrayRef cert_chain_;
176 CFArrayRef trusted_certs_;
177 CFArrayRef cert_authorities_;
178
179 bool trust_builtin_;
180
181 DISALLOW_COPY_AND_ASSIGN(SSLCertContext);
182 };
183
184 static const int kSSLFilterNativeFieldIndex = 0;
185 static const int kSecurityContextNativeFieldIndex = 0;
186 static const int kX509NativeFieldIndex = 0;
187
188 static const bool SSL_LOG_STATUS = false;
189 static const bool SSL_LOG_DATA = false;
190 static const bool SSL_LOG_CERTS = false;
191 static const int SSL_ERROR_MESSAGE_BUFFER_SIZE = 1000;
192 static const intptr_t PEM_BUFSIZE = 1024;
193
194 static char* CFStringRefToCString(CFStringRef cfstring) {
195 CFIndex len = CFStringGetLength(cfstring);
196 CFIndex max_len =
197 CFStringGetMaximumSizeForEncoding(len, kCFStringEncodingUTF8) + 1;
198 char* result = reinterpret_cast<char*>(Dart_ScopeAllocate(max_len));
199 ASSERT(result != NULL);
200 bool success =
201 CFStringGetCString(cfstring, result, max_len, kCFStringEncodingUTF8);
202 return success ? result : NULL;
203 }
204
205
206 // Handle an error reported from the SecureTransport library.
207 static void ThrowIOException(OSStatus status,
208 const char* exception_type,
209 const char* message) {
210 TextBuffer status_message(SSL_ERROR_MESSAGE_BUFFER_SIZE);
211 CFStringRef error_string = SecCopyErrorMessageString(status, NULL);
212 if (error_string == NULL) {
213 status_message.Printf("OSStatus = %ld: https://www.osstatus.com",
214 static_cast<intptr_t>(status));
215 } else {
216 char* error = CFStringRefToCString(error_string);
217 status_message.Printf("OSStatus = %ld: %s",
218 static_cast<intptr_t>(status), error);
219 CFRelease(error_string);
220 }
221 OSError os_error_struct(status, status_message.buf(), OSError::kBoringSSL);
222 Dart_Handle os_error = DartUtils::NewDartOSError(&os_error_struct);
223 Dart_Handle exception =
224 DartUtils::NewDartIOException(exception_type, message, os_error);
225 ASSERT(!Dart_IsError(exception));
226 Dart_ThrowException(exception);
227 UNREACHABLE();
228 }
229
230
231 static void CheckStatus(OSStatus status,
232 const char* type,
233 const char* message) {
234 if (status == noErr) {
235 return;
236 }
237 ThrowIOException(status, type, message);
238 }
239
240
241 static SSLFilter* GetFilter(Dart_NativeArguments args) {
242 SSLFilter* filter;
243 Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0));
244 ASSERT(Dart_IsInstance(dart_this));
245 ThrowIfError(Dart_GetNativeInstanceField(
246 dart_this,
247 kSSLFilterNativeFieldIndex,
248 reinterpret_cast<intptr_t*>(&filter)));
249 return filter;
250 }
251
252
253 static void DeleteFilter(void* isolate_data,
254 Dart_WeakPersistentHandle handle,
255 void* context_pointer) {
256 SSLFilter* filter = reinterpret_cast<SSLFilter*>(context_pointer);
257 delete filter;
258 }
259
260
261 static Dart_Handle SetFilter(Dart_NativeArguments args, SSLFilter* filter) {
262 ASSERT(filter != NULL);
263 const int approximate_size_of_filter = 1500;
264 Dart_Handle dart_this = Dart_GetNativeArgument(args, 0);
265 RETURN_IF_ERROR(dart_this);
266 ASSERT(Dart_IsInstance(dart_this));
267 Dart_Handle err = Dart_SetNativeInstanceField(
268 dart_this,
269 kSSLFilterNativeFieldIndex,
270 reinterpret_cast<intptr_t>(filter));
271 RETURN_IF_ERROR(err);
272 Dart_NewWeakPersistentHandle(dart_this,
273 reinterpret_cast<void*>(filter),
274 approximate_size_of_filter,
275 DeleteFilter);
276 return Dart_Null();
277 }
278
279
280 static SSLCertContext* GetSecurityContext(Dart_NativeArguments args) {
281 SSLCertContext* context;
282 Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0));
283 ASSERT(Dart_IsInstance(dart_this));
284 ThrowIfError(Dart_GetNativeInstanceField(
285 dart_this,
286 kSecurityContextNativeFieldIndex,
287 reinterpret_cast<intptr_t*>(&context)));
288 return context;
289 }
290
291
292 static void DeleteCertContext(void* isolate_data,
293 Dart_WeakPersistentHandle handle,
294 void* context_pointer) {
295 SSLCertContext* context = static_cast<SSLCertContext*>(context_pointer);
296 delete context;
297 }
298
299
300 static Dart_Handle SetSecurityContext(Dart_NativeArguments args,
301 SSLCertContext* context) {
302 const int approximate_size_of_context = 1500;
303 Dart_Handle dart_this = Dart_GetNativeArgument(args, 0);
304 RETURN_IF_ERROR(dart_this);
305 ASSERT(Dart_IsInstance(dart_this));
306 Dart_Handle err = Dart_SetNativeInstanceField(
307 dart_this,
308 kSecurityContextNativeFieldIndex,
309 reinterpret_cast<intptr_t>(context));
310 RETURN_IF_ERROR(err);
311 Dart_NewWeakPersistentHandle(dart_this,
312 context,
313 approximate_size_of_context,
314 DeleteCertContext);
315 return Dart_Null();
316 }
317
318
319 static SecCertificateRef GetX509Certificate(Dart_NativeArguments args) {
320 SecCertificateRef certificate;
321 Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0));
322 ASSERT(Dart_IsInstance(dart_this));
323 ThrowIfError(Dart_GetNativeInstanceField(
324 dart_this,
325 kX509NativeFieldIndex,
326 reinterpret_cast<intptr_t*>(&certificate)));
327 return certificate;
328 }
329
330
331 static void ReleaseCertificate(void* isolate_data,
332 Dart_WeakPersistentHandle handle,
333 void* context_pointer) {
334 SecCertificateRef cert = reinterpret_cast<SecCertificateRef>(context_pointer);
335 CFRelease(cert);
336 }
337
338
339 static Dart_Handle WrappedX509Certificate(SecCertificateRef certificate) {
340 const intptr_t approximate_size_of_certificate = 1500;
341 if (certificate == NULL) {
342 return Dart_Null();
343 }
344 Dart_Handle x509_type =
345 DartUtils::GetDartType(DartUtils::kIOLibURL, "X509Certificate");
346 if (Dart_IsError(x509_type)) {
347 return x509_type;
348 }
349 Dart_Handle arguments[] = { NULL };
350
351 Dart_Handle result =
352 Dart_New(x509_type, DartUtils::NewString("_"), 0, arguments);
353 if (Dart_IsError(result)) {
354 return result;
355 }
356 ASSERT(Dart_IsInstance(result));
357
358 // CFRetain in case the returned Dart object outlives the SecurityContext.
359 // CFRelease is in the Dart object's finalizer
360 CFRetain(certificate);
361 Dart_NewWeakPersistentHandle(result,
362 reinterpret_cast<void*>(certificate),
363 approximate_size_of_certificate,
364 ReleaseCertificate);
365
366 Dart_Handle status = Dart_SetNativeInstanceField(
367 result,
368 kX509NativeFieldIndex,
369 reinterpret_cast<intptr_t>(certificate));
370 if (Dart_IsError(status)) {
371 return status;
372 }
373 return result;
374 }
375
376
377 // Where the argument to the constructor is the handle for an object
378 // implementing List<int>, this class creates a scope in which the memory
379 // backing the list can be accessed.
380 //
381 // Do not make Dart_ API calls while in a ScopedMemBuffer.
382 // Do not call Dart_PropagateError while in a ScopedMemBuffer.
383 class ScopedMemBuffer {
384 public:
385 explicit ScopedMemBuffer(Dart_Handle object) {
386 if (!Dart_IsTypedData(object) && !Dart_IsList(object)) {
387 Dart_ThrowException(DartUtils::NewDartArgumentError(
388 "Argument is not a List<int>"));
389 }
390
391 uint8_t* bytes = NULL;
392 intptr_t bytes_len = 0;
393 bool is_typed_data = false;
394 if (Dart_IsTypedData(object)) {
395 is_typed_data = true;
396 Dart_TypedData_Type typ;
397 ThrowIfError(Dart_TypedDataAcquireData(
398 object,
399 &typ,
400 reinterpret_cast<void**>(&bytes),
401 &bytes_len));
402 } else {
403 ASSERT(Dart_IsList(object));
404 ThrowIfError(Dart_ListLength(object, &bytes_len));
405 bytes = Dart_ScopeAllocate(bytes_len);
406 ASSERT(bytes != NULL);
407 ThrowIfError(Dart_ListGetAsBytes(object, 0, bytes, bytes_len));
408 }
409
410 object_ = object;
411 bytes_ = bytes;
412 bytes_len_ = bytes_len;
413 is_typed_data_ = is_typed_data;
414 }
415
416 ~ScopedMemBuffer() {
417 if (is_typed_data_) {
418 ThrowIfError(Dart_TypedDataReleaseData(object_));
419 }
420 }
421
422 uint8_t* get() const { return bytes_; }
423 intptr_t length() const { return bytes_len_; }
424
425 private:
426 Dart_Handle object_;
427 uint8_t* bytes_;
428 intptr_t bytes_len_;
429 bool is_typed_data_;
430
431 DISALLOW_ALLOCATION();
432 DISALLOW_COPY_AND_ASSIGN(ScopedMemBuffer);
433 };
434
435
436 static const char* GetPasswordArgument(Dart_NativeArguments args,
437 intptr_t index) {
438 Dart_Handle password_object =
439 ThrowIfError(Dart_GetNativeArgument(args, index));
440 const char* password = NULL;
441 if (Dart_IsString(password_object)) {
442 ThrowIfError(Dart_StringToCString(password_object, &password));
443 if (strlen(password) > PEM_BUFSIZE - 1) {
444 Dart_ThrowException(DartUtils::NewDartArgumentError(
445 "Password length is greater than 1023 bytes."));
446 }
447 } else if (Dart_IsNull(password_object)) {
448 password = "";
449 } else {
450 Dart_ThrowException(DartUtils::NewDartArgumentError(
451 "Password is not a String or null"));
452 }
453 return password;
454 }
455
456
457 static OSStatus GetKeyAndCerts(CFArrayRef items,
458 CFIndex items_length,
459 CFArrayRef* out_certs,
460 SecKeyRef* out_key) {
461 OSStatus status = noErr;
462
463 // Loop through the items, take only the first private key/identity, ignore
464 // any others, populate out_certs.
465 CFMutableArrayRef certs =
466 CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
467 SecKeyRef key = NULL;
468
469 for (CFIndex i = 0; i < items_length; ++i) {
470 CFTypeRef item =
471 reinterpret_cast<CFTypeRef>(CFArrayGetValueAtIndex(items, i));
472 CFTypeID item_type = CFGetTypeID(item);
473 if (item_type == SecCertificateGetTypeID()) {
474 if (SSL_LOG_CERTS) {
475 Log::Print("\titem %ld: Certificate\n", i);
476 }
477 CFArrayAppendValue(certs, item);
478 } else if ((item_type == SecKeyGetTypeID()) && (key == NULL)) {
479 if (SSL_LOG_CERTS) {
480 Log::Print("\titem %ld: Key\n", i);
481 }
482 key = reinterpret_cast<SecKeyRef>(const_cast<void*>(item));
483 CFRetain(key);
484 } else if ((item_type == SecIdentityGetTypeID()) && (key == NULL)) {
485 if (SSL_LOG_CERTS) {
486 Log::Print("\titem %ld: Identity\n", i);
487 }
488 SecIdentityRef identity =
489 reinterpret_cast<SecIdentityRef>(const_cast<void*>(item));
490 SecCertificateRef cert = NULL;
491
492 status = SecIdentityCopyPrivateKey(identity, &key);
493 if (status != noErr) {
494 CFRelease(certs);
495 return status;
496 }
497
498 status = SecIdentityCopyCertificate(identity, &cert);
499 if (status != noErr) {
500 CFRelease(key);
501 CFRelease(certs);
502 return status;
503 }
504 CFArrayAppendValue(certs, cert);
505 CFRelease(cert);
506 }
507 // Other item types are ignored.
508 }
509
510 if (out_key == NULL) {
511 if (key != NULL) {
512 CFRelease(key);
513 }
514 } else {
515 *out_key = key;
516 }
517
518 if (out_certs == NULL) {
519 if (certs != NULL) {
520 CFRelease(certs);
521 }
522 } else {
523 *out_certs = certs;
524 }
525 return status;
526 }
527
528
529 static OSStatus TryPEMImport(CFDataRef cfdata,
530 CFStringRef password,
531 CFArrayRef* out_certs,
532 SecKeyRef* out_key) {
533 OSStatus status = noErr;
534
535 SecExternalFormat format = kSecFormatPEMSequence;
536 SecExternalItemType sitem_type = kSecItemTypeAggregate;
537
538 SecKeyImportExportParameters params;
539 memset(&params, 0, sizeof(params));
540 params.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
541 params.flags = kSecKeyNoAccessControl;
542 params.passphrase = password;
543 params.keyAttributes = CSSM_KEYATTR_EXTRACTABLE;
544
545 CFArrayRef items = NULL;
546 status = SecKeychainItemImport(
547 cfdata, NULL, &format, &sitem_type, 0, &params, NULL, &items);
548
549 if (status != noErr) {
550 if (SSL_LOG_CERTS) {
551 Log::Print("TrySecItemImport failed with: %ld, type = %d, format = %d\n",
552 static_cast<intptr_t>(status), sitem_type, format);
553 }
554 return status;
555 }
556
557 CFIndex items_length = (items == NULL) ? 0 : CFArrayGetCount(items);
558 if (SSL_LOG_CERTS) {
559 Log::Print(
560 "TrySecItemImport succeeded, type = %d, format = %d, count = %ld\n",
561 sitem_type, format, items_length);
562 }
563
564 // Empty list indicates a decoding failure of some sort.
565 if ((items != NULL) && (items_length == 0)) {
566 CFRelease(items);
567 return errSSLBadCert;
568 }
569
570 status = GetKeyAndCerts(items, items_length, out_certs, out_key);
571 CFRelease(items);
572 return status;
573 }
574
575
576 static char* TempKeychainPath() {
577 const char* exes = "keychaindir.XXXX";
578 const char* fname = "keychain";
579 const char* temp_dir = getenv("TMPDIR");
580 if (temp_dir == NULL) {
581 temp_dir = getenv("TMP");
582 }
583 if (temp_dir == NULL) {
584 temp_dir = "/tmp/";
585 }
586 ASSERT(temp_dir != NULL);
587
588 TextBuffer path(PATH_MAX);
589 path.Printf("%s/%s", temp_dir, exes);
590 char* ret = mkdtemp(path.buf());
591 ASSERT(ret != NULL);
592 path.Printf("/%s", fname);
593
594 char* result =
595 reinterpret_cast<char*>(Dart_ScopeAllocate(path.length() + 1));
596 return strncpy(result, path.buf(), path.length() + 1);
597 }
598
599
600 static OSStatus CreateKeychain(SecKeychainRef* keychain) {
601 ASSERT(keychain != NULL);
602 OSStatus status = noErr;
603 const char* temp_keychain_pwd = "dartdart";
604 char* temp_file_path = TempKeychainPath();
605 ASSERT(temp_file_path != NULL);
606 if (SSL_LOG_CERTS) {
607 Log::Print("Temporary keychain at: '%s'\n", temp_file_path);
608 }
609 status = SecKeychainCreate(temp_file_path,
610 strlen(temp_keychain_pwd) + 1,
611 reinterpret_cast<const void*>(temp_keychain_pwd),
612 FALSE, // Prompt user? Definitely no.
613 NULL, // Default access rights.
614 keychain);
615 if (status != noErr) {
616 return status;
617 }
618 ASSERT(*keychain != NULL);
619 return status;
620 }
621
622
623 static OSStatus TryPKCS12Import(CFDataRef cfdata,
624 CFStringRef password,
625 CFArrayRef* out_certs,
626 SecKeyRef* out_key,
627 SecKeychainRef* out_keychain) {
628 OSStatus status = noErr;
629
630 SecExternalFormat format = kSecFormatPKCS12;
631 SecExternalItemType sitem_type = kSecItemTypeAggregate;
632
633 SecKeyImportExportParameters params;
634 memset(&params, 0, sizeof(params));
635 params.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
636 params.flags = kSecKeyNoAccessControl;
637 params.passphrase = password;
638 params.keyAttributes = CSSM_KEYATTR_EXTRACTABLE;
639
640 CFArrayRef items = NULL;
641 if (SSL_LOG_CERTS) {
642 Log::Print("Trying PKCS12 import with: type = %d, format = %d\n",
643 sitem_type, format);
644 }
645
646 // The documentation for SecKeychainItemImport here:
647 //
648 // https://developer.apple.com/library/mac/documentation/Security/Reference/ke ychainservices/index.html
649 //
650 // states that when the SecKeychainRef argument is NULL, the CFArrayRef*
651 // argument will be populated by an array containing all keys, identities,
652 // and certificates from the data in the CFDataRef argument.
653 //
654 // Unfortunately, this is not true. The code to populate the CFArrayRef with
655 // keys and identities from PKCS12 data has been skipped and/or commented out,
656 // here:
657 //
658 // https://github.com/Apple-FOSS-Mirror/Security/blob/master/libsecurity_keych ain/lib/SecImportExportAgg.cpp#L636
659 //
660 // as "floating" SecKeyRefs from the PKCS12 decoder haven't been implemented.
661 // That is, each private key instance coming from the PKCS12 decoder has to be
662 // associated with a keychain instance. Thus, as a workaround, we create a
663 // temporary keychain here if one is needed, and stash it below in a
664 // SecurityContext. This has the drawbacks:
665 // 1.) We need to make a temporary directory to hold the keychain file, and
666 // 2.) SecKeychainItemImport() probably does blocking IO to create and
667 // manipulate the keychain file.
668 // So if the API is updated, this keychain should not be used.
669 SecKeychainRef keychain = NULL;
670 if (out_key != NULL) {
671 ASSERT(out_keychain != NULL);
672 status = CreateKeychain(&keychain);
673 if (status != noErr) {
674 return status;
675 }
676 *out_keychain = keychain;
677 }
678
679 status = SecKeychainItemImport(
680 cfdata, NULL, &format, &sitem_type, 0, &params, keychain, &items);
681 if (status != noErr) {
682 if (SSL_LOG_CERTS) {
683 Log::Print("TrySecItemImport failed with: %ld, it = %d, format = %d\n",
684 static_cast<intptr_t>(status), sitem_type, format);
685 }
686 return status;
687 }
688
689 CFIndex items_length = (items == NULL) ? 0 : CFArrayGetCount(items);
690 if (SSL_LOG_CERTS) {
691 Log::Print("TrySecItemImport succeeded, count = %ld\n", items_length);
692 }
693
694 // Empty list indicates a decoding failure of some sort.
695 if ((items != NULL) && (items_length == 0)) {
696 CFRelease(items);
697 return errSSLBadCert;
698 }
699
700 status = GetKeyAndCerts(items, items_length, out_certs, out_key);
701 CFRelease(items);
702 return status;
703 }
704
705
706 static OSStatus ExtractSecItems(uint8_t* buffer,
707 intptr_t length,
708 const char* password,
709 CFArrayRef* out_certs,
710 SecKeyRef* out_key,
711 SecKeychainRef* out_keychain) {
712 ASSERT(buffer != NULL);
713 ASSERT(password != NULL);
714 OSStatus status = noErr;
715
716 CFDataRef cfdata = CFDataCreateWithBytesNoCopy(
717 NULL, buffer, length, kCFAllocatorNull);
718 CFStringRef cfpassword = CFStringCreateWithCStringNoCopy(
719 NULL, password, kCFStringEncodingUTF8, kCFAllocatorNull);
720 ASSERT(cfdata != NULL);
721 ASSERT(cfpassword != NULL);
722
723 status = TryPEMImport(cfdata, cfpassword, out_certs, out_key);
724 if (status != noErr) {
725 status =
726 TryPKCS12Import(cfdata, cfpassword, out_certs, out_key, out_keychain);
727 }
728
729 CFRelease(cfdata);
730 CFRelease(cfpassword);
731 return status;
732 }
733
734
735 void FUNCTION_NAME(SecureSocket_Init)(Dart_NativeArguments args) {
736 Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0));
737 SSLFilter* filter = new SSLFilter(); // Deleted in DeleteFilter finalizer.
738 Dart_Handle err = SetFilter(args, filter);
739 if (Dart_IsError(err)) {
740 delete filter;
741 Dart_PropagateError(err);
742 }
743 err = filter->Init(dart_this);
744 if (Dart_IsError(err)) {
745 // The finalizer was set up by SetFilter. It will delete `filter` if there
746 // is an error.
747 filter->Destroy();
748 Dart_PropagateError(err);
749 }
750 }
751
752
753 void FUNCTION_NAME(SecureSocket_Connect)(Dart_NativeArguments args) {
754 Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0));
755 Dart_Handle host_name_object = ThrowIfError(Dart_GetNativeArgument(args, 1));
756 Dart_Handle context_object = ThrowIfError(Dart_GetNativeArgument(args, 2));
757 bool is_server = DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 3));
758 bool request_client_certificate =
759 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 4));
760 bool require_client_certificate =
761 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 5));
762
763 const char* host_name = NULL;
764 // TODO(whesse): Is truncating a Dart string containing \0 what we want?
765 ThrowIfError(Dart_StringToCString(host_name_object, &host_name));
766
767 SSLCertContext* context = NULL;
768 if (!Dart_IsNull(context_object)) {
769 ThrowIfError(Dart_GetNativeInstanceField(
770 context_object,
771 kSecurityContextNativeFieldIndex,
772 reinterpret_cast<intptr_t*>(&context)));
773 }
774
775 GetFilter(args)->Connect(dart_this,
776 host_name,
777 context,
778 is_server,
779 request_client_certificate,
780 require_client_certificate);
781 }
782
783
784 void FUNCTION_NAME(SecureSocket_Destroy)(Dart_NativeArguments args) {
785 SSLFilter* filter = GetFilter(args);
786 // The SSLFilter is deleted in the finalizer for the Dart object created by
787 // SetFilter. There is no need to NULL-out the native field for the SSLFilter
788 // here because the SSLFilter won't be deleted until the finalizer for the
789 // Dart object runs while the Dart object is being GCd. This approach avoids a
790 // leak if Destroy isn't called, and avoids a NULL-dereference if Destroy is
791 // called more than once.
792 filter->Destroy();
793 }
794
795
796 void FUNCTION_NAME(SecureSocket_Handshake)(Dart_NativeArguments args) {
797 OSStatus status = GetFilter(args)->CheckHandshake();
798 CheckStatus(status, "HandshakeException", "Handshake error");
799 }
800
801
802 void FUNCTION_NAME(SecureSocket_GetSelectedProtocol)(
803 Dart_NativeArguments args) {
804 Dart_SetReturnValue(args, Dart_Null());
805 }
806
807
808 void FUNCTION_NAME(SecureSocket_Renegotiate)(Dart_NativeArguments args) {
809 bool use_session_cache =
810 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 1));
811 bool request_client_certificate =
812 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 2));
813 bool require_client_certificate =
814 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 3));
815 GetFilter(args)->Renegotiate(use_session_cache,
816 request_client_certificate,
817 require_client_certificate);
818 }
819
820
821 void FUNCTION_NAME(SecureSocket_RegisterHandshakeCompleteCallback)(
822 Dart_NativeArguments args) {
823 Dart_Handle handshake_complete =
824 ThrowIfError(Dart_GetNativeArgument(args, 1));
825 if (!Dart_IsClosure(handshake_complete)) {
826 Dart_ThrowException(DartUtils::NewDartArgumentError(
827 "Illegal argument to RegisterHandshakeCompleteCallback"));
828 }
829 GetFilter(args)->RegisterHandshakeCompleteCallback(handshake_complete);
830 }
831
832
833 void FUNCTION_NAME(SecureSocket_RegisterBadCertificateCallback)(
834 Dart_NativeArguments args) {
835 Dart_Handle callback =
836 ThrowIfError(Dart_GetNativeArgument(args, 1));
837 if (!Dart_IsClosure(callback) && !Dart_IsNull(callback)) {
838 Dart_ThrowException(DartUtils::NewDartArgumentError(
839 "Illegal argument to RegisterBadCertificateCallback"));
840 }
841 GetFilter(args)->RegisterBadCertificateCallback(callback);
842 }
843
844
845 void FUNCTION_NAME(SecureSocket_PeerCertificate)
846 (Dart_NativeArguments args) {
847 Dart_SetReturnValue(args, GetFilter(args)->PeerCertificate());
848 }
849
850
851 void FUNCTION_NAME(SecureSocket_FilterPointer)(Dart_NativeArguments args) {
852 intptr_t filter_pointer = reinterpret_cast<intptr_t>(GetFilter(args));
853 Dart_SetReturnValue(args, Dart_NewInteger(filter_pointer));
854 }
855
856
857 void FUNCTION_NAME(SecurityContext_Allocate)(Dart_NativeArguments args) {
858 SSLCertContext* cert_context = new SSLCertContext();
859 // cert_context deleted in DeleteCertContext finalizer.
860 Dart_Handle err = SetSecurityContext(args, cert_context);
861 if (Dart_IsError(err)) {
862 delete cert_context;
863 Dart_PropagateError(err);
864 }
865 }
866
867
868 void FUNCTION_NAME(SecurityContext_UsePrivateKeyBytes)(
869 Dart_NativeArguments args) {
870 SSLCertContext* context = GetSecurityContext(args);
871 const char* password = GetPasswordArgument(args, 2);
872
873 OSStatus status;
874 SecKeyRef key = NULL;
875 SecKeychainRef keychain = NULL;
876 {
877 ScopedMemBuffer buffer(ThrowIfError(Dart_GetNativeArgument(args, 1)));
878 status = ExtractSecItems(
879 buffer.get(), buffer.length(), password, NULL, &key, &keychain);
880 }
881
882 // Set the context fields. If there's a failure, release the items.
883 bool set_failure = false;
884 if ((key != NULL) && !context->set_private_key(key)) {
885 CFRelease(key);
886 SecKeychainDelete(keychain);
887 CFRelease(keychain);
888 set_failure = true;
889 }
890 if (!set_failure && (keychain != NULL) && !context->set_keychain(keychain)) {
891 SecKeychainDelete(keychain);
892 CFRelease(keychain);
893 }
894
895 if (set_failure) {
896 Dart_ThrowException(DartUtils::NewDartArgumentError(
897 "usePrivateKeyBytes has already been called on the given context."));
898 }
899 CheckStatus(status, "TlsException", "Failure in usePrivateKeyBytes");
900 }
901
902
903 void FUNCTION_NAME(SecurityContext_SetTrustedCertificatesBytes)(
904 Dart_NativeArguments args) {
905 SSLCertContext* context = GetSecurityContext(args);
906 const char* password = GetPasswordArgument(args, 2);
907
908 OSStatus status;
909 CFArrayRef certs = NULL;
910 {
911 ScopedMemBuffer buffer(ThrowIfError(Dart_GetNativeArgument(args, 1)));
912 status = ExtractSecItems(
913 buffer.get(), buffer.length(), password, &certs, NULL, NULL);
914 }
915
916 // Set the field in the context. If there's a failure, release the certs,
917 // and throw an exception.
918 if ((certs != NULL) && !context->set_trusted_certs(certs)) {
919 CFRelease(certs);
920 Dart_ThrowException(DartUtils::NewDartArgumentError(
921 "setTrustedCertificatesBytes has already been called "
922 "on the given context."));
923 }
924
925 CheckStatus(status, "TlsException", "Failure in setTrustedCertificatesBytes");
926 }
927
928
929 void FUNCTION_NAME(SecurityContext_AlpnSupported)(Dart_NativeArguments args) {
930 Dart_SetReturnValue(args, Dart_NewBoolean(false));
931 }
932
933
934 void FUNCTION_NAME(SecurityContext_TrustBuiltinRoots)(
935 Dart_NativeArguments args) {
936 SSLCertContext* context = GetSecurityContext(args);
937 context->set_trust_builtin(true);
938 }
939
940
941 void FUNCTION_NAME(SecurityContext_UseCertificateChainBytes)(
942 Dart_NativeArguments args) {
943 SSLCertContext* context = GetSecurityContext(args);
944
945 const char* password = GetPasswordArgument(args, 2);
946 OSStatus status;
947 CFArrayRef certs = NULL;
948 {
949 ScopedMemBuffer buffer(ThrowIfError(Dart_GetNativeArgument(args, 1)));
950 status = ExtractSecItems(
951 buffer.get(), buffer.length(), password, &certs, NULL, NULL);
952 }
953
954 // Set the field in the context. If there's a failure, release the certs,
955 // and throw an exception.
956 if ((certs != NULL) && !context->set_cert_chain(certs)) {
957 CFRelease(certs);
958 Dart_ThrowException(DartUtils::NewDartArgumentError(
959 "useCertificateChainBytes has already been called "
960 "on the given context."));
961 }
962
963 CheckStatus(status, "TlsException", "Failure in useCertificateChainBytes");
964 }
965
966
967 void FUNCTION_NAME(SecurityContext_SetClientAuthoritiesBytes)(
968 Dart_NativeArguments args) {
969 SSLCertContext* context = GetSecurityContext(args);
970 const char* password = GetPasswordArgument(args, 2);
971
972 OSStatus status;
973 CFArrayRef certs = NULL;
974 {
975 ScopedMemBuffer buffer(ThrowIfError(Dart_GetNativeArgument(args, 1)));
976 status = ExtractSecItems(
977 buffer.get(), buffer.length(), password, &certs, NULL, NULL);
978 }
979
980 // Set the field in the context. If there's a failure, release the certs,
981 // and throw an exception.
982 if ((certs != NULL) && !context->set_cert_authorities(certs)) {
983 CFRelease(certs);
984 Dart_ThrowException(DartUtils::NewDartArgumentError(
985 "setClientAuthoritiesBytes has already been called "
986 "on the given context."));
987 }
988
989 CheckStatus(status, "TlsException", "Failure in setClientAuthoritiesBytes");
990 }
991
992
993 void FUNCTION_NAME(SecurityContext_SetAlpnProtocols)(
994 Dart_NativeArguments args) {
995 Dart_ThrowException(DartUtils::NewDartUnsupportedError(
996 "ALPN is not supported on this platform"));
997 }
998
999
1000 static char* GetNameFromCert(SecCertificateRef certificate,
1001 CFTypeRef field,
1002 CFStringRef name) {
1003 char* issuer_name = NULL;
1004
1005 CFTypeRef keys[] = { field };
1006 CFArrayRef key_array = CFArrayCreate(NULL, keys, 1, &kCFTypeArrayCallBacks);
1007 CFErrorRef error = NULL;
1008 CFDictionaryRef cert_dict =
1009 SecCertificateCopyValues(certificate, key_array, &error);
1010 if (cert_dict == NULL) {
1011 CFRelease(key_array);
1012 Dart_ThrowException(DartUtils::NewDartArgumentError(
1013 "X509.issuer failed to copy issuer field out of certificate"));
1014 }
1015
1016 CFTypeRef item = CFDictionaryGetValue(cert_dict, keys[0]);
1017 ASSERT(CFGetTypeID(item) == CFDictionaryGetTypeID());
1018 CFDictionaryRef val_dict = reinterpret_cast<CFDictionaryRef>(item);
1019
1020 item = CFDictionaryGetValue(val_dict, kSecPropertyKeyValue);
1021 ASSERT(CFGetTypeID(item) == CFArrayGetTypeID());
1022 CFArrayRef val_array = reinterpret_cast<CFArrayRef>(item);
1023
1024 for (intptr_t i = 0; i < CFArrayGetCount(val_array); i++) {
1025 item = CFArrayGetValueAtIndex(val_array, i);
1026 ASSERT(CFGetTypeID(item) == CFDictionaryGetTypeID());
1027 CFDictionaryRef val_dict2 = reinterpret_cast<CFDictionaryRef>(item);
1028
1029 item = CFDictionaryGetValue(val_dict2, kSecPropertyKeyLabel);
1030 ASSERT(CFGetTypeID(item) == CFStringGetTypeID());
1031 CFStringRef label = reinterpret_cast<CFStringRef>(item);
1032
1033 if (CFStringCompare(label, name, 0) == kCFCompareEqualTo) {
1034 item = CFDictionaryGetValue(val_dict2, kSecPropertyKeyValue);
1035 ASSERT(CFGetTypeID(item) == CFStringGetTypeID());
1036 CFStringRef value = reinterpret_cast<CFStringRef>(item);
1037 issuer_name = CFStringRefToCString(value);
1038 break;
1039 }
1040 }
1041
1042 CFRelease(cert_dict);
1043 CFRelease(key_array);
1044 return issuer_name;
1045 }
1046
1047
1048 void FUNCTION_NAME(X509_Subject)(Dart_NativeArguments args) {
1049 SecCertificateRef certificate = GetX509Certificate(args);
1050 char* subject_name = GetNameFromCert(certificate,
1051 kSecOIDX509V1SubjectName,
1052 kSecOIDCommonName);
1053 if (subject_name == NULL) {
1054 Dart_ThrowException(DartUtils::NewDartArgumentError(
1055 "X509.subject failed to find issuer's common name."));
1056 } else {
1057 Dart_SetReturnValue(args, Dart_NewStringFromCString(subject_name));
1058 }
1059 }
1060
1061
1062 void FUNCTION_NAME(X509_Issuer)(Dart_NativeArguments args) {
1063 SecCertificateRef certificate = GetX509Certificate(args);
1064 char* issuer_name = GetNameFromCert(certificate,
1065 kSecOIDX509V1IssuerName,
1066 kSecOIDCommonName);
1067 if (issuer_name == NULL) {
1068 Dart_ThrowException(DartUtils::NewDartArgumentError(
1069 "X509.issuer failed to find issuer's common name."));
1070 } else {
1071 Dart_SetReturnValue(args, Dart_NewStringFromCString(issuer_name));
1072 }
1073 }
1074
1075
1076 // Returns the number of seconds since the epoch from 'field'.
1077 static int64_t GetTimeFromCert(SecCertificateRef certificate, CFTypeRef field) {
1078 CFTypeRef keys[] = { field };
1079 CFArrayRef key_array = CFArrayCreate(NULL, keys, 1, &kCFTypeArrayCallBacks);
1080 CFErrorRef error = NULL;
1081 CFDictionaryRef cert_dict =
1082 SecCertificateCopyValues(certificate, key_array, &error);
1083 if (cert_dict == NULL) {
1084 CFRelease(key_array);
1085 Dart_ThrowException(DartUtils::NewDartArgumentError(
1086 "X509.startValidity: failed to copy issuer field out of certificate"));
1087 }
1088
1089 CFTypeRef item = CFDictionaryGetValue(cert_dict, keys[0]);
1090 ASSERT(CFGetTypeID(item) == CFDictionaryGetTypeID());
1091 CFDictionaryRef val_dict = reinterpret_cast<CFDictionaryRef>(item);
1092
1093 item = CFDictionaryGetValue(val_dict, kSecPropertyKeyValue);
1094 ASSERT(CFGetTypeID(item) == CFNumberGetTypeID());
1095 CFNumberRef date_number = reinterpret_cast<CFNumberRef>(item);
1096
1097 CFAbsoluteTime date_abs_time;
1098 CFNumberGetValue(date_number, kCFNumberDoubleType, &date_abs_time);
1099 CFAbsoluteTime seconds_since_epoch =
1100 date_abs_time + kCFAbsoluteTimeIntervalSince1970;
1101 return static_cast<int64_t>(seconds_since_epoch) * 1000LL;
1102 }
1103
1104
1105 void FUNCTION_NAME(X509_StartValidity)(Dart_NativeArguments args) {
1106 SecCertificateRef certificate = GetX509Certificate(args);
1107 int64_t seconds_since_epoch = GetTimeFromCert(certificate,
1108 kSecOIDX509V1ValidityNotBefore);
1109 Dart_SetReturnValue(args,
1110 Dart_NewInteger(static_cast<int64_t>(seconds_since_epoch) * 1000LL));
1111 }
1112
1113
1114 void FUNCTION_NAME(X509_EndValidity)(Dart_NativeArguments args) {
1115 SecCertificateRef certificate = GetX509Certificate(args);
1116 int64_t seconds_since_epoch = GetTimeFromCert(certificate,
1117 kSecOIDX509V1ValidityNotAfter);
1118 Dart_SetReturnValue(args,
1119 Dart_NewInteger(static_cast<int64_t>(seconds_since_epoch) * 1000LL));
1120 }
1121
1122
1123 // Pushes data through the SSL filter, reading and writing from circular
1124 // buffers shared with Dart. Called from the IOService thread.
1125 //
1126 // The Dart _SecureFilterImpl class contains 4 ExternalByteArrays used to
1127 // pass encrypted and plaintext data to and from the C++ SSLFilter object.
1128 //
1129 // ProcessFilter is called with a CObject array containing the pointer to
1130 // the SSLFilter, encoded as an int, and the start and end positions of the
1131 // valid data in the four circular buffers. The function only reads from
1132 // the valid data area of the input buffers, and only writes to the free
1133 // area of the output buffers. The function returns the new start and end
1134 // positions in the buffers, but it only updates start for input buffers, and
1135 // end for output buffers. Therefore, the Dart thread can simultaneously
1136 // write to the free space and end pointer of input buffers, and read from
1137 // the data space of output buffers, and modify the start pointer.
1138 //
1139 // When ProcessFilter returns, the Dart thread is responsible for combining
1140 // the updated pointers from Dart and C++, to make the new valid state of
1141 // the circular buffer.
1142 CObject* SSLFilter::ProcessFilterRequest(const CObjectArray& request) {
1143 CObjectIntptr filter_object(request[0]);
1144 SSLFilter* filter = reinterpret_cast<SSLFilter*>(filter_object.Value());
1145 bool in_handshake = CObjectBool(request[1]).Value();
1146 intptr_t starts[SSLFilter::kNumBuffers];
1147 intptr_t ends[SSLFilter::kNumBuffers];
1148 for (intptr_t i = 0; i < SSLFilter::kNumBuffers; ++i) {
1149 starts[i] = CObjectInt32(request[2 * i + 2]).Value();
1150 ends[i] = CObjectInt32(request[2 * i + 3]).Value();
1151 }
1152
1153 OSStatus status = filter->ProcessAllBuffers(starts, ends, in_handshake);
1154 if (status == noErr) {
1155 CObjectArray* result = new CObjectArray(
1156 CObject::NewArray(SSLFilter::kNumBuffers * 2));
1157 for (intptr_t i = 0; i < SSLFilter::kNumBuffers; ++i) {
1158 result->SetAt(2 * i, new CObjectInt32(CObject::NewInt32(starts[i])));
1159 result->SetAt(2 * i + 1, new CObjectInt32(CObject::NewInt32(ends[i])));
1160 }
1161 return result;
1162 } else {
1163 TextBuffer status_message(SSL_ERROR_MESSAGE_BUFFER_SIZE);
1164 CFStringRef error_string = SecCopyErrorMessageString(status, NULL);
1165 if (error_string == NULL) {
1166 status_message.Printf("OSStatus = %ld: https://www.osstatus.com",
1167 static_cast<intptr_t>(status));
1168 } else {
1169 char* error = CFStringRefToCString(error_string);
1170 status_message.Printf("OSStatus = %ld: %s",
1171 static_cast<intptr_t>(status), error);
1172 CFRelease(error_string);
1173 }
1174 CObjectArray* result = new CObjectArray(CObject::NewArray(2));
1175 result->SetAt(0, new CObjectInt32(CObject::NewInt32(status)));
1176 result->SetAt(1, new CObjectString(CObject::NewString(
1177 status_message.buf())));
1178 return result;
1179 }
1180 }
1181
1182
1183 // Usually buffer_starts_ and buffer_ends_ are populated by ProcessAllBuffers,
1184 // called from ProcessFilterRequest, called from the IOService thread.
1185 // However, the first call to SSLHandshake comes from the Dart thread, and so
1186 // doesn't go through there. This results in calls to SSLReadCallback and
1187 // SSLWriteCallback in which buffer_starts_ and buffer_ends_ haven't been set
1188 // up. In that case, since we're coming from Dart anyway, we can access the
1189 // fieds directly from the Dart objects.
1190 intptr_t SSLFilter::GetBufferStart(intptr_t idx) const {
1191 if (buffer_starts_[idx] != NULL) {
1192 return *buffer_starts_[idx];
1193 }
1194 Dart_Handle buffer_handle =
1195 ThrowIfError(Dart_HandleFromPersistent(dart_buffer_objects_[idx]));
1196 Dart_Handle start_handle =
1197 ThrowIfError(Dart_GetField(buffer_handle, DartUtils::NewString("start")));
1198 int64_t start = DartUtils::GetIntegerValue(start_handle);
1199 return static_cast<intptr_t>(start);
1200 }
1201
1202
1203 intptr_t SSLFilter::GetBufferEnd(intptr_t idx) const {
1204 if (buffer_ends_[idx] != NULL) {
1205 return *buffer_ends_[idx];
1206 }
1207 Dart_Handle buffer_handle =
1208 ThrowIfError(Dart_HandleFromPersistent(dart_buffer_objects_[idx]));
1209 Dart_Handle end_handle =
1210 ThrowIfError(Dart_GetField(buffer_handle, DartUtils::NewString("end")));
1211 int64_t end = DartUtils::GetIntegerValue(end_handle);
1212 return static_cast<intptr_t>(end);
1213 }
1214
1215
1216 void SSLFilter::SetBufferStart(intptr_t idx, intptr_t value) {
1217 if (buffer_starts_[idx] != NULL) {
1218 *buffer_starts_[idx] = value;
1219 return;
1220 }
1221 Dart_Handle buffer_handle =
1222 ThrowIfError(Dart_HandleFromPersistent(dart_buffer_objects_[idx]));
1223 ThrowIfError(DartUtils::SetIntegerField(
1224 buffer_handle, "start", static_cast<int64_t>(value)));
1225 }
1226
1227
1228 void SSLFilter::SetBufferEnd(intptr_t idx, intptr_t value) {
1229 if (buffer_ends_[idx] != NULL) {
1230 *buffer_ends_[idx] = value;
1231 return;
1232 }
1233 Dart_Handle buffer_handle =
1234 ThrowIfError(Dart_HandleFromPersistent(dart_buffer_objects_[idx]));
1235 ThrowIfError(DartUtils::SetIntegerField(
1236 buffer_handle, "end", static_cast<int64_t>(value)));
1237 }
1238
1239
1240 OSStatus SSLFilter::ProcessAllBuffers(intptr_t starts[kNumBuffers],
1241 intptr_t ends[kNumBuffers],
1242 bool in_handshake) {
1243 for (intptr_t i = 0; i < kNumBuffers; ++i) {
1244 buffer_starts_[i] = &starts[i];
1245 buffer_ends_[i] = &ends[i];
1246 }
1247
1248 if (in_handshake) {
1249 OSStatus status = Handshake();
1250 if (status != noErr) {
1251 return status;
1252 }
1253 } else {
1254 for (intptr_t i = 0; i < kNumBuffers; ++i) {
1255 intptr_t start = starts[i];
1256 intptr_t end = ends[i];
1257 intptr_t size =
1258 isBufferEncrypted(i) ? encrypted_buffer_size_ : buffer_size_;
1259 if (start < 0 || end < 0 || start >= size || end >= size) {
1260 FATAL("Out-of-bounds internal buffer access in dart:io SecureSocket");
1261 }
1262 switch (i) {
1263 case kReadPlaintext:
1264 // Write data to the circular buffer's free space. If the buffer
1265 // is full, neither if statement is executed and nothing happens.
1266 if (start <= end) {
1267 // If the free space may be split into two segments,
1268 // then the first is [end, size), unless start == 0.
1269 // Then, since the last free byte is at position start - 2,
1270 // the interval is [end, size - 1).
1271 intptr_t buffer_end = (start == 0) ? size - 1 : size;
1272 intptr_t bytes = 0;
1273 OSStatus status =
1274 ProcessReadPlaintextBuffer(end, buffer_end, &bytes);
1275 if ((status != noErr) && (status != errSSLWouldBlock)) {
1276 return status;
1277 }
1278 end += bytes;
1279 ASSERT(end <= size);
1280 if (end == size) {
1281 end = 0;
1282 }
1283 }
1284 if (start > end + 1) {
1285 intptr_t bytes = 0;
1286 OSStatus status =
1287 ProcessReadPlaintextBuffer(end, start - 1, &bytes);
1288 if ((status != noErr) && (status != errSSLWouldBlock)) {
1289 return status;
1290 }
1291 end += bytes;
1292 ASSERT(end < start);
1293 }
1294 ends[i] = end;
1295 break;
1296 case kWritePlaintext:
1297 // Read/Write data from circular buffer. If the buffer is empty,
1298 // neither if statement's condition is true.
1299 if (end < start) {
1300 // Data may be split into two segments. In this case,
1301 // the first is [start, size).
1302 intptr_t bytes = 0;
1303 OSStatus status = ProcessWritePlaintextBuffer(start, size, &bytes);
1304 if ((status != noErr) && (status != errSSLWouldBlock)) {
1305 return status;
1306 }
1307 start += bytes;
1308 ASSERT(start <= size);
1309 if (start == size) {
1310 start = 0;
1311 }
1312 }
1313 if (start < end) {
1314 intptr_t bytes = 0;
1315 OSStatus status = ProcessWritePlaintextBuffer(start, end, &bytes);
1316 if ((status != noErr) && (status != errSSLWouldBlock)) {
1317 return status;
1318 }
1319 start += bytes;
1320 ASSERT(start <= end);
1321 }
1322 starts[i] = start;
1323 break;
1324 case kReadEncrypted:
1325 case kWriteEncrypted:
1326 // These buffers are advanced through SSLReadCallback and
1327 // SSLWriteCallback, which are called from SSLRead, SSLWrite, and
1328 // SSLHandshake.
1329 break;
1330 default:
1331 UNREACHABLE();
1332 }
1333 }
1334 }
1335
1336 for (intptr_t i = 0; i < kNumBuffers; ++i) {
1337 buffer_starts_[i] = NULL;
1338 buffer_ends_[i] = NULL;
1339 }
1340 return noErr;
1341 }
1342
1343
1344 Dart_Handle SSLFilter::Init(Dart_Handle dart_this) {
1345 ASSERT(string_start_ == NULL);
1346 string_start_ = Dart_NewPersistentHandle(DartUtils::NewString("start"));
1347 ASSERT(string_start_ != NULL);
1348 ASSERT(string_length_ == NULL);
1349 string_length_ = Dart_NewPersistentHandle(DartUtils::NewString("length"));
1350 ASSERT(string_length_ != NULL);
1351 ASSERT(bad_certificate_callback_ == NULL);
1352 bad_certificate_callback_ = Dart_NewPersistentHandle(Dart_Null());
1353 ASSERT(bad_certificate_callback_ != NULL);
1354
1355 // Caller handles cleanup on an error.
1356 return InitializeBuffers(dart_this);
1357 }
1358
1359
1360 Dart_Handle SSLFilter::InitializeBuffers(Dart_Handle dart_this) {
1361 // Create SSLFilter buffers as ExternalUint8Array objects.
1362 Dart_Handle buffers_string = DartUtils::NewString("buffers");
1363 RETURN_IF_ERROR(buffers_string);
1364 Dart_Handle dart_buffers_object = Dart_GetField(dart_this, buffers_string);
1365 RETURN_IF_ERROR(dart_buffers_object);
1366 Dart_Handle secure_filter_impl_type = Dart_InstanceGetType(dart_this);
1367 RETURN_IF_ERROR(secure_filter_impl_type);
1368 Dart_Handle size_string = DartUtils::NewString("SIZE");
1369 RETURN_IF_ERROR(size_string);
1370 Dart_Handle dart_buffer_size = Dart_GetField(
1371 secure_filter_impl_type, size_string);
1372 RETURN_IF_ERROR(dart_buffer_size);
1373
1374 int64_t buffer_size = 0;
1375 Dart_Handle err = Dart_IntegerToInt64(dart_buffer_size, &buffer_size);
1376 RETURN_IF_ERROR(err);
1377
1378 Dart_Handle encrypted_size_string = DartUtils::NewString("ENCRYPTED_SIZE");
1379 RETURN_IF_ERROR(encrypted_size_string);
1380
1381 Dart_Handle dart_encrypted_buffer_size = Dart_GetField(
1382 secure_filter_impl_type, encrypted_size_string);
1383 RETURN_IF_ERROR(dart_encrypted_buffer_size);
1384
1385 int64_t encrypted_buffer_size = 0;
1386 err = Dart_IntegerToInt64(dart_encrypted_buffer_size, &encrypted_buffer_size);
1387 RETURN_IF_ERROR(err);
1388
1389 if (buffer_size <= 0 || buffer_size > 1 * MB) {
1390 FATAL("Invalid buffer size in _ExternalBuffer");
1391 }
1392 if (encrypted_buffer_size <= 0 || encrypted_buffer_size > 1 * MB) {
1393 FATAL("Invalid encrypted buffer size in _ExternalBuffer");
1394 }
1395 buffer_size_ = static_cast<intptr_t>(buffer_size);
1396 encrypted_buffer_size_ = static_cast<intptr_t>(encrypted_buffer_size);
1397
1398 Dart_Handle data_identifier = DartUtils::NewString("data");
1399 RETURN_IF_ERROR(data_identifier);
1400
1401 for (int i = 0; i < kNumBuffers; i++) {
1402 int size = isBufferEncrypted(i) ? encrypted_buffer_size_ : buffer_size_;
1403 buffers_[i] = new uint8_t[size];
1404 ASSERT(buffers_[i] != NULL);
1405 buffer_starts_[i] = NULL;
1406 buffer_ends_[i] = NULL;
1407 dart_buffer_objects_[i] = NULL;
1408 }
1409
1410 Dart_Handle result = Dart_Null();
1411 for (int i = 0; i < kNumBuffers; ++i) {
1412 int size = isBufferEncrypted(i) ? encrypted_buffer_size_ : buffer_size_;
1413 result = Dart_ListGetAt(dart_buffers_object, i);
1414 if (Dart_IsError(result)) {
1415 break;
1416 }
1417
1418 dart_buffer_objects_[i] = Dart_NewPersistentHandle(result);
1419 ASSERT(dart_buffer_objects_[i] != NULL);
1420 Dart_Handle data =
1421 Dart_NewExternalTypedData(Dart_TypedData_kUint8, buffers_[i], size);
1422 if (Dart_IsError(data)) {
1423 result = data;
1424 break;
1425 }
1426 result = Dart_HandleFromPersistent(dart_buffer_objects_[i]);
1427 if (Dart_IsError(result)) {
1428 break;
1429 }
1430 result = Dart_SetField(result, data_identifier, data);
1431 if (Dart_IsError(result)) {
1432 break;
1433 }
1434 }
1435
1436 // Caller handles cleanup on an error.
1437 return result;
1438 }
1439
1440
1441 void SSLFilter::RegisterHandshakeCompleteCallback(Dart_Handle complete) {
1442 ASSERT(NULL == handshake_complete_);
1443 handshake_complete_ = Dart_NewPersistentHandle(complete);
1444 ASSERT(handshake_complete_ != NULL);
1445 }
1446
1447
1448 void SSLFilter::RegisterBadCertificateCallback(Dart_Handle callback) {
1449 ASSERT(bad_certificate_callback_ != NULL);
1450 Dart_DeletePersistentHandle(bad_certificate_callback_);
1451 bad_certificate_callback_ = Dart_NewPersistentHandle(callback);
1452 ASSERT(bad_certificate_callback_ != NULL);
1453 }
1454
1455
1456 Dart_Handle SSLFilter::PeerCertificate() {
1457 if (peer_certs_ == NULL) {
1458 return Dart_Null();
1459 }
1460
1461 CFTypeRef item = CFArrayGetValueAtIndex(peer_certs_, 0);
1462 ASSERT(CFGetTypeID(item) == SecCertificateGetTypeID());
1463 SecCertificateRef cert =
1464 reinterpret_cast<SecCertificateRef>(const_cast<void*>(item));
1465 if (cert == NULL) {
1466 return Dart_Null();
1467 }
1468
1469 return WrappedX509Certificate(cert);
1470 }
1471
1472
1473 void SSLFilter::Connect(Dart_Handle dart_this,
1474 const char* hostname,
1475 SSLCertContext* context,
1476 bool is_server,
1477 bool request_client_certificate,
1478 bool require_client_certificate) {
1479 if (in_handshake_) {
1480 FATAL("Connect called twice on the same _SecureFilter.");
1481 }
1482
1483 // Create the underlying context
1484 SSLContextRef ssl_context = SSLCreateContext(
1485 NULL, is_server ? kSSLServerSide : kSSLClientSide, kSSLStreamType);
1486
1487 // Configure the context.
1488 OSStatus status;
1489 status = SSLSetPeerDomainName(ssl_context, hostname, strlen(hostname));
1490 CheckStatus(status,
1491 "TlsException",
1492 "Failed to set peer domain name");
1493
1494 status = SSLSetIOFuncs(
1495 ssl_context, SSLFilter::SSLReadCallback, SSLFilter::SSLWriteCallback);
1496 CheckStatus(status,
1497 "TlsException",
1498 "Failed to set IO Callbacks");
1499
1500 status = SSLSetConnection(
1501 ssl_context, reinterpret_cast<SSLConnectionRef>(this));
1502 CheckStatus(status,
1503 "TlsException",
1504 "Failed to set connection object");
1505
1506 // Always evaluate the certs manually so that we can cache the peer
1507 // certificates in the context for calls to peerCertificate.
1508 status = SSLSetSessionOption(
1509 ssl_context, kSSLSessionOptionBreakOnServerAuth, true);
1510 CheckStatus(status,
1511 "TlsException",
1512 "Failed to set BreakOnServerAuth option");
1513
1514 status = SSLSetProtocolVersionMin(ssl_context, kTLSProtocol1);
1515 CheckStatus(status,
1516 "TlsException",
1517 "Failed to set minimum protocol version to kTLSProtocol1");
1518
1519 // If the context has a private key and certificate chain, combine the
1520 // private key and first certificate into a SecIdentityRef, and place that
1521 // and the remaining certs in an array to pass to SSLSetCertificate().
1522 if ((context->private_key() != NULL) && (context->cert_chain() != NULL)) {
1523 CFIndex chain_length = CFArrayGetCount(context->cert_chain());
1524 CFMutableArrayRef certs =
1525 CFArrayCreateMutable(NULL, chain_length, &kCFTypeArrayCallBacks);
1526 CFTypeRef item = CFArrayGetValueAtIndex(context->cert_chain(), 0);
1527 ASSERT(CFGetTypeID(item) == SecCertificateGetTypeID());
1528 SecCertificateRef first_cert =
1529 reinterpret_cast<SecCertificateRef>(const_cast<void*>(item));
1530 SecIdentityRef identity =
1531 SecIdentityCreate(NULL, first_cert, context->private_key());
1532 CFArrayAppendValue(certs, identity);
1533 for (CFIndex i = 0; i < chain_length; i++) {
1534 CFArrayAppendValue(certs,
1535 CFArrayGetValueAtIndex(context->cert_chain(), i));
1536 }
1537 CFRelease(identity);
1538 status = SSLSetCertificate(ssl_context, certs);
1539 CFRelease(certs);
1540 CheckStatus(status, "TlsException", "SSLSetCertificate failed");
1541 }
1542
1543 if (context->cert_authorities() != NULL) {
1544 status = SSLSetCertificateAuthorities(
1545 ssl_context, context->cert_authorities(), true);
1546 CheckStatus(status,
1547 "TlsException",
1548 "Failed to set certificate authorities");
1549 }
1550
1551 if (is_server) {
1552 SSLAuthenticate auth =
1553 require_client_certificate
1554 ? kAlwaysAuthenticate
1555 : (request_client_certificate ? kTryAuthenticate : kNeverAuthenticate);
1556 status = SSLSetClientSideAuthenticate(ssl_context, auth);
1557 CheckStatus(status,
1558 "TlsException",
1559 "Failed to set client authentication mode");
1560
1561 // If we're at least trying client authentication, then break handshake
1562 // for client authentication.
1563 if (auth != kNeverAuthenticate) {
1564 status = SSLSetSessionOption(
1565 ssl_context, kSSLSessionOptionBreakOnClientAuth, true);
1566 CheckStatus(status,
1567 "TlsException",
1568 "Failed to set client authentication mode");
1569 }
1570 }
1571
1572 // Add the contexts to our wrapper.
1573 cert_context_ = context;
1574 ssl_context_ = ssl_context;
1575 is_server_ = is_server;
1576
1577 // Kick-off the handshake. Expect the handshake to need more data.
1578 // SSLHandshake calls our SSLReadCallback and SSLWriteCallback.
1579 status = SSLHandshake(ssl_context);
1580 ASSERT(status != noErr);
1581 if (status == errSSLWouldBlock) {
1582 status = noErr;
1583 in_handshake_ = true;
1584 }
1585 CheckStatus(status,
1586 "HandshakeException",
1587 is_server_ ? "Handshake error in server" : "Handshake error in client");
1588 }
1589
1590
1591 OSStatus SSLFilter::EvaluatePeerTrust() {
1592 OSStatus status = noErr;
1593
1594 if (SSL_LOG_STATUS) {
1595 Log::Print("Handshake evaluating trust.\n");
1596 }
1597 SecTrustRef peer_trust = NULL;
1598 status = SSLCopyPeerTrust(ssl_context_, &peer_trust);
1599 if (status != noErr) {
1600 if (is_server_ && (status == errSSLBadCert)) {
1601 // A client certificate was requested, but not required, and wasn't sent.
1602 return noErr;
1603 }
1604 if (SSL_LOG_STATUS) {
1605 Log::Print("Handshake error from SSLCopyPeerTrust(): %ld.\n",
1606 static_cast<intptr_t>(status));
1607 }
1608 return status;
1609 }
1610
1611 CFArrayRef trusted_certs = NULL;
1612 if (cert_context_->trusted_certs() != NULL) {
1613 trusted_certs = CFArrayCreateCopy(NULL, cert_context_->trusted_certs());
1614 } else {
1615 trusted_certs = CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks);
1616 }
1617
1618 status = SecTrustSetAnchorCertificates(peer_trust, trusted_certs);
1619 if (status != noErr) {
1620 if (SSL_LOG_STATUS) {
1621 Log::Print("Handshake error from SecTrustSetAnchorCertificates: %ld\n",
1622 static_cast<intptr_t>(status));
1623 }
1624 CFRelease(trusted_certs);
1625 CFRelease(peer_trust);
1626 return status;
1627 }
1628
1629 if (SSL_LOG_STATUS) {
1630 Log::Print("Handshake %s built in root certs\n",
1631 cert_context_->trust_builtin() ? "trusting" : "not trusting");
1632 }
1633
1634 status = SecTrustSetAnchorCertificatesOnly(
1635 peer_trust, !cert_context_->trust_builtin());
1636 if (status != noErr) {
1637 CFRelease(trusted_certs);
1638 CFRelease(peer_trust);
1639 return status;
1640 }
1641
1642 SecTrustResultType trust_result;
1643 status = SecTrustEvaluate(peer_trust, &trust_result);
1644 if (status != noErr) {
1645 CFRelease(trusted_certs);
1646 CFRelease(peer_trust);
1647 return status;
1648 }
1649
1650 // Grab the peer's certificate chain.
1651 CFIndex peer_chain_length = SecTrustGetCertificateCount(peer_trust);
1652 CFMutableArrayRef peer_certs =
1653 CFArrayCreateMutable(NULL, peer_chain_length, &kCFTypeArrayCallBacks);
1654 for (CFIndex i = 0; i < peer_chain_length; ++i) {
1655 CFArrayAppendValue(peer_certs,
1656 SecTrustGetCertificateAtIndex(peer_trust, i));
1657 }
1658 peer_certs_ = peer_certs;
1659
1660 CFRelease(trusted_certs);
1661 CFRelease(peer_trust);
1662
1663 if ((trust_result == kSecTrustResultProceed) ||
1664 (trust_result == kSecTrustResultUnspecified)) {
1665 // Trusted.
1666 return noErr;
1667 } else {
1668 if (SSL_LOG_STATUS) {
1669 Log::Print("Trust eval failed: trust_restul = %d\n", trust_result);
1670 }
1671 bad_cert_ = true;
1672 return errSSLBadCert;
1673 }
1674 }
1675
1676
1677 OSStatus SSLFilter::Handshake() {
1678 ASSERT(cert_context_ != NULL);
1679 ASSERT(ssl_context_ != NULL);
1680 // Try and push handshake along.
1681 if (SSL_LOG_STATUS) {
1682 Log::Print("Doing SSLHandshake\n");
1683 }
1684 OSStatus status = SSLHandshake(ssl_context_);
1685 if (SSL_LOG_STATUS) {
1686 Log::Print("SSLHandshake returned %ld\n", static_cast<intptr_t>(status));
1687 }
1688
1689 if ((status == errSSLServerAuthCompleted) ||
1690 (status == errSSLClientAuthCompleted)) {
1691 status = EvaluatePeerTrust();
1692 if (status == errSSLBadCert) {
1693 // Need to invoke the bad certificate callback.
1694 return noErr;
1695 } else if (status != noErr) {
1696 return status;
1697 }
1698 // When trust evaluation succeeds, we can call SSLHandshake again
1699 // immediately.
1700 status = SSLHandshake(ssl_context_);
1701 }
1702
1703 if (status == errSSLWouldBlock) {
1704 in_handshake_ = true;
1705 return noErr;
1706 }
1707
1708 // Handshake succeeded.
1709 if ((in_handshake_) && (status == noErr)) {
1710 if (SSL_LOG_STATUS) {
1711 Log::Print("Finished with the Handshake\n");
1712 }
1713 connected_ = true;
1714 }
1715 return status;
1716 }
1717
1718
1719 // Returns false if Handshake should fail, and true if Handshake should
1720 // proceed.
1721 Dart_Handle SSLFilter::InvokeBadCertCallback(SecCertificateRef peer_cert) {
1722 Dart_Handle callback = bad_certificate_callback_;
1723 if (Dart_IsNull(callback)) {
1724 return callback;
1725 }
1726 Dart_Handle args[1];
1727 args[0] = WrappedX509Certificate(peer_cert);
1728 if (Dart_IsError(args[0])) {
1729 return args[0];
1730 }
1731 Dart_Handle result = Dart_InvokeClosure(callback, 1, args);
1732 if (!Dart_IsError(result) && !Dart_IsBoolean(result)) {
1733 result = Dart_NewUnhandledExceptionError(DartUtils::NewDartIOException(
1734 "HandshakeException",
1735 "BadCertificateCallback returned a value that was not a boolean",
1736 Dart_Null()));
1737 }
1738 return result;
1739 }
1740
1741
1742 OSStatus SSLFilter::CheckHandshake() {
1743 if (bad_cert_ && in_handshake_) {
1744 if (SSL_LOG_STATUS) {
1745 Log::Print("Invoking bad certificate callback\n");
1746 }
1747 ASSERT(peer_certs_ != NULL);
1748 CFIndex peer_certs_len = CFArrayGetCount(peer_certs_);
1749 ASSERT(peer_certs_len > 0);
1750 CFTypeRef item = CFArrayGetValueAtIndex(peer_certs_, peer_certs_len - 1);
1751 ASSERT(item != NULL);
1752 ASSERT(CFGetTypeID(item) == SecCertificateGetTypeID());
1753 SecCertificateRef peer_cert =
1754 reinterpret_cast<SecCertificateRef>(const_cast<void*>(item));
1755 Dart_Handle result = InvokeBadCertCallback(peer_cert);
1756 ThrowIfError(result);
1757 if (Dart_IsNull(result)) {
1758 return errSSLBadCert;
1759 } else {
1760 bool good_cert = DartUtils::GetBooleanValue(result);
1761 bad_cert_ = !good_cert;
1762 return good_cert ? noErr : errSSLBadCert;
1763 }
1764 }
1765
1766 if (connected_ && in_handshake_) {
1767 if (SSL_LOG_STATUS) {
1768 Log::Print("Invoking handshake complete callback\n");
1769 }
1770 ThrowIfError(Dart_InvokeClosure(
1771 Dart_HandleFromPersistent(handshake_complete_), 0, NULL));
1772 in_handshake_ = false;
1773 }
1774 return noErr;
1775 }
1776
1777
1778 void SSLFilter::Renegotiate(bool use_session_cache,
1779 bool request_client_certificate,
1780 bool require_client_certificate) {
1781 // The SSL_REQUIRE_CERTIFICATE option only takes effect if the
1782 // SSL_REQUEST_CERTIFICATE option is also set, so set it.
1783 request_client_certificate =
1784 request_client_certificate || require_client_certificate;
1785 // TODO(24070, 24069): Implement setting the client certificate parameters,
1786 // and triggering rehandshake.
1787 }
1788
1789
1790 SSLFilter::~SSLFilter() {
1791 // cert_context_ deleted by finalizer. Don't delete here.
1792 cert_context_ = NULL;
1793 if (ssl_context_ != NULL) {
1794 CFRelease(ssl_context_);
1795 ssl_context_ = NULL;
1796 }
1797 if (peer_certs_ != NULL) {
1798 CFRelease(peer_certs_);
1799 peer_certs_ = NULL;
1800 }
1801 if (hostname_ != NULL) {
1802 free(hostname_);
1803 hostname_ = NULL;
1804 }
1805 for (int i = 0; i < kNumBuffers; ++i) {
1806 if (buffers_[i] != NULL) {
1807 delete[] buffers_[i];
1808 buffers_[i] = NULL;
1809 }
1810 }
1811 }
1812
1813
1814 void SSLFilter::Destroy() {
1815 if (ssl_context_ != NULL) {
1816 SSLClose(ssl_context_);
1817 }
1818 for (int i = 0; i < kNumBuffers; ++i) {
1819 if (dart_buffer_objects_[i] != NULL) {
1820 Dart_DeletePersistentHandle(dart_buffer_objects_[i]);
1821 dart_buffer_objects_[i] = NULL;
1822 }
1823 }
1824 if (string_start_ != NULL) {
1825 Dart_DeletePersistentHandle(string_start_);
1826 string_start_ = NULL;
1827 }
1828 if (string_length_ != NULL) {
1829 Dart_DeletePersistentHandle(string_length_);
1830 string_length_ = NULL;
1831 }
1832 if (handshake_complete_ != NULL) {
1833 Dart_DeletePersistentHandle(handshake_complete_);
1834 handshake_complete_ = NULL;
1835 }
1836 if (bad_certificate_callback_ != NULL) {
1837 Dart_DeletePersistentHandle(bad_certificate_callback_);
1838 bad_certificate_callback_ = NULL;
1839 }
1840 }
1841
1842
1843 static intptr_t AvailableToRead(intptr_t start, intptr_t end, intptr_t size) {
1844 intptr_t data_available = 0;
1845 if (end < start) {
1846 // Data may be split into two segments. In this case,
1847 // the first is [start, size).
1848 intptr_t buffer_end = (start == 0) ? size - 1 : size;
1849 intptr_t available = buffer_end - start;
1850 start += available;
1851 data_available += available;
1852 ASSERT(start <= size);
1853 if (start == size) {
1854 start = 0;
1855 }
1856 }
1857 if (start < end) {
1858 intptr_t available = end - start;
1859 start += available;
1860 data_available += available;
1861 ASSERT(start <= end);
1862 }
1863 return data_available;
1864 }
1865
1866
1867 OSStatus SSLFilter::SSLReadCallback(SSLConnectionRef connection,
1868 void* data, size_t* data_requested) {
1869 // Copy at most `data_requested` bytes from `buffers_[kReadEncrypted]` into
1870 // `data`
1871 ASSERT(connection != NULL);
1872 ASSERT(data != NULL);
1873 ASSERT(data_requested != NULL);
1874
1875 SSLFilter* filter =
1876 const_cast<SSLFilter*>(reinterpret_cast<const SSLFilter*>(connection));
1877 uint8_t* datap = reinterpret_cast<uint8_t*>(data);
1878 uint8_t* buffer = filter->buffers_[kReadEncrypted];
1879 intptr_t start = filter->GetBufferStart(kReadEncrypted);
1880 intptr_t end = filter->GetBufferEnd(kReadEncrypted);
1881 intptr_t size = filter->encrypted_buffer_size_;
1882 intptr_t requested = static_cast<intptr_t>(*data_requested);
1883 intptr_t data_read = 0;
1884
1885 if (AvailableToRead(start, end, size) < requested) {
1886 *data_requested = 0;
1887 return errSSLWouldBlock;
1888 }
1889
1890 if (end < start) {
1891 // Data may be split into two segments. In this case,
1892 // the first is [start, size).
1893 intptr_t buffer_end = (start == 0) ? size - 1 : size;
1894 intptr_t available = buffer_end - start;
1895 intptr_t bytes = requested < available ? requested : available;
1896 memmove(datap, &buffer[start], bytes);
1897 start += bytes;
1898 datap += bytes;
1899 data_read += bytes;
1900 requested -= bytes;
1901 ASSERT(start <= size);
1902 if (start == size) {
1903 start = 0;
1904 }
1905 }
1906 if ((requested > 0) && (start < end)) {
1907 intptr_t available = end - start;
1908 intptr_t bytes = requested < available ? requested : available;
1909 memmove(datap, &buffer[start], bytes);
1910 start += bytes;
1911 datap += bytes;
1912 data_read += bytes;
1913 requested -= bytes;
1914 ASSERT(start <= end);
1915 }
1916
1917 if (SSL_LOG_DATA) {
1918 Log::Print("SSLReadCallback: requested: %ld, read %ld bytes\n",
1919 *data_requested, data_read);
1920 }
1921
1922 filter->SetBufferStart(kReadEncrypted, start);
1923 *data_requested = data_read;
1924 return noErr;
1925 }
1926
1927
1928 // Read decrypted data from the filter to the circular buffer.
1929 OSStatus SSLFilter::ProcessReadPlaintextBuffer(intptr_t start,
1930 intptr_t end,
1931 intptr_t* bytes_processed) {
1932 ASSERT(bytes_processed != NULL);
1933 intptr_t length = end - start;
1934 OSStatus status = noErr;
1935 size_t bytes = 0;
1936 if (length > 0) {
1937 status = SSLRead(
1938 ssl_context_,
1939 reinterpret_cast<void*>((buffers_[kReadPlaintext] + start)),
1940 length,
1941 &bytes);
1942 if ((status != noErr) && (status != errSSLWouldBlock)) {
1943 *bytes_processed = 0;
1944 return status;
1945 }
1946 }
1947 if (SSL_LOG_DATA) {
1948 Log::Print("ProcessReadPlaintextBuffer: requested: %ld, read %ld bytes\n",
1949 length, bytes);
1950 }
1951 *bytes_processed = static_cast<intptr_t>(bytes);
1952 return status;
1953 }
1954
1955
1956 intptr_t SpaceToWrite(intptr_t start, intptr_t end, intptr_t size) {
1957 intptr_t writable_space = 0;
1958
1959 // is full, neither if statement is executed and nothing happens.
1960 if (start <= end) {
1961 // If the free space may be split into two segments,
1962 // then the first is [end, size), unless start == 0.
1963 // Then, since the last free byte is at position start - 2,
1964 // the interval is [end, size - 1).
1965 intptr_t buffer_end = (start == 0) ? size - 1 : size;
1966 intptr_t available = buffer_end - end;
1967 end += available;
1968 writable_space += available;
1969 ASSERT(end <= size);
1970 if (end == size) {
1971 end = 0;
1972 }
1973 }
1974 if (start > end + 1) {
1975 intptr_t available = (start - 1) - end;
1976 end += available;
1977 writable_space += available;
1978 ASSERT(end < start);
1979 }
1980
1981 return writable_space;
1982 }
1983
1984
1985 OSStatus SSLFilter::SSLWriteCallback(SSLConnectionRef connection,
1986 const void* data, size_t* data_provided) {
1987 // Copy at most `data_provided` bytes from data into
1988 // `buffers_[kWriteEncrypted]`.
1989 ASSERT(connection != NULL);
1990 ASSERT(data != NULL);
1991 ASSERT(data_provided != NULL);
1992
1993 SSLFilter* filter =
1994 const_cast<SSLFilter*>(reinterpret_cast<const SSLFilter*>(connection));
1995 const uint8_t* datap = reinterpret_cast<const uint8_t*>(data);
1996 uint8_t* buffer = filter->buffers_[kWriteEncrypted];
1997 intptr_t start = filter->GetBufferStart(kWriteEncrypted);
1998 intptr_t end = filter->GetBufferEnd(kWriteEncrypted);
1999 intptr_t size = filter->encrypted_buffer_size_;
2000 intptr_t provided = static_cast<intptr_t>(*data_provided);
2001 intptr_t data_written = 0;
2002
2003 if (SpaceToWrite(start, end, size) < provided) {
2004 *data_provided = 0;
2005 return errSSLWouldBlock;
2006 }
2007
2008 // is full, neither if statement is executed and nothing happens.
2009 if (start <= end) {
2010 // If the free space may be split into two segments,
2011 // then the first is [end, size), unless start == 0.
2012 // Then, since the last free byte is at position start - 2,
2013 // the interval is [end, size - 1).
2014 intptr_t buffer_end = (start == 0) ? size - 1 : size;
2015 intptr_t available = buffer_end - end;
2016 intptr_t bytes = provided < available ? provided : available;
2017 memmove(&buffer[end], datap, bytes);
2018 end += bytes;
2019 datap += bytes;
2020 data_written += bytes;
2021 provided -= bytes;
2022 ASSERT(end <= size);
2023 if (end == size) {
2024 end = 0;
2025 }
2026 }
2027 if ((provided > 0) && (start > end + 1)) {
2028 intptr_t available = (start - 1) - end;
2029 intptr_t bytes = provided < available ? provided : available;
2030 memmove(&buffer[end], datap, bytes);
2031 end += bytes;
2032 datap += bytes;
2033 data_written += bytes;
2034 provided -= bytes;
2035 ASSERT(end < start);
2036 }
2037
2038 if (SSL_LOG_DATA) {
2039 Log::Print("SSLWriteCallback: provided: %ld, written %ld bytes\n",
2040 *data_provided, data_written);
2041 }
2042
2043 filter->SetBufferEnd(kWriteEncrypted, end);
2044 *data_provided = data_written;
2045 return noErr;
2046 }
2047
2048
2049 OSStatus SSLFilter::ProcessWritePlaintextBuffer(intptr_t start,
2050 intptr_t end,
2051 intptr_t* bytes_processed) {
2052 ASSERT(bytes_processed != NULL);
2053 intptr_t length = end - start;
2054 OSStatus status = noErr;
2055 size_t bytes = 0;
2056 if (length > 0) {
2057 status = SSLWrite(
2058 ssl_context_,
2059 reinterpret_cast<void*>(buffers_[kWritePlaintext] + start),
2060 length,
2061 &bytes);
2062 if ((status != noErr) && (status != errSSLWouldBlock)) {
2063 *bytes_processed = 0;
2064 return status;
2065 }
2066 }
2067 *bytes_processed = static_cast<intptr_t>(bytes);
2068 return status;
2069 }
2070
2071 } // namespace bin
2072 } // namespace dart
2073
2074 #endif // defined(TARGET_OS_MACOS)
OLDNEW
« no previous file with comments | « runtime/bin/secure_socket_macos.h ('k') | runtime/bin/secure_socket_patch.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698