Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/pyasn1/type/base.py: 71%

249 statements  

« prev     ^ index     » next       coverage.py v7.2.2, created at 2023-03-26 06:25 +0000

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