summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2023-04-05 17:54:06 +0200
committerJustus Winter <justus@sequoia-pgp.org>2023-11-07 12:18:24 +0100
commit0cebc44a178f9c43e5f68de5d8df6e7c553efe1d (patch)
tree62b0bcf02e187cfc1c056599adeaa8101b304c47
parent2ba611ac0ae408200ef92249be8f6e5a417038d8 (diff)
openpgp: Add support for v6 OPS packets, inline-signed messages.
todo: - finish facade, at least set_last
-rw-r--r--openpgp/src/packet/header/mod.rs4
-rw-r--r--openpgp/src/packet/mod.rs110
-rw-r--r--openpgp/src/packet/one_pass_sig.rs9
-rw-r--r--openpgp/src/packet/one_pass_sig/v6.rs222
-rw-r--r--openpgp/src/packet/prelude.rs1
-rw-r--r--openpgp/src/parse.rs161
-rw-r--r--openpgp/src/parse/hashed_reader.rs32
-rw-r--r--openpgp/src/serialize.rs57
8 files changed, 542 insertions, 54 deletions
diff --git a/openpgp/src/packet/header/mod.rs b/openpgp/src/packet/header/mod.rs
index d0df418b..61eab916 100644
--- a/openpgp/src/packet/header/mod.rs
+++ b/openpgp/src/packet/header/mod.rs
@@ -181,7 +181,9 @@ impl Header {
// 10 bytes of fixed header, plus the
// encrypted session key.
10 < l && l < 10 * 1024,
- Tag::OnePassSig if ! future_compatible => l == 13,
+ Tag::OnePassSig if ! future_compatible =>
+ l == 13 // v3
+ || (6 + 32..6 + 32 + 256).contains(&l), // v6
Tag::OnePassSig => l < 1024,
Tag::PublicKey | Tag::PublicSubkey
| Tag::SecretKey | Tag::SecretSubkey =>
diff --git a/openpgp/src/packet/mod.rs b/openpgp/src/packet/mod.rs
index 85ae61d6..dfd3427b 100644
--- a/openpgp/src/packet/mod.rs
+++ b/openpgp/src/packet/mod.rs
@@ -168,9 +168,17 @@ pub use container::Body;
pub mod prelude;
-use crate::crypto::{
- KeyPair,
- Password,
+use crate::{
+ crypto::{
+ KeyPair,
+ Password,
+ },
+ types::{
+ SignatureType,
+ PublicKeyAlgorithm,
+ HashAlgorithm,
+ },
+ KeyHandle,
};
mod any;
@@ -451,7 +459,8 @@ impl Deref for Packet {
match self {
Packet::Unknown(ref packet) => &packet.common,
Packet::Signature(ref packet) => &packet.common,
- Packet::OnePassSig(ref packet) => &packet.common,
+ Packet::OnePassSig(OnePassSig::V3(ref packet)) => &packet.common,
+ Packet::OnePassSig(OnePassSig::V6(ref packet)) => &packet.common.common,
Packet::PublicKey(ref packet) => &packet.common,
Packet::PublicSubkey(ref packet) => &packet.common,
Packet::SecretKey(ref packet) => &packet.common,
@@ -478,7 +487,8 @@ impl DerefMut for Packet {
match self {
Packet::Unknown(ref mut packet) => &mut packet.common,
Packet::Signature(ref mut packet) => &mut packet.common,
- Packet::OnePassSig(ref mut packet) => &mut packet.common,
+ Packet::OnePassSig(OnePassSig::V3(ref mut packet)) => &mut packet.common,
+ Packet::OnePassSig(OnePassSig::V6(ref mut packet)) => &mut packet.common.common,
Packet::PublicKey(ref mut packet) => &mut packet.common,
Packet::PublicSubkey(ref mut packet) => &mut packet.common,
Packet::SecretKey(ref mut packet) => &mut packet.common,
@@ -1079,6 +1089,8 @@ impl DerefMut for Signature {
pub enum OnePassSig {
/// OnePassSig packet version 3.
V3(self::one_pass_sig::OnePassSig3),
+ /// OnePassSig packet version 6.
+ V6(self::one_pass_sig::OnePassSig6),
}
assert_send_and_sync!(OnePassSig);
@@ -1087,32 +1099,90 @@ impl OnePassSig {
pub fn version(&self) -> u8 {
match self {
OnePassSig::V3(_) => 3,
+ OnePassSig::V6(_) => 6,
}
}
-}
-impl From<OnePassSig> for Packet {
- fn from(s: OnePassSig) -> Self {
- Packet::OnePassSig(s)
+ /// Gets the signature type.
+ pub fn typ(&self) -> SignatureType {
+ match self {
+ OnePassSig::V3(p) => p.typ(),
+ OnePassSig::V6(p) => p.typ(),
+ }
}
-}
-// Trivial forwarder for singleton enum.
-impl Deref for OnePassSig {
- type Target = one_pass_sig::OnePassSig3;
+ /// Gets the public key algorithm.
+ pub fn pk_algo(&self) -> PublicKeyAlgorithm {
+ match self {
+ OnePassSig::V3(p) => p.pk_algo(),
+ OnePassSig::V6(p) => p.pk_algo(),
+ }
+ }
- fn deref(&self) -> &Self::Target {
+ /// Gets the hash algorithm.
+ pub fn hash_algo(&self) -> HashAlgorithm {
match self {
- OnePassSig::V3(ops) => ops,
+ OnePassSig::V3(p) => p.hash_algo(),
+ OnePassSig::V6(p) => p.hash_algo(),
}
}
-}
-// Trivial forwarder for singleton enum.
-impl DerefMut for OnePassSig {
- fn deref_mut(&mut self) -> &mut Self::Target {
+ /// Gets the salt, if any.
+ pub fn salt(&self) -> Option<&[u8]> {
+ match self {
+ OnePassSig::V3(_) => None,
+ OnePassSig::V6(p) => Some(p.salt()),
+ }
+ }
+
+ /// Gets the issuer.
+ pub fn issuer(&self) -> KeyHandle {
+ match self {
+ OnePassSig::V3(p) => p.issuer().into(),
+ OnePassSig::V6(p) => p.issuer().into(),
+ }
+ }
+
+ /// Gets the last flag.
+ pub fn last(&self) -> bool {
+ match self {
+ OnePassSig::V3(p) => p.last(),
+ OnePassSig::V6(p) => p.last(),
+ }
+ }
+
+ /// Sets the last flag.
+ pub fn set_last(&mut self, last: bool) -> bool {
+ match self {
+ OnePassSig::V3(p) => p.set_last(last),
+ OnePassSig::V6(p) => p.set_last(last),
+ }
+ }
+
+ /// Gets the raw value of the last flag.
+ pub fn last_raw(&self) -> u8 {
match self {
- OnePassSig::V3(ref mut ops) => ops,
+ OnePassSig::V3(p) => p.last_raw(),
+ OnePassSig::V6(p) => p.last_raw(),
+ }
+ }
+}
+
+impl From<OnePassSig> for Packet {
+ fn from(s: OnePassSig) -> Self {
+ Packet::OnePassSig(s)
+ }
+}
+
+impl<'a> std::convert::TryFrom<&'a Signature> for OnePassSig {
+ type Error = anyhow::Error;
+
+ fn try_from(s: &'a Signature) -> Result<Self> {
+ match s.version() {
+ 4 => one_pass_sig::OnePassSig3::try_from(s).map(Into::into),
+ 6 => one_pass_sig::OnePassSig6::try_from(s).map(Into::into),
+ n => Err(Error::InvalidOperation(
+ format!("Unsupported signature version {}", n)).into()),
}
}
}
diff --git a/openpgp/src/packet/one_pass_sig.rs b/openpgp/src/packet/one_pass_sig.rs
index 14bad636..19242e40 100644
--- a/openpgp/src/packet/one_pass_sig.rs
+++ b/openpgp/src/packet/one_pass_sig.rs
@@ -19,6 +19,9 @@ use crate::HashAlgorithm;
use crate::PublicKeyAlgorithm;
use crate::SignatureType;
+mod v6;
+pub use v6::OnePassSig6;
+
/// Holds a one-pass signature packet.
///
/// See [Section 5.4 of RFC 4880] for details.
@@ -172,7 +175,11 @@ impl<'a> std::convert::TryFrom<&'a Signature> for OnePassSig3 {
#[cfg(test)]
impl Arbitrary for super::OnePassSig {
fn arbitrary(g: &mut Gen) -> Self {
- OnePassSig3::arbitrary(g).into()
+ if Arbitrary::arbitrary(g) {
+ OnePassSig3::arbitrary(g).into()
+ } else {
+ OnePassSig6::arbitrary(g).into()
+ }
}
}
diff --git a/openpgp/src/packet/one_pass_sig/v6.rs b/openpgp/src/packet/one_pass_sig/v6.rs
new file mode 100644
index 00000000..7fc83b2e
--- /dev/null
+++ b/openpgp/src/packet/one_pass_sig/v6.rs
@@ -0,0 +1,222 @@
+//! OpenPGP v6 signature implementation.
+
+use std::convert::TryFrom;
+use std::fmt;
+use std::mem;
+
+#[cfg(test)]
+use quickcheck::{Arbitrary, Gen};
+
+use crate::{
+ Error,
+ Fingerprint,
+ HashAlgorithm,
+ Packet,
+ PublicKeyAlgorithm,
+ Result,
+ SignatureType,
+ packet::{
+ Signature,
+ OnePassSig,
+ one_pass_sig::{
+ OnePassSig3,
+ },
+ },
+};
+
+/// Holds a v6 OnePassSig packet.
+///
+/// This holds a [version 6] OnePassSig packet. Normally, you won't
+/// directly work with this data structure, but with the [`OnePassSig`]
+/// enum, which is version agnostic. An exception is when you need to
+/// do version-specific operations. But currently, there aren't any
+/// version-specific methods.
+///
+/// [version 6]: https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-08.html#name-one-pass-signature-packets-
+/// [`OnePassSig`]: crate::packet::OnePassSig
+#[derive(PartialEq, Eq, Hash, Clone)]
+pub struct OnePassSig6 {
+ pub(crate) common: OnePassSig3,
+ salt: Vec<u8>,
+ issuer: Fingerprint,
+}
+assert_send_and_sync!(OnePassSig6);
+
+impl TryFrom<OnePassSig> for OnePassSig6 {
+ type Error = anyhow::Error;
+
+ fn try_from(ops: OnePassSig) -> Result<Self> {
+ match ops {
+ OnePassSig::V6(ops) => Ok(ops),
+ ops => Err(
+ Error::InvalidArgument(
+ format!(
+ "Got a v{}, require a v6 one-pass signature",
+ ops.version()))
+ .into()),
+ }
+ }
+}
+
+impl fmt::Debug for OnePassSig6 {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.debug_struct("OnePassSig6")
+ .field("typ", &self.typ())
+ .field("hash_algo", &self.hash_algo())
+ .field("pk_algo", &self.pk_algo())
+ .field("salt", &crate::fmt::hex::encode(self.salt()))
+ .field("issuer", &self.issuer())
+ .field("last", &self.last())
+ .finish()
+ }
+}
+
+impl OnePassSig6 {
+ /// Returns a new One-Pass Signature packet.
+ pub fn new(typ: SignatureType, issuer: Fingerprint) -> Self {
+ OnePassSig6 {
+ common: OnePassSig3::new(typ),
+ salt: vec![],
+ issuer,
+ }
+ }
+
+ /// Gets the signature type.
+ pub fn typ(&self) -> SignatureType {
+ self.common.typ()
+ }
+
+ /// Sets the signature type.
+ pub fn set_type(&mut self, t: SignatureType) -> SignatureType {
+ self.common.set_type(t)
+ }
+
+ /// Gets the public key algorithm.
+ pub fn pk_algo(&self) -> PublicKeyAlgorithm {
+ self.common.pk_algo()
+ }
+
+ /// Sets the public key algorithm.
+ pub fn set_pk_algo(&mut self, algo: PublicKeyAlgorithm) -> PublicKeyAlgorithm {
+ self.common.set_pk_algo(algo)
+ }
+
+ /// Gets the hash algorithm.
+ pub fn hash_algo(&self) -> HashAlgorithm {
+ self.common.hash_algo()
+ }
+
+ /// Sets the hash algorithm.
+ pub fn set_hash_algo(&mut self, algo: HashAlgorithm) -> HashAlgorithm {
+ self.common.set_hash_algo(algo)
+ }
+
+ /// Gets the salt.
+ pub fn salt(&self) -> &[u8] {
+ &self.salt
+ }
+
+ /// Sets the salt.
+ pub fn set_salt(&mut self, salt: Vec<u8>) -> Vec<u8> {
+ mem::replace(&mut self.salt, salt)
+ }
+
+ /// Gets the issuer.
+ pub fn issuer(&self) -> &Fingerprint {
+ &self.issuer
+ }
+
+ /// Sets the issuer.
+ pub fn set_issuer(&mut self, issuer: Fingerprint) -> Fingerprint {
+ mem::replace(&mut self.issuer, issuer)
+ }
+
+ /// Gets the last flag.
+ pub fn last(&self) -> bool {
+ self.common.last()
+ }
+
+ /// Sets the last flag.
+ pub fn set_last(&mut self, last: bool) -> bool {
+ self.common.set_last(last)
+ }
+
+ /// Gets the raw value of the last flag.
+ pub fn last_raw(&self) -> u8 {
+ self.common.last_raw()
+ }
+
+ /// Sets the raw value of the last flag.
+ pub fn set_last_raw(&mut self, last: u8) -> u8 {
+ self.common.set_last_raw(last)
+ }
+}
+
+impl From<OnePassSig6> for OnePassSig {
+ fn from(s: OnePassSig6) -> Self {
+ OnePassSig::V6(s)
+ }
+}
+
+impl From<OnePassSig6> for Packet {
+ fn from(p: OnePassSig6) -> Self {
+ OnePassSig::from(p).into()
+ }
+}
+
+impl<'a> std::convert::TryFrom<&'a Signature> for OnePassSig6 {
+ type Error = anyhow::Error;
+
+ fn try_from(s: &'a Signature) -> Result<Self> {
+ let s = if let Signature::V6(s) = s {
+ s
+ } else {
+ return Err(Error::InvalidArgument(format!(
+ "Can not derive a v6 OnePassSig from a v{} Signature",
+ s.version())).into());
+ };
+
+ let issuer = match s.issuer_fingerprints().next() {
+ Some(i) => i.clone(),
+ None =>
+ return Err(Error::InvalidArgument(
+ "Signature has no issuer fingerprints".into()).into()),
+ };
+ let mut common = OnePassSig3::new(s.typ());
+ common.set_hash_algo(s.hash_algo());
+ common.set_pk_algo(s.pk_algo());
+ Ok(OnePassSig6 {
+ common,
+ salt: s.salt().to_vec(),
+ issuer,
+ })
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::arbitrary_helper::arbitrary_bounded_vec;
+ use crate::parse::Parse;
+ use crate::serialize::MarshalInto;
+
+ impl Arbitrary for OnePassSig6 {
+ fn arbitrary(g: &mut Gen) -> Self {
+ let mut ops = OnePassSig6::new(SignatureType::arbitrary(g),
+ Fingerprint::arbitrary_v6(g));
+ ops.set_hash_algo(HashAlgorithm::arbitrary(g));
+ ops.set_pk_algo(PublicKeyAlgorithm::arbitrary(g));
+ ops.set_last_raw(u8::arbitrary(g));
+ ops.set_salt(arbitrary_bounded_vec(g, 256));
+ ops
+ }
+ }
+
+ quickcheck! {
+ fn roundtrip(p: OnePassSig6) -> bool {
+ let q = OnePassSig6::from_bytes(&p.to_vec().unwrap()).unwrap();
+ assert_eq!(p, q);
+ true
+ }
+ }
+}
diff --git a/openpgp/src/packet/prelude.rs b/openpgp/src/packet/prelude.rs
index 5c3d7782..c433dda9 100644
--- a/openpgp/src/packet/prelude.rs
+++ b/openpgp/src/packet/prelude.rs
@@ -48,6 +48,7 @@ pub use crate::packet::{
key::Key6,
key::SecretKeyMaterial,
one_pass_sig::OnePassSig3,
+ one_pass_sig::OnePassSig6,
pkesk::PKESK3,
seip::SEIP1,
signature,
diff --git a/openpgp/src/parse.rs b/openpgp/src/parse.rs
index 81dfdf26..f06335d8 100644
--- a/openpgp/src/parse.rs
+++ b/openpgp/src/parse.rs
@@ -829,12 +829,26 @@ pub(crate) struct SignatureGroup {
ops_count: usize,
/// The hash contexts.
- pub(crate) hashes: Vec<HashingMode<Box<dyn crypto::hash::Digest>>>,
+ ///
+ /// We store a salt and the hash context as tuples.
+ ///
+ /// In v6, the hash is salted. We store the salt here so that we
+ /// can find the right hash context again when we encounter the
+ /// signature packet.
+ ///
+ /// In v4, the hash is not salted. Hence, salt is the zero-length
+ /// vector. The fact that the hash is not salted allows for an
+ /// optimization: to verify two signatures using the same hash
+ /// algorithm, the hash must be computed just once. We implement
+ /// this optimization for v4 signatures.
+ pub(crate) hashes: Vec<(Vec<u8>,
+ HashingMode<Box<dyn crypto::hash::Digest>>)>,
}
impl fmt::Debug for SignatureGroup {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- let algos = self.hashes.iter().map(|mode| mode.map(|ctx| ctx.algo()))
+ let algos = self.hashes.iter()
+ .map(|(salt, mode)| (salt, mode.map(|ctx| ctx.algo())))
.collect::<Vec<_>>();
f.debug_struct("Cookie")
@@ -1406,6 +1420,12 @@ impl Signature {
}
let need_hash = HashingMode::for_signature(hash_algo, typ);
+ let need_salt =
+ if let Packet::Signature(Signature::V6(sig)) = &pp.packet {
+ sig.salt()
+ } else {
+ &[]
+ };
// Locate the corresponding HashedReader and extract the
// computed hash.
@@ -1447,8 +1467,10 @@ impl Signature {
{
if let Some(hash) =
cookie.sig_group().hashes.iter().find_map(
- |mode|
- if mode.map(|ctx| ctx.algo()) == need_hash {
+ |(salt, mode)|
+ if salt == need_salt
+ && mode.map(|ctx| ctx.algo()) == need_hash
+ {
Some(mode.as_ref())
} else {
None
@@ -2042,6 +2064,7 @@ impl OnePassSig {
let version = php_try!(php.parse_u8("version"));
match version {
3 => OnePassSig3::parse(php),
+ 6 => OnePassSig6::parse(php),
_ => {
t!("Ignoring version {} packet", version);
@@ -2114,13 +2137,16 @@ impl OnePassSig3 {
// hash algorithm.
if php.state.settings.automatic_hashing
&& ! cookie.sig_group().hashes.iter()
- .any(|mode| {
+ .any(|(salt, mode)| {
mode.map(|ctx| ctx.algo()) == need_hash
+ && salt.is_empty()
})
{
if let Ok(ctx) = hash_algo.context() {
cookie.sig_group_mut().hashes.push(
- HashingMode::for_signature(Box::new(ctx), typ)
+ (vec![],
+ HashingMode::for_signature(
+ Box::new(ctx), typ))
);
}
}
@@ -2177,7 +2203,7 @@ impl OnePassSig3 {
assert!(! fake_eof);
let mut reader = HashedReader::new(
- reader, want_hashes_for, algos)?;
+ reader, want_hashes_for, vec![], algos)?;
reader.cookie_mut().level = Some(recursion_depth - 1);
// Account for this OPS packet.
reader.cookie_mut().sig_group_mut().ops_count += 1;
@@ -2253,6 +2279,7 @@ impl PacketParser<'_> {
let hash_algo = ops.hash_algo();
let typ = ops.typ();
+ let salt = ops.salt();
let need_hash = HashingMode::for_signature(hash_algo, typ);
let recursion_depth = self.recursion_depth();
let want_hashes_for = if Cookie::processing_csf_message(&self.reader) {
@@ -2279,12 +2306,13 @@ impl PacketParser<'_> {
// hash algorithm.
if ! cookie.sig_group().hashes.iter()
.any(|mode| {
- mode.map(|ctx| ctx.algo()) == need_hash
+ mode.1.map(|ctx| ctx.algo()) == need_hash
})
{
- cookie.sig_group_mut().hashes.push(
+ cookie.sig_group_mut().hashes.push((
+ salt.map(|s| s.into()).unwrap_or_default(),
HashingMode::for_signature(
- Box::new(hash_algo.context()?), typ));
+ Box::new(hash_algo.context()?), typ)));
}
break;
}
@@ -2300,7 +2328,7 @@ impl PacketParser<'_> {
}
#[test]
-fn one_pass_sig_parser_test () {
+fn one_pass_sig3_parser_test () {
use crate::SignatureType;
use crate::PublicKeyAlgorithm;
@@ -2324,12 +2352,108 @@ fn one_pass_sig_parser_test () {
impl<'a> Parse<'a, OnePassSig3> for OnePassSig3 {
fn from_reader<R: 'a + Read + Send + Sync>(reader: R) -> Result<Self> {
- OnePassSig::from_reader(reader).map(|p| match p {
- OnePassSig::V3(p) => p,
- // XXX: Once we have a second variant.
- //
- // p => Err(Error::InvalidOperation(
- // format!("Not a OnePassSig::V3 packet: {:?}", p)).into()),
+ OnePassSig::from_reader(reader).and_then(|p| match p {
+ OnePassSig::V3(p) => Ok(p),
+ p => Err(Error::InvalidOperation(
+ format!("Not a OnePassSig::V3 packet: {:?}", p)).into()),
+ })
+ }
+}
+
+impl OnePassSig6 {
+ #[allow(clippy::blocks_in_if_conditions)]
+ fn parse(mut php: PacketHeaderParser) -> Result<PacketParser> {
+ let indent = php.recursion_depth();
+ tracer!(TRACE, "OnePassSig6", indent);
+
+ make_php_try!(php);
+
+ let typ = php_try!(php.parse_u8("type"));
+ let hash_algo = php_try!(php.parse_u8("hash_algo"));
+ let pk_algo = php_try!(php.parse_u8("pk_algo"));
+ let salt_len = php_try!(php.parse_u8("salt_len"));
+ let salt = php_try!(php.parse_bytes("salt", salt_len.into()));
+ let mut issuer = [0u8; 32];
+ issuer.copy_from_slice(&php_try!(php.parse_bytes("issuer", 32)));
+ let last = php_try!(php.parse_u8("last"));
+
+ let hash_algo = hash_algo.into();
+ let typ = typ.into();
+ let mut sig = OnePassSig6::new(typ, Fingerprint::from_bytes(&issuer));
+ sig.set_salt(salt.clone());
+ sig.set_hash_algo(hash_algo);
+ sig.set_pk_algo(pk_algo.into());
+ sig.set_last_raw(last);
+
+ let recursion_depth = php.recursion_depth();
+
+ // Check if we are processing a cleartext signed message.
+ let want_hashes_for = if Cookie::processing_csf_message(&php.reader) {
+ HashesFor::CleartextSignature
+ } else {
+ HashesFor::Signature
+ };
+
+ // We create an empty hashed reader even if we don't support
+ // the hash algorithm so that we have something to match
+ // against when we get to the Signature packet.
+ let mut algos = Vec::new();
+ if hash_algo.is_supported() {
+ algos.push(HashingMode::for_signature(hash_algo, typ));
+ }
+
+ // Commit here after potentially pushing a signature group.
+ let mut pp = php.ok(Packet::OnePassSig(sig.into()))?;
+
+ // We can't push the HashedReader on the BufferedReader stack:
+ // when we finish processing this OnePassSig packet, it will
+ // be popped. Instead, we need to insert it at the next
+ // higher level. Unfortunately, this isn't possible. But,
+ // since we're done reading the current packet, we can pop the
+ // readers associated with it, and then push the HashedReader.
+ // This is a bit of a layering violation, but I (Neal) can't
+ // think of a more elegant solution.
+
+ assert!(pp.reader.cookie_ref().level <= Some(recursion_depth));
+ let (fake_eof, reader)
+ = buffered_reader_stack_pop(Box::new(pp.take_reader()),
+ recursion_depth)?;
+ // We only pop the buffered readers for the OPS, and we
+ // (currently) never use a fake eof for OPS packets.
+ assert!(! fake_eof);
+
+ let mut reader = HashedReader::new(
+ reader, want_hashes_for, salt, algos)?;
+ reader.cookie_mut().level = Some(recursion_depth - 1);
+ // Account for this OPS packet.
+ reader.cookie_mut().sig_group_mut().ops_count += 1;
+ // Keep track of the last flag.
+ reader.cookie_mut().saw_last = last > 0;
+
+ t!("Pushed a hashed reader, level {:?}", reader.cookie_mut().level);
+
+ // We add an empty limitor on top of the hashed reader,
+ // because when we are done processing a packet,
+ // PacketParser::finish discards any unread data from the top
+ // reader. Since the top reader is the HashedReader, this
+ // discards any following packets. To prevent this, we push a
+ // Limitor on the reader stack.
+ let mut reader = buffered_reader::Limitor::with_cookie(
+ reader, 0, Cookie::default());
+ reader.cookie_mut().level = Some(recursion_depth);
+
+ pp.reader = Box::new(reader);
+
+ Ok(pp)
+ }
+}
+
+impl<'a> Parse<'a, OnePassSig6> for OnePassSig6 {
+ fn from_reader<R: 'a + Read + Send + Sync>(reader: R) -> Result<Self> {
+ OnePassSig::from_reader(reader).and_then(|p| match p {
+ OnePassSig::V6(p) => Ok(p),
+ p => Err(Error::InvalidOperation(
+ format!("Not a OnePassSig::V6 packet: {:?}", p)).into()),
})
}
}
@@ -3276,7 +3400,7 @@ impl MDC {
if !state.sig_group().hashes.is_empty() {
let h = state.sig_group_mut().hashes
.iter_mut().find_map(
- |mode|
+ |(_salt, mode)|
if mode.map(|ctx| ctx.algo()) ==
HashingMode::Binary(HashAlgorithm::SHA1)
{
@@ -5829,6 +5953,7 @@ impl<'a> PacketParser<'a> {
// And the hasher.
let mut reader = HashedReader::new(
reader, HashesFor::MDC,
+ vec![],
vec![HashingMode::Binary(HashAlgorithm::SHA1)])?;
reader.cookie_mut().level = Some(self.recursion_depth());
diff --git a/openpgp/src/parse/hashed_reader.rs b/openpgp/src/parse/hashed_reader.rs
index 7668fecd..51549060 100644
--- a/openpgp/src/parse/hashed_reader.rs
+++ b/openpgp/src/parse/hashed_reader.rs
@@ -217,17 +217,19 @@ impl<R: BufferedReader<Cookie>> HashedReader<R> {
/// purpose. `algos` is a list of algorithms for which we should
/// compute the hash.
pub fn new(reader: R, hashes_for: HashesFor,
+ salt: Vec<u8>,
algos: Vec<HashingMode<HashAlgorithm>>)
-> Result<Self> {
let mut cookie = Cookie::default();
for mode in algos {
let mode = mode.mapf(|algo| {
- let ctx = algo.context()?;
+ let mut ctx = algo.context()?;
+ ctx.update(&salt);
Ok(ctx)
})?;