mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
New PIN Callback attributes in gpg-agent.
Common prompts for keypad and simple card reader. More support for Netkey cards; PIN management works now.
This commit is contained in:
parent
2749c6bcd9
commit
59d7a54e72
4
NEWS
4
NEWS
@ -1,3 +1,7 @@
|
||||
Noteworthy changes in version 2.0.12
|
||||
-------------------------------------------------
|
||||
|
||||
|
||||
Noteworthy changes in version 2.0.11 (2009-03-03)
|
||||
-------------------------------------------------
|
||||
|
||||
|
@ -1,3 +1,9 @@
|
||||
2009-03-05 Werner Koch <wk@g10code.com>
|
||||
|
||||
* divert-scd.c (getpin_cb): Support flag 'P'. Change max_digits
|
||||
from 8 to 16. Append a message about keypads.
|
||||
* findkey.c (unprotect): Change max digits to 16.
|
||||
|
||||
2009-03-02 Werner Koch <wk@g10code.com>
|
||||
|
||||
* command.c (cmd_getinfo): Add subcommand "scd_running".
|
||||
|
@ -1061,7 +1061,7 @@ cmd_learn (assuan_context_t ctx, char *line)
|
||||
|
||||
/* PASSWD <hexstring_with_keygrip>
|
||||
|
||||
Change the passphrase/PID for the key identified by keygrip in LINE. */
|
||||
Change the passphrase/PIN for the key identified by keygrip in LINE. */
|
||||
static int
|
||||
cmd_passwd (assuan_context_t ctx, char *line)
|
||||
{
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* divert-scd.c - divert operations to the scdaemon
|
||||
* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2002, 2003, 2009 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
@ -181,10 +181,11 @@ encode_md_for_card (const unsigned char *digest, size_t digestlen, int algo,
|
||||
|
||||
Flags:
|
||||
|
||||
'N' = New PIN, this requests a second prompt to repeat the the
|
||||
'N' = New PIN, this requests a second prompt to repeat the
|
||||
PIN. If the PIN is not correctly repeated it starts from
|
||||
all over.
|
||||
'A' = The PIN is an Admin PIN, SO-PIN, PUK or alike.
|
||||
'A' = The PIN is an Admin PIN, SO-PIN or alike.
|
||||
'P' = The PIN is a PUK (Personal Unblocking Key).
|
||||
'R' = The PIN is a Reset Code.
|
||||
|
||||
Example:
|
||||
@ -204,6 +205,7 @@ getpin_cb (void *opaque, const char *info, char *buf, size_t maxbuf)
|
||||
int any_flags = 0;
|
||||
int newpin = 0;
|
||||
int resetcode = 0;
|
||||
int is_puk = 0;
|
||||
const char *again_text = NULL;
|
||||
const char *prompt = "PIN";
|
||||
|
||||
@ -217,6 +219,13 @@ getpin_cb (void *opaque, const char *info, char *buf, size_t maxbuf)
|
||||
{
|
||||
if (*s == 'A')
|
||||
prompt = _("Admin PIN");
|
||||
else if (*s == 'P')
|
||||
{
|
||||
/* TRANSLATORS: A PUK is the Personal Unblocking Code
|
||||
used to unblock a PIN. */
|
||||
prompt = _("PUK");
|
||||
is_puk = 1;
|
||||
}
|
||||
else if (*s == 'N')
|
||||
newpin = 1;
|
||||
else if (*s == 'R')
|
||||
@ -242,7 +251,22 @@ getpin_cb (void *opaque, const char *info, char *buf, size_t maxbuf)
|
||||
}
|
||||
else if (maxbuf == 1) /* Open the pinentry. */
|
||||
{
|
||||
rc = agent_popup_message_start (ctrl, info, NULL);
|
||||
if (info)
|
||||
{
|
||||
char *desc;
|
||||
|
||||
if ( asprintf (&desc,
|
||||
_("%s%%0A%%0AUse the reader's keypad for input."),
|
||||
info) < 0 )
|
||||
rc = gpg_error_from_syserror ();
|
||||
else
|
||||
{
|
||||
rc = agent_popup_message_start (ctrl, desc, NULL);
|
||||
xfree (desc);
|
||||
}
|
||||
}
|
||||
else
|
||||
rc = agent_popup_message_start (ctrl, NULL, NULL);
|
||||
}
|
||||
else
|
||||
rc = gpg_error (GPG_ERR_INV_VALUE);
|
||||
@ -258,7 +282,7 @@ getpin_cb (void *opaque, const char *info, char *buf, size_t maxbuf)
|
||||
return gpg_error_from_syserror ();
|
||||
pi->max_length = maxbuf-1;
|
||||
pi->min_digits = 0; /* we want a real passphrase */
|
||||
pi->max_digits = 8;
|
||||
pi->max_digits = 16;
|
||||
pi->max_tries = 3;
|
||||
|
||||
if (any_flags)
|
||||
@ -277,17 +301,21 @@ getpin_cb (void *opaque, const char *info, char *buf, size_t maxbuf)
|
||||
}
|
||||
pi2->max_length = maxbuf-1;
|
||||
pi2->min_digits = 0;
|
||||
pi2->max_digits = 8;
|
||||
pi2->max_digits = 16;
|
||||
pi2->max_tries = 1;
|
||||
rc = agent_askpin (ctrl,
|
||||
(resetcode?
|
||||
_("Repeat this Reset Code"):
|
||||
is_puk?
|
||||
_("Repeat this PUK"):
|
||||
_("Repeat this PIN")),
|
||||
prompt, NULL, pi2);
|
||||
if (!rc && strcmp (pi->pin, pi2->pin))
|
||||
{
|
||||
again_text = (resetcode?
|
||||
N_("Reset Code not correctly repeated; try again"):
|
||||
is_puk?
|
||||
N_("PUK not correctly repeated; try again"):
|
||||
N_("PIN not correctly repeated; try again"));
|
||||
xfree (pi2);
|
||||
xfree (pi);
|
||||
|
@ -367,7 +367,7 @@ unprotect (ctrl_t ctrl, const char *desc_text,
|
||||
return gpg_error_from_syserror ();
|
||||
pi->max_length = 100;
|
||||
pi->min_digits = 0; /* we want a real passphrase */
|
||||
pi->max_digits = 8;
|
||||
pi->max_digits = 16;
|
||||
pi->max_tries = 3;
|
||||
pi->check_cb = try_unprotect_cb;
|
||||
arg.ctrl = ctrl;
|
||||
|
@ -24,8 +24,8 @@ min_automake_version="1.10"
|
||||
# Remember to change the version number immediately *after* a release.
|
||||
# Set my_issvn to "yes" for non-released code. Remember to run an
|
||||
# "svn up" and "autogen.sh" right before creating a distribution.
|
||||
m4_define([my_version], [2.0.11])
|
||||
m4_define([my_issvn], [no])
|
||||
m4_define([my_version], [2.0.12])
|
||||
m4_define([my_issvn], [yes])
|
||||
|
||||
m4_define([svn_revision], m4_esyscmd([printf "%d" $(svn info 2>/dev/null \
|
||||
| sed -n '/^Revision:/ s/[^0-9]//gp'|head -1)]))
|
||||
|
@ -1,3 +1,12 @@
|
||||
2009-03-04 Werner Koch <wk@g10code.com>
|
||||
|
||||
* help.txt (gpg.keygen.size): Add a link to web page.
|
||||
|
||||
2009-03-03 Werner Koch <wk@g10code.com>
|
||||
|
||||
* gpg.texi (Operational GPG Commands): "merge-only" is an
|
||||
import-option. Reported by Joseph Oreste Bruni.
|
||||
|
||||
2009-03-02 Werner Koch <wk@g10code.com>
|
||||
|
||||
* gpg-agent.texi (Invoking GPG-AGENT): Modernized instructions.
|
||||
|
@ -425,7 +425,7 @@ Import/merge keys. This adds the given keys to the
|
||||
keyring. The fast version is currently just a synonym.
|
||||
|
||||
There are a few other options which control how this command works.
|
||||
Most notable here is the @option{--keyserver-options merge-only} option
|
||||
Most notable here is the @option{--import-options merge-only} option
|
||||
which does not insert new keys but does only the merging of new
|
||||
signatures, user-IDs and subkeys.
|
||||
|
||||
|
@ -136,6 +136,12 @@ Please consult your security expert first.
|
||||
|
||||
.gpg.keygen.size
|
||||
Enter the size of the key.
|
||||
|
||||
The suggested default is usually a good choice.
|
||||
|
||||
If you want to use a large key size, for example 4096 bit, please
|
||||
think again whether it really makes sense for you. You may want
|
||||
to view the web page http://www.xkcd.com/538/ .
|
||||
.
|
||||
|
||||
.gpg.keygen.size.huge.okay
|
||||
|
@ -1,3 +1,30 @@
|
||||
2009-03-05 Werner Koch <wk@g10code.com>
|
||||
|
||||
* app-openpgp.c (verify_a_chv): Remove special case for keypads.
|
||||
(verify_chv3): Ditto.
|
||||
|
||||
* app-nks.c (get_chv_status): New.
|
||||
(parse_pwidstr): New.
|
||||
(verify_pin): Add args PWID and DESC and use them. Remove the
|
||||
CHV1 caching.
|
||||
(do_change_pin): Allow PIN selection and add reset mode.
|
||||
(do_learn_status): Use NKS-NKS3 tag for TCOS 3 cards.
|
||||
(do_readcert, do_sign): Allow NKS-NKS3 tag.
|
||||
|
||||
2009-03-04 Werner Koch <wk@g10code.com>
|
||||
|
||||
* app-nks.c (do_getattr): New.
|
||||
(app_select_nks): Register it.
|
||||
(verify_pin): Factor some code out to...
|
||||
(basic_pin_checks): New.
|
||||
(do_change_pin): Call the basic check.
|
||||
(app_select_nks): Move AID to ..
|
||||
(aid_nks): .. new.
|
||||
(aid_sigg): New.
|
||||
(switch_application): New.
|
||||
(do_getattr, do_learn_status, do_readcert, do_sign, do_decipher)
|
||||
(do_change_pin, do_check_pin): Make sure we are in NKS mode.
|
||||
|
||||
2009-03-03 Werner Koch <wk@g10code.com>
|
||||
|
||||
* command.c (scd_command_handler): Remove dereference of STOPME
|
||||
|
584
scd/app-nks.c
584
scd/app-nks.c
@ -17,6 +17,27 @@
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* Notes:
|
||||
|
||||
- This is still work in progress. We are now targeting TCOS 3 cards
|
||||
but try to keep compatibility to TCOS 2. Both are not fully
|
||||
working as of now. TCOS 3 PIN management seems to work. Use GPA
|
||||
from SVN trunk to test it.
|
||||
|
||||
- If required, we automagically switch between the NKS application
|
||||
and the SigG application. This avoids to use the DINSIG
|
||||
application which is somewhat limited, has no support for Secure
|
||||
Messaging as required by TCOS 3 and has no way to change the PIN
|
||||
or even set the NullPIN.
|
||||
|
||||
- We use the prefix NKS-DF01 for TCOS 2 cards and NKS-NKS3 for newer
|
||||
cards. This is because the NKS application has moved to DF02 with
|
||||
TCOS 3 and thus we better use a DF independent tag.
|
||||
|
||||
- We use only the global PINs for the NKS application.
|
||||
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
@ -30,9 +51,15 @@
|
||||
#include "iso7816.h"
|
||||
#include "app-common.h"
|
||||
#include "tlv.h"
|
||||
#include "apdu.h"
|
||||
|
||||
static char const aid_nks[] = { 0xD2, 0x76, 0x00, 0x00, 0x03, 0x01, 0x02 };
|
||||
static char const aid_sigg[] = { 0xD2, 0x76, 0x00, 0x00, 0x66, 0x01 };
|
||||
|
||||
|
||||
static struct
|
||||
{
|
||||
int is_sigg; /* Valid for SigG application. */
|
||||
int fid; /* File ID. */
|
||||
int nks_ver; /* 0 for NKS version 2, 3 for version 3. */
|
||||
int certtype; /* Type of certificate or 0 if it is not a certificate. */
|
||||
@ -40,20 +67,23 @@ static struct
|
||||
int issignkey; /* True if file is a key usable for signing. */
|
||||
int isenckey; /* True if file is a key usable for decryption. */
|
||||
} filelist[] = {
|
||||
{ 0x4531, 0, 0, 0xC000, 1, 0 }, /* EF_PK.NKS.SIG */
|
||||
{ 0xC000, 0, 101 }, /* EF_C.NKS.SIG */
|
||||
{ 0x4331, 0, 100 },
|
||||
{ 0x4332, 0, 100 },
|
||||
{ 0xB000, 0, 110 }, /* EF_PK.RCA.NKS */
|
||||
{ 0x45B1, 0, 0, 0xC200, 0, 1 }, /* EF_PK.NKS.ENC */
|
||||
{ 0xC200, 0, 101 }, /* EF_C.NKS.ENC */
|
||||
{ 0x43B1, 0, 100 },
|
||||
{ 0x43B2, 0, 100 },
|
||||
{ 0x4571, 3, 0, 0xc500, 0, 0 }, /* EF_PK.NKS.AUT */
|
||||
{ 0xC500, 3, 101 }, /* EF_C.NKS.AUT */
|
||||
{ 0x45B2, 3, 0, 0xC201, 0, 1 }, /* EF_PK.NKS.ENC1024 */
|
||||
{ 0xC201, 3, 101 }, /* EF_C.NKS.ENC1024 */
|
||||
{ 0 }
|
||||
{ 0, 0x4531, 0, 0, 0xC000, 1, 0 }, /* EF_PK.NKS.SIG */
|
||||
{ 1, 0x4531, 3, 0, 0x0000, 1, 1 }, /* EF_PK.CH.SIG */
|
||||
{ 0, 0xC000, 0, 101 }, /* EF_C.NKS.SIG */
|
||||
{ 1, 0xC000, 0, 101 }, /* EF_C.CH.SIG */
|
||||
{ 0, 0x4331, 0, 100 },
|
||||
{ 0, 0x4332, 0, 100 },
|
||||
{ 0, 0xB000, 0, 110 }, /* EF_PK.RCA.NKS */
|
||||
{ 0, 0x45B1, 0, 0, 0xC200, 0, 1 }, /* EF_PK.NKS.ENC */
|
||||
{ 0, 0xC200, 0, 101 }, /* EF_C.NKS.ENC */
|
||||
{ 0, 0x43B1, 0, 100 },
|
||||
{ 0, 0x43B2, 0, 100 },
|
||||
{ 0, 0x4571, 3, 0, 0xc500, 0, 0 }, /* EF_PK.NKS.AUT */
|
||||
{ 0, 0xC500, 3, 101 }, /* EF_C.NKS.AUT */
|
||||
{ 0, 0x45B2, 3, 0, 0xC201, 0, 1 }, /* EF_PK.NKS.ENC1024 */
|
||||
{ 0, 0xC201, 3, 101 }, /* EF_C.NKS.ENC1024 */
|
||||
/* { 1, 0xB000, 3, ... */
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
|
||||
@ -62,9 +92,13 @@ static struct
|
||||
struct app_local_s {
|
||||
int nks_version; /* NKS version. */
|
||||
|
||||
int sigg_active; /* True if switched to the SigG application. */
|
||||
};
|
||||
|
||||
|
||||
|
||||
static gpg_error_t switch_application (app_t app, int enable_sigg);
|
||||
|
||||
|
||||
|
||||
/* Release local data. */
|
||||
@ -146,6 +180,134 @@ keygripstr_from_pk_file (app_t app, int fid, char *r_gripstr)
|
||||
}
|
||||
|
||||
|
||||
/* TCOS responds to a verify with empty data (i.e. without the Lc
|
||||
byte) with the status of the PIN. PWID is the PIN ID, If SIGG is
|
||||
true, the application is switched into SigG mode.
|
||||
Returns:
|
||||
-1 = Error retrieving the data,
|
||||
-2 = No such PIN,
|
||||
-3 = PIN blocked,
|
||||
-4 = NullPIN activ,
|
||||
n >= 0 = Number of verification attempts left. */
|
||||
static int
|
||||
get_chv_status (app_t app, int sigg, int pwid)
|
||||
{
|
||||
unsigned char *result = NULL;
|
||||
size_t resultlen;
|
||||
char command[4];
|
||||
int rc;
|
||||
|
||||
if (switch_application (app, sigg))
|
||||
return sigg? -2 : -1; /* No such PIN / General error. */
|
||||
|
||||
command[0] = 0x00;
|
||||
command[1] = 0x20;
|
||||
command[2] = 0x00;
|
||||
command[3] = pwid;
|
||||
|
||||
if (apdu_send_direct (app->slot, command, 4, 0, &result, &resultlen))
|
||||
rc = -1; /* Error. */
|
||||
else if (resultlen < 2)
|
||||
rc = -1; /* Error. */
|
||||
else
|
||||
{
|
||||
unsigned int sw = ((result[resultlen-2] << 8) | result[resultlen-1]);
|
||||
|
||||
if (sw == 0x6a88)
|
||||
rc = -2; /* No such PIN. */
|
||||
else if (sw == 0x6983)
|
||||
rc = -3; /* PIN is blocked. */
|
||||
else if (sw == 0x6985)
|
||||
rc = -4; /* NullPIN is activ. */
|
||||
else if ((sw & 0xfff0) == 0x63C0)
|
||||
rc = (sw & 0x000f); /* PIN has N tries left. */
|
||||
else
|
||||
rc = -1; /* Other error. */
|
||||
}
|
||||
xfree (result);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/* Implement the GETATTR command. This is similar to the LEARN
|
||||
command but returns just one value via the status interface. */
|
||||
static gpg_error_t
|
||||
do_getattr (app_t app, ctrl_t ctrl, const char *name)
|
||||
{
|
||||
static struct {
|
||||
const char *name;
|
||||
int special;
|
||||
} table[] = {
|
||||
{ "$AUTHKEYID", 1 },
|
||||
{ "NKS-VERSION", 2 },
|
||||
{ "CHV-STATUS", 3 },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
gpg_error_t err = 0;
|
||||
int idx;
|
||||
char buffer[100];
|
||||
|
||||
err = switch_application (app, 0);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
for (idx=0; table[idx].name && strcmp (table[idx].name, name); idx++)
|
||||
;
|
||||
if (!table[idx].name)
|
||||
return gpg_error (GPG_ERR_INV_NAME);
|
||||
|
||||
switch (table[idx].special)
|
||||
{
|
||||
case 1: /* $AUTHKEYID */
|
||||
{
|
||||
/* NetKey 3.0 cards define this key for authentication.
|
||||
FIXME: We don't have the readkey command, so this
|
||||
information is pretty useless. */
|
||||
char const tmp[] = "NKS-NKS3.4571";
|
||||
send_status_info (ctrl, table[idx].name, tmp, strlen (tmp), NULL, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: /* NKS-VERSION */
|
||||
snprintf (buffer, sizeof buffer, "%d", app->app_local->nks_version);
|
||||
send_status_info (ctrl, table[idx].name,
|
||||
buffer, strlen (buffer), NULL, 0);
|
||||
break;
|
||||
|
||||
case 3: /* CHV-STATUS */
|
||||
{
|
||||
/* Returns: PW1.CH PW2.CH PW1.CH.SIG PW2.CH.SIG That are the
|
||||
two global passwords followed by the two SigG passwords.
|
||||
For the values, see the function get_chv_status. */
|
||||
int tmp[4];
|
||||
|
||||
/* We use a helper array so that we can control that there is
|
||||
no superfluous application switch. Note that PW2.CH.SIG
|
||||
really has the identifier 0x83 and not 0x82 as one would
|
||||
expect. */
|
||||
tmp[0] = get_chv_status (app, 0, 0x00);
|
||||
tmp[1] = get_chv_status (app, 0, 0x01);
|
||||
tmp[2] = get_chv_status (app, 1, 0x81);
|
||||
tmp[3] = get_chv_status (app, 1, 0x83);
|
||||
snprintf (buffer, sizeof buffer,
|
||||
"%d %d %d %d", tmp[0], tmp[1], tmp[2], tmp[3]);
|
||||
send_status_info (ctrl, table[idx].name,
|
||||
buffer, strlen (buffer), NULL, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
|
||||
break;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static gpg_error_t
|
||||
do_learn_status (app_t app, ctrl_t ctrl)
|
||||
@ -154,12 +316,19 @@ do_learn_status (app_t app, ctrl_t ctrl)
|
||||
char ct_buf[100], id_buf[100];
|
||||
int i;
|
||||
|
||||
/* Output information about all useful objects. */
|
||||
err = switch_application (app, 0);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Output information about all useful objects in the NKS application. */
|
||||
for (i=0; filelist[i].fid; i++)
|
||||
{
|
||||
if (filelist[i].nks_ver > app->app_local->nks_version)
|
||||
continue;
|
||||
|
||||
if (filelist[i].is_sigg)
|
||||
continue;
|
||||
|
||||
if (filelist[i].certtype)
|
||||
{
|
||||
size_t len;
|
||||
@ -171,8 +340,10 @@ do_learn_status (app_t app, ctrl_t ctrl)
|
||||
/* FIXME: We should store the length in the application's
|
||||
context so that a following readcert does only need to
|
||||
read that many bytes. */
|
||||
sprintf (ct_buf, "%d", filelist[i].certtype);
|
||||
sprintf (id_buf, "NKS-DF01.%04X", filelist[i].fid);
|
||||
snprintf (ct_buf, sizeof ct_buf, "%d", filelist[i].certtype);
|
||||
snprintf (id_buf, sizeof id_buf, "NKS-%s.%04X",
|
||||
app->app_local->nks_version < 3? "DF01":"NKS3",
|
||||
filelist[i].fid);
|
||||
send_status_info (ctrl, "CERTINFO",
|
||||
ct_buf, strlen (ct_buf),
|
||||
id_buf, strlen (id_buf),
|
||||
@ -189,7 +360,9 @@ do_learn_status (app_t app, ctrl_t ctrl)
|
||||
filelist[i].fid, gpg_strerror (err));
|
||||
else
|
||||
{
|
||||
sprintf (id_buf, "NKS-DF01.%04X", filelist[i].fid);
|
||||
snprintf (id_buf, sizeof id_buf, "NKS-%s.%04X",
|
||||
app->app_local->nks_version < 3? "DF01":"NKS3",
|
||||
filelist[i].fid);
|
||||
send_status_info (ctrl, "KEYPAIRINFO",
|
||||
gripstr, 40,
|
||||
id_buf, strlen (id_buf),
|
||||
@ -198,6 +371,59 @@ do_learn_status (app_t app, ctrl_t ctrl)
|
||||
}
|
||||
}
|
||||
|
||||
err = switch_application (app, 1);
|
||||
if (err)
|
||||
return 0; /* Silently ignore if we can't swicth to SigG. */
|
||||
|
||||
for (i=0; filelist[i].fid; i++)
|
||||
{
|
||||
if (filelist[i].nks_ver > app->app_local->nks_version)
|
||||
continue;
|
||||
|
||||
if (!filelist[i].is_sigg)
|
||||
continue;
|
||||
|
||||
if (filelist[i].certtype)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
len = app_help_read_length_of_cert (app->slot,
|
||||
filelist[i].fid, NULL);
|
||||
if (len)
|
||||
{
|
||||
/* FIXME: We should store the length in the application's
|
||||
context so that a following readcert does only need to
|
||||
read that many bytes. */
|
||||
snprintf (ct_buf, sizeof ct_buf, "%d", filelist[i].certtype);
|
||||
snprintf (id_buf, sizeof id_buf, "NKS-SIGG.%04X",
|
||||
filelist[i].fid);
|
||||
send_status_info (ctrl, "CERTINFO",
|
||||
ct_buf, strlen (ct_buf),
|
||||
id_buf, strlen (id_buf),
|
||||
NULL, (size_t)0);
|
||||
}
|
||||
}
|
||||
else if (filelist[i].iskeypair)
|
||||
{
|
||||
char gripstr[40+1];
|
||||
|
||||
err = keygripstr_from_pk_file (app, filelist[i].fid, gripstr);
|
||||
if (err)
|
||||
log_error ("can't get keygrip from FID 0x%04X: %s\n",
|
||||
filelist[i].fid, gpg_strerror (err));
|
||||
else
|
||||
{
|
||||
snprintf (id_buf, sizeof id_buf, "NKS-SIGG.%04X",
|
||||
filelist[i].fid);
|
||||
send_status_info (ctrl, "KEYPAIRINFO",
|
||||
gripstr, 40,
|
||||
id_buf, strlen (id_buf),
|
||||
NULL, (size_t)0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -223,7 +449,16 @@ do_readcert (app_t app, const char *certid,
|
||||
|
||||
*cert = NULL;
|
||||
*certlen = 0;
|
||||
if (strncmp (certid, "NKS-DF01.", 9) )
|
||||
|
||||
err = switch_application (app, 0);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (!strncmp (certid, "NKS-NKS3.", 9))
|
||||
;
|
||||
else if (!strncmp (certid, "NKS-DF01.", 9))
|
||||
;
|
||||
else
|
||||
return gpg_error (GPG_ERR_INV_ID);
|
||||
certid += 9;
|
||||
if (!hexdigitp (certid) || !hexdigitp (certid+1)
|
||||
@ -331,21 +566,34 @@ do_readcert (app_t app, const char *certid,
|
||||
}
|
||||
|
||||
|
||||
static gpg_error_t
|
||||
basic_pin_checks (const char *pinvalue, int minlen, int maxlen)
|
||||
{
|
||||
if (strlen (pinvalue) < minlen)
|
||||
{
|
||||
log_error ("PIN is too short; minimum length is %d\n", minlen);
|
||||
return gpg_error (GPG_ERR_BAD_PIN);
|
||||
}
|
||||
if (strlen (pinvalue) > maxlen)
|
||||
{
|
||||
log_error ("PIN is too large; maximum length is %d\n", maxlen);
|
||||
return gpg_error (GPG_ERR_BAD_PIN);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Verify the PIN if required. */
|
||||
static gpg_error_t
|
||||
verify_pin (app_t app,
|
||||
verify_pin (app_t app, int pwid, const char *desc,
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg)
|
||||
{
|
||||
iso7816_pininfo_t pininfo;
|
||||
int rc;
|
||||
|
||||
/* Note that force_chv1 is never set but we do it here anyway so
|
||||
that other applications may reuse this function. For example it
|
||||
makes sense to set force_chv1 for German signature law cards.
|
||||
NKS is very similar to the DINSIG draft standard. */
|
||||
if ( app->did_chv1 && !app->force_chv1 )
|
||||
return 0; /* No need to verify it again. */
|
||||
if (!desc)
|
||||
desc = "PIN";
|
||||
|
||||
memset (&pininfo, 0, sizeof pininfo);
|
||||
pininfo.mode = 1;
|
||||
@ -375,7 +623,7 @@ verify_pin (app_t app,
|
||||
{
|
||||
char *pinvalue;
|
||||
|
||||
rc = pincb (pincb_arg, "PIN", &pinvalue);
|
||||
rc = pincb (pincb_arg, desc, &pinvalue);
|
||||
if (rc)
|
||||
{
|
||||
log_info ("PIN callback returned error: %s\n", gpg_strerror (rc));
|
||||
@ -384,24 +632,14 @@ verify_pin (app_t app,
|
||||
|
||||
/* The following limits are due to TCOS but also defined in the
|
||||
NKS specs. */
|
||||
if (strlen (pinvalue) < pininfo.minlen)
|
||||
rc = basic_pin_checks (pinvalue, pininfo.minlen, pininfo.maxlen);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("PIN is too short; minimum length is %d\n",
|
||||
pininfo.minlen);
|
||||
xfree (pinvalue);
|
||||
return gpg_error (GPG_ERR_BAD_PIN);
|
||||
}
|
||||
else if (strlen (pinvalue) > pininfo.maxlen)
|
||||
{
|
||||
log_error ("PIN is too large; maximum length is %d\n",
|
||||
pininfo.maxlen);
|
||||
xfree (pinvalue);
|
||||
return gpg_error (GPG_ERR_BAD_PIN);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Although it is possible to use a local PIN, we use the global
|
||||
PIN for this application. */
|
||||
rc = iso7816_verify (app->slot, 0, pinvalue, strlen (pinvalue));
|
||||
rc = iso7816_verify (app->slot, pwid, pinvalue, strlen (pinvalue));
|
||||
xfree (pinvalue);
|
||||
}
|
||||
|
||||
@ -413,7 +651,6 @@ verify_pin (app_t app,
|
||||
log_error ("verify PIN failed\n");
|
||||
return rc;
|
||||
}
|
||||
app->did_chv1 = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -447,9 +684,17 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
|
||||
if (indatalen != 20 && indatalen != 16 && indatalen != 35)
|
||||
return gpg_error (GPG_ERR_INV_VALUE);
|
||||
|
||||
rc = switch_application (app, 0);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* Check that the provided ID is valid. This is not really needed
|
||||
but we do it to enforce correct usage by the caller. */
|
||||
if (strncmp (keyidstr, "NKS-DF01.", 9) )
|
||||
if (!strncmp (keyidstr, "NKS-NKS3.", 9) )
|
||||
;
|
||||
else if (!strncmp (keyidstr, "NKS-DF01.", 9) )
|
||||
;
|
||||
else
|
||||
return gpg_error (GPG_ERR_INV_ID);
|
||||
keyidstr += 9;
|
||||
if (!hexdigitp (keyidstr) || !hexdigitp (keyidstr+1)
|
||||
@ -490,7 +735,7 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
|
||||
memcpy (data+15, indata, indatalen);
|
||||
}
|
||||
|
||||
rc = verify_pin (app, pincb, pincb_arg);
|
||||
rc = verify_pin (app, 0, NULL, pincb, pincb_arg);
|
||||
if (!rc)
|
||||
rc = iso7816_compute_ds (app->slot, data, 35, outdata, outdatalen);
|
||||
return rc;
|
||||
@ -519,9 +764,17 @@ do_decipher (app_t app, const char *keyidstr,
|
||||
if (!keyidstr || !*keyidstr || !indatalen)
|
||||
return gpg_error (GPG_ERR_INV_VALUE);
|
||||
|
||||
rc = switch_application (app, 0);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* Check that the provided ID is valid. This is not really needed
|
||||
but we do it to to enforce correct usage by the caller. */
|
||||
if (strncmp (keyidstr, "NKS-DF01.", 9) )
|
||||
if (!strncmp (keyidstr, "NKS-NKS3.", 9) )
|
||||
;
|
||||
else if (!strncmp (keyidstr, "NKS-DF01.", 9) )
|
||||
;
|
||||
else
|
||||
return gpg_error (GPG_ERR_INV_ID);
|
||||
keyidstr += 9;
|
||||
if (!hexdigitp (keyidstr) || !hexdigitp (keyidstr+1)
|
||||
@ -542,7 +795,7 @@ do_decipher (app_t app, const char *keyidstr,
|
||||
0xC1, 0xB8,
|
||||
mse_parm, sizeof mse_parm);
|
||||
if (!rc)
|
||||
rc = verify_pin (app, pincb, pincb_arg);
|
||||
rc = verify_pin (app, 0, NULL, pincb, pincb_arg);
|
||||
if (!rc)
|
||||
rc = iso7816_decipher (app->slot, indata, indatalen, 0x81,
|
||||
outdata, outdatalen);
|
||||
@ -550,67 +803,221 @@ do_decipher (app_t app, const char *keyidstr,
|
||||
}
|
||||
|
||||
|
||||
/* Handle the PASSWD command. CHVNOSTR is currently ignored; we
|
||||
always use VHV0. RESET_MODE is not yet implemented. */
|
||||
|
||||
/* Parse a password ID string. Returns NULL on error or a string
|
||||
suitable as passpahrse prompt on success. On success stores the
|
||||
reference value for the password at R_PWID and a flag indicating
|
||||
that the SigG application is to be used at R_SIGG. If NEW_MODE is
|
||||
true, the returned description is suitable for a new Password.
|
||||
Supported values for PWIDSTR are:
|
||||
|
||||
PW1.CH - Global password 1
|
||||
PW2.CH - Global password 2
|
||||
PW1.CH.SIG - SigG password 1
|
||||
PW2.CH.SIG - SigG password 2
|
||||
*/
|
||||
static const char *
|
||||
parse_pwidstr (const char *pwidstr, int new_mode, int *r_sigg, int *r_pwid)
|
||||
{
|
||||
const char *desc;
|
||||
|
||||
if (!pwidstr)
|
||||
desc = NULL;
|
||||
else if (!strcmp (pwidstr, "PW1.CH"))
|
||||
{
|
||||
*r_sigg = 0;
|
||||
*r_pwid = 0x00;
|
||||
/* TRANSLATORS: Do not translate the "|*|" prefixes but keep
|
||||
them verbatim at the start of the string. */
|
||||
desc = (new_mode
|
||||
? _("|N|Please enter a new PIN for the standard keys.")
|
||||
: _("||Please enter the PIN for the standard keys."));
|
||||
}
|
||||
else if (!strcmp (pwidstr, "PW2.CH"))
|
||||
{
|
||||
*r_pwid = 0x01;
|
||||
desc = (new_mode
|
||||
? _("|NP|Please enter a new PIN Unblocking Code (PUK) "
|
||||
"for the standard keys.")
|
||||
: _("|P|Please enter the PIN Unblocking Code (PUK) "
|
||||
"for the standard keys."));
|
||||
}
|
||||
else if (!strcmp (pwidstr, "PW1.CH.SIG"))
|
||||
{
|
||||
*r_pwid = 0x81;
|
||||
*r_sigg = 1;
|
||||
desc = (new_mode
|
||||
? _("|N|Please enter a new PIN for the key to create "
|
||||
"qualified signatures.")
|
||||
: _("||Please enter the PIN for the key to create "
|
||||
"qualified signatures."));
|
||||
}
|
||||
else if (!strcmp (pwidstr, "PW2.CH.SIG"))
|
||||
{
|
||||
*r_pwid = 0x83; /* Yes, that is 83 and not 82. */
|
||||
*r_sigg = 1;
|
||||
desc = (new_mode
|
||||
? _("|NP|Please enter a new PIN Unblocking Code (PUK) "
|
||||
"for the key to create qualified signatures.")
|
||||
: _("|P|Please enter the PIN Unblocking Code (PUK) "
|
||||
"for the key to create qualified signatures."));
|
||||
}
|
||||
else
|
||||
desc = NULL;
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
|
||||
/* Handle the PASSWD command. See parse_pwidstr() for allowed values
|
||||
for CHVNOSTR. */
|
||||
static gpg_error_t
|
||||
do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr,
|
||||
do_change_pin (app_t app, ctrl_t ctrl, const char *pwidstr,
|
||||
unsigned int flags,
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg)
|
||||
{
|
||||
gpg_error_t err;
|
||||
char *pinvalue;
|
||||
const char *oldpin;
|
||||
char *newpin = NULL;
|
||||
char *oldpin = NULL;
|
||||
size_t newpinlen;
|
||||
size_t oldpinlen;
|
||||
int is_sigg;
|
||||
const char *newdesc;
|
||||
int pwid;
|
||||
iso7816_pininfo_t pininfo;
|
||||
|
||||
(void)ctrl;
|
||||
(void)chvnostr;
|
||||
|
||||
if ((flags & APP_CHANGE_FLAG_RESET))
|
||||
return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
|
||||
/* The minimum length is enforced by TCOS, the maximum length is
|
||||
just a reasonable value. */
|
||||
memset (&pininfo, 0, sizeof pininfo);
|
||||
pininfo.minlen = 6;
|
||||
pininfo.maxlen = 16;
|
||||
|
||||
newdesc = parse_pwidstr (pwidstr, 1, &is_sigg, &pwid);
|
||||
if (!newdesc)
|
||||
return gpg_error (GPG_ERR_INV_ID);
|
||||
|
||||
err = switch_application (app, is_sigg);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if ((flags & APP_CHANGE_FLAG_NULLPIN))
|
||||
{
|
||||
/* With the nullpin flag, we do not verify the PIN - it would fail
|
||||
if the Nullpin is still set. */
|
||||
oldpin = "\0\0\0\0\0";
|
||||
/* With the nullpin flag, we do not verify the PIN - it would
|
||||
fail if the Nullpin is still set. */
|
||||
oldpin = xtrycalloc (1, 6);
|
||||
if (!oldpin)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
goto leave;
|
||||
}
|
||||
oldpinlen = 6;
|
||||
}
|
||||
else
|
||||
{
|
||||
err = verify_pin (app, pincb, pincb_arg);
|
||||
const char *desc;
|
||||
int dummy1, dummy2;
|
||||
|
||||
if ((flags & APP_CHANGE_FLAG_RESET))
|
||||
{
|
||||
/* Reset mode: Ask for the alternate PIN. */
|
||||
const char *altpwidstr;
|
||||
|
||||
if (!strcmp (pwidstr, "PW1.CH"))
|
||||
altpwidstr = "PW2.CH";
|
||||
else if (!strcmp (pwidstr, "PW2.CH"))
|
||||
altpwidstr = "PW1.CH";
|
||||
else if (!strcmp (pwidstr, "PW1.CH.SIG"))
|
||||
altpwidstr = "PW2.CH.SIG";
|
||||
else if (!strcmp (pwidstr, "PW2.CH.SIG"))
|
||||
altpwidstr = "PW1.CH.SIG";
|
||||
else
|
||||
{
|
||||
err = gpg_error (GPG_ERR_BUG);
|
||||
goto leave;
|
||||
}
|
||||
desc = parse_pwidstr (altpwidstr, 0, &dummy1, &dummy2);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Regular change mode: Ask for the old PIN. */
|
||||
desc = parse_pwidstr (pwidstr, 0, &dummy1, &dummy2);
|
||||
}
|
||||
err = pincb (pincb_arg, desc, &oldpin);
|
||||
if (err)
|
||||
return err;
|
||||
oldpin = NULL;
|
||||
oldpinlen = 0;
|
||||
{
|
||||
log_error ("error getting old PIN: %s\n", gpg_strerror (err));
|
||||
goto leave;
|
||||
}
|
||||
oldpinlen = strlen (oldpin);
|
||||
err = basic_pin_checks (oldpin, pininfo.minlen, pininfo.maxlen);
|
||||
if (err)
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* TRANSLATORS: Do not translate the "|*|" prefixes but
|
||||
keep it at the start of the string. We need this elsewhere
|
||||
to get some infos on the string. */
|
||||
err = pincb (pincb_arg, _("|N|New PIN"), &pinvalue);
|
||||
err = pincb (pincb_arg, newdesc, &newpin);
|
||||
if (err)
|
||||
{
|
||||
log_error (_("error getting new PIN: %s\n"), gpg_strerror (err));
|
||||
return err;
|
||||
goto leave;
|
||||
}
|
||||
newpinlen = strlen (newpin);
|
||||
|
||||
err = iso7816_change_reference_data (app->slot, 0x00,
|
||||
err = basic_pin_checks (newpin, pininfo.minlen, pininfo.maxlen);
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
if ((flags & APP_CHANGE_FLAG_RESET))
|
||||
{
|
||||
char *data;
|
||||
size_t datalen = oldpinlen + newpinlen;
|
||||
|
||||
data = xtrymalloc (datalen);
|
||||
if (!data)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
goto leave;
|
||||
}
|
||||
memcpy (data, oldpin, oldpinlen);
|
||||
memcpy (data+oldpinlen, newpin, newpinlen);
|
||||
err = iso7816_reset_retry_counter_with_rc (app->slot, pwid,
|
||||
data, datalen);
|
||||
wipememory (data, datalen);
|
||||
xfree (data);
|
||||
}
|
||||
else
|
||||
err = iso7816_change_reference_data (app->slot, pwid,
|
||||
oldpin, oldpinlen,
|
||||
pinvalue, strlen (pinvalue));
|
||||
xfree (pinvalue);
|
||||
newpin, newpinlen);
|
||||
leave:
|
||||
xfree (oldpin);
|
||||
xfree (newpin);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/* Perform a simple verify operation. KEYIDSTR should be NULL or empty. */
|
||||
static gpg_error_t
|
||||
do_check_pin (app_t app, const char *keyidstr,
|
||||
do_check_pin (app_t app, const char *pwidstr,
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg)
|
||||
{
|
||||
(void)keyidstr;
|
||||
return verify_pin (app, pincb, pincb_arg);
|
||||
gpg_error_t err;
|
||||
int pwid;
|
||||
int is_sigg;
|
||||
const char *desc;
|
||||
|
||||
desc = parse_pwidstr (pwidstr, 0, &is_sigg, &pwid);
|
||||
if (!desc)
|
||||
return gpg_error (GPG_ERR_INV_ID);
|
||||
|
||||
err = switch_application (app, is_sigg);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return verify_pin (app, pwid, desc, pincb, pincb_arg);
|
||||
}
|
||||
|
||||
|
||||
@ -647,15 +1054,42 @@ get_nks_version (int slot)
|
||||
}
|
||||
|
||||
|
||||
/* If ENABLE_SIGG is true switch to the SigG application if not yet
|
||||
active. If false switch to the NKS application if not yet active.
|
||||
Returns 0 on success. */
|
||||
static gpg_error_t
|
||||
switch_application (app_t app, int enable_sigg)
|
||||
{
|
||||
gpg_error_t err;
|
||||
|
||||
if ((app->app_local->sigg_active && enable_sigg)
|
||||
|| (!app->app_local->sigg_active && !enable_sigg) )
|
||||
return 0; /* Already switched. */
|
||||
|
||||
log_info ("app-nks: switching to %s\n", enable_sigg? "SigG":"NKS");
|
||||
if (enable_sigg)
|
||||
err = iso7816_select_application (app->slot, aid_sigg, sizeof aid_sigg, 0);
|
||||
else
|
||||
err = iso7816_select_application (app->slot, aid_nks, sizeof aid_nks, 0);
|
||||
|
||||
if (!err)
|
||||
app->app_local->sigg_active = enable_sigg;
|
||||
else
|
||||
log_error ("app-nks: error switching to %s: %s\n",
|
||||
enable_sigg? "SigG":"NKS", gpg_strerror (err));
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/* Select the NKS application. */
|
||||
gpg_error_t
|
||||
app_select_nks (app_t app)
|
||||
{
|
||||
static char const aid[] = { 0xD2, 0x76, 0x00, 0x00, 0x03, 0x01, 0x02 };
|
||||
int slot = app->slot;
|
||||
int rc;
|
||||
|
||||
rc = iso7816_select_application (slot, aid, sizeof aid, 0);
|
||||
rc = iso7816_select_application (slot, aid_nks, sizeof aid_nks, 0);
|
||||
if (!rc)
|
||||
{
|
||||
app->apptype = "NKS";
|
||||
@ -674,7 +1108,7 @@ app_select_nks (app_t app)
|
||||
app->fnc.deinit = do_deinit;
|
||||
app->fnc.learn_status = do_learn_status;
|
||||
app->fnc.readcert = do_readcert;
|
||||
app->fnc.getattr = NULL;
|
||||
app->fnc.getattr = do_getattr;
|
||||
app->fnc.setattr = NULL;
|
||||
app->fnc.genkey = NULL;
|
||||
app->fnc.sign = do_sign;
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* app-openpgp.c - The OpenPGP card application.
|
||||
* Copyright (C) 2003, 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2003, 2004, 2005, 2007, 2008,
|
||||
* 2009 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
@ -1402,7 +1403,8 @@ verify_a_chv (app_t app,
|
||||
int chvno, unsigned long sigcount, char **pinvalue)
|
||||
{
|
||||
int rc = 0;
|
||||
char *prompt;
|
||||
char *prompt_buffer = NULL;
|
||||
const char *prompt;
|
||||
iso7816_pininfo_t pininfo;
|
||||
int minlen = 6;
|
||||
|
||||
@ -1433,29 +1435,33 @@ verify_a_chv (app_t app,
|
||||
pininfo.mode = 1;
|
||||
pininfo.minlen = minlen;
|
||||
|
||||
if (!opt.disable_keypad
|
||||
&& !iso7816_check_keypad (app->slot, ISO7816_VERIFY, &pininfo) )
|
||||
{
|
||||
/* The reader supports the verify command through the keypad. */
|
||||
|
||||
if (chvno == 1)
|
||||
{
|
||||
#define PROMPTSTRING _("||Please enter your PIN at the reader's keypad%%0A" \
|
||||
"[sigs done: %lu]")
|
||||
#define PROMPTSTRING _("||Please enter the PIN%%0A[sigs done: %lu]")
|
||||
size_t promptsize = strlen (PROMPTSTRING) + 50;
|
||||
|
||||
prompt = xmalloc (promptsize);
|
||||
if (!prompt)
|
||||
prompt_buffer = xtrymalloc (promptsize);
|
||||
if (!prompt_buffer)
|
||||
return gpg_error_from_syserror ();
|
||||
snprintf (prompt, promptsize-1, PROMPTSTRING, sigcount);
|
||||
rc = pincb (pincb_arg, prompt, NULL);
|
||||
xfree (prompt);
|
||||
snprintf (prompt_buffer, promptsize-1, PROMPTSTRING, sigcount);
|
||||
prompt = prompt_buffer;
|
||||
#undef PROMPTSTRING
|
||||
}
|
||||
else
|
||||
rc = pincb (pincb_arg,
|
||||
_("||Please enter your PIN at the reader's keypad"),
|
||||
NULL);
|
||||
prompt = _("||Please enter the PIN");
|
||||
|
||||
|
||||
if (!opt.disable_keypad
|
||||
&& !iso7816_check_keypad (app->slot, ISO7816_VERIFY, &pininfo) )
|
||||
{
|
||||
/* The reader supports the verify command through the keypad.
|
||||
Note that the pincb appends a text to the prompt telling the
|
||||
user to use the keypad. */
|
||||
rc = pincb (pincb_arg, prompt, NULL);
|
||||
prompt = NULL;
|
||||
xfree (prompt_buffer);
|
||||
prompt_buffer = NULL;
|
||||
if (rc)
|
||||
{
|
||||
log_info (_("PIN callback returned error: %s\n"),
|
||||
@ -1471,23 +1477,10 @@ verify_a_chv (app_t app,
|
||||
else
|
||||
{
|
||||
/* The reader has no keypad or we don't want to use it. */
|
||||
|
||||
if (chvno == 1)
|
||||
{
|
||||
#define PROMPTSTRING _("||Please enter the PIN%%0A[sigs done: %lu]")
|
||||
size_t promptsize = strlen (PROMPTSTRING) + 50;
|
||||
|
||||
prompt = xtrymalloc (promptsize);
|
||||
if (!prompt)
|
||||
return gpg_error_from_syserror ();
|
||||
snprintf (prompt, promptsize-1, PROMPTSTRING, sigcount);
|
||||
rc = pincb (pincb_arg, prompt, pinvalue);
|
||||
xfree (prompt);
|
||||
#undef PROMPTSTRING
|
||||
}
|
||||
else
|
||||
rc = pincb (pincb_arg, _("||Please enter the PIN"), pinvalue);
|
||||
|
||||
prompt = NULL;
|
||||
xfree (prompt_buffer);
|
||||
prompt_buffer = NULL;
|
||||
if (rc)
|
||||
{
|
||||
log_info (_("PIN callback returned error: %s\n"),
|
||||
@ -1586,6 +1579,8 @@ verify_chv3 (app_t app,
|
||||
iso7816_pininfo_t pininfo;
|
||||
int minlen = 8;
|
||||
int remaining;
|
||||
char *prompt_buffer = NULL;
|
||||
const char *prompt;
|
||||
|
||||
memset (&pininfo, 0, sizeof pininfo);
|
||||
pininfo.mode = 1;
|
||||
@ -1610,31 +1605,33 @@ verify_chv3 (app_t app,
|
||||
log_info(_("%d Admin PIN attempts remaining before card"
|
||||
" is permanently locked\n"), remaining);
|
||||
|
||||
if (remaining < 3)
|
||||
{
|
||||
/* TRANSLATORS: Do not translate the "|A|" prefix but keep
|
||||
it at the start of the string. Use %%0A to force a
|
||||
lienfeed. */
|
||||
#define PROMPTSTRING _("|A|Please enter the Admin PIN%%0A" \
|
||||
"[remaining attempts: %d]")
|
||||
size_t promptsize = strlen (PROMPTSTRING) + 50;
|
||||
|
||||
prompt_buffer = xtrymalloc (promptsize);
|
||||
if (!prompt_buffer)
|
||||
return gpg_error_from_syserror ();
|
||||
snprintf (prompt_buffer, promptsize-1, PROMPTSTRING, remaining);
|
||||
prompt = prompt_buffer;
|
||||
#undef PROMPTSTRING
|
||||
}
|
||||
else
|
||||
prompt = _("|A|Please enter the Admin PIN");
|
||||
|
||||
if (!opt.disable_keypad
|
||||
&& !iso7816_check_keypad (app->slot, ISO7816_VERIFY, &pininfo) )
|
||||
{
|
||||
/* The reader supports the verify command through the keypad. */
|
||||
|
||||
if (remaining < 3)
|
||||
{
|
||||
#define PROMPTSTRING _("|A|Please enter the Admin PIN" \
|
||||
" at the reader's keypad%%0A" \
|
||||
"[remaining attempts: %d]")
|
||||
size_t promptsize = strlen (PROMPTSTRING) + 50;
|
||||
char *prompt;
|
||||
|
||||
prompt = xmalloc (promptsize);
|
||||
if (!prompt)
|
||||
return gpg_error_from_syserror ();
|
||||
snprintf (prompt, promptsize-1, PROMPTSTRING, remaining);
|
||||
rc = pincb (pincb_arg, prompt, NULL);
|
||||
xfree (prompt);
|
||||
#undef PROMPTSTRING
|
||||
}
|
||||
else
|
||||
rc = pincb (pincb_arg, _("|A|Please enter the Admin PIN"
|
||||
" at the reader's keypad"), NULL);
|
||||
|
||||
prompt = NULL;
|
||||
xfree (prompt_buffer);
|
||||
prompt_buffer = NULL;
|
||||
if (rc)
|
||||
{
|
||||
log_info (_("PIN callback returned error: %s\n"),
|
||||
@ -1649,10 +1646,10 @@ verify_chv3 (app_t app,
|
||||
{
|
||||
char *pinvalue;
|
||||
|
||||
/* TRANSLATORS: Do not translate the "|A|" prefix but keep
|
||||
it at the start of the string. We need this elsewhere to
|
||||
get some infos on the string. */
|
||||
rc = pincb (pincb_arg, _("|A|Admin PIN"), &pinvalue);
|
||||
rc = pincb (pincb_arg, prompt, &pinvalue);
|
||||
prompt = NULL;
|
||||
xfree (prompt_buffer);
|
||||
prompt_buffer = NULL;
|
||||
if (rc)
|
||||
{
|
||||
log_info (_("PIN callback returned error: %s\n"),
|
||||
|
@ -1370,9 +1370,10 @@ cmd_random (assuan_context_t ctx, char *line)
|
||||
|
||||
/* PASSWD [--reset] [--nullpin] <chvno>
|
||||
|
||||
Change the PIN or reset the retry counter of the card holder
|
||||
verfication vector CHVNO. The option --nullpin is used for TCOS
|
||||
cards to set the initial PIN. */
|
||||
Change the PIN or, if --reset is given, reset the retry counter of
|
||||
the card holder verfication vector CHVNO. The option --nullpin is
|
||||
used for TCOS cards to set the initial PIN. The format of CHVNO
|
||||
depends on the card application. */
|
||||
static int
|
||||
cmd_passwd (assuan_context_t ctx, char *line)
|
||||
{
|
||||
@ -1435,13 +1436,27 @@ cmd_passwd (assuan_context_t ctx, char *line)
|
||||
literal string "[CHV3]": In this case the Admin PIN is checked
|
||||
if and only if the retry counter is still at 3.
|
||||
|
||||
For Netkey:
|
||||
|
||||
Any of the valid PIN Ids may be used. These are the strings:
|
||||
|
||||
PW1.CH - Global password 1
|
||||
PW2.CH - Global password 2
|
||||
PW1.CH.SIG - SigG password 1
|
||||
PW2.CH.SIG - SigG password 2
|
||||
|
||||
For a definitive list, see the implementation in app-nks.c.
|
||||
Note that we call a PW2.* PIN a "PUK" despite that since TCOS
|
||||
3.0 they are technically alternative PINs used to mutally
|
||||
unblock each other.
|
||||
|
||||
*/
|
||||
static int
|
||||
cmd_checkpin (assuan_context_t ctx, char *line)
|
||||
{
|
||||
ctrl_t ctrl = assuan_get_pointer (ctx);
|
||||
int rc;
|
||||
char *keyidstr;
|
||||
char *idstr;
|
||||
|
||||
if ( IS_LOCKED (ctrl) )
|
||||
return gpg_error (GPG_ERR_LOCKED);
|
||||
@ -1455,14 +1470,12 @@ cmd_checkpin (assuan_context_t ctx, char *line)
|
||||
/* We have to use a copy of the key ID because the function may use
|
||||
the pin_cb which in turn uses the assuan line buffer and thus
|
||||
overwriting the original line with the keyid. */
|
||||
keyidstr = xtrystrdup (line);
|
||||
if (!keyidstr)
|
||||
idstr = xtrystrdup (line);
|
||||
if (!idstr)
|
||||
return out_of_core ();
|
||||
|
||||
rc = app_check_pin (ctrl->app_ctx,
|
||||
keyidstr,
|
||||
pin_cb, ctx);
|
||||
xfree (keyidstr);
|
||||
rc = app_check_pin (ctrl->app_ctx, idstr, pin_cb, ctx);
|
||||
xfree (idstr);
|
||||
if (rc)
|
||||
log_error ("app_check_pin failed: %s\n", gpg_strerror (rc));
|
||||
|
||||
@ -1566,7 +1579,7 @@ cmd_unlock (assuan_context_t ctx, char *line)
|
||||
deny_admin - Returns OK if admin commands are not allowed or
|
||||
GPG_ERR_GENERAL if admin commands are allowed.
|
||||
|
||||
app_list - Return a list of supported applciations. One
|
||||
app_list - Return a list of supported applications. One
|
||||
application per line, fields delimited by colons,
|
||||
first field is the name.
|
||||
*/
|
||||
|
Loading…
x
Reference in New Issue
Block a user