capsules_extra/
signature_verify_in_memory_keys.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2025.
4
5//! Mechanism for verifying signatures with multiple in-memory keys.
6//!
7//! This capsule should be used when a system wants to be able to verify
8//! signatures with multiple keys and the underlying signature verifier stores
9//! keys in memory and only stores one key at a time.
10//!
11//! This capsule stores `NUM_KEYS` buffers holding keys. Users should construct
12//! this capsule and then call `init_key()` `NUM_KEYS` times to set all of the
13//! internal keys to store.
14//!
15//! The intended layering with this capsule looks like this:
16//!
17//! ```text
18//!   ┌───────────────────────────────────────┐
19//!   │                                       │
20//!   │         Signature User                │
21//!   │ (e.g., `AppCheckerSignature`)         │
22//!   │                                       │
23//!   └───────────────────────────────────────┘
24//!     SignatureVerify + SelectKey      ^
25//!   ┌─────────────────────────────┐    │
26//!   │                             │    │
27//!   │ SignatureVerifyInMemoryKeys │    │SignatureVerifyClient
28//!   │    (this module)            │    │
29//!   │                             │    │
30//!   └─────────────────────────────┘    │
31//!     SignatureVerify + SetKeyBySlice  │
32//!   ┌───────────────────────────────────────┐
33//!   │                                       │
34//!   │         Signature Verifier            │
35//!   │  (e.g., `EcdsaP256SignatureVerifier`) │
36//!   │                                       │
37//!   └───────────────────────────────────────┘
38//! ```
39
40use kernel::hil;
41use kernel::utilities::cells::MapCell;
42use kernel::utilities::cells::OptionalCell;
43use kernel::ErrorCode;
44
45pub struct SignatureVerifyInMemoryKeys<
46    'a,
47    S: hil::public_key_crypto::signature::SignatureVerify<'a, HL, SL>
48        + hil::public_key_crypto::keys::SetKeyBySlice<'a, KL>,
49    const NUM_KEYS: usize,
50    const KL: usize,
51    const HL: usize,
52    const SL: usize,
53> {
54    verifier: &'a S,
55
56    keys: [MapCell<&'static mut [u8; KL]>; NUM_KEYS],
57    active_key: OptionalCell<usize>,
58
59    client_key_select: OptionalCell<&'a dyn hil::public_key_crypto::keys::SelectKeyClient>,
60
61    deferred_call: kernel::deferred_call::DeferredCall,
62}
63
64impl<
65        'a,
66        S: hil::public_key_crypto::signature::SignatureVerify<'a, HL, SL>
67            + hil::public_key_crypto::keys::SetKeyBySlice<'a, KL>,
68        const NUM_KEYS: usize,
69        const KL: usize,
70        const HL: usize,
71        const SL: usize,
72    > SignatureVerifyInMemoryKeys<'a, S, NUM_KEYS, KL, HL, SL>
73{
74    pub fn new(verifier: &'a S) -> Self {
75        Self {
76            verifier,
77            keys: [const { MapCell::empty() }; NUM_KEYS],
78            active_key: OptionalCell::empty(),
79            client_key_select: OptionalCell::empty(),
80            deferred_call: kernel::deferred_call::DeferredCall::new(),
81        }
82    }
83
84    /// Set the keys this module should store.
85    pub fn init_key(&self, index: usize, key: &'static mut [u8; KL]) -> Result<(), ()> {
86        self.keys.get(index).ok_or(())?.replace(key);
87        Ok(())
88    }
89}
90
91impl<
92        'a,
93        S: hil::public_key_crypto::signature::SignatureVerify<'a, HL, SL>
94            + hil::public_key_crypto::keys::SetKeyBySlice<'a, KL>,
95        const NUM_KEYS: usize,
96        const KL: usize,
97        const HL: usize,
98        const SL: usize,
99    > hil::public_key_crypto::signature::SignatureVerify<'a, HL, SL>
100    for SignatureVerifyInMemoryKeys<'a, S, NUM_KEYS, KL, HL, SL>
101{
102    fn set_verify_client(
103        &self,
104        client: &'a dyn hil::public_key_crypto::signature::ClientVerify<HL, SL>,
105    ) {
106        self.verifier.set_verify_client(client);
107    }
108
109    fn verify(
110        &self,
111        hash: &'static mut [u8; HL],
112        signature: &'static mut [u8; SL],
113    ) -> Result<
114        (),
115        (
116            kernel::ErrorCode,
117            &'static mut [u8; HL],
118            &'static mut [u8; SL],
119        ),
120    > {
121        self.verifier.verify(hash, signature)
122    }
123}
124
125impl<
126        'a,
127        S: hil::public_key_crypto::signature::SignatureVerify<'a, HL, SL>
128            + hil::public_key_crypto::keys::SetKeyBySlice<'a, KL>,
129        const NUM_KEYS: usize,
130        const KL: usize,
131        const HL: usize,
132        const SL: usize,
133    > hil::public_key_crypto::keys::SelectKey<'a>
134    for SignatureVerifyInMemoryKeys<'a, S, NUM_KEYS, KL, HL, SL>
135{
136    fn get_key_count(&self) -> Result<(), ErrorCode> {
137        self.deferred_call.set();
138        Ok(())
139    }
140
141    fn select_key(&self, index: usize) -> Result<(), ErrorCode> {
142        // Extract the key from our stored list of buffers holding keys. Return
143        // `INVAL` if the index is greater than the number of keys we have and
144        // return `NOMEM` if the key is not in our storage.
145        let key = self
146            .keys
147            .get(index)
148            .ok_or(ErrorCode::INVAL)?
149            .take()
150            .ok_or(ErrorCode::NOMEM)?;
151
152        // Mark which key is now active.
153        self.active_key.set(index);
154
155        // Set the key in the verifier. Replace if there is an error.
156        self.verifier.set_key(key).map_err(|(e, k)| {
157            if let Some(slot) = self.keys.get(self.active_key.get().unwrap_or(0)) {
158                slot.replace(k);
159            }
160            self.active_key.clear();
161
162            e
163        })
164    }
165
166    fn set_client(&self, client: &'a dyn hil::public_key_crypto::keys::SelectKeyClient) {
167        self.client_key_select.replace(client);
168    }
169}
170
171impl<
172        'a,
173        S: hil::public_key_crypto::signature::SignatureVerify<'a, HL, SL>
174            + hil::public_key_crypto::keys::SetKeyBySlice<'a, KL>,
175        const NUM_KEYS: usize,
176        const KL: usize,
177        const HL: usize,
178        const SL: usize,
179    > hil::public_key_crypto::keys::SetKeyBySliceClient<KL>
180    for SignatureVerifyInMemoryKeys<'a, S, NUM_KEYS, KL, HL, SL>
181{
182    fn set_key_done(&self, key: &'static mut [u8; KL], error: Result<(), ErrorCode>) {
183        // Re-store the key we just set.
184        if let Some(slot) = self.keys.get(self.active_key.get().unwrap_or(0)) {
185            slot.replace(key);
186        }
187
188        self.client_key_select.map(|client| {
189            client.select_key_done(self.active_key.get().unwrap_or(0), error);
190        });
191    }
192}
193
194impl<
195        'a,
196        S: hil::public_key_crypto::signature::SignatureVerify<'a, HL, SL>
197            + hil::public_key_crypto::keys::SetKeyBySlice<'a, KL>,
198        const NUM_KEYS: usize,
199        const KL: usize,
200        const HL: usize,
201        const SL: usize,
202    > kernel::deferred_call::DeferredCallClient
203    for SignatureVerifyInMemoryKeys<'a, S, NUM_KEYS, KL, HL, SL>
204{
205    fn handle_deferred_call(&self) {
206        self.client_key_select.map(|client| {
207            client.get_key_count_done(NUM_KEYS);
208        });
209    }
210
211    fn register(&'static self) {
212        self.deferred_call.register(self);
213    }
214}