* cardglue.c (pin_cb): Detect whether an admin or regular PIN is
authorWerner Koch <wk@gnupg.org>
Wed, 8 Oct 2003 15:21:20 +0000 (15:21 +0000)
committerWerner Koch <wk@gnupg.org>
Wed, 8 Oct 2003 15:21:20 +0000 (15:21 +0000)
requested.
(genkey_status_cb): New.
(agent_scd_genkey): Implemented.

* keygen.c (generate_keypair): New arg CARD_SERIALNO and prepare
parameters for on card key generation. Changed all callers.
(do_generate_keypair): Add new arg card and merged casrd specific
changes from 1.9.
(proc_parameter_file): New arg card, apss it down to
do_generate_keypair and changed all callers.
(gen_card_key): New.

* g10.c: Include cardclue.h.
(main): s/app_set_default_reader_port/card_set_reader_port/.
* cardglue.c (card_set_reader_port): New to address include file
issues.

g10/ChangeLog
g10/Makefile.am
g10/app-openpgp.c
g10/card-util.c
g10/cardglue.c
g10/cardglue.h
g10/g10.c
g10/gpgv.c
g10/keygen.c
g10/main.h
g10/sign.c

index 0306e26..23f5db5 100644 (file)
@@ -1,3 +1,23 @@
+2003-10-08  Werner Koch  <wk@gnupg.org>
+
+       * cardglue.c (pin_cb): Detect whether an admin or regular PIN is
+       requested.
+       (genkey_status_cb): New.
+       (agent_scd_genkey): Implemented.
+
+       * keygen.c (generate_keypair): New arg CARD_SERIALNO and prepare
+       parameters for on card key generation. Changed all callers.
+       (do_generate_keypair): Add new arg card and merged casrd specific
+       changes from 1.9.
+       (proc_parameter_file): New arg card, apss it down to
+       do_generate_keypair and changed all callers.
+       (gen_card_key): New.
+
+       * g10.c: Include cardclue.h.
+       (main): s/app_set_default_reader_port/card_set_reader_port/.
+       * cardglue.c (card_set_reader_port): New to address include file
+       issues.
+
 2003-10-02  Werner Koch  <wk@gnupg.org>
 
        * cardglue.c (learn_status_cb): Release values before assignment
index e289a82..b64c448 100644 (file)
@@ -142,12 +142,16 @@ install-data-local:
 
 # Helper to update some source files.
 update-source-from-gnupg-2:
-       test -d ../../gnupg-1.9/scd
-       @for i in $(card_support_source_scd); do \
-           cp ../../gnupg-1.9/scd/$$i $$i; echo $$i; \
-       done
-       @for i in $(card_support_source_g10); do \
-           cp ../../gnupg-1.9/g10/$$i $$i; echo $$i; \
-       done
-       @echo "Please remember to update the ChangeLog accordingly!"
+       @set -e; \
+        if test -d ../../gnupg-1.9/scd; then dir="../../gnupg-1.9"; \
+        elif test -d ../../gnupg/scd; then dir="../../gnupg"; \
+        else exit 1; \
+        fi; \
+        for i in $(card_support_source_scd); do \
+           cp $$dir/scd/$$i $$i; echo $$i; \
+        done ;\
+        for i in $(card_support_source_g10); do \
+           cp $$dir/g10/$$i $$i; echo $$i; \
+        done ; \
+        echo "Please remember to update the ChangeLog accordingly!"
 
index e8fe19e..174d2e9 100644 (file)
@@ -425,6 +425,8 @@ do_getattr (APP app, CTRL ctrl, const char *name)
     { "CA-FPR",       0x00C6, 3 },
     { "CHV-STATUS",   0x00C4, 1 },
     { "SIG-COUNTER",  0x0093, 2 },
+    { "SERIALNO",     0x004F, -1 },
+    { "AID",          0x004F },
     { NULL, 0 }
   };
   int idx, i;
@@ -437,6 +439,29 @@ do_getattr (APP app, CTRL ctrl, const char *name)
   if (!table[idx].name)
     return gpg_error (GPG_ERR_INV_NAME); 
   
+  if (table[idx].special == -1)
+    {
+      /* The serial number is very special.  We could have used the
+         AID DO to retrieve it, but we have it already in the app
+         context and the stanmp argument is required anyway which we
+         can't by other means. The AID DO is available anyway but not
+         hex formatted. */
+      char *serial;
+      time_t stamp;
+      char tmp[50];
+
+      if (!app_get_serial_and_stamp (app, &serial, &stamp))
+        {
+          sprintf (tmp, "%lu", (unsigned long)stamp);
+          send_status_info (ctrl, "SERIALNO",
+                            serial, strlen (serial),
+                            tmp, strlen (tmp),
+                            NULL, 0);
+          xfree (serial);
+        }
+      return 0;
+    }
+
   relptr = get_one_do (app->slot, table[idx].tag, &value, &valuelen);
   if (relptr)
     {
index 70518e9..6699277 100644 (file)
@@ -241,6 +241,17 @@ print_isoname (FILE *fp, const char *text, const char *tag, const char *name)
     tty_fprintf (fp, "\n");
 }
 
+/* Return true if the SHA1 fingerprint FPR consists only of zeroes. */
+static int
+fpr_is_zero (const char *fpr)
+{
+  int i;
+
+  for (i=0; i < 20 && !fpr[i]; i++)
+    ;
+  return (i == 20);
+}
+
 
 /* Print all available information about the current card. */
 void
@@ -569,6 +580,76 @@ toggle_forcesig (void)
 }
 
 
+static void
+generate_card_keys (void)
+{
+  struct agent_card_info_s info;
+  int rc;
+  int forced_chv1;
+
+  memset (&info, 0, sizeof info);
+  rc = agent_scd_getattr ("KEY-FPR", &info);
+  if (!rc)
+    rc = agent_scd_getattr ("SERIALNO", &info);
+  if (!rc)
+    rc = agent_scd_getattr ("CHV-STATUS", &info);
+  if (!rc)
+    rc = agent_scd_getattr ("DISP-NAME", &info);
+  if (rc)
+    {
+      log_error ("error getting current key info: %s\n", gpg_strerror (rc));
+      return;
+    }
+  if ( (info.fpr1valid && !fpr_is_zero (info.fpr1))
+       || (info.fpr2valid && !fpr_is_zero (info.fpr2))
+       || (info.fpr3valid && !fpr_is_zero (info.fpr3)))
+    {
+      tty_printf ("\n");
+      log_info ("NOTE: keys are already stored on the card!\n");
+      tty_printf ("\n");
+      if ( !cpr_get_answer_is_yes( "cardedit.genkeys.replace_keys",
+                                  _("Replace existing keys? ")))
+        {
+          agent_release_card_info (&info);
+          return;
+        }
+    }
+  else if (!info.disp_name || !*info.disp_name)
+    {
+      tty_printf ("\n");
+      tty_printf (_("Please note that the factory settings of the PINs are\n"
+                    "   PIN = \"%s\"     Admin PIN = \"%s\"\n"
+                    "You should change them using the command --change-pin\n"),
+                  "123456", "12345678");
+      tty_printf ("\n");
+    }
+
+  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));
+          return;
+        }
+    }
+  generate_keypair (NULL, info.serialno);
+  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;
+        }
+    }
+}
 
 /* Menu to edit all user changeable values on an OpenPGP card.  Only
    Key creation is not handled here. */
@@ -579,7 +660,7 @@ card_edit (STRLIST commands)
     cmdNOP = 0,
     cmdQUIT, cmdHELP, cmdLIST, cmdDEBUG,
     cmdNAME, cmdURL, cmdLOGIN, cmdLANG, cmdSEX,
-    cmdFORCESIG,
+    cmdFORCESIG, cmdGENERATE,
     cmdINVCMD
   };
 
@@ -601,6 +682,7 @@ card_edit (STRLIST commands)
     { N_("lang")  , cmdLANG  , N_("change the language preferences") },
     { N_("sex")   , cmdSEX   , N_("change card holder's sex") },
     { N_("forcesig"), cmdFORCESIG, N_("toggle the signature force PIN flag") },
+    { N_("generate"), cmdGENERATE, N_("generate new keys") },
     { NULL, cmdINVCMD } 
   };
  
@@ -725,6 +807,10 @@ card_edit (STRLIST commands)
           toggle_forcesig ();
           break;
 
+        case cmdGENERATE:
+          generate_card_keys ();
+          break;
+
         case cmdQUIT:
           goto leave;
 
index 802bae5..fd7cf8b 100644 (file)
@@ -184,6 +184,13 @@ app_set_default_reader_port (const char *portstr)
 }
 
 
+void
+card_set_reader_port (const char *portstr)
+{
+  app_set_default_reader_port (portstr);
+}
+
+
 /* Retrieve the serial number and the time of the last update of the
    card.  The serial number is returned as a malloced string (hex
    encoded) in SERIAL and the time of update is returned in STAMP.  If
@@ -493,7 +500,10 @@ pin_cb (void *opaque, const char *info, char **retstr)
   *retstr = NULL;
   log_debug ("asking for PIN '%s'\n", info);
 
-  value = ask_passphrase (info, "Enter PIN: ", &canceled);
+  value = ask_passphrase (info, 
+                          info && strstr (info, "dmin")?
+                           _("Enter Admin PIN: ") : _("Enter PIN: "),
+                          &canceled);
   if (!value && canceled)
     return -1;
   else if (!value)
@@ -519,19 +529,86 @@ agent_scd_setattr (const char *name,
   return app->fnc.setattr (app, name, pin_cb, NULL, value, valuelen);
 }
 
+
+static int
+genkey_status_cb (void *opaque, const char *line)
+{
+  struct agent_card_genkey_s *parm = opaque;
+  const char *keyword = line;
+  int keywordlen;
+
+  log_debug ("got status line `%s'\n", line);
+  for (keywordlen=0; *line && !spacep (line); line++, keywordlen++)
+    ;
+  while (spacep (line))
+    line++;
+
+  if (keywordlen == 7 && !memcmp (keyword, "KEY-FPR", keywordlen))
+    {
+      parm->fprvalid = unhexify_fpr (line, parm->fpr);
+    }
+  if (keywordlen == 8 && !memcmp (keyword, "KEY-DATA", keywordlen))
+    {
+      MPI a;
+      const char *name = line;
+      char *buf;
+
+      while (!spacep (line))
+        line++;
+      while (spacep (line))
+        line++;
+
+      buf = xmalloc ( 2 + strlen (line) + 1);
+      strcpy (stpcpy (buf, "0x"), line);
+      a = mpi_alloc (300);
+      if( mpi_fromstr (a, buf) )
+        log_error ("error parsing received key data\n");
+      else if (*name == 'n' && spacep (name+1))
+        parm->n = a;
+      else if (*name == 'e' && spacep (name+1))
+        parm->e = a;
+      else
+        {
+          log_info ("unknown parameter name in received key data\n");
+          mpi_free (a);
+        }
+      xfree (buf);
+    }
+  else if (keywordlen == 14 && !memcmp (keyword,"KEY-CREATED-AT", keywordlen))
+    {
+      parm->created_at = (u32)strtoul (line, NULL, 10);
+    }
+
+  return 0;
+}
+
 /* Send a GENKEY command to the SCdaemon. */
 int 
 agent_scd_genkey (struct agent_card_genkey_s *info, int keyno, int force)
 {
+  APP app;
+  char keynostr[20];
+  struct ctrl_ctx_s ctrl;
 
-  return gpg_error (GPG_ERR_CARD);
+  app = current_app? current_app : open_card ();
+  if (!app)
+    return gpg_error (GPG_ERR_CARD);
+
+  memset (info, 0, sizeof *info);
+  sprintf (keynostr, "%d", keyno);
+  ctrl.status_cb = genkey_status_cb;
+  ctrl.status_cb_arg = info;
+
+  return app->fnc.genkey (app, &ctrl, keynostr,
+                           force? 1:0,
+                           pin_cb, NULL);
 }
 
 /* Send a PKSIGN command to the SCdaemon. */
 int 
 agent_scd_pksign (const char *serialno, int hashalgo,
                   const unsigned char *indata, size_t indatalen,
-                  char **r_buf, size_t *r_buflen)
+                  unsigned char **r_buf, size_t *r_buflen)
 {
   APP app;
 
index 42a22b5..273b993 100644 (file)
@@ -67,6 +67,7 @@ typedef struct app_ctx_s *APP;
 typedef struct ctrl_ctx_s *CTRL;
 
 
+#define GPG_ERR_GENERAL           G10ERR_GENERAL
 #define GPG_ERR_BAD_PIN           G10ERR_BAD_PASS
 #define GPG_ERR_CARD              G10ERR_GENERAL
 #define GPG_ERR_EEXIST            G10ERR_FILE_EXISTS
@@ -107,6 +108,8 @@ typedef int gpg_err_code_t;
 #define gnupg_get_time() make_timestamp ()
 
 
+void card_set_reader_port (const char *portstr);
+
 char *serialno_and_fpr_from_sk (const unsigned char *sn, size_t snlen,
                                 PKT_secret_key *sk);
 void send_status_info (CTRL ctrl, const char *keyword, ...);
@@ -143,7 +146,7 @@ int agent_scd_genkey (struct agent_card_genkey_s *info, int keyno, int force);
 /* Send a PKSIGN command to the SCdaemon. */
 int agent_scd_pksign (const char *keyid, int hashalgo,
                       const unsigned char *indata, size_t indatalen,
-                      char **r_buf, size_t *r_buflen);
+                      unsigned char **r_buf, size_t *r_buflen);
 
 /* Send a PKDECRYPT command to the SCdaemon. */
 int agent_scd_pkdecrypt (const char *serialno,
index 70b9bd3..d925c36 100644 (file)
--- a/g10/g10.c
+++ b/g10/g10.c
@@ -51,6 +51,7 @@
 #include "g10defs.h"
 #include "keyserver-internal.h"
 #include "exec.h"
+#include "cardglue.h"
 
 enum cmd_and_opt_values
   {
@@ -1425,7 +1426,7 @@ main( int argc, char **argv )
           case aCardEdit: set_cmd (&cmd, aCardEdit); break;
           case aChangePIN: set_cmd (&cmd, aChangePIN); break;
           case oReaderPort:
-            app_set_default_reader_port (pargs.r.ret_str);
+            card_set_reader_port (pargs.r.ret_str);
             break;
           case octapiDriver: opt.ctapi_driver = pargs.r.ret_str; break;
           case opcscDriver: opt.pcsc_driver = pargs.r.ret_str; break;
@@ -2603,12 +2604,12 @@ main( int argc, char **argv )
        if( opt.batch ) {
            if( argc > 1 )
                wrong_args("--gen-key [parameterfile]");
-           generate_keypair( argc? *argv : NULL );
+           generate_keypair( argc? *argv : NULL, NULL );
        }
        else {
            if( argc )
                wrong_args("--gen-key");
-           generate_keypair(NULL);
+           generate_keypair(NULL, NULL);
        }
        break;
 
index 0701ead..c01263f 100644 (file)
@@ -385,9 +385,9 @@ 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_print_string( byte *p, size_t n ) { }
-void tty_print_utf8_string( byte *p, size_t n ) {}
-void tty_print_utf8_string2( byte *p, size_t n, size_t max_n ) {}
+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 ) {}
 char *tty_get( const char *prompt ) { return NULL;}
 char *tty_get_hidden( const char *prompt ) {return NULL; }
 void tty_kill_prompt(void) {}
index bcfdcfa..a3cf671 100644 (file)
@@ -36,6 +36,7 @@
 #include "trustdb.h"
 #include "status.h"
 #include "i18n.h"
+#include "cardglue.h"
 
 #define MAX_PREFS 30 
 
@@ -46,6 +47,7 @@ enum para_name {
   pSUBKEYTYPE,
   pSUBKEYLENGTH,
   pSUBKEYUSAGE,
+  pAUTHKEYTYPE,
   pNAMEREAL,
   pNAMEEMAIL,
   pNAMECOMMENT,
@@ -57,7 +59,8 @@ enum para_name {
   pSUBKEYEXPIRE, /* in n seconds */
   pPASSPHRASE,
   pPASSPHRASE_DEK,
-  pPASSPHRASE_S2K
+  pPASSPHRASE_S2K,
+  pSERIALNO
 };
 
 struct para_data_s {
@@ -109,9 +112,12 @@ static int nzip_prefs;
 static int mdc_available,ks_modify;
 
 static void do_generate_keypair( struct para_data_s *para,
-                                struct output_control_s *outctrl );
+                                struct output_control_s *outctrl, int card );
 static int  write_keyblock( IOBUF out, KBNODE node );
-
+#ifdef ENABLE_CARD_SUPPORT
+static int gen_card_key (int algo, int keyno, KBNODE pub_root, KBNODE sec_root,
+                         u32 expireval, struct para_data_s *para);
+#endif
 
 static void
 write_uid( KBNODE root, const char *s )
@@ -1762,7 +1768,7 @@ get_parameter_revkey( struct para_data_s *para, enum para_name key )
 
 static int
 proc_parameter_file( struct para_data_s *para, const char *fname,
-                     struct output_control_s *outctrl )
+                     struct output_control_s *outctrl, int card )
 {
     struct para_data_s *r;
     const char *s1, *s2, *s3;
@@ -1874,7 +1880,7 @@ proc_parameter_file( struct para_data_s *para, const char *fname,
        return -1;
     }
 
-    do_generate_keypair( para, outctrl );
+    do_generate_keypair( para, outctrl, card );
     return 0;
 }
 
@@ -1958,7 +1964,7 @@ read_parameter_file( const char *fname )
                outctrl.dryrun = 1;
            else if( !ascii_strcasecmp( keyword, "%commit" ) ) {
                outctrl.lnr = lnr;
-               proc_parameter_file( para, fname, &outctrl );
+               proc_parameter_file( para, fname, &outctrl, 0 );
                release_parameter_list( para );
                para = NULL;
            }
@@ -2018,7 +2024,7 @@ read_parameter_file( const char *fname )
 
        if( keywords[i].key == pKEYTYPE && para ) {
            outctrl.lnr = lnr;
-           proc_parameter_file( para, fname, &outctrl );
+           proc_parameter_file( para, fname, &outctrl, 0 );
            release_parameter_list( para );
            para = NULL;
        }
@@ -2046,7 +2052,7 @@ read_parameter_file( const char *fname )
     }
     else if( para ) {
        outctrl.lnr = lnr;
-       proc_parameter_file( para, fname, &outctrl );
+       proc_parameter_file( para, fname, &outctrl, 0 );
     }
 
     if( outctrl.use_files ) { /* close open streams */
@@ -2064,91 +2070,146 @@ read_parameter_file( const char *fname )
 }
 
 
-/****************
- * Generate a keypair
- * (fname is only used in batch mode)
+/*
+ * Generate a keypair (fname is only used in batch mode) If
+ * CARD_SERIALNO is not NULL the fucntion will create the keys on an
+ * OpenPGP Card.
  */
 void
-generate_keypair( const char *fname )
+generate_keypair( const char *fname, const char *card_serialno )
 {
-    unsigned int nbits;
-    char *uid = NULL;
-    DEK *dek;
-    STRING2KEY *s2k;
-    int algo;
-    unsigned int use;
-    int both = 0;
-    u32 expire;
-    struct para_data_s *para = NULL;
-    struct para_data_s *r;
-    struct output_control_s outctrl;
-
-    memset( &outctrl, 0, sizeof( outctrl ) );
-
-    if( opt.batch ) {
-       read_parameter_file( fname );
-       return;
-    }
-
-    algo = ask_algo( 0, &use );
-    if( !algo ) { /* default: DSA with ElG subkey of the specified size */
-       both = 1;
-       r = m_alloc_clear( sizeof *r + 20 );
-       r->key = pKEYTYPE;
-       sprintf( r->u.value, "%d", PUBKEY_ALGO_DSA );
-       r->next = para;
-       para = r;
-       tty_printf(_("DSA keypair will have 1024 bits.\n"));
-       r = m_alloc_clear( sizeof *r + 20 );
-       r->key = pKEYLENGTH;
-       strcpy( r->u.value, "1024" );
-       r->next = para;
-       para = r;
-       r = m_alloc_clear( sizeof *r + 20 );
-       r->key = pKEYUSAGE;
-       strcpy( r->u.value, "sign" );
-       r->next = para;
-       para = r;
-
-       algo = PUBKEY_ALGO_ELGAMAL_E;
-       r = m_alloc_clear( sizeof *r + 20 );
-       r->key = pSUBKEYTYPE;
-       sprintf( r->u.value, "%d", algo );
-       r->next = para;
-       para = r;
-       r = m_alloc_clear( sizeof *r + 20 );
-       r->key = pSUBKEYUSAGE;
-       strcpy( r->u.value, "encrypt" );
-       r->next = para;
-       para = r;
-    }
-    else {
-       r = m_alloc_clear( sizeof *r + 20 );
-       r->key = pKEYTYPE;
-       sprintf( r->u.value, "%d", algo );
-       r->next = para;
-       para = r;
-
-        if (use) {
-            r = m_alloc_clear( sizeof *r + 20 );
-            r->key = pKEYUSAGE;
-            sprintf( r->u.value, "%s%s",
-                     (use & PUBKEY_USAGE_SIG)? "sign ":"",
-                     (use & PUBKEY_USAGE_ENC)? "encrypt ":"" );
-            r->next = para;
-            para = r;
-        }
-
+  unsigned int nbits;
+  char *uid = NULL;
+  DEK *dek;
+  STRING2KEY *s2k;
+  int algo;
+  unsigned int use;
+  int both = 0;
+  u32 expire;
+  struct para_data_s *para = NULL;
+  struct para_data_s *r;
+  struct output_control_s outctrl;
+  
+  memset( &outctrl, 0, sizeof( outctrl ) );
+  
+  if (opt.batch && card_serialno)
+    {
+      /* We don't yet support unattended key generation. */
+      log_error (_("sorry, can't do this in batch mode\n"));
+      return;
     }
-
-    nbits = ask_keysize( algo );
-    r = m_alloc_clear( sizeof *r + 20 );
-    r->key = both? pSUBKEYLENGTH : pKEYLENGTH;
-    sprintf( r->u.value, "%u", nbits);
-    r->next = para;
-    para = r;
-
-    expire = ask_expire_interval(0);
+  
+   if (opt.batch)
+     {
+       read_parameter_file( fname );
+       return;
+     }
+
+   if (card_serialno)
+     {
+#ifdef ENABLE_CARD_SUPPORT
+       r = xcalloc (1, sizeof *r + strlen (card_serialno) );
+       r->key = pSERIALNO;
+       strcpy( r->u.value, card_serialno);
+       r->next = para;
+       para = r;
+       
+       algo = PUBKEY_ALGO_RSA;
+       
+       r = xcalloc (1, sizeof *r + 20 );
+       r->key = pKEYTYPE;
+       sprintf( r->u.value, "%d", algo );
+       r->next = para;
+       para = r;
+       r = xcalloc (1, sizeof *r + 20 );
+       r->key = pKEYUSAGE;
+       strcpy (r->u.value, "sign");
+       r->next = para;
+       para = r;
+       
+       r = xcalloc (1, sizeof *r + 20 );
+       r->key = pSUBKEYTYPE;
+       sprintf( r->u.value, "%d", algo );
+       r->next = para;
+       para = r;
+       r = xcalloc (1, sizeof *r + 20 );
+       r->key = pSUBKEYUSAGE;
+       strcpy (r->u.value, "encrypt");
+       r->next = para;
+       para = r;
+       
+       r = xcalloc (1, sizeof *r + 20 );
+       r->key = pAUTHKEYTYPE;
+       sprintf( r->u.value, "%d", algo );
+       r->next = para;
+       para = r;
+#endif /*ENABLE_CARD_SUPPORT*/
+     }
+   else
+     {
+       algo = ask_algo( 0, &use );
+       if( !algo )
+         { /* default: DSA with ElG subkey of the specified size */
+           both = 1;
+           r = m_alloc_clear( sizeof *r + 20 );
+           r->key = pKEYTYPE;
+           sprintf( r->u.value, "%d", PUBKEY_ALGO_DSA );
+           r->next = para;
+           para = r;
+           tty_printf(_("DSA keypair will have 1024 bits.\n"));
+           r = m_alloc_clear( sizeof *r + 20 );
+           r->key = pKEYLENGTH;
+           strcpy( r->u.value, "1024" );
+           r->next = para;
+           para = r;
+           r = m_alloc_clear( sizeof *r + 20 );
+           r->key = pKEYUSAGE;
+           strcpy( r->u.value, "sign" );
+           r->next = para;
+           para = r;
+           
+           algo = PUBKEY_ALGO_ELGAMAL_E;
+           r = m_alloc_clear( sizeof *r + 20 );
+           r->key = pSUBKEYTYPE;
+           sprintf( r->u.value, "%d", algo );
+           r->next = para;
+           para = r;
+           r = m_alloc_clear( sizeof *r + 20 );
+           r->key = pSUBKEYUSAGE;
+           strcpy( r->u.value, "encrypt" );
+           r->next = para;
+           para = r;
+         }
+       else 
+         {
+           r = m_alloc_clear( sizeof *r + 20 );
+           r->key = pKEYTYPE;
+           sprintf( r->u.value, "%d", algo );
+           r->next = para;
+           para = r;
+           
+           if (use)
+             {
+               r = m_alloc_clear( sizeof *r + 20 );
+               r->key = pKEYUSAGE;
+               sprintf( r->u.value, "%s%s",
+                        (use & PUBKEY_USAGE_SIG)? "sign ":"",
+                        (use & PUBKEY_USAGE_ENC)? "encrypt ":"" );
+               r->next = para;
+               para = r;
+             }
+           
+         }
+       
+       nbits = ask_keysize( algo );
+       r = m_alloc_clear( sizeof *r + 20 );
+       r->key = both? pSUBKEYLENGTH : pKEYLENGTH;
+       sprintf( r->u.value, "%u", nbits);
+       r->next = para;
+       para = r;
+     }
+
+   expire = ask_expire_interval(0);
     r = m_alloc_clear( sizeof *r + 20 );
     r->key = pKEYEXPIRE;
     r->u.expire = expire;
@@ -2161,19 +2222,21 @@ generate_keypair( const char *fname )
     para = r;
 
     uid = ask_user_id(0);
-    if( !uid ) {
+    if( !uid ) 
+      {
        log_error(_("Key generation canceled.\n"));
        release_parameter_list( para );
        return;
-    }
+      }
     r = m_alloc_clear( sizeof *r + strlen(uid) );
     r->key = pUSERID;
     strcpy( r->u.value, uid );
     r->next = para;
     para = r;
-
-    dek = do_ask_passphrase( &s2k );
-    if( dek ) {
+    
+    dek = card_serialno? NULL : do_ask_passphrase( &s2k );
+    if( dek )
+      {
        r = m_alloc_clear( sizeof *r );
        r->key = pPASSPHRASE_DEK;
        r->u.dek = dek;
@@ -2184,9 +2247,9 @@ generate_keypair( const char *fname )
        r->u.s2k = s2k;
        r->next = para;
        para = r;
-    }
-
-    proc_parameter_file( para, "[internal]", &outctrl );
+      }
+    
+    proc_parameter_file( para, "[internal]", &outctrl, !!card_serialno);
     release_parameter_list( para );
 }
 
@@ -2211,7 +2274,7 @@ print_status_key_created (int letter, PKT_public_key *pk)
 
 static void
 do_generate_keypair( struct para_data_s *para,
-                    struct output_control_s *outctrl )
+                    struct output_control_s *outctrl, int card )
 {
     KBNODE pub_root = NULL;
     KBNODE sec_root = NULL;
@@ -2270,7 +2333,11 @@ do_generate_keypair( struct para_data_s *para,
        assert( outctrl->sec.stream );
         if( opt.verbose ) {
             log_info(_("writing public key to `%s'\n"), outctrl->pub.fname );
-            log_info(_("writing secret key to `%s'\n"), outctrl->sec.fname );
+            if (card)
+              log_info (_("writing secret key stub to `%s'\n"),
+                        outctrl->sec.fname);
+            else
+              log_info(_("writing secret key to `%s'\n"), outctrl->sec.fname );
         }
     }
 
@@ -2283,13 +2350,26 @@ do_generate_keypair( struct para_data_s *para,
     pub_root = make_comment_node("#"); delete_kbnode(pub_root);
     sec_root = make_comment_node("#"); delete_kbnode(sec_root);
 
-    rc = do_create( get_parameter_algo( para, pKEYTYPE ),
-                   get_parameter_uint( para, pKEYLENGTH ),
-                   pub_root, sec_root,
-                   get_parameter_dek( para, pPASSPHRASE_DEK ),
-                   get_parameter_s2k( para, pPASSPHRASE_S2K ),
-                   &sk,
-                   get_parameter_u32( para, pKEYEXPIRE ) );
+    if (!card)
+      {
+        rc = do_create( get_parameter_algo( para, pKEYTYPE ),
+                        get_parameter_uint( para, pKEYLENGTH ),
+                        pub_root, sec_root,
+                        get_parameter_dek( para, pPASSPHRASE_DEK ),
+                        get_parameter_s2k( para, pPASSPHRASE_S2K ),
+                        &sk,
+                        get_parameter_u32( para, pKEYEXPIRE ) );
+      }
+    else
+      {
+        rc = gen_card_key (PUBKEY_ALGO_RSA, 1, pub_root, sec_root,
+                           get_parameter_u32 (para, pKEYEXPIRE), para);
+        if (!rc)
+          {
+            sk = sec_root->next->pkt->pkt.secret_key;
+            assert (sk);
+          }
+      }
 
     if(!rc && (revkey=get_parameter_revkey(para,pREVOKER)))
       {
@@ -2310,24 +2390,44 @@ do_generate_keypair( struct para_data_s *para,
                                get_parameter_uint (para, pKEYUSAGE));
     }
 
-    if( get_parameter( para, pSUBKEYTYPE ) ) {
-       rc = do_create( get_parameter_algo( para, pSUBKEYTYPE ),
-                       get_parameter_uint( para, pSUBKEYLENGTH ),
-                       pub_root, sec_root,
-                       get_parameter_dek( para, pPASSPHRASE_DEK ),
-                       get_parameter_s2k( para, pPASSPHRASE_S2K ),
-                       NULL,
-                       get_parameter_u32( para, pSUBKEYEXPIRE ) );
-       if( !rc )
-           rc = write_keybinding(pub_root, pub_root, sk,
-                                         get_parameter_uint (para, pSUBKEYUSAGE));
-       if( !rc )
-           rc = write_keybinding(sec_root, pub_root, sk,
-                                         get_parameter_uint (para, pSUBKEYUSAGE));
+    if( get_parameter( para, pSUBKEYTYPE ) )
+      {
+        if (!card)
+          {
+            rc = do_create( get_parameter_algo( para, pSUBKEYTYPE ),
+                            get_parameter_uint( para, pSUBKEYLENGTH ),
+                            pub_root, sec_root,
+                            get_parameter_dek( para, pPASSPHRASE_DEK ),
+                            get_parameter_s2k( para, pPASSPHRASE_S2K ),
+                            NULL,
+                            get_parameter_u32( para, pSUBKEYEXPIRE ) );
+          }
+        else
+          {
+            rc = gen_card_key (PUBKEY_ALGO_RSA, 2, pub_root, sec_root,
+                               get_parameter_u32 (para, pKEYEXPIRE), para);
+          }
+
+        if( !rc )
+          rc = write_keybinding(pub_root, pub_root, sk,
+                                get_parameter_uint (para, pSUBKEYUSAGE));
+        if( !rc )
+          rc = write_keybinding(sec_root, pub_root, sk,
+                                get_parameter_uint (para, pSUBKEYUSAGE));
         did_sub = 1;
-    }
-
+      }
 
+    if (card && get_parameter (para, pAUTHKEYTYPE))
+      {
+        rc = gen_card_key (PUBKEY_ALGO_RSA, 3, pub_root, sec_root,
+                           get_parameter_u32 (para, pKEYEXPIRE), para);
+        
+        if (!rc)
+          rc = write_keybinding (pub_root, pub_root, sk, PUBKEY_USAGE_AUTH);
+        if (!rc)
+          rc = write_keybinding (sec_root, pub_root, sk, PUBKEY_USAGE_AUTH);
+      }
+    
     if( !rc && outctrl->use_files ) { /* direct write to specified files */
        rc = write_keyblock( outctrl->pub.stream, pub_root );
        if( rc )
@@ -2359,8 +2459,12 @@ do_generate_keypair( struct para_data_s *para,
         if (!rc && opt.verbose) {
             log_info(_("writing public key to `%s'\n"),
                      keydb_get_resource_name (pub_hd));
-            log_info(_("writing secret key to `%s'\n"),
-                     keydb_get_resource_name (sec_hd));
+            if (card)
+              log_info (_("writing secret key stub to `%s'\n"),
+                        keydb_get_resource_name (sec_hd));
+            else
+              log_info(_("writing secret key to `%s'\n"),
+                       keydb_get_resource_name (sec_hd));
         }
 
         if (!rc) {
@@ -2426,8 +2530,8 @@ do_generate_keypair( struct para_data_s *para,
     }
     release_kbnode( pub_root );
     release_kbnode( sec_root );
-    if( sk ) /* the unprotected  secret key */
-       free_secret_key(sk);
+    if( sk && !card) /* the unprotected  secret key unless we have a */
+      free_secret_key(sk); /* shallow copy in card mode. */
 }
 
 
@@ -2554,3 +2658,81 @@ write_keyblock( IOBUF out, KBNODE node )
     }
     return 0;
 }
+
+
+static int
+gen_card_key (int algo, int keyno, KBNODE pub_root, KBNODE sec_root,
+              u32 expireval, struct para_data_s *para)
+{
+#ifdef ENABLE_CARD_SUPPORT
+  int rc;
+  const char *s;
+  struct agent_card_genkey_s info;
+  PACKET *pkt;
+  PKT_secret_key *sk;
+  PKT_public_key *pk;
+
+  assert (algo == PUBKEY_ALGO_RSA);
+
+  rc = agent_scd_genkey (&info, keyno, 1);
+/*    if (gpg_err_code (rc) == GPG_ERR_EEXIST) */
+/*      { */
+/*        tty_printf ("\n"); */
+/*        log_error ("WARNING: key does already exists!\n"); */
+/*        tty_printf ("\n"); */
+/*        if ( cpr_get_answer_is_yes( "keygen.card.replace_key", */
+/*                                    _("Replace existing key? "))) */
+/*          rc = agent_scd_genkey (&info, keyno, 1); */
+/*      } */
+
+  if (rc)
+    {
+      log_error ("key generation failed: %s\n", gpg_strerror (rc));
+      return rc;
+    }
+  if ( !info.n || !info.e )
+    {
+      log_error ("communication error with SCD\n");
+      mpi_free (info.n);
+      mpi_free (info.e);
+      return gpg_error (GPG_ERR_GENERAL);
+    }
+  
+
+  pk = xcalloc (1, sizeof *pk );
+  sk = xcalloc (1, sizeof *sk );
+  sk->timestamp = pk->timestamp = info.created_at;
+  sk->version = pk->version = 4;
+  if (expireval)
+      sk->expiredate = pk->expiredate = pk->timestamp + expireval;
+  sk->pubkey_algo = pk->pubkey_algo = algo;
+  pk->pkey[0] = info.n;
+  pk->pkey[1] = info.e; 
+  sk->skey[0] = mpi_copy (pk->pkey[0]);
+  sk->skey[1] = mpi_copy (pk->pkey[1]);
+  sk->skey[2] = mpi_set_opaque (NULL, xstrdup ("dummydata"), 10);
+  sk->is_protected = 1;
+  sk->protect.s2k.mode = 1002;
+  s = get_parameter_value (para, pSERIALNO);
+  if (s)
+    {
+      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);
+    }
+
+  pkt = xcalloc (1,sizeof *pkt);
+  pkt->pkttype = keyno == 1 ? 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->pkt.secret_key = sk;
+  add_kbnode(sec_root, new_kbnode( pkt ));
+
+  return 0;
+#else
+  return -1;
+#endif /*!ENABLE_CARD_SUPPORT*/
+}
index ca37b62..6bfa3cd 100644 (file)
@@ -143,7 +143,7 @@ void show_basic_key_info (KBNODE keyblock);
 /*-- keygen.c --*/
 u32 ask_expire_interval(int object);
 u32 ask_expiredate(void);
-void generate_keypair( const char *fname );
+void generate_keypair( const char *fname, const char *card_serialno );
 int keygen_set_std_prefs (const char *string,int personal);
 PKT_user_id *keygen_get_std_prefs (void);
 int keygen_add_key_expire( PKT_signature *sig, void *opaque );
@@ -241,4 +241,11 @@ void pause_on_sigusr( int which );
 void block_all_signals(void);
 void unblock_all_signals(void);
 
+#ifdef ENABLE_CARD_SUPPORT
+/*-- card-util.c --*/
+void change_pin (int no);
+void card_status (FILE *fp);
+void card_edit (STRLIST commands);
+#endif
+
 #endif /*G10_MAIN_H*/
index b7fd7bb..9826c2a 100644 (file)
@@ -309,7 +309,7 @@ do_sign( PKT_secret_key *sk, PKT_signature *sig,
 #ifdef ENABLE_CARD_SUPPORT
     if (sk->is_protected && sk->protect.s2k.mode == 1002) 
       { 
-        char *rbuf;
+        unsigned char *rbuf;
         size_t rbuflen;
         char *snbuf;