summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeal H. Walfield <neal@pep.foundation>2023-03-23 12:26:39 +0100
committerNeal H. Walfield <neal@pep.foundation>2023-03-23 13:27:18 +0100
commitb1d8527d1fb56e2d97c8a285d2ff1dc1e931d4c6 (patch)
tree648aeab9c479e6ad8241940d6bde4d2f090d1810
parent330c9a66abc6ce7d6cb79e5361ad0903b4ce3ab1 (diff)
openpgp: Implement Parse for RawCert
- We implement `Parse` for `Cert`. Do the same for `RawCert` and check that they have the same semantics.
-rw-r--r--openpgp/NEWS1
-rw-r--r--openpgp/src/cert/raw.rs91
2 files changed, 88 insertions, 4 deletions
diff --git a/openpgp/NEWS b/openpgp/NEWS
index 841241ea..61cd54e7 100644
--- a/openpgp/NEWS
+++ b/openpgp/NEWS
@@ -13,6 +13,7 @@
- fmt::hex::Dumper::with_offset
- parse::buffered_reader re-export
- policy::AsymmetricAlgorithm::BrainpoolP384
+ - RawCert implements Parse
** Deprecated functionality
- crypto::mpi::SecretKeyMaterial::parse
- crypto::mpi::SecretKeyMaterial::parse_with_checksum
diff --git a/openpgp/src/cert/raw.rs b/openpgp/src/cert/raw.rs
index fa99b9ae..cc3efe7d 100644
--- a/openpgp/src/cert/raw.rs
+++ b/openpgp/src/cert/raw.rs
@@ -116,7 +116,7 @@ pub use iter::KeyIter;
/// use sequoia_openpgp as openpgp;
/// # use openpgp::Result;
/// # use openpgp::cert::prelude::*;
-/// use openpgp::cert::raw::RawCertParser;
+/// # use openpgp::cert::raw::RawCert;
/// use openpgp::packet::Packet;
/// use openpgp::packet::Tag;
/// # use openpgp::parse::Parse;
@@ -135,9 +135,7 @@ pub use iter::KeyIter;
/// # cert.as_tsk().serialize(&mut bytes);
/// # let mut count = 0;
/// #
-/// # let rawcert = RawCertParser::from_bytes(&bytes)?
-/// # .next().expect("got a cert")
-/// # .expect("valid cert");
+/// # let rawcert = RawCert::from_bytes(&bytes)?;
/// for p in rawcert.packets() {
/// if p.tag() == Tag::SecretSubkey {
/// if let Ok(packet) = Packet::try_from(p) {
@@ -457,6 +455,26 @@ impl<'a> TryFrom<RawCert<'a>> for Cert {
}
}
+impl<'a> Parse<'a, RawCert<'a>> for RawCert<'a> {
+ /// Returns the first RawCert encountered in the reader.
+ ///
+ /// Returns an error if there are multiple certificates.
+ fn from_reader<R: 'a + Read + Send + Sync>(reader: R) -> Result<Self> {
+ let mut parser = RawCertParser::from_reader(reader)?;
+ if let Some(cert_result) = parser.next() {
+ if parser.next().is_some() {
+ Err(Error::MalformedCert(
+ "Additional packets found, is this a keyring?".into()
+ ).into())
+ } else {
+ cert_result
+ }
+ } else {
+ Err(Error::MalformedCert("No data".into()).into())
+ }
+ }
+}
+
impl<'a> crate::seal::Sealed for RawCert<'a> {}
impl<'a> crate::serialize::Marshal for RawCert<'a> {
fn serialize(&self, o: &mut dyn std::io::Write) -> Result<()> {
@@ -1531,4 +1549,69 @@ mod test {
.collect::<Vec<_>>(),
vec![ "Testy McTestface <testy@example.org>" ]);
}
+
+ // Test the raw cert parser implementation.
+ #[test]
+ fn raw_cert_parser_impl() {
+ // Read one certificate.
+ let testy = crate::tests::key("testy.pgp");
+
+ let raw = RawCert::from_bytes(testy).expect("valid");
+ let cert = Cert::from_bytes(testy).expect("valid");
+
+ assert_eq!(
+ raw.keys().map(|k| k.fingerprint()).collect::<Vec<_>>(),
+ cert.keys().map(|k| k.fingerprint()).collect::<Vec<_>>());
+
+ assert_eq!(
+ raw.userids().collect::<Vec<_>>(),
+ cert.userids().map(|ua| ua.userid().clone()).collect::<Vec<_>>());
+
+ // Parse zero certificates.
+ eprintln!("Parsing 0 bytes");
+ let raw = RawCert::from_bytes(b"");
+ match &raw {
+ Ok(_) => eprintln!("raw: Ok"),
+ Err(err) => eprintln!("raw: {}", err),
+ }
+ let cert = Cert::from_bytes(b"");
+ match &cert {
+ Ok(_) => eprintln!("cert: Ok"),
+ Err(err) => eprintln!("cert: {}", err),
+ }
+
+ assert!(
+ matches!(cert.map_err(|e| e.downcast::<Error>()),
+ Err(Ok(Error::MalformedCert(_)))));
+ assert!(
+ matches!(raw.map_err(|e| e.downcast::<Error>()),
+ Err(Ok(Error::MalformedCert(_)))));
+
+ // Parse two certificates.
+ let mut bytes = Vec::new();
+ bytes.extend(testy);
+ bytes.extend(testy);
+
+ let parser = CertParser::from_bytes(&bytes).expect("valid");
+ assert_eq!(parser.count(), 2);
+
+ eprintln!("Parsing two certificates");
+ let raw = RawCert::from_bytes(&bytes);
+ match &raw {
+ Ok(_) => eprintln!("raw: Ok"),
+ Err(err) => eprintln!("raw: {}", err),
+ }
+ let cert = Cert::from_bytes(&bytes);
+ match &cert {
+ Ok(_) => eprintln!("cert: Ok"),
+ Err(err) => eprintln!("cert: {}", err),
+ }
+
+ assert!(
+ matches!(cert.map_err(|e| e.downcast::<Error>()),
+ Err(Ok(Error::MalformedCert(_)))));
+ assert!(
+ matches!(raw.map_err(|e| e.downcast::<Error>()),
+ Err(Ok(Error::MalformedCert(_)))));
+ }
}