1#[cfg(feature = "deprecated-zlib")]
2use crate::algorithm::{compression, Compress};
3use crate::{
4 algorithm::{
5 encryption,
6 hash::{self, HashCtx},
7 key_exchange::{self, KeyExchange},
8 mac,
9 public_key::{self, PublicKey},
10 Digest,
11 },
12 client::Client,
13 config::algorithm::AlgList,
14 constant::ssh_transport_code,
15 error::{SshError, SshResult},
16 model::{Data, Packet, SecPacket},
17};
18use std::io::{Read, Write};
19use tracing::*;
20
21impl Client {
22 pub fn key_agreement<S>(
23 &mut self,
24 stream: &mut S,
25 server_algs: AlgList,
26 digest: &mut Digest,
27 ) -> SshResult<()>
28 where
29 S: Read + Write,
30 {
31 digest.hash_ctx.set_v_c(&self.config.ver.client_ver);
33 digest.hash_ctx.set_v_s(&self.config.ver.server_ver);
34
35 info!("start for key negotiation.");
36 info!("send client algorithm list.");
37
38 let algs = self.config.algs.clone();
39 let client_algs = algs.pack(self);
40 digest.hash_ctx.set_i_c(client_algs.get_inner());
41 client_algs.write_stream(stream)?;
42
43 let negotiated = self.config.algs.match_with(&server_algs)?;
44
45 let mut key_exchange = key_exchange::from(&negotiated.key_exchange[0])?;
47 self.send_qc(stream, key_exchange.get_public_key())?;
48
49 let mut public_key = public_key::from(&negotiated.public_key[0]);
51
52 let session_id = {
54 let session_id = self.verify_signature_and_new_keys(
55 stream,
56 &mut public_key,
57 &mut key_exchange,
58 &mut digest.hash_ctx,
59 )?;
60
61 if self.session_id.is_empty() {
62 session_id
63 } else {
64 self.session_id.clone()
65 }
66 };
67
68 let hash = hash::Hash::new(
69 digest.hash_ctx.clone(),
70 &session_id,
71 key_exchange.get_hash_type(),
72 );
73
74 let mac = mac::from(&negotiated.c_mac[0]);
76
77 let encryption = encryption::from(&negotiated.c_encryption[0], hash, mac);
79
80 self.session_id = session_id;
81 self.negotiated = negotiated;
82 self.encryptor = encryption;
83
84 #[cfg(feature = "deprecated-zlib")]
85 {
86 if let Compress::Zlib = self.negotiated.c_compress[0] {
87 let comp = compression::from(&Compress::Zlib);
88 self.compressor = comp;
89 }
90 }
91
92 digest.key_exchange = Some(key_exchange);
93
94 info!("key negotiation successful.");
95
96 Ok(())
97 }
98
99 fn send_qc<S>(&mut self, stream: &mut S, public_key: &[u8]) -> SshResult<()>
101 where
102 S: Read + Write,
103 {
104 let mut data = Data::new();
105 data.put_u8(ssh_transport_code::KEXDH_INIT)
106 .put_u8s(public_key);
107 data.pack(self).write_stream(stream)
108 }
109
110 fn verify_signature_and_new_keys<S>(
111 &mut self,
112 stream: &mut S,
113 public_key: &mut Box<dyn PublicKey>,
114 key_exchange: &mut Box<dyn KeyExchange>,
115 h: &mut HashCtx,
116 ) -> SshResult<Vec<u8>>
117 where
118 S: Read + Write,
119 {
120 let mut session_id = vec![];
121 loop {
122 let mut data = Data::unpack(SecPacket::from_stream(stream, self)?)?;
123 let message_code = data.get_u8();
124 match message_code {
125 ssh_transport_code::KEXDH_REPLY => {
126 let sig = self.generate_signature(data, h, key_exchange)?;
128 session_id = hash::digest(&h.as_bytes(), key_exchange.get_hash_type());
130 let flag = public_key.verify_signature(&h.k_s, &session_id, &sig)?;
131 if !flag {
132 let err_msg = "signature verification failure.".to_owned();
133 error!(err_msg);
134 return Err(SshError::KexError(err_msg));
135 }
136 info!("signature verification success.");
137 }
138 ssh_transport_code::NEWKEYS => {
139 self.new_keys(stream)?;
140 return Ok(session_id);
141 }
142 _ => unreachable!(),
143 }
144 }
145 }
146
147 fn generate_signature(
149 &mut self,
150 mut data: Data,
151 h: &mut HashCtx,
152 key_exchange: &mut Box<dyn KeyExchange>,
153 ) -> SshResult<Vec<u8>> {
154 let ks = data.get_u8s();
155 h.set_k_s(&ks);
156 let qs = data.get_u8s();
159 h.set_e(key_exchange.get_public_key());
160 h.set_f(&qs);
161 let vec = key_exchange.get_shared_secret(qs)?;
162 h.set_k(&vec);
163 let h = data.get_u8s();
164 let mut hd = Data::from(h);
165 hd.get_u8s();
166 let signature = hd.get_u8s();
167 Ok(signature)
168 }
169
170 fn new_keys<S>(&mut self, stream: &mut S) -> SshResult<()>
172 where
173 S: Write,
174 {
175 let mut data = Data::new();
176 data.put_u8(ssh_transport_code::NEWKEYS);
177 info!("send new keys");
178 data.pack(self).write_stream(stream)
179 }
180}