mirror of
https://github.com/warp-tech/warpgate.git
synced 2024-11-10 09:12:56 +08:00
fixed GHSA-3cjp-w4cp-m9c8 - interpreting SSH public key offers as a successful authentication
This commit is contained in:
parent
1cdd29b6b8
commit
a4df7f7a21
4 changed files with 122 additions and 36 deletions
45
Cargo.lock
generated
45
Cargo.lock
generated
|
@ -1473,9 +1473,9 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "form_urlencoded"
|
name = "form_urlencoded"
|
||||||
version = "1.1.0"
|
version = "1.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8"
|
checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
]
|
]
|
||||||
|
@ -2057,9 +2057,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "idna"
|
name = "idna"
|
||||||
version = "0.3.0"
|
version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6"
|
checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-bidi",
|
"unicode-bidi",
|
||||||
"unicode-normalization",
|
"unicode-normalization",
|
||||||
|
@ -2978,9 +2978,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "percent-encoding"
|
name = "percent-encoding"
|
||||||
version = "2.2.0"
|
version = "2.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
|
checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "phf"
|
name = "phf"
|
||||||
|
@ -3625,9 +3625,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "russh"
|
name = "russh"
|
||||||
version = "0.38.0"
|
version = "0.39.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ae0efcc0f4cd6c062c07e572ce4b806e3967fa029fcbfcc0aa98fb5910a37925"
|
checksum = "7878311587d0353a854d5be954fbe68bdf6e77873933b484d1e45db12bb2f8cf"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aes",
|
"aes",
|
||||||
"aes-gcm",
|
"aes-gcm",
|
||||||
|
@ -5162,9 +5162,9 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "url"
|
name = "url"
|
||||||
version = "2.3.1"
|
version = "2.4.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643"
|
checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"form_urlencoded",
|
"form_urlencoded",
|
||||||
"idna",
|
"idna",
|
||||||
|
@ -5256,7 +5256,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "warpgate"
|
name = "warpgate"
|
||||||
version = "0.7.4"
|
version = "0.8.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ansi_term",
|
"ansi_term",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
@ -5292,7 +5292,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "warpgate-admin"
|
name = "warpgate-admin"
|
||||||
version = "0.7.4"
|
version = "0.8.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
|
@ -5321,7 +5321,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "warpgate-common"
|
name = "warpgate-common"
|
||||||
version = "0.7.4"
|
version = "0.8.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"argon2",
|
"argon2",
|
||||||
|
@ -5357,7 +5357,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "warpgate-core"
|
name = "warpgate-core"
|
||||||
version = "0.7.4"
|
version = "0.8.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"argon2",
|
"argon2",
|
||||||
|
@ -5397,7 +5397,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "warpgate-database-protocols"
|
name = "warpgate-database-protocols"
|
||||||
version = "0.7.4"
|
version = "0.8.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.3.2",
|
"bitflags 1.3.2",
|
||||||
"bytes",
|
"bytes",
|
||||||
|
@ -5410,7 +5410,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "warpgate-db-entities"
|
name = "warpgate-db-entities"
|
||||||
version = "0.7.4"
|
version = "0.8.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"poem-openapi",
|
"poem-openapi",
|
||||||
|
@ -5423,7 +5423,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "warpgate-db-migrations"
|
name = "warpgate-db-migrations"
|
||||||
version = "0.7.4"
|
version = "0.8.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-std",
|
"async-std",
|
||||||
"chrono",
|
"chrono",
|
||||||
|
@ -5435,7 +5435,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "warpgate-protocol-http"
|
name = "warpgate-protocol-http"
|
||||||
version = "0.7.4"
|
version = "0.8.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
|
@ -5456,6 +5456,7 @@ dependencies = [
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-tungstenite 0.17.2",
|
"tokio-tungstenite 0.17.2",
|
||||||
"tracing",
|
"tracing",
|
||||||
|
"url",
|
||||||
"uuid",
|
"uuid",
|
||||||
"warpgate-admin",
|
"warpgate-admin",
|
||||||
"warpgate-common",
|
"warpgate-common",
|
||||||
|
@ -5467,7 +5468,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "warpgate-protocol-mysql"
|
name = "warpgate-protocol-mysql"
|
||||||
version = "0.7.4"
|
version = "0.8.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
|
@ -5494,7 +5495,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "warpgate-protocol-ssh"
|
name = "warpgate-protocol-ssh"
|
||||||
version = "0.7.4"
|
version = "0.8.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ansi_term",
|
"ansi_term",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
@ -5519,7 +5520,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "warpgate-sso"
|
name = "warpgate-sso"
|
||||||
version = "0.7.4"
|
version = "0.8.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"data-encoding",
|
"data-encoding",
|
||||||
|
@ -5535,7 +5536,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "warpgate-web"
|
name = "warpgate-web"
|
||||||
version = "0.7.4"
|
version = "0.8.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rust-embed",
|
"rust-embed",
|
||||||
"serde",
|
"serde",
|
||||||
|
|
|
@ -12,7 +12,7 @@ bimap = "0.6"
|
||||||
bytes = "1.3"
|
bytes = "1.3"
|
||||||
dialoguer = "0.10"
|
dialoguer = "0.10"
|
||||||
futures = "0.3"
|
futures = "0.3"
|
||||||
russh = { version = "0.38.0", features = ["vendored-openssl"] }
|
russh = { version = "0.39.0", features = ["vendored-openssl"] }
|
||||||
# russh = { version = "0.35.0-beta.6", features = ["vendored-openssl"], path = "../../russh/russh"}
|
# russh = { version = "0.35.0-beta.6", features = ["vendored-openssl"], path = "../../russh/russh"}
|
||||||
russh-keys = { version = "0.38.0", features = ["vendored-openssl"] }
|
russh-keys = { version = "0.38.0", features = ["vendored-openssl"] }
|
||||||
# russh-keys = { version = "0.23.0-beta.1", features = ["vendored-openssl"], path = "../../russh/russh-keys" }
|
# russh-keys = { version = "0.23.0-beta.1", features = ["vendored-openssl"], path = "../../russh/russh-keys" }
|
||||||
|
|
|
@ -29,6 +29,7 @@ pub enum ServerHandlerEvent {
|
||||||
PtyRequest(ServerChannelId, PtyRequest, oneshot::Sender<()>),
|
PtyRequest(ServerChannelId, PtyRequest, oneshot::Sender<()>),
|
||||||
ShellRequest(ServerChannelId, oneshot::Sender<bool>),
|
ShellRequest(ServerChannelId, oneshot::Sender<bool>),
|
||||||
AuthPublicKey(Secret<String>, PublicKey, oneshot::Sender<Auth>),
|
AuthPublicKey(Secret<String>, PublicKey, oneshot::Sender<Auth>),
|
||||||
|
AuthPublicKeyOffer(Secret<String>, PublicKey, oneshot::Sender<bool>),
|
||||||
AuthPassword(Secret<String>, Secret<String>, oneshot::Sender<Auth>),
|
AuthPassword(Secret<String>, Secret<String>, oneshot::Sender<Auth>),
|
||||||
AuthKeyboardInteractive(
|
AuthKeyboardInteractive(
|
||||||
Secret<String>,
|
Secret<String>,
|
||||||
|
@ -178,6 +179,33 @@ impl russh::server::Handler for ServerHandler {
|
||||||
Ok((self, session))
|
Ok((self, session))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn auth_publickey_offered(
|
||||||
|
self,
|
||||||
|
user: &str,
|
||||||
|
key: &russh_keys::key::PublicKey,
|
||||||
|
) -> Result<(Self, Auth), Self::Error> {
|
||||||
|
let user = Secret::new(user.to_string());
|
||||||
|
let (tx, rx) = oneshot::channel();
|
||||||
|
|
||||||
|
self.send_event(ServerHandlerEvent::AuthPublicKeyOffer(
|
||||||
|
user,
|
||||||
|
key.clone(),
|
||||||
|
tx,
|
||||||
|
))?;
|
||||||
|
|
||||||
|
let result = rx.await.unwrap_or(false);
|
||||||
|
Ok((
|
||||||
|
self,
|
||||||
|
if result {
|
||||||
|
Auth::Accept
|
||||||
|
} else {
|
||||||
|
Auth::Reject {
|
||||||
|
proceed_with_methods: None,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
async fn auth_publickey(
|
async fn auth_publickey(
|
||||||
self,
|
self,
|
||||||
user: &str,
|
user: &str,
|
||||||
|
|
|
@ -466,6 +466,10 @@ impl ServerSession {
|
||||||
let _ = reply.send(self._auth_publickey(username, key).await);
|
let _ = reply.send(self._auth_publickey(username, key).await);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ServerHandlerEvent::AuthPublicKeyOffer(username, key, reply) => {
|
||||||
|
let _ = reply.send(self._auth_publickey_offer(username, key).await);
|
||||||
|
}
|
||||||
|
|
||||||
ServerHandlerEvent::AuthPassword(username, password, reply) => {
|
ServerHandlerEvent::AuthPassword(username, password, reply) => {
|
||||||
let _ = reply.send(self._auth_password(username, password).await);
|
let _ = reply.send(self._auth_password(username, password).await);
|
||||||
}
|
}
|
||||||
|
@ -1149,19 +1153,7 @@ impl ServerSession {
|
||||||
.map_err(anyhow::Error::from)
|
.map_err(anyhow::Error::from)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn _auth_publickey(
|
fn _get_public_keys_from_of(&self, key: PublicKey) -> Vec<PublicKey> {
|
||||||
&mut self,
|
|
||||||
ssh_username: Secret<String>,
|
|
||||||
key: PublicKey,
|
|
||||||
) -> russh::server::Auth {
|
|
||||||
let selector: AuthSelector = ssh_username.expose_secret().into();
|
|
||||||
|
|
||||||
info!(
|
|
||||||
"Public key auth as {:?} with key {}",
|
|
||||||
selector,
|
|
||||||
key.public_key_base64()
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut keys = vec![key.clone()];
|
let mut keys = vec![key.clone()];
|
||||||
// Try all supported hash algorithms
|
// Try all supported hash algorithms
|
||||||
if let PublicKey::RSA { key, hash } = &key {
|
if let PublicKey::RSA { key, hash } = &key {
|
||||||
|
@ -1178,6 +1170,48 @@ impl ServerSession {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
keys
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn _auth_publickey_offer(
|
||||||
|
&mut self,
|
||||||
|
ssh_username: Secret<String>,
|
||||||
|
key: PublicKey,
|
||||||
|
) -> bool {
|
||||||
|
let keys = self._get_public_keys_from_of(key);
|
||||||
|
let selector: AuthSelector = ssh_username.expose_secret().into();
|
||||||
|
|
||||||
|
for key in keys {
|
||||||
|
if let Ok(true) = self
|
||||||
|
.try_validate_public_key_offer(
|
||||||
|
&selector,
|
||||||
|
Some(AuthCredential::PublicKey {
|
||||||
|
kind: key.name().to_string(),
|
||||||
|
public_key_bytes: Bytes::from(key.public_key_bytes()),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn _auth_publickey(
|
||||||
|
&mut self,
|
||||||
|
ssh_username: Secret<String>,
|
||||||
|
key: PublicKey,
|
||||||
|
) -> russh::server::Auth {
|
||||||
|
let selector: AuthSelector = ssh_username.expose_secret().into();
|
||||||
|
|
||||||
|
info!(
|
||||||
|
"Public key auth as {:?} with key {}",
|
||||||
|
selector,
|
||||||
|
key.public_key_base64()
|
||||||
|
);
|
||||||
|
|
||||||
|
let keys = self._get_public_keys_from_of(key);
|
||||||
|
|
||||||
let mut result = Ok(AuthResult::Rejected);
|
let mut result = Ok(AuthResult::Rejected);
|
||||||
for key in keys {
|
for key in keys {
|
||||||
|
@ -1361,6 +1395,29 @@ impl ServerSession {
|
||||||
m
|
m
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn try_validate_public_key_offer(
|
||||||
|
&mut self,
|
||||||
|
selector: &AuthSelector,
|
||||||
|
credential: Option<AuthCredential>,
|
||||||
|
) -> Result<bool> {
|
||||||
|
match selector {
|
||||||
|
AuthSelector::User { username, .. } => {
|
||||||
|
let cp = self.services.config_provider.clone();
|
||||||
|
|
||||||
|
if let Some(credential) = credential {
|
||||||
|
return Ok(cp
|
||||||
|
.lock()
|
||||||
|
.await
|
||||||
|
.validate_credential(username, &credential)
|
||||||
|
.await?);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(false)
|
||||||
|
}
|
||||||
|
_ => Ok(false),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async fn try_auth(
|
async fn try_auth(
|
||||||
&mut self,
|
&mut self,
|
||||||
selector: &AuthSelector,
|
selector: &AuthSelector,
|
||||||
|
|
Loading…
Reference in a new issue