Coverage Report

Created: 2026-06-09 06:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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