// 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.

#ifndef RUNTIME_BIN_SECURITY_CONTEXT_H_
#define RUNTIME_BIN_SECURITY_CONTEXT_H_

#include <openssl/ssl.h>
#include <openssl/x509.h>

#include "bin/lockers.h"
#include "bin/reference_counting.h"
#include "bin/socket.h"

namespace dart {
namespace bin {

// Forward declaration
class SSLFilter;

typedef void (*TrustEvaluateHandlerFunc)(Dart_Port dest_port_id,
                                         Dart_CObject* message);

class SSLCertContext : public ReferenceCounted<SSLCertContext> {
 public:
  static const intptr_t kApproximateSize;
  static const int kSecurityContextNativeFieldIndex = 0;
  static const int kX509NativeFieldIndex = 0;

  explicit SSLCertContext(SSL_CTX* context)
      : ReferenceCounted(),
        context_(context),
        alpn_protocol_string_(nullptr),
        trust_builtin_(false),
        allow_tls_renegotiation_(false) {}

  ~SSLCertContext() {
    SSL_CTX_free(context_);
    free(alpn_protocol_string_);
  }

  static int CertificateCallback(int preverify_ok, X509_STORE_CTX* store_ctx);
  static void KeyLogCallback(const SSL* ssl, const char* line);

  static SSLCertContext* GetSecurityContext(Dart_NativeArguments args);
  static const char* GetPasswordArgument(Dart_NativeArguments args,
                                         intptr_t index);
  static void SetAlpnProtocolList(Dart_Handle protocols_handle,
                                  SSL* ssl,
                                  SSLCertContext* context,
                                  bool is_server);

  static const char* root_certs_file() { return root_certs_file_; }
  static void set_root_certs_file(const char* root_certs_file) {
    root_certs_file_ = root_certs_file;
  }
  static const char* root_certs_cache() { return root_certs_cache_; }
  static void set_root_certs_cache(const char* root_certs_cache) {
    root_certs_cache_ = root_certs_cache;
  }

  void SetTrustedCertificatesBytes(Dart_Handle cert_bytes,
                                   const char* password);

  void SetClientAuthoritiesBytes(Dart_Handle client_authorities_bytes,
                                 const char* password);

  int UseCertificateChainBytes(Dart_Handle cert_chain_bytes,
                               const char* password);

  void TrustBuiltinRoots();

  SSL_CTX* context() const { return context_; }

  uint8_t* alpn_protocol_string() const { return alpn_protocol_string_; }

  void set_alpn_protocol_string(uint8_t* protocol_string) {
    if (alpn_protocol_string_ != NULL) {
      free(alpn_protocol_string_);
    }
    alpn_protocol_string_ = protocol_string;
  }

  bool trust_builtin() const { return trust_builtin_; }

  void set_allow_tls_renegotiation(bool allow) {
    allow_tls_renegotiation_ = allow;
  }
  bool allow_tls_renegotiation() const { return allow_tls_renegotiation_; }

  void set_trust_builtin(bool trust_builtin) { trust_builtin_ = trust_builtin; }

  void RegisterCallbacks(SSL* ssl);
  TrustEvaluateHandlerFunc GetTrustEvaluateHandler() const;

  static bool long_ssl_cert_evaluation() { return long_ssl_cert_evaluation_; }
  static void set_long_ssl_cert_evaluation(bool long_ssl_cert_evaluation) {
    long_ssl_cert_evaluation_ = long_ssl_cert_evaluation;
  }

  static bool bypass_trusting_system_roots() {
    return bypass_trusting_system_roots_;
  }
  static void set_bypass_trusting_system_roots(
      bool bypass_trusting_system_roots) {
    bypass_trusting_system_roots_ = bypass_trusting_system_roots;
  }

 private:
  void AddCompiledInCerts();
  void LoadRootCertFile(const char* file);
  void LoadRootCertCache(const char* cache);

  static const char* root_certs_file_;
  static const char* root_certs_cache_;

  SSL_CTX* context_;
  uint8_t* alpn_protocol_string_;

  bool trust_builtin_;
  bool allow_tls_renegotiation_;
  static bool long_ssl_cert_evaluation_;
  static bool bypass_trusting_system_roots_;

  DISALLOW_COPY_AND_ASSIGN(SSLCertContext);
};

class X509Helper : public AllStatic {
 public:
  static Dart_Handle GetDer(Dart_NativeArguments args);
  static Dart_Handle GetPem(Dart_NativeArguments args);
  static Dart_Handle GetSha1(Dart_NativeArguments args);
  static Dart_Handle GetSubject(Dart_NativeArguments args);
  static Dart_Handle GetIssuer(Dart_NativeArguments args);
  static Dart_Handle GetStartValidity(Dart_NativeArguments args);
  static Dart_Handle GetEndValidity(Dart_NativeArguments args);
  static Dart_Handle WrappedX509Certificate(X509* certificate);
};

}  // namespace bin
}  // namespace dart

#endif  // RUNTIME_BIN_SECURITY_CONTEXT_H_
