etingof / pyasn1

Generic ASN.1 library for Python
http://snmplabs.com/pyasn1
BSD 2-Clause "Simplified" License
244 stars 118 forks source link

Component value is tag-incompatible, when assigning value to Choice. #183

Closed daniel-leicht closed 4 years ago

daniel-leicht commented 4 years ago

Hi @etingof or any other pyasn1 users!

From a research around the net it seems that pyasn1 is by far the best package to handle any ASN1 related tasks.

I am trying to use pyasn1 to encode and decode MMS PDUs.

I managed to create all the classes from the MMS ASN definition: https://pastebin.com/JitDfL2R (named it mms_classes.py)

I started by decoding a simple MMS packet and it worked, but when I tried to create one from scratch:

from mms_classes import MMSpdu, Confirmed_RequestPDU, ConfirmedServiceRequest

csr = ConfirmedServiceRequest()
csr['identify'] = b""

crp = Confirmed_RequestPDU()
crp["invokeID"] = 2
crp["confirmedServiceRequest"] = csr

mp = MMSpdu()
mp["confirmed-RequestPDU"] = crp

I get the following exception:

Traceback (most recent call last):
  File "", line 23, in <module>
    mp["confirmed-RequestPDU"] = crp
  File "C:\Users\User\AppData\Local\Programs\Python\Python37-32\lib\site-packages\pyasn1\type\univ.py", line 2073, in __setitem__
    raise KeyError(sys.exc_info()[1])
KeyError: PyAsn1Error("Component value is tag-incompatible: <Confirmed_RequestPDU schema object at 0x3ae4a70 tagSet=<TagSet object at 0x3ace790 tags 0:32:16> subtypeSpec=<ConstraintsInte...(truncated)

I tried following the documentation but still couldn't find where I went wrong.

Daniel

etingof commented 4 years ago

I think the problem is here:

    namedtype.NamedType('confirmed-RequestPDU', Confirmed_RequestPDU().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))),

Within the MMSpdu structure, confirmed-RequestPDU field carries a subtype of Confirmed_RequestPDU, not vanilla Confirmed_RequestPDU that you are trying to assign.

One solution could be to have a free-standing Confirmed_RequestPDU subtype which you could instantiate and assign. Or you can just instantiate the field:

crp = mp["confirmed-RequestPDU"]

Just keep in mind that crp here is a reference to an object, not a copy.

daniel-leicht commented 4 years ago

Will test it again promptly, thank you!

daniel-leicht commented 4 years ago

Thank you, it works!