| # coding: utf-8 |
| from __future__ import unicode_literals, division, absolute_import, print_function |
| |
| import unittest |
| import os |
| from datetime import datetime, timedelta |
| |
| from asn1crypto import core, util |
| |
| from .unittest_data import data_decorator, data |
| from ._unittest_compat import patch |
| |
| patch() |
| |
| tests_root = os.path.dirname(__file__) |
| fixtures_dir = os.path.join(tests_root, 'fixtures') |
| |
| |
| class NamedBits(core.BitString): |
| _map = { |
| 0: 'zero', |
| 1: 'one', |
| 2: 'two', |
| 3: 'three', |
| 4: 'four', |
| 6: 'six', |
| 7: 'seven', |
| } |
| |
| |
| class SequenceOfInts(core.SequenceOf): |
| _child_spec = core.Integer |
| |
| |
| class SequenceAny(core.SequenceOf): |
| _child_spec = core.Any |
| |
| |
| class Seq(core.Sequence): |
| _fields = [ |
| ('id', core.ObjectIdentifier), |
| ('value', core.Any), |
| ] |
| |
| _oid_pair = ('id', 'value') |
| _oid_specs = { |
| '1.2.3': core.Integer, |
| '2.3.4': core.OctetString, |
| } |
| |
| |
| class CopySeq(core.Sequence): |
| _fields = [ |
| ('name', core.UTF8String), |
| ('pair', Seq), |
| ] |
| |
| |
| class NestSeqAny(core.Sequence): |
| _fields = [ |
| ('id', core.ObjectIdentifier), |
| ('value', core.Any), |
| ] |
| |
| _oid_pair = ('id', 'value') |
| _oid_specs = { |
| '3.4.5': Seq, |
| } |
| |
| |
| class NestSeqExplicit(core.Sequence): |
| _fields = [ |
| ('id', core.ObjectIdentifier), |
| ('value', NamedBits), |
| ] |
| |
| _oid_pair = ('id', 'value') |
| _oid_specs = { |
| '3.4.5': Seq, |
| } |
| |
| |
| class Enum(core.Enumerated): |
| _map = { |
| 0: 'a', |
| 1: 'b', |
| } |
| |
| |
| class ExplicitFieldDefault(core.Sequence): |
| _fields = [ |
| ('bits', NamedBits), |
| ('seq', Seq, {'explicit': 2, 'default': {'id': '1.2.3', 'value': 10}}), |
| ] |
| |
| |
| class NumChoice(core.Choice): |
| _alternatives = [ |
| ('one', core.Integer, {'explicit': 0}), |
| ('two', core.Integer, {'implicit': 1}), |
| ('three', core.Integer, {'explicit': 2}), |
| ] |
| |
| |
| class NumChoiceOldApi(core.Choice): |
| _alternatives = [ |
| ('one', core.Integer, {'tag_type': 'explicit', 'tag': 0}), |
| ('two', core.Integer, {'tag_type': 'implicit', 'tag': 1}), |
| ('three', core.Integer, {'tag_type': 'explicit', 'tag': 2}), |
| ] |
| |
| |
| class SeqChoice(core.Choice): |
| _alternatives = [ |
| ('one', CopySeq, {'explicit': 0}), |
| ('two', CopySeq, {'implicit': 1}), |
| ] |
| |
| |
| class SeqChoiceOldApi(core.Choice): |
| _alternatives = [ |
| ('one', CopySeq, {'tag_type': 'explicit', 'tag': 0}), |
| ('two', CopySeq, {'tag_type': 'implicit', 'tag': 1}), |
| ] |
| |
| |
| class ChoiceChoice(core.Choice): |
| _alternatives = [ |
| ('num', NumChoice, {'explicit': 0}), |
| ('seq', SeqChoice, {'explicit': 1}), |
| ] |
| |
| |
| class CCSeq(core.Sequence): |
| _fields = [ |
| ('cc', ChoiceChoice) |
| ] |
| |
| |
| class ExplicitField(core.Sequence): |
| _fields = [ |
| ('field', NumChoice, {'tag_type': 'explicit', 'tag': 0}), |
| ] |
| |
| |
| class ExplicitFieldOldApi(core.Sequence): |
| _fields = [ |
| ('field', NumChoiceOldApi, {'explicit': 0}), |
| ] |
| |
| |
| class SetTest(core.Set): |
| _fields = [ |
| ('two', core.Integer, {'tag_type': 'implicit', 'tag': 2}), |
| ('one', core.Integer, {'tag_type': 'implicit', 'tag': 1}), |
| ] |
| |
| |
| class SetTestOldApi(core.Set): |
| _fields = [ |
| ('two', core.Integer, {'implicit': 2}), |
| ('one', core.Integer, {'implicit': 1}), |
| ] |
| |
| |
| class SetOfTest(core.SetOf): |
| _child_spec = core.Integer |
| |
| |
| class ConcatTest(core.Concat): |
| _child_specs = [Seq, core.Integer] |
| |
| |
| class IntegerConcats(core.Concat): |
| _child_specs = [core.Integer, core.Integer] |
| |
| |
| class MyOids(core.ObjectIdentifier): |
| _map = { |
| '1.2.3': 'abc', |
| '4.5.6': 'def', |
| } |
| |
| |
| class ApplicationTaggedInteger(core.Integer): |
| # This class attribute may be a 2-element tuple of integers, |
| # or a tuple of 2-element tuple of integers. The first form |
| # will be converted to the second form the first time an |
| # object of this type is constructed. |
| explicit = ((1, 10), ) |
| |
| |
| class ApplicationTaggedInner(core.Sequence): |
| """ |
| TESTCASE DEFINITIONS EXPLICIT TAGS ::= |
| BEGIN |
| |
| INNERSEQ ::= SEQUENCE { |
| innernumber [21] INTEGER |
| } |
| |
| INNER ::= [APPLICATION 20] INNERSEQ |
| """ |
| |
| explicit = (1, 20) |
| |
| _fields = [ |
| ('innernumber', core.Integer, {'explicit': 21}), |
| ] |
| |
| |
| class ApplicationTaggedOuter(core.Sequence): |
| """ |
| OUTERSEQ ::= SEQUENCE { |
| outernumber [11] INTEGER, |
| inner [12] INNER |
| } |
| |
| OUTER ::= [APPLICATION 10] OUTERSEQ |
| END |
| """ |
| |
| explicit = (1, 10) |
| |
| _fields = [ |
| ('outernumber', core.Integer, {'explicit': 11}), |
| ('inner', ApplicationTaggedInner, {'explicit': 12}), |
| ] |
| |
| |
| class SpcPeImageFlags(core.BitString): |
| _map = { |
| 0: "includeResources", |
| 1: "includeDebugInfo", |
| 2: "includeImportAddressTable", |
| } |
| |
| |
| class SpcSerializedObject(core.Sequence): |
| _fields = [ |
| ("classId", core.OctetString), |
| ("serializedData", core.OctetString), |
| ] |
| |
| |
| class SpcString(core.Choice): |
| _alternatives = [ |
| ("unicode", core.BMPString, {"implicit": 0}), |
| ("ascii", core.IA5String, {"implicit": 1}), |
| ] |
| |
| |
| class SpcLink(core.Choice): |
| _alternatives = [ |
| ("url", core.IA5String, {"implicit": 0}), |
| ("moniker", SpcSerializedObject, {"implicit": 1}), |
| ("file", SpcString, {"explicit": 2}) |
| ] |
| |
| |
| class SpcPeImageData(core.Sequence): |
| _fields = [ |
| ("flags", SpcPeImageFlags, {"default": "includeResources"}), |
| ("file", SpcLink, {"explicit": 0}) |
| ] |
| |
| |
| class UTF8Sequence(core.Sequence): |
| _fields = [ |
| ("string", core.UTF8String) |
| ] |
| |
| |
| class NestedUTF8Sequence(core.Sequence): |
| _fields = [ |
| ("seq", UTF8Sequence) |
| ] |
| |
| |
| @data_decorator |
| class CoreTests(unittest.TestCase): |
| |
| def test_large_tag_encode(self): |
| # https://misc.daniel-marschall.de/asn.1/oid_facts.html |
| v = core.Primitive(tag=31, contents=b'') |
| self.assertEqual(b'\x1f\x1f\x00', v.dump()) |
| |
| v = core.Primitive(tag=36, contents=b'') |
| self.assertEqual(b'\x1f\x24\x00', v.dump()) |
| |
| # One extra byte |
| v = core.Primitive( |
| class_="application", |
| method="constructed", |
| tag=73, |
| contents=b'' |
| ) |
| self.assertEqual(b'\x7f\x49\x00', v.dump()) |
| |
| # Two extra bytes |
| v = core.Primitive( |
| class_="application", |
| method="constructed", |
| tag=201, |
| contents=b'' |
| ) |
| self.assertEqual(b'\x7f\x81\x49\x00', v.dump()) |
| |
| # Three extra bytes |
| v = core.Primitive( |
| class_="application", |
| method="constructed", |
| tag=16384, |
| contents=b'' |
| ) |
| self.assertEqual(b'\x7f\x81\x80\x00\x00', v.dump()) |
| |
| def test_manual_construction(self): |
| v = core.Asn1Value( |
| class_="application", |
| method="constructed", |
| tag=1, |
| contents=b'' |
| ) |
| self.assertEqual(b'\x61\x00', v.dump()) |
| |
| def test_sequence_spec(self): |
| seq = Seq() |
| seq['id'] = '1.2.3' |
| self.assertEqual(core.Integer, seq.spec('value')) |
| seq['id'] = '2.3.4' |
| self.assertEqual(core.OctetString, seq.spec('value')) |
| |
| def test_sequence_of_spec(self): |
| seq = SequenceAny() |
| self.assertEqual(core.Any, seq.spec()) |
| |
| @staticmethod |
| def compare_primitive_info(): |
| return ( |
| (core.ObjectIdentifier('1.2.3'), core.ObjectIdentifier('1.2.3'), True), |
| (core.Integer(1), Enum(1), False), |
| (core.Integer(1), core.Integer(1, implicit=5), True), |
| (core.Integer(1), core.Integer(1, explicit=5), True), |
| (core.Integer(1), core.Integer(2), False), |
| (core.OctetString(b''), core.OctetString(b''), True), |
| (core.OctetString(b''), core.OctetString(b'1'), False), |
| (core.OctetString(b''), core.OctetBitString(b''), False), |
| (core.ParsableOctetString(b'12'), core.OctetString(b'12'), True), |
| (core.ParsableOctetBitString(b'12'), core.OctetBitString(b'12'), True), |
| (core.UTF8String('12'), core.UTF8String('12'), True), |
| (core.UTF8String('12'), core.UTF8String('1'), False), |
| (core.UTF8String('12'), core.IA5String('12'), False), |
| ) |
| |
| @data('compare_primitive_info') |
| def compare_primitive(self, one, two, equal): |
| if equal: |
| self.assertEqual(one, two) |
| else: |
| self.assertNotEqual(one, two) |
| |
| @staticmethod |
| def integer_info(): |
| return ( |
| (0, b'\x02\x01\x00'), |
| (255, b'\x02\x02\x00\xFF'), |
| (128, b'\x02\x02\x00\x80'), |
| (127, b'\x02\x01\x7F'), |
| (-127, b'\x02\x01\x81'), |
| (-127, b'\x02\x01\x81'), |
| (32768, b'\x02\x03\x00\x80\x00'), |
| (-32768, b'\x02\x02\x80\x00'), |
| (-32769, b'\x02\x03\xFF\x7F\xFF'), |
| ) |
| |
| @data('integer_info') |
| def integer(self, native, der_bytes): |
| i = core.Integer(native) |
| self.assertEqual(der_bytes, i.dump()) |
| self.assertEqual(native, core.Integer.load(der_bytes).native) |
| |
| @staticmethod |
| def utctime_info(): |
| return ( |
| (datetime(2030, 12, 31, 8, 30, 0, tzinfo=util.timezone.utc), b'\x17\x0D301231083000Z'), |
| (datetime(2049, 12, 31, 8, 30, 0, tzinfo=util.timezone.utc), b'\x17\x0D491231083000Z'), |
| (datetime(1950, 12, 31, 8, 30, 0, tzinfo=util.timezone.utc), b'\x17\x0D501231083000Z'), |
| (datetime(2018, 10, 20, 7, 35, 4, tzinfo=util.timezone(timedelta(hours=7, minutes=40))), |
| b'\x17\x0D181019235504Z'), |
| ) |
| |
| @data('utctime_info') |
| def utctime(self, native, der_bytes): |
| u = core.UTCTime(native) |
| self.assertEqual(der_bytes, u.dump()) |
| self.assertEqual(native, core.UTCTime.load(der_bytes).native) |
| |
| def test_utctime_errors(self): |
| with self.assertRaises(ValueError): |
| # is not aware |
| core.UTCTime(datetime.fromtimestamp(1234567890)) |
| |
| with self.assertRaises(ValueError): |
| # Is pre 1950 |
| core.UTCTime(datetime(1910, 6, 22, 11, 33, 44, tzinfo=util.timezone.utc)) |
| |
| with self.assertRaises(ValueError): |
| # Is past 2050 |
| core.UTCTime(datetime(2106, 2, 7, 6, 28, 16, tzinfo=util.timezone.utc)) |
| |
| def test_utctime_copy(self): |
| a = core.UTCTime(datetime(2019, 11, 11, 17, 45, 18, tzinfo=util.timezone.utc)) |
| # Ensure _native is set because we want to test copy on the nested timezone object. |
| a.native |
| b = a.copy() |
| self.assertEqual(a.native, b.native) |
| self.assertEqual(a.contents, b.contents) |
| self.assertEqual(a.dump(), b.dump()) |
| |
| @staticmethod |
| def generalized_time_info(): |
| def tz(hours, minutes=0): |
| return util.create_timezone(timedelta(hours=hours, minutes=minutes)) |
| |
| return ( |
| (b'\x18\x1520180405062426.0+0200', datetime(2018, 4, 5, 6, 24, 26, 0, tz(2)), b'\x18\x0f20180405042426Z'), |
| (b'\x18\x0f2018062419-1355', datetime(2018, 6, 24, 19, 0, 0, 0, tz(-13, -55)), b'\x18\x0f20180625085500Z'), |
| (b'\x18\x0d2018062419-13', datetime(2018, 6, 24, 19, 0, 0, 0, tz(-13)), b'\x18\x0f20180625080000Z'), |
| (b'\x18\x0b2018062419Z', datetime(2018, 6, 24, 19, 0, 0, 0, tz(0)), b'\x18\x0f20180624190000Z'), |
| (b'\x18\x122018062419.15+0345', datetime(2018, 6, 24, 19, 9, 0, 0, tz(3, 45)), b'\x18\x0f20180624152400Z'), |
| ( |
| b'\x18\x13201806241957,433+02', |
| datetime(2018, 6, 24, 19, 57, 25, 980000, tz(2)), |
| b'\x18\x1220180624175725.98Z', |
| ), |
| ( |
| b'\x18\x1620180624195724.215999Z', |
| datetime(2018, 6, 24, 19, 57, 24, 215999, tz(0)), |
| b'\x18\x1620180624195724.215999Z', |
| ), |
| ( |
| b'\x18\x150000022910.31337-0815', |
| util.extended_datetime(0, 2, 29, 10, 18, 48, 132000, tz(-8, -15)), |
| b'\x18\x1300000229183348.132Z', |
| ), |
| (b'\x18\x1520180624195724.215999', datetime(2018, 6, 24, 19, 57, 24, 215999), None), |
| (b'\x18\x0a2018062419', datetime(2018, 6, 24, 19, 0, 0, 0), None), |
| ) |
| |
| @data('generalized_time_info') |
| def generalized_time(self, ber_bytes, native, der_bytes): |
| decoded = core.GeneralizedTime.load(ber_bytes) |
| |
| self.assertEqual(decoded.native, native) |
| self.assertEqual(decoded.native.tzinfo, native.tzinfo) |
| |
| if der_bytes is not None: |
| encoded = core.GeneralizedTime(native).dump() |
| self.assertEqual(encoded, der_bytes) |
| |
| decoded2 = core.GeneralizedTime.load(encoded) |
| self.assertEqual(decoded2.native, native) |
| else: |
| with self.assertRaises(ValueError): |
| encoded = core.GeneralizedTime(native).dump() |
| |
| @staticmethod |
| def type_info(): |
| return ( |
| ('universal/object_identifier.der', core.ObjectIdentifier, '1.2.840.113549.1.1.1'), |
| ) |
| |
| @data('type_info') |
| def parse_universal_type(self, input_filename, type_class, native): |
| with open(os.path.join(fixtures_dir, input_filename), 'rb') as f: |
| der = f.read() |
| parsed = type_class.load(der) |
| |
| self.assertEqual(native, parsed.native) |
| self.assertEqual(der, parsed.dump(force=True)) |
| |
| def test_int_to_bit_tuple(self): |
| self.assertEqual((), core._int_to_bit_tuple(0, 0)) |
| self.assertEqual((0,), core._int_to_bit_tuple(0, 1)) |
| self.assertEqual((1,), core._int_to_bit_tuple(1, 1)) |
| self.assertEqual((0, 0), core._int_to_bit_tuple(0, 2)) |
| self.assertEqual((0, 1), core._int_to_bit_tuple(1, 2)) |
| self.assertEqual((0, 0, 1), core._int_to_bit_tuple(1, 3)) |
| self.assertEqual((0, 1, 0), core._int_to_bit_tuple(2, 3)) |
| self.assertEqual((1, 0, 1), core._int_to_bit_tuple(5, 3)) |
| |
| with self.assertRaises(ValueError): |
| core._int_to_bit_tuple(9, 3) |
| with self.assertRaises(ValueError): |
| core._int_to_bit_tuple(-9, 5) |
| |
| @staticmethod |
| def bit_string_info(): |
| return ( |
| ((0, 1, 1), b'\x03\x02\x05\x60'), |
| ((0, 1, 1, 0, 0, 0, 0, 0), b'\x03\x02\x00\x60'), |
| ((0, 0, 0, 0, 0, 0, 0, 0), b'\x03\x02\x00\x00'), |
| ((0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1), b'\x03\x03\x00\x00\x01'), |
| ) |
| |
| @data('bit_string_info') |
| def bit_string(self, native, der_bytes): |
| bs = core.BitString(native) |
| self.assertEqual(der_bytes, bs.dump()) |
| self.assertEqual(native, core.BitString.load(der_bytes).native) |
| |
| def test_bit_string_load_dump(self): |
| bs = core.BitString.load(b'\x03\x01\x00') |
| self.assertEqual(tuple(), bs.native) |
| self.assertEqual(b'\x03\x01\x00', bs.dump(True)) |
| |
| @staticmethod |
| def bit_string_error_values(): |
| return ( |
| # unused bits in empty bit string |
| (b'\x03\x01\x05',), |
| # too many unused bits |
| (b'\x03\x03\x0e\x0c\x00',), |
| # chunk with unused bits is not last chunk |
| (b'\x23\x80\x03\x02\x01\xfe\x03\x02\x00\x55\x00\x00',), |
| ) |
| |
| @data('bit_string_error_values') |
| def bit_string_errors(self, enc_bytes): |
| with self.assertRaises(ValueError): |
| core.BitString.load(enc_bytes).native |
| |
| def test_cast(self): |
| a = core.OctetBitString(b'\x00\x01\x02\x03') |
| self.assertEqual(b'\x00\x01\x02\x03', a.native) |
| b = a.cast(core.BitString) |
| self.assertIsInstance(b, core.BitString) |
| self.assertEqual( |
| ( |
| 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 1, |
| 0, 0, 0, 0, 0, 0, 1, 0, |
| 0, 0, 0, 0, 0, 0, 1, 1 |
| ), |
| b.native |
| ) |
| c = a.cast(core.IntegerBitString) |
| self.assertIsInstance(c, core.IntegerBitString) |
| self.assertEqual(66051, c.native) |
| |
| def test_load(self): |
| i = core.load(b'\x02\x01\x00') |
| self.assertIsInstance(i, core.Integer) |
| self.assertEqual(0, i.native) |
| |
| def test_load_wrong_type(self): |
| with self.assertRaises(TypeError): |
| core.load('\x02\x01\x00') |
| |
| @staticmethod |
| def truncated_der_byte_strings(): |
| return ( |
| (b'',), |
| (b'\x30',), |
| (b'\x30\x03\x02\x00\x02',), |
| ) |
| |
| @data('truncated_der_byte_strings') |
| def truncated(self, der_bytes): |
| with self.assertRaises(ValueError): |
| core.load(der_bytes).native |
| |
| def test_strict(self): |
| with self.assertRaises(ValueError): |
| core.load(b'\x02\x01\x00\x00', strict=True) |
| |
| def test_strict_on_class(self): |
| with self.assertRaises(ValueError): |
| core.Integer.load(b'\x02\x01\x00\x00', strict=True) |
| |
| def test_strict_concat(self): |
| with self.assertRaises(ValueError): |
| IntegerConcats.load(b'\x02\x01\x00\x02\x01\x00\x00', strict=True) |
| |
| def test_strict_choice(self): |
| with self.assertRaises(ValueError): |
| NumChoice.load(b'\xA0\x03\x02\x01\x00\x00', strict=True) |
| with self.assertRaises(ValueError): |
| NumChoiceOldApi.load(b'\xA0\x03\x02\x01\x00\x00', strict=True) |
| |
| def test_choice_parse_return(self): |
| nc = NumChoice.load(b'\xA0\x03\x02\x01\x00\x00') |
| nc._parsed = None |
| self.assertEqual(0, nc.parse().native) |
| |
| def test_sequece_choice_choice(self): |
| CCSeq({ |
| 'cc': ChoiceChoice( |
| 'num', |
| NumChoice('one', core.Integer(0)) |
| ) |
| }) |
| |
| def test_bit_string_item_access(self): |
| named = core.BitString() |
| named[0] = True |
| self.assertEqual(False, named[2]) |
| self.assertEqual(False, named[1]) |
| self.assertEqual(True, named[0]) |
| |
| @staticmethod |
| def mapped_bit_string_info(): |
| return ( |
| ( |
| (0, 1, 1), |
| b'\x03\x02\x05\x60', |
| set(['one', 'two']) |
| ), |
| ( |
| (0,), |
| b'\x03\x01\x00', |
| set() |
| ), |
| ( |
| set(['one', 'two']), |
| b'\x03\x02\x05\x60', |
| set(['one', 'two']) |
| ) |
| ) |
| |
| @data('mapped_bit_string_info') |
| def mapped_bit_string(self, input_native, der_bytes, native): |
| named = NamedBits(input_native) |
| self.assertEqual(der_bytes, named.dump()) |
| self.assertEqual(native, NamedBits.load(der_bytes).native) |
| |
| def test_mapped_bit_string_item_access(self): |
| named = NamedBits() |
| named['one'] = True |
| self.assertEqual(False, named['two']) |
| self.assertEqual(True, named['one']) |
| self.assertEqual(True, 'one' in named.native) |
| |
| def test_mapped_bit_string_unset_bit(self): |
| named = NamedBits(set(['one', 'two'])) |
| named['one'] = False |
| self.assertEqual(True, named['two']) |
| self.assertEqual(set(['two']), named.native) |
| |
| def test_mapped_bit_string_sparse(self): |
| named = NamedBits((0, 0, 0, 0, 0, 1)) |
| self.assertEqual(False, named['two']) |
| self.assertEqual(True, named[5]) |
| self.assertEqual(True, 5 in named.native) |
| |
| def test_mapped_bit_string_numeric(self): |
| named = NamedBits() |
| named[1] = True |
| self.assertEqual(True, named['one']) |
| self.assertEqual(set(['one']), named.native) |
| |
| def test_get_sequence_value(self): |
| seq = SequenceOfInts([1, 2]) |
| self.assertEqual(2, seq[1].native) |
| |
| def test_replace_sequence_value(self): |
| seq = SequenceOfInts([1, 2]) |
| self.assertEqual([1, 2], seq.native) |
| seq[0] = 5 |
| self.assertEqual([5, 2], seq.native) |
| |
| def test_add_to_end_sequence_value(self): |
| seq = SequenceOfInts([1, 2]) |
| self.assertEqual([1, 2], seq.native) |
| seq[2] = 5 |
| self.assertEqual([1, 2, 5], seq.native) |
| seq.append(6) |
| self.assertEqual([1, 2, 5, 6], seq.native) |
| |
| def test_delete_sequence_value(self): |
| seq = SequenceOfInts([1, 2]) |
| self.assertEqual([1, 2], seq.native) |
| del seq[0] |
| self.assertEqual([2], seq.native) |
| |
| def test_sequence_any_asn1value(self): |
| seq = SequenceAny() |
| seq.append(core.Integer(5)) |
| self.assertEqual([5], seq.native) |
| |
| def test_sequence_any_native_value(self): |
| seq = SequenceAny() |
| with self.assertRaises(ValueError): |
| seq.append(5) |
| |
| def test_copy(self): |
| a = core.Integer(200) |
| b = a.copy() |
| self.assertNotEqual(id(a), id(b)) |
| self.assertEqual(a.contents, b.contents) |
| self.assertEqual(a.dump(), b.dump()) |
| |
| def test_copy_mutable(self): |
| a = CopySeq({'name': 'foo', 'pair': {'id': '1.2.3', 'value': 5}}) |
| # Cache the native representation so it is copied during the copy operation |
| a.native |
| b = a.copy() |
| self.assertNotEqual(id(a), id(b)) |
| self.assertNotEqual(id(a['pair']), id(b['pair'])) |
| self.assertEqual(a.contents, b.contents) |
| self.assertEqual(a.dump(), b.dump()) |
| |
| self.assertEqual(a['pair']['value'].native, b['pair']['value'].native) |
| a['pair']['value'] = 6 |
| self.assertNotEqual(a['pair']['value'].native, b['pair']['value'].native) |
| |
| a.native['pair']['value'] = 6 |
| self.assertNotEqual(a.native['pair']['value'], b.native['pair']['value']) |
| |
| self.assertNotEqual(a.contents, b.contents) |
| self.assertNotEqual(a.dump(), b.dump()) |
| |
| def test_explicit_tag_header(self): |
| val = NumChoice.load(b'\xa0\x03\x02\x01\x00') |
| self.assertEqual(b'\xa0\x03\x02\x01', val.chosen._header) |
| self.assertEqual(b'\x00', val.chosen.contents) |
| val2 = NumChoiceOldApi.load(b'\xa0\x03\x02\x01\x00') |
| self.assertEqual(b'\xa0\x03\x02\x01', val2.chosen._header) |
| self.assertEqual(b'\x00', val2.chosen.contents) |
| |
| def test_explicit_field_default(self): |
| val = ExplicitFieldDefault.load(b'\x30\x0f\x03\x02\x06@\xa2\x090\x07\x06\x02*\x03\x02\x01\x01') |
| self.assertEqual(set(['one']), val['bits'].native) |
| self.assertEqual( |
| util.OrderedDict([ |
| ('id', '1.2.3'), |
| ('value', 1) |
| ]), |
| val['seq'].native |
| ) |
| |
| def test_explicit_header_field_choice(self): |
| der = b'\x30\x07\xa0\x05\xa0\x03\x02\x01\x00' |
| val = ExplicitField.load(der) |
| self.assertEqual(0, val['field'].chosen.native) |
| self.assertEqual(der, val.dump(force=True)) |
| |
| val2 = ExplicitFieldOldApi.load(der) |
| self.assertEqual(0, val2['field'].chosen.native) |
| self.assertEqual(der, val2.dump(force=True)) |
| |
| def test_retag(self): |
| a = core.Integer(200) |
| b = a.retag('explicit', 0) |
| self.assertNotEqual(id(a), id(b)) |
| self.assertEqual(a.contents, b.contents) |
| self.assertNotEqual(a.dump(), b.dump()) |
| |
| def test_untag(self): |
| a = core.Integer(200, explicit=0) |
| b = a.untag() |
| self.assertNotEqual(id(a), id(b)) |
| self.assertEqual(a.contents, b.contents) |
| self.assertNotEqual(a.dump(), b.dump()) |
| |
| def test_choice_dict_name(self): |
| a = CopySeq({'name': 'foo', 'pair': {'id': '1.2.3', 'value': 5}}) |
| choice = SeqChoice({'one': a}) |
| self.assertEqual('one', choice.name) |
| |
| with self.assertRaises(ValueError): |
| SeqChoice({}) |
| |
| with self.assertRaises(ValueError): |
| SeqChoice({'one': a, 'two': a}) |
| |
| choice2 = SeqChoiceOldApi({'one': a}) |
| self.assertEqual('one', choice2.name) |
| |
| with self.assertRaises(ValueError): |
| SeqChoiceOldApi({}) |
| |
| with self.assertRaises(ValueError): |
| SeqChoiceOldApi({'one': a, 'two': a}) |
| |
| def test_choice_tuple_name(self): |
| a = CopySeq({'name': 'foo', 'pair': {'id': '1.2.3', 'value': 5}}) |
| choice = SeqChoice(('one', a)) |
| self.assertEqual('one', choice.name) |
| |
| with self.assertRaises(ValueError): |
| SeqChoice(('one',)) |
| |
| with self.assertRaises(ValueError): |
| SeqChoice(('one', a, None)) |
| |
| choice2 = SeqChoiceOldApi(('one', a)) |
| self.assertEqual('one', choice2.name) |
| |
| with self.assertRaises(ValueError): |
| SeqChoiceOldApi(('one',)) |
| |
| with self.assertRaises(ValueError): |
| SeqChoiceOldApi(('one', a, None)) |
| |
| def test_load_invalid_choice(self): |
| with self.assertRaises(ValueError): |
| NumChoice.load(b'\x02\x01\x00') |
| with self.assertRaises(ValueError): |
| NumChoiceOldApi.load(b'\x02\x01\x00') |
| |
| def test_fix_tagging_choice(self): |
| correct = core.Integer(200, explicit=2) |
| choice = NumChoice( |
| name='three', |
| value=core.Integer(200, explicit=1) |
| ) |
| self.assertEqual(correct.dump(), choice.dump()) |
| self.assertEqual(correct.explicit, choice.chosen.explicit) |
| choice2 = NumChoiceOldApi( |
| name='three', |
| value=core.Integer(200, explicit=1) |
| ) |
| self.assertEqual(correct.dump(), choice2.dump()) |
| self.assertEqual(correct.explicit, choice2.chosen.explicit) |
| |
| def test_copy_choice_mutate(self): |
| a = CopySeq({'name': 'foo', 'pair': {'id': '1.2.3', 'value': 5}}) |
| choice = SeqChoice( |
| name='one', |
| value=a |
| ) |
| choice.dump() |
| choice_copy = choice.copy() |
| choice.chosen['name'] = 'bar' |
| self.assertNotEqual(choice.chosen['name'], choice_copy.chosen['name']) |
| |
| choice2 = SeqChoiceOldApi( |
| name='one', |
| value=a |
| ) |
| choice2.dump() |
| choice2_copy = choice2.copy() |
| choice2.chosen['name'] = 'bar' |
| self.assertNotEqual(choice2.chosen['name'], choice2_copy.chosen['name']) |
| |
| def test_dump_ber_indefinite(self): |
| # A simple primitive type that is indefinite-length-encoded will be |
| # automatically re-encoded to DER encoding |
| data = b'\x2C\x80\x0C\x03foo\x00\x00' |
| v = core.UTF8String.load(data) |
| self.assertEqual(True, v._indefinite) |
| self.assertEqual('foo', v.native) |
| self.assertEqual(b'\x0C\x03foo', v.dump()) |
| |
| # In this case the indefinite length items are nested, and the |
| # top-level item is fixed-length, so it won't get automatically |
| # re-encoded |
| data = b'\x30\x0d\x30\x80\x2C\x80\x0C\x03foo\x00\x00\x00\x00' |
| v = NestedUTF8Sequence.load(data) |
| self.assertEqual(data, v.dump()) |
| |
| # Here both the top-level and the nested encoding will get fixed since |
| # the top-level being indefinitely triggers a full re-encoding |
| data = b'\x30\x80\x30\x09\x2C\x80\x0C\x03foo\x00\x00\x00\x00' |
| v = NestedUTF8Sequence.load(data) |
| self.assertEqual(b'\x30\x07\x30\x05\x0C\x03foo', v.dump()) |
| |
| def test_copy_indefinite(self): |
| v = core.BitString.load(b'\x23\x80\x03\x02\x00\x04\x00\x00') |
| self.assertEqual(True, v._indefinite) |
| v2 = v.copy() |
| self.assertEqual(0, v2.method) |
| self.assertEqual(3, v2.tag) |
| self.assertEqual(False, v2._indefinite) |
| self.assertEqual((0, 0, 0, 0, 0, 1, 0, 0), v2.native) |
| self.assertEqual(b'\x03\x02\x00\x04', v2.dump()) |
| |
| v = core.OctetBitString.load(b'\x23\x80\x03\x02\x00\x04\x00\x00') |
| self.assertEqual(True, v._indefinite) |
| v2 = v.copy() |
| self.assertEqual(0, v2.method) |
| self.assertEqual(3, v2.tag) |
| self.assertEqual(False, v2._indefinite) |
| self.assertEqual(b'\x04', v2.native) |
| self.assertEqual(b'\x03\x02\x00\x04', v2.dump()) |
| |
| v = core.ParsableOctetBitString.load(b'\x23\x80\x03\x04\x00\x02\x01\x04\x00\x00') |
| self.assertEqual(4, v.parsed.native) |
| self.assertEqual(True, v._indefinite) |
| v2 = v.copy() |
| self.assertEqual(0, v2.method) |
| self.assertEqual(3, v2.tag) |
| self.assertEqual(False, v2._indefinite) |
| self.assertEqual(4, v2.parsed.native) |
| self.assertEqual(b'\x03\x04\x00\x02\x01\x04', v2.dump()) |
| |
| v = core.IntegerBitString.load(b'\x23\x80\x03\x02\x00\x04\x00\x00') |
| self.assertEqual(True, v._indefinite) |
| v2 = v.copy() |
| self.assertEqual(0, v2.method) |
| self.assertEqual(3, v2.tag) |
| self.assertEqual(False, v2._indefinite) |
| self.assertEqual(4, v2.native) |
| self.assertEqual(b'\x03\x02\x00\x04', v2.dump()) |
| |
| v = core.OctetString.load(b'\x24\x80\x04\x03foo\x00\x00') |
| self.assertEqual(True, v._indefinite) |
| v2 = v.copy() |
| self.assertEqual(0, v2.method) |
| self.assertEqual(4, v2.tag) |
| self.assertEqual(False, v2._indefinite) |
| self.assertEqual(b'foo', v2.native) |
| self.assertEqual(b'\x04\x03foo', v2.dump()) |
| |
| v = core.IntegerOctetString.load(b'\x24\x80\x04\x01\x04\x00\x00') |
| self.assertEqual(True, v._indefinite) |
| v2 = v.copy() |
| self.assertEqual(0, v2.method) |
| self.assertEqual(4, v2.tag) |
| self.assertEqual(False, v2._indefinite) |
| self.assertEqual(4, v2.native) |
| self.assertEqual(b'\x04\x01\x04', v2.dump()) |
| |
| v = core.ParsableOctetString.load(b'\x24\x80\x04\x03\x02\x01\x04\x00\x00') |
| self.assertEqual(4, v.parsed.native) |
| self.assertEqual(True, v._indefinite) |
| v2 = v.copy() |
| self.assertEqual(0, v2.method) |
| self.assertEqual(4, v2.tag) |
| self.assertEqual(False, v2._indefinite) |
| self.assertEqual(4, v2.parsed.native) |
| self.assertEqual(b'\x02\x01\x04', v2.__bytes__()) |
| self.assertEqual(b'\x04\x03\x02\x01\x04', v2.dump()) |
| |
| v = core.UTF8String.load(b'\x2C\x80\x0C\x03foo\x00\x00') |
| self.assertEqual(True, v._indefinite) |
| v2 = v.copy() |
| self.assertEqual(0, v2.method) |
| self.assertEqual(12, v2.tag) |
| self.assertEqual(False, v2._indefinite) |
| self.assertEqual('foo', v2.native) |
| self.assertEqual(b'\x0C\x03foo', v2.dump()) |
| |
| def test_concat(self): |
| child1 = Seq({ |
| 'id': '1.2.3', |
| 'value': 1 |
| }) |
| child2 = core.Integer(0) |
| parent = ConcatTest([ |
| child1, |
| child2 |
| ]) |
| self.assertEqual(child1, parent[0]) |
| self.assertEqual(child2, parent[1]) |
| self.assertEqual(child1.dump() + child2.dump(), parent.dump()) |
| |
| def test_oid_map_unmap(self): |
| self.assertEqual('abc', MyOids.map('1.2.3')) |
| self.assertEqual('def', MyOids.map('4.5.6')) |
| self.assertEqual('7.8.9', MyOids.map('7.8.9')) |
| self.assertEqual('1.2.3', MyOids.unmap('abc')) |
| self.assertEqual('4.5.6', MyOids.unmap('def')) |
| self.assertEqual('7.8.9', MyOids.unmap('7.8.9')) |
| |
| with self.assertRaises(ValueError): |
| MyOids.unmap('no_such_mapping') |
| |
| def test_oid_dotted_native(self): |
| self.assertEqual('abc', MyOids('1.2.3').native) |
| self.assertEqual('1.2.3', MyOids('1.2.3').dotted) |
| self.assertEqual('abc', MyOids('abc').native) |
| self.assertEqual('1.2.3', MyOids('abc').dotted) |
| |
| def test_dump_set(self): |
| st = SetTest({'two': 2, 'one': 1}) |
| self.assertEqual(b'1\x06\x81\x01\x01\x82\x01\x02', st.dump()) |
| |
| def test_dump_set_of(self): |
| st = SetOfTest([3, 2, 1]) |
| self.assertEqual(b'1\x09\x02\x01\x01\x02\x01\x02\x02\x01\x03', st.dump()) |
| |
| def test_indefinite_length_octet_string(self): |
| data = b'$\x80\x04\x02\x01\x01\x04\x01\x01\x00\x00' |
| a = core.OctetString.load(data) |
| self.assertEqual(b'\x01\x01\x01', a.native) |
| self.assertEqual(b'\x01\x01\x01', a.__bytes__()) |
| self.assertEqual(1, a.method) |
| # Test copying moves internal state |
| self.assertEqual(a._bytes, a.copy()._bytes) |
| |
| def test_indefinite_length_octet_string_2(self): |
| data = b'$\x80\x04\r\x8d\xff\xf0\x98\x076\xaf\x93nB:\xcf\xcc\x04\x15' \ |
| b'\x92w\xf7\xf0\xe4y\xff\xc7\xdc3\xb2\xd0={\x1a\x18mDr\xaaI\x00\x00' |
| a = core.OctetString.load(data) |
| self.assertEqual( |
| b'\x8d\xff\xf0\x98\x076\xaf\x93nB:\xcf\xcc\x92w\xf7\xf0\xe4y\xff\xc7\xdc3\xb2\xd0={\x1a\x18mDr\xaaI', |
| a.native |
| ) |
| |
| def test_nested_indefinite_length_octet_string(self): |
| data = b'\x24\x80\x24\x80\x24\x80\x04\x00\x00\x00\x00\x00\x00\x00' |
| a = core.load(data) |
| self.assertEqual(b'', a.native) |
| self.assertEqual(b'', a.__bytes__()) |
| self.assertEqual(1, a.method) |
| self.assertEqual(b'\x04\x00', a.dump(force=True)) |
| # Test copying moves internal state |
| self.assertEqual(a._bytes, a.copy()._bytes) |
| |
| def test_indefinite_length_integer_octet_string(self): |
| data = b'$\x80\x04\x02\x01\x01\x04\x01\x01\x00\x00' |
| a = core.IntegerOctetString.load(data) |
| self.assertEqual(65793, a.native) |
| self.assertEqual(1, a.method) |
| self.assertEqual(b'\x01\x01\x01', a.cast(core.OctetString).native) |
| |
| def test_indefinite_length_parsable_octet_string(self): |
| data = b'$\x80\x04\x02\x04\x01\x04\x01\x01\x00\x00' |
| a = core.ParsableOctetString.load(data) |
| self.assertEqual(b'\x04\x01\x01', a.parsed.dump()) |
| self.assertEqual(b'\x04\x01\x01', a.__bytes__()) |
| self.assertEqual(1, a.method) |
| self.assertEqual(b'\x01', a.parsed.native) |
| self.assertEqual(b'\x01', a.native) |
| self.assertEqual(b'\x04\x01\x01', a.cast(core.OctetString).native) |
| # Test copying moves internal state |
| self.assertEqual(a._bytes, a.copy()._bytes) |
| self.assertEqual(a._parsed, a.copy()._parsed) |
| |
| def test_indefinite_length_utf8string(self): |
| data = b'\x2C\x80\x0C\x02\x61\x62\x0C\x01\x63\x00\x00' |
| a = core.UTF8String.load(data) |
| self.assertEqual('abc', a.native) |
| self.assertEqual('abc', a.__unicode__()) |
| self.assertEqual(1, a.method) |
| # Ensure a forced re-encoding is proper DER |
| self.assertEqual(b'\x0C\x03\x61\x62\x63', a.dump(force=True)) |
| # Test copying moves internal state |
| self.assertEqual(a._unicode, a.copy()._unicode) |
| |
| def test_indefinite_length_bit_string(self): |
| data = b'#\x80\x03\x02\x00\x01\x03\x02\x02\x04\x00\x00' |
| a = core.BitString.load(data) |
| self.assertEqual((0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1), a.native) |
| self.assertEqual((0, 0), a.unused_bits) |
| |
| # Example from X.690 §8.6.4.2 |
| prim = core.BitString.load(b'\x03\x07\x04\x0A\x3B\x5F\x29\x1C\xD0') |
| self.assertEqual((0, 0, 0, 0), prim.unused_bits) |
| indef = core.BitString.load(b'\x23\x80\x03\x03\x00\x0a\x3b\x03\x05\x04\x5f\x29\x1c\xd0\x00\x00') |
| self.assertEqual(prim.native, indef.native) |
| self.assertEqual(core._int_to_bit_tuple(0x0A3B5F291CD, 44), indef.native) |
| self.assertEqual((0, 0, 0, 0), indef.unused_bits) |
| |
| unused = core.BitString.load(b'\x23\x80\x03\x03\x00\x0a\x3b\x03\x05\x04\x5f\x29\x1c\xdd\x00\x00') |
| self.assertEqual(indef.native, unused.native) |
| self.assertEqual((1, 1, 0, 1), unused.unused_bits) |
| |
| unused.set(indef.native) |
| self.assertEqual(indef.native, unused.native) |
| self.assertEqual((0, 0, 0, 0), unused.unused_bits) |
| |
| def test_integer_bit_string(self): |
| a = core.IntegerBitString.load(b'\x03\x02\x04\xcb') |
| self.assertEqual(12, a.native) |
| self.assertEqual((1, 0, 1, 1), a.unused_bits) |
| |
| b = a.copy() |
| self.assertEqual(12, b.native) |
| self.assertEqual((1, 0, 1, 1), b.unused_bits) |
| |
| a.set(56) |
| self.assertEqual((), a.unused_bits) |
| self.assertEqual(56, a.native) |
| self.assertEqual(b'\x03\x02\x00\x38', a.dump()) |
| |
| with self.assertRaises(TypeError): |
| a.set('badtype') |
| |
| with self.assertRaises(ValueError): |
| core.IntegerBitString(-1) |
| |
| def test_indefinite_length_integer_bit_string(self): |
| data = b'#\x80\x03\x02\x00\x01\x03\x02\x00\x04\x00\x00' |
| a = core.IntegerBitString.load(data) |
| self.assertEqual(260, a.native) |
| self.assertEqual((), a.unused_bits) |
| |
| a = core.IntegerBitString.load(b'\x23\x80\x00\x00') |
| self.assertEqual(0, a.native) |
| self.assertEqual((), a.unused_bits) |
| |
| a = core.IntegerBitString.load(b'\x23\x80\x03\x01\x00\x03\x03\x03\x03\x03\x00\x00') |
| self.assertEqual(96, a.native) |
| self.assertEqual((0, 1, 1), a.unused_bits) |
| |
| a.set(56) |
| self.assertEqual((), a.unused_bits) |
| self.assertEqual(56, a.native) |
| self.assertEqual(b'\x03\x02\x00\x38', a.dump()) |
| |
| @data('bit_string_error_values') |
| def integer_bit_string_errors(self, enc_bytes): |
| with self.assertRaises(ValueError): |
| core.IntegerBitString.load(enc_bytes).native |
| |
| def test_octet_bit_string(self): |
| a = core.OctetBitString.load(b'\x03\x02\x04\xcb') |
| self.assertEqual(b'\xc0', a.native) |
| self.assertEqual((1, 0, 1, 1), a.unused_bits) |
| |
| a.set(b'\x38') |
| self.assertEqual((), a.unused_bits) |
| self.assertEqual(b'\x38', a.native) |
| self.assertEqual(b'\x03\x02\x00\x38', a.dump()) |
| |
| with self.assertRaises(TypeError): |
| a.set('badtype') |
| |
| def test_indefinite_length_octet_bit_string(self): |
| data = b'#\x80\x03\x02\x00\x01\x03\x02\x00\x04\x00\x00' |
| a = core.OctetBitString.load(data) |
| self.assertEqual(b'\x01\x04', a.native) |
| self.assertEqual(b'\x01\x04', a.__bytes__()) |
| # Test copying moves internal state |
| self.assertEqual(a._bytes, a.copy()._bytes) |
| |
| # octet bit string with unused bits |
| a = core.OctetBitString.load(b'\x23\x80\x03\x05\x05\x74\x65\x73\x74\x00\x00') |
| self.assertEqual(b'\x74\x65\x73\x60', a.native) |
| self.assertEqual((1, 0, 1, 0, 0), a.unused_bits) |
| |
| a.set(b'\x38') |
| self.assertEqual((), a.unused_bits) |
| self.assertEqual(b'\x38', a.native) |
| self.assertEqual(b'\x03\x02\x00\x38', a.dump()) |
| |
| @data('bit_string_error_values') |
| def octet_bit_string_errors(self, enc_bytes): |
| with self.assertRaises(ValueError): |
| core.OctetBitString.load(enc_bytes).native |
| |
| def test_indefinite_length_parsable_octet_bit_string(self): |
| data = b'#\x80\x03\x03\x00\x0C\x02\x03\x03\x00\x61\x62\x00\x00' |
| a = core.ParsableOctetBitString.load(data) |
| self.assertEqual(b'\x0C\x02\x61\x62', a.parsed.dump()) |
| self.assertEqual(b'\x0C\x02\x61\x62', a.__bytes__()) |
| self.assertEqual('ab', a.parsed.native) |
| self.assertEqual('ab', a.native) |
| # Test copying moves internal state |
| self.assertEqual(a._bytes, a.copy()._bytes) |
| self.assertEqual(a._parsed, a.copy()._parsed) |
| |
| with self.assertRaises(ValueError): |
| # parsable octet bit string with unused bits |
| core.ParsableOctetBitString.load(b'\x23\x80\x03\x03\x04\x02\x00\x03\x03\x04\x12\xa0\x00\x00').native |
| |
| def test_integer_octet_string(self): |
| v = core.IntegerOctetString(10) |
| self.assertEqual(10, v.native) |
| |
| with self.assertRaises(TypeError): |
| core.IntegerOctetString('0') |
| |
| with self.assertRaises(ValueError): |
| core.IntegerOctetString(-1) |
| |
| def test_explicit_application_tag(self): |
| data = b'\x6a\x81\x03\x02\x01\x00' |
| ati = ApplicationTaggedInteger.load(data) |
| |
| self.assertEqual(((1, 10),), ati.explicit) |
| self.assertEqual(0, ati.class_) |
| self.assertEqual(2, ati.tag) |
| self.assertEqual(0, ati.native) |
| |
| # The output encoding is DER, whereas the input was not, so |
| # the length encoding changes from long form to short form |
| self.assertEqual(b'\x6a\x03\x02\x01\x00', ati.dump(force=True)) |
| |
| def test_required_field(self): |
| with self.assertRaisesRegex(ValueError, '"id" is missing from structure'): |
| Seq({'value': core.Integer(5)}).dump() |
| |
| def test_explicit_application_tag_nested(self): |
| # tag = [APPLICATION 10] constructed; length = 18 |
| # OUTER SEQUENCE: tag = [UNIVERSAL 16] constructed; length = 16 |
| # outernumber : tag = [11] constructed; length = 3 |
| # INTEGER: tag = [UNIVERSAL 2] primitive; length = 1 |
| # 23 |
| # inner : tag = [12] constructed; length = 9 |
| # tag = [APPLICATION 20] constructed; length = 7 |
| # INNER SEQUENCE: tag = [UNIVERSAL 16] constructed; length = 5 |
| # innernumber : tag = [21] constructed; length = 3 |
| # INTEGER: tag = [UNIVERSAL 2] primitive; length = 1 |
| # 42 |
| der = ( |
| b'\x6A\x12\x30\x10\xAB\x03\x02\x01\x17\xAC\x09\x74' |
| b'\x07\x30\x05\xB5\x03\x02\x01\x2A' |
| ) |
| |
| ato = ApplicationTaggedOuter.load(der) |
| self.assertEqual(((1, 10),), ato.explicit) |
| self.assertEqual(0, ato.class_) |
| self.assertEqual(16, ato.tag) |
| self.assertEqual(1, ato.method) |
| |
| onum = ato['outernumber'] |
| self.assertEqual(((2, 11),), onum.explicit) |
| self.assertEqual(0, onum.class_) |
| self.assertEqual(2, onum.tag) |
| self.assertEqual(0, onum.method) |
| self.assertEqual(23, onum.native) |
| |
| ati = ato['inner'] |
| self.assertEqual(((1, 20), (2, 12)), ati.explicit) |
| self.assertEqual(0, ati.class_) |
| self.assertEqual(16, ati.tag) |
| self.assertEqual(util.OrderedDict([('innernumber', 42)]), ati.native) |
| |
| inum = ati['innernumber'] |
| self.assertEqual(((2, 21),), inum.explicit) |
| self.assertEqual(0, inum.class_) |
| self.assertEqual(2, inum.tag) |
| self.assertEqual(0, inum.method) |
| self.assertEqual(42, inum.native) |
| |
| self.assertEqual(der, ato.dump(force=True)) |
| |
| def test_sequence_choice_field_by_tuple(self): |
| val = ExplicitField({'field': ('one', 32)}) |
| self.assertEqual('one', val['field'].name) |
| self.assertEqual(32, val['field'].chosen.native) |
| |
| def test_sequence_choice_field_by_dict(self): |
| val = ExplicitField({'field': {'two': 32}}) |
| self.assertEqual('two', val['field'].name) |
| self.assertEqual(32, val['field'].chosen.native) |
| |
| def test_nested_explicit_tag_choice(self): |
| # Explicitly tagged values have a _header that contains |
| # the explicit tag and the header for the contained value. |
| # When parsing nested Choice values, it is necessary to not pull |
| # up the next Choice value's header, since Choice values |
| # themselves don't have their own header and it will result in |
| # duplication. |
| data = b'\x30\x09\x03\x01\x00\xa0\x04\xa2\x02\x80\x00' |
| image_data = SpcPeImageData.load(data, strict=True) |
| self.assertEqual(data[2:5], image_data['flags'].dump()) |
| self.assertEqual(data[5:11], image_data['file'].dump()) |
| self.assertEqual(data[5:7], image_data['file']._header) |
| self.assertEqual(data[7:11], image_data['file'].chosen.dump()) |
| self.assertEqual(data[7:9], image_data['file'].chosen._header) |
| self.assertEqual(data[9:11], image_data['file'].chosen.chosen.dump()) |
| self.assertEqual(data[9:11], image_data['file'].chosen.chosen._header) |
| |
| image_data2 = SpcPeImageData.load(data, strict=True) |
| self.assertEqual(data[2:5], image_data2['flags'].dump(True)) |
| self.assertEqual(data[5:11], image_data2['file'].dump(True)) |
| self.assertEqual(data[5:7], image_data2['file']._header) |
| self.assertEqual(data[7:11], image_data2['file'].chosen.dump(True)) |
| self.assertEqual(data[7:9], image_data2['file'].chosen._header) |
| self.assertEqual(data[9:11], image_data2['file'].chosen.chosen.dump(True)) |
| self.assertEqual(data[9:11], image_data2['file'].chosen.chosen._header) |
| |
| def test_choice_dump_header_native(self): |
| s = SpcString({'unicode': 'test'}) |
| self.assertEqual(b'\x80\x08\x00t\x00e\x00s\x00t', s.dump()) |
| self.assertEqual(b'', s._header) |
| self.assertEqual('test', s.native) |
| self.assertEqual(b'\x80\x08', s.chosen._header) |
| self.assertEqual('test', s.chosen.native) |
| |
| link = SpcLink('file', {'unicode': 'test'}) |
| self.assertEqual(b'\xa2\x0a\x80\x08\x00t\x00e\x00s\x00t', link.dump()) |
| self.assertEqual(b'', link._header) |
| self.assertEqual('test', link.native) |
| self.assertEqual(b'\xa2\x0a', link.chosen._header) |
| self.assertEqual('test', link.chosen.native) |
| self.assertEqual(b'\x80\x08', link.chosen.chosen._header) |
| self.assertEqual('test', link.chosen.chosen.native) |
| |
| def test_parse_broken_sequence_fields_repeatedly(self): |
| s = Seq.load(b'\x30\x06\x88\x00\x00\x00\x00\x00') |
| with self.assertRaises(ValueError): |
| s.native |
| with self.assertRaises(ValueError): |
| s.native |
| |
| def test_parse_broken_sequenceof_children_repeatedly(self): |
| s = SequenceOfInts.load(b'\x30\x06\x88\x00\x00\x00\x00\x00') |
| with self.assertRaises(ValueError): |
| s.native |
| with self.assertRaises(ValueError): |
| s.native |
| |
| def test_wrong_asn1value(self): |
| with self.assertRaises(TypeError): |
| Seq({ |
| 'id': core.Integer(1), |
| 'value': 1 |
| }) |
| |
| def test_wrong_asn1value2(self): |
| with self.assertRaises(TypeError): |
| CopySeq({ |
| 'name': core.UTF8String('Test'), |
| 'pair': core.Integer(1) |
| }) |
| |
| def test_wrong_asn1value3(self): |
| with self.assertRaises(TypeError): |
| NestSeqAny({ |
| 'id': '3.4.5', |
| 'value': core.Integer(1) |
| }) |
| |
| def test_wrong_asn1value4(self): |
| with self.assertRaises(TypeError): |
| NestSeqExplicit({ |
| 'id': '3.4.5', |
| 'value': core.Integer(1) |
| }) |
| |
| def test_integer_octet_string_encoded_width(self): |
| a = core.IntegerOctetString(1) |
| self.assertEqual(1, a.native) |
| self.assertEqual(b'\x04\x01\x01', a.dump()) |
| |
| b = core.IntegerOctetString(1) |
| b.set_encoded_width(4) |
| self.assertEqual(1, b.native) |
| self.assertEqual(b'\x04\x04\x00\x00\x00\x01', b.dump()) |