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

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

            
9
use rand::{CryptoRng, RngCore};
10
use tor_error::into_internal;
11

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

            
17
/// State for a CREATE_FAST client handshake.
18
pub(crate) struct CreateFastClientState([u8; FAST_C_HANDSHAKE_LEN]);
19

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

            
25
impl super::ClientHandshake for CreateFastClient {
26
    type KeyType = ();
27
    type StateType = CreateFastClientState;
28
    type KeyGen = super::TapKeyGenerator;
29

            
30
8
    fn client1<R: RngCore + CryptoRng>(
31
8
        rng: &mut R,
32
8
        _key: &Self::KeyType,
33
8
    ) -> Result<(Self::StateType, Vec<u8>)> {
34
8
        let mut state = [0_u8; FAST_C_HANDSHAKE_LEN];
35
8
        rng.fill_bytes(&mut state);
36
8
        Ok((CreateFastClientState(state), state.into()))
37
8
    }
38

            
39
8
    fn client2<T: AsRef<[u8]>>(state: Self::StateType, msg: T) -> Result<Self::KeyGen> {
40
8
        let msg = msg.as_ref();
41
8
        if msg.len() != FAST_S_HANDSHAKE_LEN {
42
            return Err(Error::BadCircHandshake);
43
8
        }
44
8
        let mut inp = Vec::new();
45
8
        inp.extend(&state.0[..]);
46
8
        inp.extend(&msg[0..20]);
47

            
48
8
        let kh_expect = LegacyKdf::new(0).derive(&inp[..], 20)?;
49

            
50
8
        if !bytes_eq(&kh_expect, &msg[20..40]) {
51
1
            return Err(Error::BadCircHandshake);
52
7
        }
53
7

            
54
7
        Ok(super::TapKeyGenerator::new(inp.into()))
55
8
    }
56
}
57

            
58
/// Relay-handshake for CREATE_FAST.
59
///
60
/// See module documentation; you probably don't want to use this.
61
pub(crate) struct CreateFastServer;
62

            
63
impl super::ServerHandshake for CreateFastServer {
64
    type KeyType = ();
65
    type KeyGen = super::TapKeyGenerator;
66

            
67
9
    fn server<R: RngCore + CryptoRng, T: AsRef<[u8]>>(
68
9
        rng: &mut R,
69
9
        _key: &[Self::KeyType],
70
9
        msg: T,
71
9
    ) -> RelayHandshakeResult<(Self::KeyGen, Vec<u8>)> {
72
9
        let msg = msg.as_ref();
73
9
        if msg.len() != FAST_C_HANDSHAKE_LEN {
74
1
            return Err(RelayHandshakeError::BadHandshake);
75
8
        }
76
8
        let mut reply = vec![0_u8; FAST_S_HANDSHAKE_LEN];
77
8
        rng.fill_bytes(&mut reply[0..20]);
78
8

            
79
8
        let mut inp = Vec::new();
80
8
        inp.extend(msg);
81
8
        inp.extend(&reply[0..20]);
82
8
        let kh = LegacyKdf::new(0)
83
8
            .derive(&inp[..], 20)
84
8
            .map_err(into_internal!("Can't expand key"))?;
85
8
        reply[20..].copy_from_slice(&kh);
86
8

            
87
8
        Ok((super::TapKeyGenerator::new(inp.into()), reply))
88
9
    }
89
}
90

            
91
#[cfg(test)]
92
mod test {
93
    #![allow(clippy::unwrap_used)]
94
    use super::*;
95
    use crate::crypto::handshake::{ClientHandshake, KeyGenerator, ServerHandshake};
96
    use hex_literal::hex;
97

            
98
    #[test]
99
    fn roundtrip() {
100
        let mut rng = rand::thread_rng();
101

            
102
        let (state, cmsg) = CreateFastClient::client1(&mut rng, &()).unwrap();
103
        let (s_kg, smsg) = CreateFastServer::server(&mut rng, &[()], cmsg).unwrap();
104
        let c_kg = CreateFastClient::client2(state, smsg).unwrap();
105

            
106
        let s_key = s_kg.expand(200).unwrap();
107
        let c_key = c_kg.expand(200).unwrap();
108

            
109
        assert_eq!(s_key, c_key);
110
    }
111

            
112
    #[test]
113
    fn failure() {
114
        let mut rng = rand::thread_rng();
115

            
116
        // badly formatted client message.
117
        let cmsg = [6_u8; 19];
118
        let ans = CreateFastServer::server(&mut rng, &[()], cmsg);
119
        assert!(ans.is_err());
120

            
121
        // corrupt/ incorrect server reply.
122
        let (state, cmsg) = CreateFastClient::client1(&mut rng, &()).unwrap();
123
        let (_, mut smsg) = CreateFastServer::server(&mut rng, &[()], cmsg).unwrap();
124
        smsg[35] ^= 16;
125
        let ans = CreateFastClient::client2(state, smsg);
126
        assert!(ans.is_err());
127
    }
128

            
129
    fn test_one_handshake(cmsg: [u8; 20], smsg: [u8; 40], keys: [u8; 100]) {
130
        use crate::crypto::testing::FakePRNG;
131

            
132
        let mut rng = FakePRNG::new(&cmsg);
133
        let (state, cmsg) = CreateFastClient::client1(&mut rng, &()).unwrap();
134

            
135
        let mut rng = FakePRNG::new(&smsg);
136
        let (s_kg, smsg) = CreateFastServer::server(&mut rng, &[()], cmsg).unwrap();
137
        let c_kg = CreateFastClient::client2(state, smsg).unwrap();
138

            
139
        let s_key = s_kg.expand(100).unwrap();
140
        let c_key = c_kg.expand(100).unwrap();
141

            
142
        assert_eq!(s_key, c_key);
143
        assert_eq!(&s_key[..], &keys[..]);
144
    }
145

            
146
    #[test]
147
    fn testvec() {
148
        // Generated from Tor.
149
        test_one_handshake(
150
            hex!("080E247DF7C252FCD2DC10F459703480C223E3A6"),
151
            hex!("BA95C0D092335428BF80093BBED0B7A26C49E1E8696FBF9C8D6BE26504219C000D26AFE370FCEF04"),
152
            hex!("AFA89B4FC8CF882335A582C52478B5FCB1E08DAF707E2C2D23B8C27D30BD461F3DF98A3AF82221CB658AD0AA8680B99067E4F7DBC546970EA9A56B26433C71DA867BDD09C14A1308BC327D6A448D71D2382B3AB6AF0BB4E19649A8DFF607DB9C57A04AC3"));
153

            
154
        test_one_handshake(
155
            hex!("5F786C724C2F5978474A04FA63772057AD896A03"),
156
            hex!("6210B037001405742FE78B6F5B34E6DB3C9F2F7E24239498613E0ED872E110A00774A3FCB37A7507"),
157
            hex!("D41B65D83FB4B34A322B658BE4D706EDCD8B62813757E719118C394E1F22E1C8EA8959BAB30E856A914C3054946F547397094DE031F5BCA384C65C8880BF7AAB9CE7BEE33971F9DE8C22A23366F46BF8B5E5112321E216B0E02C62EEA3ABB72A0E062592"));
158
    }
159
}