diff options
author | Justus Winter <justus@sequoia-pgp.org> | 2020-01-16 15:42:47 +0100 |
---|---|---|
committer | Justus Winter <justus@sequoia-pgp.org> | 2020-01-16 15:52:58 +0100 |
commit | e3ca51fc146b7c335762c7e977ab736da9e79999 (patch) | |
tree | a54f23d304fda4613cec95fb67162b323ba45b01 | |
parent | 9dcff17ee0075213fa3f2fefcaa6579336f68be1 (diff) |
openpgp: Consolidate public key verification code.
-rw-r--r-- | openpgp/src/crypto/asymmetric.rs | 94 | ||||
-rw-r--r-- | openpgp/src/packet/signature/mod.rs | 113 |
2 files changed, 97 insertions, 110 deletions
diff --git a/openpgp/src/crypto/asymmetric.rs b/openpgp/src/crypto/asymmetric.rs index e8dd32e4..a92b18ec 100644 --- a/openpgp/src/crypto/asymmetric.rs +++ b/openpgp/src/crypto/asymmetric.rs @@ -304,4 +304,98 @@ impl<P: key::KeyParts, R: key::KeyRole> Key<P, R> { algo => Err(Error::UnsupportedPublicKeyAlgorithm(algo).into()), } } + + /// Verifies the given signature. + pub fn verify(&self, + sig: &packet::signature::Signature4, // XXX: Should be Signature + digest: &[u8]) -> Result<bool> + { + use crate::PublicKeyAlgorithm::*; + use crate::crypto::mpis::{PublicKey, Signature}; + + #[allow(deprecated)] + match (sig.pk_algo(), self.mpis(), sig.mpis()) { + (RSASign, PublicKey::RSA { e, n }, Signature::RSA { s }) | + (RSAEncryptSign, PublicKey::RSA { e, n }, Signature::RSA { s }) => { + let key = rsa::PublicKey::new(n.value(), e.value())?; + + // As described in [Section 5.2.2 and 5.2.3 of RFC 4880], + // to verify the signature, we need to encode the + // signature data in a PKCS1-v1.5 packet. + // + // [Section 5.2.2 and 5.2.3 of RFC 4880]: + // https://tools.ietf.org/html/rfc4880#section-5.2.2 + rsa::verify_digest_pkcs1(&key, digest, sig.hash_algo().oid()?, + s.value()) + }, + (DSA, PublicKey::DSA{ y, p, q, g }, Signature::DSA { s, r }) => { + let key = dsa::PublicKey::new(y.value()); + let params = dsa::Params::new(p.value(), q.value(), g.value()); + let signature = dsa::Signature::new(r.value(), s.value()); + + Ok(dsa::verify(¶ms, &key, digest, &signature)) + }, + (EdDSA, PublicKey::EdDSA{ curve, q }, Signature::EdDSA { r, s }) => + match curve { + Curve::Ed25519 => { + if q.value().get(0).map(|&b| b != 0x40).unwrap_or(true) { + return Err(Error::MalformedPacket( + "Invalid point encoding".into()).into()); + } + + // OpenPGP encodes R and S separately, but our + // cryptographic library expects them to be + // concatenated. + let mut signature = + Vec::with_capacity(ed25519::ED25519_SIGNATURE_SIZE); + + // We need to zero-pad them at the front, because + // the MPI encoding drops leading zero bytes. + let half = ed25519::ED25519_SIGNATURE_SIZE / 2; + if r.value().len() < half { + for _ in 0..half - r.value().len() { + signature.push(0); + } + } + signature.extend_from_slice(r.value()); + if s.value().len() < half { + for _ in 0..half - s.value().len() { + signature.push(0); + } + } + signature.extend_from_slice(s.value()); + + // Let's see if we got it right. + if signature.len() != ed25519::ED25519_SIGNATURE_SIZE { + return Err(Error::MalformedPacket( + format!( + "Invalid signature size: {}, r: {:?}, s: {:?}", + signature.len(), r.value(), s.value())).into()); + } + + ed25519::verify(&q.value()[1..], digest, &signature) + }, + _ => + Err(Error::UnsupportedEllipticCurve(curve.clone()).into()), + }, + (ECDSA, PublicKey::ECDSA{ curve, q }, Signature::ECDSA { s, r }) => + { + let (x, y) = q.decode_point(curve)?; + let key = match curve { + Curve::NistP256 => ecc::Point::new::<ecc::Secp256r1>(x, y)?, + Curve::NistP384 => ecc::Point::new::<ecc::Secp384r1>(x, y)?, + Curve::NistP521 => ecc::Point::new::<ecc::Secp521r1>(x, y)?, + _ => return Err( + Error::UnsupportedEllipticCurve(curve.clone()).into()), + }; + + let signature = dsa::Signature::new(r.value(), s.value()); + Ok(ecdsa::verify(&key, digest, &signature)) + }, + _ => Err(Error::MalformedPacket(format!( + "unsupported combination of algorithm {}, key {} and \ + signature {:?}.", + sig.pk_algo(), self.pk_algo(), sig.mpis())).into()), + } + } } diff --git a/openpgp/src/packet/signature/mod.rs b/openpgp/src/packet/signature/mod.rs index 34ceaf50..2dfb5833 100644 --- a/openpgp/src/packet/signature/mod.rs +++ b/openpgp/src/packet/signature/mod.rs @@ -3,7 +3,6 @@ use std::fmt; use std::ops::{Deref, DerefMut}; -use crate::types::Curve; use crate::Error; use crate::Result; use crate::crypto::{ @@ -28,9 +27,6 @@ use crate::packet::signature::subpacket::{ SubpacketAreas, }; -use nettle::{dsa, ecc, ecdsa, ed25519, rsa}; -use nettle::rsa::verify_digest_pkcs1; - pub mod subpacket; /// Builds a signature packet. @@ -606,10 +602,6 @@ impl Signature4 { R: key::KeyRole, D: AsRef<[u8]>, { - use crate::PublicKeyAlgorithm::*; - use crate::crypto::mpis::PublicKey; - let digest = digest.as_ref(); - if let Some(creation_time) = self.signature_creation_time() { if creation_time < key.creation_time() { return Err(Error::BadSignature( @@ -621,107 +613,7 @@ impl Signature4 { "Signature has no creation time subpacket".into()).into()); } - #[allow(deprecated)] - match (self.pk_algo(), key.mpis(), self.mpis()) { - (RSASign, - &PublicKey::RSA{ ref e, ref n }, - &mpis::Signature::RSA { ref s }) | - (RSAEncryptSign, - &PublicKey::RSA{ ref e, ref n }, - &mpis::Signature::RSA { ref s }) => { - let key = rsa::PublicKey::new(n.value(), e.value())?; - - // As described in [Section 5.2.2 and 5.2.3 of RFC 4880], - // to verify the signature, we need to encode the - // signature data in a PKCS1-v1.5 packet. - // - // [Section 5.2.2 and 5.2.3 of RFC 4880]: - // https://tools.ietf.org/html/rfc4880#section-5.2.2 - verify_digest_pkcs1(&key, digest, self.hash_algo().oid()?, - s.value()) - } - - (DSA, - &PublicKey::DSA{ ref y, ref p, ref q, ref g }, - &mpis::Signature::DSA { ref s, ref r }) => { - let key = dsa::PublicKey::new(y.value()); - let params = dsa::Params::new(p.value(), q.value(), g.value()); - let signature = dsa::Signature::new(r.value(), s.value()); - - Ok(dsa::verify(¶ms, &key, digest, &signature)) - } - - (EdDSA, - &PublicKey::EdDSA{ ref curve, ref q }, - &mpis::Signature::EdDSA { ref r, ref s }) => match curve { - Curve::Ed25519 => { - if q.value().get(0).map(|&b| b != 0x40).unwrap_or(true) { - return Err(Error::MalformedPacket( - "Invalid point encoding".into()).into()); - } - - // OpenPGP encodes R and S separately, but our - // cryptographic library expects them to be - // concatenated. - let mut signature = - Vec::with_capacity(ed25519::ED25519_SIGNATURE_SIZE); - - // We need to zero-pad them at the front, because - // the MPI encoding drops leading zero bytes. - let half = ed25519::ED25519_SIGNATURE_SIZE / 2; - if r.value().len() < half { - for _ in 0..half - r.value().len() { - signature.push(0); - } - } - signature.extend_from_slice(r.value()); - if s.value().len() < half { - for _ in 0..half - s.value().len() { - signature.push(0); - } - } - signature.extend_from_slice(s.value()); - - // Let's see if we got it right. - if signature.len() != ed25519::ED25519_SIGNATURE_SIZE { - return Err(Error::MalformedPacket( - format!( - "Invalid signature size: {}, r: {:?}, s: {:?}", - signature.len(), r.value(), s.value())).into()); - } - - ed25519::verify(&q.value()[1..], digest, &signature) - }, - _ => - Err(Error::UnsupportedEllipticCurve(curve.clone()) - .into()), - }, - - (ECDSA, - &PublicKey::ECDSA{ ref curve, ref q }, - &mpis::Signature::ECDSA { ref s, ref r }) => { - let (x, y) = q.decode_point(curve)?; - let key = match curve { - Curve::NistP256 => - ecc::Point::new::<ecc::Secp256r1>(x, y)?, - Curve::NistP384 => - ecc::Point::new::<ecc::Secp384r1>(x, y)?, - Curve::NistP521 => - ecc::Point::new::<ecc::Secp521r1>(x, y)?, - _ => - return Err( - Error::UnsupportedEllipticCurve(curve.clone()) - .into()), - }; - - let signature = dsa::Signature::new(r.value(), s.value()); - Ok(ecdsa::verify(&key, digest, &signature)) - }, - - _ => Err(Error::MalformedPacket(format!( - "unsupported combination of algorithm {:?}, key {:?} and signature {:?}.", - self.pk_algo(), key.mpis(), self.mpis)).into()) - } + key.verify(self, digest.as_ref()) } /// Verifies the signature over text or binary documents using @@ -1227,6 +1119,7 @@ mod test { use crate::parse::Parse; use crate::packet::Key; use crate::packet::key::Key4; + use crate::types::Curve; #[cfg(feature = "compression-deflate")] #[test] @@ -1454,7 +1347,7 @@ mod test { 0x1,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2 ]; let mut pnt = [0x40u8; nettle::ed25519::ED25519_KEY_SIZE + 1]; - ed25519::public_key(&mut pnt[1..], &sec[..]).unwrap(); + nettle::ed25519::public_key(&mut pnt[1..], &sec[..]).unwrap(); let public_mpis = mpis::PublicKey::EdDSA { curve: Curve::Ed25519, |