Skip to main content

capsules_extra/test/
hmac_sha512.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 Oxidos Automotive 2026.
4
5//! Test the software implementation of HMAC-SHA512 by performing a hash and
6//! checking it against the expected hash value.
7
8use capsules_core::test::capsule_test::{CapsuleTest, CapsuleTestClient, CapsuleTestError};
9use kernel::ErrorCode;
10use kernel::hil::digest;
11use kernel::hil::digest::HmacSha512;
12use kernel::utilities::cells::OptionalCell;
13use kernel::utilities::cells::TakeCell;
14use kernel::utilities::leasable_buffer::SubSlice;
15use kernel::utilities::leasable_buffer::SubSliceMut;
16
17const HMAC_SHA512_DIGEST_LEN: usize = 64;
18
19pub struct TestHmacSha512<'a, H: digest::Digest<'a, HMAC_SHA512_DIGEST_LEN>> {
20    hmac: &'a H,
21    key: TakeCell<'static, [u8]>,  // The key to use for HMAC
22    data: TakeCell<'static, [u8]>, // The data to hash
23    digest: TakeCell<'static, [u8; HMAC_SHA512_DIGEST_LEN]>, // The supplied hash
24    correct: &'static [u8; HMAC_SHA512_DIGEST_LEN], // The supplied hash
25    client: OptionalCell<&'static dyn CapsuleTestClient>,
26}
27
28impl<'a, H: digest::Digest<'a, HMAC_SHA512_DIGEST_LEN> + HmacSha512> TestHmacSha512<'a, H> {
29    pub fn new(
30        hmac: &'a H,
31        key: &'static mut [u8],
32        data: &'static mut [u8],
33        digest: &'static mut [u8; HMAC_SHA512_DIGEST_LEN],
34        correct: &'static [u8; HMAC_SHA512_DIGEST_LEN],
35    ) -> Self {
36        TestHmacSha512 {
37            hmac,
38            key: TakeCell::new(key),
39            data: TakeCell::new(data),
40            digest: TakeCell::new(digest),
41            correct,
42            client: OptionalCell::empty(),
43        }
44    }
45
46    pub fn run(&'static self) {
47        kernel::hil::digest::Digest::set_client(self.hmac, self);
48        let key = self.key.take().unwrap();
49        let r = self.hmac.set_mode_hmacsha512(key);
50        if r.is_err() {
51            panic!("HmacSha512Test: failed to set key: {:?}", r);
52        }
53        let data = self.data.take().unwrap();
54        let buffer = SubSliceMut::new(data);
55        let r = self.hmac.add_mut_data(buffer);
56        if r.is_err() {
57            panic!("HmacSha512Test: failed to add data: {:?}", r);
58        }
59    }
60}
61
62impl<'a, H: digest::Digest<'a, HMAC_SHA512_DIGEST_LEN> + HmacSha512>
63    digest::ClientData<HMAC_SHA512_DIGEST_LEN> for TestHmacSha512<'a, H>
64{
65    fn add_data_done(&self, _result: Result<(), ErrorCode>, _data: SubSlice<'static, u8>) {
66        unimplemented!()
67    }
68
69    fn add_mut_data_done(&self, result: Result<(), ErrorCode>, data: SubSliceMut<'static, u8>) {
70        self.data.replace(data.take());
71
72        match result {
73            Ok(()) => {}
74            Err(e) => {
75                kernel::debug!("HmacSha512Test: failed to add data: {:?}", e);
76                self.client.map(|client| {
77                    client.done(Err(CapsuleTestError::ErrorCode(e)));
78                });
79                return;
80            }
81        }
82
83        let r = self.hmac.run(self.digest.take().unwrap());
84        match r {
85            Ok(()) => {}
86            Err((e, d)) => {
87                kernel::debug!("HmacSha512Test: failed to run HMAC: {:?}", e);
88
89                self.digest.replace(d);
90                self.client.map(|client| {
91                    client.done(Err(CapsuleTestError::ErrorCode(e)));
92                });
93            }
94        }
95    }
96}
97
98impl<'a, H: digest::Digest<'a, HMAC_SHA512_DIGEST_LEN> + HmacSha512>
99    digest::ClientHash<HMAC_SHA512_DIGEST_LEN> for TestHmacSha512<'a, H>
100{
101    fn hash_done(
102        &self,
103        _result: Result<(), ErrorCode>,
104        digest: &'static mut [u8; HMAC_SHA512_DIGEST_LEN],
105    ) {
106        let mut error = false;
107        for i in 0..HMAC_SHA512_DIGEST_LEN {
108            if self.correct[i] != digest[i] {
109                error = true;
110                break;
111            }
112        }
113        if !error {
114            kernel::debug!("HMAC-SHA512 matches!");
115            self.client.map(|client| {
116                client.done(Ok(()));
117            });
118        } else {
119            kernel::debug!("HmacSha512Test: incorrect HMAC output!");
120            self.client.map(|client| {
121                client.done(Err(CapsuleTestError::IncorrectResult));
122            });
123        }
124    }
125}
126
127impl<'a, H: digest::Digest<'a, HMAC_SHA512_DIGEST_LEN> + HmacSha512>
128    digest::ClientVerify<HMAC_SHA512_DIGEST_LEN> for TestHmacSha512<'a, H>
129{
130    fn verification_done(
131        &self,
132        _result: Result<bool, ErrorCode>,
133        _compare: &'static mut [u8; HMAC_SHA512_DIGEST_LEN],
134    ) {
135    }
136}
137
138impl<'a, H: digest::Digest<'a, HMAC_SHA512_DIGEST_LEN> + HmacSha512> CapsuleTest
139    for TestHmacSha512<'a, H>
140{
141    fn set_client(&self, client: &'static dyn CapsuleTestClient) {
142        self.client.set(client);
143    }
144}