Botan 3.5.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/pk_ops.h>
14 #include <botan/rng.h>
15 #include <botan/internal/keypair.h>
16 #include <botan/internal/p11_mechanism.h>
17
18namespace Botan::PKCS11 {
19
20ECDSA_PublicKey PKCS11_ECDSA_PublicKey::export_key() const {
21 return ECDSA_PublicKey(domain(), public_point());
22}
23
24bool PKCS11_ECDSA_PrivateKey::check_key(RandomNumberGenerator& rng, bool strong) const {
25 if(!public_point().on_the_curve()) {
26 return false;
27 }
28
29 if(!strong) {
30 return true;
31 }
32
33 ECDSA_PublicKey pubkey(domain(), public_point());
34 return KeyPair::signature_consistency_check(rng, *this, pubkey, "SHA-256");
35}
36
37ECDSA_PrivateKey PKCS11_ECDSA_PrivateKey::export_key() const {
38 auto priv_key = get_attribute_value(AttributeType::Value);
39
40 Null_RNG rng;
41 return ECDSA_PrivateKey(rng, domain(), BigInt::from_bytes(priv_key));
42}
43
44secure_vector<uint8_t> PKCS11_ECDSA_PrivateKey::private_key_bits() const {
45 return export_key().private_key_bits();
46}
47
48std::unique_ptr<Public_Key> PKCS11_ECDSA_PrivateKey::public_key() const {
49 return std::make_unique<ECDSA_PublicKey>(domain(), public_point());
50}
51
52namespace {
53
54class PKCS11_ECDSA_Signature_Operation final : public PK_Ops::Signature {
55 public:
56 PKCS11_ECDSA_Signature_Operation(const PKCS11_ECDSA_PrivateKey& key, std::string_view hash) :
57 PK_Ops::Signature(),
58 m_key(key),
59 m_order_bytes(key.domain().get_order_bytes()),
60 m_mechanism(MechanismWrapper::create_ecdsa_mechanism(hash)),
61 m_hash(hash) {}
62
63 void update(const uint8_t msg[], size_t msg_len) override {
64 if(!m_initialized) {
65 // first call to update: initialize and cache message because we can not determine yet whether a single- or multiple-part operation will be performed
66 m_key.module()->C_SignInit(m_key.session().handle(), m_mechanism.data(), m_key.handle());
67 m_initialized = true;
68 m_first_message = secure_vector<uint8_t>(msg, msg + msg_len);
69 return;
70 }
71
72 if(!m_first_message.empty()) {
73 // second call to update: start multiple-part operation
74 m_key.module()->C_SignUpdate(m_key.session().handle(), m_first_message);
75 m_first_message.clear();
76 }
77
78 m_key.module()->C_SignUpdate(m_key.session().handle(), msg, static_cast<Ulong>(msg_len));
79 }
80
81 secure_vector<uint8_t> sign(RandomNumberGenerator& /*rng*/) override {
82 secure_vector<uint8_t> signature;
83 if(!m_first_message.empty()) {
84 // single call to update: perform single-part operation
85 m_key.module()->C_Sign(m_key.session().handle(), m_first_message, signature);
86 m_first_message.clear();
87 } else {
88 // multiple calls to update (or none): finish multiple-part operation
89 m_key.module()->C_SignFinal(m_key.session().handle(), signature);
90 }
91 m_initialized = false;
92 return signature;
93 }
94
95 size_t signature_length() const override { return 2 * m_order_bytes; }
96
97 AlgorithmIdentifier algorithm_identifier() const override;
98
99 std::string hash_function() const override { return m_hash; }
100
101 private:
102 const PKCS11_ECDSA_PrivateKey m_key;
103 const size_t m_order_bytes;
104 MechanismWrapper m_mechanism;
105 const std::string m_hash;
106 secure_vector<uint8_t> m_first_message;
107 bool m_initialized = false;
108};
109
110AlgorithmIdentifier PKCS11_ECDSA_Signature_Operation::algorithm_identifier() const {
111 const std::string full_name = "ECDSA/" + hash_function();
112 const OID oid = OID::from_string(full_name);
113 return AlgorithmIdentifier(oid, AlgorithmIdentifier::USE_EMPTY_PARAM);
114}
115
116class PKCS11_ECDSA_Verification_Operation final : public PK_Ops::Verification {
117 public:
118 PKCS11_ECDSA_Verification_Operation(const PKCS11_ECDSA_PublicKey& key, std::string_view hash) :
119 PK_Ops::Verification(),
120 m_key(key),
121 m_mechanism(MechanismWrapper::create_ecdsa_mechanism(hash)),
122 m_hash(hash) {}
123
124 void update(const uint8_t msg[], size_t msg_len) override {
125 if(!m_initialized) {
126 // first call to update: initialize and cache message because we can not determine yet whether a single- or multiple-part operation will be performed
127 m_key.module()->C_VerifyInit(m_key.session().handle(), m_mechanism.data(), m_key.handle());
128 m_initialized = true;
129 m_first_message = secure_vector<uint8_t>(msg, msg + msg_len);
130 return;
131 }
132
133 if(!m_first_message.empty()) {
134 // second call to update: start multiple-part operation
135 m_key.module()->C_VerifyUpdate(m_key.session().handle(), m_first_message);
136 m_first_message.clear();
137 }
138
139 m_key.module()->C_VerifyUpdate(m_key.session().handle(), msg, static_cast<Ulong>(msg_len));
140 }
141
142 bool is_valid_signature(const uint8_t sig[], size_t sig_len) override {
143 ReturnValue return_value = ReturnValue::SignatureInvalid;
144 if(!m_first_message.empty()) {
145 // single call to update: perform single-part operation
146 m_key.module()->C_Verify(m_key.session().handle(),
147 m_first_message.data(),
148 static_cast<Ulong>(m_first_message.size()),
149 sig,
150 static_cast<Ulong>(sig_len),
151 &return_value);
152 m_first_message.clear();
153 } else {
154 // multiple calls to update (or none): finish multiple-part operation
155 m_key.module()->C_VerifyFinal(m_key.session().handle(), sig, static_cast<Ulong>(sig_len), &return_value);
156 }
157 m_initialized = false;
158 if(return_value != ReturnValue::OK && return_value != ReturnValue::SignatureInvalid) {
159 throw PKCS11_ReturnError(return_value);
160 }
161 return return_value == ReturnValue::OK;
162 }
163
164 std::string hash_function() const override { return m_hash; }
165
166 private:
167 const PKCS11_ECDSA_PublicKey m_key;
168 MechanismWrapper m_mechanism;
169 const std::string m_hash;
170 secure_vector<uint8_t> m_first_message;
171 bool m_initialized = false;
172};
173
174} // namespace
175
176std::unique_ptr<PK_Ops::Verification> PKCS11_ECDSA_PublicKey::create_verification_op(
177 std::string_view params, std::string_view /*provider*/) const {
178 return std::make_unique<PKCS11_ECDSA_Verification_Operation>(*this, params);
179}
180
181std::unique_ptr<PK_Ops::Signature> PKCS11_ECDSA_PrivateKey::create_signature_op(RandomNumberGenerator& /*rng*/,
182 std::string_view params,
183 std::string_view /*provider*/) const {
184 return std::make_unique<PKCS11_ECDSA_Signature_Operation>(*this, params);
185}
186
187PKCS11_ECDSA_KeyPair generate_ecdsa_keypair(Session& session,
188 const EC_PublicKeyGenerationProperties& pub_props,
189 const EC_PrivateKeyGenerationProperties& priv_props) {
190 ObjectHandle pub_key_handle = 0;
191 ObjectHandle priv_key_handle = 0;
192
193 Mechanism mechanism = {static_cast<CK_MECHANISM_TYPE>(MechanismType::EcKeyPairGen), nullptr, 0};
194
195 session.module()->C_GenerateKeyPair(session.handle(),
196 &mechanism,
197 pub_props.data(),
198 static_cast<Ulong>(pub_props.count()),
199 priv_props.data(),
200 static_cast<Ulong>(priv_props.count()),
201 &pub_key_handle,
202 &priv_key_handle);
203
204 return std::make_pair(PKCS11_ECDSA_PublicKey(session, pub_key_handle),
205 PKCS11_ECDSA_PrivateKey(session, priv_key_handle));
206}
207
208} // namespace Botan::PKCS11
209
210#endif
static BigInt from_bytes(std::span< const uint8_t > bytes)
Definition bigint.cpp:95
static OID from_string(std::string_view str)
Definition asn1_oid.cpp:86
int(* update)(CTX *, const void *, CC_LONG len)
int(* final)(unsigned char *, CTX *)
bool signature_consistency_check(RandomNumberGenerator &rng, const Private_Key &private_key, const Public_Key &public_key, std::string_view padding)
Definition keypair.cpp:49
CK_MECHANISM Mechanism
Definition p11.h:819
CK_OBJECT_HANDLE ObjectHandle
Definition p11.h:826
CK_ULONG Ulong
Definition p11.h:816
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:61
CK_ULONG CK_MECHANISM_TYPE
Definition pkcs11t.h:583