Botan 3.13.0
Crypto and TLS for C&
p11_ecdsa.cpp
Go to the documentation of this file.
1/*
2* PKCS#11 ECDSA
3* (C) 2016 Daniel Neus, Sirrix AG
4* (C) 2016 Philipp Weber, Sirrix AG
5*
6* Botan is released under the Simplified BSD License (see license.txt)
7*/
8
9#include <botan/p11_ecdsa.h>
10
11#if defined(BOTAN_HAS_ECDSA)
12
13 #include <botan/p11_mechanism.h>
14 #include <botan/pk_ops.h>
15 #include <botan/rng.h>
16 #include <botan/internal/keypair.h>
17 #include <botan/internal/scan_name.h>
18
19namespace Botan::PKCS11 {
20
21ECDSA_PublicKey PKCS11_ECDSA_PublicKey::export_key() const {
22 return ECDSA_PublicKey(domain(), _public_ec_point());
23}
24
25bool PKCS11_ECDSA_PrivateKey::check_key(RandomNumberGenerator& rng, bool strong) const {
26 if(!strong) {
27 return true;
28 }
29
30 const ECDSA_PublicKey pubkey(domain(), public_ec_point());
31 return KeyPair::signature_consistency_check(rng, *this, pubkey, "SHA-256");
32}
33
34ECDSA_PrivateKey PKCS11_ECDSA_PrivateKey::export_key() const {
35 auto priv_key = get_attribute_value(AttributeType::Value);
36
37 Null_RNG rng;
38 return ECDSA_PrivateKey(rng, domain(), BigInt::from_bytes(priv_key));
39}
40
41secure_vector<uint8_t> PKCS11_ECDSA_PrivateKey::private_key_bits() const {
42 return export_key().private_key_bits();
43}
44
45std::unique_ptr<Public_Key> PKCS11_ECDSA_PrivateKey::public_key() const {
46 return std::make_unique<ECDSA_PublicKey>(domain(), public_ec_point());
47}
48
49namespace {
50
51// PKCS#11 ECDSA accepts EMSA1(X) as an alias for X; unwrap so callers like
52// algorithm_identifier() see the normalized hash name (e.g. "SHA-256" instead
53// of "EMSA1(SHA-256)") and produce a registered OID such as ECDSA/SHA-256.
54std::string canonical_ecdsa_hash(std::string_view hash) {
55 const SCAN_Name req((std::string(hash)));
56 if(req.algo_name() == "EMSA1" && req.arg_count() == 1) {
57 return req.arg(0);
58 }
59 return std::string(hash);
60}
61
62class PKCS11_ECDSA_Signature_Operation final : public PK_Ops::Signature {
63 public:
64 PKCS11_ECDSA_Signature_Operation(const PKCS11_ECDSA_PrivateKey& key, std::string_view hash) :
65 PK_Ops::Signature(),
66 m_key(key),
67 m_order_bytes(key.domain().get_order_bytes()),
68 m_mechanism(MechanismWrapper::create_ecdsa_mechanism(hash)),
69 m_hash(canonical_ecdsa_hash(hash)) {}
70
71 void update(std::span<const uint8_t> input) override {
72 if(!m_initialized) {
73 // first call to update: initialize and cache message because we can not determine yet whether a single- or multiple-part operation will be performed
74 m_key.module()->C_SignInit(m_key.session().handle(), m_mechanism.data(), m_key.handle());
75 m_initialized = true;
76 m_first_message.assign(input.begin(), input.end());
77 m_has_first_message = true;
78 return;
79 }
80
81 if(m_has_first_message) {
82 // second call to update: start multiple-part operation
83 m_key.module()->C_SignUpdate(m_key.session().handle(), m_first_message);
84 m_first_message.clear();
85 m_has_first_message = false;
86 }
87
88 m_key.module()->C_SignUpdate(m_key.session().handle(), input.data(), checked_ulong_cast(input.size()));
89 }
90
91 std::vector<uint8_t> sign(RandomNumberGenerator& /*rng*/) override {
92 if(!m_initialized) {
93 // sign() called with no prior update(): treat as a single-part operation over the empty message
94 m_key.module()->C_SignInit(m_key.session().handle(), m_mechanism.data(), m_key.handle());
95 m_initialized = true;
96 m_has_first_message = true;
97 }
98 std::vector<uint8_t> signature;
99 if(m_has_first_message) {
100 // single call to update: perform single-part operation
101 m_key.module()->C_Sign(m_key.session().handle(), m_first_message, signature);
102 m_first_message.clear();
103 m_has_first_message = false;
104 } else {
105 // multiple calls to update: finish multiple-part operation
106 m_key.module()->C_SignFinal(m_key.session().handle(), signature);
107 }
108 m_initialized = false;
109 return signature;
110 }
111
112 size_t signature_length() const override { return 2 * m_order_bytes; }
113
114 AlgorithmIdentifier algorithm_identifier() const override;
115
116 std::string hash_function() const override { return m_hash; }
117
118 private:
119 const PKCS11_ECDSA_PrivateKey m_key;
120 const size_t m_order_bytes;
121 MechanismWrapper m_mechanism;
122 const std::string m_hash;
123 secure_vector<uint8_t> m_first_message;
124 bool m_initialized = false;
125 bool m_has_first_message = false;
126};
127
128AlgorithmIdentifier PKCS11_ECDSA_Signature_Operation::algorithm_identifier() const {
129 const std::string full_name = "ECDSA/" + hash_function();
130 const OID oid = OID::from_string(full_name);
131 return AlgorithmIdentifier(oid, AlgorithmIdentifier::USE_EMPTY_PARAM);
132}
133
134class PKCS11_ECDSA_Verification_Operation final : public PK_Ops::Verification {
135 public:
136 PKCS11_ECDSA_Verification_Operation(const PKCS11_ECDSA_PublicKey& key, std::string_view hash) :
137 PK_Ops::Verification(),
138 m_key(key),
139 m_mechanism(MechanismWrapper::create_ecdsa_mechanism(hash)),
140 m_hash(canonical_ecdsa_hash(hash)) {}
141
142 void update(std::span<const uint8_t> input) override {
143 if(!m_initialized) {
144 // first call to update: initialize and cache message because we can not determine yet whether a single- or multiple-part operation will be performed
145 m_key.module()->C_VerifyInit(m_key.session().handle(), m_mechanism.data(), m_key.handle());
146 m_initialized = true;
147 m_first_message.assign(input.begin(), input.end());
148 m_has_first_message = true;
149 return;
150 }
151
152 if(m_has_first_message) {
153 // second call to update: start multiple-part operation
154 m_key.module()->C_VerifyUpdate(m_key.session().handle(), m_first_message);
155 m_first_message.clear();
156 m_has_first_message = false;
157 }
158
159 m_key.module()->C_VerifyUpdate(m_key.session().handle(), input.data(), checked_ulong_cast(input.size()));
160 }
161
162 bool is_valid_signature(std::span<const uint8_t> sig) override {
163 if(!m_initialized) {
164 // is_valid_signature() called with no prior update(): treat as a single-part operation over the empty message
165 m_key.module()->C_VerifyInit(m_key.session().handle(), m_mechanism.data(), m_key.handle());
166 m_initialized = true;
167 m_has_first_message = true;
168 }
169 ReturnValue return_value = ReturnValue::SignatureInvalid;
170 if(m_has_first_message) {
171 // single call to update: perform single-part operation
172 m_key.module()->C_Verify(m_key.session().handle(),
173 m_first_message.data(),
174 checked_ulong_cast(m_first_message.size()),
175 sig.data(),
176 checked_ulong_cast(sig.size()),
177 &return_value);
178 m_first_message.clear();
179 m_has_first_message = false;
180 } else {
181 // multiple calls to update: finish multiple-part operation
182 m_key.module()->C_VerifyFinal(
183 m_key.session().handle(), sig.data(), checked_ulong_cast(sig.size()), &return_value);
184 }
185 m_initialized = false;
186 if(return_value == ReturnValue::SignatureInvalid || return_value == ReturnValue::SignatureLenRange) {
187 return false;
188 } else if(return_value == ReturnValue::OK) {
189 return true;
190 } else {
191 throw PKCS11_ReturnError(return_value);
192 }
193 }
194
195 std::string hash_function() const override { return m_hash; }
196
197 private:
198 const PKCS11_ECDSA_PublicKey m_key;
199 MechanismWrapper m_mechanism;
200 const std::string m_hash;
201 secure_vector<uint8_t> m_first_message;
202 bool m_initialized = false;
203 bool m_has_first_message = false;
204};
205
206} // namespace
207
208std::unique_ptr<PK_Ops::Verification> PKCS11_ECDSA_PublicKey::create_verification_op(
209 std::string_view params, std::string_view /*provider*/) const {
210 return std::make_unique<PKCS11_ECDSA_Verification_Operation>(*this, params);
211}
212
213std::unique_ptr<PK_Ops::Signature> PKCS11_ECDSA_PrivateKey::create_signature_op(RandomNumberGenerator& /*rng*/,
214 std::string_view params,
215 std::string_view /*provider*/) const {
216 return std::make_unique<PKCS11_ECDSA_Signature_Operation>(*this, params);
217}
218
219PKCS11_ECDSA_KeyPair generate_ecdsa_keypair(Session& session,
220 const EC_PublicKeyGenerationProperties& pub_props,
221 const EC_PrivateKeyGenerationProperties& priv_props) {
222 ObjectHandle pub_key_handle = 0;
223 ObjectHandle priv_key_handle = 0;
224
225 const Mechanism mechanism = {static_cast<CK_MECHANISM_TYPE>(MechanismType::EcKeyPairGen), nullptr, 0};
226
227 session.module()->C_GenerateKeyPair(session.handle(),
228 &mechanism,
229 pub_props.data(),
230 checked_ulong_cast(pub_props.count()),
231 priv_props.data(),
232 checked_ulong_cast(priv_props.count()),
233 &pub_key_handle,
234 &priv_key_handle);
235
236 return std::make_pair(PKCS11_ECDSA_PublicKey(session, pub_key_handle),
237 PKCS11_ECDSA_PrivateKey(session, priv_key_handle));
238}
239
240} // namespace Botan::PKCS11
241
242#endif
static BigInt from_bytes(std::span< const uint8_t > bytes)
Definition bigint.cpp:83
static OID from_string(std::string_view str)
Definition asn1_oid.cpp:80
Represents a PKCS#11 session.
Definition p11_types.h:125
bool signature_consistency_check(RandomNumberGenerator &rng, const Private_Key &private_key, const Public_Key &public_key, std::string_view padding)
Definition keypair.cpp:49
Ulong checked_ulong_cast(size_t v)
Definition p11.h:1228
CK_MECHANISM Mechanism
Definition p11.h:1207
CK_OBJECT_HANDLE ObjectHandle
Definition p11.h:1214
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:128
CK_ULONG CK_MECHANISM_TYPE
Definition pkcs11.h:59