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