1use async_trait::async_trait;
2use rand::{rngs::OsRng, RngCore};
3use serde::{Deserialize, Serialize};
4use std::time::Duration;
5use thiserror::Error;
6
7use crate::crypto::{KeyExchangeAlgorithm, SessionKeys};
8use crate::messages::{
9 Acknowledge, ControlEnvelope, Keepalive, SessionAck, SessionComplete, SessionEstablished,
10 SessionInit, SessionReady,
11};
12
13pub mod client;
14pub mod keepalive;
15pub mod server;
16pub mod transport;
17
18#[async_trait]
20pub trait HandshakeTransport {
21 async fn send(&mut self, msg: HandshakeMessage) -> Result<(), HandshakeError>;
22 async fn recv(&mut self) -> Result<HandshakeMessage, HandshakeError>;
23}
24
25#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
27#[serde(untagged)]
28pub enum HandshakeMessage {
29 SessionInit(SessionInit),
30 SessionAck(SessionAck),
31 SessionReady(SessionReady),
32 SessionComplete(SessionComplete),
33 SessionEstablished(SessionEstablished),
34 Keepalive(Keepalive),
35 Control(ControlEnvelope),
36 Ack(Acknowledge),
37}
38
39#[derive(Debug, Clone)]
41pub struct HandshakeContext {
42 pub key_algorithm: KeyExchangeAlgorithm,
43 pub expected_controller: Option<String>,
44 pub required_firmware_rev: Option<String>,
45 pub client_nonce: Vec<u8>,
46 pub device_identity_pubkey: Option<Vec<u8>>,
47 pub recv_timeout: Duration,
48 pub debug_cbor: bool,
49}
50
51impl HandshakeContext {
52 pub fn with_client_nonce(mut self, nonce: Vec<u8>) -> Self {
53 self.client_nonce = nonce;
54 self
55 }
56
57 pub fn with_device_identity_pubkey(mut self, pubkey: Vec<u8>) -> Self {
58 self.device_identity_pubkey = Some(pubkey);
59 self
60 }
61
62 pub fn with_recv_timeout(mut self, timeout: Duration) -> Self {
63 self.recv_timeout = timeout;
64 self
65 }
66
67 pub fn with_debug_cbor(mut self, enabled: bool) -> Self {
68 self.debug_cbor = enabled;
69 self
70 }
71}
72
73impl Default for HandshakeContext {
74 fn default() -> Self {
75 Self {
76 key_algorithm: KeyExchangeAlgorithm::X25519,
77 expected_controller: None,
78 required_firmware_rev: None,
79 client_nonce: new_nonce().to_vec(),
80 device_identity_pubkey: None,
81 recv_timeout: Duration::from_millis(7000),
82 debug_cbor: false,
83 }
84 }
85}
86
87#[derive(Debug, Error)]
88pub enum HandshakeError {
89 #[error("transport error: {0}")]
90 Transport(String),
91 #[error("protocol violation: {0}")]
92 Protocol(String),
93 #[error("authentication failed: {0}")]
94 Authentication(String),
95 #[error("unsupported capability: {0}")]
96 Capability(String),
97}
98
99pub fn new_nonce() -> [u8; 32] {
101 let mut bytes = [0u8; 32];
102 OsRng.fill_bytes(&mut bytes);
103 bytes
104}
105
106#[async_trait]
108pub trait HandshakeParticipant {
109 async fn run<T: HandshakeTransport + Send>(
110 &self,
111 transport: &mut T,
112 ) -> Result<HandshakeOutcome, HandshakeError>;
113}
114
115pub trait ChallengeAuthenticator {
117 fn sign_challenge(&self, nonce: &[u8]) -> Vec<u8>;
118 fn verify_challenge(&self, nonce: &[u8], signature: &[u8]) -> bool;
119 fn identity_verifying_key(&self) -> Option<Vec<u8>> {
120 None
121 }
122}
123
124#[derive(Debug, Clone)]
126pub struct HandshakeOutcome {
127 pub established: SessionEstablished,
128 pub keys: SessionKeys,
129}