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