2017-07-04 21:12:41 +00:00
|
|
|
|
# -*- coding: UTF-8 -*-
|
|
|
|
|
#/**
|
|
|
|
|
# * Software Name : pycrate
|
2019-02-25 10:26:10 +00:00
|
|
|
|
# * Version : 0.4
|
2017-07-04 21:12:41 +00:00
|
|
|
|
# *
|
2017-11-12 13:43:59 +00:00
|
|
|
|
# * Copyright 2017. Benoit Michau. ANSSI.
|
2018-12-11 17:09:54 +00:00
|
|
|
|
# * Copyright 2018. Benoit Michau. P1Sec.
|
2017-07-04 21:12:41 +00:00
|
|
|
|
# *
|
2018-04-15 19:47:21 +00:00
|
|
|
|
# * This library is free software; you can redistribute it and/or
|
|
|
|
|
# * modify it under the terms of the GNU Lesser General Public
|
|
|
|
|
# * License as published by the Free Software Foundation; either
|
|
|
|
|
# * version 2.1 of the License, or (at your option) any later version.
|
|
|
|
|
# *
|
|
|
|
|
# * This library is distributed in the hope that it will be useful,
|
2017-07-04 21:12:41 +00:00
|
|
|
|
# * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
2018-04-15 19:47:21 +00:00
|
|
|
|
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
# * Lesser General Public License for more details.
|
|
|
|
|
# *
|
|
|
|
|
# * You should have received a copy of the GNU Lesser General Public
|
|
|
|
|
# * License along with this library; if not, write to the Free Software
|
|
|
|
|
# * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
|
|
|
# * MA 02110-1301 USA
|
2017-07-04 21:12:41 +00:00
|
|
|
|
# *
|
|
|
|
|
# *--------------------------------------------------------
|
|
|
|
|
# * File Name : pycrate_asn1rt/asnobj_basic.py
|
|
|
|
|
# * Created : 2017-01-31
|
|
|
|
|
# * Authors : Benoit Michau
|
|
|
|
|
# *--------------------------------------------------------
|
|
|
|
|
#*/
|
|
|
|
|
|
2018-12-07 17:07:49 +00:00
|
|
|
|
|
2017-07-04 21:12:41 +00:00
|
|
|
|
from .utils import *
|
|
|
|
|
from .err import *
|
|
|
|
|
from .dictobj import *
|
|
|
|
|
from .glob import *
|
|
|
|
|
from .refobj import *
|
|
|
|
|
from .setobj import *
|
|
|
|
|
from .asnobj import *
|
|
|
|
|
from .codecs import *
|
|
|
|
|
|
2018-12-07 17:07:49 +00:00
|
|
|
|
from .asnobj import _with_json
|
2017-07-04 21:12:41 +00:00
|
|
|
|
|
|
|
|
|
#------------------------------------------------------------------------------#
|
|
|
|
|
# NULL and BOOLEAN
|
|
|
|
|
#------------------------------------------------------------------------------#
|
|
|
|
|
|
|
|
|
|
class NULL(ASN1Obj):
|
|
|
|
|
__doc__ = """
|
|
|
|
|
ASN.1 basic type NULL object
|
|
|
|
|
|
|
|
|
|
Single value: int 0
|
|
|
|
|
%s
|
|
|
|
|
""" % ASN1Obj_docstring
|
|
|
|
|
|
|
|
|
|
TYPE = TYPE_NULL
|
|
|
|
|
TAG = 5
|
|
|
|
|
|
|
|
|
|
def _safechk_val(self, val):
|
|
|
|
|
if val != 0:
|
|
|
|
|
raise(ASN1ObjErr('{0}: invalid value, {1!r}'.format(self.fullname(), val)))
|
|
|
|
|
|
|
|
|
|
###
|
|
|
|
|
# conversion between internal value and ASN.1 syntax
|
|
|
|
|
###
|
|
|
|
|
|
|
|
|
|
def _from_asn1(self, txt):
|
|
|
|
|
if txt[:4] == 'NULL':
|
|
|
|
|
self._val = 0
|
|
|
|
|
return txt[4:].strip()
|
|
|
|
|
else:
|
|
|
|
|
raise(ASN1ASNDecodeErr('{0}: invalid text, {1!r}'\
|
|
|
|
|
.format(self.fullname(), txt)))
|
|
|
|
|
|
|
|
|
|
def _to_asn1(self):
|
|
|
|
|
return 'NULL'
|
|
|
|
|
|
|
|
|
|
###
|
|
|
|
|
# conversion between internal value and ASN.1 PER encoding
|
|
|
|
|
###
|
|
|
|
|
|
|
|
|
|
def _from_per_ws(self, char):
|
|
|
|
|
self._struct = Envelope(self._name)
|
|
|
|
|
self._val = 0
|
|
|
|
|
|
|
|
|
|
def _from_per(self, char):
|
|
|
|
|
self._val = 0
|
|
|
|
|
|
|
|
|
|
def _to_per_ws(self):
|
|
|
|
|
self._struct = Envelope(self._name)
|
|
|
|
|
return self._struct
|
|
|
|
|
|
|
|
|
|
def _to_per(self):
|
|
|
|
|
return []
|
|
|
|
|
|
|
|
|
|
###
|
|
|
|
|
# conversion between internal value and ASN.1 BER encoding
|
|
|
|
|
###
|
|
|
|
|
|
|
|
|
|
def _decode_ber_cont_ws(self, char, vbnd):
|
|
|
|
|
if not isinstance(vbnd, tuple):
|
|
|
|
|
raise(ASN1BERDecodeErr('{0}: invalid NULL constructed structure'\
|
|
|
|
|
.format(self.fullname())))
|
|
|
|
|
if vbnd[1] != vbnd[0]:
|
|
|
|
|
raise(ASN1BERDecodeErr('{0}: invalid NULL length, {1!r}'\
|
|
|
|
|
.format(self.fullname(), lval)))
|
|
|
|
|
self._val = 0
|
|
|
|
|
return Buf('V', val=b'', bl=0)
|
|
|
|
|
|
|
|
|
|
def _decode_ber_cont(self, char, vbnd):
|
|
|
|
|
if not isinstance(vbnd, tuple):
|
|
|
|
|
raise(ASN1BERDecodeErr('{0}: invalid NULL constructed structure'\
|
|
|
|
|
.format(self.fullname())))
|
|
|
|
|
if vbnd[1] != vbnd[0]:
|
|
|
|
|
raise(ASN1BERDecodeErr('{0}: invalid NULL length, {1!r}'\
|
|
|
|
|
.format(self.fullname(), lval)))
|
|
|
|
|
self._val = 0
|
|
|
|
|
|
|
|
|
|
def _encode_ber_cont_ws(self):
|
2018-04-21 19:16:39 +00:00
|
|
|
|
return 0, 0, Buf('V', val=b'', bl=0)
|
2017-07-04 21:12:41 +00:00
|
|
|
|
|
|
|
|
|
def _encode_ber_cont(self):
|
|
|
|
|
return 0, 0, []
|
2018-12-07 17:07:49 +00:00
|
|
|
|
|
|
|
|
|
###
|
|
|
|
|
# conversion between internal value and ASN.1 JER encoding
|
|
|
|
|
###
|
|
|
|
|
if _with_json:
|
|
|
|
|
|
|
|
|
|
def _from_jval(self, val):
|
|
|
|
|
if val is None:
|
|
|
|
|
self._val = 0
|
|
|
|
|
else:
|
|
|
|
|
raise(ASN1JERDecodeErr('{0}: invalid json value, {1!r}'\
|
|
|
|
|
.format(self.fullname(), val)))
|
|
|
|
|
|
|
|
|
|
def _to_jval(self):
|
|
|
|
|
return None
|
2017-07-04 21:12:41 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class BOOL(ASN1Obj):
|
|
|
|
|
__doc__ = """
|
|
|
|
|
ASN.1 basic type BOOLEAN object
|
|
|
|
|
|
|
|
|
|
Single value: Python bool
|
|
|
|
|
%s
|
|
|
|
|
""" % ASN1Obj_docstring
|
|
|
|
|
|
|
|
|
|
TYPE = TYPE_BOOL
|
|
|
|
|
TAG = 1
|
|
|
|
|
|
2018-06-02 13:25:28 +00:00
|
|
|
|
_ASN_RE = re.compile('TRUE|FALSE')
|
|
|
|
|
_ASN_LUT = {'FALSE': False, 'TRUE': True, False: 'FALSE', True: 'TRUE'}
|
|
|
|
|
_PER_LUT = {0: False, 1: True}
|
|
|
|
|
_PER_LUTR = {False: 0, True: 1}
|
2017-07-04 21:12:41 +00:00
|
|
|
|
|
|
|
|
|
def _safechk_val(self, val):
|
|
|
|
|
if not isinstance(val, bool):
|
|
|
|
|
raise(ASN1ObjErr('{0}: invalid value, {1!r}'.format(self.fullname(), val)))
|
|
|
|
|
|
|
|
|
|
###
|
|
|
|
|
# conversion between internal value and ASN.1 syntax
|
|
|
|
|
###
|
|
|
|
|
|
|
|
|
|
def _from_asn1(self, txt):
|
|
|
|
|
m = self._ASN_RE.match(txt)
|
|
|
|
|
if m:
|
|
|
|
|
self._val = self._ASN_LUT[m.group()]
|
|
|
|
|
return txt[m.end():].strip()
|
|
|
|
|
else:
|
|
|
|
|
raise(ASN1ASNDecodeErr('{0}: invalid text, {1!r}'\
|
|
|
|
|
.format(self.fullname(), txt)))
|
|
|
|
|
|
|
|
|
|
def _to_asn1(self):
|
|
|
|
|
return self._ASN_LUT[self._val]
|
|
|
|
|
|
|
|
|
|
###
|
|
|
|
|
# conversion between internal value and ASN.1 PER encoding
|
|
|
|
|
###
|
|
|
|
|
|
|
|
|
|
def _from_per_ws(self, char):
|
|
|
|
|
self._struct = Envelope(self._name, GEN=(
|
|
|
|
|
Uint('V', bl=1, dic={0:'FALSE', 1:'TRUE'}), ))
|
|
|
|
|
self._struct._from_char(char)
|
|
|
|
|
self._val = self._PER_LUT[self._struct[0]._val]
|
|
|
|
|
if ASN1CodecPER.ALIGNED:
|
|
|
|
|
ASN1CodecPER._off[-1] += 1
|
|
|
|
|
|
|
|
|
|
def _from_per(self, char):
|
|
|
|
|
self._val = self._PER_LUT[char.get_uint(1)]
|
|
|
|
|
if ASN1CodecPER.ALIGNED:
|
|
|
|
|
ASN1CodecPER._off[-1] += 1
|
|
|
|
|
|
|
|
|
|
def _to_per_ws(self):
|
|
|
|
|
self._struct = Envelope(self._name, GEN=(
|
2018-06-02 13:25:28 +00:00
|
|
|
|
Uint('V', bl=1, val=self._PER_LUTR[self._val], dic={0:'FALSE', 1:'TRUE'}), ))
|
2017-07-04 21:12:41 +00:00
|
|
|
|
if ASN1CodecPER.ALIGNED:
|
|
|
|
|
ASN1CodecPER._off[-1] += 1
|
|
|
|
|
return self._struct
|
|
|
|
|
|
|
|
|
|
def _to_per(self):
|
|
|
|
|
if ASN1CodecPER.ALIGNED:
|
|
|
|
|
ASN1CodecPER._off[-1] += 1
|
2018-06-02 13:25:28 +00:00
|
|
|
|
return [(T_UINT, self._PER_LUTR[self._val], 1)]
|
2017-07-04 21:12:41 +00:00
|
|
|
|
|
|
|
|
|
###
|
|
|
|
|
# conversion between internal value and ASN.1 BER encoding
|
|
|
|
|
###
|
|
|
|
|
|
|
|
|
|
def _decode_ber_cont_ws(self, char, vbnd):
|
|
|
|
|
if not isinstance(vbnd, tuple):
|
|
|
|
|
raise(ASN1BERDecodeErr('{0}: invalid BOOLEAN constructed structure'\
|
|
|
|
|
.format(self.fullname())))
|
|
|
|
|
if vbnd[1] - vbnd[0] != 8:
|
|
|
|
|
raise(ASN1BERDecodeErr('{0}: invalid BOOLEAN length, {1!r}'\
|
|
|
|
|
.format(self.fullname(), lval)))
|
|
|
|
|
char._cur, char._len_bit = vbnd[0], vbnd[1]
|
|
|
|
|
V = Uint('V', bl=8)
|
|
|
|
|
V._from_char(char)
|
|
|
|
|
if V() == 0:
|
|
|
|
|
self._val = False
|
|
|
|
|
else:
|
|
|
|
|
self._val = True
|
|
|
|
|
return V
|
|
|
|
|
|
|
|
|
|
def _decode_ber_cont(self, char, vbnd):
|
|
|
|
|
if not isinstance(vbnd, tuple):
|
|
|
|
|
raise(ASN1BERDecodeErr('{0}: invalid BOOLEAN constructed structure'\
|
|
|
|
|
.format(self.fullname())))
|
|
|
|
|
if vbnd[1] - vbnd[0] != 8:
|
|
|
|
|
raise(ASN1BERDecodeErr('{0}: invalid BOOLEAN length, {1!r}'\
|
|
|
|
|
.format(self.fullname(), lval)))
|
|
|
|
|
char._cur, char._len_bit = vbnd[0], vbnd[1]
|
|
|
|
|
val = char.get_uint(8)
|
|
|
|
|
if val:
|
|
|
|
|
self._val = True
|
|
|
|
|
else:
|
|
|
|
|
self._val = False
|
|
|
|
|
|
|
|
|
|
def _encode_ber_cont_ws(self):
|
|
|
|
|
if self._val:
|
|
|
|
|
return 0, 1, Uint('V', val=ASN1CodecBER.ENC_BOOLTRUE, bl=8)
|
|
|
|
|
else:
|
|
|
|
|
return 0, 1, Uint('V', val=0, bl=8)
|
|
|
|
|
|
|
|
|
|
def _encode_ber_cont(self):
|
|
|
|
|
if self._val:
|
|
|
|
|
return 0, 1, [(T_UINT, ASN1CodecBER.ENC_BOOLTRUE, 8)]
|
|
|
|
|
else:
|
|
|
|
|
return 0, 1, [(T_UINT, 0, 8)]
|
2018-12-07 17:07:49 +00:00
|
|
|
|
|
|
|
|
|
###
|
|
|
|
|
# conversion between internal value and ASN.1 JER encoding
|
|
|
|
|
###
|
|
|
|
|
|
|
|
|
|
if _with_json:
|
|
|
|
|
|
|
|
|
|
def _from_jval(self, val):
|
|
|
|
|
if isinstance(val, bool):
|
|
|
|
|
self._val = val
|
|
|
|
|
else:
|
|
|
|
|
raise(ASN1JERDecodeErr('{0}: invalid json value, {1!r}'\
|
|
|
|
|
.format(self.fullname(), val)))
|
|
|
|
|
|
|
|
|
|
def _to_jval(self):
|
|
|
|
|
return self._val
|
|
|
|
|
|
2017-07-04 21:12:41 +00:00
|
|
|
|
|
|
|
|
|
#------------------------------------------------------------------------------#
|
|
|
|
|
# INTEGER and REAL
|
|
|
|
|
#------------------------------------------------------------------------------#
|
|
|
|
|
|
|
|
|
|
class INT(ASN1Obj):
|
|
|
|
|
__doc__ = """
|
|
|
|
|
ASN.1 basic type INTEGER object
|
|
|
|
|
|
|
|
|
|
Single value: Python int
|
|
|
|
|
|
2018-12-07 17:07:49 +00:00
|
|
|
|
Alternative setting value: Python str (from the object's NamedNumber)
|
2017-11-26 11:09:36 +00:00
|
|
|
|
This is only to be used in set_val() method, and is converted to a Python
|
|
|
|
|
int when set
|
|
|
|
|
|
2017-07-04 21:12:41 +00:00
|
|
|
|
Specific attribute:
|
|
|
|
|
|
|
|
|
|
- cont: None or ASN1Dict {ident (str): single value},
|
|
|
|
|
provides the content of the INTEGER object
|
|
|
|
|
%s
|
|
|
|
|
""" % ASN1Obj_docstring
|
|
|
|
|
|
|
|
|
|
TYPE = TYPE_INT
|
|
|
|
|
TAG = 2
|
|
|
|
|
|
|
|
|
|
_ASN_RE = re.compile('\-{0,1}[0-9]{1,}')
|
|
|
|
|
|
|
|
|
|
def _safechk_val(self, val):
|
|
|
|
|
self._safechk_val_int(val)
|
|
|
|
|
|
2017-11-26 11:09:36 +00:00
|
|
|
|
def set_val(self, val):
|
|
|
|
|
if isinstance(val, str_types):
|
|
|
|
|
try:
|
|
|
|
|
self._val = self._cont[val]
|
2019-09-26 08:20:18 +00:00
|
|
|
|
except Exception:
|
2017-11-26 11:09:36 +00:00
|
|
|
|
raise(ASN1ObjErr('{0}: invalid named value, {1!r}'.format(self.fullname(), val)))
|
|
|
|
|
else:
|
|
|
|
|
self._val = val
|
|
|
|
|
if self._SAFE_VAL:
|
|
|
|
|
self._safechk_val(self._val)
|
|
|
|
|
if self._SAFE_BND:
|
|
|
|
|
self._safechk_bnd(self._val)
|
|
|
|
|
|
|
|
|
|
def get_name(self):
|
|
|
|
|
"""Returns the NamedNumber corresponding to the internal value
|
|
|
|
|
"""
|
|
|
|
|
try:
|
|
|
|
|
return self._cont_rev[self._val]
|
2019-09-26 08:20:18 +00:00
|
|
|
|
except Exception:
|
2017-11-26 11:09:36 +00:00
|
|
|
|
return None
|
|
|
|
|
|
2017-07-04 21:12:41 +00:00
|
|
|
|
###
|
|
|
|
|
# conversion between internal value and ASN.1 syntax
|
|
|
|
|
###
|
|
|
|
|
|
|
|
|
|
def _from_asn1(self, txt):
|
|
|
|
|
m = self._ASN_RE.match(txt)
|
|
|
|
|
if m:
|
|
|
|
|
self._val = int(m.group())
|
|
|
|
|
return txt[m.end():].strip()
|
|
|
|
|
elif self._cont:
|
|
|
|
|
if not hasattr(self, '_ASN_RE_CONT'):
|
|
|
|
|
items = list(self._cont.keys())
|
|
|
|
|
items.sort(key=len, reverse=True)
|
|
|
|
|
self._ASN_RE_CONT = re.compile('|'.join(items))
|
|
|
|
|
m = self._ASN_RE_CONT.match(txt)
|
|
|
|
|
if m:
|
|
|
|
|
self._val = self._cont[m.group()]
|
|
|
|
|
return txt[m.end():].strip()
|
|
|
|
|
raise(ASN1ASNDecodeErr('{0}: invalid text, {1!r}'.format(self.fullname(), txt)))
|
|
|
|
|
|
|
|
|
|
def _to_asn1(self):
|
2017-08-27 21:21:04 +00:00
|
|
|
|
if self._cont and self._val in self._cont_rev:
|
|
|
|
|
return '%i -- %s --' % (self._val, self._cont_rev[self._val])
|
|
|
|
|
else:
|
2017-09-01 20:04:28 +00:00
|
|
|
|
return '%i' % self._val
|
2017-07-04 21:12:41 +00:00
|
|
|
|
|
|
|
|
|
###
|
|
|
|
|
# conversion between internal value and ASN.1 PER encoding
|
|
|
|
|
###
|
|
|
|
|
|
|
|
|
|
def _from_per_ws(self, char):
|
|
|
|
|
GEN = []
|
|
|
|
|
if self._const_val:
|
|
|
|
|
if self._const_val.ext is not None:
|
|
|
|
|
E = Uint('E', bl=1)
|
|
|
|
|
E._from_char(char)
|
|
|
|
|
GEN.append(E)
|
|
|
|
|
if ASN1CodecPER.ALIGNED:
|
|
|
|
|
ASN1CodecPER._off[-1] += 1
|
|
|
|
|
if E():
|
|
|
|
|
# 1) value in the extension part
|
|
|
|
|
# decoded as unconstraint integer
|
|
|
|
|
self._val, _gen = ASN1CodecPER.decode_intunconst_ws(char)
|
|
|
|
|
self._struct = Envelope(self._name, GEN=tuple(GEN + _gen))
|
|
|
|
|
return
|
|
|
|
|
# value in the root part
|
|
|
|
|
if self._const_val.rdyn:
|
|
|
|
|
# 2) defined range of possible values
|
|
|
|
|
self._val, _gen = ASN1CodecPER.decode_intconst_ws(char, self._const_val)
|
|
|
|
|
self._struct = Envelope(self._name, GEN=tuple(GEN + _gen))
|
|
|
|
|
return
|
|
|
|
|
elif self._const_val.rdyn == 0:
|
|
|
|
|
# 3) only a single value possible
|
|
|
|
|
self._val = self._const_val.lb
|
|
|
|
|
self._struct = Envelope(self._name, GEN=tuple(GEN))
|
|
|
|
|
return
|
|
|
|
|
elif self._const_val.lb is not None and self._const_val.ub is None:
|
|
|
|
|
# 4) semi-constraint value
|
|
|
|
|
self._val, _gen = ASN1CodecPER.decode_intunconst_ws(char, self._const_val.lb)
|
|
|
|
|
self._struct = Envelope(self._name, GEN=tuple(GEN + _gen))
|
|
|
|
|
return
|
|
|
|
|
# 5) no constraint
|
|
|
|
|
self._val, _gen = ASN1CodecPER.decode_intunconst_ws(char)
|
|
|
|
|
self._struct = Envelope(self._name, GEN=tuple(GEN + _gen))
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
def _from_per(self, char):
|
|
|
|
|
if self._const_val:
|
|
|
|
|
if self._const_val.ext is not None:
|
|
|
|
|
E = char.get_uint(1)
|
|
|
|
|
if ASN1CodecPER.ALIGNED:
|
|
|
|
|
ASN1CodecPER._off[-1] += 1
|
|
|
|
|
if E:
|
|
|
|
|
# 1) value in the extension part
|
|
|
|
|
# decoded as unconstraint integer
|
|
|
|
|
self._val = ASN1CodecPER.decode_intunconst(char)
|
|
|
|
|
return
|
|
|
|
|
# value in the root part
|
|
|
|
|
if self._const_val.rdyn:
|
|
|
|
|
# 2) defined range of possible values
|
|
|
|
|
self._val = ASN1CodecPER.decode_intconst(char, self._const_val)
|
|
|
|
|
return
|
|
|
|
|
elif self._const_val.rdyn == 0:
|
|
|
|
|
# 3) only a single value possible
|
|
|
|
|
self._val = self._const_val.lb
|
|
|
|
|
return
|
|
|
|
|
elif self._const_val.lb is not None and self._const_val.ub is None:
|
|
|
|
|
# 4) semi-constraint value
|
|
|
|
|
self._val = ASN1CodecPER.decode_intunconst(char, self._const_val.lb)
|
|
|
|
|
return
|
|
|
|
|
# 5) no constraint
|
|
|
|
|
self._val = ASN1CodecPER.decode_intunconst(char)
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
def _to_per_ws(self):
|
|
|
|
|
GEN = []
|
|
|
|
|
if self._const_val:
|
|
|
|
|
if self._const_val.ext is not None:
|
|
|
|
|
if not self._const_val.in_root(self._val):
|
|
|
|
|
GEN.append( Uint('E', val=1, bl=1) )
|
|
|
|
|
if ASN1CodecPER.ALIGNED:
|
|
|
|
|
ASN1CodecPER._off[-1] += 1
|
|
|
|
|
GEN.extend( ASN1CodecPER.encode_intunconst_ws(self._val) )
|
|
|
|
|
self._struct = Envelope(self._name, GEN=tuple(GEN))
|
|
|
|
|
return self._struct
|
|
|
|
|
else:
|
|
|
|
|
GEN.append( Uint('E', val=0, bl=1) )
|
|
|
|
|
if ASN1CodecPER.ALIGNED:
|
|
|
|
|
ASN1CodecPER._off[-1] += 1
|
|
|
|
|
# value in the root part
|
|
|
|
|
if self._const_val.rdyn:
|
|
|
|
|
# 2) defined range of possible values
|
|
|
|
|
GEN.extend( ASN1CodecPER.encode_intconst_ws(self._val, self._const_val) )
|
|
|
|
|
self._struct = Envelope(self._name, GEN=tuple(GEN))
|
|
|
|
|
return self._struct
|
|
|
|
|
elif self._const_val.rdyn == 0:
|
|
|
|
|
# 3) only a single value possible
|
|
|
|
|
self._struct = Envelope(self._name, GEN=tuple(GEN))
|
|
|
|
|
return self._struct
|
|
|
|
|
elif self._const_val.lb is not None and self._const_val.ub is None:
|
|
|
|
|
# 4) semi-constraint value
|
|
|
|
|
GEN.extend( ASN1CodecPER.encode_intunconst_ws(self._val, self._const_val.lb) )
|
|
|
|
|
self._struct = Envelope(self._name, GEN=tuple(GEN))
|
|
|
|
|
return self._struct
|
|
|
|
|
# 5) no constraint
|
|
|
|
|
GEN.extend( ASN1CodecPER.encode_intunconst_ws(self._val) )
|
|
|
|
|
self._struct = Envelope(self._name, GEN=tuple(GEN))
|
|
|
|
|
return self._struct
|
|
|
|
|
|
|
|
|
|
def _to_per(self):
|
|
|
|
|
GEN = []
|
|
|
|
|
if self._const_val:
|
|
|
|
|
if self._const_val.ext is not None:
|
|
|
|
|
if not self._const_val.in_root(self._val):
|
|
|
|
|
GEN.append( (T_UINT, 1, 1) )
|
|
|
|
|
if ASN1CodecPER.ALIGNED:
|
|
|
|
|
ASN1CodecPER._off[-1] += 1
|
|
|
|
|
GEN.extend( ASN1CodecPER.encode_intunconst(self._val) )
|
|
|
|
|
return GEN
|
|
|
|
|
else:
|
|
|
|
|
GEN.append( (T_UINT, 0, 1) )
|
|
|
|
|
if ASN1CodecPER.ALIGNED:
|
|
|
|
|
ASN1CodecPER._off[-1] += 1
|
|
|
|
|
# value in the root part
|
|
|
|
|
if self._const_val.rdyn:
|
|
|
|
|
GEN.extend( ASN1CodecPER.encode_intconst(self._val, self._const_val) )
|
|
|
|
|
return GEN
|
|
|
|
|
elif self._const_val.rdyn == 0:
|
|
|
|
|
# 3) only a single value possible
|
|
|
|
|
return GEN
|
|
|
|
|
elif self._const_val.lb is not None and self._const_val.ub is None:
|
|
|
|
|
# 4) semi-constraint value
|
|
|
|
|
GEN.extend( ASN1CodecPER.encode_intunconst(self._val, self._const_val.lb) )
|
|
|
|
|
return GEN
|
|
|
|
|
# 5) no constraint
|
|
|
|
|
GEN.extend( ASN1CodecPER.encode_intunconst(self._val) )
|
|
|
|
|
return GEN
|
|
|
|
|
|
|
|
|
|
###
|
|
|
|
|
# conversion between internal value and ASN.1 BER encoding
|
|
|
|
|
###
|
|
|
|
|
|
|
|
|
|
def _decode_ber_cont_ws(self, char, vbnd):
|
|
|
|
|
if not isinstance(vbnd, tuple):
|
|
|
|
|
raise(ASN1BERDecodeErr('{0}: invalid INTEGER constructed structure'\
|
|
|
|
|
.format(self.fullname())))
|
|
|
|
|
if vbnd[1] - vbnd[0] <= 0:
|
|
|
|
|
raise(ASN1BERDecodeErr('{0}: invalid INTEGER length, {1!r}'\
|
|
|
|
|
.format(self.fullname(), lval)))
|
|
|
|
|
char._cur, char._len_bit = vbnd[0], vbnd[1]
|
|
|
|
|
V = Int('V', bl=vbnd[1]-vbnd[0])
|
|
|
|
|
V._from_char(char)
|
|
|
|
|
self._val = V()
|
|
|
|
|
return V
|
|
|
|
|
|
|
|
|
|
def _decode_ber_cont(self, char, vbnd):
|
|
|
|
|
if not isinstance(vbnd, tuple):
|
|
|
|
|
raise(ASN1BERDecodeErr('{0}: invalid INTEGER constructed structure'\
|
|
|
|
|
.format(self.fullname())))
|
|
|
|
|
if vbnd[1] - vbnd[0] <= 0:
|
|
|
|
|
raise(ASN1BERDecodeErr('{0}: invalid INTEGER length, {1!r}'\
|
|
|
|
|
.format(self.fullname(), lval)))
|
|
|
|
|
char._cur, char._len_bit = vbnd[0], vbnd[1]
|
|
|
|
|
self._val = char.get_int(vbnd[1]-vbnd[0])
|
|
|
|
|
|
|
|
|
|
def _encode_ber_cont_ws(self):
|
|
|
|
|
lval = int_bytelen(self._val)
|
|
|
|
|
return 0, lval, Int('V', val=self._val, bl=8*lval)
|
|
|
|
|
|
|
|
|
|
def _encode_ber_cont(self):
|
|
|
|
|
lval = int_bytelen(self._val)
|
|
|
|
|
return 0, lval, [(T_INT, self._val, 8*lval)]
|
|
|
|
|
|
2018-12-07 17:07:49 +00:00
|
|
|
|
###
|
|
|
|
|
# conversion between internal value and ASN.1 JER encoding
|
|
|
|
|
###
|
|
|
|
|
|
|
|
|
|
if _with_json:
|
|
|
|
|
|
|
|
|
|
def _from_jval(self, val):
|
|
|
|
|
if isinstance(val, integer_types):
|
|
|
|
|
self._val = val
|
|
|
|
|
else:
|
|
|
|
|
raise(ASN1JERDecodeErr('{0}: invalid json value, {1!r}'\
|
|
|
|
|
.format(self.fullname(), val)))
|
|
|
|
|
|
|
|
|
|
def _to_jval(self):
|
|
|
|
|
return self._val
|
|
|
|
|
|
2017-07-04 21:12:41 +00:00
|
|
|
|
|
|
|
|
|
class REAL(ASN1Obj):
|
|
|
|
|
__doc__ = """
|
|
|
|
|
ASN.1 basic type REAL object
|
|
|
|
|
|
|
|
|
|
Single value: Python tuple of 3 int
|
|
|
|
|
1st int is the mantissa, 2nd is the base, 3rd is the exponent
|
|
|
|
|
Special values are:
|
|
|
|
|
(-1, None, None): MINUS-INFINITY
|
|
|
|
|
(1, None, None): PLUS-INFINITY
|
|
|
|
|
(0, None, None): NOT-A-NUMBER
|
|
|
|
|
|
|
|
|
|
Specific attribute:
|
|
|
|
|
|
|
|
|
|
- cont: ASN1Dict {"mantissa": int, "base": 2|10, "exponent": int},
|
|
|
|
|
provides the content of the REAL object
|
|
|
|
|
|
|
|
|
|
%s
|
|
|
|
|
""" % ASN1Obj_docstring
|
|
|
|
|
|
|
|
|
|
# SEQUENCE-like definition of REAL:
|
|
|
|
|
#
|
|
|
|
|
# REAL ::= SEQUENCE {
|
|
|
|
|
# mantissa INTEGER,
|
|
|
|
|
# base INTEGER (2|10),
|
|
|
|
|
# exponent INTEGER }
|
|
|
|
|
|
|
|
|
|
TYPE = TYPE_REAL
|
|
|
|
|
TAG = 9
|
|
|
|
|
|
|
|
|
|
_ASN_RE = re.compile(
|
|
|
|
|
'((\-{0,1}[0-9]{1,}){1}(?:\.([0-9]{0,})){0,1}(?:[eE](\-{0,1}[0-9]{1,})){0,1})|'\
|
|
|
|
|
'(\{\s{0,}mantissa\s{1,}(\-{0,1}[0-9]{1,})\s{0,},\s{0,}base\s{1,}(2|10)\s{0,},\s{0,}exponent\s{1,}(\-{0,1}[0-9]{1,})\s{0,}\})|'\
|
|
|
|
|
'((?:PLUS\-INFINITY)|(?:MINUS\-INFINITY)|(?:NOT-A-NUMBER))')
|
|
|
|
|
_NR1_RE = re.compile('[ 0]{0,}[-+]{0,1}[0-9]{1,}')
|
|
|
|
|
_NR2_RE = re.compile('[ 0]{0,}([-+]{0,1}[0-9]{0,})[\.,]{1}([0-9]{0,})')
|
|
|
|
|
_NR3_RE = re.compile('[ 0]{0,}([-+]{0,1}[0-9]{0,})[\.,]{1}([0-9]{0,})[eE]([-+]{0,1}[0-9]{1,})')
|
|
|
|
|
|
|
|
|
|
_ASN_LUT = {'MINUS-INFINITY': (-1, None, None),
|
|
|
|
|
'PLUS-INFINITY' : ( 1, None, None),
|
|
|
|
|
'NOT-A-NUMBER' : ( 0, None, None),
|
|
|
|
|
(-1, None, None): 'MINUS-INFINITY',
|
|
|
|
|
( 1, None, None): 'PLUS-INFINITY',
|
|
|
|
|
( 0, None, None): 'NOT-A-NUMBER'}
|
|
|
|
|
|
2018-12-11 17:09:54 +00:00
|
|
|
|
_JER_RE = re.compile('[ 0]{0,}([-+]{0,1}[0-9]{0,})(?:[\.,]{1}([0-9]{0,})){0,1}[eE]([-+]{0,1}[0-9]{1,})')
|
|
|
|
|
|
2017-07-04 21:12:41 +00:00
|
|
|
|
def _safechk_val(self, val):
|
|
|
|
|
self._safechk_val_real(val)
|
|
|
|
|
|
|
|
|
|
###
|
|
|
|
|
# conversion between internal value and ASN.1 syntax
|
|
|
|
|
###
|
|
|
|
|
|
|
|
|
|
def _from_asn1(self, txt):
|
|
|
|
|
m = self._ASN_RE.match(txt)
|
|
|
|
|
if m:
|
|
|
|
|
grp = m.groups()
|
|
|
|
|
if grp[0] is not None:
|
|
|
|
|
self._from_asn1_sci(*grp[1:4])
|
|
|
|
|
elif grp[4] is not None:
|
|
|
|
|
self._val = (int(grp[5]), int(grp[6]), int(grp[7]))
|
|
|
|
|
else:
|
|
|
|
|
self._val = self._ASN_LUT[grp[8]]
|
|
|
|
|
return txt[m.end():].strip()
|
|
|
|
|
else:
|
|
|
|
|
raise(ASN1ASNDecodeErr('{0}: invalid text, {1!r}'\
|
|
|
|
|
.format(self.fullname(), txt)))
|
|
|
|
|
|
|
|
|
|
def _from_asn1_sci(self, i, d, e):
|
|
|
|
|
# integral, decimal, base 10 exponent parts
|
|
|
|
|
if not d:
|
|
|
|
|
if not e:
|
|
|
|
|
self._val = (int(i), 10, 0)
|
|
|
|
|
else:
|
|
|
|
|
self._val = (int(i), 10, int(e))
|
|
|
|
|
else:
|
|
|
|
|
# decimal part present
|
|
|
|
|
# need to adjust the base 10 exponent
|
|
|
|
|
if not e:
|
|
|
|
|
e = 0
|
|
|
|
|
else:
|
|
|
|
|
e = int(e)
|
|
|
|
|
e -= len(d)
|
|
|
|
|
self._val = (int(i+d), 10, e)
|
|
|
|
|
|
|
|
|
|
def _to_asn1(self):
|
|
|
|
|
if self._val in self._ASN_LUT:
|
|
|
|
|
return self._ASN_LUT[self._val]
|
|
|
|
|
else:
|
|
|
|
|
return '{mantissa %d, base %d, exponent %d}' % self._val
|
|
|
|
|
|
|
|
|
|
###
|
|
|
|
|
# conversion between internal value and ASN.1 PER encoding
|
|
|
|
|
# content is actually encoded like the BER one, prefixed with a bytes count
|
|
|
|
|
###
|
|
|
|
|
|
|
|
|
|
def _from_per_ws(self, char):
|
|
|
|
|
buf, GEN = ASN1CodecPER.decode_unconst_open_ws(char, wrapped=None)
|
|
|
|
|
self._decode_cont(buf)
|
|
|
|
|
self._struct = Envelope(self._name, GEN=tuple(GEN))
|
|
|
|
|
|
|
|
|
|
def _from_per(self, char):
|
|
|
|
|
self._decode_cont( ASN1CodecPER.decode_unconst_open(char, wrapped=None) )
|
|
|
|
|
|
|
|
|
|
def _to_per_ws(self):
|
|
|
|
|
GEN = ASN1CodecPER.encode_unconst_buf_ws( self._encode_cont() )
|
|
|
|
|
self._struct = Envelope(self._name, GEN=tuple(GEN))
|
|
|
|
|
return self._struct
|
|
|
|
|
|
|
|
|
|
def _to_per(self):
|
|
|
|
|
return ASN1CodecPER.encode_unconst_buf( self._encode_cont() )
|
|
|
|
|
|
|
|
|
|
###
|
|
|
|
|
# conversion between internal value and ASN.1 BER encoding
|
|
|
|
|
###
|
|
|
|
|
|
|
|
|
|
def _decode_cont(self, bytes):
|
|
|
|
|
if not bytes:
|
|
|
|
|
# 0 value, whatever base 2 or 10 and exponent
|
|
|
|
|
self._val = ASN1CodecBER.DEC_REALNULL
|
|
|
|
|
else:
|
|
|
|
|
B0 = ord(bytes[0:1])
|
|
|
|
|
b2 = B0 >> 6
|
|
|
|
|
if b2 == 0:
|
|
|
|
|
# base 10: character string encoding
|
|
|
|
|
if B0 == 1:
|
|
|
|
|
# NR1 encoding, simple whole numbers
|
2017-09-01 19:47:54 +00:00
|
|
|
|
if python_version < 3:
|
|
|
|
|
m = self._NR1_RE.match( bytes[1:] )
|
|
|
|
|
else:
|
|
|
|
|
m = self._NR1_RE.match( str(bytes[1:], 'ascii') )
|
|
|
|
|
if not m:
|
2017-07-04 21:12:41 +00:00
|
|
|
|
raise(ASN1BERDecodeErr('{0}: invalid REAL base 10 NR1 encoding, {1!r}'\
|
|
|
|
|
.format(self.fullname(), bytes[1:])))
|
|
|
|
|
mant = int(bytes[1:])
|
|
|
|
|
self._val = (mant, 10, 0)
|
|
|
|
|
elif B0 == 2:
|
2017-09-01 19:47:54 +00:00
|
|
|
|
# NR2 encoding, requires a decimal mark
|
|
|
|
|
if python_version < 3:
|
|
|
|
|
m = self._NR2_RE.match( bytes[1:] )
|
|
|
|
|
else:
|
|
|
|
|
m = self._NR2_RE.match( str(bytes[1:], 'ascii') )
|
2017-07-04 21:12:41 +00:00
|
|
|
|
if not m:
|
|
|
|
|
raise(ASN1BERDecodeErr('{0}: invalid REAL base 10 NR2 encoding, {1!r}'\
|
|
|
|
|
.format(self.fullname(), bytes[1:])))
|
|
|
|
|
i, d = m.groups()
|
|
|
|
|
# remove trailing zero of the decimal part and keep track of
|
|
|
|
|
# the exponent
|
|
|
|
|
d = d.rstrip('0')
|
|
|
|
|
e = -len(d)
|
|
|
|
|
self._val = (int(i+d), 10, e)
|
|
|
|
|
elif B0 == 3:
|
|
|
|
|
# NR3 encoding, requires the exponent notation
|
2017-09-01 19:47:54 +00:00
|
|
|
|
if python_version < 3:
|
|
|
|
|
m = self._NR3_RE.match( bytes[1:] )
|
|
|
|
|
else:
|
|
|
|
|
m = self._NR3_RE.match( str(bytes[1:], 'ascii') )
|
2017-07-04 21:12:41 +00:00
|
|
|
|
if not m:
|
|
|
|
|
raise(ASN1BERDecodeErr('{0}: invalid REAL base 10 NR3 encoding, {1!r}'\
|
|
|
|
|
.format(self.fullname(), bytes[1:])))
|
|
|
|
|
i, d, e = m.groups()
|
|
|
|
|
# remove trailing zero of the decimal part and adjust
|
|
|
|
|
# the exponent
|
|
|
|
|
d = d.rstrip('0')
|
|
|
|
|
if not e:
|
|
|
|
|
e = -len(d)
|
|
|
|
|
else:
|
|
|
|
|
e = int(e) - len(d)
|
|
|
|
|
self._val = (int(i+d), 10, e)
|
|
|
|
|
else:
|
|
|
|
|
raise(ASN1BERDecodeErr('{0}: invalid REAL base 10 encoding, {1}'\
|
|
|
|
|
.format(self.fullname(), B0&0x3F)))
|
|
|
|
|
elif b2 == 1:
|
|
|
|
|
# special values
|
|
|
|
|
if B0 == 64:
|
|
|
|
|
# PLUS-INFINITY
|
|
|
|
|
self._val = (1, None, None)
|
|
|
|
|
elif B0 == 65:
|
|
|
|
|
# MINUS-INFINITY
|
|
|
|
|
self._val = (-1, None, None)
|
|
|
|
|
elif B0 == 66:
|
|
|
|
|
# NOT-A-NUMBER
|
|
|
|
|
self._val = (0, None, None)
|
2018-11-05 08:38:22 +00:00
|
|
|
|
elif B0 == 67:
|
2017-07-04 21:12:41 +00:00
|
|
|
|
# minus zero
|
|
|
|
|
self._val = ASN1CodecBER.DEC_REALNULL
|
|
|
|
|
else:
|
|
|
|
|
raise(ASN1BERDecodeErr('{0}: invalid REAL special value, {1!r}'\
|
|
|
|
|
.format(self.fullname(), B0&0x3F)))
|
|
|
|
|
else:
|
|
|
|
|
# base 2 encoding
|
|
|
|
|
B0 &= 0x3F
|
|
|
|
|
S, B, F, LE = b2&1, B0>>4, (B0>>2)&3, B0&3
|
|
|
|
|
# decode the exponent
|
|
|
|
|
if LE < 3:
|
|
|
|
|
E = bytes_to_int(bytes[1:2+LE], 8*(1+LE))
|
|
|
|
|
bytes = bytes[2+LE:]
|
|
|
|
|
else:
|
|
|
|
|
# LE == 3
|
|
|
|
|
LE = ord(bytes[1:2])
|
|
|
|
|
if len(bytes)-2 < LE:
|
|
|
|
|
raise(ASN1BERDecodeErr('{0}: invalid REAL base 2 exponent length, {1!r}'\
|
|
|
|
|
.format(self.fullname(), LE)))
|
|
|
|
|
E = bytes_to_int(bytes[2:2+LE], 8*LE)
|
|
|
|
|
bytes = bytes[2+LE:]
|
|
|
|
|
N = bytes_to_uint(bytes, 8*len(bytes))
|
|
|
|
|
# REAL value = (-1)**S * N * 2**F * B**E
|
|
|
|
|
# F is just increasing E, for the REAL standard base 2 notation
|
|
|
|
|
self._val = (N * (-1)**S, 2, E<<F)
|
|
|
|
|
|
|
|
|
|
def _encode_cont(self):
|
|
|
|
|
if self._val[0] == 0:
|
|
|
|
|
return b''
|
|
|
|
|
elif self._val in self._ASN_LUT:
|
|
|
|
|
# special values
|
|
|
|
|
if self._val == (1, None, None):
|
|
|
|
|
# PLUS-INFINITY
|
|
|
|
|
return b'\x40'
|
|
|
|
|
elif self._val == (-1, None, None):
|
|
|
|
|
# MINUS-INFINITY
|
|
|
|
|
return b'\x41'
|
|
|
|
|
else:
|
|
|
|
|
# NOT-A-NUMBER
|
|
|
|
|
return b'\x42'
|
|
|
|
|
elif self._val[1] == 10:
|
|
|
|
|
# base 10: character string encoding
|
|
|
|
|
if ASN1CodecBER.ENC_REALNR == 1:
|
|
|
|
|
if self._val[2] < 0:
|
|
|
|
|
raise(ASN1BEREncodeErr('{0}: invalid REAL base 10 encoding NR1 for decimal value'\
|
|
|
|
|
.format(self.fullname())))
|
|
|
|
|
i = self._val[0] * (10**self._val[2])
|
2017-09-01 19:47:54 +00:00
|
|
|
|
if python_version < 3:
|
|
|
|
|
return '\x01' + \
|
|
|
|
|
ASN1CodecBER.ENC_REALNR1_SPA * ' ' + \
|
|
|
|
|
ASN1CodecBER.ENC_REALNR1_ZER * '0' + \
|
|
|
|
|
str(i)
|
|
|
|
|
else:
|
|
|
|
|
return b'\x01' + \
|
|
|
|
|
ASN1CodecBER.ENC_REALNR1_SPA * b' ' + \
|
|
|
|
|
ASN1CodecBER.ENC_REALNR1_ZER * b'0' + \
|
|
|
|
|
bytes(str(i), 'ascii')
|
2017-07-04 21:12:41 +00:00
|
|
|
|
elif ASN1CodecBER.ENC_REALNR == 2:
|
2017-09-01 19:47:54 +00:00
|
|
|
|
if python_version < 3:
|
|
|
|
|
i = bytes(self._val[0])
|
|
|
|
|
else:
|
|
|
|
|
i = bytes(str(self._val[0]), 'ascii')
|
2017-07-04 21:12:41 +00:00
|
|
|
|
if self._val[2] >= 0:
|
|
|
|
|
# we need to add trailing zero
|
|
|
|
|
i += self._val[2] * b'0'
|
|
|
|
|
i += b'.'
|
|
|
|
|
else:
|
|
|
|
|
#self._val[2] < 0:
|
|
|
|
|
# we need to place a coma correctly
|
|
|
|
|
d = -self._val[2]
|
|
|
|
|
if len(i) < d:
|
|
|
|
|
# we need to add heading zero
|
|
|
|
|
i = b'.' + (d-len(i)) * b'0' + i
|
|
|
|
|
else:
|
|
|
|
|
# we need to place the coma within i
|
|
|
|
|
i = i[:len(i)-d] + b'.' + i[len(i)-d:]
|
|
|
|
|
return b'\x02' + \
|
|
|
|
|
ASN1CodecBER.ENC_REALNR2_SPA * b' ' + \
|
|
|
|
|
ASN1CodecBER.ENC_REALNR2_ZER * b'0' + \
|
|
|
|
|
i + \
|
|
|
|
|
ASN1CodecBER.ENC_REALNR2_ZERTRAIL * b'0'
|
|
|
|
|
else:
|
|
|
|
|
#ASN1CodecBER.ENC_REALNR == 3
|
2017-09-01 19:47:54 +00:00
|
|
|
|
if python_version < 3:
|
|
|
|
|
i, e = bytes(self._val[0]), self._val[2]
|
|
|
|
|
else:
|
|
|
|
|
i, e = bytes(str(self._val[0]), 'ascii'), self._val[2]
|
2017-07-04 21:12:41 +00:00
|
|
|
|
# remove trailing zero
|
|
|
|
|
while i[-1:] == b'0':
|
|
|
|
|
i = i[:-1]
|
|
|
|
|
e += 1
|
|
|
|
|
if e == 0:
|
|
|
|
|
e = b'+0'
|
2017-09-01 19:47:54 +00:00
|
|
|
|
elif python_version < 3:
|
|
|
|
|
e = bytes(e)
|
2017-07-04 21:12:41 +00:00
|
|
|
|
else:
|
|
|
|
|
e = bytes(str(e), 'ascii')
|
|
|
|
|
return b'\x03' + i + b'.E' + e
|
|
|
|
|
else:
|
|
|
|
|
# base 2, encoding the CER / DER way:
|
|
|
|
|
# msb = 1
|
|
|
|
|
# B = 0 (base 2), F = 0, mant = 0 or is odd,
|
|
|
|
|
# mant and exp encoded in the minimum number of bytes
|
|
|
|
|
# ensure mant is 0 or odd
|
|
|
|
|
if self._val[0] < 0:
|
|
|
|
|
S, m, E = 1, -self._val[0], self._val[2]
|
|
|
|
|
else:
|
|
|
|
|
S, m, E = 0, self._val[0], self._val[2]
|
|
|
|
|
while m > 0 and m % 2 == 0:
|
|
|
|
|
m >>= 1
|
|
|
|
|
E += 1
|
|
|
|
|
LE = int_bytelen(E)
|
|
|
|
|
E = int_to_bytes(E, 8*LE)
|
|
|
|
|
N = uint_to_bytes(m, 8*uint_bytelen(m))
|
2017-09-01 19:47:54 +00:00
|
|
|
|
if python_version < 3:
|
|
|
|
|
if LE > 3:
|
|
|
|
|
return chr(0x80 + (S<<6) + 3) + uint_to_bytes(LE) + E + N
|
|
|
|
|
else:
|
|
|
|
|
return chr(0x80 + (S<<6) + LE-1) + E + N
|
2017-07-04 21:12:41 +00:00
|
|
|
|
else:
|
2017-09-01 19:47:54 +00:00
|
|
|
|
if LE > 3:
|
|
|
|
|
return bytes((0x80 + (S<<6) + 3, )) + uint_to_bytes(LE) + E + N
|
|
|
|
|
else:
|
|
|
|
|
return bytes((0x80 + (S<<6) + LE-1, )) + E + N
|
2017-07-04 21:12:41 +00:00
|
|
|
|
|
|
|
|
|
def _decode_ber_cont_ws(self, char, vbnd):
|
|
|
|
|
char._cur, char._len_bit = vbnd[0], vbnd[1]
|
|
|
|
|
V = Buf('V', bl=vbnd[1]-vbnd[0])
|
|
|
|
|
V._from_char(char)
|
|
|
|
|
self._decode_cont(V.to_bytes())
|
|
|
|
|
return V
|
|
|
|
|
|
|
|
|
|
def _decode_ber_cont(self, char, vbnd):
|
|
|
|
|
char._cur, char._len_bit = vbnd[0], vbnd[1]
|
|
|
|
|
self._decode_cont(char.get_bytes(vbnd[1]-vbnd[0]))
|
|
|
|
|
|
|
|
|
|
def _encode_ber_cont_ws(self):
|
|
|
|
|
buf = self._encode_cont()
|
|
|
|
|
lval = len(buf)
|
|
|
|
|
return 0, lval, Buf('V', val=buf, bl=8*lval)
|
|
|
|
|
|
|
|
|
|
def _encode_ber_cont(self):
|
|
|
|
|
buf = self._encode_cont()
|
|
|
|
|
lval = len(buf)
|
|
|
|
|
return 0, lval, [(T_BYTES, buf, 8*lval)]
|
2018-12-07 17:07:49 +00:00
|
|
|
|
|
|
|
|
|
###
|
|
|
|
|
# conversion between internal value and ASN.1 JER encoding
|
|
|
|
|
###
|
|
|
|
|
|
|
|
|
|
if _with_json:
|
|
|
|
|
|
|
|
|
|
def _from_jval(self, val):
|
|
|
|
|
if isinstance(val, integer_types):
|
|
|
|
|
self._val = (val, 2, 0)
|
|
|
|
|
elif isinstance(val, float):
|
|
|
|
|
if val == float('inf'):
|
|
|
|
|
self._val = (1, None, None)
|
|
|
|
|
elif val == float('nan'):
|
|
|
|
|
self._val = (0, None, None)
|
|
|
|
|
elif val == float('-inf'):
|
|
|
|
|
self._val = (-1, None, None)
|
|
|
|
|
else:
|
2018-12-11 17:09:54 +00:00
|
|
|
|
num, den = val.as_integer_ratio()
|
|
|
|
|
# den is the fractionnal denominator, which must be a pow of 2
|
|
|
|
|
p = 0
|
|
|
|
|
while den > 1:
|
|
|
|
|
den >> 1
|
|
|
|
|
p += 1
|
|
|
|
|
self._val = (num, 2, p)
|
|
|
|
|
elif isinstance(val, dict):
|
|
|
|
|
try:
|
|
|
|
|
sci = val['base10Value']
|
|
|
|
|
except KeyError:
|
|
|
|
|
raise(ASN1JERDecodeErr('{0}: invalid json value, {1!r}'\
|
|
|
|
|
.format(self.fullname(), val)))
|
|
|
|
|
m = self._JER_RE.match(sci)
|
|
|
|
|
if not m:
|
|
|
|
|
raise(ASN1JERDecodeErr('{0}: invalid json value, {1!r}'\
|
|
|
|
|
.format(self.fullname(), val)))
|
|
|
|
|
i, d, e = m.groups()
|
|
|
|
|
# remove trailing zero of the decimal part and adjust
|
|
|
|
|
# the exponent
|
|
|
|
|
if d:
|
|
|
|
|
d = d.rstrip('0')
|
|
|
|
|
if not e:
|
|
|
|
|
e = -len(d)
|
|
|
|
|
else:
|
|
|
|
|
e = int(e) - len(d)
|
|
|
|
|
self._val = (int(i+d), 10, e)
|
|
|
|
|
else:
|
|
|
|
|
self._val = (int(i), 10, int(e))
|
2018-12-07 17:07:49 +00:00
|
|
|
|
else:
|
|
|
|
|
raise(ASN1JERDecodeErr('{0}: invalid json value, {1!r}'\
|
|
|
|
|
.format(self.fullname(), val)))
|
|
|
|
|
|
|
|
|
|
def _to_jval(self):
|
2018-12-11 17:09:54 +00:00
|
|
|
|
if self._val[1] == 2:
|
|
|
|
|
if self._val[2] >= 0:
|
|
|
|
|
return self._val[0] * (2<<self._val[2])
|
|
|
|
|
else:
|
|
|
|
|
return {'base10Value': '%s' % (self._val[0]*(2**self._val[2]))}
|
|
|
|
|
else:
|
|
|
|
|
#self._val[1] == 10
|
|
|
|
|
# TODO: some constraints on the mantissa / base / exponent should
|
|
|
|
|
# lead to an integer encoding instead of this scientific notation
|
|
|
|
|
return {'base10Value': '%ie%i' % (self._val[0], self._val[2])}
|
2017-07-04 21:12:41 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#------------------------------------------------------------------------------#
|
|
|
|
|
# ENUMERATED, OID and RELATIVE-OID
|
|
|
|
|
#------------------------------------------------------------------------------#
|
|
|
|
|
|
|
|
|
|
class ENUM(ASN1Obj):
|
|
|
|
|
__doc__ = """
|
|
|
|
|
ASN.1 basic type ENUMERATED object
|
|
|
|
|
|
|
|
|
|
Single value: Python str, must be a key in _cont
|
|
|
|
|
special case is the "_ext_$ind" value which encodes an unknown extension
|
|
|
|
|
index $ind
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Specific attribute:
|
|
|
|
|
|
|
|
|
|
- cont: ASN1Dict {enum (str): enum index (int)},
|
|
|
|
|
provides the content of the ENUMERATED object
|
|
|
|
|
|
|
|
|
|
- cont_rev: Python dict {enum index (int): enum (str)}
|
|
|
|
|
|
|
|
|
|
- const_ind: ASN1Set, provides the set of ranges for root indexes and ext
|
|
|
|
|
indexes of the content
|
|
|
|
|
%s
|
|
|
|
|
""" % ASN1Obj_docstring
|
|
|
|
|
|
|
|
|
|
_cont_rev = {}
|
|
|
|
|
_const_ind = None
|
|
|
|
|
|
|
|
|
|
TYPE = TYPE_ENUM
|
|
|
|
|
TAG = 10
|
|
|
|
|
|
|
|
|
|
#_ASN_RE created at runtime, depends of self._cont
|
|
|
|
|
|
|
|
|
|
def _safechk_val(self, val):
|
2018-02-09 21:00:34 +00:00
|
|
|
|
if not isinstance(val, str_types) or val not in self._cont:
|
2017-07-04 21:12:41 +00:00
|
|
|
|
if self._ext is None or not re.match('_ext_[0-9]{1,}', val):
|
|
|
|
|
raise(ASN1ObjErr('{0}: invalid value, {1!r}'.format(self.fullname(), val)))
|
|
|
|
|
|
|
|
|
|
###
|
|
|
|
|
# conversion between internal value and ASN.1 syntax
|
|
|
|
|
###
|
|
|
|
|
|
|
|
|
|
def _from_asn1(self, txt):
|
|
|
|
|
if not hasattr(self, '_ASN_RE'):
|
|
|
|
|
items = list(self._cont.keys())
|
|
|
|
|
items.sort(key=len, reverse=True)
|
|
|
|
|
self._ASN_RE = re.compile('|'.join(items))
|
|
|
|
|
m = self._ASN_RE.match(txt)
|
|
|
|
|
if m:
|
|
|
|
|
self._val = m.group()
|
|
|
|
|
return txt[m.end():].strip()
|
|
|
|
|
else:
|
|
|
|
|
raise(ASN1ASNDecodeErr('{0}: invalid text, {1!r}'\
|
|
|
|
|
.format(self.fullname(), txt)))
|
|
|
|
|
|
|
|
|
|
def _to_asn1(self):
|
|
|
|
|
return self._val
|
|
|
|
|
|
|
|
|
|
###
|
|
|
|
|
# conversion between internal value and ASN.1 PER encoding
|
|
|
|
|
###
|
|
|
|
|
|
|
|
|
|
def _from_per_ws(self, char):
|
|
|
|
|
GEN = []
|
|
|
|
|
if self._ext is not None:
|
|
|
|
|
E = Uint('E', bl=1)
|
|
|
|
|
E._from_char(char)
|
|
|
|
|
GEN.append(E)
|
|
|
|
|
if E():
|
|
|
|
|
# 1) index value is in the extended part (could be unknown)
|
|
|
|
|
big = Uint('big', bl=1)
|
|
|
|
|
big._from_char(char)
|
|
|
|
|
GEN.append(big)
|
|
|
|
|
if ASN1CodecPER.ALIGNED:
|
|
|
|
|
ASN1CodecPER._off[-1] += 2
|
|
|
|
|
if big():
|
|
|
|
|
# 2) not-small index value (>= 64)
|
|
|
|
|
ind, _gen = ASN1CodecPER.decode_intunconst_ws(char, 0, name='I')
|
|
|
|
|
GEN.extend(_gen)
|
|
|
|
|
else:
|
|
|
|
|
# 3) normally-small index value (< 64)
|
|
|
|
|
nsv = Uint('I', bl=6)
|
|
|
|
|
nsv._from_char(char)
|
|
|
|
|
ind = nsv()
|
|
|
|
|
GEN.append(nsv)
|
|
|
|
|
if ASN1CodecPER.ALIGNED:
|
|
|
|
|
ASN1CodecPER._off[-1] += 6
|
|
|
|
|
if ind < len(self._ext):
|
|
|
|
|
# known extension
|
|
|
|
|
self._val = self._ext[ind]
|
|
|
|
|
else:
|
|
|
|
|
# unknown extension
|
|
|
|
|
if not self._SILENT:
|
|
|
|
|
asnlog('ENUM._from_per_ws: %s, unknown extension index %r'\
|
|
|
|
|
% (self._name, ind))
|
|
|
|
|
self._val = '_ext_%r' % ind
|
|
|
|
|
self._struct = Envelope(self._name, GEN=tuple(GEN))
|
|
|
|
|
return
|
|
|
|
|
elif ASN1CodecPER.ALIGNED:
|
|
|
|
|
ASN1CodecPER._off[-1] += 1
|
|
|
|
|
# 4) value is in the root part
|
|
|
|
|
if len(self._root) == 1:
|
|
|
|
|
# 5) only a single enum possible, nothing to decode
|
|
|
|
|
self._val = self._root[0]
|
|
|
|
|
self._struct = Envelope(self._name, GEN=tuple(GEN))
|
|
|
|
|
return
|
|
|
|
|
else:
|
|
|
|
|
# 6) decode the enum index in the minimum number of bits
|
|
|
|
|
ind, _gen = ASN1CodecPER.decode_intconst_ws(char, self._const_ind, name='I')
|
|
|
|
|
self._val = self._root[ind]
|
|
|
|
|
self._struct = Envelope(self._name, GEN=tuple(GEN + _gen))
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
def _from_per(self, char):
|
|
|
|
|
if self._ext is not None:
|
|
|
|
|
E = char.get_uint(1)
|
|
|
|
|
if E:
|
|
|
|
|
# 1) index value is in the extended part (could be unknown)
|
|
|
|
|
big = char.get_uint(1)
|
|
|
|
|
if ASN1CodecPER.ALIGNED:
|
|
|
|
|
ASN1CodecPER._off[-1] += 2
|
|
|
|
|
if big:
|
|
|
|
|
# 2) not-small index value (>= 64)
|
|
|
|
|
ind = ASN1CodecPER.decode_intunconst(char, 0)
|
|
|
|
|
else:
|
|
|
|
|
# 3) normally-small index value (< 64)
|
|
|
|
|
ind = char.get_uint(6)
|
|
|
|
|
if ASN1CodecPER.ALIGNED:
|
|
|
|
|
ASN1CodecPER._off[-1] += 6
|
|
|
|
|
if ind < len(self._ext):
|
|
|
|
|
# known extension
|
|
|
|
|
self._val = self._ext[ind]
|
|
|
|
|
else:
|
|
|
|
|
# unknown extension
|
|
|
|
|
if not self._SILENT:
|
|
|
|
|
asnlog('ENUM._from_per: %s, unknown extension index %r'\
|
|
|
|
|
% (self._name, ind))
|
|
|
|
|
self._val = '_ext_%r' % ind
|
|
|
|
|
return
|
|
|
|
|
elif ASN1CodecPER.ALIGNED:
|
|
|
|
|
ASN1CodecPER._off[-1] += 1
|
|
|
|
|
# 4) value is in the root part
|
|
|
|
|
if len(self._root) == 1:
|
|
|
|
|
# 5) only a single enum possible, nothing to decode
|
|
|
|
|
self._val = self._root[0]
|
|
|
|
|
return
|
|
|
|
|
else:
|
|
|
|
|
# 6) decode the enum index in the minimum number of bits
|
|
|
|
|
ind = ASN1CodecPER.decode_intconst(char, self._const_ind)
|
|
|
|
|
self._val = self._root[ind]
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
def _to_per_ws(self):
|
|
|
|
|
GEN = []
|
|
|
|
|
if self._ext is not None:
|
|
|
|
|
# 1) extensible type
|
|
|
|
|
if self._val in self._root:
|
|
|
|
|
# 2) value index in the root part
|
|
|
|
|
GEN.append( Uint('E', val=0, bl=1) )
|
|
|
|
|
if ASN1CodecPER.ALIGNED:
|
|
|
|
|
ASN1CodecPER._off[-1] += 1
|
|
|
|
|
ind = self._root.index(self._val)
|
|
|
|
|
else:
|
|
|
|
|
# 3) extended value index
|
|
|
|
|
GEN.append( Uint('E', val=1, bl=1) )
|
|
|
|
|
if self._val in self._ext:
|
|
|
|
|
ind = self._ext.index(self._val)
|
|
|
|
|
else:
|
2019-03-15 16:51:26 +00:00
|
|
|
|
#self._val[:5] == '_ext_'
|
2017-07-04 21:12:41 +00:00
|
|
|
|
ind = int(self._val[5:])
|
|
|
|
|
if ind < 64:
|
|
|
|
|
# 4) normally small index
|
|
|
|
|
GEN.extend( (Uint('big', val=0, bl=1), Uint('I', val=ind, bl=6)) )
|
|
|
|
|
if ASN1CodecPER.ALIGNED:
|
|
|
|
|
ASN1CodecPER._off[-1] += 8
|
|
|
|
|
else:
|
|
|
|
|
# 5) big index
|
|
|
|
|
GEN.append( Uint('big', val=1, bl=1) )
|
|
|
|
|
if ASN1CodecPER.ALIGNED:
|
|
|
|
|
ASN1CodecPER._off[-1] += 2
|
|
|
|
|
GEN.extend( ASN1CodecPER.encode_intunconst_ws(ind, 0, name='I') )
|
|
|
|
|
self._struct = Envelope(self._name, GEN=tuple(GEN))
|
|
|
|
|
return self._struct
|
|
|
|
|
else:
|
|
|
|
|
ind = self._root.index(self._val)
|
|
|
|
|
# 6) value index in the root part
|
|
|
|
|
if len(self._root) > 1:
|
|
|
|
|
# 7) encode the enum index in the minimum number of bits
|
|
|
|
|
GEN.extend( ASN1CodecPER.encode_intconst_ws(ind, self._const_ind, name='I') )
|
|
|
|
|
self._struct = Envelope(self._name, GEN=tuple(GEN))
|
|
|
|
|
return self._struct
|
|
|
|
|
|
|
|
|
|
def _to_per(self):
|
|
|
|
|
GEN = []
|
|
|
|
|
if self._ext is not None:
|
|
|
|
|
# 1) extensible type
|
|
|
|
|
if self._val in self._root:
|
|
|
|
|
# 2) value index in the root part
|
|
|
|
|
GEN.append( (T_UINT, 0, 1) )
|
|
|
|
|
if ASN1CodecPER.ALIGNED:
|
|
|
|
|
ASN1CodecPER._off[-1] += 1
|
|
|
|
|
ind = self._root.index(self._val)
|
|
|
|
|
else:
|
|
|
|
|
# 3) extended value index
|
|
|
|
|
if self._val in self._ext:
|
|
|
|
|
GEN.append( (T_UINT, 1, 1) )
|
|
|
|
|
ind = self._ext.index(self._val)
|
2019-03-15 16:51:26 +00:00
|
|
|
|
else:
|
|
|
|
|
# self._val[:5] == '_ext_'
|
2017-07-04 21:12:41 +00:00
|
|
|
|
GEN.append( (T_UINT, 1, 1) )
|
|
|
|
|
ind = int(self._val[5:])
|
|
|
|
|
if ind < 64:
|
|
|
|
|
# 4) normally small index, msb (the "big" bit) is 0
|
|
|
|
|
GEN.append( (T_UINT, ind, 7) )
|
|
|
|
|
if ASN1CodecPER.ALIGNED:
|
|
|
|
|
ASN1CodecPER._off[-1] += 8
|
|
|
|
|
else:
|
|
|
|
|
# 5) big index
|
|
|
|
|
GEN.append( (T_UINT, 1, 1) )
|
|
|
|
|
if ASN1CodecPER.ALIGNED:
|
|
|
|
|
ASN1CodecPER._off[-1] += 2
|
|
|
|
|
GEN.extend( ASN1CodecPER.encode_intunconst(ind, 0) )
|
|
|
|
|
return GEN
|
|
|
|
|
else:
|
|
|
|
|
ind = self._root.index(self._val)
|
|
|
|
|
# 6) value index in the root part
|
|
|
|
|
if len(self._root) > 1:
|
|
|
|
|
# 7) encode the enum index in the minimum number of bits
|
|
|
|
|
GEN.extend( ASN1CodecPER.encode_intconst(ind, self._const_ind) )
|
|
|
|
|
return GEN
|
|
|
|
|
|
|
|
|
|
###
|
|
|
|
|
# conversion between internal value and ASN.1 BER encoding
|
|
|
|
|
###
|
|
|
|
|
|
|
|
|
|
def _decode_ber_cont_ws(self, char, vbnd):
|
|
|
|
|
if not isinstance(vbnd, tuple):
|
|
|
|
|
raise(ASN1BERDecodeErr('{0}: invalid ENUMERATED constructed structure'\
|
|
|
|
|
.format(self.fullname())))
|
|
|
|
|
char._cur, char._len_bit = vbnd[0], vbnd[1]
|
|
|
|
|
V = Int('V', bl=vbnd[1]-vbnd[0])
|
|
|
|
|
V._from_char(char)
|
|
|
|
|
val = V()
|
|
|
|
|
if val not in self._cont_rev:
|
|
|
|
|
if self._ext is not None:
|
|
|
|
|
# unknown extension
|
|
|
|
|
if not self._SILENT:
|
|
|
|
|
asnlog('ENUM._from_ber_ws: %s, unknown extension value %r'\
|
|
|
|
|
% (self._name, val))
|
|
|
|
|
self._val = '_ext_%r' % val
|
|
|
|
|
else:
|
|
|
|
|
raise(ASN1BERDecodeErr('{0}: invalid ENUMERATED value, %r'\
|
|
|
|
|
.format(self.fullname(), val)))
|
|
|
|
|
else:
|
|
|
|
|
self._val = self._cont_rev[val]
|
|
|
|
|
return V
|
|
|
|
|
|
|
|
|
|
def _decode_ber_cont(self, char, vbnd):
|
|
|
|
|
if not isinstance(vbnd, tuple):
|
|
|
|
|
raise(ASN1BERDecodeErr('{0}: invalid ENUMERATED constructed structure'\
|
|
|
|
|
.format(self.fullname())))
|
|
|
|
|
char._cur, char._len_bit = vbnd[0], vbnd[1]
|
|
|
|
|
val = char.get_int(vbnd[1]-vbnd[0])
|
|
|
|
|
if val not in self._cont_rev:
|
|
|
|
|
if self._ext is not None:
|
|
|
|
|
# unknown extension
|
|
|
|
|
if not self._SILENT:
|
|
|
|
|
asnlog('ENUM._from_ber_ws: %s, unknown extension value %r'\
|
|
|
|
|
% (self._name, val))
|
|
|
|
|
self._val = '_ext_%r' % val
|
|
|
|
|
else:
|
|
|
|
|
raise(ASN1BERDecodeErr('{0}: invalid ENUMERATED value, %r'\
|
|
|
|
|
.format(self.fullname(), val)))
|
|
|
|
|
else:
|
|
|
|
|
self._val = self._cont_rev[val]
|
|
|
|
|
|
|
|
|
|
def _encode_ber_cont_ws(self):
|
2019-03-15 16:51:26 +00:00
|
|
|
|
if self._val in self._cont:
|
2017-07-04 21:12:41 +00:00
|
|
|
|
val = self._cont[self._val]
|
2019-03-15 16:51:26 +00:00
|
|
|
|
else:
|
|
|
|
|
# self._val[:5] == '_ext_'
|
|
|
|
|
val = int(self._val[5:])
|
2017-07-04 21:12:41 +00:00
|
|
|
|
lval = int_bytelen(val)
|
|
|
|
|
return 0, lval, Int('V', val=val, bl=8*lval)
|
|
|
|
|
|
|
|
|
|
def _encode_ber_cont(self):
|
2019-03-15 16:51:26 +00:00
|
|
|
|
if self._val in self._cont:
|
2017-07-04 21:12:41 +00:00
|
|
|
|
val = self._cont[self._val]
|
2019-03-15 16:51:26 +00:00
|
|
|
|
else:
|
|
|
|
|
# self._val[:5] == '_ext_'
|
|
|
|
|
val = int(self._val[5:])
|
2017-07-04 21:12:41 +00:00
|
|
|
|
lval = int_bytelen(val)
|
|
|
|
|
return 0, lval, [ (T_INT, val, 8*lval) ]
|
2018-12-07 17:07:49 +00:00
|
|
|
|
|
|
|
|
|
###
|
|
|
|
|
# conversion between internal value and ASN.1 JER encoding
|
|
|
|
|
###
|
|
|
|
|
|
|
|
|
|
if _with_json:
|
|
|
|
|
|
|
|
|
|
def _from_jval(self, val):
|
|
|
|
|
if val in self._cont:
|
|
|
|
|
self._val = val
|
|
|
|
|
else:
|
|
|
|
|
raise(ASN1JERDecodeErr('{0}: invalid json value, {1!r}'\
|
|
|
|
|
.format(self.fullname(), val)))
|
|
|
|
|
|
|
|
|
|
def _to_jval(self):
|
|
|
|
|
return self._val
|
2017-07-04 21:12:41 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class _OID(ASN1Obj):
|
|
|
|
|
|
|
|
|
|
# this class implements the methods that are common to OID and REL_OID
|
|
|
|
|
|
|
|
|
|
_ASN_RE = re.compile('\{([a-zA-Z0-9\-\(\)\s]{1,})\}')
|
|
|
|
|
_ASN_RE_COMP = re.compile(
|
|
|
|
|
'([0-9]{1,})|(?:([a-zA-Z]{1}[a-zA-Z0-9\-]{0,})\s{0,}(?:\(([0-9]{1,})\)){0,1})')
|
|
|
|
|
|
|
|
|
|
def _safechk_val(self, val):
|
|
|
|
|
if not isinstance(val, tuple) or \
|
|
|
|
|
not all([isinstance(i, integer_types) for i in val]):
|
|
|
|
|
raise(ASN1ObjErr('{0}: invalid value, {1!r}'.format(self.fullname(), val)))
|
|
|
|
|
|
|
|
|
|
###
|
|
|
|
|
# conversion between internal value and ASN.1 syntax
|
|
|
|
|
###
|
|
|
|
|
|
|
|
|
|
def _from_asn1(self, txt):
|
|
|
|
|
m = self._ASN_RE.match(txt)
|
|
|
|
|
if m:
|
|
|
|
|
txtval = txt[m.start()+1:m.end()-1]
|
|
|
|
|
_val = []
|
|
|
|
|
txt = txt[m.end():].strip()
|
|
|
|
|
m = self._ASN_RE_COMP.match(txtval)
|
|
|
|
|
while m is not None:
|
|
|
|
|
if m.group(1) or m.group(3):
|
|
|
|
|
_val.append( int(m.group(1) or m.group(3)) )
|
|
|
|
|
else:
|
|
|
|
|
key = tuple(_val + [m.group(2)])
|
|
|
|
|
if key in ASN1_OID_ISO:
|
|
|
|
|
_val.append( ASN1_OID_ISO[key] )
|
|
|
|
|
else:
|
|
|
|
|
raise(ASN1NotSuppErr('{0}: unknown OID identifier, {1}'\
|
|
|
|
|
.format(self.fullname(), m.group(2))))
|
|
|
|
|
txtval = txtval[m.end():].strip()
|
|
|
|
|
m = self._ASN_RE_COMP.match(txtval)
|
|
|
|
|
if txtval:
|
|
|
|
|
raise(ASN1ASNDecodeErr('{0}: invalid remaining OID definition, {1}'\
|
|
|
|
|
.format(self.fullname(), txtval)))
|
|
|
|
|
self._val = tuple(_val)
|
|
|
|
|
return txt
|
|
|
|
|
else:
|
|
|
|
|
raise(ASN1ASNDecodeErr('{0}: invalid text, {1!r}'\
|
|
|
|
|
.format(self.fullname(), txt)))
|
|
|
|
|
|
|
|
|
|
def _to_asn1(self):
|
2017-08-27 21:21:04 +00:00
|
|
|
|
if self.TYPE == TYPE_OID and self._val in GLOBAL.OID:
|
|
|
|
|
return '{%s} -- %s --' % (' '.join(map(str, self._val)), GLOBAL.OID[self._val])
|
|
|
|
|
else:
|
|
|
|
|
return '{%s}' % ' '.join(map(str, self._val))
|
2017-07-04 21:12:41 +00:00
|
|
|
|
|
|
|
|
|
###
|
|
|
|
|
# conversion between internal value and ASN.1 PER encoding
|
|
|
|
|
# content is actually encoded like the BER one, prefixed with a bytes count
|
|
|
|
|
###
|
|
|
|
|
|
|
|
|
|
def _from_per_ws(self, char):
|
|
|
|
|
buf, GEN = ASN1CodecPER.decode_unconst_open_ws(char, wrapped=None)
|
|
|
|
|
self._decode_cont(buf)
|
|
|
|
|
self._struct = Envelope(self._name, GEN=tuple(GEN))
|
|
|
|
|
|
|
|
|
|
def _from_per(self, char):
|
|
|
|
|
self._decode_cont( ASN1CodecPER.decode_unconst_open(char, wrapped=None) )
|
|
|
|
|
|
|
|
|
|
def _to_per_ws(self):
|
|
|
|
|
GEN = ASN1CodecPER.encode_unconst_buf_ws( self._encode_cont() )
|
|
|
|
|
self._struct = Envelope(self._name, GEN=tuple(GEN))
|
|
|
|
|
return self._struct
|
|
|
|
|
|
|
|
|
|
def _to_per(self):
|
|
|
|
|
return ASN1CodecPER.encode_unconst_buf( self._encode_cont() )
|
|
|
|
|
|
|
|
|
|
###
|
|
|
|
|
# conversion between internal value and ASN.1 BER encoding
|
|
|
|
|
###
|
|
|
|
|
|
|
|
|
|
def _decode_ber_cont_ws(self, char, vbnd):
|
|
|
|
|
if not isinstance(vbnd, tuple):
|
|
|
|
|
raise(ASN1BERDecodeErr('{0}: invalid OID constructed structure'\
|
|
|
|
|
.format(self.fullname())))
|
|
|
|
|
char._cur, char._len_bit = vbnd[0], vbnd[1]
|
|
|
|
|
V = Buf('V', bl=vbnd[1]-vbnd[0])
|
|
|
|
|
V._from_char(char)
|
|
|
|
|
self._decode_cont(V.to_bytes())
|
|
|
|
|
return V
|
|
|
|
|
|
|
|
|
|
def _decode_ber_cont(self, char, vbnd):
|
|
|
|
|
if not isinstance(vbnd, tuple):
|
|
|
|
|
raise(ASN1BERDecodeErr('{0}: invalid OID constructed structure'\
|
|
|
|
|
.format(self.fullname())))
|
|
|
|
|
char._cur, char._len_bit = vbnd[0], vbnd[1]
|
|
|
|
|
self._decode_cont(char.get_bytes(vbnd[1]-vbnd[0]))
|
|
|
|
|
|
|
|
|
|
def _encode_ber_cont_ws(self):
|
|
|
|
|
buf = self._encode_cont()
|
|
|
|
|
lval = len(buf)
|
|
|
|
|
return 0, lval, Buf('V', val=buf, bl=8*lval)
|
|
|
|
|
|
|
|
|
|
def _encode_ber_cont(self):
|
|
|
|
|
buf = self._encode_cont()
|
|
|
|
|
lval = len(buf)
|
|
|
|
|
return 0, lval, [ (T_BYTES, buf, 8*lval) ]
|
2018-12-07 17:07:49 +00:00
|
|
|
|
|
|
|
|
|
###
|
|
|
|
|
# conversion between internal value and ASN.1 JER encoding
|
|
|
|
|
###
|
|
|
|
|
|
|
|
|
|
if _with_json:
|
|
|
|
|
|
|
|
|
|
def _from_jval(self, val):
|
|
|
|
|
try:
|
|
|
|
|
self._val = tuple(map(int, val.split('.')))
|
2019-09-26 08:20:18 +00:00
|
|
|
|
except Exception:
|
2018-12-07 17:07:49 +00:00
|
|
|
|
raise(ASN1JERDecodeErr('{0}: invalid json value, {1!r}'\
|
|
|
|
|
.format(self.fullname(), val)))
|
|
|
|
|
|
|
|
|
|
def _to_jval(self):
|
|
|
|
|
return '.'.join(map(str, self._val))
|
2017-07-04 21:12:41 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class OID(_OID):
|
|
|
|
|
__doc__ = """
|
|
|
|
|
ASN.1 basic type OBJECT IDENTIFIER object
|
|
|
|
|
|
|
|
|
|
Single value: Python tuple of int
|
|
|
|
|
%s
|
|
|
|
|
""" % ASN1Obj_docstring
|
|
|
|
|
|
|
|
|
|
TYPE = TYPE_OID
|
|
|
|
|
TAG = 6
|
|
|
|
|
|
|
|
|
|
###
|
|
|
|
|
# conversion between internal value and ASN.1 BER encoding
|
|
|
|
|
###
|
|
|
|
|
|
|
|
|
|
def _decode_cont(self, buf):
|
|
|
|
|
# 1) decode the list of integers, encoded like a BER tag
|
|
|
|
|
arcs = []
|
|
|
|
|
char = Charpy(buf)
|
|
|
|
|
lb = 8 * len(buf)
|
|
|
|
|
while char._cur < lb:
|
|
|
|
|
e = char.get_uint(1)
|
|
|
|
|
v = char.get_uint(7)
|
|
|
|
|
while e:
|
|
|
|
|
try:
|
|
|
|
|
e = char.get_uint(1)
|
|
|
|
|
v <<= 7
|
|
|
|
|
v += char.get_uint(7)
|
2019-09-26 08:20:18 +00:00
|
|
|
|
except Exception:
|
2017-07-04 21:12:41 +00:00
|
|
|
|
raise(ASN1BERDecodeErr('{0}: invalid OID integer value'\
|
|
|
|
|
.format(self.fullname())))
|
|
|
|
|
arcs.append(v)
|
|
|
|
|
# 2) expand the 1st value as the value for the 2 1st arcs
|
|
|
|
|
if arcs:
|
|
|
|
|
if arcs[0] < 40:
|
|
|
|
|
arcs.insert(0, 0)
|
|
|
|
|
elif arcs[0] < 80:
|
|
|
|
|
arcs.insert(0, 1)
|
|
|
|
|
arcs[1] -= 40
|
|
|
|
|
else:
|
|
|
|
|
arcs.insert(0, 2)
|
|
|
|
|
arcs[1] -= 80
|
|
|
|
|
self._val = tuple(arcs)
|
|
|
|
|
|
|
|
|
|
def _encode_cont(self):
|
|
|
|
|
if len(self._val) < 2:
|
|
|
|
|
raise(ASN1BEREncodeErr('{0}: missing OID 2 first integer values'\
|
|
|
|
|
.format(self.fullname())))
|
|
|
|
|
# 1) encode the 1st 2 arcs
|
|
|
|
|
if self._val[0] == 0:
|
|
|
|
|
arcs = self._val[1:]
|
|
|
|
|
elif self._val[0] == 1:
|
|
|
|
|
arcs = (40 + self._val[1], ) + self._val[2:]
|
|
|
|
|
else:
|
|
|
|
|
arcs = (80 + self._val[1], ) + self._val[2:]
|
|
|
|
|
# 2) encode each integer like a BER tag
|
|
|
|
|
by = []
|
|
|
|
|
for i in arcs:
|
|
|
|
|
fact = decompose_uint_sl(7, i)
|
2019-02-22 15:15:09 +00:00
|
|
|
|
if ASN1CodecBER.ENC_OID_LEXT and len(fact) < ASN1CodecBER.ENC_OID_LEXT:
|
|
|
|
|
fact.extend([0]*(ASN1CodecBER.ENC_OID_LEXT-len(fact)))
|
2017-07-04 21:12:41 +00:00
|
|
|
|
fact.reverse()
|
|
|
|
|
for f in fact[:-1]:
|
|
|
|
|
by.append( 0x80 + f )
|
|
|
|
|
by.append( fact[-1] )
|
|
|
|
|
if python_version > 2:
|
|
|
|
|
return bytes(by)
|
|
|
|
|
else:
|
|
|
|
|
return ''.join(map(chr, by))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class REL_OID(_OID):
|
|
|
|
|
__doc__ = """
|
|
|
|
|
ASN.1 basic type RELATIVE-OID object
|
|
|
|
|
|
|
|
|
|
Single value: Python tuple of int
|
|
|
|
|
%s
|
|
|
|
|
""" % ASN1Obj_docstring
|
|
|
|
|
|
|
|
|
|
TYPE = TYPE_REL_OID
|
|
|
|
|
TAG = 13
|
|
|
|
|
|
|
|
|
|
###
|
|
|
|
|
# conversion between internal value and ASN.1 BER encoding
|
|
|
|
|
###
|
|
|
|
|
|
|
|
|
|
def _decode_cont(self, buf):
|
|
|
|
|
# decode the list of integers, encoded like a BER tag
|
|
|
|
|
arcs = []
|
|
|
|
|
char = Charpy(buf)
|
|
|
|
|
lb = 8 * len(buf)
|
|
|
|
|
while char._cur < lb:
|
|
|
|
|
e = char.get_uint(1)
|
|
|
|
|
v = char.get_uint(7)
|
|
|
|
|
while e:
|
|
|
|
|
try:
|
|
|
|
|
e = char.get_uint(1)
|
|
|
|
|
v <<= 7
|
|
|
|
|
v += char.get_uint(7)
|
2019-09-26 08:20:18 +00:00
|
|
|
|
except Exception:
|
2017-07-04 21:12:41 +00:00
|
|
|
|
raise(ASN1BERDecodeErr('{0}: invalid OID integer value'\
|
|
|
|
|
.format(self.fullname())))
|
|
|
|
|
arcs.append(v)
|
|
|
|
|
self._val = tuple(arcs)
|
|
|
|
|
|
|
|
|
|
def _encode_cont(self):
|
|
|
|
|
# encode each integer like a BER tag
|
|
|
|
|
by = []
|
|
|
|
|
for i in self._val:
|
|
|
|
|
fact = decompose_uint_sl(7, i)
|
2019-02-22 15:15:09 +00:00
|
|
|
|
if ASN1CodecBER.ENC_OID_LEXT and len(fact) < ASN1CodecBER.ENC_OID_LEXT:
|
|
|
|
|
fact.extend([0]*(ASN1CodecBER.ENC_OID_LEXT-len(fact)))
|
2017-07-04 21:12:41 +00:00
|
|
|
|
fact.reverse()
|
|
|
|
|
for f in fact[:-1]:
|
|
|
|
|
by.append( 0x80 + f )
|
|
|
|
|
by.append( fact[-1] )
|
|
|
|
|
if python_version > 2:
|
|
|
|
|
return bytes(by)
|
|
|
|
|
else:
|
|
|
|
|
return ''.join(map(chr, by))
|
|
|
|
|
|