ssh/client/
client_auth.rs1use std::io::{Read, Write};
2use tracing::*;
3
4use crate::{
5 algorithm::{compression, Compress, Digest},
6 constant::{ssh_connection_code, ssh_str, ssh_transport_code, ssh_user_auth_code},
7 error::{SshError, SshResult},
8 model::{Data, Packet, SecPacket},
9};
10
11use super::Client;
12
13impl Client {
14 pub fn do_auth<S>(&mut self, stream: &mut S, digest: &Digest) -> SshResult<()>
15 where
16 S: Read + Write,
17 {
18 info!("Auth start");
19 let mut data = Data::new();
20 data.put_u8(ssh_transport_code::SERVICE_REQUEST)
21 .put_str(ssh_str::SSH_USERAUTH);
22 data.pack(self).write_stream(stream)?;
23
24 let mut tried_public_key = false;
25 loop {
26 let mut data = Data::unpack(SecPacket::from_stream(stream, self)?)?;
27 let message_code = data.get_u8();
28 match message_code {
29 ssh_transport_code::SERVICE_ACCEPT => {
30 if self.config.auth.key_pair.is_none() {
31 tried_public_key = true;
32 self.password_authentication(stream)?
35 } else {
36 self.public_key_authentication(stream)?
39 }
40 }
41 ssh_user_auth_code::FAILURE => {
42 if !tried_public_key {
43 error!("user auth failure. (public key)");
44 info!("fallback to password authentication");
45 tried_public_key = true;
46 self.password_authentication(stream)?
50 } else {
51 error!("user auth failure. (password)");
52 return Err(SshError::AuthError);
53 }
54 }
55 ssh_user_auth_code::PK_OK => {
56 info!("user auth support this algorithm.");
57 self.public_key_signature(stream, digest)?
58 }
59 ssh_user_auth_code::SUCCESS => {
60 info!("user auth successful.");
61 if let Compress::ZlibOpenSsh = self.negotiated.c_compress[0] {
64 let comp = compression::from(&Compress::ZlibOpenSsh);
65 self.compressor = comp;
66 }
67 return Ok(());
68 }
69 ssh_connection_code::GLOBAL_REQUEST => {
70 let mut data = Data::new();
71 data.put_u8(ssh_connection_code::REQUEST_FAILURE);
72 data.pack(self).write_stream(stream)?;
73 }
74 _ => {}
75 }
76 }
77 }
78
79 fn password_authentication<S>(&mut self, stream: &mut S) -> SshResult<()>
80 where
81 S: Write,
82 {
83 info!("password authentication.");
84 let mut data = Data::new();
85 data.put_u8(ssh_user_auth_code::REQUEST)
86 .put_str(self.config.auth.username.as_str())
87 .put_str(ssh_str::SSH_CONNECTION)
88 .put_str(ssh_str::PASSWORD)
89 .put_u8(false as u8)
90 .put_str(self.config.auth.password.as_str());
91
92 data.pack(self).write_stream(stream)
93 }
94
95 fn public_key_authentication<S>(&mut self, stream: &mut S) -> SshResult<()>
96 where
97 S: Write,
98 {
99 let data = {
100 let pubkey_alg = &self.negotiated.public_key[0];
101 info!(
102 "public key authentication. algorithm: {}",
103 pubkey_alg.as_ref()
104 );
105 let mut data = Data::new();
106 data.put_u8(ssh_user_auth_code::REQUEST)
107 .put_str(self.config.auth.username.as_str())
108 .put_str(ssh_str::SSH_CONNECTION)
109 .put_str(ssh_str::PUBLIC_KEY)
110 .put_u8(false as u8)
111 .put_str(pubkey_alg.as_ref())
112 .put_u8s(
113 &self
114 .config
115 .auth
116 .key_pair
117 .as_ref()
118 .unwrap()
119 .get_blob(pubkey_alg),
120 );
121 data
122 };
123 data.pack(self).write_stream(stream)
124 }
125
126 pub(crate) fn public_key_signature<S>(
127 &mut self,
128 stream: &mut S,
129 digest: &Digest,
130 ) -> SshResult<()>
131 where
132 S: Write,
133 {
134 let data = {
135 let pubkey_alg = &self.negotiated.public_key[0];
136
137 let mut data = Data::new();
138 data.put_u8(ssh_user_auth_code::REQUEST)
139 .put_str(self.config.auth.username.as_str())
140 .put_str(ssh_str::SSH_CONNECTION)
141 .put_str(ssh_str::PUBLIC_KEY)
142 .put_u8(true as u8)
143 .put_str(pubkey_alg.as_ref())
144 .put_u8s(
145 &self
146 .config
147 .auth
148 .key_pair
149 .as_ref()
150 .unwrap()
151 .get_blob(pubkey_alg),
152 );
153 let signature = self.config.auth.key_pair.as_ref().unwrap().signature(
154 data.as_slice(),
155 digest.hash_ctx.clone(),
156 digest.key_exchange.as_ref().unwrap().get_hash_type(),
157 pubkey_alg,
158 );
159 data.put_u8s(&signature);
160 data
161 };
162 data.pack(self).write_stream(stream)
163 }
164}