diff options
author | Justus Winter <justus@sequoia-pgp.org> | 2019-05-09 15:19:24 +0200 |
---|---|---|
committer | Justus Winter <justus@sequoia-pgp.org> | 2019-05-09 15:19:24 +0200 |
commit | 75d4e6dda12e8b7ae8573227e61e718ede3f2cfc (patch) | |
tree | c6b9e3f177d8c65d134acfd889c236203b2ac13f | |
parent | 8e0f817f312f469871a5fbed6bb961f6117ba742 (diff) |
openpgp: Communicate message structure from the decryptor.
- Fixes #100.
-rw-r--r-- | guide/src/chapter_01.md | 204 | ||||
-rw-r--r-- | guide/src/chapter_02.md | 8 | ||||
-rw-r--r-- | openpgp-ffi/examples/decrypt-with.c | 87 | ||||
-rw-r--r-- | openpgp-ffi/include/sequoia/openpgp.h | 96 | ||||
-rw-r--r-- | openpgp-ffi/include/sequoia/openpgp/types.h | 37 | ||||
-rw-r--r-- | openpgp-ffi/src/parse/stream.rs | 379 | ||||
-rw-r--r-- | openpgp/examples/decrypt-with.rs | 44 | ||||
-rw-r--r-- | openpgp/examples/generate-encrypt-decrypt.rs | 2 | ||||
-rw-r--r-- | openpgp/examples/generate-sign-verify.rs | 51 | ||||
-rw-r--r-- | openpgp/src/parse/stream.rs | 574 | ||||
-rw-r--r-- | openpgp/src/serialize/stream.rs | 30 | ||||
-rw-r--r-- | tool/src/commands/decrypt.rs | 6 | ||||
-rw-r--r-- | tool/src/commands/mod.rs | 131 |
13 files changed, 1150 insertions, 499 deletions
diff --git a/guide/src/chapter_01.md b/guide/src/chapter_01.md index f5663bc9..8d973e07 100644 --- a/guide/src/chapter_01.md +++ b/guide/src/chapter_01.md @@ -101,30 +101,41 @@ fn main() { # 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")) # } # } # } @@ -231,30 +242,41 @@ fn generate() -> openpgp::Result<openpgp::TPK> { # 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")) # } # } # } @@ -361,30 +383,41 @@ fn sign(sink: &mut Write, plaintext: &str, tsk: &openpgp::TPK) # 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")) # } # } # } @@ -502,30 +535,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/guide/src/chapter_02.md b/guide/src/chapter_02.md index 751a04a1..f66e15b3 100644 --- a/guide/src/chapter_02.md +++ b/guide/src/chapter_02.md @@ -102,7 +102,7 @@ fn main() { # 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(()) @@ -236,7 +236,7 @@ fn generate() -> openpgp::Result<openpgp::TPK> { # 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(()) @@ -370,7 +370,7 @@ fn encrypt(sink: &mut Write, plaintext: &str, recipient: &openpgp::TPK) # 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(()) @@ -518,7 +518,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-ffi/examples/decrypt-with.c b/openpgp-ffi/examples/decrypt-with.c index 969b7e28..68ef0606 100644 --- a/openpgp-ffi/examples/decrypt-with.c +++ b/openpgp-ffi/examples/decrypt-with.c @@ -38,9 +38,90 @@ get_public_keys_cb (void *cookie_raw, } static pgp_status_t -check_signatures_cb(void *cookie_opaque, - pgp_verification_results_t results, size_t levels) +check_cb (void *cookie_opaque, pgp_message_structure_t structure) { + pgp_message_structure_iter_t iter = pgp_message_structure_iter (structure); + + for (pgp_message_layer_t layer = pgp_message_structure_iter_next (iter); + layer; + layer = pgp_message_structure_iter_next (iter)) { + uint8_t algo; + uint8_t aead_algo; + pgp_verification_result_iter_t results; + + switch (pgp_message_layer_variant (layer)) { + case PGP_MESSAGE_LAYER_COMPRESSION: + pgp_message_layer_compression (layer, &algo); + fprintf (stderr, "Compressed using %d\n", algo); + break; + + case PGP_MESSAGE_LAYER_ENCRYPTION: + pgp_message_layer_encryption (layer, &algo, &aead_algo); + if (aead_algo) { + fprintf (stderr, "Encrypted and protected using %d/%d\n", + algo, aead_algo); + } else { + fprintf (stderr, "Encrypted using %d\n", algo); + } + break; + + case PGP_MESSAGE_LAYER_SIGNATURE_GROUP: + pgp_message_layer_signature_group (layer, &results); + for (pgp_verification_result_t result = + pgp_verification_result_iter_next (results); + result; + result = pgp_verification_result_iter_next (results)) { + pgp_signature_t sig; + pgp_keyid_t keyid; + char *keyid_str = NULL; + + switch (pgp_verification_result_variant (result)) { + case PGP_VERIFICATION_RESULT_GOOD_CHECKSUM: + pgp_verification_result_good_checksum (result, &sig, NULL, + NULL, NULL, NULL); + keyid = pgp_signature_issuer (sig); + keyid_str = pgp_keyid_to_string (keyid); + fprintf (stderr, "Good signature from %s\n", keyid_str); + break; + + case PGP_VERIFICATION_RESULT_MISSING_KEY: + pgp_verification_result_missing_key (result, &sig); + keyid = pgp_signature_issuer (sig); + keyid_str = pgp_keyid_to_string (keyid); + fprintf (stderr, "No key to check signature from %s\n", keyid_str); + break; + + case PGP_VERIFICATION_RESULT_BAD_CHECKSUM: + pgp_verification_result_bad_checksum (result, &sig); + keyid = pgp_signature_issuer (sig); + if (keyid) { + keyid_str = pgp_keyid_to_string (keyid); + fprintf (stderr, "Bad signature from %s\n", keyid_str); + } else { + fprintf (stderr, "Bad signature without issuer information\n"); + } + break; + + default: + assert (! "reachable"); + } + free (keyid_str); + pgp_signature_free (sig); + pgp_verification_result_free (result); + } + pgp_verification_result_iter_free (results); + break; + + default: + assert (! "reachable"); + } + + pgp_message_layer_free (layer); + } + + pgp_message_structure_iter_free (iter); + pgp_message_structure_free (structure); + /* Implement your verification policy here. */ return PGP_STATUS_SUCCESS; } @@ -128,7 +209,7 @@ main (int argc, char **argv) }; plaintext = pgp_decryptor_new (&err, source, get_public_keys_cb, decrypt_cb, - check_signatures_cb, &cookie, 0); + check_cb, &cookie, 0); if (! plaintext) error (1, 0, "pgp_decryptor_new: %s", pgp_error_to_string (err)); diff --git a/openpgp-ffi/include/sequoia/openpgp.h b/openpgp-ffi/include/sequoia/openpgp.h index db3c82aa..3b001a15 100644 --- a/openpgp-ffi/include/sequoia/openpgp.h +++ b/openpgp-ffi/include/sequoia/openpgp.h @@ -1447,33 +1447,91 @@ pgp_writer_stack_t pgp_encryptor_new (pgp_error_t *errp, pgp_encryption_mode_t mode, uint8_t cipher_algo); -void pgp_verification_results_at_level(pgp_verification_results_t results, - size_t level, - pgp_verification_result_t **r, - size_t *r_count); +/*/ +/// Frees this object. +/*/ +void pgp_message_structure_free (pgp_message_structure_t); + +/*/ +/// Returns a human readable description of this object suitable for +/// debugging. +/*/ +char *pgp_message_structure_debug (const pgp_message_structure_t); +pgp_message_structure_iter_t +pgp_message_structure_iter (pgp_message_structure_t); /*/ -/// Returns the verification result code. +/// Frees this object. /*/ -pgp_verification_result_code_t pgp_verification_result_code( - pgp_verification_result_t r); +void pgp_message_structure_iter_free (pgp_message_structure_iter_t); + +pgp_message_layer_t +pgp_message_structure_iter_next (pgp_message_structure_iter_t); /*/ -/// Returns a reference to the signature. -/// -/// Do not modify the signature nor free it. +/// Frees this object. /*/ -pgp_signature_t pgp_verification_result_signature( +void pgp_message_layer_free (pgp_message_layer_t); + +/*/ +/// Returns a human readable description of this object suitable for +/// debugging. +/*/ +char *pgp_message_layer_debug (const pgp_message_layer_t); + +/*/ +/// Returns the message layer variant. +/*/ +pgp_message_layer_variant_t +pgp_message_layer_variant (pgp_message_layer_t); + +/*/ +/// Return the fields of the variants. +/*/ +bool pgp_message_layer_compression (pgp_message_layer_t, uint8_t *); +bool pgp_message_layer_encryption (pgp_message_layer_t, uint8_t *, uint8_t *); +bool pgp_message_layer_signature_group (pgp_message_layer_t, + pgp_verification_result_iter_t *); + +/*/ +/// Frees this object. +/*/ +void pgp_verification_result_iter_free (pgp_verification_result_iter_t); + +pgp_verification_result_t +pgp_verification_result_iter_next (pgp_verification_result_iter_t); + +/*/ +/// Frees this object. +/*/ +void pgp_verification_result_free (pgp_verification_result_t); + +/*/ +/// Returns a human readable description of this object suitable for +/// debugging. +/*/ +char *pgp_verification_result_debug (const pgp_verification_result_t); + +/*/ +/// Returns the verification result variant. +/*/ +pgp_verification_result_variant_t pgp_verification_result_variant ( pgp_verification_result_t r); /*/ -/// Returns the signature's level. -/// -/// A level of zero means that the data was signed, a level of one -/// means that one or more signatures were notarized, etc. +/// Return the fields of the variants. /*/ -int pgp_verification_result_level(pgp_verification_result_t r); +bool pgp_verification_result_good_checksum (pgp_verification_result_t, + pgp_signature_t *, + pgp_tpk_t *, + pgp_key_t *, + pgp_signature_t *, + pgp_revocation_status_t *); +bool pgp_verification_result_missing_key (pgp_verification_result_t, + pgp_signature_t *); +bool pgp_verification_result_bad_checksum (pgp_verification_result_t, + pgp_signature_t *); /*/ /// Decrypts an OpenPGP message. @@ -1492,7 +1550,7 @@ int pgp_verification_result_level(pgp_verification_result_t r); pgp_reader_t pgp_decryptor_new (pgp_error_t *errp, pgp_reader_t input, pgp_decryptor_get_public_keys_cb_t get_public_keys, pgp_decryptor_decrypt_cb_t decrypt, - pgp_decryptor_check_signatures_cb_t check_signatures, + pgp_decryptor_check_cb_t check, void *cookie, time_t time); /*/ @@ -1503,7 +1561,7 @@ pgp_reader_t pgp_decryptor_new (pgp_error_t *errp, pgp_reader_t input, /*/ pgp_reader_t pgp_verifier_new (pgp_error_t *errp, pgp_reader_t input, pgp_decryptor_get_public_keys_cb_t get_public_keys, - pgp_decryptor_check_signatures_cb_t check_signatures, + pgp_decryptor_check_cb_t check, void *cookie, time_t time); /*/ @@ -1512,7 +1570,7 @@ pgp_reader_t pgp_verifier_new (pgp_error_t *errp, pgp_reader_t input, pgp_reader_t pgp_detached_verifier_new (pgp_error_t *errp, pgp_reader_t signature_input, pgp_reader_t input, pgp_decryptor_get_public_keys_cb_t get_public_keys, - pgp_decryptor_check_signatures_cb_t check_signatures, + pgp_decryptor_check_cb_t check, void *cookie, time_t time); #endif diff --git a/openpgp-ffi/include/sequoia/openpgp/types.h b/openpgp-ffi/include/sequoia/openpgp/types.h index c6572346..40c926d0 100644 --- a/openpgp-ffi/include/sequoia/openpgp/types.h +++ b/openpgp-ffi/include/sequoia/openpgp/types.h @@ -464,18 +464,38 @@ typedef enum pgp_encryption_mode { PGP_ENCRYPTION_MODE_FOR_TRANSPORT = 1, } pgp_encryption_mode_t; -typedef struct pgp_verification_results *pgp_verification_results_t; +/// Communicates the message structure to the VerificationHelper. +typedef struct pgp_message_structure *pgp_message_structure_t; + +/// Iterates over the message structure. +typedef struct pgp_message_structure_iter *pgp_message_structure_iter_t; + +/// Represents a layer of the message structure. +typedef struct pgp_message_layer *pgp_message_layer_t; + +typedef enum pgp_message_layer_variant { + PGP_MESSAGE_LAYER_COMPRESSION = 1, + PGP_MESSAGE_LAYER_ENCRYPTION = 2, + PGP_MESSAGE_LAYER_SIGNATURE_GROUP = 3, + + /* Dummy value to make sure the enumeration has a defined size. Do + not use this value. */ + PGP_MESSAGE_LAYER_CODE_FORCE_WIDTH = INT_MAX, +} pgp_message_layer_variant_t; + typedef struct pgp_verification_result *pgp_verification_result_t; -typedef enum pgp_verification_result_code { - PGP_VERIFICATION_RESULT_CODE_GOOD_CHECKSUM = 1, - PGP_VERIFICATION_RESULT_CODE_MISSING_KEY = 2, - PGP_VERIFICATION_RESULT_CODE_BAD_CHECKSUM = 3, +typedef struct pgp_verification_result_iter *pgp_verification_result_iter_t; + +typedef enum pgp_verification_result_variant { + PGP_VERIFICATION_RESULT_GOOD_CHECKSUM = 1, + PGP_VERIFICATION_RESULT_MISSING_KEY = 2, + PGP_VERIFICATION_RESULT_BAD_CHECKSUM = 3, /* Dummy value to make sure the enumeration has a defined size. Do not use this value. */ PGP_VERIFICATION_RESULT_CODE_FORCE_WIDTH = INT_MAX, -} pgp_verification_result_code_t; +} pgp_verification_result_variant_t; typedef pgp_status_t (*pgp_decryptor_get_public_keys_cb_t) (void *, pgp_keyid_t *, size_t, @@ -494,8 +514,7 @@ typedef pgp_status_t (*pgp_decryptor_decrypt_cb_t) (void *, void *, pgp_fingerprint_t *); -typedef pgp_status_t (*pgp_decryptor_check_signatures_cb_t) (void *, - pgp_verification_results_t, - size_t); +typedef pgp_status_t (*pgp_decryptor_check_cb_t) (void *, + pgp_message_structure_t); #endif diff --git a/openpgp-ffi/src/parse/stream.rs b/openpgp-ffi/src/parse/stream.rs index ebd4bc50..8dcaf101 100644 --- a/openpgp-ffi/src/parse/stream.rs +++ b/openpgp-ffi/src/parse/stream.rs @@ -11,7 +11,7 @@ //! [`sequoia-openpgp::parse::stream`]: ../../../sequoia_openpgp/parse/stream/index.html use std::ptr; -use libc::{c_int, size_t, c_void, uint8_t, time_t}; +use libc::{c_int, c_void, uint8_t, time_t}; extern crate sequoia_openpgp as openpgp; extern crate time; @@ -25,10 +25,10 @@ use self::openpgp::{ }, }; use self::openpgp::parse::stream::{ + self, DecryptionHelper, Decryptor, VerificationHelper, - VerificationResult, Verifier, DetachedVerifier, }; @@ -45,93 +45,221 @@ use super::super::{ crypto, io, keyid, - packet, tpk::TPK, + packet::signature::Signature, + packet::key::Key, |