1 // Copyright 2019 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 ///////////////////////////////////////////////////////////////////////////////
16 #include "tink/core/private_key_manager_impl.h"
17
18 #include <memory>
19 #include <string>
20
21 #include "gmock/gmock.h"
22 #include "gtest/gtest.h"
23 #include "absl/status/status.h"
24 #include "tink/core/key_manager_impl.h"
25 #include "tink/core/private_key_type_manager.h"
26 #include "tink/registry.h"
27 #include "tink/subtle/aes_gcm_boringssl.h"
28 #include "tink/subtle/random.h"
29 #include "tink/util/status.h"
30 #include "tink/util/statusor.h"
31 #include "tink/util/test_matchers.h"
32 #include "tink/util/test_util.h"
33 #include "tink/util/validation.h"
34 #include "proto/ecdsa.pb.h"
35
36 namespace crypto {
37 namespace tink {
38 namespace internal {
39 namespace {
40
41 using ::crypto::tink::test::StatusIs;
42 using ::google::crypto::tink::EcdsaKeyFormat;
43 using ::google::crypto::tink::EcdsaPrivateKey;
44 using ::google::crypto::tink::EcdsaPublicKey;
45 using ::google::crypto::tink::EcdsaSignatureEncoding;
46 using ::testing::Eq;
47 using ::testing::HasSubstr;
48 using ::testing::Return;
49
50 } // namespace
51
52 // Placeholders for the primitives. We don't really want to test anything with
53 // these except that things compile and List<PrivatePrimitive> is never confused
54 // with List<PublicPrimitive> in private_key_manager_impl.
55 // NOTE: These are outside of the anonymous namespace to allow compiling with
56 // MSVC.
57 class PrivatePrimitive {};
58 class PublicPrimitive {};
59
60 namespace {
61
62 class ExamplePrivateKeyTypeManager
63 : public PrivateKeyTypeManager<EcdsaPrivateKey, EcdsaKeyFormat,
64 EcdsaPublicKey, List<PrivatePrimitive>> {
65 public:
66 class PrivatePrimitiveFactory : public PrimitiveFactory<PrivatePrimitive> {
67 public:
Create(const EcdsaPrivateKey & key) const68 crypto::tink::util::StatusOr<std::unique_ptr<PrivatePrimitive>> Create(
69 const EcdsaPrivateKey& key) const override {
70 return util::Status(absl::StatusCode::kUnimplemented, "Not implemented");
71 }
72 };
73
ExamplePrivateKeyTypeManager()74 ExamplePrivateKeyTypeManager()
75 : PrivateKeyTypeManager(absl::make_unique<PrivatePrimitiveFactory>()) {}
76
key_material_type() const77 google::crypto::tink::KeyData::KeyMaterialType key_material_type()
78 const override {
79 return google::crypto::tink::KeyData::ASYMMETRIC_PRIVATE;
80 }
81
82 MOCK_METHOD(uint32_t, get_version, (), (const, override));
83
84 // We mock out ValidateKey and ValidateKeyFormat so that we can easily test
85 // proper behavior in case they return an error.
86 MOCK_METHOD(crypto::tink::util::Status, ValidateKey,
87 (const EcdsaPrivateKey& key), (const, override));
88 MOCK_METHOD(crypto::tink::util::Status, ValidateKeyFormat,
89 (const EcdsaKeyFormat& key), (const, override));
90
get_key_type() const91 const std::string& get_key_type() const override { return kKeyType; }
92
CreateKey(const EcdsaKeyFormat & key_format) const93 crypto::tink::util::StatusOr<EcdsaPrivateKey> CreateKey(
94 const EcdsaKeyFormat& key_format) const override {
95 EcdsaPublicKey public_key;
96 *public_key.mutable_params() = key_format.params();
97 EcdsaPrivateKey result;
98 *result.mutable_public_key() = public_key;
99 return result;
100 }
101
GetPublicKey(const EcdsaPrivateKey & private_key) const102 crypto::tink::util::StatusOr<EcdsaPublicKey> GetPublicKey(
103 const EcdsaPrivateKey& private_key) const override {
104 return private_key.public_key();
105 }
106
107 private:
108 const std::string kKeyType =
109 "type.googleapis.com/google.crypto.tink.EcdsaPublicKey";
110 };
111
112 class TestPublicKeyTypeManager
113 : public KeyTypeManager<EcdsaPublicKey, void, List<PublicPrimitive>> {
114 public:
115 class PublicPrimitiveFactory : public PrimitiveFactory<PublicPrimitive> {
116 public:
Create(const EcdsaPublicKey & key) const117 crypto::tink::util::StatusOr<std::unique_ptr<PublicPrimitive>> Create(
118 const EcdsaPublicKey& key) const override {
119 return util::Status(absl::StatusCode::kUnimplemented, "Not implemented");
120 }
121 };
122
TestPublicKeyTypeManager()123 TestPublicKeyTypeManager()
124 : KeyTypeManager(absl::make_unique<PublicPrimitiveFactory>()) {}
125
key_material_type() const126 google::crypto::tink::KeyData::KeyMaterialType key_material_type()
127 const override {
128 return google::crypto::tink::KeyData::ASYMMETRIC_PRIVATE;
129 }
130
131 MOCK_METHOD(uint32_t, get_version, (), (const, override));
132
133 // We mock out ValidateKey and ValidateKeyFormat so that we can easily test
134 // proper behavior in case they return an error.
135 MOCK_METHOD(crypto::tink::util::Status, ValidateKey,
136 (const EcdsaPublicKey& key), (const, override));
137
get_key_type() const138 const std::string& get_key_type() const override { return kKeyType; }
139
140 private:
141 const std::string kKeyType =
142 "type.googleapis.com/google.crypto.tink.EcdsaPublicKey";
143 };
144
TEST(PrivateKeyManagerImplTest,FactoryNewKeyFromMessage)145 TEST(PrivateKeyManagerImplTest, FactoryNewKeyFromMessage) {
146 ExamplePrivateKeyTypeManager private_km;
147 TestPublicKeyTypeManager public_km;
148 std::unique_ptr<KeyManager<PrivatePrimitive>> key_manager =
149 MakePrivateKeyManager<PrivatePrimitive>(&private_km, &public_km);
150
151 EcdsaKeyFormat key_format;
152 key_format.mutable_params()->set_encoding(EcdsaSignatureEncoding::DER);
153 auto key = key_manager->get_key_factory().NewKey(key_format).value();
154 EXPECT_THAT(
155 dynamic_cast<EcdsaPrivateKey&>(*key).public_key().params().encoding(),
156 Eq(EcdsaSignatureEncoding::DER));
157 }
158
TEST(PrivateKeyManagerImplTest,GetPublicKeyData)159 TEST(PrivateKeyManagerImplTest, GetPublicKeyData) {
160 ExamplePrivateKeyTypeManager private_km;
161 TestPublicKeyTypeManager public_km;
162 std::unique_ptr<KeyManager<PrivatePrimitive>> key_manager =
163 MakePrivateKeyManager<PrivatePrimitive>(&private_km, &public_km);
164
165 EcdsaPrivateKey private_key;
166 private_key.mutable_public_key()->mutable_params()->set_encoding(
167 EcdsaSignatureEncoding::DER);
168
169 auto key_data =
170 dynamic_cast<const PrivateKeyFactory&>(key_manager->get_key_factory())
171 .GetPublicKeyData(private_key.SerializeAsString())
172 .value();
173 ASSERT_THAT(key_data->type_url(), Eq(public_km.get_key_type()));
174 EcdsaPublicKey public_key;
175 public_key.ParseFromString(key_data->value());
176 EXPECT_THAT(public_key.params().encoding(), Eq(EcdsaSignatureEncoding::DER));
177 }
178
TEST(PrivateKeyManagerImplTest,GetPublicKeyDataValidatePrivateKey)179 TEST(PrivateKeyManagerImplTest, GetPublicKeyDataValidatePrivateKey) {
180 ExamplePrivateKeyTypeManager private_km;
181 TestPublicKeyTypeManager public_km;
182 EXPECT_CALL(private_km, ValidateKey)
183 .WillOnce(Return(util::Status(absl::StatusCode::kOutOfRange,
184 "GetPublicKeyDataValidatePrivateKey")));
185
186 std::unique_ptr<KeyManager<PrivatePrimitive>> key_manager =
187 MakePrivateKeyManager<PrivatePrimitive>(&private_km, &public_km);
188
189 EXPECT_THAT(
190 dynamic_cast<const PrivateKeyFactory&>(key_manager->get_key_factory())
191 .GetPublicKeyData(EcdsaPrivateKey().SerializeAsString())
192 .status(),
193 StatusIs(absl::StatusCode::kOutOfRange,
194 HasSubstr("GetPublicKeyDataValidatePrivateKey")));
195 }
196
TEST(PrivateKeyManagerImplTest,PublicKeyManagerCanHaveShortLifetime)197 TEST(PrivateKeyManagerImplTest, PublicKeyManagerCanHaveShortLifetime) {
198 ExamplePrivateKeyTypeManager private_km;
199 std::unique_ptr<KeyManager<PrivatePrimitive>> key_manager;
200 {
201 TestPublicKeyTypeManager public_km;
202 key_manager =
203 MakePrivateKeyManager<PrivatePrimitive>(&private_km, &public_km);
204 // Let the public_km go out of scope; the key_manager should still work.
205 }
206
207 EcdsaKeyFormat key_format;
208 key_format.mutable_params()->set_encoding(EcdsaSignatureEncoding::DER);
209 auto key = key_manager->get_key_factory().NewKey(key_format).value();
210 EXPECT_THAT(
211 dynamic_cast<EcdsaPrivateKey&>(*key).public_key().params().encoding(),
212 Eq(EcdsaSignatureEncoding::DER));
213 }
214
215 } // namespace
216
217 } // namespace internal
218 } // namespace tink
219 } // namespace crypto
220