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:
parent
2490f4e8e1
commit
33aaa37e5b
@ -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";
|
||||||
|
@ -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. */
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user