diff options
-rw-r--r-- | g10/ChangeLog | 16 | ||||
-rw-r--r-- | g10/getkey.c | 45 | ||||
-rw-r--r-- | g10/keygen.c | 2 | ||||
-rw-r--r-- | g10/main.h | 5 | ||||
-rw-r--r-- | g10/packet.h | 4 | ||||
-rw-r--r-- | g10/parse-packet.c | 4 | ||||
-rw-r--r-- | g10/sig-check.c | 54 |
7 files changed, 123 insertions, 7 deletions
diff --git a/g10/ChangeLog b/g10/ChangeLog index 998401636..b180b25d9 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,3 +1,19 @@ +2004-04-22 David Shaw <[email protected]> + + * keygen.c (make_backsig): If DO_BACKSIGS is not defined, do not + create backsigs. + + * getkey.c (merge_selfsigs_subkey): Find 0x19 backsigs on subkey + selfsigs and verify they are valid. If DO_BACKSIGS is not + defined, fake this as always valid. + + * packet.h, parse-packet.c (parse_signature): Make parse_signature + non-static so we can parse 0x19s in self-sigs. + + * main.h, sig-check.c (check_backsig): Check a 0x19 signature. + (signature_check2): Give a backsig warning if there is no or a bad + 0x19 with signatures from a subkey. + 2004-04-21 David Shaw <[email protected]> * parse-packet.c (dump_sig_subpkt, parse_one_sig_subpkt, diff --git a/g10/getkey.c b/g10/getkey.c index 171d8216c..3bee10a35 100644 --- a/g10/getkey.c +++ b/g10/getkey.c @@ -1923,8 +1923,51 @@ merge_selfsigs_subkey( KBNODE keyblock, KBNODE subnode ) key_expire = 0; subpk->has_expired = key_expire >= curtime? 0 : key_expire; subpk->expiredate = key_expire; -} +#ifndef DO_BACKSIGS + /* Pretend the backsig is present and accounted for. */ + subpk->backsig=2; +#else + /* Find the first 0x19 embedded signature on our self-sig. */ + if(subpk->backsig==0) + { + int seq=0; + + while((p=enum_sig_subpkt(sig->hashed, + SIGSUBPKT_SIGNATURE,&n,&seq,NULL))) + if(n>3 && ((p[0]==3 && p[2]==0x19) || (p[0]==4 && p[1]==0x19))) + break; + + if(p==NULL) + { + seq=0; + /* It is safe to have this in the unhashed area since the + 0x19 is located here for convenience, not security. */ + while((p=enum_sig_subpkt(sig->unhashed,SIGSUBPKT_SIGNATURE, + &n,&seq,NULL))) + if(n>3 && ((p[0]==3 && p[2]==0x19) || (p[0]==4 && p[1]==0x19))) + break; + } + + if(p) + { + PKT_signature *backsig=m_alloc_clear(sizeof(PKT_signature)); + IOBUF backsig_buf=iobuf_temp_with_content(p,n); + + if(parse_signature(backsig_buf,PKT_SIGNATURE,n,backsig)==0) + { + if(check_backsig(mainpk,subpk,backsig)==0) + subpk->backsig=2; + else + subpk->backsig=1; + } + + iobuf_close(backsig_buf); + free_seckey_enc(backsig); + } + } +#endif +} /* diff --git a/g10/keygen.c b/g10/keygen.c index c7df8ead4..baa43c908 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -531,10 +531,12 @@ make_backsig(PKT_signature *sig, PKT_public_key *pk, PKT_signature *backsig; int rc; +#ifndef DO_BACKSIGS /* This is not enabled yet, as I want to get a bit closer to RFC day before enabling this. I've been burned before :) */ return 0; +#endif cache_public_key (sub_pk); diff --git a/g10/main.h b/g10/main.h index 1fbfda781..51d6c1827 100644 --- a/g10/main.h +++ b/g10/main.h @@ -1,5 +1,6 @@ /* main.h - * Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, + * 2004 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -119,6 +120,8 @@ int sign_symencrypt_file (const char *fname, STRLIST locusr); /*-- sig-check.c --*/ int check_revocation_keys (PKT_public_key *pk, PKT_signature *sig); +int check_backsig(PKT_public_key *main_pk,PKT_public_key *sub_pk, + PKT_signature *backsig); int check_key_signature( KBNODE root, KBNODE node, int *is_selfsig ); int check_key_signature2( KBNODE root, KBNODE node, PKT_public_key *check_pk, int *is_selfsig, u32 *r_expiredate, int *r_expired ); diff --git a/g10/packet.h b/g10/packet.h index d873c6ba7..8d7819ea8 100644 --- a/g10/packet.h +++ b/g10/packet.h @@ -205,6 +205,7 @@ typedef struct { without the key to check it */ int is_valid; /* key (especially subkey) is valid */ int dont_cache; /* do not cache this */ + byte backsig; /* 0=none, 1=bad, 2=good */ u32 main_keyid[2]; /* keyid of the primary key */ u32 keyid[2]; /* calculated by keyid_from_pk() */ byte is_primary; @@ -352,6 +353,7 @@ typedef enum { SIGSUBPKT_SIGNERS_UID =28, /* signer's user id */ SIGSUBPKT_REVOC_REASON =29, /* reason for revocation */ SIGSUBPKT_FEATURES =30, /* feature flags */ + SIGSUBPKT_SIGNATURE =32, /* embedded signature */ SIGSUBPKT_FLAG_CRITICAL=128 @@ -397,6 +399,8 @@ int copy_some_packets( IOBUF inp, IOBUF out, off_t stopoff ); int skip_some_packets( IOBUF inp, unsigned n ); #endif +int parse_signature( IOBUF inp, int pkttype, unsigned long pktlen, + PKT_signature *sig ); const byte *enum_sig_subpkt ( const subpktarea_t *subpkts, sigsubpkttype_t reqtype, size_t *ret_n, int *start, int *critical ); diff --git a/g10/parse-packet.c b/g10/parse-packet.c index 439ae1f49..954a42aae 100644 --- a/g10/parse-packet.c +++ b/g10/parse-packet.c @@ -55,8 +55,6 @@ static int parse_symkeyenc( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet ); static int parse_pubkeyenc( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet ); -static int parse_signature( IOBUF inp, int pkttype, unsigned long pktlen, - PKT_signature *sig ); static int parse_onepass_sig( IOBUF inp, int pkttype, unsigned long pktlen, PKT_onepass_sig *ops ); static int parse_key( IOBUF inp, int pkttype, unsigned long pktlen, @@ -1201,7 +1199,7 @@ void parse_revkeys(PKT_signature *sig) } } -static int +int parse_signature( IOBUF inp, int pkttype, unsigned long pktlen, PKT_signature *sig ) { diff --git a/g10/sig-check.c b/g10/sig-check.c index 499a9cb14..a6707a1ed 100644 --- a/g10/sig-check.c +++ b/g10/sig-check.c @@ -75,11 +75,29 @@ signature_check2( PKT_signature *sig, MD_HANDLE digest, else if(!pk->is_valid && !pk->is_primary) rc=G10ERR_BAD_PUBKEY; /* you cannot have a good sig from an invalid subkey */ - else { + else + { if(r_expiredate) *r_expiredate = pk->expiredate; rc = do_check( pk, sig, digest, r_expired, r_revoked ); - } + + /* Check the backsig. This is a 0x19 signature from the + subkey on the primary key. The idea here is that it should + not be possible for someone to "steal" subkeys and claim + them as their own. The attacker couldn't actually use the + subkey, but they could try and claim ownership of any + signaures issued by it. */ + if(rc==0 && !pk->is_primary && pk->backsig<2) + { + if(pk->backsig==0) + log_info(_("WARNING: signing subkey %08lX is not" + " cross-certified\n"),(ulong)keyid_from_pk(pk,NULL)); + else + log_info(_("WARNING: signing subkey %08lX has an invalid" + " cross-certification\n"), + (ulong)keyid_from_pk(pk,NULL)); + } + } free_public_key( pk ); @@ -473,6 +491,38 @@ check_revocation_keys(PKT_public_key *pk,PKT_signature *sig) return rc; } +/* Backsigs (0x19) have the same format as binding sigs (0x18), but + this function is simpler than check_key_signature in a few ways. + For example, there is no support for expiring backsigs since it is + questionable what such a thing actually means. Note also that the + sig cache check here, unlike other sig caches in GnuPG, is not + persistent. */ +int +check_backsig(PKT_public_key *main_pk,PKT_public_key *sub_pk, + PKT_signature *backsig) +{ + MD_HANDLE md; + int rc; + + if(!opt.no_sig_cache && backsig->flags.checked) + { + if((rc=check_digest_algo(backsig->digest_algo))) + return rc; + + return backsig->flags.valid? 0 : G10ERR_BAD_SIGN; + } + + md=md_open(backsig->digest_algo,0); + hash_public_key(md,main_pk); + hash_public_key(md,sub_pk); + rc=do_check(sub_pk,backsig,md,NULL,NULL); + cache_sig_result(backsig,rc); + md_close(md); + + return rc; +} + + /**************** * check the signature pointed to by NODE. This is a key signature. * If the function detects a self-signature, it uses the PK from |