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