mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
Finished support for v2 cards with the exception of secure messaging.
This commit is contained in:
parent
0d71795aae
commit
96f16f736e
22
NEWS
22
NEWS
@ -4,31 +4,35 @@ Noteworthy changes in version 2.0.10 (unreleased)
|
|||||||
* New keyserver helper gpg2keys_kdns as generic DNS CERT lookup. Run
|
* New keyserver helper gpg2keys_kdns as generic DNS CERT lookup. Run
|
||||||
with --help for a short description. Requires the ADNS library.
|
with --help for a short description. Requires the ADNS library.
|
||||||
|
|
||||||
* New mechanisms "local" and "nodefault" for --auto-key-locate [gpg].
|
* [gpg] New mechanisms "local" and "nodefault" for --auto-key-locate.
|
||||||
Fixed a few problems with this option.
|
Fixed a few problems with this option.
|
||||||
|
|
||||||
* [W32] Initialized the socket subsystem for all keyserver helpers.
|
* [w32] Initialized the socket subsystem for all keyserver helpers.
|
||||||
|
|
||||||
* [W32] The sysconf directory has been moved from a subdirectory of
|
* [w32] The sysconf directory has been moved from a subdirectory of
|
||||||
the installation directory to %CSIDL_COMMON_APPDATA%/GNU/etc/gnupg.
|
the installation directory to %CSIDL_COMMON_APPDATA%/GNU/etc/gnupg.
|
||||||
|
|
||||||
* New gpg2 command --locate-keys.
|
* [gpg] New command --locate-keys.
|
||||||
|
|
||||||
* New gpg2 options --with-sig-list and --with-sig-check.
|
* [gpg] New options --with-sig-list and --with-sig-check.
|
||||||
|
|
||||||
* Made gpgsm's --output option work with --export-secret-key-p12.
|
* [gpgsm] Made --output option work with --export-secret-key-p12.
|
||||||
|
|
||||||
* gpg-connect-agent accepts commands given as command line arguments.
|
* gpg-connect-agent accepts commands given as command line arguments.
|
||||||
|
|
||||||
* The gpg2 option --fixed-list-mode is now implicitly used and obsolete.
|
* [gpg] The option --fixed-list-mode is now implicitly used and obsolete.
|
||||||
|
|
||||||
* New control statement %ask-passphrase for the unattended key
|
* [gpg] New control statement %ask-passphrase for the unattended key
|
||||||
generation of gpg2.
|
generation.
|
||||||
|
|
||||||
* gpgsm now uses AES by default.
|
* gpgsm now uses AES by default.
|
||||||
|
|
||||||
* gpg-preset-passphrase works again.
|
* gpg-preset-passphrase works again.
|
||||||
|
|
||||||
|
* Admin PINs are cached again (bug in 2.0.9).
|
||||||
|
|
||||||
|
* Support for version 2 OpenPGP cards.
|
||||||
|
|
||||||
|
|
||||||
Noteworthy changes in version 2.0.9 (2008-03-26)
|
Noteworthy changes in version 2.0.9 (2008-03-26)
|
||||||
------------------------------------------------
|
------------------------------------------------
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
|
2008-09-25 Werner Koch <wk@g10code.com>
|
||||||
|
|
||||||
|
* divert-scd.c (getpin_cb): Support a Reset Code style PINs..
|
||||||
|
|
||||||
2008-09-03 Werner Koch <wk@g10code.com>
|
2008-09-03 Werner Koch <wk@g10code.com>
|
||||||
|
|
||||||
* command.c (parse_keygrip): Use hex2bin.
|
* command.c (parse_keygrip): Use hex2bin.
|
||||||
|
@ -185,6 +185,7 @@ encode_md_for_card (const unsigned char *digest, size_t digestlen, int algo,
|
|||||||
PIN. If the PIN is not correctly repeated it starts from
|
PIN. If the PIN is not correctly repeated it starts from
|
||||||
all over.
|
all over.
|
||||||
'A' = The PIN is an Admin PIN, SO-PIN, PUK or alike.
|
'A' = The PIN is an Admin PIN, SO-PIN, PUK or alike.
|
||||||
|
'R' = The PIN is a Reset Code.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
@ -202,6 +203,7 @@ getpin_cb (void *opaque, const char *info, char *buf, size_t maxbuf)
|
|||||||
const char *ends, *s;
|
const char *ends, *s;
|
||||||
int any_flags = 0;
|
int any_flags = 0;
|
||||||
int newpin = 0;
|
int newpin = 0;
|
||||||
|
int resetcode = 0;
|
||||||
const char *again_text = NULL;
|
const char *again_text = NULL;
|
||||||
const char *prompt = "PIN";
|
const char *prompt = "PIN";
|
||||||
|
|
||||||
@ -217,6 +219,11 @@ getpin_cb (void *opaque, const char *info, char *buf, size_t maxbuf)
|
|||||||
prompt = _("Admin PIN");
|
prompt = _("Admin PIN");
|
||||||
else if (*s == 'N')
|
else if (*s == 'N')
|
||||||
newpin = 1;
|
newpin = 1;
|
||||||
|
else if (*s == 'R')
|
||||||
|
{
|
||||||
|
prompt = _("Reset Code");
|
||||||
|
resetcode = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
info = ends+1;
|
info = ends+1;
|
||||||
any_flags = 1;
|
any_flags = 1;
|
||||||
@ -272,10 +279,16 @@ getpin_cb (void *opaque, const char *info, char *buf, size_t maxbuf)
|
|||||||
pi2->min_digits = 0;
|
pi2->min_digits = 0;
|
||||||
pi2->max_digits = 8;
|
pi2->max_digits = 8;
|
||||||
pi2->max_tries = 1;
|
pi2->max_tries = 1;
|
||||||
rc = agent_askpin (ctrl, _("Repeat this PIN"), prompt, NULL, pi2);
|
rc = agent_askpin (ctrl,
|
||||||
|
(resetcode?
|
||||||
|
_("Repeat this Reset Code"):
|
||||||
|
_("Repeat this PIN")),
|
||||||
|
prompt, NULL, pi2);
|
||||||
if (!rc && strcmp (pi->pin, pi2->pin))
|
if (!rc && strcmp (pi->pin, pi2->pin))
|
||||||
{
|
{
|
||||||
again_text = N_("PIN not correctly repeated; try again");
|
again_text = (resetcode?
|
||||||
|
N_("Reset Code not correctly repeated; try again"):
|
||||||
|
N_("PIN not correctly repeated; try again"));
|
||||||
xfree (pi2);
|
xfree (pi2);
|
||||||
xfree (pi);
|
xfree (pi);
|
||||||
goto again;
|
goto again;
|
||||||
|
@ -1,3 +1,16 @@
|
|||||||
|
2008-09-25 Werner Koch <wk@g10code.com>
|
||||||
|
|
||||||
|
* card-util.c (change_pin): Support setting of the reset code.
|
||||||
|
|
||||||
|
2008-09-24 Werner Koch <wk@g10code.com>
|
||||||
|
|
||||||
|
* call-agent.h (struct agent_card_info_s): Add field IS_V2.
|
||||||
|
* call-agent.c (learn_status_cb): That that field.
|
||||||
|
|
||||||
|
* card-util.c (change_pin): Rename first arg to UNBLOCK_v2 and use
|
||||||
|
it this way.
|
||||||
|
(card_edit): Add new command UNBLOCK.
|
||||||
|
|
||||||
2008-09-23 David Shaw <dshaw@jabberwocky.com>
|
2008-09-23 David Shaw <dshaw@jabberwocky.com>
|
||||||
|
|
||||||
* pkclist.c (select_algo_from_prefs): Redo function to rank prefs
|
* pkclist.c (select_algo_from_prefs): Redo function to rank prefs
|
||||||
|
@ -264,6 +264,8 @@ learn_status_cb (void *opaque, const char *line)
|
|||||||
{
|
{
|
||||||
xfree (parm->serialno);
|
xfree (parm->serialno);
|
||||||
parm->serialno = store_serialno (line);
|
parm->serialno = store_serialno (line);
|
||||||
|
parm->is_v2 = (strlen (parm->serialno) >= 16
|
||||||
|
&& xtoi_2 (parm->serialno+12) >= 2 );
|
||||||
}
|
}
|
||||||
else if (keywordlen == 9 && !memcmp (keyword, "DISP-NAME", keywordlen))
|
else if (keywordlen == 9 && !memcmp (keyword, "DISP-NAME", keywordlen))
|
||||||
{
|
{
|
||||||
@ -758,10 +760,12 @@ agent_scd_pkdecrypt (const char *serialno,
|
|||||||
|
|
||||||
/* Change the PIN of an OpenPGP card or reset the retry counter.
|
/* Change the PIN of an OpenPGP card or reset the retry counter.
|
||||||
CHVNO 1: Change the PIN
|
CHVNO 1: Change the PIN
|
||||||
2: Same as 1
|
2: For v1 cards: Same as 1.
|
||||||
|
For v2 cards: Reset the PIN using the Reset Code.
|
||||||
3: Change the admin PIN
|
3: Change the admin PIN
|
||||||
101: Set a new PIN and reset the retry counter
|
101: Set a new PIN and reset the retry counter
|
||||||
102: Same as 101
|
102: For v1 cars: Same as 101.
|
||||||
|
For v2 cards: Set a new Reset Code.
|
||||||
SERIALNO is not used.
|
SERIALNO is not used.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
|
@ -49,6 +49,7 @@ struct agent_card_info_s
|
|||||||
int chv1_cached; /* True if a PIN is not required for each
|
int chv1_cached; /* True if a PIN is not required for each
|
||||||
signing. Note that the gpg-agent might cache
|
signing. Note that the gpg-agent might cache
|
||||||
it anyway. */
|
it anyway. */
|
||||||
|
int is_v2; /* True if this is a v2 card. */
|
||||||
int chvmaxlen[3]; /* Maximum allowed length of a CHV. */
|
int chvmaxlen[3]; /* Maximum allowed length of a CHV. */
|
||||||
int chvretry[3]; /* Allowed retries for the CHV; 0 = blocked. */
|
int chvretry[3]; /* Allowed retries for the CHV; 0 = blocked. */
|
||||||
};
|
};
|
||||||
|
@ -51,7 +51,7 @@
|
|||||||
/* Change the PIN of a an OpenPGP card. This is an interactive
|
/* Change the PIN of a an OpenPGP card. This is an interactive
|
||||||
function. */
|
function. */
|
||||||
void
|
void
|
||||||
change_pin (int chvno, int allow_admin)
|
change_pin (int unblock_v2, int allow_admin)
|
||||||
{
|
{
|
||||||
struct agent_card_info_s info;
|
struct agent_card_info_s info;
|
||||||
int rc;
|
int rc;
|
||||||
@ -76,7 +76,26 @@ change_pin (int chvno, int allow_admin)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!allow_admin)
|
|
||||||
|
if (unblock_v2)
|
||||||
|
{
|
||||||
|
if (!info.is_v2)
|
||||||
|
log_error (_("This command is only available for version 2 cards\n"));
|
||||||
|
else if (!info.chvretry[1])
|
||||||
|
log_error (_("Reset Code not or not anymore available\n"));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rc = agent_scd_change_pin (2, info.serialno);
|
||||||
|
if (rc)
|
||||||
|
tty_printf ("Error changing the PIN: %s\n", gpg_strerror (rc));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
write_status (STATUS_SC_OP_SUCCESS);
|
||||||
|
tty_printf ("PIN changed.\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!allow_admin)
|
||||||
{
|
{
|
||||||
rc = agent_scd_change_pin (1, info.serialno);
|
rc = agent_scd_change_pin (1, info.serialno);
|
||||||
if (rc)
|
if (rc)
|
||||||
@ -96,6 +115,7 @@ change_pin (int chvno, int allow_admin)
|
|||||||
tty_printf ("1 - change PIN\n"
|
tty_printf ("1 - change PIN\n"
|
||||||
"2 - unblock PIN\n"
|
"2 - unblock PIN\n"
|
||||||
"3 - change Admin PIN\n"
|
"3 - change Admin PIN\n"
|
||||||
|
"4 - set the Reset Code\n"
|
||||||
"Q - quit\n");
|
"Q - quit\n");
|
||||||
tty_printf ("\n");
|
tty_printf ("\n");
|
||||||
|
|
||||||
@ -107,6 +127,7 @@ change_pin (int chvno, int allow_admin)
|
|||||||
rc = 0;
|
rc = 0;
|
||||||
if (*answer == '1')
|
if (*answer == '1')
|
||||||
{
|
{
|
||||||
|
/* Change PIN. */
|
||||||
rc = agent_scd_change_pin (1, info.serialno);
|
rc = agent_scd_change_pin (1, info.serialno);
|
||||||
if (rc)
|
if (rc)
|
||||||
tty_printf ("Error changing the PIN: %s\n", gpg_strerror (rc));
|
tty_printf ("Error changing the PIN: %s\n", gpg_strerror (rc));
|
||||||
@ -118,6 +139,7 @@ change_pin (int chvno, int allow_admin)
|
|||||||
}
|
}
|
||||||
else if (*answer == '2')
|
else if (*answer == '2')
|
||||||
{
|
{
|
||||||
|
/* Unblock PIN. */
|
||||||
rc = agent_scd_change_pin (101, info.serialno);
|
rc = agent_scd_change_pin (101, info.serialno);
|
||||||
if (rc)
|
if (rc)
|
||||||
tty_printf ("Error unblocking the PIN: %s\n", gpg_strerror (rc));
|
tty_printf ("Error unblocking the PIN: %s\n", gpg_strerror (rc));
|
||||||
@ -129,6 +151,7 @@ change_pin (int chvno, int allow_admin)
|
|||||||
}
|
}
|
||||||
else if (*answer == '3')
|
else if (*answer == '3')
|
||||||
{
|
{
|
||||||
|
/* Change Admin PIN. */
|
||||||
rc = agent_scd_change_pin (3, info.serialno);
|
rc = agent_scd_change_pin (3, info.serialno);
|
||||||
if (rc)
|
if (rc)
|
||||||
tty_printf ("Error changing the PIN: %s\n", gpg_strerror (rc));
|
tty_printf ("Error changing the PIN: %s\n", gpg_strerror (rc));
|
||||||
@ -138,6 +161,19 @@ change_pin (int chvno, int allow_admin)
|
|||||||
tty_printf ("PIN changed.\n");
|
tty_printf ("PIN changed.\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (*answer == '4')
|
||||||
|
{
|
||||||
|
/* Set a new Reset Code. */
|
||||||
|
rc = agent_scd_change_pin (102, info.serialno);
|
||||||
|
if (rc)
|
||||||
|
tty_printf ("Error setting the Reset Code: %s\n",
|
||||||
|
gpg_strerror (rc));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
write_status (STATUS_SC_OP_SUCCESS);
|
||||||
|
tty_printf ("Reset Code set.\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (*answer == 'q' || *answer == 'Q')
|
else if (*answer == 'q' || *answer == 'Q')
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
@ -1345,6 +1381,7 @@ enum cmdids
|
|||||||
cmdQUIT, cmdADMIN, cmdHELP, cmdLIST, cmdDEBUG, cmdVERIFY,
|
cmdQUIT, cmdADMIN, cmdHELP, cmdLIST, cmdDEBUG, cmdVERIFY,
|
||||||
cmdNAME, cmdURL, cmdFETCH, cmdLOGIN, cmdLANG, cmdSEX, cmdCAFPR,
|
cmdNAME, cmdURL, cmdFETCH, cmdLOGIN, cmdLANG, cmdSEX, cmdCAFPR,
|
||||||
cmdFORCESIG, cmdGENERATE, cmdPASSWD, cmdPRIVATEDO, cmdWRITECERT,
|
cmdFORCESIG, cmdGENERATE, cmdPASSWD, cmdPRIVATEDO, cmdWRITECERT,
|
||||||
|
cmdUNBLOCK,
|
||||||
cmdINVCMD
|
cmdINVCMD
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1375,6 +1412,7 @@ static struct
|
|||||||
{ "generate", cmdGENERATE, 1, N_("generate new keys")},
|
{ "generate", cmdGENERATE, 1, N_("generate new keys")},
|
||||||
{ "passwd" , cmdPASSWD, 0, N_("menu to change or unblock the PIN")},
|
{ "passwd" , cmdPASSWD, 0, N_("menu to change or unblock the PIN")},
|
||||||
{ "verify" , cmdVERIFY, 0, N_("verify the PIN and list all data")},
|
{ "verify" , cmdVERIFY, 0, N_("verify the PIN and list all data")},
|
||||||
|
{ "unblock" , cmdUNBLOCK,0, N_("unblock the PIN using a Reset Code") },
|
||||||
/* Note, that we do not announce these command yet. */
|
/* Note, that we do not announce these command yet. */
|
||||||
{ "privatedo", cmdPRIVATEDO, 0, NULL },
|
{ "privatedo", cmdPRIVATEDO, 0, NULL },
|
||||||
{ "writecert", cmdWRITECERT, 1, NULL },
|
{ "writecert", cmdWRITECERT, 1, NULL },
|
||||||
@ -1644,6 +1682,11 @@ card_edit (strlist_t commands)
|
|||||||
did_checkpin = 0; /* Need to reset it of course. */
|
did_checkpin = 0; /* Need to reset it of course. */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case cmdUNBLOCK:
|
||||||
|
change_pin (1, allow_admin);
|
||||||
|
did_checkpin = 0; /* Need to reset it of course. */
|
||||||
|
break;
|
||||||
|
|
||||||
case cmdQUIT:
|
case cmdQUIT:
|
||||||
goto leave;
|
goto leave;
|
||||||
|
|
||||||
|
@ -1,9 +1,30 @@
|
|||||||
|
2008-09-25 Werner Koch <wk@g10code.com>
|
||||||
|
|
||||||
|
* app-openpgp.c (do_setattr): Do not allow setting of the reset
|
||||||
|
code.
|
||||||
|
(do_change_pin): Allow setting of the reset code.
|
||||||
|
|
||||||
|
2008-09-24 Werner Koch <wk@g10code.com>
|
||||||
|
|
||||||
|
* app-openpgp.c (verify_chv3): Set the did_chv3 flag which was
|
||||||
|
accidently removed on 2008-03-26.
|
||||||
|
(verify_chv2): Revert last change.
|
||||||
|
(do_change_pin): Do not change CHV2. Add reset code logic for v2
|
||||||
|
cards.
|
||||||
|
* iso7816.c (iso7816_reset_retry_counter_with_rc): New.
|
||||||
|
|
||||||
|
* app-openpgp.c (add_tlv, build_privkey_template): New.
|
||||||
|
(do_writekey): Support v2 keys and other key lengths than 1024.
|
||||||
|
* iso7816.c (iso7816_put_data_odd): New.
|
||||||
|
|
||||||
2008-09-23 Werner Koch <wk@g10code.com>
|
2008-09-23 Werner Koch <wk@g10code.com>
|
||||||
|
|
||||||
* app-openpgp.c (do_sign): Support SHA-2 digests.
|
* app-openpgp.c (do_sign): Support SHA-2 digests.
|
||||||
(verify_chv2): No CHV auto-sync for v2 cards.
|
(verify_chv2): No CHV auto-sync for v2 cards.
|
||||||
(do_auth): Allow 2048 bit keys.
|
(do_auth): Allow 2048 bit keys.
|
||||||
(parse_algorithm_attribute): New.
|
(parse_algorithm_attribute): New.
|
||||||
|
(rsa_key_format_t): New.
|
||||||
|
(struct app_local_s): Add struct KEYATTR.
|
||||||
|
|
||||||
2008-09-23 Marcus Brinkmann <marcus@g10code.com>
|
2008-09-23 Marcus Brinkmann <marcus@g10code.com>
|
||||||
|
|
||||||
@ -1815,7 +1836,7 @@
|
|||||||
the gpg-agent.
|
the gpg-agent.
|
||||||
|
|
||||||
|
|
||||||
Copyright 2002, 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
|
Copyright 2002, 2003, 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
|
||||||
|
|
||||||
This file is free software; as a special exception the author gives
|
This file is free software; as a special exception the author gives
|
||||||
unlimited permission to copy and/or distribute it, with or without
|
unlimited permission to copy and/or distribute it, with or without
|
||||||
|
@ -19,6 +19,29 @@
|
|||||||
* $Id$
|
* $Id$
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* Some notes:
|
||||||
|
|
||||||
|
CHV means Card Holder Verification and is nothing else than a PIN
|
||||||
|
or password. That term seems to have been used originally with GSM
|
||||||
|
cards. Version v2 of the specs changes the term to the clearer
|
||||||
|
term PW for password. We use the terms here interchangeable
|
||||||
|
because we do not want to change existing strings i18n wise.
|
||||||
|
|
||||||
|
Version 2 of the specs also drops the separate PW2 which was
|
||||||
|
required in v1 due to ISO requirements. It is now possible to have
|
||||||
|
one physical PW but two reference to it so that they can be
|
||||||
|
individually be verified (e.g. to implement a forced verification
|
||||||
|
for one key). Thus you will noticed the use of PW2 with the verify
|
||||||
|
command but not with change_reference_data because the latter
|
||||||
|
operates directly on the physical PW.
|
||||||
|
|
||||||
|
The Reset Code (RC) as implemented by v2 cards uses the same error
|
||||||
|
counter as the PW2 of v1 cards. By default no RC is set and thus
|
||||||
|
that error counter is set to 0. After setting the RC the error
|
||||||
|
counter will be initialized to 3.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@ -46,6 +69,7 @@
|
|||||||
#include "tlv.h"
|
#include "tlv.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* A table describing the DOs of the card. */
|
||||||
static struct {
|
static struct {
|
||||||
int tag;
|
int tag;
|
||||||
int constructed;
|
int constructed;
|
||||||
@ -91,6 +115,18 @@ static struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* The format of RSA private keys. */
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
RSA_UNKNOWN_FMT,
|
||||||
|
RSA_STD,
|
||||||
|
RSA_STD_N,
|
||||||
|
RSA_CRT,
|
||||||
|
RSA_CRT_N
|
||||||
|
}
|
||||||
|
rsa_key_format_t;
|
||||||
|
|
||||||
|
|
||||||
/* One cache item for DOs. */
|
/* One cache item for DOs. */
|
||||||
struct cache_s {
|
struct cache_s {
|
||||||
struct cache_s *next;
|
struct cache_s *next;
|
||||||
@ -150,6 +186,16 @@ struct app_local_s {
|
|||||||
unsigned int no_sync:1; /* Do not sync CHV1 and CHV2 */
|
unsigned int no_sync:1; /* Do not sync CHV1 and CHV2 */
|
||||||
unsigned int def_chv2:1; /* Use 123456 for CHV2. */
|
unsigned int def_chv2:1; /* Use 123456 for CHV2. */
|
||||||
} flags;
|
} flags;
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
unsigned int n_bits; /* Size of the modulus in bits. The rest
|
||||||
|
of this strucuire is only valid if
|
||||||
|
this is not 0. */
|
||||||
|
unsigned int e_bits; /* Size of the public exponent in bits. */
|
||||||
|
rsa_key_format_t format;
|
||||||
|
} keyattr[3];
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -1495,8 +1541,7 @@ verify_chv2 (app_t app,
|
|||||||
|
|
||||||
app->did_chv2 = 1;
|
app->did_chv2 = 1;
|
||||||
|
|
||||||
if (!app->did_chv1 && !app->force_chv1 && pinvalue
|
if (!app->did_chv1 && !app->force_chv1 && pinvalue)
|
||||||
&& !app->app_local->extcap.is_v2)
|
|
||||||
{
|
{
|
||||||
/* For convenience we verify CHV1 here too. We do this only if
|
/* For convenience we verify CHV1 here too. We do this only if
|
||||||
the card is not configured to require a verification before
|
the card is not configured to require a verification before
|
||||||
@ -1635,6 +1680,7 @@ verify_chv3 (app_t app,
|
|||||||
flush_cache_after_error (app);
|
flush_cache_after_error (app);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
app->did_chv3 = 1;
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@ -1673,7 +1719,6 @@ do_setattr (app_t app, const char *name,
|
|||||||
{ "CERT-3", 0x7F21, 3, 0, 1 },
|
{ "CERT-3", 0x7F21, 3, 0, 1 },
|
||||||
{ "SM-KEY-ENC", 0x00D1, 3, 0, 1 },
|
{ "SM-KEY-ENC", 0x00D1, 3, 0, 1 },
|
||||||
{ "SM-KEY-MAC", 0x00D2, 3, 0, 1 },
|
{ "SM-KEY-MAC", 0x00D2, 3, 0, 1 },
|
||||||
{ "PW-RESET-CODE",0x00D3, 3, 0, 1 },
|
|
||||||
{ NULL, 0 }
|
{ NULL, 0 }
|
||||||
};
|
};
|
||||||
int exmode;
|
int exmode;
|
||||||
@ -1758,8 +1803,10 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr,
|
|||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
int chvno = atoi (chvnostr);
|
int chvno = atoi (chvnostr);
|
||||||
|
char *resetcode = NULL;
|
||||||
char *pinvalue;
|
char *pinvalue;
|
||||||
int reset_mode = !!(flags & APP_CHANGE_FLAG_RESET);
|
int reset_mode = !!(flags & APP_CHANGE_FLAG_RESET);
|
||||||
|
int set_resetcode = 0;
|
||||||
|
|
||||||
if (reset_mode && chvno == 3)
|
if (reset_mode && chvno == 3)
|
||||||
{
|
{
|
||||||
@ -1768,11 +1815,54 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr,
|
|||||||
}
|
}
|
||||||
else if (reset_mode || chvno == 3)
|
else if (reset_mode || chvno == 3)
|
||||||
{
|
{
|
||||||
/* we always require that the PIN is entered. */
|
/* We always require that the PIN is entered. */
|
||||||
app->did_chv3 = 0;
|
app->did_chv3 = 0;
|
||||||
rc = verify_chv3 (app, pincb, pincb_arg);
|
rc = verify_chv3 (app, pincb, pincb_arg);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto leave;
|
goto leave;
|
||||||
|
|
||||||
|
if (chvno == 2 && app->app_local->extcap.is_v2)
|
||||||
|
set_resetcode = 1;
|
||||||
|
}
|
||||||
|
else if (chvno == 2 && app->app_local->extcap.is_v2)
|
||||||
|
{
|
||||||
|
/* There is no PW2 for v2 cards. We use this condition to allow
|
||||||
|
a PW reset using the Reset Code. */
|
||||||
|
void *relptr;
|
||||||
|
unsigned char *value;
|
||||||
|
size_t valuelen;
|
||||||
|
int remaining;
|
||||||
|
|
||||||
|
relptr = get_one_do (app, 0x00C4, &value, &valuelen, NULL);
|
||||||
|
if (!relptr || valuelen < 7)
|
||||||
|
{
|
||||||
|
log_error (_("error retrieving CHV status from card\n"));
|
||||||
|
xfree (relptr);
|
||||||
|
rc = gpg_error (GPG_ERR_CARD);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
remaining = value[5];
|
||||||
|
xfree (relptr);
|
||||||
|
if (!remaining)
|
||||||
|
{
|
||||||
|
log_error (_("Reset Code not or not anymore available\n"));
|
||||||
|
rc = gpg_error (GPG_ERR_BAD_PIN);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = pincb (pincb_arg, _("||Please enter the Reset Code for the card"),
|
||||||
|
&resetcode);
|
||||||
|
if (rc)
|
||||||
|
{
|
||||||
|
log_info (_("PIN callback returned error: %s\n"), gpg_strerror (rc));
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
if (strlen (resetcode) < 8)
|
||||||
|
{
|
||||||
|
log_error (_("Reset Code is too short; minimum length is %d\n"), 8);
|
||||||
|
rc = gpg_error (GPG_ERR_BAD_PIN);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (chvno == 1 || chvno == 2)
|
else if (chvno == 1 || chvno == 2)
|
||||||
{
|
{
|
||||||
@ -1802,7 +1892,9 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr,
|
|||||||
/* TRANSLATORS: Do not translate the "|*|" prefixes but
|
/* TRANSLATORS: Do not translate the "|*|" prefixes but
|
||||||
keep it at the start of the string. We need this elsewhere
|
keep it at the start of the string. We need this elsewhere
|
||||||
to get some infos on the string. */
|
to get some infos on the string. */
|
||||||
rc = pincb (pincb_arg, chvno == 3? _("|AN|New Admin PIN") : _("|N|New PIN"),
|
rc = pincb (pincb_arg,
|
||||||
|
set_resetcode? _("|RN|New Reset Code") :
|
||||||
|
chvno == 3? _("|AN|New Admin PIN") : _("|N|New PIN"),
|
||||||
&pinvalue);
|
&pinvalue);
|
||||||
if (rc)
|
if (rc)
|
||||||
{
|
{
|
||||||
@ -1810,11 +1902,38 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr,
|
|||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reset_mode)
|
if (resetcode)
|
||||||
|
{
|
||||||
|
char *buffer;
|
||||||
|
|
||||||
|
buffer = xtrymalloc (strlen (resetcode) + strlen (pinvalue) + 1);
|
||||||
|
if (!buffer)
|
||||||
|
rc = gpg_error_from_syserror ();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
strcpy (stpcpy (buffer, resetcode), pinvalue);
|
||||||
|
rc = iso7816_reset_retry_counter_with_rc (app->slot, 0x81,
|
||||||
|
buffer, strlen (buffer));
|
||||||
|
wipememory (buffer, strlen (buffer));
|
||||||
|
xfree (buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (set_resetcode)
|
||||||
|
{
|
||||||
|
if (strlen (pinvalue) < 8)
|
||||||
|
{
|
||||||
|
log_error (_("Reset Code is too short; minimum length is %d\n"), 8);
|
||||||
|
rc = gpg_error (GPG_ERR_BAD_PIN);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
rc = iso7816_put_data (app->slot, 0, 0xD3,
|
||||||
|
pinvalue, strlen (pinvalue));
|
||||||
|
}
|
||||||
|
else if (reset_mode)
|
||||||
{
|
{
|
||||||
rc = iso7816_reset_retry_counter (app->slot, 0x81,
|
rc = iso7816_reset_retry_counter (app->slot, 0x81,
|
||||||
pinvalue, strlen (pinvalue));
|
pinvalue, strlen (pinvalue));
|
||||||
if (!rc)
|
if (!rc && !app->app_local->extcap.is_v2)
|
||||||
rc = iso7816_reset_retry_counter (app->slot, 0x82,
|
rc = iso7816_reset_retry_counter (app->slot, 0x82,
|
||||||
pinvalue, strlen (pinvalue));
|
pinvalue, strlen (pinvalue));
|
||||||
}
|
}
|
||||||
@ -1824,7 +1943,7 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr,
|
|||||||
{
|
{
|
||||||
rc = iso7816_change_reference_data (app->slot, 0x81, NULL, 0,
|
rc = iso7816_change_reference_data (app->slot, 0x81, NULL, 0,
|
||||||
pinvalue, strlen (pinvalue));
|
pinvalue, strlen (pinvalue));
|
||||||
if (!rc)
|
if (!rc && !app->app_local->extcap.is_v2)
|
||||||
rc = iso7816_change_reference_data (app->slot, 0x82, NULL, 0,
|
rc = iso7816_change_reference_data (app->slot, 0x82, NULL, 0,
|
||||||
pinvalue, strlen (pinvalue));
|
pinvalue, strlen (pinvalue));
|
||||||
}
|
}
|
||||||
@ -1832,11 +1951,20 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr,
|
|||||||
rc = iso7816_change_reference_data (app->slot, 0x80 + chvno, NULL, 0,
|
rc = iso7816_change_reference_data (app->slot, 0x80 + chvno, NULL, 0,
|
||||||
pinvalue, strlen (pinvalue));
|
pinvalue, strlen (pinvalue));
|
||||||
}
|
}
|
||||||
|
if (pinvalue)
|
||||||
|
{
|
||||||
|
wipememory (pinvalue, strlen (pinvalue));
|
||||||
xfree (pinvalue);
|
xfree (pinvalue);
|
||||||
|
}
|
||||||
if (rc)
|
if (rc)
|
||||||
flush_cache_after_error (app);
|
flush_cache_after_error (app);
|
||||||
|
|
||||||
leave:
|
leave:
|
||||||
|
if (resetcode)
|
||||||
|
{
|
||||||
|
wipememory (resetcode, strlen (resetcode));
|
||||||
|
xfree (resetcode);
|
||||||
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1883,6 +2011,162 @@ does_key_exist (app_t app, int keyidx, int force)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Create a TLV tag and value and store it at BUFFER. Return the length
|
||||||
|
of tag and length. A LENGTH greater than 65535 is truncated. */
|
||||||
|
static size_t
|
||||||
|
add_tlv (unsigned char *buffer, unsigned int tag, size_t length)
|
||||||
|
{
|
||||||
|
unsigned char *p = buffer;
|
||||||
|
|
||||||
|
assert (tag <= 0xffff);
|
||||||
|
if ( tag > 0xff )
|
||||||
|
*p++ = tag >> 8;
|
||||||
|
*p++ = tag;
|
||||||
|
if (length < 128)
|
||||||
|
*p++ = length;
|
||||||
|
else if (length < 256)
|
||||||
|
{
|
||||||
|
*p++ = 0x81;
|
||||||
|
*p++ = length;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (length > 0xffff)
|
||||||
|
length = 0xffff;
|
||||||
|
*p++ = 0x82;
|
||||||
|
*p++ = length >> 8;
|
||||||
|
*p++ = length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return p - buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Build the private key template as specified in the OpenPGP specs
|
||||||
|
v2.0 section 4.3.3.7. */
|
||||||
|
static gpg_error_t
|
||||||
|
build_privkey_template (app_t app, int keyno,
|
||||||
|
const unsigned char *rsa_n, size_t rsa_n_len,
|
||||||
|
const unsigned char *rsa_e, size_t rsa_e_len,
|
||||||
|
const unsigned char *rsa_p, size_t rsa_p_len,
|
||||||
|
const unsigned char *rsa_q, size_t rsa_q_len,
|
||||||
|
unsigned char **result, size_t *resultlen)
|
||||||
|
{
|
||||||
|
size_t rsa_e_reqlen;
|
||||||
|
unsigned char privkey[7*(1+3)];
|
||||||
|
size_t privkey_len;
|
||||||
|
unsigned char exthdr[2+2+3];
|
||||||
|
size_t exthdr_len;
|
||||||
|
unsigned char suffix[2+3];
|
||||||
|
size_t suffix_len;
|
||||||
|
unsigned char *tp;
|
||||||
|
size_t datalen;
|
||||||
|
unsigned char *template;
|
||||||
|
size_t template_size;
|
||||||
|
|
||||||
|
*result = NULL;
|
||||||
|
*resultlen = 0;
|
||||||
|
|
||||||
|
switch (app->app_local->keyattr[keyno].format)
|
||||||
|
{
|
||||||
|
case RSA_STD:
|
||||||
|
case RSA_STD_N:
|
||||||
|
break;
|
||||||
|
case RSA_CRT:
|
||||||
|
case RSA_CRT_N:
|
||||||
|
return gpg_error (GPG_ERR_NOT_SUPPORTED);
|
||||||
|
|
||||||
|
default:
|
||||||
|
return gpg_error (GPG_ERR_INV_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the required length for E. */
|
||||||
|
rsa_e_reqlen = app->app_local->keyattr[keyno].e_bits/8;
|
||||||
|
assert (rsa_e_len <= rsa_e_reqlen);
|
||||||
|
|
||||||
|
/* Build the 7f48 cardholder private key template. */
|
||||||
|
datalen = 0;
|
||||||
|
tp = privkey;
|
||||||
|
|
||||||
|
tp += add_tlv (tp, 0x91, rsa_e_reqlen);
|
||||||
|
datalen += rsa_e_reqlen;
|
||||||
|
|
||||||
|
tp += add_tlv (tp, 0x92, rsa_p_len);
|
||||||
|
datalen += rsa_p_len;
|
||||||
|
|
||||||
|
tp += add_tlv (tp, 0x93, rsa_q_len);
|
||||||
|
datalen += rsa_q_len;
|
||||||
|
|
||||||
|
if (app->app_local->keyattr[keyno].format == RSA_STD_N
|
||||||
|
|| app->app_local->keyattr[keyno].format == RSA_CRT_N)
|
||||||
|
{
|
||||||
|
tp += add_tlv (tp, 0x97, rsa_n_len);
|
||||||
|
datalen += rsa_n_len;
|
||||||
|
}
|
||||||
|
privkey_len = tp - privkey;
|
||||||
|
|
||||||
|
/* Build the extended header list without the private key template. */
|
||||||
|
tp = exthdr;
|
||||||
|
*tp++ = keyno ==0 ? 0xb6 : keyno == 1? 0xb8 : 0xa4;
|
||||||
|
*tp++ = 0;
|
||||||
|
tp += add_tlv (tp, 0x7f48, privkey_len);
|
||||||
|
exthdr_len = tp - exthdr;
|
||||||
|
|
||||||
|
/* Build the 5f48 suffix of the data. */
|
||||||
|
tp = suffix;
|
||||||
|
tp += add_tlv (tp, 0x5f48, datalen);
|
||||||
|
suffix_len = tp - suffix;
|
||||||
|
|
||||||
|
/* Now concatenate everything. */
|
||||||
|
template_size = (1 + 3 /* 0x4d and len. */
|
||||||
|
+ exthdr_len
|
||||||
|
+ privkey_len
|
||||||
|
+ suffix_len
|
||||||
|
+ datalen);
|
||||||
|
tp = template = xtrymalloc_secure (template_size);
|
||||||
|
if (!template)
|
||||||
|
return gpg_error_from_syserror ();
|
||||||
|
|
||||||
|
tp += add_tlv (tp, 0x4d, exthdr_len + privkey_len + suffix_len + datalen);
|
||||||
|
memcpy (tp, exthdr, exthdr_len);
|
||||||
|
tp += exthdr_len;
|
||||||
|
memcpy (tp, privkey, privkey_len);
|
||||||
|
tp += privkey_len;
|
||||||
|
memcpy (tp, suffix, suffix_len);
|
||||||
|
tp += suffix_len;
|
||||||
|
|
||||||
|
memcpy (tp, rsa_e, rsa_e_len);
|
||||||
|
if (rsa_e_len < rsa_e_reqlen)
|
||||||
|
{
|
||||||
|
/* Right justify E. */
|
||||||
|
memmove (tp + rsa_e_reqlen - rsa_e_len, tp, rsa_e_len);
|
||||||
|
memset (tp, 0, rsa_e_reqlen - rsa_e_len);
|
||||||
|
}
|
||||||
|
tp += rsa_e_reqlen;
|
||||||
|
|
||||||
|
memcpy (tp, rsa_p, rsa_p_len);
|
||||||
|
tp += rsa_p_len;
|
||||||
|
|
||||||
|
memcpy (tp, rsa_q, rsa_q_len);
|
||||||
|
tp += rsa_q_len;
|
||||||
|
|
||||||
|
if (app->app_local->keyattr[keyno].format == RSA_STD_N
|
||||||
|
|| app->app_local->keyattr[keyno].format == RSA_CRT_N)
|
||||||
|
{
|
||||||
|
memcpy (tp, rsa_n, rsa_n_len);
|
||||||
|
tp += rsa_n_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sanity check. We don't know the exact length because we
|
||||||
|
allocated 3 bytes for the first length header. */
|
||||||
|
assert (tp - template <= template_size);
|
||||||
|
|
||||||
|
*result = template;
|
||||||
|
*resultlen = tp - template;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Handle the WRITEKEY command for OpenPGP. This function expects a
|
/* Handle the WRITEKEY command for OpenPGP. This function expects a
|
||||||
canonical encoded S-expression with the secret key in KEYDATA and
|
canonical encoded S-expression with the secret key in KEYDATA and
|
||||||
@ -1910,6 +2194,7 @@ do_writekey (app_t app, ctrl_t ctrl,
|
|||||||
const unsigned char *rsa_q = NULL;
|
const unsigned char *rsa_q = NULL;
|
||||||
size_t rsa_n_len, rsa_e_len, rsa_p_len, rsa_q_len;
|
size_t rsa_n_len, rsa_e_len, rsa_p_len, rsa_q_len;
|
||||||
unsigned int nbits;
|
unsigned int nbits;
|
||||||
|
unsigned int maxbits;
|
||||||
unsigned char *template = NULL;
|
unsigned char *template = NULL;
|
||||||
unsigned char *tp;
|
unsigned char *tp;
|
||||||
size_t template_len;
|
size_t template_len;
|
||||||
@ -2049,39 +2334,86 @@ do_writekey (app_t app, ctrl_t ctrl,
|
|||||||
err = gpg_error (GPG_ERR_INV_VALUE);
|
err = gpg_error (GPG_ERR_INV_VALUE);
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
maxbits = app->app_local->keyattr[keyno].n_bits;
|
||||||
nbits = rsa_n? count_bits (rsa_n, rsa_n_len) : 0;
|
nbits = rsa_n? count_bits (rsa_n, rsa_n_len) : 0;
|
||||||
if (nbits != 1024)
|
if (nbits != maxbits)
|
||||||
{
|
{
|
||||||
log_error (_("RSA modulus missing or not of size %d bits\n"), 1024);
|
log_error (_("RSA modulus missing or not of size %d bits\n"),
|
||||||
|
(int)maxbits);
|
||||||
err = gpg_error (GPG_ERR_BAD_SECKEY);
|
err = gpg_error (GPG_ERR_BAD_SECKEY);
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
maxbits = app->app_local->keyattr[keyno].e_bits;
|
||||||
|
if (maxbits > 32 && !app->app_local->extcap.is_v2)
|
||||||
|
maxbits = 32; /* Our code for v1 does only support 32 bits. */
|
||||||
nbits = rsa_e? count_bits (rsa_e, rsa_e_len) : 0;
|
nbits = rsa_e? count_bits (rsa_e, rsa_e_len) : 0;
|
||||||
if (nbits < 2 || nbits > 32)
|
if (nbits < 2 || nbits > maxbits)
|
||||||
{
|
{
|
||||||
log_error (_("RSA public exponent missing or larger than %d bits\n"),
|
log_error (_("RSA public exponent missing or larger than %d bits\n"),
|
||||||
32);
|
(int)maxbits);
|
||||||
err = gpg_error (GPG_ERR_BAD_SECKEY);
|
err = gpg_error (GPG_ERR_BAD_SECKEY);
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
maxbits = app->app_local->keyattr[keyno].n_bits/2;
|
||||||
nbits = rsa_p? count_bits (rsa_p, rsa_p_len) : 0;
|
nbits = rsa_p? count_bits (rsa_p, rsa_p_len) : 0;
|
||||||
if (nbits != 512)
|
if (nbits != maxbits)
|
||||||
{
|
{
|
||||||
log_error (_("RSA prime %s missing or not of size %d bits\n"), "P", 512);
|
log_error (_("RSA prime %s missing or not of size %d bits\n"),
|
||||||
|
"P", (int)maxbits);
|
||||||
err = gpg_error (GPG_ERR_BAD_SECKEY);
|
err = gpg_error (GPG_ERR_BAD_SECKEY);
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
nbits = rsa_q? count_bits (rsa_q, rsa_q_len) : 0;
|
nbits = rsa_q? count_bits (rsa_q, rsa_q_len) : 0;
|
||||||
if (nbits != 512)
|
if (nbits != maxbits)
|
||||||
{
|
{
|
||||||
log_error (_("RSA prime %s missing or not of size %d bits\n"), "Q", 512);
|
log_error (_("RSA prime %s missing or not of size %d bits\n"),
|
||||||
|
"Q", (int)maxbits);
|
||||||
err = gpg_error (GPG_ERR_BAD_SECKEY);
|
err = gpg_error (GPG_ERR_BAD_SECKEY);
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* We need to remove the cached public key. */
|
||||||
|
xfree (app->app_local->pk[keyno].key);
|
||||||
|
app->app_local->pk[keyno].key = NULL;
|
||||||
|
app->app_local->pk[keyno].keylen = 0;
|
||||||
|
app->app_local->pk[keyno].read_done = 0;
|
||||||
|
|
||||||
|
|
||||||
|
if (app->app_local->extcap.is_v2)
|
||||||
|
{
|
||||||
|
/* Build the private key template as described in section 4.3.3.7 of
|
||||||
|
the OpenPGP card specs version 2.0. */
|
||||||
|
int exmode;
|
||||||
|
|
||||||
|
err = build_privkey_template (app, keyno,
|
||||||
|
rsa_n, rsa_n_len,
|
||||||
|
rsa_e, rsa_e_len,
|
||||||
|
rsa_p, rsa_p_len,
|
||||||
|
rsa_q, rsa_q_len,
|
||||||
|
&template, &template_len);
|
||||||
|
if (err)
|
||||||
|
goto leave;
|
||||||
|
|
||||||
|
/* Prepare for storing the key. */
|
||||||
|
err = verify_chv3 (app, pincb, pincb_arg);
|
||||||
|
if (err)
|
||||||
|
goto leave;
|
||||||
|
|
||||||
|
/* Store the key. */
|
||||||
|
if (app->app_local->cardcap.cmd_chaining && template_len > 254)
|
||||||
|
exmode = -254;
|
||||||
|
else
|
||||||
|
exmode = 0;
|
||||||
|
err = iso7816_put_data_odd (app->slot, exmode, 0x3fff,
|
||||||
|
template, template_len);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
/* Build the private key template as described in section 4.3.3.6 of
|
/* Build the private key template as described in section 4.3.3.6 of
|
||||||
the OpenPGP card specs:
|
the OpenPGP card specs version 1.1:
|
||||||
0xC0 <length> public exponent
|
0xC0 <length> public exponent
|
||||||
0xC1 <length> prime p
|
0xC1 <length> prime p
|
||||||
0xC2 <length> prime q
|
0xC2 <length> prime q
|
||||||
@ -2119,13 +2451,6 @@ do_writekey (app_t app, ctrl_t ctrl,
|
|||||||
|
|
||||||
assert (tp - template == template_len);
|
assert (tp - template == template_len);
|
||||||
|
|
||||||
|
|
||||||
/* Obviously we need to remove the cached public key. */
|
|
||||||
xfree (app->app_local->pk[keyno].key);
|
|
||||||
app->app_local->pk[keyno].key = NULL;
|
|
||||||
app->app_local->pk[keyno].keylen = 0;
|
|
||||||
app->app_local->pk[keyno].read_done = 0;
|
|
||||||
|
|
||||||
/* Prepare for storing the key. */
|
/* Prepare for storing the key. */
|
||||||
err = verify_chv3 (app, pincb, pincb_arg);
|
err = verify_chv3 (app, pincb, pincb_arg);
|
||||||
if (err)
|
if (err)
|
||||||
@ -2135,6 +2460,7 @@ do_writekey (app_t app, ctrl_t ctrl,
|
|||||||
err = iso7816_put_data (app->slot, 0,
|
err = iso7816_put_data (app->slot, 0,
|
||||||
(app->card_version > 0x0007? 0xE0:0xE9)+keyno,
|
(app->card_version > 0x0007? 0xE0:0xE9)+keyno,
|
||||||
template, template_len);
|
template, template_len);
|
||||||
|
}
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
log_error (_("failed to store the key: %s\n"), gpg_strerror (err));
|
log_error (_("failed to store the key: %s\n"), gpg_strerror (err));
|
||||||
@ -2891,8 +3217,8 @@ parse_historical (struct app_local_s *apploc,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Read and parse the algorithm attributes for KEYNO. KEYNO must be
|
/* Parse and optionally show the algorithm attributes for KEYNO.
|
||||||
in the range 0..2. */
|
KEYNO must be in the range 0..2. */
|
||||||
static void
|
static void
|
||||||
parse_algorithm_attribute (app_t app, int keyno)
|
parse_algorithm_attribute (app_t app, int keyno)
|
||||||
{
|
{
|
||||||
@ -2903,6 +3229,8 @@ parse_algorithm_attribute (app_t app, int keyno)
|
|||||||
|
|
||||||
assert (keyno >=0 && keyno <= 2);
|
assert (keyno >=0 && keyno <= 2);
|
||||||
|
|
||||||
|
app->app_local->keyattr[keyno].n_bits = 0;
|
||||||
|
|
||||||
relptr = get_one_do (app, 0xC1+keyno, &buffer, &buflen, NULL);
|
relptr = get_one_do (app, 0xC1+keyno, &buffer, &buflen, NULL);
|
||||||
if (!relptr)
|
if (!relptr)
|
||||||
{
|
{
|
||||||
@ -2916,21 +3244,33 @@ parse_algorithm_attribute (app_t app, int keyno)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (opt.verbose)
|
||||||
log_info ("Key-Attr-%s ..: ", desc[keyno]);
|
log_info ("Key-Attr-%s ..: ", desc[keyno]);
|
||||||
if (*buffer == 1 && (buflen == 5 || buflen == 6))
|
if (*buffer == 1 && (buflen == 5 || buflen == 6))
|
||||||
{
|
{
|
||||||
log_printf ("RSA, n=%d, e=%d",
|
app->app_local->keyattr[keyno].n_bits = (buffer[1]<<8 | buffer[2]);
|
||||||
(buffer[1]<<8 | buffer[2]),
|
app->app_local->keyattr[keyno].e_bits = (buffer[3]<<8 | buffer[4]);
|
||||||
(buffer[3]<<8 | buffer[4]));
|
app->app_local->keyattr[keyno].format = 0;
|
||||||
if (buflen == 6)
|
if (buflen < 6)
|
||||||
log_printf (", format=%s",
|
app->app_local->keyattr[keyno].format = RSA_STD;
|
||||||
buffer[5] == 0? "std" :
|
|
||||||
buffer[5] == 1? "std+n" :
|
|
||||||
buffer[5] == 2? "crt" :
|
|
||||||
buffer[5] == 2? "crt+n" : "?");
|
|
||||||
log_printf ("\n");
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
|
app->app_local->keyattr[keyno].format = (buffer[5] == 0? RSA_STD :
|
||||||
|
buffer[5] == 1? RSA_STD_N :
|
||||||
|
buffer[5] == 2? RSA_CRT :
|
||||||
|
buffer[5] == 3? RSA_CRT_N :
|
||||||
|
RSA_UNKNOWN_FMT);
|
||||||
|
|
||||||
|
if (opt.verbose)
|
||||||
|
log_printf
|
||||||
|
("RSA, n=%u, e=%u, fmt=%s\n",
|
||||||
|
app->app_local->keyattr[keyno].n_bits,
|
||||||
|
app->app_local->keyattr[keyno].e_bits,
|
||||||
|
app->app_local->keyattr[keyno].format == RSA_STD? "std" :
|
||||||
|
app->app_local->keyattr[keyno].format == RSA_STD_N?"std+n":
|
||||||
|
app->app_local->keyattr[keyno].format == RSA_CRT? "crt" :
|
||||||
|
app->app_local->keyattr[keyno].format == RSA_CRT_N?"crt+n":"?");
|
||||||
|
}
|
||||||
|
else if (opt.verbose)
|
||||||
log_printhex ("", buffer, buflen);
|
log_printhex ("", buffer, buflen);
|
||||||
|
|
||||||
xfree (relptr);
|
xfree (relptr);
|
||||||
@ -3057,12 +3397,9 @@ app_select_openpgp (app_t app)
|
|||||||
if (opt.verbose)
|
if (opt.verbose)
|
||||||
show_caps (app->app_local);
|
show_caps (app->app_local);
|
||||||
|
|
||||||
if (opt.verbose)
|
|
||||||
{
|
|
||||||
parse_algorithm_attribute (app, 0);
|
parse_algorithm_attribute (app, 0);
|
||||||
parse_algorithm_attribute (app, 1);
|
parse_algorithm_attribute (app, 1);
|
||||||
parse_algorithm_attribute (app, 2);
|
parse_algorithm_attribute (app, 2);
|
||||||
}
|
|
||||||
|
|
||||||
if (opt.verbose > 1)
|
if (opt.verbose > 1)
|
||||||
dump_all_do (slot);
|
dump_all_do (slot);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* iso7816.c - ISO 7816 commands
|
/* iso7816.c - ISO 7816 commands
|
||||||
* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
|
* Copyright (C) 2003, 2004, 2008 Free Software Foundation, Inc.
|
||||||
*
|
*
|
||||||
* This file is part of GnuPG.
|
* This file is part of GnuPG.
|
||||||
*
|
*
|
||||||
@ -335,6 +335,7 @@ iso7816_reset_retry_counter_kp (int slot, int chvno,
|
|||||||
if (!newchv || !newchvlen )
|
if (!newchv || !newchvlen )
|
||||||
return gpg_error (GPG_ERR_INV_VALUE);
|
return gpg_error (GPG_ERR_INV_VALUE);
|
||||||
|
|
||||||
|
/* FIXME: The keypad mode has not yet been tested. */
|
||||||
if (pininfo && pininfo->mode)
|
if (pininfo && pininfo->mode)
|
||||||
sw = apdu_send_simple_kp (slot, 0x00, CMD_RESET_RETRY_COUNTER,
|
sw = apdu_send_simple_kp (slot, 0x00, CMD_RESET_RETRY_COUNTER,
|
||||||
2, chvno, newchvlen, newchv,
|
2, chvno, newchvlen, newchv,
|
||||||
@ -349,6 +350,21 @@ iso7816_reset_retry_counter_kp (int slot, int chvno,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
gpg_error_t
|
||||||
|
iso7816_reset_retry_counter_with_rc (int slot, int chvno,
|
||||||
|
const char *data, size_t datalen)
|
||||||
|
{
|
||||||
|
int sw;
|
||||||
|
|
||||||
|
if (!data || !datalen )
|
||||||
|
return gpg_error (GPG_ERR_INV_VALUE);
|
||||||
|
|
||||||
|
sw = apdu_send_simple (slot, 0, 0x00, CMD_RESET_RETRY_COUNTER,
|
||||||
|
0, chvno, datalen, data);
|
||||||
|
return map_sw (sw);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
gpg_error_t
|
gpg_error_t
|
||||||
iso7816_reset_retry_counter (int slot, int chvno,
|
iso7816_reset_retry_counter (int slot, int chvno,
|
||||||
const char *newchv, size_t newchvlen)
|
const char *newchv, size_t newchvlen)
|
||||||
@ -404,6 +420,19 @@ iso7816_put_data (int slot, int extended_mode, int tag,
|
|||||||
return map_sw (sw);
|
return map_sw (sw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Same as iso7816_put_data but uses an odd instrcution byte. */
|
||||||
|
gpg_error_t
|
||||||
|
iso7816_put_data_odd (int slot, int extended_mode, int tag,
|
||||||
|
const unsigned char *data, size_t datalen)
|
||||||
|
{
|
||||||
|
int sw;
|
||||||
|
|
||||||
|
sw = apdu_send_simple (slot, extended_mode, 0x00, CMD_PUT_DATA+1,
|
||||||
|
((tag >> 8) & 0xff), (tag & 0xff),
|
||||||
|
datalen, (const char*)data);
|
||||||
|
return map_sw (sw);
|
||||||
|
}
|
||||||
|
|
||||||
/* Manage Security Environment. This is a weird operation and there
|
/* Manage Security Environment. This is a weird operation and there
|
||||||
is no easy abstraction for it. Furthermore, some card seem to have
|
is no easy abstraction for it. Furthermore, some card seem to have
|
||||||
a different interpreation of 7816-8 and thus we resort to let the
|
a different interpreation of 7816-8 and thus we resort to let the
|
||||||
|
@ -77,10 +77,15 @@ gpg_error_t iso7816_reset_retry_counter_kp (int slot, int chvno,
|
|||||||
const char *newchv,
|
const char *newchv,
|
||||||
size_t newchvlen,
|
size_t newchvlen,
|
||||||
iso7816_pininfo_t *pininfo);
|
iso7816_pininfo_t *pininfo);
|
||||||
|
gpg_error_t iso7816_reset_retry_counter_with_rc (int slot, int chvno,
|
||||||
|
const char *data,
|
||||||
|
size_t datalen);
|
||||||
gpg_error_t iso7816_get_data (int slot, int tag,
|
gpg_error_t iso7816_get_data (int slot, int tag,
|
||||||
unsigned char **result, size_t *resultlen);
|
unsigned char **result, size_t *resultlen);
|
||||||
gpg_error_t iso7816_put_data (int slot, int extended_mode, int tag,
|
gpg_error_t iso7816_put_data (int slot, int extended_mode, int tag,
|
||||||
const unsigned char *data, size_t datalen);
|
const unsigned char *data, size_t datalen);
|
||||||
|
gpg_error_t iso7816_put_data_odd (int slot, int extended_mode, int tag,
|
||||||
|
const unsigned char *data, size_t datalen);
|
||||||
gpg_error_t iso7816_manage_security_env (int slot, int p1, int p2,
|
gpg_error_t iso7816_manage_security_env (int slot, int p1, int p2,
|
||||||
const unsigned char *data,
|
const unsigned char *data,
|
||||||
size_t datalen);
|
size_t datalen);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user