1# 2# This file is part of pyasn1 software. 3# 4# Copyright (c) 2005-2019, Ilya Etingof <etingof@gmail.com> 5# License: http://snmplabs.com/pyasn1/license.html 6# 7import sys 8 9from pyasn1 import error 10from pyasn1.compat import calling 11from pyasn1.type import constraint 12from pyasn1.type import tag 13from pyasn1.type import tagmap 14 15__all__ = ['Asn1Item', 'Asn1Type', 'SimpleAsn1Type', 16 'ConstructedAsn1Type'] 17 18 19class Asn1Item(object): 20 @classmethod 21 def getTypeId(cls, increment=1): 22 try: 23 Asn1Item._typeCounter += increment 24 except AttributeError: 25 Asn1Item._typeCounter = increment 26 return Asn1Item._typeCounter 27 28 29class Asn1Type(Asn1Item): 30 """Base class for all classes representing ASN.1 types. 31 32 In the user code, |ASN.1| class is normally used only for telling 33 ASN.1 objects from others. 34 35 Note 36 ---- 37 For as long as ASN.1 is concerned, a way to compare ASN.1 types 38 is to use :meth:`isSameTypeWith` and :meth:`isSuperTypeOf` methods. 39 """ 40 #: Set or return a :py:class:`~pyasn1.type.tag.TagSet` object representing 41 #: ASN.1 tag(s) associated with |ASN.1| type. 42 tagSet = tag.TagSet() 43 44 #: Default :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` 45 #: object imposing constraints on initialization values. 46 subtypeSpec = constraint.ConstraintsIntersection() 47 48 # Disambiguation ASN.1 types identification 49 typeId = None 50 51 def __init__(self, **kwargs): 52 readOnly = { 53 'tagSet': self.tagSet, 54 'subtypeSpec': self.subtypeSpec 55 } 56 57 readOnly.update(kwargs) 58 59 self.__dict__.update(readOnly) 60 61 self._readOnly = readOnly 62 63 def __setattr__(self, name, value): 64 if name[0] != '_' and name in self._readOnly: 65 raise error.PyAsn1Error('read-only instance attribute "%s"' % name) 66 67 self.__dict__[name] = value 68 69 def __str__(self): 70 return self.prettyPrint() 71 72 @property 73 def readOnly(self): 74 return self._readOnly 75 76 @property 77 def effectiveTagSet(self): 78 """For |ASN.1| type is equivalent to *tagSet* 79 """ 80 return self.tagSet # used by untagged types 81 82 @property 83 def tagMap(self): 84 """Return a :class:`~pyasn1.type.tagmap.TagMap` object mapping ASN.1 tags to ASN.1 objects within callee object. 85 """ 86 return tagmap.TagMap({self.tagSet: self}) 87 88 def isSameTypeWith(self, other, matchTags=True, matchConstraints=True): 89 """Examine |ASN.1| type for equality with other ASN.1 type. 90 91 ASN.1 tags (:py:mod:`~pyasn1.type.tag`) and constraints 92 (:py:mod:`~pyasn1.type.constraint`) are examined when carrying 93 out ASN.1 types comparison. 94 95 Python class inheritance relationship is NOT considered. 96 97 Parameters 98 ---------- 99 other: a pyasn1 type object 100 Class instance representing ASN.1 type. 101 102 Returns 103 ------- 104 : :class:`bool` 105 :obj:`True` if *other* is |ASN.1| type, 106 :obj:`False` otherwise. 107 """ 108 return (self is other or 109 (not matchTags or self.tagSet == other.tagSet) and 110 (not matchConstraints or self.subtypeSpec == other.subtypeSpec)) 111 112 def isSuperTypeOf(self, other, matchTags=True, matchConstraints=True): 113 """Examine |ASN.1| type for subtype relationship with other ASN.1 type. 114 115 ASN.1 tags (:py:mod:`~pyasn1.type.tag`) and constraints 116 (:py:mod:`~pyasn1.type.constraint`) are examined when carrying 117 out ASN.1 types comparison. 118 119 Python class inheritance relationship is NOT considered. 120 121 Parameters 122 ---------- 123 other: a pyasn1 type object 124 Class instance representing ASN.1 type. 125 126 Returns 127 ------- 128 : :class:`bool` 129 :obj:`True` if *other* is a subtype of |ASN.1| type, 130 :obj:`False` otherwise. 131 """ 132 return (not matchTags or 133 (self.tagSet.isSuperTagSetOf(other.tagSet)) and 134 (not matchConstraints or self.subtypeSpec.isSuperTypeOf(other.subtypeSpec))) 135 136 @staticmethod 137 def isNoValue(*values): 138 for value in values: 139 if value is not noValue: 140 return False 141 return True 142 143 def prettyPrint(self, scope=0): 144 raise NotImplementedError() 145 146 # backward compatibility 147 148 def getTagSet(self): 149 return self.tagSet 150 151 def getEffectiveTagSet(self): 152 return self.effectiveTagSet 153 154 def getTagMap(self): 155 return self.tagMap 156 157 def getSubtypeSpec(self): 158 return self.subtypeSpec 159 160 # backward compatibility 161 def hasValue(self): 162 return self.isValue 163 164# Backward compatibility 165Asn1ItemBase = Asn1Type 166 167 168class NoValue(object): 169 """Create a singleton instance of NoValue class. 170 171 The *NoValue* sentinel object represents an instance of ASN.1 schema 172 object as opposed to ASN.1 value object. 173 174 Only ASN.1 schema-related operations can be performed on ASN.1 175 schema objects. 176 177 Warning 178 ------- 179 Any operation attempted on the *noValue* object will raise the 180 *PyAsn1Error* exception. 181 """ 182 skipMethods = set( 183 ('__slots__', 184 # attributes 185 '__getattribute__', 186 '__getattr__', 187 '__setattr__', 188 '__delattr__', 189 # class instance 190 '__class__', 191 '__init__', 192 '__del__', 193 '__new__', 194 '__repr__', 195 '__qualname__', 196 '__objclass__', 197 'im_class', 198 '__sizeof__', 199 # pickle protocol 200 '__reduce__', 201 '__reduce_ex__', 202 '__getnewargs__', 203 '__getinitargs__', 204 '__getstate__', 205 '__setstate__') 206 ) 207 208 _instance = None 209 210 def __new__(cls): 211 if cls._instance is None: 212 def getPlug(name): 213 def plug(self, *args, **kw): 214 raise error.PyAsn1Error('Attempted "%s" operation on ASN.1 schema object' % name) 215 return plug 216 217 op_names = [name 218 for typ in (str, int, list, dict) 219 for name in dir(typ) 220 if (name not in cls.skipMethods and 221 name.startswith('__') and 222 name.endswith('__') and 223 calling.callable(getattr(typ, name)))] 224 225 for name in set(op_names): 226 setattr(cls, name, getPlug(name)) 227 228 cls._instance = object.__new__(cls) 229 230 return cls._instance 231 232 def __getattr__(self, attr): 233 if attr in self.skipMethods: 234 raise AttributeError('Attribute %s not present' % attr) 235 236 raise error.PyAsn1Error('Attempted "%s" operation on ASN.1 schema object' % attr) 237 238 def __repr__(self): 239 return '<%s object>' % self.__class__.__name__ 240 241 242noValue = NoValue() 243 244 245class SimpleAsn1Type(Asn1Type): 246 """Base class for all simple classes representing ASN.1 types. 247 248 ASN.1 distinguishes types by their ability to hold other objects. 249 Scalar types are known as *simple* in ASN.1. 250 251 In the user code, |ASN.1| class is normally used only for telling 252 ASN.1 objects from others. 253 254 Note 255 ---- 256 For as long as ASN.1 is concerned, a way to compare ASN.1 types 257 is to use :meth:`isSameTypeWith` and :meth:`isSuperTypeOf` methods. 258 """ 259 #: Default payload value 260 defaultValue = noValue 261 262 def __init__(self, value=noValue, **kwargs): 263 Asn1Type.__init__(self, **kwargs) 264 if value is noValue: 265 value = self.defaultValue 266 else: 267 value = self.prettyIn(value) 268 try: 269 self.subtypeSpec(value) 270 271 except error.PyAsn1Error: 272 exType, exValue, exTb = sys.exc_info() 273 raise exType('%s at %s' % (exValue, self.__class__.__name__)) 274 275 self._value = value 276 277 def __repr__(self): 278 representation = '%s %s object' % ( 279 self.__class__.__name__, self.isValue and 'value' or 'schema') 280 281 for attr, value in self.readOnly.items(): 282 if value: 283 representation += ', %s %s' % (attr, value) 284 285 if self.isValue: 286 value = self.prettyPrint() 287 if len(value) > 32: 288 value = value[:16] + '...' + value[-16:] 289 representation += ', payload [%s]' % value 290 291 return '<%s>' % representation 292 293 def __eq__(self, other): 294 return self is other and True or self._value == other 295 296 def __ne__(self, other): 297 return self._value != other 298 299 def __lt__(self, other): 300 return self._value < other 301 302 def __le__(self, other): 303 return self._value <= other 304 305 def __gt__(self, other): 306 return self._value > other 307 308 def __ge__(self, other): 309 return self._value >= other 310 311 if sys.version_info[0] <= 2: 312 def __nonzero__(self): 313 return self._value and True or False 314 else: 315 def __bool__(self): 316 return self._value and True or False 317 318 def __hash__(self): 319 return hash(self._value) 320 321 @property 322 def isValue(self): 323 """Indicate that |ASN.1| object represents ASN.1 value. 324 325 If *isValue* is :obj:`False` then this object represents just 326 ASN.1 schema. 327 328 If *isValue* is :obj:`True` then, in addition to its ASN.1 schema 329 features, this object can also be used like a Python built-in object 330 (e.g. :class:`int`, :class:`str`, :class:`dict` etc.). 331 332 Returns 333 ------- 334 : :class:`bool` 335 :obj:`False` if object represents just ASN.1 schema. 336 :obj:`True` if object represents ASN.1 schema and can be used as a normal value. 337 338 Note 339 ---- 340 There is an important distinction between PyASN1 schema and value objects. 341 The PyASN1 schema objects can only participate in ASN.1 schema-related 342 operations (e.g. defining or testing the structure of the data). Most 343 obvious uses of ASN.1 schema is to guide serialisation codecs whilst 344 encoding/decoding serialised ASN.1 contents. 345 346 The PyASN1 value objects can **additionally** participate in many operations 347 involving regular Python objects (e.g. arithmetic, comprehension etc). 348 """ 349 return self._value is not noValue 350 351 def clone(self, value=noValue, **kwargs): 352 """Create a modified version of |ASN.1| schema or value object. 353 354 The `clone()` method accepts the same set arguments as |ASN.1| 355 class takes on instantiation except that all arguments 356 of the `clone()` method are optional. 357 358 Whatever arguments are supplied, they are used to create a copy 359 of `self` taking precedence over the ones used to instantiate `self`. 360 361 Note 362 ---- 363 Due to the immutable nature of the |ASN.1| object, if no arguments 364 are supplied, no new |ASN.1| object will be created and `self` will 365 be returned instead. 366 """ 367 if value is noValue: 368 if not kwargs: 369 return self 370 371 value = self._value 372 373 initializers = self.readOnly.copy() 374 initializers.update(kwargs) 375 376 return self.__class__(value, **initializers) 377 378 def subtype(self, value=noValue, **kwargs): 379 """Create a specialization of |ASN.1| schema or value object. 380 381 The subtype relationship between ASN.1 types has no correlation with 382 subtype relationship between Python types. ASN.1 type is mainly identified 383 by its tag(s) (:py:class:`~pyasn1.type.tag.TagSet`) and value range 384 constraints (:py:class:`~pyasn1.type.constraint.ConstraintsIntersection`). 385 These ASN.1 type properties are implemented as |ASN.1| attributes. 386 387 The `subtype()` method accepts the same set arguments as |ASN.1| 388 class takes on instantiation except that all parameters 389 of the `subtype()` method are optional. 390 391 With the exception of the arguments described below, the rest of 392 supplied arguments they are used to create a copy of `self` taking 393 precedence over the ones used to instantiate `self`. 394 395 The following arguments to `subtype()` create a ASN.1 subtype out of 396 |ASN.1| type: 397 398 Other Parameters 399 ---------------- 400 implicitTag: :py:class:`~pyasn1.type.tag.Tag` 401 Implicitly apply given ASN.1 tag object to `self`'s 402 :py:class:`~pyasn1.type.tag.TagSet`, then use the result as 403 new object's ASN.1 tag(s). 404 405 explicitTag: :py:class:`~pyasn1.type.tag.Tag` 406 Explicitly apply given ASN.1 tag object to `self`'s 407 :py:class:`~pyasn1.type.tag.TagSet`, then use the result as 408 new object's ASN.1 tag(s). 409 410 subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` 411 Add ASN.1 constraints object to one of the `self`'s, then 412 use the result as new object's ASN.1 constraints. 413 414 Returns 415 ------- 416 : 417 new instance of |ASN.1| schema or value object 418 419 Note 420 ---- 421 Due to the immutable nature of the |ASN.1| object, if no arguments 422 are supplied, no new |ASN.1| object will be created and `self` will 423 be returned instead. 424 """ 425 if value is noValue: 426 if not kwargs: 427 return self 428 429 value = self._value 430 431 initializers = self.readOnly.copy() 432 433 implicitTag = kwargs.pop('implicitTag', None) 434 if implicitTag is not None: 435 initializers['tagSet'] = self.tagSet.tagImplicitly(implicitTag) 436 437 explicitTag = kwargs.pop('explicitTag', None) 438 if explicitTag is not None: 439 initializers['tagSet'] = self.tagSet.tagExplicitly(explicitTag) 440 441 for arg, option in kwargs.items(): 442 initializers[arg] += option 443 444 return self.__class__(value, **initializers) 445 446 def prettyIn(self, value): 447 return value 448 449 def prettyOut(self, value): 450 return str(value) 451 452 def prettyPrint(self, scope=0): 453 return self.prettyOut(self._value) 454 455 def prettyPrintType(self, scope=0): 456 return '%s -> %s' % (self.tagSet, self.__class__.__name__) 457 458# Backward compatibility 459AbstractSimpleAsn1Item = SimpleAsn1Type 460 461# 462# Constructed types: 463# * There are five of them: Sequence, SequenceOf/SetOf, Set and Choice 464# * ASN1 types and values are represened by Python class instances 465# * Value initialization is made for defaulted components only 466# * Primary method of component addressing is by-position. Data model for base 467# type is Python sequence. Additional type-specific addressing methods 468# may be implemented for particular types. 469# * SequenceOf and SetOf types do not implement any additional methods 470# * Sequence, Set and Choice types also implement by-identifier addressing 471# * Sequence, Set and Choice types also implement by-asn1-type (tag) addressing 472# * Sequence and Set types may include optional and defaulted 473# components 474# * Constructed types hold a reference to component types used for value 475# verification and ordering. 476# * Component type is a scalar type for SequenceOf/SetOf types and a list 477# of types for Sequence/Set/Choice. 478# 479 480 481class ConstructedAsn1Type(Asn1Type): 482 """Base class for all constructed classes representing ASN.1 types. 483 484 ASN.1 distinguishes types by their ability to hold other objects. 485 Those "nesting" types are known as *constructed* in ASN.1. 486 487 In the user code, |ASN.1| class is normally used only for telling 488 ASN.1 objects from others. 489 490 Note 491 ---- 492 For as long as ASN.1 is concerned, a way to compare ASN.1 types 493 is to use :meth:`isSameTypeWith` and :meth:`isSuperTypeOf` methods. 494 """ 495 496 #: If :obj:`True`, requires exact component type matching, 497 #: otherwise subtype relation is only enforced 498 strictConstraints = False 499 500 componentType = None 501 502 # backward compatibility, unused 503 sizeSpec = constraint.ConstraintsIntersection() 504 505 def __init__(self, **kwargs): 506 readOnly = { 507 'componentType': self.componentType, 508 # backward compatibility, unused 509 'sizeSpec': self.sizeSpec 510 } 511 512 # backward compatibility: preserve legacy sizeSpec support 513 kwargs = self._moveSizeSpec(**kwargs) 514 515 readOnly.update(kwargs) 516 517 Asn1Type.__init__(self, **readOnly) 518 519 def _moveSizeSpec(self, **kwargs): 520 # backward compatibility, unused 521 sizeSpec = kwargs.pop('sizeSpec', self.sizeSpec) 522 if sizeSpec: 523 subtypeSpec = kwargs.pop('subtypeSpec', self.subtypeSpec) 524 if subtypeSpec: 525 subtypeSpec = sizeSpec 526 527 else: 528 subtypeSpec += sizeSpec 529 530 kwargs['subtypeSpec'] = subtypeSpec 531 532 return kwargs 533 534 def __repr__(self): 535 representation = '%s %s object' % ( 536 self.__class__.__name__, self.isValue and 'value' or 'schema' 537 ) 538 539 for attr, value in self.readOnly.items(): 540 if value is not noValue: 541 representation += ', %s=%r' % (attr, value) 542 543 if self.isValue and self.components: 544 representation += ', payload [%s]' % ', '.join( 545 [repr(x) for x in self.components]) 546 547 return '<%s>' % representation 548 549 def __eq__(self, other): 550 return self is other or self.components == other 551 552 def __ne__(self, other): 553 return self.components != other 554 555 def __lt__(self, other): 556 return self.components < other 557 558 def __le__(self, other): 559 return self.components <= other 560 561 def __gt__(self, other): 562 return self.components > other 563 564 def __ge__(self, other): 565 return self.components >= other 566 567 if sys.version_info[0] <= 2: 568 def __nonzero__(self): 569 return bool(self.components) 570 else: 571 def __bool__(self): 572 return bool(self.components) 573 574 @property 575 def components(self): 576 raise error.PyAsn1Error('Method not implemented') 577 578 def _cloneComponentValues(self, myClone, cloneValueFlag): 579 pass 580 581 def clone(self, **kwargs): 582 """Create a modified version of |ASN.1| schema object. 583 584 The `clone()` method accepts the same set arguments as |ASN.1| 585 class takes on instantiation except that all arguments 586 of the `clone()` method are optional. 587 588 Whatever arguments are supplied, they are used to create a copy 589 of `self` taking precedence over the ones used to instantiate `self`. 590 591 Possible values of `self` are never copied over thus `clone()` can 592 only create a new schema object. 593 594 Returns 595 ------- 596 : 597 new instance of |ASN.1| type/value 598 599 Note 600 ---- 601 Due to the mutable nature of the |ASN.1| object, even if no arguments 602 are supplied, a new |ASN.1| object will be created and returned. 603 """ 604 cloneValueFlag = kwargs.pop('cloneValueFlag', False) 605 606 initializers = self.readOnly.copy() 607 initializers.update(kwargs) 608 609 clone = self.__class__(**initializers) 610 611 if cloneValueFlag: 612 self._cloneComponentValues(clone, cloneValueFlag) 613 614 return clone 615 616 def subtype(self, **kwargs): 617 """Create a specialization of |ASN.1| schema object. 618 619 The `subtype()` method accepts the same set arguments as |ASN.1| 620 class takes on instantiation except that all parameters 621 of the `subtype()` method are optional. 622 623 With the exception of the arguments described below, the rest of 624 supplied arguments they are used to create a copy of `self` taking 625 precedence over the ones used to instantiate `self`. 626 627 The following arguments to `subtype()` create a ASN.1 subtype out of 628 |ASN.1| type. 629 630 Other Parameters 631 ---------------- 632 implicitTag: :py:class:`~pyasn1.type.tag.Tag` 633 Implicitly apply given ASN.1 tag object to `self`'s 634 :py:class:`~pyasn1.type.tag.TagSet`, then use the result as 635 new object's ASN.1 tag(s). 636 637 explicitTag: :py:class:`~pyasn1.type.tag.Tag` 638 Explicitly apply given ASN.1 tag object to `self`'s 639 :py:class:`~pyasn1.type.tag.TagSet`, then use the result as 640 new object's ASN.1 tag(s). 641 642 subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` 643 Add ASN.1 constraints object to one of the `self`'s, then 644 use the result as new object's ASN.1 constraints. 645 646 647 Returns 648 ------- 649 : 650 new instance of |ASN.1| type/value 651 652 Note 653 ---- 654 Due to the mutable nature of the |ASN.1| object, even if no arguments 655 are supplied, a new |ASN.1| object will be created and returned. 656 """ 657 658 initializers = self.readOnly.copy() 659 660 cloneValueFlag = kwargs.pop('cloneValueFlag', False) 661 662 implicitTag = kwargs.pop('implicitTag', None) 663 if implicitTag is not None: 664 initializers['tagSet'] = self.tagSet.tagImplicitly(implicitTag) 665 666 explicitTag = kwargs.pop('explicitTag', None) 667 if explicitTag is not None: 668 initializers['tagSet'] = self.tagSet.tagExplicitly(explicitTag) 669 670 for arg, option in kwargs.items(): 671 initializers[arg] += option 672 673 clone = self.__class__(**initializers) 674 675 if cloneValueFlag: 676 self._cloneComponentValues(clone, cloneValueFlag) 677 678 return clone 679 680 def getComponentByPosition(self, idx): 681 raise error.PyAsn1Error('Method not implemented') 682 683 def setComponentByPosition(self, idx, value, verifyConstraints=True): 684 raise error.PyAsn1Error('Method not implemented') 685 686 def setComponents(self, *args, **kwargs): 687 for idx, value in enumerate(args): 688 self[idx] = value 689 for k in kwargs: 690 self[k] = kwargs[k] 691 return self 692 693 # backward compatibility 694 695 def setDefaultComponents(self): 696 pass 697 698 def getComponentType(self): 699 return self.componentType 700 701 # backward compatibility, unused 702 def verifySizeSpec(self): 703 self.subtypeSpec(self) 704 705 706 # Backward compatibility 707AbstractConstructedAsn1Item = ConstructedAsn1Type 708