aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--oxish-proto/src/key_exchange.rs24
-rw-r--r--oxish/src/lib.rs21
-rw-r--r--oxish/src/server.rs34
-rw-r--r--oxish/src/session/mod.rs21
4 files changed, 56 insertions, 44 deletions
diff --git a/oxish-proto/src/key_exchange.rs b/oxish-proto/src/key_exchange.rs
index e2acb98..eaa75e4 100644
--- a/oxish-proto/src/key_exchange.rs
+++ b/oxish-proto/src/key_exchange.rs
@@ -433,11 +433,11 @@ impl EcdhKeyExchangeReply {
host_key: &dyn SigningKey,
provider: &dyn CryptoProvider,
) -> Result<(Self, Digest, KeySourceSet), CryptoError> {
- let KeyExchangeOutput {
+ let KeyExchangeStarted {
shared_secret,
exchange_hash,
reply,
- } = KeyExchangeOutput::new(
+ } = KeyExchangeStarted::new(
exchange,
ecdh_key_exchange_init.client_ephemeral_public_key,
negotiated,
@@ -584,13 +584,13 @@ impl SessionHostKey {
}
}
-struct KeyExchangeOutput {
+struct KeyExchangeStarted {
shared_secret: SharedSecret,
exchange_hash: Digest,
reply: EcdhKeyExchangeReply,
}
-impl KeyExchangeOutput {
+impl KeyExchangeStarted {
fn new(
mut exchange: HandshakeHash,
client_ephemeral_public_key: &[u8],
@@ -933,6 +933,22 @@ impl Encode for ExtInfo<'_> {
}
}
+/// Output of the initial key exchange
+pub struct KeyExchangeOutput<'a> {
+ /// The identities exchanged after connection acceptance
+ pub identities: Identities,
+ /// The host key used for the connection
+ pub host_key: ServerHostKey<'a>,
+ /// The strict key exchange state, if negotiated
+ pub strict_kx: Option<StrictKeyExchange>,
+ /// The session ID for the connection
+ pub session_id: Digest,
+ /// The keys derived for the connection
+ pub keys: KeySourceSet,
+ /// Whether post-quantum key exchange was negotiated
+ pub post_quantum_kx: bool,
+}
+
/// The raw hashes from which we will derive the crypto keys.
///
/// See <https://www.rfc-editor.org/rfc/rfc4253#section-7.2>.
diff --git a/oxish/src/lib.rs b/oxish/src/lib.rs
index 7219e96..8e389a6 100644
--- a/oxish/src/lib.rs
+++ b/oxish/src/lib.rs
@@ -20,8 +20,8 @@ use proto::{
KeySourceSide,
},
key_exchange::{
- EcdhKeyExchangeInit, HostKeys, Identities, KeyExchange, KeySourceSet, NewKeys, Rekey,
- ServerHostKey, SessionHostKey, StrictKeyExchange,
+ EcdhKeyExchangeInit, HostKeys, Identities, KeyExchange, KeyExchangeOutput, KeySourceSet,
+ NewKeys, Rekey, ServerHostKey, SessionHostKey, StrictKeyExchange,
},
named::{EncryptionAlgorithm, ExtensionId},
};
@@ -70,14 +70,7 @@ impl<T: AsyncRead + AsyncWrite + Unpin> Connection<T> {
&mut self,
host_keys: &'h HostKeys,
provider: &dyn CryptoProvider,
- ) -> anyhow::Result<(
- Identities,
- ServerHostKey<'h>,
- Option<StrictKeyExchange>,
- Digest,
- KeySourceSet,
- bool,
- )> {
+ ) -> anyhow::Result<KeyExchangeOutput<'h>> {
let (exchange, identities) = self.identify().await.context("identification failed")?;
// Receive and send key exchange init packets
@@ -98,7 +91,7 @@ impl<T: AsyncRead + AsyncWrite + Unpin> Connection<T> {
let packet = receive(&mut self.stream, &mut self.read).await?;
let ecdh_key_exchange_init = EcdhKeyExchangeInit::try_from(packet)?;
- let post_quantum_kex = kx.negotiated.key_exchange.post_quantum_secure();
+ let post_quantum_kx = kx.negotiated.key_exchange.post_quantum_secure();
let (host_key, key_exchange_reply, session_id, keys) = kx
.complete(ecdh_key_exchange_init, host_keys, provider)
.context("key exchange failed")?;
@@ -112,14 +105,14 @@ impl<T: AsyncRead + AsyncWrite + Unpin> Connection<T> {
}
self.send(&Ignore::default()).await?;
- Ok((
+ Ok(KeyExchangeOutput {
identities,
host_key,
strict_kx,
session_id,
keys,
- post_quantum_kex,
- ))
+ post_quantum_kx,
+ })
}
/// Complete a client-initiated rekey after its `SSH_MSG_KEXINIT` has been parsed
diff --git a/oxish/src/server.rs b/oxish/src/server.rs
index 1389640..30f62f2 100644
--- a/oxish/src/server.rs
+++ b/oxish/src/server.rs
@@ -21,7 +21,7 @@ use anyhow::Context as _;
use proto::{
Encode, ReadState, WriteState,
crypto::CryptoProvider,
- key_exchange::{HostKeys, Rekey, ServerHostKey, SessionHostKey},
+ key_exchange::{HostKeys, ServerHostKey},
};
use rustix::net::{
RecvAncillaryBuffer, RecvFlags, SendAncillaryBuffer, SendAncillaryMessage, SendFlags,
@@ -126,24 +126,18 @@ impl Server {
};
let future = conn.exchange_keys(&self.host_keys, self.provider);
- let (identities, host_key, strict_kx, session_id, keys, post_quantum_kx) =
- match timeout(Duration::from_secs(30), future).await {
- Ok(result) => result.context("key exchange failed")?,
- Err(_) => return Err(anyhow::anyhow!("key exchange timed out")),
- };
+ let kx = match timeout(Duration::from_secs(30), future).await {
+ Ok(result) => result.context("key exchange failed")?,
+ Err(_) => return Err(anyhow::anyhow!("key exchange timed out")),
+ };
- let user = authenticate(&session_id, &mut conn, &*self.store, self.provider)
+ let user = authenticate(&kx.session_id, &mut conn, &*self.store, self.provider)
.await
.context("authentication failed")?;
drop(authenticating);
if !self.config.spawn {
- let host_key = SessionHostKey::from_server(host_key, self.provider)?;
- let session = Session::new(
- conn,
- Rekey::new(session_id, strict_kx, identities, host_key),
- post_quantum_kx,
- );
+ let session = Session::new(kx, conn, self.provider)?;
return session.run(self.provider).await.context("session failed");
}
@@ -168,18 +162,18 @@ impl Server {
let state = SessionState {
addr,
- host_key,
- identities,
- post_quantum_kx,
- strict_kx,
- session_id,
+ host_key: kx.host_key,
+ identities: kx.identities,
+ post_quantum_kx: kx.post_quantum_kx,
+ strict_kx: kx.strict_kx,
+ session_id: kx.session_id,
read: SideState {
- source: keys.client_to_server,
+ source: kx.keys.client_to_server,
counter: read.opener.as_ref().map_or(0, |opener| opener.counter()),
sequence_number: read.sequence_number,
},
write: SideState {
- source: keys.server_to_client,
+ source: kx.keys.server_to_client,
counter: write.sealer.as_ref().map_or(0, |sealer| sealer.counter()),
sequence_number: write.sequence_number,
},
diff --git a/oxish/src/session/mod.rs b/oxish/src/session/mod.rs
index ae4a45c..26a1899 100644
--- a/oxish/src/session/mod.rs
+++ b/oxish/src/session/mod.rs
@@ -23,7 +23,7 @@ use tokio::{
use tracing::{debug, info, instrument, trace, warn};
use zeroize::Zeroizing;
-use crate::{Connection, DEFAULT_PROVIDER, Error, SessionState, receive, send};
+use crate::{Connection, DEFAULT_PROVIDER, Error, KeyExchangeOutput, SessionState, receive, send};
mod connections;
use connections::{Channels, IncomingChannelMessage, TerminalsFuture};
@@ -166,13 +166,22 @@ impl Session<TcpStream> {
}
impl<T: AsyncRead + AsyncWrite + Unpin> Session<T> {
- pub(crate) fn new(conn: Connection<T>, rekey: Rekey, post_quantum_kx: bool) -> Self {
- Self {
+ pub(crate) fn new(
+ kx: KeyExchangeOutput<'_>,
+ conn: Connection<T>,
+ provider: &dyn CryptoProvider,
+ ) -> Result<Self, Error> {
+ Ok(Self {
conn,
channels: Channels::default(),
- rekey,
- post_quantum_kx,
- }
+ rekey: Rekey::new(
+ kx.session_id,
+ kx.strict_kx,
+ kx.identities,
+ SessionHostKey::from_server(kx.host_key, provider)?,
+ ),
+ post_quantum_kx: kx.post_quantum_kx,
+ })
}
/// Run the session, driving the connection forward and handling channel messages