From 81972ca7d53ff1996e0086702a09d4405bdc2a7e Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 2 Jul 2009 09:49:31 +0000 Subject: [PATCH] Create a pkcs#10 request directly from a card. Deprecate gpgsm-gencert.sh script. --- NEWS | 6 +- sm/ChangeLog | 8 +++ sm/call-agent.c | 144 ++++++++++++++++++++++++++++++++++++++++- sm/certreqgen-ui.c | 64 +++++++++++++++--- sm/gpgsm.h | 2 + tools/gpgsm-gencert.sh | 4 +- 6 files changed, 216 insertions(+), 12 deletions(-) diff --git a/NEWS b/NEWS index e41e8b9e8..b08e2501d 100644 --- a/NEWS +++ b/NEWS @@ -3,9 +3,11 @@ Noteworthy changes in version 2.0.13 This is a BETA version! - * Minor bnug fixes + * Minor bug fixes. - * gpgsm --gen-key now implements a --batch mode. + * gpgsm --gen-key implements a --batch mode. + + * gpgsm --gen-key implements all features of gpgsm-gencert.sh. Noteworthy changes in version 2.0.12 (2009-06-17) diff --git a/sm/ChangeLog b/sm/ChangeLog index 2913c58ee..216791556 100644 --- a/sm/ChangeLog +++ b/sm/ChangeLog @@ -1,3 +1,11 @@ +2009-07-02 Werner Koch + + * certreqgen-ui.c (gpgsm_gencertreq_tty): Allow using a key from a + card. + * call-agent.c (gpgsm_agent_scd_serialno) + (scd_serialno_status_cb, store_serialno): New. + (scd_keypairinfo_status_cb, gpgsm_agent_scd_keypairinfo): New. + 2009-07-01 Werner Koch * certreqgen-ui.c (check_keygrip): New. diff --git a/sm/call-agent.c b/sm/call-agent.c index 1f8eecb3b..777c44cec 100644 --- a/sm/call-agent.c +++ b/sm/call-agent.c @@ -538,8 +538,150 @@ gpgsm_agent_readkey (ctrl_t ctrl, int fromcard, const char *hexkeygrip, return 0; } - + +/* Take the serial number from LINE and return it verbatim in a newly + allocated string. We make sure that only hex characters are + returned. */ +static char * +store_serialno (const char *line) +{ + const char *s; + char *p; + + for (s=line; hexdigitp (s); s++) + ; + p = xtrymalloc (s + 1 - line); + if (p) + { + memcpy (p, line, s-line); + p[s-line] = 0; + } + return p; +} + + +/* Callback for the gpgsm_agent_serialno fucntion. */ +static int +scd_serialno_status_cb (void *opaque, const char *line) +{ + char **r_serialno = opaque; + const char *keyword = line; + int keywordlen; + + for (keywordlen=0; *line && !spacep (line); line++, keywordlen++) + ; + while (spacep (line)) + line++; + + if (keywordlen == 8 && !memcmp (keyword, "SERIALNO", keywordlen)) + { + xfree (*r_serialno); + *r_serialno = store_serialno (line); + } + + return 0; +} + + +/* Call the agent to read the serial number of the current card. */ +int +gpgsm_agent_scd_serialno (ctrl_t ctrl, char **r_serialno) +{ + int rc; + char *serialno = NULL; + + *r_serialno = NULL; + rc = start_agent (ctrl); + if (rc) + return rc; + + rc = assuan_transact (agent_ctx, "SCD SERIALNO", + NULL, NULL, + default_inq_cb, ctrl, + scd_serialno_status_cb, &serialno); + if (!rc && !serialno) + rc = gpg_error (GPG_ERR_INTERNAL); + if (rc) + { + xfree (serialno); + return rc; + } + *r_serialno = serialno; + return 0; +} + + + +/* Callback for the gpgsm_agent_serialno fucntion. */ +static int +scd_keypairinfo_status_cb (void *opaque, const char *line) +{ + strlist_t *listaddr = opaque; + const char *keyword = line; + int keywordlen; + strlist_t sl; + char *p; + + for (keywordlen=0; *line && !spacep (line); line++, keywordlen++) + ; + while (spacep (line)) + line++; + + if (keywordlen == 11 && !memcmp (keyword, "KEYPAIRINFO", keywordlen)) + { + sl = append_to_strlist (listaddr, line); + p = sl->d; + /* Make sure that we only have two tokes so that future + extensions of the format won't change the format expected by + the caller. */ + while (*p && !spacep (p)) + p++; + if (*p) + { + while (spacep (p)) + p++; + while (*p && !spacep (p)) + p++; + *p = 0; + } + } + + return 0; +} + + +/* Call the agent to read the keypairinfo lines of the current card. + The list is returned as a string made up of the keygrip, a space + and the keyid. */ +int +gpgsm_agent_scd_keypairinfo (ctrl_t ctrl, strlist_t *r_list) +{ + int rc; + strlist_t list = NULL; + + *r_list = NULL; + rc = start_agent (ctrl); + if (rc) + return rc; + + rc = assuan_transact (agent_ctx, "SCD LEARN --force", + NULL, NULL, + default_inq_cb, ctrl, + scd_keypairinfo_status_cb, &list); + if (!rc && !list) + rc = gpg_error (GPG_ERR_NO_DATA); + if (rc) + { + free_strlist (list); + return rc; + } + *r_list = list; + return 0; +} + + + static int istrusted_status_cb (void *opaque, const char *line) { diff --git a/sm/certreqgen-ui.c b/sm/certreqgen-ui.c index 868af6b0e..3e98b660f 100644 --- a/sm/certreqgen-ui.c +++ b/sm/certreqgen-ui.c @@ -97,8 +97,8 @@ check_keygrip (ctrl_t ctrl, const char *hexgrip) size_t publiclen; int algo; - if (hexgrip[0] == '0' && hexgrip[1] == 'x') - hexgrip += 2; + if (hexgrip[0] == '&') + hexgrip++; err = gpgsm_agent_readkey (ctrl, 0, hexgrip, &public); if (err) @@ -132,6 +132,7 @@ gpgsm_gencertreq_tty (ctrl_t ctrl, FILE *output_fp) int selection; estream_t fp = NULL; int method; + char *keytype_buffer = NULL; const char *keytype; char *keygrip = NULL; unsigned int nbits; @@ -205,24 +206,70 @@ gpgsm_gencertreq_tty (ctrl_t ctrl, FILE *output_fp) if (!*answer) goto again; else if (strlen (answer) != 40 && - !(answer[0] == '0' && answer[1] == 'x' - && strlen (answer+2) == 40)) + !(answer[0] == '&' && strlen (answer+1) == 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; + nbits = 1024; /* A dummy value is sufficient. */ } else /* method == 3 */ { - tty_printf ("Not yet supported; " - "use the gpgsm-gencert.sh script instead\n"); - goto again; + char *serialno; + strlist_t keypairlist, sl; + int count; + + err = gpgsm_agent_scd_serialno (ctrl, &serialno); + if (err) + { + tty_printf (_("error reading the card: %s\n"), gpg_strerror (err)); + goto again; + } + tty_printf (_("Serial number of the card: %s\n"), serialno); + xfree (serialno); + + err = gpgsm_agent_scd_keypairinfo (ctrl, &keypairlist); + if (err) + { + tty_printf (_("error reading the card: %s\n"), gpg_strerror (err)); + goto again; + } + + do + { + tty_printf (_("Available keys:\n")); + for (count=1,sl=keypairlist; sl; sl = sl->next, count++) + tty_printf (" (%d) %s\n", count, sl->d); + xfree (answer); + answer = tty_get (_("Your selection? ")); + tty_kill_prompt (); + trim_spaces (answer); + selection = atoi (answer); + } + while (!(selection > 0 && selection < count)); + + for (count=1,sl=keypairlist; sl; sl = sl->next, count++) + if (count == selection) + break; + + s = sl->d; + while (*s && !spacep (s)) + s++; + while (spacep (s)) + s++; + + xfree (keygrip); + keygrip = NULL; + xfree (keytype_buffer); + keytype_buffer = xasprintf ("card:%s", s); + free_strlist (keypairlist); + keytype = keytype_buffer; + nbits = 1024; /* A dummy value is sufficient. */ } /* Ask for the key usage. */ @@ -358,6 +405,7 @@ gpgsm_gencertreq_tty (ctrl_t ctrl, FILE *output_fp) es_fclose (fp); xfree (answer); xfree (subject_name); + xfree (keytype_buffer); xfree (keygrip); xfree (get_membuf (&mb_email, NULL)); xfree (get_membuf (&mb_dns, NULL)); diff --git a/sm/gpgsm.h b/sm/gpgsm.h index 781561a71..d2c38fb25 100644 --- a/sm/gpgsm.h +++ b/sm/gpgsm.h @@ -388,6 +388,8 @@ int gpgsm_agent_genkey (ctrl_t ctrl, ksba_const_sexp_t keyparms, ksba_sexp_t *r_pubkey); int gpgsm_agent_readkey (ctrl_t ctrl, int fromcard, const char *hexkeygrip, ksba_sexp_t *r_pubkey); +int gpgsm_agent_scd_serialno (ctrl_t ctrl, char **r_serialno); +int gpgsm_agent_scd_keypairinfo (ctrl_t ctrl, strlist_t *r_list); int gpgsm_agent_istrusted (ctrl_t ctrl, ksba_cert_t cert, const char *hexfpr, struct rootca_flags_s *rootca_flags); int gpgsm_agent_havekey (ctrl_t ctrl, const char *hexkeygrip); diff --git a/tools/gpgsm-gencert.sh b/tools/gpgsm-gencert.sh index c66208e50..b209c8e5a 100755 --- a/tools/gpgsm-gencert.sh +++ b/tools/gpgsm-gencert.sh @@ -83,7 +83,9 @@ query_user_menu() } - +echo "WARNING: This script is deprecated; please use" >&2 +echo " gpgsm --gen-key" >&2 +echo " instead." >&2 KEY_TYPE="" while [ -z "$KEY_TYPE" ]; do query_user_menu "Key type" "RSA" "Existing key" "Direct from card"