From ef2d8c235fbaafabf5232d4b2c8c6b01de628b89 Mon Sep 17 00:00:00 2001 From: Daniel Alley Date: Sat, 27 May 2023 02:32:46 -0400 Subject: [PATCH] Ensure that we return an error when verifying signatures on a package with no signatures --- src/rpm/headers/header.rs | 6 ++ src/rpm/package.rs | 154 +++++++++++++++++++++++++++----------- src/rpm/signature/pgp.rs | 2 +- 3 files changed, 116 insertions(+), 46 deletions(-) diff --git a/src/rpm/headers/header.rs b/src/rpm/headers/header.rs index f69cc784..4379e0f5 100644 --- a/src/rpm/headers/header.rs +++ b/src/rpm/headers/header.rs @@ -111,6 +111,12 @@ where Ok(()) } + pub fn entry_is_present(&self, tag: T) -> bool { + self.index_entries + .iter() + .any(|entry| entry.tag == tag.to_u32()) + } + pub(crate) fn find_entry_or_err(&self, tag: T) -> Result<&IndexEntry, RPMError> { self.index_entries .iter() diff --git a/src/rpm/package.rs b/src/rpm/package.rs index 6e863dde..27e80b6e 100644 --- a/src/rpm/package.rs +++ b/src/rpm/package.rs @@ -12,6 +12,8 @@ use crate::constants::*; use crate::errors::*; #[cfg(feature = "signature-meta")] use crate::signature; +#[cfg(feature = "signature-pgp")] +use crate::signature::pgp::Verifier; use crate::CompressionType; #[cfg(feature = "signature-meta")] use std::io::Read; @@ -148,7 +150,42 @@ impl RPMPackage { Ok(()) } - // @todo: a function that returns the key ID of the key used to sign this package would be useful + /// Return the key id (issuer) of the signature + #[cfg(feature = "signature-pgp")] + pub fn signature_key_id(&self) -> Result, RPMError> { + let rsa_sig = &self + .metadata + .signature + .get_entry_data_as_binary(IndexSignatureTag::RPMSIGTAG_RSA); + if let Ok(rsa_sig) = rsa_sig { + return Ok(Verifier::parse_signature(rsa_sig)? + .issuer() + .map(hex::encode)); + } + + let eddsa_sig = &self + .metadata + .signature + .get_entry_data_as_binary(IndexSignatureTag::RPMSIGTAG_DSA); + if let Ok(eddsa_sig) = eddsa_sig { + return Ok(Verifier::parse_signature(eddsa_sig)? + .issuer() + .map(hex::encode)); + } + + let rpm_v3_sig = &self + .metadata + .signature + .get_entry_data_as_binary(IndexSignatureTag::RPMSIGTAG_PGP); + if let Ok(rpm_v3_sig) = rpm_v3_sig { + return Ok(Verifier::parse_signature(rpm_v3_sig)? + .issuer() + .map(hex::encode)); + } + + Ok(None) + } + // @todo: verify_signature() and verify_digests() don't provide any feedback on whether a signature/digest // was present and verified or whether it was not present at all. @@ -162,49 +199,78 @@ impl RPMPackage { self.metadata.header.write(&mut header_bytes)?; self.verify_digests()?; - match verifier.algorithm() { - signature::AlgorithmType::RSA => { - if let Ok(signature_header_and_content) = self - .metadata - .signature - .get_entry_data_as_binary(IndexSignatureTag::RPMSIGTAG_PGP) - { - signature::echo_signature( - "signature_header(header and content)", - signature_header_and_content, - ); - let header_and_content_cursor = - io::Cursor::new(&header_bytes).chain(io::Cursor::new(&self.content)); - verifier.verify(header_and_content_cursor, signature_header_and_content)?; - } - - if let Ok(signature_header_only) = self - .metadata - .signature - .get_entry_data_as_binary(IndexSignatureTag::RPMSIGTAG_RSA) - { - signature::echo_signature( - "signature_header(header only)", - signature_header_only, - ); - verifier.verify(header_bytes.as_slice(), signature_header_only)?; - } - } - signature::AlgorithmType::EdDSA => { - if let Ok(signature_header_only) = self - .metadata - .signature - .get_entry_data_as_binary(IndexSignatureTag::RPMSIGTAG_DSA) - { - signature::echo_signature( - "signature_header(header only)", - signature_header_only, - ); - verifier.verify(header_bytes.as_slice(), signature_header_only)?; - } - } + let rsa_sig = &self + .metadata + .signature + .get_entry_data_as_binary(IndexSignatureTag::RPMSIGTAG_RSA); + let eddsa_sig = &self + .metadata + .signature + .get_entry_data_as_binary(IndexSignatureTag::RPMSIGTAG_DSA); + let rpm_v3_sig = &self + .metadata + .signature + .get_entry_data_as_binary(IndexSignatureTag::RPMSIGTAG_PGP); + + if !rsa_sig.is_ok() && !eddsa_sig.is_ok() && !rpm_v3_sig.is_ok() { + return Err(RPMError::NoSignatureFound); } + if let Ok(signature_header_only) = eddsa_sig { + signature::echo_signature("signature_header(header only)", signature_header_only); + verifier.verify(header_bytes.as_slice(), signature_header_only)?; + } + + if let Ok(signature_header_and_content) = rpm_v3_sig { + signature::echo_signature( + "signature_header(header and content)", + signature_header_and_content, + ); + let header_and_content_cursor = + io::Cursor::new(&header_bytes).chain(io::Cursor::new(&self.content)); + verifier.verify(header_and_content_cursor, signature_header_and_content)?; + } + + if let Ok(signature_header_only) = rsa_sig { + signature::echo_signature("signature_header(header only)", signature_header_only); + verifier.verify(header_bytes.as_slice(), signature_header_only)?; + } + + // match verifier.algorithm() { + // signature::AlgorithmType::RSA => { + // if let Ok(signature_header_and_content) = rpm_v3_sig { + // signature::echo_signature( + // "signature_header(header and content)", + // signature_header_and_content, + // ); + // let header_and_content_cursor = + // io::Cursor::new(&header_bytes).chain(io::Cursor::new(&self.content)); + // verifier.verify(header_and_content_cursor, signature_header_and_content)?; + // } + + // if let Ok(signature_header_only) = rsa_sig { + // signature::echo_signature( + // "signature_header(header only)", + // signature_header_only, + // ); + // verifier.verify(header_bytes.as_slice(), signature_header_only)?; + // } else { + // return Err(RPMError::VerificationError { source: (), key_ref: () }) + // } + // } + // signature::AlgorithmType::EdDSA => { + // if let Ok(signature_header_only) = eddsa_sig { + // signature::echo_signature( + // "signature_header(header only)", + // signature_header_only, + // ); + // verifier.verify(header_bytes.as_slice(), signature_header_only)?; + // } else { + // return Err(RPMError::VerificationError { source: (), key_ref: () }) + // } + // } + //} + Ok(()) } @@ -326,9 +392,7 @@ impl RPMPackageMetadata { /// Whether this package is a source package, or not #[inline] pub fn is_source_package(&self) -> bool { - self.header - .find_entry_or_err(IndexTag::RPMTAG_SOURCEPACKAGE) - .is_ok() + self.header.entry_is_present(IndexTag::RPMTAG_SOURCEPACKAGE) } /// Get the package name diff --git a/src/rpm/signature/pgp.rs b/src/rpm/signature/pgp.rs index 93282dba..7a11f7c3 100644 --- a/src/rpm/signature/pgp.rs +++ b/src/rpm/signature/pgp.rs @@ -124,7 +124,7 @@ pub struct Verifier { } impl Verifier { - fn parse_signature(signature: &[u8]) -> Result<::pgp::packet::Signature, RPMError> { + pub(crate) fn parse_signature(signature: &[u8]) -> Result<::pgp::packet::Signature, RPMError> { let mut cursor = Cursor::new(signature); let parser = pgp::packet::PacketParser::new(&mut cursor); let signature = parser