aboutsummaryrefslogtreecommitdiffstats
path: root/scd/app-p15.c
diff options
context:
space:
mode:
Diffstat (limited to 'scd/app-p15.c')
-rw-r--r--scd/app-p15.c35
1 files changed, 30 insertions, 5 deletions
diff --git a/scd/app-p15.c b/scd/app-p15.c
index 602e97e2c..3737b85ca 100644
--- a/scd/app-p15.c
+++ b/scd/app-p15.c
@@ -466,6 +466,7 @@ select_and_read_binary (int slot, unsigned short efid, const char *efid_desc,
unsigned char **buffer, size_t *buflen)
{
gpg_error_t err;
+ int sw;
err = iso7816_select_file (slot, efid, 0);
if (err)
@@ -474,11 +475,33 @@ select_and_read_binary (int slot, unsigned short efid, const char *efid_desc,
efid_desc, efid, gpg_strerror (err));
return err;
}
- err = iso7816_read_binary (slot, 0, 0, buffer, buflen);
- if (err)
+
+ err = iso7816_read_binary_ext (slot, 0, 0, 0, buffer, buflen, &sw);
+ if (err && sw == 0x6981)
{
- log_error ("p15: error reading %s (0x%04X): %s\n",
- efid_desc, efid, gpg_strerror (err));
+ /* Command was not possible for file structure. Try to read the
+ * first record instead. */
+ err = iso7816_read_record_ext (slot, 1, 1, 0, buffer, buflen, &sw);
+ if (err)
+ {
+ log_error ("p15: error reading %s (0x%04X)"
+ " after fallback to record mode: %s (sw=%04X)\n",
+ efid_desc, efid, gpg_strerror (err), sw);
+ return err;
+ }
+ /* On a CardOS based card I noticed that the record started with
+ * a byte 0x01 followed by another byte with the length of the
+ * record. Detect this here and remove this prefix. */
+ if (*buflen > 2 && (*buffer)[0] == 1 && (*buffer)[1] == *buflen - 2)
+ {
+ memmove (*buffer, *buffer + 2, *buflen - 2);
+ *buflen = *buflen - 2;
+ }
+ }
+ else if (err)
+ {
+ log_error ("p15: error reading %s (0x%04X): %s (sw=%04X)\n",
+ efid_desc, efid, gpg_strerror (err), sw);
return err;
}
return 0;
@@ -2180,6 +2203,8 @@ read_ef_aodf (app_t app, unsigned short fid, aodf_object_t *result)
extensions of pkcs#15. */
ready:
+ if (gpg_err_code (err) == GPG_ERR_EOF)
+ err = 0;
if (opt.verbose)
{
log_info ("p15: AODF %04hX: id=", fid);
@@ -2922,7 +2947,7 @@ readcert_by_cdf (app_t app, cdf_object_t cdf,
goto leave;
err = iso7816_read_binary_ext (app_get_slot (app), 1, cdf->off, cdf->len,
- &buffer, &buflen);
+ &buffer, &buflen, NULL);
if (!err && (!buflen || *buffer == 0xff))
err = gpg_error (GPG_ERR_NOT_FOUND);
if (err)