/src/botan/src/lib/pubkey/xmss/xmss_publickey.cpp
Line | Count | Source |
1 | | /* |
2 | | * XMSS Public Key |
3 | | * An XMSS: Extended Hash-Based Signature public key. |
4 | | * The XMSS public key does not support the X509 standard. Instead the |
5 | | * raw format described in [1] is used. |
6 | | * |
7 | | * [1] XMSS: Extended Hash-Based Signatures, |
8 | | * Request for Comments: 8391 |
9 | | * Release: May 2018. |
10 | | * https://datatracker.ietf.org/doc/rfc8391/ |
11 | | * |
12 | | * (C) 2016,2017 Matthias Gierlings |
13 | | * |
14 | | * Botan is released under the Simplified BSD License (see license.txt) |
15 | | **/ |
16 | | |
17 | | #include <botan/xmss.h> |
18 | | |
19 | | #include <botan/ber_dec.h> |
20 | | #include <botan/der_enc.h> |
21 | | #include <botan/rng.h> |
22 | | #include <botan/internal/buffer_slicer.h> |
23 | | #include <botan/internal/concat_util.h> |
24 | | #include <botan/internal/loadstor.h> |
25 | | #include <botan/internal/xmss_verification_operation.h> |
26 | | |
27 | | namespace Botan { |
28 | | |
29 | | namespace { |
30 | | |
31 | 0 | XMSS_Parameters::xmss_algorithm_t deserialize_xmss_oid(std::span<const uint8_t> raw_key) { |
32 | 0 | if(raw_key.size() < 4) { |
33 | 0 | throw Decoding_Error("XMSS signature OID missing."); |
34 | 0 | } |
35 | | |
36 | | // extract and convert algorithm id to enum type |
37 | 0 | uint32_t raw_id = 0; |
38 | 0 | for(size_t i = 0; i < 4; i++) { |
39 | 0 | raw_id = ((raw_id << 8) | raw_key[i]); |
40 | 0 | } |
41 | |
|
42 | 0 | return static_cast<XMSS_Parameters::xmss_algorithm_t>(raw_id); |
43 | 0 | } |
44 | | |
45 | | // fall back to raw decoding for previous versions, which did not encode an OCTET STRING |
46 | 0 | std::vector<uint8_t> extract_raw_public_key(std::span<const uint8_t> key_bits) { |
47 | 0 | std::vector<uint8_t> raw_key; |
48 | 0 | try { |
49 | 0 | BER_Decoder(key_bits, BER_Decoder::Limits::DER()).decode(raw_key, ASN1_Type::OctetString).verify_end(); |
50 | | |
51 | | // Smoke check the decoded key. Valid raw keys might be decodable as BER |
52 | | // and they might be either a sole public key or a concatenation of public |
53 | | // and private key (with the optional WOTS+ derivation identifier). |
54 | 0 | const XMSS_Parameters params = XMSS_Parameters::from_id(deserialize_xmss_oid(raw_key)); |
55 | 0 | if(raw_key.size() != params.raw_public_key_size() && raw_key.size() != params.raw_private_key_size() && |
56 | 0 | raw_key.size() != params.raw_legacy_private_key_size()) { |
57 | 0 | throw Decoding_Error("unpacked XMSS key does not have the correct length"); |
58 | 0 | } |
59 | 0 | } catch(Decoding_Error&) { |
60 | 0 | raw_key.assign(key_bits.begin(), key_bits.end()); |
61 | 0 | } catch(Not_Implemented&) { |
62 | 0 | raw_key.assign(key_bits.begin(), key_bits.end()); |
63 | 0 | } |
64 | | |
65 | 0 | return raw_key; |
66 | 0 | } |
67 | | |
68 | | } // namespace |
69 | | |
70 | | class XMSS_PublicKey_Internal final { |
71 | | public: |
72 | | XMSS_PublicKey_Internal(const XMSS_Parameters& params, |
73 | | secure_vector<uint8_t> root, |
74 | | secure_vector<uint8_t> public_seed) : |
75 | 0 | m_xmss_params(params), |
76 | 0 | m_wots_params(m_xmss_params.wots_parameters()), |
77 | 0 | m_root(std::move(root)), |
78 | 0 | m_public_seed(std::move(public_seed)) {} |
79 | | |
80 | 0 | const XMSS_Parameters& xmss_parameters() const { return m_xmss_params; } |
81 | | |
82 | 0 | const XMSS_WOTS_Parameters& wots_parameters() const { return m_wots_params; } |
83 | | |
84 | 0 | const secure_vector<uint8_t>& root() const { return m_root; } |
85 | | |
86 | 0 | const secure_vector<uint8_t>& public_seed() const { return m_public_seed; } |
87 | | |
88 | 0 | void set_root(secure_vector<uint8_t> root) { m_root = std::move(root); } |
89 | | |
90 | 0 | std::vector<uint8_t> raw_public_key_bits() const { |
91 | 0 | return concat<std::vector<uint8_t>>( |
92 | 0 | store_be(static_cast<uint32_t>(m_xmss_params.oid())), m_root, m_public_seed); |
93 | 0 | } |
94 | | |
95 | | private: |
96 | | XMSS_Parameters m_xmss_params; |
97 | | XMSS_WOTS_Parameters m_wots_params; |
98 | | secure_vector<uint8_t> m_root; |
99 | | secure_vector<uint8_t> m_public_seed; |
100 | | }; |
101 | | |
102 | 0 | XMSS_PublicKey::XMSS_PublicKey(XMSS_Parameters::xmss_algorithm_t xmss_oid, RandomNumberGenerator& rng) { |
103 | 0 | const auto params = XMSS_Parameters::from_id(xmss_oid); |
104 | 0 | m_public_key = std::make_shared<XMSS_PublicKey_Internal>( |
105 | 0 | params, secure_vector<uint8_t>(params.element_size()), rng.random_vec(params.element_size())); |
106 | 0 | } Unexecuted instantiation: Botan::XMSS_PublicKey::XMSS_PublicKey(Botan::XMSS_Parameters::xmss_algorithm_t, Botan::RandomNumberGenerator&) Unexecuted instantiation: Botan::XMSS_PublicKey::XMSS_PublicKey(Botan::XMSS_Parameters::xmss_algorithm_t, Botan::RandomNumberGenerator&) |
107 | | |
108 | 0 | XMSS_PublicKey::XMSS_PublicKey(std::span<const uint8_t> key_bits) : XMSS_PublicKey(AlgorithmIdentifier(), key_bits) {}Unexecuted instantiation: Botan::XMSS_PublicKey::XMSS_PublicKey(std::__1::span<unsigned char const, 18446744073709551615ul>) Unexecuted instantiation: Botan::XMSS_PublicKey::XMSS_PublicKey(std::__1::span<unsigned char const, 18446744073709551615ul>) |
109 | | |
110 | 0 | XMSS_PublicKey::XMSS_PublicKey(const AlgorithmIdentifier& alg_id, std::span<const uint8_t> key_bits) { |
111 | | // The XMSS parameter set is carried in the key bits; no AlgorithmIdentifier parameters are defined |
112 | 0 | if(!alg_id.parameters_are_empty()) { |
113 | 0 | throw Decoding_Error("Unexpected parameters for XMSS public key"); |
114 | 0 | } |
115 | | |
116 | 0 | const auto raw_key = extract_raw_public_key(key_bits); |
117 | 0 | const auto xmss_oid = deserialize_xmss_oid(raw_key); |
118 | 0 | const auto params = XMSS_Parameters::from_id(xmss_oid); |
119 | 0 | if(raw_key.size() < params.raw_public_key_size()) { |
120 | 0 | throw Decoding_Error("Invalid XMSS public key size detected"); |
121 | 0 | } |
122 | | |
123 | 0 | BufferSlicer s(raw_key); |
124 | 0 | s.skip(4 /* algorithm ID -- already consumed by `deserialize_xmss_oid()` */); |
125 | |
|
126 | 0 | auto root = s.copy_as_secure_vector(params.element_size()); |
127 | 0 | auto public_seed = s.copy_as_secure_vector(params.element_size()); |
128 | |
|
129 | 0 | m_public_key = std::make_shared<XMSS_PublicKey_Internal>(params, std::move(root), std::move(public_seed)); |
130 | 0 | } Unexecuted instantiation: Botan::XMSS_PublicKey::XMSS_PublicKey(Botan::AlgorithmIdentifier const&, std::__1::span<unsigned char const, 18446744073709551615ul>) Unexecuted instantiation: Botan::XMSS_PublicKey::XMSS_PublicKey(Botan::AlgorithmIdentifier const&, std::__1::span<unsigned char const, 18446744073709551615ul>) |
131 | | |
132 | | XMSS_PublicKey::XMSS_PublicKey(XMSS_Parameters::xmss_algorithm_t xmss_oid, |
133 | | secure_vector<uint8_t> root, |
134 | 0 | secure_vector<uint8_t> public_seed) { |
135 | 0 | const auto params = XMSS_Parameters::from_id(xmss_oid); |
136 | 0 | BOTAN_ARG_CHECK(root.size() == params.element_size(), "XMSS: unexpected byte length of root hash"); |
137 | 0 | BOTAN_ARG_CHECK(public_seed.size() == params.element_size(), "XMSS: unexpected byte length of public seed"); |
138 | 0 | m_public_key = std::make_shared<XMSS_PublicKey_Internal>(params, std::move(root), std::move(public_seed)); |
139 | 0 | } Unexecuted instantiation: Botan::XMSS_PublicKey::XMSS_PublicKey(Botan::XMSS_Parameters::xmss_algorithm_t, std::__1::vector<unsigned char, Botan::secure_allocator<unsigned char> >, std::__1::vector<unsigned char, Botan::secure_allocator<unsigned char> >) Unexecuted instantiation: Botan::XMSS_PublicKey::XMSS_PublicKey(Botan::XMSS_Parameters::xmss_algorithm_t, std::__1::vector<unsigned char, Botan::secure_allocator<unsigned char> >, std::__1::vector<unsigned char, Botan::secure_allocator<unsigned char> >) |
140 | | |
141 | 0 | const secure_vector<uint8_t>& XMSS_PublicKey::public_seed() const { |
142 | 0 | return m_public_key->public_seed(); |
143 | 0 | } |
144 | | |
145 | 0 | const secure_vector<uint8_t>& XMSS_PublicKey::root() const { |
146 | 0 | return m_public_key->root(); |
147 | 0 | } |
148 | | |
149 | 0 | const XMSS_Parameters& XMSS_PublicKey::xmss_parameters() const { |
150 | 0 | return m_public_key->xmss_parameters(); |
151 | 0 | } |
152 | | |
153 | 0 | void XMSS_PublicKey::set_root(secure_vector<uint8_t> root) { |
154 | 0 | m_public_key->set_root(std::move(root)); |
155 | 0 | } |
156 | | |
157 | 0 | size_t XMSS_PublicKey::estimated_strength() const { |
158 | 0 | return xmss_parameters().estimated_strength(); |
159 | 0 | } |
160 | | |
161 | 0 | size_t XMSS_PublicKey::key_length() const { |
162 | 0 | return xmss_parameters().estimated_strength(); |
163 | 0 | } |
164 | | |
165 | 0 | bool XMSS_PublicKey::check_key(RandomNumberGenerator& /*rng*/, bool /*strong*/) const { |
166 | | // The public key consists of (OID, root hash, public seed). The OID is |
167 | | // validated and the byte lengths of root and public_seed are verified |
168 | | // against the parameter set during deserialization. These are opaque |
169 | | // hash outputs with no further structural invariants to check. |
170 | 0 | return true; |
171 | 0 | } |
172 | | |
173 | | std::unique_ptr<PK_Ops::Verification> XMSS_PublicKey::create_verification_op(std::string_view /*params*/, |
174 | 0 | std::string_view provider) const { |
175 | 0 | if(provider == "base" || provider.empty()) { |
176 | 0 | return std::make_unique<XMSS_Verification_Operation>(*this); |
177 | 0 | } |
178 | 0 | throw Provider_Not_Found(algo_name(), provider); |
179 | 0 | } |
180 | | |
181 | | std::unique_ptr<PK_Ops::Verification> XMSS_PublicKey::create_x509_verification_op(const AlgorithmIdentifier& alg_id, |
182 | 0 | std::string_view provider) const { |
183 | 0 | if(provider == "base" || provider.empty()) { |
184 | 0 | if(alg_id != this->algorithm_identifier()) { |
185 | 0 | throw Decoding_Error("Unexpected AlgorithmIdentifier for XMSS X509 signature"); |
186 | 0 | } |
187 | 0 | return std::make_unique<XMSS_Verification_Operation>(*this); |
188 | 0 | } |
189 | 0 | throw Provider_Not_Found(algo_name(), provider); |
190 | 0 | } |
191 | | |
192 | 0 | std::vector<uint8_t> XMSS_PublicKey::raw_public_key_bits() const { |
193 | 0 | return m_public_key->raw_public_key_bits(); |
194 | 0 | } |
195 | | |
196 | 0 | std::vector<uint8_t> XMSS_PublicKey::public_key_bits() const { |
197 | 0 | std::vector<uint8_t> output; |
198 | 0 | DER_Encoder(output).encode(raw_public_key_bits(), ASN1_Type::OctetString); |
199 | 0 | return output; |
200 | 0 | } |
201 | | |
202 | 0 | std::vector<uint8_t> XMSS_PublicKey::raw_public_key() const { |
203 | 0 | return raw_public_key_bits(); |
204 | 0 | } |
205 | | |
206 | 0 | std::unique_ptr<Private_Key> XMSS_PublicKey::generate_another(RandomNumberGenerator& rng) const { |
207 | | // Note: Given only an XMSS public key we cannot know which WOTS key |
208 | | // derivation method was used to build the XMSS tree. Hence, we have to |
209 | | // use the default here. |
210 | 0 | return std::make_unique<XMSS_PrivateKey>(xmss_parameters().oid(), rng); |
211 | 0 | } |
212 | | |
213 | | } // namespace Botan |