1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-12-22 10:19:57 +01:00

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_WRONG_LENGTH : return "wrong length";
case SW_SM_NOT_SUP : return "secure messaging not supported"; case SW_SM_NOT_SUP : return "secure messaging not supported";
case SW_CC_NOT_SUP : return "command chaining 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_WRONG : return "CHV wrong";
case SW_CHV_BLOCKED : return "CHV blocked"; case SW_CHV_BLOCKED : return "CHV blocked";
case SW_REF_DATA_INV : return "referenced data invalidated"; case SW_REF_DATA_INV : return "referenced data invalidated";

View File

@ -35,6 +35,7 @@ enum {
SW_WRONG_LENGTH = 0x6700, SW_WRONG_LENGTH = 0x6700,
SW_SM_NOT_SUP = 0x6882, /* Secure Messaging is not supported. */ SW_SM_NOT_SUP = 0x6882, /* Secure Messaging is not supported. */
SW_CC_NOT_SUP = 0x6884, /* Command Chaining 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_WRONG = 0x6982,
SW_CHV_BLOCKED = 0x6983, SW_CHV_BLOCKED = 0x6983,
SW_REF_DATA_INV = 0x6984, /* Referenced data invalidated. */ 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 /* 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 desctription of the EF to be used with error messages. On success
BUFFER and BUFLEN contain the entire content of the EF. The caller 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 static gpg_error_t
select_and_read_binary (app_t app, unsigned short efid, const char *efid_desc, select_and_read_binary (app_t app, unsigned short efid, const char *efid_desc,
unsigned char **buffer, size_t *buflen) unsigned char **buffer, size_t *buflen)
@ -531,6 +531,8 @@ select_and_read_binary (app_t app, unsigned short efid, const char *efid_desc,
gpg_error_t err; gpg_error_t err;
int sw; int sw;
if (efid)
{
err = select_ef_by_path (app, &efid, 1); err = select_ef_by_path (app, &efid, 1);
if (err) if (err)
{ {
@ -538,6 +540,7 @@ select_and_read_binary (app_t app, unsigned short efid, const char *efid_desc,
efid_desc, efid, gpg_strerror (err)); efid_desc, efid, gpg_strerror (err));
return err; return err;
} }
}
err = iso7816_read_binary_ext (app_get_slot (app), err = iso7816_read_binary_ext (app_get_slot (app),
0, 0, 0, buffer, buflen, &sw); 0, 0, 0, buffer, buflen, &sw);
@ -555,11 +558,14 @@ select_and_read_binary (app_t app, unsigned short efid, const char *efid_desc,
static gpg_error_t static gpg_error_t
select_and_read_record (app_t app, unsigned short efid, int recno, select_and_read_record (app_t app, unsigned short efid, int recno,
const char *efid_desc, const char *efid_desc,
unsigned char **buffer, size_t *buflen) unsigned char **buffer, size_t *buflen, int *r_sw)
{ {
gpg_error_t err; gpg_error_t err;
int sw; int sw;
if (r_sw)
*r_sw = 0x9000;
if (efid) if (efid)
{ {
err = select_ef_by_path (app, &efid, 1); 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", log_error ("p15: error selecting %s (0x%04X): %s\n",
efid_desc, efid, gpg_strerror (err)); efid_desc, efid, gpg_strerror (err));
if (r_sw)
*r_sw = sw;
return err; return err;
} }
} }
@ -575,9 +583,15 @@ select_and_read_record (app_t app, unsigned short efid, int recno,
recno, 1, 0, buffer, buflen, &sw); recno, 1, 0, buffer, buflen, &sw);
if (err) 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", log_error ("p15: error reading %s (0x%04X) record %d: %s (sw=%04X)\n",
efid_desc, efid, recno, gpg_strerror (err), sw); efid_desc, efid, recno, gpg_strerror (err), sw);
if (r_sw)
*r_sw = sw;
return err; return err;
} }
/* On CardOS with a Linear TLV file structure the records starts /* 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) if (!pathlen)
return gpg_error (GPG_ERR_INV_VALUE); 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 (app->app_local->direct_path_selection)
{ {
if (pathlen && *path == 0x3f00 ) 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)); err = iso7816_select_mf (app_get_slot (app));
else else
err = iso7816_select_path (app_get_slot (app), path+1, pathlen-1, err = iso7816_select_path (app_get_slot (app), path+1, pathlen-1,
app->app_local->home_df); 0);
} }
else else
err = iso7816_select_path (app_get_slot (app), path, pathlen, 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; return 0;
err_print_path: err_print_path:
if (pathlen && *path == 0x3f00 ) if (pathlen && *path != 0x3f00 )
log_printf ("3F00/"); log_printf ("3F00/");
else else
log_printf ("%04hX/", app->app_local->home_df); 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. */ * the entire data. */
static gpg_error_t static gpg_error_t
read_first_record (app_t app, unsigned short fid, const char *fid_desc, 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; gpg_error_t err;
int sw;
*r_buffer = NULL; *r_buffer = NULL;
*r_buflen = 0; *r_buflen = 0;
*r_use_read_record = 0;
if (!fid) if (!fid)
return gpg_error (GPG_ERR_NO_DATA); /* No such file. */ return gpg_error (GPG_ERR_NO_DATA); /* No such file. */
if (IS_CARDOS_5 (app)) 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 else
err = select_and_read_binary (app, fid, fid_desc, r_buffer, r_buflen); 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; size_t authidlen = 0;
unsigned char *objid = NULL; unsigned char *objid = NULL;
size_t objidlen = 0; 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) if (err)
return 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 /* If the card uses a record oriented file structure, read the
* next record. Otherwise we keep on parsing the current buffer. */ * next record. Otherwise we keep on parsing the current buffer. */
recno++; recno++;
if (IS_CARDOS_5 (app)) if (record_mode)
{ {
xfree (buffer); buffer = NULL; xfree (buffer); buffer = NULL;
err = select_and_read_record (app, 0, recno, "PrKDF", err = select_and_read_record (app, 0, recno, "PrKDF",
&buffer, &buflen); &buffer, &buflen, NULL);
if (err) { if (err) {
if (gpg_err_code (err) == GPG_ERR_NOT_FOUND) if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
err = 0; err = 0;
@ -1660,8 +1692,9 @@ read_ef_pukdf (app_t app, unsigned short fid, pukdf_object_t *result)
size_t authidlen = 0; size_t authidlen = 0;
unsigned char *objid = NULL; unsigned char *objid = NULL;
size_t objidlen = 0; 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) if (err)
return 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 /* If the card uses a record oriented file structure, read the
* next record. Otherwise we keep on parsing the current buffer. */ * next record. Otherwise we keep on parsing the current buffer. */
recno++; recno++;
if (IS_CARDOS_5 (app)) if (record_mode)
{ {
xfree (buffer); buffer = NULL; xfree (buffer); buffer = NULL;
err = select_and_read_record (app, 0, recno, "PuKDF", err = select_and_read_record (app, 0, recno, "PuKDF",
&buffer, &buflen); &buffer, &buflen, NULL);
if (err) { if (err) {
if (gpg_err_code (err) == GPG_ERR_NOT_FOUND) if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
err = 0; 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 caller is then responsible of releasing this list. On error a
error code is returned and RESULT won't get changed. */ error code is returned and RESULT won't get changed. */
static gpg_error_t 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; gpg_error_t err;
unsigned char *buffer; 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; cdf_object_t cdflist = NULL;
int i; int i;
int recno = 1; 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) if (err)
return err; return err;
@ -2175,7 +2209,7 @@ read_ef_cdf (app_t app, unsigned short fid, cdf_object_t *result)
if (opt.verbose) 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++) for (i=0; i < cdf->objidlen; i++)
log_printf ("%02X", cdf->objid[i]); log_printf ("%02X", cdf->objid[i]);
log_printf (" path="); 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 /* If the card uses a record oriented file structure, read the
* next record. Otherwise we keep on parsing the current buffer. */ * next record. Otherwise we keep on parsing the current buffer. */
recno++; recno++;
if (IS_CARDOS_5 (app)) if (record_mode)
{ {
xfree (buffer); buffer = NULL; xfree (buffer); buffer = NULL;
err = select_and_read_record (app, 0, recno, "CDF", err = select_and_read_record (app, 0, recno, "CDF",
&buffer, &buflen); &buffer, &buflen, NULL);
if (err) { if (err) {
if (gpg_err_code (err) == GPG_ERR_NOT_FOUND) if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
err = 0; err = 0;
@ -2276,8 +2310,9 @@ read_ef_aodf (app_t app, unsigned short fid, aodf_object_t *result)
aodf_object_t aodflist = NULL; aodf_object_t aodflist = NULL;
int i; int i;
int recno = 1; 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) if (err)
return 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 /* If the card uses a record oriented file structure, read the
* next record. Otherwise we keep on parsing the current buffer. */ * next record. Otherwise we keep on parsing the current buffer. */
recno++; recno++;
if (IS_CARDOS_5 (app)) if (record_mode)
{ {
xfree (buffer); buffer = NULL; xfree (buffer); buffer = NULL;
err = select_and_read_record (app, 0, recno, "AODF", err = select_and_read_record (app, 0, recno, "AODF",
&buffer, &buflen); &buffer, &buflen, NULL);
if (err) { if (err) {
if (gpg_err_code (err) == GPG_ERR_NOT_FOUND) if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
err = 0; err = 0;
@ -3153,13 +3188,13 @@ read_p15_info (app_t app)
assert (!app->app_local->certificate_info); assert (!app->app_local->certificate_info);
assert (!app->app_local->trusted_certificate_info); assert (!app->app_local->trusted_certificate_info);
assert (!app->app_local->useful_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); &app->app_local->certificate_info);
if (!err || gpg_err_code (err) == GPG_ERR_NO_DATA) 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); &app->app_local->trusted_certificate_info);
if (!err || gpg_err_code (err) == GPG_ERR_NO_DATA) 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); &app->app_local->useful_certificate_info);
if (gpg_err_code (err) == GPG_ERR_NO_DATA) if (gpg_err_code (err) == GPG_ERR_NO_DATA)
err = 0; err = 0;

View File

@ -60,6 +60,7 @@ map_sw (int sw)
case SW_ACK_TIMEOUT: ec = GPG_ERR_TIMEOUT; break; case SW_ACK_TIMEOUT: ec = GPG_ERR_TIMEOUT; break;
case SW_SM_NOT_SUP: ec = GPG_ERR_NOT_SUPPORTED; 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_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_WRONG: ec = GPG_ERR_BAD_PIN; break;
case SW_CHV_BLOCKED: ec = GPG_ERR_PIN_BLOCKED; break; case SW_CHV_BLOCKED: ec = GPG_ERR_PIN_BLOCKED; break;
case SW_USE_CONDITIONS: ec = GPG_ERR_USE_CONDITIONS; break; case SW_USE_CONDITIONS: ec = GPG_ERR_USE_CONDITIONS; break;