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

248 statements  

« prev     ^ index     » next       coverage.py v7.3.2, created at 2023-12-08 06:51 +0000

1# 

2# This file is part of pyasn1 software. 

3# 

4# Copyright (c) 2005-2020, Ilya Etingof <etingof@gmail.com> 

5# License: https://pyasn1.readthedocs.io/en/latest/license.html 

6# 

7import sys 

8 

9from pyasn1 import error 

10from pyasn1.type import constraint 

11from pyasn1.type import tag 

12from pyasn1.type import tagmap 

13 

14__all__ = ['Asn1Item', 'Asn1Type', 'SimpleAsn1Type', 

15 'ConstructedAsn1Type'] 

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 Asn1Type(Asn1Item): 

29 """Base class for all classes representing ASN.1 types. 

30 

31 In the user code, |ASN.1| class is normally used only for telling 

32 ASN.1 objects from others. 

33 

34 Note 

35 ---- 

36 For as long as ASN.1 is concerned, a way to compare ASN.1 types 

37 is to use :meth:`isSameTypeWith` and :meth:`isSuperTypeOf` methods. 

38 """ 

39 #: Set or return a :py:class:`~pyasn1.type.tag.TagSet` object representing 

40 #: ASN.1 tag(s) associated with |ASN.1| type. 

41 tagSet = tag.TagSet() 

42 

43 #: Default :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` 

44 #: object imposing constraints on initialization values. 

45 subtypeSpec = constraint.ConstraintsIntersection() 

46 

47 # Disambiguation ASN.1 types identification 

48 typeId = None 

49 

50 def __init__(self, **kwargs): 

51 readOnly = { 

52 'tagSet': self.tagSet, 

53 'subtypeSpec': self.subtypeSpec 

54 } 

55 

56 readOnly.update(kwargs) 

57 

58 self.__dict__.update(readOnly) 

59 

60 self._readOnly = readOnly 

61 

62 def __setattr__(self, name, value): 

63 if name[0] != '_' and name in self._readOnly: 

64 raise error.PyAsn1Error('read-only instance attribute "%s"' % name) 

65 

66 self.__dict__[name] = value 

67 

68 def __str__(self): 

69 return self.prettyPrint() 

70 

71 @property 

72 def readOnly(self): 

73 return self._readOnly 

74 

75 @property 

76 def effectiveTagSet(self): 

77 """For |ASN.1| type is equivalent to *tagSet* 

78 """ 

79 return self.tagSet # used by untagged types 

80 

81 @property 

82 def tagMap(self): 

83 """Return a :class:`~pyasn1.type.tagmap.TagMap` object mapping ASN.1 tags to ASN.1 objects within callee object. 

84 """ 

85 return tagmap.TagMap({self.tagSet: self}) 

86 

87 def isSameTypeWith(self, other, matchTags=True, matchConstraints=True): 

88 """Examine |ASN.1| type for equality with other ASN.1 type. 

89 

90 ASN.1 tags (:py:mod:`~pyasn1.type.tag`) and constraints 

91 (:py:mod:`~pyasn1.type.constraint`) are examined when carrying 

92 out ASN.1 types comparison. 

93 

94 Python class inheritance relationship is NOT considered. 

95 

96 Parameters 

97 ---------- 

98 other: a pyasn1 type object 

99 Class instance representing ASN.1 type. 

100 

101 Returns 

102 ------- 

103 : :class:`bool` 

104 :obj:`True` if *other* is |ASN.1| type, 

105 :obj:`False` otherwise. 

106 """ 

107 return (self is other or 

108 (not matchTags or self.tagSet == other.tagSet) and 

109 (not matchConstraints or self.subtypeSpec == other.subtypeSpec)) 

110 

111 def isSuperTypeOf(self, other, matchTags=True, matchConstraints=True): 

112 """Examine |ASN.1| type for subtype relationship with other ASN.1 type. 

113 

114 ASN.1 tags (:py:mod:`~pyasn1.type.tag`) and constraints 

115 (:py:mod:`~pyasn1.type.constraint`) are examined when carrying 

116 out ASN.1 types comparison. 

117 

118 Python class inheritance relationship is NOT considered. 

119 

120 Parameters 

121 ---------- 

122 other: a pyasn1 type object 

123 Class instance representing ASN.1 type. 

124 

125 Returns 

126 ------- 

127 : :class:`bool` 

128 :obj:`True` if *other* is a subtype of |ASN.1| type, 

129 :obj:`False` otherwise. 

130 """ 

131 return (not matchTags or 

132 (self.tagSet.isSuperTagSetOf(other.tagSet)) and 

133 (not matchConstraints or self.subtypeSpec.isSuperTypeOf(other.subtypeSpec))) 

134 

135 @staticmethod 

136 def isNoValue(*values): 

137 for value in values: 

138 if value is not noValue: 

139 return False 

140 return True 

141 

142 def prettyPrint(self, scope=0): 

143 raise NotImplementedError() 

144 

145 # backward compatibility 

146 

147 def getTagSet(self): 

148 return self.tagSet 

149 

150 def getEffectiveTagSet(self): 

151 return self.effectiveTagSet 

152 

153 def getTagMap(self): 

154 return self.tagMap 

155 

156 def getSubtypeSpec(self): 

157 return self.subtypeSpec 

158 

159 # backward compatibility 

160 def hasValue(self): 

161 return self.isValue 

162 

163# Backward compatibility 

164Asn1ItemBase = Asn1Type 

165 

166 

167class NoValue(object): 

168 """Create a singleton instance of NoValue class. 

169 

170 The *NoValue* sentinel object represents an instance of ASN.1 schema 

171 object as opposed to ASN.1 value object. 

172 

173 Only ASN.1 schema-related operations can be performed on ASN.1 

174 schema objects. 

175 

176 Warning 

177 ------- 

178 Any operation attempted on the *noValue* object will raise the 

179 *PyAsn1Error* exception. 

180 """ 

181 skipMethods = { 

182 '__slots__', 

183 # attributes 

184 '__getattribute__', 

185 '__getattr__', 

186 '__setattr__', 

187 '__delattr__', 

188 # class instance 

189 '__class__', 

190 '__init__', 

191 '__del__', 

192 '__new__', 

193 '__repr__', 

194 '__qualname__', 

195 '__objclass__', 

196 'im_class', 

197 '__sizeof__', 

198 # pickle protocol 

199 '__reduce__', 

200 '__reduce_ex__', 

201 '__getnewargs__', 

202 '__getinitargs__', 

203 '__getstate__', 

204 '__setstate__', 

205 } 

206 

207 _instance = None 

208 

209 def __new__(cls): 

210 if cls._instance is None: 

211 def getPlug(name): 

212 def plug(self, *args, **kw): 

213 raise error.PyAsn1Error('Attempted "%s" operation on ASN.1 schema object' % name) 

214 return plug 

215 

216 op_names = [name 

217 for typ in (str, int, list, dict) 

218 for name in dir(typ) 

219 if (name not in cls.skipMethods and 

220 name.startswith('__') and 

221 name.endswith('__') and 

222 callable(getattr(typ, name)))] 

223 

224 for name in set(op_names): 

225 setattr(cls, name, getPlug(name)) 

226 

227 cls._instance = object.__new__(cls) 

228 

229 return cls._instance 

230 

231 def __getattr__(self, attr): 

232 if attr in self.skipMethods: 

233 raise AttributeError('Attribute %s not present' % attr) 

234 

235 raise error.PyAsn1Error('Attempted "%s" operation on ASN.1 schema object' % attr) 

236 

237 def __repr__(self): 

238 return '<%s object>' % self.__class__.__name__ 

239 

240 

241noValue = NoValue() 

242 

243 

244class SimpleAsn1Type(Asn1Type): 

245 """Base class for all simple classes representing ASN.1 types. 

246 

247 ASN.1 distinguishes types by their ability to hold other objects. 

248 Scalar types are known as *simple* in ASN.1. 

249 

250 In the user code, |ASN.1| class is normally used only for telling 

251 ASN.1 objects from others. 

252 

253 Note 

254 ---- 

255 For as long as ASN.1 is concerned, a way to compare ASN.1 types 

256 is to use :meth:`isSameTypeWith` and :meth:`isSuperTypeOf` methods. 

257 """ 

258 #: Default payload value 

259 defaultValue = noValue 

260 

261 def __init__(self, value=noValue, **kwargs): 

262 Asn1Type.__init__(self, **kwargs) 

263 if value is noValue: 

264 value = self.defaultValue 

265 else: 

266 value = self.prettyIn(value) 

267 try: 

268 self.subtypeSpec(value) 

269 

270 except error.PyAsn1Error: 

271 exType, exValue, exTb = sys.exc_info() 

272 raise exType('%s at %s' % (exValue, self.__class__.__name__)) 

273 

274 self._value = value 

275 

276 def __repr__(self): 

277 representation = '%s %s object' % ( 

278 self.__class__.__name__, self.isValue and 'value' or 'schema') 

279 

280 for attr, value in self.readOnly.items(): 

281 if value: 

282 representation += ', %s %s' % (attr, value) 

283 

284 if self.isValue: 

285 value = self.prettyPrint() 

286 if len(value) > 32: 

287 value = value[:16] + '...' + value[-16:] 

288 representation += ', payload [%s]' % value 

289 

290 return '<%s>' % representation 

291 

292 def __eq__(self, other): 

293 return self is other and True or self._value == other 

294 

295 def __ne__(self, other): 

296 return self._value != other 

297 

298 def __lt__(self, other): 

299 return self._value < other 

300 

301 def __le__(self, other): 

302 return self._value <= other 

303 

304 def __gt__(self, other): 

305 return self._value > other 

306 

307 def __ge__(self, other): 

308 return self._value >= other 

309 

310 if sys.version_info[0] <= 2: 

311 def __nonzero__(self): 

312 return self._value and True or False 

313 else: 

314 def __bool__(self): 

315 return self._value and True or False 

316 

317 def __hash__(self): 

318 return hash(self._value) 

319 

320 @property 

321 def isValue(self): 

322 """Indicate that |ASN.1| object represents ASN.1 value. 

323 

324 If *isValue* is :obj:`False` then this object represents just 

325 ASN.1 schema. 

326 

327 If *isValue* is :obj:`True` then, in addition to its ASN.1 schema 

328 features, this object can also be used like a Python built-in object 

329 (e.g. :class:`int`, :class:`str`, :class:`dict` etc.). 

330 

331 Returns 

332 ------- 

333 : :class:`bool` 

334 :obj:`False` if object represents just ASN.1 schema. 

335 :obj:`True` if object represents ASN.1 schema and can be used as a normal value. 

336 

337 Note 

338 ---- 

339 There is an important distinction between PyASN1 schema and value objects. 

340 The PyASN1 schema objects can only participate in ASN.1 schema-related 

341 operations (e.g. defining or testing the structure of the data). Most 

342 obvious uses of ASN.1 schema is to guide serialisation codecs whilst 

343 encoding/decoding serialised ASN.1 contents. 

344 

345 The PyASN1 value objects can **additionally** participate in many operations 

346 involving regular Python objects (e.g. arithmetic, comprehension etc). 

347 """ 

348 return self._value is not noValue 

349 

350 def clone(self, value=noValue, **kwargs): 

351 """Create a modified version of |ASN.1| schema or value object. 

352 

353 The `clone()` method accepts the same set arguments as |ASN.1| 

354 class takes on instantiation except that all arguments 

355 of the `clone()` method are optional. 

356 

357 Whatever arguments are supplied, they are used to create a copy 

358 of `self` taking precedence over the ones used to instantiate `self`. 

359 

360 Note 

361 ---- 

362 Due to the immutable nature of the |ASN.1| object, if no arguments 

363 are supplied, no new |ASN.1| object will be created and `self` will 

364 be returned instead. 

365 """ 

366 if value is noValue: 

367 if not kwargs: 

368 return self 

369 

370 value = self._value 

371 

372 initializers = self.readOnly.copy() 

373 initializers.update(kwargs) 

374 

375 return self.__class__(value, **initializers) 

376 

377 def subtype(self, value=noValue, **kwargs): 

378 """Create a specialization of |ASN.1| schema or value object. 

379 

380 The subtype relationship between ASN.1 types has no correlation with 

381 subtype relationship between Python types. ASN.1 type is mainly identified 

382 by its tag(s) (:py:class:`~pyasn1.type.tag.TagSet`) and value range 

383 constraints (:py:class:`~pyasn1.type.constraint.ConstraintsIntersection`). 

384 These ASN.1 type properties are implemented as |ASN.1| attributes.  

385 

386 The `subtype()` method accepts the same set arguments as |ASN.1| 

387 class takes on instantiation except that all parameters 

388 of the `subtype()` method are optional. 

389 

390 With the exception of the arguments described below, the rest of 

391 supplied arguments they are used to create a copy of `self` taking 

392 precedence over the ones used to instantiate `self`. 

393 

394 The following arguments to `subtype()` create a ASN.1 subtype out of 

395 |ASN.1| type: 

396 

397 Other Parameters 

398 ---------------- 

399 implicitTag: :py:class:`~pyasn1.type.tag.Tag` 

400 Implicitly apply given ASN.1 tag object to `self`'s 

401 :py:class:`~pyasn1.type.tag.TagSet`, then use the result as 

402 new object's ASN.1 tag(s). 

403 

404 explicitTag: :py:class:`~pyasn1.type.tag.Tag` 

405 Explicitly apply given ASN.1 tag object to `self`'s 

406 :py:class:`~pyasn1.type.tag.TagSet`, then use the result as 

407 new object's ASN.1 tag(s). 

408 

409 subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` 

410 Add ASN.1 constraints object to one of the `self`'s, then 

411 use the result as new object's ASN.1 constraints. 

412 

413 Returns 

414 ------- 

415 : 

416 new instance of |ASN.1| schema or value object 

417 

418 Note 

419 ---- 

420 Due to the immutable nature of the |ASN.1| object, if no arguments 

421 are supplied, no new |ASN.1| object will be created and `self` will 

422 be returned instead. 

423 """ 

424 if value is noValue: 

425 if not kwargs: 

426 return self 

427 

428 value = self._value 

429 

430 initializers = self.readOnly.copy() 

431 

432 implicitTag = kwargs.pop('implicitTag', None) 

433 if implicitTag is not None: 

434 initializers['tagSet'] = self.tagSet.tagImplicitly(implicitTag) 

435 

436 explicitTag = kwargs.pop('explicitTag', None) 

437 if explicitTag is not None: 

438 initializers['tagSet'] = self.tagSet.tagExplicitly(explicitTag) 

439 

440 for arg, option in kwargs.items(): 

441 initializers[arg] += option 

442 

443 return self.__class__(value, **initializers) 

444 

445 def prettyIn(self, value): 

446 return value 

447 

448 def prettyOut(self, value): 

449 return str(value) 

450 

451 def prettyPrint(self, scope=0): 

452 return self.prettyOut(self._value) 

453 

454 def prettyPrintType(self, scope=0): 

455 return '%s -> %s' % (self.tagSet, self.__class__.__name__) 

456 

457# Backward compatibility 

458AbstractSimpleAsn1Item = SimpleAsn1Type 

459 

460# 

461# Constructed types: 

462# * There are five of them: Sequence, SequenceOf/SetOf, Set and Choice 

463# * ASN1 types and values are represened by Python class instances 

464# * Value initialization is made for defaulted components only 

465# * Primary method of component addressing is by-position. Data model for base 

466# type is Python sequence. Additional type-specific addressing methods 

467# may be implemented for particular types. 

468# * SequenceOf and SetOf types do not implement any additional methods 

469# * Sequence, Set and Choice types also implement by-identifier addressing 

470# * Sequence, Set and Choice types also implement by-asn1-type (tag) addressing 

471# * Sequence and Set types may include optional and defaulted 

472# components 

473# * Constructed types hold a reference to component types used for value 

474# verification and ordering. 

475# * Component type is a scalar type for SequenceOf/SetOf types and a list 

476# of types for Sequence/Set/Choice. 

477# 

478 

479 

480class ConstructedAsn1Type(Asn1Type): 

481 """Base class for all constructed classes representing ASN.1 types. 

482 

483 ASN.1 distinguishes types by their ability to hold other objects. 

484 Those "nesting" types are known as *constructed* in ASN.1. 

485 

486 In the user code, |ASN.1| class is normally used only for telling 

487 ASN.1 objects from others. 

488 

489 Note 

490 ---- 

491 For as long as ASN.1 is concerned, a way to compare ASN.1 types 

492 is to use :meth:`isSameTypeWith` and :meth:`isSuperTypeOf` methods. 

493 """ 

494 

495 #: If :obj:`True`, requires exact component type matching, 

496 #: otherwise subtype relation is only enforced 

497 strictConstraints = False 

498 

499 componentType = None 

500 

501 # backward compatibility, unused 

502 sizeSpec = constraint.ConstraintsIntersection() 

503 

504 def __init__(self, **kwargs): 

505 readOnly = { 

506 'componentType': self.componentType, 

507 # backward compatibility, unused 

508 'sizeSpec': self.sizeSpec 

509 } 

510 

511 # backward compatibility: preserve legacy sizeSpec support 

512 kwargs = self._moveSizeSpec(**kwargs) 

513 

514 readOnly.update(kwargs) 

515 

516 Asn1Type.__init__(self, **readOnly) 

517 

518 def _moveSizeSpec(self, **kwargs): 

519 # backward compatibility, unused 

520 sizeSpec = kwargs.pop('sizeSpec', self.sizeSpec) 

521 if sizeSpec: 

522 subtypeSpec = kwargs.pop('subtypeSpec', self.subtypeSpec) 

523 if subtypeSpec: 

524 subtypeSpec = sizeSpec 

525 

526 else: 

527 subtypeSpec += sizeSpec 

528 

529 kwargs['subtypeSpec'] = subtypeSpec 

530 

531 return kwargs 

532 

533 def __repr__(self): 

534 representation = '%s %s object' % ( 

535 self.__class__.__name__, self.isValue and 'value' or 'schema' 

536 ) 

537 

538 for attr, value in self.readOnly.items(): 

539 if value is not noValue: 

540 representation += ', %s=%r' % (attr, value) 

541 

542 if self.isValue and self.components: 

543 representation += ', payload [%s]' % ', '.join( 

544 [repr(x) for x in self.components]) 

545 

546 return '<%s>' % representation 

547 

548 def __eq__(self, other): 

549 return self is other or self.components == other 

550 

551 def __ne__(self, other): 

552 return self.components != other 

553 

554 def __lt__(self, other): 

555 return self.components < other 

556 

557 def __le__(self, other): 

558 return self.components <= other 

559 

560 def __gt__(self, other): 

561 return self.components > other 

562 

563 def __ge__(self, other): 

564 return self.components >= other 

565 

566 if sys.version_info[0] <= 2: 

567 def __nonzero__(self): 

568 return bool(self.components) 

569 else: 

570 def __bool__(self): 

571 return bool(self.components) 

572 

573 @property 

574 def components(self): 

575 raise error.PyAsn1Error('Method not implemented') 

576 

577 def _cloneComponentValues(self, myClone, cloneValueFlag): 

578 pass 

579 

580 def clone(self, **kwargs): 

581 """Create a modified version of |ASN.1| schema object. 

582 

583 The `clone()` method accepts the same set arguments as |ASN.1| 

584 class takes on instantiation except that all arguments 

585 of the `clone()` method are optional. 

586 

587 Whatever arguments are supplied, they are used to create a copy 

588 of `self` taking precedence over the ones used to instantiate `self`. 

589 

590 Possible values of `self` are never copied over thus `clone()` can 

591 only create a new schema object. 

592 

593 Returns 

594 ------- 

595 : 

596 new instance of |ASN.1| type/value 

597 

598 Note 

599 ---- 

600 Due to the mutable nature of the |ASN.1| object, even if no arguments 

601 are supplied, a new |ASN.1| object will be created and returned. 

602 """ 

603 cloneValueFlag = kwargs.pop('cloneValueFlag', False) 

604 

605 initializers = self.readOnly.copy() 

606 initializers.update(kwargs) 

607 

608 clone = self.__class__(**initializers) 

609 

610 if cloneValueFlag: 

611 self._cloneComponentValues(clone, cloneValueFlag) 

612 

613 return clone 

614 

615 def subtype(self, **kwargs): 

616 """Create a specialization of |ASN.1| schema object. 

617 

618 The `subtype()` method accepts the same set arguments as |ASN.1| 

619 class takes on instantiation except that all parameters 

620 of the `subtype()` method are optional. 

621 

622 With the exception of the arguments described below, the rest of 

623 supplied arguments they are used to create a copy of `self` taking 

624 precedence over the ones used to instantiate `self`. 

625 

626 The following arguments to `subtype()` create a ASN.1 subtype out of 

627 |ASN.1| type. 

628 

629 Other Parameters 

630 ---------------- 

631 implicitTag: :py:class:`~pyasn1.type.tag.Tag` 

632 Implicitly apply given ASN.1 tag object to `self`'s 

633 :py:class:`~pyasn1.type.tag.TagSet`, then use the result as 

634 new object's ASN.1 tag(s). 

635 

636 explicitTag: :py:class:`~pyasn1.type.tag.Tag` 

637 Explicitly apply given ASN.1 tag object to `self`'s 

638 :py:class:`~pyasn1.type.tag.TagSet`, then use the result as 

639 new object's ASN.1 tag(s). 

640 

641 subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` 

642 Add ASN.1 constraints object to one of the `self`'s, then 

643 use the result as new object's ASN.1 constraints. 

644 

645 

646 Returns 

647 ------- 

648 : 

649 new instance of |ASN.1| type/value 

650 

651 Note 

652 ---- 

653 Due to the mutable nature of the |ASN.1| object, even if no arguments 

654 are supplied, a new |ASN.1| object will be created and returned. 

655 """ 

656 

657 initializers = self.readOnly.copy() 

658 

659 cloneValueFlag = kwargs.pop('cloneValueFlag', False) 

660 

661 implicitTag = kwargs.pop('implicitTag', None) 

662 if implicitTag is not None: 

663 initializers['tagSet'] = self.tagSet.tagImplicitly(implicitTag) 

664 

665 explicitTag = kwargs.pop('explicitTag', None) 

666 if explicitTag is not None: 

667 initializers['tagSet'] = self.tagSet.tagExplicitly(explicitTag) 

668 

669 for arg, option in kwargs.items(): 

670 initializers[arg] += option 

671 

672 clone = self.__class__(**initializers) 

673 

674 if cloneValueFlag: 

675 self._cloneComponentValues(clone, cloneValueFlag) 

676 

677 return clone 

678 

679 def getComponentByPosition(self, idx): 

680 raise error.PyAsn1Error('Method not implemented') 

681 

682 def setComponentByPosition(self, idx, value, verifyConstraints=True): 

683 raise error.PyAsn1Error('Method not implemented') 

684 

685 def setComponents(self, *args, **kwargs): 

686 for idx, value in enumerate(args): 

687 self[idx] = value 

688 for k in kwargs: 

689 self[k] = kwargs[k] 

690 return self 

691 

692 # backward compatibility 

693 

694 def setDefaultComponents(self): 

695 pass 

696 

697 def getComponentType(self): 

698 return self.componentType 

699 

700 # backward compatibility, unused 

701 def verifySizeSpec(self): 

702 self.subtypeSpec(self) 

703 

704 

705 # Backward compatibility 

706AbstractConstructedAsn1Item = ConstructedAsn1Type