feat: implement HTTPS mTLS tunnel with auth handshake
Add HTTPS default tunnel endpoint and outbound connector using Rustls with mTLS and an additional auth/session token. - Add rustls, tokio-rustls, hyper, and related dependencies - Implement TLS config builders (server/client) with cert validation - Implement HTTPS tunnel listener with mTLS accept and auth handshake - Implement HTTPS tunnel connector with server cert validation - Add auth token loading from CLI value or file - Add security gate state machine for tracking auth progression - Fail closed for missing/invalid TLS config, cert mismatch, auth failures - Port conflicts fail without fallback - Reconnect revalidates all security gates - 67 tests covering all validation assertions
This commit is contained in:
+118
@@ -0,0 +1,118 @@
|
||||
/// Error types for the HTTPS mTLS tunnel.
|
||||
///
|
||||
/// All errors are designed to be actionable and fail-closed — they never
|
||||
/// silently degrade to an insecure path.
|
||||
use thiserror::Error;
|
||||
|
||||
/// Errors that occur when loading or configuring TLS material.
|
||||
#[derive(Debug, Error)]
|
||||
pub enum TlsError {
|
||||
#[error("missing {0}")]
|
||||
Missing(&'static str),
|
||||
|
||||
#[error("invalid {0}: {1}")]
|
||||
Invalid(&'static str, String),
|
||||
|
||||
#[error("certificate identity mismatch: {0}")]
|
||||
IdentityMismatch(String),
|
||||
|
||||
#[error("certificate expired: {0}")]
|
||||
#[allow(dead_code)]
|
||||
Expired(String),
|
||||
|
||||
#[error("certificate verification failed: {0}")]
|
||||
VerificationFailed(String),
|
||||
|
||||
#[error("I/O error: {0}")]
|
||||
Io(#[from] std::io::Error),
|
||||
|
||||
#[error("rustls error: {0}")]
|
||||
#[allow(dead_code)]
|
||||
Rustls(String),
|
||||
}
|
||||
|
||||
/// Errors that occur during application-level authentication.
|
||||
#[derive(Debug, Error)]
|
||||
pub enum AuthError {
|
||||
#[error("auth token missing")]
|
||||
Missing,
|
||||
|
||||
#[error("auth token invalid")]
|
||||
Invalid,
|
||||
|
||||
#[error("auth token expired")]
|
||||
#[allow(dead_code)]
|
||||
Expired,
|
||||
|
||||
#[error("too many auth attempts")]
|
||||
#[allow(dead_code)]
|
||||
TooManyAttempts,
|
||||
}
|
||||
|
||||
/// Errors that occur during tunnel lifecycle operations.
|
||||
#[derive(Debug, Error)]
|
||||
pub enum TunnelError {
|
||||
#[error("TLS error: {0}")]
|
||||
Tls(#[from] TlsError),
|
||||
|
||||
#[error("auth error: {0}")]
|
||||
Auth(#[from] AuthError),
|
||||
|
||||
#[error("bind error on {0}: {1}")]
|
||||
BindError(String, String),
|
||||
|
||||
#[error("connection refused: {0}")]
|
||||
ConnectionRefused(String),
|
||||
|
||||
#[error("connection closed")]
|
||||
ConnectionClosed,
|
||||
|
||||
#[error("port {0} already in use")]
|
||||
PortInUse(u16),
|
||||
|
||||
#[error("shutdown requested")]
|
||||
#[allow(dead_code)]
|
||||
Shutdown,
|
||||
|
||||
#[error("I/O error: {0}")]
|
||||
Io(#[from] std::io::Error),
|
||||
|
||||
#[error("protocol error: {0}")]
|
||||
Protocol(String),
|
||||
|
||||
#[error("timeout: {0}")]
|
||||
#[allow(dead_code)]
|
||||
Timeout(String),
|
||||
}
|
||||
|
||||
/// Errors returned by the connector side.
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ConnectorError {
|
||||
#[error("TLS handshake failed: {0}")]
|
||||
TlsHandshake(String),
|
||||
|
||||
#[error("server certificate verification failed: {0}")]
|
||||
ServerCertVerification(String),
|
||||
|
||||
#[error("server certificate identity mismatch for {0}: {1}")]
|
||||
ServerIdentityMismatch(String, String),
|
||||
|
||||
#[error("server certificate expired")]
|
||||
ServerCertExpired,
|
||||
|
||||
#[error("auth rejected: {0}")]
|
||||
AuthRejected(String),
|
||||
|
||||
#[error("connection failed: {0}")]
|
||||
ConnectionFailed(String),
|
||||
|
||||
#[error("I/O error: {0}")]
|
||||
Io(#[from] std::io::Error),
|
||||
|
||||
#[error("protocol error: {0}")]
|
||||
Protocol(String),
|
||||
|
||||
#[error("timeout: {0}")]
|
||||
Timeout(String),
|
||||
}
|
||||
Reference in New Issue
Block a user