Skip to content

Commit a7ae585

Browse files
rusty1968FerralCoder
authored andcommitted
Extend the HubrisDigestDevice with sesison management methods.
1 parent 60c0de5 commit a7ae585

File tree

2 files changed

+269
-5
lines changed

2 files changed

+269
-5
lines changed

platform/impls/rustcrypto/src/controller.rs

Lines changed: 96 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use openprot_hal_blocking::mac::{
1717
Error as MacError, ErrorKind as MacErrorKind, ErrorType as MacErrorType, KeyHandle,
1818
};
1919
use openprot_hal_blocking::mac::{HmacSha2_256, HmacSha2_384, HmacSha2_512};
20-
use openprot_platform_traits_hubris::{HubrisCryptoError, HubrisDigestDevice};
20+
use openprot_platform_traits_hubris::{CryptoSession, HubrisCryptoError, HubrisDigestDevice};
2121
use sha2::{Digest as Sha2Digest, Sha256, Sha384, Sha512};
2222

2323
/// A type implementing RustCrypto-based hash/digest owned traits.
@@ -26,6 +26,8 @@ use sha2::{Digest as Sha2Digest, Sha256, Sha384, Sha512};
2626
///
2727
/// Provides software-based cryptographic operations using the `RustCrypto`
2828
/// ecosystem for Hubris and other embedded environments.
29+
///
30+
/// NOTE: Intentionally non-cloneable to simulate hardware controller behavior
2931
pub struct RustCryptoController {}
3032

3133
impl RustCryptoController {
@@ -535,6 +537,66 @@ impl HubrisDigestDevice for RustCryptoController {
535537
) -> Result<Self::HmacContext512, HubrisCryptoError> {
536538
MacInit::init(self, HmacSha2_512, key).map_err(|_| HubrisCryptoError::HardwareFailure)
537539
}
540+
541+
// Session methods for digest operations
542+
fn init_digest_session_sha256(
543+
self,
544+
) -> Result<CryptoSession<Self::DigestContext256, Self>, HubrisCryptoError> {
545+
// Create context using self, then recover device using new()
546+
let context =
547+
DigestInit::init(self, Sha2_256).map_err(|_| HubrisCryptoError::HardwareFailure)?;
548+
let recovered_device = RustCryptoController::new();
549+
Ok(CryptoSession::new(context, recovered_device))
550+
}
551+
552+
fn init_digest_session_sha384(
553+
self,
554+
) -> Result<CryptoSession<Self::DigestContext384, Self>, HubrisCryptoError> {
555+
let context =
556+
DigestInit::init(self, Sha2_384).map_err(|_| HubrisCryptoError::HardwareFailure)?;
557+
let recovered_device = RustCryptoController::new();
558+
Ok(CryptoSession::new(context, recovered_device))
559+
}
560+
561+
fn init_digest_session_sha512(
562+
self,
563+
) -> Result<CryptoSession<Self::DigestContext512, Self>, HubrisCryptoError> {
564+
let context =
565+
DigestInit::init(self, Sha2_512).map_err(|_| HubrisCryptoError::HardwareFailure)?;
566+
let recovered_device = RustCryptoController::new();
567+
Ok(CryptoSession::new(context, recovered_device))
568+
}
569+
570+
// Session methods for HMAC operations
571+
fn init_hmac_session_sha256(
572+
self,
573+
key: Self::HmacKey,
574+
) -> Result<CryptoSession<Self::HmacContext256, Self>, HubrisCryptoError> {
575+
let context = MacInit::init(self, HmacSha2_256, key)
576+
.map_err(|_| HubrisCryptoError::HardwareFailure)?;
577+
let recovered_device = RustCryptoController::new();
578+
Ok(CryptoSession::new(context, recovered_device))
579+
}
580+
581+
fn init_hmac_session_sha384(
582+
self,
583+
key: Self::HmacKey,
584+
) -> Result<CryptoSession<Self::HmacContext384, Self>, HubrisCryptoError> {
585+
let context = MacInit::init(self, HmacSha2_384, key)
586+
.map_err(|_| HubrisCryptoError::HardwareFailure)?;
587+
let recovered_device = RustCryptoController::new();
588+
Ok(CryptoSession::new(context, recovered_device))
589+
}
590+
591+
fn init_hmac_session_sha512(
592+
self,
593+
key: Self::HmacKey,
594+
) -> Result<CryptoSession<Self::HmacContext512, Self>, HubrisCryptoError> {
595+
let context = MacInit::init(self, HmacSha2_512, key)
596+
.map_err(|_| HubrisCryptoError::HardwareFailure)?;
597+
let recovered_device = RustCryptoController::new();
598+
Ok(CryptoSession::new(context, recovered_device))
599+
}
538600
}
539601

540602
#[cfg(test)]
@@ -934,4 +996,37 @@ mod tests {
934996
// ✅ heapless::Vec integration working
935997
// ✅ Controller recovery after operations working
936998
}
999+
1000+
#[test]
1001+
fn test_session_guards_with_non_cloneable_controller() {
1002+
use openprot_platform_traits_hubris::HubrisDigestDevice;
1003+
1004+
// Test that SessionGuards work with non-cloneable controllers (hardware simulation)
1005+
let controller = RustCryptoController::new();
1006+
1007+
// Test digest session guard
1008+
let digest_session = controller.init_digest_session_sha256().unwrap();
1009+
let digest_session = digest_session.update(b"Hello, ").unwrap();
1010+
let digest_session = digest_session.update(b"hardware simulation!").unwrap();
1011+
let (digest, recovered_controller) = digest_session.finalize().unwrap();
1012+
1013+
// Verify we got back a controller and can use it again
1014+
assert_eq!(digest.as_bytes().len(), 32); // SHA-256 produces 32 bytes
1015+
1016+
// Test HMAC session guard with recovered controller
1017+
let key = SecureOwnedKey::new(b"test_key").unwrap();
1018+
let hmac_session = recovered_controller.init_hmac_session_sha256(key).unwrap();
1019+
let hmac_session = hmac_session.update_mac(b"Hello, ").unwrap();
1020+
let hmac_session = hmac_session.update_mac(b"hardware simulation!").unwrap();
1021+
let (hmac, _final_controller) = hmac_session.finalize_mac().unwrap();
1022+
1023+
assert_eq!(hmac.len(), 32); // HMAC-SHA256 produces 32 bytes
1024+
1025+
// This test proves:
1026+
// ✅ SessionGuards work without requiring Clone on the controller
1027+
// ✅ Device recovery strategy allows reuse of hardware resources
1028+
// ✅ RAII pattern ensures proper resource management
1029+
// ✅ Compatible with both digest and MAC operations
1030+
// ✅ Simulates real hardware controller constraints
1031+
}
9371032
}

platform/traits/hubris/src/lib.rs

Lines changed: 173 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use openprot_hal_blocking::{
2626
/// Hubris IPC error codes for inter-task communication.
2727
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2828
pub enum HubrisCryptoError {
29-
/// Invalid key length for the requested operation333
29+
/// Invalid key length for the requested operation
3030
InvalidKeyLength,
3131
/// Hardware crypto accelerator failure
3232
HardwareFailure,
@@ -36,6 +36,129 @@ pub enum HubrisCryptoError {
3636
ResourceBusy,
3737
/// Operation not supported by hardware
3838
NotSupported,
39+
/// Session state error (context or device missing)
40+
SessionStateError,
41+
}
42+
43+
/// RAII-style crypto session management
44+
///
45+
/// This type provides RAII-style resource management for crypto devices used in
46+
/// session-based operations. It ensures that crypto hardware devices are properly
47+
/// recovered and can be reused after operations complete.
48+
///
49+
/// The CryptoSession handles the fundamental constraint that hardware controllers
50+
/// cannot be cloned, providing a mechanism for device recovery that works with
51+
/// both software implementations (which can create new instances) and hardware
52+
/// controllers (which require different recovery strategies).
53+
///
54+
/// ## Design Rationale
55+
///
56+
/// Session-based crypto operations consume the device when creating contexts,
57+
/// but we need to recover the device for reuse. This type solves that by:
58+
/// 1. Storing both the crypto context and a recovery device
59+
/// 2. Providing update/finalize methods that manage the context lifecycle
60+
/// 3. Returning the recovered device when the session completes
61+
///
62+
/// ## Usage Pattern
63+
///
64+
/// ```rust,ignore
65+
/// let session = device.init_digest_session_sha256()?;
66+
/// let session = session.update(b"data")?;
67+
/// let (result, recovered_device) = session.finalize()?;
68+
/// // recovered_device can now be used for new operations
69+
/// ```
70+
pub struct CryptoSession<Context, Device> {
71+
context: Option<Context>,
72+
device: Option<Device>,
73+
}
74+
75+
impl<Context, Device> CryptoSession<Context, Device> {
76+
/// Create a new crypto session with the given context and recovery device
77+
pub fn new(context: Context, device: Device) -> Self {
78+
Self {
79+
context: Some(context),
80+
device: Some(device),
81+
}
82+
}
83+
84+
/// Take the context out of the session (for move operations)
85+
fn take_context(&mut self) -> Result<Context, HubrisCryptoError> {
86+
self.context
87+
.take()
88+
.ok_or(HubrisCryptoError::SessionStateError)
89+
}
90+
91+
/// Put a context back into the session (after move operations)
92+
fn put_context(&mut self, context: Context) {
93+
self.context = Some(context);
94+
}
95+
96+
/// Update the session with new data
97+
///
98+
/// This method uses move semantics to update the context while maintaining
99+
/// the device for recovery.
100+
pub fn update(mut self, data: &[u8]) -> Result<Self, HubrisCryptoError>
101+
where
102+
Context: DigestOp<Controller = Device>,
103+
{
104+
let context = self.take_context()?;
105+
let updated_context = context
106+
.update(data)
107+
.map_err(|_| HubrisCryptoError::HardwareFailure)?;
108+
self.put_context(updated_context);
109+
Ok(self)
110+
}
111+
112+
/// Finalize the digest session and recover the device
113+
///
114+
/// Returns the computed result and the device for reuse.
115+
pub fn finalize(mut self) -> Result<(Context::Output, Device), HubrisCryptoError>
116+
where
117+
Context: DigestOp<Controller = Device>,
118+
{
119+
let context = self.take_context()?;
120+
let (output, _controller) = context
121+
.finalize()
122+
.map_err(|_| HubrisCryptoError::HardwareFailure)?;
123+
124+
// Recover our device from the session
125+
let device = self
126+
.device
127+
.take()
128+
.ok_or(HubrisCryptoError::SessionStateError)?;
129+
Ok((output, device))
130+
}
131+
132+
/// Update the MAC session with new data
133+
pub fn update_mac(mut self, data: &[u8]) -> Result<Self, HubrisCryptoError>
134+
where
135+
Context: MacOp<Controller = Device>,
136+
{
137+
let context = self.take_context()?;
138+
let updated_context = context
139+
.update(data)
140+
.map_err(|_| HubrisCryptoError::HardwareFailure)?;
141+
self.put_context(updated_context);
142+
Ok(self)
143+
}
144+
145+
/// Finalize the MAC session and recover the device
146+
pub fn finalize_mac(mut self) -> Result<(Context::Output, Device), HubrisCryptoError>
147+
where
148+
Context: MacOp<Controller = Device>,
149+
{
150+
let context = self.take_context()?;
151+
let (output, _controller) = context
152+
.finalize()
153+
.map_err(|_| HubrisCryptoError::HardwareFailure)?;
154+
155+
// Recover our device from the session
156+
let device = self
157+
.device
158+
.take()
159+
.ok_or(HubrisCryptoError::SessionStateError)?;
160+
Ok((output, device))
161+
}
39162
}
40163

41164
/// Hubrus-specific digest device trait
@@ -108,11 +231,57 @@ pub trait HubrisDigestDevice {
108231
/// - Validates key size against device limits
109232
/// - Ensures compatibility with task memory constraints
110233
fn create_hmac_key(data: &[u8]) -> Result<Self::HmacKey, HubrisCryptoError> {
111-
if data.len() > Self::MAX_KEY_SIZE {
112-
return Err(HubrisCryptoError::InvalidKeyLength);
113-
}
114234
Self::HmacKey::try_from(data).map_err(|_| HubrisCryptoError::InvalidKeyLength)
115235
}
236+
237+
// Session methods for digest operations
238+
239+
/// Initialize SHA-256 digest session with device recovery
240+
fn init_digest_session_sha256(
241+
self,
242+
) -> Result<CryptoSession<Self::DigestContext256, Self>, HubrisCryptoError>
243+
where
244+
Self: Sized;
245+
246+
/// Initialize SHA-384 digest session with device recovery
247+
fn init_digest_session_sha384(
248+
self,
249+
) -> Result<CryptoSession<Self::DigestContext384, Self>, HubrisCryptoError>
250+
where
251+
Self: Sized;
252+
253+
/// Initialize SHA-512 digest session with device recovery
254+
fn init_digest_session_sha512(
255+
self,
256+
) -> Result<CryptoSession<Self::DigestContext512, Self>, HubrisCryptoError>
257+
where
258+
Self: Sized;
259+
260+
// Session methods for HMAC operations
261+
262+
/// Initialize HMAC-SHA256 session with device recovery
263+
fn init_hmac_session_sha256(
264+
self,
265+
key: Self::HmacKey,
266+
) -> Result<CryptoSession<Self::HmacContext256, Self>, HubrisCryptoError>
267+
where
268+
Self: Sized;
269+
270+
/// Initialize HMAC-SHA384 session with device recovery
271+
fn init_hmac_session_sha384(
272+
self,
273+
key: Self::HmacKey,
274+
) -> Result<CryptoSession<Self::HmacContext384, Self>, HubrisCryptoError>
275+
where
276+
Self: Sized;
277+
278+
/// Initialize HMAC-SHA512 session with device recovery
279+
fn init_hmac_session_sha512(
280+
self,
281+
key: Self::HmacKey,
282+
) -> Result<CryptoSession<Self::HmacContext512, Self>, HubrisCryptoError>
283+
where
284+
Self: Sized;
116285
}
117286

118287
/// Extension trait for one-shot operations in Hubris

0 commit comments

Comments
 (0)