asn.1pyasn1

How to recover the substrate from a pyasn1 object?


I have a complicated nested ASN.1 structure as bytes. I want to find all T61Strings (say) in that structure, in the original byte encoding. Is this possible in pyasn1?

So far, I only know how to locate the the T61Strings (or whatever) in the BER-decoded Python object. I could re-encode each one, but there's no guarantee that the re-encoded values would match the originals. There's some crypto in play here, hence the fussiness about those byte values.

If I could just do decoded_object.get_substrate(), or similar, I'd be sorted.

Thoughts? Thanks.


Update: Ilya Etingof's answer seems to work nicely.

In [61]: class X(pyasn1.codec.ber.decoder.Decoder):
    ...:     def __call__(self,*v,**kw):
    ...:         parsed,remainder = pyasn1.codec.ber.decoder.Decoder.__call__(self,*v,**kw)
    ...:         parsed._substrate = v[0][:len(v[0])-len(remainder)]
    ...:         return parsed,remainder
    ...:     

In [62]: decode = X(pyasn1.codec.ber.decoder.tagMap,pyasn1.codec.ber.decoder.typeMap)

In [63]: tmp = decode(b'\x30\x05\x02\x01\x7f\x05\x00')[0]

In [64]: tmp._substrate.encode('hex')
Out[64]: '300502017f0500'

In [65]: tmp[0]._substrate.encode('hex')
Out[65]: '02017f'

In [66]: tmp[1]._substrate.encode('hex')
Out[66]: '0500'

In [67]: 

Solution

  • Is it BER, not DER? Crypto applications tend to use DER because it's stable. If it'a DER you should be able to safely re-encode once decoded items and get the same outcome.

    There is no built-in feature in pyasn1 that allows you matching substrate fragments to decoded objects. But you can probably simulate that by overriding Decoder.call() method and taking note of its substrate + length parameters to see what's being decoded and the return value of the overridden __call__() method which is the object produced from the substrate you observe.

    Keep in mind that decoding process is recursive so you will see both terminal (scalar) and container objects containing many others.