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.
This commit is contained in:
Werner Koch 2021-02-23 12:56:42 +01:00
parent 2490f4e8e1
commit 33aaa37e5b
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
4 changed files with 67 additions and 29 deletions

View File

@ -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";

View File

@ -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. */

View File

@ -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;

View File

@ -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;