wbond / asn1crypto

Python ASN.1 library with a focus on performance and a pythonic API
MIT License
335 stars 140 forks source link

Recursive parsing (how to do) #198

Open defacto64 opened 3 years ago

defacto64 commented 3 years ago

Hi,

I have to parse a nested ASN.1 object that is a SEQUENCE OF items that are in turn SEQUENCE objects themselves. I am not sure how to do that using asn1crypto.

I mean: with Sequence.load(der_bytes) I can instantiate the outer sequence, but then how do I parse the inner objects?

Should I extract the der encoding of the inner objects, and the call load() again ? If so, how do I do that?

joernheissler commented 3 years ago

Hello! Does this help? Not sure if this is the best way though.

#!/usr/bin/env python3

from asn1crypto.core import Sequence, SequenceOf, Integer
import json

class ManyFoo(SequenceOf):
    _child_spec = None

class Foo(Sequence):
    _fields = [
        ("1st", Integer),
        ("2nd", Integer),
        ("rec", ManyFoo, {"optional": True}),
    ]

# That part is especially ugly.
ManyFoo._child_spec = Foo

orig = {
    "1st": 10,
    "2nd": 20,
    "rec": [
        {
            "1st": 7,
            "2nd": 123,
            "rec": [
                {
                    "1st": 100,
                    "2nd": 200,
                    "rec": []
                }
            ]
        },
        {
            "1st": 70,
            "2nd": 1230,
            "rec": [
                {
                    "1st": 400,
                    "2nd": 800,
                    "rec": [
                        {
                            "1st": 1000,
                            "2nd": 20000,
                            "rec": []
                        }
                    ]
                },
                {
                    "1st": 500,
                    "2nd": 600,
                    "rec": []
                }
            ]
        }
    ]
}

encoded = Foo(orig).dump()
print(encoded.hex())

decoded = Foo.load(encoded)
print(orig == decoded.native)
print()

print(json.dumps(decoded.native, indent=4, sort_keys=True))
defacto64 commented 3 years ago

Hello Jörn,

thank you for replying.

That helps, to some extent, but I still cannot extract some inner field because it's a tagged field (like e.g. [3] foobar UTF8String).

How do I extract a tagged field from a Sequence?

If temp is a Sequence, I get an error if I try temp[0] to extract the first field (which happens to be a tagged field):

    print temp[0]
  File "/usr/local/lib/python2.7/dist-packages/asn1crypto/core.py", line 3536, in __getitem__
    raise e
ValueError: Unknown element - context class, constructed method, tag 0
    while parsing asn1crypto.core.Sequence
wbond commented 3 years ago

@defacto64 Is the tagged field an implicit or explicit field? If you look through the various modules in the package (other than core.py you should be able to find some explicitly and implicitly tagged fields that can help in how to configure a class to represent what you need to parse.