Enumerated support including *_ws methods.

This commit is contained in:
Josef 2020-08-20 15:27:04 +02:00
parent ecddbd4d23
commit 07a8b63d1a
4 changed files with 142 additions and 6 deletions

View File

@ -1529,6 +1529,65 @@ Specific attribute:
def _to_jval(self):
return self._val
###
# conversion between internal value and ASN.1 OER/COER encoding
###
def _get_index(self):
try:
ind = self._cont[self._val]
except KeyError:
if self._ext is not None:
# Just try to convert the value into an index
try:
ind = int(self._val)
except ValueError:
try:
# The pycrate "_ext_" format
ind = int(self._val[5:])
except ValueError:
raise ASN1OEREncodeErr(
"{0}: invalid ENUMERATED value, {1}".format(
self.fullname(),
self._val))
return ind
def _get_index_value(self, index):
try:
val = self._cont_rev[index]
except (KeyError):
if self._ext is not None:
if not self._SILENT:
asnlog('ENUM._from_oer: %s, unknown extension value %r' \
% (self._name, index))
# Just try to convert the value into an index
val = '_ext_%r' % index
else:
raise (ASN1OERDecodeErr(
'{0}: invalid ENUMERATED value, {1}'.format(self.fullname(),
index)))
return val
def _from_oer_ws(self, char):
index, _gen = ASN1CodecOER.decode_enumerated_ws(char)
self._val = self._get_index_value(index)
self._struct = Envelope(self._name, GEN=tuple(_gen))
def _from_oer(self, char):
self._val = self._get_index_value(ASN1CodecOER.decode_enumerated(char))
def _to_oer_ws(self):
self._struct = Envelope(self._name, GEN=(
ASN1CodecOER.encode_enumerated_ws(self._get_index()),
))
return self._struct
def _to_oer(self):
return ASN1CodecOER.encode_enumerated(self._get_index())
class _OID(ASN1Obj):

View File

@ -1878,12 +1878,63 @@ class ASN1CodecOER(ASN1Codec):
# No lower bound -> encode with length determinant
return cls.decode_intunconst_ws(char)
@classmethod
def encode_enumerated(cls, val):
# Always canonical (implementing non-canonical doesn't make sense)
_gen = []
if 0 <= val <= 127:
# short form
_gen.append((T_UINT, val, 8))
else:
# long form
dl = int_bytelen(val)
_gen.extend([(T_UINT, 1, 1),
(T_UINT, dl, 7),
(T_INT, val, dl * 8)
])
return _gen
@classmethod
def encode_ieee754_32(cls, val):
GEN = [
(T_UINT, )
]
def encode_enumerated_ws(cls, val):
if 0 <= val <= 127:
# short form
_gen = (
Uint('Form', val=0, bl=1, dic=cls.LenFormLUT),
Uint('Val', val=val, bl=7)
)
else:
# long form
dl = int_bytelen(val)
_gen = (
Uint('Form', val=1, bl=1, dic=cls.LenFormLUT),
Uint('Len', val=dl, bl=7),
Int('Val', val=val, bl=dl*8)
)
return Envelope('L', GEN=_gen)
@classmethod
def decode_enumerated(cls, char):
long_form = char.get_uint(1)
val = char.get_uint(7)
if long_form:
val = char.get_int(val*8)
return val
@classmethod
def decode_enumerated_ws(cls, char):
t_enum = Envelope('L', GEN=(
Uint('Form', bl=1, dic=cls.LenFormLUT),
Uint('Val', bl=7)
))
t_enum._from_char(char)
long_form = t_enum[0].get_val()
enum_val = t_enum[1].get_val()
if long_form:
t_enum[1]._name = "Len"
val = Int('Val', bl=8*enum_val)
val._from_char(char)
enum_val = val.get_val()
t_enum.append(val)
return enum_val, t_enum

View File

@ -85,3 +85,8 @@ class ASN1JERDecodeErr(ASN1CodecErr):
#class ASN1GSERDecodeErr(ASN1CodecErr):
# pass
class ASN1OERDecodeErr(ASN1CodecErr):
pass
class ASN1OEREncodeErr(ASN1CodecErr):
pass

View File

@ -1076,6 +1076,8 @@ def _test_rt_base():
assert( Enu01.to_ber() == Enu01.to_ber_ws() == b'\n\x01\x02' )
assert( Enu01.to_cer() == Enu01.to_cer_ws() == b'\n\x01\x02' )
assert( Enu01.to_der() == Enu01.to_der_ws() == b'\n\x01\x02' )
assert( Enu01.to_oer() == Enu01.to_oer_ws() == b'\x02' )
assert( Enu01.to_coer() == Enu01.to_coer_ws() == b'\x02' )
# decoding
Enu01.from_aper(b'\x80')
assert( Enu01._val == 'coffee' )
@ -1102,7 +1104,16 @@ def _test_rt_base():
assert( Enu01.to_jer() == '"coffee"' )
Enu01.from_jer('"coffee"')
assert( Enu01._val == 'coffee' )
# OER/COER
Enu01.from_oer(b'\x02')
assert( Enu01._val == 'coffee' )
Enu01.from_oer_ws(b'\x02')
assert( Enu01._val == 'coffee' )
Enu01.from_coer(b'\x02')
assert( Enu01._val == 'coffee' )
Enu01.from_coer_ws(b'\x02')
assert( Enu01._val == 'coffee' )
# Enu04 ::= ENUMERATED {cheese, ..., cake, coffee, tea}
Enu04 = Mod['Enu04']
Enu04.from_asn1('tea')
@ -1112,6 +1123,8 @@ def _test_rt_base():
assert( Enu04.to_ber() == Enu04.to_ber_ws() == b'\n\x01\x03' )
assert( Enu04.to_cer() == Enu04.to_cer_ws() == b'\n\x01\x03' )
assert( Enu04.to_der() == Enu04.to_der_ws() == b'\n\x01\x03' )
assert( Enu04.to_oer() == Enu04.to_oer_ws() == b'\x03' )
assert( Enu04.to_coer() == Enu04.to_coer_ws() == b'\x03' )
# decoding
Enu04.from_aper(b'\x82')
assert( Enu04._val == 'tea' )
@ -1133,7 +1146,15 @@ def _test_rt_base():
assert( Enu04._val == 'tea' )
Enu04.from_der_ws(b'\n\x01\x03')
assert( Enu04._val == 'tea' )
Enu04.from_oer(b'\x03')
assert( Enu04._val == 'tea' )
Enu04.from_oer_ws(b'\x03')
assert( Enu04._val == 'tea' )
Enu04.from_coer(b'\x03')
assert( Enu04._val == 'tea' )
Enu04.from_coer_ws(b'\x03')
assert( Enu04._val == 'tea' )
# Oid01 ::= OBJECT IDENTIFIER
Oid01 = Mod['Oid01']
Oid01.from_asn1('{iso member-body(2) fr(250) type-org(1)}')