* keygen.c (make_backsig): If DO_BACKSIGS is not defined, do not create
authorDavid Shaw <dshaw@jabberwocky.com>
Fri, 23 Apr 2004 03:25:58 +0000 (03:25 +0000)
committerDavid Shaw <dshaw@jabberwocky.com>
Fri, 23 Apr 2004 03:25:58 +0000 (03:25 +0000)
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.

g10/ChangeLog
g10/getkey.c
g10/keygen.c
g10/main.h
g10/packet.h
g10/parse-packet.c
g10/sig-check.c

index 485d2c1..ebdbfb2 100644 (file)
@@ -1,3 +1,19 @@
+2004-04-22  David Shaw  <dshaw@jabberwocky.com>
+
+       * 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  <dshaw@jabberwocky.com>
 
        * parse-packet.c (dump_sig_subpkt, parse_one_sig_subpkt,
index 381b2f5..d24253a 100644 (file)
@@ -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
+}
 
 
 /* 
index 5d319c7..a5c749f 100644 (file)
@@ -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);
 
index 500d45d..0bb8a2d 100644 (file)
@@ -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,
index 558a603..0449c7d 100644 (file)
@@ -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 );
index 4faf27f..56a7177 100644 (file)
@@ -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 )
 {
index eb36641..09dc5a2 100644 (file)
@@ -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