Subject: Re: More spec-ulations - update
From: Hal Finney <[email-masked]>
To: [email-masked], [email-masked]
Date: Thu, 26 Mar 1998 12:10:39 -0800

[email-masked] writes:
> > 3. Are multiple signatures allowed similar to multiple recipient keys?
> > (The spec is at work and I am not right now)  E.g. 1psig(k1) 1psig(k2)...
> > signed text ... sig(k1) sig(k2) ... And would the order be important?
>
> I read about the nested signature bits.  Which presents a problem.
>
> if I have
> 1psig(k1,nest),1psig(k2,nonest),literal,sig(k1),sig(k2)
> And I want to alter the text, I can get:
> 1psig(k1,nonest),1psig(k2,nonest),literal,sig(k1),sig(k2)
> where I alter the second 1psig until my altered literal has the same hash
> value.

To do this you would need to create two different byte sequences which
both hash to the same value.  This is assumed to be impossible with the
cryptographically strong hash functions which we use.  We do not attempt
to defend against attacks which require breaking the hash function.

> But to isolate the problem: I didn't see any clear definition of what a
> data signature packet is supposed to be hashing.  I would think "only the
> immediately preceeding compressed, literal, or encrypted data packet" with
> a note that multiple signature packets must be concatenated.
>
> For example, a message of the form: (literal)(literal)(signature) - what
> would the hash for the signature be over?  Both literal packets or just
> the final one?

This is not a legal OP message, according to the grammar in section 10.2.
Signatures can only go at the end if there is a 1psig packet at the
beginning, and there cannot be two OP messages between the 1psig and sig,
only one.

> I would also prefer ignoring the nest/nonest octet; any signature packet
> to be signed can be encapsulated in a literal packet.  The 1-pass sig
> packets would then fire up the hash algorithms (optionally only if the
> corresponding keyids were available) as a convienience for any signature
> packet that would happen to occur after the literal.

The historical evolution of signatures has resulted in a rather complicated
set of conventions.  We could consider simplifying them, but it would
impair compatibility with the installed PGP 2.X base.

PGP 2.X normally signs files by wrapping them in a literal packet, and then
putting a signature packet in front.  However, it was also allowed for
any legal PGP messge to be signed by putting a signature packet in front
of it.

With PGP 2.X, you could sign a (binary) PGP encrypted file, and it would
say, "this looks like a PGP file, should I assume that it is?"  If you
said yes, it would not wrap the file in a literal packet but would just
stick the signature packet in front.  You could sign an encrypted file
in this way.  (Signing an encrypted file is a somewhat questionable
thing to do, but in some circumstances it may be appropriate.)

The main advantage of this is that it allows easy "unwrapping" of a
message which may be multiply signed and encrypted.  The unwrapping
stops when it comes to a literal packet.  PGP 2.X, if decrypting the
file above, would first say that it had found a signature, then that
it had found encrypted data, then it would proceed to describe what
it found within the encrypted portion.

Generalizing this to the one pass signatures, we allow any legal PGP
message to be signed by putting a 1pass packet in front of it and a
signature packet behind it.

However at the same time the "nested" flag was introduced in the 1pass
packet.  This is intended to allow multiple signatures to be on the
same data.  You could not do that with the old PGP 2.X format, as each
signature packet applied to the entire following message.

If you have a case like:

  1psig(k1,nest),1psig(k2,nonest),literal,sig(k2),sig(k1)

then both the signatures by k1 and k2 are on the literal data, or more
generally, on whatever OP message lies between the last 1psig and the
matching sig packet.  With the opposite setting for the nest flag:

  1psig(k1,nonest),1psig(k2,nonest),literal,sig(k2),sig(k1)

then the signature by k1 is on the three-packet signed message by k2.
(Note that I reversed the order of the sig packets from your example,
so that they are paired appropriately.)

I believe you are suggesting eliminating the nest flag and assuming that
we always use the first interpretation, where multiple 1psig packets
all apply to the same signed data.  Then, when we want to express the
second, we would do:

  1psig(k1), literal( 1psig(k2),literal,sig(k2) ), sig(k1)

wrapping the signed message by k2 in a literal packet.

The main problem I see is that the unwrapping process described above
would not work smoothly.  We would either stop when we see the literal
packet, and not report the k2 signature, or else we would have to have
a policy of always peeking inside literal packets and seeing if the data
looks like PGP data, and perhaps proceeding to decode it.  The literal
packets then lose their useful function as a known stopping point.

Derek Atkins was the designer of the one-pass signature packets, back
before PGP, Inc. existed.  He told me that he was not completely satisfied
with the design, that he thought the grammar still had some ambiguities,
and that a three state nesting flag was necessary to cover all possible
cases.  I have never gone back and looked into this area thoroughly.
PGP 5.X will parse and verify these various signature forms, but does not
create them.

Hal