Add limited support for NetKey 3.0 cards.

This commit is contained in:
Werner Koch 2009-01-08 19:56:30 +00:00
parent 901842d522
commit 7784e86a66
7 changed files with 187 additions and 54 deletions

View File

@ -1248,17 +1248,16 @@ unescape_percent_string (const unsigned char *s)
}
/* Check whether the string has characters not valid in an RFC822
/* Check whether the string has characters not valid in an RFC-822
address. To cope with OpenPGP we ignore allow non-ascii characters
so that for example umlauts are legal in an email address. An
OpenPGP user ID must be utf-8 encoded and tehre is no strict
OpenPGP user ID must be utf-8 encoded but there is no strict
requirement for RFC-822. Thus to avoid IDNA encoding we put the
address verbatim as utf-8 into the user ID under the assumtiopn
that mail programs etc handle IDNA at a lower level and take
OpenPGP user IDS as utf-8. Note that we can't do an utf-8 encoding
checking here becuase in keygen.c this function is called with the
native encoding and native to utf-8 encoding is done only after
checking. */
address verbatim as utf-8 into the user ID under the assumption
that mail programs handle IDNA at a lower level and take OpenPGP
user IDs as utf-8. Note that we can't do an utf-8 encoding
checking here because in keygen.c this function is called with the
native encoding and native to utf-8 encoding is only done later. */
int
has_invalid_email_chars (const char *s)
{

View File

@ -1,3 +1,18 @@
2009-01-08 Werner Koch <wk@g10code.com>
* iso7816.c (iso7816_read_record, iso7816_read_binary): Pass 0 for
L_e because the problem with the CCID driver has gone.
(iso7816_apdu_direct): New.
* app-nks.c (filelist): Add NKS_VER field. Add NKS 3 specific
entries.
(app_local_s, do_deinit): New.
(get_nks_version): New.
(app_select_nks): Setup local data.
(keygripstr_from_pk_file): Replace SLOT by APP and take care of
NKS version > 2.
(do_learn_status): Take care of NKS version.
2009-01-05 Werner Koch <wk@g10code.com>
* apdu.c (apdu_get_status): Save the last status.

View File

@ -2793,9 +2793,9 @@ send_apdu (int slot, unsigned char *apdu, size_t apdulen,
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
n < 0 := Use command chaining with 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
n == 1 := Use extended length for input and output without a
length limit.
n > 1 := Use extended length with up to N bytes.
*/
@ -3107,7 +3107,7 @@ apdu_send_simple_kp (int slot, int class, int ins, int p0, int p1,
/* 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 an APDU including the status word. With
and returns 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
@ -3237,7 +3237,7 @@ apdu_send_direct (int slot, const unsigned char *apdudata, size_t apdudatalen,
}
}
else
log_info ("apdu_send_sdirect(%d) "
log_info ("apdu_send_direct(%d) "
"got unexpected status %04X from get response\n",
slot, sw);
}
@ -3268,8 +3268,8 @@ apdu_send_direct (int slot, const unsigned char *apdudata, size_t apdudatalen,
unlock_slot (slot);
/* Append the status word - we reseved the two extra bytes while
allocating the buffer. */
/* Append the status word. Note that we reserved the two extra
bytes while allocating the buffer. */
if (retbuf)
{
(*retbuf)[(*retbuflen)++] = (sw >> 8);

View File

@ -1,5 +1,5 @@
/* app-nks.c - The Telesec NKS 2.0 card application.
* Copyright (C) 2004, 2007, 2008 Free Software Foundation, Inc.
/* app-nks.c - The Telesec NKS card application.
* Copyright (C) 2004, 2007, 2008, 2009 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@ -34,29 +34,55 @@
static struct
{
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. */
int iskeypair; /* If true has the FID of the correspoding certificate. */
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, 0xC000, 1, 0 },
{ 0xC000, 101 },
{ 0x4331, 100 },
{ 0x4332, 100 },
{ 0xB000, 110 },
{ 0x45B1, 0, 0xC200, 0, 1 },
{ 0xC200, 101 },
{ 0x43B1, 100 },
{ 0x43B2, 100 },
{ 0, 0 }
{ 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 }
};
/* Object with application (i.e. NKS) specific data. */
struct app_local_s {
int nks_version; /* NKS version. */
};
/* Release local data. */
static void
do_deinit (app_t app)
{
if (app && app->app_local)
{
xfree (app->app_local);
app->app_local = NULL;
}
}
/* Read the file with FID, assume it contains a public key and return
its keygrip in the caller provided 41 byte buffer R_GRIPSTR. */
static gpg_error_t
keygripstr_from_pk_file (int slot, int fid, char *r_gripstr)
keygripstr_from_pk_file (app_t app, int fid, char *r_gripstr)
{
gpg_error_t err;
unsigned char grip[20];
@ -65,29 +91,34 @@ keygripstr_from_pk_file (int slot, int fid, char *r_gripstr)
gcry_sexp_t sexp;
int i;
err = iso7816_select_file (slot, fid, 0, NULL, NULL);
err = iso7816_select_file (app->slot, fid, 0, NULL, NULL);
if (err)
return err;
err = iso7816_read_record (slot, 1, 1, 0, &buffer[0], &buflen[0]);
err = iso7816_read_record (app->slot, 1, 1, 0, &buffer[0], &buflen[0]);
if (err)
return err;
err = iso7816_read_record (slot, 2, 1, 0, &buffer[1], &buflen[1]);
err = iso7816_read_record (app->slot, 2, 1, 0, &buffer[1], &buflen[1]);
if (err)
{
xfree (buffer[0]);
return err;
}
for (i=0; i < 2; i++)
if (app->app_local->nks_version < 3)
{
/* Check that the value appears like an integer encoded as
Simple-TLV. We don't check the tag because the tests cards I
have use 1 for both, the modulus and the exponent - the
example in the documentation gives 2 for the exponent. */
if (buflen[i] < 3)
err = gpg_error (GPG_ERR_TOO_SHORT);
else if (buffer[i][1] != buflen[i]-2 )
err = gpg_error (GPG_ERR_INV_OBJ);
/* Old versions of NKS store the values in a TLV encoded format.
We need to do some checks. */
for (i=0; i < 2; i++)
{
/* Check that the value appears like an integer encoded as
Simple-TLV. We don't check the tag because the tests cards I
have use 1 for both, the modulus and the exponent - the
example in the documentation gives 2 for the exponent. */
if (buflen[i] < 3)
err = gpg_error (GPG_ERR_TOO_SHORT);
else if (buffer[i][1] != buflen[i]-2 )
err = gpg_error (GPG_ERR_INV_OBJ);
}
}
if (!err)
@ -126,6 +157,9 @@ do_learn_status (app_t app, ctrl_t ctrl)
/* Output information about all useful objects. */
for (i=0; filelist[i].fid; i++)
{
if (filelist[i].nks_ver > app->app_local->nks_version)
continue;
if (filelist[i].certtype)
{
size_t len;
@ -149,7 +183,7 @@ do_learn_status (app_t app, ctrl_t ctrl)
{
char gripstr[40+1];
err = keygripstr_from_pk_file (app->slot, filelist[i].fid, gripstr);
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));
@ -580,7 +614,40 @@ do_check_pin (app_t app, const char *keyidstr,
}
/* Select the NKS 2.0 application. */
/* Return the version of the NKS application. */
static int
get_nks_version (int slot)
{
unsigned char *result = NULL;
size_t resultlen;
int type;
if (iso7816_apdu_direct (slot, "\x80\xaa\x06\x00\x00", 5, 0,
&result, &resultlen))
return 2; /* NKS 2 does not support this command. */
/* Example value: 04 11 19 22 21 6A 20 80 03 03 01 01 01 00 00 00
vv tt ccccccccccccccccc aa bb cc vvvvvvvvvvv xx
vendor (Philips) -+ | | | | | | |
chip type -----------+ | | | | | |
chip id ----------------+ | | | | |
card type (3 - tcos 3) -------------------+ | | | |
OS version of card type ---------------------+ | | |
OS release of card type ------------------------+ | |
OS vendor internal version ------------------------+ |
RFU -----------------------------------------------------------+
*/
if (resultlen < 16)
type = 0; /* Invalid data returned. */
else
type = result[8];
xfree (result);
return type;
}
/* Select the NKS application. */
gpg_error_t
app_select_nks (app_t app)
{
@ -593,6 +660,18 @@ app_select_nks (app_t app)
{
app->apptype = "NKS";
app->app_local = xtrycalloc (1, sizeof *app->app_local);
if (!app->app_local)
{
rc = gpg_error (gpg_err_code_from_errno (errno));
goto leave;
}
app->app_local->nks_version = get_nks_version (slot);
if (opt.verbose)
log_info ("Detected NKS version: %d\n", app->app_local->nks_version);
app->fnc.deinit = do_deinit;
app->fnc.learn_status = do_learn_status;
app->fnc.readcert = do_readcert;
app->fnc.getattr = NULL;
@ -605,6 +684,9 @@ app_select_nks (app_t app)
app->fnc.check_pin = do_check_pin;
}
leave:
if (rc)
do_deinit (app);
return rc;
}

View File

@ -559,7 +559,7 @@ cmd_serialno (assuan_context_t ctx, char *line)
100 := Regular X.509 cert
101 := Trusted X.509 cert
102 := Useful X.509 cert
110 := Root CA cert (DINSIG)
110 := Root CA cert (e.g. DINSIG)
For certain cards, more information will be returned:

View File

@ -1,5 +1,5 @@
/* iso7816.c - ISO 7816 commands
* Copyright (C) 2003, 2004, 2008 Free Software Foundation, Inc.
* Copyright (C) 2003, 2004, 2008, 2009 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@ -226,6 +226,48 @@ iso7816_list_directory (int slot, int list_dirs,
}
/* This funcion sends an already formatted APDU to the card. With
HANDLE_MORE set to true a MORE DATA status will be handled
internally. The return value is a gpg error code (i.e. a mapped
status word). This is basically the same as apdu_send_direct but
it maps the status word and does not return it in the result
buffer. */
gpg_error_t
iso7816_apdu_direct (int slot, const void *apdudata, size_t apdudatalen,
int handle_more,
unsigned char **result, size_t *resultlen)
{
int sw;
if (!result || !resultlen)
return gpg_error (GPG_ERR_INV_VALUE);
*result = NULL;
*resultlen = 0;
sw = apdu_send_direct (slot, apdudata, apdudatalen, handle_more,
result, resultlen);
if (!sw)
{
if (*resultlen < 2)
sw = SW_HOST_GENERAL_ERROR;
else
{
sw = ((*result)[*resultlen-2] << 8) | (*result)[*resultlen-1];
(*resultlen)--;
(*resultlen)--;
}
}
if (sw != SW_SUCCESS)
{
/* Make sure that pending buffers are released. */
xfree (*result);
*result = NULL;
*resultlen = 0;
}
return map_sw (sw);
}
/* Check whether the reader supports the ISO command code COMMAND on
the keypad. Returns 0 on success. */
gpg_error_t
@ -668,14 +710,7 @@ iso7816_read_binary (int slot, size_t offset, size_t nmax,
{
buffer = NULL;
bufferlen = 0;
/* Note, that we to set N to 254 due to problems either with the
ccid driver or some TCOS cards. It actually should be 0
which is the official ISO value to read a variable length
object. */
if (read_all || nmax > 254)
n = 254;
else
n = nmax;
n = read_all? 0 : nmax;
sw = apdu_send_le (slot, 0x00, CMD_READ_BINARY,
((offset>>8) & 0xff), (offset & 0xff) , -1, NULL,
n, &buffer, &bufferlen);
@ -769,13 +804,11 @@ iso7816_read_record (int slot, int recno, int reccount, int short_ef,
buffer = NULL;
bufferlen = 0;
/* Fixme: Either the ccid driver or the TCOS cards have problems
with an Le of 0. */
sw = apdu_send_le (slot, 0x00, CMD_READ_RECORD,
recno,
short_ef? short_ef : 0x04,
-1, NULL,
254, &buffer, &bufferlen);
0, &buffer, &bufferlen);
if (sw != SW_SUCCESS && sw != SW_EOF_REACHED)
{

View File

@ -57,6 +57,10 @@ gpg_error_t iso7816_select_path (int slot,
unsigned char **result, size_t *resultlen);
gpg_error_t iso7816_list_directory (int slot, int list_dirs,
unsigned char **result, size_t *resultlen);
gpg_error_t iso7816_apdu_direct (int slot,
const void *apdudata, size_t apdudatalen,
int handle_more,
unsigned char **result, size_t *resultlen);
gpg_error_t iso7816_check_keypad (int slot, int command,
iso7816_pininfo_t *pininfo);
gpg_error_t iso7816_verify (int slot,