diff --git a/g10/ChangeLog b/g10/ChangeLog index 485d2c19d..ebdbfb2f8 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,3 +1,19 @@ +2004-04-22 David Shaw + + * 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 * parse-packet.c (dump_sig_subpkt, parse_one_sig_subpkt, diff --git a/g10/getkey.c b/g10/getkey.c index 381b2f5ab..d24253ada 100644 --- a/g10/getkey.c +++ b/g10/getkey.c @@ -1934,8 +1934,51 @@ merge_selfsigs_subkey( KBNODE keyblock, KBNODE subnode ) return; subpk->is_valid = 1; -} +#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 5d319c73b..a5c749f3e 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -630,10 +630,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 500d45d4f..0bb8a2df9 100644 --- a/g10/main.h +++ b/g10/main.h @@ -135,6 +135,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, PKT_public_key *ret_pk, int *is_selfsig, diff --git a/g10/packet.h b/g10/packet.h index 558a6030a..0449c7d5f 100644 --- a/g10/packet.h +++ b/g10/packet.h @@ -212,6 +212,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; @@ -364,6 +365,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 @@ -409,6 +411,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 4faf27f18..56a717725 100644 --- a/g10/parse-packet.c +++ b/g10/parse-packet.c @@ -56,8 +56,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, @@ -1223,7 +1221,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 eb3664134..09dc5a2fc 100644 --- a/g10/sig-check.c +++ b/g10/sig-check.c @@ -80,11 +80,29 @@ signature_check2( PKT_signature *sig, MD_HANDLE digest, u32 *r_expiredate, 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, ret_pk ); - } + + /* 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 %s is not" + " cross-certified\n"),keystr_from_pk(pk)); + else + log_info(_("WARNING: signing subkey %s has an invalid" + " cross-certification\n"),keystr_from_pk(pk)); + } + } free_public_key( pk ); @@ -387,6 +405,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,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