1
0
mirror of https://github.com/bitwarden/browser synced 2026-02-03 02:03:53 +00:00
This commit is contained in:
Bernd Schoolmann
2025-10-16 14:49:29 +02:00
parent c7be485de8
commit bc0819b0da
10 changed files with 41 additions and 54 deletions

View File

@@ -6,7 +6,7 @@ use tokio_util::sync::CancellationToken;
use crate::{
agent::ui_requester::UiRequester,
memory::UnlockedSshItem,
protocol::{self, key_store::Agent, protocol::serve_listener, types::PublicKeyWithName},
protocol::{self, agent_listener::serve_listener, key_store::Agent, types::PublicKeyWithName},
transport::peer_info::PeerInfo,
};
@@ -31,9 +31,10 @@ impl BitwardenDesktopAgent {
S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Send + Sync + Unpin + 'static,
L: Stream<Item = tokio::io::Result<(S, PeerInfo)>> + Unpin,
{
serve_listener(listener, self.cancellation_token.clone(), self)
.await
.unwrap();
let err = serve_listener(listener, self.cancellation_token.clone(), self).await;
if let Err(e) = err {
tracing::error!("Error in agent listener: {e}");
}
}
pub fn stop(&self) {

View File

@@ -1,5 +1,5 @@
pub mod agent;
pub mod desktop_agent;
pub mod ui_requester;
pub use agent::BitwardenDesktopAgent;
pub use desktop_agent::BitwardenDesktopAgent;
mod platform;
pub use platform::PlatformListener;

View File

@@ -12,7 +12,7 @@ pub struct UiRequester {
get_ui_response_rx: Arc<Mutex<tokio::sync::broadcast::Receiver<(u32, bool)>>>,
}
const REQUEST_ID_COUNTER: AtomicU32 = AtomicU32::new(0);
static REQUEST_ID_COUNTER: AtomicU32 = AtomicU32::new(0);
#[derive(Clone, Debug)]
pub enum UiRequestMessage {

View File

@@ -98,11 +98,11 @@ async fn handle_connection(
.flatten();
if let Some(ssh_item) = ssh_item {
SshSignReply::new(
SshSignReply::try_create(
ssh_item.key_pair.private_key(),
sign_request.payload_to_sign(),
sign_request.signing_scheme(),
)
)?
.encode()
} else {
Ok(AgentFailure::new().into())

View File

@@ -22,12 +22,3 @@ pub(crate) trait Agent: Send + Sync {
public_key: &PublicKey,
) -> Result<Option<UnlockedSshItem>, anyhow::Error>;
}
#[cfg(test)]
pub const PRIVATE_ED25519_KEY: &str = "-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACBDUDO7ChZIednIJxGA95T/ZTyREftahrFEJM/eeC8mmAAAAKByJoOYciaD
mAAAAAtzc2gtZWQyNTUxOQAAACBDUDO7ChZIednIJxGA95T/ZTyREftahrFEJM/eeC8mmA
AAAEBQK5JpycFzP/4rchfpZhbdwxjTwHNuGx2/kvG4i6xfp0NQM7sKFkh52cgnEYD3lP9l
PJER+1qGsUQkz954LyaYAAAAHHF1ZXh0ZW5ATWFjQm9vay1Qcm8tMTYubG9jYWwB
-----END OPENSSH PRIVATE KEY-----";

View File

@@ -1,8 +1,8 @@
//! An implementation of ssh agent
pub(crate) mod agent_listener;
pub(crate) mod async_stream_wrapper;
pub(crate) mod connection;
pub(crate) mod key_store;
pub(crate) mod protocol;
pub(crate) mod replies;
pub(crate) mod requests;
pub mod types;

View File

@@ -90,15 +90,15 @@ impl IdentitiesReply {
pub(crate) struct SshSignReply(Signature);
impl SshSignReply {
pub fn new(
pub fn try_create(
private_key: &PrivateKey,
data: &[u8],
requested_signing_scheme: Option<RsaSigningScheme>,
) -> Self {
Self(
) -> Result<Self, anyhow::Error> {
Ok(Self(
// Note, this should take into account the extension / signing scheme.
private_key.sign(data, requested_signing_scheme).unwrap(),
)
private_key.sign(data, requested_signing_scheme)?,
))
}
/// `https://www.ietf.org/archive/id/draft-miller-ssh-agent-11.html#name-private-key-operations`
@@ -109,7 +109,7 @@ impl SshSignReply {
pub fn encode(&self) -> Result<ReplyFrame, ssh_encoding::Error> {
Ok(ReplyFrame::new(ReplyType::SSH_AGENT_SIGN_RESPONSE, {
let mut reply_payload = Vec::new();
self.0.encode().unwrap().encode(&mut reply_payload)?;
self.0.encode()?.encode(&mut reply_payload)?;
reply_payload
}))
}

View File

@@ -337,7 +337,7 @@ mod tests {
let req =
ParsedSignRequest::try_from(TEST_VECTOR_REQUEST_SIGN_SSHSIG_GIT).expect("Should parse");
assert!(
matches!(req, ParsedSignRequest::SshSigRequest { namespace } if namespace == "git".to_string())
matches!(req, ParsedSignRequest::SshSigRequest { namespace } if namespace == *"git".to_string())
);
}
}

View File

@@ -117,7 +117,7 @@ impl Signature {
let sec1_bytes = public_key_parsed
.key_data()
.ecdsa()
.unwrap()
.ok_or(anyhow::anyhow!("Ecdsa key failed to parse"))?
.as_sec1_bytes();
match curve {
EcdsaCurve::NistP256 => {
@@ -178,10 +178,9 @@ impl TryFrom<&[u8]> for Signature {
type Error = anyhow::Error;
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
let mut buffer = bytes;
let alg = Algorithm::new(
String::from_utf8_lossy(read_bytes(&mut buffer).unwrap().as_slice()).as_ref(),
)?;
let sig = read_bytes(&mut buffer).unwrap();
let alg =
Algorithm::new(String::from_utf8_lossy(read_bytes(&mut buffer)?.as_slice()).as_ref())?;
let sig = read_bytes(&mut buffer)?;
Ok(Signature(ssh_key::Signature::new(alg, sig)?))
}
}
@@ -284,15 +283,24 @@ impl TryFrom<ssh_key::private::PrivateKey> for PrivateKey {
fn try_from(key: ssh_key::private::PrivateKey) -> Result<Self, Self::Error> {
match key.algorithm() {
ssh_key::Algorithm::Ed25519 => {
Ok(Self::Ed25519(key.key_data().ed25519().unwrap().to_owned()))
}
ssh_key::Algorithm::Rsa { hash: _ } => {
Ok(Self::Rsa(key.key_data().rsa().unwrap().to_owned()))
}
ssh_key::Algorithm::Ecdsa { curve: _ } => {
Ok(Self::Ecdsa(key.key_data().ecdsa().unwrap().to_owned()))
}
ssh_key::Algorithm::Ed25519 => Ok(Self::Ed25519(
key.key_data()
.ed25519()
.ok_or(anyhow::anyhow!("Failed to parse ed25519 key"))?
.to_owned(),
)),
ssh_key::Algorithm::Rsa { hash: _ } => Ok(Self::Rsa(
key.key_data()
.rsa()
.ok_or(anyhow::anyhow!("Failed to parse RSA key"))?
.to_owned(),
)),
ssh_key::Algorithm::Ecdsa { curve: _ } => Ok(Self::Ecdsa(
key.key_data()
.ecdsa()
.ok_or(anyhow::anyhow!("Failed to parse ECDSA key"))?
.to_owned(),
)),
_ => Err(anyhow::anyhow!("Unsupported key type")),
}
}
@@ -367,16 +375,3 @@ fn parse_key_safe(pem: &str) -> Result<ssh_key::private::PrivateKey, anyhow::Err
Err(e) => Err(anyhow::Error::msg(format!("Failed to parse key: {e}"))),
}
}
#[cfg(test)]
mod tests {
use crate::protocol::key_store::PRIVATE_ED25519_KEY;
use super::*;
#[test]
fn test_keypair_creation() {
let private_key = PrivateKey::try_from(PRIVATE_ED25519_KEY.to_string())
.expect("Test key is always valid");
}
}

View File

@@ -6,7 +6,7 @@ use std::{fs, io};
use tokio::net::{UnixListener, UnixStream};
use tracing::{error, info};
use crate::agent::agent::BitwardenDesktopAgent;
use crate::agent::desktop_agent::BitwardenDesktopAgent;
use crate::transport::peer_info::{PeerInfo, PeerType};
pub struct UnixListenerStream {