// 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(DART_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"

#ifndef DART_TARGET_OS_WINDOWS_UWP
#pragma comment(lib, "crypt32.lib")
#endif

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 %s\n", str, error_string);
}

#ifndef DART_TARGET_OS_WINDOWS_UWP
static bool AddCertificatesFromNamedSystemStore(const wchar_t* name,
                                                DWORD store_type,
                                                X509_STORE* store) {
  ASSERT(store_type == CERT_SYSTEM_STORE_CURRENT_USER ||
         store_type == CERT_SYSTEM_STORE_LOCAL_MACHINE);

  if (SSL_LOG_STATUS) {
    Syslog::Print("AddCertificatesFromNamedSystemStore %ls type: %s\n", name,
                  store_type == CERT_SYSTEM_STORE_CURRENT_USER
                      ? "Current User"
                      : "Local Machine");
  }

  HCERTSTORE cert_store =
      CertOpenStore(CERT_STORE_PROV_SYSTEM,
                    0,     // the encoding type is not needed
                    NULL,  // use the default HCRYPTPROV
                    store_type | CERT_STORE_READONLY_FLAG, name);

  if (cert_store == NULL) {
    if (SSL_LOG_STATUS) {
      DWORD error = GetLastError();
      Syslog::PrintErr(
          "Failed to open Windows root store %ls type %d due to %d\n", name,
          store_type, 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);

    if (SSL_LOG_STATUS) {
      auto s_name = X509_get_subject_name(root_cert);
      auto s_issuer_name = X509_get_issuer_name(root_cert);
      auto serial_number = X509_get_serialNumber(root_cert);
      BIGNUM* bn = ASN1_INTEGER_to_BN(serial_number, nullptr);
      char* hex = BN_bn2hex(bn);
      Syslog::Print("Considering root certificate serial: %s subject name: ",
                    hex);
      OPENSSL_free(hex);
      X509_NAME_print_ex_fp(stdout, s_name, 4, 0);
      Syslog::Print(" issuer:");
      X509_NAME_print_ex_fp(stdout, s_issuer_name, 4, 0);
      Syslog::Print("\n");
    }

    if (!SecureSocketUtils::IsCurrentTimeInsideCertValidDateRange(root_cert)) {
      if (SSL_LOG_STATUS) {
        Syslog::Print("...certificate is outside of its valid date range\n");
      }
      X509_free(root_cert);
      continue;
    }

    int status = X509_STORE_add_cert(store, root_cert);
    if (status == 0) {
      int error = ERR_get_error();
      if (ERR_GET_REASON(error) == X509_R_CERT_ALREADY_IN_HASH_TABLE) {
        if (SSL_LOG_STATUS) {
          Syslog::Print("...duplicate\n");
        }
        X509_free(root_cert);
        continue;
      }
      if (SSL_LOG_STATUS) {
        PrintSSLErr("Failed to add certificate to x509 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;
}

static bool AddCertificatesFromSystemStore(DWORD store_type,
                                           X509_STORE* store) {
  if (!AddCertificatesFromNamedSystemStore(L"ROOT", store_type, store)) {
    return false;
  }
  if (!AddCertificatesFromNamedSystemStore(L"CA", store_type, store)) {
    return false;
  }
  if (!AddCertificatesFromNamedSystemStore(L"TRUST", store_type, store)) {
    return false;
  }
  if (!AddCertificatesFromNamedSystemStore(L"MY", store_type, store)) {
    return false;
  }
  return true;
}
#endif  // ifdef DART_TARGET_OS_WINDOWS_UWP

// Add certificates from Windows trusted root store.
static bool AddCertificatesFromRootStore(X509_STORE* store) {
// The UWP platform doesn't support CertEnumCertificatesInStore hence
// this function cannot work when compiled in UWP mode.
#ifdef DART_TARGET_OS_WINDOWS_UWP
  return false;
#else
  if (!AddCertificatesFromSystemStore(CERT_SYSTEM_STORE_CURRENT_USER, store)) {
    return false;
  }

  if (!AddCertificatesFromSystemStore(CERT_SYSTEM_STORE_LOCAL_MACHINE, store)) {
    return false;
  }

  return true;
#endif  // ifdef DART_TARGET_OS_WINDOWS_UWP
}

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 (bypass_trusting_system_roots()) {
    if (SSL_LOG_STATUS) {
      Syslog::Print("Bypass trusting Windows built-in roots\n");
    }
  } else {
    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(DART_HOST_OS_WINDOWS)

#endif  // !defined(DART_IO_SECURE_SOCKET_DISABLED)
