From 1925cb37f9cad721ff7ca228dab3ba214a14f767 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 1 Jul 2009 18:30:33 +0000 Subject: [PATCH] Alow batch ode for gpgsm --gen-key. Allow CSR generation using an existing key with gpgsm. --- NEWS | 4 ++- common/ChangeLog | 4 +++ common/sexputil.c | 54 ++++++++++++++++++++++++++----- common/util.h | 3 ++ doc/gpgsm.texi | 7 ++-- sm/ChangeLog | 8 +++++ sm/certreqgen-ui.c | 79 ++++++++++++++++++++++++++++++++++++++-------- sm/gpgsm.c | 58 +++++++++++++++++++++++++++++++--- tools/ChangeLog | 4 +++ tools/ccidmon.c | 10 +++--- 10 files changed, 197 insertions(+), 34 deletions(-) diff --git a/NEWS b/NEWS index 306e5ff44..e41e8b9e8 100644 --- 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) diff --git a/common/ChangeLog b/common/ChangeLog index bd4be4faf..40faa541e 100644 --- a/common/ChangeLog +++ b/common/ChangeLog @@ -1,3 +1,7 @@ +2009-07-01 Werner Koch + + * sexputil.c (get_pk_algo_from_canon_sexp): New. + 2009-06-29 Werner Koch * estream.c (BUFFER_ROUND_TO_BLOCK): Remove unused macro. diff --git a/common/sexputil.c b/common/sexputil.c index 73608816d..1e5918723 100644 --- a/common/sexputil.c +++ b/common/sexputil.c @@ -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; +} diff --git a/common/util.h b/common/util.h index 816afff0b..61b26f1de 100644 --- a/common/util.h +++ b/common/util.h @@ -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); diff --git a/doc/gpgsm.texi b/doc/gpgsm.texi index 08b1c4568..d1898133c 100644 --- a/doc/gpgsm.texi +++ b/doc/gpgsm.texi @@ -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 diff --git a/sm/ChangeLog b/sm/ChangeLog index 93a9af122..2913c58ee 100644 --- a/sm/ChangeLog +++ b/sm/ChangeLog @@ -1,3 +1,11 @@ +2009-07-01 Werner Koch + + * certreqgen-ui.c (check_keygrip): New. + (gpgsm_gencertreq_tty): Allow using an existing key. + + * gpgsm.c (open_es_fread): New. + (main) : Implement --batch mode. + 2009-06-24 Werner Koch * call-dirmngr.c (pattern_from_strlist): Remove dead assignment of N. diff --git a/sm/certreqgen-ui.c b/sm/certreqgen-ui.c index 3dc948f0b..868af6b0e 100644 --- a/sm/certreqgen-ui.c +++ b/sm/certreqgen-ui.c @@ -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)); diff --git a/sm/gpgsm.c b/sm/gpgsm.c index cb9aaab44..6b2684abe 100644 --- a/sm/gpgsm.c +++ b/sm/gpgsm.c @@ -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 diff --git a/tools/ChangeLog b/tools/ChangeLog index 3faaf18f4..5f716e320 100644 --- a/tools/ChangeLog +++ b/tools/ChangeLog @@ -1,3 +1,7 @@ +2009-06-30 Werner Koch + + * ccidmon.c (parse_line_sniffusb): Take also TAB as delimiter. + 2009-06-29 Werner Koch * ccidmon.c (parse_line_sniffusb): New. diff --git a/tools/ccidmon.c b/tools/ccidmon.c index 4c373061e..b8546407e 100644 --- a/tools/ccidmon.c +++ b/tools/ccidmon.c @@ -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")) {