Skip to content

Commit

Permalink
ssh-key: DRY out ECDSA impls with macro_rules!
Browse files Browse the repository at this point in the history
Adds some macros which write the boilerplate trait impls for each curve
  • Loading branch information
tarcieri committed Nov 20, 2023
1 parent 03e1145 commit 0ffd6c6
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 234 deletions.
131 changes: 33 additions & 98 deletions ssh-key/src/public/ecdsa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,113 +155,48 @@ impl fmt::UpperHex for EcdsaPublicKey {
}
}

#[cfg(feature = "p256")]
impl TryFrom<EcdsaPublicKey> for p256::ecdsa::VerifyingKey {
type Error = Error;

fn try_from(key: EcdsaPublicKey) -> Result<p256::ecdsa::VerifyingKey> {
p256::ecdsa::VerifyingKey::try_from(&key)
}
}

#[cfg(feature = "p384")]
impl TryFrom<EcdsaPublicKey> for p384::ecdsa::VerifyingKey {
type Error = Error;

fn try_from(key: EcdsaPublicKey) -> Result<p384::ecdsa::VerifyingKey> {
p384::ecdsa::VerifyingKey::try_from(&key)
}
}

#[cfg(feature = "p521")]
impl TryFrom<EcdsaPublicKey> for p521::ecdsa::VerifyingKey {
type Error = Error;

fn try_from(key: EcdsaPublicKey) -> Result<p521::ecdsa::VerifyingKey> {
p521::ecdsa::VerifyingKey::try_from(&key)
}
}

#[cfg(feature = "p256")]
impl TryFrom<&EcdsaPublicKey> for p256::ecdsa::VerifyingKey {
type Error = Error;

fn try_from(public_key: &EcdsaPublicKey) -> Result<p256::ecdsa::VerifyingKey> {
match public_key {
EcdsaPublicKey::NistP256(key) => {
p256::ecdsa::VerifyingKey::from_encoded_point(key).map_err(|_| Error::Crypto)
macro_rules! impl_ecdsa_for_curve {
($krate:ident, $feature:expr, $curve:ident) => {
#[cfg(feature = $feature)]
impl TryFrom<EcdsaPublicKey> for $krate::ecdsa::VerifyingKey {
type Error = Error;

fn try_from(key: EcdsaPublicKey) -> Result<$krate::ecdsa::VerifyingKey> {
$krate::ecdsa::VerifyingKey::try_from(&key)
}
_ => Err(Error::AlgorithmUnknown),
}
}
}

#[cfg(feature = "p384")]
impl TryFrom<&EcdsaPublicKey> for p384::ecdsa::VerifyingKey {
type Error = Error;
#[cfg(feature = $feature)]
impl TryFrom<&EcdsaPublicKey> for $krate::ecdsa::VerifyingKey {
type Error = Error;

fn try_from(public_key: &EcdsaPublicKey) -> Result<p384::ecdsa::VerifyingKey> {
match public_key {
EcdsaPublicKey::NistP384(key) => {
p384::ecdsa::VerifyingKey::from_encoded_point(key).map_err(|_| Error::Crypto)
fn try_from(public_key: &EcdsaPublicKey) -> Result<$krate::ecdsa::VerifyingKey> {
match public_key {
EcdsaPublicKey::$curve(key) => {
$krate::ecdsa::VerifyingKey::from_encoded_point(key)
.map_err(|_| Error::Crypto)
}
_ => Err(Error::AlgorithmUnknown),
}
}
_ => Err(Error::AlgorithmUnknown),
}
}
}

#[cfg(feature = "p521")]
impl TryFrom<&EcdsaPublicKey> for p521::ecdsa::VerifyingKey {
type Error = Error;

fn try_from(public_key: &EcdsaPublicKey) -> Result<p521::ecdsa::VerifyingKey> {
match public_key {
EcdsaPublicKey::NistP521(key) => {
p521::ecdsa::VerifyingKey::from_encoded_point(key).map_err(|_| Error::Crypto)
#[cfg(feature = $feature)]
impl From<$krate::ecdsa::VerifyingKey> for EcdsaPublicKey {
fn from(key: $krate::ecdsa::VerifyingKey) -> EcdsaPublicKey {
EcdsaPublicKey::from(&key)
}
_ => Err(Error::AlgorithmUnknown),
}
}
}

#[cfg(feature = "p256")]
impl From<p256::ecdsa::VerifyingKey> for EcdsaPublicKey {
fn from(key: p256::ecdsa::VerifyingKey) -> EcdsaPublicKey {
EcdsaPublicKey::from(&key)
}
}

#[cfg(feature = "p256")]
impl From<&p256::ecdsa::VerifyingKey> for EcdsaPublicKey {
fn from(key: &p256::ecdsa::VerifyingKey) -> EcdsaPublicKey {
EcdsaPublicKey::NistP256(key.to_encoded_point(false))
}
}

#[cfg(feature = "p384")]
impl From<p384::ecdsa::VerifyingKey> for EcdsaPublicKey {
fn from(key: p384::ecdsa::VerifyingKey) -> EcdsaPublicKey {
EcdsaPublicKey::from(&key)
}
}

#[cfg(feature = "p384")]
impl From<&p384::ecdsa::VerifyingKey> for EcdsaPublicKey {
fn from(key: &p384::ecdsa::VerifyingKey) -> EcdsaPublicKey {
EcdsaPublicKey::NistP384(key.to_encoded_point(false))
}
}

#[cfg(feature = "p521")]
impl From<p521::ecdsa::VerifyingKey> for EcdsaPublicKey {
fn from(key: p521::ecdsa::VerifyingKey) -> EcdsaPublicKey {
EcdsaPublicKey::from(&key)
}
#[cfg(feature = $feature)]
impl From<&$krate::ecdsa::VerifyingKey> for EcdsaPublicKey {
fn from(key: &$krate::ecdsa::VerifyingKey) -> EcdsaPublicKey {
EcdsaPublicKey::$curve(key.to_encoded_point(false))
}
}
};
}

#[cfg(feature = "p521")]
impl From<&p521::ecdsa::VerifyingKey> for EcdsaPublicKey {
fn from(key: &p521::ecdsa::VerifyingKey) -> EcdsaPublicKey {
EcdsaPublicKey::NistP521(key.to_encoded_point(false))
}
}
impl_ecdsa_for_curve!(p256, "p256", NistP256);
impl_ecdsa_for_curve!(p384, "p384", NistP384);
impl_ecdsa_for_curve!(p521, "p521", NistP521);
182 changes: 46 additions & 136 deletions ssh-key/src/signature.rs
Original file line number Diff line number Diff line change
Expand Up @@ -459,125 +459,62 @@ fn split_sk_signature(signature: &Signature) -> Result<(&[u8], &[u8])> {
))
}

#[cfg(feature = "p256")]
impl TryFrom<p256::ecdsa::Signature> for Signature {
type Error = Error;

fn try_from(signature: p256::ecdsa::Signature) -> Result<Signature> {
Signature::try_from(&signature)
}
}

#[cfg(feature = "p384")]
impl TryFrom<p384::ecdsa::Signature> for Signature {
type Error = Error;

fn try_from(signature: p384::ecdsa::Signature) -> Result<Signature> {
Signature::try_from(&signature)
}
}

#[cfg(feature = "p521")]
impl TryFrom<p521::ecdsa::Signature> for Signature {
type Error = Error;

fn try_from(signature: p521::ecdsa::Signature) -> Result<Signature> {
Signature::try_from(&signature)
}
}

#[cfg(feature = "p256")]
impl TryFrom<&p256::ecdsa::Signature> for Signature {
type Error = Error;

fn try_from(signature: &p256::ecdsa::Signature) -> Result<Signature> {
let (r, s) = signature.split_bytes();

#[allow(clippy::arithmetic_side_effects)]
let mut data = Vec::with_capacity(32 * 2 + 4 * 2 + 2);

Mpint::from_positive_bytes(&r)?.encode(&mut data)?;
Mpint::from_positive_bytes(&s)?.encode(&mut data)?;

Ok(Signature {
algorithm: Algorithm::Ecdsa {
curve: EcdsaCurve::NistP256,
},
data,
})
}
}

#[cfg(feature = "p384")]
impl TryFrom<&p384::ecdsa::Signature> for Signature {
type Error = Error;

fn try_from(signature: &p384::ecdsa::Signature) -> Result<Signature> {
let (r, s) = signature.split_bytes();

#[allow(clippy::arithmetic_side_effects)]
let mut data = Vec::with_capacity(48 * 2 + 4 * 2 + 2);

Mpint::from_positive_bytes(&r)?.encode(&mut data)?;
Mpint::from_positive_bytes(&s)?.encode(&mut data)?;

Ok(Signature {
algorithm: Algorithm::Ecdsa {
curve: EcdsaCurve::NistP384,
},
data,
})
}
}

#[cfg(feature = "p521")]
impl TryFrom<&p521::ecdsa::Signature> for Signature {
type Error = Error;
macro_rules! impl_signature_for_curve {
($krate:ident, $feature:expr, $curve:ident, $size:expr) => {
#[cfg(feature = $feature)]
impl TryFrom<$krate::ecdsa::Signature> for Signature {
type Error = Error;

fn try_from(signature: $krate::ecdsa::Signature) -> Result<Signature> {
Signature::try_from(&signature)
}
}

fn try_from(signature: &p521::ecdsa::Signature) -> Result<Signature> {
let (r, s) = signature.split_bytes();
#[cfg(feature = $feature)]
impl TryFrom<&$krate::ecdsa::Signature> for Signature {
type Error = Error;

#[allow(clippy::arithmetic_side_effects)]
let mut data = Vec::with_capacity(48 * 2 + 4 * 2 + 2);
fn try_from(signature: &$krate::ecdsa::Signature) -> Result<Signature> {
let (r, s) = signature.split_bytes();

Mpint::from_positive_bytes(&r)?.encode(&mut data)?;
Mpint::from_positive_bytes(&s)?.encode(&mut data)?;
#[allow(clippy::arithmetic_side_effects)]
let mut data = Vec::with_capacity($size * 2 + 4 * 2 + 2);

Ok(Signature {
algorithm: Algorithm::Ecdsa {
curve: EcdsaCurve::NistP521,
},
data,
})
}
}
Mpint::from_positive_bytes(&r)?.encode(&mut data)?;
Mpint::from_positive_bytes(&s)?.encode(&mut data)?;

#[cfg(feature = "p256")]
impl TryFrom<Signature> for p256::ecdsa::Signature {
type Error = Error;
Ok(Signature {
algorithm: Algorithm::Ecdsa {
curve: EcdsaCurve::$curve,
},
data,
})
}
}

fn try_from(signature: Signature) -> Result<p256::ecdsa::Signature> {
p256::ecdsa::Signature::try_from(&signature)
}
}
#[cfg(feature = $feature)]
impl TryFrom<Signature> for $krate::ecdsa::Signature {
type Error = Error;

#[cfg(feature = "p384")]
impl TryFrom<Signature> for p384::ecdsa::Signature {
type Error = Error;
fn try_from(signature: Signature) -> Result<$krate::ecdsa::Signature> {
$krate::ecdsa::Signature::try_from(&signature)
}
}

fn try_from(signature: Signature) -> Result<p384::ecdsa::Signature> {
p384::ecdsa::Signature::try_from(&signature)
}
#[cfg(feature = $feature)]
impl Signer<Signature> for EcdsaPrivateKey<$size> {
fn try_sign(&self, message: &[u8]) -> signature::Result<Signature> {
let signing_key = $krate::ecdsa::SigningKey::from_slice(self.as_ref())?;
let signature: $krate::ecdsa::Signature = signing_key.try_sign(message)?;
Ok(signature.try_into()?)
}
}
};
}

#[cfg(feature = "p521")]
impl TryFrom<Signature> for p521::ecdsa::Signature {
type Error = Error;

fn try_from(signature: Signature) -> Result<p521::ecdsa::Signature> {
p521::ecdsa::Signature::try_from(&signature)
}
}
impl_signature_for_curve!(p256, "p256", NistP256, 32);
impl_signature_for_curve!(p384, "p384", NistP384, 48);
impl_signature_for_curve!(p521, "p521", NistP521, 66);

#[cfg(feature = "p256")]
impl TryFrom<&Signature> for p256::ecdsa::Signature {
Expand Down Expand Up @@ -687,33 +624,6 @@ impl Signer<Signature> for EcdsaKeypair {
}
}

#[cfg(feature = "p256")]
impl Signer<Signature> for EcdsaPrivateKey<32> {
fn try_sign(&self, message: &[u8]) -> signature::Result<Signature> {
let signing_key = p256::ecdsa::SigningKey::from_slice(self.as_ref())?;
let signature: p256::ecdsa::Signature = signing_key.try_sign(message)?;
Ok(signature.try_into()?)
}
}

#[cfg(feature = "p384")]
impl Signer<Signature> for EcdsaPrivateKey<48> {
fn try_sign(&self, message: &[u8]) -> signature::Result<Signature> {
let signing_key = p384::ecdsa::SigningKey::from_slice(self.as_ref())?;
let signature: p384::ecdsa::Signature = signing_key.try_sign(message)?;
Ok(signature.try_into()?)
}
}

#[cfg(feature = "p521")]
impl Signer<Signature> for EcdsaPrivateKey<66> {
fn try_sign(&self, message: &[u8]) -> signature::Result<Signature> {
let signing_key = p521::ecdsa::SigningKey::from_slice(self.as_ref())?;
let signature: p521::ecdsa::Signature = signing_key.try_sign(message)?;
Ok(signature.try_into()?)
}
}

#[cfg(any(feature = "p256", feature = "p384", feature = "p521"))]
impl Verifier<Signature> for EcdsaPublicKey {
fn verify(&self, message: &[u8], signature: &Signature) -> signature::Result<()> {
Expand Down

0 comments on commit 0ffd6c6

Please sign in to comment.