xref: /aosp_15_r20/external/tink/cc/signature/ecdsa_sign_key_manager.cc (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
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