aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2021-02-23 12:56:42 +0100
committerWerner Koch <wk@gnupg.org>2021-02-23 12:56:42 +0100
commit33aaa37e5bc0beb75305cdf9d8be850daccaee5e (patch)
tree7ab0774072679e01afd912a513e624fc9884bba9
parent2490f4e8e1d1feecb44aefa79bd71f5f8b06c9a4 (diff)
downloadgnupg-33aaa37e5bc0beb75305cdf9d8be850daccaee5e.tar.gz
scd:p15: Make it code work again for D-Trust cards.
* scd/app-p15.c (select_and_read_binary): Allow to skip the select. (select_and_read_record): Return the statusword. Silence error message for SW_FILE_STRUCT. (select_ef_by_path): Fix selection with a home_DF. (read_first_record): Fallback to read_binary for CardOS and return info about this. (read_ef_prkdf): Use info from read_first_record to decide whether to use record or binary mode. (read_ef_pukdf): Ditto. (read_ef_aodf): Ditto. (read_ef_cdf): Ditto. New arg cdftype for diagnostics. (read_p15_info): Pass cdftype. * scd/apdu.h (SW_FILE_STRUCT): New. * scd/apdu.c (apdu_strerror): Map that one to a string. * scd/iso7816.c (map_sw): and to a gpg-error.
-rw-r--r--scd/apdu.c1
-rw-r--r--scd/apdu.h1
-rw-r--r--scd/app-p15.c93
-rw-r--r--scd/iso7816.c1
4 files changed, 67 insertions, 29 deletions
diff --git a/scd/apdu.c b/scd/apdu.c
index fa0fb7c43..68ad733cb 100644
--- a/scd/apdu.c
+++ b/scd/apdu.c
@@ -544,6 +544,7 @@ apdu_strerror (int rc)
case SW_WRONG_LENGTH : return "wrong length";
case SW_SM_NOT_SUP : return "secure messaging not supported";
case SW_CC_NOT_SUP : return "command chaining not supported";
+ case SW_FILE_STRUCT : return "command can't be used for file structure.";
case SW_CHV_WRONG : return "CHV wrong";
case SW_CHV_BLOCKED : return "CHV blocked";
case SW_REF_DATA_INV : return "referenced data invalidated";
diff --git a/scd/apdu.h b/scd/apdu.h
index fd03ae6f0..2d89d68d9 100644
--- a/scd/apdu.h
+++ b/scd/apdu.h
@@ -35,6 +35,7 @@ enum {
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_FILE_STRUCT = 0x6981, /* Command can't be used for file structure. */
SW_CHV_WRONG = 0x6982,
SW_CHV_BLOCKED = 0x6983,
SW_REF_DATA_INV = 0x6984, /* Referenced data invalidated. */
diff --git a/scd/app-p15.c b/scd/app-p15.c
index 581798d2b..7016e20ec 100644
--- a/scd/app-p15.c
+++ b/scd/app-p15.c
@@ -523,7 +523,7 @@ do_deinit (app_t app)
/* Do a select and a read for the file with EFID. EFID_DESC is a
desctription of the EF to be used with error messages. On success
BUFFER and BUFLEN contain the entire content of the EF. The caller
- must free BUFFER only on success. */
+ must free BUFFER only on success. If EFID is 0 no seelct is done. */
static gpg_error_t
select_and_read_binary (app_t app, unsigned short efid, const char *efid_desc,
unsigned char **buffer, size_t *buflen)
@@ -531,12 +531,15 @@ select_and_read_binary (app_t app, unsigned short efid, const char *efid_desc,
gpg_error_t err;
int sw;
- err = select_ef_by_path (app, &efid, 1);
- if (err)
+ if (efid)
{
- log_error ("p15: error selecting %s (0x%04X): %s\n",
- efid_desc, efid, gpg_strerror (err));
- return err;
+ err = select_ef_by_path (app, &efid, 1);
+ if (err)
+ {
+ log_error ("p15: error selecting %s (0x%04X): %s\n",
+ efid_desc, efid, gpg_strerror (err));
+ return err;
+ }
}
err = iso7816_read_binary_ext (app_get_slot (app),
@@ -555,11 +558,14 @@ select_and_read_binary (app_t app, unsigned short efid, const char *efid_desc,
static gpg_error_t
select_and_read_record (app_t app, unsigned short efid, int recno,
const char *efid_desc,
- unsigned char **buffer, size_t *buflen)
+ unsigned char **buffer, size_t *buflen, int *r_sw)
{
gpg_error_t err;
int sw;
+ if (r_sw)
+ *r_sw = 0x9000;
+
if (efid)
{
err = select_ef_by_path (app, &efid, 1);
@@ -567,6 +573,8 @@ select_and_read_record (app_t app, unsigned short efid, int recno,
{
log_error ("p15: error selecting %s (0x%04X): %s\n",
efid_desc, efid, gpg_strerror (err));
+ if (r_sw)
+ *r_sw = sw;
return err;
}
}
@@ -575,9 +583,15 @@ select_and_read_record (app_t app, unsigned short efid, int recno,
recno, 1, 0, buffer, buflen, &sw);
if (err)
{
- if (gpg_err_code (err) != GPG_ERR_NOT_FOUND)
+ if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
+ ;
+ else if (err && sw == SW_FILE_STRUCT)
+ ;
+ else
log_error ("p15: error reading %s (0x%04X) record %d: %s (sw=%04X)\n",
efid_desc, efid, recno, gpg_strerror (err), sw);
+ if (r_sw)
+ *r_sw = sw;
return err;
}
/* On CardOS with a Linear TLV file structure the records starts
@@ -604,6 +618,11 @@ select_ef_by_path (app_t app, const unsigned short *path, size_t pathlen)
if (!pathlen)
return gpg_error (GPG_ERR_INV_VALUE);
+ /* log_debug ("%s: path=", __func__); */
+ /* for (j=0; j < pathlen; j++) */
+ /* log_printf ("%s%04hX", j? "/":"", path[j]); */
+ /* log_printf ("%s\n",app->app_local->direct_path_selection?" (direct)":"");*/
+
if (app->app_local->direct_path_selection)
{
if (pathlen && *path == 0x3f00 )
@@ -612,7 +631,7 @@ select_ef_by_path (app_t app, const unsigned short *path, size_t pathlen)
err = iso7816_select_mf (app_get_slot (app));
else
err = iso7816_select_path (app_get_slot (app), path+1, pathlen-1,
- app->app_local->home_df);
+ 0);
}
else
err = iso7816_select_path (app_get_slot (app), path, pathlen,
@@ -643,7 +662,7 @@ select_ef_by_path (app_t app, const unsigned short *path, size_t pathlen)
return 0;
err_print_path:
- if (pathlen && *path == 0x3f00 )
+ if (pathlen && *path != 0x3f00 )
log_printf ("3F00/");
else
log_printf ("%04hX/", app->app_local->home_df);
@@ -950,18 +969,30 @@ read_ef_odf (app_t app, unsigned short odf_fid)
* the entire data. */
static gpg_error_t
read_first_record (app_t app, unsigned short fid, const char *fid_desc,
- unsigned char **r_buffer, size_t *r_buflen)
+ unsigned char **r_buffer, size_t *r_buflen,
+ int *r_use_read_record)
{
gpg_error_t err;
+ int sw;
*r_buffer = NULL;
*r_buflen = 0;
+ *r_use_read_record = 0;
if (!fid)
return gpg_error (GPG_ERR_NO_DATA); /* No such file. */
if (IS_CARDOS_5 (app))
- err = select_and_read_record (app, fid, 1, fid_desc, r_buffer, r_buflen);
+ {
+ *r_use_read_record = 1;
+ err = select_and_read_record (app, fid, 1, fid_desc,
+ r_buffer, r_buflen, &sw);
+ if (err && sw == SW_FILE_STRUCT)
+ {
+ *r_use_read_record = 0;
+ err = select_and_read_binary (app, 0, fid_desc, r_buffer, r_buflen);
+ }
+ }
else
err = select_and_read_binary (app, fid, fid_desc, r_buffer, r_buflen);
@@ -1372,8 +1403,9 @@ read_ef_prkdf (app_t app, unsigned short fid, prkdf_object_t *result)
size_t authidlen = 0;
unsigned char *objid = NULL;
size_t objidlen = 0;
+ int record_mode;
- err = read_first_record (app, fid, "PrKDF", &buffer, &buflen);
+ err = read_first_record (app, fid, "PrKDF", &buffer, &buflen, &record_mode);
if (err)
return err;
@@ -1616,11 +1648,11 @@ read_ef_prkdf (app_t app, unsigned short fid, prkdf_object_t *result)
/* If the card uses a record oriented file structure, read the
* next record. Otherwise we keep on parsing the current buffer. */
recno++;
- if (IS_CARDOS_5 (app))
+ if (record_mode)
{
xfree (buffer); buffer = NULL;
err = select_and_read_record (app, 0, recno, "PrKDF",
- &buffer, &buflen);
+ &buffer, &buflen, NULL);
if (err) {
if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
err = 0;
@@ -1660,8 +1692,9 @@ read_ef_pukdf (app_t app, unsigned short fid, pukdf_object_t *result)
size_t authidlen = 0;
unsigned char *objid = NULL;
size_t objidlen = 0;
+ int record_mode;
- err = read_first_record (app, fid, "PuKDF", &buffer, &buflen);
+ err = read_first_record (app, fid, "PuKDF", &buffer, &buflen, &record_mode);
if (err)
return err;
@@ -1940,11 +1973,11 @@ read_ef_pukdf (app_t app, unsigned short fid, pukdf_object_t *result)
/* If the card uses a record oriented file structure, read the
* next record. Otherwise we keep on parsing the current buffer. */
recno++;
- if (IS_CARDOS_5 (app))
+ if (record_mode)
{
xfree (buffer); buffer = NULL;
err = select_and_read_record (app, 0, recno, "PuKDF",
- &buffer, &buflen);
+ &buffer, &buflen, NULL);
if (err) {
if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
err = 0;
@@ -1972,7 +2005,7 @@ read_ef_pukdf (app_t app, unsigned short fid, pukdf_object_t *result)
caller is then responsible of releasing this list. On error a
error code is returned and RESULT won't get changed. */
static gpg_error_t
-read_ef_cdf (app_t app, unsigned short fid, cdf_object_t *result)
+read_ef_cdf (app_t app, unsigned short fid, int cdftype, cdf_object_t *result)
{
gpg_error_t err;
unsigned char *buffer;
@@ -1983,8 +2016,9 @@ read_ef_cdf (app_t app, unsigned short fid, cdf_object_t *result)
cdf_object_t cdflist = NULL;
int i;
int recno = 1;
+ int record_mode;
- err = read_first_record (app, fid, "CDF", &buffer, &buflen);
+ err = read_first_record (app, fid, "CDF", &buffer, &buflen, &record_mode);
if (err)
return err;
@@ -2175,7 +2209,7 @@ read_ef_cdf (app_t app, unsigned short fid, cdf_object_t *result)
if (opt.verbose)
{
- log_info ("p15: CDF %04hX: id=", fid);
+ log_info ("p15: CDF(%c) %04hX: id=", cdftype, fid);
for (i=0; i < cdf->objidlen; i++)
log_printf ("%02X", cdf->objid[i]);
log_printf (" path=");
@@ -2202,11 +2236,11 @@ read_ef_cdf (app_t app, unsigned short fid, cdf_object_t *result)
/* If the card uses a record oriented file structure, read the
* next record. Otherwise we keep on parsing the current buffer. */
recno++;
- if (IS_CARDOS_5 (app))
+ if (record_mode)
{
xfree (buffer); buffer = NULL;
err = select_and_read_record (app, 0, recno, "CDF",
- &buffer, &buflen);
+ &buffer, &buflen, NULL);
if (err) {
if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
err = 0;
@@ -2276,8 +2310,9 @@ read_ef_aodf (app_t app, unsigned short fid, aodf_object_t *result)
aodf_object_t aodflist = NULL;
int i;
int recno = 1;
+ int record_mode;
- err = read_first_record (app, fid, "AODF", &buffer, &buflen);
+ err = read_first_record (app, fid, "AODF", &buffer, &buflen, &record_mode);
if (err)
return err;
@@ -2823,11 +2858,11 @@ read_ef_aodf (app_t app, unsigned short fid, aodf_object_t *result)
/* If the card uses a record oriented file structure, read the
* next record. Otherwise we keep on parsing the current buffer. */
recno++;
- if (IS_CARDOS_5 (app))
+ if (record_mode)
{
xfree (buffer); buffer = NULL;
err = select_and_read_record (app, 0, recno, "AODF",
- &buffer, &buflen);
+ &buffer, &buflen, NULL);
if (err) {
if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
err = 0;
@@ -3153,13 +3188,13 @@ read_p15_info (app_t app)
assert (!app->app_local->certificate_info);
assert (!app->app_local->trusted_certificate_info);
assert (!app->app_local->useful_certificate_info);
- err = read_ef_cdf (app, app->app_local->odf.certificates,
+ err = read_ef_cdf (app, app->app_local->odf.certificates, 'c',
&app->app_local->certificate_info);
if (!err || gpg_err_code (err) == GPG_ERR_NO_DATA)
- err = read_ef_cdf (app, app->app_local->odf.trusted_certificates,
+ err = read_ef_cdf (app, app->app_local->odf.trusted_certificates, 't',
&app->app_local->trusted_certificate_info);
if (!err || gpg_err_code (err) == GPG_ERR_NO_DATA)
- err = read_ef_cdf (app, app->app_local->odf.useful_certificates,
+ err = read_ef_cdf (app, app->app_local->odf.useful_certificates, 'u',
&app->app_local->useful_certificate_info);
if (gpg_err_code (err) == GPG_ERR_NO_DATA)
err = 0;
diff --git a/scd/iso7816.c b/scd/iso7816.c
index a796553d7..19464eab7 100644
--- a/scd/iso7816.c
+++ b/scd/iso7816.c
@@ -60,6 +60,7 @@ map_sw (int sw)
case SW_ACK_TIMEOUT: ec = GPG_ERR_TIMEOUT; 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_FILE_STRUCT: ec = GPG_ERR_CARD; 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;