summaryrefslogtreecommitdiffstats
path: root/openpgp/src/parse/stream.rs
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2023-05-24 11:18:18 +0200
committerJustus Winter <justus@sequoia-pgp.org>2023-06-06 08:47:21 +0200
commit4f3d260a013835a8ab0b2f15f45e22ca4678ab24 (patch)
treec9c485e53b73841efe07a29f71bc0906396d1361 /openpgp/src/parse/stream.rs
parent940a7267a61418661f61da2f0676069096ca2626 (diff)
openpgp: Fix the cleartext signature framework.
- Previously, we considered the line break immediately before the signature marker to be part of the signature. This is not correct. See Section 7.1 of RFC4880: The line ending (i.e., the <CR><LF>) before the '-----BEGIN PGP SIGNATURE-----' line that terminates the signed text is not considered part of the signed text. - This interpretation allows us to preserve the final newline in the signed text. See https://gitlab.com/sequoia-pgp/sequoia-sop/-/issues/16 where dkg requests: [...] if a trailing newline goes in, a trailing newline comes out. - The previous interpretation required very careful handling of the trailing line break, making sure it is not hashed. This was complicated by the fact that line breaks may use two characters, and the two characters may straddle reads/writes. So, this change of interpretation makes the code quite a bit simpler. - To clarify, signing the four octet string "test" yields a message looking like -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA512 test -----BEGIN PGP SIGNATURE----- ... -----END PGP SIGNATURE----- Whereas signing the five octet string "test\n" now yields -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA512 test -----BEGIN PGP SIGNATURE----- ... -----END PGP SIGNATURE----- - It is worth pointing out that GnuPG does something similar to what we did before: it makes sure any signed text ends in a line break (see `copy_clearsig_text`), but "swallows" this newline by using it as delimiter between text and signature (see `clearsign_file` where no explicit newline is emitted before the armor filter is pushed and the signatures are emitted). When verifying a message, GnuPG will emit the final line break, being very careful not to hash it (see `handle_plaintext`). The result is that any message signed by GnuPG seems to end in a line break when verified by GnuPG, but will never end in a line break when verified with Sequoia (or any other implementation that considers the signature-separating line break to be not part of the message, like OpenPGP.js). Signature validity is not affected.
Diffstat (limited to 'openpgp/src/parse/stream.rs')
-rw-r--r--openpgp/src/parse/stream.rs17
1 files changed, 13 insertions, 4 deletions
diff --git a/openpgp/src/parse/stream.rs b/openpgp/src/parse/stream.rs
index 74036553..b59005e7 100644
--- a/openpgp/src/parse/stream.rs
+++ b/openpgp/src/parse/stream.rs
@@ -3204,13 +3204,15 @@ pub mod test {
(crate::tests::message("a-cypherpunks-manifesto.txt.cleartext.sig")
.to_vec(),
{
+ // The test vector, created by GnuPG, does not preserve
+ // the final newline.
+ //
// The transformation process trims trailing whitespace,
// and the manifesto has a trailing whitespace right at
// the end.
let mut manifesto = crate::tests::manifesto().to_vec();
- let ws_at = manifesto.len() - 2;
- let ws = manifesto.remove(ws_at);
- assert_eq!(ws, b' ');
+ assert_eq!(manifesto.pop(), Some(b'\n'));
+ assert_eq!(manifesto.pop(), Some(b' '));
manifesto
},
false,
@@ -3218,7 +3220,14 @@ pub mod test {
VHelper::new(1, 0, 0, 0, certs.clone())),
(crate::tests::message("a-problematic-poem.txt.cleartext.sig")
.to_vec(),
- crate::tests::message("a-problematic-poem.txt").to_vec(),
+ {
+ // The test vector, created by GnuPG, does not preserve
+ // the final newline.
+ let mut reference =
+ crate::tests::message("a-problematic-poem.txt").to_vec();
+ assert_eq!(reference.pop(), Some(b'\n'));
+ reference
+ },
false,
None,
VHelper::new(1, 0, 0, 0, certs.clone())),