/*
 *
 * Copyright 2015 gRPC authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

#include <grpc/support/port_platform.h>

#include "src/core/lib/http/httpcli.h"

#include <string.h>

#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>

#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/channel/handshaker_registry.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/iomgr/pollset.h"
#include "src/core/lib/security/credentials/credentials.h"
#include "src/core/lib/security/security_connector/ssl_utils.h"
#include "src/core/lib/security/transport/security_handshaker.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/tsi/ssl_transport_security.h"

class grpc_httpcli_ssl_channel_security_connector final
    : public grpc_channel_security_connector {
 public:
  explicit grpc_httpcli_ssl_channel_security_connector(char* secure_peer_name)
      : grpc_channel_security_connector(
            /*url_scheme=*/nullptr,
            /*channel_creds=*/nullptr,
            /*request_metadata_creds=*/nullptr),
        secure_peer_name_(secure_peer_name) {}

  ~grpc_httpcli_ssl_channel_security_connector() override {
    if (handshaker_factory_ != nullptr) {
      tsi_ssl_client_handshaker_factory_unref(handshaker_factory_);
    }
    if (secure_peer_name_ != nullptr) {
      gpr_free(secure_peer_name_);
    }
  }

  tsi_result InitHandshakerFactory(const char* pem_root_certs,
                                   const tsi_ssl_root_certs_store* root_store) {
    tsi_ssl_client_handshaker_options options;
    memset(&options, 0, sizeof(options));
    options.pem_root_certs = pem_root_certs;
    options.root_store = root_store;
    return tsi_create_ssl_client_handshaker_factory_with_options(
        &options, &handshaker_factory_);
  }

  void add_handshakers(grpc_pollset_set* interested_parties,
                       grpc_handshake_manager* handshake_mgr) override {
    tsi_handshaker* handshaker = nullptr;
    if (handshaker_factory_ != nullptr) {
      tsi_result result = tsi_ssl_client_handshaker_factory_create_handshaker(
          handshaker_factory_, secure_peer_name_, &handshaker);
      if (result != TSI_OK) {
        gpr_log(GPR_ERROR, "Handshaker creation failed with error %s.",
                tsi_result_to_string(result));
      }
    }
    grpc_handshake_manager_add(
        handshake_mgr, grpc_security_handshaker_create(handshaker, this));
  }

  tsi_ssl_client_handshaker_factory* handshaker_factory() const {
    return handshaker_factory_;
  }

  void check_peer(tsi_peer peer, grpc_endpoint* ep,
                  grpc_core::RefCountedPtr<grpc_auth_context>* /*auth_context*/,
                  grpc_closure* on_peer_checked) override {
    grpc_error* error = GRPC_ERROR_NONE;

    /* Check the peer name. */
    if (secure_peer_name_ != nullptr &&
        !tsi_ssl_peer_matches_name(&peer, secure_peer_name_)) {
      char* msg;
      gpr_asprintf(&msg, "Peer name %s is not in peer certificate",
                   secure_peer_name_);
      error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
      gpr_free(msg);
    }
    GRPC_CLOSURE_SCHED(on_peer_checked, error);
    tsi_peer_destruct(&peer);
  }

  int cmp(const grpc_security_connector* other_sc) const override {
    auto* other =
        reinterpret_cast<const grpc_httpcli_ssl_channel_security_connector*>(
            other_sc);
    return strcmp(secure_peer_name_, other->secure_peer_name_);
  }

  bool check_call_host(const char* host, grpc_auth_context* auth_context,
                       grpc_closure* on_call_host_checked,
                       grpc_error** error) override {
    *error = GRPC_ERROR_NONE;
    return true;
  }

  void cancel_check_call_host(grpc_closure* on_call_host_checked,
                              grpc_error* error) override {
    GRPC_ERROR_UNREF(error);
  }

  const char* secure_peer_name() const { return secure_peer_name_; }

 private:
  tsi_ssl_client_handshaker_factory* handshaker_factory_ = nullptr;
  char* secure_peer_name_;
};

static grpc_core::RefCountedPtr<grpc_channel_security_connector>
httpcli_ssl_channel_security_connector_create(
    const char* pem_root_certs, const tsi_ssl_root_certs_store* root_store,
    const char* secure_peer_name) {
  if (secure_peer_name != nullptr && pem_root_certs == nullptr) {
    gpr_log(GPR_ERROR,
            "Cannot assert a secure peer name without a trust root.");
    return nullptr;
  }
  grpc_core::RefCountedPtr<grpc_httpcli_ssl_channel_security_connector> c =
      grpc_core::MakeRefCounted<grpc_httpcli_ssl_channel_security_connector>(
          secure_peer_name == nullptr ? nullptr : gpr_strdup(secure_peer_name));
  tsi_result result = c->InitHandshakerFactory(pem_root_certs, root_store);
  if (result != TSI_OK) {
    gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.",
            tsi_result_to_string(result));
    return nullptr;
  }
  return c;
}

/* handshaker */

typedef struct {
  void (*func)(void* arg, grpc_endpoint* endpoint);
  void* arg;
  grpc_handshake_manager* handshake_mgr;
} on_done_closure;

static void on_handshake_done(void* arg, grpc_error* error) {
  grpc_handshaker_args* args = static_cast<grpc_handshaker_args*>(arg);
  on_done_closure* c = static_cast<on_done_closure*>(args->user_data);
  if (error != GRPC_ERROR_NONE) {
    const char* msg = grpc_error_string(error);
    gpr_log(GPR_ERROR, "Secure transport setup failed: %s", msg);

    c->func(c->arg, nullptr);
  } else {
    grpc_channel_args_destroy(args->args);
    grpc_slice_buffer_destroy_internal(args->read_buffer);
    gpr_free(args->read_buffer);
    c->func(c->arg, args->endpoint);
  }
  grpc_handshake_manager_destroy(c->handshake_mgr);
  gpr_free(c);
}

static void ssl_handshake(void* arg, grpc_endpoint* tcp, const char* host,
                          grpc_millis deadline,
                          void (*on_done)(void* arg, grpc_endpoint* endpoint)) {
  on_done_closure* c = static_cast<on_done_closure*>(gpr_malloc(sizeof(*c)));
  const char* pem_root_certs =
      grpc_core::DefaultSslRootStore::GetPemRootCerts();
  const tsi_ssl_root_certs_store* root_store =
      grpc_core::DefaultSslRootStore::GetRootStore();
  if (root_store == nullptr) {
    gpr_log(GPR_ERROR, "Could not get default pem root certs.");
    on_done(arg, nullptr);
    gpr_free(c);
    return;
  }
  c->func = on_done;
  c->arg = arg;
  grpc_core::RefCountedPtr<grpc_channel_security_connector> sc =
      httpcli_ssl_channel_security_connector_create(pem_root_certs, root_store,
                                                    host);
  GPR_ASSERT(sc != nullptr);
  grpc_arg channel_arg = grpc_security_connector_to_arg(sc.get());
  grpc_channel_args args = {1, &channel_arg};
  c->handshake_mgr = grpc_handshake_manager_create();
  grpc_handshakers_add(HANDSHAKER_CLIENT, &args,
                       nullptr /* interested_parties */, c->handshake_mgr);
  grpc_handshake_manager_do_handshake(
      c->handshake_mgr, tcp, nullptr /* channel_args */, deadline,
      nullptr /* acceptor */, on_handshake_done, c /* user_data */);
  sc.reset(DEBUG_LOCATION, "httpcli");
}

const grpc_httpcli_handshaker grpc_httpcli_ssl = {"https", ssl_handshake};
