mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
Add limited support for NetKey 3.0 cards.
This commit is contained in:
parent
901842d522
commit
7784e86a66
15
g10/misc.c
15
g10/misc.c
@ -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)
|
||||
{
|
||||
|
@ -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.
|
||||
|
12
scd/apdu.c
12
scd/apdu.c
@ -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);
|
||||
|
136
scd/app-nks.c
136
scd/app-nks.c
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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:
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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,
|
||||
|
Loading…
x
Reference in New Issue
Block a user