1 // Copyright 2017 Google Inc.
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
17 #include "tink/signature/ecdsa_sign_key_manager.h"
18
19 #include <memory>
20 #include <string>
21 #include <utility>
22
23 #include "absl/memory/memory.h"
24 #include "absl/status/status.h"
25 #include "absl/strings/string_view.h"
26 #include "tink/config/tink_fips.h"
27 #include "tink/internal/ec_util.h"
28 #include "tink/public_key_sign.h"
29 #include "tink/signature/ecdsa_verify_key_manager.h"
30 #include "tink/subtle/ecdsa_sign_boringssl.h"
31 #include "tink/util/enums.h"
32 #include "tink/util/errors.h"
33 #include "tink/util/input_stream_util.h"
34 #include "tink/util/protobuf_helper.h"
35 #include "tink/util/secret_data.h"
36 #include "tink/util/status.h"
37 #include "tink/util/statusor.h"
38 #include "tink/util/validation.h"
39 #include "proto/ecdsa.pb.h"
40
41 namespace crypto {
42 namespace tink {
43
44 using crypto::tink::util::Enums;
45 using crypto::tink::util::Status;
46 using crypto::tink::util::StatusOr;
47 using google::crypto::tink::EcdsaKeyFormat;
48 using google::crypto::tink::EcdsaPrivateKey;
49 using google::crypto::tink::EcdsaPublicKey;
50
CreateKey(const EcdsaKeyFormat & ecdsa_key_format) const51 StatusOr<EcdsaPrivateKey> EcdsaSignKeyManager::CreateKey(
52 const EcdsaKeyFormat& ecdsa_key_format) const {
53 // Generate new EC key.
54 auto ec_key_result = internal::NewEcKey(
55 util::Enums::ProtoToSubtle(ecdsa_key_format.params().curve()));
56 if (!ec_key_result.ok()) return ec_key_result.status();
57 auto ec_key = ec_key_result.value();
58
59 // Build EcdsaPrivateKey.
60 EcdsaPrivateKey ecdsa_private_key;
61 ecdsa_private_key.set_version(get_version());
62 ecdsa_private_key.set_key_value(
63 std::string(util::SecretDataAsStringView(ec_key.priv)));
64 auto ecdsa_public_key = ecdsa_private_key.mutable_public_key();
65 ecdsa_public_key->set_version(get_version());
66 ecdsa_public_key->set_x(ec_key.pub_x);
67 ecdsa_public_key->set_y(ec_key.pub_y);
68 *(ecdsa_public_key->mutable_params()) = ecdsa_key_format.params();
69 return ecdsa_private_key;
70 }
71
DeriveKey(const EcdsaKeyFormat & ecdsa_key_format,InputStream * input_stream) const72 StatusOr<EcdsaPrivateKey> EcdsaSignKeyManager::DeriveKey(
73 const EcdsaKeyFormat& ecdsa_key_format, InputStream* input_stream) const {
74 if (IsFipsModeEnabled()) {
75 return crypto::tink::util::Status(
76 absl::StatusCode::kInternal,
77 "Deriving EC keys is not allowed in FIPS mode.");
78 }
79
80 util::Status status =
81 ValidateVersion(ecdsa_key_format.version(), get_version());
82 if (!status.ok()) {
83 return status;
84 }
85
86 // Extract enough random bytes from the input_stream to match the security
87 // level of the EC. Note that the input_stream here must come from a PRF
88 // and will not use more bytes than required by the security level of the EC.
89 // Providing an input_stream which has more bytes available than required,
90 // will result in the same keys being generated.
91 int random_bytes_used = 0;
92 switch (ecdsa_key_format.params().curve()) {
93 case google::crypto::tink::EllipticCurveType::NIST_P256:
94 random_bytes_used = 16;
95 break;
96 case google::crypto::tink::EllipticCurveType::NIST_P384:
97 random_bytes_used = 24;
98 break;
99 case google::crypto::tink::EllipticCurveType::NIST_P521:
100 random_bytes_used = 32;
101 break;
102 default:
103 return crypto::tink::util::Status(
104 absl::StatusCode::kInvalidArgument,
105 "Curve does not support key derivation.");
106 }
107
108 crypto::tink::util::StatusOr<util::SecretData> randomness =
109 ReadSecretBytesFromStream(random_bytes_used, input_stream);
110 if (!randomness.ok()) {
111 if (randomness.status().code() == absl::StatusCode::kOutOfRange) {
112 return crypto::tink::util::Status(
113 absl::StatusCode::kInvalidArgument,
114 "Could not get enough pseudorandomness from input stream");
115 }
116 return randomness.status();
117 }
118
119 // Generate new EC key from the seed.
120 crypto::tink::util::StatusOr<internal::EcKey> ec_key =
121 internal::NewEcKey(
122 util::Enums::ProtoToSubtle(ecdsa_key_format.params().curve()),
123 *randomness);
124
125 if (!ec_key.ok()) {
126 return ec_key.status();
127 }
128
129 // Build EcdsaPrivateKey.
130 EcdsaPrivateKey ecdsa_private_key;
131 ecdsa_private_key.set_version(get_version());
132 ecdsa_private_key.set_key_value(
133 std::string(util::SecretDataAsStringView(ec_key->priv)));
134 EcdsaPublicKey* ecdsa_public_key = ecdsa_private_key.mutable_public_key();
135 ecdsa_public_key->set_version(get_version());
136 ecdsa_public_key->set_x(ec_key->pub_x);
137 ecdsa_public_key->set_y(ec_key->pub_y);
138 *(ecdsa_public_key->mutable_params()) = ecdsa_key_format.params();
139 return ecdsa_private_key;
140 }
141
142 StatusOr<std::unique_ptr<PublicKeySign>>
Create(const EcdsaPrivateKey & ecdsa_private_key) const143 EcdsaSignKeyManager::PublicKeySignFactory::Create(
144 const EcdsaPrivateKey& ecdsa_private_key) const {
145 const EcdsaPublicKey& public_key = ecdsa_private_key.public_key();
146 internal::EcKey ec_key;
147 ec_key.curve = Enums::ProtoToSubtle(public_key.params().curve());
148 ec_key.pub_x = public_key.x();
149 ec_key.pub_y = public_key.y();
150 ec_key.priv = util::SecretDataFromStringView(ecdsa_private_key.key_value());
151 auto result = subtle::EcdsaSignBoringSsl::New(
152 ec_key, Enums::ProtoToSubtle(public_key.params().hash_type()),
153 Enums::ProtoToSubtle(public_key.params().encoding()));
154 if (!result.ok()) return result.status();
155 return {std::move(result.value())};
156 }
157
ValidateKey(const EcdsaPrivateKey & key) const158 Status EcdsaSignKeyManager::ValidateKey(const EcdsaPrivateKey& key) const {
159 Status status = ValidateVersion(key.version(), get_version());
160 if (!status.ok()) return status;
161 return EcdsaVerifyKeyManager().ValidateKey(key.public_key());
162 }
163
ValidateKeyFormat(const EcdsaKeyFormat & key_format) const164 Status EcdsaSignKeyManager::ValidateKeyFormat(
165 const EcdsaKeyFormat& key_format) const {
166 if (!key_format.has_params()) {
167 return Status(absl::StatusCode::kInvalidArgument, "Missing params.");
168 }
169 return EcdsaVerifyKeyManager().ValidateParams(key_format.params());
170 }
171
172 } // namespace tink
173 } // namespace crypto
174