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.
13
pub(crate) mod fast;
14
#[cfg(feature = "hs")]
15
pub(crate) mod hs_ntor;
16
pub(crate) mod ntor;
17
#[cfg(feature = "ntor_v3")]
18
pub(crate) mod ntor_v3;
19

            
20
use crate::{Result, SecretBytes};
21
//use zeroize::Zeroizing;
22
use rand_core::{CryptoRng, RngCore};
23

            
24
/// A ClientHandshake is used to generate a client onionskin and
25
/// handle a relay onionskin.
26
pub(crate) trait ClientHandshake {
27
    /// The type for the onion key.
28
    type KeyType;
29
    /// The type for the state that the client holds while waiting for a reply.
30
    type StateType;
31
    /// A type that is returned and used to generate session keys.x
32
    type KeyGen;
33
    /// Generate a new client onionskin for a relay with a given onion key.
34
    ///
35
    /// On success, return a state object that will be used to
36
    /// complete the handshake, along with the message to send.
37
    fn client1<R: RngCore + CryptoRng>(
38
        rng: &mut R,
39
        key: &Self::KeyType,
40
    ) -> Result<(Self::StateType, Vec<u8>)>;
41
    /// Handle an onionskin from a relay, and produce a key generator.
42
    ///
43
    /// The state object must match the one that was used to make the
44
    /// client onionskin that the server is replying to.
45
    fn client2<T: AsRef<[u8]>>(state: Self::StateType, msg: T) -> Result<Self::KeyGen>;
46
}
47

            
48
/// A ServerHandshake is used to handle a client onionskin and generate a
49
/// server onionskin.
50
pub(crate) trait ServerHandshake {
51
    /// The type for the onion key.  This is a private key type.
52
    type KeyType;
53
    /// The returned key generator type.
54
    type KeyGen;
55

            
56
    /// Perform the server handshake.  Take as input a strong PRNG in `rng`,
57
    /// a slice of all our private onion keys, and the client's message.
58
    ///
59
    /// On success, return a key generator and a server handshake message
60
    /// to send in reply.
61
    fn server<R: RngCore + CryptoRng, T: AsRef<[u8]>>(
62
        rng: &mut R,
63
        key: &[Self::KeyType],
64
        msg: T,
65
    ) -> RelayHandshakeResult<(Self::KeyGen, Vec<u8>)>;
66
}
67

            
68
/// A KeyGenerator is returned by a handshake, and used to generate
69
/// session keys for the protocol.
70
///
71
/// Typically, it wraps a KDF function, and some seed key material.
72
///
73
/// It can only be used once.
74
pub(crate) trait KeyGenerator {
75
    /// Consume the key
76
    fn expand(self, keylen: usize) -> Result<SecretBytes>;
77
}
78

            
79
/// Generates keys based on the KDF-TOR function.
80
///
81
/// This is deprecated and shouldn't be used for new keys.
82
pub(crate) struct TapKeyGenerator {
83
    /// Seed for the TAP KDF.
84
    seed: SecretBytes,
85
}
86

            
87
impl TapKeyGenerator {
88
    /// Create a key generator based on a provided seed
89
15
    pub(crate) fn new(seed: SecretBytes) -> Self {
90
15
        TapKeyGenerator { seed }
91
15
    }
92
}
93

            
94
impl KeyGenerator for TapKeyGenerator {
95
10
    fn expand(self, keylen: usize) -> Result<SecretBytes> {
96
10
        use crate::crypto::ll::kdf::{Kdf, LegacyKdf};
97
10
        LegacyKdf::new(1).derive(&self.seed[..], keylen)
98
10
    }
99
}
100

            
101
/// Generates keys based on SHAKE-256.
102
pub(crate) struct ShakeKeyGenerator {
103
    /// Seed for the key generator
104
    seed: SecretBytes,
105
}
106

            
107
impl ShakeKeyGenerator {
108
    /// Create a key generator based on a provided seed
109
    #[allow(dead_code)] // We'll construct these for v3 onion services
110
6
    pub(crate) fn new(seed: SecretBytes) -> Self {
111
6
        ShakeKeyGenerator { seed }
112
6
    }
113
}
114

            
115
impl KeyGenerator for ShakeKeyGenerator {
116
6
    fn expand(self, keylen: usize) -> Result<SecretBytes> {
117
6
        use crate::crypto::ll::kdf::{Kdf, ShakeKdf};
118
6
        ShakeKdf::new().derive(&self.seed[..], keylen)
119
6
    }
120
}
121

            
122
/// An error produced by a Relay's attempt to handle a client's onion handshake.
123
#[derive(Clone, Debug, thiserror::Error)]
124
pub(crate) enum RelayHandshakeError {
125
    /// An error in parsing or encoding a handshake message.
126
    #[error("problem in handshake format.")]
127
    Fmt(#[from] tor_bytes::Error),
128
    /// The client asked for a key we didn't have.
129
    #[error("unrecognized key or identity in handshake")]
130
    MissingKey,
131
    /// The client did something wrong with their handshake or cryptography.
132
    #[error("bad handshake from client")]
133
    BadHandshake,
134
    /// An internal error.
135
    #[error("internal error")]
136
    Internal(#[from] tor_error::Bug),
137
}
138

            
139
/// Type alias for results from a relay's attempt to handle a client's onion
140
/// handshake.
141
pub(crate) type RelayHandshakeResult<T> = std::result::Result<T, RelayHandshakeError>;