/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
 * Copyright (c) 2013-2017 Regents of the University of California.
 *
 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
 *
 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
 * terms of the GNU Lesser General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later version.
 *
 * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 *
 * You should have received copies of the GNU General Public License and GNU Lesser
 * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
 * <http://www.gnu.org/licenses/>.
 *
 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
 */

#include "private-key.hpp"
#include "base64-decode.hpp"
#include "base64-encode.hpp"
#include "buffer-source.hpp"
#include "stream-sink.hpp"
#include "stream-source.hpp"
#include "../detail/openssl-helper.hpp"
#include "../key-params.hpp"
#include "../../encoding/buffer-stream.hpp"

#include <cstring>

#define ENSURE_PRIVATE_KEY_LOADED(key) \
  do { \
    if (key == nullptr) \
      BOOST_THROW_EXCEPTION(Error("Private key has not been loaded yet")); \
  } while (false)

namespace ndn {
namespace security {
namespace transform {

static void
opensslInitAlgorithms()
{
#if OPENSSL_VERSION_NUMBER < 0x1010000fL
  static bool isInitialized = false;
  if (!isInitialized) {
    OpenSSL_add_all_algorithms();
    isInitialized = true;
  }
#endif // OPENSSL_VERSION_NUMBER < 0x1010000fL
}

class PrivateKey::Impl
{
public:
  Impl()
    : key(nullptr)
  {
  }

  ~Impl()
  {
    EVP_PKEY_free(key);
  }

public:
  EVP_PKEY* key;
};

PrivateKey::PrivateKey()
  : m_impl(new Impl)
{
}

PrivateKey::~PrivateKey() = default;

void
PrivateKey::loadPkcs1(const uint8_t* buf, size_t size)
{
  detail::Bio mem(BIO_s_mem());
  BIO_write(mem.get(), buf, size);

  d2i_PrivateKey_bio(mem.get(), &m_impl->key);

  ENSURE_PRIVATE_KEY_LOADED(m_impl->key);
}

void
PrivateKey::loadPkcs1(std::istream& is)
{
  OBufferStream os;
  streamSource(is) >> streamSink(os);
  this->loadPkcs1(os.buf()->buf(), os.buf()->size());
}

void
PrivateKey::loadPkcs1Base64(const uint8_t* buf, size_t size)
{
  OBufferStream os;
  bufferSource(buf, size) >> base64Decode() >> streamSink(os);
  this->loadPkcs1(os.buf()->buf(), os.buf()->size());
}

void
PrivateKey::loadPkcs1Base64(std::istream& is)
{
  OBufferStream os;
  streamSource(is) >> base64Decode() >> streamSink(os);
  this->loadPkcs1(os.buf()->buf(), os.buf()->size());
}

void
PrivateKey::loadPkcs8(const uint8_t* buf, size_t size, const char* pw, size_t pwLen)
{
  BOOST_ASSERT(std::strlen(pw) == pwLen);
  opensslInitAlgorithms();

  detail::Bio mem(BIO_s_mem());
  BIO_write(mem.get(), buf, size);

  m_impl->key = d2i_PKCS8PrivateKey_bio(mem.get(), &m_impl->key, nullptr, const_cast<char*>(pw));

  ENSURE_PRIVATE_KEY_LOADED(m_impl->key);
}

static inline int
passwordCallback(char* buf, int size, int rwflag, void* u)
{
  BOOST_ASSERT(size >= 0);
  auto cb = reinterpret_cast<PrivateKey::PasswordCallback*>(u);
  return (*cb)(buf, static_cast<size_t>(size), rwflag);
}

void
PrivateKey::loadPkcs8(const uint8_t* buf, size_t size, PasswordCallback pwCallback)
{
  opensslInitAlgorithms();

  detail::Bio mem(BIO_s_mem());
  BIO_write(mem.get(), buf, size);

  if (pwCallback)
    m_impl->key = d2i_PKCS8PrivateKey_bio(mem.get(), &m_impl->key, passwordCallback, &pwCallback);
  else
    m_impl->key = d2i_PKCS8PrivateKey_bio(mem.get(), &m_impl->key, nullptr, nullptr);

  ENSURE_PRIVATE_KEY_LOADED(m_impl->key);
}

void
PrivateKey::loadPkcs8(std::istream& is, const char* pw, size_t pwLen)
{
  OBufferStream os;
  streamSource(is) >> streamSink(os);
  this->loadPkcs8(os.buf()->buf(), os.buf()->size(), pw, pwLen);
}

void
PrivateKey::loadPkcs8(std::istream& is, PasswordCallback pwCallback)
{
  OBufferStream os;
  streamSource(is) >> streamSink(os);
  this->loadPkcs8(os.buf()->buf(), os.buf()->size(), pwCallback);
}

void
PrivateKey::loadPkcs8Base64(const uint8_t* buf, size_t size, const char* pw, size_t pwLen)
{
  OBufferStream os;
  bufferSource(buf, size) >> base64Decode() >> streamSink(os);
  this->loadPkcs8(os.buf()->buf(), os.buf()->size(), pw, pwLen);
}

void
PrivateKey::loadPkcs8Base64(const uint8_t* buf, size_t size, PasswordCallback pwCallback)
{
  OBufferStream os;
  bufferSource(buf, size) >> base64Decode() >> streamSink(os);
  this->loadPkcs8(os.buf()->buf(), os.buf()->size(), pwCallback);
}

void
PrivateKey::loadPkcs8Base64(std::istream& is, const char* pw, size_t pwLen)
{
  OBufferStream os;
  streamSource(is) >> base64Decode() >> streamSink(os);
  this->loadPkcs8(os.buf()->buf(), os.buf()->size(), pw, pwLen);
}

void
PrivateKey::loadPkcs8Base64(std::istream& is, PasswordCallback pwCallback)
{
  OBufferStream os;
  streamSource(is) >> base64Decode() >> streamSink(os);
  this->loadPkcs8(os.buf()->buf(), os.buf()->size(), pwCallback);
}

void
PrivateKey::savePkcs1(std::ostream& os) const
{
  bufferSource(*this->toPkcs1()) >> streamSink(os);
}

void
PrivateKey::savePkcs1Base64(std::ostream& os) const
{
  bufferSource(*this->toPkcs1()) >> base64Encode() >> streamSink(os);
}

void
PrivateKey::savePkcs8(std::ostream& os, const char* pw, size_t pwLen) const
{
  bufferSource(*this->toPkcs8(pw, pwLen)) >> streamSink(os);
}

void
PrivateKey::savePkcs8(std::ostream& os, PasswordCallback pwCallback) const
{
  bufferSource(*this->toPkcs8(pwCallback)) >> streamSink(os);
}

void
PrivateKey::savePkcs8Base64(std::ostream& os, const char* pw, size_t pwLen) const
{
  bufferSource(*this->toPkcs8(pw, pwLen)) >> base64Encode() >> streamSink(os);
}

void
PrivateKey::savePkcs8Base64(std::ostream& os, PasswordCallback pwCallback) const
{
  bufferSource(*this->toPkcs8(pwCallback)) >> base64Encode() >> streamSink(os);
}

ConstBufferPtr
PrivateKey::derivePublicKey() const
{
  ENSURE_PRIVATE_KEY_LOADED(m_impl->key);

  uint8_t* pkcs8 = nullptr;
  int len = i2d_PUBKEY(m_impl->key, &pkcs8);

  if (len <= 0)
    BOOST_THROW_EXCEPTION(Error("Failed to derive public key"));

  auto result = make_shared<Buffer>(pkcs8, len);
  OPENSSL_free(pkcs8);

  return result;
}

ConstBufferPtr
PrivateKey::decrypt(const uint8_t* cipherText, size_t cipherLen) const
{
  ENSURE_PRIVATE_KEY_LOADED(m_impl->key);

#if OPENSSL_VERSION_NUMBER < 0x1010000fL
  switch (EVP_PKEY_type(m_impl->key->type)) {
#else
  switch (EVP_PKEY_base_id(m_impl->key)) {
#endif // OPENSSL_VERSION_NUMBER < 0x1010000fL
    case EVP_PKEY_RSA:
      return rsaDecrypt(cipherText, cipherLen);
    default:
      BOOST_THROW_EXCEPTION(Error("Decryption is not supported for this key type"));
  }
}

void*
PrivateKey::getEvpPkey() const
{
  return m_impl->key;
}

ConstBufferPtr
PrivateKey::toPkcs1() const
{
  ENSURE_PRIVATE_KEY_LOADED(m_impl->key);
  opensslInitAlgorithms();

  detail::Bio mem(BIO_s_mem());
  int ret = i2d_PrivateKey_bio(mem.get(), m_impl->key);
  if (ret != 1)
    BOOST_THROW_EXCEPTION(Error("Cannot convert key into PKCS1 format"));

  int len8 = BIO_pending(mem.get());
  auto buffer = make_shared<Buffer>(len8);
  BIO_read(mem.get(), buffer->buf(), len8);

  return buffer;
}

ConstBufferPtr
PrivateKey::toPkcs8(const char* pw, size_t pwLen) const
{
  BOOST_ASSERT(std::strlen(pw) == pwLen);
  ENSURE_PRIVATE_KEY_LOADED(m_impl->key);
  opensslInitAlgorithms();

  detail::Bio mem(BIO_s_mem());
  int ret = i2d_PKCS8PrivateKey_bio(mem.get(), m_impl->key, EVP_des_cbc(),
                                    const_cast<char*>(pw), pwLen, nullptr, nullptr);
  if (ret != 1)
    BOOST_THROW_EXCEPTION(Error("Cannot convert key into PKCS8 format"));

  int len8 = BIO_pending(mem.get());
  auto buffer = make_shared<Buffer>(len8);
  BIO_read(mem.get(), buffer->buf(), len8);

  return buffer;
}

ConstBufferPtr
PrivateKey::toPkcs8(PasswordCallback pwCallback) const
{
  ENSURE_PRIVATE_KEY_LOADED(m_impl->key);
  opensslInitAlgorithms();

  detail::Bio mem(BIO_s_mem());
  int ret = i2d_PKCS8PrivateKey_bio(mem.get(), m_impl->key, EVP_des_cbc(),
                                    nullptr, 0,
                                    passwordCallback, &pwCallback);
  if (ret != 1)
    BOOST_THROW_EXCEPTION(Error("Cannot convert key into PKCS8 format"));

  int len8 = BIO_pending(mem.get());
  auto buffer = make_shared<Buffer>(len8);
  BIO_read(mem.get(), buffer->buf(), len8);

  return buffer;
}

ConstBufferPtr
PrivateKey::rsaDecrypt(const uint8_t* cipherText, size_t cipherLen) const
{
  detail::EvpPkeyCtx ctx(m_impl->key);

  if (EVP_PKEY_decrypt_init(ctx.get()) <= 0)
    BOOST_THROW_EXCEPTION(Error("Failed to initialize decryption context"));

  if (EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_PKCS1_OAEP_PADDING) <= 0)
    BOOST_THROW_EXCEPTION(Error("Failed to set padding"));

  size_t outlen = 0;
  // Determine buffer length
  if (EVP_PKEY_decrypt(ctx.get(), nullptr, &outlen, cipherText, cipherLen) <= 0)
    BOOST_THROW_EXCEPTION(Error("Failed to estimate output length"));

  auto out = make_shared<Buffer>(outlen);

  if (EVP_PKEY_decrypt(ctx.get(), out->buf(), &outlen, cipherText, cipherLen) <= 0)
    BOOST_THROW_EXCEPTION(Error("Failed to decrypt cipher text"));

  out->resize(outlen);
  return out;
}

static unique_ptr<PrivateKey>
generateRsaKey(uint32_t keySize)
{
  detail::EvpPkeyCtx kctx(EVP_PKEY_RSA);

  int ret = EVP_PKEY_keygen_init(kctx.get());
  if (ret != 1)
    BOOST_THROW_EXCEPTION(PrivateKey::Error("Fail to generate RSA key"));

  ret = EVP_PKEY_CTX_set_rsa_keygen_bits(kctx.get(), keySize);
  if (ret != 1)
    BOOST_THROW_EXCEPTION(PrivateKey::Error("Fail to generate RSA key"));

  detail::EvpPkey key;
  ret = EVP_PKEY_keygen(kctx.get(), &key);
  if (ret != 1)
    BOOST_THROW_EXCEPTION(PrivateKey::Error("Fail to generate RSA key"));

  detail::Bio mem(BIO_s_mem());
  i2d_PrivateKey_bio(mem.get(), key.get());
  int len = BIO_pending(mem.get());
  Buffer buffer(len);
  BIO_read(mem.get(), buffer.buf(), len);

  auto privateKey = make_unique<PrivateKey>();
  privateKey->loadPkcs1(buffer.buf(), buffer.size());

  return privateKey;
}

static unique_ptr<PrivateKey>
generateEcKey(uint32_t keySize)
{
  detail::EvpPkeyCtx ctx(EVP_PKEY_EC);

  int ret = EVP_PKEY_paramgen_init(ctx.get());
  if (ret != 1)
    BOOST_THROW_EXCEPTION(PrivateKey::Error("Fail to generate EC key"));

  switch (keySize) {
    case 256:
      ret = EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx.get(), NID_X9_62_prime256v1);
      break;
    case 384:
      ret = EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx.get(), NID_secp384r1);
      break;
    default:
      BOOST_THROW_EXCEPTION(PrivateKey::Error("Fail to generate EC key"));
  }
  if (ret != 1)
    BOOST_THROW_EXCEPTION(PrivateKey::Error("Fail to generate EC key"));

  detail::EvpPkey params;
  ret = EVP_PKEY_paramgen(ctx.get(), &params);
  if (ret != 1)
    BOOST_THROW_EXCEPTION(PrivateKey::Error("Fail to generate EC key"));

  detail::EvpPkeyCtx kctx(params.get());
  ret = EVP_PKEY_keygen_init(kctx.get());
  if (ret != 1)
    BOOST_THROW_EXCEPTION(PrivateKey::Error("Fail to generate EC key"));

  detail::EvpPkey key;
  ret = EVP_PKEY_keygen(kctx.get(), &key);
  if (ret != 1)
    BOOST_THROW_EXCEPTION(PrivateKey::Error("Fail to generate EC key"));

  detail::Bio mem(BIO_s_mem());
  i2d_PrivateKey_bio(mem.get(), key.get());
  int len = BIO_pending(mem.get());
  Buffer buffer(len);
  BIO_read(mem.get(), buffer.buf(), len);

  auto privateKey = make_unique<PrivateKey>();
  privateKey->loadPkcs1(buffer.buf(), buffer.size());

  return privateKey;
}

unique_ptr<PrivateKey>
generatePrivateKey(const KeyParams& keyParams)
{
  switch (keyParams.getKeyType()) {
    case KeyType::RSA: {
      const RsaKeyParams& rsaParams = static_cast<const RsaKeyParams&>(keyParams);
      return generateRsaKey(rsaParams.getKeySize());
    }
    case KeyType::EC: {
      const EcKeyParams& ecParams = static_cast<const EcKeyParams&>(keyParams);
      return generateEcKey(ecParams.getKeySize());
    }
    default:
      BOOST_THROW_EXCEPTION(std::invalid_argument("Unsupported asymmetric key type"));
  }
}

} // namespace transform
} // namespace security
} // namespace ndn
