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