mirror of
https://github.com/moghtech/komodo.git
synced 2026-04-28 11:49:39 -05:00
auth forward error
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -3349,7 +3349,6 @@ version = "2.0.0-dev-0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base64 0.22.1",
|
||||
"bytes",
|
||||
"snow",
|
||||
]
|
||||
|
||||
@@ -5770,6 +5769,7 @@ dependencies = [
|
||||
"noise",
|
||||
"rand 0.9.2",
|
||||
"serde",
|
||||
"serror",
|
||||
"sha1",
|
||||
"sha2",
|
||||
"tokio",
|
||||
|
||||
@@ -85,7 +85,17 @@ impl<W: Websocket, S: FnMut()> WebsocketHandler<'_, W, S> {
|
||||
.await?;
|
||||
on_login_success();
|
||||
|
||||
info!("Logged in to Core connection websocket");
|
||||
let config = periphery_config();
|
||||
info!(
|
||||
"Logged in to Core connection websocket{}",
|
||||
if config.core_host.is_some()
|
||||
&& let Some(connect_as) = &config.connect_as
|
||||
{
|
||||
format!(" as Server {connect_as}")
|
||||
} else {
|
||||
String::new()
|
||||
}
|
||||
);
|
||||
|
||||
let (mut ws_write, mut ws_read) = socket.split();
|
||||
|
||||
@@ -148,7 +158,7 @@ impl PublicKeyValidator for CorePublicKeyValidator {
|
||||
periphery_config().core_public_key.as_ref()
|
||||
&& &public_key != expected_public_key
|
||||
{
|
||||
Err(anyhow!("Failed to validate Core public key"))
|
||||
Err(anyhow!("Periphery failed to validate Core public key"))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -10,5 +10,4 @@ homepage.workspace = true
|
||||
[dependencies]
|
||||
anyhow.workspace = true
|
||||
base64.workspace = true
|
||||
bytes.workspace = true
|
||||
snow.workspace = true
|
||||
@@ -1,6 +1,5 @@
|
||||
use anyhow::{Context, anyhow};
|
||||
use base64::{engine::Engine, prelude::BASE64_STANDARD};
|
||||
use bytes::Bytes;
|
||||
|
||||
const NOISE_XX_PARAMS: &str = "Noise_XX_25519_ChaChaPoly_BLAKE2s";
|
||||
|
||||
@@ -67,10 +66,10 @@ impl NoiseHandshake {
|
||||
}
|
||||
|
||||
/// Produces next message to be read on other side of handshake
|
||||
pub fn next_message(&mut self) -> Result<Bytes, snow::Error> {
|
||||
pub fn next_message(&mut self) -> Result<Vec<u8>, snow::Error> {
|
||||
let mut buf = [0u8; 1024];
|
||||
let written = self.0.write_message(&[], &mut buf)?;
|
||||
Ok(Bytes::copy_from_slice(&buf[..written]))
|
||||
Ok(buf[..written].to_vec())
|
||||
}
|
||||
|
||||
/// Gets the base64-encoded remote public key.
|
||||
|
||||
@@ -8,6 +8,8 @@ repository.workspace = true
|
||||
homepage.workspace = true
|
||||
|
||||
[dependencies]
|
||||
serror.workspace = true
|
||||
#
|
||||
tokio-tungstenite.workspace = true
|
||||
futures-util.workspace = true
|
||||
tracing.workspace = true
|
||||
|
||||
@@ -6,12 +6,13 @@
|
||||
//! This is trivial for Periphery -> Core connection, but presents a challenge
|
||||
//! for Core -> Periphery, where untrusted TLS certs are being used.
|
||||
|
||||
use anyhow::{Context, anyhow};
|
||||
use anyhow::Context;
|
||||
use axum::http::{HeaderMap, HeaderValue};
|
||||
use base64::{Engine, prelude::BASE64_STANDARD};
|
||||
use bytes::Bytes;
|
||||
use noise::NoiseHandshake;
|
||||
use rand::RngCore;
|
||||
use serror::{deserialize_error_bytes, serialize_error_bytes};
|
||||
use sha2::{Digest, Sha256};
|
||||
use tracing::warn;
|
||||
|
||||
@@ -70,16 +71,26 @@ impl LoginFlow for ServerLoginFlow {
|
||||
.recv_bytes()
|
||||
.await
|
||||
.context("Failed to get handshake_m1")?;
|
||||
handshake
|
||||
.read_message(&handshake_m1)
|
||||
.context("Failed to read handshake_m1")?;
|
||||
match MessageState::from_byte(
|
||||
*handshake_m1.last().context("handshake_m1 is empty")?,
|
||||
) {
|
||||
MessageState::Successful => handshake
|
||||
.read_message(&handshake_m1[..(handshake_m1.len() - 1)])
|
||||
.context("Failed to read handshake_m1")?,
|
||||
_ => {
|
||||
return Err(deserialize_error_bytes(
|
||||
&handshake_m1[..(handshake_m1.len() - 1)],
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// Send handshake_m2
|
||||
let handshake_m2 = handshake
|
||||
let mut handshake_m2 = handshake
|
||||
.next_message()
|
||||
.context("Failed to write handshake_m2")?;
|
||||
handshake_m2.push(MessageState::Successful.as_byte());
|
||||
socket
|
||||
.send(handshake_m2)
|
||||
.send(handshake_m2.into())
|
||||
.await
|
||||
.context("Failed to send handshake_m2")?;
|
||||
|
||||
@@ -88,14 +99,22 @@ impl LoginFlow for ServerLoginFlow {
|
||||
.recv_bytes()
|
||||
.await
|
||||
.context("Failed to get handshake_m3")?;
|
||||
handshake
|
||||
.read_message(&handshake_m3)
|
||||
.context("Failed to read handshake_m3")?;
|
||||
match MessageState::from_byte(
|
||||
*handshake_m3.last().context("handshake_m3 is empty")?,
|
||||
) {
|
||||
MessageState::Successful => handshake
|
||||
.read_message(&handshake_m3[..(handshake_m3.len() - 1)])
|
||||
.context("Failed to read handshake_m3")?,
|
||||
_ => {
|
||||
return Err(deserialize_error_bytes(
|
||||
&handshake_m3[..(handshake_m3.len() - 1)],
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// Server now has client public key
|
||||
public_key_validator
|
||||
.validate(handshake.remote_public_key()?)
|
||||
.context("Failed to validate remote public key")?;
|
||||
.validate(handshake.remote_public_key()?)?;
|
||||
|
||||
anyhow::Ok(())
|
||||
}
|
||||
@@ -110,10 +129,12 @@ impl LoginFlow for ServerLoginFlow {
|
||||
Ok(())
|
||||
}
|
||||
Err(e) => {
|
||||
let mut bytes = serialize_error_bytes(&e);
|
||||
bytes.push(MessageState::Failed.as_byte());
|
||||
if let Err(e) = socket
|
||||
.send(MessageState::Successful.into())
|
||||
.send(bytes.into())
|
||||
.await
|
||||
.context("Failed to send login successful to client")
|
||||
.context("Failed to send login failed to client")
|
||||
{
|
||||
// Log additional error
|
||||
warn!("{e:#}");
|
||||
@@ -136,65 +157,98 @@ impl LoginFlow for ClientLoginFlow {
|
||||
private_key: &str,
|
||||
public_key_validator: &impl PublicKeyValidator,
|
||||
) -> anyhow::Result<()> {
|
||||
// Receive nonce from server
|
||||
let nonce = socket
|
||||
.recv_bytes()
|
||||
.await
|
||||
.context("Failed to receive connection nonce")?;
|
||||
let res = async {
|
||||
// Receive nonce from server
|
||||
let nonce = socket
|
||||
.recv_bytes()
|
||||
.await
|
||||
.context("Failed to receive connection nonce")?;
|
||||
|
||||
let mut handshake = NoiseHandshake::new_initiator(
|
||||
private_key,
|
||||
// Builds the handshake using the connection-unique prologue hash.
|
||||
// The prologue must be the same on both sides of connection.
|
||||
&connection_identifiers.hash(&nonce),
|
||||
)
|
||||
.context("Failed to inialize handshake")?;
|
||||
let mut handshake = NoiseHandshake::new_initiator(
|
||||
private_key,
|
||||
// Builds the handshake using the connection-unique prologue hash.
|
||||
// The prologue must be the same on both sides of connection.
|
||||
&connection_identifiers.hash(&nonce),
|
||||
)
|
||||
.context("Failed to inialize handshake")?;
|
||||
|
||||
// Send handshake_m1
|
||||
let handshake_m1 = handshake
|
||||
.next_message()
|
||||
.context("Failed to write handshake m1")?;
|
||||
socket
|
||||
.send(handshake_m1)
|
||||
.await
|
||||
.context("Failed to send handshake_m1")?;
|
||||
// Send handshake_m1
|
||||
let mut handshake_m1 = handshake
|
||||
.next_message()
|
||||
.context("Failed to write handshake m1")?;
|
||||
handshake_m1.push(MessageState::Successful.as_byte());
|
||||
socket
|
||||
.send(handshake_m1.into())
|
||||
.await
|
||||
.context("Failed to send handshake_m1")?;
|
||||
|
||||
// Receive and read handshake_m2
|
||||
let handshake_m2 = socket
|
||||
.recv_bytes()
|
||||
.await
|
||||
.context("Failed to get handshake_m2")?;
|
||||
handshake
|
||||
.read_message(&handshake_m2)
|
||||
.context("Failed to read handshake_m2")?;
|
||||
// Receive and read handshake_m2
|
||||
let handshake_m2 = socket
|
||||
.recv_bytes()
|
||||
.await
|
||||
.context("Failed to get handshake_m2")?;
|
||||
match MessageState::from_byte(
|
||||
*handshake_m2.last().context("handshake_m2 is empty")?,
|
||||
) {
|
||||
MessageState::Successful => handshake
|
||||
.read_message(&handshake_m2[..(handshake_m2.len() - 1)])
|
||||
.context("Failed to read handshake_m2")?,
|
||||
_ => {
|
||||
return Err(deserialize_error_bytes(
|
||||
&handshake_m2[..(handshake_m2.len() - 1)],
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// Client now has server public key,
|
||||
// can perform validation.
|
||||
public_key_validator
|
||||
.validate(handshake.remote_public_key()?)
|
||||
.context("Failed to validate remote public key")?;
|
||||
// Client now has server public key,
|
||||
// can perform validation.
|
||||
public_key_validator
|
||||
.validate(handshake.remote_public_key()?)?;
|
||||
|
||||
// Send handshake_m3
|
||||
let handshake_m3 = handshake
|
||||
.next_message()
|
||||
.context("Failed to write handshake_m3")?;
|
||||
socket
|
||||
.send(handshake_m3)
|
||||
.await
|
||||
.context("Failed to send handshake_m3")?;
|
||||
// Send handshake_m3
|
||||
let mut handshake_m3 = handshake
|
||||
.next_message()
|
||||
.context("Failed to write handshake_m3")?;
|
||||
handshake_m3.push(MessageState::Successful.as_byte());
|
||||
socket
|
||||
.send(handshake_m3.into())
|
||||
.await
|
||||
.context("Failed to send handshake_m3")?;
|
||||
|
||||
// Receive login state message and return based on value
|
||||
let state = socket
|
||||
.recv_bytes()
|
||||
.await
|
||||
.context("Failed to receive authentication state message")?;
|
||||
let state = state.first().context(
|
||||
"Authentication state message did not contain state byte",
|
||||
)?;
|
||||
match MessageState::from_byte(*state) {
|
||||
MessageState::Successful => Ok(()),
|
||||
// Todo: More descriptive error?
|
||||
_ => Err(anyhow!("Authentication failed")),
|
||||
// Receive login state message and return based on value
|
||||
let state_msg = socket
|
||||
.recv_bytes()
|
||||
.await
|
||||
.context("Failed to receive authentication state message")?;
|
||||
let state = state_msg.last().context(
|
||||
"Authentication state message did not contain state byte",
|
||||
)?;
|
||||
match MessageState::from_byte(*state) {
|
||||
MessageState::Successful => anyhow::Ok(()),
|
||||
_ => Err(deserialize_error_bytes(
|
||||
&state_msg[..(state_msg.len() - 1)],
|
||||
)),
|
||||
}
|
||||
}
|
||||
.await;
|
||||
|
||||
if let Err(e) = res {
|
||||
let mut bytes = serialize_error_bytes(&e);
|
||||
bytes.push(MessageState::Failed.as_byte());
|
||||
if let Err(e) = socket
|
||||
.send(bytes.into())
|
||||
.await
|
||||
.context("Failed to send login failed to client")
|
||||
{
|
||||
// Log additional error
|
||||
warn!("{e:#}");
|
||||
// Close socket
|
||||
let _ = socket.close(None).await;
|
||||
}
|
||||
// Return the original error
|
||||
Err(e)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user