Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions demo/common/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,10 @@ impl DemoCommon {
ServEvent::FirstAuth(a) => self.handle_firstauth(a),
ServEvent::PasswordAuth(a) => self.handle_password(a),
ServEvent::PubkeyAuth(a) => self.handle_pubkey(a),
ServEvent::Authenticated => {
info!("Auth success");
Ok(())
}
ServEvent::OpenSession(a) => self.open_session(a),
ServEvent::SessionPty(a) => a.succeed(),
ServEvent::SessionEnv(a) => a.succeed(),
Expand Down
9 changes: 4 additions & 5 deletions fuzz/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@ fn serv_event(input: &mut FuzzInput, ev: Event, state: &mut State) -> Result<()>
}
if input.chance(0.9)? {
h.allow()?;
state.authed = true;
} else if input.chance(0.4)? {
h.reject()?;
}
Expand All @@ -88,15 +87,15 @@ fn serv_event(input: &mut FuzzInput, ev: Event, state: &mut State) -> Result<()>
h.enable_pubkey_auth(false).unwrap();
}
if input.chance(0.9)? {
let real = h.real();
h.allow()?;
if real {
state.authed = true;
}
} else if input.chance(0.4)? {
h.reject()?;
}
}
ServEvent::Authenticated => {
assert!(state.authed);
state.authed = true;
}
ServEvent::OpenSession(h) => {
assert!(state.authed);

Expand Down
11 changes: 7 additions & 4 deletions src/conn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use {
use crate::*;
use channel::{Channels, CliSessionExit};
use client::Client;
use event::{CliEventId, ServEventId};
use kex::{AlgoConfig, Kex, SessId};
use packets::{Packet, ParseContext};
use server::Server;
Expand Down Expand Up @@ -64,8 +65,8 @@ enum ConnState {
pub(crate) enum DispatchEvent {
/// Incoming channel data
Data(channel::DataIn),
CliEvent(event::CliEventId),
ServEvent(event::ServEventId),
CliEvent(CliEventId),
ServEvent(ServEventId),
/// NewKeys was received, wake any output channels in case they were waiting.
KexDone,
/// Connection state has changed, should poll again
Expand Down Expand Up @@ -683,13 +684,15 @@ impl Conn<Server> {
&mut self,
allow: bool,
s: &mut TrafSend,
) -> Result<()> {
) -> Result<DispatchEvent> {
let auth = &mut self.mut_server()?.auth;
auth.resume_request(allow, s)?;
if auth.authed && matches!(self.state, ConnState::PreAuth) {
self.state = ConnState::Authed;
Ok(DispatchEvent::ServEvent(ServEventId::Authenticated))
} else {
Ok(DispatchEvent::None)
}
Ok(())
}

pub(crate) fn resume_servauth_pkok(
Expand Down
27 changes: 17 additions & 10 deletions src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -273,8 +273,14 @@ pub enum ServEvent<'g, 'a> {
///
/// Note that this event may be emitted multiple times,
/// since the client first queries acceptable public keys,
/// and then later sends an actual signature.
/// and then later sends an actual signature. The application
/// should give consistent `allow()`/`deny()` (default) responses
/// for requests of the same key.
PubkeyAuth(ServPubkeyAuth<'g, 'a>),
/// Authentication success.
///
/// Emitted when a client first successfully authenticates.
Authenticated,
/// Client's request for a session channel.
///
/// After accepting a channel the [`ChanHandle`] will be returned.
Expand Down Expand Up @@ -313,6 +319,7 @@ impl Debug for ServEvent<'_, '_> {
Self::PasswordAuth(_) => "PasswordAuth",
Self::PubkeyAuth(_) => "PubkeyAuth",
Self::FirstAuth(_) => "FirstAuth",
Self::Authenticated => "Authenticated",
Self::OpenSession(_) => "OpenSession",
Self::SessionShell(_) => "SessionShell",
Self::SessionExec(_) => "SessionExec",
Expand Down Expand Up @@ -473,14 +480,6 @@ impl<'g, 'a> ServPubkeyAuth<'g, 'a> {
self.runner.fetch_servpubkey()
}

/// Whether this is an pubkey auth attempt.
///
/// `real()` will be `false` for a pubkey key query (no signature attemp),
/// or `true` for the actual login attempt with signature.
pub fn real(&self) -> bool {
self.real_sig
}

/// Accept the presented public key.
pub fn allow(mut self) -> Result<()> {
self.done = true;
Expand Down Expand Up @@ -913,6 +912,7 @@ pub(crate) enum ServEventId {
real_sig: bool,
},
FirstAuth,
Authenticated,
OpenSession {
num: ChanNum,
},
Expand Down Expand Up @@ -964,6 +964,13 @@ impl ServEventId {
debug_assert!(matches!(p, Some(Packet::UserauthRequest(_))));
Ok(ServEvent::FirstAuth(ServFirstAuth::new(runner)))
}
Self::Authenticated => {
// TODO: Doesn't actually need Packet::UserauthRequest
// since it's not using data from it. But it fits the current
// flow.
debug_assert!(matches!(p, Some(Packet::UserauthRequest(_))));
Ok(ServEvent::Authenticated)
}
Self::OpenSession { num } => {
debug_assert!(matches!(p, Some(Packet::ChannelOpen(_))));
Ok(ServEvent::OpenSession(ServOpenSession::new(runner, num)))
Expand Down Expand Up @@ -996,7 +1003,7 @@ impl ServEventId {
// Used for internal correctness checks.
pub(crate) fn needs_resume(&self) -> bool {
match self {
Self::Defunct => false,
Self::Defunct | Self::Authenticated => false,
Self::Hostkeys
| Self::FirstAuth
| Self::PasswordAuth
Expand Down
1 change: 1 addition & 0 deletions src/kex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1049,6 +1049,7 @@ impl KexMlkemX25519 {
#[cfg(test)]
mod tests {
use crate::encrypt::{self, KeyState, KeysRecv, KeysSend, SSH_PAYLOAD_START};
use crate::event::CliEventId;
use crate::ident::RemoteVersion;
use crate::kex;
use crate::kex::*;
Expand Down
1 change: 0 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ mod termmodes;
mod traffic;

use conn::DispatchEvent;
use event::CliEventId;

// Application API
pub use sshwire::TextString;
Expand Down
21 changes: 9 additions & 12 deletions src/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,21 +226,18 @@ impl<'a> Runner<'a, server::Server> {
let prev_event = self.resume_event.take();
// auth packets have passwords
self.traf_in.zeroize_payload();
debug_assert!(
matches!(
prev_event,
DispatchEvent::ServEvent(ServEventId::PasswordAuth)
) || matches!(
prev_event,
DispatchEvent::ServEvent(ServEventId::PubkeyAuth { .. })
) || matches!(
prev_event,
DispatchEvent::ServEvent(ServEventId::FirstAuth)
debug_assert!(matches!(
prev_event,
DispatchEvent::ServEvent(
ServEventId::PasswordAuth
| ServEventId::PubkeyAuth { .. }
| ServEventId::FirstAuth
)
);
));

let mut s = self.traf_out.sender(&mut self.keys);
self.conn.resume_servauth(allow, &mut s)
self.resume_event = self.conn.resume_servauth(allow, &mut s)?;
Ok(())
}

pub(crate) fn resume_servauth_pkok(&mut self) -> Result<()> {
Expand Down
Loading