mirror of
git://git.gnupg.org/gnupg.git
synced 2025-07-03 22:56:33 +02:00
Stricter test of allowed signature packet compositions.
There is still one problem to solve.
This commit is contained in:
parent
a200f76dcf
commit
3e08d87168
7 changed files with 304 additions and 128 deletions
|
@ -1,7 +1,8 @@
|
|||
2006-03-06 Werner Koch <wk@g10code.com>
|
||||
|
||||
* mainproc.c (check_sig_and_print): Check for multiple plaintexts
|
||||
before a signature. Reported by Tavis Ormandy.
|
||||
* mainproc.c (check_sig_and_print): Made the composition test more
|
||||
tight. This is due to another bug report by Tavis Ormandy.
|
||||
(add_onepass_sig): Simplified.
|
||||
|
||||
2006-03-05 Werner Koch <wk@g10code.com>
|
||||
|
||||
|
|
219
g10/mainproc.c
219
g10/mainproc.c
|
@ -114,27 +114,14 @@ release_list( CTX c )
|
|||
static int
|
||||
add_onepass_sig( CTX c, PACKET *pkt )
|
||||
{
|
||||
KBNODE node;
|
||||
KBNODE node;
|
||||
|
||||
if( c->list ) { /* add another packet */
|
||||
/* We can only append another onepass packet if the list
|
||||
* does contain only onepass packets */
|
||||
for( node=c->list; node && node->pkt->pkttype == PKT_ONEPASS_SIG;
|
||||
node = node->next )
|
||||
;
|
||||
if( node ) {
|
||||
/* this is not the case, so we flush the current thing and
|
||||
* allow this packet to start a new verification thing */
|
||||
release_list( c );
|
||||
c->list = new_kbnode( pkt );
|
||||
}
|
||||
else
|
||||
add_kbnode( c->list, new_kbnode( pkt ));
|
||||
}
|
||||
else /* insert the first one */
|
||||
c->list = node = new_kbnode( pkt );
|
||||
if ( c->list ) /* add another packet */
|
||||
add_kbnode( c->list, new_kbnode( pkt ));
|
||||
else /* insert the first one */
|
||||
c->list = node = new_kbnode( pkt );
|
||||
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1416,93 +1403,118 @@ pka_uri_from_sig (PKT_signature *sig)
|
|||
static int
|
||||
check_sig_and_print( CTX c, KBNODE node )
|
||||
{
|
||||
PKT_signature *sig = node->pkt->pkt.signature;
|
||||
const char *astr;
|
||||
int rc, is_expkey=0, is_revkey=0;
|
||||
PKT_signature *sig = node->pkt->pkt.signature;
|
||||
const char *astr;
|
||||
int rc, is_expkey=0, is_revkey=0;
|
||||
|
||||
if( opt.skip_verify ) {
|
||||
log_info(_("signature verification suppressed\n"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* It is not in all cases possible to check multiple signatures:
|
||||
* PGP 2 (which is also allowed by OpenPGP), does use the packet
|
||||
* sequence: sig+data, OpenPGP does use onepas+data=sig and GnuPG
|
||||
* sometimes uses (because I did'nt read the specs right) data+sig.
|
||||
* Because it is possible to create multiple signatures with
|
||||
* different packet sequence (e.g. data+sig and sig+data) it might
|
||||
* not be possible to get it right: let's say we have:
|
||||
* data+sig, sig+data,sig+data and we have not yet encountered the last
|
||||
* data, we could also see this a one data with 2 signatures and then
|
||||
* data+sig.
|
||||
* To protect against this we check that all signatures follow
|
||||
* without any intermediate packets. Note, that we won't get this
|
||||
* error when we use onepass packets or cleartext signatures because
|
||||
* we reset the list every time
|
||||
*
|
||||
* FIXME: Now that we have these marker packets, we should create a
|
||||
* real grammar and check against this.
|
||||
*/
|
||||
if (opt.skip_verify)
|
||||
{
|
||||
KBNODE n;
|
||||
int n_sig = 0;
|
||||
int n_plaintext = 0;
|
||||
int sig_seen, onepass_seen;
|
||||
|
||||
for (n=c->list; n; n=n->next )
|
||||
{
|
||||
if ( n->pkt->pkttype == PKT_SIGNATURE )
|
||||
n_sig++;
|
||||
else if (n->pkt->pkttype == PKT_GPG_CONTROL
|
||||
&& (n->pkt->pkt.gpg_control->control
|
||||
== CTRLPKT_PLAINTEXT_MARK) )
|
||||
n_plaintext++;
|
||||
}
|
||||
|
||||
for (sig_seen=onepass_seen=0,n=c->list; n; n=n->next )
|
||||
{
|
||||
if (n->pkt->pkttype == PKT_ONEPASS_SIG)
|
||||
{
|
||||
onepass_seen++;
|
||||
}
|
||||
else if (n->pkt->pkttype == PKT_GPG_CONTROL
|
||||
&& (n->pkt->pkt.gpg_control->control
|
||||
== CTRLPKT_CLEARSIGN_START) )
|
||||
{
|
||||
onepass_seen++; /* Handle the same way as a onepass. */
|
||||
}
|
||||
else if ( (sig_seen && n->pkt->pkttype != PKT_SIGNATURE) )
|
||||
{
|
||||
log_error(_("can't handle these multiple signatures\n"));
|
||||
return 0;
|
||||
}
|
||||
else if ( n->pkt->pkttype == PKT_SIGNATURE )
|
||||
{
|
||||
sig_seen = 1;
|
||||
}
|
||||
else if (n_sig > 1 && !sig_seen && !onepass_seen
|
||||
&& n->pkt->pkttype == PKT_GPG_CONTROL
|
||||
&& (n->pkt->pkt.gpg_control->control
|
||||
== CTRLPKT_PLAINTEXT_MARK) )
|
||||
{
|
||||
/* Plaintext before signatures but no onepass
|
||||
signature packets. */
|
||||
log_error(_("can't handle these multiple signatures\n"));
|
||||
return 0;
|
||||
}
|
||||
else if (n_plaintext > 1 && !sig_seen && !onepass_seen
|
||||
&& n->pkt->pkttype == PKT_GPG_CONTROL
|
||||
&& (n->pkt->pkt.gpg_control->control
|
||||
== CTRLPKT_PLAINTEXT_MARK) )
|
||||
{
|
||||
/* More than one plaintext before a signature but no
|
||||
onepass packets. */
|
||||
log_error(_("can't handle this ambiguous signed data\n"));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
log_info(_("signature verification suppressed\n"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check that the message composition is valid.
|
||||
|
||||
Per RFC-2440bis (-15) allowed:
|
||||
|
||||
S{1,n} -- detached signature.
|
||||
S{1,n} P -- old style PGP2 signature
|
||||
O{1,n} P S{1,n} -- standard OpenPGP signature.
|
||||
C P S{1,n} -- cleartext signature.
|
||||
|
||||
|
||||
O = One-Pass Signature packet.
|
||||
S = Signature packet.
|
||||
P = OpenPGP Message packet (Encrypted | Compressed | Literal)
|
||||
(Note that the current rfc2440bis draft also allows
|
||||
for a signed message but that does not work as it
|
||||
introduces ambiguities.)
|
||||
We keep track of these packages using the marker packet
|
||||
CTRLPKT_PLAINTEXT_MARK.
|
||||
C = Marker packet for cleartext signatures.
|
||||
|
||||
We reject all other messages.
|
||||
|
||||
Actually we are calling this too often, i.e. for verification of
|
||||
each message but better have some duplicate work than to silently
|
||||
introduce a bug here.
|
||||
*/
|
||||
{
|
||||
KBNODE n;
|
||||
int n_onepass, n_sig;
|
||||
|
||||
log_debug ("checking signature packet composition\n");
|
||||
dump_kbnode (c->list);
|
||||
|
||||
n = c->list;
|
||||
assert (n);
|
||||
if ( n->pkt->pkttype == PKT_SIGNATURE )
|
||||
{
|
||||
/* This is either "S{1,n}" case (detached signature) or
|
||||
"S{1,n} P" (old style PGP2 signature). */
|
||||
for (n = n->next; n; n = n->next)
|
||||
if (n->pkt->pkttype != PKT_SIGNATURE)
|
||||
break;
|
||||
if (!n)
|
||||
; /* Okay, this is a detached signature. */
|
||||
else if (n->pkt->pkttype == PKT_GPG_CONTROL
|
||||
&& (n->pkt->pkt.gpg_control->control
|
||||
== CTRLPKT_PLAINTEXT_MARK) )
|
||||
{
|
||||
if (n->next)
|
||||
goto ambiguous; /* We only allow one P packet. */
|
||||
}
|
||||
else
|
||||
goto ambiguous;
|
||||
}
|
||||
else if (n->pkt->pkttype == PKT_ONEPASS_SIG)
|
||||
{
|
||||
/* This is the "O{1,n} P S{1,n}" case (standard signature). */
|
||||
for (n_onepass=1, n = n->next;
|
||||
n && n->pkt->pkttype == PKT_ONEPASS_SIG; n = n->next)
|
||||
n_onepass++;
|
||||
if (!n || !(n->pkt->pkttype == PKT_GPG_CONTROL
|
||||
&& (n->pkt->pkt.gpg_control->control
|
||||
== CTRLPKT_PLAINTEXT_MARK)))
|
||||
goto ambiguous;
|
||||
for (n_sig=0, n = n->next;
|
||||
n && n->pkt->pkttype == PKT_SIGNATURE; n = n->next)
|
||||
n_sig++;
|
||||
if (n || !n_sig)
|
||||
goto ambiguous;
|
||||
if (n_onepass != n_sig)
|
||||
{
|
||||
log_info ("number of one-pass packets does not match "
|
||||
"number of signature packets\n");
|
||||
goto ambiguous;
|
||||
}
|
||||
}
|
||||
else if (n->pkt->pkttype == PKT_GPG_CONTROL
|
||||
&& n->pkt->pkt.gpg_control->control == CTRLPKT_CLEARSIGN_START )
|
||||
{
|
||||
/* This is the "C P S{1,n}" case (clear text signature). */
|
||||
n = n->next;
|
||||
if (!n || !(n->pkt->pkttype == PKT_GPG_CONTROL
|
||||
&& (n->pkt->pkt.gpg_control->control
|
||||
== CTRLPKT_PLAINTEXT_MARK)))
|
||||
goto ambiguous;
|
||||
for (n_sig=0, n = n->next;
|
||||
n && n->pkt->pkttype == PKT_SIGNATURE; n = n->next)
|
||||
n_sig++;
|
||||
if (n || !n_sig)
|
||||
goto ambiguous;
|
||||
}
|
||||
else
|
||||
{
|
||||
ambiguous:
|
||||
log_error(_("can't handle this ambiguous signature data\n"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* (Indendation below not yet changed to GNU style.) */
|
||||
|
||||
astr = pubkey_algo_to_string( sig->pubkey_algo );
|
||||
if(keystrlen()>8)
|
||||
{
|
||||
|
@ -1926,7 +1938,8 @@ proc_tree( CTX c, KBNODE node )
|
|||
/* prepare to create all requested message digests */
|
||||
c->mfx.md = md_open(0, 0);
|
||||
|
||||
/* fixme: why looking for the signature packet and not 1passpacket*/
|
||||
/* fixme: why looking for the signature packet and not the
|
||||
one-pass packet? */
|
||||
for( n1 = node; (n1 = find_next_kbnode(n1, PKT_SIGNATURE )); ) {
|
||||
md_enable( c->mfx.md, n1->pkt->pkt.signature->digest_algo);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue