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

Unified Diff: runtime/bin/secure_socket_macos.cc

Issue 2903743002: Porting SecureSocket to use BoringSSL on OSX (Closed)
Patch Set: General cleanup Created 3 years, 7 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 side-by-side diff with in-line comments
Download patch
Index: runtime/bin/secure_socket_macos.cc
diff --git a/runtime/bin/secure_socket_macos.cc b/runtime/bin/secure_socket_macos.cc
index 520f2c93780a521dd0a27ada0804d884447f368f..5efc97c568d11c589c48dea5c973a379579dcac8 100644
--- a/runtime/bin/secure_socket_macos.cc
+++ b/runtime/bin/secure_socket_macos.cc
@@ -1,7 +1,6 @@
// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-
zra 2017/05/26 18:11:13 restore newline
bkonyi 2017/05/26 23:35:30 Done.
#if !defined(DART_IO_DISABLED) && !defined(DART_IO_SECURE_SOCKET_DISABLED)
#include "platform/globals.h"
@@ -9,6 +8,7 @@
#include "bin/secure_socket.h"
#include "bin/secure_socket_macos.h"
+#include "bin/secure_socket_scope_utils.h"
#include <errno.h>
#include <fcntl.h>
@@ -21,6 +21,14 @@
#include <Security/SecureTransport.h>
#include <Security/Security.h>
+#include <openssl/bio.h>
+#include <openssl/err.h>
+#include <openssl/pkcs12.h>
+#include <openssl/safestack.h>
+#include <openssl/ssl.h>
+#include <openssl/tls1.h>
+#include <openssl/x509.h>
+
#include "bin/builtin.h"
#include "bin/dartutils.h"
#include "bin/lockers.h"
@@ -34,37 +42,22 @@
#include "include/dart_api.h"
-// Return the error from the containing function if handle is an error handle.
-#define RETURN_IF_ERROR(handle) \
- { \
- Dart_Handle __handle = handle; \
- if (Dart_IsError((__handle))) { \
- return __handle; \
- } \
- }
-
-// We need to access this private API function to create a SecIdentityRef
-// without writing a custom keychain to the filesystem. This is the approach
-// taken in WebKit:
-// https://webkit.googlesource.com/WebKit/+/master/Source/WebKit2/Shared/cf/ArgumentCodersCF.cpp
-extern "C" {
-SecIdentityRef SecIdentityCreate(CFAllocatorRef allocator,
- SecCertificateRef certificate,
- SecKeyRef private_key);
-}
-
namespace dart {
namespace bin {
-static const int kSSLFilterNativeFieldIndex = 0;
-static const int kSecurityContextNativeFieldIndex = 0;
-static const int kX509NativeFieldIndex = 0;
+extern const int kSSLFilterNativeFieldIndex;
zra 2017/05/26 18:11:13 Why are these extern? Maybe make them static const
bkonyi 2017/05/26 23:35:31 Done.
+extern const int kSecurityContextNativeFieldIndex;
+
+const int kX509NativeFieldIndex = 0;
zra 2017/05/26 18:11:13 This one could go in the SSLCertContext, too, I th
bkonyi 2017/05/26 23:35:31 Done.
+
+const intptr_t SSLCertContext::kApproximateSize = sizeof(SSLCertContext);
+static void ReleaseCertificate(void* isolate_data,
+ Dart_WeakPersistentHandle handle,
+ void* context_pointer) {
+ SecCertificateRef cert = reinterpret_cast<SecCertificateRef>(context_pointer);
+ CFRelease(cert);
+}
-static const bool SSL_LOG_STATUS = false;
-static const bool SSL_LOG_DATA = false;
-static const bool SSL_LOG_CERTS = false;
-static const int SSL_ERROR_MESSAGE_BUFFER_SIZE = 1000;
-static const intptr_t PEM_BUFSIZE = 1024;
static char* CFStringRefToCString(CFStringRef cfstring) {
CFIndex len = CFStringGetLength(cfstring);
@@ -78,111 +71,6 @@ static char* CFStringRefToCString(CFStringRef cfstring) {
}
-// Handle an error reported from the SecureTransport library.
-static void ThrowIOException(OSStatus status,
- const char* exception_type,
- const char* message) {
- TextBuffer status_message(SSL_ERROR_MESSAGE_BUFFER_SIZE);
- CFStringRef error_string = SecCopyErrorMessageString(status, NULL);
- if (error_string == NULL) {
- status_message.Printf("OSStatus = %ld: https://www.osstatus.com",
- static_cast<intptr_t>(status));
- } else {
- char* error = CFStringRefToCString(error_string);
- status_message.Printf("OSStatus = %ld: %s", static_cast<intptr_t>(status),
- error);
- CFRelease(error_string);
- }
- OSError os_error_struct(status, status_message.buf(), OSError::kBoringSSL);
- Dart_Handle os_error = DartUtils::NewDartOSError(&os_error_struct);
- Dart_Handle exception =
- DartUtils::NewDartIOException(exception_type, message, os_error);
- ASSERT(!Dart_IsError(exception));
- Dart_ThrowException(exception);
- UNREACHABLE();
-}
-
-
-static void CheckStatus(OSStatus status,
- const char* type,
- const char* message) {
- if (status == noErr) {
- return;
- }
- ThrowIOException(status, type, message);
-}
-
-
-static SSLFilter* GetFilter(Dart_NativeArguments args) {
- SSLFilter* filter;
- Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0));
- ASSERT(Dart_IsInstance(dart_this));
- ThrowIfError(
- Dart_GetNativeInstanceField(dart_this, kSSLFilterNativeFieldIndex,
- reinterpret_cast<intptr_t*>(&filter)));
- return filter;
-}
-
-
-static void DeleteFilter(void* isolate_data,
- Dart_WeakPersistentHandle handle,
- void* context_pointer) {
- SSLFilter* filter = reinterpret_cast<SSLFilter*>(context_pointer);
- filter->Release();
-}
-
-
-static Dart_Handle SetFilter(Dart_NativeArguments args, SSLFilter* filter) {
- ASSERT(filter != NULL);
- const int approximate_size_of_filter = 1500;
- Dart_Handle dart_this = Dart_GetNativeArgument(args, 0);
- RETURN_IF_ERROR(dart_this);
- ASSERT(Dart_IsInstance(dart_this));
- Dart_Handle err =
- Dart_SetNativeInstanceField(dart_this, kSSLFilterNativeFieldIndex,
- reinterpret_cast<intptr_t>(filter));
- RETURN_IF_ERROR(err);
- Dart_NewWeakPersistentHandle(dart_this, reinterpret_cast<void*>(filter),
- approximate_size_of_filter, DeleteFilter);
- return Dart_Null();
-}
-
-
-static SSLCertContext* GetSecurityContext(Dart_NativeArguments args) {
- SSLCertContext* context;
- Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0));
- ASSERT(Dart_IsInstance(dart_this));
- ThrowIfError(
- Dart_GetNativeInstanceField(dart_this, kSecurityContextNativeFieldIndex,
- reinterpret_cast<intptr_t*>(&context)));
- return context;
-}
-
-
-static void DeleteCertContext(void* isolate_data,
- Dart_WeakPersistentHandle handle,
- void* context_pointer) {
- SSLCertContext* context = static_cast<SSLCertContext*>(context_pointer);
- context->Release();
-}
-
-
-static Dart_Handle SetSecurityContext(Dart_NativeArguments args,
- SSLCertContext* context) {
- const int approximate_size_of_context = 1500;
- Dart_Handle dart_this = Dart_GetNativeArgument(args, 0);
- RETURN_IF_ERROR(dart_this);
- ASSERT(Dart_IsInstance(dart_this));
- Dart_Handle err =
- Dart_SetNativeInstanceField(dart_this, kSecurityContextNativeFieldIndex,
- reinterpret_cast<intptr_t>(context));
- RETURN_IF_ERROR(err);
- Dart_NewWeakPersistentHandle(dart_this, context, approximate_size_of_context,
- DeleteCertContext);
- return Dart_Null();
-}
-
-
static SecCertificateRef GetX509Certificate(Dart_NativeArguments args) {
SecCertificateRef certificate;
Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0));
@@ -194,14 +82,6 @@ static SecCertificateRef GetX509Certificate(Dart_NativeArguments args) {
}
-static void ReleaseCertificate(void* isolate_data,
- Dart_WeakPersistentHandle handle,
- void* context_pointer) {
- SecCertificateRef cert = reinterpret_cast<SecCertificateRef>(context_pointer);
- CFRelease(cert);
-}
-
-
static Dart_Handle WrappedX509Certificate(SecCertificateRef certificate) {
const intptr_t approximate_size_of_certificate = 1500;
if (certificate == NULL) {
@@ -237,38 +117,189 @@ static Dart_Handle WrappedX509Certificate(SecCertificateRef certificate) {
}
-static const char* GetPasswordArgument(Dart_NativeArguments args,
- intptr_t index) {
- Dart_Handle password_object =
- ThrowIfError(Dart_GetNativeArgument(args, index));
- const char* password = NULL;
- if (Dart_IsString(password_object)) {
- ThrowIfError(Dart_StringToCString(password_object, &password));
- if (strlen(password) > PEM_BUFSIZE - 1) {
- Dart_ThrowException(DartUtils::NewDartArgumentError(
- "Password length is greater than 1023 bytes."));
+static void CheckStatusMacOS(int status,
zra 2017/05/26 18:11:13 I think you can call this just CheckStatus if you
bkonyi 2017/05/26 23:35:30 Done.
+ const char* type,
+ const char* message) {
+ if (status == noErr) {
+ return;
+ }
+ ThrowIOException(status, type, message, NULL);
+}
+
+
+SecCertificateRef CreateMacosCertFromX509(X509* cert) {
zra 2017/05/26 18:11:13 Same comment about MacosCert -> SecCertificate.
bkonyi 2017/05/26 23:35:30 Done.
+ unsigned char* deb_cert = NULL;
+ int length = i2d_X509(cert, &deb_cert);
+ if (length < 0) {
+ return 0;
+ }
+ ASSERT(deb_cert != NULL);
+ CFDataRef cert_buf =
+ CFDataCreateWithBytesNoCopy(NULL, deb_cert, length, kCFAllocatorNull);
+ SecCertificateRef auth_cert = SecCertificateCreateWithData(NULL, cert_buf);
+ if (auth_cert == NULL) {
+ return NULL;
+ }
+ return auth_cert;
+}
+
+
+int MacosCertVerificationCallback(X509_STORE_CTX* ctx, void* arg) {
zra 2017/05/26 18:11:13 static Maybe just CertVerificationCallback
bkonyi 2017/05/26 23:35:30 Done.
+ SSLCertContext* context = static_cast<SSLCertContext*>(arg);
+
+ // Convert BoringSSL formatted certificates to SecCertificate certificates.
+ CFMutableArrayRef cert_chain = NULL;
+ X509* root_cert = NULL;
+ if (ctx->untrusted != NULL) {
+ STACK_OF(X509)* user_provided_certs = ctx->untrusted;
+ int num_certs = sk_X509_num(user_provided_certs);
+ int current_cert = 0;
+ cert_chain = CFArrayCreateMutable(NULL, num_certs, NULL);
+ X509* ca;
+ while ((ca = sk_X509_shift(user_provided_certs)) != NULL) {
+ SecCertificateRef cert = CreateMacosCertFromX509(ca);
+ ASSERT(cert != NULL);
zra 2017/05/26 18:11:13 Same comment here as in _ios.cc
bkonyi 2017/05/26 23:35:31 Done.
+ CFArrayAppendValue(cert_chain, cert);
+ CFRelease(cert);
+ ++current_cert;
+
+ if (current_cert == num_certs) {
+ root_cert = ca;
+ }
}
- } else if (Dart_IsNull(password_object)) {
- password = "";
- } else {
- Dart_ThrowException(
- DartUtils::NewDartArgumentError("Password is not a String or null"));
}
- return password;
+
+ // Generate a generic X509 verification policy.
+ SecPolicyRef policy = SecPolicyCreateBasicX509();
+
+ // Create the trust object with the certificates provided by the user.
+ SecTrustRef trust = NULL;
+ OSStatus status = SecTrustCreateWithCertificates(cert_chain, policy, &trust);
+ if (status != noErr) {
+ CFRelease(cert_chain);
+ CFRelease(policy);
+ return ctx->verify_cb(0, ctx);
+ }
+
+ // If the user provided any additional CA certificates, add them to the trust
+ // object.
+ if (context->trusted_certs() != NULL) {
+ status = SecTrustSetAnchorCertificates(trust, context->trusted_certs());
+ if (status != noErr) {
+ CFRelease(cert_chain);
+ CFRelease(policy);
+ CFRelease(trust);
+ return ctx->verify_cb(0, ctx);
+ }
+ }
+
+ // Specify whether or not to use the built-in CA certificates for
+ // verification.
+ status = SecTrustSetAnchorCertificatesOnly(trust, !context->trust_builtin());
+ if (status != noErr) {
+ CFRelease(cert_chain);
+ CFRelease(policy);
+ CFRelease(trust);
+ return ctx->verify_cb(0, ctx);
+ }
+
+ // Perform the certificate verification.
+ SecTrustResultType trust_result;
+ status = SecTrustEvaluate(trust, &trust_result);
+ if (status != noErr) {
+ CFRelease(cert_chain);
+ CFRelease(policy);
+ CFRelease(trust);
+ return ctx->verify_cb(0, ctx);
+ }
+
+ CFRelease(cert_chain);
+ CFRelease(policy);
+ CFRelease(trust);
+
+ if ((trust_result == kSecTrustResultProceed) ||
+ (trust_result == kSecTrustResultUnspecified)) {
+ // Successfully verified certificate!
+ return ctx->verify_cb(1, ctx);
+ }
+
+ // Set current_cert to the root of the certificate chain. This will be passed
+ // to the callback provided by the user for additional verification steps.
+ ctx->current_cert = root_cert;
+ return ctx->verify_cb(0, ctx);
+}
+
+
+int CertificateCallback(int preverify_ok, X509_STORE_CTX* store_ctx) {
zra 2017/05/26 18:11:13 static
bkonyi 2017/05/26 23:35:31 Done.
+ if (preverify_ok == 1) {
+ return 1;
+ }
+ Dart_Isolate isolate = Dart_CurrentIsolate();
+ if (isolate == NULL) {
+ FATAL("CertificateCallback called with no current isolate\n");
+ }
+ int ssl_index = SSL_get_ex_data_X509_STORE_CTX_idx();
+ SSL* ssl =
+ static_cast<SSL*>(X509_STORE_CTX_get_ex_data(store_ctx, ssl_index));
+ SSLFilter* filter = static_cast<SSLFilter*>(
+ SSL_get_ex_data(ssl, SSLFilter::filter_ssl_index));
+ X509* certificate = X509_STORE_CTX_get_current_cert(store_ctx);
+ Dart_Handle callback = filter->bad_certificate_callback();
+ if (Dart_IsNull(callback)) {
+ return 0;
+ }
+
+ // Upref since the Dart X509 object may outlive the SecurityContext.
+ if (certificate != NULL) {
+ X509_up_ref(certificate);
+ }
+ Dart_Handle args[1];
+ args[0] = WrappedX509Certificate(CreateMacosCertFromX509(certificate));
+ if (Dart_IsError(args[0])) {
+ filter->callback_error = args[0];
+ return 0;
+ }
+ Dart_Handle result = Dart_InvokeClosure(callback, 1, args);
+ if (!Dart_IsError(result) && !Dart_IsBoolean(result)) {
+ result = Dart_NewUnhandledExceptionError(DartUtils::NewDartIOException(
+ "HandshakeException",
+ "BadCertificateCallback returned a value that was not a boolean",
+ Dart_Null()));
+ }
+ if (Dart_IsError(result)) {
+ filter->callback_error = result;
+ return 0;
+ }
+ return DartUtils::GetBooleanValue(result);
+}
+
+
+void SSLFilter::RegisterCallbacks(SSLCertContext* cert_ctx) {
+ SSL_CTX* ctx = SSL_get_SSL_CTX(ssl_);
+ SSL_CTX_set_cert_verify_callback(ctx, MacosCertVerificationCallback,
+ cert_ctx);
+}
+
+
+Dart_Handle SSLFilter::PeerCertificate() {
+ X509* ca = SSL_get_peer_certificate(ssl_);
+ if (ca == NULL) {
+ return Dart_Null();
+ }
+ SecCertificateRef peer = CreateMacosCertFromX509(ca);
+ return WrappedX509Certificate(peer);
}
-static OSStatus GetKeyAndCerts(CFArrayRef items,
- CFIndex items_length,
- CFArrayRef* out_certs,
- SecKeyRef* out_key) {
+static OSStatus GetCerts(CFArrayRef items,
+ CFIndex items_length,
+ CFArrayRef* out_certs) {
OSStatus status = noErr;
// Loop through the items, take only the first private key/identity, ignore
// any others, populate out_certs.
CFMutableArrayRef certs =
CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
- SecKeyRef key = NULL;
for (CFIndex i = 0; i < items_length; ++i) {
CFTypeRef item =
@@ -279,46 +310,10 @@ static OSStatus GetKeyAndCerts(CFArrayRef items,
Log::Print("\titem %ld: Certificate\n", i);
}
CFArrayAppendValue(certs, item);
- } else if ((item_type == SecKeyGetTypeID()) && (key == NULL)) {
- if (SSL_LOG_CERTS) {
- Log::Print("\titem %ld: Key\n", i);
- }
- key = reinterpret_cast<SecKeyRef>(const_cast<void*>(item));
- CFRetain(key);
- } else if ((item_type == SecIdentityGetTypeID()) && (key == NULL)) {
- if (SSL_LOG_CERTS) {
- Log::Print("\titem %ld: Identity\n", i);
- }
- SecIdentityRef identity =
- reinterpret_cast<SecIdentityRef>(const_cast<void*>(item));
- SecCertificateRef cert = NULL;
-
- status = SecIdentityCopyPrivateKey(identity, &key);
- if (status != noErr) {
- CFRelease(certs);
- return status;
- }
-
- status = SecIdentityCopyCertificate(identity, &cert);
- if (status != noErr) {
- CFRelease(key);
- CFRelease(certs);
- return status;
- }
- CFArrayAppendValue(certs, cert);
- CFRelease(cert);
}
// Other item types are ignored.
}
- if (out_key == NULL) {
- if (key != NULL) {
- CFRelease(key);
- }
- } else {
- *out_key = key;
- }
-
if (out_certs == NULL) {
if (certs != NULL) {
CFRelease(certs);
@@ -332,8 +327,7 @@ static OSStatus GetKeyAndCerts(CFArrayRef items,
static OSStatus TryPEMImport(CFDataRef cfdata,
CFStringRef password,
- CFArrayRef* out_certs,
- SecKeyRef* out_key) {
+ CFArrayRef* out_certs) {
OSStatus status = noErr;
SecExternalFormat format = kSecFormatPEMSequence;
@@ -370,62 +364,14 @@ static OSStatus TryPEMImport(CFDataRef cfdata,
return errSSLBadCert;
}
- status = GetKeyAndCerts(items, items_length, out_certs, out_key);
+ status = GetCerts(items, items_length, out_certs);
CFRelease(items);
return status;
}
-
-static char* TempKeychainPath() {
- const char* exes = "keychaindir.XXXX";
- const char* fname = "keychain";
- const char* temp_dir = getenv("TMPDIR");
- if (temp_dir == NULL) {
- temp_dir = getenv("TMP");
- }
- if (temp_dir == NULL) {
- temp_dir = "/tmp/";
- }
- ASSERT(temp_dir != NULL);
-
- TextBuffer path(PATH_MAX);
- path.Printf("%s/%s", temp_dir, exes);
- char* ret = mkdtemp(path.buf());
- ASSERT(ret != NULL);
- path.Printf("/%s", fname);
-
- char* result = reinterpret_cast<char*>(Dart_ScopeAllocate(path.length() + 1));
- return strncpy(result, path.buf(), path.length() + 1);
-}
-
-
-static OSStatus CreateKeychain(SecKeychainRef* keychain) {
- ASSERT(keychain != NULL);
- OSStatus status = noErr;
- const char* temp_keychain_pwd = "dartdart";
- char* temp_file_path = TempKeychainPath();
- ASSERT(temp_file_path != NULL);
- if (SSL_LOG_CERTS) {
- Log::Print("Temporary keychain at: '%s'\n", temp_file_path);
- }
- status = SecKeychainCreate(temp_file_path, strlen(temp_keychain_pwd) + 1,
- reinterpret_cast<const void*>(temp_keychain_pwd),
- FALSE, // Prompt user? Definitely no.
- NULL, // Default access rights.
- keychain);
- if (status != noErr) {
- return status;
- }
- ASSERT(*keychain != NULL);
- return status;
-}
-
-
static OSStatus TryPKCS12Import(CFDataRef cfdata,
CFStringRef password,
- CFArrayRef* out_certs,
- SecKeyRef* out_key,
- SecKeychainRef* out_keychain) {
+ CFArrayRef* out_certs) {
OSStatus status = noErr;
SecExternalFormat format = kSecFormatPKCS12;
@@ -443,41 +389,8 @@ static OSStatus TryPKCS12Import(CFDataRef cfdata,
sitem_type, format);
}
- // The documentation for SecKeychainItemImport here:
- //
- // https://developer.apple.com/library/mac/documentation/Security/Reference/keychainservices/index.html
- //
- // states that when the SecKeychainRef argument is NULL, the CFArrayRef*
- // argument will be populated by an array containing all keys, identities,
- // and certificates from the data in the CFDataRef argument.
- //
- // Unfortunately, this is not true. The code to populate the CFArrayRef with
- // keys and identities from PKCS12 data has been skipped and/or commented out,
- // here:
- //
- // https://github.com/Apple-FOSS-Mirror/Security/blob/master/libsecurity_keychain/lib/SecImportExportAgg.cpp#L636
- //
- // as "floating" SecKeyRefs from the PKCS12 decoder haven't been implemented.
- // That is, each private key instance coming from the PKCS12 decoder has to be
- // associated with a keychain instance. Thus, as a workaround, we create a
- // temporary keychain here if one is needed, and stash it below in a
- // SecurityContext. This has the drawbacks:
- // 1.) We need to make a temporary directory to hold the keychain file, and
- // 2.) SecKeychainItemImport() probably does blocking IO to create and
- // manipulate the keychain file.
- // So if the API is updated, this keychain should not be used.
- SecKeychainRef keychain = NULL;
- if (out_key != NULL) {
- ASSERT(out_keychain != NULL);
- status = CreateKeychain(&keychain);
- if (status != noErr) {
- return status;
- }
- *out_keychain = keychain;
- }
-
- status = SecItemImport(cfdata, NULL, &format, &sitem_type, 0, &params,
- keychain, &items);
+ status = SecItemImport(cfdata, NULL, &format, &sitem_type, 0, &params, NULL,
+ &items);
if (status != noErr) {
if (SSL_LOG_CERTS) {
Log::Print("TrySecItemImport failed with: %ld, it = %d, format = %d\n",
@@ -497,7 +410,7 @@ static OSStatus TryPKCS12Import(CFDataRef cfdata,
return errSSLBadCert;
}
- status = GetKeyAndCerts(items, items_length, out_certs, out_key);
+ status = GetCerts(items, items_length, out_certs);
CFRelease(items);
return status;
}
@@ -506,9 +419,7 @@ static OSStatus TryPKCS12Import(CFDataRef cfdata,
static OSStatus ExtractSecItems(uint8_t* buffer,
intptr_t length,
const char* password,
- CFArrayRef* out_certs,
- SecKeyRef* out_key,
- SecKeychainRef* out_keychain) {
+ CFArrayRef* out_certs) {
ASSERT(buffer != NULL);
ASSERT(password != NULL);
OSStatus status = noErr;
@@ -520,280 +431,196 @@ static OSStatus ExtractSecItems(uint8_t* buffer,
ASSERT(cfdata != NULL);
ASSERT(cfpassword != NULL);
- status = TryPEMImport(cfdata, cfpassword, out_certs, out_key);
+ status = TryPEMImport(cfdata, cfpassword, out_certs);
if (status != noErr) {
- status =
- TryPKCS12Import(cfdata, cfpassword, out_certs, out_key, out_keychain);
+ status = TryPKCS12Import(cfdata, cfpassword, out_certs);
}
-
CFRelease(cfdata);
CFRelease(cfpassword);
return status;
}
-void FUNCTION_NAME(SecureSocket_Init)(Dart_NativeArguments args) {
- Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0));
- SSLFilter* filter = new SSLFilter(); // Deleted in DeleteFilter finalizer.
- Dart_Handle err = SetFilter(args, filter);
- if (Dart_IsError(err)) {
- filter->Release();
- Dart_PropagateError(err);
- }
- err = filter->Init(dart_this);
- if (Dart_IsError(err)) {
- // The finalizer was set up by SetFilter. It will delete `filter` if there
- // is an error.
- filter->Destroy();
- Dart_PropagateError(err);
- }
-}
+void FUNCTION_NAME(SecurityContext_SetTrustedCertificatesBytes)(
+ Dart_NativeArguments args) {
+ SSLCertContext* context = SSLCertContext::GetSecurityContext(args);
+ const char* password = SSLCertContext::GetPasswordArgument(args, 2);
+ OSStatus status;
+ CFArrayRef certs = NULL;
+ {
+ ScopedMemBuffer buffer(ThrowIfError(Dart_GetNativeArgument(args, 1)));
+ status = ExtractSecItems(buffer.get(), buffer.length(), password, &certs);
+ }
-void FUNCTION_NAME(SecureSocket_Connect)(Dart_NativeArguments args) {
- Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0));
- Dart_Handle host_name_object = ThrowIfError(Dart_GetNativeArgument(args, 1));
- Dart_Handle context_object = ThrowIfError(Dart_GetNativeArgument(args, 2));
- bool is_server = DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 3));
- bool request_client_certificate =
- DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 4));
- bool require_client_certificate =
- DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 5));
-
- const char* host_name = NULL;
- // TODO(whesse): Is truncating a Dart string containing \0 what we want?
- ThrowIfError(Dart_StringToCString(host_name_object, &host_name));
-
- SSLCertContext* context = NULL;
- if (!Dart_IsNull(context_object)) {
- ThrowIfError(Dart_GetNativeInstanceField(
- context_object, kSecurityContextNativeFieldIndex,
- reinterpret_cast<intptr_t*>(&context)));
+ // Set the field in the context. If there's a failure, release the certs,
+ // and throw an exception.
+ if ((certs != NULL) && !context->set_trusted_certs(certs)) {
+ CFRelease(certs);
+ Dart_ThrowException(DartUtils::NewDartArgumentError(
+ "setTrustedCertificatesBytes has already been called "
+ "on the given context."));
}
- GetFilter(args)->Connect(dart_this, host_name, context, is_server,
- request_client_certificate,
- require_client_certificate);
+ CheckStatusMacOS(status, "TlsException",
+ "Failure in setTrustedCertificatesBytes");
}
-void FUNCTION_NAME(SecureSocket_Destroy)(Dart_NativeArguments args) {
- SSLFilter* filter = GetFilter(args);
- // The SSLFilter is deleted in the finalizer for the Dart object created by
- // SetFilter. There is no need to NULL-out the native field for the SSLFilter
- // here because the SSLFilter won't be deleted until the finalizer for the
- // Dart object runs while the Dart object is being GCd. This approach avoids a
- // leak if Destroy isn't called, and avoids a NULL-dereference if Destroy is
- // called more than once.
- filter->Destroy();
-}
-
+void FUNCTION_NAME(SecurityContext_SetClientAuthoritiesBytes)(
+ Dart_NativeArguments args) {
+ SSLCertContext* context = SSLCertContext::GetSecurityContext(args);
+ const char* password = SSLCertContext::GetPasswordArgument(args, 2);
-void FUNCTION_NAME(SecureSocket_Handshake)(Dart_NativeArguments args) {
- OSStatus status = GetFilter(args)->CheckHandshake();
- CheckStatus(status, "HandshakeException", "Handshake error");
-}
+ OSStatus status;
+ CFArrayRef certs = NULL;
+ {
+ ScopedMemBuffer buffer(ThrowIfError(Dart_GetNativeArgument(args, 1)));
+ status = ExtractSecItems(buffer.get(), buffer.length(), password, &certs);
+ }
+ // Set the field in the context. If there's a failure, release the certs,
+ // and throw an exception.
+ if ((certs != NULL) && !context->set_cert_authorities(certs)) {
+ CFRelease(certs);
+ Dart_ThrowException(DartUtils::NewDartArgumentError(
+ "setClientAuthoritiesBytes has already been called "
+ "on the given context."));
+ }
-void FUNCTION_NAME(SecureSocket_GetSelectedProtocol)(
- Dart_NativeArguments args) {
- Dart_SetReturnValue(args, Dart_Null());
+ CheckStatusMacOS(status, "TlsException",
+ "Failure in setClientAuthoritiesBytes");
}
-void FUNCTION_NAME(SecureSocket_Renegotiate)(Dart_NativeArguments args) {
- bool use_session_cache =
- DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 1));
- bool request_client_certificate =
- DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 2));
- bool require_client_certificate =
- DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 3));
- GetFilter(args)->Renegotiate(use_session_cache, request_client_certificate,
- require_client_certificate);
+static bool NoPEMStartLine() {
zra 2017/05/26 18:11:13 Maybe move to a utility class in secure_socket.h
bkonyi 2017/05/26 23:35:30 Done.
+ uint32_t last_error = ERR_peek_last_error();
+ return (ERR_GET_LIB(last_error) == ERR_LIB_PEM) &&
+ (ERR_GET_REASON(last_error) == PEM_R_NO_START_LINE);
}
-void FUNCTION_NAME(SecureSocket_RegisterHandshakeCompleteCallback)(
- Dart_NativeArguments args) {
- Dart_Handle handshake_complete =
- ThrowIfError(Dart_GetNativeArgument(args, 1));
- if (!Dart_IsClosure(handshake_complete)) {
- Dart_ThrowException(DartUtils::NewDartArgumentError(
- "Illegal argument to RegisterHandshakeCompleteCallback"));
+static int UseChainBytesPKCS12(SSL_CTX* context,
+ BIO* bio,
+ const char* password) {
+ ScopedPKCS12 p12(d2i_PKCS12_bio(bio, NULL));
+ if (p12.get() == NULL) {
+ return 0;
}
- GetFilter(args)->RegisterHandshakeCompleteCallback(handshake_complete);
-}
-
-void FUNCTION_NAME(SecureSocket_RegisterBadCertificateCallback)(
- Dart_NativeArguments args) {
- Dart_Handle callback = ThrowIfError(Dart_GetNativeArgument(args, 1));
- if (!Dart_IsClosure(callback) && !Dart_IsNull(callback)) {
- Dart_ThrowException(DartUtils::NewDartArgumentError(
- "Illegal argument to RegisterBadCertificateCallback"));
+ EVP_PKEY* key = NULL;
+ X509* cert = NULL;
+ STACK_OF(X509)* ca_certs = NULL;
+ int status = PKCS12_parse(p12.get(), password, &key, &cert, &ca_certs);
+ if (status == 0) {
+ return status;
}
- GetFilter(args)->RegisterBadCertificateCallback(callback);
-}
+ ScopedX509 x509(cert);
+ ScopedX509Stack certs(ca_certs);
+ status = SSL_CTX_use_certificate(context, x509.get());
+ if (ERR_peek_error() != 0) {
+ // Key/certificate mismatch doesn't imply status is 0.
+ status = 0;
+ }
+ if (status == 0) {
+ return status;
+ }
-void FUNCTION_NAME(SecureSocket_PeerCertificate)(Dart_NativeArguments args) {
- Dart_SetReturnValue(args, GetFilter(args)->PeerCertificate());
-}
+ SSL_CTX_clear_chain_certs(context);
+ X509* ca;
+ while ((ca = sk_X509_shift(certs.get())) != NULL) {
+ status = SSL_CTX_add0_chain_cert(context, ca);
+ // SSL_CTX_add0_chain_cert does not inc ref count, so don't free unless the
+ // call fails.
+ if (status == 0) {
+ X509_free(ca);
+ return status;
+ }
+ }
-void FUNCTION_NAME(SecureSocket_FilterPointer)(Dart_NativeArguments args) {
- SSLFilter* filter = GetFilter(args);
- // This filter pointer is passed to the IO Service thread. The IO Service
- // thread must Release() the pointer when it is done with it.
- filter->Retain();
- intptr_t filter_pointer = reinterpret_cast<intptr_t>(filter);
- Dart_SetReturnValue(args, Dart_NewInteger(filter_pointer));
+ return status;
}
-void FUNCTION_NAME(SecurityContext_Allocate)(Dart_NativeArguments args) {
- SSLCertContext* cert_context = new SSLCertContext();
- // cert_context deleted in DeleteCertContext finalizer.
- Dart_Handle err = SetSecurityContext(args, cert_context);
- if (Dart_IsError(err)) {
- cert_context->Release();
- Dart_PropagateError(err);
+static int UseChainBytesPEM(SSL_CTX* context, BIO* bio) {
+ int status = 0;
+ ScopedX509 x509(PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL));
+ if (x509.get() == NULL) {
+ return 0;
}
-}
+ status = SSL_CTX_use_certificate(context, x509.get());
+ if (ERR_peek_error() != 0) {
+ // Key/certificate mismatch doesn't imply status is 0.
+ status = 0;
+ }
+ if (status == 0) {
+ return status;
+ }
-void FUNCTION_NAME(SecurityContext_UsePrivateKeyBytes)(
- Dart_NativeArguments args) {
- SSLCertContext* context = GetSecurityContext(args);
- const char* password = GetPasswordArgument(args, 2);
+ SSL_CTX_clear_chain_certs(context);
- OSStatus status;
- SecKeyRef key = NULL;
- SecKeychainRef keychain = NULL;
- {
- ScopedMemBuffer buffer(ThrowIfError(Dart_GetNativeArgument(args, 1)));
- status = ExtractSecItems(buffer.get(), buffer.length(), password, NULL,
- &key, &keychain);
+ X509* ca;
+ while ((ca = PEM_read_bio_X509(bio, NULL, NULL, NULL)) != NULL) {
+ status = SSL_CTX_add0_chain_cert(context, ca);
+ // SSL_CTX_add0_chain_cert does not inc ref count, so don't free unless the
+ // call fails.
+ if (status == 0) {
+ X509_free(ca);
+ return status;
+ }
+ // Note that we must not free `ca` if it was successfully added to the
+ // chain. We must free the main certificate x509, though since its reference
+ // count is increased by SSL_CTX_use_certificate.
}
- // Set the context fields. If there's a failure, release the items.
- bool set_failure = false;
- if ((key != NULL) && !context->set_private_key(key)) {
- CFRelease(key);
- SecKeychainDelete(keychain);
- CFRelease(keychain);
- set_failure = true;
- }
- if (!set_failure && (keychain != NULL) && !context->set_keychain(keychain)) {
- SecKeychainDelete(keychain);
- CFRelease(keychain);
- }
+ return NoPEMStartLine() ? status : 0;
+}
- if (set_failure) {
- Dart_ThrowException(DartUtils::NewDartArgumentError(
- "usePrivateKeyBytes has already been called on the given context."));
+
+static int UseChainBytes(SSL_CTX* context, BIO* bio, const char* password) {
+ int status = UseChainBytesPEM(context, bio);
+ if (status == 0) {
+ if (NoPEMStartLine()) {
+ ERR_clear_error();
+ BIO_reset(bio);
+ status = UseChainBytesPKCS12(context, bio, password);
+ }
+ } else {
+ // The PEM file was successfully read.
+ ERR_clear_error();
}
- CheckStatus(status, "TlsException", "Failure in usePrivateKeyBytes");
+ return status;
}
-void FUNCTION_NAME(SecurityContext_SetTrustedCertificatesBytes)(
+void FUNCTION_NAME(SecurityContext_UseCertificateChainBytes)(
Dart_NativeArguments args) {
- SSLCertContext* context = GetSecurityContext(args);
- const char* password = GetPasswordArgument(args, 2);
-
- OSStatus status;
- CFArrayRef certs = NULL;
+ SSLCertContext* context = SSLCertContext::GetSecurityContext(args);
+ const char* password = SSLCertContext::GetPasswordArgument(args, 2);
+ int status;
{
- ScopedMemBuffer buffer(ThrowIfError(Dart_GetNativeArgument(args, 1)));
- status = ExtractSecItems(buffer.get(), buffer.length(), password, &certs,
- NULL, NULL);
- }
-
- // Set the field in the context. If there's a failure, release the certs,
- // and throw an exception.
- if ((certs != NULL) && !context->set_trusted_certs(certs)) {
- CFRelease(certs);
- Dart_ThrowException(DartUtils::NewDartArgumentError(
- "setTrustedCertificatesBytes has already been called "
- "on the given context."));
+ ScopedMemBIO bio(ThrowIfError(Dart_GetNativeArgument(args, 1)));
+ status = UseChainBytes(context->context(), bio.bio(), password);
}
-
- CheckStatus(status, "TlsException", "Failure in setTrustedCertificatesBytes");
+ CheckStatus(status, "TlsException", "Failure in useCertificateChainBytes");
}
void FUNCTION_NAME(SecurityContext_AlpnSupported)(Dart_NativeArguments args) {
- Dart_SetReturnValue(args, Dart_NewBoolean(false));
+ Dart_SetReturnValue(args, Dart_NewBoolean(true));
}
void FUNCTION_NAME(SecurityContext_TrustBuiltinRoots)(
Dart_NativeArguments args) {
- SSLCertContext* context = GetSecurityContext(args);
+ SSLCertContext* context = SSLCertContext::GetSecurityContext(args);
context->set_trust_builtin(true);
}
-void FUNCTION_NAME(SecurityContext_UseCertificateChainBytes)(
- Dart_NativeArguments args) {
- SSLCertContext* context = GetSecurityContext(args);
-
- const char* password = GetPasswordArgument(args, 2);
- OSStatus status;
- CFArrayRef certs = NULL;
- {
- ScopedMemBuffer buffer(ThrowIfError(Dart_GetNativeArgument(args, 1)));
- status = ExtractSecItems(buffer.get(), buffer.length(), password, &certs,
- NULL, NULL);
- }
-
- // Set the field in the context. If there's a failure, release the certs,
- // and throw an exception.
- if ((certs != NULL) && !context->set_cert_chain(certs)) {
- CFRelease(certs);
- Dart_ThrowException(DartUtils::NewDartArgumentError(
- "useCertificateChainBytes has already been called "
- "on the given context."));
- }
-
- CheckStatus(status, "TlsException", "Failure in useCertificateChainBytes");
-}
-
-
-void FUNCTION_NAME(SecurityContext_SetClientAuthoritiesBytes)(
- Dart_NativeArguments args) {
- SSLCertContext* context = GetSecurityContext(args);
- const char* password = GetPasswordArgument(args, 2);
-
- OSStatus status;
- CFArrayRef certs = NULL;
- {
- ScopedMemBuffer buffer(ThrowIfError(Dart_GetNativeArgument(args, 1)));
- status = ExtractSecItems(buffer.get(), buffer.length(), password, &certs,
- NULL, NULL);
- }
-
- // Set the field in the context. If there's a failure, release the certs,
- // and throw an exception.
- if ((certs != NULL) && !context->set_cert_authorities(certs)) {
- CFRelease(certs);
- Dart_ThrowException(DartUtils::NewDartArgumentError(
- "setClientAuthoritiesBytes has already been called "
- "on the given context."));
- }
-
- CheckStatus(status, "TlsException", "Failure in setClientAuthoritiesBytes");
-}
-
-
-void FUNCTION_NAME(SecurityContext_SetAlpnProtocols)(
- Dart_NativeArguments args) {
- Dart_ThrowException(DartUtils::NewDartUnsupportedError(
- "ALPN is not supported on this platform"));
-}
-
-
static char* GetNameFromCert(SecCertificateRef certificate,
CFTypeRef field,
CFStringRef name) {
@@ -826,7 +653,6 @@ static char* GetNameFromCert(SecCertificateRef certificate,
item = CFDictionaryGetValue(val_dict2, kSecPropertyKeyLabel);
ASSERT(CFGetTypeID(item) == CFStringGetTypeID());
CFStringRef label = reinterpret_cast<CFStringRef>(item);
-
if (CFStringCompare(label, name, 0) == kCFCompareEqualTo) {
item = CFDictionaryGetValue(val_dict2, kSecPropertyKeyValue);
ASSERT(CFGetTypeID(item) == CFStringGetTypeID());
@@ -918,894 +744,6 @@ void FUNCTION_NAME(X509_EndValidity)(Dart_NativeArguments args) {
Dart_NewInteger(static_cast<int64_t>(seconds_since_epoch) * 1000LL));
}
-
-// Pushes data through the SSL filter, reading and writing from circular
-// buffers shared with Dart. Called from the IOService thread.
-//
-// The Dart _SecureFilterImpl class contains 4 ExternalByteArrays used to
-// pass encrypted and plaintext data to and from the C++ SSLFilter object.
-//
-// ProcessFilter is called with a CObject array containing the pointer to
-// the SSLFilter, encoded as an int, and the start and end positions of the
-// valid data in the four circular buffers. The function only reads from
-// the valid data area of the input buffers, and only writes to the free
-// area of the output buffers. The function returns the new start and end
-// positions in the buffers, but it only updates start for input buffers, and
-// end for output buffers. Therefore, the Dart thread can simultaneously
-// write to the free space and end pointer of input buffers, and read from
-// the data space of output buffers, and modify the start pointer.
-//
-// When ProcessFilter returns, the Dart thread is responsible for combining
-// the updated pointers from Dart and C++, to make the new valid state of
-// the circular buffer.
-CObject* SSLFilter::ProcessFilterRequest(const CObjectArray& request) {
- CObjectIntptr filter_object(request[0]);
- SSLFilter* filter = reinterpret_cast<SSLFilter*>(filter_object.Value());
- RefCntReleaseScope<SSLFilter> rs(filter);
-
- bool in_handshake = CObjectBool(request[1]).Value();
- intptr_t starts[SSLFilter::kNumBuffers];
- intptr_t ends[SSLFilter::kNumBuffers];
- for (intptr_t i = 0; i < SSLFilter::kNumBuffers; ++i) {
- starts[i] = CObjectInt32(request[2 * i + 2]).Value();
- ends[i] = CObjectInt32(request[2 * i + 3]).Value();
- }
-
- OSStatus status = filter->ProcessAllBuffers(starts, ends, in_handshake);
- if (status == noErr) {
- CObjectArray* result =
- new CObjectArray(CObject::NewArray(SSLFilter::kNumBuffers * 2));
- for (intptr_t i = 0; i < SSLFilter::kNumBuffers; ++i) {
- result->SetAt(2 * i, new CObjectInt32(CObject::NewInt32(starts[i])));
- result->SetAt(2 * i + 1, new CObjectInt32(CObject::NewInt32(ends[i])));
- }
- return result;
- } else {
- TextBuffer status_message(SSL_ERROR_MESSAGE_BUFFER_SIZE);
- CFStringRef error_string = SecCopyErrorMessageString(status, NULL);
- if (error_string == NULL) {
- status_message.Printf("OSStatus = %ld: https://www.osstatus.com",
- static_cast<intptr_t>(status));
- } else {
- char* error = CFStringRefToCString(error_string);
- status_message.Printf("OSStatus = %ld: %s", static_cast<intptr_t>(status),
- error);
- CFRelease(error_string);
- }
- CObjectArray* result = new CObjectArray(CObject::NewArray(2));
- result->SetAt(0, new CObjectInt32(CObject::NewInt32(status)));
- result->SetAt(1,
- new CObjectString(CObject::NewString(status_message.buf())));
- return result;
- }
-}
-
-
-// Usually buffer_starts_ and buffer_ends_ are populated by ProcessAllBuffers,
-// called from ProcessFilterRequest, called from the IOService thread.
-// However, the first call to SSLHandshake comes from the Dart thread, and so
-// doesn't go through there. This results in calls to SSLReadCallback and
-// SSLWriteCallback in which buffer_starts_ and buffer_ends_ haven't been set
-// up. In that case, since we're coming from Dart anyway, we can access the
-// fieds directly from the Dart objects.
-intptr_t SSLFilter::GetBufferStart(intptr_t idx) const {
- if (buffer_starts_[idx] != NULL) {
- return *buffer_starts_[idx];
- }
- Dart_Handle buffer_handle =
- ThrowIfError(Dart_HandleFromPersistent(dart_buffer_objects_[idx]));
- Dart_Handle start_handle =
- ThrowIfError(Dart_GetField(buffer_handle, DartUtils::NewString("start")));
- int64_t start = DartUtils::GetIntegerValue(start_handle);
- return static_cast<intptr_t>(start);
-}
-
-
-intptr_t SSLFilter::GetBufferEnd(intptr_t idx) const {
- if (buffer_ends_[idx] != NULL) {
- return *buffer_ends_[idx];
- }
- Dart_Handle buffer_handle =
- ThrowIfError(Dart_HandleFromPersistent(dart_buffer_objects_[idx]));
- Dart_Handle end_handle =
- ThrowIfError(Dart_GetField(buffer_handle, DartUtils::NewString("end")));
- int64_t end = DartUtils::GetIntegerValue(end_handle);
- return static_cast<intptr_t>(end);
-}
-
-
-void SSLFilter::SetBufferStart(intptr_t idx, intptr_t value) {
- if (buffer_starts_[idx] != NULL) {
- *buffer_starts_[idx] = value;
- return;
- }
- Dart_Handle buffer_handle =
- ThrowIfError(Dart_HandleFromPersistent(dart_buffer_objects_[idx]));
- ThrowIfError(DartUtils::SetIntegerField(buffer_handle, "start",
- static_cast<int64_t>(value)));
-}
-
-
-void SSLFilter::SetBufferEnd(intptr_t idx, intptr_t value) {
- if (buffer_ends_[idx] != NULL) {
- *buffer_ends_[idx] = value;
- return;
- }
- Dart_Handle buffer_handle =
- ThrowIfError(Dart_HandleFromPersistent(dart_buffer_objects_[idx]));
- ThrowIfError(DartUtils::SetIntegerField(buffer_handle, "end",
- static_cast<int64_t>(value)));
-}
-
-
-OSStatus SSLFilter::ProcessAllBuffers(intptr_t starts[kNumBuffers],
- intptr_t ends[kNumBuffers],
- bool in_handshake) {
- for (intptr_t i = 0; i < kNumBuffers; ++i) {
- buffer_starts_[i] = &starts[i];
- buffer_ends_[i] = &ends[i];
- }
-
- if (in_handshake) {
- OSStatus status = Handshake();
- if (status != noErr) {
- return status;
- }
- } else {
- for (intptr_t i = 0; i < kNumBuffers; ++i) {
- intptr_t start = starts[i];
- intptr_t end = ends[i];
- intptr_t size =
- isBufferEncrypted(i) ? encrypted_buffer_size_ : buffer_size_;
- if (start < 0 || end < 0 || start >= size || end >= size) {
- FATAL("Out-of-bounds internal buffer access in dart:io SecureSocket");
- }
- switch (i) {
- case kReadPlaintext:
- // Write data to the circular buffer's free space. If the buffer
- // is full, neither if statement is executed and nothing happens.
- if (start <= end) {
- // If the free space may be split into two segments,
- // then the first is [end, size), unless start == 0.
- // Then, since the last free byte is at position start - 2,
- // the interval is [end, size - 1).
- intptr_t buffer_end = (start == 0) ? size - 1 : size;
- intptr_t bytes = 0;
- OSStatus status =
- ProcessReadPlaintextBuffer(end, buffer_end, &bytes);
- if ((status != noErr) && (status != errSSLWouldBlock)) {
- return status;
- }
- end += bytes;
- ASSERT(end <= size);
- if (end == size) {
- end = 0;
- }
- }
- if (start > end + 1) {
- intptr_t bytes = 0;
- OSStatus status =
- ProcessReadPlaintextBuffer(end, start - 1, &bytes);
- if ((status != noErr) && (status != errSSLWouldBlock)) {
- return status;
- }
- end += bytes;
- ASSERT(end < start);
- }
- ends[i] = end;
- break;
- case kWritePlaintext:
- // Read/Write data from circular buffer. If the buffer is empty,
- // neither if statement's condition is true.
- if (end < start) {
- // Data may be split into two segments. In this case,
- // the first is [start, size).
- intptr_t bytes = 0;
- OSStatus status = ProcessWritePlaintextBuffer(start, size, &bytes);
- if ((status != noErr) && (status != errSSLWouldBlock)) {
- return status;
- }
- start += bytes;
- ASSERT(start <= size);
- if (start == size) {
- start = 0;
- }
- }
- if (start < end) {
- intptr_t bytes = 0;
- OSStatus status = ProcessWritePlaintextBuffer(start, end, &bytes);
- if ((status != noErr) && (status != errSSLWouldBlock)) {
- return status;
- }
- start += bytes;
- ASSERT(start <= end);
- }
- starts[i] = start;
- break;
- case kReadEncrypted:
- case kWriteEncrypted:
- // These buffers are advanced through SSLReadCallback and
- // SSLWriteCallback, which are called from SSLRead, SSLWrite, and
- // SSLHandshake.
- break;
- default:
- UNREACHABLE();
- }
- }
- }
-
- for (intptr_t i = 0; i < kNumBuffers; ++i) {
- buffer_starts_[i] = NULL;
- buffer_ends_[i] = NULL;
- }
- return noErr;
-}
-
-
-Dart_Handle SSLFilter::Init(Dart_Handle dart_this) {
- ASSERT(string_start_ == NULL);
- string_start_ = Dart_NewPersistentHandle(DartUtils::NewString("start"));
- ASSERT(string_start_ != NULL);
- ASSERT(string_length_ == NULL);
- string_length_ = Dart_NewPersistentHandle(DartUtils::NewString("length"));
- ASSERT(string_length_ != NULL);
- ASSERT(bad_certificate_callback_ == NULL);
- bad_certificate_callback_ = Dart_NewPersistentHandle(Dart_Null());
- ASSERT(bad_certificate_callback_ != NULL);
-
- // Caller handles cleanup on an error.
- return InitializeBuffers(dart_this);
-}
-
-
-Dart_Handle SSLFilter::InitializeBuffers(Dart_Handle dart_this) {
- // Create SSLFilter buffers as ExternalUint8Array objects.
- Dart_Handle buffers_string = DartUtils::NewString("buffers");
- RETURN_IF_ERROR(buffers_string);
- Dart_Handle dart_buffers_object = Dart_GetField(dart_this, buffers_string);
- RETURN_IF_ERROR(dart_buffers_object);
- Dart_Handle secure_filter_impl_type = Dart_InstanceGetType(dart_this);
- RETURN_IF_ERROR(secure_filter_impl_type);
- Dart_Handle size_string = DartUtils::NewString("SIZE");
- RETURN_IF_ERROR(size_string);
- Dart_Handle dart_buffer_size =
- Dart_GetField(secure_filter_impl_type, size_string);
- RETURN_IF_ERROR(dart_buffer_size);
-
- int64_t buffer_size = 0;
- Dart_Handle err = Dart_IntegerToInt64(dart_buffer_size, &buffer_size);
- RETURN_IF_ERROR(err);
-
- Dart_Handle encrypted_size_string = DartUtils::NewString("ENCRYPTED_SIZE");
- RETURN_IF_ERROR(encrypted_size_string);
-
- Dart_Handle dart_encrypted_buffer_size =
- Dart_GetField(secure_filter_impl_type, encrypted_size_string);
- RETURN_IF_ERROR(dart_encrypted_buffer_size);
-
- int64_t encrypted_buffer_size = 0;
- err = Dart_IntegerToInt64(dart_encrypted_buffer_size, &encrypted_buffer_size);
- RETURN_IF_ERROR(err);
-
- if (buffer_size <= 0 || buffer_size > 1 * MB) {
- FATAL("Invalid buffer size in _ExternalBuffer");
- }
- if (encrypted_buffer_size <= 0 || encrypted_buffer_size > 1 * MB) {
- FATAL("Invalid encrypted buffer size in _ExternalBuffer");
- }
- buffer_size_ = static_cast<intptr_t>(buffer_size);
- encrypted_buffer_size_ = static_cast<intptr_t>(encrypted_buffer_size);
-
- Dart_Handle data_identifier = DartUtils::NewString("data");
- RETURN_IF_ERROR(data_identifier);
-
- for (int i = 0; i < kNumBuffers; i++) {
- int size = isBufferEncrypted(i) ? encrypted_buffer_size_ : buffer_size_;
- buffers_[i] = new uint8_t[size];
- ASSERT(buffers_[i] != NULL);
- buffer_starts_[i] = NULL;
- buffer_ends_[i] = NULL;
- dart_buffer_objects_[i] = NULL;
- }
-
- Dart_Handle result = Dart_Null();
- for (int i = 0; i < kNumBuffers; ++i) {
- int size = isBufferEncrypted(i) ? encrypted_buffer_size_ : buffer_size_;
- result = Dart_ListGetAt(dart_buffers_object, i);
- if (Dart_IsError(result)) {
- break;
- }
-
- dart_buffer_objects_[i] = Dart_NewPersistentHandle(result);
- ASSERT(dart_buffer_objects_[i] != NULL);
- Dart_Handle data =
- Dart_NewExternalTypedData(Dart_TypedData_kUint8, buffers_[i], size);
- if (Dart_IsError(data)) {
- result = data;
- break;
- }
- result = Dart_HandleFromPersistent(dart_buffer_objects_[i]);
- if (Dart_IsError(result)) {
- break;
- }
- result = Dart_SetField(result, data_identifier, data);
- if (Dart_IsError(result)) {
- break;
- }
- }
-
- // Caller handles cleanup on an error.
- return result;
-}
-
-
-void SSLFilter::RegisterHandshakeCompleteCallback(Dart_Handle complete) {
- ASSERT(NULL == handshake_complete_);
- handshake_complete_ = Dart_NewPersistentHandle(complete);
- ASSERT(handshake_complete_ != NULL);
-}
-
-
-void SSLFilter::RegisterBadCertificateCallback(Dart_Handle callback) {
- ASSERT(bad_certificate_callback_ != NULL);
- Dart_DeletePersistentHandle(bad_certificate_callback_);
- bad_certificate_callback_ = Dart_NewPersistentHandle(callback);
- ASSERT(bad_certificate_callback_ != NULL);
-}
-
-
-Dart_Handle SSLFilter::PeerCertificate() {
- if (peer_certs_ == NULL) {
- return Dart_Null();
- }
-
- CFTypeRef item = CFArrayGetValueAtIndex(peer_certs_, 0);
- ASSERT(CFGetTypeID(item) == SecCertificateGetTypeID());
- SecCertificateRef cert =
- reinterpret_cast<SecCertificateRef>(const_cast<void*>(item));
- if (cert == NULL) {
- return Dart_Null();
- }
-
- return WrappedX509Certificate(cert);
-}
-
-
-void SSLFilter::Connect(Dart_Handle dart_this,
- const char* hostname,
- SSLCertContext* context,
- bool is_server,
- bool request_client_certificate,
- bool require_client_certificate) {
- if (in_handshake_) {
- FATAL("Connect called twice on the same _SecureFilter.");
- }
-
- // Create the underlying context
- SSLContextRef ssl_context = SSLCreateContext(
- NULL, is_server ? kSSLServerSide : kSSLClientSide, kSSLStreamType);
-
- // Configure the context.
- OSStatus status;
- status = SSLSetPeerDomainName(ssl_context, hostname, strlen(hostname));
- CheckStatus(status, "TlsException", "Failed to set peer domain name");
-
- status = SSLSetIOFuncs(ssl_context, SSLFilter::SSLReadCallback,
- SSLFilter::SSLWriteCallback);
- CheckStatus(status, "TlsException", "Failed to set IO Callbacks");
-
- status =
- SSLSetConnection(ssl_context, reinterpret_cast<SSLConnectionRef>(this));
- CheckStatus(status, "TlsException", "Failed to set connection object");
-
- // Always evaluate the certs manually so that we can cache the peer
- // certificates in the context for calls to peerCertificate.
- status = SSLSetSessionOption(ssl_context, kSSLSessionOptionBreakOnServerAuth,
- true);
- CheckStatus(status, "TlsException", "Failed to set BreakOnServerAuth option");
-
- status = SSLSetProtocolVersionMin(ssl_context, kTLSProtocol1);
- CheckStatus(status, "TlsException",
- "Failed to set minimum protocol version to kTLSProtocol1");
-
- // If the context has a private key and certificate chain, combine the
- // private key and first certificate into a SecIdentityRef, and place that
- // and the remaining certs in an array to pass to SSLSetCertificate().
- if ((context->private_key() != NULL) && (context->cert_chain() != NULL)) {
- CFIndex chain_length = CFArrayGetCount(context->cert_chain());
- CFMutableArrayRef certs =
- CFArrayCreateMutable(NULL, chain_length, &kCFTypeArrayCallBacks);
- CFTypeRef item = CFArrayGetValueAtIndex(context->cert_chain(), 0);
- ASSERT(CFGetTypeID(item) == SecCertificateGetTypeID());
- SecCertificateRef first_cert =
- reinterpret_cast<SecCertificateRef>(const_cast<void*>(item));
- SecIdentityRef identity =
- SecIdentityCreate(NULL, first_cert, context->private_key());
- CFArrayAppendValue(certs, identity);
- for (CFIndex i = 0; i < chain_length; i++) {
- CFArrayAppendValue(certs,
- CFArrayGetValueAtIndex(context->cert_chain(), i));
- }
- CFRelease(identity);
- status = SSLSetCertificate(ssl_context, certs);
- CFRelease(certs);
- CheckStatus(status, "TlsException", "SSLSetCertificate failed");
- }
-
- if (context->cert_authorities() != NULL) {
- status = SSLSetCertificateAuthorities(ssl_context,
- context->cert_authorities(), true);
- CheckStatus(status, "TlsException",
- "Failed to set certificate authorities");
- }
-
- if (is_server) {
- SSLAuthenticate auth =
- require_client_certificate
- ? kAlwaysAuthenticate
- : (request_client_certificate ? kTryAuthenticate
- : kNeverAuthenticate);
- status = SSLSetClientSideAuthenticate(ssl_context, auth);
- CheckStatus(status, "TlsException",
- "Failed to set client authentication mode");
-
- // If we're at least trying client authentication, then break handshake
- // for client authentication.
- if (auth != kNeverAuthenticate) {
- status = SSLSetSessionOption(ssl_context,
- kSSLSessionOptionBreakOnClientAuth, true);
- CheckStatus(status, "TlsException",
- "Failed to set client authentication mode");
- }
- }
-
- // Add the contexts to our wrapper.
- cert_context_.set(context);
- ssl_context_ = ssl_context;
- is_server_ = is_server;
-
- // Kick-off the handshake. Expect the handshake to need more data.
- // SSLHandshake calls our SSLReadCallback and SSLWriteCallback.
- status = SSLHandshake(ssl_context);
- ASSERT(status != noErr);
- if (status == errSSLWouldBlock) {
- status = noErr;
- in_handshake_ = true;
- }
- CheckStatus(status, "HandshakeException", is_server_
- ? "Handshake error in server"
- : "Handshake error in client");
-}
-
-
-OSStatus SSLFilter::EvaluatePeerTrust() {
- OSStatus status = noErr;
-
- if (SSL_LOG_STATUS) {
- Log::Print("Handshake evaluating trust.\n");
- }
- SecTrustRef peer_trust = NULL;
- status = SSLCopyPeerTrust(ssl_context_, &peer_trust);
- if (status != noErr) {
- if (is_server_ && (status == errSSLBadCert)) {
- // A client certificate was requested, but not required, and wasn't sent.
- return noErr;
- }
- if (SSL_LOG_STATUS) {
- Log::Print("Handshake error from SSLCopyPeerTrust(): %ld.\n",
- static_cast<intptr_t>(status));
- }
- return status;
- }
-
- CFArrayRef trusted_certs = NULL;
- if (cert_context_.get()->trusted_certs() != NULL) {
- trusted_certs =
- CFArrayCreateCopy(NULL, cert_context_.get()->trusted_certs());
- } else {
- trusted_certs = CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks);
- }
-
- status = SecTrustSetAnchorCertificates(peer_trust, trusted_certs);
- if (status != noErr) {
- if (SSL_LOG_STATUS) {
- Log::Print("Handshake error from SecTrustSetAnchorCertificates: %ld\n",
- static_cast<intptr_t>(status));
- }
- CFRelease(trusted_certs);
- CFRelease(peer_trust);
- return status;
- }
-
- if (SSL_LOG_STATUS) {
- Log::Print(
- "Handshake %s built in root certs\n",
- cert_context_.get()->trust_builtin() ? "trusting" : "not trusting");
- }
-
- status = SecTrustSetAnchorCertificatesOnly(
- peer_trust, !cert_context_.get()->trust_builtin());
- if (status != noErr) {
- CFRelease(trusted_certs);
- CFRelease(peer_trust);
- return status;
- }
-
- SecTrustResultType trust_result;
- status = SecTrustEvaluate(peer_trust, &trust_result);
- if (status != noErr) {
- CFRelease(trusted_certs);
- CFRelease(peer_trust);
- return status;
- }
-
- // Grab the peer's certificate chain.
- CFIndex peer_chain_length = SecTrustGetCertificateCount(peer_trust);
- CFMutableArrayRef peer_certs =
- CFArrayCreateMutable(NULL, peer_chain_length, &kCFTypeArrayCallBacks);
- for (CFIndex i = 0; i < peer_chain_length; ++i) {
- CFArrayAppendValue(peer_certs,
- SecTrustGetCertificateAtIndex(peer_trust, i));
- }
- peer_certs_ = peer_certs;
-
- CFRelease(trusted_certs);
- CFRelease(peer_trust);
-
- if ((trust_result == kSecTrustResultProceed) ||
- (trust_result == kSecTrustResultUnspecified)) {
- // Trusted.
- return noErr;
- } else {
- if (SSL_LOG_STATUS) {
- Log::Print("Trust eval failed: trust_restul = %d\n", trust_result);
- }
- bad_cert_ = true;
- return errSSLBadCert;
- }
-}
-
-
-OSStatus SSLFilter::Handshake() {
- ASSERT(cert_context_.get() != NULL);
- ASSERT(ssl_context_ != NULL);
- // Try and push handshake along.
- if (SSL_LOG_STATUS) {
- Log::Print("Doing SSLHandshake\n");
- }
- OSStatus status = SSLHandshake(ssl_context_);
- if (SSL_LOG_STATUS) {
- Log::Print("SSLHandshake returned %ld\n", static_cast<intptr_t>(status));
- }
-
- if ((status == errSSLServerAuthCompleted) ||
- (status == errSSLClientAuthCompleted)) {
- status = EvaluatePeerTrust();
- if (status == errSSLBadCert) {
- // Need to invoke the bad certificate callback.
- return noErr;
- } else if (status != noErr) {
- return status;
- }
- // When trust evaluation succeeds, we can call SSLHandshake again
- // immediately.
- status = SSLHandshake(ssl_context_);
- }
-
- if (status == errSSLWouldBlock) {
- in_handshake_ = true;
- return noErr;
- }
-
- // Handshake succeeded.
- if ((in_handshake_) && (status == noErr)) {
- if (SSL_LOG_STATUS) {
- Log::Print("Finished with the Handshake\n");
- }
- connected_ = true;
- }
- return status;
-}
-
-
-// Returns false if Handshake should fail, and true if Handshake should
-// proceed.
-Dart_Handle SSLFilter::InvokeBadCertCallback(SecCertificateRef peer_cert) {
- Dart_Handle callback = bad_certificate_callback_;
- if (Dart_IsNull(callback)) {
- return callback;
- }
- Dart_Handle args[1];
- args[0] = WrappedX509Certificate(peer_cert);
- if (Dart_IsError(args[0])) {
- return args[0];
- }
- Dart_Handle result = Dart_InvokeClosure(callback, 1, args);
- if (!Dart_IsError(result) && !Dart_IsBoolean(result)) {
- result = Dart_NewUnhandledExceptionError(DartUtils::NewDartIOException(
- "HandshakeException",
- "BadCertificateCallback returned a value that was not a boolean",
- Dart_Null()));
- }
- return result;
-}
-
-
-OSStatus SSLFilter::CheckHandshake() {
- if (bad_cert_ && in_handshake_) {
- if (SSL_LOG_STATUS) {
- Log::Print("Invoking bad certificate callback\n");
- }
- ASSERT(peer_certs_ != NULL);
- CFIndex peer_certs_len = CFArrayGetCount(peer_certs_);
- ASSERT(peer_certs_len > 0);
- CFTypeRef item = CFArrayGetValueAtIndex(peer_certs_, peer_certs_len - 1);
- ASSERT(item != NULL);
- ASSERT(CFGetTypeID(item) == SecCertificateGetTypeID());
- SecCertificateRef peer_cert =
- reinterpret_cast<SecCertificateRef>(const_cast<void*>(item));
- Dart_Handle result = InvokeBadCertCallback(peer_cert);
- ThrowIfError(result);
- if (Dart_IsNull(result)) {
- return errSSLBadCert;
- } else {
- bool good_cert = DartUtils::GetBooleanValue(result);
- bad_cert_ = !good_cert;
- return good_cert ? noErr : errSSLBadCert;
- }
- }
-
- if (connected_ && in_handshake_) {
- if (SSL_LOG_STATUS) {
- Log::Print("Invoking handshake complete callback\n");
- }
- ThrowIfError(Dart_InvokeClosure(
- Dart_HandleFromPersistent(handshake_complete_), 0, NULL));
- in_handshake_ = false;
- }
- return noErr;
-}
-
-
-void SSLFilter::Renegotiate(bool use_session_cache,
- bool request_client_certificate,
- bool require_client_certificate) {
- // The SSL_REQUIRE_CERTIFICATE option only takes effect if the
- // SSL_REQUEST_CERTIFICATE option is also set, so set it.
- request_client_certificate =
- request_client_certificate || require_client_certificate;
- // TODO(24070, 24069): Implement setting the client certificate parameters,
- // and triggering rehandshake.
-}
-
-
-SSLFilter::~SSLFilter() {
- if (ssl_context_ != NULL) {
- CFRelease(ssl_context_);
- ssl_context_ = NULL;
- }
- if (peer_certs_ != NULL) {
- CFRelease(peer_certs_);
- peer_certs_ = NULL;
- }
- if (hostname_ != NULL) {
- free(hostname_);
- hostname_ = NULL;
- }
- for (int i = 0; i < kNumBuffers; ++i) {
- if (buffers_[i] != NULL) {
- delete[] buffers_[i];
- buffers_[i] = NULL;
- }
- }
-}
-
-
-void SSLFilter::Destroy() {
- if (ssl_context_ != NULL) {
- SSLClose(ssl_context_);
- }
- for (int i = 0; i < kNumBuffers; ++i) {
- if (dart_buffer_objects_[i] != NULL) {
- Dart_DeletePersistentHandle(dart_buffer_objects_[i]);
- dart_buffer_objects_[i] = NULL;
- }
- }
- if (string_start_ != NULL) {
- Dart_DeletePersistentHandle(string_start_);
- string_start_ = NULL;
- }
- if (string_length_ != NULL) {
- Dart_DeletePersistentHandle(string_length_);
- string_length_ = NULL;
- }
- if (handshake_complete_ != NULL) {
- Dart_DeletePersistentHandle(handshake_complete_);
- handshake_complete_ = NULL;
- }
- if (bad_certificate_callback_ != NULL) {
- Dart_DeletePersistentHandle(bad_certificate_callback_);
- bad_certificate_callback_ = NULL;
- }
-}
-
-
-OSStatus SSLFilter::SSLReadCallback(SSLConnectionRef connection,
- void* data,
- size_t* data_requested) {
- // Copy at most `data_requested` bytes from `buffers_[kReadEncrypted]` into
- // `data`
- ASSERT(connection != NULL);
- ASSERT(data != NULL);
- ASSERT(data_requested != NULL);
-
- SSLFilter* filter =
- const_cast<SSLFilter*>(reinterpret_cast<const SSLFilter*>(connection));
- uint8_t* datap = reinterpret_cast<uint8_t*>(data);
- uint8_t* buffer = filter->buffers_[kReadEncrypted];
- intptr_t start = filter->GetBufferStart(kReadEncrypted);
- intptr_t end = filter->GetBufferEnd(kReadEncrypted);
- intptr_t size = filter->encrypted_buffer_size_;
- intptr_t requested = static_cast<intptr_t>(*data_requested);
- intptr_t data_read = 0;
-
- if (end < start) {
- // Data may be split into two segments. In this case,
- // the first is [start, size).
- intptr_t buffer_end = (start == 0) ? size - 1 : size;
- intptr_t available = buffer_end - start;
- intptr_t bytes = requested < available ? requested : available;
- memmove(datap, &buffer[start], bytes);
- start += bytes;
- datap += bytes;
- data_read += bytes;
- requested -= bytes;
- ASSERT(start <= size);
- if (start == size) {
- start = 0;
- }
- }
- if ((requested > 0) && (start < end)) {
- intptr_t available = end - start;
- intptr_t bytes = requested < available ? requested : available;
- memmove(datap, &buffer[start], bytes);
- start += bytes;
- datap += bytes;
- data_read += bytes;
- requested -= bytes;
- ASSERT(start <= end);
- }
-
- if (SSL_LOG_DATA) {
- Log::Print("SSLReadCallback: requested: %ld, read %ld bytes\n",
- *data_requested, data_read);
- }
-
- filter->SetBufferStart(kReadEncrypted, start);
- bool short_read = data_read < static_cast<intptr_t>(*data_requested);
- *data_requested = data_read;
- return short_read ? errSSLWouldBlock : noErr;
-}
-
-
-// Read decrypted data from the filter to the circular buffer.
-OSStatus SSLFilter::ProcessReadPlaintextBuffer(intptr_t start,
- intptr_t end,
- intptr_t* bytes_processed) {
- ASSERT(bytes_processed != NULL);
- intptr_t length = end - start;
- OSStatus status = noErr;
- size_t bytes = 0;
- if (length > 0) {
- status =
- SSLRead(ssl_context_,
- reinterpret_cast<void*>((buffers_[kReadPlaintext] + start)),
- length, &bytes);
- if (SSL_LOG_STATUS) {
- Log::Print("SSLRead: status = %ld\n", static_cast<intptr_t>(status));
- }
- if ((status != noErr) && (status != errSSLWouldBlock)) {
- *bytes_processed = 0;
- return status;
- }
- }
- if (SSL_LOG_DATA) {
- Log::Print("ProcessReadPlaintextBuffer: requested: %ld, read %ld bytes\n",
- length, bytes);
- }
- *bytes_processed = static_cast<intptr_t>(bytes);
- return status;
-}
-
-
-OSStatus SSLFilter::SSLWriteCallback(SSLConnectionRef connection,
- const void* data,
- size_t* data_provided) {
- // Copy at most `data_provided` bytes from data into
- // `buffers_[kWriteEncrypted]`.
- ASSERT(connection != NULL);
- ASSERT(data != NULL);
- ASSERT(data_provided != NULL);
-
- SSLFilter* filter =
- const_cast<SSLFilter*>(reinterpret_cast<const SSLFilter*>(connection));
- const uint8_t* datap = reinterpret_cast<const uint8_t*>(data);
- uint8_t* buffer = filter->buffers_[kWriteEncrypted];
- intptr_t start = filter->GetBufferStart(kWriteEncrypted);
- intptr_t end = filter->GetBufferEnd(kWriteEncrypted);
- intptr_t size = filter->encrypted_buffer_size_;
- intptr_t provided = static_cast<intptr_t>(*data_provided);
- intptr_t data_written = 0;
-
- // is full, neither if statement is executed and nothing happens.
- if (start <= end) {
- // If the free space may be split into two segments,
- // then the first is [end, size), unless start == 0.
- // Then, since the last free byte is at position start - 2,
- // the interval is [end, size - 1).
- intptr_t buffer_end = (start == 0) ? size - 1 : size;
- intptr_t available = buffer_end - end;
- intptr_t bytes = provided < available ? provided : available;
- memmove(&buffer[end], datap, bytes);
- end += bytes;
- datap += bytes;
- data_written += bytes;
- provided -= bytes;
- ASSERT(end <= size);
- if (end == size) {
- end = 0;
- }
- }
- if ((provided > 0) && (start > end + 1)) {
- intptr_t available = (start - 1) - end;
- intptr_t bytes = provided < available ? provided : available;
- memmove(&buffer[end], datap, bytes);
- end += bytes;
- datap += bytes;
- data_written += bytes;
- provided -= bytes;
- ASSERT(end < start);
- }
-
- if (SSL_LOG_DATA) {
- Log::Print("SSLWriteCallback: provided: %ld, written %ld bytes\n",
- *data_provided, data_written);
- }
-
- filter->SetBufferEnd(kWriteEncrypted, end);
- *data_provided = data_written;
- return (data_written == 0) ? errSSLWouldBlock : noErr;
-}
-
-
-OSStatus SSLFilter::ProcessWritePlaintextBuffer(intptr_t start,
- intptr_t end,
- intptr_t* bytes_processed) {
- ASSERT(bytes_processed != NULL);
- intptr_t length = end - start;
- OSStatus status = noErr;
- size_t bytes = 0;
- if (length > 0) {
- status =
- SSLWrite(ssl_context_,
- reinterpret_cast<void*>(buffers_[kWritePlaintext] + start),
- length, &bytes);
- if (SSL_LOG_STATUS) {
- Log::Print("SSLWrite: status = %ld\n", static_cast<intptr_t>(status));
- }
- if ((status != noErr) && (status != errSSLWouldBlock)) {
- *bytes_processed = 0;
- return status;
- }
- }
- if (SSL_LOG_DATA) {
- Log::Print("ProcessWritePlaintextBuffer: requested: %ld, written: %ld\n",
- length, bytes);
- }
- *bytes_processed = static_cast<intptr_t>(bytes);
- return status;
-}
-
} // namespace bin
} // namespace dart

Powered by Google App Engine
This is Rietveld 408576698