Files
sdk/runtime/bin/security_context_win.cc
T
Alexander Aprelev a6dafabb88 [vm/io/mac] On macos/ios run trust evaluation part of ssl certification validation on separate worker thread.
Running trust evaluation system api call on worker thread effectively unblocks main isolate when it attempts to establish https connection.

Execution of the worker thread is implemented via dart native port infrastructure which allows to run C++ code as a dart message handler.
TrustEvaluateHandlerFunc (if provided by platform-dependent SSLCertContext) is that handler, only mac(ios) implementation provides it.

Asynchrony of CertificateVerificationCallback (for mac/ios) is implemented via [ssl_verify_retry] return code which allows to suspend ssl handshake until certificate trust is confirmed.
When dart's _RawSecureSocket.secureHandshake() method that initiated ssl's handshake received this return code it knows it has to wait for a future that is completed by another callback([rpEvaluteResponse]) that waits for trust evaluation handler response.
rpEvaluateResponse purpose is to listen for response from TrustEvaluateHandler and also invoke user-provided [badCertficateCallback] that can override trust decision for a given connection request, for a given certificate.
Once that future is completed and CertificateVerificationCallback knows whether to trust a certificate or not, _secureHandshake retries ssl handshake.


Bug: https://github.com/dart-lang/sdk/issues/41519
Change-Id: Ifee18639c78099ec77cad50000444bc6c7b9369b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/165520
Reviewed-by: Siva Annamalai <asiva@google.com>
Commit-Queue: Alexander Aprelev <aam@google.com>
2020-10-01 23:40:16 +00:00

147 lines
4.6 KiB
C++

// Copyright (c) 2017, 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.
#if !defined(DART_IO_SECURE_SOCKET_DISABLED)
#include "platform/globals.h"
#if defined(HOST_OS_WINDOWS)
#include "bin/security_context.h"
#include <openssl/bio.h>
#include <openssl/ssl.h>
#include <openssl/x509.h>
#include <wincrypt.h>
#include "bin/directory.h"
#include "bin/file.h"
#include "bin/secure_socket_filter.h"
#include "bin/secure_socket_utils.h"
#include "platform/syslog.h"
#pragma comment(lib, "crypt32.lib")
namespace dart {
namespace bin {
// The security context won't necessarily use the compiled-in root certificates,
// but since there is no way to update the size of the allocation after creating
// the weak persistent handle, we assume that it will. Note that when the
// root certs aren't compiled in, |root_certificates_pem_length| is 0.
const intptr_t SSLCertContext::kApproximateSize =
sizeof(SSLCertContext) + root_certificates_pem_length;
static void PrintSSLErr(const char* str) {
int error = ERR_get_error();
char error_string[SecureSocketUtils::SSL_ERROR_MESSAGE_BUFFER_SIZE];
ERR_error_string_n(error, error_string,
SecureSocketUtils::SSL_ERROR_MESSAGE_BUFFER_SIZE);
Syslog::PrintErr("%s ERROR: %d %s\n", str, error, error_string);
}
// Add certificates from Windows trusted root store.
static bool AddCertificatesFromRootStore(X509_STORE* store) {
// Open root system store.
// Note that only current user certificates are accessible using this method,
// not the local machine store.
HCERTSTORE cert_store = CertOpenSystemStore(NULL, L"ROOT");
if (cert_store == NULL) {
if (SSL_LOG_STATUS) {
DWORD error = GetLastError();
Syslog::PrintErr("Failed to open Windows root store due to %d\n", error);
}
return false;
}
// Iterating through all certificates in the store. A NULL is required to
// start iteration.
PCCERT_CONTEXT cert_context = NULL;
do {
cert_context = CertEnumCertificatesInStore(cert_store, cert_context);
if (cert_context == NULL) {
// reach the end of store.
break;
}
BIO* root_cert_bio =
BIO_new_mem_buf(const_cast<unsigned char*>(cert_context->pbCertEncoded),
cert_context->cbCertEncoded);
// `root_cert` has to be initialized to NULL, otherwise, it will be
// considerred as an existing X509 and cause segmentation fault.
X509* root_cert = NULL;
if (d2i_X509_bio(root_cert_bio, &root_cert) == NULL) {
if (SSL_LOG_STATUS) {
PrintSSLErr("Fail to read certificate");
}
BIO_free(root_cert_bio);
continue;
}
BIO_free(root_cert_bio);
int status = X509_STORE_add_cert(store, root_cert);
if (status == 0) {
if (SSL_LOG_STATUS) {
PrintSSLErr("Fail to add certificate to trust store");
}
X509_free(root_cert);
CertFreeCertificateContext(cert_context);
CertCloseStore(cert_store, 0);
return false;
}
} while (cert_context != NULL);
// It always returns non-zero.
CertFreeCertificateContext(cert_context);
if (!CertCloseStore(cert_store, 0)) {
if (SSL_LOG_STATUS) {
PrintSSLErr("Fail to close system root store");
}
return false;
}
return true;
}
void SSLCertContext::TrustBuiltinRoots() {
// First, try to use locations specified on the command line.
if (root_certs_file() != NULL) {
LoadRootCertFile(root_certs_file());
return;
}
if (root_certs_cache() != NULL) {
LoadRootCertCache(root_certs_cache());
return;
}
if (SSL_LOG_STATUS) {
Syslog::Print("Trusting Windows built-in roots\n");
}
X509_STORE* store = SSL_CTX_get_cert_store(context());
if (AddCertificatesFromRootStore(store)) {
return;
}
// Reset store. SSL_CTX_set_cert_store will take ownership of store. A manual
// free is not needed.
SSL_CTX_set_cert_store(context(), X509_STORE_new());
// Fall back on the compiled-in certs if the standard locations don't exist,
// or fail to load certificates from Windows root store.
if (SSL_LOG_STATUS) {
Syslog::Print("Trusting compiled-in roots\n");
}
AddCompiledInCerts();
}
void SSLCertContext::RegisterCallbacks(SSL* ssl) {
// No callbacks to register for implementations using BoringSSL's built-in
// verification mechanism.
}
TrustEvaluateHandlerFunc SSLCertContext::GetTrustEvaluateHandler() const {
return nullptr;
}
} // namespace bin
} // namespace dart
#endif // defined(HOST_OS_WINDOWS)
#endif // !defined(DART_IO_SECURE_SOCKET_DISABLED)