Skip to main content

tor_proto/crypto/
handshake.rs

1//! Circuit extension handshake for Tor.
2//!
3//! Tor circuit handshakes all implement a one-way-authenticated key
4//! exchange, where a client that knows a public "onion key" for a
5//! relay sends a "client onionskin" to extend to a relay, and receives a
6//! "relay onionskin" in response.  When the handshake is successful,
7//! both the client and relay share a set of session keys, and the
8//! client knows that nobody _else_ shares those keys unless they
9//! relay's private onion key.
10//!
11//! Currently, this module implements only the "ntor" handshake used
12//! for circuits on today's Tor.
13pub(crate) mod fast;
14#[cfg(feature = "hs-common")]
15pub mod hs_ntor;
16pub(crate) mod ntor;
17pub(crate) mod ntor_v3;
18
19use std::borrow::Borrow;
20
21use crate::Result;
22//use zeroize::Zeroizing;
23use rand_core::{CryptoRng, Rng};
24use tor_bytes::SecretBuf;
25use tor_error::{ErrorKind, HasKind};
26
27/// A ClientHandshake is used to generate a client onionskin and
28/// handle a relay onionskin.
29pub(crate) trait ClientHandshake {
30    /// The type for the onion key.
31    type KeyType;
32    /// The type for the state that the client holds while waiting for a reply.
33    type StateType;
34    /// A type that is returned and used to generate session keys.x
35    type KeyGen;
36    /// Type of extra data sent from client (without forward secrecy).
37    type ClientAuxData: ?Sized;
38    /// Type of extra data returned by server (without forward secrecy).
39    type ServerAuxData;
40    /// Generate a new client onionskin for a relay with a given onion key,
41    /// including `client_aux_data` to be sent without forward secrecy.
42    ///
43    /// On success, return a state object that will be used to
44    /// complete the handshake, along with the message to send.
45    fn client1<R: Rng + CryptoRng, M: Borrow<Self::ClientAuxData>>(
46        rng: &mut R,
47        key: &Self::KeyType,
48        client_aux_data: &M,
49    ) -> Result<(Self::StateType, Vec<u8>)>;
50    /// Handle an onionskin from a relay, and produce aux data returned
51    /// from the server, and a key generator.
52    ///
53    /// The state object must match the one that was used to make the
54    /// client onionskin that the server is replying to.
55    fn client2<T: AsRef<[u8]>>(
56        state: Self::StateType,
57        msg: T,
58    ) -> Result<(Self::ServerAuxData, Self::KeyGen)>;
59}
60
61/// Trait for an object that handles incoming auxiliary data and
62/// returns the server's auxiliary data to be included in the reply.
63///
64/// This is implemented for `FnMut(&H::ClientAuxData) -> Option<H::ServerAuxData>` automatically.
65pub(crate) trait AuxDataReply<H>
66where
67    H: ServerHandshake + ?Sized,
68{
69    /// Given a list of extensions received from a client, decide
70    /// what extensions to send in reply.
71    ///
72    /// Return None if the handshake should fail.
73    fn reply(&mut self, msg: &H::ClientAuxData) -> Option<H::ServerAuxData>;
74}
75
76impl<F, H> AuxDataReply<H> for F
77where
78    H: ServerHandshake + ?Sized,
79    F: FnMut(&H::ClientAuxData) -> Option<H::ServerAuxData>,
80{
81    fn reply(&mut self, msg: &H::ClientAuxData) -> Option<H::ServerAuxData> {
82        self(msg)
83    }
84}
85
86/// A ServerHandshake is used to handle a client onionskin and generate a
87/// server onionskin.
88pub(crate) trait ServerHandshake {
89    /// The type for the onion key.  This is a private key type.
90    type KeyType;
91    /// The returned key generator type.
92    type KeyGen;
93    /// Type of extra data sent from client (without forward secrecy).
94    type ClientAuxData: ?Sized;
95    /// Type of extra data returned by server (without forward secrecy).
96    type ServerAuxData;
97
98    /// Perform the server handshake.  Take as input a strong PRNG in `rng`, a
99    /// function for processing requested extensions, a slice of all our private
100    /// onion keys, and the client's message.
101    ///
102    /// On success, return a key generator and a server handshake message
103    /// to send in reply.
104    #[allow(dead_code)] // TODO #1383 ????
105    fn server<R: Rng + CryptoRng, REPLY: AuxDataReply<Self>, T: AsRef<[u8]>>(
106        rng: &mut R,
107        reply_fn: &mut REPLY,
108        key: &[Self::KeyType],
109        msg: T,
110    ) -> RelayHandshakeResult<(Self::KeyGen, Vec<u8>)>;
111}
112
113/// A KeyGenerator is returned by a handshake, and used to generate
114/// session keys for the protocol.
115///
116/// Typically, it wraps a KDF function, and some seed key material.
117///
118/// It can only be used once.
119#[allow(unreachable_pub)] // This is only exported depending on enabled features.
120pub trait KeyGenerator {
121    /// Consume the key
122    fn expand(self, keylen: usize) -> Result<SecretBuf>;
123}
124
125/// Generates keys based on the KDF-TOR function.
126///
127/// This is deprecated and shouldn't be used for new keys.
128pub(crate) struct TapKeyGenerator {
129    /// Seed for the TAP KDF.
130    seed: SecretBuf,
131}
132
133impl TapKeyGenerator {
134    /// Create a key generator based on a provided seed
135    pub(crate) fn new(seed: SecretBuf) -> Self {
136        TapKeyGenerator { seed }
137    }
138}
139
140impl KeyGenerator for TapKeyGenerator {
141    fn expand(self, keylen: usize) -> Result<SecretBuf> {
142        use crate::crypto::ll::kdf::{Kdf, LegacyKdf};
143        LegacyKdf::new(1).derive(&self.seed[..], keylen)
144    }
145}
146
147/// Generates keys based on SHAKE-256.
148#[cfg_attr(feature = "bench", visibility::make(pub))]
149pub(crate) struct ShakeKeyGenerator {
150    /// Seed for the key generator
151    seed: SecretBuf,
152}
153
154impl ShakeKeyGenerator {
155    /// Create a key generator based on a provided seed
156    #[allow(dead_code)] // We'll construct these for v3 onion services
157    #[cfg_attr(feature = "bench", visibility::make(pub))]
158    pub(crate) fn new(seed: SecretBuf) -> Self {
159        ShakeKeyGenerator { seed }
160    }
161}
162
163impl KeyGenerator for ShakeKeyGenerator {
164    fn expand(self, keylen: usize) -> Result<SecretBuf> {
165        use crate::crypto::ll::kdf::{Kdf, ShakeKdf};
166        ShakeKdf::new().derive(&self.seed[..], keylen)
167    }
168}
169
170/// An error produced by a Relay's attempt to handle a client's onion handshake.
171#[derive(Clone, Debug, thiserror::Error)]
172pub(crate) enum RelayHandshakeError {
173    /// An error in parsing a handshake message.
174    #[error("Problem decoding onion handshake")]
175    Fmt(#[from] tor_bytes::Error),
176    /// The client asked for a key we didn't have.
177    #[error("Client asked for a key or ID that we don't have")]
178    MissingKey,
179    /// The client did something wrong with their handshake or cryptography.
180    #[error("Bad handshake from client")]
181    BadClientHandshake,
182    /// An internal error.
183    #[error("Internal error")]
184    Internal(#[from] tor_error::Bug),
185}
186
187impl HasKind for RelayHandshakeError {
188    fn kind(&self) -> ErrorKind {
189        match self {
190            Self::Fmt(_) => ErrorKind::RemoteProtocolViolation,
191            Self::MissingKey => ErrorKind::RemoteProtocolViolation,
192            Self::BadClientHandshake => ErrorKind::RemoteProtocolViolation,
193            Self::Internal(_) => ErrorKind::Internal,
194        }
195    }
196}
197
198/// Type alias for results from a relay's attempt to handle a client's onion
199/// handshake.
200pub(crate) type RelayHandshakeResult<T> = std::result::Result<T, RelayHandshakeError>;