2011-02-04 12:57:53 +01:00
|
|
|
/* divert-scd.c - divert operations to the scdaemon
|
2009-03-05 20:19:37 +01:00
|
|
|
* Copyright (C) 2002, 2003, 2009 Free Software Foundation, Inc.
|
2003-08-05 19:11:04 +02:00
|
|
|
*
|
|
|
|
* This file is part of GnuPG.
|
|
|
|
*
|
|
|
|
* GnuPG is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
2007-07-04 21:49:40 +02:00
|
|
|
* the Free Software Foundation; either version 3 of the License, or
|
2003-08-05 19:11:04 +02:00
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* GnuPG is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
2016-11-05 12:02:19 +01:00
|
|
|
* along with this program; if not, see <https://www.gnu.org/licenses/>.
|
2003-08-05 19:11:04 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <assert.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
|
|
|
#include "agent.h"
|
agent: Resolve conflict of util.h.
* agent/Makefile.am (AM_CPPFLAGS): Remove -I$(top_srcdir)/common.
* agent/call-pinentry.c, agent/call-scd.c: Follow the change.
* agent/command-ssh.c, agent/command.c, agent/cvt-openpgp.c: Ditto.
* agent/divert-scd.c, agent/findkey.c, agent/genkey.c: Ditto.
* agent/gpg-agent.c, agent/pksign.c, agent/preset-passphrase.c: Ditto.
* agent/protect-tool.c, agent/protect.c, agent/trustlist.c: Ditto.
* agent/w32main.c: Ditto.
--
For openpty function, we need to include util.h on some OS.
We also have util.h in common/, so this change is needed.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-03-07 11:22:48 +01:00
|
|
|
#include "../common/i18n.h"
|
|
|
|
#include "../common/sexp-parse.h"
|
2003-08-05 19:11:04 +02:00
|
|
|
|
2022-08-15 12:49:56 +02:00
|
|
|
/* Replace all linefeeds in STRING by "%0A" and return a new malloced
|
|
|
|
* string. May return NULL on memory error. */
|
|
|
|
static char *
|
|
|
|
linefeed_to_percent0A (const char *string)
|
|
|
|
{
|
|
|
|
const char *s;
|
|
|
|
size_t n;
|
|
|
|
char *buf, *p;
|
|
|
|
|
|
|
|
for (n=0, s=string; *s; s++)
|
|
|
|
if (*s == '\n')
|
|
|
|
n += 3;
|
|
|
|
else
|
|
|
|
n++;
|
|
|
|
p = buf = xtrymalloc (n+1);
|
|
|
|
if (!buf)
|
|
|
|
return NULL;
|
|
|
|
for (s=string; *s; s++)
|
|
|
|
if (*s == '\n')
|
|
|
|
{
|
|
|
|
memcpy (p, "%0A", 3);
|
|
|
|
p += 3;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
*p++ = *s;
|
|
|
|
*p = 0;
|
|
|
|
return buf;
|
|
|
|
}
|
2003-08-05 19:11:04 +02:00
|
|
|
|
2022-08-15 12:49:56 +02:00
|
|
|
|
|
|
|
/* Ask for the card using SHADOW_INFO. If GRIP is not NULL, the
|
|
|
|
* function also tries to find additional information from the shadow
|
|
|
|
* key file. */
|
2003-08-05 19:11:04 +02:00
|
|
|
static int
|
2022-08-15 12:49:56 +02:00
|
|
|
ask_for_card (ctrl_t ctrl, const unsigned char *shadow_info,
|
|
|
|
const unsigned char *grip, char **r_kid)
|
2003-08-05 19:11:04 +02:00
|
|
|
{
|
|
|
|
int rc, i;
|
|
|
|
char *serialno;
|
|
|
|
int no_card = 0;
|
|
|
|
char *desc;
|
2017-02-22 13:03:52 +01:00
|
|
|
char *want_sn, *want_kid, *want_sn_disp;
|
2022-08-15 12:49:56 +02:00
|
|
|
int got_sn_disp_from_meta = 0;
|
2017-02-22 13:03:52 +01:00
|
|
|
int len;
|
2022-08-15 12:49:56 +02:00
|
|
|
char *comment = NULL;
|
2003-08-05 19:11:04 +02:00
|
|
|
|
|
|
|
*r_kid = NULL;
|
2009-03-06 18:31:27 +01:00
|
|
|
|
2012-02-07 14:17:33 +01:00
|
|
|
rc = parse_shadow_info (shadow_info, &want_sn, &want_kid, NULL);
|
2009-03-06 18:31:27 +01:00
|
|
|
if (rc)
|
|
|
|
return rc;
|
2017-02-22 13:03:52 +01:00
|
|
|
want_sn_disp = xtrystrdup (want_sn);
|
|
|
|
if (!want_sn_disp)
|
|
|
|
{
|
|
|
|
rc = gpg_error_from_syserror ();
|
|
|
|
xfree (want_sn);
|
2017-05-30 06:56:20 +02:00
|
|
|
xfree (want_kid);
|
2022-08-15 12:49:56 +02:00
|
|
|
xfree (comment);
|
2017-02-22 13:03:52 +01:00
|
|
|
return rc;
|
|
|
|
}
|
2009-03-06 18:31:27 +01:00
|
|
|
|
2022-08-15 12:49:56 +02:00
|
|
|
if (grip)
|
|
|
|
{
|
|
|
|
nvc_t keymeta;
|
|
|
|
const char *s;
|
|
|
|
size_t snlen;
|
|
|
|
nve_t item;
|
|
|
|
char **tokenfields = NULL;
|
|
|
|
|
|
|
|
rc = agent_keymeta_from_file (ctrl, grip, &keymeta);
|
|
|
|
if (!rc)
|
|
|
|
{
|
|
|
|
snlen = strlen (want_sn);
|
|
|
|
s = NULL;
|
|
|
|
for (item = nvc_lookup (keymeta, "Token:");
|
|
|
|
item;
|
|
|
|
item = nve_next_value (item, "Token:"))
|
|
|
|
if ((s = nve_value (item)) && !strncmp (s, want_sn, snlen))
|
|
|
|
break;
|
|
|
|
if (s && (tokenfields = strtokenize (s, " \t\n")))
|
|
|
|
{
|
|
|
|
if (tokenfields[0] && tokenfields[1] && tokenfields[2]
|
|
|
|
&& tokenfields[3] && strlen (tokenfields[3]) > 1)
|
|
|
|
{
|
|
|
|
xfree (want_sn_disp);
|
|
|
|
want_sn_disp = percent_plus_unescape (tokenfields[3], 0xff);
|
|
|
|
if (!want_sn_disp)
|
|
|
|
{
|
|
|
|
rc = gpg_error_from_syserror ();
|
|
|
|
xfree (tokenfields);
|
|
|
|
nvc_release (keymeta);
|
|
|
|
xfree (want_sn);
|
|
|
|
xfree (want_kid);
|
|
|
|
xfree (comment);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
got_sn_disp_from_meta = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
xfree (tokenfields);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((s = nvc_get_string (keymeta, "Label:")))
|
|
|
|
comment = linefeed_to_percent0A (s);
|
|
|
|
|
|
|
|
nvc_release (keymeta);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-22 13:03:52 +01:00
|
|
|
len = strlen (want_sn_disp);
|
2022-08-15 12:49:56 +02:00
|
|
|
if (got_sn_disp_from_meta)
|
|
|
|
; /* We got the the display S/N from the key file. */
|
|
|
|
else if (len == 32 && !strncmp (want_sn_disp, "D27600012401", 12))
|
2017-02-22 13:03:52 +01:00
|
|
|
{
|
|
|
|
/* This is an OpenPGP card - reformat */
|
|
|
|
memmove (want_sn_disp, want_sn_disp+16, 4);
|
|
|
|
want_sn_disp[4] = ' ';
|
|
|
|
memmove (want_sn_disp+5, want_sn_disp+20, 8);
|
|
|
|
want_sn_disp[13] = 0;
|
|
|
|
}
|
|
|
|
else if (len == 20 && want_sn_disp[19] == '0')
|
|
|
|
{
|
|
|
|
/* We assume that a 20 byte serial number is a standard one
|
|
|
|
* which has the property to have a zero in the last nibble (Due
|
|
|
|
* to BCD representation). We don't display this '0' because it
|
|
|
|
* may confuse the user. */
|
|
|
|
want_sn_disp[19] = 0;
|
|
|
|
}
|
2003-08-05 19:11:04 +02:00
|
|
|
|
|
|
|
for (;;)
|
|
|
|
{
|
2017-01-16 02:33:08 +01:00
|
|
|
rc = agent_card_serialno (ctrl, &serialno, want_sn);
|
2003-08-05 19:11:04 +02:00
|
|
|
if (!rc)
|
|
|
|
{
|
2020-11-13 16:05:28 +01:00
|
|
|
log_info ("detected card with S/N %s\n", serialno);
|
2003-08-05 19:11:04 +02:00
|
|
|
i = strcmp (serialno, want_sn);
|
|
|
|
xfree (serialno);
|
|
|
|
serialno = NULL;
|
|
|
|
if (!i)
|
|
|
|
{
|
2017-05-30 06:56:20 +02:00
|
|
|
xfree (want_sn_disp);
|
2003-08-05 19:11:04 +02:00
|
|
|
xfree (want_sn);
|
2022-08-15 12:49:56 +02:00
|
|
|
xfree (comment);
|
2003-08-05 19:11:04 +02:00
|
|
|
*r_kid = want_kid;
|
|
|
|
return 0; /* yes, we have the correct card */
|
|
|
|
}
|
|
|
|
}
|
2017-01-16 02:33:08 +01:00
|
|
|
else if (gpg_err_code (rc) == GPG_ERR_ENODEV)
|
|
|
|
{
|
2020-11-13 16:05:28 +01:00
|
|
|
log_info ("no device present\n");
|
2017-01-16 02:33:08 +01:00
|
|
|
rc = 0;
|
|
|
|
no_card = 1;
|
|
|
|
}
|
2003-08-05 19:11:04 +02:00
|
|
|
else if (gpg_err_code (rc) == GPG_ERR_CARD_NOT_PRESENT)
|
|
|
|
{
|
2020-11-13 16:05:28 +01:00
|
|
|
log_info ("no card present\n");
|
2003-08-05 19:11:04 +02:00
|
|
|
rc = 0;
|
2017-01-16 02:33:08 +01:00
|
|
|
no_card = 2;
|
2003-08-05 19:11:04 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-01-08 20:18:49 +01:00
|
|
|
log_error ("error accessing card: %s\n", gpg_strerror (rc));
|
2003-08-05 19:11:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!rc)
|
|
|
|
{
|
|
|
|
if (asprintf (&desc,
|
|
|
|
"%s:%%0A%%0A"
|
2022-08-15 12:49:56 +02:00
|
|
|
" %s%%0A"
|
2017-02-22 13:03:52 +01:00
|
|
|
" %s",
|
2009-08-11 12:56:44 +02:00
|
|
|
no_card
|
2015-06-30 21:58:02 +02:00
|
|
|
? L_("Please insert the card with serial number")
|
|
|
|
: L_("Please remove the current card and "
|
|
|
|
"insert the one with serial number"),
|
2022-08-15 12:49:56 +02:00
|
|
|
want_sn_disp, comment? comment:"") < 0)
|
2003-08-05 19:11:04 +02:00
|
|
|
{
|
|
|
|
rc = out_of_core ();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-06-17 12:19:50 +02:00
|
|
|
rc = agent_get_confirmation (ctrl, desc, NULL, NULL, 0);
|
2017-05-30 06:56:20 +02:00
|
|
|
if (ctrl->pinentry_mode == PINENTRY_MODE_LOOPBACK &&
|
|
|
|
gpg_err_code (rc) == GPG_ERR_NO_PIN_ENTRY)
|
|
|
|
rc = gpg_error (GPG_ERR_CARD_NOT_PRESENT);
|
2012-01-26 01:16:33 +01:00
|
|
|
|
2008-05-27 14:03:50 +02:00
|
|
|
xfree (desc);
|
2003-08-05 19:11:04 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (rc)
|
|
|
|
{
|
2017-02-22 13:03:52 +01:00
|
|
|
xfree (want_sn_disp);
|
2003-08-05 19:11:04 +02:00
|
|
|
xfree (want_sn);
|
|
|
|
xfree (want_kid);
|
2022-08-15 12:49:56 +02:00
|
|
|
xfree (comment);
|
2003-08-05 19:11:04 +02:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-01-28 17:19:46 +01:00
|
|
|
/* Put the DIGEST into an DER encoded container and return it in R_VAL. */
|
2003-08-05 19:11:04 +02:00
|
|
|
static int
|
|
|
|
encode_md_for_card (const unsigned char *digest, size_t digestlen, int algo,
|
|
|
|
unsigned char **r_val, size_t *r_len)
|
|
|
|
{
|
2005-06-16 10:12:03 +02:00
|
|
|
unsigned char *frame;
|
|
|
|
unsigned char asn[100];
|
2003-08-05 19:11:04 +02:00
|
|
|
size_t asnlen;
|
|
|
|
|
2005-06-16 10:12:03 +02:00
|
|
|
*r_val = NULL;
|
|
|
|
*r_len = 0;
|
|
|
|
|
2003-08-05 19:11:04 +02:00
|
|
|
asnlen = DIM(asn);
|
2006-10-05 13:06:42 +02:00
|
|
|
if (!algo || gcry_md_test_algo (algo))
|
|
|
|
return gpg_error (GPG_ERR_DIGEST_ALGO);
|
2003-08-05 19:11:04 +02:00
|
|
|
if (gcry_md_algo_info (algo, GCRYCTL_GET_ASNOID, asn, &asnlen))
|
|
|
|
{
|
|
|
|
log_error ("no object identifier for algo %d\n", algo);
|
|
|
|
return gpg_error (GPG_ERR_INTERNAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
frame = xtrymalloc (asnlen + digestlen);
|
|
|
|
if (!frame)
|
|
|
|
return out_of_core ();
|
|
|
|
memcpy (frame, asn, asnlen);
|
|
|
|
memcpy (frame+asnlen, digest, digestlen);
|
|
|
|
if (DBG_CRYPTO)
|
2020-05-12 18:51:47 +02:00
|
|
|
log_printhex (frame, asnlen+digestlen, "encoded hash:");
|
2011-02-04 12:57:53 +01:00
|
|
|
|
2003-08-05 19:11:04 +02:00
|
|
|
*r_val = frame;
|
|
|
|
*r_len = asnlen+digestlen;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-02-22 11:04:55 +01:00
|
|
|
/* Return true if STRING ends in "%0A". */
|
|
|
|
static int
|
|
|
|
has_percent0A_suffix (const char *string)
|
|
|
|
{
|
|
|
|
size_t n;
|
|
|
|
|
|
|
|
return (string
|
|
|
|
&& (n = strlen (string)) >= 3
|
|
|
|
&& !strcmp (string + n - 3, "%0A"));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-08-05 19:11:04 +02:00
|
|
|
/* Callback used to ask for the PIN which should be set into BUF. The
|
|
|
|
buf has been allocated by the caller and is of size MAXBUF which
|
|
|
|
includes the terminating null. The function should return an UTF-8
|
|
|
|
string with the passphrase, the buffer may optionally be padded
|
2005-05-24 14:37:36 +02:00
|
|
|
with arbitrary characters.
|
|
|
|
|
2017-02-22 09:40:50 +01:00
|
|
|
If DESC_TEXT is not NULL it can be used as further informtion shown
|
|
|
|
atop of the INFO message.
|
|
|
|
|
2005-05-24 14:37:36 +02:00
|
|
|
INFO gets displayed as part of a generic string. However if the
|
|
|
|
first character of INFO is a vertical bar all up to the next
|
|
|
|
verical bar are considered flags and only everything after the
|
|
|
|
second vertical bar gets displayed as the full prompt.
|
|
|
|
|
|
|
|
Flags:
|
|
|
|
|
2009-03-05 20:19:37 +01:00
|
|
|
'N' = New PIN, this requests a second prompt to repeat the
|
2005-05-24 14:37:36 +02:00
|
|
|
PIN. If the PIN is not correctly repeated it starts from
|
|
|
|
all over.
|
2009-03-05 20:19:37 +01:00
|
|
|
'A' = The PIN is an Admin PIN, SO-PIN or alike.
|
|
|
|
'P' = The PIN is a PUK (Personal Unblocking Key).
|
2008-09-25 12:06:02 +02:00
|
|
|
'R' = The PIN is a Reset Code.
|
2005-05-24 14:37:36 +02:00
|
|
|
|
|
|
|
Example:
|
|
|
|
|
|
|
|
"|AN|Please enter the new security officer's PIN"
|
2011-02-04 12:57:53 +01:00
|
|
|
|
2005-05-24 14:37:36 +02:00
|
|
|
The text "Please ..." will get displayed and the flags 'A' and 'N'
|
|
|
|
are considered.
|
|
|
|
*/
|
2011-02-04 12:57:53 +01:00
|
|
|
static int
|
2017-02-22 09:40:50 +01:00
|
|
|
getpin_cb (void *opaque, const char *desc_text, const char *info,
|
|
|
|
char *buf, size_t maxbuf)
|
2003-08-05 19:11:04 +02:00
|
|
|
{
|
|
|
|
struct pin_entry_info_s *pi;
|
|
|
|
int rc;
|
2005-05-24 14:37:36 +02:00
|
|
|
ctrl_t ctrl = opaque;
|
|
|
|
const char *ends, *s;
|
|
|
|
int any_flags = 0;
|
|
|
|
int newpin = 0;
|
2008-09-25 12:06:02 +02:00
|
|
|
int resetcode = 0;
|
2009-03-05 20:19:37 +01:00
|
|
|
int is_puk = 0;
|
2005-05-24 14:37:36 +02:00
|
|
|
const char *again_text = NULL;
|
|
|
|
const char *prompt = "PIN";
|
2003-08-05 19:11:04 +02:00
|
|
|
|
2005-11-28 12:52:25 +01:00
|
|
|
if (buf && maxbuf < 2)
|
2003-08-05 19:11:04 +02:00
|
|
|
return gpg_error (GPG_ERR_INV_VALUE);
|
|
|
|
|
2005-05-24 14:37:36 +02:00
|
|
|
/* Parse the flags. */
|
|
|
|
if (info && *info =='|' && (ends=strchr (info+1, '|')))
|
|
|
|
{
|
|
|
|
for (s=info+1; s < ends; s++)
|
|
|
|
{
|
|
|
|
if (*s == 'A')
|
2015-06-30 21:58:02 +02:00
|
|
|
prompt = L_("Admin PIN");
|
2009-03-05 20:19:37 +01:00
|
|
|
else if (*s == 'P')
|
|
|
|
{
|
|
|
|
/* TRANSLATORS: A PUK is the Personal Unblocking Code
|
|
|
|
used to unblock a PIN. */
|
2015-06-30 21:58:02 +02:00
|
|
|
prompt = L_("PUK");
|
2009-03-05 20:19:37 +01:00
|
|
|
is_puk = 1;
|
|
|
|
}
|
2005-05-24 14:37:36 +02:00
|
|
|
else if (*s == 'N')
|
|
|
|
newpin = 1;
|
2008-09-25 12:06:02 +02:00
|
|
|
else if (*s == 'R')
|
|
|
|
{
|
2015-06-30 21:58:02 +02:00
|
|
|
prompt = L_("Reset Code");
|
2008-09-25 12:06:02 +02:00
|
|
|
resetcode = 1;
|
|
|
|
}
|
2005-05-24 14:37:36 +02:00
|
|
|
}
|
|
|
|
info = ends+1;
|
|
|
|
any_flags = 1;
|
|
|
|
}
|
|
|
|
else if (info && *info == '|')
|
|
|
|
log_debug ("pin_cb called without proper PIN info hack\n");
|
|
|
|
|
scd: Rename 'keypad' to 'pinpad'.
* NEWS: Mention scd changes.
* agent/divert-scd.c (getpin_cb): Change message.
* agent/call-scd.c (inq_needpin): Change the protocol to
POPUPPINPADPROMPT and DISMISSPINPADPROMPT.
* scd/command.c (pin_cb): Likewise.
* scd/apdu.c (struct reader_table_s): Rename member functions.
(check_pcsc_pinpad, pcsc_pinpad_verify, pcsc_pinpad_modify,
check_ccid_pinpad, ccid_pinpad_operation, apdu_check_pinpad
apdu_pinpad_verify, apdu_pinpad_modify): Rename.
* scd/apdu.h (SW_HOST_NO_PINPAD, apdu_check_pinpad)
(apdu_pinpad_verify, apdu_pinpad_modify): Rename.
* scd/iso7816.h (iso7816_check_pinpad): Rename.
* scd/iso7816.c (map_sw): Use SW_HOST_NO_PINPAD.
(iso7816_check_pinpad): Rename.
(iso7816_verify_kp, iso7816_change_reference_data_kp): Follow
the change.
* scd/ccid-driver.h (CCID_DRIVER_ERR_NO_PINPAD): Rename.
* scd/ccid-driver.c (ccid_transceive_secure): Use it.
* scd/app-dinsig.c (verify_pin): Follow the change.
* scd/app-nks.c (verify_pin): Follow the change.
* scd/app-openpgp.c (check_pinpad_request): Rename.
(parse_login_data, verify_a_chv, verify_chv3, do_change_pin): Follow
the change.
* scd/scdaemon.c (oDisablePinpad, oEnablePinpadVarlen): Rename.
* scd/scdaemon.h (opt): Rename to disable_pinpad,
enable_pinpad_varlen.
* tools/gpgconf-comp.c (gc_options_scdaemon): Rename to
disable-pinpad.
2013-02-07 02:07:51 +01:00
|
|
|
/* If BUF has been passed as NULL, we are in pinpad mode: The
|
2015-11-16 12:41:46 +01:00
|
|
|
callback opens the popup and immediately returns. */
|
2005-11-28 12:52:25 +01:00
|
|
|
if (!buf)
|
|
|
|
{
|
|
|
|
if (maxbuf == 0) /* Close the pinentry. */
|
|
|
|
{
|
|
|
|
agent_popup_message_stop (ctrl);
|
|
|
|
rc = 0;
|
|
|
|
}
|
|
|
|
else if (maxbuf == 1) /* Open the pinentry. */
|
|
|
|
{
|
2018-10-12 04:36:59 +02:00
|
|
|
if (info)
|
2009-03-05 20:19:37 +01:00
|
|
|
{
|
2018-10-12 04:36:59 +02:00
|
|
|
char *desc;
|
|
|
|
const char *desc2;
|
2009-03-05 20:19:37 +01:00
|
|
|
|
2018-10-12 04:36:59 +02:00
|
|
|
if (!strcmp (info, "--ack"))
|
|
|
|
{
|
|
|
|
desc2 = L_("Push ACK button on card/token.");
|
|
|
|
|
|
|
|
if (desc_text)
|
|
|
|
{
|
|
|
|
desc = strconcat (desc_text,
|
|
|
|
has_percent0A_suffix (desc_text)
|
|
|
|
? "%0A" : "%0A%0A",
|
|
|
|
desc2, NULL);
|
|
|
|
desc2 = NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
desc = NULL;
|
|
|
|
}
|
2009-03-05 20:19:37 +01:00
|
|
|
else
|
|
|
|
{
|
2018-10-12 04:36:59 +02:00
|
|
|
desc2 = NULL;
|
|
|
|
|
2017-02-22 11:04:55 +01:00
|
|
|
if (desc_text)
|
2018-10-12 04:36:59 +02:00
|
|
|
desc = strconcat (desc_text,
|
|
|
|
has_percent0A_suffix (desc_text)
|
|
|
|
? "%0A" : "%0A%0A",
|
|
|
|
info, "%0A%0A",
|
|
|
|
L_("Use the reader's pinpad for input."),
|
|
|
|
NULL);
|
2017-02-22 11:04:55 +01:00
|
|
|
else
|
2018-10-12 04:36:59 +02:00
|
|
|
desc = strconcat (info, "%0A%0A",
|
|
|
|
L_("Use the reader's pinpad for input."),
|
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!desc2 && !desc)
|
|
|
|
rc = gpg_error_from_syserror ();
|
|
|
|
else
|
|
|
|
{
|
2017-02-22 11:04:55 +01:00
|
|
|
rc = agent_popup_message_start (ctrl,
|
|
|
|
desc2? desc2:desc, NULL);
|
2009-03-05 20:19:37 +01:00
|
|
|
xfree (desc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2017-02-22 11:04:55 +01:00
|
|
|
rc = agent_popup_message_start (ctrl, desc_text, NULL);
|
2005-11-28 12:52:25 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
rc = gpg_error (GPG_ERR_INV_VALUE);
|
|
|
|
return rc;
|
|
|
|
}
|
2003-08-05 19:11:04 +02:00
|
|
|
|
|
|
|
/* FIXME: keep PI and TRIES in OPAQUE. Frankly this is a whole
|
|
|
|
mess because we should call the card's verify function from the
|
|
|
|
pinentry check pin CB. */
|
2005-05-24 14:37:36 +02:00
|
|
|
again:
|
|
|
|
pi = gcry_calloc_secure (1, sizeof (*pi) + maxbuf + 10);
|
|
|
|
if (!pi)
|
2006-09-14 18:50:33 +02:00
|
|
|
return gpg_error_from_syserror ();
|
2003-08-05 19:11:04 +02:00
|
|
|
pi->max_length = maxbuf-1;
|
|
|
|
pi->min_digits = 0; /* we want a real passphrase */
|
2009-03-05 20:19:37 +01:00
|
|
|
pi->max_digits = 16;
|
2003-08-05 19:11:04 +02:00
|
|
|
pi->max_tries = 3;
|
|
|
|
|
2005-05-24 14:37:36 +02:00
|
|
|
if (any_flags)
|
|
|
|
{
|
2017-02-22 11:04:55 +01:00
|
|
|
{
|
|
|
|
char *desc2;
|
|
|
|
|
|
|
|
if (desc_text)
|
|
|
|
desc2 = strconcat (desc_text,
|
|
|
|
has_percent0A_suffix (desc_text)
|
|
|
|
? "%0A" : "%0A%0A",
|
|
|
|
info, NULL);
|
|
|
|
else
|
|
|
|
desc2 = NULL;
|
2017-02-22 13:03:52 +01:00
|
|
|
rc = agent_askpin (ctrl, desc2? desc2 : info,
|
|
|
|
prompt, again_text, pi, NULL, 0);
|
2017-02-22 11:04:55 +01:00
|
|
|
xfree (desc2);
|
|
|
|
}
|
2005-05-24 14:37:36 +02:00
|
|
|
again_text = NULL;
|
|
|
|
if (!rc && newpin)
|
|
|
|
{
|
|
|
|
struct pin_entry_info_s *pi2;
|
|
|
|
pi2 = gcry_calloc_secure (1, sizeof (*pi) + maxbuf + 10);
|
|
|
|
if (!pi2)
|
|
|
|
{
|
2006-09-14 18:50:33 +02:00
|
|
|
rc = gpg_error_from_syserror ();
|
2005-05-24 14:37:36 +02:00
|
|
|
xfree (pi);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
pi2->max_length = maxbuf-1;
|
|
|
|
pi2->min_digits = 0;
|
2009-03-05 20:19:37 +01:00
|
|
|
pi2->max_digits = 16;
|
2005-05-24 14:37:36 +02:00
|
|
|
pi2->max_tries = 1;
|
2008-09-25 12:06:02 +02:00
|
|
|
rc = agent_askpin (ctrl,
|
|
|
|
(resetcode?
|
2015-06-30 21:58:02 +02:00
|
|
|
L_("Repeat this Reset Code"):
|
2009-03-05 20:19:37 +01:00
|
|
|
is_puk?
|
2015-06-30 21:58:02 +02:00
|
|
|
L_("Repeat this PUK"):
|
|
|
|
L_("Repeat this PIN")),
|
2015-04-14 18:41:05 +02:00
|
|
|
prompt, NULL, pi2, NULL, 0);
|
2005-05-24 14:37:36 +02:00
|
|
|
if (!rc && strcmp (pi->pin, pi2->pin))
|
|
|
|
{
|
2011-02-04 12:57:53 +01:00
|
|
|
again_text = (resetcode?
|
2015-06-30 21:58:02 +02:00
|
|
|
L_("Reset Code not correctly repeated; try again"):
|
2009-03-05 20:19:37 +01:00
|
|
|
is_puk?
|
2015-06-30 21:58:02 +02:00
|
|
|
L_("PUK not correctly repeated; try again"):
|
|
|
|
L_("PIN not correctly repeated; try again"));
|
2005-05-24 14:37:36 +02:00
|
|
|
xfree (pi2);
|
|
|
|
xfree (pi);
|
|
|
|
goto again;
|
|
|
|
}
|
|
|
|
xfree (pi2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-02-22 11:04:55 +01:00
|
|
|
char *desc, *desc2;
|
|
|
|
|
2005-05-24 14:37:36 +02:00
|
|
|
if ( asprintf (&desc,
|
2015-06-30 21:58:02 +02:00
|
|
|
L_("Please enter the PIN%s%s%s to unlock the card"),
|
2012-06-05 19:29:22 +02:00
|
|
|
info? " (":"",
|
2005-05-24 14:37:36 +02:00
|
|
|
info? info:"",
|
2012-06-05 19:29:22 +02:00
|
|
|
info? ")":"") < 0)
|
2005-05-24 14:37:36 +02:00
|
|
|
desc = NULL;
|
2017-02-22 11:04:55 +01:00
|
|
|
if (desc_text)
|
|
|
|
desc2 = strconcat (desc_text,
|
|
|
|
has_percent0A_suffix (desc_text)
|
|
|
|
? "%0A" : "%0A%0A",
|
|
|
|
desc, NULL);
|
|
|
|
else
|
|
|
|
desc2 = NULL;
|
|
|
|
rc = agent_askpin (ctrl, desc2? desc2 : desc? desc : info,
|
|
|
|
prompt, NULL, pi, NULL, 0);
|
|
|
|
xfree (desc2);
|
2008-05-27 14:03:50 +02:00
|
|
|
xfree (desc);
|
2005-05-24 14:37:36 +02:00
|
|
|
}
|
|
|
|
|
2003-08-05 19:11:04 +02:00
|
|
|
if (!rc)
|
|
|
|
{
|
|
|
|
strncpy (buf, pi->pin, maxbuf-1);
|
|
|
|
buf[maxbuf-1] = 0;
|
|
|
|
}
|
|
|
|
xfree (pi);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2017-02-22 09:40:50 +01:00
|
|
|
/* This function is used when a sign operation has been diverted to a
|
|
|
|
* smartcard. DESC_TEXT is the original text for a prompt has send by
|
|
|
|
* gpg to gpg-agent.
|
|
|
|
*
|
|
|
|
* FIXME: Explain the other args. */
|
2003-08-05 19:11:04 +02:00
|
|
|
int
|
2017-02-22 09:40:50 +01:00
|
|
|
divert_pksign (ctrl_t ctrl, const char *desc_text,
|
2003-08-05 19:11:04 +02:00
|
|
|
const unsigned char *digest, size_t digestlen, int algo,
|
2020-11-13 16:05:28 +01:00
|
|
|
const unsigned char *grip,
|
2013-02-28 03:17:47 +01:00
|
|
|
const unsigned char *shadow_info, unsigned char **r_sig,
|
|
|
|
size_t *r_siglen)
|
2003-08-05 19:11:04 +02:00
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
char *kid;
|
|
|
|
size_t siglen;
|
2006-10-06 12:58:18 +02:00
|
|
|
unsigned char *sigval = NULL;
|
2003-08-05 19:11:04 +02:00
|
|
|
|
2017-02-22 13:03:52 +01:00
|
|
|
(void)desc_text;
|
|
|
|
|
2022-08-15 12:49:56 +02:00
|
|
|
rc = ask_for_card (ctrl, shadow_info, grip, &kid);
|
2003-08-05 19:11:04 +02:00
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
2020-11-13 16:05:28 +01:00
|
|
|
/* For OpenPGP cards we better use the keygrip as key reference.
|
|
|
|
* This has the advantage that app-openpgp can check that the stored
|
|
|
|
* key matches our expectation. This is important in case new keys
|
|
|
|
* have been created on the same card but the sub file has not been
|
|
|
|
* updated. In that case we would get a error from our final
|
|
|
|
* signature checking code or, if the pubkey algo is different,
|
|
|
|
* weird errors from the card (Conditions of use not satisfied). */
|
|
|
|
if (kid && grip && !strncmp (kid, "OPENPGP.", 8))
|
|
|
|
{
|
|
|
|
xfree (kid);
|
|
|
|
kid = bin2hex (grip, KEYGRIP_LEN, NULL);
|
|
|
|
if (!kid)
|
|
|
|
return gpg_error_from_syserror ();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-09-29 17:02:55 +02:00
|
|
|
if (algo == MD_USER_TLS_MD5SHA1)
|
2006-10-06 12:58:18 +02:00
|
|
|
{
|
2006-10-06 13:06:15 +02:00
|
|
|
int save = ctrl->use_auth_call;
|
|
|
|
ctrl->use_auth_call = 1;
|
2017-02-22 13:03:52 +01:00
|
|
|
rc = agent_card_pksign (ctrl, kid, getpin_cb, ctrl, NULL,
|
2011-03-02 15:35:10 +01:00
|
|
|
algo, digest, digestlen, &sigval, &siglen);
|
2006-10-06 13:06:15 +02:00
|
|
|
ctrl->use_auth_call = save;
|
2006-10-06 12:58:18 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
unsigned char *data;
|
|
|
|
size_t ndata;
|
|
|
|
|
|
|
|
rc = encode_md_for_card (digest, digestlen, algo, &data, &ndata);
|
|
|
|
if (!rc)
|
|
|
|
{
|
2017-02-22 13:03:52 +01:00
|
|
|
rc = agent_card_pksign (ctrl, kid, getpin_cb, ctrl, NULL,
|
2011-03-02 15:35:10 +01:00
|
|
|
algo, data, ndata, &sigval, &siglen);
|
2006-10-06 12:58:18 +02:00
|
|
|
xfree (data);
|
|
|
|
}
|
|
|
|
}
|
2003-08-05 19:11:04 +02:00
|
|
|
|
|
|
|
if (!rc)
|
2013-02-28 03:17:47 +01:00
|
|
|
{
|
|
|
|
*r_sig = sigval;
|
|
|
|
*r_siglen = siglen;
|
|
|
|
}
|
2006-10-06 12:58:18 +02:00
|
|
|
|
2003-08-05 19:11:04 +02:00
|
|
|
xfree (kid);
|
2006-10-06 12:58:18 +02:00
|
|
|
|
2003-08-05 19:11:04 +02:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-02-20 22:19:50 +01:00
|
|
|
/* Decrypt the value given asn an S-expression in CIPHER using the
|
2003-08-05 19:11:04 +02:00
|
|
|
key identified by SHADOW_INFO and return the plaintext in an
|
2013-08-26 17:29:54 +02:00
|
|
|
allocated buffer in R_BUF. The padding information is stored at
|
|
|
|
R_PADDING with -1 for not known. */
|
2011-02-04 12:57:53 +01:00
|
|
|
int
|
2017-02-22 09:40:50 +01:00
|
|
|
divert_pkdecrypt (ctrl_t ctrl, const char *desc_text,
|
2003-08-05 19:11:04 +02:00
|
|
|
const unsigned char *cipher,
|
2020-11-13 16:05:28 +01:00
|
|
|
const unsigned char *grip,
|
2003-08-05 19:11:04 +02:00
|
|
|
const unsigned char *shadow_info,
|
2013-08-26 17:29:54 +02:00
|
|
|
char **r_buf, size_t *r_len, int *r_padding)
|
2003-08-05 19:11:04 +02:00
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
char *kid;
|
|
|
|
const unsigned char *s;
|
|
|
|
size_t n;
|
2019-02-22 14:09:02 +01:00
|
|
|
int depth;
|
2003-08-05 19:11:04 +02:00
|
|
|
const unsigned char *ciphertext;
|
|
|
|
size_t ciphertextlen;
|
|
|
|
char *plaintext;
|
|
|
|
size_t plaintextlen;
|
|
|
|
|
2017-02-22 13:03:52 +01:00
|
|
|
(void)desc_text;
|
|
|
|
|
2013-08-26 17:29:54 +02:00
|
|
|
*r_padding = -1;
|
2003-08-05 19:11:04 +02:00
|
|
|
s = cipher;
|
|
|
|
if (*s != '(')
|
|
|
|
return gpg_error (GPG_ERR_INV_SEXP);
|
|
|
|
s++;
|
|
|
|
n = snext (&s);
|
|
|
|
if (!n)
|
2011-02-04 12:57:53 +01:00
|
|
|
return gpg_error (GPG_ERR_INV_SEXP);
|
2003-08-05 19:11:04 +02:00
|
|
|
if (!smatch (&s, n, "enc-val"))
|
2011-02-04 12:57:53 +01:00
|
|
|
return gpg_error (GPG_ERR_UNKNOWN_SEXP);
|
2003-08-05 19:11:04 +02:00
|
|
|
if (*s != '(')
|
|
|
|
return gpg_error (GPG_ERR_UNKNOWN_SEXP);
|
|
|
|
s++;
|
|
|
|
n = snext (&s);
|
|
|
|
if (!n)
|
2011-02-04 12:57:53 +01:00
|
|
|
return gpg_error (GPG_ERR_INV_SEXP);
|
2019-02-22 14:09:02 +01:00
|
|
|
|
|
|
|
/* First check whether we have a flags parameter and skip it. */
|
|
|
|
if (smatch (&s, n, "flags"))
|
|
|
|
{
|
|
|
|
depth = 1;
|
|
|
|
if (sskip (&s, &depth) || depth)
|
|
|
|
return gpg_error (GPG_ERR_INV_SEXP);
|
|
|
|
if (*s != '(')
|
|
|
|
return gpg_error (GPG_ERR_INV_SEXP);
|
|
|
|
s++;
|
|
|
|
n = snext (&s);
|
|
|
|
if (!n)
|
|
|
|
return gpg_error (GPG_ERR_INV_SEXP);
|
|
|
|
}
|
|
|
|
|
2014-12-22 01:27:00 +01:00
|
|
|
if (smatch (&s, n, "rsa"))
|
|
|
|
{
|
|
|
|
if (*s != '(')
|
|
|
|
return gpg_error (GPG_ERR_UNKNOWN_SEXP);
|
|
|
|
s++;
|
|
|
|
n = snext (&s);
|
|
|
|
if (!n)
|
|
|
|
return gpg_error (GPG_ERR_INV_SEXP);
|
|
|
|
if (!smatch (&s, n, "a"))
|
|
|
|
return gpg_error (GPG_ERR_UNKNOWN_SEXP);
|
|
|
|
n = snext (&s);
|
|
|
|
}
|
|
|
|
else if (smatch (&s, n, "ecdh"))
|
|
|
|
{
|
|
|
|
if (*s != '(')
|
|
|
|
return gpg_error (GPG_ERR_UNKNOWN_SEXP);
|
|
|
|
s++;
|
|
|
|
n = snext (&s);
|
|
|
|
if (!n)
|
|
|
|
return gpg_error (GPG_ERR_INV_SEXP);
|
|
|
|
if (smatch (&s, n, "s"))
|
|
|
|
{
|
|
|
|
n = snext (&s);
|
|
|
|
s += n;
|
|
|
|
if (*s++ != ')')
|
|
|
|
return gpg_error (GPG_ERR_INV_SEXP);
|
|
|
|
if (*s++ != '(')
|
|
|
|
return gpg_error (GPG_ERR_UNKNOWN_SEXP);
|
|
|
|
n = snext (&s);
|
|
|
|
if (!n)
|
|
|
|
return gpg_error (GPG_ERR_INV_SEXP);
|
|
|
|
}
|
|
|
|
if (!smatch (&s, n, "e"))
|
|
|
|
return gpg_error (GPG_ERR_UNKNOWN_SEXP);
|
|
|
|
n = snext (&s);
|
|
|
|
}
|
|
|
|
else
|
2011-02-04 12:57:53 +01:00
|
|
|
return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
|
2014-12-22 01:27:00 +01:00
|
|
|
|
2003-08-05 19:11:04 +02:00
|
|
|
if (!n)
|
2011-02-04 12:57:53 +01:00
|
|
|
return gpg_error (GPG_ERR_UNKNOWN_SEXP);
|
2003-08-05 19:11:04 +02:00
|
|
|
ciphertext = s;
|
|
|
|
ciphertextlen = n;
|
|
|
|
|
2022-08-15 12:49:56 +02:00
|
|
|
rc = ask_for_card (ctrl, shadow_info, grip, &kid);
|
2003-08-05 19:11:04 +02:00
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
2020-11-13 16:05:28 +01:00
|
|
|
/* For OpenPGP cards we better use the keygrip as key reference.
|
|
|
|
* This has the advantage that app-openpgp can check that the stored
|
|
|
|
* key matches our expectation. This is important in case new keys
|
|
|
|
* have been created on the same card but the sub file has not been
|
|
|
|
* updated. In that case we would get a error from our final
|
|
|
|
* signature checking code or, if the pubkey algo is different,
|
|
|
|
* weird errors from the card (Conditions of use not satisfied). */
|
|
|
|
if (kid && grip && !strncmp (kid, "OPENPGP.", 8))
|
|
|
|
{
|
|
|
|
xfree (kid);
|
|
|
|
kid = bin2hex (grip, KEYGRIP_LEN, NULL);
|
|
|
|
if (!kid)
|
|
|
|
return gpg_error_from_syserror ();
|
|
|
|
}
|
|
|
|
|
2017-02-22 13:03:52 +01:00
|
|
|
rc = agent_card_pkdecrypt (ctrl, kid, getpin_cb, ctrl, NULL,
|
2003-08-05 19:11:04 +02:00
|
|
|
ciphertext, ciphertextlen,
|
2013-08-26 17:29:54 +02:00
|
|
|
&plaintext, &plaintextlen, r_padding);
|
2003-08-05 19:11:04 +02:00
|
|
|
if (!rc)
|
|
|
|
{
|
|
|
|
*r_buf = plaintext;
|
|
|
|
*r_len = plaintextlen;
|
|
|
|
}
|
|
|
|
xfree (kid);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2013-02-06 06:00:05 +01:00
|
|
|
int
|
|
|
|
divert_writekey (ctrl_t ctrl, int force, const char *serialno,
|
|
|
|
const char *id, const char *keydata, size_t keydatalen)
|
|
|
|
{
|
|
|
|
return agent_card_writekey (ctrl, force, serialno, id, keydata, keydatalen,
|
|
|
|
getpin_cb, ctrl);
|
|
|
|
}
|
2003-08-05 19:11:04 +02:00
|
|
|
|
2011-02-04 12:57:53 +01:00
|
|
|
int
|
2006-09-06 18:35:52 +02:00
|
|
|
divert_generic_cmd (ctrl_t ctrl, const char *cmdline, void *assuan_context)
|
2003-08-05 19:11:04 +02:00
|
|
|
{
|
2004-01-29 21:17:27 +01:00
|
|
|
return agent_card_scd (ctrl, cmdline, getpin_cb, ctrl, assuan_context);
|
2003-08-05 19:11:04 +02:00
|
|
|
}
|