// 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 "tink/core/private_key_manager_impl.h"

#include <string>

#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "tink/core/key_manager_impl.h"
#include "tink/core/private_key_type_manager.h"
#include "tink/registry.h"
#include "tink/subtle/aes_gcm_boringssl.h"
#include "tink/subtle/random.h"
#include "tink/util/status.h"
#include "tink/util/statusor.h"
#include "tink/util/test_matchers.h"
#include "tink/util/test_util.h"
#include "tink/util/validation.h"
#include "proto/ecdsa.pb.h"

namespace crypto {
namespace tink {
namespace internal {
namespace {

using ::crypto::tink::test::StatusIs;
using ::google::crypto::tink::EcdsaKeyFormat;
using ::google::crypto::tink::EcdsaPrivateKey;
using ::google::crypto::tink::EcdsaPublicKey;
using ::google::crypto::tink::EcdsaSignatureEncoding;
using ::google::crypto::tink::KeyData;
using ::testing::Eq;
using ::testing::HasSubstr;
using ::testing::Return;

// Placeholders for the primitives. We don't really want to test anything with
// these except that things compile and List<PrivatePrimitive> is never confused
// with List<PublicPrimitive> in private_key_manager_impl.
class PrivatePrimitive {};
class PublicPrimitive {};

class ExamplePrivateKeyTypeManager
    : public PrivateKeyTypeManager<EcdsaPrivateKey, EcdsaKeyFormat,
                                   EcdsaPublicKey, List<PrivatePrimitive>> {
 public:
  class PrivatePrimitiveFactory : public PrimitiveFactory<PrivatePrimitive> {
   public:
    crypto::tink::util::StatusOr<std::unique_ptr<PrivatePrimitive>> Create(
        const EcdsaPrivateKey& key) const override {
      return util::Status(util::error::UNIMPLEMENTED, "Not implemented");
    }
  };

  ExamplePrivateKeyTypeManager()
      : PrivateKeyTypeManager(absl::make_unique<PrivatePrimitiveFactory>()) {}

  google::crypto::tink::KeyData::KeyMaterialType key_material_type()
      const override {
    return google::crypto::tink::KeyData::ASYMMETRIC_PRIVATE;
  }

  MOCK_CONST_METHOD0(get_version, uint32_t());

  // We mock out ValidateKey and ValidateKeyFormat so that we can easily test
  // proper behavior in case they return an error.
  MOCK_CONST_METHOD1(ValidateKey,
                     crypto::tink::util::Status(const EcdsaPrivateKey& key));
  MOCK_CONST_METHOD1(ValidateKeyFormat,
                     crypto::tink::util::Status(const EcdsaKeyFormat& key));

  const std::string& get_key_type() const override { return kKeyType; }

  crypto::tink::util::StatusOr<EcdsaPrivateKey> CreateKey(
      const EcdsaKeyFormat& key_format) const override {
    EcdsaPublicKey public_key;
    *public_key.mutable_params() = key_format.params();
    EcdsaPrivateKey result;
    *result.mutable_public_key() = public_key;
    return result;
  }

  crypto::tink::util::StatusOr<EcdsaPublicKey> GetPublicKey(
      const EcdsaPrivateKey& private_key) const override {
    return private_key.public_key();
  }

 private:
  const std::string kKeyType =
      "type.googleapis.com/google.crypto.tink.EcdsaPublicKey";
};

class TestPublicKeyTypeManager
    : public KeyTypeManager<EcdsaPublicKey, void, List<PublicPrimitive>> {
 public:
  class PublicPrimitiveFactory : public PrimitiveFactory<PublicPrimitive> {
   public:
    crypto::tink::util::StatusOr<std::unique_ptr<PublicPrimitive>> Create(
        const EcdsaPublicKey& key) const override {
      return util::Status(util::error::UNIMPLEMENTED, "Not implemented");
    }
  };

  TestPublicKeyTypeManager()
      : KeyTypeManager(absl::make_unique<PublicPrimitiveFactory>()) {}

  google::crypto::tink::KeyData::KeyMaterialType key_material_type()
      const override {
    return google::crypto::tink::KeyData::ASYMMETRIC_PRIVATE;
  }

  MOCK_CONST_METHOD0(get_version, uint32_t());

  // We mock out ValidateKey and ValidateKeyFormat so that we can easily test
  // proper behavior in case they return an error.
  MOCK_CONST_METHOD1(ValidateKey,
                     crypto::tink::util::Status(const EcdsaPublicKey& key));

  const std::string& get_key_type() const override { return kKeyType; }

 private:
  const std::string kKeyType =
      "type.googleapis.com/google.crypto.tink.EcdsaPublicKey";
};

TEST(PrivateKeyManagerImplTest, FactoryNewKeyFromMessage) {
  ExamplePrivateKeyTypeManager private_km;
  TestPublicKeyTypeManager public_km;
  std::unique_ptr<KeyManager<PrivatePrimitive>> key_manager =
      MakePrivateKeyManager<PrivatePrimitive>(&private_km, &public_km);

  EcdsaKeyFormat key_format;
  key_format.mutable_params()->set_encoding(EcdsaSignatureEncoding::DER);
  auto key = key_manager->get_key_factory().NewKey(key_format).ValueOrDie();
  EXPECT_THAT(
      dynamic_cast<EcdsaPrivateKey&>(*key).public_key().params().encoding(),
      Eq(EcdsaSignatureEncoding::DER));
}

TEST(PrivateKeyManagerImplTest, GetPublicKeyData) {
  ExamplePrivateKeyTypeManager private_km;
  TestPublicKeyTypeManager public_km;
  std::unique_ptr<KeyManager<PrivatePrimitive>> key_manager =
      MakePrivateKeyManager<PrivatePrimitive>(&private_km, &public_km);

  EcdsaPrivateKey private_key;
  private_key.mutable_public_key()->mutable_params()->set_encoding(
      EcdsaSignatureEncoding::DER);

  auto key_data =
      dynamic_cast<const PrivateKeyFactory&>(key_manager->get_key_factory())
          .GetPublicKeyData(private_key.SerializeAsString())
          .ValueOrDie();
  ASSERT_THAT(key_data->type_url(), Eq(public_km.get_key_type()));
  EcdsaPublicKey public_key;
  public_key.ParseFromString(key_data->value());
  EXPECT_THAT(public_key.params().encoding(), Eq(EcdsaSignatureEncoding::DER));
}

TEST(PrivateKeyManagerImplTest, GetPublicKeyDataValidatePrivateKey) {
  ExamplePrivateKeyTypeManager private_km;
  TestPublicKeyTypeManager public_km;
  EXPECT_CALL(private_km, ValidateKey)
      .WillOnce(Return(ToStatusF(util::error::OUT_OF_RANGE,
                                 "GetPublicKeyDataValidatePrivateKey")));

  std::unique_ptr<KeyManager<PrivatePrimitive>> key_manager =
      MakePrivateKeyManager<PrivatePrimitive>(&private_km, &public_km);

  EXPECT_THAT(
      dynamic_cast<const PrivateKeyFactory&>(key_manager->get_key_factory())
          .GetPublicKeyData(EcdsaPrivateKey().SerializeAsString())
          .status(),
      StatusIs(util::error::OUT_OF_RANGE,
               HasSubstr("GetPublicKeyDataValidatePrivateKey")));
}

TEST(PrivateKeyManagerImplTest, PublicKeyManagerCanHaveShortLifetime) {
  ExamplePrivateKeyTypeManager private_km;
  std::unique_ptr<KeyManager<PrivatePrimitive>> key_manager;
  {
    TestPublicKeyTypeManager public_km;
    key_manager =
        MakePrivateKeyManager<PrivatePrimitive>(&private_km, &public_km);
    // Let the public_km go out of scope; the key_manager should still work.
  }

  EcdsaKeyFormat key_format;
  key_format.mutable_params()->set_encoding(EcdsaSignatureEncoding::DER);
  auto key = key_manager->get_key_factory().NewKey(key_format).ValueOrDie();
  EXPECT_THAT(
      dynamic_cast<EcdsaPrivateKey&>(*key).public_key().params().encoding(),
      Eq(EcdsaSignatureEncoding::DER));
}

}  // namespace

}  // namespace internal
}  // namespace tink
}  // namespace crypto
