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

Unified Diff: runtime/bin/secure_socket.cc

Issue 1319703002: Breaking Change: merge BoringSSL branch into master (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 5 years, 4 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
« no previous file with comments | « runtime/bin/secure_socket.h ('k') | runtime/bin/secure_socket_patch.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/bin/secure_socket.cc
diff --git a/runtime/bin/secure_socket.cc b/runtime/bin/secure_socket.cc
index 63f600ff7915027afb7974ae80279568d4db5b03..8f27ef93a69ae79a2585c05168ccc78abebd221d 100644
--- a/runtime/bin/secure_socket.cc
+++ b/runtime/bin/secure_socket.cc
@@ -10,21 +10,17 @@
#include <stdio.h>
#include <string.h>
-#include <key.h>
-#include <keyt.h>
-#include <nss.h>
-#include <pk11pub.h>
-#include <prerror.h>
-#include <prinit.h>
-#include <prnetdb.h>
-#include <secmod.h>
-#include <ssl.h>
-#include <sslproto.h>
+#include <openssl/bio.h>
+#include <openssl/err.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"
-#include "bin/net/nss_memio.h"
+#include "bin/log.h"
#include "bin/socket.h"
#include "bin/thread.h"
#include "bin/utils.h"
@@ -32,27 +28,33 @@
#include "include/dart_api.h"
-
namespace dart {
namespace bin {
bool SSLFilter::library_initialized_ = false;
// To protect library initialization.
Mutex* SSLFilter::mutex_ = new Mutex();
-// The password is needed when creating secure server sockets. It can
-// be null if only secure client sockets are used.
-const char* SSLFilter::password_ = NULL;
+int SSLFilter::filter_ssl_index;
static const int kSSLFilterNativeFieldIndex = 0;
+static const int kSecurityContextNativeFieldIndex = 0;
+static const int kX509NativeFieldIndex = 0;
+
+static const bool SSL_LOG_STATUS = false;
+static const bool SSL_LOG_DATA = false;
+static const int SSL_ERROR_MESSAGE_BUFFER_SIZE = 200;
-/* Handle an error reported from the NSS library. */
-static void ThrowPRException(const char* exception_type,
+/* Handle an error reported from the BoringSSL library. */
+static void ThrowIOException(const char* exception_type,
const char* message,
bool free_message = false) {
- PRErrorCode error_code = PR_GetError();
- const char* error_message = PR_ErrorToString(error_code, PR_LANGUAGE_EN);
- OSError os_error_struct(error_code, error_message, OSError::kNSS);
+ // TODO(24068): Get the error code and message from the error stack.
+ // There may be more than one error on the stack - should we
+ // concatenate the error messages?
+ int error_code = 0;
+ const char* error_message = "Unknown error from BoringSSL library";
+ OSError os_error_struct(error_code, error_message, OSError::kBoringSSL);
Dart_Handle os_error = DartUtils::NewDartOSError(&os_error_struct);
Dart_Handle exception =
DartUtils::NewDartIOException(exception_type, message, os_error);
@@ -64,20 +66,6 @@ static void ThrowPRException(const char* exception_type,
}
-static void ThrowCertificateException(const char* format,
- const char* certificate_name) {
- int length = strlen(certificate_name);
- length += strlen(format);
- char* message = reinterpret_cast<char*>(malloc(length + 1));
- if (message == NULL) {
- FATAL("Out of memory formatting CertificateException for throwing");
- }
- snprintf(message, length + 1, format, certificate_name);
- message[length] = '\0';
- ThrowPRException("CertificateException", message, true);
-}
-
-
static SSLFilter* GetFilter(Dart_NativeArguments args) {
SSLFilter* filter;
Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0));
@@ -100,6 +88,48 @@ static void SetFilter(Dart_NativeArguments args, SSLFilter* filter) {
}
+static SSL_CTX* GetSecurityContext(Dart_NativeArguments args) {
+ SSL_CTX* 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 SetSecurityContext(Dart_NativeArguments args,
+ SSL_CTX* context) {
+ Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0));
+ ASSERT(Dart_IsInstance(dart_this));
+ ThrowIfError(Dart_SetNativeInstanceField(
+ dart_this,
+ kSecurityContextNativeFieldIndex,
+ reinterpret_cast<intptr_t>(context)));
+}
+
+
+static X509* GetX509Certificate(Dart_NativeArguments args) {
+ X509* certificate;
+ Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0));
+ ASSERT(Dart_IsInstance(dart_this));
+ ThrowIfError(Dart_GetNativeInstanceField(
+ dart_this,
+ kX509NativeFieldIndex,
+ reinterpret_cast<intptr_t*>(&certificate)));
+ return certificate;
+}
+
+
+// Forward declaration.
+static void SetAlpnProtocolList(Dart_Handle protocols_handle,
+ SSL* ssl,
+ SSL_CTX* context,
+ bool is_server);
+
+
void FUNCTION_NAME(SecureSocket_Init)(Dart_NativeArguments args) {
Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0));
SSLFilter* filter = new SSLFilter;
@@ -110,50 +140,36 @@ void FUNCTION_NAME(SecureSocket_Init)(Dart_NativeArguments args) {
void FUNCTION_NAME(SecureSocket_Connect)(Dart_NativeArguments args) {
Dart_Handle host_name_object = ThrowIfError(Dart_GetNativeArgument(args, 1));
- Dart_Handle host_sockaddr_storage_object =
- ThrowIfError(Dart_GetNativeArgument(args, 2));
- Dart_Handle port_object = ThrowIfError(Dart_GetNativeArgument(args, 3));
- bool is_server = DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 4));
- Dart_Handle certificate_name_object =
- ThrowIfError(Dart_GetNativeArgument(args, 5));
+ 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, 6));
+ DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 4));
bool require_client_certificate =
- DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 7));
+ DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 5));
bool send_client_certificate =
- DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 8));
+ DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 6));
Dart_Handle protocols_handle =
- ThrowIfError(Dart_GetNativeArgument(args, 9));
+ ThrowIfError(Dart_GetNativeArgument(args, 7));
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));
- RawAddr raw_addr;
- SocketAddress::GetSockAddr(host_sockaddr_storage_object, &raw_addr);
-
- int64_t port;
- if (!DartUtils::GetInt64Value(port_object, &port)) {
- FATAL("The range of port_object was checked in Dart - it cannot fail here");
- }
-
- const char* certificate_name = NULL;
- if (Dart_IsString(certificate_name_object)) {
- ThrowIfError(Dart_StringToCString(certificate_name_object,
- &certificate_name));
+ SSL_CTX* context = NULL;
+ if (!Dart_IsNull(context_object)) {
+ ThrowIfError(Dart_GetNativeInstanceField(
+ context_object,
+ kSecurityContextNativeFieldIndex,
+ reinterpret_cast<intptr_t*>(&context)));
}
- // If this is a server connection, it must have a certificate to connect with.
- ASSERT(!is_server || certificate_name != NULL);
// The protocols_handle is guaranteed to be a valid Uint8List.
// It will have the correct length encoding of the protocols array.
ASSERT(!Dart_IsNull(protocols_handle));
GetFilter(args)->Connect(host_name,
- raw_addr,
- static_cast<int>(port),
+ context,
is_server,
- certificate_name,
request_client_certificate,
require_client_certificate,
send_client_certificate,
@@ -217,59 +233,300 @@ void FUNCTION_NAME(SecureSocket_RegisterBadCertificateCallback)(
}
-void FUNCTION_NAME(SecureSocket_InitializeLibrary)
+void FUNCTION_NAME(SecureSocket_PeerCertificate)
(Dart_NativeArguments args) {
- Dart_Handle certificate_database_object =
- ThrowIfError(Dart_GetNativeArgument(args, 0));
- // Check that the type is string, and get the UTF-8 C string value from it.
- const char* certificate_database = NULL;
- if (Dart_IsString(certificate_database_object)) {
- ThrowIfError(Dart_StringToCString(certificate_database_object,
- &certificate_database));
- } else if (!Dart_IsNull(certificate_database_object)) {
- Dart_ThrowException(DartUtils::NewDartArgumentError(
- "Non-String certificate directory argument to SetCertificateDatabase"));
+ Dart_SetReturnValue(args, GetFilter(args)->PeerCertificate());
+}
+
+
+void FUNCTION_NAME(SecureSocket_FilterPointer)(Dart_NativeArguments args) {
+ intptr_t filter_pointer = reinterpret_cast<intptr_t>(GetFilter(args));
+ Dart_SetReturnValue(args, Dart_NewInteger(filter_pointer));
+}
+
+
+static Dart_Handle WrappedX509Certificate(X509* certificate) {
+ if (certificate == NULL) return Dart_Null();
+ Dart_Handle x509_type =
+ DartUtils::GetDartType(DartUtils::kIOLibURL, "X509Certificate");
+ if (Dart_IsError(x509_type)) {
+ return x509_type;
+ }
+ Dart_Handle arguments[] = { NULL };
+ Dart_Handle result =
+ Dart_New(x509_type, DartUtils::NewString("_"), 0, arguments);
+ if (Dart_IsError(result)) {
+ return result;
+ }
+ ASSERT(Dart_IsInstance(result));
+ Dart_Handle status = Dart_SetNativeInstanceField(
+ result,
+ kX509NativeFieldIndex,
+ reinterpret_cast<intptr_t>(certificate));
+ if (Dart_IsError(status)) {
+ return status;
+ }
+ return result;
+}
+
+
+int CertificateCallback(int preverify_ok, X509_STORE_CTX* store_ctx) {
+ if (preverify_ok == 1) return 1;
+ Dart_Isolate isolate = Dart_CurrentIsolate();
+ if (isolate == NULL) {
+ FATAL("CertificateCallback called with no current isolate\n");
+ }
+ X509* certificate = X509_STORE_CTX_get_current_cert(store_ctx);
+ 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));
+ Dart_Handle callback = filter->bad_certificate_callback();
+ if (Dart_IsNull(callback)) return 0;
+ Dart_Handle args[1];
+ args[0] = WrappedX509Certificate(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 FUNCTION_NAME(SecurityContext_Allocate)(Dart_NativeArguments args) {
+ SSLFilter::InitializeLibrary();
+ SSL_CTX* context = SSL_CTX_new(TLS_method());
+ SSL_CTX_set_verify(context, SSL_VERIFY_PEER, CertificateCallback);
+ SSL_CTX_set_min_version(context, TLS1_VERSION);
+ SSL_CTX_set_cipher_list(context, "HIGH:MEDIUM");
+ SSL_CTX_set_cipher_list_tls11(context, "HIGH:MEDIUM");
+ SetSecurityContext(args, context);
+ // TODO(whesse): Use WeakPersistentHandle to free the SSL_CTX
+ // when the object is GC'd. Also free the alpn_select_cb data pointer,
+ // if non-null (allocated in SetAlpnProtocolList).
+}
+
+
+int PasswordCallback(char* buf, int size, int rwflag, void* userdata) {
+ char* password = static_cast<char*>(userdata);
+ if (static_cast<size_t>(size) < strlen(password) + 1) {
+ Log::PrintErr("Password buffer too small.\n");
+ exit(1);
+ // TODO(24182): Find the actual value of size passed in here, and
+ // check for password length longer than this in the Dart function
+ // that passes in the password, so we never have this problem.
+ }
+ strncpy(buf, static_cast<char*>(userdata), size);
+ return strlen(static_cast<char*>(userdata));
+}
+
+
+void CheckStatus(int status, const char* message, int line) {
+ // TODO(24183): Take appropriate action on failed calls,
+ // throw exception that includes all messages from the error stack.
+ if (status != 1 && SSL_LOG_STATUS) {
+ int error = ERR_get_error();
+ Log::PrintErr("Failed: %s line %d\n", message, line);
+ char error_string[SSL_ERROR_MESSAGE_BUFFER_SIZE];
+ ERR_error_string_n(error, error_string, SSL_ERROR_MESSAGE_BUFFER_SIZE);
+ Log::PrintErr("ERROR: %d %s\n", error, error_string);
}
- // Leave certificate_database as NULL if no value was provided.
+}
+
- Dart_Handle password_object = ThrowIfError(Dart_GetNativeArgument(args, 1));
- // Check that the type is string or null,
- // and get the UTF-8 C string value from it.
+void FUNCTION_NAME(SecurityContext_UsePrivateKey)(Dart_NativeArguments args) {
+ SSL_CTX* context = GetSecurityContext(args);
+ Dart_Handle filename_object = ThrowIfError(Dart_GetNativeArgument(args, 1));
+ const char* filename = NULL;
+ if (Dart_IsString(filename_object)) {
+ ThrowIfError(Dart_StringToCString(filename_object, &filename));
+ } else {
+ Dart_ThrowException(DartUtils::NewDartArgumentError(
+ "File argument to SecurityContext.usePrivateKey is not a String"));
+ }
+ Dart_Handle password_object = ThrowIfError(Dart_GetNativeArgument(args, 2));
const char* password = NULL;
if (Dart_IsString(password_object)) {
ThrowIfError(Dart_StringToCString(password_object, &password));
} else if (Dart_IsNull(password_object)) {
- // Pass the empty string as the password.
password = "";
} else {
Dart_ThrowException(DartUtils::NewDartArgumentError(
- "Password argument to SetCertificateDatabase is not a String or null"));
+ "Password argument to SecurityContext.usePrivateKey is not "
+ "a String or null"));
+ }
+
+ SSL_CTX_set_default_passwd_cb(context, PasswordCallback);
+ SSL_CTX_set_default_passwd_cb_userdata(context, const_cast<char*>(password));
+ int status = SSL_CTX_use_PrivateKey_file(context,
+ filename,
+ SSL_FILETYPE_PEM);
+ // TODO(24184): Handle different expected errors here - file missing,
+ // incorrect password, file not a PEM, and throw exceptions.
+ // CheckStatus should also throw an exception in uncaught cases.
+ CheckStatus(status, "SSL_CTX_use_PrivateKey_file", __LINE__);
+ SSL_CTX_set_default_passwd_cb_userdata(context, NULL);
+}
+
+
+void FUNCTION_NAME(SecurityContext_SetTrustedCertificates)(
+ Dart_NativeArguments args) {
+ SSL_CTX* context = GetSecurityContext(args);
+ Dart_Handle filename_object = ThrowIfError(Dart_GetNativeArgument(args, 1));
+ const char* filename = NULL;
+ if (Dart_IsString(filename_object)) {
+ ThrowIfError(Dart_StringToCString(filename_object, &filename));
+ }
+ Dart_Handle directory_object = ThrowIfError(Dart_GetNativeArgument(args, 2));
+ const char* directory = NULL;
+ if (Dart_IsString(directory_object)) {
+ ThrowIfError(Dart_StringToCString(directory_object, &directory));
+ } else if (Dart_IsNull(directory_object)) {
+ directory = NULL;
+ } else {
+ Dart_ThrowException(DartUtils::NewDartArgumentError(
+ "Directory argument to SecurityContext.usePrivateKey is not "
+ "a String or null"));
+ }
+
+ int status = SSL_CTX_load_verify_locations(context, filename, directory);
+ CheckStatus(status, "SSL_CTX_load_verify_locations", __LINE__);
+}
+
+
+void FUNCTION_NAME(SecurityContext_TrustBuiltinRoots)(
+ Dart_NativeArguments args) {
+ SSL_CTX* context = GetSecurityContext(args);
+ X509_STORE* store = SSL_CTX_get_cert_store(context);
+ BIO* roots_bio =
+ BIO_new_mem_buf(const_cast<unsigned char*>(root_certificates_pem),
+ root_certificates_pem_length);
+ X509* root_cert;
+ // PEM_read_bio_X509 reads PEM-encoded certificates from a bio (in our case,
+ // backed by a memory buffer), and returns X509 objects, one by one.
+ // When the end of the bio is reached, it returns null.
+ while ((root_cert = PEM_read_bio_X509(roots_bio, NULL, NULL, NULL))) {
+ X509_STORE_add_cert(store, root_cert);
+ }
+ BIO_free(roots_bio);
+}
+
+
+void FUNCTION_NAME(SecurityContext_UseCertificateChain)(
+ Dart_NativeArguments args) {
+ SSL_CTX* context = GetSecurityContext(args);
+ Dart_Handle filename_object = ThrowIfError(Dart_GetNativeArgument(args, 1));
+ const char* filename = NULL;
+ if (Dart_IsString(filename_object)) {
+ ThrowIfError(Dart_StringToCString(filename_object, &filename));
+ } else {
+ Dart_ThrowException(DartUtils::NewDartArgumentError(
+ "file argument in SecurityContext.useCertificateChain"
+ " is not a String"));
+ }
+ int status = SSL_CTX_use_certificate_chain_file(context, filename);
+ CheckStatus(status, "SSL_CTX_use_certificate_chain_file", __LINE__);
+}
+
+
+void FUNCTION_NAME(SecurityContext_SetClientAuthorities)(
+ Dart_NativeArguments args) {
+ SSL_CTX* context = GetSecurityContext(args);
+ Dart_Handle filename_object = ThrowIfError(Dart_GetNativeArgument(args, 1));
+ const char* filename = NULL;
+ if (Dart_IsString(filename_object)) {
+ ThrowIfError(Dart_StringToCString(filename_object, &filename));
+ } else {
+ Dart_ThrowException(DartUtils::NewDartArgumentError(
+ "file argument in SecurityContext.setClientAuthorities"
+ " is not a String"));
}
+ STACK_OF(X509_NAME)* certificate_names;
+ certificate_names = SSL_load_client_CA_file(filename);
+ if (certificate_names != NULL) {
+ SSL_CTX_set_client_CA_list(context, certificate_names);
+ } else {
+ Dart_ThrowException(DartUtils::NewDartArgumentError(
+ "Could not load certificate names from file in SetClientAuthorities"));
+ }
+}
- Dart_Handle builtin_roots_object =
+
+void FUNCTION_NAME(SecurityContext_SetAlpnProtocols)(
+ Dart_NativeArguments args) {
+ SSL_CTX* context = GetSecurityContext(args);
+ Dart_Handle protocols_handle =
+ ThrowIfError(Dart_GetNativeArgument(args, 1));
+ Dart_Handle is_server_handle =
ThrowIfError(Dart_GetNativeArgument(args, 2));
- // Check that the type is boolean, and get the boolean value from it.
- bool builtin_roots = true;
- if (Dart_IsBoolean(builtin_roots_object)) {
- ThrowIfError(Dart_BooleanValue(builtin_roots_object, &builtin_roots));
+ if (Dart_IsBoolean(is_server_handle)) {
+ bool is_server = DartUtils::GetBooleanValue(is_server_handle);
+ SetAlpnProtocolList(protocols_handle, NULL, context, is_server);
} else {
Dart_ThrowException(DartUtils::NewDartArgumentError(
- "UseBuiltinRoots argument to SetCertificateDatabase is not a bool"));
+ "Non-boolean is_server argument passed to SetAlpnProtocols"));
}
+}
+
- SSLFilter::InitializeLibrary(certificate_database, password, builtin_roots);
+void FUNCTION_NAME(X509_Subject)(
+ Dart_NativeArguments args) {
+ X509* certificate = GetX509Certificate(args);
+ X509_NAME* subject = X509_get_subject_name(certificate);
+ char* subject_string = X509_NAME_oneline(subject, NULL, 0);
+ Dart_SetReturnValue(args, Dart_NewStringFromCString(subject_string));
+ OPENSSL_free(subject_string);
}
-void FUNCTION_NAME(SecureSocket_PeerCertificate)
- (Dart_NativeArguments args) {
- Dart_SetReturnValue(args, GetFilter(args)->PeerCertificate());
+void FUNCTION_NAME(X509_Issuer)(
+ Dart_NativeArguments args) {
+ X509* certificate = GetX509Certificate(args);
+ X509_NAME* issuer = X509_get_issuer_name(certificate);
+ char* issuer_string = X509_NAME_oneline(issuer, NULL, 0);
+ Dart_SetReturnValue(args, Dart_NewStringFromCString(issuer_string));
+ OPENSSL_free(issuer_string);
}
+static Dart_Handle ASN1TimeToMilliseconds(ASN1_TIME* aTime) {
+ ASN1_UTCTIME* epoch_start = M_ASN1_UTCTIME_new();
+ ASN1_UTCTIME_set_string(epoch_start, "700101000000Z");
+ int days;
+ int seconds;
+ int result = ASN1_TIME_diff(&days, &seconds, epoch_start, aTime);
+ M_ASN1_UTCTIME_free(epoch_start);
+ if (result != 1) {
+ // TODO(whesse): Propagate an error to Dart.
+ Log::PrintErr("ASN1Time error %d\n", result);
+ }
+ return Dart_NewInteger((86400LL * days + seconds) * 1000LL);
+}
-void FUNCTION_NAME(SecureSocket_FilterPointer)(Dart_NativeArguments args) {
- intptr_t filter_pointer = reinterpret_cast<intptr_t>(GetFilter(args));
- Dart_SetReturnValue(args, Dart_NewInteger(filter_pointer));
+void FUNCTION_NAME(X509_StartValidity)(
+ Dart_NativeArguments args) {
+ X509* certificate = GetX509Certificate(args);
+ ASN1_TIME* not_before = X509_get_notBefore(certificate);
+ Dart_SetReturnValue(args, ASN1TimeToMilliseconds(not_before));
+}
+
+
+void FUNCTION_NAME(X509_EndValidity)(
+ Dart_NativeArguments args) {
+ X509* certificate = GetX509Certificate(args);
+ ASN1_TIME* not_after = X509_get_notAfter(certificate);
+ Dart_SetReturnValue(args, ASN1TimeToMilliseconds(not_after));
}
@@ -314,8 +571,9 @@ CObject* SSLFilter::ProcessFilterRequest(const CObjectArray& request) {
}
return result;
} else {
- PRErrorCode error_code = PR_GetError();
- const char* error_message = PR_ErrorToString(error_code, PR_LANGUAGE_EN);
+ // TODO(24185): Extract the BoringSSL OS error here and return it.
+ int error_code = 1;
+ const char* error_message = "Obsolete PR Error message";
CObjectArray* result = new CObjectArray(CObject::NewArray(2));
result->SetAt(0, new CObjectInt32(CObject::NewInt32(error_code)));
result->SetAt(1, new CObjectString(CObject::NewString(error_message)));
@@ -365,33 +623,24 @@ bool SSLFilter::ProcessAllBuffers(int starts[kNumBuffers],
ends[i] = end;
break;
case kReadEncrypted:
- // Read data from circular buffer.
+ 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).
- int bytes = ProcessReadEncryptedBuffer(start, size);
+ int bytes = (i == kReadEncrypted) ?
+ ProcessReadEncryptedBuffer(start, size) :
+ ProcessWritePlaintextBuffer(start, size);
if (bytes < 0) return false;
start += bytes;
ASSERT(start <= size);
if (start == size) start = 0;
}
if (start < end) {
- int bytes = ProcessReadEncryptedBuffer(start, end);
- if (bytes < 0) return false;
- start += bytes;
- ASSERT(start <= end);
- }
- starts[i] = start;
- break;
- case kWritePlaintext:
- if (end < start) {
- // Data is split into two segments, [start, size) and [0, end).
- int bytes = ProcessWritePlaintextBuffer(start, size, 0, end);
- if (bytes < 0) return false;
- start += bytes;
- if (start >= size) start -= size;
- } else {
- int bytes = ProcessWritePlaintextBuffer(start, end, 0, 0);
+ int bytes = (i == kReadEncrypted) ?
+ ProcessReadEncryptedBuffer(start, end) :
+ ProcessWritePlaintextBuffer(start, end);
if (bytes < 0) return false;
start += bytes;
ASSERT(start <= end);
@@ -406,47 +655,9 @@ bool SSLFilter::ProcessAllBuffers(int starts[kNumBuffers],
}
-static Dart_Handle X509FromCertificate(CERTCertificate* certificate) {
- PRTime start_validity;
- PRTime end_validity;
- SECStatus status =
- CERT_GetCertTimes(certificate, &start_validity, &end_validity);
- if (status != SECSuccess) {
- ThrowPRException("CertificateException",
- "Cannot get validity times from certificate");
- }
- int64_t start_epoch_ms = start_validity / PR_USEC_PER_MSEC;
- int64_t end_epoch_ms = end_validity / PR_USEC_PER_MSEC;
- Dart_Handle subject_name_object =
- DartUtils::NewString(certificate->subjectName);
- Dart_Handle issuer_name_object =
- DartUtils::NewString(certificate->issuerName);
- Dart_Handle start_epoch_ms_int = Dart_NewInteger(start_epoch_ms);
- Dart_Handle end_epoch_ms_int = Dart_NewInteger(end_epoch_ms);
-
- Dart_Handle date_type =
- DartUtils::GetDartType(DartUtils::kCoreLibURL, "DateTime");
- Dart_Handle from_milliseconds =
- DartUtils::NewString("fromMillisecondsSinceEpoch");
-
- Dart_Handle start_validity_date =
- Dart_New(date_type, from_milliseconds, 1, &start_epoch_ms_int);
- Dart_Handle end_validity_date =
- Dart_New(date_type, from_milliseconds, 1, &end_epoch_ms_int);
-
- Dart_Handle x509_type =
- DartUtils::GetDartType(DartUtils::kIOLibURL, "X509Certificate");
- Dart_Handle arguments[] = { subject_name_object,
- issuer_name_object,
- start_validity_date,
- end_validity_date };
- return Dart_New(x509_type, Dart_Null(), 4, arguments);
-}
-
-
void SSLFilter::Init(Dart_Handle dart_this) {
if (!library_initialized_) {
- InitializeLibrary(NULL, "", true, false);
+ InitializeLibrary();
}
ASSERT(string_start_ == NULL);
string_start_ = Dart_NewPersistentHandle(DartUtils::NewString("start"));
@@ -459,7 +670,6 @@ void SSLFilter::Init(Dart_Handle dart_this) {
ASSERT(bad_certificate_callback_ != NULL);
InitializeBuffers(dart_this);
- filter_ = memio_CreateIOLayer(kMemioBufferSize, kMemioBufferSize);
}
@@ -507,6 +717,7 @@ void SSLFilter::InitializeBuffers(Dart_Handle dart_this) {
void SSLFilter::RegisterHandshakeCompleteCallback(Dart_Handle complete) {
ASSERT(NULL == handshake_complete_);
handshake_complete_ = Dart_NewPersistentHandle(complete);
+
ASSERT(handshake_complete_ != NULL);
}
@@ -519,157 +730,123 @@ void SSLFilter::RegisterBadCertificateCallback(Dart_Handle callback) {
}
-char* PasswordCallback(PK11SlotInfo* slot, PRBool retry, void* arg) {
- if (!retry) {
- return PL_strdup(static_cast<char*>(arg)); // Freed by NSS internals.
- }
- return NULL;
-}
-
-
-static const char* builtin_roots_module =
-#if defined(TARGET_OS_LINUX) || defined(TARGET_OS_ANDROID)
- "name=\"Root Certs\" library=\"libnssckbi.so\"";
-#elif defined(TARGET_OS_MACOS)
- "name=\"Root Certs\" library=\"libnssckbi.dylib\"";
-#elif defined(TARGET_OS_WINDOWS)
- "name=\"Root Certs\" library=\"nssckbi.dll\"";
-#else
-#error Automatic target os detection failed.
-#endif
-
-
-
-void SSLFilter::InitializeLibrary(const char* certificate_database,
- const char* password,
- bool use_builtin_root_certificates,
- bool report_duplicate_initialization) {
+void SSLFilter::InitializeLibrary() {
MutexLocker locker(mutex_);
- SECStatus status;
if (!library_initialized_) {
- PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
- // TODO(whesse): Verify there are no UTF-8 issues here.
- if (certificate_database == NULL || certificate_database[0] == '\0') {
- status = NSS_NoDB_Init(NULL);
- if (status != SECSuccess) {
- mutex_->Unlock(); // MutexLocker destructor not called when throwing.
- ThrowPRException("TlsException",
- "Failed NSS_NoDB_Init call.");
- }
- if (use_builtin_root_certificates) {
- SECMODModule* module = SECMOD_LoadUserModule(
- const_cast<char*>(builtin_roots_module), NULL, PR_FALSE);
- if (!module) {
- mutex_->Unlock(); // MutexLocker destructor not called when throwing.
- ThrowPRException("TlsException",
- "Failed to load builtin root certificates.");
- }
- }
- } else {
- PRUint32 init_flags = NSS_INIT_READONLY;
- if (!use_builtin_root_certificates) {
- init_flags |= NSS_INIT_NOMODDB;
- }
- status = NSS_Initialize(certificate_database,
- "",
- "",
- SECMOD_DB,
- init_flags);
- if (status != SECSuccess) {
- mutex_->Unlock(); // MutexLocker destructor not called when throwing.
- ThrowPRException("TlsException",
- "Failed NSS_Init call.");
- }
- password_ = strdup(password); // This one copy persists until Dart exits.
- PK11_SetPasswordFunc(PasswordCallback);
- }
+ SSL_library_init();
+ filter_ssl_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);
+ ASSERT(filter_ssl_index >= 0);
library_initialized_ = true;
+ }
+}
- status = NSS_SetDomesticPolicy();
- if (status != SECSuccess) {
- mutex_->Unlock(); // MutexLocker destructor not called when throwing.
- ThrowPRException("TlsException",
- "Failed NSS_SetDomesticPolicy call.");
- }
- // Enable the same additional ciphers that Chromium does.
- // See NSSSSLInitSingleton() in Chromium's net/socket/nss_ssl_util.cc.
- // Explicitly enable exactly those ciphers with keys of at least 80 bits.
- const PRUint16* const ssl_ciphers = SSL_GetImplementedCiphers();
- const PRUint16 num_ciphers = SSL_GetNumImplementedCiphers();
- for (int i = 0; i < num_ciphers; i++) {
- SSLCipherSuiteInfo info;
- if (SSL_GetCipherSuiteInfo(ssl_ciphers[i], &info, sizeof(info)) ==
- SECSuccess) {
- bool enabled = (info.effectiveKeyBits >= 80);
- // Trim the list of cipher suites in order to keep the size of the
- // ClientHello down. DSS, ECDH, CAMELLIA, SEED, ECC+3DES, and
- // HMAC-SHA256 cipher suites are disabled.
- if (info.symCipher == ssl_calg_camellia ||
- info.symCipher == ssl_calg_seed ||
- (info.symCipher == ssl_calg_3des && info.keaType != ssl_kea_rsa) ||
- info.authAlgorithm == ssl_auth_dsa ||
- info.macAlgorithm == ssl_hmac_sha256 ||
- info.nonStandard ||
- strcmp(info.keaTypeName, "ECDH") == 0) {
- enabled = false;
- }
+Dart_Handle SSLFilter::PeerCertificate() {
+ X509* certificate = SSL_get_peer_certificate(ssl_);
+ Dart_Handle x509_object = WrappedX509Certificate(certificate);
+ if (Dart_IsError(x509_object)) {
+ Dart_PropagateError(x509_object);
+ }
+ return x509_object;
+}
+
- if (ssl_ciphers[i] == TLS_DHE_DSS_WITH_AES_128_CBC_SHA) {
- // Enabled to allow servers with only a DSA certificate to function.
- enabled = true;
+int AlpnCallback(SSL *ssl,
+ const uint8_t **out,
+ uint8_t *outlen,
+ const uint8_t *in,
+ unsigned int inlen,
+ void *arg) {
+ // 'in' and 'arg' are sequences of (length, data) strings with 1-byte lengths.
+ // 'arg' is 0-terminated. Finds the first string in 'arg' that is in 'in'.
+ uint8_t* server_list = static_cast<uint8_t*>(arg);
+ while (*server_list != 0) {
+ uint8_t protocol_length = *server_list++;
+ const uint8_t* client_list = in;
+ while (client_list < in + inlen) {
+ uint8_t client_protocol_length = *client_list++;
+ if (client_protocol_length == protocol_length) {
+ if (0 == memcmp(server_list, client_list, protocol_length)) {
+ *out = client_list;
+ *outlen = client_protocol_length;
+ return SSL_TLSEXT_ERR_OK; // Success
}
- SSL_CipherPrefSetDefault(ssl_ciphers[i], enabled);
}
+ client_list += client_protocol_length;
}
-
- status = SSL_ConfigServerSessionIDCache(0, 0, 0, NULL);
- if (status != SECSuccess) {
- mutex_->Unlock(); // MutexLocker destructor not called when throwing.
- ThrowPRException("TlsException",
- "Failed SSL_ConfigServerSessionIDCache call.");
- }
-
- } else if (report_duplicate_initialization) {
- mutex_->Unlock(); // MutexLocker destructor not called when throwing.
- // Like ThrowPRException, without adding an OSError.
- Dart_ThrowException(DartUtils::NewDartIOException("TlsException",
- "Called SecureSocket.initialize more than once",
- Dart_Null()));
+ server_list += protocol_length;
}
+ // TODO(23580): Make failure send a fatal alert instead of ignoring ALPN.
+ return SSL_TLSEXT_ERR_NOACK;
}
-SECStatus BadCertificateCallback(void* filter, PRFileDesc* fd) {
- SSLFilter* ssl_filter = static_cast<SSLFilter*>(filter);
- Dart_Handle callback = ssl_filter->bad_certificate_callback();
- if (Dart_IsNull(callback)) return SECFailure;
- Dart_Handle x509_object = ssl_filter->PeerCertificate();
- Dart_Handle result = Dart_InvokeClosure(callback, 1, &x509_object);
+// Sets the protocol list for ALPN on a SSL object or a context.
+static void SetAlpnProtocolList(Dart_Handle protocols_handle,
+ SSL* ssl,
+ SSL_CTX* context,
+ bool is_server) {
+ // Enable ALPN (application layer protocol negotiation) if the caller provides
+ // a valid list of supported protocols.
+ Dart_TypedData_Type protocols_type;
+ uint8_t* protocol_string = NULL;
+ uint8_t* protocol_string_copy = NULL;
+ intptr_t protocol_string_len = 0;
+ int status;
+
+ Dart_Handle result = Dart_TypedDataAcquireData(
+ protocols_handle,
+ &protocols_type,
+ reinterpret_cast<void**>(&protocol_string),
+ &protocol_string_len);
if (Dart_IsError(result)) {
- ssl_filter->callback_error = result;
- return SECFailure;
+ Dart_PropagateError(result);
}
- // Our wrapper is guaranteed to return a boolean.
- bool c_result = DartUtils::GetBooleanValue(result);
- return c_result ? SECSuccess : SECFailure;
-}
+ if (protocols_type != Dart_TypedData_kUint8) {
+ Dart_TypedDataReleaseData(protocols_handle);
+ Dart_PropagateError(Dart_NewApiError(
+ "Unexpected type for protocols (expected valid Uint8List)."));
+ }
-Dart_Handle SSLFilter::PeerCertificate() {
- CERTCertificate* certificate = SSL_PeerCertificate(filter_);
- if (certificate == NULL) return Dart_Null();
- Dart_Handle x509_object = X509FromCertificate(certificate);
- CERT_DestroyCertificate(certificate);
- return x509_object;
+ if (protocol_string_len > 0) {
+ if (is_server) {
+ // ALPN on server connections must be set on an SSL_CTX object,
+ // not on the SSL object of the individual connection.
+ ASSERT(context != NULL);
+ ASSERT(ssl == NULL);
+ // Because it must be passed as a single void*, terminate
+ // the list of (length, data) strings with a length 0 string.
+ protocol_string_copy =
+ static_cast<uint8_t*>(malloc(protocol_string_len + 1));
+ memmove(protocol_string_copy, protocol_string, protocol_string_len);
+ protocol_string_copy[protocol_string_len] = '\0';
+ SSL_CTX_set_alpn_select_cb(context, AlpnCallback, protocol_string_copy);
+ // TODO(whesse): If this function is called again, free the previous
+ // protocol_string_copy. It may be better to keep this as a native
+ // field on the Dart object, since fetching it from the structure is
+ // not in the public api. Also free this when the context is destroyed.
+ } else {
+ // The function makes a local copy of protocol_string, which it owns.
+ if (ssl != NULL) {
+ ASSERT(context == NULL);
+ status = SSL_set_alpn_protos(ssl, protocol_string, protocol_string_len);
+ } else {
+ ASSERT(context != NULL);
+ ASSERT(ssl == NULL);
+ status = SSL_CTX_set_alpn_protos(
+ context, protocol_string, protocol_string_len);
+ }
+ ASSERT(status == 0); // The function returns a non-standard status.
+ }
+ }
+ Dart_TypedDataReleaseData(protocols_handle);
}
-void SSLFilter::Connect(const char* host_name,
- const RawAddr& raw_addr,
- int port,
+void SSLFilter::Connect(const char* hostname,
+ SSL_CTX* context,
bool is_server,
- const char* certificate_name,
bool request_client_certificate,
bool require_client_certificate,
bool send_client_certificate,
@@ -679,197 +856,131 @@ void SSLFilter::Connect(const char* host_name,
FATAL("Connect called twice on the same _SecureFilter.");
}
- if (!is_server && certificate_name != NULL) {
- client_certificate_name_ = strdup(certificate_name);
- }
+ int status;
+ int error;
+ BIO* ssl_side;
+ status = BIO_new_bio_pair(&ssl_side, 10000, &socket_side_, 10000);
+ CheckStatus(status, "BIO_new_bio_pair", __LINE__);
- filter_ = SSL_ImportFD(NULL, filter_);
- if (filter_ == NULL) {
- ThrowPRException("TlsException", "Failed SSL_ImportFD call");
+ if (context == NULL) {
+ DART_CHECK_VALID(Dart_ThrowException(DartUtils::NewDartArgumentError(
+ "Default SecurityContext not implemented, context cannot be null.")));
}
-
- SECStatus status;
-
- // Enable ALPN (application layer protocol negogiation) if the caller provides
- // a valid list of supported protocols.
- {
- Dart_TypedData_Type protocols_type;
- uint8_t* protocol_string = NULL;
- intptr_t protocol_string_len = 0;
-
- Dart_Handle result = Dart_TypedDataAcquireData(
- protocols_handle,
- &protocols_type,
- reinterpret_cast<void**>(&protocol_string),
- &protocol_string_len);
- if (Dart_IsError(result)) {
- Dart_PropagateError(result);
- }
-
- if (protocols_type != Dart_TypedData_kUint8) {
- Dart_TypedDataReleaseData(protocols_handle);
- Dart_PropagateError(Dart_NewApiError(
- "Unexpected type for protocols (expected valid Uint8List)."));
- }
-
- if (protocol_string_len > 0) {
- status = SSL_OptionSet(filter_, SSL_ENABLE_ALPN, PR_TRUE);
- ASSERT(status == SECSuccess);
-
- status = SSL_SetNextProtoNego(filter_,
- protocol_string,
- protocol_string_len);
- ASSERT(status == SECSuccess);
- }
-
- Dart_TypedDataReleaseData(protocols_handle);
+ ssl_ = SSL_new(context);
+ SSL_set_bio(ssl_, ssl_side, ssl_side);
+ SSL_set_mode(ssl_, SSL_MODE_AUTO_RETRY); // TODO(whesse): Is this right?
+ SSL_set_ex_data(ssl_, filter_ssl_index, this);
+
+ if (!is_server_) {
+ SetAlpnProtocolList(protocols_handle, ssl_, NULL, false);
+ // Sets the hostname in the certificate-checking object, so it is checked
+ // against the certificate presented by the server.
+ X509_VERIFY_PARAM* certificate_checking_parameters_ = SSL_get0_param(ssl_);
+ hostname_ = strdup(hostname);
+ X509_VERIFY_PARAM_set_hostflags(certificate_checking_parameters_, 0);
+ X509_VERIFY_PARAM_set1_host(certificate_checking_parameters_,
+ hostname_, 0);
+ // TODO(24186) free hostname_ if it is not freed when SSL is destroyed.
+ // otherwise, make it a local variable, not a instance field.
}
-
- SSLVersionRange vrange;
- vrange.min = SSL_LIBRARY_VERSION_3_0;
- vrange.max = SSL_LIBRARY_VERSION_TLS_1_2;
- SSL_VersionRangeSet(filter_, &vrange);
-
- if (is_server) {
- CERTCertificate* certificate = NULL;
- if (strstr(certificate_name, "CN=") != NULL) {
- // Look up certificate using the distinguished name (DN) certificate_name.
- CERTCertDBHandle* certificate_database = CERT_GetDefaultCertDB();
- if (certificate_database == NULL) {
- ThrowPRException("CertificateException",
- "Certificate database cannot be loaded");
- }
- certificate = CERT_FindCertByNameString(certificate_database,
- const_cast<char*>(certificate_name));
- if (certificate == NULL) {
- ThrowCertificateException(
- "Cannot find server certificate by distinguished name: %s",
- certificate_name);
- }
- } else {
- // Look up certificate using the nickname certificate_name.
- certificate = PK11_FindCertFromNickname(
- const_cast<char*>(certificate_name),
- static_cast<void*>(const_cast<char*>(password_)));
- if (certificate == NULL) {
- ThrowCertificateException(
- "Cannot find server certificate by nickname: %s",
- certificate_name);
- }
- }
- SECKEYPrivateKey* key = PK11_FindKeyByAnyCert(
- certificate,
- static_cast<void*>(const_cast<char*>(password_)));
- if (key == NULL) {
- CERT_DestroyCertificate(certificate);
- if (PR_GetError() == -8177) {
- ThrowPRException("CertificateException",
- "Certificate database password incorrect");
- } else {
- ThrowCertificateException(
- "Cannot find private key for certificate %s",
- certificate_name);
- }
+ if (is_server_) {
+ status = SSL_accept(ssl_);
+ if (SSL_LOG_STATUS) Log::Print("SSL_accept status: %d\n", status);
+ if (status != 1) {
+ // TODO(whesse): expect a needs-data error here. Handle other errors.
+ error = SSL_get_error(ssl_, status);
+ if (SSL_LOG_STATUS) Log::Print("SSL_accept error: %d\n", error);
}
-
- // kt_rsa (key type RSA) is an enum constant from the NSS libraries.
- // TODO(whesse): Allow different key types.
- status = SSL_ConfigSecureServer(filter_, certificate, key, kt_rsa);
- CERT_DestroyCertificate(certificate);
- SECKEY_DestroyPrivateKey(key);
- if (status != SECSuccess) {
- ThrowCertificateException(
- "Failed SSL_ConfigSecureServer call with certificate %s",
- certificate_name);
+ } else {
+ status = SSL_connect(ssl_);
+ if (SSL_LOG_STATUS) Log::Print("SSL_connect status: %d\n", status);
+ if (status != 1) {
+ // TODO(whesse): expect a needs-data error here. Handle other errors.
+ error = SSL_get_error(ssl_, status);
+ if (SSL_LOG_STATUS) Log::Print("SSL_connect error: %d\n", error);
}
-
+ }
+ if (is_server_) {
if (request_client_certificate) {
- status = SSL_OptionSet(filter_, SSL_REQUEST_CERTIFICATE, PR_TRUE);
- if (status != SECSuccess) {
- ThrowPRException("TlsException",
- "Failed SSL_OptionSet(REQUEST_CERTIFICATE) call");
- }
- status = SSL_OptionSet(filter_,
- SSL_REQUIRE_CERTIFICATE,
- require_client_certificate);
- if (status != SECSuccess) {
- ThrowPRException("TlsException",
- "Failed SSL_OptionSet(REQUIRE_CERTIFICATE) call");
- }
+ // TODO(24069): Handle client certificates on server side.
+ Dart_ThrowException(DartUtils::NewDartArgumentError(
+ "requestClientCertificate not implemented."));
}
} else { // Client.
- if (SSL_SetURL(filter_, host_name) == -1) {
- ThrowPRException("TlsException", "Failed SetURL call");
- }
if (send_client_certificate) {
- SSL_SetPKCS11PinArg(filter_, const_cast<char*>(password_));
- status = SSL_GetClientAuthDataHook(
- filter_,
- NSS_GetClientAuthData,
- static_cast<void*>(client_certificate_name_));
- if (status != SECSuccess) {
- ThrowPRException("TlsException",
- "Failed SSL_GetClientAuthDataHook call");
- }
+ // TODO(24070): Handle client certificates on client side.
+ Dart_ThrowException(DartUtils::NewDartArgumentError(
+ "sendClientCertificate not implemented."));
}
}
+ Handshake();
+}
- // Install bad certificate callback, and pass 'this' to it if it is called.
- status = SSL_BadCertHook(filter_,
- BadCertificateCallback,
- static_cast<void*>(this));
-
- status = SSL_ResetHandshake(filter_, is_server);
- if (status != SECSuccess) {
- ThrowPRException("TlsException",
- "Failed SSL_ResetHandshake call");
- }
- // Set the peer address from the address passed. The DNS has already
- // been done in Dart code, so just use that address. This relies on
- // following about PRNetAddr: "The raw member of the union is
- // equivalent to struct sockaddr", which is stated in the NSS
- // documentation.
- PRNetAddr peername;
- memset(&peername, 0, sizeof(peername));
- intptr_t len = SocketAddress::GetAddrLength(raw_addr);
- ASSERT(static_cast<size_t>(len) <= sizeof(peername));
- memmove(&peername, &raw_addr.addr, len);
-
- // Adjust the address family field for BSD, whose sockaddr
- // structure has a one-byte length and one-byte address family
- // field at the beginning. PRNetAddr has a two-byte address
- // family field at the beginning.
- peername.raw.family = raw_addr.addr.sa_family;
-
- memio_SetPeerName(filter_, &peername);
+int printErrorCallback(const char *str, size_t len, void *ctx) {
+ Log::PrintErr("%.*s\n", static_cast<int>(len), str);
+ return 1;
}
-
void SSLFilter::Handshake() {
- SECStatus status = SSL_ForceHandshake(filter_);
- if (status == SECSuccess) {
+ // Try and push handshake along.
+ int status;
+ int error;
+ status = SSL_do_handshake(ssl_);
+ if (callback_error != NULL) {
+ // The SSL_do_handshake will try performing a handshake and might call
+ // a CertificateCallback. If the certificate validation
+ // failed the 'callback_error" will be set by the certificateCallback
+ // logic and we propagate the error"
+ Dart_PropagateError(callback_error);
+ }
+ if (SSL_LOG_STATUS) Log::Print("SSL_handshake status: %d\n", status);
+ if (status != 1) {
+ error = SSL_get_error(ssl_, status);
+ if (SSL_LOG_STATUS) Log::Print("ERROR: %d\n", error);
+ ERR_print_errors_cb(printErrorCallback, NULL);
+ }
+ if (status == 1) {
if (in_handshake_) {
+ // TODO(24071): Check return value of SSL_get_verify_result, this
+ // should give us the hostname check.
+ int result = SSL_get_verify_result(ssl_);
+ if (SSL_LOG_STATUS) {
+ Log::Print("Handshake verification status: %d\n", result);
+ X509* peer_certificate = SSL_get_peer_certificate(ssl_);
+ if (peer_certificate == NULL) {
+ Log::Print("No peer certificate received\n");
+ } else {
+ X509_NAME* s_name = X509_get_subject_name(peer_certificate);
+ printf("Peer certificate SN: ");
+ X509_NAME_print_ex_fp(stdout, s_name, 4, 0);
+ printf("\n");
+ }
+ }
ThrowIfError(Dart_InvokeClosure(
Dart_HandleFromPersistent(handshake_complete_), 0, NULL));
in_handshake_ = false;
}
- } else {
- if (callback_error != NULL) {
- Dart_PropagateError(callback_error);
+ } else if (status == 0) {
+ if (is_server_) {
+ ThrowIOException("HandshakeException",
+ "Handshake error in server");
+ } else {
+ ThrowIOException("HandshakeException",
+ "Handshake error in client");
}
- PRErrorCode error = PR_GetError();
- if (error == PR_WOULD_BLOCK_ERROR) {
+ } else if (status < 0) {
+ if (SSL_want_write(ssl_) || SSL_want_read(ssl_)) {
if (!in_handshake_) {
in_handshake_ = true;
}
} else {
if (is_server_) {
- ThrowPRException("HandshakeException",
+ ThrowIOException("HandshakeException",
"Handshake error in server");
} else {
- ThrowPRException("HandshakeException",
+ ThrowIOException("HandshakeException",
"Handshake error in client");
}
}
@@ -877,42 +988,13 @@ void SSLFilter::Handshake() {
}
void SSLFilter::GetSelectedProtocol(Dart_NativeArguments args) {
- // Space for the selected protocol.
- const unsigned int kBufferSize = 256;
- unsigned char buffer[kBufferSize + 1];
-
- unsigned int outLength = 0;
- SSLNextProtoState outState;
-
- SECStatus status = SSL_GetNextProto(
- filter_, &outState, buffer, &outLength, kBufferSize);
- if (status == SECSuccess) {
- if (outState == SSL_NEXT_PROTO_SELECTED ||
- outState == SSL_NEXT_PROTO_NEGOTIATED) {
- ASSERT(outLength <= kBufferSize);
- buffer[outLength] = '\0';
- Dart_Handle protocol_string = DartUtils::NewString(
- reinterpret_cast<const char *>(&buffer[0]));
- if (Dart_IsError(protocol_string)) {
- ThrowPRException("HandshakeException",
- "Protocol selected via ALPN, unable to get protocol "
- "string.");
- } else {
- Dart_SetReturnValue(args, protocol_string);
- }
- } else if (outState == SSL_NEXT_PROTO_NO_OVERLAP) {
- ThrowPRException("HandshakeException",
- "Client and Server could not agree upon a protocol");
- } else if (outState == SSL_NEXT_PROTO_NO_SUPPORT) {
- // A value of `null` denotes that the client did not support protocol
- // negogiation.
- Dart_SetReturnValue(args, Dart_Null());
- } else {
- UNREACHABLE();
- }
+ const uint8_t* protocol;
+ unsigned length;
+ SSL_get0_alpn_selected(ssl_, &protocol, &length);
+ if (length == 0) {
+ Dart_SetReturnValue(args, Dart_Null());
} else {
- ThrowPRException("HandshakeException",
- "Could not retrieve selected protocol via ALPN");
+ Dart_SetReturnValue(args, Dart_NewStringFromUTF8(protocol, length));
}
}
@@ -920,41 +1002,20 @@ void SSLFilter::GetSelectedProtocol(Dart_NativeArguments args) {
void SSLFilter::Renegotiate(bool use_session_cache,
bool request_client_certificate,
bool require_client_certificate) {
- SECStatus status;
// 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;
-
- status = SSL_OptionSet(filter_,
- SSL_REQUEST_CERTIFICATE,
- request_client_certificate);
- if (status != SECSuccess) {
- ThrowPRException("TlsException",
- "Failure in (Raw)SecureSocket.renegotiate request_client_certificate");
- }
- status = SSL_OptionSet(filter_,
- SSL_REQUIRE_CERTIFICATE,
- require_client_certificate);
- if (status != SECSuccess) {
- ThrowPRException("TlsException",
- "Failure in (Raw)SecureSocket.renegotiate require_client_certificate");
- }
- bool flush_cache = !use_session_cache;
- status = SSL_ReHandshake(filter_, flush_cache);
- if (status != SECSuccess) {
- if (is_server_) {
- ThrowPRException("HandshakeException",
- "Failure in (Raw)SecureSocket.renegotiate in server");
- } else {
- ThrowPRException("HandshakeException",
- "Failure in (Raw)SecureSocket.renegotiate in client");
- }
- }
+ // TODO(24070, 24069): Implement setting the client certificate parameters,
+ // and triggering rehandshake.
}
void SSLFilter::Destroy() {
+ if (ssl_ != NULL) {
+ SSL_free(ssl_);
+ ssl_ = NULL;
+ }
for (int i = 0; i < kNumBuffers; ++i) {
Dart_DeletePersistentHandle(dart_buffer_objects_[i]);
delete[] buffers_[i];
@@ -963,25 +1024,21 @@ void SSLFilter::Destroy() {
Dart_DeletePersistentHandle(string_length_);
Dart_DeletePersistentHandle(handshake_complete_);
Dart_DeletePersistentHandle(bad_certificate_callback_);
- free(client_certificate_name_);
-
- PR_Close(filter_);
}
-intptr_t SSLFilter::ProcessReadPlaintextBuffer(int start, int end) {
+/* Read decrypted data from the filter to the circular buffer */
+int SSLFilter::ProcessReadPlaintextBuffer(int start, int end) {
int length = end - start;
int bytes_processed = 0;
if (length > 0) {
- bytes_processed = PR_Read(filter_,
- buffers_[kReadPlaintext] + start,
- length);
+ bytes_processed = SSL_read(
+ ssl_,
+ reinterpret_cast<char*>((buffers_[kReadPlaintext] + start)),
+ length);
if (bytes_processed < 0) {
- ASSERT(bytes_processed == -1);
- PRErrorCode pr_error = PR_GetError();
- if (PR_WOULD_BLOCK_ERROR != pr_error) {
- return -1;
- }
+ int error = SSL_get_error(ssl_, bytes_processed);
+ USE(error);
bytes_processed = 0;
}
}
@@ -989,70 +1046,58 @@ intptr_t SSLFilter::ProcessReadPlaintextBuffer(int start, int end) {
}
-intptr_t SSLFilter::ProcessWritePlaintextBuffer(int start1, int end1,
- int start2, int end2) {
- PRIOVec ranges[2];
- uint8_t* buffer = buffers_[kWritePlaintext];
- ranges[0].iov_base = reinterpret_cast<char*>(buffer + start1);
- ranges[0].iov_len = end1 - start1;
- ranges[1].iov_base = reinterpret_cast<char*>(buffer + start2);
- ranges[1].iov_len = end2 - start2;
- int bytes_processed = PR_Writev(filter_, ranges, 2, PR_INTERVAL_NO_TIMEOUT);
+int SSLFilter::ProcessWritePlaintextBuffer(int start, int end) {
+ int length = end - start;
+ int bytes_processed = SSL_write(
+ ssl_, buffers_[kWritePlaintext] + start, length);
if (bytes_processed < 0) {
- ASSERT(bytes_processed == -1);
- PRErrorCode pr_error = PR_GetError();
- if (PR_WOULD_BLOCK_ERROR != pr_error) {
- return -1;
+ if (SSL_LOG_DATA) {
+ Log::Print("SSL_write returned error %d\n", bytes_processed);
}
- bytes_processed = 0;
+ return 0;
}
return bytes_processed;
}
-intptr_t SSLFilter::ProcessReadEncryptedBuffer(int start, int end) {
+/* Read encrypted data from the circular buffer to the filter */
+int SSLFilter::ProcessReadEncryptedBuffer(int start, int end) {
int length = end - start;
+ if (SSL_LOG_DATA) Log::Print(
+ "Entering ProcessReadEncryptedBuffer with %d bytes\n", length);
int bytes_processed = 0;
if (length > 0) {
- memio_Private* secret = memio_GetSecret(filter_);
- uint8_t* filter_buf;
- int free_bytes = memio_GetReadParams(secret, &filter_buf);
- bytes_processed = dart::Utils::Minimum(length, free_bytes);
- memmove(filter_buf, buffers_[kReadEncrypted] + start, bytes_processed);
- memio_PutReadResult(secret, bytes_processed);
+ bytes_processed =
+ BIO_write(socket_side_, buffers_[kReadEncrypted] + start, length);
+ if (bytes_processed <= 0) {
+ bool retry = BIO_should_retry(socket_side_);
+ if (!retry) {
+ if (SSL_LOG_DATA) Log::Print(
+ "BIO_write failed in ReadEncryptedBuffer\n");
+ }
+ bytes_processed = 0;
+ }
}
+ if (SSL_LOG_DATA) Log::Print(
+ "Leaving ProcessReadEncryptedBuffer wrote %d bytes\n", bytes_processed);
return bytes_processed;
}
-intptr_t SSLFilter::ProcessWriteEncryptedBuffer(int start, int end) {
+int SSLFilter::ProcessWriteEncryptedBuffer(int start, int end) {
int length = end - start;
int bytes_processed = 0;
if (length > 0) {
- uint8_t* buffer = buffers_[kWriteEncrypted];
- const uint8_t* buf1;
- const uint8_t* buf2;
- unsigned int len1;
- unsigned int len2;
- memio_Private* secret = memio_GetSecret(filter_);
- int status = memio_GetWriteParams(secret, &buf1, &len1, &buf2, &len2);
- if (status != 0) {
- return -1;
- }
- int bytes_to_send =
- dart::Utils::Minimum(len1, static_cast<unsigned>(length));
- if (bytes_to_send > 0) {
- memmove(buffer + start, buf1, bytes_to_send);
- bytes_processed = bytes_to_send;
- }
- bytes_to_send = dart::Utils::Minimum(len2,
- static_cast<unsigned>(length - bytes_processed));
- if (bytes_to_send > 0) {
- memmove(buffer + start + bytes_processed, buf2, bytes_to_send);
- bytes_processed += bytes_to_send;
- }
- if (bytes_processed > 0) {
- memio_PutWriteResult(secret, bytes_processed);
+ bytes_processed = BIO_read(socket_side_,
+ buffers_[kWriteEncrypted] + start,
+ length);
+ if (bytes_processed < 0) {
+ if (SSL_LOG_DATA) Log::Print(
+ "WriteEncrypted BIO_read returned error %d\n", bytes_processed);
+ return 0;
+ } else {
+ if (SSL_LOG_DATA) Log::Print(
+ "WriteEncrypted BIO_read wrote %d bytes\n", bytes_processed);
}
}
return bytes_processed;
« no previous file with comments | « runtime/bin/secure_socket.h ('k') | runtime/bin/secure_socket_patch.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698