* app-p15.c (micardo_mse): New.

(do_sign): Call it.
* iso7816.c (iso7816_manage_security_env): Allow passing DATA as
NULL to indicate an empty Lc.
* tlv.c (find_tlv): Check that a found object fits into the
buffer.
(find_tlv_unchecked): New as replacement for the old non-checking
variant.
* app.c (select_application): Keep on using the non-checking
variant.
* app-openpgp.c (get_one_do, dump_all_do): Ditto.
This commit is contained in:
Werner Koch 2005-04-27 19:47:53 +00:00
parent f2fe118bfb
commit eb3f014b5d
7 changed files with 175 additions and 29 deletions

View File

@ -1,5 +1,18 @@
2005-04-27 Werner Koch <wk@g10code.com>
* app-p15.c (micardo_mse): New.
(do_sign): Call it.
* iso7816.c (iso7816_manage_security_env): Allow passing DATA as
NULL to indicate an empty Lc.
* tlv.c (find_tlv): Check that a found object fits into the
buffer.
(find_tlv_unchecked): New as replacement for the old non-checking
variant.
* app.c (select_application): Keep on using the non-checking
variant.
* app-openpgp.c (get_one_do, dump_all_do): Ditto.
Removal of the old OpenSC based code.
* app-p15.c: New. Basic support for pkcs15 cards without OpenSC.

View File

@ -357,7 +357,7 @@ get_one_do (app_t app, int tag, unsigned char **result, size_t *nbytes,
{
const unsigned char *s;
s = find_tlv (buffer, buflen, tag, &valuelen);
s = find_tlv_unchecked (buffer, buflen, tag, &valuelen);
if (!s)
value = NULL; /* not found */
else if (valuelen > buflen - (s - buffer))
@ -433,8 +433,8 @@ dump_all_do (int slot)
if (j==i || data_objects[i].tag != data_objects[j].get_from)
continue;
value = find_tlv (buffer, buflen,
data_objects[j].tag, &valuelen);
value = find_tlv_unchecked (buffer, buflen,
data_objects[j].tag, &valuelen);
if (!value)
; /* not found */
else if (valuelen > buflen - (value - buffer))

View File

@ -59,11 +59,15 @@ static struct
"\x90\x00\x66",
CARD_TYPE_TCOS }, /* SLE66P */
{ 27, "\x3B\xFF\x94\x00\xFF\x80\xB1\xFE\x45\x1F\x03\x00\x68\xD2\x76\x00"
"\x00\x28\xFF\x05\x1E\x31\x80\x00\x90\x00\x23",
"\x00\x28\xFF\x05\x1E\x31\x80\x00\x90\x00\x23",
CARD_TYPE_MICARDO }, /* German BMI card */
{ 19, "\x3B\x6F\x00\xFF\x00\x68\xD2\x76\x00\x00\x28\xFF\x05\x1E\x31\x80"
"\x00\x90\x00",
CARD_TYPE_MICARDO }, /* German BMI card (ATR due to reader problem) */
{ 26, "\x3B\xFE\x94\x00\xFF\x80\xB1\xFA\x45\x1F\x03\x45\x73\x74\x45\x49"
"\x44\x20\x76\x65\x72\x20\x31\x2E\x30\x43",
CARD_TYPE_MICARDO }, /* EstEID (Estonian Big Brother card) */
{ 0 }
};
@ -392,7 +396,7 @@ select_and_read_binary (int slot, unsigned short efid, const char *efid_desc,
}
/* This function calls select file to read a file suing a complete
/* This function calls select file to read a file using a complete
path which may or may not start at the master file (MF). */
static gpg_error_t
select_ef_by_path (app_t app, const unsigned short *path, size_t pathlen)
@ -2525,6 +2529,99 @@ do_readcert (app_t app, const char *certid,
}
/* Micardo cards require special treatment. This is a helper for the
crypto functions to manage the security environment. We expect that
the key file has already been selected. FID is the one of the
selected key. */
static gpg_error_t
micardo_mse (app_t app, unsigned short fid)
{
gpg_error_t err;
int recno;
unsigned short refdata = 0;
int se_num;
unsigned char msebuf[10];
/* Read the KeyD file containing extra information on keys. */
err = iso7816_select_file (app->slot, 0x0013, 0, NULL, NULL);
if (err)
{
log_error ("error reading EF_keyD: %s\n", gpg_strerror (err));
return err;
}
for (recno = 1, se_num = -1; ; recno++)
{
unsigned char *buffer;
size_t buflen;
size_t n, nn;
const unsigned char *p, *pp;
err = iso7816_read_record (app->slot, recno, 1, 0, &buffer, &buflen);
if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
break; /* ready */
if (err)
{
log_error ("error reading EF_keyD record: %s\n",
gpg_strerror (err));
return err;
}
log_printhex ("keyD record:", buffer, buflen);
p = find_tlv (buffer, buflen, 0x83, &n);
if (p && n == 4 && ((p[2]<<8)|p[3]) == fid)
{
refdata = ((p[0]<<8)|p[1]);
/* Locate the SE DO and the there included sec env number. */
p = find_tlv (buffer, buflen, 0x7b, &n);
if (p && n)
{
pp = find_tlv (p, n, 0x80, &nn);
if (pp && nn == 1)
{
se_num = *pp;
xfree (buffer);
break; /* found. */
}
}
}
xfree (buffer);
}
if (se_num == -1)
{
log_error ("CRT for keyfile %04hX not found\n", fid);
return gpg_error (GPG_ERR_NOT_FOUND);
}
/* Restore the security environment to SE_NUM if needed */
if (se_num)
{
err = iso7816_manage_security_env (app->slot, 0xf3, se_num, NULL, 0);
if (err)
{
log_error ("restoring SE to %d failed: %s\n",
se_num, gpg_strerror (err));
return err;
}
}
/* Set the DST reference data. */
msebuf[0] = 0x83;
msebuf[1] = 0x03;
msebuf[2] = 0x80;
msebuf[3] = (refdata >> 8);
msebuf[4] = refdata;
err = iso7816_manage_security_env (app->slot, 0x41, 0xb6, msebuf, 5);
if (err)
{
log_error ("setting SE to reference file %04hX failed: %s\n",
refdata, gpg_strerror (err));
return err;
}
return 0;
}
/* Handler for the PKSIGN command.
@ -2561,6 +2658,13 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
err = prkdf_object_from_keyidstr (app, keyidstr, &prkdf);
if (err)
return err;
if (!(prkdf->usageflags.sign || prkdf->usageflags.sign_recover
||prkdf->usageflags.non_repudiation))
{
log_error ("key %s may not be used for signing\n", keyidstr);
return gpg_error (GPG_ERR_WRONG_KEY_USAGE);
}
if (!prkdf->authid)
{
log_error ("no authentication object defined for %s\n", keyidstr);
@ -2597,6 +2701,16 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
return gpg_error (GPG_ERR_INV_CARD);
}
/* Select the key file. Note that this may change the security
environment thus we do it before PIN verification. */
err = select_ef_by_path (app, prkdf->path, prkdf->pathlen);
if (err)
{
log_error ("error selecting file for key %s: %s\n",
keyidstr, gpg_strerror (errno));
return err;
}
/* Now that we have all the information available, prepare and run
the PIN verification.*/
if (1)
@ -2742,7 +2856,6 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
memcpy (data+15, indata, indatalen);
}
/* Manage security environment needs to be weaked for certain cards. */
if (app->app_local->card_type == CARD_TYPE_TCOS)
{
@ -2751,10 +2864,10 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
}
else if (app->app_local->card_type == CARD_TYPE_MICARDO)
{
/* Micardo cards are very special in that they need to restore a
security environment using a infomration from a special
file. */
log_error ("WARNING: support for MICARDO cards is not yet available\n");
if (!prkdf->pathlen)
err = gpg_error (GPG_ERR_BUG);
else
err = micardo_mse (app, prkdf->path[prkdf->pathlen-1]);
}
else if (prkdf->key_reference_valid)
{
@ -2767,11 +2880,11 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
err = iso7816_manage_security_env (app->slot,
0x41, 0xB6,
mse, sizeof mse);
if (err)
{
log_error ("MSE failed: %s\n", gpg_strerror (err));
return err;
}
}
if (err)
{
log_error ("MSE failed: %s\n", gpg_strerror (err));
return err;
}
@ -2782,9 +2895,6 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
/* Select the PKCS#15 application on the card in SLOT. */
gpg_error_t
app_select_p15 (app_t app)
@ -2846,7 +2956,7 @@ app_select_p15 (app_t app)
the common APP structure. */
app->app_local->card_type = card_type;
/* Read basic information and check whether this is a real
/* Read basic information and thus check whether this is a real
card. */
rc = read_p15_info (app);
if (rc)

View File

@ -83,7 +83,7 @@ select_application (ctrl_t ctrl, int slot, const char *name, app_t *r_app)
size_t n;
const unsigned char *p;
p = find_tlv (result, resultlen, 0x5A, &n);
p = find_tlv_unchecked (result, resultlen, 0x5A, &n);
if (p)
resultlen -= (p-result);
if (p && n > resultlen && n == 0x0d && resultlen+1 == n)

View File

@ -299,10 +299,11 @@ iso7816_manage_security_env (int slot, int p1, int p2,
{
int sw;
if (p1 < 0 || p1 > 255 || p2 < 0 || p2 > 255 || !data || !datalen)
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, datalen, data);
sw = apdu_send_simple (slot, 0x00, CMD_MSE, p1, p2,
data? datalen : -1, data);
return map_sw (sw);
}
@ -605,7 +606,7 @@ iso7816_read_record (int slot, int recno, int reccount, int short_ef,
buffer = NULL;
bufferlen = 0;
/* Fixme: Either the ccid driver of the TCOS cards have problems
/* 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,

View File

@ -1,5 +1,5 @@
/* tlv.c - Tag-Length-Value Utilities
* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
* Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@ -113,17 +113,32 @@ do_find_tlv (const unsigned char *buffer, size_t length,
/* Locate a TLV encoded data object in BUFFER of LENGTH and
return a pointer to value as well as its length in NBYTES. Return
NULL if it was not found. Note, that the function does not check
whether the value fits into the provided buffer. */
NULL if it was not found or if the object does not fit into the buffer. */
const unsigned char *
find_tlv (const unsigned char *buffer, size_t length,
int tag, size_t *nbytes)
{
return do_find_tlv (buffer, length, tag, nbytes, 0);
const unsigned char *p;
p = do_find_tlv (buffer, length, tag, nbytes, 0);
if (p && *nbytes > (length - (p-buffer)))
p = NULL; /* Object longer than buffer. */
return p;
}
/* Locate a TLV encoded data object in BUFFER of LENGTH and
return a pointer to value as well as its length in NBYTES. Return
NULL if it was not found. Note, that the function does not check
whether the value fits into the provided buffer. */
const unsigned char *
find_tlv_unchecked (const unsigned char *buffer, size_t length,
int tag, size_t *nbytes)
{
return do_find_tlv (buffer, length, tag, nbytes, 0);
}
/* ASN.1 BER parser: Parse BUFFER of length SIZE and return the tag
and the length part from the TLV triplet. Update BUFFER and SIZE

View File

@ -62,13 +62,20 @@ enum tlv_tag_type {
};
/* Locate a TLV encoded data object in BUFFER of LENGTH and return a
pointer to value as well as its length in NBYTES. Return NULL if
it was not found or if the object does not fit into the buffer. */
const unsigned char *find_tlv (const unsigned char *buffer, size_t length,
int tag, size_t *nbytes);
/* Locate a TLV encoded data object in BUFFER of LENGTH and return a
pointer to value as well as its length in NBYTES. Return NULL if
it was not found. Note, that the function does not check whether
the value fits into the provided buffer.*/
const unsigned char *find_tlv (const unsigned char *buffer, size_t length,
int tag, size_t *nbytes);
const unsigned char *find_tlv_unchecked (const unsigned char *buffer,
size_t length,
int tag, size_t *nbytes);
/* ASN.1 BER parser: Parse BUFFER of length SIZE and return the tag