alpine/handshake/
mod.rs

1use async_trait::async_trait;
2use rand::{rngs::OsRng, RngCore};
3use serde::{Deserialize, Serialize};
4use thiserror::Error;
5
6use crate::crypto::{KeyExchangeAlgorithm, SessionKeys};
7use crate::messages::{
8    Acknowledge, ControlEnvelope, Keepalive, SessionAck, SessionComplete, SessionEstablished,
9    SessionInit, SessionReady,
10};
11
12pub mod client;
13pub mod keepalive;
14pub mod server;
15pub mod transport;
16
17/// Transport abstraction used during the ALNP handshake.
18#[async_trait]
19pub trait HandshakeTransport {
20    async fn send(&mut self, msg: HandshakeMessage) -> Result<(), HandshakeError>;
21    async fn recv(&mut self) -> Result<HandshakeMessage, HandshakeError>;
22}
23
24/// Minimal message envelope for the handshake pipeline.
25#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
26pub enum HandshakeMessage {
27    SessionInit(SessionInit),
28    SessionAck(SessionAck),
29    SessionReady(SessionReady),
30    SessionComplete(SessionComplete),
31    SessionEstablished(SessionEstablished),
32    Keepalive(Keepalive),
33    Control(ControlEnvelope),
34    Ack(Acknowledge),
35}
36
37/// Context shared between handshake participants.
38#[derive(Debug, Clone)]
39pub struct HandshakeContext {
40    pub key_algorithm: KeyExchangeAlgorithm,
41    pub expected_controller: Option<String>,
42    pub required_firmware_rev: Option<String>,
43}
44
45impl Default for HandshakeContext {
46    fn default() -> Self {
47        Self {
48            key_algorithm: KeyExchangeAlgorithm::X25519,
49            expected_controller: None,
50            required_firmware_rev: None,
51        }
52    }
53}
54
55#[derive(Debug, Error)]
56pub enum HandshakeError {
57    #[error("transport error: {0}")]
58    Transport(String),
59    #[error("protocol violation: {0}")]
60    Protocol(String),
61    #[error("authentication failed: {0}")]
62    Authentication(String),
63    #[error("unsupported capability: {0}")]
64    Capability(String),
65}
66
67/// Generates a cryptographic nonce for challenge/response.
68pub fn new_nonce() -> [u8; 32] {
69    let mut bytes = [0u8; 32];
70    OsRng.fill_bytes(&mut bytes);
71    bytes
72}
73
74/// Shared behavior between controller and node handshake roles.
75#[async_trait]
76pub trait HandshakeParticipant {
77    async fn run<T: HandshakeTransport + Send>(
78        &self,
79        transport: &mut T,
80    ) -> Result<HandshakeOutcome, HandshakeError>;
81}
82
83/// Minimal authenticator stub for challenge validation.
84pub trait ChallengeAuthenticator {
85    fn sign_challenge(&self, nonce: &[u8]) -> Vec<u8>;
86    fn verify_challenge(&self, nonce: &[u8], signature: &[u8]) -> bool;
87}
88
89/// Output returned by handshake drivers.
90#[derive(Debug, Clone)]
91pub struct HandshakeOutcome {
92    pub established: SessionEstablished,
93    pub keys: SessionKeys,
94}