Improve ssh crate API
Signed-off-by: Alexis Sellier <alexis@radicle.xyz>
This commit is contained in:
parent
79c1372d33
commit
c8bff35229
|
|
@ -218,10 +218,12 @@ impl<S: ClientStream> AgentClient<S> {
|
||||||
if self.buf[0] == msg::IDENTITIES_ANSWER {
|
if self.buf[0] == msg::IDENTITIES_ANSWER {
|
||||||
let mut r = self.buf.reader(1);
|
let mut r = self.buf.reader(1);
|
||||||
let n = r.read_u32()?;
|
let n = r.read_u32()?;
|
||||||
|
|
||||||
for _ in 0..n {
|
for _ in 0..n {
|
||||||
let key = r.read_string()?;
|
let key = r.read_string()?;
|
||||||
let _ = r.read_string()?;
|
let _ = r.read_string()?;
|
||||||
let mut r = key.reader(0);
|
let mut r = key.reader(0);
|
||||||
|
|
||||||
if let Some(pk) = K::read(&mut r).map_err(|err| Error::Public(Box::new(err)))? {
|
if let Some(pk) = K::read(&mut r).map_err(|err| Error::Public(Box::new(err)))? {
|
||||||
keys.push(pk);
|
keys.push(pk);
|
||||||
}
|
}
|
||||||
|
|
@ -261,7 +263,7 @@ impl<S: ClientStream> AgentClient<S> {
|
||||||
// uint32 flags
|
// uint32 flags
|
||||||
|
|
||||||
let mut pk = Vec::new().into();
|
let mut pk = Vec::new().into();
|
||||||
let n = public.write_blob(&mut pk);
|
let n = public.write(&mut pk);
|
||||||
let total = 1 + n + 4 + data.len() + 4;
|
let total = 1 + n + 4 + data.len() + 4;
|
||||||
|
|
||||||
debug_assert_eq!(n, pk.len());
|
debug_assert_eq!(n, pk.len());
|
||||||
|
|
@ -295,7 +297,7 @@ impl<S: ClientStream> AgentClient<S> {
|
||||||
K: Public,
|
K: Public,
|
||||||
{
|
{
|
||||||
let mut pk = Vec::new().into();
|
let mut pk = Vec::new().into();
|
||||||
let n = public.write_blob(&mut pk);
|
let n = public.write(&mut pk);
|
||||||
let total = 1 + n;
|
let total = 1 + n;
|
||||||
|
|
||||||
debug_assert_eq!(n, pk.len());
|
debug_assert_eq!(n, pk.len());
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,26 @@
|
||||||
|
use std::error::Error;
|
||||||
|
|
||||||
use crate::encoding::{Buffer, Cursor};
|
use crate::encoding::{Buffer, Cursor};
|
||||||
|
|
||||||
|
/// A public SSH key.
|
||||||
pub trait Public: Sized {
|
pub trait Public: Sized {
|
||||||
type Error;
|
type Error: Error + Send + Sync + 'static;
|
||||||
|
|
||||||
fn write_blob(&self, buf: &mut Buffer) -> usize;
|
/// Write the public key to the given buffer, in SSH "blob" format.
|
||||||
|
fn write(&self, buf: &mut Buffer) -> usize;
|
||||||
|
/// Read the public key from the given reader.
|
||||||
fn read(reader: &mut Cursor) -> Result<Option<Self>, Self::Error>;
|
fn read(reader: &mut Cursor) -> Result<Option<Self>, Self::Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A private SSH key.
|
||||||
pub trait Private: Sized {
|
pub trait Private: Sized {
|
||||||
type Error;
|
type Error: Error + Send + Sync + 'static;
|
||||||
|
|
||||||
fn read(reader: &mut Cursor) -> Result<Option<(Vec<u8>, Self)>, Self::Error>;
|
/// Read a private key from the given reader.
|
||||||
|
fn read(reader: &mut Cursor) -> Result<Option<Self>, Self::Error>;
|
||||||
|
/// Write the key bytes to the supplied buffer.
|
||||||
fn write(&self, buf: &mut Buffer) -> Result<(), Self::Error>;
|
fn write(&self, buf: &mut Buffer) -> Result<(), Self::Error>;
|
||||||
fn write_signature<T: AsRef<[u8]>>(
|
/// Sign the data and write the signature to the given buffer.
|
||||||
&self,
|
fn write_signature<T: AsRef<[u8]>>(&self, data: T, buf: &mut Buffer)
|
||||||
buf: &mut Buffer,
|
-> Result<(), Self::Error>;
|
||||||
to_sign: T,
|
|
||||||
) -> Result<(), Self::Error>;
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -86,7 +86,7 @@ pub enum PublicKeyError {
|
||||||
impl radicle_ssh::key::Public for PublicKey {
|
impl radicle_ssh::key::Public for PublicKey {
|
||||||
type Error = PublicKeyError;
|
type Error = PublicKeyError;
|
||||||
|
|
||||||
fn write_blob(&self, buf: &mut Zeroizing<Vec<u8>>) -> usize {
|
fn write(&self, buf: &mut Zeroizing<Vec<u8>>) -> usize {
|
||||||
let mut n = 0;
|
let mut n = 0;
|
||||||
let typ = b"ssh-ed25519";
|
let typ = b"ssh-ed25519";
|
||||||
let size = typ.len() + self.len() + mem::size_of::<u32>() * 2;
|
let size = typ.len() + self.len() + mem::size_of::<u32>() * 2;
|
||||||
|
|
@ -124,19 +124,21 @@ impl From<crypto::SecretKey> for SecretKey {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum SigningKeyError {
|
pub enum SecretKeyError {
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
Encoding(#[from] encoding::Error),
|
Encoding(#[from] encoding::Error),
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
Crypto(#[from] crypto::Error),
|
Crypto(#[from] crypto::Error),
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
Io(#[from] io::Error),
|
Io(#[from] io::Error),
|
||||||
|
#[error("public key does not match secret key")]
|
||||||
|
Mismatch,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl radicle_ssh::key::Private for SecretKey {
|
impl radicle_ssh::key::Private for SecretKey {
|
||||||
type Error = SigningKeyError;
|
type Error = SecretKeyError;
|
||||||
|
|
||||||
fn read(r: &mut encoding::Cursor) -> Result<Option<(Vec<u8>, Self)>, Self::Error> {
|
fn read(r: &mut encoding::Cursor) -> Result<Option<Self>, Self::Error> {
|
||||||
match r.read_string()? {
|
match r.read_string()? {
|
||||||
b"ssh-ed25519" => {
|
b"ssh-ed25519" => {
|
||||||
let public = r.read_string()?;
|
let public = r.read_string()?;
|
||||||
|
|
@ -144,7 +146,10 @@ impl radicle_ssh::key::Private for SecretKey {
|
||||||
let _comment = r.read_string()?;
|
let _comment = r.read_string()?;
|
||||||
let key = crypto::SecretKey::from_slice(pair).unwrap();
|
let key = crypto::SecretKey::from_slice(pair).unwrap();
|
||||||
|
|
||||||
Ok(Some((public.to_vec(), SecretKey(key))))
|
if public != key.public_key().as_ref() {
|
||||||
|
return Err(SecretKeyError::Mismatch);
|
||||||
|
}
|
||||||
|
Ok(Some(SecretKey(key)))
|
||||||
}
|
}
|
||||||
_ => Ok(None),
|
_ => Ok(None),
|
||||||
}
|
}
|
||||||
|
|
@ -164,11 +169,11 @@ impl radicle_ssh::key::Private for SecretKey {
|
||||||
|
|
||||||
fn write_signature<Bytes: AsRef<[u8]>>(
|
fn write_signature<Bytes: AsRef<[u8]>>(
|
||||||
&self,
|
&self,
|
||||||
|
data: Bytes,
|
||||||
buf: &mut Zeroizing<Vec<u8>>,
|
buf: &mut Zeroizing<Vec<u8>>,
|
||||||
to_sign: Bytes,
|
|
||||||
) -> Result<(), Self::Error> {
|
) -> Result<(), Self::Error> {
|
||||||
let name = "ssh-ed25519";
|
let name = "ssh-ed25519";
|
||||||
let signature: [u8; 64] = *self.0.sign(to_sign.as_ref(), None);
|
let signature: [u8; 64] = *self.0.sign(data.as_ref(), None);
|
||||||
|
|
||||||
buf.deref_mut()
|
buf.deref_mut()
|
||||||
.write_u32::<BigEndian>((name.len() + signature.len() + 8) as u32)?;
|
.write_u32::<BigEndian>((name.len() + signature.len() + 8) as u32)?;
|
||||||
|
|
@ -221,7 +226,7 @@ mod test {
|
||||||
SecretKey(sk).write(&mut buf).unwrap();
|
SecretKey(sk).write(&mut buf).unwrap();
|
||||||
|
|
||||||
let mut cursor = buf.reader(0);
|
let mut cursor = buf.reader(0);
|
||||||
let (_, output) = SecretKey::read(&mut cursor).unwrap().unwrap();
|
let output = SecretKey::read(&mut cursor).unwrap().unwrap();
|
||||||
|
|
||||||
assert_eq!(sk, output.0);
|
assert_eq!(sk, output.0);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue