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

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.
This commit is contained in:
Werner Koch 2020-11-25 15:27:21 +01:00
parent 60e1ce6612
commit c7b9a4ee43
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
3 changed files with 68 additions and 14 deletions

View File

@ -466,6 +466,7 @@ select_and_read_binary (int slot, unsigned short efid, const char *efid_desc,
unsigned char **buffer, size_t *buflen) unsigned char **buffer, size_t *buflen)
{ {
gpg_error_t err; gpg_error_t err;
int sw;
err = iso7816_select_file (slot, efid, 0); err = iso7816_select_file (slot, efid, 0);
if (err) 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)); efid_desc, efid, gpg_strerror (err));
return err; return err;
} }
err = iso7816_read_binary (slot, 0, 0, buffer, buflen);
err = iso7816_read_binary_ext (slot, 0, 0, 0, buffer, buflen, &sw);
if (err && sw == 0x6981)
{
/* 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) if (err)
{ {
log_error ("p15: error reading %s (0x%04X): %s\n", log_error ("p15: error reading %s (0x%04X)"
efid_desc, efid, gpg_strerror (err)); " 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 err;
} }
return 0; return 0;
@ -2180,6 +2203,8 @@ read_ef_aodf (app_t app, unsigned short fid, aodf_object_t *result)
extensions of pkcs#15. */ extensions of pkcs#15. */
ready: ready:
if (gpg_err_code (err) == GPG_ERR_EOF)
err = 0;
if (opt.verbose) if (opt.verbose)
{ {
log_info ("p15: AODF %04hX: id=", fid); log_info ("p15: AODF %04hX: id=", fid);
@ -2922,7 +2947,7 @@ readcert_by_cdf (app_t app, cdf_object_t cdf,
goto leave; goto leave;
err = iso7816_read_binary_ext (app_get_slot (app), 1, cdf->off, cdf->len, err = iso7816_read_binary_ext (app_get_slot (app), 1, cdf->off, cdf->len,
&buffer, &buflen); &buffer, &buflen, NULL);
if (!err && (!buflen || *buffer == 0xff)) if (!err && (!buflen || *buffer == 0xff))
err = gpg_error (GPG_ERR_NOT_FOUND); err = gpg_error (GPG_ERR_NOT_FOUND);
if (err) if (err)

View File

@ -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 /* Perform a READ BINARY command requesting a maximum of NMAX bytes
from OFFSET. With NMAX = 0 the entire file is read. The result is * 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. * stored in a newly allocated buffer at the address passed by RESULT.
Returns the length of this data at the address of RESULTLEN. */ * 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 gpg_error_t
iso7816_read_binary_ext (int slot, int extended_mode, iso7816_read_binary_ext (int slot, int extended_mode,
size_t offset, size_t nmax, size_t offset, size_t nmax,
unsigned char **result, size_t *resultlen) unsigned char **result, size_t *resultlen,
int *r_sw)
{ {
int sw; int sw;
unsigned char *buffer; unsigned char *buffer;
@ -889,6 +891,9 @@ iso7816_read_binary_ext (int slot, int extended_mode,
int read_all = !nmax; int read_all = !nmax;
size_t n; size_t n;
if (r_sw)
*r_sw = 0;
if (!result || !resultlen) if (!result || !resultlen)
return gpg_error (GPG_ERR_INV_VALUE); return gpg_error (GPG_ERR_INV_VALUE);
*result = NULL; *result = NULL;
@ -914,6 +919,8 @@ iso7816_read_binary_ext (int slot, int extended_mode,
((offset>>8) & 0xff), (offset & 0xff) , -1, NULL, ((offset>>8) & 0xff), (offset & 0xff) , -1, NULL,
n, &buffer, &bufferlen); n, &buffer, &bufferlen);
} }
if (r_sw)
*r_sw = sw;
if (*result && sw == SW_BAD_P0_P1) 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, iso7816_read_binary (int slot, size_t offset, size_t nmax,
unsigned char **result, size_t *resultlen) 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 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 result is stored in a newly allocated buffer at the address passed
by RESULT. Returns the length of this data at the address of 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 gpg_error_t
iso7816_read_record (int slot, int recno, int reccount, int short_ef, iso7816_read_record_ext (int slot, int recno, int reccount, int short_ef,
unsigned char **result, size_t *resultlen) unsigned char **result, size_t *resultlen,
int *r_sw)
{ {
int sw; int sw;
unsigned char *buffer; unsigned char *buffer;
size_t bufferlen; size_t bufferlen;
if (r_sw)
*r_sw = 0;
if (!result || !resultlen) if (!result || !resultlen)
return gpg_error (GPG_ERR_INV_VALUE); return gpg_error (GPG_ERR_INV_VALUE);
*result = NULL; *result = NULL;
@ -1011,6 +1024,8 @@ iso7816_read_record (int slot, int recno, int reccount, int short_ef,
short_ef? short_ef : 0x04, short_ef? short_ef : 0x04,
-1, NULL, -1, NULL,
0, &buffer, &bufferlen); 0, &buffer, &bufferlen);
if (r_sw)
*r_sw = sw;
if (sw != SW_SUCCESS && sw != SW_EOF_REACHED) 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 /* Perform an UPDATE BINARY command on card in SLOT. Write DATA of
* length DATALEN to a transparent file at OFFSET. */ * length DATALEN to a transparent file at OFFSET. */
gpg_error_t gpg_error_t

View File

@ -142,9 +142,14 @@ gpg_error_t iso7816_get_challenge (int slot,
gpg_error_t iso7816_read_binary_ext (int slot, int extended_mode, gpg_error_t iso7816_read_binary_ext (int slot, int extended_mode,
size_t offset, size_t nmax, 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, gpg_error_t iso7816_read_binary (int slot, size_t offset, size_t nmax,
unsigned char **result, size_t *resultlen); 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, gpg_error_t iso7816_read_record (int slot, int recno, int reccount,
int short_ef, int short_ef,
unsigned char **result, size_t *resultlen); unsigned char **result, size_t *resultlen);