pyasn1 icon indicating copy to clipboard operation
pyasn1 copied to clipboard

Can't decode native encoded AttributeTypeAndValue with univ.Choice inside

Open geckyan opened this issue 6 years ago • 1 comments

I was using pyasn1 0.4.5 and rfc5280 module to:

  • decode the public key certificate,
  • encode it to native Python objects,
  • make some changes,
  • and revert it all the way back to the der binary format.

But I've encountered an error "TypeError: 'str' object cannot be interpreted as an integer" when tried to decode native Python representation of AttributeTypeAndValue with X520StateOrProvinceName value lying inside.

Minimal working example without rfc5280 module:

from pyasn1.codec.native import decoder, encoder
from pyasn1.type import univ, char
from pyasn1.type.namedtype import NamedType, NamedTypes
from pyasn1.type.opentype import OpenType
import pyasn1.debug as debug

debug.setLogger(debug.Debug('all'))

class FooChoice(univ.Choice):
    componentType = NamedTypes(NamedType('utf8String', char.UTF8String()))

fooTypeMap = { univ.ObjectIdentifier('1.2.3'): FooChoice() }

class FooType(univ.ObjectIdentifier): pass
class FooValue(univ.Any): pass

class FooTypeAndValue(univ.Sequence):
    componentType = NamedTypes(
        NamedType('type', FooType()),
        NamedType('value', FooValue(), openType=OpenType('type', fooTypeMap))
    )

fooTV = FooTypeAndValue()
fooTV['type'] = univ.ObjectIdentifier('1.2.3')
fooChoice = FooChoice()
fooChoice['utf8String'] = 'bar'
fooTV['value'] = fooChoice

natified = encoder.encode(fooTV)
print(f'Natified object: {natified}')
print(decoder.decode(natified, FooTypeAndValue()))

Standard output:

2019-06-08 19:03:57,175 pyasn1: running pyasn1 0.4.5, debug flags all2019-06-08 19:03:57,175 pyasn1: debug category 'all' enabled
2019-06-08 19:03:57,176 pyasn1: encoder called for type FooTypeAndValue <FooTypeAndValue:
 type=1.2.3 value=FooChoice:
  utf8String=bar

>
2019-06-08 19:03:57,176 pyasn1: using value codec SequenceEncoder chosen by <TagSet object at 0x3bd2dd0 tags 0:32:16>
2019-06-08 19:03:57,176 pyasn1: encoder called for type ObjectIdentifier <1.2.3>
2019-06-08 19:03:57,176 pyasn1: using value codec ObjectIdentifierEncoder chosen by <TagSet object at 0x3bd28b0 tags 0:0:6>
2019-06-08 19:03:57,177 pyasn1: encoder ObjectIdentifierEncoder produced: '1.2.3'
2019-06-08 19:03:57,177 pyasn1: encoder called for type FooChoice <FooChoice:
 utf8String=bar
>
2019-06-08 19:03:57,177 pyasn1: using value codec ChoiceEncoder chosen by <TagSet object at 0x3be3090 untagged>
2019-06-08 19:03:57,178 pyasn1: encoder called for type UTF8String <bar>
2019-06-08 19:03:57,178 pyasn1: using value codec OctetStringEncoder chosen by <TagSet object at 0x3be3270 tags 0:0:12>
2019-06-08 19:03:57,179 pyasn1: encoder OctetStringEncoder produced: b'bar'
2019-06-08 19:03:57,179 pyasn1: encoder ChoiceEncoder produced: OrderedDict([('utf8String', b'bar')])
2019-06-08 19:03:57,179 pyasn1: encoder SequenceEncoder produced: OrderedDict([('type', '1.2.3'), ('value', OrderedDict([('utf8String', b'bar')]))])
Natified object: OrderedDict([('type', '1.2.3'), ('value', OrderedDict([('utf8String', b'bar')]))])
2019-06-08 19:03:57,179 pyasn1: decoder called at scope OrderedDict, working with type OrderedDict
2019-06-08 19:03:57,180 pyasn1: calling decoder SequenceOrSetDecoder on Python type OrderedDict <OrderedDict([('type', '1.2.3'), ('value', OrderedDict([('utf8String', b'bar')]))])>
2019-06-08 19:03:57,180 pyasn1: decoder called at scope OrderedDict.str, working with type str
2019-06-08 19:03:57,180 pyasn1: calling decoder AbstractScalarDecoder on Python type str <'1.2.3'>
2019-06-08 19:03:57,181 pyasn1: decoder AbstractScalarDecoder produced ASN.1 type FooType <<FooType value object at 0x3be3990 tagSet <TagSet object at 0x3bd28b0 tags 0:0:6> payload [1.2.3]>>
2019-06-08 19:03:57,181 pyasn1: decoder called at scope OrderedDict.OrderedDict, working with type OrderedDict
2019-06-08 19:03:57,181 pyasn1: calling decoder AbstractScalarDecoder on Python type OrderedDict <OrderedDict([('utf8String', b'bar')])>
Traceback (most recent call last):
  File "mwe_basic.py", line 31, in <module>
    print(decoder.decode(natified, FooTypeAndValue()))
  File "...\lib\site-packages\pyasn1\codec\native\decoder.py", line 164, in __call__
    value = valueDecoder(pyObject, asn1Spec, self, **options)
  File "...\lib\site-packages\pyasn1\codec\native\decoder.py", line 38, in __call__
    asn1Value[field] = decodeFun(pyObject[field], componentsTypes[field].asn1Object, **options)
  File "...\lib\site-packages\pyasn1\codec\native\decoder.py", line 164, in __call__
    value = valueDecoder(pyObject, asn1Spec, self, **options)
  File "...\lib\site-packages\pyasn1\codec\native\decoder.py", line 22, in __call__
    return asn1Spec.clone(pyObject)
  File "...\lib\site-packages\pyasn1\type\base.py", line 349, in clone
    return self.__class__(value, **initializers)
  File "...\lib\site-packages\pyasn1\type\univ.py", line 819, in __init__
    base.AbstractSimpleAsn1Item.__init__(self, value, **kwargs)
  File "...\lib\site-packages\pyasn1\type\base.py", line 240, in __init__
    value = self.prettyIn(value)
  File "...\lib\site-packages\pyasn1\type\univ.py", line 878, in prettyIn
    return bytes(value)
TypeError: 'str' object cannot be interpreted as an integer

Minimal working example based upon rfc5280 module:

from pyasn1_modules.rfc5280 import AttributeTypeAndValue, AttributeType, X520StateOrProvinceName
from pyasn1.codec.native import decoder, encoder
import pyasn1.debug as debug

debug.setLogger(debug.Debug('all'))

fooTV = AttributeTypeAndValue()
fooTV['type'] = AttributeType('2.5.4.8')
fooValue = X520StateOrProvinceName()
fooValue['utf8String'] = 'bar'
fooTV['value'] = fooValue

natified = encoder.encode(fooTV)
print(f'Natified object: {natified}')
print(decoder.decode(natified, AttributeTypeAndValue()))

Standard output:

2019-06-08 23:57:01,209 pyasn1: running pyasn1 0.4.5, debug flags all
2019-06-08 23:57:01,209 pyasn1: debug category 'all' enabled
2019-06-08 23:57:01,210 pyasn1: encoder called for type AttributeTypeAndValue <AttributeTypeAndValue:
 type=2.5.4.8
 value=X520StateOrProvinceName:
  utf8String=bar

>
2019-06-08 23:57:01,210 pyasn1: using value codec SequenceEncoder chosen by <TagSet object at 0x3a11830 tags 0:32:16>
2019-06-08 23:57:01,211 pyasn1: encoder called for type AttributeType <2.5.4.8>
2019-06-08 23:57:01,211 pyasn1: using value codec ObjectIdentifierEncoder chosen by <TagSet object at 0x3a11310 tags 0:0:6>
2019-06-08 23:57:01,211 pyasn1: encoder ObjectIdentifierEncoder produced: '2.5.4.8'
2019-06-08 23:57:01,211 pyasn1: encoder called for type X520StateOrProvinceName <X520StateOrProvinceName:
 utf8String=bar
>
2019-06-08 23:57:01,212 pyasn1: using value codec ChoiceEncoder chosen by <TagSet object at 0x3a11ad0 untagged>
2019-06-08 23:57:01,212 pyasn1: encoder called for type UTF8String <bar>
2019-06-08 23:57:01,212 pyasn1: using value codec OctetStringEncoder chosen by <TagSet object at 0x3a11cb0 tags 0:0:12>
2019-06-08 23:57:01,212 pyasn1: encoder OctetStringEncoder produced: b'bar'
2019-06-08 23:57:01,213 pyasn1: encoder ChoiceEncoder produced: OrderedDict([('utf8String', b'bar')])
2019-06-08 23:57:01,213 pyasn1: encoder SequenceEncoder produced: OrderedDict([('type', '2.5.4.8'), ('value', OrderedDict([('utf8String', b'bar')]))])
Natified object: OrderedDict([('type', '2.5.4.8'), ('value', OrderedDict([('utf8String', b'bar')]))])
2019-06-08 23:57:01,213 pyasn1: decoder called at scope OrderedDict, working with type OrderedDict
2019-06-08 23:57:01,214 pyasn1: calling decoder SequenceOrSetDecoder on Python type OrderedDict <OrderedDict([('type', '2.5.4.8'), ('value', OrderedDict([('utf8String', b'bar')]))])>
2019-06-08 23:57:01,214 pyasn1: decoder called at scope OrderedDict.str, working with type str
2019-06-08 23:57:01,214 pyasn1: calling decoder AbstractScalarDecoder on Python type str <'2.5.4.8'>
2019-06-08 23:57:01,214 pyasn1: decoder AbstractScalarDecoder produced ASN.1 type AttributeType <<AttributeType value object at 0x3b269f0 tagSet <TagSet object at 0x3a11310 tags 0:0:6> payload [2.5.4.8]>>
2019-06-08 23:57:01,215 pyasn1: decoder called at scope OrderedDict.OrderedDict, working with type OrderedDict
2019-06-08 23:57:01,215 pyasn1: calling decoder AbstractScalarDecoder on Python type OrderedDict <OrderedDict([('utf8String', b'bar')])>
Traceback (most recent call last):
  File "mwe_rfc5280.py", line 15, in <module>
    print(decoder.decode(natified, AttributeTypeAndValue()))
  File "...\lib\site-packages\pyasn1\codec\native\decoder.py", line 164, in __call__
    value = valueDecoder(pyObject, asn1Spec, self, **options)
  File "...\lib\site-packages\pyasn1\codec\native\decoder.py", line 38, in __call__
    asn1Value[field] = decodeFun(pyObject[field], componentsTypes[field].asn1Object, **options)
  File "...\lib\site-packages\pyasn1\codec\native\decoder.py", line 164, in __call__
    value = valueDecoder(pyObject, asn1Spec, self, **options)
  File "...\lib\site-packages\pyasn1\codec\native\decoder.py", line 22, in __call__
    return asn1Spec.clone(pyObject)
  File "...\lib\site-packages\pyasn1\type\base.py", line 349, in clone
    return self.__class__(value, **initializers)
  File "...\lib\site-packages\pyasn1\type\univ.py", line 819, in __init__
    base.AbstractSimpleAsn1Item.__init__(self, value, **kwargs)
  File "...\lib\site-packages\pyasn1\type\base.py", line 240, in __init__
    value = self.prettyIn(value)
  File "...\lib\site-packages\pyasn1\type\univ.py", line 878, in prettyIn
    return bytes(value)
TypeError: 'str' object cannot be interpreted as an integer
(parts_generator)

geckyan avatar Jun 08 '19 12:06 geckyan

Thank you for reporting this issue!

It appears, that openType feature is not implemented for the native decoder. Let me see if we could add it there.

etingof avatar Jun 29 '19 15:06 etingof