summaryrefslogtreecommitdiffstats
path: root/openpgp
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2019-05-09 15:19:24 +0200
committerJustus Winter <justus@sequoia-pgp.org>2019-05-09 15:19:24 +0200
commit75d4e6dda12e8b7ae8573227e61e718ede3f2cfc (patch)
treec6b9e3f177d8c65d134acfd889c236203b2ac13f /openpgp
parent8e0f817f312f469871a5fbed6bb961f6117ba742 (diff)
openpgp: Communicate message structure from the decryptor.
- Fixes #100.
Diffstat (limited to 'openpgp')
-rw-r--r--openpgp/examples/decrypt-with.rs44
-rw-r--r--openpgp/examples/generate-encrypt-decrypt.rs2
-rw-r--r--openpgp/examples/generate-sign-verify.rs51
-rw-r--r--openpgp/src/parse/stream.rs574
-rw-r--r--openpgp/src/serialize/stream.rs30
5 files changed, 492 insertions, 209 deletions
diff --git a/openpgp/examples/decrypt-with.rs b/openpgp/examples/decrypt-with.rs
index 908b8650..63582299 100644
--- a/openpgp/examples/decrypt-with.rs
+++ b/openpgp/examples/decrypt-with.rs
@@ -17,6 +17,8 @@ use openpgp::parse::{
Decryptor,
VerificationHelper,
VerificationResult,
+ MessageStructure,
+ MessageLayer,
},
};
@@ -95,7 +97,7 @@ impl DecryptionHelper for Helper {
}
// XXX: In production code, return the Fingerprint of the
// recipient's TPK here
- Ok(None)
+ Ok(None)
}
}
@@ -104,8 +106,46 @@ impl VerificationHelper for Helper {
-> failure::Fallible<Vec<openpgp::TPK>> {
Ok(Vec::new()) // Feed the TPKs to the verifier here.
}
- fn check(&mut self, _sigs: Vec<Vec<VerificationResult>>)
+ fn check(&mut self, structure: &MessageStructure)
-> failure::Fallible<()> {
+ use self::VerificationResult::*;
+ for layer in structure.iter() {
+ match layer {
+ MessageLayer::Compression { algo } =>
+ eprintln!("Compressed using {}", algo),
+ MessageLayer::Encryption { sym_algo, aead_algo } =>
+ if let Some(aead_algo) = aead_algo {
+ eprintln!("Encrypted and protected using {}/{}",
+ sym_algo, aead_algo);
+ } else {
+ eprintln!("Encrypted using {}", sym_algo);
+ },
+ MessageLayer::SignatureGroup { ref results } =>
+ for result in results {
+ match result {
+ GoodChecksum(ref sig, ..) => {
+ let issuer = sig.issuer()
+ .expect("good checksum has an issuer");
+ eprintln!("Good signature from {}", issuer);
+ },
+ MissingKey(ref sig) => {
+ let issuer = sig.issuer()
+ .expect("missing key checksum has an \
+ issuer");
+ eprintln!("No key to check signature from {}",
+ issuer);
+ },
+ BadChecksum(ref sig) =>
+ if let Some(issuer) = sig.issuer() {
+ eprintln!("Bad signature from {}", issuer);
+ } else {
+ eprintln!("Bad signature without issuer \
+ information");
+ },
+ }
+ }
+ }
+ }
Ok(()) // Implement your verification policy here.
}
}
diff --git a/openpgp/examples/generate-encrypt-decrypt.rs b/openpgp/examples/generate-encrypt-decrypt.rs
index c338f154..4645cb0c 100644
--- a/openpgp/examples/generate-encrypt-decrypt.rs
+++ b/openpgp/examples/generate-encrypt-decrypt.rs
@@ -93,7 +93,7 @@ impl<'a> VerificationHelper for Helper<'a> {
Ok(Vec::new())
}
- fn check(&mut self, _sigs: Vec<Vec<VerificationResult>>)
+ fn check(&mut self, _structure: &MessageStructure)
-> openpgp::Result<()> {
// Implement your signature verification policy here.
Ok(())
diff --git a/openpgp/examples/generate-sign-verify.rs b/openpgp/examples/generate-sign-verify.rs
index 0ebb3d1e..70899c81 100644
--- a/openpgp/examples/generate-sign-verify.rs
+++ b/openpgp/examples/generate-sign-verify.rs
@@ -92,30 +92,41 @@ impl<'a> VerificationHelper for Helper<'a> {
Ok(vec![self.tpk.clone()])
}
- fn check(&mut self, sigs: Vec<Vec<VerificationResult>>)
+ fn check(&mut self, structure: &MessageStructure)
-> openpgp::Result<()> {
// In this function, we implement our signature verification
// policy.
- // First, we are interested in signatures over the data,
- // i.e. level 0 signatures.
- let sigs_over_data = sigs.get(0)
- .ok_or_else(|| failure::err_msg("No level 0 signatures found"))?;
-
- // Now, let's see if there is a signature on that level.
- let sig_result = sigs_over_data.get(0)
- .ok_or_else(|| failure::err_msg("No signature found"))?;
-
- // Finally, given a VerificationResult, which only says
- // whether the signature checks out mathematically, we apply
- // our policy.
- match sig_result {
- VerificationResult::GoodChecksum(..) =>
- Ok(()), // Good signature
- VerificationResult::MissingKey(_) =>
- Err(failure::err_msg("Missing key to verify signature")),
- VerificationResult::BadChecksum(_) =>
- Err(failure::err_msg("Bad signature")),
+ let mut good = false;
+ for (i, layer) in structure.iter().enumerate() {
+ match (i, layer) {
+ // First, we are interested in signatures over the
+ // data, i.e. level 0 signatures.
+ (0, MessageLayer::SignatureGroup { ref results }) => {
+ // Finally, given a VerificationResult, which only says
+ // whether the signature checks out mathematically, we apply
+ // our policy.
+ match results.get(0) {
+ Some(VerificationResult::GoodChecksum(..)) =>
+ good = true,
+ Some(VerificationResult::MissingKey(_)) =>
+ return Err(failure::err_msg(
+ "Missing key to verify signature")),
+ Some(VerificationResult::BadChecksum(_)) =>
+ return Err(failure::err_msg("Bad signature")),
+ None =>
+ return Err(failure::err_msg("No signature")),
+ }
+ },
+ _ => return Err(failure::err_msg(
+ "Unexpected message structure")),
+ }
+ }
+
+ if good {
+ Ok(()) // Good signature.
+ } else {
+ Err(failure::err_msg("Signature verification failed"))
}
}
}
diff --git a/openpgp/src/parse/stream.rs b/openpgp/src/parse/stream.rs
index f6b20a0f..d9791479 100644
--- a/openpgp/src/parse/stream.rs
+++ b/openpgp/src/parse/stream.rs
@@ -19,6 +19,8 @@ use {
Error,
Fingerprint,
constants::{
+ AEADAlgorithm,
+ CompressionAlgorithm,
DataFormat,
SymmetricAlgorithm,
},
@@ -27,6 +29,7 @@ use {
ctb::CTB,
Key,
Literal,
+ OnePassSig,
one_pass_sig::OnePassSig3,
PKESK,
SKESK,
@@ -83,7 +86,7 @@ const BUFFER_SIZE: usize = 25 * 1024 * 1024;
/// fn get_public_keys(&mut self, _ids: &[KeyID]) -> Result<Vec<TPK>> {
/// Ok(Vec::new()) // Feed the TPKs to the verifier here...
/// }
-/// fn check(&mut self, sigs: Vec<Vec<VerificationResult>>) -> Result<()> {
+/// fn check(&mut self, structure: &MessageStructure) -> Result<()> {
/// Ok(()) // Implement your verification policy here.
/// }
/// }
@@ -120,7 +123,7 @@ pub struct Verifier<'a, H: VerificationHelper> {
/// Maps KeyID to tpks[i].keys_all().nth(j).
keys: HashMap<KeyID, (usize, usize)>,
oppr: Option<PacketParserResult<'a>>,
- sigs: Vec<Vec<Signature>>,
+ structure: IMessageStructure,
// The reserve data.
reserve: Option<Vec<u8>>,
@@ -162,29 +165,229 @@ impl<'a> VerificationResult<'a> {
}
}
+/// Communicates the message structure to the VerificationHelper.
+#[derive(Debug)]
+pub struct MessageStructure<'a>(Vec<MessageLayer<'a>>);
+
+impl<'a> MessageStructure<'a> {
+ fn new() -> Self {
+ MessageStructure(Vec::new())
+ }
+
+ fn new_compression_layer(&mut self, algo: CompressionAlgorithm) {
+ self.0.push(MessageLayer::Compression {
+ algo: algo,
+ })
+ }
+
+ fn new_encryption_layer(&mut self, sym_algo: SymmetricAlgorithm,
+ aead_algo: Option<AEADAlgorithm>) {
+ self.0.push(MessageLayer::Encryption {
+ sym_algo: sym_algo,
+ aead_algo: aead_algo,
+ })
+ }
+
+ fn new_signature_group(&mut self) {
+ self.0.push(MessageLayer::SignatureGroup {
+ results: Vec::new(),
+ })
+ }
+
+ fn push_verification_result(&mut self, sig: VerificationResult<'a>) {
+ if let Some(MessageLayer::SignatureGroup { ref mut results }) =
+ self.0.iter_mut().last()
+ {
+ results.push(sig);
+ } else {
+ panic!("cannot push to encryption or compression layer");
+ }
+ }
+
+ /// Iterates over the message structure.
+ pub fn iter(&self) -> MessageStructureIter {
+ MessageStructureIter(self.0.iter())
+ }
+}
+
+/// Iterates over the message structure.
+pub struct MessageStructureIter<'a>(::std::slice::Iter<'a, MessageLayer<'a>>);
+
+impl<'a> Iterator for MessageStructureIter<'a> {
+ type Item = &'a MessageLayer<'a>;
+ fn next(&mut self) -> Option<Self::Item> {
+ self.0.next()
+ }
+}
+
+/// Represents a layer of the message structure.
+#[derive(Debug)]
+pub enum MessageLayer<'a> {
+ /// Represents an compression container.
+ Compression {
+ /// Compression algorithm used.
+ algo: CompressionAlgorithm,
+ },
+ /// Represents an encryption container.
+ Encryption {
+ /// Symmetric algorithm used.
+ sym_algo: SymmetricAlgorithm,
+ /// AEAD algorithm used, if any.
+ aead_algo: Option<AEADAlgorithm>,
+ },
+ /// Represents a signature group.
+ SignatureGroup {
+ /// The results of the signature verifications.
+ results: Vec<VerificationResult<'a>>,
+ }
+}
+
+/// Internal version of the message structure.
+///
+/// In contrast to MessageStructure, this owns unverified
+/// signature packets.
+#[derive(Debug)]
+struct IMessageStructure {
+ layers: Vec<IMessageLayer>,
+
+ // We insert a SignatureGroup layer every time we see a OnePassSig
+ // packet with the last flag.
+ //
+ // However, we need to make sure that we insert a SignatureGroup
+ // layer even if the OnePassSig packet has the last flag set to
+ // false. To do that, we keep track of the fact that we saw such
+ // a OPS packet.
+ sig_group_counter: usize,
+}
+
+impl IMessageStructure {
+ fn new() -> Self {
+ IMessageStructure {
+ layers: Vec::new(),
+ sig_group_counter: 0,
+ }
+ }
+
+ fn new_compression_layer(&mut self, algo: CompressionAlgorithm) {
+ self.insert_missing_signature_group();
+ self.layers.push(IMessageLayer::Compression {
+ algo: algo,
+ });
+ }
+
+ fn new_encryption_layer(&mut self, sym_algo: SymmetricAlgorithm,
+ aead_algo: Option<AEADAlgorithm>) {
+ self.insert_missing_signature_group();
+ self.layers.push(IMessageLayer::Encryption {
+ sym_algo: sym_algo,
+ aead_algo: aead_algo,
+ });
+ }
+
+ /// Makes sure that we insert a signature group even if the
+ /// previous OPS packet had the last flag set to false.
+ fn insert_missing_signature_group(&mut self) {
+ if self.sig_group_counter > 0 {
+ self.layers.push(IMessageLayer::SignatureGroup {
+ sigs: Vec::new(),
+ count: self.sig_group_counter,
+ });
+ }
+ self.sig_group_counter = 0;
+ }
+
+ fn push_ops(&mut self, ops: &OnePassSig) {
+ self.sig_group_counter += 1;
+ if ops.last() {
+ self.layers.push(IMessageLayer::SignatureGroup {
+ sigs: Vec::new(),
+ count: self.sig_group_counter,
+ });
+ self.sig_group_counter = 0;
+ }
+ }
+
+ fn push_signature(&mut self, sig: Signature) {
+ for layer in self.layers.iter_mut().rev() {
+ match layer {
+ IMessageLayer::SignatureGroup {
+ ref mut sigs, ref mut count,
+ } if *count > 0 => {
+ sigs.push(sig);
+ *count -= 1;
+ return;
+ },
+ _ => (),
+ }
+ }
+ panic!("signature unaccounted for");
+ }
+
+ fn push_bare_signature(&mut self, sig: Signature) {
+ if let Some(IMessageLayer::SignatureGroup { .. }) = self.layers.iter().last() {
+ // The last layer is a SignatureGroup. We will append the
+ // signature there without accounting for it.
+ } else {
+ // The last layer is not a SignatureGroup, or there is no
+ // layer at all. Create one.
+ self.layers.push(IMessageLayer::SignatureGroup {
+ sigs: Vec::new(),
+ count: 0,
+ });
+ }
+
+ if let IMessageLayer::SignatureGroup { ref mut sigs, .. } =
+ self.layers.iter_mut().last().expect("just checked or created")
+ {
+ sigs.push(sig);
+ } else {
+ unreachable!()
+ }
+ }
+
+}
+
+/// Internal version of a layer of the message structure.
+///
+/// In contrast to MessageLayer, this owns unverified signature packets.
+#[derive(Debug)]
+enum IMessageLayer {
+ Compression {
+ algo: CompressionAlgorithm,
+ },
+ Encryption {
+ sym_algo: SymmetricAlgorithm,
+ aead_algo: Option<AEADAlgorithm>,
+ },
+ SignatureGroup {
+ sigs: Vec<Signature>,
+ count: usize,
+ }
+}
+
/// Helper for signature verification.
pub trait VerificationHelper {
/// Retrieves the TPKs containing the specified keys.
fn get_public_keys(&mut self, &[KeyID]) -> Result<Vec<TPK>>;
- /// Conveys the result of a signature verification.
+ /// Conveys the message structure.
+ ///
+ /// The message structure contains the results of signature
+ /// verifications. See [`MessageStructure`] for more information.
+ ///
+ /// [`MessageStructure`]: struct.MessageStructure.html
///
/// This is called after the last signature has been verified.
/// This is the place to implement your verification policy.
/// Check that the required number of signatures or notarizations
/// were confirmed as valid.
///
- /// The argument is a vector, with `sigs[sigs.len()-1]` being the
- /// vector of signatures over the data, `sigs[sigs.len()-2]` being
- /// notarizations over signatures of level 0, and the data, and so
- /// on.
- ///
/// This callback is only called before all data is returned.
/// That is, once `io::Read` returns EOF, this callback will not
/// be called again. As such, any error returned by this function
/// will abort reading, and the error will be propagated via the
/// `io::Read` operation.
- fn check(&mut self, sigs: Vec<Vec<VerificationResult>>) -> Result<()>;
+ fn check(&mut self, structure: &MessageStructure) -> Result<()>;
}
impl<'a, H: VerificationHelper> Verifier<'a, H> {
@@ -271,18 +474,12 @@ impl<'a, H: VerificationHelper> Verifier<'a, H> {
tpks: Vec::new(),
keys: HashMap::new(),
oppr: None,
- sigs: Vec::new(),
+ structure: IMessageStructure::new(),
reserve: None,
time: t,
};
let mut issuers = Vec::new();
- // The following structure is allowed:
- //
- // SIG LITERAL
- //
- // In this case, we queue the signature packets.
- let mut sigs = Vec::new();
while let PacketParserResult::Some(pp) = ppr {
if ! pp.possible_message() {
@@ -291,9 +488,14 @@ impl<'a, H: VerificationHelper> Verifier<'a, H> {
}
match pp.packet {
- Packet::OnePassSig(ref ops) =>
- issuers.push(ops.issuer().clone()),
+ Packet::CompressedData(ref p) =>
+ v.structure.new_compression_layer(p.algorithm()),
+ Packet::OnePassSig(ref ops) => {
+ v.structure.push_ops(ops);
+ issuers.push(ops.issuer().clone());
+ },
Packet::Literal(_) => {
+ v.structure.insert_missing_signature_group();
// Query keys.
v.tpks = v.helper.get_public_keys(&issuers)?;
@@ -325,12 +527,6 @@ impl<'a, H: VerificationHelper> Verifier<'a, H> {
v.oppr = Some(PacketParserResult::Some(pp));
v.finish_maybe()?;
-
- // Stash signatures.
- for sig in sigs.into_iter() {
- v.push_sig(Packet::Signature(sig))?;
- }
-
return Ok(v);
},
_ => (),
@@ -338,12 +534,19 @@ impl<'a, H: VerificationHelper> Verifier<'a, H> {
let (p, ppr_tmp) = pp.recurse()?;
if let Packet::Signature(sig) = p {
+ // The following structure is allowed:
+ //
+ // SIG LITERAL
+ //
+ // In this case, we get the issuer from the
+ // signature itself.
if let Some(issuer) = sig.get_issuer() {
issuers.push(issuer);
} else {
issuers.push(KeyID::wildcard());
}
- sigs.push(sig);
+
+ v.structure.push_bare_signature(sig);
}
ppr = ppr_tmp;
@@ -361,21 +564,7 @@ impl<'a, H: VerificationHelper> Verifier<'a, H> {
fn push_sig(&mut self, p: Packet) -> Result<()> {
match p {
Packet::Signature(sig) => {
- if self.sigs.is_empty() {
- self.sigs.push(Vec::new());
- }
-
- if let Some(current_level) = self.sigs.iter().last()
- .expect("sigs is never empty")
- .get(0).map(|r| r.level())
- {
- if current_level != sig.level() {
- self.sigs.push(Vec::new());
- }
- }
-
- self.sigs.iter_mut().last()
- .expect("sigs is never empty").push(sig);
+ self.structure.push_signature(sig);
},
_ => (),
}
@@ -408,38 +597,52 @@ impl<'a, H: VerificationHelper> Verifier<'a, H> {
}
// Verify the signatures.
- let mut results = Vec::new();
- for sigs in ::std::mem::replace(&mut self.sigs, Vec::new())
- .into_iter().rev()
+ let mut results = MessageStructure::new();
+ for layer in ::std::mem::replace(&mut self.structure,
+ IMessageStructure::new())
+ .layers.into_iter()
{
- results.push(Vec::new());
- for sig in sigs.into_iter() {
- results.iter_mut().last().expect("never empty").push(
- if let Some(issuer) = sig.get_issuer() {
- if let Some((i, j)) = self.keys.get(&issuer) {
- let tpk = &self.tpks[*i];
- let (binding, revocation, key)
- = tpk.keys_all().nth(*j).unwrap();
- if sig.verify(key).unwrap_or(false) &&
- sig.signature_alive_at(self.time)
- {
- VerificationResult::GoodChecksum
- (sig, tpk, key, binding, revocation)
+ match layer {
+ IMessageLayer::Compression { algo } =>
+ results.new_compression_layer(algo),
+ IMessageLayer::Encryption { .. } =>
+ unreachable!("not decrypting messages"),
+ IMessageLayer::SignatureGroup { sigs, .. } => {
+ results.new_signature_group();
+ for sig in sigs.into_iter() {
+ results.push_verification_result(
+ if let Some(issuer) = sig.get_issuer() {
+ if let Some((i, j)) =
+ self.keys.get(&issuer)
+ {
+ let tpk = &self.tpks[*i];
+ let (binding, revocation, key)
+ = tpk.keys_all().nth(*j)
+ .unwrap();
+ if sig.verify(key).unwrap_or(false)
+ && sig.signature_alive_at(self.time)
+ {
+ VerificationResult::GoodChecksum
+ (sig, tpk, key, binding,
+ revocation)
+ } else {
+ VerificationResult::BadChecksum
+ (sig)
+ }
+ } else {
+ VerificationResult::MissingKey(sig)
+ }
} else {
+ // No issuer.
VerificationResult::BadChecksum(sig)
}
- } else {
- VerificationResult::MissingKey(sig)
- }
- } else {
- // No issuer.
- VerificationResult::BadChecksum(sig)
+ )
}
- )
+ },
}
}
- self.helper.check(results)
+ self.helper.check(&results)
} else {
self.oppr = Some(PacketParserResult::Some(pp));
Ok(())
@@ -706,7 +909,7 @@ impl<'a> io::Read for Transformer<'a> {
/// fn get_public_keys(&mut self, _ids: &[KeyID]) -> Result<Vec<TPK>> {
/// Ok(Vec::new()) // Feed the TPKs to the verifier here...
/// }
-/// fn check(&mut self, sigs: Vec<Vec<VerificationResult>>) -> Result<()> {
+/// fn check(&mut self, structure: &MessageStructure) -> Result<()> {
/// Ok(()) // Implement your verification policy here.
/// }
/// }
@@ -844,7 +1047,7 @@ impl DetachedVerifier {
/// fn get_public_keys(&mut self, _ids: &[KeyID]) -> Result<Vec<TPK>> {
/// Ok(Vec::new()) // Feed the TPKs to the verifier here...
/// }
-/// fn check(&mut self, sigs: Vec<Vec<VerificationResult>>) -> Result<()> {
+/// fn check(&mut self, structure: &MessageStructure) -> Result<()> {
/// Ok(()) // Implement your verification policy here.
/// }
/// }
@@ -891,7 +1094,7 @@ pub struct Decryptor<'a, H: VerificationHelper + DecryptionHelper> {
keys: HashMap<KeyID, (usize, usize)>,
oppr: Option<PacketParserResult<'a>>,
identity: Option<Fingerprint>,
- sigs: Vec<Vec<Signature>>,
+ structure: IMessageStructure,
reserve: Option<Vec<u8>>,
/// Signature verification relative to this time.
@@ -1017,18 +1220,12 @@ impl<'a, H: VerificationHelper + DecryptionHelper> Decryptor<'a, H> {
keys: HashMap::new(),
oppr: None,
identity: None,
- sigs: Vec::new(),
+ structure: IMessageStructure::new(),
reserve: None,
time: t,
};
let mut issuers = Vec::new();
- // The following structure is allowed:
- //
- // SIG LITERAL
- //
- // In this case, we queue the signature packets.
- let mut sigs = Vec::new();
let mut pkesks: Vec<packet::PKESK> = Vec::new();
let mut skesks: Vec<packet::SKESK> = Vec::new();
let mut saw_content = false;
@@ -1042,23 +1239,49 @@ impl<'a, H: VerificationHelper + DecryptionHelper> Decryptor<'a, H> {
}
match pp.packet {
+ Packet::CompressedData(ref p) =>
+ v.structure.new_compression_layer(p.algorithm()),
Packet::SEIP(_) | Packet::AED(_) => {
saw_content = true;
- v.identity =
- v.helper.decrypt(&pkesks[..], &skesks[..],
- |algo, secret| pp.decrypt(algo, secret)
- )?;
+ // Get the symmetric algorithm from the decryption
+ // proxy function. This is necessary because we
+ // cannot get the algorithm from the SEIP packet.
+ let mut sym_algo = None;
+ {
+ let decryption_proxy = |algo, secret: &SessionKey| {
+ let result = pp.decrypt(algo, secret);
+ if let Ok(_) = result {
+ sym_algo = Some(algo);
+ }
+ result
+ };
+
+ v.identity =
+ v.helper.decrypt(&pkesks[..], &skesks[..],
+ decryption_proxy)?;
+ }
if ! pp.decrypted() {
// XXX: That is not quite the right error to return.
return Err(
Error::InvalidSessionKey("No session key".into())
.into());
}
+
+ v.structure.new_encryption_layer(
+ sym_algo.expect("if we got here, sym_algo is set"),
+ if let Packet::AED(ref p) = pp.packet {
+ Some(p.aead())
+ } else {
+ None
+ });
+ },
+ Packet::OnePassSig(ref ops) => {
+ v.structure.push_ops(ops);