Ask to insert the right OpenPGP card.

This commit is contained in:
Werner Koch 2009-08-11 10:56:44 +00:00
parent 019601191a
commit 25659d66f1
6 changed files with 186 additions and 18 deletions

3
NEWS
View File

@ -18,6 +18,9 @@ Noteworthy changes in version 2.0.13
* Add hack to the internal CCID driver to allow the use of some
Omnikey based card readers with 2048 bit keys.
* GPG now repeatly asks the user to insert the requested OpenPGP
card. This can be disabled with --limit-card-insert-tries=1.
* Minor bug fixes.

View File

@ -1,3 +1,7 @@
2009-08-11 Werner Koch <wk@g10code.com>
* divert-scd.c (ask_for_card): I18n a prompt string.
2009-07-06 Werner Koch <wk@g10code.com>
* agent.h: Include session-env.h.

View File

@ -88,9 +88,10 @@ ask_for_card (ctrl_t ctrl, const unsigned char *shadow_info, char **r_kid)
if (asprintf (&desc,
"%s:%%0A%%0A"
" \"%.*s\"",
no_card? "Please insert the card with serial number"
: "Please remove the current card and "
"insert the one with serial number",
no_card
? _("Please insert the card with serial number")
: _("Please remove the current card and "
"insert the one with serial number"),
want_sn_displen, want_sn) < 0)
{
rc = out_of_core ();

View File

@ -1,3 +1,10 @@
2009-08-11 Werner Koch <wk@g10code.com>
* call-agent.c (get_serialno_cb): New. From ../agent/call-scd.c.
(gpg_agent_get_confirmation): New.
(select_openpgp): New.
(agent_scd_pkdecrypt, agent_scd_pksign): Use it here.
2009-08-06 Werner Koch <wk@g10code.com>
* skclist.c (build_sk_list): Print INV_SGNR status line.

View File

@ -1,6 +1,6 @@
/* call-agent.c - Divert GPG operations to the agent.
* Copyright (C) 2001, 2002, 2003, 2006, 2007,
* 2008 Free Software Foundation, Inc.
* 2008, 2009 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@ -239,6 +239,38 @@ dummy_data_cb (void *opaque, const void *buffer, size_t length)
return 0;
}
/* A simple callback used to return the serialnumber of a card. */
static int
get_serialno_cb (void *opaque, const char *line)
{
char **serialno = opaque;
const char *keyword = line;
const char *s;
int keywordlen, n;
for (keywordlen=0; *line && !spacep (line); line++, keywordlen++)
;
while (spacep (line))
line++;
if (keywordlen == 8 && !memcmp (keyword, "SERIALNO", keywordlen))
{
if (*serialno)
return gpg_error (GPG_ERR_CONFLICT); /* Unexpected status line. */
for (n=0,s=line; hexdigitp (s); s++, n++)
;
if (!n || (n&1)|| !(spacep (s) || !*s) )
return gpg_error (GPG_ERR_ASS_PARAMETER);
*serialno = xtrymalloc (n+1);
if (!*serialno)
return out_of_core ();
memcpy (*serialno, line, n);
(*serialno)[n] = 0;
}
return 0;
}
/* This is the default inquiry callback. It mainly handles the
Pinentry notifications. */
@ -755,6 +787,100 @@ agent_scd_genkey (struct agent_card_genkey_s *info, int keyno, int force,
return rc;
}
/* Issue an SCD SERIALNO openpgp command and if SERIALNO is not NULL
ask the user to insert the requested card. */
gpg_error_t
select_openpgp (const char *serialno)
{
gpg_error_t err;
/* Send the serialno command to initialize the connection. Without
a given S/N we don't care about the data returned. If the card
has already been initialized, this is a very fast command. We
request the openpgp card because that is what we expect.
Note that an opt.limit_card_insert_tries of 1 means: No tries at
all whereas 0 means do not limit the number of tries. Due to the
sue of a pinentry prompt with a cancel option we use it here in a
boolean sense. */
if (!serialno || opt.limit_card_insert_tries == 1)
err = assuan_transact (agent_ctx, "SCD SERIALNO openpgp",
NULL, NULL, NULL, NULL, NULL, NULL);
else
{
char *this_sn = NULL;
char *desc;
int ask;
char *want_sn;
char *p;
want_sn = xtrystrdup (serialno);
if (!want_sn)
return gpg_error_from_syserror ();
p = strchr (want_sn, '/');
if (p)
*p = 0;
do
{
ask = 0;
err = assuan_transact (agent_ctx, "SCD SERIALNO openpgp",
NULL, NULL, NULL, NULL,
get_serialno_cb, &this_sn);
if (gpg_err_code (err) == GPG_ERR_CARD_NOT_PRESENT)
ask = 1;
else if (gpg_err_code (err) == GPG_ERR_NOT_SUPPORTED)
ask = 2;
else if (err)
;
else if (this_sn)
{
if (strcmp (want_sn, this_sn))
ask = 2;
}
xfree (this_sn);
this_sn = NULL;
if (ask)
{
char *formatted = NULL;
char *ocodeset = i18n_switchto_utf8 ();
if (!strncmp (want_sn, "D27600012401", 12)
&& strlen (want_sn) == 32 )
formatted = xtryasprintf ("(%.4s) %.8s",
want_sn + 16, want_sn + 20);
err = 0;
desc = xtryasprintf
("%s:\n\n"
" \"%s\"",
ask == 1
? _("Please insert the card with serial number")
: _("Please remove the current card and "
"insert the one with serial number"),
formatted? formatted : want_sn);
if (!desc)
err = gpg_error_from_syserror ();
xfree (formatted);
i18n_switchback (ocodeset);
if (!err)
err = gpg_agent_get_confirmation (desc);
xfree (desc);
}
}
while (ask && !err);
xfree (want_sn);
}
return err;
}
static int
membuf_data_cb (void *opaque, const void *buffer, size_t length)
@ -784,18 +910,16 @@ agent_scd_pksign (const char *serialno, int hashalgo,
*r_buflen = 0;
rc = start_agent (1);
if (gpg_err_code (rc) == GPG_ERR_CARD_NOT_PRESENT
|| gpg_err_code (rc) == GPG_ERR_NOT_SUPPORTED)
rc = 0; /* We check later. */
if (rc)
return rc;
if (indatalen*2 + 50 > DIM(line))
return gpg_error (GPG_ERR_GENERAL);
/* Send the serialno command to initialize the connection. We don't
care about the data returned. If the card has already been
initialized, this is a very fast command. We request the openpgp
card because that is what we expect. */
rc = assuan_transact (agent_ctx, "SCD SERIALNO openpgp",
NULL, NULL, NULL, NULL, NULL, NULL);
rc = select_openpgp (serialno);
if (rc)
return rc;
@ -833,7 +957,7 @@ agent_scd_pksign (const char *serialno, int hashalgo,
/* Decrypt INDATA of length INDATALEN using the card identified by
SERIALNO. Return the plaintext in a nwly allocated buffer stored
at the address of R_BUF.
at the address of R_BUF.
Note, we currently support only RSA or more exactly algorithms
taking one input data element. */
@ -849,6 +973,9 @@ agent_scd_pkdecrypt (const char *serialno,
*r_buf = NULL;
rc = start_agent (1);
if (gpg_err_code (rc) == GPG_ERR_CARD_NOT_PRESENT
|| gpg_err_code (rc) == GPG_ERR_NOT_SUPPORTED)
rc = 0; /* We check later. */
if (rc)
return rc;
@ -856,15 +983,10 @@ agent_scd_pkdecrypt (const char *serialno,
if (indatalen*2 + 50 > DIM(line))
return gpg_error (GPG_ERR_GENERAL);
/* Send the serialno command to initialize the connection. We don't
care about the data returned. If the card has already been
initialized, this is a very fast command. We request the openpgp
card because that is what we expect. */
rc = assuan_transact (agent_ctx, "SCD SERIALNO openpgp",
NULL, NULL, NULL, NULL, NULL, NULL);
rc = select_openpgp (serialno);
if (rc)
return rc;
sprintf (line, "SCD SETDATA ");
p = line + strlen (line);
for (i=0; i < indatalen ; i++, p += 2 )
@ -1104,3 +1226,31 @@ agent_clear_passphrase (const char *cache_id)
return assuan_transact (agent_ctx, line, NULL, NULL,
default_inq_cb, NULL, NULL, NULL);
}
/* Ask the agent to pop up a confirmation dialog with the text DESC
and an okay and cancel button. */
gpg_error_t
gpg_agent_get_confirmation (const char *desc)
{
int rc;
char *tmp;
char line[ASSUAN_LINELENGTH];
rc = start_agent (0);
if (rc)
return rc;
tmp = percent_plus_escape (desc);
if (!tmp)
return gpg_error_from_syserror ();
snprintf (line, DIM(line)-1, "GET_CONFIRMATION %s", tmp);
line[DIM(line)-1] = 0;
xfree (tmp);
rc = assuan_transact (agent_ctx, line, NULL, NULL,
default_inq_cb, NULL, NULL, NULL);
return rc;
}

View File

@ -134,6 +134,9 @@ gpg_error_t agent_get_passphrase (const char *cache_id,
/* Send the CLEAR_PASSPHRASE command to the agent. */
gpg_error_t agent_clear_passphrase (const char *cache_id);
/* Present the prompt DESC and ask the user to confirm. */
gpg_error_t gpg_agent_get_confirmation (const char *desc);
#endif /*GNUPG_G10_CALL_AGENT_H*/