aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2020-11-25 15:27:21 +0100
committerWerner Koch <wk@gnupg.org>2020-11-25 15:27:21 +0100
commitc7b9a4ee439eca5a4bde4781f7d8983af3b9201e (patch)
tree91c9e32dd9b3465e28108e5f5f30dc3dd5a46f78
parent60e1ce66120b2972539c7c73248ca94ed1c76bc4 (diff)
downloadgnupg-c7b9a4ee439eca5a4bde4781f7d8983af3b9201e.tar.gz
scd:p15: Improve support for some CardOS based cards.
* scd/iso7816.c (iso7816_read_binary_ext): Add optional arg r_sw and change callers. (iso7816_read_record): Factor all code out to ... (iso7816_read_record_ext): new. * scd/app-p15.c (select_and_read_binary): Fallback to record reading. (read_ef_aodf): Clear EOF error.
-rw-r--r--scd/app-p15.c35
-rw-r--r--scd/iso7816.c40
-rw-r--r--scd/iso7816.h7
3 files changed, 68 insertions, 14 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)
diff --git a/scd/iso7816.c b/scd/iso7816.c
index 5316d0b3b..ef02d64cc 100644
--- a/scd/iso7816.c
+++ b/scd/iso7816.c
@@ -875,13 +875,15 @@ iso7816_get_challenge (int slot, int length, unsigned char *buffer)
}
/* Perform a READ BINARY command requesting a maximum of NMAX bytes
- from OFFSET. With NMAX = 0 the entire file is read. The result is
- stored in a newly allocated buffer at the address passed by RESULT.
- Returns the length of this data at the address of RESULTLEN. */
+ * from OFFSET. With NMAX = 0 the entire file is read. The result is
+ * stored in a newly allocated buffer at the address passed by RESULT.
+ * Returns the length of this data at the address of RESULTLEN. If
+ * R_SW is not NULL the last status word is stored there. */
gpg_error_t
iso7816_read_binary_ext (int slot, int extended_mode,
size_t offset, size_t nmax,
- unsigned char **result, size_t *resultlen)
+ unsigned char **result, size_t *resultlen,
+ int *r_sw)
{
int sw;
unsigned char *buffer;
@@ -889,6 +891,9 @@ iso7816_read_binary_ext (int slot, int extended_mode,
int read_all = !nmax;
size_t n;
+ if (r_sw)
+ *r_sw = 0;
+
if (!result || !resultlen)
return gpg_error (GPG_ERR_INV_VALUE);
*result = NULL;
@@ -914,6 +919,8 @@ iso7816_read_binary_ext (int slot, int extended_mode,
((offset>>8) & 0xff), (offset & 0xff) , -1, NULL,
n, &buffer, &bufferlen);
}
+ if (r_sw)
+ *r_sw = sw;
if (*result && sw == SW_BAD_P0_P1)
{
@@ -974,7 +981,8 @@ gpg_error_t
iso7816_read_binary (int slot, size_t offset, size_t nmax,
unsigned char **result, size_t *resultlen)
{
- return iso7816_read_binary_ext (slot, 0, offset, nmax, result, resultlen);
+ return iso7816_read_binary_ext (slot, 0, offset, nmax,
+ result, resultlen, NULL);
}
@@ -984,15 +992,20 @@ iso7816_read_binary (int slot, size_t offset, size_t nmax,
should be 0 to read the current EF or contain a short EF. The
result is stored in a newly allocated buffer at the address passed
by RESULT. Returns the length of this data at the address of
- RESULTLEN. */
+ RESULTLEN. If R_SW is not NULL the last status word is stored
+ there. */
gpg_error_t
-iso7816_read_record (int slot, int recno, int reccount, int short_ef,
- unsigned char **result, size_t *resultlen)
+iso7816_read_record_ext (int slot, int recno, int reccount, int short_ef,
+ unsigned char **result, size_t *resultlen,
+ int *r_sw)
{
int sw;
unsigned char *buffer;
size_t bufferlen;
+ if (r_sw)
+ *r_sw = 0;
+
if (!result || !resultlen)
return gpg_error (GPG_ERR_INV_VALUE);
*result = NULL;
@@ -1011,6 +1024,8 @@ iso7816_read_record (int slot, int recno, int reccount, int short_ef,
short_ef? short_ef : 0x04,
-1, NULL,
0, &buffer, &bufferlen);
+ if (r_sw)
+ *r_sw = sw;
if (sw != SW_SUCCESS && sw != SW_EOF_REACHED)
{
@@ -1028,6 +1043,15 @@ iso7816_read_record (int slot, int recno, int reccount, int short_ef,
}
+gpg_error_t
+iso7816_read_record (int slot, int recno, int reccount, int short_ef,
+ unsigned char **result, size_t *resultlen)
+{
+ return iso7816_read_record_ext (slot, recno, reccount, short_ef,
+ result, resultlen, NULL);
+}
+
+
/* Perform an UPDATE BINARY command on card in SLOT. Write DATA of
* length DATALEN to a transparent file at OFFSET. */
gpg_error_t
diff --git a/scd/iso7816.h b/scd/iso7816.h
index 10a1aa8d1..d68ee57f2 100644
--- a/scd/iso7816.h
+++ b/scd/iso7816.h
@@ -142,9 +142,14 @@ gpg_error_t iso7816_get_challenge (int slot,
gpg_error_t iso7816_read_binary_ext (int slot, int extended_mode,
size_t offset, size_t nmax,
- unsigned char **result, size_t *resultlen);
+ unsigned char **result, size_t *resultlen,
+ int *r_sw);
gpg_error_t iso7816_read_binary (int slot, size_t offset, size_t nmax,
unsigned char **result, size_t *resultlen);
+gpg_error_t iso7816_read_record_ext (int slot, int recno, int reccount,
+ int short_ef,
+ unsigned char **result, size_t *resultlen,
+ int *r_sw);
gpg_error_t iso7816_read_record (int slot, int recno, int reccount,
int short_ef,
unsigned char **result, size_t *resultlen);