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