1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
//! Circuit extension handshake for Tor.
//!
//! Tor circuit handshakes all implement a one-way-authenticated key
//! exchange, where a client that knows a public "onion key" for a
//! relay sends a "client onionskin" to extend to a relay, and receives a
//! "relay onionskin" in response.  When the handshake is successful,
//! both the client and relay share a set of session keys, and the
//! client knows that nobody _else_ shares those keys unless they
//! relay's private onion key.
//!
//! Currently, this module implements only the "ntor" handshake used
//! for circuits on today's Tor.
pub(crate) mod fast;
#[cfg(feature = "hs")]
pub(crate) mod hs_ntor;
pub(crate) mod ntor;
#[cfg(feature = "ntor_v3")]
pub(crate) mod ntor_v3;

use crate::{Result, SecretBytes};
//use zeroize::Zeroizing;
use rand_core::{CryptoRng, RngCore};

/// A ClientHandshake is used to generate a client onionskin and
/// handle a relay onionskin.
pub(crate) trait ClientHandshake {
    /// The type for the onion key.
    type KeyType;
    /// The type for the state that the client holds while waiting for a reply.
    type StateType;
    /// A type that is returned and used to generate session keys.x
    type KeyGen;
    /// Generate a new client onionskin for a relay with a given onion key.
    ///
    /// On success, return a state object that will be used to
    /// complete the handshake, along with the message to send.
    fn client1<R: RngCore + CryptoRng>(
        rng: &mut R,
        key: &Self::KeyType,
    ) -> Result<(Self::StateType, Vec<u8>)>;
    /// Handle an onionskin from a relay, and produce a key generator.
    ///
    /// The state object must match the one that was used to make the
    /// client onionskin that the server is replying to.
    fn client2<T: AsRef<[u8]>>(state: Self::StateType, msg: T) -> Result<Self::KeyGen>;
}

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

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

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

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

impl TapKeyGenerator {
    /// Create a key generator based on a provided seed
    pub(crate) fn new(seed: SecretBytes) -> Self {
        TapKeyGenerator { seed }
    }
}

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

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

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

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

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

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