Alow batch ode for gpgsm --gen-key.
authorWerner Koch <wk@gnupg.org>
Wed, 1 Jul 2009 18:30:33 +0000 (18:30 +0000)
committerWerner Koch <wk@gnupg.org>
Wed, 1 Jul 2009 18:30:33 +0000 (18:30 +0000)
Allow CSR generation using an existing key with gpgsm.

NEWS
common/ChangeLog
common/sexputil.c
common/util.h
doc/gpgsm.texi
sm/ChangeLog
sm/certreqgen-ui.c
sm/gpgsm.c
tools/ChangeLog
tools/ccidmon.c

diff --git a/NEWS b/NEWS
index 306e5ff..e41e8b9 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -3,7 +3,9 @@ Noteworthy changes in version 2.0.13
 
  This is a BETA version!
 
- *
+ * Minor bnug fixes
+
+ * gpgsm --gen-key now implements a --batch mode.
 
 
 Noteworthy changes in version 2.0.12 (2009-06-17)
index bd4be4f..40faa54 100644 (file)
@@ -1,3 +1,7 @@
+2009-07-01  Werner Koch  <wk@g10code.com>
+
+       * sexputil.c (get_pk_algo_from_canon_sexp): New.
+
 2009-06-29  Werner Koch  <wk@g10code.com>
 
        * estream.c (BUFFER_ROUND_TO_BLOCK): Remove unused macro.
index 7360881..1e59187 100644 (file)
@@ -292,14 +292,8 @@ make_canon_sexp_from_rsa_pk (const void *m_arg, size_t mlen,
 }
 
 
-/* Return the so called "keygrip" which is the SHA-1 hash of the
-   public key parameters expressed in a way depended on the algorithm.
-
-   KEY is expected to be an canonical encoded S-expression with a
-   public or private key. KEYLEN is the length of that buffer.
-
-   GRIP must be at least 20 bytes long.  On success 0 is returned, on
-   error an error code. */
+/* Return the so parameters of a public RSA key expressed as an
+   canonical encoded S-expression.  */
 gpg_error_t
 get_rsa_pk_from_canon_sexp (const unsigned char *keydata, size_t keydatalen,
                             unsigned char const **r_n, size_t *r_nlen,
@@ -389,3 +383,47 @@ get_rsa_pk_from_canon_sexp (const unsigned char *keydata, size_t keydatalen,
   *r_elen = rsa_e_len;
   return 0;
 }
+
+
+/* Return the algo of a public RSA expressed as an canonical encoded
+   S-expression.  On error the algo is set to 0. */
+gpg_error_t
+get_pk_algo_from_canon_sexp (const unsigned char *keydata, size_t keydatalen,
+                             int *r_algo)
+{
+  gpg_error_t err;
+  const unsigned char *buf, *tok;
+  size_t buflen, toklen;
+  int depth;
+    
+  *r_algo = 0;
+
+  buf = keydata;
+  buflen = keydatalen;
+  depth = 0;
+  if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
+    return err;
+  if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
+    return err;
+  if (!tok || toklen != 10 || memcmp ("public-key", tok, toklen))
+    return gpg_error (GPG_ERR_BAD_PUBKEY);
+  if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
+    return err;
+  if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
+    return err;
+  if (!tok)
+    return gpg_error (GPG_ERR_BAD_PUBKEY);
+
+  if (toklen == 3 && !memcmp ("rsa", tok, toklen))
+    *r_algo = GCRY_PK_RSA;
+  else if (toklen == 3 && !memcmp ("dsa", tok, toklen))
+    *r_algo = GCRY_PK_DSA;
+  else if (toklen == 3 && !memcmp ("elg", tok, toklen))
+    *r_algo = GCRY_PK_ELG;
+  else if (toklen == 5 && !memcmp ("ecdsa", tok, toklen))
+    *r_algo = GCRY_PK_ECDSA;
+  else
+    return  gpg_error (GPG_ERR_PUBKEY_ALGO);
+
+  return 0;
+}
index 816afff..61b26f1 100644 (file)
@@ -201,6 +201,9 @@ gpg_error_t get_rsa_pk_from_canon_sexp (const unsigned char *keydata,
                                         size_t *r_nlen,
                                         unsigned char const **r_e, 
                                         size_t *r_elen);
+gpg_error_t get_pk_algo_from_canon_sexp (const unsigned char *keydata,
+                                         size_t keydatalen,
+                                         int *r_algo);
 
 /*-- convert.c --*/
 int hex2bin (const char *string, void *buffer, size_t length);
index 08b1c45..d189813 100644 (file)
@@ -165,9 +165,10 @@ use @samp{--help} to get a list of supported operations.
 @table @gnupgtabopt
 @item --gen-key
 @opindex gen-key
-This command allows the interactive creation of a certifcate signing
-request.  It is commonly used along with the @option{--output} option to
-save the created CSR into a file.
+This command allows the creation of a certificate signing request.  It
+is commonly used along with the @option{--output} option to save the
+created CSR into a file.  If used with the @option{--batch} the signing
+is requested from a parameter file.
 
 @item --list-keys
 @itemx -k 
index 93a9af1..2913c58 100644 (file)
@@ -1,3 +1,11 @@
+2009-07-01  Werner Koch  <wk@g10code.com>
+
+       * certreqgen-ui.c (check_keygrip): New.
+       (gpgsm_gencertreq_tty): Allow using an existing key.
+
+       * gpgsm.c (open_es_fread): New.
+       (main) <aKeygen>: Implement --batch mode.
+
 2009-06-24  Werner Koch  <wk@g10code.com>
 
        * call-dirmngr.c (pattern_from_strlist): Remove dead assignment of N.
index 3dc948f..868af6b 100644 (file)
@@ -86,6 +86,39 @@ store_mb_lines (membuf_t *mb, membuf_t *lines)
 }
 
 
+/* Chech whether we have a key for the key with HEXGRIP.  Returns NULL
+   if not or a string describing the type of the key (RSA, ELG, DSA,
+   etc..).  */ 
+static const char *
+check_keygrip (ctrl_t ctrl, const char *hexgrip)
+{
+  gpg_error_t err;
+  ksba_sexp_t public;
+  size_t publiclen;
+  int algo;
+
+  if (hexgrip[0] == '0' && hexgrip[1] == 'x')
+    hexgrip += 2;
+
+  err = gpgsm_agent_readkey (ctrl, 0, hexgrip, &public);
+  if (err)
+    return NULL;
+  publiclen = gcry_sexp_canon_len (public, 0, NULL, NULL);
+
+  get_pk_algo_from_canon_sexp (public, publiclen, &algo);
+  xfree (public);
+
+  switch (algo)
+    {
+    case GCRY_PK_RSA: return "RSA";
+    case GCRY_PK_DSA: return "DSA";
+    case GCRY_PK_ELG: return "ELG";
+    case GCRY_PK_ECDSA: return "ECDSA";
+    default: return NULL;
+    }
+}
+
+
 /* This function is used to create a certificate request from the
    command line.  In the past the similar gpgsm-gencert.sh script has
    been used for it; however that scripts requires a full Unix shell
@@ -99,7 +132,7 @@ gpgsm_gencertreq_tty (ctrl_t ctrl, FILE *output_fp)
   int selection;
   estream_t fp = NULL;
   int method;
-  char *keytype;
+  const char *keytype;
   char *keygrip = NULL;
   unsigned int nbits;
   int minbits = 1024;
@@ -112,11 +145,13 @@ gpgsm_gencertreq_tty (ctrl_t ctrl, FILE *output_fp)
   int i;
   const char *s, *s2;
 
+  answer = NULL;
   init_membuf (&mb_email, 100);
   init_membuf (&mb_dns, 100);
   init_membuf (&mb_uri, 100);
   init_membuf (&mb_result, 512);
 
+ again:
   /* Get the type of the key.  */
   tty_printf (_("Please select what kind of key you want:\n"));
   tty_printf (_("   (%d) RSA\n"), 1 );
@@ -125,10 +160,10 @@ gpgsm_gencertreq_tty (ctrl_t ctrl, FILE *output_fp)
 
   do
     {
+      xfree (answer);
       answer = tty_get (_("Your selection? "));
       tty_kill_prompt ();
       selection = *answer? atoi (answer): 1;
-      xfree (answer);
     }
   while (!(selection >= 1 && selection <= 3));
   method = selection;
@@ -136,13 +171,14 @@ gpgsm_gencertreq_tty (ctrl_t ctrl, FILE *output_fp)
   /* Get  size of the key.  */
   if (method == 1)
     {
-      keytype = xstrdup ("RSA");
+      keytype = "RSA";
       for (;;)
         {
+          xfree (answer);
           answer = tty_getf (_("What keysize do you want? (%u) "), defbits);
           tty_kill_prompt ();
+          trim_spaces (answer);
           nbits = *answer? atoi (answer): defbits;
-          xfree (answer);
           if (nbits < minbits || nbits > maxbits)
             tty_printf(_("%s keysizes must be in the range %u-%u\n"),
                          "RSA", minbits, maxbits);
@@ -159,17 +195,34 @@ gpgsm_gencertreq_tty (ctrl_t ctrl, FILE *output_fp)
     }
   else if (method == 2)
     {
-      tty_printf ("Not yet supported; "
-                  "use the gpgsm-gencert.sh script instead\n");
-      keytype = xstrdup ("RSA"); 
-      nbits = defbits; /* We need a dummy value.  */
+      for (;;)
+        {
+          xfree (answer);
+          answer = tty_get (_("Enter the keygrip: "));
+          tty_kill_prompt ();
+          trim_spaces (answer);
+          
+          if (!*answer)
+            goto again;
+          else if (strlen (answer) != 40 &&
+                   !(answer[0] == '0' && answer[1] == 'x' 
+                     && strlen (answer+2) == 40))
+            tty_printf (_("Not a valid keygrip (expecting 40 hex digits)\n"));
+          else if (!(keytype = check_keygrip (ctrl, answer)) )
+            tty_printf (_("No key with this keygrip\n"));
+          else
+            break; /* Okay.  */
+        }
+      nbits = 1024; /* A dummy value is sufficient.  */
+      xfree (keygrip);
+      keygrip = answer;
+      answer = NULL;
     }
   else /* method == 3 */
     {
       tty_printf ("Not yet supported; "
                   "use the gpgsm-gencert.sh script instead\n");
-      keytype = xstrdup ("card:foobar");
-      nbits = defbits; /* We need a dummy value.  */
+      goto again;
     }
 
   /* Ask for the key usage.  */
@@ -179,10 +232,11 @@ gpgsm_gencertreq_tty (ctrl_t ctrl, FILE *output_fp)
   tty_printf (_("   (%d) encrypt\n"), 3 );
   do
     {
+      xfree (answer);
       answer = tty_get (_("Your selection? "));
       tty_kill_prompt ();
+      trim_spaces (answer);
       selection = *answer? atoi (answer): 1;
-      xfree (answer);
       switch (selection)
         {
         case 1: keyusage = "sign, encrypt"; break;
@@ -194,7 +248,6 @@ gpgsm_gencertreq_tty (ctrl_t ctrl, FILE *output_fp)
   while (!keyusage);
 
   /* Get the subject name.  */
-  answer = NULL;
   do
     {
       size_t erroff, errlen;
@@ -303,7 +356,7 @@ gpgsm_gencertreq_tty (ctrl_t ctrl, FILE *output_fp)
   log_error (_("resource problem: out of core\n"));
  leave:
   es_fclose (fp);
-  xfree (keytype);         
+  xfree (answer);
   xfree (subject_name);
   xfree (keygrip);
   xfree (get_membuf (&mb_email, NULL));
index cb9aaab..6b2684a 100644 (file)
@@ -417,6 +417,7 @@ static void set_cmd (enum cmd_and_opt_values *ret_cmd,
 static void emergency_cleanup (void);
 static int check_special_filename (const char *fname, int for_write);
 static int open_read (const char *filename);
+static estream_t open_es_fread (const char *filename);
 static FILE *open_fwrite (const char *filename);
 static estream_t open_es_fwrite (const char *filename);
 static void run_protect_tool (int argc, char **argv);
@@ -1770,10 +1771,28 @@ main ( int argc, char **argv)
 
     case aKeygen: /* Generate a key; well kind of. */
       {
-        FILE *fp = open_fwrite (opt.outfile?opt.outfile:"-");
-        gpgsm_gencertreq_tty (&ctrl, fp);
-        if (fp != stdout)
-          fclose (fp);
+        estream_t fpin = NULL;
+        FILE *fpout;
+
+        if (opt.batch)
+          {
+            if (!argc) /* Create from stdin. */
+              fpin = open_es_fread ("-"); 
+            else if (argc == 1) /* From file. */
+              fpin = open_es_fread (*argv); 
+            else
+              wrong_args ("--gen-key --batch [parmfile]");
+          }
+        
+        fpout = open_fwrite (opt.outfile?opt.outfile:"-");
+
+        if (fpin)
+          gpgsm_genkey (&ctrl, fpin, fpout);
+        else
+          gpgsm_gencertreq_tty (&ctrl, fpout);
+
+        if (fpout != stdout)
+          fclose (fpout);
       }
       break;
 
@@ -1976,6 +1995,37 @@ open_read (const char *filename)
   return fd;
 }
 
+/* Same as open_read but return an estream_t.  */
+static estream_t
+open_es_fread (const char *filename)
+{
+  int fd;
+  estream_t fp;
+
+  if (filename[0] == '-' && !filename[1])
+    fd = fileno (stdin);
+  else
+    fd = check_special_filename (filename, 0);
+  if (fd != -1)
+    {
+      fp = es_fdopen_nc (fd, "rb");
+      if (!fp)
+        {
+          log_error ("es_fdopen(%d) failed: %s\n", fd, strerror (errno));
+          gpgsm_exit (2);
+        }
+      return fp;
+    }
+  fp = es_fopen (filename, "rb");
+  if (!fp)
+    {
+      log_error (_("can't open `%s': %s\n"), filename, strerror (errno));
+      gpgsm_exit (2);
+    }
+  return fp;
+}
+
+
 /* Open FILENAME for fwrite and return the stream.  Stop with an error
    message in case of problems.  "-" denotes stdout and if special
    filenames are allowed the given fd is opened instead. Caller must
index 3faaf18..5f716e3 100644 (file)
@@ -1,3 +1,7 @@
+2009-06-30  Werner Koch  <wk@g10code.com>
+
+       * ccidmon.c (parse_line_sniffusb): Take also TAB as delimiter.
+
 2009-06-29  Werner Koch  <wk@g10code.com>
 
        * ccidmon.c (parse_line_sniffusb): New.
index 4c37306..b854640 100644 (file)
@@ -702,13 +702,13 @@ parse_line_sniffusb (char *line, unsigned int lineno)
   if (debug)
     printf ("line[%u] =`%s'\n", lineno, line);
 
-  p = strtok (line, " ");
+  p = strtok (line, " \t");
   if (!p)
     return;
-  p = strtok (NULL, " ");
+  p = strtok (NULL, " \t");
   if (!p)
     return; 
-  p = strtok (NULL, " ");
+  p = strtok (NULL, " \t");
   if (!p)
     return; 
 
@@ -720,7 +720,7 @@ parse_line_sniffusb (char *line, unsigned int lineno)
       unsigned int value;
       
       length = databuffer.count;
-      while ((p=strtok (NULL, " ")))
+      while ((p=strtok (NULL, " \t")))
         {
           if (!hexdigitp (p[0]) || !hexdigitp (p[1]))
             {
@@ -745,7 +745,7 @@ parse_line_sniffusb (char *line, unsigned int lineno)
       flush_data ();
 
       *databuffer.address = 0;
-      while ((p=strtok (NULL, " (,)")))
+      while ((p=strtok (NULL, " \t(,)")))
         {
           if (!strcmp (p, "USBD_TRANSFER_DIRECTION_IN"))
             {