• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# coding: utf-8
2from __future__ import unicode_literals, division, absolute_import, print_function
3
4import unittest
5import os
6from datetime import datetime, timedelta
7
8from asn1crypto import core, util
9
10from .unittest_data import data_decorator, data
11from ._unittest_compat import patch
12
13patch()
14
15tests_root = os.path.dirname(__file__)
16fixtures_dir = os.path.join(tests_root, 'fixtures')
17
18
19class NamedBits(core.BitString):
20    _map = {
21        0: 'zero',
22        1: 'one',
23        2: 'two',
24        3: 'three',
25        4: 'four',
26        6: 'six',
27        7: 'seven',
28    }
29
30
31class SequenceOfInts(core.SequenceOf):
32    _child_spec = core.Integer
33
34
35class SequenceAny(core.SequenceOf):
36    _child_spec = core.Any
37
38
39class Seq(core.Sequence):
40    _fields = [
41        ('id', core.ObjectIdentifier),
42        ('value', core.Any),
43    ]
44
45    _oid_pair = ('id', 'value')
46    _oid_specs = {
47        '1.2.3': core.Integer,
48        '2.3.4': core.OctetString,
49    }
50
51
52class CopySeq(core.Sequence):
53    _fields = [
54        ('name', core.UTF8String),
55        ('pair', Seq),
56    ]
57
58
59class NestSeqAny(core.Sequence):
60    _fields = [
61        ('id', core.ObjectIdentifier),
62        ('value', core.Any),
63    ]
64
65    _oid_pair = ('id', 'value')
66    _oid_specs = {
67        '2.3.4.5': Seq,
68    }
69
70
71class NestSeqExplicit(core.Sequence):
72    _fields = [
73        ('id', core.ObjectIdentifier),
74        ('value', NamedBits),
75    ]
76
77    _oid_pair = ('id', 'value')
78    _oid_specs = {
79        '2.3.4.5': Seq,
80    }
81
82
83class Enum(core.Enumerated):
84    _map = {
85        0: 'a',
86        1: 'b',
87    }
88
89
90class ExplicitFieldDefault(core.Sequence):
91    _fields = [
92        ('bits', NamedBits),
93        ('seq', Seq, {'explicit': 2, 'default': {'id': '1.2.3', 'value': 10}}),
94    ]
95
96
97class NumChoice(core.Choice):
98    _alternatives = [
99        ('one', core.Integer, {'explicit': 0}),
100        ('two', core.Integer, {'implicit': 1}),
101        ('three', core.Integer, {'explicit': 2}),
102    ]
103
104
105class NumChoiceOldApi(core.Choice):
106    _alternatives = [
107        ('one', core.Integer, {'tag_type': 'explicit', 'tag': 0}),
108        ('two', core.Integer, {'tag_type': 'implicit', 'tag': 1}),
109        ('three', core.Integer, {'tag_type': 'explicit', 'tag': 2}),
110    ]
111
112
113class SeqChoice(core.Choice):
114    _alternatives = [
115        ('one', CopySeq, {'explicit': 0}),
116        ('two', CopySeq, {'implicit': 1}),
117    ]
118
119
120class SeqChoiceOldApi(core.Choice):
121    _alternatives = [
122        ('one', CopySeq, {'tag_type': 'explicit', 'tag': 0}),
123        ('two', CopySeq, {'tag_type': 'implicit', 'tag': 1}),
124    ]
125
126
127class ChoiceChoice(core.Choice):
128    _alternatives = [
129        ('num', NumChoice, {'explicit': 0}),
130        ('seq', SeqChoice, {'explicit': 1}),
131    ]
132
133
134class CCSeq(core.Sequence):
135    _fields = [
136        ('cc', ChoiceChoice)
137    ]
138
139
140class ExplicitField(core.Sequence):
141    _fields = [
142        ('field', NumChoice, {'tag_type': 'explicit', 'tag': 0}),
143    ]
144
145
146class ExplicitFieldOldApi(core.Sequence):
147    _fields = [
148        ('field', NumChoiceOldApi, {'explicit': 0}),
149    ]
150
151
152class SetTest(core.Set):
153    _fields = [
154        ('two', core.Integer, {'tag_type': 'implicit', 'tag': 2}),
155        ('one', core.Integer, {'tag_type': 'implicit', 'tag': 1}),
156    ]
157
158
159class SetTestOldApi(core.Set):
160    _fields = [
161        ('two', core.Integer, {'implicit': 2}),
162        ('one', core.Integer, {'implicit': 1}),
163    ]
164
165
166class SetOfTest(core.SetOf):
167    _child_spec = core.Integer
168
169
170class ConcatTest(core.Concat):
171    _child_specs = [Seq, core.Integer]
172
173
174class IntegerConcats(core.Concat):
175    _child_specs = [core.Integer, core.Integer]
176
177
178class MyOids(core.ObjectIdentifier):
179    _map = {
180        '1.2.3': 'abc',
181        '4.5.6': 'def',
182    }
183
184
185class ApplicationTaggedInteger(core.Integer):
186    # This class attribute may be a 2-element tuple of integers,
187    # or a tuple of 2-element tuple of integers. The first form
188    # will be converted to the second form the first time an
189    # object of this type is constructed.
190    explicit = ((1, 10), )
191
192
193class ApplicationTaggedInner(core.Sequence):
194    """
195    TESTCASE DEFINITIONS EXPLICIT TAGS ::=
196    BEGIN
197
198    INNERSEQ ::= SEQUENCE {
199        innernumber       [21] INTEGER
200    }
201
202    INNER ::= [APPLICATION 20] INNERSEQ
203    """
204
205    explicit = (1, 20)
206
207    _fields = [
208        ('innernumber', core.Integer, {'explicit': 21}),
209    ]
210
211
212class ApplicationTaggedOuter(core.Sequence):
213    """
214    OUTERSEQ ::= SEQUENCE {
215        outernumber  [11] INTEGER,
216        inner        [12] INNER
217    }
218
219    OUTER ::= [APPLICATION 10] OUTERSEQ
220    END
221    """
222
223    explicit = (1, 10)
224
225    _fields = [
226        ('outernumber', core.Integer, {'explicit': 11}),
227        ('inner', ApplicationTaggedInner, {'explicit': 12}),
228    ]
229
230
231class SpcPeImageFlags(core.BitString):
232    _map = {
233        0: "includeResources",
234        1: "includeDebugInfo",
235        2: "includeImportAddressTable",
236    }
237
238
239class SpcSerializedObject(core.Sequence):
240    _fields = [
241        ("classId", core.OctetString),
242        ("serializedData", core.OctetString),
243    ]
244
245
246class SpcString(core.Choice):
247    _alternatives = [
248        ("unicode", core.BMPString, {"implicit": 0}),
249        ("ascii", core.IA5String, {"implicit": 1}),
250    ]
251
252
253class SpcLink(core.Choice):
254    _alternatives = [
255        ("url", core.IA5String, {"implicit": 0}),
256        ("moniker", SpcSerializedObject, {"implicit": 1}),
257        ("file", SpcString, {"explicit": 2})
258    ]
259
260
261class SpcPeImageData(core.Sequence):
262    _fields = [
263        ("flags", SpcPeImageFlags, {"default": "includeResources"}),
264        ("file", SpcLink, {"explicit": 0})
265    ]
266
267
268class UTF8Sequence(core.Sequence):
269    _fields = [
270        ("string", core.UTF8String)
271    ]
272
273
274class NestedUTF8Sequence(core.Sequence):
275    _fields = [
276        ("seq", UTF8Sequence)
277    ]
278
279
280@data_decorator
281class CoreTests(unittest.TestCase):
282
283    def test_large_tag_encode(self):
284        # https://misc.daniel-marschall.de/asn.1/oid_facts.html
285        v = core.Primitive(tag=31, contents=b'')
286        self.assertEqual(b'\x1f\x1f\x00', v.dump())
287
288        v = core.Primitive(tag=36, contents=b'')
289        self.assertEqual(b'\x1f\x24\x00', v.dump())
290
291        # One extra byte
292        v = core.Primitive(
293            class_="application",
294            method="constructed",
295            tag=73,
296            contents=b''
297        )
298        self.assertEqual(b'\x7f\x49\x00', v.dump())
299
300        # Two extra bytes
301        v = core.Primitive(
302            class_="application",
303            method="constructed",
304            tag=201,
305            contents=b''
306        )
307        self.assertEqual(b'\x7f\x81\x49\x00', v.dump())
308
309        # Three extra bytes
310        v = core.Primitive(
311            class_="application",
312            method="constructed",
313            tag=16384,
314            contents=b''
315        )
316        self.assertEqual(b'\x7f\x81\x80\x00\x00', v.dump())
317
318    def test_manual_construction(self):
319        v = core.Asn1Value(
320            class_="application",
321            method="constructed",
322            tag=1,
323            contents=b''
324        )
325        self.assertEqual(b'\x61\x00', v.dump())
326
327    def test_sequence_spec(self):
328        seq = Seq()
329        seq['id'] = '1.2.3'
330        self.assertEqual(core.Integer, seq.spec('value'))
331        seq['id'] = '2.3.4'
332        self.assertEqual(core.OctetString, seq.spec('value'))
333
334    def test_sequence_of_spec(self):
335        seq = SequenceAny()
336        self.assertEqual(core.Any, seq.spec())
337
338    @staticmethod
339    def compare_primitive_info():
340        return (
341            (core.ObjectIdentifier('1.2.3'), core.ObjectIdentifier('1.2.3'), True),
342            (core.Integer(1), Enum(1), False),
343            (core.Integer(1), core.Integer(1, implicit=5), True),
344            (core.Integer(1), core.Integer(1, explicit=5), True),
345            (core.Integer(1), core.Integer(2), False),
346            (core.OctetString(b''), core.OctetString(b''), True),
347            (core.OctetString(b''), core.OctetString(b'1'), False),
348            (core.OctetString(b''), core.OctetBitString(b''), False),
349            (core.ParsableOctetString(b'12'), core.OctetString(b'12'), True),
350            (core.ParsableOctetBitString(b'12'), core.OctetBitString(b'12'), True),
351            (core.UTF8String('12'), core.UTF8String('12'), True),
352            (core.UTF8String('12'), core.UTF8String('1'), False),
353            (core.UTF8String('12'), core.IA5String('12'), False),
354        )
355
356    @data('compare_primitive_info')
357    def compare_primitive(self, one, two, equal):
358        if equal:
359            self.assertEqual(one, two)
360        else:
361            self.assertNotEqual(one, two)
362
363    @staticmethod
364    def integer_info():
365        return (
366            (0, b'\x02\x01\x00'),
367            (255, b'\x02\x02\x00\xFF'),
368            (128, b'\x02\x02\x00\x80'),
369            (127, b'\x02\x01\x7F'),
370            (-127, b'\x02\x01\x81'),
371            (-127, b'\x02\x01\x81'),
372            (32768, b'\x02\x03\x00\x80\x00'),
373            (-32768, b'\x02\x02\x80\x00'),
374            (-32769, b'\x02\x03\xFF\x7F\xFF'),
375        )
376
377    @data('integer_info')
378    def integer(self, native, der_bytes):
379        i = core.Integer(native)
380        self.assertEqual(der_bytes, i.dump())
381        self.assertEqual(native, core.Integer.load(der_bytes).native)
382
383    @staticmethod
384    def utctime_info():
385        return (
386            (datetime(2030, 12, 31, 8, 30, 0, tzinfo=util.timezone.utc), b'\x17\x0D301231083000Z'),
387            (datetime(2049, 12, 31, 8, 30, 0, tzinfo=util.timezone.utc), b'\x17\x0D491231083000Z'),
388            (datetime(1950, 12, 31, 8, 30, 0, tzinfo=util.timezone.utc), b'\x17\x0D501231083000Z'),
389            (datetime(2018, 10, 20, 7, 35, 4, tzinfo=util.timezone(timedelta(hours=7, minutes=40))),
390             b'\x17\x0D181019235504Z'),
391        )
392
393    @data('utctime_info')
394    def utctime(self, native, der_bytes):
395        u = core.UTCTime(native)
396        self.assertEqual(der_bytes, u.dump())
397        self.assertEqual(native, core.UTCTime.load(der_bytes).native)
398
399    def test_utctime_errors(self):
400        with self.assertRaises(ValueError):
401            # is not aware
402            core.UTCTime(datetime.fromtimestamp(1234567890))
403
404        with self.assertRaises(ValueError):
405            # Is pre 1950
406            core.UTCTime(datetime(1910, 6, 22, 11, 33, 44, tzinfo=util.timezone.utc))
407
408        with self.assertRaises(ValueError):
409            # Is past 2050
410            core.UTCTime(datetime(2106, 2, 7, 6, 28, 16, tzinfo=util.timezone.utc))
411
412    def test_utctime_copy(self):
413        a = core.UTCTime(datetime(2019, 11, 11, 17, 45, 18, tzinfo=util.timezone.utc))
414        # Ensure _native is set because we want to test copy on the nested timezone object.
415        a.native
416        b = a.copy()
417        self.assertEqual(a.native, b.native)
418        self.assertEqual(a.contents, b.contents)
419        self.assertEqual(a.dump(), b.dump())
420
421    @staticmethod
422    def generalized_time_info():
423        def tz(hours, minutes=0):
424            return util.create_timezone(timedelta(hours=hours, minutes=minutes))
425
426        return (
427            (b'\x18\x1520180405062426.0+0200', datetime(2018, 4, 5, 6, 24, 26, 0, tz(2)), b'\x18\x0f20180405042426Z'),
428            (b'\x18\x0f2018062419-1355', datetime(2018, 6, 24, 19, 0, 0, 0, tz(-13, -55)), b'\x18\x0f20180625085500Z'),
429            (b'\x18\x0d2018062419-13', datetime(2018, 6, 24, 19, 0, 0, 0, tz(-13)), b'\x18\x0f20180625080000Z'),
430            (b'\x18\x0b2018062419Z', datetime(2018, 6, 24, 19, 0, 0, 0, tz(0)), b'\x18\x0f20180624190000Z'),
431            (b'\x18\x122018062419.15+0345', datetime(2018, 6, 24, 19, 9, 0, 0, tz(3, 45)), b'\x18\x0f20180624152400Z'),
432            (
433                b'\x18\x13201806241957,433+02',
434                datetime(2018, 6, 24, 19, 57, 25, 980000, tz(2)),
435                b'\x18\x1220180624175725.98Z',
436            ),
437            (
438                b'\x18\x1620180624195724.215999Z',
439                datetime(2018, 6, 24, 19, 57, 24, 215999, tz(0)),
440                b'\x18\x1620180624195724.215999Z',
441            ),
442            (
443                b'\x18\x150000022910.31337-0815',
444                util.extended_datetime(0, 2, 29, 10, 18, 48, 132000, tz(-8, -15)),
445                b'\x18\x1300000229183348.132Z',
446            ),
447            (b'\x18\x1520180624195724.215999', datetime(2018, 6, 24, 19, 57, 24, 215999), None),
448            (b'\x18\x0a2018062419', datetime(2018, 6, 24, 19, 0, 0, 0), None),
449        )
450
451    @data('generalized_time_info')
452    def generalized_time(self, ber_bytes, native, der_bytes):
453        decoded = core.GeneralizedTime.load(ber_bytes)
454
455        self.assertEqual(decoded.native, native)
456        self.assertEqual(decoded.native.tzinfo, native.tzinfo)
457
458        if der_bytes is not None:
459            encoded = core.GeneralizedTime(native).dump()
460            self.assertEqual(encoded, der_bytes)
461
462            decoded2 = core.GeneralizedTime.load(encoded)
463            self.assertEqual(decoded2.native, native)
464        else:
465            with self.assertRaises(ValueError):
466                encoded = core.GeneralizedTime(native).dump()
467
468    @staticmethod
469    def type_info():
470        return (
471            ('universal/object_identifier.der', core.ObjectIdentifier, '1.2.840.113549.1.1.1'),
472        )
473
474    @data('type_info')
475    def parse_universal_type(self, input_filename, type_class, native):
476        with open(os.path.join(fixtures_dir, input_filename), 'rb') as f:
477            der = f.read()
478            parsed = type_class.load(der)
479
480        self.assertEqual(native, parsed.native)
481        self.assertEqual(der, parsed.dump(force=True))
482
483    def test_int_to_bit_tuple(self):
484        self.assertEqual((), core._int_to_bit_tuple(0, 0))
485        self.assertEqual((0,), core._int_to_bit_tuple(0, 1))
486        self.assertEqual((1,), core._int_to_bit_tuple(1, 1))
487        self.assertEqual((0, 0), core._int_to_bit_tuple(0, 2))
488        self.assertEqual((0, 1), core._int_to_bit_tuple(1, 2))
489        self.assertEqual((0, 0, 1), core._int_to_bit_tuple(1, 3))
490        self.assertEqual((0, 1, 0), core._int_to_bit_tuple(2, 3))
491        self.assertEqual((1, 0, 1), core._int_to_bit_tuple(5, 3))
492
493        with self.assertRaises(ValueError):
494            core._int_to_bit_tuple(9, 3)
495        with self.assertRaises(ValueError):
496            core._int_to_bit_tuple(-9, 5)
497
498    @staticmethod
499    def bit_string_info():
500        return (
501            ((0, 1, 1), b'\x03\x02\x05\x60'),
502            ((0, 1, 1, 0, 0, 0, 0, 0), b'\x03\x02\x00\x60'),
503            ((0, 0, 0, 0, 0, 0, 0, 0), b'\x03\x02\x00\x00'),
504            ((0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1), b'\x03\x03\x00\x00\x01'),
505        )
506
507    @data('bit_string_info')
508    def bit_string(self, native, der_bytes):
509        bs = core.BitString(native)
510        self.assertEqual(der_bytes, bs.dump())
511        self.assertEqual(native, core.BitString.load(der_bytes).native)
512
513    def test_bit_string_load_dump(self):
514        bs = core.BitString.load(b'\x03\x01\x00')
515        self.assertEqual(tuple(), bs.native)
516        self.assertEqual(b'\x03\x01\x00', bs.dump(True))
517
518    @staticmethod
519    def bit_string_error_values():
520        return (
521            # unused bits in empty bit string
522            (b'\x03\x01\x05',),
523            # too many unused bits
524            (b'\x03\x03\x0e\x0c\x00',),
525            # chunk with unused bits is not last chunk
526            (b'\x23\x80\x03\x02\x01\xfe\x03\x02\x00\x55\x00\x00',),
527        )
528
529    @data('bit_string_error_values')
530    def bit_string_errors(self, enc_bytes):
531        with self.assertRaises(ValueError):
532            core.BitString.load(enc_bytes).native
533
534    def test_cast(self):
535        a = core.OctetBitString(b'\x00\x01\x02\x03')
536        self.assertEqual(b'\x00\x01\x02\x03', a.native)
537        b = a.cast(core.BitString)
538        self.assertIsInstance(b, core.BitString)
539        self.assertEqual(
540            (
541                0, 0, 0, 0, 0, 0, 0, 0,
542                0, 0, 0, 0, 0, 0, 0, 1,
543                0, 0, 0, 0, 0, 0, 1, 0,
544                0, 0, 0, 0, 0, 0, 1, 1
545            ),
546            b.native
547        )
548        c = a.cast(core.IntegerBitString)
549        self.assertIsInstance(c, core.IntegerBitString)
550        self.assertEqual(66051, c.native)
551
552    def test_load(self):
553        i = core.load(b'\x02\x01\x00')
554        self.assertIsInstance(i, core.Integer)
555        self.assertEqual(0, i.native)
556
557    def test_load_wrong_type(self):
558        with self.assertRaises(TypeError):
559            core.load('\x02\x01\x00')
560
561    @staticmethod
562    def truncated_der_byte_strings():
563        return (
564            (b'',),
565            (b'\x30',),
566            (b'\x30\x03\x02\x00\x02',),
567        )
568
569    @data('truncated_der_byte_strings')
570    def truncated(self, der_bytes):
571        with self.assertRaises(ValueError):
572            core.load(der_bytes).native
573
574    def test_strict(self):
575        with self.assertRaises(ValueError):
576            core.load(b'\x02\x01\x00\x00', strict=True)
577
578    def test_strict_on_class(self):
579        with self.assertRaises(ValueError):
580            core.Integer.load(b'\x02\x01\x00\x00', strict=True)
581
582    def test_strict_concat(self):
583        with self.assertRaises(ValueError):
584            IntegerConcats.load(b'\x02\x01\x00\x02\x01\x00\x00', strict=True)
585
586    def test_strict_choice(self):
587        with self.assertRaises(ValueError):
588            NumChoice.load(b'\xA0\x03\x02\x01\x00\x00', strict=True)
589        with self.assertRaises(ValueError):
590            NumChoiceOldApi.load(b'\xA0\x03\x02\x01\x00\x00', strict=True)
591
592    def test_choice_parse_return(self):
593        nc = NumChoice.load(b'\xA0\x03\x02\x01\x00\x00')
594        nc._parsed = None
595        self.assertEqual(0, nc.parse().native)
596
597    def test_sequece_choice_choice(self):
598        CCSeq({
599            'cc': ChoiceChoice(
600                'num',
601                NumChoice('one', core.Integer(0))
602            )
603        })
604
605    def test_bit_string_item_access(self):
606        named = core.BitString()
607        named[0] = True
608        self.assertEqual(False, named[2])
609        self.assertEqual(False, named[1])
610        self.assertEqual(True, named[0])
611
612    @staticmethod
613    def mapped_bit_string_info():
614        return (
615            (
616                (0, 1, 1),
617                b'\x03\x02\x05\x60',
618                set(['one', 'two'])
619            ),
620            (
621                (0,),
622                b'\x03\x01\x00',
623                set()
624            ),
625            (
626                set(['one', 'two']),
627                b'\x03\x02\x05\x60',
628                set(['one', 'two'])
629            )
630        )
631
632    @data('mapped_bit_string_info')
633    def mapped_bit_string(self, input_native, der_bytes, native):
634        named = NamedBits(input_native)
635        self.assertEqual(der_bytes, named.dump())
636        self.assertEqual(native, NamedBits.load(der_bytes).native)
637
638    def test_mapped_bit_string_item_access(self):
639        named = NamedBits()
640        named['one'] = True
641        self.assertEqual(False, named['two'])
642        self.assertEqual(True, named['one'])
643        self.assertEqual(True, 'one' in named.native)
644
645    def test_mapped_bit_string_unset_bit(self):
646        named = NamedBits(set(['one', 'two']))
647        named['one'] = False
648        self.assertEqual(True, named['two'])
649        self.assertEqual(set(['two']), named.native)
650
651    def test_mapped_bit_string_sparse(self):
652        named = NamedBits((0, 0, 0, 0, 0, 1))
653        self.assertEqual(False, named['two'])
654        self.assertEqual(True, named[5])
655        self.assertEqual(True, 5 in named.native)
656
657    def test_mapped_bit_string_numeric(self):
658        named = NamedBits()
659        named[1] = True
660        self.assertEqual(True, named['one'])
661        self.assertEqual(set(['one']), named.native)
662
663    def test_get_sequence_value(self):
664        seq = SequenceOfInts([1, 2])
665        self.assertEqual(2, seq[1].native)
666
667    def test_replace_sequence_value(self):
668        seq = SequenceOfInts([1, 2])
669        self.assertEqual([1, 2], seq.native)
670        seq[0] = 5
671        self.assertEqual([5, 2], seq.native)
672
673    def test_add_to_end_sequence_value(self):
674        seq = SequenceOfInts([1, 2])
675        self.assertEqual([1, 2], seq.native)
676        seq[2] = 5
677        self.assertEqual([1, 2, 5], seq.native)
678        seq.append(6)
679        self.assertEqual([1, 2, 5, 6], seq.native)
680
681    def test_delete_sequence_value(self):
682        seq = SequenceOfInts([1, 2])
683        self.assertEqual([1, 2], seq.native)
684        del seq[0]
685        self.assertEqual([2], seq.native)
686
687    def test_sequence_any_asn1value(self):
688        seq = SequenceAny()
689        seq.append(core.Integer(5))
690        self.assertEqual([5], seq.native)
691
692    def test_sequence_any_native_value(self):
693        seq = SequenceAny()
694        with self.assertRaises(ValueError):
695            seq.append(5)
696
697    def test_copy(self):
698        a = core.Integer(200)
699        b = a.copy()
700        self.assertNotEqual(id(a), id(b))
701        self.assertEqual(a.contents, b.contents)
702        self.assertEqual(a.dump(), b.dump())
703
704    def test_copy_mutable(self):
705        a = CopySeq({'name': 'foo', 'pair': {'id': '1.2.3', 'value': 5}})
706        # Cache the native representation so it is copied during the copy operation
707        a.native
708        b = a.copy()
709        self.assertNotEqual(id(a), id(b))
710        self.assertNotEqual(id(a['pair']), id(b['pair']))
711        self.assertEqual(a.contents, b.contents)
712        self.assertEqual(a.dump(), b.dump())
713
714        self.assertEqual(a['pair']['value'].native, b['pair']['value'].native)
715        a['pair']['value'] = 6
716        self.assertNotEqual(a['pair']['value'].native, b['pair']['value'].native)
717
718        a.native['pair']['value'] = 6
719        self.assertNotEqual(a.native['pair']['value'], b.native['pair']['value'])
720
721        self.assertNotEqual(a.contents, b.contents)
722        self.assertNotEqual(a.dump(), b.dump())
723
724    def test_explicit_tag_header(self):
725        val = NumChoice.load(b'\xa0\x03\x02\x01\x00')
726        self.assertEqual(b'\xa0\x03\x02\x01', val.chosen._header)
727        self.assertEqual(b'\x00', val.chosen.contents)
728        val2 = NumChoiceOldApi.load(b'\xa0\x03\x02\x01\x00')
729        self.assertEqual(b'\xa0\x03\x02\x01', val2.chosen._header)
730        self.assertEqual(b'\x00', val2.chosen.contents)
731
732    def test_explicit_field_default(self):
733        val = ExplicitFieldDefault.load(b'\x30\x0f\x03\x02\x06@\xa2\x090\x07\x06\x02*\x03\x02\x01\x01')
734        self.assertEqual(set(['one']), val['bits'].native)
735        self.assertEqual(
736            util.OrderedDict([
737                ('id', '1.2.3'),
738                ('value', 1)
739            ]),
740            val['seq'].native
741        )
742
743    def test_explicit_header_field_choice(self):
744        der = b'\x30\x07\xa0\x05\xa0\x03\x02\x01\x00'
745        val = ExplicitField.load(der)
746        self.assertEqual(0, val['field'].chosen.native)
747        self.assertEqual(der, val.dump(force=True))
748
749        val2 = ExplicitFieldOldApi.load(der)
750        self.assertEqual(0, val2['field'].chosen.native)
751        self.assertEqual(der, val2.dump(force=True))
752
753    def test_retag(self):
754        a = core.Integer(200)
755        b = a.retag('explicit', 0)
756        self.assertNotEqual(id(a), id(b))
757        self.assertEqual(a.contents, b.contents)
758        self.assertNotEqual(a.dump(), b.dump())
759
760    def test_untag(self):
761        a = core.Integer(200, explicit=0)
762        b = a.untag()
763        self.assertNotEqual(id(a), id(b))
764        self.assertEqual(a.contents, b.contents)
765        self.assertNotEqual(a.dump(), b.dump())
766
767    def test_choice_dict_name(self):
768        a = CopySeq({'name': 'foo', 'pair': {'id': '1.2.3', 'value': 5}})
769        choice = SeqChoice({'one': a})
770        self.assertEqual('one', choice.name)
771
772        with self.assertRaises(ValueError):
773            SeqChoice({})
774
775        with self.assertRaises(ValueError):
776            SeqChoice({'one': a, 'two': a})
777
778        choice2 = SeqChoiceOldApi({'one': a})
779        self.assertEqual('one', choice2.name)
780
781        with self.assertRaises(ValueError):
782            SeqChoiceOldApi({})
783
784        with self.assertRaises(ValueError):
785            SeqChoiceOldApi({'one': a, 'two': a})
786
787    def test_choice_tuple_name(self):
788        a = CopySeq({'name': 'foo', 'pair': {'id': '1.2.3', 'value': 5}})
789        choice = SeqChoice(('one', a))
790        self.assertEqual('one', choice.name)
791
792        with self.assertRaises(ValueError):
793            SeqChoice(('one',))
794
795        with self.assertRaises(ValueError):
796            SeqChoice(('one', a, None))
797
798        choice2 = SeqChoiceOldApi(('one', a))
799        self.assertEqual('one', choice2.name)
800
801        with self.assertRaises(ValueError):
802            SeqChoiceOldApi(('one',))
803
804        with self.assertRaises(ValueError):
805            SeqChoiceOldApi(('one', a, None))
806
807    def test_load_invalid_choice(self):
808        with self.assertRaises(ValueError):
809            NumChoice.load(b'\x02\x01\x00')
810        with self.assertRaises(ValueError):
811            NumChoiceOldApi.load(b'\x02\x01\x00')
812
813    def test_fix_tagging_choice(self):
814        correct = core.Integer(200, explicit=2)
815        choice = NumChoice(
816            name='three',
817            value=core.Integer(200, explicit=1)
818        )
819        self.assertEqual(correct.dump(), choice.dump())
820        self.assertEqual(correct.explicit, choice.chosen.explicit)
821        choice2 = NumChoiceOldApi(
822            name='three',
823            value=core.Integer(200, explicit=1)
824        )
825        self.assertEqual(correct.dump(), choice2.dump())
826        self.assertEqual(correct.explicit, choice2.chosen.explicit)
827
828    def test_copy_choice_mutate(self):
829        a = CopySeq({'name': 'foo', 'pair': {'id': '1.2.3', 'value': 5}})
830        choice = SeqChoice(
831            name='one',
832            value=a
833        )
834        choice.dump()
835        choice_copy = choice.copy()
836        choice.chosen['name'] = 'bar'
837        self.assertNotEqual(choice.chosen['name'], choice_copy.chosen['name'])
838
839        choice2 = SeqChoiceOldApi(
840            name='one',
841            value=a
842        )
843        choice2.dump()
844        choice2_copy = choice2.copy()
845        choice2.chosen['name'] = 'bar'
846        self.assertNotEqual(choice2.chosen['name'], choice2_copy.chosen['name'])
847
848    def test_dump_ber_indefinite(self):
849        # A simple primitive type that is indefinite-length-encoded will be
850        # automatically re-encoded to DER encoding
851        data = b'\x2C\x80\x0C\x03foo\x00\x00'
852        v = core.UTF8String.load(data)
853        self.assertEqual(True, v._indefinite)
854        self.assertEqual('foo', v.native)
855        self.assertEqual(b'\x0C\x03foo', v.dump())
856
857        # In this case the indefinite length items are nested, and the
858        # top-level item is fixed-length, so it won't get automatically
859        # re-encoded
860        data = b'\x30\x0d\x30\x80\x2C\x80\x0C\x03foo\x00\x00\x00\x00'
861        v = NestedUTF8Sequence.load(data)
862        self.assertEqual(data, v.dump())
863
864        # Here both the top-level and the nested encoding will get fixed since
865        # the top-level being indefinitely triggers a full re-encoding
866        data = b'\x30\x80\x30\x09\x2C\x80\x0C\x03foo\x00\x00\x00\x00'
867        v = NestedUTF8Sequence.load(data)
868        self.assertEqual(b'\x30\x07\x30\x05\x0C\x03foo', v.dump())
869
870    def test_copy_indefinite(self):
871        v = core.BitString.load(b'\x23\x80\x03\x02\x00\x04\x00\x00')
872        self.assertEqual(True, v._indefinite)
873        v2 = v.copy()
874        self.assertEqual(0, v2.method)
875        self.assertEqual(3, v2.tag)
876        self.assertEqual(False, v2._indefinite)
877        self.assertEqual((0, 0, 0, 0, 0, 1, 0, 0), v2.native)
878        self.assertEqual(b'\x03\x02\x00\x04', v2.dump())
879
880        v = core.OctetBitString.load(b'\x23\x80\x03\x02\x00\x04\x00\x00')
881        self.assertEqual(True, v._indefinite)
882        v2 = v.copy()
883        self.assertEqual(0, v2.method)
884        self.assertEqual(3, v2.tag)
885        self.assertEqual(False, v2._indefinite)
886        self.assertEqual(b'\x04', v2.native)
887        self.assertEqual(b'\x03\x02\x00\x04', v2.dump())
888
889        v = core.ParsableOctetBitString.load(b'\x23\x80\x03\x04\x00\x02\x01\x04\x00\x00')
890        self.assertEqual(4, v.parsed.native)
891        self.assertEqual(True, v._indefinite)
892        v2 = v.copy()
893        self.assertEqual(0, v2.method)
894        self.assertEqual(3, v2.tag)
895        self.assertEqual(False, v2._indefinite)
896        self.assertEqual(4, v2.parsed.native)
897        self.assertEqual(b'\x03\x04\x00\x02\x01\x04', v2.dump())
898
899        v = core.IntegerBitString.load(b'\x23\x80\x03\x02\x00\x04\x00\x00')
900        self.assertEqual(True, v._indefinite)
901        v2 = v.copy()
902        self.assertEqual(0, v2.method)
903        self.assertEqual(3, v2.tag)
904        self.assertEqual(False, v2._indefinite)
905        self.assertEqual(4, v2.native)
906        self.assertEqual(b'\x03\x02\x00\x04', v2.dump())
907
908        v = core.OctetString.load(b'\x24\x80\x04\x03foo\x00\x00')
909        self.assertEqual(True, v._indefinite)
910        v2 = v.copy()
911        self.assertEqual(0, v2.method)
912        self.assertEqual(4, v2.tag)
913        self.assertEqual(False, v2._indefinite)
914        self.assertEqual(b'foo', v2.native)
915        self.assertEqual(b'\x04\x03foo', v2.dump())
916
917        v = core.IntegerOctetString.load(b'\x24\x80\x04\x01\x04\x00\x00')
918        self.assertEqual(True, v._indefinite)
919        v2 = v.copy()
920        self.assertEqual(0, v2.method)
921        self.assertEqual(4, v2.tag)
922        self.assertEqual(False, v2._indefinite)
923        self.assertEqual(4, v2.native)
924        self.assertEqual(b'\x04\x01\x04', v2.dump())
925
926        v = core.ParsableOctetString.load(b'\x24\x80\x04\x03\x02\x01\x04\x00\x00')
927        self.assertEqual(4, v.parsed.native)
928        self.assertEqual(True, v._indefinite)
929        v2 = v.copy()
930        self.assertEqual(0, v2.method)
931        self.assertEqual(4, v2.tag)
932        self.assertEqual(False, v2._indefinite)
933        self.assertEqual(4, v2.parsed.native)
934        self.assertEqual(b'\x02\x01\x04', v2.__bytes__())
935        self.assertEqual(b'\x04\x03\x02\x01\x04', v2.dump())
936
937        v = core.UTF8String.load(b'\x2C\x80\x0C\x03foo\x00\x00')
938        self.assertEqual(True, v._indefinite)
939        v2 = v.copy()
940        self.assertEqual(0, v2.method)
941        self.assertEqual(12, v2.tag)
942        self.assertEqual(False, v2._indefinite)
943        self.assertEqual('foo', v2.native)
944        self.assertEqual(b'\x0C\x03foo', v2.dump())
945
946    def test_concat(self):
947        child1 = Seq({
948            'id': '1.2.3',
949            'value': 1
950        })
951        child2 = core.Integer(0)
952        parent = ConcatTest([
953            child1,
954            child2
955        ])
956        self.assertEqual(child1, parent[0])
957        self.assertEqual(child2, parent[1])
958        self.assertEqual(child1.dump() + child2.dump(), parent.dump())
959
960    def test_oid_map_unmap(self):
961        self.assertEqual('abc', MyOids.map('1.2.3'))
962        self.assertEqual('def', MyOids.map('4.5.6'))
963        self.assertEqual('7.8.9', MyOids.map('7.8.9'))
964        self.assertEqual('1.2.3', MyOids.unmap('abc'))
965        self.assertEqual('4.5.6', MyOids.unmap('def'))
966        self.assertEqual('7.8.9', MyOids.unmap('7.8.9'))
967
968        with self.assertRaises(ValueError):
969            MyOids.unmap('no_such_mapping')
970
971    def test_oid_dotted_native(self):
972        self.assertEqual('abc', MyOids('1.2.3').native)
973        self.assertEqual('1.2.3', MyOids('1.2.3').dotted)
974        self.assertEqual('abc', MyOids('abc').native)
975        self.assertEqual('1.2.3', MyOids('abc').dotted)
976
977    def test_dump_set(self):
978        st = SetTest({'two': 2, 'one': 1})
979        self.assertEqual(b'1\x06\x81\x01\x01\x82\x01\x02', st.dump())
980
981    def test_dump_set_of(self):
982        st = SetOfTest([3, 2, 1])
983        self.assertEqual(b'1\x09\x02\x01\x01\x02\x01\x02\x02\x01\x03', st.dump())
984
985    def test_indefinite_length_octet_string(self):
986        data = b'$\x80\x04\x02\x01\x01\x04\x01\x01\x00\x00'
987        a = core.OctetString.load(data)
988        self.assertEqual(b'\x01\x01\x01', a.native)
989        self.assertEqual(b'\x01\x01\x01', a.__bytes__())
990        self.assertEqual(1, a.method)
991        # Test copying moves internal state
992        self.assertEqual(a._bytes, a.copy()._bytes)
993
994    def test_indefinite_length_octet_string_2(self):
995        data = b'$\x80\x04\r\x8d\xff\xf0\x98\x076\xaf\x93nB:\xcf\xcc\x04\x15' \
996            b'\x92w\xf7\xf0\xe4y\xff\xc7\xdc3\xb2\xd0={\x1a\x18mDr\xaaI\x00\x00'
997        a = core.OctetString.load(data)
998        self.assertEqual(
999            b'\x8d\xff\xf0\x98\x076\xaf\x93nB:\xcf\xcc\x92w\xf7\xf0\xe4y\xff\xc7\xdc3\xb2\xd0={\x1a\x18mDr\xaaI',
1000            a.native
1001        )
1002
1003    def test_nested_indefinite_length_octet_string(self):
1004        data = b'\x24\x80\x24\x80\x24\x80\x04\x00\x00\x00\x00\x00\x00\x00'
1005        a = core.load(data)
1006        self.assertEqual(b'', a.native)
1007        self.assertEqual(b'', a.__bytes__())
1008        self.assertEqual(1, a.method)
1009        self.assertEqual(b'\x04\x00', a.dump(force=True))
1010        # Test copying moves internal state
1011        self.assertEqual(a._bytes, a.copy()._bytes)
1012
1013    def test_indefinite_length_integer_octet_string(self):
1014        data = b'$\x80\x04\x02\x01\x01\x04\x01\x01\x00\x00'
1015        a = core.IntegerOctetString.load(data)
1016        self.assertEqual(65793, a.native)
1017        self.assertEqual(1, a.method)
1018        self.assertEqual(b'\x01\x01\x01', a.cast(core.OctetString).native)
1019
1020    def test_indefinite_length_parsable_octet_string(self):
1021        data = b'$\x80\x04\x02\x04\x01\x04\x01\x01\x00\x00'
1022        a = core.ParsableOctetString.load(data)
1023        self.assertEqual(b'\x04\x01\x01', a.parsed.dump())
1024        self.assertEqual(b'\x04\x01\x01', a.__bytes__())
1025        self.assertEqual(1, a.method)
1026        self.assertEqual(b'\x01', a.parsed.native)
1027        self.assertEqual(b'\x01', a.native)
1028        self.assertEqual(b'\x04\x01\x01', a.cast(core.OctetString).native)
1029        # Test copying moves internal state
1030        self.assertEqual(a._bytes, a.copy()._bytes)
1031        self.assertEqual(a._parsed, a.copy()._parsed)
1032
1033    def test_indefinite_length_utf8string(self):
1034        data = b'\x2C\x80\x0C\x02\x61\x62\x0C\x01\x63\x00\x00'
1035        a = core.UTF8String.load(data)
1036        self.assertEqual('abc', a.native)
1037        self.assertEqual('abc', a.__unicode__())
1038        self.assertEqual(1, a.method)
1039        # Ensure a forced re-encoding is proper DER
1040        self.assertEqual(b'\x0C\x03\x61\x62\x63', a.dump(force=True))
1041        # Test copying moves internal state
1042        self.assertEqual(a._unicode, a.copy()._unicode)
1043
1044    def test_indefinite_length_bit_string(self):
1045        data = b'#\x80\x03\x02\x00\x01\x03\x02\x02\x04\x00\x00'
1046        a = core.BitString.load(data)
1047        self.assertEqual((0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1), a.native)
1048        self.assertEqual((0, 0), a.unused_bits)
1049
1050        # Example from X.690 §8.6.4.2
1051        prim = core.BitString.load(b'\x03\x07\x04\x0A\x3B\x5F\x29\x1C\xD0')
1052        self.assertEqual((0, 0, 0, 0), prim.unused_bits)
1053        indef = core.BitString.load(b'\x23\x80\x03\x03\x00\x0a\x3b\x03\x05\x04\x5f\x29\x1c\xd0\x00\x00')
1054        self.assertEqual(prim.native, indef.native)
1055        self.assertEqual(core._int_to_bit_tuple(0x0A3B5F291CD, 44), indef.native)
1056        self.assertEqual((0, 0, 0, 0), indef.unused_bits)
1057
1058        unused = core.BitString.load(b'\x23\x80\x03\x03\x00\x0a\x3b\x03\x05\x04\x5f\x29\x1c\xdd\x00\x00')
1059        self.assertEqual(indef.native, unused.native)
1060        self.assertEqual((1, 1, 0, 1), unused.unused_bits)
1061
1062        unused.set(indef.native)
1063        self.assertEqual(indef.native, unused.native)
1064        self.assertEqual((0, 0, 0, 0), unused.unused_bits)
1065
1066    def test_integer_bit_string(self):
1067        a = core.IntegerBitString.load(b'\x03\x02\x04\xcb')
1068        self.assertEqual(12, a.native)
1069        self.assertEqual((1, 0, 1, 1), a.unused_bits)
1070
1071        b = a.copy()
1072        self.assertEqual(12, b.native)
1073        self.assertEqual((1, 0, 1, 1), b.unused_bits)
1074
1075        a.set(56)
1076        self.assertEqual((), a.unused_bits)
1077        self.assertEqual(56, a.native)
1078        self.assertEqual(b'\x03\x02\x00\x38', a.dump())
1079
1080        with self.assertRaises(TypeError):
1081            a.set('badtype')
1082
1083        with self.assertRaises(ValueError):
1084            core.IntegerBitString(-1)
1085
1086    def test_indefinite_length_integer_bit_string(self):
1087        data = b'#\x80\x03\x02\x00\x01\x03\x02\x00\x04\x00\x00'
1088        a = core.IntegerBitString.load(data)
1089        self.assertEqual(260, a.native)
1090        self.assertEqual((), a.unused_bits)
1091
1092        a = core.IntegerBitString.load(b'\x23\x80\x00\x00')
1093        self.assertEqual(0, a.native)
1094        self.assertEqual((), a.unused_bits)
1095
1096        a = core.IntegerBitString.load(b'\x23\x80\x03\x01\x00\x03\x03\x03\x03\x03\x00\x00')
1097        self.assertEqual(96, a.native)
1098        self.assertEqual((0, 1, 1), a.unused_bits)
1099
1100        a.set(56)
1101        self.assertEqual((), a.unused_bits)
1102        self.assertEqual(56, a.native)
1103        self.assertEqual(b'\x03\x02\x00\x38', a.dump())
1104
1105    @data('bit_string_error_values')
1106    def integer_bit_string_errors(self, enc_bytes):
1107        with self.assertRaises(ValueError):
1108            core.IntegerBitString.load(enc_bytes).native
1109
1110    def test_octet_bit_string(self):
1111        a = core.OctetBitString.load(b'\x03\x02\x04\xcb')
1112        self.assertEqual(b'\xc0', a.native)
1113        self.assertEqual((1, 0, 1, 1), a.unused_bits)
1114
1115        a.set(b'\x38')
1116        self.assertEqual((), a.unused_bits)
1117        self.assertEqual(b'\x38', a.native)
1118        self.assertEqual(b'\x03\x02\x00\x38', a.dump())
1119
1120        with self.assertRaises(TypeError):
1121            a.set('badtype')
1122
1123    def test_indefinite_length_octet_bit_string(self):
1124        data = b'#\x80\x03\x02\x00\x01\x03\x02\x00\x04\x00\x00'
1125        a = core.OctetBitString.load(data)
1126        self.assertEqual(b'\x01\x04', a.native)
1127        self.assertEqual(b'\x01\x04', a.__bytes__())
1128        # Test copying moves internal state
1129        self.assertEqual(a._bytes, a.copy()._bytes)
1130
1131        # octet bit string with unused bits
1132        a = core.OctetBitString.load(b'\x23\x80\x03\x05\x05\x74\x65\x73\x74\x00\x00')
1133        self.assertEqual(b'\x74\x65\x73\x60', a.native)
1134        self.assertEqual((1, 0, 1, 0, 0), a.unused_bits)
1135
1136        a.set(b'\x38')
1137        self.assertEqual((), a.unused_bits)
1138        self.assertEqual(b'\x38', a.native)
1139        self.assertEqual(b'\x03\x02\x00\x38', a.dump())
1140
1141    @data('bit_string_error_values')
1142    def octet_bit_string_errors(self, enc_bytes):
1143        with self.assertRaises(ValueError):
1144            core.OctetBitString.load(enc_bytes).native
1145
1146    def test_indefinite_length_parsable_octet_bit_string(self):
1147        data = b'#\x80\x03\x03\x00\x0C\x02\x03\x03\x00\x61\x62\x00\x00'
1148        a = core.ParsableOctetBitString.load(data)
1149        self.assertEqual(b'\x0C\x02\x61\x62', a.parsed.dump())
1150        self.assertEqual(b'\x0C\x02\x61\x62', a.__bytes__())
1151        self.assertEqual('ab', a.parsed.native)
1152        self.assertEqual('ab', a.native)
1153        # Test copying moves internal state
1154        self.assertEqual(a._bytes, a.copy()._bytes)
1155        self.assertEqual(a._parsed, a.copy()._parsed)
1156
1157        with self.assertRaises(ValueError):
1158            # parsable octet bit string with unused bits
1159            core.ParsableOctetBitString.load(b'\x23\x80\x03\x03\x04\x02\x00\x03\x03\x04\x12\xa0\x00\x00').native
1160
1161    def test_integer_octet_string(self):
1162        v = core.IntegerOctetString(10)
1163        self.assertEqual(10, v.native)
1164
1165        with self.assertRaises(TypeError):
1166            core.IntegerOctetString('0')
1167
1168        with self.assertRaises(ValueError):
1169            core.IntegerOctetString(-1)
1170
1171    def test_explicit_application_tag(self):
1172        data = b'\x6a\x81\x03\x02\x01\x00'
1173        ati = ApplicationTaggedInteger.load(data)
1174
1175        self.assertEqual(((1, 10),), ati.explicit)
1176        self.assertEqual(0, ati.class_)
1177        self.assertEqual(2, ati.tag)
1178        self.assertEqual(0, ati.native)
1179
1180        # The output encoding is DER, whereas the input was not, so
1181        # the length encoding changes from long form to short form
1182        self.assertEqual(b'\x6a\x03\x02\x01\x00', ati.dump(force=True))
1183
1184    def test_required_field(self):
1185        with self.assertRaisesRegex(ValueError, '"id" is missing from structure'):
1186            Seq({'value': core.Integer(5)}).dump()
1187
1188    def test_explicit_application_tag_nested(self):
1189        # tag = [APPLICATION 10] constructed; length = 18
1190        #   OUTER SEQUENCE: tag = [UNIVERSAL 16] constructed; length = 16
1191        #     outernumber : tag = [11] constructed; length = 3
1192        #       INTEGER: tag = [UNIVERSAL 2] primitive; length = 1
1193        #         23
1194        #     inner : tag = [12] constructed; length = 9
1195        #       tag = [APPLICATION 20] constructed; length = 7
1196        #         INNER SEQUENCE: tag = [UNIVERSAL 16] constructed; length = 5
1197        #           innernumber : tag = [21] constructed; length = 3
1198        #             INTEGER: tag = [UNIVERSAL 2] primitive; length = 1
1199        #               42
1200        der = (
1201            b'\x6A\x12\x30\x10\xAB\x03\x02\x01\x17\xAC\x09\x74'
1202            b'\x07\x30\x05\xB5\x03\x02\x01\x2A'
1203        )
1204
1205        ato = ApplicationTaggedOuter.load(der)
1206        self.assertEqual(((1, 10),), ato.explicit)
1207        self.assertEqual(0, ato.class_)
1208        self.assertEqual(16, ato.tag)
1209        self.assertEqual(1, ato.method)
1210
1211        onum = ato['outernumber']
1212        self.assertEqual(((2, 11),), onum.explicit)
1213        self.assertEqual(0, onum.class_)
1214        self.assertEqual(2, onum.tag)
1215        self.assertEqual(0, onum.method)
1216        self.assertEqual(23, onum.native)
1217
1218        ati = ato['inner']
1219        self.assertEqual(((1, 20), (2, 12)), ati.explicit)
1220        self.assertEqual(0, ati.class_)
1221        self.assertEqual(16, ati.tag)
1222        self.assertEqual(util.OrderedDict([('innernumber', 42)]), ati.native)
1223
1224        inum = ati['innernumber']
1225        self.assertEqual(((2, 21),), inum.explicit)
1226        self.assertEqual(0, inum.class_)
1227        self.assertEqual(2, inum.tag)
1228        self.assertEqual(0, inum.method)
1229        self.assertEqual(42, inum.native)
1230
1231        self.assertEqual(der, ato.dump(force=True))
1232
1233    def test_sequence_choice_field_by_tuple(self):
1234        val = ExplicitField({'field': ('one', 32)})
1235        self.assertEqual('one', val['field'].name)
1236        self.assertEqual(32, val['field'].chosen.native)
1237
1238    def test_sequence_choice_field_by_dict(self):
1239        val = ExplicitField({'field': {'two': 32}})
1240        self.assertEqual('two', val['field'].name)
1241        self.assertEqual(32, val['field'].chosen.native)
1242
1243    def test_nested_explicit_tag_choice(self):
1244        # Explicitly tagged values have a _header that contains
1245        # the explicit tag and the header for the contained value.
1246        # When parsing nested Choice values, it is necessary to not pull
1247        # up the next Choice value's header, since Choice values
1248        # themselves don't have their own header and it will result in
1249        # duplication.
1250        data = b'\x30\x09\x03\x01\x00\xa0\x04\xa2\x02\x80\x00'
1251        image_data = SpcPeImageData.load(data, strict=True)
1252        self.assertEqual(data[2:5],  image_data['flags'].dump())
1253        self.assertEqual(data[5:11],  image_data['file'].dump())
1254        self.assertEqual(data[5:7],  image_data['file']._header)
1255        self.assertEqual(data[7:11],  image_data['file'].chosen.dump())
1256        self.assertEqual(data[7:9],  image_data['file'].chosen._header)
1257        self.assertEqual(data[9:11],  image_data['file'].chosen.chosen.dump())
1258        self.assertEqual(data[9:11],  image_data['file'].chosen.chosen._header)
1259
1260        image_data2 = SpcPeImageData.load(data, strict=True)
1261        self.assertEqual(data[2:5],  image_data2['flags'].dump(True))
1262        self.assertEqual(data[5:11],  image_data2['file'].dump(True))
1263        self.assertEqual(data[5:7],  image_data2['file']._header)
1264        self.assertEqual(data[7:11],  image_data2['file'].chosen.dump(True))
1265        self.assertEqual(data[7:9],  image_data2['file'].chosen._header)
1266        self.assertEqual(data[9:11],  image_data2['file'].chosen.chosen.dump(True))
1267        self.assertEqual(data[9:11],  image_data2['file'].chosen.chosen._header)
1268
1269    def test_choice_dump_header_native(self):
1270        s = SpcString({'unicode': 'test'})
1271        self.assertEqual(b'\x80\x08\x00t\x00e\x00s\x00t', s.dump())
1272        self.assertEqual(b'', s._header)
1273        self.assertEqual('test', s.native)
1274        self.assertEqual(b'\x80\x08', s.chosen._header)
1275        self.assertEqual('test', s.chosen.native)
1276
1277        link = SpcLink('file', {'unicode': 'test'})
1278        self.assertEqual(b'\xa2\x0a\x80\x08\x00t\x00e\x00s\x00t', link.dump())
1279        self.assertEqual(b'', link._header)
1280        self.assertEqual('test', link.native)
1281        self.assertEqual(b'\xa2\x0a', link.chosen._header)
1282        self.assertEqual('test', link.chosen.native)
1283        self.assertEqual(b'\x80\x08', link.chosen.chosen._header)
1284        self.assertEqual('test', link.chosen.chosen.native)
1285
1286    def test_parse_broken_sequence_fields_repeatedly(self):
1287        s = Seq.load(b'\x30\x06\x88\x00\x00\x00\x00\x00')
1288        with self.assertRaises(ValueError):
1289            s.native
1290        with self.assertRaises(ValueError):
1291            s.native
1292
1293    def test_parse_broken_sequenceof_children_repeatedly(self):
1294        s = SequenceOfInts.load(b'\x30\x06\x88\x00\x00\x00\x00\x00')
1295        with self.assertRaises(ValueError):
1296            s.native
1297        with self.assertRaises(ValueError):
1298            s.native
1299
1300    def test_wrong_asn1value(self):
1301        with self.assertRaises(TypeError):
1302            Seq({
1303                'id': core.Integer(1),
1304                'value': 1
1305            })
1306
1307    def test_wrong_asn1value2(self):
1308        with self.assertRaises(TypeError):
1309            CopySeq({
1310                'name': core.UTF8String('Test'),
1311                'pair': core.Integer(1)
1312            })
1313
1314    def test_wrong_asn1value3(self):
1315        with self.assertRaises(TypeError):
1316            NestSeqAny({
1317                'id': '2.3.4.5',
1318                'value': core.Integer(1)
1319            })
1320
1321    def test_wrong_asn1value4(self):
1322        with self.assertRaises(TypeError):
1323            NestSeqExplicit({
1324                'id': '2.3.4.5',
1325                'value': core.Integer(1)
1326            })
1327
1328    def test_integer_octet_string_encoded_width(self):
1329        a = core.IntegerOctetString(1)
1330        self.assertEqual(1, a.native)
1331        self.assertEqual(b'\x04\x01\x01', a.dump())
1332
1333        b = core.IntegerOctetString(1)
1334        b.set_encoded_width(4)
1335        self.assertEqual(1, b.native)
1336        self.assertEqual(b'\x04\x04\x00\x00\x00\x01', b.dump())
1337
1338    @staticmethod
1339    def object_identifier_info():
1340        return (
1341            ("0.0", b"\x06\x01\x00"),
1342            ("0.39", b"\x06\x01\x27"),
1343            ("1.0", b"\x06\x01\x28"),
1344            ("1.39", b"\x06\x01\x4f"),
1345            ("2.0", b"\x06\x01\x50"),
1346            ("2.39", b"\x06\x01\x77"),
1347            ("2.100.3", b"\x06\x03\x81\x34\x03"),
1348            ("2.16.840.1.113730.1.1", b"\x06\x09\x60\x86\x48\x01\x86\xf8\x42\x01\x01"),
1349        )
1350
1351    @data('object_identifier_info')
1352    def object_identifier(self, native, der_bytes):
1353        oid = core.ObjectIdentifier(native)
1354        self.assertEqual(der_bytes, oid.dump())
1355        self.assertEqual(native, core.ObjectIdentifier.load(der_bytes).native)
1356
1357    def test_broken_object_identifier(self):
1358        with self.assertRaisesRegex(ValueError, "First arc must be "):
1359            core.ObjectIdentifier("3.4.5")
1360
1361        with self.assertRaisesRegex(ValueError, "Second arc must be "):
1362            core.ObjectIdentifier("1.100.1000")
1363
1364        with self.assertRaisesRegex(ValueError, "Second arc must be "):
1365            core.ObjectIdentifier("0.40")
1366