// Copyright 2019 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/keyderivation/keyset_deriver_wrapper.h" #include #include #include #include #include "gmock/gmock.h" #include "gtest/gtest.h" #include "absl/status/status.h" #include "tink/cleartext_keyset_handle.h" #include "tink/keyderivation/keyset_deriver.h" #include "tink/primitive_set.h" #include "tink/util/test_matchers.h" #include "proto/tink.pb.h" namespace crypto { namespace tink { namespace { using ::crypto::tink::test::IsOk; using ::crypto::tink::test::StatusIs; using ::google::crypto::tink::Keyset; using ::google::crypto::tink::KeysetInfo; using ::google::crypto::tink::KeyStatusType; using ::google::crypto::tink::OutputPrefixType; using ::testing::Eq; using ::testing::HasSubstr; // TODO(b/255828521): Move this to a shared location once KeysetDeriver is in // the public API. class DummyDeriver : public KeysetDeriver { public: explicit DummyDeriver(absl::string_view name) : name_(name) {} util::StatusOr> DeriveKeyset( absl::string_view salt) const override { Keyset::Key key; key.mutable_key_data()->set_type_url( absl::StrCat(name_.size(), ":", name_, salt)); key.set_status(KeyStatusType::UNKNOWN_STATUS); key.set_key_id(0); key.set_output_prefix_type(OutputPrefixType::UNKNOWN_PREFIX); Keyset keyset; *keyset.add_key() = key; keyset.set_primary_key_id(0); return CleartextKeysetHandle::GetKeysetHandle(keyset); } private: std::string name_; }; TEST(KeysetDeriverWrapperTest, WrapNullptr) { EXPECT_THAT(KeysetDeriverWrapper().Wrap(nullptr).status(), StatusIs(absl::StatusCode::kInternal, HasSubstr("non-NULL"))); } TEST(KeysetDeriverWrapperTest, WrapEmpty) { EXPECT_THAT( KeysetDeriverWrapper() .Wrap(absl::make_unique>()) .status(), StatusIs(absl::StatusCode::kInvalidArgument, HasSubstr("no primary"))); } TEST(KeysetDeriverWrapperTest, WrapNoPrimary) { auto deriver_set = absl::make_unique>(); KeysetInfo::KeyInfo key_info; key_info.set_key_id(1234); key_info.set_status(KeyStatusType::ENABLED); key_info.set_output_prefix_type(OutputPrefixType::TINK); EXPECT_THAT( deriver_set->AddPrimitive(absl::make_unique(""), key_info) .status(), IsOk()); EXPECT_THAT( KeysetDeriverWrapper().Wrap(std::move(deriver_set)).status(), StatusIs(absl::StatusCode::kInvalidArgument, HasSubstr("no primary"))); } TEST(KeysetDeriverWrapperTest, WrapSingle) { auto deriver_set = absl::make_unique>(); KeysetInfo::KeyInfo key_info; key_info.set_key_id(1234); key_info.set_status(KeyStatusType::ENABLED); key_info.set_output_prefix_type(OutputPrefixType::TINK); key_info.set_type_url( "type.googleapis.com/google.crypto.tink.PrfBasedDeriverKey"); auto entry_or = deriver_set->AddPrimitive( absl::make_unique("wrap_single_key"), key_info); ASSERT_THAT(entry_or, IsOk()); EXPECT_THAT(deriver_set->set_primary(entry_or.value()), IsOk()); auto wrapper_deriver_or = KeysetDeriverWrapper().Wrap(std::move(deriver_set)); ASSERT_THAT(wrapper_deriver_or, IsOk()); auto derived_keyset_or = wrapper_deriver_or.value()->DeriveKeyset("wrap_single_salt"); ASSERT_THAT(derived_keyset_or, IsOk()); Keyset keyset = CleartextKeysetHandle::GetKeyset(*derived_keyset_or.value()); EXPECT_THAT(keyset.primary_key_id(), Eq(1234)); ASSERT_THAT(keyset.key_size(), Eq(1)); EXPECT_THAT(keyset.key(0).key_data().type_url(), Eq("15:wrap_single_keywrap_single_salt")); EXPECT_THAT(keyset.key(0).status(), Eq(KeyStatusType::ENABLED)); EXPECT_THAT(keyset.key(0).key_id(), Eq(1234)); EXPECT_THAT(keyset.key(0).output_prefix_type(), Eq(OutputPrefixType::TINK)); } TEST(KeysetDeriverWrapperTest, WrapMultiple) { auto pset = absl::make_unique>(); std::vector key_infos; KeysetInfo::KeyInfo key_info; key_info.set_key_id(1010101); key_info.set_status(KeyStatusType::ENABLED); key_info.set_output_prefix_type(OutputPrefixType::RAW); key_info.set_type_url( "type.googleapis.com/google.crypto.tink.PrfBasedDeriverKey"); ASSERT_THAT( pset->AddPrimitive(absl::make_unique("k1"), key_info) .status(), IsOk()); key_infos.push_back(key_info); key_info.set_key_id(2020202); key_info.set_status(KeyStatusType::ENABLED); key_info.set_output_prefix_type(OutputPrefixType::LEGACY); key_info.set_type_url( "type.googleapis.com/google.crypto.tink.PrfBasedDeriverKey"); util::StatusOr::Entry*> entry = pset->AddPrimitive(absl::make_unique("k2"), key_info); ASSERT_THAT(entry, IsOk()); ASSERT_THAT(pset->set_primary(*entry), IsOk()); key_infos.push_back(key_info); key_info.set_key_id(3030303); key_info.set_status(KeyStatusType::ENABLED); key_info.set_output_prefix_type(OutputPrefixType::TINK); key_info.set_type_url( "type.googleapis.com/google.crypto.tink.PrfBasedDeriverKey"); ASSERT_THAT( pset->AddPrimitive(absl::make_unique("k3"), key_info), IsOk()); key_infos.push_back(key_info); util::StatusOr> wrapper_deriver = KeysetDeriverWrapper().Wrap(std::move(pset)); ASSERT_THAT(wrapper_deriver, IsOk()); util::StatusOr> derived_keyset = (*wrapper_deriver)->DeriveKeyset("salt"); ASSERT_THAT(derived_keyset, IsOk()); Keyset keyset = CleartextKeysetHandle::GetKeyset(**derived_keyset); EXPECT_THAT(keyset.primary_key_id(), Eq(2020202)); ASSERT_THAT(keyset.key_size(), Eq(3)); for (int i = 0; i < keyset.key().size(); i++) { std::string type_url = absl::StrCat("2:k", i + 1, "salt"); EXPECT_THAT(keyset.key(i).key_data().type_url(), Eq(type_url)); Keyset::Key key = keyset.key(i); key_info = key_infos[i]; EXPECT_THAT(key.status(), Eq(key_info.status())); EXPECT_THAT(key.key_id(), Eq(key_info.key_id())); EXPECT_THAT(key.output_prefix_type(), Eq(key_info.output_prefix_type())); } } } // namespace } // namespace tink } // namespace crypto