* gpgv.c (tty_fprintf): New stub.
authorWerner Koch <wk@gnupg.org>
Thu, 20 Jan 2005 17:21:40 +0000 (17:21 +0000)
committerWerner Koch <wk@gnupg.org>
Thu, 20 Jan 2005 17:21:40 +0000 (17:21 +0000)
* card-util.c (card_status): Create asecret key stub on the fly
and print more information about a card key.
* import.c (pub_to_sec_keyblock, auto_create_card_key_stub): New.
* getkey.c (get_seckeyblock_byfprint): New.
* keylist.c (print_card_key_info): New.

NEWS
doc/README.W32
g10/ChangeLog
g10/card-util.c
g10/getkey.c
g10/gpgv.c
g10/import.c
g10/keydb.h
g10/keylist.c
g10/main.h

diff --git a/NEWS b/NEWS
index ea26d3c..eb6ae73 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,15 +1,6 @@
 Noteworthy changes in version 1.4.1
 -------------------------------------------------
 
-    * [W32] The algorithm for the default home directory changed:
-      First we look at the environment variable GNUPGHOME, if this one
-      is not set, we check whether the registry entry
-      HKCU\Software\GNU\GnuPG:HomeDir has been set and if this fails
-      we use a GnuPG directory below the standard application data
-      directory (APPDATA) of the current user. Only in the case that
-      this directory cannot be determined, the old default of c:\gnupg
-      will be used.  The option --homedir still overrides all of them.
-
     * New --rfc2440-text option which controls how text is handled in
       signatures.  This is in response to some problems seen with
       certain PGP/MIME mail clients and GnuPG version 1.4.0.  More
@@ -27,6 +18,28 @@ Noteworthy changes in version 1.4.1
       option --with-libcurl.  Without this option, the existing HTTP
       code is used for HTTP, and HTTPS and FTP are not supported.
 
+    * When running a --card-status or --card-edit and a public key is
+      available, missing secret key stubs will be created on the fly.
+      Details of the key are listed too.
+
+    * [W32] The algorithm for the default home directory changed:
+      First we look at the environment variable GNUPGHOME, if this one
+      is not set, we check whether the registry entry
+      {HKCU,HKLM}\Software\GNU\GnuPG:HomeDir has been set. If this
+      fails we use a GnuPG directory below the standard application
+      data directory (APPDATA) of the current user. Only in the case
+      that this directory cannot be determined, the old default of
+      c:\gnupg will be used.  The option --homedir still overrides all
+      of them.
+
+    * [W32] The locale selection under Windows changed. You need to
+      enter the locale in the registry at HKCU\Software\GNU\GnuPG:Lang. 
+      For German you would use "de".  If it is not set, GnupG falls
+      back to HKLM.  The languages files "*.mo" are expected in a
+      directory named "gnupg.nls" below the installation directory;
+      that directory must be stored in the registry at the same key as
+      above with the name "Install Directory".
+
 
 Noteworthy changes in version 1.4.0 (2004-12-16)
 -------------------------------------------------
index a552205..cbee319 100644 (file)
@@ -30,18 +30,10 @@ Installation instructions:
 
 Internationalization support:
 -----------------------------
-  1. Decide where to store the translation files for your language.
-     Here we assume the directory "c:/gnu/locale/fr"
-
-  2. Set the directory with the translations into the Registry under
-     the key:
-       HKEY_CURRENT_USER -> Control Panel -> Mingw32 -> NLS
-     (you probably need to create the keys Mingw32 and NLS) using a string
-     entry with the name "MoDir".
-  3. Select which language to use and copy the currect translation file
-     under the name "gnupg.mo" into the directory set in step 2
-     (Example: "copy fr.mo c:\gnu\locale\fr\gnupg.mo")
-  4. Done.
+ 1
+
+Store the locale id (like "de") into the registry under the key
+HKEY_CURRENT_USER\Software\GNU\GnuPG with the name "Lang".
 
 
 How to build it from the source:
index 6f6bfc5..4be117f 100644 (file)
@@ -1,5 +1,13 @@
 2005-01-20  Werner Koch  <wk@g10code.com>
 
+       * gpgv.c (tty_fprintf): New stub.
+
+       * card-util.c (card_status): Create asecret key stub on the fly
+       and print more information about a card key.
+       * import.c (pub_to_sec_keyblock, auto_create_card_key_stub): New.
+       * getkey.c (get_seckeyblock_byfprint): New.
+       * keylist.c (print_card_key_info): New.
+
        * g10.c (i18n_init) [W32]: Pass registry key to gettext
        initialization.
        * gpgv.c (i18n_init) [W32]: Ditto.
index 8d38fb4..3b67400 100644 (file)
@@ -1,5 +1,5 @@
 /* card-util.c - Utility functions for the OpenPGP card.
- *     Copyright (C) 2003 Free Software Foundation, Inc.
+ *     Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -270,6 +270,7 @@ card_status (FILE *fp, char *serialno, size_t serialnobuflen)
   PKT_public_key *pk = xcalloc (1, sizeof *pk);
   int rc;
   unsigned int uval;
+  const unsigned char *thefpr;
 
   if (serialno && serialnobuflen)
     *serialno = 0;
@@ -425,8 +426,34 @@ card_status (FILE *fp, char *serialno, size_t serialnobuflen)
         tty_fprintf (fp, "      created ....: %s\n",
                      asctimestamp (info.fpr3time));
       tty_fprintf (fp, "General key info..: "); 
-      if (info.fpr1valid && !get_pubkey_byfprint (pk, info.fpr1, 20))
-        print_pubkey_info (fp, pk);
+
+      thefpr = (info.fpr1valid? info.fpr1 : info.fpr2valid? info.fpr2 : 
+                info.fpr3valid? info.fpr3 : NULL);
+      if ( thefpr && !get_pubkey_byfprint (pk, thefpr, 20))
+        {
+          KBNODE keyblock = NULL;
+
+          print_pubkey_info (fp, pk);
+
+          if ( !get_seckeyblock_byfprint (&keyblock, thefpr, 20) )
+            print_card_key_info (fp, keyblock);
+          else if ( !get_keyblock_byfprint (&keyblock, thefpr, 20) )
+            {
+              release_kbnode (keyblock);
+              keyblock = NULL;
+              
+              if (!auto_create_card_key_stub (info.serialno,
+                                              info.fpr1valid? info.fpr1:NULL,
+                                              info.fpr2valid? info.fpr2:NULL,
+                                              info.fpr3valid? info.fpr3:NULL))
+                {
+                  if ( !get_seckeyblock_byfprint (&keyblock, thefpr, 20) )
+                    print_card_key_info (fp, keyblock);
+                }
+            }
+
+          release_kbnode (keyblock);
+        }
       else
         tty_fprintf (fp, "[none]\n");
     }
@@ -1037,7 +1064,7 @@ generate_card_keys (const char *serialno)
 }
 
 
-/* This fucntion is used by the key edit menu to generate an arbitrary
+/* This function is used by the key edit menu to generate an arbitrary
    subkey. */
 int
 card_generate_subkey (KBNODE pub_keyblock, KBNODE sec_keyblock)
index 9cc0cbb..824c9bb 100644 (file)
@@ -1,6 +1,6 @@
 /* getkey.c -  Get a key from the database
  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003,
- *               2004 Free Software Foundation, Inc.
+ *               2004, 2005 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -1139,13 +1139,41 @@ get_seckey_byfprint( PKT_secret_key *sk,
         if (!rc && sk )
             sk_from_block ( &ctx, sk, kb );
         release_kbnode ( kb );
-       get_pubkey_end( &ctx );
+       get_seckey_end( &ctx );
     }
     else
        rc = G10ERR_GENERAL; /* Oops */
     return rc;
 }
 
+
+/* Search for a secret key with the given fingerprint and return the
+   complete keyblock which may have more than only this key. */
+int
+get_seckeyblock_byfprint (KBNODE *ret_keyblock, const byte *fprint,
+                          size_t fprint_len )
+{
+  int rc;
+  struct getkey_ctx_s ctx;
+  
+  if (fprint_len != 20 && fprint_len == 16)
+    return G10ERR_GENERAL; /* Oops */
+    
+  memset (&ctx, 0, sizeof ctx);
+  ctx.not_allocated = 1;
+  ctx.kr_handle = keydb_new (1);
+  ctx.nitems = 1;
+  ctx.items[0].mode = (fprint_len==16
+                       ? KEYDB_SEARCH_MODE_FPR16
+                       : KEYDB_SEARCH_MODE_FPR20);
+  memcpy (ctx.items[0].u.fpr, fprint, fprint_len);
+  rc = lookup (&ctx, ret_keyblock, 1);
+  get_seckey_end (&ctx);
+  
+  return rc;
+}
+
+
 \f
 /************************************************
  ************* Merging stuff ********************
index 020b548..3e545cc 100644 (file)
@@ -380,6 +380,7 @@ void rndlinux_constructor(void) {}
 /* Stubs to avoid linking to ../util/ttyio.c */
 int tty_batchmode( int onoff ) { return 0; }
 void tty_printf( const char *fmt, ... ) { }
+void tty_fprintf (FILE *fp, const char *fmt, ... ) { }
 void tty_print_string( const byte *p, size_t n ) { }
 void tty_print_utf8_string( const byte *p, size_t n ) {}
 void tty_print_utf8_string2( const byte *p, size_t n, size_t max_n ) {}
index d0c1c01..4119b01 100644 (file)
@@ -1,6 +1,6 @@
-/* import.c
+/* import.c - import a key into our key storage.
  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003,
- *               2004 Free Software Foundation, Inc.
+ *               2004, 2005 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -2118,3 +2118,232 @@ append_key( KBNODE keyblock, KBNODE node, int *n_sigs,
 
     return 0;
 }
+
+
+
+/* Walk a public keyblock and produce a secret keyblock out of it.
+   Instead of inserting the secret key parameters (which we don't
+   have), we insert a stub.  */
+static KBNODE
+pub_to_sec_keyblock (KBNODE pub_keyblock)
+{
+  KBNODE pubnode, secnode;
+  KBNODE sec_keyblock = NULL;
+  KBNODE walkctx = NULL;
+
+  while((pubnode = walk_kbnode (pub_keyblock,&walkctx,0)))
+    {
+      if (pubnode->pkt->pkttype == PKT_PUBLIC_KEY
+          || pubnode->pkt->pkttype == PKT_PUBLIC_SUBKEY)
+       {
+         /* Make a secret key.  We only need to convert enough to
+            write the keyblock out. */
+         PKT_public_key *pk = pubnode->pkt->pkt.public_key;
+         PACKET *pkt = m_alloc_clear (sizeof *pkt);
+         PKT_secret_key *sk = m_alloc_clear (sizeof *sk);
+          int i, n;
+          
+          if (pubnode->pkt->pkttype == PKT_PUBLIC_KEY)
+           pkt->pkttype = PKT_SECRET_KEY;
+         else
+           pkt->pkttype = PKT_SECRET_SUBKEY;
+          
+         pkt->pkt.secret_key = sk;
+
+          copy_public_parts_to_secret_key ( pk, sk );
+         sk->version     = pk->version;
+         sk->timestamp   = pk->timestamp;
+        
+          n = pubkey_get_npkey (pk->pubkey_algo);
+          if (!n)
+            n = 1; /* Unknown number of parameters, however the data
+                      is stored in the first mpi. */
+          for (i=0; i < n; i++ )
+            sk->skey[i] = mpi_copy (pk->pkey[i]);
+  
+          sk->is_protected = 1;
+          sk->protect.s2k.mode = 1001;
+  
+         secnode = new_kbnode (pkt);
+        }
+      else
+       {
+         secnode = clone_kbnode (pubnode);
+       }
+      
+      if(!sec_keyblock)
+       sec_keyblock = secnode;
+      else
+       add_kbnode (sec_keyblock, secnode);
+    }
+
+  return sec_keyblock;
+}
+
+
+/* Walk over the secret keyring SEC_KEYBLOCK and update any simple
+   stub keys with the serial number SNNUM of the card if one of the
+   fingerprints FPR1, FPR2 or FPR3 match.  Print a note if the key is
+   a duplicate (may happen in case of backed uped keys). 
+   
+   Returns: True if anything changed.
+*/
+static int
+update_sec_keyblock_with_cardinfo (KBNODE sec_keyblock, 
+                                   const unsigned char *fpr1,
+                                   const unsigned char *fpr2,
+                                   const unsigned char *fpr3,
+                                   const char *serialnostr)
+{
+  KBNODE node;
+  KBNODE walkctx = NULL;
+  PKT_secret_key *sk;
+  byte array[MAX_FINGERPRINT_LEN];
+  size_t n;
+  int result = 0;
+  const char *s;
+
+  while((node = walk_kbnode (sec_keyblock, &walkctx, 0)))
+    {
+      if (node->pkt->pkttype != PKT_SECRET_KEY
+          && node->pkt->pkttype != PKT_SECRET_SUBKEY)
+        continue;
+      sk = node->pkt->pkt.secret_key;
+      
+      fingerprint_from_sk (sk, array, &n);
+      if (n != 20)
+        continue; /* Can't be a card key.  */
+      if ( !((fpr1 && !memcmp (array, fpr1, 20))
+             || (fpr2 && !memcmp (array, fpr2, 20))
+             || (fpr3 && !memcmp (array, fpr3, 20))) )
+        continue;  /* No match.  */
+
+      if (sk->is_protected == 1 && sk->protect.s2k.mode == 1001)
+        {
+          /* Standard case: migrate that stub to a key stub.  */
+          sk->protect.s2k.mode = 1002;
+          s = serialnostr;
+          for (sk->protect.ivlen=0; sk->protect.ivlen < 16 && *s && s[1];
+               sk->protect.ivlen++, s += 2)
+            sk->protect.iv[sk->protect.ivlen] = xtoi_2 (s);
+          result = 1;
+        }
+      else if (sk->is_protected == 1 && sk->protect.s2k.mode == 1002)
+        {
+          s = serialnostr;
+          for (sk->protect.ivlen=0; sk->protect.ivlen < 16 && *s && s[1];
+               sk->protect.ivlen++, s += 2)
+            if (sk->protect.iv[sk->protect.ivlen] != xtoi_2 (s))
+              {
+                log_info (_("NOTE: a key's S/N does not "
+                            "match the card's one\n"));
+                break;
+              }
+        }
+      else
+        {
+          if (node->pkt->pkttype != PKT_SECRET_KEY)
+            log_info (_("NOTE: primary key is online and stored on card\n"));
+          else
+            log_info (_("NOTE: secondary key is online and stored on card\n"));
+        }
+    }
+
+  return result;
+}
+
+
+
+/* Check whether a secret key stub exists for the public key PK.  If
+   not create such a stub key and store it into the secring.  If it
+   exists, add appropriate subkey stubs and update the secring.
+   Return 0 if the key could be created. */
+int
+auto_create_card_key_stub ( const char *serialnostr, 
+                            const unsigned char *fpr1,
+                            const unsigned char *fpr2,
+                            const unsigned char *fpr3)
+{
+  KBNODE pub_keyblock;
+  KBNODE sec_keyblock;
+  KEYDB_HANDLE hd;
+  int rc;
+
+  /* We only want to do this for an OpenPGP card.  */
+  if (!serialnostr || strncmp (serialnostr, "D27600012401", 12) 
+      || strlen (serialnostr) != 32 )
+    return G10ERR_GENERAL;
+
+  /* First get the public keyring from any of the provided fingerprints. */
+  if ( (fpr1 && !get_keyblock_byfprint (&pub_keyblock, fpr1, 20))
+       || (fpr2 && !get_keyblock_byfprint (&pub_keyblock, fpr2, 20))
+       || (fpr3 && !get_keyblock_byfprint (&pub_keyblock, fpr3, 20)))
+    ;
+  else
+    return G10ERR_GENERAL;
+  hd = keydb_new (1);
+
+  /* Now check whether there is a secret keyring.  */
+  {
+    PKT_public_key *pk = pub_keyblock->pkt->pkt.public_key;
+    byte afp[MAX_FINGERPRINT_LEN];
+    size_t an;
+
+    fingerprint_from_pk (pk, afp, &an);
+    memset (afp, 0, MAX_FINGERPRINT_LEN);
+    rc = keydb_search_fpr (hd, afp);
+  }
+
+  if (!rc)
+    {
+      rc = keydb_get_keyblock (hd, &sec_keyblock);
+      if (rc)
+        {
+          log_error (_("error reading keyblock: %s\n"), g10_errstr(rc) );
+          rc = G10ERR_GENERAL;
+        }
+      else
+        {
+          merge_keys_and_selfsig (sec_keyblock);
+          
+          /* FIXME: We need to add new subkeys first.  */
+          if (update_sec_keyblock_with_cardinfo (sec_keyblock,
+                                                 fpr1, fpr2, fpr3,
+                                                 serialnostr))
+            {
+              rc = keydb_update_keyblock (hd, sec_keyblock );
+              if (rc)
+                log_error (_("error writing keyring `%s': %s\n"),
+                           keydb_get_resource_name (hd), g10_errstr(rc) );
+            }
+        }
+    }
+  else  /* A secret key does not exists - create it.  */
+    {
+      sec_keyblock = pub_to_sec_keyblock (pub_keyblock);
+      update_sec_keyblock_with_cardinfo (sec_keyblock,
+                                         fpr1, fpr2, fpr3,
+                                         serialnostr);
+
+      rc = keydb_locate_writable (hd, NULL);
+      if (rc)
+        {
+          log_error (_("no default secret keyring: %s\n"), g10_errstr (rc));
+          rc = G10ERR_GENERAL;
+        }
+      else
+        {
+          rc = keydb_insert_keyblock (hd, sec_keyblock );
+          if (rc)
+            log_error (_("error writing keyring `%s': %s\n"),
+                       keydb_get_resource_name (hd), g10_errstr(rc) );
+        }
+    }
+    
+  release_kbnode (sec_keyblock);
+  release_kbnode (pub_keyblock);
+  keydb_release (hd);
+  return rc;
+}
+
index eb5b2b5..7ec0384 100644 (file)
@@ -224,10 +224,15 @@ int seckey_available( u32 *keyid );
 int get_seckey_byname( PKT_secret_key *sk, const char *name, int unlock );
 int get_seckey_bynames( GETKEY_CTX *rx, PKT_secret_key *sk,
                        STRLIST names, KBNODE *ret_keyblock );
+int get_seckey_next (GETKEY_CTX ctx, PKT_secret_key *sk, KBNODE *ret_keyblock);
+void get_seckey_end( GETKEY_CTX ctx );
+
 int get_seckey_byfprint( PKT_secret_key *sk,
                         const byte *fprint, size_t fprint_len);
-int get_seckey_next( GETKEY_CTX ctx, PKT_secret_key *sk, KBNODE *ret_keyblock );
-void get_seckey_end( GETKEY_CTX ctx );
+int get_seckeyblock_byfprint (KBNODE *ret_keyblock, const byte *fprint,
+                              size_t fprint_len );
+
+
 int enum_secret_keys( void **context, PKT_secret_key *sk,
                      int with_subkeys, int with_spm );
 void merge_keys_and_selfsig( KBNODE keyblock );
index b712aa4..6425989 100644 (file)
@@ -1,6 +1,6 @@
 /* keylist.c
  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003,
- *               2004 Free Software Foundation, Inc.
+ *               2004, 2005 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -167,6 +167,60 @@ print_pubkey_info (FILE *fp, PKT_public_key *pk)
   m_free (p);
 }
 
+
+/* Print basic information of a secret key including the card serial
+   number information. */
+void
+print_card_key_info (FILE *fp, KBNODE keyblock)
+{
+  KBNODE node;
+  int i;
+
+  for (node = keyblock; node; node = node->next ) 
+    {
+      if (node->pkt->pkttype == PKT_SECRET_KEY
+          || (node->pkt->pkttype == PKT_SECRET_SUBKEY) )
+        {
+          PKT_secret_key *sk = node->pkt->pkt.secret_key;
+          
+          tty_fprintf (fp, "%s%c  %4u%c/%s  ",
+                      node->pkt->pkttype == PKT_SECRET_KEY? "sec":"ssb",
+                       (sk->protect.s2k.mode==1001)?'#':
+                       (sk->protect.s2k.mode==1002)?'>':' ',
+                      nbits_from_sk (sk),
+                      pubkey_letter (sk->pubkey_algo),
+                      keystr_from_sk(sk));
+          tty_fprintf (fp, _("created: %s"), datestr_from_sk (sk));
+          tty_fprintf (fp, "  ");
+          tty_fprintf (fp, _("expires: %s"), expirestr_from_sk (sk));
+          if (sk->is_protected && sk->protect.s2k.mode == 1002)
+            {
+              tty_fprintf (fp, "\n                      ");
+              tty_fprintf (fp, _("card-no: ")); 
+              if (sk->protect.ivlen == 16
+                  && !memcmp (sk->protect.iv, "\xD2\x76\x00\x01\x24\x01", 6))
+                { 
+                  /* This is an OpenPGP card. */
+                  for (i=8; i < 14; i++)
+                    {
+                      if (i == 10)
+                        tty_fprintf (fp, " ");
+                      tty_fprintf (fp, "%02X", sk->protect.iv[i]);
+                    }
+                }
+              else
+                { /* Something is wrong: Print all. */
+                  for (i=0; i < sk->protect.ivlen; i++)
+                    tty_fprintf (fp, "%02X", sk->protect.iv[i]);
+                }
+            }
+          tty_fprintf (fp, "\n");
+        }
+    }
+}
+
+
+
 /* Flags = 0x01 hashed 0x02 critical */
 static void
 status_one_subpacket(sigsubpkttype_t type,size_t len,int flags,const byte *buf)
@@ -1437,9 +1491,9 @@ print_fingerprint (PKT_public_key *pk, PKT_secret_key *sk, int mode )
     }
     else if (mode == 2) {
         fp = NULL; /* use tty */
-        /* Translators: this should fit into 24 bytes to that the fingerprint
-         * data is properly aligned with the user ID */
        if(primary)
+          /* TRANSLATORS: this should fit into 24 bytes to that the
+           * fingerprint data is properly aligned with the user ID */
          text = _(" Primary key fingerprint:");
        else
          text = _("      Subkey fingerprint:");
index bf8543f..a456c96 100644 (file)
@@ -211,6 +211,11 @@ void import_print_stats (void *hd);
 
 int collapse_uids( KBNODE *keyblock );
 
+int auto_create_card_key_stub ( const char *serialnostr, 
+                                const unsigned char *fpr1,
+                                const unsigned char *fpr2,
+                                const unsigned char *fpr3);
+
 /*-- export.c --*/
 int parse_export_options(char *str,unsigned int *options,int noisy);
 int export_pubkeys( STRLIST users, unsigned int options );
@@ -247,6 +252,7 @@ void dump_attribs(const PKT_user_id *uid,
 void set_attrib_fd(int fd);
 void print_seckey_info (PKT_secret_key *sk);
 void print_pubkey_info (FILE *fp, PKT_public_key *pk);
+void print_card_key_info (FILE *fp, KBNODE keyblock);
 
 /*-- verify.c --*/
 void print_file_status( int status, const char *name, int what );