* gpg.sgml: Document -K.
authorWerner Koch <wk@gnupg.org>
Mon, 20 Sep 2004 18:38:39 +0000 (18:38 +0000)
committerWerner Koch <wk@gnupg.org>
Mon, 20 Sep 2004 18:38:39 +0000 (18:38 +0000)
* g10.c: Make -K an alias for --list-secret-keys.

* keylist.c (print_card_serialno): New. Taken from gnupg 1.9.11.
(list_keyblock_print): Make use of it.
* keyedit.c (show_key_with_all_names): Print the card S/N.

* keyedit.c (keyedit_menu): New command ADDCARDKEY.
* card-util.c (card_generate_subkey): New.
* keygen.c (generate_card_subkeypair): New.
(gen_card_key): New arg IS_PRIMARY; changed all callers.

* cardglue.c (open_card): Use shutdown code if possible.
(check_card_serialno): Ditto.

12 files changed:
NEWS
TODO
doc/ChangeLog
doc/gpg.sgml
g10/ChangeLog
g10/card-util.c
g10/cardglue.c
g10/g10.c
g10/keyedit.c
g10/keygen.c
g10/keylist.c
g10/main.h

diff --git a/NEWS b/NEWS
index db07c24..da633db 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -7,7 +7,13 @@ Noteworthy changes in version 1.3.7
 
     * Support for the OpenPGP smartcard is now enabled by default.
       Use the option --disable-card-support to build without support
-      for smartcards.
+      for smartcards. 
+
+    * New command "addcardkey" in the key edit menu to add subkeys to
+      a smartcard.  The serial number of the card is show in secret
+      key listings.
+
+    * -K may now be used as an alias for --list-secret-keys.      
 
     * HTTP Basic authentication is now supported for all HKP and HTTP
       keyserver functions, either through a proxy or via direct
diff --git a/TODO b/TODO
index d51ce1b..4869262 100644 (file)
--- a/TODO
+++ b/TODO
 
   * Add the NEWSIG status.
 
+  * When generating a key onh the card we should try to also set the
+    display name or provide the display name as a default in the key
+    generation.  The problem however is that the display name must be
+    given with an indication of the surname and the usable characters
+    are also restricted.
+
 
 Things we won't do
 ------------------
index 47332c3..deb9a77 100644 (file)
@@ -1,3 +1,7 @@
+2004-09-20  Werner Koch  <wk@g10code.com>
+
+       * gpg.sgml: Document -K.
+
 2004-09-16  David Shaw  <dshaw@jabberwocky.com>
 
        * DETAILS: Document the 'spk' signature subpacket record.  Add
index f74bd43..f5bb069 100644 (file)
@@ -252,7 +252,7 @@ scripts and other programs.
 
 
 <varlistentry>
-<term>--list-secret-keys &OptParmNames;</term>
+<term>-K, --list-secret-keys &OptParmNames;</term>
 <listitem><para>
 List all keys from the secret keyrings, or just the ones given on the
 command line.  A '#' after the letters 'sec' means that the secret key
@@ -410,6 +410,11 @@ Revoke a user id.</para></listitem></varlistentry>
     <listitem><para>
 Add a subkey to this key.</para></listitem></varlistentry>
     <varlistentry>
+    <term>addcardkey</term>
+    <listitem><para>
+Generate a key on a card and add it 
+to this key.</para></listitem></varlistentry>
+    <varlistentry>
     <term>delkey</term>
     <listitem><para>
 Remove a subkey.</para></listitem></varlistentry>
index b487124..0b88373 100644 (file)
@@ -1,5 +1,16 @@
 2004-09-20  Werner Koch  <wk@g10code.com>
 
+       * g10.c: Make -K an alias for --list-secret-keys.
+
+       * keylist.c (print_card_serialno): New. Taken from gnupg 1.9.11.
+       (list_keyblock_print): Make use of it.
+       * keyedit.c (show_key_with_all_names): Print the card S/N.
+
+       * keyedit.c (keyedit_menu): New command ADDCARDKEY.
+       * card-util.c (card_generate_subkey): New.
+       * keygen.c (generate_card_subkeypair): New.
+       (gen_card_key): New arg IS_PRIMARY; changed all callers.
+
        * cardglue.c (open_card): Use shutdown code if possible.
        (check_card_serialno): Ditto.
 
index 597faba..194bd83 100644 (file)
@@ -828,6 +828,120 @@ generate_card_keys (const char *serialno)
     }
 }
 
+
+/* This fucntion is used by the key edit menu to generate an arbitrary
+   subkey. */
+int
+card_generate_subkey (KBNODE pub_keyblock, KBNODE sec_keyblock)
+{
+  struct agent_card_info_s info;
+  int okay = 0;
+  int forced_chv1 = 0;
+  int rc;
+  int keyno;
+
+  memset (&info, 0, sizeof info);
+  rc = agent_scd_getattr ("SERIALNO", &info);
+  if (rc || !info.serialno || strncmp (info.serialno, "D27600012401", 12) 
+      || strlen (info.serialno) != 32 )
+    {
+      log_error (_("cannot generate key: %s\n"),
+                 rc ? gpg_strerror (rc) : _("not an OpenPGP card"));
+      goto leave;
+    }
+  rc = agent_scd_getattr ("KEY-FPR", &info);
+  if (!rc)
+    rc = agent_scd_getattr ("CHV-STATUS", &info);
+  if (rc)
+    {
+      log_error ("error getting current key info: %s\n", gpg_strerror (rc));
+      goto leave;
+    }
+  
+  tty_fprintf (NULL, "Signature key ....:");
+  print_sha1_fpr (NULL, info.fpr1valid? info.fpr1:NULL);
+  tty_fprintf (NULL, "Encryption key....:");
+  print_sha1_fpr (NULL, info.fpr2valid? info.fpr2:NULL);
+  tty_fprintf (NULL, "Authentication key:");
+  print_sha1_fpr (NULL, info.fpr3valid? info.fpr3:NULL);
+  tty_printf ("\n");
+
+  tty_printf (_("Please select the type of key to generate:\n"));
+
+  tty_printf (_("   (1) Signature key\n"));
+  tty_printf (_("   (2) Encryption key\n"));
+  tty_printf (_("   (3) Authentication key\n"));
+
+  for (;;) 
+    {
+      char *answer = cpr_get ("cardedit.genkeys.subkeytype",
+                              _("Your selection? "));
+      cpr_kill_prompt();
+      if (*answer == CONTROL_D)
+        {
+          xfree (answer);
+          goto leave;
+        }
+      keyno = *answer? atoi(answer): 0;
+      xfree(answer);
+      if (keyno >= 1 && keyno <= 3)
+        break; /* Okay. */
+      tty_printf(_("Invalid selection.\n"));
+    }
+
+  if ((keyno == 1 && info.fpr1valid)
+      || (keyno == 2 && info.fpr2valid)
+      || (keyno == 3 && info.fpr3valid))
+    {
+      tty_printf ("\n");
+      log_info ("WARNING: such a key has already been stored on the card!\n");
+      tty_printf ("\n");
+      if ( !cpr_get_answer_is_yes( "cardedit.genkeys.replace_key",
+                                  _("Replace existing key? ")))
+        goto leave;
+    }
+
+  forced_chv1 = !info.chv1_cached;
+  if (forced_chv1)
+    { /* Switch of the forced mode so that during key generation we
+         don't get bothered with PIN queries for each
+         self-signature. */
+      rc = agent_scd_setattr ("CHV-STATUS-1", "\x01", 1);
+      if (rc)
+        {
+          log_error ("error clearing forced signature PIN flag: %s\n",
+                     gpg_strerror (rc));
+          forced_chv1 = 0;
+          goto leave;
+        }
+    }
+
+  /* Check the PIN now, so that we won't get asked later for each
+     binding signature. */
+  rc = agent_scd_checkpin (info.serialno);
+  if (rc)
+    log_error ("error checking the PIN: %s\n", gpg_strerror (rc));
+  else
+    okay = generate_card_subkeypair (pub_keyblock, sec_keyblock,
+                                     keyno, info.serialno);
+
+ leave:
+  agent_release_card_info (&info);
+  if (forced_chv1)
+    { /* Switch back to forced state. */
+      rc = agent_scd_setattr ("CHV-STATUS-1", "", 1);
+      if (rc)
+        {
+          log_error ("error setting forced signature PIN flag: %s\n",
+                     gpg_strerror (rc));
+          return okay;
+        }
+    }
+  return okay;
+}
+
+
+
 /* Menu to edit all user changeable values on an OpenPGP card.  Only
    Key creation is not handled here. */
 void
index 5faa41b..cff025c 100644 (file)
@@ -812,8 +812,8 @@ agent_scd_change_pin (int chvno)
                               pin_cb, NULL);
 }
 
-/* Perform a CHECKPIN operation.  SERIALNO should be the seriial
-   number of the card - optioanlly followed by the fingerprint;
+/* Perform a CHECKPIN operation.  SERIALNO should be the serial
+   number of the card - optionally followed by the fingerprint;
    however the fingerprint is ignored here. */
 int
 agent_scd_checkpin (const char *serialnobuf)
index 3fd6c9a..66692f7 100644 (file)
--- a/g10/g10.c
+++ b/g10/g10.c
@@ -80,6 +80,7 @@ enum cmd_and_opt_values
     oVerbose     = 'v',
     oCompress    = 'z',
     oSetNotation  = 'N',
+    aListSecretKeys = 'K',
     oBatch       = 500,
     oMaxOutput,
     oSigNotation,
@@ -114,7 +115,6 @@ enum cmd_and_opt_values
     aVerifyFiles,
     aListKeys,
     aListSigs,
-    aListSecretKeys,
     aSendKeys,
     aRecvKeys,
     aSearchKeys,
index 288d8ba..014f3a8 100644 (file)
@@ -1191,6 +1191,7 @@ keyedit_menu( const char *username, STRLIST locusr,
           cmdTOGGLE, cmdSELKEY, cmdPASSWD, cmdTRUST, cmdPREF, cmdEXPIRE,
           cmdENABLEKEY, cmdDISABLEKEY, cmdSHOWPREF, cmdSETPREF, cmdUPDPREF,
           cmdPREFKS, cmdINVCMD, cmdSHOWPHOTO, cmdUPDTRUST, cmdCHKTRUST,
+           cmdADDCARDKEY,
           cmdNOP };
     static struct { const char *name;
                    enum cmdids id;
@@ -1223,6 +1224,7 @@ keyedit_menu( const char *username, STRLIST locusr,
        /* delphoto is really deluid in disguise */
        { N_("delphoto"), cmdDELUID    , 0,1, NULL },
        { N_("addkey")  , cmdADDKEY    , 1,1, N_("add a secondary key") },
+       { N_("addcardkey"), cmdADDCARDKEY , 1,1, N_("add a key to a smartcard") },
        { N_("delkey")  , cmdDELKEY    , 0,1, N_("delete a secondary key") },
        { N_("addrevoker"),cmdADDREVOKER,1,1, N_("add a revocation key") },
        { N_("delsig")  , cmdDELSIG    , 0,1, N_("delete signatures") },
@@ -1530,6 +1532,16 @@ keyedit_menu( const char *username, STRLIST locusr,
            }
            break;
 
+#ifdef ENABLE_CARD_SUPPORT
+         case cmdADDCARDKEY:
+           if (card_generate_subkey (keyblock, sec_keyblock)) {
+               redisplay = 1;
+               sec_modified = modified = 1;
+               merge_keys_and_selfsig( sec_keyblock );
+               merge_keys_and_selfsig( keyblock );
+           }
+           break;
+#endif /* ENABLE_CARD_SUPPORT */
 
          case cmdDELKEY: {
                int n1;
@@ -2210,6 +2222,27 @@ show_key_with_all_names( KBNODE keyblock, int only_marked, int with_revoker,
            tty_printf("  ");
            tty_printf(_("expires: %s"),expirestr_from_sk(sk));
            tty_printf("\n");
+            if (sk->is_protected && sk->protect.s2k.mode == 1002)
+              {
+               tty_printf("                     ");
+                tty_printf(_("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_printf (" ");
+                        tty_printf ("%02X", sk->protect.iv[i]);
+                      }
+                  }
+                else
+                  { /* Something is wrong: Print all. */
+                    for (i=0; i < sk->protect.ivlen; i++)
+                      tty_printf ("%02X", sk->protect.iv[i]);
+                  }
+                tty_printf ("\n");
+              }
          }
        else if( with_subkeys && node->pkt->pkttype == PKT_SIGNATURE
                 && node->pkt->pkt.signature->sig_class == 0x28       ) {
@@ -2555,7 +2588,7 @@ menu_adduid( KBNODE pub_keyblock, KBNODE sec_keyblock, int photo)
 
 
 /****************
- * Remove all selceted userids from the keyrings
+ * Remove all selected userids from the keyrings
  */
 static void
 menu_deluid( KBNODE pub_keyblock, KBNODE sec_keyblock )
index 6bf1c0c..44cfc00 100644 (file)
@@ -117,7 +117,8 @@ static int mdc_available,ks_modify;
 static void do_generate_keypair( struct para_data_s *para,
                                 struct output_control_s *outctrl, int card );
 static int  write_keyblock( IOBUF out, KBNODE node );
-static int gen_card_key (int algo, int keyno, KBNODE pub_root, KBNODE sec_root,
+static int gen_card_key (int algo, int keyno, int is_primary,
+                         KBNODE pub_root, KBNODE sec_root,
                          u32 expireval, struct para_data_s *para);
 
 static void
@@ -2481,7 +2482,7 @@ do_generate_keypair( struct para_data_s *para,
       }
     else
       {
-        rc = gen_card_key (PUBKEY_ALGO_RSA, 1, pub_root, sec_root,
+        rc = gen_card_key (PUBKEY_ALGO_RSA, 1, 1, pub_root, sec_root,
                            get_parameter_u32 (para, pKEYEXPIRE), para);
         if (!rc)
           {
@@ -2523,7 +2524,7 @@ do_generate_keypair( struct para_data_s *para,
           }
         else
           {
-            rc = gen_card_key (PUBKEY_ALGO_RSA, 2, pub_root, sec_root,
+            rc = gen_card_key (PUBKEY_ALGO_RSA, 2, 0, pub_root, sec_root,
                                get_parameter_u32 (para, pKEYEXPIRE), para);
           }
 
@@ -2538,7 +2539,7 @@ do_generate_keypair( struct para_data_s *para,
 
     if (card && get_parameter (para, pAUTHKEYTYPE))
       {
-        rc = gen_card_key (PUBKEY_ALGO_RSA, 3, pub_root, sec_root,
+        rc = gen_card_key (PUBKEY_ALGO_RSA, 3, 0, pub_root, sec_root,
                            get_parameter_u32 (para, pKEYEXPIRE), para);
         
         if (!rc)
@@ -2768,6 +2769,120 @@ generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock )
     return okay;
 }
 
+
+#ifdef ENABLE_CARD_SUPPORT
+/* Generate a subkey on a card. */
+int
+generate_card_subkeypair (KBNODE pub_keyblock, KBNODE sec_keyblock,
+                          int keyno, const char *serialno)
+{
+  int okay=0, rc=0;
+  KBNODE node;
+  PKT_secret_key *pri_sk = NULL;
+  int algo;
+  unsigned int use;
+  u32 expire;
+  char *passphrase = NULL;
+  u32 cur_time;
+  struct para_data_s *para = NULL;
+
+  assert (keyno >= 1 && keyno <= 3);
+
+  para = xcalloc (1, sizeof *para + strlen (serialno) );
+  para->key = pSERIALNO;
+  strcpy (para->u.value, serialno);
+
+  /* Break out the primary secret key */
+  node = find_kbnode( sec_keyblock, PKT_SECRET_KEY );
+  if(!node)
+    {
+      log_error("Oops; secret key not found anymore!\n");
+      goto leave;
+    }
+
+  /* Make a copy of the sk to keep the protected one in the keyblock */
+  pri_sk = copy_secret_key (NULL, node->pkt->pkt.secret_key);
+
+  cur_time = make_timestamp();
+  if (pri_sk->timestamp > cur_time)
+    {
+      ulong d = pri_sk->timestamp - cur_time;
+      log_info (d==1 ? _("key has been created %lu second "
+                         "in future (time warp or clock problem)\n")
+                     : _("key has been created %lu seconds "
+                         "in future (time warp or clock problem)\n"), d );
+       if (!opt.ignore_time_conflict)
+          {
+           rc = G10ERR_TIME_CONFLICT;
+           goto leave;
+          }
+    }
+
+  if (pri_sk->version < 4)
+    {
+      log_info (_("NOTE: creating subkeys for v3 keys "
+                  "is not OpenPGP compliant\n"));
+      goto leave;
+    }
+
+  /* Unprotect to get the passphrase. */
+  switch( is_secret_key_protected (pri_sk) )
+    {
+    case -1:
+      rc = G10ERR_PUBKEY_ALGO;
+      break;
+    case 0:
+      tty_printf("This key is not protected.\n");
+      break;
+    default:
+      tty_printf("Key is protected.\n");
+      rc = check_secret_key( pri_sk, 0 );
+      if (!rc)
+        passphrase = get_last_passphrase();
+      break;
+    }
+  if (rc)
+    goto leave;
+
+  algo = PUBKEY_ALGO_RSA;
+  expire = ask_expire_interval (0);
+  if (keyno == 1)
+    use = PUBKEY_USAGE_SIG;
+  else if (keyno == 2)
+    use = PUBKEY_USAGE_ENC;
+  else
+    use = PUBKEY_USAGE_AUTH;
+  if (!cpr_enabled() && !cpr_get_answer_is_yes("keygen.cardsub.okay",
+                                               _("Really create? ") ) )
+    goto leave;
+
+  if (passphrase)
+    set_next_passphrase (passphrase);
+  rc = gen_card_key (algo, keyno, 0, pub_keyblock, sec_keyblock, expire, para);
+  if (!rc)
+    rc = write_keybinding (pub_keyblock, pub_keyblock, pri_sk, NULL, use);
+  if (!rc)
+    rc = write_keybinding (sec_keyblock, pub_keyblock, pri_sk, NULL, use);
+  if (!rc)
+    {
+      okay = 1;
+      write_status_text (STATUS_KEY_CREATED, "S");
+    }
+
+ leave:
+  if (rc)
+    log_error (_("Key generation failed: %s\n"), g10_errstr(rc) );
+  m_free (passphrase);
+  /* Release the copy of the (now unprotected) secret keys. */
+  if (pri_sk)
+    free_secret_key (pri_sk);
+  set_next_passphrase( NULL );
+  release_parameter_list (para);
+  return okay;
+}
+#endif /* !ENABLE_CARD_SUPPORT */
+
+
 /****************
  * Write a keyblock to an output stream
  */
@@ -2787,7 +2902,8 @@ write_keyblock( IOBUF out, KBNODE node )
 
 
 static int
-gen_card_key (int algo, int keyno, KBNODE pub_root, KBNODE sec_root,
+gen_card_key (int algo, int keyno, int is_primary,
+              KBNODE pub_root, KBNODE sec_root,
               u32 expireval, struct para_data_s *para)
 {
 #ifdef ENABLE_CARD_SUPPORT
@@ -2848,12 +2964,12 @@ gen_card_key (int algo, int keyno, KBNODE pub_root, KBNODE sec_root,
     }
 
   pkt = xcalloc (1,sizeof *pkt);
-  pkt->pkttype = keyno == 1 ? PKT_PUBLIC_KEY : PKT_PUBLIC_SUBKEY;
+  pkt->pkttype = is_primary ? PKT_PUBLIC_KEY : PKT_PUBLIC_SUBKEY;
   pkt->pkt.public_key = pk;
   add_kbnode(pub_root, new_kbnode( pkt ));
 
   pkt = xcalloc (1,sizeof *pkt);
-  pkt->pkttype = keyno == 1 ? PKT_SECRET_KEY : PKT_SECRET_SUBKEY;
+  pkt->pkttype = is_primary ? PKT_SECRET_KEY : PKT_SECRET_SUBKEY;
   pkt->pkt.secret_key = sk;
   add_kbnode(sec_root, new_kbnode( pkt ));
 
index ce66a13..cb38026 100644 (file)
@@ -41,6 +41,7 @@
 
 static void list_all(int);
 static void list_one( STRLIST names, int secret);
+static void print_card_serialno (PKT_secret_key *sk);
 
 struct sig_stats
 {
@@ -752,6 +753,7 @@ list_keyblock_print ( KBNODE keyblock, int secret, int fpr, void *opaque )
            if( !any ) {
                if( fpr )
                    print_fingerprint( pk, sk, 0 );
+                print_card_serialno (sk);
                if( opt.with_key_data )
                    print_key_data( pk );
                any = 1;
@@ -805,6 +807,7 @@ list_keyblock_print ( KBNODE keyblock, int secret, int fpr, void *opaque )
                putchar('\n');
                if( fpr )
                  print_fingerprint( pk, sk, 0 ); /* of the main key */
+                print_card_serialno (sk);
                any = 1;
              }
 
@@ -817,7 +820,10 @@ list_keyblock_print ( KBNODE keyblock, int secret, int fpr, void *opaque )
              printf(_(" [expires: %s]"), expirestr_from_sk( sk2 ) );
            putchar('\n');
            if( fpr > 1 )
-             print_fingerprint( NULL, sk2, 0 );
+              {
+                print_fingerprint( NULL, sk2, 0 );
+                print_card_serialno (sk2);
+              }
          }
        else if( opt.list_sigs
                 && node->pkt->pkttype == PKT_SIGNATURE
@@ -861,6 +867,7 @@ list_keyblock_print ( KBNODE keyblock, int secret, int fpr, void *opaque )
                    putchar('\n');
                if( fpr )
                    print_fingerprint( pk, sk, 0 );
+                print_card_serialno (sk);
                any=1;
            }
 
@@ -1475,6 +1482,41 @@ print_fingerprint (PKT_public_key *pk, PKT_secret_key *sk, int mode )
         tty_printf ("\n");
 }
 
+/* Print the serial number of an OpenPGP card if available. */
+static void
+print_card_serialno (PKT_secret_key *sk)
+{
+  int i;
+
+  if (!sk)
+    return;
+  if (!sk->is_protected || sk->protect.s2k.mode != 1002) 
+    return; /* Not a card. */
+  if (opt.with_colons)
+    return; /* Handled elesewhere. */
+
+  fputs (_("      Card serial no. ="), stdout);
+  putchar (' ');
+  if (sk->protect.ivlen == 16
+      && !memcmp (sk->protect.iv, "\xD2\x76\x00\x01\x24\x01", 6) )
+    { /* This is an OpenPGP card. Just print the relevant part. */
+      for (i=8; i < 14; i++)
+        {
+          if (i == 10)
+            putchar (' ');
+          printf ("%02X", sk->protect.iv[i]);
+        }
+    }
+  else
+    { /* Something is wrong: Print all. */
+      for (i=0; i < sk->protect.ivlen; i++)
+        printf ("%02X", sk->protect.iv[i]);
+    }
+  putchar ('\n');
+}
+
+
+
 void set_attrib_fd(int fd)
 {
   static int last_fd=-1;
index d86931e..c84a059 100644 (file)
@@ -162,6 +162,10 @@ int keygen_upd_std_prefs( PKT_signature *sig, void *opaque );
 int keygen_add_keyserver_url(PKT_signature *sig, void *opaque);
 int keygen_add_revkey(PKT_signature *sig, void *opaque);
 int generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock );
+#ifdef ENABLE_CARD_SUPPORT
+int generate_card_subkeypair (KBNODE pub_keyblock, KBNODE sec_keyblock,
+                              int keyno, const char *serialno);
+#endif
 
 /*-- openfile.c --*/
 int overwrite_filep( const char *fname );
@@ -257,6 +261,7 @@ void unblock_all_signals(void);
 void change_pin (int no);
 void card_status (FILE *fp, char *serialno, size_t serialnobuflen);
 void card_edit (STRLIST commands);
+int  card_generate_subkey (KBNODE pub_keyblock, KBNODE sec_keyblock);
 #endif
 
 #endif /*G10_MAIN_H*/