ecdsa_sw/
p256_signer.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//! ECDSA Signer for P256 signatures.
6
7use p256::ecdsa;
8use p256::ecdsa::signature::hazmat::PrehashSigner;
9
10use kernel::hil;
11use kernel::hil::public_key_crypto::keys::SetKeyBySliceClient;
12use kernel::utilities::cells::{OptionalCell, TakeCell};
13use kernel::ErrorCode;
14
15enum State {
16    Signing,
17    ChangingKey(&'static mut [u8; 64]),
18}
19
20pub struct EcdsaP256SignatureSigner<'a> {
21    client: OptionalCell<&'a dyn hil::public_key_crypto::signature::ClientSign<32, 64>>,
22    client_key_set: OptionalCell<&'a dyn hil::public_key_crypto::keys::SetKeyBySliceClient<64>>,
23    signing_key: TakeCell<'static, [u8; 32]>,
24    hash_storage: TakeCell<'static, [u8; 32]>,
25    signature_storage: TakeCell<'static, [u8; 64]>,
26    deferred_call: kernel::deferred_call::DeferredCall,
27    state: OptionalCell<State>,
28}
29
30impl EcdsaP256SignatureSigner<'_> {
31    pub fn new(signing_key: &'static mut [u8; 32]) -> Self {
32        Self {
33            client: OptionalCell::empty(),
34            client_key_set: OptionalCell::empty(),
35            signing_key: TakeCell::new(signing_key),
36            hash_storage: TakeCell::empty(),
37            signature_storage: TakeCell::empty(),
38            deferred_call: kernel::deferred_call::DeferredCall::new(),
39            state: OptionalCell::empty(),
40        }
41    }
42}
43
44impl<'a> hil::public_key_crypto::signature::SignatureSign<'a, 32, 64>
45    for EcdsaP256SignatureSigner<'a>
46{
47    fn set_sign_client(
48        &self,
49        client: &'a dyn hil::public_key_crypto::signature::ClientSign<32, 64>,
50    ) {
51        self.client.replace(client);
52    }
53
54    fn sign(
55        &self,
56        hash: &'static mut [u8; 32],
57        signature: &'static mut [u8; 64],
58    ) -> Result<
59        (),
60        (
61            kernel::ErrorCode,
62            &'static mut [u8; 32],
63            &'static mut [u8; 64],
64        ),
65    > {
66        if self.signing_key.is_some() {
67            self.signing_key
68                .map(|skey| {
69                    let skey: &[u8; 32] = skey;
70                    if let Ok(ecdsa_key) = ecdsa::SigningKey::from_bytes(skey.into()) {
71                        let maybe_sig: Result<ecdsa::Signature, _> = ecdsa_key.sign_prehash(hash);
72                        if let Ok(sig) = maybe_sig {
73                            signature.copy_from_slice(&sig.to_bytes());
74                            self.hash_storage.replace(hash);
75                            self.signature_storage.replace(signature);
76                            self.state.set(State::Signing);
77                            self.deferred_call.set();
78                            Ok(())
79                        } else {
80                            Err((kernel::ErrorCode::FAIL, hash, signature))
81                        }
82                    } else {
83                        Err((kernel::ErrorCode::INVAL, hash, signature))
84                    }
85                })
86                .unwrap()
87        } else {
88            Err((kernel::ErrorCode::FAIL, hash, signature))
89        }
90    }
91}
92
93impl<'a> hil::public_key_crypto::keys::SetKeyBySlice<'a, 64> for EcdsaP256SignatureSigner<'a> {
94    fn set_key(
95        &self,
96        key: &'static mut [u8; 64],
97    ) -> Result<(), (ErrorCode, &'static mut [u8; 64])> {
98        // Just wait for the deferred call to make the change so we can keep
99        // both the old and the new key in the meantime.
100        self.state.set(State::ChangingKey(key));
101        self.deferred_call.set();
102        Ok(())
103    }
104
105    fn set_client(&self, client: &'a dyn SetKeyBySliceClient<64>) {
106        self.client_key_set.replace(client);
107    }
108}
109
110impl kernel::deferred_call::DeferredCallClient for EcdsaP256SignatureSigner<'_> {
111    fn handle_deferred_call(&self) {
112        if let Some(s) = self.state.take() {
113            match s {
114                State::Signing => {
115                    self.client.map(|client| {
116                        if let Some(h) = self.hash_storage.take() {
117                            if let Some(s) = self.signature_storage.take() {
118                                client.signing_done(Ok(()), h, s);
119                            }
120                        }
121                    });
122                }
123                State::ChangingKey(key) => {
124                    self.signing_key.map(|skey| {
125                        skey.copy_from_slice(key);
126                    });
127
128                    self.client_key_set.map(|client| {
129                        client.set_key_done(key, Ok(()));
130                    });
131                }
132            }
133        }
134    }
135
136    fn register(&'static self) {
137        self.deferred_call.register(self);
138    }
139}