1 use byteorder::{BigEndian, ByteOrder, WriteBytesExt};
2 use futures::{Async, Future, Poll};
3 use hmac::{Hmac, Mac};
4 use protobuf::{self, Message};
5 use rand::thread_rng;
6 use sha1::Sha1;
7 use std::io::{self, Read};
8 use std::marker::PhantomData;
9 use tokio_codec::{Decoder, Framed};
10 use tokio_io::io::{read_exact, write_all, ReadExact, Window, WriteAll};
11 use tokio_io::{AsyncRead, AsyncWrite};
12 
13 use super::codec::APCodec;
14 use crate::diffie_hellman::DHLocalKeys;
15 use crate::protocol;
16 use crate::protocol::keyexchange::{APResponseMessage, ClientHello, ClientResponsePlaintext};
17 use crate::util;
18 
19 pub struct Handshake<T> {
20     keys: DHLocalKeys,
21     state: HandshakeState<T>,
22 }
23 
24 enum HandshakeState<T> {
25     ClientHello(WriteAll<T, Vec<u8>>),
26     APResponse(RecvPacket<T, APResponseMessage>),
27     ClientResponse(Option<APCodec>, WriteAll<T, Vec<u8>>),
28 }
29 
handshake<T: AsyncRead + AsyncWrite>(connection: T) -> Handshake<T>30 pub fn handshake<T: AsyncRead + AsyncWrite>(connection: T) -> Handshake<T> {
31     let local_keys = DHLocalKeys::random(&mut thread_rng());
32     let client_hello = client_hello(connection, local_keys.public_key());
33 
34     Handshake {
35         keys: local_keys,
36         state: HandshakeState::ClientHello(client_hello),
37     }
38 }
39 
40 impl<T: AsyncRead + AsyncWrite> Future for Handshake<T> {
41     type Item = Framed<T, APCodec>;
42     type Error = io::Error;
43 
poll(&mut self) -> Poll<Self::Item, io::Error>44     fn poll(&mut self) -> Poll<Self::Item, io::Error> {
45         use self::HandshakeState::*;
46         loop {
47             self.state = match self.state {
48                 ClientHello(ref mut write) => {
49                     let (connection, accumulator) = try_ready!(write.poll());
50 
51                     let read = recv_packet(connection, accumulator);
52                     APResponse(read)
53                 }
54 
55                 APResponse(ref mut read) => {
56                     let (connection, message, accumulator) = try_ready!(read.poll());
57                     let remote_key = message
58                         .get_challenge()
59                         .get_login_crypto_challenge()
60                         .get_diffie_hellman()
61                         .get_gs()
62                         .to_owned();
63 
64                     let shared_secret = self.keys.shared_secret(&remote_key);
65                     let (challenge, send_key, recv_key) =
66                         compute_keys(&shared_secret, &accumulator);
67                     let codec = APCodec::new(&send_key, &recv_key);
68 
69                     let write = client_response(connection, challenge);
70                     ClientResponse(Some(codec), write)
71                 }
72 
73                 ClientResponse(ref mut codec, ref mut write) => {
74                     let (connection, _) = try_ready!(write.poll());
75                     let codec = codec.take().unwrap();
76                     let framed = codec.framed(connection);
77                     return Ok(Async::Ready(framed));
78                 }
79             }
80         }
81     }
82 }
83 
client_hello<T: AsyncWrite>(connection: T, gc: Vec<u8>) -> WriteAll<T, Vec<u8>>84 fn client_hello<T: AsyncWrite>(connection: T, gc: Vec<u8>) -> WriteAll<T, Vec<u8>> {
85     let mut packet = ClientHello::new();
86     packet
87         .mut_build_info()
88         .set_product(protocol::keyexchange::Product::PRODUCT_PARTNER);
89     packet
90         .mut_build_info()
91         .set_platform(protocol::keyexchange::Platform::PLATFORM_LINUX_X86);
92     packet.mut_build_info().set_version(109800078);
93     packet
94         .mut_cryptosuites_supported()
95         .push(protocol::keyexchange::Cryptosuite::CRYPTO_SUITE_SHANNON);
96     packet
97         .mut_login_crypto_hello()
98         .mut_diffie_hellman()
99         .set_gc(gc);
100     packet
101         .mut_login_crypto_hello()
102         .mut_diffie_hellman()
103         .set_server_keys_known(1);
104     packet.set_client_nonce(util::rand_vec(&mut thread_rng(), 0x10));
105     packet.set_padding(vec![0x1e]);
106 
107     let mut buffer = vec![0, 4];
108     let size = 2 + 4 + packet.compute_size();
109     buffer.write_u32::<BigEndian>(size).unwrap();
110     packet.write_to_vec(&mut buffer).unwrap();
111 
112     write_all(connection, buffer)
113 }
114 
client_response<T: AsyncWrite>(connection: T, challenge: Vec<u8>) -> WriteAll<T, Vec<u8>>115 fn client_response<T: AsyncWrite>(connection: T, challenge: Vec<u8>) -> WriteAll<T, Vec<u8>> {
116     let mut packet = ClientResponsePlaintext::new();
117     packet
118         .mut_login_crypto_response()
119         .mut_diffie_hellman()
120         .set_hmac(challenge);
121     packet.mut_pow_response();
122     packet.mut_crypto_response();
123 
124     let mut buffer = vec![];
125     let size = 4 + packet.compute_size();
126     buffer.write_u32::<BigEndian>(size).unwrap();
127     packet.write_to_vec(&mut buffer).unwrap();
128 
129     write_all(connection, buffer)
130 }
131 
132 enum RecvPacket<T, M: Message> {
133     Header(ReadExact<T, Window<Vec<u8>>>, PhantomData<M>),
134     Body(ReadExact<T, Window<Vec<u8>>>, PhantomData<M>),
135 }
136 
recv_packet<T: AsyncRead, M>(connection: T, acc: Vec<u8>) -> RecvPacket<T, M> where T: Read, M: Message,137 fn recv_packet<T: AsyncRead, M>(connection: T, acc: Vec<u8>) -> RecvPacket<T, M>
138 where
139     T: Read,
140     M: Message,
141 {
142     RecvPacket::Header(read_into_accumulator(connection, 4, acc), PhantomData)
143 }
144 
145 impl<T: AsyncRead, M> Future for RecvPacket<T, M>
146 where
147     T: Read,
148     M: Message,
149 {
150     type Item = (T, M, Vec<u8>);
151     type Error = io::Error;
152 
poll(&mut self) -> Poll<Self::Item, io::Error>153     fn poll(&mut self) -> Poll<Self::Item, io::Error> {
154         use self::RecvPacket::*;
155         loop {
156             *self = match *self {
157                 Header(ref mut read, _) => {
158                     let (connection, header) = try_ready!(read.poll());
159                     let size = BigEndian::read_u32(header.as_ref()) as usize;
160 
161                     let acc = header.into_inner();
162                     let read = read_into_accumulator(connection, size - 4, acc);
163                     RecvPacket::Body(read, PhantomData)
164                 }
165 
166                 Body(ref mut read, _) => {
167                     let (connection, data) = try_ready!(read.poll());
168                     let message = protobuf::parse_from_bytes(data.as_ref()).unwrap();
169 
170                     let acc = data.into_inner();
171                     return Ok(Async::Ready((connection, message, acc)));
172                 }
173             }
174         }
175     }
176 }
177 
read_into_accumulator<T: AsyncRead>( connection: T, size: usize, mut acc: Vec<u8>, ) -> ReadExact<T, Window<Vec<u8>>>178 fn read_into_accumulator<T: AsyncRead>(
179     connection: T,
180     size: usize,
181     mut acc: Vec<u8>,
182 ) -> ReadExact<T, Window<Vec<u8>>> {
183     let offset = acc.len();
184     acc.resize(offset + size, 0);
185 
186     let mut window = Window::new(acc);
187     window.set_start(offset);
188 
189     read_exact(connection, window)
190 }
191 
compute_keys(shared_secret: &[u8], packets: &[u8]) -> (Vec<u8>, Vec<u8>, Vec<u8>)192 fn compute_keys(shared_secret: &[u8], packets: &[u8]) -> (Vec<u8>, Vec<u8>, Vec<u8>) {
193     type HmacSha1 = Hmac<Sha1>;
194 
195     let mut data = Vec::with_capacity(0x64);
196     for i in 1..6 {
197         let mut mac = HmacSha1::new_varkey(&shared_secret).expect("HMAC can take key of any size");
198         mac.input(packets);
199         mac.input(&[i]);
200         data.extend_from_slice(&mac.result().code());
201     }
202 
203     let mut mac = HmacSha1::new_varkey(&data[..0x14]).expect("HMAC can take key of any size");
204     mac.input(packets);
205 
206     (
207         mac.result().code().to_vec(),
208         data[0x14..0x34].to_vec(),
209         data[0x34..0x54].to_vec(),
210     )
211 }
212