Botan 3.13.0
Crypto and TLS for C&
stateful_key_index_registry.h
Go to the documentation of this file.
1/*
2 * (C) 2016 Matthias Gierlings
3 * 2026 Jack Lloyd
4 *
5 * Botan is released under the Simplified BSD License (see license.txt)
6 */
7
8#ifndef BOTAN_STATEFUL_KEY_INDEX_REGISTRY_H_
9#define BOTAN_STATEFUL_KEY_INDEX_REGISTRY_H_
10
11#include <botan/mutex.h>
12#include <botan/types.h>
13#include <array>
14#include <map>
15#include <optional>
16#include <span>
17#include <string_view>
18
19namespace Botan {
20
21/**
22 * A process-wide registry mapping stateful key identity to a shared
23 * monotonic counter. Ensures that independent copies of the same key
24 * material (e.g. deserialized separately) share a single leaf index,
25 * preventing catastrophic one-time signature reuse.
26 *
27 * The same key material used with different algorithm parameters is
28 * tracked independently, since the parameters are part of the key
29 * identity. The maximum operation count is a function of the identity.
30 *
31 * Used by XMSS and HSS-LMS.
32 *
33 * If this registry or a key identity is inherited across fork(), it fails
34 * closed and refuses to issue further indices in the child process.
35 */
37 public:
38 class KeyId final {
39 public:
40 /**
41 * Create a KeyId for some kind of key material
42 *
43 * @param algo_name Algorithm name (ex "XMSS", "HSS-LMS")
44 * @param algo_params Encoding of the algorithm parameters
45 * @param max_operations Maximum number of operations the key supports.
46 * This must be derived from algo_params; equal
47 * identities must have equal maximums.
48 * @param key_material_1 First part of key identifying material
49 * @param key_material_2 Second part of key identifying material (can be omitted)
50 */
51 KeyId(std::string_view algo_name,
52 std::span<const uint8_t> algo_params,
53 uint64_t max_operations,
54 std::span<const uint8_t> key_material_1,
55 std::span<const uint8_t> key_material_2);
56
57 // A default constructed KeyId permits no operations
58 KeyId() = default;
59
60 uint64_t max_operations() const { return m_max_operations; }
61
62 // Identity is the hash; the maximum is not hashed in, since an
63 // inconsistent maximum forking the counter would be worse than
64 // the error the registry raises for it.
65 auto operator<=>(const KeyId& other) const { return m_val <=> other.m_val; }
66
67 bool operator==(const KeyId& other) const { return m_val == other.m_val; }
68
69 private:
70 std::array<uint8_t, 32> m_val{};
71 uint32_t m_process_id = 0;
72 uint64_t m_max_operations = 0;
73
75 };
76
82
83 /**
84 * Retrieve the process-wide instance
85 */
87
88 /**
89 * Return the current counter
90 */
91 uint64_t current_index(const KeyId& key_id);
92
93 /**
94 * Reserve and return the next counter value, or nullopt if the counter
95 * has already reached the key's maximum. The counter never increments
96 * past the maximum, so it cannot wrap, and an exhausted key remains
97 * exhausted.
98 */
99 std::optional<uint64_t> reserve_next_index(const KeyId& key_id);
100
101 /**
102 * Set the counter to at least min (but if already higher it will retain its current value)
103 */
104 void set_index_lower_bound(const KeyId& key_id, uint64_t min);
105
106 /**
107 * If the current counter is >= the key's maximum returns 0, otherwise maximum - counter
108 */
109 uint64_t remaining_operations(const KeyId& key_id);
110
111 private:
112 typedef std::map<KeyId, uint64_t> RegistryMap;
113
114 RegistryMap::iterator lookup(const KeyId& key_id);
115 bool fork_detected(const KeyId& key_id);
116
118
119 mutex_type m_mutex;
120 RegistryMap m_registry;
121 uint32_t m_process_id = 0;
122 bool m_fork_detected = false;
123};
124
125} // namespace Botan
126
127#endif
KeyId(std::string_view algo_name, std::span< const uint8_t > algo_params, uint64_t max_operations, std::span< const uint8_t > key_material_1, std::span< const uint8_t > key_material_2)
Stateful_Key_Index_Registry & operator=(Stateful_Key_Index_Registry &&)=delete
uint64_t remaining_operations(const KeyId &key_id)
std::optional< uint64_t > reserve_next_index(const KeyId &key_id)
Stateful_Key_Index_Registry & operator=(const Stateful_Key_Index_Registry &)=delete
Stateful_Key_Index_Registry(Stateful_Key_Index_Registry &&)=delete
void set_index_lower_bound(const KeyId &key_id, uint64_t min)
static Stateful_Key_Index_Registry & global()
Stateful_Key_Index_Registry(const Stateful_Key_Index_Registry &)=delete
noop_mutex mutex_type
Definition mutex.h:40