Cleartext signing with CR character.

alex abc3def at
Wed Feb 5 18:57:20 CET 2014

This is what I get:

assert("A\r\nB\r\n", "A\r\nB"); // OK
assert("A\nB\r\n", "A\r\nB"); // OK
assert("A\n\nB\r\n", "A\r\n\r\nB"); // OK


assert("A\rB\r\n", "A\r\nB"); // BAD
assert("A\rB\r\n", "A\rB"); // BAD

RFC4880 tells:

   "The signature is calculated over the text with its line endings
converted to <CR><LF>."

But they do not clarify what is the "line endings". I would consider any of
CR, LF, CRLF as the line ending, but when I read the GnuPGP sources, it
looks like they consider LF as the line ending, e.g. iobuf.c, function

The next thing I read in  RFC4880:

  "Also, any trailing whitespace -- spaces (0x20) and tabs (0x09) -- at the
end of any line is removed when the cleartext signature is generated."

In implementation I see (textfilter.c, copy_clearsig_text):

  len_without_trailing_chars (buffer, n, pgp2mode? " \r\n":" \t\r\n"));

So how it works... Consider I have such text: "A\r\r\r\nB".

- The code will search for '\n' to identify the end of the line. As result
on first iteration we'll get "A\r\r\r\n" in buffer.
- Then the "len_without_trailing_chars" computed -  chars \r and \n will be
considered as trailing, so the length will be 1.
- Copy 1 byte from buffer  to message digest, i.e. copy "A".
- On second iteration they copy "\r\n" into the digest (normalized line
- The buffer will be filled with "B", no trailing chars, so the bytes
copied to message digest "B" as well.

We end up with "A\r\nB" used to compute signature...

And this is confirmed by my test:

    assert("A\r\r\r\nB\r\n", "A\r\nB"); // OK

I write first argument as "cleartext" part, compute signature (wihtout any
normalization) from "A\r\nB", and ask gpg2 to validate the result message -
and it tells "Good signature".

Now let me analyze what will happen with "A\rB" text..

- The first iteration will be looking for the \n (or end of text). There is
no LF in my text, so the buffer will have "A\rB".
- Then we try to remove trailing chars, but there are no trailing chars, so
the whole string is copied to digest calculator.

We end up with signature computed from "A\rB".

But my test fails:
   assert("A\rB\r\n", "A\rB"); // BAD

So I wonder, if someone (who can build GnuPGP from sources) can add some
diagnostic code, and tell me, why gpg2 fails to validate such messages. It
looks like when it see "A\rB" it computes signature NOT from "A\rB".

2014-02-05 David Shaw <dshaw at>:

> This is the standard canonicalization of text in OpenPGP where line
> endings are converted to CRLF.  Signatures for clearsigned documents are
> sigclass 0x01, so are canonicalized.
> David
- Alex
-------------- next part --------------
An HTML attachment was scrubbed...
URL: </pipermail/attachments/20140205/02bd72b5/attachment.html>

More information about the Gnupg-devel mailing list