alpine/handshake/
server.rs1use async_trait::async_trait;
2use uuid::Uuid;
3
4use super::{
5 new_nonce, ChallengeAuthenticator, HandshakeContext, HandshakeError, HandshakeMessage,
6 HandshakeOutcome, HandshakeParticipant, HandshakeTransport,
7};
8use crate::crypto::{compute_mac, KeyExchange};
9use crate::messages::{
10 CapabilitySet, DeviceIdentity, MessageType, SessionAck, SessionComplete, SessionEstablished,
11};
12
13pub struct ServerHandshake<A, K>
15where
16 A: ChallengeAuthenticator + Send + Sync,
17 K: KeyExchange + Send + Sync,
18{
19 pub identity: DeviceIdentity,
20 pub capabilities: CapabilitySet,
21 pub authenticator: A,
22 pub key_exchange: K,
23 pub context: HandshakeContext,
24}
25
26#[async_trait]
27impl<A, K> HandshakeParticipant for ServerHandshake<A, K>
28where
29 A: ChallengeAuthenticator + Send + Sync,
30 K: KeyExchange + Send + Sync,
31{
32 async fn run<T: HandshakeTransport + Send>(
33 &self,
34 transport: &mut T,
35 ) -> Result<HandshakeOutcome, HandshakeError> {
36 let init = match transport.recv().await? {
38 HandshakeMessage::SessionInit(msg) => msg,
39 other => {
40 return Err(HandshakeError::Protocol(format!(
41 "expected SessionInit, got {:?}",
42 other
43 )))
44 }
45 };
46
47 let _session_uuid = Uuid::parse_str(&init.session_id)
48 .map_err(|_| HandshakeError::Protocol("invalid session_id".into()))?;
49
50 if let Some(expected) = &self.context.expected_controller {
51 if expected != &init.session_id {
52 return Err(HandshakeError::Authentication(
53 "controller identity not authorized".into(),
54 ));
55 }
56 }
57
58 let device_nonce = new_nonce().to_vec();
60 let signature = self.authenticator.sign_challenge(&init.controller_nonce);
61 let identity_pubkey = self
62 .authenticator
63 .identity_verifying_key()
64 .unwrap_or_default();
65 let ack = SessionAck {
66 message_type: MessageType::SessionAck,
67 device_nonce: device_nonce.clone(),
68 device_pubkey: self.key_exchange.public_key(),
69 device_identity_pubkey: identity_pubkey,
70 device_identity: self.identity.clone(),
71 capabilities: self.capabilities.clone(),
72 signature,
73 session_id: init.session_id.clone(),
74 };
75 transport
76 .send(HandshakeMessage::SessionAck(ack.clone()))
77 .await?;
78
79 let ready = match transport.recv().await? {
81 HandshakeMessage::SessionReady(r) => r,
82 other => {
83 return Err(HandshakeError::Protocol(format!(
84 "expected SessionReady, got {:?}",
85 other
86 )))
87 }
88 };
89
90 if ready.session_id != init.session_id {
91 return Err(HandshakeError::Protocol(
92 "session_id mismatch between init and ready".into(),
93 ));
94 }
95
96 let mut salt = init.controller_nonce.clone();
97 salt.extend_from_slice(&device_nonce);
98 let keys = self
99 .key_exchange
100 .derive_keys(&init.controller_pubkey, &salt)
101 .map_err(|e| HandshakeError::Authentication(format!("{}", e)))?;
102 let mac_valid = compute_mac(
103 &keys,
104 0,
105 init.session_id.as_bytes(),
106 device_nonce.as_slice(),
107 )
108 .map(|expected| expected == ready.mac)
109 .unwrap_or(false);
110 if !mac_valid {
111 return Err(HandshakeError::Authentication(
112 "session_ready MAC invalid".into(),
113 ));
114 }
115
116 let complete = SessionComplete {
118 message_type: MessageType::SessionComplete,
119 session_id: init.session_id.clone(),
120 ok: true,
121 error: None,
122 };
123 transport
124 .send(HandshakeMessage::SessionComplete(complete))
125 .await?;
126
127 let established = SessionEstablished {
128 session_id: init.session_id,
129 controller_nonce: init.controller_nonce,
130 device_nonce,
131 capabilities: init.requested,
132 device_identity: self.identity.clone(),
133 };
134
135 Ok(HandshakeOutcome { established, keys })
136 }
137}