| Index: runtime/bin/secure_socket_boringssl.cc
|
| diff --git a/runtime/bin/secure_socket_boringssl.cc b/runtime/bin/secure_socket_boringssl.cc
|
| index e881815796af5c897652ef5f08f09ba3aa652799..132588d31c43de20c08a248057d7a512b1504e16 100644
|
| --- a/runtime/bin/secure_socket_boringssl.cc
|
| +++ b/runtime/bin/secure_socket_boringssl.cc
|
| @@ -28,6 +28,8 @@
|
|
|
| #include "bin/builtin.h"
|
| #include "bin/dartutils.h"
|
| +#include "bin/directory.h"
|
| +#include "bin/file.h"
|
| #include "bin/lockers.h"
|
| #include "bin/log.h"
|
| #include "bin/socket.h"
|
| @@ -64,6 +66,10 @@ static const bool SSL_LOG_DATA = false;
|
| static const int SSL_ERROR_MESSAGE_BUFFER_SIZE = 1000;
|
|
|
|
|
| +const char* commandline_root_certs_file = NULL;
|
| +const char* commandline_root_certs_cache = NULL;
|
| +
|
| +
|
| /* Get the error messages from BoringSSL, and put them in buffer as a
|
| * null-terminated string. */
|
| static void FetchErrorString(char* buffer, int length) {
|
| @@ -788,22 +794,10 @@ void FUNCTION_NAME(SecurityContext_AlpnSupported)(Dart_NativeArguments args) {
|
| }
|
|
|
|
|
| -void FUNCTION_NAME(SecurityContext_TrustBuiltinRoots)(
|
| - Dart_NativeArguments args) {
|
| - SSLContext* context = GetSecurityContext(args);
|
| -#if defined(TARGET_OS_ANDROID)
|
| - // On Android, we don't compile in the trusted root certificates. Insead,
|
| - // we use the directory of trusted certificates already present on the device.
|
| - // This saves ~240KB from the size of the binary. This has the drawback that
|
| - // SSL_do_handshake will synchronously hit the filesystem looking for root
|
| - // certs during its trust evaluation. We call SSL_do_handshake directly from
|
| - // the Dart thread so that Dart code can be invoked from the "bad certificate"
|
| - // callback called by SSL_do_handshake.
|
| - const char* android_cacerts = "/system/etc/security/cacerts";
|
| - int status = SSL_CTX_load_verify_locations(
|
| - context->context(), NULL, android_cacerts);
|
| - CheckStatus(status, "TlsException", "Failure trusting builtint roots");
|
| -#else
|
| +static void AddCompiledInCerts(SSLContext* context) {
|
| + if (root_certificates_pem == NULL) {
|
| + return;
|
| + }
|
| X509_STORE* store = SSL_CTX_get_cert_store(context->context());
|
| BIO* roots_bio =
|
| BIO_new_mem_buf(const_cast<unsigned char*>(root_certificates_pem),
|
| @@ -825,7 +819,90 @@ void FUNCTION_NAME(SecurityContext_TrustBuiltinRoots)(
|
| // reading PEM certificates.
|
| ASSERT((ERR_peek_error() == 0) || NoPEMStartLine());
|
| ERR_clear_error();
|
| +}
|
| +
|
| +
|
| +static void LoadRootCertFile(SSLContext* context, const char* file) {
|
| + if (SSL_LOG_STATUS) {
|
| + Log::Print("Looking for trusted roots in %s\n", file);
|
| + }
|
| + if (!File::Exists(file)) {
|
| + ThrowIOException(-1, "TlsException", "Failed to find root cert file");
|
| + }
|
| + int status = SSL_CTX_load_verify_locations(context->context(), file, NULL);
|
| + CheckStatus(status, "TlsException", "Failure trusting builtint roots");
|
| + if (SSL_LOG_STATUS) {
|
| + Log::Print("Trusting roots from: %s\n", file);
|
| + }
|
| +}
|
| +
|
| +
|
| +static void LoadRootCertCache(SSLContext* context, const char* cache) {
|
| + if (SSL_LOG_STATUS) {
|
| + Log::Print("Looking for trusted roots in %s\n", cache);
|
| + }
|
| + if (Directory::Exists(cache) != Directory::EXISTS) {
|
| + ThrowIOException(-1, "TlsException", "Failed to find root cert cache");
|
| + }
|
| + int status = SSL_CTX_load_verify_locations(context->context(), NULL, cache);
|
| + CheckStatus(status, "TlsException", "Failure trusting builtint roots");
|
| + if (SSL_LOG_STATUS) {
|
| + Log::Print("Trusting roots from: %s\n", cache);
|
| + }
|
| +}
|
| +
|
| +
|
| +void FUNCTION_NAME(SecurityContext_TrustBuiltinRoots)(
|
| + Dart_NativeArguments args) {
|
| + SSLContext* context = GetSecurityContext(args);
|
| +
|
| + // First, try to use locations specified on the command line.
|
| + if (commandline_root_certs_file != NULL) {
|
| + LoadRootCertFile(context, commandline_root_certs_file);
|
| + return;
|
| + }
|
| +
|
| + if (commandline_root_certs_cache != NULL) {
|
| + LoadRootCertCache(context, commandline_root_certs_cache);
|
| + return;
|
| + }
|
| +
|
| +#if defined(TARGET_OS_ANDROID)
|
| + // On Android, we don't compile in the trusted root certificates. Insead,
|
| + // we use the directory of trusted certificates already present on the device.
|
| + // This saves ~240KB from the size of the binary. This has the drawback that
|
| + // SSL_do_handshake will synchronously hit the filesystem looking for root
|
| + // certs during its trust evaluation. We call SSL_do_handshake directly from
|
| + // the Dart thread so that Dart code can be invoked from the "bad certificate"
|
| + // callback called by SSL_do_handshake.
|
| + const char* android_cacerts = "/system/etc/security/cacerts";
|
| + LoadRootCertCache(context, android_cacerts);
|
| + return;
|
| +#elif defined(TARGET_OS_LINUX)
|
| + // On Linux, we use the compiled-in trusted certs as a last resort. First,
|
| + // we try to find the trusted certs in various standard locations. A good
|
| + // discussion of the complexities of this endeavor can be found here:
|
| + //
|
| + // https://www.happyassassin.net/2015/01/12/a-note-about-ssltls-trusted-certificate-stores-and-platforms/
|
| + const char* bundle = "/etc/pki/tls/certs/ca-bundle.crt";
|
| + const char* cachedir = "/etc/ssl/certs";
|
| + if (File::Exists(bundle)) {
|
| + LoadRootCertFile(context, bundle);
|
| + return;
|
| + }
|
| +
|
| + if (Directory::Exists(cachedir) == Directory::EXISTS) {
|
| + LoadRootCertCache(context, cachedir);
|
| + return;
|
| + }
|
| #endif // defined(TARGET_OS_ANDROID)
|
| +
|
| + // Fall back on the compiled-in certs if the standard locations don't exist,
|
| + // or we aren't on Linux.
|
| + AddCompiledInCerts(context);
|
| + if (SSL_LOG_STATUS) {
|
| + Log::Print("Trusting compiled-in roots\n");
|
| + }
|
| }
|
|
|
|
|
| @@ -1494,19 +1571,27 @@ void SSLFilter::Connect(const char* hostname,
|
| // Make the connection:
|
| if (is_server_) {
|
| status = SSL_accept(ssl_);
|
| - if (SSL_LOG_STATUS) Log::Print("SSL_accept status: %d\n", status);
|
| + 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);
|
| + if (SSL_LOG_STATUS) {
|
| + Log::Print("SSL_accept error: %d\n", error);
|
| + }
|
| }
|
| } else {
|
| status = SSL_connect(ssl_);
|
| - if (SSL_LOG_STATUS) Log::Print("SSL_connect status: %d\n", status);
|
| + 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 (SSL_LOG_STATUS) {
|
| + Log::Print("SSL_connect error: %d\n", error);
|
| + }
|
| }
|
| }
|
| Handshake();
|
|
|