in stk-sample/lambda/stk-player-events-loader-pg/package/asn1crypto/core.py [0:0]
def _build(class_, method, tag, header, contents, trailer, spec=None, spec_params=None, nested_spec=None):
"""
Builds an Asn1Value object generically, or using a spec with optional params
:param class_:
An integer representing the ASN.1 class
:param method:
An integer representing the ASN.1 method
:param tag:
An integer representing the ASN.1 tag
:param header:
A byte string of the ASN.1 header (class, method, tag, length)
:param contents:
A byte string of the ASN.1 value
:param trailer:
A byte string of any ASN.1 trailer (only used by indefinite length encodings)
:param spec:
A class derived from Asn1Value that defines what class_ and tag the
value should have, and the semantics of the encoded value. The
return value will be of this type. If omitted, the encoded value
will be decoded using the standard universal tag based on the
encoded tag number.
:param spec_params:
A dict of params to pass to the spec object
:param nested_spec:
For certain Asn1Value classes (such as OctetString and BitString), the
contents can be further parsed and interpreted as another Asn1Value.
This parameter controls the spec for that sub-parsing.
:return:
An object of the type spec, or if not specified, a child of Asn1Value
"""
if spec_params is not None:
_tag_type_to_explicit_implicit(spec_params)
if header is None:
return VOID
header_set = False
# If an explicit specification was passed in, make sure it matches
if spec is not None:
# If there is explicit tagging and contents, we have to split
# the header and trailer off before we do the parsing
no_explicit = spec_params and 'no_explicit' in spec_params
if not no_explicit and (spec.explicit or (spec_params and 'explicit' in spec_params)):
if spec_params:
value = spec(**spec_params)
else:
value = spec()
original_explicit = value.explicit
explicit_info = reversed(original_explicit)
parsed_class = class_
parsed_method = method
parsed_tag = tag
to_parse = contents
explicit_header = header
explicit_trailer = trailer or b''
for expected_class, expected_tag in explicit_info:
if parsed_class != expected_class:
raise ValueError(unwrap(
'''
Error parsing %s - explicitly-tagged class should have been
%s, but %s was found
''',
type_name(value),
CLASS_NUM_TO_NAME_MAP.get(expected_class),
CLASS_NUM_TO_NAME_MAP.get(parsed_class, parsed_class)
))
if parsed_method != 1:
raise ValueError(unwrap(
'''
Error parsing %s - explicitly-tagged method should have
been %s, but %s was found
''',
type_name(value),
METHOD_NUM_TO_NAME_MAP.get(1),
METHOD_NUM_TO_NAME_MAP.get(parsed_method, parsed_method)
))
if parsed_tag != expected_tag:
raise ValueError(unwrap(
'''
Error parsing %s - explicitly-tagged tag should have been
%s, but %s was found
''',
type_name(value),
expected_tag,
parsed_tag
))
info, _ = _parse(to_parse, len(to_parse))
parsed_class, parsed_method, parsed_tag, parsed_header, to_parse, parsed_trailer = info
if not isinstance(value, Choice):
explicit_header += parsed_header
explicit_trailer = parsed_trailer + explicit_trailer
value = _build(*info, spec=spec, spec_params={'no_explicit': True})
value._header = explicit_header
value._trailer = explicit_trailer
value.explicit = original_explicit
header_set = True
else:
if spec_params:
value = spec(contents=contents, **spec_params)
else:
value = spec(contents=contents)
if spec is Any:
pass
elif isinstance(value, Choice):
value.validate(class_, tag, contents)
try:
# Force parsing the Choice now
value.contents = header + value.contents
header = b''
value.parse()
except (ValueError, TypeError) as e:
args = e.args[1:]
e.args = (e.args[0] + '\n while parsing %s' % type_name(value),) + args
raise e
else:
if class_ != value.class_:
raise ValueError(unwrap(
'''
Error parsing %s - class should have been %s, but %s was
found
''',
type_name(value),
CLASS_NUM_TO_NAME_MAP.get(value.class_),
CLASS_NUM_TO_NAME_MAP.get(class_, class_)
))
if method != value.method:
# Allow parsing a primitive method as constructed if the value
# is indefinite length. This is to allow parsing BER.
ber_indef = method == 1 and value.method == 0 and trailer == b'\x00\x00'
if not ber_indef or not isinstance(value, Constructable):
raise ValueError(unwrap(
'''
Error parsing %s - method should have been %s, but %s was found
''',
type_name(value),
METHOD_NUM_TO_NAME_MAP.get(value.method),
METHOD_NUM_TO_NAME_MAP.get(method, method)
))
else:
value.method = method
value._indefinite = True
if tag != value.tag:
if isinstance(value._bad_tag, tuple):
is_bad_tag = tag in value._bad_tag
else:
is_bad_tag = tag == value._bad_tag
if not is_bad_tag:
raise ValueError(unwrap(
'''
Error parsing %s - tag should have been %s, but %s was found
''',
type_name(value),
value.tag,
tag
))
# For explicitly tagged, un-speced parsings, we use a generic container
# since we will be parsing the contents and discarding the outer object
# anyway a little further on
elif spec_params and 'explicit' in spec_params:
original_value = Asn1Value(contents=contents, **spec_params)
original_explicit = original_value.explicit
to_parse = contents
explicit_header = header
explicit_trailer = trailer or b''
for expected_class, expected_tag in reversed(original_explicit):
info, _ = _parse(to_parse, len(to_parse))
_, _, _, parsed_header, to_parse, parsed_trailer = info
explicit_header += parsed_header
explicit_trailer = parsed_trailer + explicit_trailer
value = _build(*info, spec=spec, spec_params={'no_explicit': True})
value._header = header + value._header
value._trailer += trailer or b''
value.explicit = original_explicit
header_set = True
# If no spec was specified, allow anything and just process what
# is in the input data
else:
if tag not in _UNIVERSAL_SPECS:
raise ValueError(unwrap(
'''
Unknown element - %s class, %s method, tag %s
''',
CLASS_NUM_TO_NAME_MAP.get(class_),
METHOD_NUM_TO_NAME_MAP.get(method),
tag
))
spec = _UNIVERSAL_SPECS[tag]
value = spec(contents=contents, class_=class_)
ber_indef = method == 1 and value.method == 0 and trailer == b'\x00\x00'
if ber_indef and isinstance(value, Constructable):
value._indefinite = True
value.method = method
if not header_set:
value._header = header
value._trailer = trailer or b''
# Destroy any default value that our contents have overwritten
value._native = None
if nested_spec:
try:
value.parse(nested_spec)
except (ValueError, TypeError) as e:
args = e.args[1:]
e.args = (e.args[0] + '\n while parsing %s' % type_name(value),) + args
raise e
return value