aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--oxish-proto/src/auth.rs75
-rw-r--r--oxish/src/authentication.rs58
2 files changed, 76 insertions, 57 deletions
diff --git a/oxish-proto/src/auth.rs b/oxish-proto/src/auth.rs
index 153f037..a7ce60c 100644
--- a/oxish-proto/src/auth.rs
+++ b/oxish-proto/src/auth.rs
@@ -177,6 +177,68 @@ pub struct Signature<'a> {
pub signature_blob: &'a [u8],
}
+impl Signature<'_> {
+ /// Encode the signature for verification
+ pub fn encode(self) -> Result<EncodedSignature, ProtoError> {
+ Ok(EncodedSignature(match &self.algorithm {
+ PublicKeyAlgorithm::EcdsaSha2Nistp256 => {
+ let Decoded {
+ value: r,
+ next: rest,
+ } = <&[u8]>::decode(self.signature_blob)?;
+
+ let Decoded { value: s, next } = <&[u8]>::decode(rest)?;
+ if !next.is_empty() {
+ return Err(ProtoError::InvalidPacket(
+ "extra data after ECDSA signature components",
+ ));
+ }
+
+ let mut fixed = [0u8; 64];
+ if mpint_to_fixed(r, &mut fixed[..64 / 2]).is_none() {
+ return Err(ProtoError::InvalidPacket(
+ "failure to decode r in ECDSA signature",
+ ));
+ }
+
+ if mpint_to_fixed(s, &mut fixed[64 / 2..]).is_none() {
+ return Err(ProtoError::InvalidPacket(
+ "failure to decode s in ECDSA signature",
+ ));
+ }
+
+ fixed.to_vec()
+ }
+ PublicKeyAlgorithm::Ed25519 => self.signature_blob.to_vec(),
+ algorithm => {
+ warn!(
+ ?algorithm,
+ "unsupported public key algorithm for verification"
+ );
+ return Err(ProtoError::InvalidPacket(
+ "unsupported public key algorithm for verification",
+ ));
+ }
+ }))
+ }
+}
+
+/// Convert an SSH mpint to a fixed-width big-endian representation
+fn mpint_to_fixed(mpint: &[u8], out: &mut [u8]) -> Option<()> {
+ let data = match mpint.split_first() {
+ Some((&0, rest)) if !rest.is_empty() => rest,
+ _ => mpint,
+ };
+
+ if data.len() > out.len() {
+ return None;
+ }
+
+ let offset = out.len() - data.len();
+ out[offset..].copy_from_slice(data);
+ Some(())
+}
+
impl<'a> Decode<'a> for Signature<'a> {
fn decode(input: &'a [u8]) -> Result<Decoded<'a, Self>, ProtoError> {
let Decoded { value: input, next } = <&[u8]>::decode(input)?;
@@ -208,6 +270,19 @@ impl<'a> Decode<'a> for Signature<'a> {
}
}
+/// Encoded signature for public key authentication
+///
+/// Constructed by [`Signature::encode()`].
+pub struct EncodedSignature(Vec<u8>);
+
+impl Deref for EncodedSignature {
+ type Target = [u8];
+
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+
/// The `SSH_MSG_USERAUTH_FAILURE` message
///
/// See <https://www.rfc-editor.org/rfc/rfc4252#section-5.1>.
diff --git a/oxish/src/authentication.rs b/oxish/src/authentication.rs
index 42f4b0f..705d26a 100644
--- a/oxish/src/authentication.rs
+++ b/oxish/src/authentication.rs
@@ -730,48 +730,8 @@ impl AuthorizedKey {
message: SignatureData<'_>,
signature: Signature<'_>,
) -> Result<(), ProtoError> {
- let signature = match &self.algorithm {
- PublicKeyAlgorithm::EcdsaSha2Nistp256 => {
- let Decoded {
- value: r,
- next: rest,
- } = <&[u8]>::decode(signature.signature_blob)?;
-
- let Decoded { value: s, next } = <&[u8]>::decode(rest)?;
- if !next.is_empty() {
- return Err(ProtoError::InvalidPacket(
- "extra data after ECDSA signature components",
- ));
- }
-
- let mut fixed = [0u8; 64];
- if mpint_to_fixed(r, &mut fixed[..64 / 2]).is_none() {
- return Err(ProtoError::InvalidPacket(
- "failure to decode r in ECDSA signature",
- ));
- }
-
- if mpint_to_fixed(s, &mut fixed[64 / 2..]).is_none() {
- return Err(ProtoError::InvalidPacket(
- "failure to decode s in ECDSA signature",
- ));
- }
-
- fixed.to_vec()
- }
- PublicKeyAlgorithm::Ed25519 => signature.signature_blob.to_vec(),
- algorithm => {
- warn!(
- ?algorithm,
- "unsupported public key algorithm for verification"
- );
- return Err(ProtoError::InvalidPacket(
- "unsupported public key algorithm for verification",
- ));
- }
- };
-
let encoded = message.encode();
+ let signature = signature.encode()?;
let key = self.key.clone();
spawn_blocking(move || {
key.verify(&encoded, &signature)
@@ -789,19 +749,3 @@ impl fmt::Debug for AuthorizedKey {
.finish_non_exhaustive()
}
}
-
-/// Convert an SSH mpint to a fixed-width big-endian representation
-fn mpint_to_fixed(mpint: &[u8], out: &mut [u8]) -> Option<()> {
- let data = match mpint.split_first() {
- Some((&0, rest)) if !rest.is_empty() => rest,
- _ => mpint,
- };
-
- if data.len() > out.len() {
- return None;
- }
-
- let offset = out.len() - data.len();
- out[offset..].copy_from_slice(data);
- Some(())
-}