1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-12-22 10:19:57 +01:00

Support the Certifciate DO of the v2 OpenPGP cards.

This commit is contained in:
Werner Koch 2008-09-23 09:57:45 +00:00
parent 1377e1fe8d
commit f899b9683b
18 changed files with 746 additions and 174 deletions

View File

@ -75,7 +75,7 @@ do_encode_md (const byte * md, size_t mdlen, int algo, gcry_sexp_t * r_hash,
}
/* Special version of do_encode_md to take care of pckcs#1 padding.
/* Special version of do_encode_md to take care of pkcs#1 padding.
For TLS-MD5SHA1 we need to do the padding ourself as Libgrypt does
not know about this special scheme. Fixme: We should have a
pkcs1-only-padding flag for Libgcrypt. */

View File

@ -2709,6 +2709,9 @@ make a clear text signature
@item gpg -sb @code{file}
make a detached signature
@item gpg -u 0x12345678 -sb @code{file}
make a detached signature with the key 0x12345678
@item gpg --list-keys @code{user_ID}
show keys

View File

@ -1,3 +1,14 @@
2008-09-16 Werner Koch <wk@g10code.com>
* card-util.c (fpr_is_ff): New.
(card_status): Do not print general key info for an all-ff fpr.
(change_login, change_private_do): Factor common code out to ...
(get_data_from_file): .. new.
(change_cert): New.
(card_edit): Add command "writecert".
* call-agent.c (writecert_parm_s): New.
(inq_writecert_parms, agent_scd_writecert): New.
2008-09-04 David Shaw <dshaw@jabberwocky.com>
* keyserver.c (keyserver_import_cert): Allow keyserver URLs in

View File

@ -53,6 +53,13 @@ struct cipher_parm_s
size_t ciphertextlen;
};
struct writecert_parm_s
{
assuan_context_t ctx;
const unsigned char *certdata;
size_t certdatalen;
};
struct writekey_parm_s
{
assuan_context_t ctx;
@ -444,6 +451,56 @@ agent_scd_setattr (const char *name,
}
/* Handle a CERTDATA inquiry. Note, we only send the data,
assuan_transact takes care of flushing and writing the END
command. */
static int
inq_writecert_parms (void *opaque, const char *line)
{
int rc;
struct writecert_parm_s *parm = opaque;
if (!strncmp (line, "CERTDATA", 8) && (line[8]==' '||!line[8]))
{
rc = assuan_send_data (parm->ctx, parm->certdata, parm->certdatalen);
}
else
rc = default_inq_cb (opaque, line);
return rc;
}
/* Send a WRITECERT command to the SCdaemon. */
int
agent_scd_writecert (const char *certidstr,
const unsigned char *certdata, size_t certdatalen)
{
int rc;
char line[ASSUAN_LINELENGTH];
struct writecert_parm_s parms;
rc = start_agent ();
if (rc)
return rc;
memset (&parms, 0, sizeof parms);
snprintf (line, DIM(line)-1, "SCD WRITECERT %s", certidstr);
line[DIM(line)-1] = 0;
parms.ctx = agent_ctx;
parms.certdata = certdata;
parms.certdatalen = certdatalen;
rc = assuan_transact (agent_ctx, line, NULL, NULL,
inq_writecert_parms, &parms, NULL, NULL);
return rc;
}
/* Handle a KEYDATA inquiry. Note, we only send the data,
assuan_transact takes care of flushing and writing the end */

View File

@ -76,6 +76,10 @@ int agent_scd_setattr (const char *name,
const unsigned char *value, size_t valuelen,
const char *serialno);
/* Send a WRITECERT command to the SCdaemon. */
int agent_scd_writecert (const char *certidstr,
const unsigned char *certdata, size_t certdatalen);
/* Send a WRITEKEY command to the SCdaemon. */
int agent_scd_writekey (int keyno, const char *serialno,
const unsigned char *keydata, size_t keydatalen);

View File

@ -288,6 +288,18 @@ fpr_is_zero (const char *fpr)
}
/* Return true if the SHA1 fingerprint FPR consists only of 0xFF. */
static int
fpr_is_ff (const char *fpr)
{
int i;
for (i=0; i < 20 && fpr[i] == '\xff'; i++)
;
return (i == 20);
}
/* Print all available information about the current card. */
void
card_status (FILE *fp, char *serialno, size_t serialnobuflen)
@ -467,7 +479,10 @@ card_status (FILE *fp, char *serialno, size_t serialnobuflen)
thefpr = (info.fpr1valid? info.fpr1 : info.fpr2valid? info.fpr2 :
info.fpr3valid? info.fpr3 : NULL);
if ( thefpr && !get_pubkey_byfprint (pk, thefpr, 20))
/* If the fingerprint is all 0xff, the key has no asssociated
OpenPGP certificate. */
if ( thefpr && !fpr_is_ff (thefpr)
&& !get_pubkey_byfprint (pk, thefpr, 20))
{
KBNODE keyblock = NULL;
@ -655,6 +670,58 @@ fetch_url(void)
}
/* Read data from file FNAME up to MAXLEN characters. On error return
-1 and store NULl at R_BUFFER; on success return the number of
bytes read and store the address of a newly allocated buffer at
R_BUFFER. */
static int
get_data_from_file (const char *fname, size_t maxlen, char **r_buffer)
{
FILE *fp;
char *data;
int n;
*r_buffer = NULL;
fp = fopen (fname, "rb");
#if GNUPG_MAJOR_VERSION == 1
if (fp && is_secured_file (fileno (fp)))
{
fclose (fp);
fp = NULL;
errno = EPERM;
}
#endif
if (!fp)
{
tty_printf (_("can't open `%s': %s\n"), fname, strerror (errno));
return -1;
}
data = xtrymalloc (maxlen? maxlen:1);
if (!data)
{
tty_printf (_("error allocating enough memory: %s\n"), strerror (errno));
fclose (fp);
return -1;
}
if (maxlen)
n = fread (data, 1, maxlen, fp);
else
n = 0;
fclose (fp);
if (n < 0)
{
tty_printf (_("error reading `%s': %s\n"), fname, strerror (errno));
xfree (data);
return -1;
}
*r_buffer = data;
return n;
}
static int
change_login (const char *args)
{
@ -664,34 +731,11 @@ change_login (const char *args)
if (args && *args == '<') /* Read it from a file */
{
FILE *fp;
for (args++; spacep (args); args++)
;
fp = fopen (args, "rb");
#if GNUPG_MAJOR_VERSION == 1
if (fp && is_secured_file (fileno (fp)))
{
fclose (fp);
fp = NULL;
errno = EPERM;
}
#endif
if (!fp)
{
tty_printf (_("can't open `%s': %s\n"), args, strerror (errno));
return -1;
}
data = xmalloc (254);
n = fread (data, 1, 254, fp);
fclose (fp);
n = get_data_from_file (args, 254, &data);
if (n < 0)
{
tty_printf (_("error reading `%s': %s\n"), args, strerror (errno));
xfree (data);
return -1;
}
return -1;
}
else
{
@ -732,35 +776,11 @@ change_private_do (const char *args, int nr)
if (args && (args = strchr (args, '<'))) /* Read it from a file */
{
FILE *fp;
/* Fixme: Factor this duplicated code out. */
for (args++; spacep (args); args++)
;
fp = fopen (args, "rb");
#if GNUPG_MAJOR_VERSION == 1
if (fp && is_secured_file (fileno (fp)))
{
fclose (fp);
fp = NULL;
errno = EPERM;
}
#endif
if (!fp)
{
tty_printf (_("can't open `%s': %s\n"), args, strerror (errno));
return -1;
}
data = xmalloc (254);
n = fread (data, 1, 254, fp);
fclose (fp);
n = get_data_from_file (args, 254, &data);
if (n < 0)
{
tty_printf (_("error reading `%s': %s\n"), args, strerror (errno));
xfree (data);
return -1;
}
return -1;
}
else
{
@ -788,6 +808,36 @@ change_private_do (const char *args, int nr)
return rc;
}
static int
change_cert (const char *args)
{
char *data;
int n;
int rc;
if (args && *args == '<') /* Read it from a file */
{
for (args++; spacep (args); args++)
;
n = get_data_from_file (args, 16384, &data);
if (n < 0)
return -1;
}
else
{
tty_printf ("usage error: redirectrion to file required\n");
return -1;
}
rc = agent_scd_writecert ("OPENPGP.3", data, n);
if (rc)
log_error ("error writing certificate to card: %s\n", gpg_strerror (rc));
xfree (data);
return rc;
}
static int
change_lang (void)
{
@ -1294,7 +1344,7 @@ enum cmdids
cmdNOP = 0,
cmdQUIT, cmdADMIN, cmdHELP, cmdLIST, cmdDEBUG, cmdVERIFY,
cmdNAME, cmdURL, cmdFETCH, cmdLOGIN, cmdLANG, cmdSEX, cmdCAFPR,
cmdFORCESIG, cmdGENERATE, cmdPASSWD, cmdPRIVATEDO,
cmdFORCESIG, cmdGENERATE, cmdPASSWD, cmdPRIVATEDO, cmdWRITECERT,
cmdINVCMD
};
@ -1325,8 +1375,9 @@ static struct
{ "generate", cmdGENERATE, 1, N_("generate new keys")},
{ "passwd" , cmdPASSWD, 0, N_("menu to change or unblock the PIN")},
{ "verify" , cmdVERIFY, 0, N_("verify the PIN and list all data")},
/* Note, that we do not announce this command yet. */
/* Note, that we do not announce these command yet. */
{ "privatedo", cmdPRIVATEDO, 0, NULL },
{ "writecert", cmdWRITECERT, 1, NULL },
{ NULL, cmdINVCMD, 0, NULL }
};
@ -1401,6 +1452,7 @@ card_edit (strlist_t commands)
{
int arg_number;
const char *arg_string = "";
const char *arg_rest = "";
char *p;
int i;
int cmd_admin_only;
@ -1469,6 +1521,11 @@ card_edit (strlist_t commands)
trim_spaces (p);
arg_number = atoi(p);
arg_string = p;
arg_rest = p;
while (digitp (arg_rest))
arg_rest++;
while (spacep (arg_rest))
arg_rest++;
}
for (i=0; cmds[i].name; i++ )
@ -1567,6 +1624,13 @@ card_edit (strlist_t commands)
change_private_do (arg_string, arg_number);
break;
case cmdWRITECERT:
if ( arg_number != 3 )
tty_printf ("usage: writecert 3 < FILE\n");
else
change_cert (arg_rest);
break;
case cmdFORCESIG:
toggle_forcesig ();
break;

View File

@ -1,3 +1,29 @@
2008-09-23 Werner Koch <wk@g10code.com>
* app-openpgp.c (do_setattr): Use command chaining for long
values.
* iso7816.c (iso7816_put_data): Add arg EXTENDED_MODE. Change all
callers.
* apdu.c (apdu_send_simple): Add arg EXTENDED_MODE. Change all
callers.
(send_le): Implement command chaining.
* ccid-driver.c (ccid_transceive_apdu_level): Increase allowed
APDU size.
* apdu.h: Add new SW_ codes.
2008-09-16 Werner Koch <wk@g10code.com>
* command.c (cmd_writecert): New.
(register_commands): Register it.
* app-common.h (app_ctx_s): Add member WRITECERT.
* app.c (app_writecert): New.
* app-openpgp.c (do_writecert): New.
(parse_historical): New.
(show_extcap): New.
(dump_all_do): Print only the length of longs DOs.
* command.c (cmd_writekey, cmd_apdu, cmd_pksign)
(cmd_passwd): Replace open coding by skip_options.
2008-08-30 Moritz <moritz@gnu.org>
* scdaemon.c (main): Use estream_asprintf instead of asprintf.

View File

@ -1,5 +1,5 @@
/* apdu.c - ISO 7816 APDU functions and low level I/O
* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
* Copyright (C) 2003, 2004, 2008 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@ -1182,7 +1182,7 @@ pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
err = SW_HOST_INV_VALUE;
}
/* We need to read any rest of the response, to keep the
protocol runnng. */
protocol running. */
while (full_len)
{
unsigned char dummybuf[128];
@ -2587,20 +2587,29 @@ send_apdu (int slot, unsigned char *apdu, size_t apdulen,
if (reader_table[slot].send_apdu_reader)
return reader_table[slot].send_apdu_reader (slot,
apdu, apdulen,
buffer, buflen, pininfo);
buffer, buflen,
pininfo);
else
return SW_HOST_NOT_SUPPORTED;
}
/* Core APDU trabceiver function. Parameters are described at
/* Core APDU tranceiver function. Parameters are described at
apdu_send_le with the exception of PININFO which indicates keypad
related operations if not NULL. */
related operations if not NULL. If EXTENDED_MODE is not NULL
command chaining or extended length will be used according to these
values:
n < 0 := Use command chaining without the data part limited to -n
in each chunk. If -1 is used a default value is used.
n == 1 := Use extended length for input and output with out a
length limit.
n > 1 := Use extended length with up to N bytes.
*/
static int
send_le (int slot, int class, int ins, int p0, int p1,
int lc, const char *data, int le,
unsigned char **retbuf, size_t *retbuflen,
struct pininfo_s *pininfo)
struct pininfo_s *pininfo, int extended_mode)
{
#define RESULTLEN 258
unsigned char result[RESULTLEN+10]; /* 10 extra in case of bugs in
@ -2611,16 +2620,37 @@ send_le (int slot, int class, int ins, int p0, int p1,
int sw;
long rc; /* We need a long here due to PC/SC. */
int did_exact_length_hack = 0;
int use_chaining = 0;
int lc_chunk;
if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
return SW_HOST_NO_DRIVER;
if (DBG_CARD_IO)
log_debug ("send apdu: c=%02X i=%02X p0=%02X p1=%02X lc=%d le=%d\n",
class, ins, p0, p1, lc, le);
log_debug ("send apdu: c=%02X i=%02X p0=%02X p1=%02X lc=%d le=%d em=%d\n",
class, ins, p0, p1, lc, le, extended_mode);
if (lc != -1 && (lc > 255 || lc < 0))
return SW_WRONG_LENGTH;
{
/* Data does not fit into an APDU. What we do now dependes on
the EXTENDED_MODE parameter. */
if (!extended_mode)
return SW_WRONG_LENGTH; /* No way. to send such an APDU. */
else if (extended_mode > 0)
return SW_HOST_NOT_SUPPORTED; /* FIXME. */
else if (extended_mode < 0)
{
/* Send APDU using chaining mode. */
if (lc > 16384)
return SW_WRONG_LENGTH; /* Sanity check. */
if ((class&0xf0) != 0)
return SW_HOST_INV_VALUE; /* Upper 4 bits need to be 0. */
use_chaining = extended_mode == -1? 255 : -extended_mode;
use_chaining &= 0xff;
}
else
return SW_HOST_INV_VALUE;
}
if (le != -1 && (le > 256 || le < 0))
return SW_WRONG_LENGTH;
if ((!data && lc != -1) || (data && lc == -1))
@ -2629,43 +2659,61 @@ send_le (int slot, int class, int ins, int p0, int p1,
if ((sw = lock_slot (slot)))
return sw;
apdulen = 0;
apdu[apdulen++] = class;
apdu[apdulen++] = ins;
apdu[apdulen++] = p0;
apdu[apdulen++] = p1;
if (lc != -1)
do
{
apdu[apdulen++] = lc;
memcpy (apdu+apdulen, data, lc);
apdulen += lc;
/* T=0 does not allow the use of Lc together with Le; thus
disable Le in this case. */
if (reader_table[slot].is_t0)
le = -1;
}
if (le != -1)
apdu[apdulen++] = le; /* Truncation is okay because 0 means 256. */
assert (sizeof (apdu) >= apdulen);
/* As safeguard don't pass any garbage from the stack to the driver. */
memset (apdu+apdulen, 0, sizeof (apdu) - apdulen);
exact_length_hack:
resultlen = RESULTLEN;
rc = send_apdu (slot, apdu, apdulen, result, &resultlen, pininfo);
if (rc || resultlen < 2)
{
log_error ("apdu_send_simple(%d) failed: %s\n",
slot, apdu_strerror (rc));
unlock_slot (slot);
return rc? rc : SW_HOST_INCOMPLETE_CARD_RESPONSE;
}
sw = (result[resultlen-2] << 8) | result[resultlen-1];
if (!did_exact_length_hack && SW_EXACT_LENGTH_P (sw))
{
apdu[apdulen-1] = (sw & 0x00ff);
did_exact_length_hack = 1;
goto exact_length_hack;
apdulen = 0;
apdu[apdulen] = class;
if (use_chaining && lc > 255)
{
apdu[apdulen] |= 0x10;
assert (use_chaining < 256);
lc_chunk = use_chaining;
lc -= use_chaining;
}
else
{
use_chaining = 0;
lc_chunk = lc;
}
apdulen++;
apdu[apdulen++] = ins;
apdu[apdulen++] = p0;
apdu[apdulen++] = p1;
if (lc_chunk != -1)
{
apdu[apdulen++] = lc_chunk;
memcpy (apdu+apdulen, data, lc_chunk);
data += lc_chunk;
apdulen += lc_chunk;
/* T=0 does not allow the use of Lc together with Le; thus
disable Le in this case. */
if (reader_table[slot].is_t0)
le = -1;
}
if (le != -1)
apdu[apdulen++] = le; /* Truncation is okay because 0 means 256. */
/* As safeguard don't pass any garbage from the stack to the driver. */
assert (sizeof (apdu) >= apdulen);
memset (apdu+apdulen, 0, sizeof (apdu) - apdulen);
exact_length_hack:
resultlen = RESULTLEN;
rc = send_apdu (slot, apdu, apdulen, result, &resultlen, pininfo);
if (rc || resultlen < 2)
{
log_error ("apdu_send_simple(%d) failed: %s\n",
slot, apdu_strerror (rc));
unlock_slot (slot);
return rc? rc : SW_HOST_INCOMPLETE_CARD_RESPONSE;
}
sw = (result[resultlen-2] << 8) | result[resultlen-1];
if (!did_exact_length_hack && SW_EXACT_LENGTH_P (sw))
{
apdu[apdulen-1] = (sw & 0x00ff);
did_exact_length_hack = 1;
goto exact_length_hack;
}
}
while (use_chaining && sw == SW_SUCCESS);
/* Store away the returned data but strip the statusword. */
resultlen -= 2;
@ -2808,7 +2856,7 @@ apdu_send_le(int slot, int class, int ins, int p0, int p1,
return send_le (slot, class, ins, p0, p1,
lc, data, le,
retbuf, retbuflen,
NULL);
NULL, 0);
}
@ -2826,7 +2874,7 @@ apdu_send (int slot, int class, int ins, int p0, int p1,
int lc, const char *data, unsigned char **retbuf, size_t *retbuflen)
{
return send_le (slot, class, ins, p0, p1, lc, data, 256,
retbuf, retbuflen, NULL);
retbuf, retbuflen, NULL, 0);
}
/* Send an APDU to the card in SLOT. The APDU is created from all
@ -2836,10 +2884,12 @@ apdu_send (int slot, int class, int ins, int p0, int p1,
for an invalid SLOT or other non card related error. No data will be
returned. */
int
apdu_send_simple (int slot, int class, int ins, int p0, int p1,
apdu_send_simple (int slot, int extended_mode,
int class, int ins, int p0, int p1,
int lc, const char *data)
{
return send_le (slot, class, ins, p0, p1, lc, data, -1, NULL, NULL, NULL);
return send_le (slot, class, ins, p0, p1, lc, data, -1, NULL, NULL, NULL,
extended_mode);
}
@ -2857,13 +2907,13 @@ apdu_send_simple_kp (int slot, int class, int ins, int p0, int p1,
pininfo.maxlen = pinlen_max;
pininfo.padlen = pin_padlen;
return send_le (slot, class, ins, p0, p1, lc, data, -1,
NULL, NULL, &pininfo);
NULL, NULL, &pininfo, 0);
}
/* This is a more generic version of the apdu sending routine. It
takes an already formatted APDU in APDUDATA or length APDUDATALEN
and returns the with the APDU including the status word. With
and returns the with an APDU including the status word. With
HANDLE_MORE set to true this function will handle the MORE DATA
status and return all APDUs concatenated with one status word at
the end. The function does not return a regular status word but 0

View File

@ -1,5 +1,5 @@
/* apdu.h - ISO 7816 APDU functions and low level I/O
* Copyright (C) 2003 Free Software Foundation, Inc.
* Copyright (C) 2003, 2008 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@ -29,8 +29,11 @@ enum {
SW_MORE_DATA = 0x6100, /* Note: that the low byte must be
masked of.*/
SW_EOF_REACHED = 0x6282,
SW_TERM_STATE = 0x6285, /* Selected file is in termination state. */
SW_EEPROM_FAILURE = 0x6581,
SW_WRONG_LENGTH = 0x6700,
SW_SM_NOT_SUP = 0x6882, /* Secure Messaging is not supported. */
SW_CC_NOT_SUP = 0x6884, /* Command Chaining is not supported. */
SW_CHV_WRONG = 0x6982,
SW_CHV_BLOCKED = 0x6983,
SW_USE_CONDITIONS = 0x6985,
@ -97,7 +100,8 @@ int apdu_get_status (int slot, int hang,
unsigned int *status, unsigned int *changed);
int apdu_check_keypad (int slot, int command, int pin_mode,
int pinlen_min, int pinlen_max, int pin_padlen);
int apdu_send_simple (int slot, int class, int ins, int p0, int p1,
int apdu_send_simple (int slot, int extended_mode,
int class, int ins, int p0, int p1,
int lc, const char *data);
int apdu_send_simple_kp (int slot, int class, int ins, int p0, int p1,
int lc, const char *data,

View File

@ -1,5 +1,5 @@
/* app-common.h - Common declarations for all card applications
* Copyright (C) 2003, 2005 Free Software Foundation, Inc.
* Copyright (C) 2003, 2005, 2008 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@ -94,8 +94,13 @@ struct app_ctx_s {
void *pincb_arg,
const void *indata, size_t indatalen,
unsigned char **outdata, size_t *outdatalen);
gpg_error_t (*writecert) (app_t app, ctrl_t ctrl,
const char *certid,
gpg_error_t (*pincb)(void*,const char *,char **),
void *pincb_arg,
const unsigned char *data, size_t datalen);
gpg_error_t (*writekey) (app_t app, ctrl_t ctrl,
const char *certid, unsigned int flags,
const char *keyid, unsigned int flags,
gpg_error_t (*pincb)(void*,const char *,char **),
void *pincb_arg,
const unsigned char *pk, size_t pklen);
@ -165,6 +170,11 @@ gpg_error_t app_decipher (app_t app, const char *keyidstr,
void *pincb_arg,
const void *indata, size_t indatalen,
unsigned char **outdata, size_t *outdatalen );
gpg_error_t app_writecert (app_t app, ctrl_t ctrl,
const char *certidstr,
gpg_error_t (*pincb)(void*, const char *, char **),
void *pincb_arg,
const unsigned char *keydata, size_t keydatalen);
gpg_error_t app_writekey (app_t app, ctrl_t ctrl,
const char *keyidstr, unsigned int flags,
gpg_error_t (*pincb)(void*, const char *, char **),

View File

@ -63,6 +63,7 @@ static struct {
} data_objects[] = {
{ 0x005E, 0, 0, 1, 0, 0, 0, "Login Data" },
{ 0x5F50, 0, 0, 0, 0, 0, 0, "URL" },
{ 0x5F52, 0, 0, 1, 0, 0, 0, "Historical Bytes" },
{ 0x0065, 1, 0, 1, 0, 0, 0, "Cardholder Related Data"},
{ 0x005B, 0, 0x65, 0, 0, 0, 0, "Name" },
{ 0x5F2D, 0, 0x65, 0, 0, 0, 0, "Language preferences" },
@ -118,7 +119,16 @@ struct app_local_s {
implicitly available. */
} pk[3];
/* Keep track of card capabilities. */
unsigned char status_indicator; /* The card status indicator. */
/* Keep track of the ISO card capabilities. */
struct
{
unsigned int cmd_chaining:1; /* Command chaining is supported. */
unsigned int ext_lc_le:1; /* Extended Lc and Le are supported. */
} cardcap;
/* Keep track of extended card capabilities. */
struct
{
unsigned int is_v2:1; /* This is a v2.0 compatible card. */
@ -126,7 +136,12 @@ struct app_local_s {
unsigned int key_import:1;
unsigned int change_force_chv:1;
unsigned int private_dos:1;
unsigned int sm_supported:1; /* Secure Messaging is supported. */
unsigned int sm_aes128:1; /* Use AES-128 for SM. */
unsigned int max_certlen_3:16;
unsigned int max_get_challenge:16; /* Maximum size for get_challenge. */
unsigned int max_cmd_data:16; /* Maximum data size for a command. */
unsigned int max_rsp_data:16; /* Maximum size of a response. */
} extcap;
/* Flags used to control the application. */
@ -451,7 +466,10 @@ dump_all_do (int slot)
if (data_objects[j].binary)
{
log_info ("DO `%s': ", data_objects[j].desc);
log_printhex ("", value, valuelen);
if (valuelen > 200)
log_info ("[%u]\n", (unsigned int)valuelen);
else
log_printhex ("", value, valuelen);
}
else
log_info ("DO `%s': `%.*s'\n",
@ -596,8 +614,9 @@ store_fpr (int slot, int keynumber, u32 timestamp,
xfree (buffer);
rc = iso7816_put_data (slot, (card_version > 0x0007? 0xC7 : 0xC6)
+ keynumber, fpr, 20);
rc = iso7816_put_data (slot, 0,
(card_version > 0x0007? 0xC7 : 0xC6)
+ keynumber, fpr, 20);
if (rc)
log_error (_("failed to store the fingerprint: %s\n"),gpg_strerror (rc));
@ -610,7 +629,7 @@ store_fpr (int slot, int keynumber, u32 timestamp,
buf[2] = timestamp >> 8;
buf[3] = timestamp;
rc = iso7816_put_data (slot, 0xCE + keynumber, buf, 4);
rc = iso7816_put_data (slot, 0, 0xCE + keynumber, buf, 4);
if (rc)
log_error (_("failed to store the creation date: %s\n"),
gpg_strerror (rc));
@ -1278,10 +1297,10 @@ do_readkey (app_t app, const char *keyid, unsigned char **pk, size_t *pklen)
#endif
}
/* Read the statdard certificate of an OpenPGP v2 card. It is
/* Read the standard certificate of an OpenPGP v2 card. It is
returned in a freshly allocated buffer with that address stored at
CERT and the length of the certificate stored at CERTLEN. CERTID
needs to be set to "OpenPGP.3". */
needs to be set to "OPENPGP.3". */
static gpg_error_t
do_readcert (app_t app, const char *certid,
unsigned char **cert, size_t *certlen)
@ -1296,10 +1315,10 @@ do_readcert (app_t app, const char *certid,
*certlen = 0;
if (strcmp (certid, "OPENPGP.3"))
return gpg_error (GPG_ERR_INV_ID);
if (app->app_local->extcap.is_v2)
if (!app->app_local->extcap.is_v2)
return gpg_error (GPG_ERR_NOT_FOUND);
relptr = get_one_do (app, 0x00C4, &buffer, &buflen, NULL);
relptr = get_one_do (app, 0x7F21, &buffer, &buflen, NULL);
if (!relptr)
return gpg_error (GPG_ERR_NOT_FOUND);
@ -1649,15 +1668,18 @@ do_setattr (app_t app, const char *name,
{ "PRIVATE-DO-3", 0x0103, 2 },
{ "PRIVATE-DO-4", 0x0104, 3 },
{ "CERT-3", 0x7F21, 3, 0, 1 },
{ "SM-KEY-ENC", 0x00D1, 3, 0, 1 },
{ "SM-KEY-MAC", 0x00D2, 3, 0, 1 },
{ "PW-RESET-CODE",0x00D3, 3, 0, 1 },
{ NULL, 0 }
};
int exmode;
for (idx=0; table[idx].name && strcmp (table[idx].name, name); idx++)
;
if (!table[idx].name)
return gpg_error (GPG_ERR_INV_NAME);
if (table[idx].need_v2)
if (table[idx].need_v2 && !app->app_local->extcap.is_v2)
return gpg_error (GPG_ERR_NOT_SUPPORTED); /* Not yet supported. */
switch (table[idx].need_chv)
@ -1678,7 +1700,12 @@ do_setattr (app_t app, const char *name,
will reread the data from the card and thus get synced in case of
errors (e.g. data truncated by the card). */
flush_cache_item (app, table[idx].tag);
rc = iso7816_put_data (app->slot, table[idx].tag, value, valuelen);
/* For command chaining we use a value of 254 for this card. */
if (app->app_local->cardcap.cmd_chaining && valuelen > 254)
exmode = -254;
else
exmode = 0;
rc = iso7816_put_data (app->slot, exmode, table[idx].tag, value, valuelen);
if (rc)
log_error ("failed to set `%s': %s\n", table[idx].name, gpg_strerror (rc));
@ -1691,6 +1718,34 @@ do_setattr (app_t app, const char *name,
}
/* Handle the WRITECERT command for OpenPGP. This rites the standard
certifciate to the card; CERTID needs to be set to "OPENPGP.3".
PINCB and PINCB_ARG are the usual arguments for the pinentry
callback. */
static gpg_error_t
do_writecert (app_t app, ctrl_t ctrl,
const char *certidstr,
gpg_error_t (*pincb)(void*, const char *, char **),
void *pincb_arg,
const unsigned char *certdata, size_t certdatalen)
{
#if GNUPG_MAJOR_VERSION > 1
if (strcmp (certidstr, "OPENPGP.3"))
return gpg_error (GPG_ERR_INV_ID);
if (!certdata || !certdatalen)
return gpg_error (GPG_ERR_INV_ARG);
if (!app->app_local->extcap.is_v2)
return gpg_error (GPG_ERR_NOT_SUPPORTED);
if (certdatalen > app->app_local->extcap.max_certlen_3)
return gpg_error (GPG_ERR_TOO_LARGE);
return do_setattr (app, "CERT-3", pincb, pincb_arg, certdata, certdatalen);
#else
return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
#endif
}
/* Handle the PASSWD command. */
static gpg_error_t
do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr,
@ -2074,7 +2129,7 @@ do_writekey (app_t app, ctrl_t ctrl,
goto leave;
/* Store the key. */
err = iso7816_put_data (app->slot,
err = iso7816_put_data (app->slot, 0,
(app->card_version > 0x0007? 0xE0 : 0xE9) + keyno,
template, template_len);
if (err)
@ -2711,6 +2766,80 @@ do_check_pin (app_t app, const char *keyidstr,
}
/* Show information about card capabilities. */
static void
show_caps (struct app_local_s *s)
{
log_info ("Version-2 ......: %s\n", s->extcap.is_v2? "yes":"no");
log_info ("Get-Challenge ..: %s", s->extcap.get_challenge? "yes":"no");
if (s->extcap.get_challenge)
log_printf (" (%u bytes max)", s->extcap.max_get_challenge);
log_info ("Key-Import .....: %s\n", s->extcap.key_import? "yes":"no");
log_info ("Change-Force-PW1: %s\n", s->extcap.change_force_chv? "yes":"no");
log_info ("Private-DOs ....: %s\n", s->extcap.private_dos? "yes":"no");
log_info ("SM-Support .....: %s", s->extcap.sm_supported? "yes":"no");
if (s->extcap.sm_supported)
log_printf (" (%s)", s->extcap.sm_aes128? "AES-128":"3DES");
log_info ("Max-Cert3-Len ..: %u\n", s->extcap.max_certlen_3);
log_info ("Max-Cmd-Data ...: %u\n", s->extcap.max_cmd_data);
log_info ("Max-Rsp-Data ...: %u\n", s->extcap.max_rsp_data);
log_info ("Cmd-Chaining ...: %s\n", s->cardcap.cmd_chaining?"yes":"no");
log_info ("Ext-Lc-Le ......: %s\n", s->cardcap.ext_lc_le?"yes":"no");
log_info ("Status Indicator: %02X\n", s->status_indicator);
log_info ("GnuPG-No-Sync ..: %s\n", s->flags.no_sync? "yes":"no");
log_info ("GnuPG-Def-PW2 ..: %s\n", s->flags.def_chv2? "yes":"no");
}
/* Parse the historical bytes in BUFFER of BUFLEN and store them in
APPLOC. */
static void
parse_historical (struct app_local_s *apploc,
const unsigned char * buffer, size_t buflen)
{
/* Example buffer: 00 31 C5 73 C0 01 80 00 90 00 */
if (buflen < 4)
{
log_error ("warning: historical bytes are too short\n");
return; /* Too short. */
}
if (*buffer)
{
log_error ("warning: bad category indicator in historical bytes\n");
return;
}
/* Skip category indicator. */
buffer++;
buflen--;
/* Get the status indicator. */
apploc->status_indicator = buffer[buflen-3];
buflen -= 3;
/* Parse the compact TLV. */
while (buflen)
{
unsigned int tag = (*buffer & 0xf0) >> 4;
unsigned int len = (*buffer & 0x0f);
if (len+1 > buflen)
{
log_error ("warning: bad Compact-TLV in historical bytes\n");
return; /* Error. */
}
buffer++;
buflen--;
if (tag == 7 && len == 3)
{
/* Card capabilities. */
apploc->cardcap.cmd_chaining = !!(buffer[2] & 0x80);
apploc->cardcap.ext_lc_le = !!(buffer[2] & 0x40);
}
buffer += len;
buflen -= len;
}
}
/* Select the OpenPGP application on the card in SLOT. This function
@ -2771,6 +2900,22 @@ app_select_openpgp (app_t app)
if (app->card_version >= 0x0200)
app->app_local->extcap.is_v2 = 1;
/* Read the historical bytes. */
relptr = get_one_do (app, 0x5f52, &buffer, &buflen, NULL);
if (relptr)
{
if (opt.verbose)
{
log_info ("Historical Bytes: ");
log_printhex ("", buffer, buflen);
}
parse_historical (app->app_local, buffer, buflen);
xfree (relptr);
}
/* Read the force-chv1 flag. */
relptr = get_one_do (app, 0x00C4, &buffer, &buflen, NULL);
if (!relptr)
{
@ -2781,6 +2926,7 @@ app_select_openpgp (app_t app)
app->force_chv1 = (buflen && *buffer == 0);
xfree (relptr);
/* Read the extended capabilities. */
relptr = get_one_do (app, 0x00C0, &buffer, &buflen, NULL);
if (!relptr)
{
@ -2790,6 +2936,7 @@ app_select_openpgp (app_t app)
}
if (buflen)
{
app->app_local->extcap.sm_supported = !!(*buffer & 0x80);
app->app_local->extcap.get_challenge = !!(*buffer & 0x40);
app->app_local->extcap.key_import = !!(*buffer & 0x20);
app->app_local->extcap.change_force_chv = !!(*buffer & 0x10);
@ -2798,7 +2945,12 @@ app_select_openpgp (app_t app)
if (buflen >= 10)
{
/* Available with v2 cards. */
app->app_local->extcap.sm_aes128 = (buffer[1] == 1);
app->app_local->extcap.max_get_challenge
= (buffer[2] << 8 | buffer[3]);
app->app_local->extcap.max_certlen_3 = (buffer[4] << 8 | buffer[5]);
app->app_local->extcap.max_cmd_data = (buffer[6] << 8 | buffer[7]);
app->app_local->extcap.max_rsp_data = (buffer[8] << 8 | buffer[9]);
}
xfree (relptr);
@ -2809,6 +2961,9 @@ app_select_openpgp (app_t app)
parse_login_data (app);
if (opt.verbose)
show_caps (app->app_local);
if (opt.verbose > 1)
dump_all_do (slot);
@ -2818,6 +2973,7 @@ app_select_openpgp (app_t app)
app->fnc.readkey = do_readkey;
app->fnc.getattr = do_getattr;
app->fnc.setattr = do_setattr;
app->fnc.writecert = do_writecert;
app->fnc.writekey = do_writekey;
app->fnc.genkey = do_genkey;
app->fnc.sign = do_sign;

View File

@ -240,8 +240,8 @@ select_application (ctrl_t ctrl, int slot, const char *name, app_t *r_app)
/* If we don't have an app, check whether we have a saved
application for that slot. This is useful so that a card does
not get reset even if only one session is using the card - so the
PIN cache and other cached data are preserved. */
not get reset even if only one session is using the card - this
way the PIN cache and other cached data are preserved. */
if (!app && lock_table[slot].initialized && lock_table[slot].last_app)
{
app = lock_table[slot].last_app;
@ -734,6 +734,34 @@ app_decipher (app_t app, const char *keyidstr,
}
/* Perform the WRITECERT operation. */
gpg_error_t
app_writecert (app_t app, ctrl_t ctrl,
const char *certidstr,
gpg_error_t (*pincb)(void*, const char *, char **),
void *pincb_arg,
const unsigned char *data, size_t datalen)
{
gpg_error_t err;
if (!app || !certidstr || !*certidstr || !pincb)
return gpg_error (GPG_ERR_INV_VALUE);
if (!app->initialized)
return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
if (!app->fnc.writecert)
return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
err = lock_reader (app->slot);
if (err)
return err;
err = app->fnc.writecert (app, ctrl, certidstr,
pincb, pincb_arg, data, datalen);
unlock_reader (app->slot);
if (opt.verbose)
log_info ("operation writecert result: %s\n", gpg_strerror (err));
return err;
}
/* Perform the WRITEKEY operation. */
gpg_error_t
app_writekey (app_t app, ctrl_t ctrl,
@ -759,7 +787,6 @@ app_writekey (app_t app, ctrl_t ctrl,
if (opt.verbose)
log_info ("operation writekey result: %s\n", gpg_strerror (err));
return err;
}

111
scd/atr.c
View File

@ -277,10 +277,121 @@ atr_dump (int slot, FILE *fp)
}
/* Note: This code has not yet been tested! It shall return -1 on
error or the nu,ber of hiostroical bytes and store them at
HISTORICAL. */
int
atr_get_historical (int slot, unsigned char historical[])
{
int result = -1;
unsigned char *atrbuffer = NULL;
unsigned char *atr;
size_t atrlen;
int have_ta, have_tb, have_tc, have_td;
int n_historical;
int idx;
unsigned char chksum;
atr = atrbuffer = apdu_get_atr (slot, &atrlen);
if (!atr || atrlen < 2)
goto leave;
atrlen--;
atr++;
chksum = *atr;
for (idx=1; idx < atrlen-1; idx++)
chksum ^= atr[idx];
have_ta = !!(*atr & 0x10);
have_tb = !!(*atr & 0x20);
have_tc = !!(*atr & 0x40);
have_td = !!(*atr & 0x80);
n_historical = (*atr & 0x0f);
if (have_ta + have_tb + have_tc + have_td + n_historical >= atrlen)
goto leave; /* ATR shorter than indicated by format character. */
atrlen--;
atr++;
if (have_ta + have_tb + have_tc >= atrlen)
goto leave;
atrlen -= have_ta + have_tb + have_tc;
atr += have_ta + have_tb + have_tc;
if (have_td)
{
have_ta = !!(*atr & 0x10);
have_tb = !!(*atr & 0x20);
have_tc = !!(*atr & 0x40);
have_td = !!(*atr & 0x80);
if (have_ta + have_tb + have_tc + have_td + n_historical >= atrlen)
goto leave; /* ATR shorter than indicated by format character. */
atrlen--;
atr++;
}
else
have_ta = have_tb = have_tc = have_td = 0;
if (have_ta + have_tb + have_tc >= atrlen)
goto leave;
atrlen -= have_ta + have_tb + have_tc;
atr += have_ta + have_tb + have_tc;
if (have_td)
{
have_ta = !!(*atr & 0x10);
have_tb = !!(*atr & 0x20);
have_tc = !!(*atr & 0x40);
have_td = !!(*atr & 0x80);
if (have_ta + have_tb + have_tc + have_td + n_historical >= atrlen)
goto leave; /* ATR shorter than indicated by format character. */
atrlen--;
atr++;
}
else
have_ta = have_tb = have_tc = have_td = 0;
for (idx = 3; have_ta || have_tb || have_tc || have_td; idx++)
{
if (have_ta + have_tb + have_tc >= atrlen)
goto leave;
atrlen -= have_ta + have_tb + have_tc;
atr += have_ta + have_tb + have_tc;
if (have_td)
{
have_ta = !!(*atr & 0x10);
have_tb = !!(*atr & 0x20);
have_tc = !!(*atr & 0x40);
have_td = !!(*atr & 0x80);
if (have_ta + have_tb + have_tc + have_td + n_historical >= atrlen)
goto leave; /* ATR shorter than indicated by format character. */
atrlen--;
atr++;
}
else
have_ta = have_tb = have_tc = have_td = 0;
}
if (n_historical >= atrlen)
goto leave; /* ATR shorter than required for historical bytes. */
if (n_historical)
{
for (idx=0; n_historical && atrlen; n_historical--, atrlen--, atr++)
historical[idx] = *atr;
}
if (!atrlen || *atr != chksum)
goto leave;
/* Don't care about garbage at the end of the ATR. */
result = n_historical;
leave:
xfree (atrbuffer);
return result;
}

View File

@ -1957,7 +1957,7 @@ ccid_transceive_apdu_level (ccid_driver_t handle,
size_t *nresp)
{
int rc;
unsigned char send_buffer[10+259], recv_buffer[10+259];
unsigned char send_buffer[10+261], recv_buffer[10+261];
const unsigned char *apdu;
size_t apdulen;
unsigned char *msg;
@ -1971,7 +1971,9 @@ ccid_transceive_apdu_level (ccid_driver_t handle,
apdulen = apdu_buflen;
assert (apdulen);
if (apdulen > 254)
/* The maximum length for a short APDU T=1 block is 261, for an
extra APDU T=1 block is 65544. */
if (apdulen > 261)
return CCID_DRIVER_ERR_INV_VALUE; /* Invalid length. */
msg[0] = PC_to_RDR_XfrBlock;
@ -2117,6 +2119,7 @@ ccid_transceive (ccid_driver_t handle,
assert (apdulen);
/* Construct an I-Block. */
#warning fixme: APDULEN may be larger
if (apdulen > 254)
return CCID_DRIVER_ERR_INV_VALUE; /* Invalid length. */

View File

@ -47,6 +47,9 @@
/* Maximum allowed size of key data as used in inquiries. */
#define MAXLEN_KEYDATA 4096
/* Maximum allowed size of certificate data as used in inquiries. */
#define MAXLEN_CERTDATA 16384
#define set_error(e,t) assuan_set_error (ctx, gpg_error (e), (t))
@ -851,14 +854,8 @@ cmd_pksign (assuan_context_t ctx, char *line)
hash_algo = GCRY_MD_SHA1;
else
return set_error (GPG_ERR_ASS_PARAMETER, "invalid hash algorithm");
/* Skip over options. */
while ( *line == '-' && line[1] == '-' )
{
while (*line && !spacep (line))
line++;
while (spacep (line))
line++;
}
line = skip_options (line);
if ( IS_LOCKED (ctrl) )
return gpg_error (GPG_ERR_LOCKED);
@ -1036,8 +1033,8 @@ cmd_getattr (assuan_context_t ctx, char *line)
names and values are depend on the currently selected smartcard
application. NAME and VALUE must be percent and '+' escaped.
However, the curent implementation assumes that Name is not escaped;
this works as long as noone uses arbitrary escaping.
However, the current implementation assumes that NAME is not
escaped; this works as long as noone uses arbitrary escaping.
A PIN will be requested for most NAMEs. See the corresponding
setattr function of the actually used application (app-*.c) for
@ -1083,12 +1080,74 @@ cmd_setattr (assuan_context_t ctx, char *orig_line)
/* WRITECERT <hexified_certid>
This command is used to store a certifciate on a smartcard. The
allowed certids depend on the currently selected smartcard
application. The actual certifciate is requested using the inquiry
"CERTDATA" and needs to be provided in its raw (e.g. DER) form.
In almost all cases a a PIN will be requested. See the related
writecert function of the actually used application (app-*.c) for
details. */
static int
cmd_writecert (assuan_context_t ctx, char *line)
{
ctrl_t ctrl = assuan_get_pointer (ctx);
int rc;
char *certid;
unsigned char *certdata;
size_t certdatalen;
if ( IS_LOCKED (ctrl) )
return gpg_error (GPG_ERR_LOCKED);
line = skip_options (line);
if (!*line)
return set_error (GPG_ERR_ASS_PARAMETER, "no certid given");
certid = line;
while (*line && !spacep (line))
line++;
*line = 0;
if ((rc = open_card (ctrl, NULL)))
return rc;
if (!ctrl->app_ctx)
return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
certid = xtrystrdup (certid);
if (!certid)
return out_of_core ();
/* Now get the actual keydata. */
rc = assuan_inquire (ctx, "CERTDATA",
&certdata, &certdatalen, MAXLEN_CERTDATA);
if (rc)
{
xfree (certid);
return rc;
}
/* Write the certificate to the card. */
rc = app_writecert (ctrl->app_ctx, ctrl, certid,
pin_cb, ctx, certdata, certdatalen);
xfree (certid);
xfree (certdata);
TEST_CARD_REMOVAL (ctrl, rc);
return rc;
}
/* WRITEKEY [--force] <keyid>
This command is used to store a secret key on a a smartcard. The
allowed keyids depend on the currently selected smartcard
application. The actual keydata is requested using the inquiry
"KETDATA" and need to be provided without any protection. With
"KEYDATA" and need to be provided without any protection. With
--force set an existing key under this KEYID will get overwritten.
The keydata is expected to be the usual canonical encoded
S-expression.
@ -1109,14 +1168,8 @@ cmd_writekey (assuan_context_t ctx, char *line)
if ( IS_LOCKED (ctrl) )
return gpg_error (GPG_ERR_LOCKED);
/* Skip over options. */
while ( *line == '-' && line[1] == '-' )
{
while (*line && !spacep (line))
line++;
while (spacep (line))
line++;
}
line = skip_options (line);
if (!*line)
return set_error (GPG_ERR_ASS_PARAMETER, "no keyid given");
keyid = line;
@ -1294,14 +1347,8 @@ cmd_passwd (assuan_context_t ctx, char *line)
if ( IS_LOCKED (ctrl) )
return gpg_error (GPG_ERR_LOCKED);
/* Skip over options. */
while (*line == '-' && line[1] == '-')
{
while (*line && !spacep (line))
line++;
while (spacep (line))
line++;
}
line = skip_options (line);
if (!*line)
return set_error (GPG_ERR_ASS_PARAMETER, "no CHV number given");
chvnostr = line;
@ -1601,14 +1648,7 @@ cmd_apdu (assuan_context_t ctx, char *line)
with_atr = has_option (line, "--atr");
handle_more = has_option (line, "--more");
/* Skip over options. */
while ( *line == '-' && line[1] == '-' )
{
while (*line && !spacep (line))
line++;
while (spacep (line))
line++;
}
line = skip_options (line);
if ( IS_LOCKED (ctrl) )
return gpg_error (GPG_ERR_LOCKED);
@ -1687,6 +1727,7 @@ register_commands (assuan_context_t ctx)
{ "OUTPUT", NULL },
{ "GETATTR", cmd_getattr },
{ "SETATTR", cmd_setattr },
{ "WRITECERT", cmd_writecert },
{ "WRITEKEY", cmd_writekey },
{ "GENKEY", cmd_genkey },
{ "RANDOM", cmd_random },

View File

@ -66,7 +66,10 @@ map_sw (int sw)
switch (sw)
{
case SW_EEPROM_FAILURE: ec = GPG_ERR_HARDWARE; break;
case SW_TERM_STATE: ec = GPG_ERR_CARD; break;
case SW_WRONG_LENGTH: ec = GPG_ERR_INV_VALUE; break;
case SW_SM_NOT_SUP: ec = GPG_ERR_NOT_SUPPORTED; break;
case SW_CC_NOT_SUP: ec = GPG_ERR_NOT_SUPPORTED; break;
case SW_CHV_WRONG: ec = GPG_ERR_BAD_PIN; break;
case SW_CHV_BLOCKED: ec = GPG_ERR_PIN_BLOCKED; break;
case SW_USE_CONDITIONS: ec = GPG_ERR_USE_CONDITIONS; break;
@ -130,7 +133,7 @@ iso7816_select_application (int slot, const char *aid, size_t aidlen,
unsigned int flags)
{
int sw;
sw = apdu_send_simple (slot, 0x00, CMD_SELECT_FILE, 4,
sw = apdu_send_simple (slot, 0, 0x00, CMD_SELECT_FILE, 4,
(flags&1)? 0 :0x0c, aidlen, aid);
return map_sw (sw);
}
@ -156,7 +159,7 @@ iso7816_select_file (int slot, int tag, int is_dir,
{
p0 = (tag == 0x3F00)? 0: is_dir? 1:2;
p1 = 0x0c; /* No FC return. */
sw = apdu_send_simple (slot, 0x00, CMD_SELECT_FILE,
sw = apdu_send_simple (slot, 0, 0x00, CMD_SELECT_FILE,
p0, p1, 2, (char*)tagbuf );
return map_sw (sw);
}
@ -192,7 +195,7 @@ iso7816_select_path (int slot, const unsigned short *path, size_t pathlen,
p0 = 0x08;
p1 = 0x0c; /* No FC return. */
sw = apdu_send_simple (slot, 0x00, CMD_SELECT_FILE,
sw = apdu_send_simple (slot, 0, 0x00, CMD_SELECT_FILE,
p0, p1, buflen, (char*)buffer );
return map_sw (sw);
}
@ -253,7 +256,7 @@ iso7816_verify_kp (int slot, int chvno, const char *chv, size_t chvlen,
pininfo->maxlen,
pininfo->padlen);
else
sw = apdu_send_simple (slot, 0x00, CMD_VERIFY, 0, chvno, chvlen, chv);
sw = apdu_send_simple (slot, 0, 0x00, CMD_VERIFY, 0, chvno, chvlen, chv);
return map_sw (sw);
}
@ -300,7 +303,7 @@ iso7816_change_reference_data_kp (int slot, int chvno,
pininfo->maxlen,
pininfo->padlen);
else
sw = apdu_send_simple (slot, 0x00, CMD_CHANGE_REFERENCE_DATA,
sw = apdu_send_simple (slot, 0, 0x00, CMD_CHANGE_REFERENCE_DATA,
oldchvlen? 0 : 1, chvno, oldchvlen+newchvlen, buf);
xfree (buf);
return map_sw (sw);
@ -340,7 +343,7 @@ iso7816_reset_retry_counter_kp (int slot, int chvno,
pininfo->maxlen,
pininfo->padlen);
else
sw = apdu_send_simple (slot, 0x00, CMD_RESET_RETRY_COUNTER,
sw = apdu_send_simple (slot, 0, 0x00, CMD_RESET_RETRY_COUNTER,
2, chvno, newchvlen, newchv);
return map_sw (sw);
}
@ -386,14 +389,16 @@ iso7816_get_data (int slot, int tag,
/* Perform a PUT DATA command on card in SLOT. Write DATA of length
DATALEN to TAG. */
DATALEN to TAG. EXTENDED_MODE controls whether extended length
headers or command chaining is used instead of single length
bytes. */
gpg_error_t
iso7816_put_data (int slot, int tag,
iso7816_put_data (int slot, int extended_mode, int tag,
const unsigned char *data, size_t datalen)
{
int sw;
sw = apdu_send_simple (slot, 0x00, CMD_PUT_DATA,
sw = apdu_send_simple (slot, extended_mode, 0x00, CMD_PUT_DATA,
((tag >> 8) & 0xff), (tag & 0xff),
datalen, (const char*)data);
return map_sw (sw);
@ -412,7 +417,7 @@ iso7816_manage_security_env (int slot, int p1, int p2,
if (p1 < 0 || p1 > 255 || p2 < 0 || p2 > 255 )
return gpg_error (GPG_ERR_INV_VALUE);
sw = apdu_send_simple (slot, 0x00, CMD_MSE, p1, p2,
sw = apdu_send_simple (slot, 0, 0x00, CMD_MSE, p1, p2,
data? datalen : -1, (const char*)data);
return map_sw (sw);
}

View File

@ -79,7 +79,7 @@ gpg_error_t iso7816_reset_retry_counter_kp (int slot, int chvno,
iso7816_pininfo_t *pininfo);
gpg_error_t iso7816_get_data (int slot, int tag,
unsigned char **result, size_t *resultlen);
gpg_error_t iso7816_put_data (int slot, int tag,
gpg_error_t iso7816_put_data (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,
const unsigned char *data,

View File

@ -982,7 +982,7 @@ gpgsm_format_keydesc (ksba_cert_t cert)
/* We also escape the quote character to work around a bug in
the mingw32 runtime which does not correcty handle command
line quoting. We correctly double the quote mark when
calling a program (i.e. gpg-protec-tool), but the pre-main
calling a program (i.e. gpg-protect-tool), but the pre-main
code does not notice the double quote as an escaped
quote. */
if (*s < ' ' || *s == '+' || *s == '\"')