// Copyright 2020 Google LLC // // 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 "keyset_impl.h" #include #include #include #include #include #include "gmock/gmock.h" #include "gtest/gtest.h" #include "tink/aead/aead_key_templates.h" #include "tink/binary_keyset_reader.h" #include "tink/binary_keyset_writer.h" #include "tink/cleartext_keyset_handle.h" #include "tink/config/tink_config.h" #include "tink/hybrid/hybrid_key_templates.h" #include "tink/util/test_matchers.h" #include "proto/testing_api.grpc.pb.h" namespace crypto { namespace tink { namespace { using ::crypto::tink::AeadKeyTemplates; using ::crypto::tink::BinaryKeysetReader; using ::crypto::tink::BinaryKeysetWriter; using ::crypto::tink::CleartextKeysetHandle; using ::crypto::tink::HybridKeyTemplates; using ::google::crypto::tink::KeyTemplate; using ::testing::Eq; using ::testing::IsEmpty; using ::crypto::tink::test::IsOk; using ::tink_testing_api::KeysetFromJsonRequest; using ::tink_testing_api::KeysetFromJsonResponse; using ::tink_testing_api::KeysetGenerateRequest; using ::tink_testing_api::KeysetGenerateResponse; using ::tink_testing_api::KeysetPublicRequest; using ::tink_testing_api::KeysetPublicResponse; using ::tink_testing_api::KeysetReadEncryptedRequest; using ::tink_testing_api::KeysetReadEncryptedResponse; using ::tink_testing_api::KeysetToJsonRequest; using ::tink_testing_api::KeysetToJsonResponse; using ::tink_testing_api::KeysetWriteEncryptedRequest; using ::tink_testing_api::KeysetWriteEncryptedResponse; class KeysetImplTest : public ::testing::Test { protected: static void SetUpTestSuite() { ASSERT_TRUE(TinkConfig::Register().ok()); } }; TEST_F(KeysetImplTest, GenerateSuccess) { tink_testing_api::KeysetImpl keyset; const KeyTemplate& key_template = AeadKeyTemplates::Aes128Eax(); KeysetGenerateRequest request; std::string templ; EXPECT_TRUE(key_template.SerializeToString(&templ)); request.set_template_(templ); KeysetGenerateResponse response; EXPECT_TRUE(keyset.Generate(nullptr, &request, &response).ok()); EXPECT_THAT(response.err(), IsEmpty()); auto reader_result = BinaryKeysetReader::New(response.keyset()); ASSERT_TRUE(reader_result.ok()); auto handle_result = CleartextKeysetHandle::Read(std::move(reader_result.value())); EXPECT_TRUE(handle_result.ok()); } TEST_F(KeysetImplTest, GenerateFail) { tink_testing_api::KeysetImpl keyset; KeysetGenerateRequest request; request.set_template_("bad template"); KeysetGenerateResponse response; EXPECT_TRUE(keyset.Generate(nullptr, &request, &response).ok()); EXPECT_THAT(response.err(), Not(IsEmpty())); } util::StatusOr AeadKeyset() { util::StatusOr> handle = KeysetHandle::GenerateNew(AeadKeyTemplates::Aes128Gcm()); if (!handle.ok()) { return handle.status(); } std::stringbuf keyset; util::StatusOr> writer = BinaryKeysetWriter::New(absl::make_unique(&keyset)); if (!handle.ok()) { return handle.status(); } util::Status status = CleartextKeysetHandle::Write(writer->get(), **handle); if (!status.ok()) { return status; } return keyset.str(); } util::StatusOr ValidPrivateKeyset() { util::StatusOr> handle = KeysetHandle::GenerateNew( HybridKeyTemplates::EciesP256HkdfHmacSha256Aes128Gcm()); if (!handle.ok()) { return handle.status(); } std::stringbuf keyset; util::StatusOr> writer = BinaryKeysetWriter::New(absl::make_unique(&keyset)); if (!writer.ok()) { return writer.status(); } util::Status status = CleartextKeysetHandle::Write(writer->get(), **handle); if (!status.ok()) { return status; } return keyset.str(); } TEST_F(KeysetImplTest, PublicSuccess) { tink_testing_api::KeysetImpl keyset; util::StatusOr private_keyset = ValidPrivateKeyset(); ASSERT_THAT(private_keyset.status(), IsOk()); KeysetPublicRequest request; request.set_private_keyset(*private_keyset); KeysetPublicResponse response; EXPECT_TRUE(keyset.Public(nullptr, &request, &response).ok()); EXPECT_THAT(response.err(), IsEmpty()); auto reader_result = BinaryKeysetReader::New(response.public_keyset()); ASSERT_TRUE(reader_result.ok()); auto public_handle_result = CleartextKeysetHandle::Read(std::move(reader_result.value())); EXPECT_TRUE(public_handle_result.ok()); } TEST_F(KeysetImplTest, PublicFail) { tink_testing_api::KeysetImpl keyset; KeysetPublicRequest request; request.set_private_keyset("bad keyset"); KeysetPublicResponse response; EXPECT_TRUE(keyset.Public(nullptr, &request, &response).ok()); EXPECT_THAT(response.err(), Not(IsEmpty())); } TEST_F(KeysetImplTest, FromJsonSuccess) { tink_testing_api::KeysetImpl keyset; std::string json_keyset = R""""( { "primaryKeyId": 42, "key": [ { "keyData": { "typeUrl": "type.googleapis.com/google.crypto.tink.FakeKeyType", "keyMaterialType": "SYMMETRIC", "value": "AFakeTestKeyValue1234567" }, "outputPrefixType": "TINK", "keyId": 42, "status": "ENABLED" } ] })""""; KeysetFromJsonRequest from_request; from_request.set_json_keyset(json_keyset); KeysetFromJsonResponse from_response; EXPECT_TRUE(keyset.FromJson(nullptr, &from_request, &from_response).ok()); EXPECT_THAT(from_response.err(), IsEmpty()); std::string output = from_response.keyset(); auto reader_result = BinaryKeysetReader::New(from_response.keyset()); EXPECT_TRUE(reader_result.ok()); auto keyset_proto_result = reader_result.value()->Read(); EXPECT_TRUE(keyset_proto_result.ok()); EXPECT_THAT(keyset_proto_result.value()->primary_key_id(), Eq(42)); } TEST_F(KeysetImplTest, ToFromJsonSuccess) { tink_testing_api::KeysetImpl keyset; util::StatusOr private_keyset = ValidPrivateKeyset(); EXPECT_THAT(private_keyset.status(), IsOk()); KeysetToJsonRequest to_request; to_request.set_keyset(*private_keyset); KeysetToJsonResponse to_response; EXPECT_TRUE(keyset.ToJson(nullptr, &to_request, &to_response).ok()); EXPECT_THAT(to_response.err(), IsEmpty()); std::string json_keyset = to_response.json_keyset(); KeysetFromJsonRequest from_request; from_request.set_json_keyset(json_keyset); KeysetFromJsonResponse from_response; EXPECT_TRUE(keyset.FromJson(nullptr, &from_request, &from_response).ok()); EXPECT_THAT(from_response.err(), IsEmpty()); std::string output = from_response.keyset(); EXPECT_THAT(from_response.keyset(), Eq(*private_keyset)); } TEST_F(KeysetImplTest, ToJsonFail) { tink_testing_api::KeysetImpl keyset; KeysetToJsonRequest request; request.set_keyset("bad keyset"); KeysetToJsonResponse response; EXPECT_TRUE(keyset.ToJson(nullptr, &request, &response).ok()); EXPECT_THAT(response.err(), Not(IsEmpty())); } TEST_F(KeysetImplTest, FromJsonFail) { tink_testing_api::KeysetImpl keyset; KeysetFromJsonRequest request; request.set_json_keyset("bad json keyset"); KeysetFromJsonResponse response; EXPECT_TRUE(keyset.FromJson(nullptr, &request, &response).ok()); EXPECT_THAT(response.err(), Not(IsEmpty())); } TEST_F(KeysetImplTest, ReadWriteEncryptedKeysetSuccess) { tink_testing_api::KeysetImpl keyset_impl; util::StatusOr master_keyset = AeadKeyset(); ASSERT_THAT(master_keyset.status(), IsOk()); util::StatusOr keyset = AeadKeyset(); ASSERT_THAT(master_keyset.status(), IsOk()); KeysetWriteEncryptedRequest write_request; write_request.set_keyset(*keyset); write_request.set_master_keyset(*master_keyset); write_request.set_keyset_writer_type(tink_testing_api::KEYSET_WRITER_BINARY); KeysetWriteEncryptedResponse write_response; ASSERT_TRUE( keyset_impl .WriteEncrypted(/*context=*/nullptr, &write_request, &write_response) .ok()); ASSERT_THAT(write_response.err(), IsEmpty()); KeysetReadEncryptedRequest read_request; read_request.set_encrypted_keyset(write_response.encrypted_keyset()); read_request.set_master_keyset(*master_keyset); read_request.set_keyset_reader_type(tink_testing_api::KEYSET_READER_BINARY); KeysetReadEncryptedResponse read_response; ASSERT_TRUE( keyset_impl .ReadEncrypted(/*context=*/nullptr, &read_request, &read_response) .ok()); EXPECT_THAT(read_response.err(), IsEmpty()); EXPECT_EQ(read_response.keyset(), *keyset); } TEST_F(KeysetImplTest, ReadWriteEncryptedWithAssociatedDataKeysetSuccess) { tink_testing_api::KeysetImpl keyset_impl; util::StatusOr master_keyset = AeadKeyset(); ASSERT_THAT(master_keyset.status(), IsOk()); util::StatusOr keyset = AeadKeyset(); ASSERT_THAT(keyset.status(), IsOk()); std::string associated_data = "associated_data"; KeysetWriteEncryptedRequest write_request; write_request.set_keyset(*keyset); write_request.set_master_keyset(*master_keyset); write_request.mutable_associated_data()->set_value(associated_data); write_request.set_keyset_writer_type(tink_testing_api::KEYSET_WRITER_BINARY); KeysetWriteEncryptedResponse write_response; ASSERT_TRUE( keyset_impl .WriteEncrypted(/*context=*/nullptr, &write_request, &write_response) .ok()); ASSERT_THAT(write_response.err(), IsEmpty()); KeysetReadEncryptedRequest read_request; read_request.set_encrypted_keyset(write_response.encrypted_keyset()); read_request.set_master_keyset(*master_keyset); read_request.mutable_associated_data()->set_value(associated_data); read_request.set_keyset_reader_type(tink_testing_api::KEYSET_READER_BINARY); KeysetReadEncryptedResponse read_response; ASSERT_TRUE( keyset_impl .ReadEncrypted(/*context=*/nullptr, &read_request, &read_response) .ok()); EXPECT_THAT(read_response.err(), IsEmpty()); EXPECT_EQ(read_response.keyset(), *keyset); } TEST_F(KeysetImplTest, WriteEncryptedKeysetFail) { tink_testing_api::KeysetImpl keyset_impl; util::StatusOr master_keyset = AeadKeyset(); ASSERT_THAT(master_keyset.status(), IsOk()); KeysetWriteEncryptedRequest write_request; write_request.set_keyset("invalid"); write_request.set_master_keyset(*master_keyset); write_request.set_keyset_writer_type(tink_testing_api::KEYSET_WRITER_BINARY); KeysetWriteEncryptedResponse write_response; ASSERT_TRUE( keyset_impl .WriteEncrypted(/*context=*/nullptr, &write_request, &write_response) .ok()); EXPECT_THAT(write_response.err(), Not(IsEmpty())); } TEST_F(KeysetImplTest, ReadEncryptedKeysetFail) { tink_testing_api::KeysetImpl keyset_impl; util::StatusOr master_keyset = AeadKeyset(); ASSERT_THAT(master_keyset.status(), IsOk()); KeysetReadEncryptedRequest read_request; read_request.set_encrypted_keyset("invalid"); read_request.set_master_keyset(*master_keyset); read_request.set_keyset_reader_type(tink_testing_api::KEYSET_READER_BINARY); KeysetReadEncryptedResponse read_response; ASSERT_TRUE( keyset_impl .ReadEncrypted(/*context=*/nullptr, &read_request, &read_response) .ok()); EXPECT_THAT(read_response.err(), Not(IsEmpty())); } } // namespace } // namespace tink } // namespace crypto