ASN1 lax bit string decoding

Some ASN1 objects stored on some smartcards (for instance the
IASECC/CPX ones) do not comply strictly with the rules
8.6.2.3 and 8.6.2.3 from the ITU.

Since these rules are not some strict ones, let's have a loose
decoding option that can be displayed by the command:
opensc-explorer
  asn1 7001 # for instance

Fix: issue #2224
This commit is contained in:
Vincent JARDIN 2021-02-07 17:25:48 +00:00 committed by Frank Morgner
parent b508349010
commit 4119b2c3e7
3 changed files with 34 additions and 23 deletions

View File

@ -253,10 +253,15 @@ static void sc_asn1_print_bit_string(const u8 * buf, size_t buflen, size_t depth
if (buflen > sizeof(a) + 1) {
print_hex(buf, buflen, depth);
} else {
r = sc_asn1_decode_bit_string(buf, buflen, &a, sizeof(a));
r = sc_asn1_decode_bit_string(buf, buflen, &a, sizeof(a), 1);
if (r < 0) {
printf("decode error");
return;
printf("decode error, ");
/* try again without the strict mode */
r = sc_asn1_decode_bit_string(buf, buflen, &a, sizeof(a), 0);
if (r < 0) {
printf("even for lax decoding");
return ;
}
}
for (i = r - 1; i >= 0; i--) {
printf("%c", ((a >> i) & 1) ? '1' : '0');
@ -567,7 +572,7 @@ const u8 *sc_asn1_verify_tag(sc_context_t *ctx, const u8 * buf, size_t buflen,
}
static int decode_bit_string(const u8 * inbuf, size_t inlen, void *outbuf,
size_t outlen, int invert)
size_t outlen, int invert, const int strict)
{
const u8 *in = inbuf;
u8 *out = (u8 *) outbuf;
@ -577,13 +582,19 @@ static int decode_bit_string(const u8 * inbuf, size_t inlen, void *outbuf,
if (inlen < 1)
return SC_ERROR_INVALID_ASN1_OBJECT;
/* 8.6.2.3 If the bitstring is empty, there shall be no subsequent octets,
* and the initial octet shall be zero. */
if (inlen == 1 && *in != 0)
return SC_ERROR_INVALID_ASN1_OBJECT;
/* ITU-T Rec. X.690 8.6.2.2: The number shall be in the range zero to seven. */
if ((*in & ~0x07) != 0)
return SC_ERROR_INVALID_ASN1_OBJECT;
/* The formatting is only enforced by SHALL keyword so we should accept
* by default also non-strict values. */
if (strict) {
/* 8.6.2.3 If the bitstring is empty, there shall be no
* subsequent octets,and the initial octet shall be zero. */
if (inlen == 1 && *in != 0)
return SC_ERROR_INVALID_ASN1_OBJECT;
/* ITU-T Rec. X.690 8.6.2.2: The number shall be in the range zero to seven. */
if ((*in & ~0x07) != 0)
return SC_ERROR_INVALID_ASN1_OBJECT;
}
memset(outbuf, 0, outlen);
zero_bits = *in & 0x07;
in++;
@ -622,15 +633,15 @@ static int decode_bit_string(const u8 * inbuf, size_t inlen, void *outbuf,
}
int sc_asn1_decode_bit_string(const u8 * inbuf, size_t inlen,
void *outbuf, size_t outlen)
void *outbuf, size_t outlen, const int strict)
{
return decode_bit_string(inbuf, inlen, outbuf, outlen, 1);
return decode_bit_string(inbuf, inlen, outbuf, outlen, 1, strict);
}
int sc_asn1_decode_bit_string_ni(const u8 * inbuf, size_t inlen,
void *outbuf, size_t outlen)
void *outbuf, size_t outlen, const int strict)
{
return decode_bit_string(inbuf, inlen, outbuf, outlen, 0);
return decode_bit_string(inbuf, inlen, outbuf, outlen, 0, strict);
}
static int encode_bit_string(const u8 * inbuf, size_t bits_left, u8 **outbuf,
@ -675,7 +686,7 @@ static int encode_bit_string(const u8 * inbuf, size_t bits_left, u8 **outbuf,
* Bitfields are just bit strings, stored in an unsigned int
* (taking endianness into account)
*/
static int decode_bit_field(const u8 * inbuf, size_t inlen, void *outbuf, size_t outlen)
static int decode_bit_field(const u8 * inbuf, size_t inlen, void *outbuf, size_t outlen, const int strict)
{
u8 data[sizeof(unsigned int)];
unsigned int field = 0;
@ -684,7 +695,7 @@ static int decode_bit_field(const u8 * inbuf, size_t inlen, void *outbuf, size_t
if (outlen != sizeof(data))
return SC_ERROR_BUFFER_TOO_SMALL;
n = decode_bit_string(inbuf, inlen, data, sizeof(data), 1);
n = decode_bit_string(inbuf, inlen, data, sizeof(data), 1, strict);
if (n < 0)
return n;
@ -1538,7 +1549,7 @@ static int asn1_decode_entry(sc_context_t *ctx,struct sc_asn1_entry *entry,
*len = objlen-1;
parm = *buf;
}
r = decode_bit_string(obj, objlen, (u8 *) parm, *len, invert);
r = decode_bit_string(obj, objlen, (u8 *) parm, *len, invert, 0);
if (r >= 0) {
*len = r;
r = 0;
@ -1547,7 +1558,7 @@ static int asn1_decode_entry(sc_context_t *ctx,struct sc_asn1_entry *entry,
break;
case SC_ASN1_BIT_FIELD:
if (parm != NULL)
r = decode_bit_field(obj, objlen, (u8 *) parm, *len);
r = decode_bit_field(obj, objlen, (u8 *) parm, *len, 0);
break;
case SC_ASN1_OCTET_STRING:
if (parm != NULL) {

View File

@ -96,10 +96,10 @@ void sc_asn1_print_tags(const u8 * buf, size_t buflen);
int sc_asn1_utf8string_to_ascii(const u8 * buf, size_t buflen,
u8 * outbuf, size_t outlen);
int sc_asn1_decode_bit_string(const u8 * inbuf, size_t inlen,
void *outbuf, size_t outlen);
void *outbuf, size_t outlen, const int strict);
/* non-inverting version */
int sc_asn1_decode_bit_string_ni(const u8 * inbuf, size_t inlen,
void *outbuf, size_t outlen);
void *outbuf, size_t outlen, const int strict);
int sc_asn1_decode_integer(const u8 * inbuf, size_t inlen, int *out, int strict);
int sc_asn1_decode_object_id(const u8 * inbuf, size_t inlen,
struct sc_object_id *id);

View File

@ -195,7 +195,7 @@ TORTURE_INTEGER(negative, "\xff\x20", -224)
size_t value_len = sizeof(value); \
int rv; \
\
rv = decode_bit_field(data, datalen, &value, value_len); \
rv = decode_bit_field(data, datalen, &value, value_len, 1); \
assert_int_equal(rv, SC_SUCCESS); \
assert_int_equal(value, int_value); \
}
@ -208,7 +208,7 @@ TORTURE_INTEGER(negative, "\xff\x20", -224)
size_t value_len = sizeof(value); \
int rv; \
\
rv = decode_bit_field(data, datalen, &value, value_len); \
rv = decode_bit_field(data, datalen, &value, value_len, 1); \
assert_int_equal(rv, error); \
}
/* Without the Tag (0x03) and Length */