opensc-explorer: extend do_asn1() to decode records

Have do_asn1() accept an optional parameter indicating a record number.
If this is given and the file is a record-oriented file, then ASN.1-decode
the record requested.
This commit is contained in:
Peter Marschall 2020-03-15 18:30:37 +01:00 committed by Jakub Jelen
parent d345c65a5d
commit 45e7039940
2 changed files with 59 additions and 31 deletions

View File

@ -166,11 +166,16 @@
<term>
<command>asn1</command>
<replaceable>file-id</replaceable>
<arg choice="opt"><replaceable>rec-no</replaceable></arg>
</term>
<listitem>
<para>
Parse and print the ASN.1 encoded content of the working EF
specified by <replaceable>file-id</replaceable>.
If the optional parameter
<replaceable>rec-no</replaceable> is given and the file is
a record-oriented EF, parse and print only the record
indicated by this parameter.
</para>
</listitem>
</varlistentry>

View File

@ -47,6 +47,7 @@
#include "libopensc/cardctl.h"
#include "libopensc/cards.h"
#include "libopensc/log.h"
#include "libopensc/internal.h"
#include "common/compat_strlcpy.h"
#include <getopt.h>
#include "util.h"
@ -205,8 +206,8 @@ static struct command cmds[] = {
"apdu", "<data> ...",
"send a custom apdu command" },
{ do_asn1,
"asn1", "[<file-id>]",
"decode an ASN.1 file" },
"asn1", "[<file-id> [<rec-no>]]",
"decode an ASN.1 file or record" },
{ do_sm,
"sm", "{open|close}",
"call SM 'open' or 'close' handlers, if available"},
@ -2064,10 +2065,9 @@ static int do_asn1(int argc, char **argv)
sc_path_t path;
sc_file_t *file = NULL;
int not_current = 1;
size_t len;
unsigned char *buf = NULL;
u8 buf[SC_MAX_EXT_APDU_DATA_SIZE];
if (argc > 1)
if (argc > 2)
return usage(do_asn1);
/* select file */
@ -2081,7 +2081,7 @@ static int do_asn1(int argc, char **argv)
r = sc_select_file(card, &path, &file);
sc_unlock(card);
if (r) {
check_ret(r, SC_AC_OP_SELECT, "unable to select file", current_file);
check_ret(r, SC_AC_OP_SELECT, "Unable to select file", current_file);
goto err;
}
} else {
@ -2090,34 +2090,59 @@ static int do_asn1(int argc, char **argv)
not_current = 0;
}
if (file->type != SC_FILE_TYPE_WORKING_EF) {
fprintf(stderr, "only working EFs may be read\n");
fprintf(stderr, "Only working EFs may be read\n");
goto err;
}
/* read */
if (file->ef_structure != SC_FILE_EF_TRANSPARENT) {
fprintf(stderr, "only transparent file type is supported at the moment\n");
goto err;
if (file->ef_structure == SC_FILE_EF_TRANSPARENT) {
size_t size = (file->size > 0) ? file->size : sizeof(buf);
if (argc > 1) {
fprintf(stderr, "Transparent EFs do not support records\n");
goto err;
}
r = sc_lock(card);
if (r == SC_SUCCESS)
r = sc_read_binary(card, 0, buf, MIN(size, sizeof(buf)), 0);
sc_unlock(card);
if (r < 0) {
check_ret(r, SC_AC_OP_READ, "read failed", file);
goto err;
}
if ((size_t) r != file->size) {
fprintf(stderr, "WARNING: expecting %"SC_FORMAT_LEN_SIZE_T"u, got %d bytes.\n",
file->size, r);
/* some cards return a bogus value for file length. As
* long as the actual length is not higher than the expected
* length, continue */
if ((size_t) r > file->size)
goto err;
}
}
len = file->size;
buf = calloc(1, len);
if (!buf) {
goto err;
}
r = sc_lock(card);
if (r == SC_SUCCESS)
r = sc_read_binary(card, 0, buf, len, 0);
sc_unlock(card);
if (r < 0) {
check_ret(r, SC_AC_OP_READ, "read failed", file);
goto err;
}
if ((size_t)r != len) {
printf("WARNING: expecting %lu, got %d bytes.\n", (unsigned long) len, r);
/* some cards return a bogus value for file length. As
* long as the actual length is not higher than the expected
* length, continue */
if(r > (signed)len) {
else { /* record-oriented file */
unsigned int rec = 0;
if (argc < 2) {
fprintf(stderr, "Record-oriented EFs require parameter record number.\n");
goto err;
}
rec = (unsigned int) strtoul(argv[1], NULL, 10);
if (rec < 1 || rec > file->record_count) {
fprintf(stderr, "Invalid record number %u.\n", rec);
goto err;
}
r = sc_lock(card);
if (r == SC_SUCCESS)
r = sc_read_record(card, rec, buf, sizeof(buf), SC_RECORD_BY_REC_NR);
else
r = SC_ERROR_READER_LOCKED;
sc_unlock(card);
if (r < 0) {
check_ret(r, SC_AC_OP_READ, "Read failed", file);
goto err;
}
}
@ -2127,8 +2152,6 @@ static int do_asn1(int argc, char **argv)
err = 0;
err:
if (buf)
free(buf);
if (not_current) {
sc_file_free(file);
select_current_path_or_die();