-
Notifications
You must be signed in to change notification settings - Fork 35
Description
Hi! I'm encountering an issue with the BitString decoding since version 2.5.0. Specifically, the issue was introduced in commit 18b3b7d, which strips the "unused bits" byte and shifts the unused bits from the end to the beginning of the bit string.
The issue is that ASN.1 BitStrings are big-endian, and the Decoder
doesn't output the number of unused bits, so as far as I can tell there's no way to tell which of the bits in the output corresponds to which bit in the encoded BitString. Here's a practical example:
The FIDO U2F Authenticator Transports Extension is an X.509 extension defined thus:
-- FIDO U2F certificate extensions
id-fido-u2f-ce-transports OBJECT IDENTIFIER ::= { id-fido-u2f-ce 1 }
fidoU2FTransports EXTENSION ::= {
WITH SYNTAX FIDOU2FTransports
ID id-fido-u2f-ce-transports
}
FIDOU2FTransports ::= BIT STRING {
bluetoothRadio(0), -- Bluetooth Classic
bluetoothLowEnergyRadio(1),
uSB(2),
nFC(3),
uSBInternal(4)
}
An extension value representing the list [uSB(2), nFC(3)]
is encoded in DER as: 03 02 04 30
, representing the bit string 0011 ....
with the 4 unused bits written as .
.
Now consider this example script:
import asn1
def show_bits(bstr):
return [f"{b:08b}" for b in bstr]
ext_value = bytes([0x03, 0x02, 0x04, 0x30])
dec = asn1.Decoder()
dec.start(ext_value)
tag, value = dec.read()
print(ext_value.hex(), show_bits(ext_value))
print(value.hex(), show_bits(value))
In asn1
version 2.4.2 and earlier, this outputs:
03020430 ['00000011', '00000010', '00000100', '00110000']
0430 ['00000100', '00110000']
and you can extract the bit flags by identifying bit i
in the spec with the bit 1 << (8 - i - 1)
in the second byte of value
.
In asn1
version 2.5.0 and later, this outputs:
03020430 ['00000011', '00000010', '00000100', '00110000']
03 ['00000011']
Now the decoder doesn't return now many bits are unused, so there seems to be no way to tell if the shifted bits in the outputs represent [uSB(2), nFC(3)]
(bit string 0011 ....
) or [bluetoothRadio(0), bluetoothLowEnergyRadio(1)]
(bit string 11.. ....
), or any other combination. Had the bits been reversed, you could identify bit i
in the spec with the bit 1 << i
in the output, but the output is still big-endian so that's not possible without also extracting the "unused bits" value from the original input.
Am I missing something?
I think the decoder needs to either also return the number of unused bits, or return some higher-level data model (for example, list[bool]
or an accessor class instance) that allows extracting and/or iterating over the BitString flags.