IVSHPDNR6PQRZGJXJLPG2AG5GOXQLAALKD6WWBE4XYUEGAB24EHAC AEIVL6S4SXV6CCOEHFQI7HTEULFIQBEBIBPBLCJ25374JYRXHX2QC LDEEJH5L2QGDPOAASR6FZ7NYHZF56ZPUYMXVCKXCRGTICVCJU4EAC NLPZS76WC64DN5RQEOB45KWXUSEP4VJOVEBR6OMCMFX4MYIOMKSAC LZA3GTZAFVP3RQD4HO7C5F2R5ZOLGBOUPIME4RF47C2GCJG25Q4AC G3FNNIIUCVMPJUICDYPXVS6BP6225LIQZOV5MRNEGCBC5QY3N6NAC 7FRJYUI62VW257VVFQXND6OKSAILVTHGEJCXFE6CG6FIOIUTDVYAC 2WEO7OZLWJJPUYK4WXLT5FD46G2MAEIHEYMDW5GASCBUNKOPXCVAC Q323RFJSTFYUJ5FPTKT4NI7DK3KDC3O4YLBDEYWKEYCA7G276SUQC 2NUPA5PYUATBSGP3JRSL44SL6ICHH7IG5H4CBIRYC4WD4DBSFIVQC ATOFE4ZXBULBMY55LCTFDORZR6AEPXR6RIGDFR4JKPBJ66RCVDFQC MCS77Y4VJGB6TU2HOLASGSRW4B6MT74XABD4KYALIRS54GGN2DDQC MFMCIUMJUYCV2GW5P25D5753YBYXWIMLWKKWX4PABEM7ACUIBGWAC FT67GGO45RNEBZZXT5RRIQOOQKZ5IW2CJXORMCCGITC7VOBGKDJAC OQZGSEWMQXOSEDB6ACSY7NTNZYIYX4ECZWXJ6JD5I7FC64JHTLIQC NHOSLQGG4CIWBE7VKL5MB7PSY3RZ5IVDFENMGZG6X755GGZ6B3VQC KGIUIQYIBBUEGBOQIFYJJNZGGSPV3KERBPYTKKCOBKZZ5CHIJ24AC HDEDMPBT6TKIKQ67T2UYC7QEKF7PG5I6Y4CMRPBDACFY4S3XEWZQC #[error("Environment variable `{0}` not found")]EnvVar(&'static str),#[error("Unable to connect to ssh-agent. The environment variable `SSH_AUTH_SOCK` \was set, but it points to a nonexistent file or directory.")]BadAuthSock,
}impl agent_key::Signature for Signature {type Error = Error;fn read(buf: &CryptoVec) -> Result<Self, Self::Error> {let mut r = buf.reader(1);let mut resp = r.read_string()?.reader(0);let typ = resp.read_string()?;let sig = resp.read_string()?;match typ {b"rsa-sha2-256" => Ok(Signature::RSA {bytes: sig.to_vec(),hash: SignatureHash::SHA2_256,}),b"rsa-sha2-512" => Ok(Signature::RSA {bytes: sig.to_vec(),hash: SignatureHash::SHA2_512,}),b"ssh-ed25519" => {let mut sig_bytes = [0; 64];sig_bytes.clone_from_slice(sig);Ok(Signature::Ed25519(crate::signature::SignatureBytes(sig_bytes,)))}_ => Err((Error::UnknownSignatureType {sig_type: std::str::from_utf8(typ).unwrap_or("").to_string(),}).into()),}}}impl agent_key::Private for KeyPair {type Error = Error;fn read(r: &mut Position) -> Result<Option<(Vec<u8>, Self)>, Self::Error> {let t = r.read_string()?;match t {b"ssh-ed25519" => {let public_ = r.read_string()?;let concat = r.read_string()?;let _comment = r.read_string()?;if &concat[32..64] != public_ {return Ok(None);}let mut public = ed25519::PublicKey::new_zeroed();let mut secret = ed25519::SecretKey::new_zeroed();public.key.clone_from_slice(&public_[..32]);secret.key.clone_from_slice(&concat[..]);Ok(Some((public_.to_vec(), KeyPair::Ed25519(secret))))}#[cfg(feature = "openssl")]b"ssh-rsa" => {use openssl::bn::{BigNum, BigNumContext};use openssl::rsa::Rsa;let n = r.read_mpint()?;let e = r.read_mpint()?;let d = BigNum::from_slice(r.read_mpint()?)?;let q_inv = r.read_mpint()?;let p = BigNum::from_slice(r.read_mpint()?)?;let q = BigNum::from_slice(r.read_mpint()?)?;let (dp, dq) = {let one = BigNum::from_u32(1)?;let p1 = p.as_ref() - one.as_ref();let q1 = q.as_ref() - one.as_ref();let mut context = BigNumContext::new()?;let mut dp = BigNum::new()?;let mut dq = BigNum::new()?;dp.checked_rem(&d, &p1, &mut context)?;dq.checked_rem(&d, &q1, &mut context)?;(dp, dq)};let _comment = r.read_string()?;let key = Rsa::from_private_components(BigNum::from_slice(n)?,BigNum::from_slice(e)?,d,p,q,dp,dq,BigNum::from_slice(&q_inv)?,)?;let mut buf = CryptoVec::new();buf.extend_ssh_string(b"ssh-rsa");buf.extend_ssh_mpint(&e);buf.extend_ssh_mpint(&n);let blob = buf.to_vec();Ok(Some((blob,KeyPair::RSA {key,hash: SignatureHash::SHA2_256,},)))}_ => Ok(None),}}fn write(&self, buf: &mut CryptoVec) -> Result<(), Self::Error> {match *self {KeyPair::Ed25519(ref secret) => {buf.extend_ssh_string(b"ssh-ed25519");let public = &secret.key[32..];buf.extend_ssh_string(public);buf.push_u32_be(64);buf.extend(&secret.key);buf.extend_ssh_string(b"");}#[cfg(feature = "openssl")]KeyPair::RSA { ref key, .. } => {buf.extend_ssh_string(b"ssh-rsa");buf.extend_ssh_mpint(&key.n().to_vec());buf.extend_ssh_mpint(&key.e().to_vec());buf.extend_ssh_mpint(&key.d().to_vec());if let Some(iqmp) = key.iqmp() {buf.extend_ssh_mpint(&iqmp.to_vec());} else {let mut ctx = openssl::bn::BigNumContext::new()?;let mut iqmp = openssl::bn::BigNum::new()?;iqmp.mod_inverse(key.p().unwrap(), key.q().unwrap(), &mut ctx)?;buf.extend_ssh_mpint(&iqmp.to_vec());}buf.extend_ssh_mpint(&key.p().unwrap().to_vec());buf.extend_ssh_mpint(&key.q().unwrap().to_vec());buf.extend_ssh_string(b"");}}Ok(())}fn write_signature<Bytes: AsRef<[u8]>>(&self,buf: &mut CryptoVec,to_sign: Bytes,) -> Result<(), Self::Error> {self.add_signature(buf, to_sign)}}impl agent_key::Public for PublicKey {type Error = Error;fn read(r: &mut Position) -> Result<Option<Self>, Self::Error> {let t = r.read_string()?;debug!("t = {:?}", std::str::from_utf8(t));match t {#[cfg(feature = "openssl")]b"ssh-rsa" => {let e = r.read_mpint()?;let n = r.read_mpint()?;use openssl::bn::BigNum;use openssl::pkey::PKey;use openssl::rsa::Rsa;Ok(Some(PublicKey::RSA {key: OpenSSLPKey(PKey::from_rsa(Rsa::from_public_components(BigNum::from_slice(n)?,BigNum::from_slice(e)?,)?)?),hash: SignatureHash::SHA2_512,}))}b"ssh-ed25519" => {let mut p = ed25519::PublicKey::new_zeroed();p.key.clone_from_slice(r.read_string()?);Ok(Some(PublicKey::Ed25519(p)))}t => {info!("Unsupported key type: {:?}", std::str::from_utf8(t));Ok(None)}}}fn write_blob(&self, buf: &mut CryptoVec) {match *self {#[cfg(feature = "openssl")]PublicKey::RSA { ref key, .. } => {buf.extend(&[0, 0, 0, 0]);let len0 = buf.len();buf.extend_ssh_string(b"ssh-rsa");let rsa = key.0.rsa().unwrap();buf.extend_ssh_mpint(&rsa.e().to_vec());buf.extend_ssh_mpint(&rsa.n().to_vec());let len1 = buf.len();BigEndian::write_u32(&mut buf[5..], (len1 - len0) as u32);}PublicKey::Ed25519(ref p) => {buf.extend(&[0, 0, 0, 0]);let len0 = buf.len();buf.extend_ssh_string(b"ssh-ed25519");buf.extend_ssh_string(&p.key[0..]);let len1 = buf.len();BigEndian::write_u32(&mut buf[5..], (len1 - len0) as u32);}}}fn hash(&self) -> u32 {match self {#[cfg(feature = "openssl")]PublicKey::RSA { hash, .. } => match hash {SignatureHash::SHA2_256 => 2,SignatureHash::SHA2_512 => 4,SignatureHash::SHA1 => 0,},_ => 0,}}
#[derive(Clone)]struct KeyStore(Arc<RwLock<HashMap<Vec<u8>, (Arc<key::KeyPair>, SystemTime, Vec<Constraint>)>>>);
// NOTE: need to implement this since the derived version will require `Key: Clone` which is unecessary.impl<Key> Clone for KeyStore<Key> {fn clone(&self) -> Self {KeyStore(self.0.clone())}}
pub trait Agent: Clone + Send + 'static {fn confirm(self,_pk: Arc<key::KeyPair>,) -> Box<dyn Future<Output = (Self, bool)> + Unpin + Send> {
pub trait Agent<Key>: Clone + Send + 'static {fn confirm(self, _pk: Arc<Key>) -> Box<dyn Future<Output = (Self, bool)> + Unpin + Send> {
impl<S: AsyncRead + AsyncWrite + Send + Unpin + 'static, A: Agent + Send + 'static>Connection<S, A>
impl<K, S, A> Connection<K, S, A>whereK: Private + Send + Sync + 'static,K::Error: std::error::Error + Send + Sync + 'static,S: AsyncRead + AsyncWrite + Send + Unpin + 'static,A: Agent<K> + Send + 'static,
let pos0 = r.position;let t = r.read_string()?;let (blob, key) = match t {b"ssh-ed25519" => {let public_ = r.read_string()?;let pos1 = r.position;let concat = r.read_string()?;let _comment = r.read_string()?;if &concat[32..64] != public_ {return Ok(false);}use key::ed25519::*;let mut public = PublicKey::new_zeroed();let mut secret = SecretKey::new_zeroed();public.key.clone_from_slice(&public_[..32]);secret.key.clone_from_slice(&concat[..]);writebuf.push(msg::SUCCESS);(self.buf[pos0..pos1].to_vec(), key::KeyPair::Ed25519(secret))}#[cfg(feature = "openssl")]b"ssh-rsa" => {use openssl::bn::{BigNum, BigNumContext};use openssl::rsa::Rsa;let n = r.read_mpint()?;let e = r.read_mpint()?;let d = BigNum::from_slice(r.read_mpint()?)?;let q_inv = r.read_mpint()?;let p = BigNum::from_slice(r.read_mpint()?)?;let q = BigNum::from_slice(r.read_mpint()?)?;let (dp, dq) = {let one = BigNum::from_u32(1)?;let p1 = p.as_ref() - one.as_ref();let q1 = q.as_ref() - one.as_ref();let mut context = BigNumContext::new()?;let mut dp = BigNum::new()?;let mut dq = BigNum::new()?;dp.checked_rem(&d, &p1, &mut context)?;dq.checked_rem(&d, &q1, &mut context)?;(dp, dq)};let _comment = r.read_string()?;let key = Rsa::from_private_components(BigNum::from_slice(n)?,BigNum::from_slice(e)?,d,p,q,dp,dq,BigNum::from_slice(&q_inv)?,)?;let len0 = writebuf.len();writebuf.extend_ssh_string(b"ssh-rsa");writebuf.extend_ssh_mpint(&e);writebuf.extend_ssh_mpint(&n);let blob = writebuf[len0..].to_vec();writebuf.resize(len0);writebuf.push(msg::SUCCESS);(blob,key::KeyPair::RSA {key,hash: SignatureHash::SHA2_256,},)}_ => return Ok(false),
let (blob, key) = match K::read(&mut r).map_err(|err| Error::Private(Box::new(err)))? {Some((blob, key)) => (blob, key),None => return Ok(false),
#[derive(Debug, Error)]pub enum Error {/// Agent protocol error#[error("Agent protocol error")]AgentProtocolError,#[error("Agent failure")]AgentFailure,#[error("Unable to connect to ssh-agent. The environment variable `SSH_AUTH_SOCK` \was set, but it points to a nonexistent file or directory.")]BadAuthSock,#[error(transparent)]Encoding(#[from] thrussh_encoding::Error),#[error("Environment variable `{0}` not found")]EnvVar(&'static str),#[error(transparent)]Io(#[from] std::io::Error),#[error(transparent)]Private(Box<dyn std::error::Error + Send + Sync + 'static>),
match *key {key::KeyPair::Ed25519(ref secret) => {self.buf.extend_ssh_string(b"ssh-ed25519");let public = &secret.key[32..];self.buf.extend_ssh_string(public);self.buf.push_u32_be(64);self.buf.extend(&secret.key);self.buf.extend_ssh_string(b"");}#[cfg(feature = "openssl")]key::KeyPair::RSA { ref key, .. } => {self.buf.extend_ssh_string(b"ssh-rsa");self.buf.extend_ssh_mpint(&key.n().to_vec());self.buf.extend_ssh_mpint(&key.e().to_vec());self.buf.extend_ssh_mpint(&key.d().to_vec());if let Some(iqmp) = key.iqmp() {self.buf.extend_ssh_mpint(&iqmp.to_vec());} else {let mut ctx = openssl::bn::BigNumContext::new()?;let mut iqmp = openssl::bn::BigNum::new()?;iqmp.mod_inverse(key.p().unwrap(), key.q().unwrap(), &mut ctx)?;self.buf.extend_ssh_mpint(&iqmp.to_vec());}self.buf.extend_ssh_mpint(&key.p().unwrap().to_vec());self.buf.extend_ssh_mpint(&key.q().unwrap().to_vec());self.buf.extend_ssh_string(b"");}}
key.write(&mut self.buf).map_err(|err| Error::Private(Box::new(err)))?;
let t = r.read_string()?;debug!("t = {:?}", std::str::from_utf8(t));match t {#[cfg(feature = "openssl")]b"ssh-rsa" => {let e = r.read_mpint()?;let n = r.read_mpint()?;use openssl::bn::BigNum;use openssl::pkey::PKey;use openssl::rsa::Rsa;keys.push(PublicKey::RSA {key: key::OpenSSLPKey(PKey::from_rsa(Rsa::from_public_components(BigNum::from_slice(n)?,BigNum::from_slice(e)?,)?)?),hash: SignatureHash::SHA2_512,})}b"ssh-ed25519" => {let mut p = key::ed25519::PublicKey::new_zeroed();p.key.clone_from_slice(r.read_string()?);keys.push(PublicKey::Ed25519(p))}t => {info!("Unsupported key type: {:?}", std::str::from_utf8(t))}
if let Some(pk) = K::read(&mut r).map_err(|err| Error::Public(Box::new(err)))? {keys.push(pk);
let hash = match public {#[cfg(feature = "openssl")]PublicKey::RSA { hash, .. } => match hash {SignatureHash::SHA2_256 => 2,SignatureHash::SHA2_512 => 4,SignatureHash::SHA1 => 0,},_ => 0,};
let hash = public.hash();
) -> impl futures::Future<Output = (Self, Result<crate::signature::Signature, Error>)> {
) -> impl futures::Future<Output = (Self, Result<Sig, Error>)>whereK: Public + fmt::Debug,Sig: Signature,Sig::Error: std::error::Error + Send + Sync +'static,{
let as_sig = |buf: &CryptoVec| -> Result<crate::signature::Signature, Error> {let mut r = buf.reader(1);let mut resp = r.read_string()?.reader(0);let typ = resp.read_string()?;let sig = resp.read_string()?;use crate::signature::Signature;match typ {b"rsa-sha2-256" => Ok(Signature::RSA {bytes: sig.to_vec(),hash: SignatureHash::SHA2_256,}),b"rsa-sha2-512" => Ok(Signature::RSA {bytes: sig.to_vec(),hash: SignatureHash::SHA2_512,}),b"ssh-ed25519" => {let mut sig_bytes = [0; 64];sig_bytes.clone_from_slice(sig);Ok(Signature::Ed25519(crate::signature::SignatureBytes(sig_bytes,)))}_ => Err((Error::UnknownSignatureType {sig_type: std::str::from_utf8(typ).unwrap_or("").to_string(),}).into()),}};let sig = as_sig(&self.buf);
let sig = Sig::read(&self.buf).map_err(|err| Error::Signature(Box::new(err)));
}}fn key_blob(public: &key::PublicKey, buf: &mut CryptoVec) {match *public {#[cfg(feature = "openssl")]PublicKey::RSA { ref key, .. } => {buf.extend(&[0, 0, 0, 0]);let len0 = buf.len();buf.extend_ssh_string(b"ssh-rsa");let rsa = key.0.rsa().unwrap();buf.extend_ssh_mpint(&rsa.e().to_vec());buf.extend_ssh_mpint(&rsa.n().to_vec());let len1 = buf.len();BigEndian::write_u32(&mut buf[5..], (len1 - len0) as u32);}PublicKey::Ed25519(ref p) => {buf.extend(&[0, 0, 0, 0]);let len0 = buf.len();buf.extend_ssh_string(b"ssh-ed25519");buf.extend_ssh_string(&p.key[0..]);let len1 = buf.len();BigEndian::write_u32(&mut buf[5..], (len1 - len0) as u32);}