diff --git a/src/channel.rs b/src/channel.rs index 3ca27c063ab5c7cd7bc6804d9637cdc4c2cb2fa2..c6349eac4a7f811a19b7aa0ce61caec88783c79f 100644 --- a/src/channel.rs +++ b/src/channel.rs @@ -337,9 +337,9 @@ impl Channels { packet: Packet<'_>, s: &mut TrafSend<'_, '_>, b: &mut Behaviour<'_>, - ) -> Result<Dispatched> { + ) -> Result<Option<DataIn>> { trace!("chan dispatch"); - let mut disp = Dispatched(None); + let mut data_in = None; match packet { Packet::ChannelOpen(p) => { self.dispatch_open(&p, s, b)?; @@ -400,7 +400,7 @@ impl Channels { offset: ChannelData::DATA_OFFSET, len: p.data.0.len(), }; - disp = Dispatched(Some(di)); + data_in = Some(di); } Packet::ChannelDataExt(p) => { self.get(p.num)?; @@ -436,7 +436,7 @@ impl Channels { } _ => Error::bug_msg("unreachable")?, }; - Ok(disp) + Ok(data_in) } /// Incoming packet handling @@ -447,17 +447,17 @@ impl Channels { packet: Packet<'_>, s: &mut TrafSend<'_, '_>, b: &mut Behaviour<'_>, - ) -> Result<Dispatched> { + ) -> Result<Option<DataIn>> { let r = self.dispatch_inner(packet, s, b).await; match r { Err(Error::BadChannel) => { warn!("Ignoring bad channel number"); - Ok(Dispatched(None)) + Ok(None) } // TODO: close channel on error? or on SSHProtoError? Err(any) => Err(any), - Ok(disp) => Ok(disp), + Ok(data_in) => Ok(data_in), } } } diff --git a/src/conn.rs b/src/conn.rs index 2edbeef646e111564ef222d196ff43578e1b01ee..954f771d623cb47d401a70546fcf9eb01ceb502a 100644 --- a/src/conn.rs +++ b/src/conn.rs @@ -83,7 +83,12 @@ enum ConnState { // Cleanup ?? } -pub(crate) struct Dispatched(pub Option<channel::DataIn>); +#[derive(Default)] +pub(crate) struct Dispatched { + pub data_in: Option<channel::DataIn>, + /// set for sensitive payloads such as password auth + pub zeroize_payload: bool, +} impl Conn { pub fn new_client() -> Result<Self> { @@ -174,7 +179,7 @@ impl Conn { Err(Error::UnknownPacket { number }) => { trace!("Unimplemented packet type {number}"); s.send(packets::Unimplemented { seq })?; - Ok(Dispatched(None)) + Ok(Dispatched::default()) } Err(e) => { trace!("Error decoding packet: {e} {:#?}", payload.hex_dump()); @@ -223,7 +228,7 @@ impl Conn { ) -> Result<Dispatched, Error> { // TODO: perhaps could consolidate packet client vs server checks trace!("Incoming {packet:#?}"); - let mut disp = Dispatched(None); + let mut disp = Dispatched::default(); self.check_packet(&packet)?; @@ -331,6 +336,7 @@ impl Conn { } Packet::UserauthRequest(p) => { if let ClientServer::Server(serv) = &mut self.cliserv { + disp.zeroize_payload = true; let sess_id = self.sess_id.as_ref().trap()?; let success = serv.auth.request(p, sess_id, s, b.server()?)?; if success { @@ -394,7 +400,7 @@ impl Conn { | Packet::ChannelFailure(_) // TODO: maybe needs a conn or cliserv argument. => { - disp = self.channels.dispatch(packet, s, b).await?; + disp.data_in = self.channels.dispatch(packet, s, b).await?; } }; Ok(disp) diff --git a/src/runner.rs b/src/runner.rs index 8b505adac87a83c36ff22ed95761f1cd41a9f900..5193fdb1ea669ec75d22898f9bdaf6c5185d54f1 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -94,14 +94,14 @@ impl<'a> Runner<'a> { if let Some((payload, seq)) = self.traf_in.payload() { let d = self.conn.handle_payload(payload, seq, &mut s, behaviour).await?; - if let Some(d) = d.0 { + if let Some(data_in) = d.data_in { // incoming channel data, we haven't finished with payload trace!("handle_payload chan input"); - self.traf_in.set_channel_input(d)?; + self.traf_in.set_channel_input(data_in)?; } else { // other packets have been completed trace!("handle_payload done"); - self.traf_in.done_payload()?; + self.traf_in.done_payload(d.zeroize_payload)?; } } diff --git a/src/traffic.rs b/src/traffic.rs index f0a4ed8605827861a1eeb9490a81452af9b06632..850524ccc6fd5325289fbdeb9e526c0c095b1d45 100644 --- a/src/traffic.rs +++ b/src/traffic.rs @@ -4,6 +4,8 @@ use { log::{debug, error, info, log, trace, warn}, }; +use zeroize::Zeroize; + use crate::encrypt::KeyState; use crate::encrypt::{SSH_LENGTH_SIZE, SSH_PAYLOAD_START}; use crate::ident::RemoteVersion; @@ -128,9 +130,12 @@ impl<'a> TrafIn<'a> { } /// Called when `payload()` and `payload_reborrow()` are complete. - pub(crate) fn done_payload(&mut self) -> Result<(), Error> { + pub(crate) fn done_payload(&mut self, zeroize: bool) -> Result<(), Error> { match self.state { - RxState::InPayload { .. } => { + RxState::InPayload { len, .. } => { + if zeroize { + self.buf[SSH_PAYLOAD_START..SSH_PAYLOAD_START + len].zeroize(); + } self.state = RxState::Idle; Ok(()) }