// 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 "tink/util/fake_kms_client.h" #include #include #include #include #include "gtest/gtest.h" #include "tink/aead/aead_config.h" #include "tink/aead/aead_key_templates.h" #include "tink/util/status.h" #include "tink/util/statusor.h" #include "tink/util/test_matchers.h" #include "tink/util/test_util.h" #include "proto/kms_aead.pb.h" #include "proto/kms_envelope.pb.h" using google::crypto::tink::KeyTemplate; using google::crypto::tink::KmsAeadKeyFormat; using google::crypto::tink::KmsEnvelopeAeadKeyFormat; using google::crypto::tink::OutputPrefixType; namespace crypto { namespace tink { namespace test { namespace { // TODO(b/174740983) Add this function to aead_key_templates. KeyTemplate NewKmsAeadKeyTemplate(std::string key_uri) { KeyTemplate key_template; key_template.set_type_url( "type.googleapis.com/google.crypto.tink.KmsAeadKey"); key_template.set_output_prefix_type(OutputPrefixType::TINK); KmsAeadKeyFormat key_format; key_format.set_key_uri(key_uri); key_format.SerializeToString(key_template.mutable_value()); return key_template; } // TODO(b/174740983) Add this function to aead_key_templates. KeyTemplate NewKmsEnvelopeKeyTemplate(std::string key_uri, const KeyTemplate& dek_template) { KeyTemplate key_template; key_template.set_type_url( "type.googleapis.com/google.crypto.tink.KmsEnvelopeAeadKey"); key_template.set_output_prefix_type(OutputPrefixType::TINK); KmsEnvelopeAeadKeyFormat key_format; key_format.set_kek_uri(key_uri); key_format.mutable_dek_template()->MergeFrom(dek_template); key_format.SerializeToString(key_template.mutable_value()); return key_template; } class FakeKmsClientTest : public ::testing::Test { protected: static void SetUpTestSuite() { ASSERT_TRUE(AeadConfig::Register().ok()); } }; TEST_F(FakeKmsClientTest, CreateNewAeadSuccess) { auto uri_result = FakeKmsClient::CreateFakeKeyUri(); EXPECT_TRUE(uri_result.ok()) << uri_result.status(); std::string key_uri = uri_result.value(); auto client_result = FakeKmsClient::New(key_uri, ""); EXPECT_TRUE(client_result.ok()) << client_result.status(); auto client = std::move(client_result.value()); EXPECT_TRUE(client->DoesSupport(key_uri)); auto aead_result = client->GetAead(key_uri); EXPECT_TRUE(aead_result.ok()) << aead_result.status(); auto aead = std::move(aead_result.value()); std::string plaintext = "some_plaintext"; std::string aad = "some_aad"; auto encrypt_result = aead->Encrypt(plaintext, aad); EXPECT_TRUE(encrypt_result.ok()) << encrypt_result.status(); std::string ciphertext = encrypt_result.value(); auto decrypt_result = aead->Decrypt(ciphertext, aad); EXPECT_TRUE(decrypt_result.ok()) << decrypt_result.status(); EXPECT_EQ(plaintext, decrypt_result.value()); } TEST_F(FakeKmsClientTest, ClientIsBound) { std::string key_uri = "fake-kms://" "CL3oi0kSVwpMCjB0eXBlLmdvb2dsZWFwaXMuY29tL2dvb2dsZS5jcnlwdG8udGluay5BZXNF" "YXhLZXkSFhICCBAaEPFnQNgtxEG0vEek8bBfgL8YARABGL3oi0kgAQ"; auto client_result = FakeKmsClient::New(key_uri, ""); EXPECT_TRUE(client_result.ok()) << client_result.status(); auto client = std::move(client_result.value()); // No other key_uri is accepted, even a valid one. std::string another_key_uri = "fake-kms://" "CO3y2NgHElgKTAowdHlwZS5nb29nbGVhcGlzLmNvbS9nb29nbGUuY3J5cHRvLnRpbmsuQWVz" "RWF4S2V5EhYSAggQGhALi4dQMjUR0faRYElRXi__GAEQARjt8tjYByAB"; EXPECT_FALSE(client->DoesSupport(another_key_uri)); auto aead_result = client->GetAead(another_key_uri); EXPECT_FALSE(aead_result.ok()); } TEST_F(FakeKmsClientTest, ClientIsUnbound) { auto client_result = FakeKmsClient::New("", ""); EXPECT_TRUE(client_result.ok()) << client_result.status(); auto client = std::move(client_result.value()); // All valid 'fake-kms' key_uris are accepted. std::string uri = "fake-kms://" "CL3oi0kSVwpMCjB0eXBlLmdvb2dsZWFwaXMuY29tL2dvb2dsZS5jcnlwdG8udGluay5BZXNF" "YXhLZXkSFhICCBAaEPFnQNgtxEG0vEek8bBfgL8YARABGL3oi0kgAQ"; EXPECT_TRUE(client->DoesSupport(uri)); auto aead_result = client->GetAead(uri); EXPECT_TRUE(aead_result.ok()); std::string another_uri = "fake-kms://" "CO3y2NgHElgKTAowdHlwZS5nb29nbGVhcGlzLmNvbS9nb29nbGUuY3J5cHRvLnRpbmsuQWVz" "RWF4S2V5EhYSAggQGhALi4dQMjUR0faRYElRXi__GAEQARjt8tjYByAB"; EXPECT_TRUE(client->DoesSupport(another_uri)); auto another_aead_result = client->GetAead(another_uri); EXPECT_TRUE(another_aead_result.ok()) << another_aead_result.status(); } TEST_F(FakeKmsClientTest, RegisterAndEncryptDecryptWithKmsAead) { auto uri_result = FakeKmsClient::CreateFakeKeyUri(); EXPECT_TRUE(uri_result.ok()) << uri_result.status(); std::string key_uri = uri_result.value(); auto status = FakeKmsClient::RegisterNewClient(key_uri, ""); EXPECT_THAT(status, IsOk()); KeyTemplate key_template = NewKmsAeadKeyTemplate(key_uri); auto handle_result = KeysetHandle::GenerateNew(key_template); EXPECT_TRUE(handle_result.ok()) << handle_result.status(); auto aead_result = handle_result.value()->GetPrimitive(); EXPECT_TRUE(aead_result.ok()) << aead_result.status(); auto aead = std::move(aead_result.value()); std::string plaintext = "some_plaintext"; std::string aad = "some_aad"; auto encrypt_result = aead->Encrypt(plaintext, aad); EXPECT_TRUE(encrypt_result.ok()) << encrypt_result.status(); std::string ciphertext = encrypt_result.value(); auto decrypt_result = aead->Decrypt(ciphertext, aad); EXPECT_TRUE(decrypt_result.ok()) << decrypt_result.status(); EXPECT_EQ(plaintext, decrypt_result.value()); } TEST_F(FakeKmsClientTest, RegisterAndEncryptDecryptWithKmsEnvelopeAead) { auto uri_result = FakeKmsClient::CreateFakeKeyUri(); EXPECT_TRUE(uri_result.ok()) << uri_result.status(); std::string key_uri = uri_result.value(); auto status = FakeKmsClient::RegisterNewClient(key_uri, ""); EXPECT_THAT(status, IsOk()); KeyTemplate key_template = NewKmsEnvelopeKeyTemplate(key_uri, AeadKeyTemplates::Aes128Gcm()); auto handle_result = KeysetHandle::GenerateNew(key_template); EXPECT_TRUE(handle_result.ok()) << handle_result.status(); auto aead_result = handle_result.value()->GetPrimitive(); EXPECT_TRUE(aead_result.ok()) << aead_result.status(); auto aead = std::move(aead_result.value()); std::string plaintext = "some_plaintext"; std::string aad = "some_aad"; auto encrypt_result = aead->Encrypt(plaintext, aad); EXPECT_TRUE(encrypt_result.ok()) << encrypt_result.status(); std::string ciphertext = encrypt_result.value(); auto decrypt_result = aead->Decrypt(ciphertext, aad); EXPECT_TRUE(decrypt_result.ok()) << decrypt_result.status(); EXPECT_EQ(plaintext, decrypt_result.value()); } // TODO(b/174740983): Add test where an unbounded KeyClient is registered. // This is not yet implemented as it would break the isolation of the tests: // Once a unbounded client is registered, it can't currently be unregistered. } // namespace } // namespace test } // namespace tink } // namespace crypto