diff options
| -rw-r--r-- | oxish-proto/src/auth.rs | 75 | ||||
| -rw-r--r-- | oxish/src/authentication.rs | 58 |
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(()) -} |
