1
//! Implementation for the (deprecated) CreateFast handshake.
2
//!
3

            
4
use std::borrow::Borrow;
5

            
6
use super::{RelayHandshakeError, RelayHandshakeResult};
7
use crate::crypto::ll::kdf::{Kdf, LegacyKdf};
8
use crate::util::ct::bytes_eq;
9
use crate::{Error, Result};
10

            
11
use rand::{CryptoRng, Rng};
12
use tor_bytes::SecretBuf;
13
use tor_error::into_internal;
14

            
15
/// Number of bytes used for a "CREATE_FAST" handshake by the initiator.
16
pub(crate) const FAST_C_HANDSHAKE_LEN: usize = 20;
17
/// Number of bytes used for a "CREATE_FAST" handshake by the responder
18
pub(crate) const FAST_S_HANDSHAKE_LEN: usize = 20 * 2;
19

            
20
/// State for a CREATE_FAST client handshake.
21
pub(crate) struct CreateFastClientState([u8; FAST_C_HANDSHAKE_LEN]);
22

            
23
/// Client-handshake for CREATE_FAST.
24
///
25
/// See module documentation; you probably don't want to use this.
26
pub(crate) struct CreateFastClient;
27

            
28
/// How many bytes does this handshake use for its input seed?
29
const SECRET_INPUT_LEN: usize = 40;
30

            
31
impl super::ClientHandshake for CreateFastClient {
32
    type KeyType = ();
33
    type StateType = CreateFastClientState;
34
    type KeyGen = super::TapKeyGenerator;
35
    type ClientAuxData = ();
36
    type ServerAuxData = ();
37

            
38
20
    fn client1<R: Rng + CryptoRng, M: Borrow<()>>(
39
20
        rng: &mut R,
40
20
        _key: &Self::KeyType,
41
20
        _client_aux_data: &M,
42
20
    ) -> Result<(Self::StateType, Vec<u8>)> {
43
20
        let mut state = [0_u8; FAST_C_HANDSHAKE_LEN];
44
20
        rng.fill_bytes(&mut state);
45
20
        Ok((CreateFastClientState(state), state.into()))
46
20
    }
47

            
48
20
    fn client2<T: AsRef<[u8]>>(state: Self::StateType, msg: T) -> Result<((), Self::KeyGen)> {
49
20
        let msg = msg.as_ref();
50
20
        if msg.len() != FAST_S_HANDSHAKE_LEN {
51
            return Err(Error::BadCircHandshakeAuth);
52
20
        }
53
        // There is not necessarily much point here (and below) in using a
54
        // SecretBuf, since the data at issue are already in a cell that
55
        // _wasn't_ marked with Zeroize.  Still, for consistency, we use it
56
        // here.
57
20
        let mut inp = SecretBuf::with_capacity(SECRET_INPUT_LEN);
58
20
        inp.extend_from_slice(&state.0[..]);
59
20
        inp.extend_from_slice(&msg[0..20]);
60

            
61
20
        let kh_expect = LegacyKdf::new(0).derive(&inp[..], 20)?;
62

            
63
20
        if !bytes_eq(&kh_expect, &msg[20..40]) {
64
2
            return Err(Error::BadCircHandshakeAuth);
65
18
        }
66

            
67
18
        Ok(((), super::TapKeyGenerator::new(inp)))
68
20
    }
69
}
70

            
71
/// Relay-handshake for CREATE_FAST.
72
///
73
/// See module documentation; you probably don't want to use this.
74
#[allow(dead_code)] // TODO #1467
75
pub(crate) struct CreateFastServer;
76

            
77
impl super::ServerHandshake for CreateFastServer {
78
    type KeyType = ();
79
    type KeyGen = super::TapKeyGenerator;
80
    type ClientAuxData = ();
81
    type ServerAuxData = ();
82

            
83
22
    fn server<R: Rng + CryptoRng, REPLY: super::AuxDataReply<Self>, T: AsRef<[u8]>>(
84
22
        rng: &mut R,
85
22
        reply_fn: &mut REPLY,
86
22
        _key: &[Self::KeyType],
87
22
        msg: T,
88
22
    ) -> RelayHandshakeResult<(Self::KeyGen, Vec<u8>)> {
89
22
        let _reply_extensions: () = reply_fn
90
22
            .reply(&())
91
22
            .ok_or(RelayHandshakeError::BadClientHandshake)?;
92

            
93
22
        let msg = msg.as_ref();
94
22
        if msg.len() != FAST_C_HANDSHAKE_LEN {
95
2
            return Err(RelayHandshakeError::BadClientHandshake);
96
20
        }
97
20
        let mut reply = vec![0_u8; FAST_S_HANDSHAKE_LEN];
98
20
        rng.fill_bytes(&mut reply[0..20]);
99

            
100
20
        let mut inp = SecretBuf::with_capacity(SECRET_INPUT_LEN);
101
20
        inp.extend_from_slice(msg);
102
20
        inp.extend_from_slice(&reply[0..20]);
103
20
        let kh = LegacyKdf::new(0)
104
20
            .derive(&inp[..], 20)
105
20
            .map_err(into_internal!("Can't expand key"))?;
106
20
        reply[20..].copy_from_slice(&kh);
107

            
108
20
        Ok((super::TapKeyGenerator::new(inp), reply))
109
22
    }
110
}
111

            
112
#[cfg(test)]
113
mod test {
114
    // @@ begin test lint list maintained by maint/add_warning @@
115
    #![allow(clippy::bool_assert_comparison)]
116
    #![allow(clippy::clone_on_copy)]
117
    #![allow(clippy::dbg_macro)]
118
    #![allow(clippy::mixed_attributes_style)]
119
    #![allow(clippy::print_stderr)]
120
    #![allow(clippy::print_stdout)]
121
    #![allow(clippy::single_char_pattern)]
122
    #![allow(clippy::unwrap_used)]
123
    #![allow(clippy::unchecked_time_subtraction)]
124
    #![allow(clippy::useless_vec)]
125
    #![allow(clippy::needless_pass_by_value)]
126
    #![allow(clippy::string_slice)] // See arti#2571
127
    //! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
128
    use super::*;
129
    use crate::crypto::handshake::{ClientHandshake, KeyGenerator, ServerHandshake};
130
    use hex_literal::hex;
131
    use tor_basic_utils::test_rng::testing_rng;
132

            
133
    #[test]
134
    fn roundtrip() {
135
        let mut rng = testing_rng();
136

            
137
        let (state, cmsg) = CreateFastClient::client1(&mut rng, &(), &()).unwrap();
138
        let (s_kg, smsg) =
139
            CreateFastServer::server(&mut rng, &mut |_: &()| Some(()), &[()], cmsg).unwrap();
140
        let (_msg, c_kg) = CreateFastClient::client2(state, smsg).unwrap();
141

            
142
        let s_key = s_kg.expand(200).unwrap();
143
        let c_key = c_kg.expand(200).unwrap();
144

            
145
        assert_eq!(s_key, c_key);
146
    }
147

            
148
    #[test]
149
    fn failure() {
150
        let mut rng = testing_rng();
151

            
152
        // badly formatted client message.
153
        let cmsg = [6_u8; 19];
154
        let ans = CreateFastServer::server(&mut rng, &mut |_: &()| Some(()), &[()], cmsg);
155
        assert!(ans.is_err());
156

            
157
        // corrupt/ incorrect server reply.
158
        let (state, cmsg) = CreateFastClient::client1(&mut rng, &(), &()).unwrap();
159
        let (_, mut smsg) =
160
            CreateFastServer::server(&mut rng, &mut |_: &()| Some(()), &[()], cmsg).unwrap();
161
        smsg[35] ^= 16;
162
        let ans = CreateFastClient::client2(state, smsg);
163
        assert!(ans.is_err());
164
    }
165

            
166
    fn test_one_handshake(cmsg: [u8; 20], smsg: [u8; 40], keys: [u8; 100]) {
167
        use crate::crypto::testing::FakePRNG;
168

            
169
        let mut rng = FakePRNG::new(&cmsg);
170
        let (state, cmsg) = CreateFastClient::client1(&mut rng, &(), &()).unwrap();
171

            
172
        let mut rng = FakePRNG::new(&smsg);
173
        let (s_kg, smsg) =
174
            CreateFastServer::server(&mut rng, &mut |_: &()| Some(()), &[()], cmsg).unwrap();
175
        let (_msg, c_kg) = CreateFastClient::client2(state, smsg).unwrap();
176

            
177
        let s_key = s_kg.expand(100).unwrap();
178
        let c_key = c_kg.expand(100).unwrap();
179

            
180
        assert_eq!(s_key, c_key);
181
        assert_eq!(&s_key[..], &keys[..]);
182
    }
183

            
184
    #[test]
185
    fn testvec() {
186
        // Generated from Tor.
187
        test_one_handshake(
188
            hex!("080E247DF7C252FCD2DC10F459703480C223E3A6"),
189
            hex!(
190
                "BA95C0D092335428BF80093BBED0B7A26C49E1E8696FBF9C8D6BE26504219C000D26AFE370FCEF04"
191
            ),
192
            hex!(
193
                "AFA89B4FC8CF882335A582C52478B5FCB1E08DAF707E2C2D23B8C27D30BD461F3DF98A3AF82221CB658AD0AA8680B99067E4F7DBC546970EA9A56B26433C71DA867BDD09C14A1308BC327D6A448D71D2382B3AB6AF0BB4E19649A8DFF607DB9C57A04AC3"
194
            ),
195
        );
196

            
197
        test_one_handshake(
198
            hex!("5F786C724C2F5978474A04FA63772057AD896A03"),
199
            hex!(
200
                "6210B037001405742FE78B6F5B34E6DB3C9F2F7E24239498613E0ED872E110A00774A3FCB37A7507"
201
            ),
202
            hex!(
203
                "D41B65D83FB4B34A322B658BE4D706EDCD8B62813757E719118C394E1F22E1C8EA8959BAB30E856A914C3054946F547397094DE031F5BCA384C65C8880BF7AAB9CE7BEE33971F9DE8C22A23366F46BF8B5E5112321E216B0E02C62EEA3ABB72A0E062592"
204
            ),
205
        );
206
    }
207
}