// Copyright 2021 The Pigweed 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
//
//     https://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 "boringssl_backend.h"

#include "boringssl/boringssl_utils.h"
#include "pw_log/log.h"

namespace {

int BioRead(BIO* bio, char* out, int outl) {
  TransportInterface* transport = static_cast<TransportInterface*>(bio->ptr);
  int status = transport->Read(out, static_cast<size_t>(outl));
  if (status == 0) {
    BIO_set_retry_read(bio);
    return -1;
  }
  return status;
}

int BioWrite(BIO* bio, const char* in, int inl) {
  TransportInterface* transport = static_cast<TransportInterface*>(bio->ptr);
  int status = transport->Write(in, inl);
  return status;
}

static int BioNew(BIO* bio) {
  bio->init = 1;
  return 1;
}

long BioCtrl(BIO*, int, long, void*) { return 1; }

int BioFree(BIO*) { return 1; }

const BIO_METHOD bio_method = {
    BIO_TYPE_MEM,
    "demo bio",
    BioWrite,
    BioRead,
    nullptr, /* puts */
    nullptr, /* gets */
    BioCtrl, /* ctrl */
    BioNew,
    BioFree, /* free */
    nullptr /* callback_ctrl */,
};

}  // namespace

BoringsslBackend::BoringsslBackend()
    : ctx_(SSL_CTX_new(TLS_method())),
      ssl_(SSL_new(ctx_.get())),
      bio_(BIO_new(&bio_method)) {
  SSL_set_bio(ssl_.get(), bio_.get(), bio_.get());
}

int BoringsslBackend::SetHostName(const char* host) {
  SSL_set_tlsext_host_name(ssl_.get(), host);
  return 0;
}

int BoringsslBackend::Handshake(TransportInterface* transport) {
  bio_->ptr = transport;
  while (true) {
    int ret = SSL_connect(ssl_.get());
    if (ret == 1)
      break;
    int ssl_err = SSL_get_error(ssl_.get(), ret);
    if (ssl_err != SSL_ERROR_WANT_READ) {
      PW_LOG_INFO("Error connecting. %d", ssl_err);
      return -1;
    }
  }
  long verify_result = SSL_get_verify_result(ssl_.get());
  if (verify_result) {
    PW_LOG_INFO("x.509 cert verification failed: %ld", verify_result);
  }
  return verify_result == 0 ? 0 : -1;
}

int BoringsslBackend::Write(const void* buffer,
                            size_t size,
                            TransportInterface* transport) {
  bio_->ptr = transport;
  int ssl_ret = SSL_write(ssl_.get(), buffer, size);
  if (ssl_ret <= 0) {
    PW_LOG_INFO("Failed to write");
    return -1;
  }
  return static_cast<int>(size);
}

int BoringsslBackend::Read(void* buffer,
                           size_t size,
                           TransportInterface* transport) {
  bio_->ptr = transport;
  while (true) {
    int ssl_ret = SSL_read(ssl_.get(), buffer, size);
    if (ssl_ret < 0) {
      int ssl_err = SSL_get_error(ssl_.get(), ssl_ret);
      if (ssl_err == SSL_ERROR_WANT_READ) {
        continue;
      }
      PW_LOG_INFO("Error while reading");
      return -1;
    }
    return ssl_ret;
  }
}

int BoringsslBackend::LoadCACert(const void* buffer,
                                 size_t size,
                                 X509LoadFormat format) {
  auto store = SSL_CTX_get_cert_store(ctx_.get());
  // We don't provide a fixed check time. Thus make sure that time(0) is used
  // to obtain date time.
  X509_VERIFY_PARAM_clear_flags(store->param, X509_V_FLAG_USE_CHECK_TIME);
  if (format == X509LoadFormat::kPEM || format == X509LoadFormat::kTryAll) {
    int ret = LoadCACertCrlsPEMFormat(buffer, size, store);
    if (ret > 0) {
      return 0;
    } else if (format == X509LoadFormat::kPEM) {
      PW_LOG_INFO("Failed to load CA cert as PEM. %d", ret);
      return ret;
    }
  }
  if (format == X509LoadFormat::kDER || format == X509LoadFormat::kTryAll) {
    int ret = LoadCACertCrlDERFormat(buffer, size, store);
    if (ret == 0) {
      return 0;
    } else if (format == X509LoadFormat::kDER) {
      PW_LOG_INFO("Failed to load CA cert as DER. %d", ret);
      return ret;
    }
  }
  return -1;
}

int BoringsslBackend::LoadCrl(const void* buffer,
                              size_t size,
                              X509LoadFormat format) {
  auto store = SSL_CTX_get_cert_store(ctx_.get());
  X509_VERIFY_PARAM_set_flags(store->param, X509_V_FLAG_CRL_CHECK);
  return LoadCACert(buffer, size, format);
}

TlsInterface* CreateTls() { return new BoringsslBackend(); }
