Botan 3.13.0
Crypto and TLS for C&
p11_ecdh.cpp
Go to the documentation of this file.
1/*
2* PKCS#11 ECDH
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_ecdh.h>
10
11#if defined(BOTAN_HAS_ECDH)
12
13 #include <botan/der_enc.h>
14 #include <botan/ec_apoint.h>
15 #include <botan/p11_mechanism.h>
16 #include <botan/pk_ops.h>
17 #include <botan/rng.h>
18 #include <botan/internal/scoped_cleanup.h>
19
20namespace Botan::PKCS11 {
21
22ECDH_PublicKey PKCS11_ECDH_PublicKey::export_key() const {
23 return ECDH_PublicKey(domain(), _public_ec_point());
24}
25
26ECDH_PrivateKey PKCS11_ECDH_PrivateKey::export_key() const {
27 auto priv_key = get_attribute_value(AttributeType::Value);
28
29 Null_RNG rng;
30 return ECDH_PrivateKey(rng, domain(), BigInt::from_bytes(priv_key));
31}
32
33std::unique_ptr<Public_Key> PKCS11_ECDH_PrivateKey::public_key() const {
34 return std::make_unique<ECDH_PublicKey>(domain(), public_ec_point());
35}
36
37secure_vector<uint8_t> PKCS11_ECDH_PrivateKey::private_key_bits() const {
38 return export_key().private_key_bits();
39}
40
41namespace {
42class PKCS11_ECDH_KA_Operation final : public PK_Ops::Key_Agreement {
43 public:
44 PKCS11_ECDH_KA_Operation(const PKCS11_ECDH_PrivateKey& key, std::string_view params) :
45 PK_Ops::Key_Agreement(), m_key(key), m_mechanism(MechanismWrapper::create_ecdh_mechanism(params)) {}
46
47 size_t agreed_value_size() const override { return m_key.domain().get_p_bytes(); }
48
49 /// The encoding in V2.20 was not specified and resulted in different implementations choosing different encodings.
50 /// Applications relying only on a V2.20 encoding (e.g. the DER variant) other than the one specified now (raw) may not work with all V2.30 compliant tokens.
51 secure_vector<uint8_t> agree(size_t key_len,
52 std::span<const uint8_t> other_key,
53 std::span<const uint8_t> salt) override {
54 const auto peer_point = EC_AffinePoint::deserialize(m_key.domain(), other_key);
55 if(!peer_point) {
56 throw Decoding_Error("ECDH - Invalid elliptic curve point: not on curve");
57 }
58 if(peer_point->is_identity()) {
59 throw Decoding_Error("ECDH - Invalid elliptic curve point: identity");
60 }
61
62 std::vector<uint8_t> der_encoded_other_key;
63 if(m_key.point_encoding() == PublicPointEncoding::Der) {
64 DER_Encoder(der_encoded_other_key).encode(other_key.data(), other_key.size(), ASN1_Type::OctetString);
65 m_mechanism.set_ecdh_other_key(der_encoded_other_key.data(), der_encoded_other_key.size());
66 } else {
67 m_mechanism.set_ecdh_other_key(other_key.data(), other_key.size());
68 }
69
70 const bool raw_kdf = (m_mechanism.ecdh_kdf() == KeyDerivation::Null);
71
72 if(raw_kdf && !salt.empty()) {
73 throw Invalid_Argument("PK_Key_Agreement::derive_key requires a KDF to use a salt");
74 }
75
76 if(salt.empty()) {
77 m_mechanism.set_ecdh_salt(nullptr, 0);
78 } else {
79 m_mechanism.set_ecdh_salt(salt.data(), salt.size());
80 }
81
82 const size_t out_len = raw_kdf ? agreed_value_size() : key_len;
83
84 ObjectHandle secret_handle = 0;
85 AttributeContainer attributes;
86 attributes.add_bool(AttributeType::Sensitive, false);
87 attributes.add_bool(AttributeType::Extractable, true);
88 attributes.add_numeric(AttributeType::Class, static_cast<CK_OBJECT_CLASS>(ObjectClass::SecretKey));
89 attributes.add_numeric(AttributeType::KeyType, static_cast<CK_KEY_TYPE>(KeyType::GenericSecret));
90 attributes.add_numeric(AttributeType::ValueLen, checked_ulong_cast(out_len));
91 m_key.module()->C_DeriveKey(m_key.session().handle(),
92 m_mechanism.data(),
93 m_key.handle(),
94 attributes.data(),
95 checked_ulong_cast(attributes.count()),
96 &secret_handle);
97
98 const Object secret_object(m_key.session(), secret_handle);
99 auto destroy_secret = scoped_cleanup([&]() noexcept {
100 try {
101 secret_object.destroy();
102 } catch(...) { // NOLINT(*-empty-catch)
103 }
104 });
105 secure_vector<uint8_t> secret = secret_object.get_attribute_value(AttributeType::Value);
106 if(secret.size() < out_len) {
107 throw PKCS11_Error("ECDH key derivation secret length is too short");
108 }
109 secret.resize(out_len);
110 return secret;
111 }
112
113 private:
114 PKCS11_ECDH_PrivateKey m_key;
115 MechanismWrapper m_mechanism;
116};
117
118} // namespace
119
120std::unique_ptr<PK_Ops::Key_Agreement> PKCS11_ECDH_PrivateKey::create_key_agreement_op(
121 RandomNumberGenerator& /*rng*/, std::string_view params, std::string_view /*provider*/) const {
122 return std::make_unique<PKCS11_ECDH_KA_Operation>(*this, params);
123}
124
125PKCS11_ECDH_KeyPair generate_ecdh_keypair(Session& session,
126 const EC_PublicKeyGenerationProperties& pub_props,
127 const EC_PrivateKeyGenerationProperties& priv_props) {
128 ObjectHandle pub_key_handle = 0;
129 ObjectHandle priv_key_handle = 0;
130
131 const Mechanism mechanism = {static_cast<CK_MECHANISM_TYPE>(MechanismType::EcKeyPairGen), nullptr, 0};
132
133 session.module()->C_GenerateKeyPair(session.handle(),
134 &mechanism,
135 pub_props.data(),
136 checked_ulong_cast(pub_props.count()),
137 priv_props.data(),
138 checked_ulong_cast(priv_props.count()),
139 &pub_key_handle,
140 &priv_key_handle);
141
142 return std::make_pair(PKCS11_ECDH_PublicKey(session, pub_key_handle),
143 PKCS11_ECDH_PrivateKey(session, priv_key_handle));
144}
145
146} // namespace Botan::PKCS11
147
148#endif
static BigInt from_bytes(std::span< const uint8_t > bytes)
Definition bigint.cpp:83
Represents a PKCS#11 session.
Definition p11_types.h:125
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_OBJECT_CLASS
Definition pkcs11.h:63
CK_ULONG CK_KEY_TYPE
Definition pkcs11.h:55
CK_ULONG CK_MECHANISM_TYPE
Definition pkcs11.h:59