1use crate::encoding::{Encoding, Position, Reader};
2use crate::key;
3#[cfg(feature = "openssl")]
4use crate::key::SignatureHash;
5use byteorder::{BigEndian, ByteOrder};
6use cryptovec::CryptoVec;
7use futures::future::Future;
8use futures::stream::{Stream, StreamExt};
9use std;
10use std::collections::HashMap;
11use std::sync::{Arc, RwLock};
12use std::time::Duration;
13use std::time::SystemTime;
14use tokio;
15use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
16use tokio::time::sleep;
17
18use super::msg;
19use super::Constraint;
20use crate::Error;
21
22#[derive(Clone)]
23struct KeyStore(Arc<RwLock<HashMap<Vec<u8>, (Arc<key::KeyPair>, SystemTime, Vec<Constraint>)>>>);
24
25#[derive(Clone)]
26struct Lock(Arc<RwLock<CryptoVec>>);
27
28#[allow(missing_docs)]
29#[derive(Debug)]
30pub enum ServerError<E> {
31 E(E),
32 Error(Error),
33}
34
35pub trait Agent: Clone + Send + 'static {
36 fn confirm(
37 self,
38 _pk: Arc<key::KeyPair>,
39 ) -> Box<dyn Future<Output = (Self, bool)> + Unpin + Send> {
40 Box::new(futures::future::ready((self, true)))
41 }
42}
43
44pub async fn serve<S, L, A>(mut listener: L, agent: A) -> Result<(), Error>
45where
46 S: AsyncRead + AsyncWrite + Send + Sync + Unpin + 'static,
47 L: Stream<Item = tokio::io::Result<S>> + Unpin,
48 A: Agent + Send + Sync + 'static,
49{
50 let keys = KeyStore(Arc::new(RwLock::new(HashMap::new())));
51 let lock = Lock(Arc::new(RwLock::new(CryptoVec::new())));
52 while let Some(Ok(stream)) = listener.next().await {
53 let mut buf = CryptoVec::new();
54 buf.resize(4);
55 tokio::spawn(
56 (Connection {
57 lock: lock.clone(),
58 keys: keys.clone(),
59 agent: Some(agent.clone()),
60 s: stream,
61 buf: CryptoVec::new(),
62 })
63 .run(),
64 );
65 }
66 Ok(())
67}
68
69impl Agent for () {
70 fn confirm(
71 self,
72 _: Arc<key::KeyPair>,
73 ) -> Box<dyn Future<Output = (Self, bool)> + Unpin + Send> {
74 Box::new(futures::future::ready((self, true)))
75 }
76}
77
78struct Connection<S: AsyncRead + AsyncWrite + Send + 'static, A: Agent> {
79 lock: Lock,
80 keys: KeyStore,
81 agent: Option<A>,
82 s: S,
83 buf: CryptoVec,
84}
85
86impl<S: AsyncRead + AsyncWrite + Send + Unpin + 'static, A: Agent + Send + 'static>
87 Connection<S, A>
88{
89 async fn run(mut self) -> Result<(), Error> {
90 let mut writebuf = CryptoVec::new();
91 loop {
92 self.buf.clear();
94 self.buf.resize(4);
95 self.s.read_exact(&mut self.buf).await?;
96 let len = BigEndian::read_u32(&self.buf) as usize;
98 self.buf.clear();
99 self.buf.resize(len);
100 self.s.read_exact(&mut self.buf).await?;
101 writebuf.clear();
103 self.respond(&mut writebuf).await?;
104 self.s.write_all(&writebuf).await?;
105 self.s.flush().await?
106 }
107 }
108
109 async fn respond(&mut self, writebuf: &mut CryptoVec) -> Result<(), Error> {
110 let is_locked = {
111 if let Ok(password) = self.lock.0.read() {
112 !password.is_empty()
113 } else {
114 true
115 }
116 };
117 writebuf.extend(&[0, 0, 0, 0]);
118 let mut r = self.buf.reader(0);
119 match r.read_byte() {
120 Ok(11) if !is_locked => {
121 if let Ok(keys) = self.keys.0.read() {
123 writebuf.push(msg::IDENTITIES_ANSWER);
124 writebuf.push_u32_be(keys.len() as u32);
125 for (k, _) in keys.iter() {
126 writebuf.extend_ssh_string(k);
127 writebuf.extend_ssh_string(b"");
128 }
129 } else {
130 writebuf.push(msg::FAILURE)
131 }
132 }
133 Ok(13) if !is_locked => {
134 let agent = self.agent.take().unwrap();
136 let (agent, signed) = self.try_sign(agent, r, writebuf).await?;
137 self.agent = Some(agent);
138 if signed {
139 return Ok(());
140 } else {
141 writebuf.resize(4);
142 writebuf.push(msg::FAILURE)
143 }
144 }
145 Ok(17) if !is_locked => {
146 if let Ok(true) = self.add_key(r, false, writebuf).await {
148 } else {
149 writebuf.push(msg::FAILURE)
150 }
151 }
152 Ok(18) if !is_locked => {
153 if let Ok(true) = self.remove_identity(r) {
155 writebuf.push(msg::SUCCESS)
156 } else {
157 writebuf.push(msg::FAILURE)
158 }
159 }
160 Ok(19) if !is_locked => {
161 if let Ok(mut keys) = self.keys.0.write() {
163 keys.clear();
164 writebuf.push(msg::SUCCESS)
165 } else {
166 writebuf.push(msg::FAILURE)
167 }
168 }
169 Ok(22) if !is_locked => {
170 if let Ok(()) = self.lock(r) {
172 writebuf.push(msg::SUCCESS)
173 } else {
174 writebuf.push(msg::FAILURE)
175 }
176 }
177 Ok(23) if is_locked => {
178 if let Ok(true) = self.unlock(r) {
180 writebuf.push(msg::SUCCESS)
181 } else {
182 writebuf.push(msg::FAILURE)
183 }
184 }
185 Ok(25) if !is_locked => {
186 if let Ok(true) = self.add_key(r, true, writebuf).await {
188 } else {
189 writebuf.push(msg::FAILURE)
190 }
191 }
192 _ => {
193 writebuf.push(msg::FAILURE)
195 }
196 }
197 let len = writebuf.len() - 4;
198 BigEndian::write_u32(&mut writebuf[0..], len as u32);
199 Ok(())
200 }
201
202 fn lock(&self, mut r: Position) -> Result<(), Error> {
203 let password = r.read_string()?;
204 let mut lock = self.lock.0.write().unwrap();
205 lock.extend(password);
206 Ok(())
207 }
208
209 fn unlock(&self, mut r: Position) -> Result<bool, Error> {
210 let password = r.read_string()?;
211 let mut lock = self.lock.0.write().unwrap();
212 if &lock[0..] == password {
213 lock.clear();
214 Ok(true)
215 } else {
216 Ok(false)
217 }
218 }
219
220 fn remove_identity(&self, mut r: Position) -> Result<bool, Error> {
221 if let Ok(mut keys) = self.keys.0.write() {
222 if keys.remove(r.read_string()?).is_some() {
223 Ok(true)
224 } else {
225 Ok(false)
226 }
227 } else {
228 Ok(false)
229 }
230 }
231
232 async fn add_key<'a>(
233 &self,
234 mut r: Position<'a>,
235 constrained: bool,
236 writebuf: &mut CryptoVec,
237 ) -> Result<bool, Error> {
238 let pos0 = r.position;
239 let t = r.read_string()?;
240 let (blob, key) = match t {
241 b"ssh-ed25519" => {
242 let public_ = r.read_string()?;
243 let pos1 = r.position;
244 let concat = r.read_string()?;
245 let _comment = r.read_string()?;
246 if &concat[32..64] != public_ {
247 return Ok(false);
248 }
249 use key::ed25519::*;
250 let mut public = PublicKey::new_zeroed();
251 let mut secret = SecretKey::new_zeroed();
252 public.key.clone_from_slice(&public_[..32]);
253 secret.key.clone_from_slice(&concat[..]);
254 writebuf.push(msg::SUCCESS);
255 (self.buf[pos0..pos1].to_vec(), key::KeyPair::Ed25519(secret))
256 }
257 #[cfg(feature = "p256")]
258 b"ecdsa-sha2-nistp256" => {
259 let public_ = r.read_string()?;
260 let pos1 = r.position;
261 let priv_ = r.read_mpint()?;
262 let _comment = r.read_string()?;
263 let mut priv_bytes = [0u8; 32];
264 priv_.into_iter().rev().enumerate().for_each(|(i, b)| {
265 if i < 32 {
266 priv_bytes[31 - i] = *b;
267 }
268 });
269 let key =
270 crate::key::KeyPair::P256(p256::SecretKey::from_bytes(&priv_bytes.into())?);
271 if public_ != crate::PublicKeyBase64::public_key_bytes(&key) {
272 return Ok(false);
273 }
274 (self.buf[pos0..pos1].to_vec(), key)
275 }
276 #[cfg(feature = "openssl")]
277 b"ssh-rsa" => {
278 use openssl::bn::{BigNum, BigNumContext};
279 use openssl::rsa::Rsa;
280 let n = r.read_mpint()?;
281 let e = r.read_mpint()?;
282 let d = BigNum::from_slice(r.read_mpint()?)?;
283 let q_inv = r.read_mpint()?;
284 let p = BigNum::from_slice(r.read_mpint()?)?;
285 let q = BigNum::from_slice(r.read_mpint()?)?;
286 let (dp, dq) = {
287 let one = BigNum::from_u32(1)?;
288 let p1 = p.as_ref() - one.as_ref();
289 let q1 = q.as_ref() - one.as_ref();
290 let mut context = BigNumContext::new()?;
291 let mut dp = BigNum::new()?;
292 let mut dq = BigNum::new()?;
293 dp.checked_rem(&d, &p1, &mut context)?;
294 dq.checked_rem(&d, &q1, &mut context)?;
295 (dp, dq)
296 };
297 let _comment = r.read_string()?;
298 let key = Rsa::from_private_components(
299 BigNum::from_slice(n)?,
300 BigNum::from_slice(e)?,
301 d,
302 p,
303 q,
304 dp,
305 dq,
306 BigNum::from_slice(&q_inv)?,
307 )?;
308
309 let len0 = writebuf.len();
310 writebuf.extend_ssh_string(b"ssh-rsa");
311 writebuf.extend_ssh_mpint(&e);
312 writebuf.extend_ssh_mpint(&n);
313 let blob = writebuf[len0..].to_vec();
314 writebuf.resize(len0);
315 writebuf.push(msg::SUCCESS);
316 (
317 blob,
318 key::KeyPair::RSA {
319 key,
320 hash: SignatureHash::SHA2_256,
321 },
322 )
323 }
324 _ => return Ok(false),
325 };
326 let mut w = self.keys.0.write().unwrap();
327 let now = SystemTime::now();
328 if constrained {
329 let n = r.read_u32()?;
330 let mut c = Vec::new();
331 for _ in 0..n {
332 let t = r.read_byte()?;
333 if t == msg::CONSTRAIN_LIFETIME {
334 let seconds = r.read_u32()?;
335 c.push(Constraint::KeyLifetime { seconds });
336 let blob = blob.clone();
337 let keys = self.keys.clone();
338 tokio::spawn(async move {
339 sleep(Duration::from_secs(seconds as u64)).await;
340 let mut keys = keys.0.write().unwrap();
341 let delete = if let Some(&(_, time, _)) = keys.get(&blob) {
342 time == now
343 } else {
344 false
345 };
346 if delete {
347 keys.remove(&blob);
348 }
349 });
350 } else if t == msg::CONSTRAIN_CONFIRM {
351 c.push(Constraint::Confirm)
352 } else {
353 return Ok(false);
354 }
355 }
356 w.insert(blob, (Arc::new(key), now, Vec::new()));
357 } else {
358 w.insert(blob, (Arc::new(key), now, Vec::new()));
359 }
360 Ok(true)
361 }
362
363 async fn try_sign<'a>(
364 &self,
365 agent: A,
366 mut r: Position<'a>,
367 writebuf: &mut CryptoVec,
368 ) -> Result<(A, bool), Error> {
369 let mut needs_confirm = false;
370 let key = {
371 let blob = r.read_string()?;
372 let k = self.keys.0.read().unwrap();
373 if let Some(&(ref key, _, ref constraints)) = k.get(blob) {
374 if constraints.iter().any(|c| *c == Constraint::Confirm) {
375 needs_confirm = true;
376 }
377 key.clone()
378 } else {
379 return Ok((agent, false));
380 }
381 };
382 let agent = if needs_confirm {
383 let (agent, ok) = agent.confirm(key.clone()).await;
384 if !ok {
385 return Ok((agent, false));
386 }
387 agent
388 } else {
389 agent
390 };
391 writebuf.push(msg::SIGN_RESPONSE);
392 let data = r.read_string()?;
393 key.add_signature(writebuf, data)?;
394 let len = writebuf.len();
395 BigEndian::write_u32(writebuf, (len - 4) as u32);
396
397 Ok((agent, true))
398 }
399}