kernel/hil/
digest.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 2022.
4
5//! Interface for computing digests (hashes, cryptographic hashes, and
6//! HMACs) over data.
7
8use crate::utilities::leasable_buffer::SubSlice;
9use crate::utilities::leasable_buffer::SubSliceMut;
10use crate::ErrorCode;
11
12/// Implement this trait and use `set_client()` in order to receive callbacks
13/// when data has been added to a digest.
14///
15/// 'L' is the length of the 'u8' array to store the digest output.
16pub trait ClientData<const L: usize> {
17    /// Called when the data has been added to the digest. `data` is
18    /// the `SubSlice` passed in the call to `add_data`, whose
19    /// active slice contains the data that was not added. On `Ok`,
20    /// `data` has an active slice of size zero (all data was added).
21    /// Valid `ErrorCode` values are:
22    ///  - OFF: the underlying digest engine is powered down and
23    ///  cannot be used.
24    ///  - BUSY: there is an outstanding `add_data`, `add_data_mut`,
25    ///  `run`, or `verify` operation, so the digest engine is busy
26    ///  and cannot accept more data.
27    ///  - SIZE: the active slice of the SubSlice has zero size.
28    ///  - CANCEL: the operation was cancelled by a call to `clear_data`.
29    ///  - FAIL: an internal failure.
30    fn add_data_done(&self, result: Result<(), ErrorCode>, data: SubSlice<'static, u8>);
31
32    /// Called when the data has been added to the digest. `data` is
33    /// the `SubSliceMut` passed in the call to
34    /// `add_mut_data`, whose active slice contains the data that was
35    /// not added. On `Ok`, `data` has an active slice of size zero
36    /// (all data was added). Valid `ErrorCode` values are:
37    ///  - OFF: the underlying digest engine is powered down and
38    ///  cannot be used.
39    ///  - BUSY: there is an outstanding `add_data`, `add_data_mut`,
40    ///  `run`, or `verify` operation, so the digest engine is busy
41    ///  and cannot accept more data.
42    ///  - SIZE: the active slice of the SubSlice has zero size.
43    ///  - CANCEL: the operation was cancelled by a call to `clear_data`.
44    ///  - FAIL: an internal failure.
45    fn add_mut_data_done(&self, result: Result<(), ErrorCode>, data: SubSliceMut<'static, u8>);
46}
47
48/// Implement this trait and use `set_client()` in order to receive callbacks when
49/// a digest is completed.
50///
51/// 'L' is the length of the 'u8' array to store the digest output.
52pub trait ClientHash<const L: usize> {
53    /// Called when a digest is computed. `digest` is the same
54    /// reference passed to `run()` to store the hash value. If
55    /// `result` is `Ok`, `digest` stores the computed hash. If
56    /// `result` is `Err`, the data stored in `digest` is undefined
57    /// and may have any value. Valid `ErrorCode` values are:
58    ///  - OFF: the underlying digest engine is powered down and
59    ///  cannot be used.
60    ///  - BUSY: there is an outstanding `add_data`, `add_data_mut`,
61    ///  `run`, or `verify` operation, so the digest engine is busy
62    ///  and cannot perform a hash.
63    ///  - CANCEL: the operation was cancelled by a call to `clear_data`.
64    ///  - NOSUPPORT: the requested digest algorithm is not supported,
65    ///  or one was not requested.
66    ///  - FAIL: an internal failure.
67    fn hash_done(&self, result: Result<(), ErrorCode>, digest: &'static mut [u8; L]);
68}
69
70/// Implement this trait and use `set_client()` in order to receive callbacks when
71/// digest verification is complete.
72///
73/// 'L' is the length of the 'u8' array to store the digest output.
74pub trait ClientVerify<const L: usize> {
75    /// Called when a verification is computed.  `compare` is the
76    /// reference supplied to `verify()` and the data stored in
77    /// `compare` is unchanged.  On `Ok` the `bool` indicates if the
78    /// computed hash matches the value in `compare`. Valid
79    /// `ErrorCode` values are:
80    ///  - OFF: the underlying digest engine is powered down and
81    ///  cannot be used.
82    ///  - BUSY: there is an outstanding `add_data`, `add_data_mut`,
83    ///  `run`, or `verify` operation, so the digest engine is busy
84    ///  and cannot verify a hash.
85    ///  - CANCEL: the operation was cancelled by a call to `clear_data`.
86    ///  - NOSUPPORT: the requested digest algorithm is not supported,
87    ///  or one was not requested.
88    ///  - FAIL: an internal failure.
89    fn verification_done(&self, result: Result<bool, ErrorCode>, compare: &'static mut [u8; L]);
90}
91
92pub trait Client<const L: usize>: ClientData<L> + ClientHash<L> + ClientVerify<L> {}
93
94impl<T: ClientData<L> + ClientHash<L> + ClientVerify<L>, const L: usize> Client<L> for T {}
95
96pub trait ClientDataHash<const L: usize>: ClientData<L> + ClientHash<L> {}
97impl<T: ClientData<L> + ClientHash<L>, const L: usize> ClientDataHash<L> for T {}
98
99pub trait ClientDataVerify<const L: usize>: ClientData<L> + ClientVerify<L> {}
100impl<T: ClientData<L> + ClientVerify<L>, const L: usize> ClientDataVerify<L> for T {}
101
102/// Adding data (mutable or immutable) to a digest.
103///
104/// There are two separate methods, `add_data` for immutable data
105/// (e.g., flash) and `add_mut_data` for mutable data (e.g.,
106/// RAM). Each has its own callback, but only one operation may be in
107/// flight at any time.
108///
109/// 'L' is the length of the 'u8' array to store the digest output.
110pub trait DigestData<'a, const L: usize> {
111    /// Set the client instance which will handle the `add_data_done`
112    /// and `add_mut_data_done` callbacks.
113    fn set_data_client(&'a self, client: &'a dyn ClientData<L>);
114
115    /// Add data to the input of the hash function/digest. `Ok`
116    /// indicates all of the active bytes in `data` will be added.
117    /// There is no guarantee the data has been added to the digest
118    /// until the `add_data_done()` callback is called.  On error the
119    /// cause of the error is returned along with the SubSlice
120    /// unchanged (it has the same range of active bytes as the call).
121    /// Valid `ErrorCode` values are:
122    ///  - OFF: the underlying digest engine is powered down and
123    ///  cannot be used.
124    ///  - BUSY: there is an outstanding `add_data`, `add_data_mut`,
125    ///  `run`, or `verify` operation, so the digest engine is busy
126    ///  and cannot accept more data.
127    ///  - SIZE: the active slice of the SubSlice has zero size.
128    fn add_data(
129        &self,
130        data: SubSlice<'static, u8>,
131    ) -> Result<(), (ErrorCode, SubSlice<'static, u8>)>;
132
133    /// Add data to the input of the hash function/digest. `Ok`
134    /// indicates all of the active bytes in `data` will be added.
135    /// There is no guarantee the data has been added to the digest
136    /// until the `add_mut_data_done()` callback is called.  On error
137    /// the cause of the error is returned along with the
138    /// SubSlice unchanged (it has the same range of active
139    /// bytes as the call).  Valid `ErrorCode` values are:
140    ///  - OFF: the underlying digest engine is powered down and
141    ///  cannot be used.
142    ///  - BUSY: there is an outstanding `add_data`, `add_data_mut`,
143    ///  `run`, or `verify` operation, so the digest engine is busy
144    ///  and cannot accept more data.
145    ///  - SIZE: the active slice of the SubSlice has zero size.
146    fn add_mut_data(
147        &self,
148        data: SubSliceMut<'static, u8>,
149    ) -> Result<(), (ErrorCode, SubSliceMut<'static, u8>)>;
150
151    /// Clear the keys and any other internal state. Any pending
152    /// operations terminate and issue a callback with an
153    /// `ErrorCode::CANCEL`. This call does not clear buffers passed
154    /// through `add_mut_data`, those are up to the client clear.
155    fn clear_data(&self);
156}
157
158/// Computes a digest (cryptographic hash) over data provided through a
159/// separate trait.
160///
161/// 'L' is the length of the 'u8' array to store the digest output.
162pub trait DigestHash<'a, const L: usize> {
163    /// Set the client instance which will receive the `hash_done()`
164    /// callback.
165    fn set_hash_client(&'a self, client: &'a dyn ClientHash<L>);
166
167    /// Compute a digest of all of the data added with `add_data` and
168    /// `add_data_mut`, storing the computed value in `digest`.  The
169    /// computed value is returned in a `hash_done` callback.  On
170    /// error the return value will contain a return code and the
171    /// slice passed in `digest`. Valid `ErrorCode` values are:
172    ///  - OFF: the underlying digest engine is powered down and
173    ///  cannot be used.
174    ///  - BUSY: there is an outstanding `add_data`, `add_data_mut`,
175    ///  `run`, or `verify` operation, so the digest engine is busy
176    ///  and cannot accept more data.
177    ///  - SIZE: the active slice of the SubSlice has zero size.
178    ///  - NOSUPPORT: the currently selected digest algorithm is not
179    ///  supported.
180    ///
181    /// If an appropriate `set_mode*()` wasn't called before this function the
182    /// implementation should try to use a default option. In the case where
183    /// there is only one digest supported this should be used. If there is no
184    /// suitable or obvious default option, the implementation can return
185    /// `ErrorCode::NOSUPPORT`.
186    fn run(&'a self, digest: &'static mut [u8; L])
187        -> Result<(), (ErrorCode, &'static mut [u8; L])>;
188}
189
190/// Verifies a digest (cryptographic hash) over data provided through a
191/// separate trait
192///
193/// 'L' is the length of the 'u8' array to store the digest output.
194pub trait DigestVerify<'a, const L: usize> {
195    /// Set the client instance which will receive the `verification_done()`
196    /// callback.
197    fn set_verify_client(&'a self, client: &'a dyn ClientVerify<L>);
198
199    /// Compute a digest of all of the data added with `add_data` and
200    /// `add_data_mut` then compare it with value in `compare`.  The
201    /// compare value is returned in a `verification_done` callback, along with
202    /// a boolean indicating whether it matches the computed value. On
203    /// error the return value will contain a return code and the
204    /// slice passed in `compare`. Valid `ErrorCode` values are:
205    ///  - OFF: the underlying digest engine is powered down and
206    ///  cannot be used.
207    ///  - BUSY: there is an outstanding `add_data`, `add_data_mut`,
208    ///  `run`, or `verify` operation, so the digest engine is busy
209    ///  and cannot accept more data.
210    ///  - SIZE: the active slice of the SubSlice has zero size.
211    ///  - NOSUPPORT: the currently selected digest algorithm is not
212    ///  supported.
213    ///
214    /// If an appropriate `set_mode*()` wasn't called before this function the
215    /// implementation should try to use a default option. In the case where
216    /// there is only one digest supported this should be used. If there is no
217    /// suitable or obvious default option, the implementation can return
218    /// `ErrorCode::NOSUPPORT`.
219    fn verify(
220        &'a self,
221        compare: &'static mut [u8; L],
222    ) -> Result<(), (ErrorCode, &'static mut [u8; L])>;
223}
224
225/// Computes a digest (cryptographic hash) over data or performs verification.
226///
227/// 'L' is the length of the 'u8' array to store the digest output.
228pub trait Digest<'a, const L: usize>:
229    DigestData<'a, L> + DigestHash<'a, L> + DigestVerify<'a, L>
230{
231    /// Set the client instance which will receive `hash_done()`,
232    /// `add_data_done()` and `verification_done()` callbacks.
233    fn set_client(&'a self, client: &'a dyn Client<L>);
234}
235
236/// Computes a digest (cryptographic hash) over data.
237///
238/// 'L' is the length of the 'u8' array to store the digest output.
239pub trait DigestDataHash<'a, const L: usize>: DigestData<'a, L> + DigestHash<'a, L> {
240    /// Set the client instance which will receive `hash_done()` and
241    /// `add_data_done()` callbacks.
242    fn set_client(&'a self, client: &'a dyn ClientDataHash<L>);
243}
244
245/// Verify a digest (cryptographic hash) over data.
246///
247/// 'L' is the length of the 'u8' array to store the digest output.
248pub trait DigestDataVerify<'a, const L: usize>: DigestData<'a, L> + DigestVerify<'a, L> {
249    /// Set the client instance which will receive `verify_done()` and
250    /// `add_data_done()` callbacks.
251    fn set_client(&'a self, client: &'a dyn ClientDataVerify<L>);
252}
253
254pub trait Sha224 {
255    /// Call before adding data to perform Sha224
256    fn set_mode_sha224(&self) -> Result<(), ErrorCode>;
257}
258
259pub trait Sha256 {
260    /// Call before adding data to perform Sha256
261    fn set_mode_sha256(&self) -> Result<(), ErrorCode>;
262}
263
264pub trait Sha384 {
265    /// Call before adding data to perform Sha384
266    fn set_mode_sha384(&self) -> Result<(), ErrorCode>;
267}
268
269pub trait Sha512 {
270    /// Call before adding data to perform Sha512
271    fn set_mode_sha512(&self) -> Result<(), ErrorCode>;
272}
273
274pub trait HmacSha256 {
275    /// Call before adding data to perform HMACSha256
276    ///
277    /// The key used for the HMAC is passed to this function.
278    fn set_mode_hmacsha256(&self, key: &[u8]) -> Result<(), ErrorCode>;
279}
280
281pub trait HmacSha384 {
282    /// Call before adding data to perform HMACSha384
283    ///
284    /// The key used for the HMAC is passed to this function.
285    fn set_mode_hmacsha384(&self, key: &[u8]) -> Result<(), ErrorCode>;
286}
287
288pub trait HmacSha512 {
289    /// Call before adding data to perform HMACSha512
290    ///
291    /// The key used for the HMAC is passed to this function.
292    fn set_mode_hmacsha512(&self, key: &[u8]) -> Result<(), ErrorCode>;
293}