Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/asn1crypto/core.py: 64%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

2123 statements  

1# coding: utf-8 

2 

3""" 

4ASN.1 type classes for universal types. Exports the following items: 

5 

6 - load() 

7 - Any() 

8 - Asn1Value() 

9 - BitString() 

10 - BMPString() 

11 - Boolean() 

12 - CharacterString() 

13 - Choice() 

14 - EmbeddedPdv() 

15 - Enumerated() 

16 - GeneralizedTime() 

17 - GeneralString() 

18 - GraphicString() 

19 - IA5String() 

20 - InstanceOf() 

21 - Integer() 

22 - IntegerBitString() 

23 - IntegerOctetString() 

24 - Null() 

25 - NumericString() 

26 - ObjectDescriptor() 

27 - ObjectIdentifier() 

28 - OctetBitString() 

29 - OctetString() 

30 - PrintableString() 

31 - Real() 

32 - RelativeOid() 

33 - Sequence() 

34 - SequenceOf() 

35 - Set() 

36 - SetOf() 

37 - TeletexString() 

38 - UniversalString() 

39 - UTCTime() 

40 - UTF8String() 

41 - VideotexString() 

42 - VisibleString() 

43 - VOID 

44 - Void() 

45 

46Other type classes are defined that help compose the types listed above. 

47""" 

48 

49from __future__ import unicode_literals, division, absolute_import, print_function 

50 

51from datetime import datetime, timedelta 

52from fractions import Fraction 

53import binascii 

54import copy 

55import math 

56import re 

57import sys 

58 

59from . import _teletex_codec 

60from ._errors import unwrap 

61from ._ordereddict import OrderedDict 

62from ._types import type_name, str_cls, byte_cls, int_types, chr_cls 

63from .parser import _parse, _dump_header 

64from .util import int_to_bytes, int_from_bytes, timezone, extended_datetime, create_timezone, utc_with_dst 

65 

66if sys.version_info <= (3,): 

67 from cStringIO import StringIO as BytesIO 

68 

69 range = xrange # noqa 

70 _PY2 = True 

71 

72else: 

73 from io import BytesIO 

74 

75 _PY2 = False 

76 

77 

78_teletex_codec.register() 

79 

80 

81CLASS_NUM_TO_NAME_MAP = { 

82 0: 'universal', 

83 1: 'application', 

84 2: 'context', 

85 3: 'private', 

86} 

87 

88CLASS_NAME_TO_NUM_MAP = { 

89 'universal': 0, 

90 'application': 1, 

91 'context': 2, 

92 'private': 3, 

93 0: 0, 

94 1: 1, 

95 2: 2, 

96 3: 3, 

97} 

98 

99METHOD_NUM_TO_NAME_MAP = { 

100 0: 'primitive', 

101 1: 'constructed', 

102} 

103 

104 

105_OID_RE = re.compile(r'^\d+(\.\d+)*$') 

106 

107 

108# A global tracker to ensure that _setup() is called for every class, even 

109# if is has been called for a parent class. This allows different _fields 

110# definitions for child classes. Without such a construct, the child classes 

111# would just see the parent class attributes and would use them. 

112_SETUP_CLASSES = {} 

113 

114 

115def load(encoded_data, strict=False): 

116 """ 

117 Loads a BER/DER-encoded byte string and construct a universal object based 

118 on the tag value: 

119 

120 - 1: Boolean 

121 - 2: Integer 

122 - 3: BitString 

123 - 4: OctetString 

124 - 5: Null 

125 - 6: ObjectIdentifier 

126 - 7: ObjectDescriptor 

127 - 8: InstanceOf 

128 - 9: Real 

129 - 10: Enumerated 

130 - 11: EmbeddedPdv 

131 - 12: UTF8String 

132 - 13: RelativeOid 

133 - 16: Sequence, 

134 - 17: Set 

135 - 18: NumericString 

136 - 19: PrintableString 

137 - 20: TeletexString 

138 - 21: VideotexString 

139 - 22: IA5String 

140 - 23: UTCTime 

141 - 24: GeneralizedTime 

142 - 25: GraphicString 

143 - 26: VisibleString 

144 - 27: GeneralString 

145 - 28: UniversalString 

146 - 29: CharacterString 

147 - 30: BMPString 

148 

149 :param encoded_data: 

150 A byte string of BER or DER-encoded data 

151 

152 :param strict: 

153 A boolean indicating if trailing data should be forbidden - if so, a 

154 ValueError will be raised when trailing data exists 

155 

156 :raises: 

157 ValueError - when strict is True and trailing data is present 

158 ValueError - when the encoded value tag a tag other than listed above 

159 ValueError - when the ASN.1 header length is longer than the data 

160 TypeError - when encoded_data is not a byte string 

161 

162 :return: 

163 An instance of the one of the universal classes 

164 """ 

165 

166 return Asn1Value.load(encoded_data, strict=strict) 

167 

168 

169class Asn1Value(object): 

170 """ 

171 The basis of all ASN.1 values 

172 """ 

173 

174 # The integer 0 for primitive, 1 for constructed 

175 method = None 

176 

177 # An integer 0 through 3 - see CLASS_NUM_TO_NAME_MAP for value 

178 class_ = None 

179 

180 # An integer 1 or greater indicating the tag number 

181 tag = None 

182 

183 # An alternate tag allowed for this type - used for handling broken 

184 # structures where a string value is encoded using an incorrect tag 

185 _bad_tag = None 

186 

187 # If the value has been implicitly tagged 

188 implicit = False 

189 

190 # If explicitly tagged, a tuple of 2-element tuples containing the 

191 # class int and tag int, from innermost to outermost 

192 explicit = None 

193 

194 # The BER/DER header bytes 

195 _header = None 

196 

197 # Raw encoded value bytes not including class, method, tag, length header 

198 contents = None 

199 

200 # The BER/DER trailer bytes 

201 _trailer = b'' 

202 

203 # The native python representation of the value - this is not used by 

204 # some classes since they utilize _bytes or _unicode 

205 _native = None 

206 

207 @classmethod 

208 def load(cls, encoded_data, strict=False, **kwargs): 

209 """ 

210 Loads a BER/DER-encoded byte string using the current class as the spec 

211 

212 :param encoded_data: 

213 A byte string of BER or DER-encoded data 

214 

215 :param strict: 

216 A boolean indicating if trailing data should be forbidden - if so, a 

217 ValueError will be raised when trailing data exists 

218 

219 :return: 

220 An instance of the current class 

221 """ 

222 

223 if not isinstance(encoded_data, byte_cls): 

224 raise TypeError('encoded_data must be a byte string, not %s' % type_name(encoded_data)) 

225 

226 spec = None 

227 if cls.tag is not None: 

228 spec = cls 

229 

230 value, _ = _parse_build(encoded_data, spec=spec, spec_params=kwargs, strict=strict) 

231 return value 

232 

233 def __init__(self, explicit=None, implicit=None, no_explicit=False, tag_type=None, class_=None, tag=None, 

234 optional=None, default=None, contents=None, method=None): 

235 """ 

236 The optional parameter is not used, but rather included so we don't 

237 have to delete it from the parameter dictionary when passing as keyword 

238 args 

239 

240 :param explicit: 

241 An int tag number for explicit tagging, or a 2-element tuple of 

242 class and tag. 

243 

244 :param implicit: 

245 An int tag number for implicit tagging, or a 2-element tuple of 

246 class and tag. 

247 

248 :param no_explicit: 

249 If explicit tagging info should be removed from this instance. 

250 Used internally to allow contructing the underlying value that 

251 has been wrapped in an explicit tag. 

252 

253 :param tag_type: 

254 None for normal values, or one of "implicit", "explicit" for tagged 

255 values. Deprecated in favor of explicit and implicit params. 

256 

257 :param class_: 

258 The class for the value - defaults to "universal" if tag_type is 

259 None, otherwise defaults to "context". Valid values include: 

260 - "universal" 

261 - "application" 

262 - "context" 

263 - "private" 

264 Deprecated in favor of explicit and implicit params. 

265 

266 :param tag: 

267 The integer tag to override - usually this is used with tag_type or 

268 class_. Deprecated in favor of explicit and implicit params. 

269 

270 :param optional: 

271 Dummy parameter that allows "optional" key in spec param dicts 

272 

273 :param default: 

274 The default value to use if the value is currently None 

275 

276 :param contents: 

277 A byte string of the encoded contents of the value 

278 

279 :param method: 

280 The method for the value - no default value since this is 

281 normally set on a class. Valid values include: 

282 - "primitive" or 0 

283 - "constructed" or 1 

284 

285 :raises: 

286 ValueError - when implicit, explicit, tag_type, class_ or tag are invalid values 

287 """ 

288 

289 try: 

290 if self.__class__ not in _SETUP_CLASSES: 

291 cls = self.__class__ 

292 # Allow explicit to be specified as a simple 2-element tuple 

293 # instead of requiring the user make a nested tuple 

294 if cls.explicit is not None and isinstance(cls.explicit[0], int_types): 

295 cls.explicit = (cls.explicit, ) 

296 if hasattr(cls, '_setup'): 

297 self._setup() 

298 _SETUP_CLASSES[cls] = True 

299 

300 # Normalize tagging values 

301 if explicit is not None: 

302 if isinstance(explicit, int_types): 

303 if class_ is None: 

304 class_ = 'context' 

305 explicit = (class_, explicit) 

306 # Prevent both explicit and tag_type == 'explicit' 

307 if tag_type == 'explicit': 

308 tag_type = None 

309 tag = None 

310 

311 if implicit is not None: 

312 if isinstance(implicit, int_types): 

313 if class_ is None: 

314 class_ = 'context' 

315 implicit = (class_, implicit) 

316 # Prevent both implicit and tag_type == 'implicit' 

317 if tag_type == 'implicit': 

318 tag_type = None 

319 tag = None 

320 

321 # Convert old tag_type API to explicit/implicit params 

322 if tag_type is not None: 

323 if class_ is None: 

324 class_ = 'context' 

325 if tag_type == 'explicit': 

326 explicit = (class_, tag) 

327 elif tag_type == 'implicit': 

328 implicit = (class_, tag) 

329 else: 

330 raise ValueError(unwrap( 

331 ''' 

332 tag_type must be one of "implicit", "explicit", not %s 

333 ''', 

334 repr(tag_type) 

335 )) 

336 

337 if explicit is not None: 

338 # Ensure we have a tuple of 2-element tuples 

339 if len(explicit) == 2 and isinstance(explicit[1], int_types): 

340 explicit = (explicit, ) 

341 for class_, tag in explicit: 

342 invalid_class = None 

343 if isinstance(class_, int_types): 

344 if class_ not in CLASS_NUM_TO_NAME_MAP: 

345 invalid_class = class_ 

346 else: 

347 if class_ not in CLASS_NAME_TO_NUM_MAP: 

348 invalid_class = class_ 

349 class_ = CLASS_NAME_TO_NUM_MAP[class_] 

350 if invalid_class is not None: 

351 raise ValueError(unwrap( 

352 ''' 

353 explicit class must be one of "universal", "application", 

354 "context", "private", not %s 

355 ''', 

356 repr(invalid_class) 

357 )) 

358 if tag is not None: 

359 if not isinstance(tag, int_types): 

360 raise TypeError(unwrap( 

361 ''' 

362 explicit tag must be an integer, not %s 

363 ''', 

364 type_name(tag) 

365 )) 

366 if self.explicit is None: 

367 self.explicit = ((class_, tag), ) 

368 else: 

369 self.explicit = self.explicit + ((class_, tag), ) 

370 

371 elif implicit is not None: 

372 class_, tag = implicit 

373 if class_ not in CLASS_NAME_TO_NUM_MAP: 

374 raise ValueError(unwrap( 

375 ''' 

376 implicit class must be one of "universal", "application", 

377 "context", "private", not %s 

378 ''', 

379 repr(class_) 

380 )) 

381 if tag is not None: 

382 if not isinstance(tag, int_types): 

383 raise TypeError(unwrap( 

384 ''' 

385 implicit tag must be an integer, not %s 

386 ''', 

387 type_name(tag) 

388 )) 

389 self.class_ = CLASS_NAME_TO_NUM_MAP[class_] 

390 self.tag = tag 

391 self.implicit = True 

392 else: 

393 if class_ is not None: 

394 if class_ not in CLASS_NAME_TO_NUM_MAP: 

395 raise ValueError(unwrap( 

396 ''' 

397 class_ must be one of "universal", "application", 

398 "context", "private", not %s 

399 ''', 

400 repr(class_) 

401 )) 

402 self.class_ = CLASS_NAME_TO_NUM_MAP[class_] 

403 

404 if self.class_ is None: 

405 self.class_ = 0 

406 

407 if tag is not None: 

408 self.tag = tag 

409 

410 if method is not None: 

411 if method not in set(["primitive", 0, "constructed", 1]): 

412 raise ValueError(unwrap( 

413 ''' 

414 method must be one of "primitive" or "constructed", 

415 not %s 

416 ''', 

417 repr(method) 

418 )) 

419 if method == "primitive": 

420 method = 0 

421 elif method == "constructed": 

422 method = 1 

423 self.method = method 

424 

425 if no_explicit: 

426 self.explicit = None 

427 

428 if contents is not None: 

429 self.contents = contents 

430 

431 elif default is not None: 

432 self.set(default) 

433 

434 except (ValueError, TypeError) as e: 

435 args = e.args[1:] 

436 e.args = (e.args[0] + '\n while constructing %s' % type_name(self),) + args 

437 raise e 

438 

439 def __str__(self): 

440 """ 

441 Since str is different in Python 2 and 3, this calls the appropriate 

442 method, __unicode__() or __bytes__() 

443 

444 :return: 

445 A unicode string 

446 """ 

447 

448 if _PY2: 

449 return self.__bytes__() 

450 else: 

451 return self.__unicode__() 

452 

453 def __repr__(self): 

454 """ 

455 :return: 

456 A unicode string 

457 """ 

458 

459 if _PY2: 

460 return '<%s %s b%s>' % (type_name(self), id(self), repr(self.dump())) 

461 else: 

462 return '<%s %s %s>' % (type_name(self), id(self), repr(self.dump())) 

463 

464 def __bytes__(self): 

465 """ 

466 A fall-back method for print() in Python 2 

467 

468 :return: 

469 A byte string of the output of repr() 

470 """ 

471 

472 return self.__repr__().encode('utf-8') 

473 

474 def __unicode__(self): 

475 """ 

476 A fall-back method for print() in Python 3 

477 

478 :return: 

479 A unicode string of the output of repr() 

480 """ 

481 

482 return self.__repr__() 

483 

484 def _new_instance(self): 

485 """ 

486 Constructs a new copy of the current object, preserving any tagging 

487 

488 :return: 

489 An Asn1Value object 

490 """ 

491 

492 new_obj = self.__class__() 

493 new_obj.class_ = self.class_ 

494 new_obj.tag = self.tag 

495 new_obj.implicit = self.implicit 

496 new_obj.explicit = self.explicit 

497 return new_obj 

498 

499 def __copy__(self): 

500 """ 

501 Implements the copy.copy() interface 

502 

503 :return: 

504 A new shallow copy of the current Asn1Value object 

505 """ 

506 

507 new_obj = self._new_instance() 

508 new_obj._copy(self, copy.copy) 

509 return new_obj 

510 

511 def __deepcopy__(self, memo): 

512 """ 

513 Implements the copy.deepcopy() interface 

514 

515 :param memo: 

516 A dict for memoization 

517 

518 :return: 

519 A new deep copy of the current Asn1Value object 

520 """ 

521 

522 new_obj = self._new_instance() 

523 memo[id(self)] = new_obj 

524 new_obj._copy(self, copy.deepcopy) 

525 return new_obj 

526 

527 def copy(self): 

528 """ 

529 Copies the object, preserving any special tagging from it 

530 

531 :return: 

532 An Asn1Value object 

533 """ 

534 

535 return copy.deepcopy(self) 

536 

537 def retag(self, tagging, tag=None): 

538 """ 

539 Copies the object, applying a new tagging to it 

540 

541 :param tagging: 

542 A dict containing the keys "explicit" and "implicit". Legacy 

543 API allows a unicode string of "implicit" or "explicit". 

544 

545 :param tag: 

546 A integer tag number. Only used when tagging is a unicode string. 

547 

548 :return: 

549 An Asn1Value object 

550 """ 

551 

552 # This is required to preserve the old API 

553 if not isinstance(tagging, dict): 

554 tagging = {tagging: tag} 

555 new_obj = self.__class__(explicit=tagging.get('explicit'), implicit=tagging.get('implicit')) 

556 new_obj._copy(self, copy.deepcopy) 

557 return new_obj 

558 

559 def untag(self): 

560 """ 

561 Copies the object, removing any special tagging from it 

562 

563 :return: 

564 An Asn1Value object 

565 """ 

566 

567 new_obj = self.__class__() 

568 new_obj._copy(self, copy.deepcopy) 

569 return new_obj 

570 

571 def _copy(self, other, copy_func): 

572 """ 

573 Copies the contents of another Asn1Value object to itself 

574 

575 :param object: 

576 Another instance of the same class 

577 

578 :param copy_func: 

579 An reference of copy.copy() or copy.deepcopy() to use when copying 

580 lists, dicts and objects 

581 """ 

582 

583 if self.__class__ != other.__class__: 

584 raise TypeError(unwrap( 

585 ''' 

586 Can not copy values from %s object to %s object 

587 ''', 

588 type_name(other), 

589 type_name(self) 

590 )) 

591 

592 self.contents = other.contents 

593 self._native = copy_func(other._native) 

594 

595 def debug(self, nest_level=1): 

596 """ 

597 Show the binary data and parsed data in a tree structure 

598 """ 

599 

600 prefix = ' ' * nest_level 

601 

602 # This interacts with Any and moves the tag, implicit, explicit, _header, 

603 # contents, _footer to the parsed value so duplicate data isn't present 

604 has_parsed = hasattr(self, 'parsed') 

605 

606 _basic_debug(prefix, self) 

607 if has_parsed: 

608 self.parsed.debug(nest_level + 2) 

609 elif hasattr(self, 'chosen'): 

610 self.chosen.debug(nest_level + 2) 

611 else: 

612 if _PY2 and isinstance(self.native, byte_cls): 

613 print('%s Native: b%s' % (prefix, repr(self.native))) 

614 else: 

615 print('%s Native: %s' % (prefix, self.native)) 

616 

617 def dump(self, force=False): 

618 """ 

619 Encodes the value using DER 

620 

621 :param force: 

622 If the encoded contents already exist, clear them and regenerate 

623 to ensure they are in DER format instead of BER format 

624 

625 :return: 

626 A byte string of the DER-encoded value 

627 """ 

628 

629 contents = self.contents 

630 

631 # If the length is indefinite, force the re-encoding 

632 if self._header is not None and self._header[-1:] == b'\x80': 

633 force = True 

634 

635 if self._header is None or force: 

636 if isinstance(self, Constructable) and self._indefinite: 

637 self.method = 0 

638 

639 header = _dump_header(self.class_, self.method, self.tag, self.contents) 

640 

641 if self.explicit is not None: 

642 for class_, tag in self.explicit: 

643 header = _dump_header(class_, 1, tag, header + self.contents) + header 

644 

645 self._header = header 

646 self._trailer = b'' 

647 

648 return self._header + contents + self._trailer 

649 

650 

651class ValueMap(): 

652 """ 

653 Basic functionality that allows for mapping values from ints or OIDs to 

654 python unicode strings 

655 """ 

656 

657 # A dict from primitive value (int or OID) to unicode string. This needs 

658 # to be defined in the source code 

659 _map = None 

660 

661 # A dict from unicode string to int/OID. This is automatically generated 

662 # from _map the first time it is needed 

663 _reverse_map = None 

664 

665 def _setup(self): 

666 """ 

667 Generates _reverse_map from _map 

668 """ 

669 

670 cls = self.__class__ 

671 if cls._map is None or cls._reverse_map is not None: 

672 return 

673 cls._reverse_map = {} 

674 for key, value in cls._map.items(): 

675 cls._reverse_map[value] = key 

676 

677 

678class Castable(object): 

679 """ 

680 A mixin to handle converting an object between different classes that 

681 represent the same encoded value, but with different rules for converting 

682 to and from native Python values 

683 """ 

684 

685 def cast(self, other_class): 

686 """ 

687 Converts the current object into an object of a different class. The 

688 new class must use the ASN.1 encoding for the value. 

689 

690 :param other_class: 

691 The class to instantiate the new object from 

692 

693 :return: 

694 An instance of the type other_class 

695 """ 

696 

697 if other_class.tag != self.__class__.tag: 

698 raise TypeError(unwrap( 

699 ''' 

700 Can not covert a value from %s object to %s object since they 

701 use different tags: %d versus %d 

702 ''', 

703 type_name(other_class), 

704 type_name(self), 

705 other_class.tag, 

706 self.__class__.tag 

707 )) 

708 

709 new_obj = other_class() 

710 new_obj.class_ = self.class_ 

711 new_obj.implicit = self.implicit 

712 new_obj.explicit = self.explicit 

713 new_obj._header = self._header 

714 new_obj.contents = self.contents 

715 new_obj._trailer = self._trailer 

716 if isinstance(self, Constructable): 

717 new_obj.method = self.method 

718 new_obj._indefinite = self._indefinite 

719 return new_obj 

720 

721 

722class Constructable(object): 

723 """ 

724 A mixin to handle string types that may be constructed from chunks 

725 contained within an indefinite length BER-encoded container 

726 """ 

727 

728 # Instance attribute indicating if an object was indefinite 

729 # length when parsed - affects parsing and dumping 

730 _indefinite = False 

731 

732 def _merge_chunks(self): 

733 """ 

734 :return: 

735 A concatenation of the native values of the contained chunks 

736 """ 

737 

738 if not self._indefinite: 

739 return self._as_chunk() 

740 

741 pointer = 0 

742 contents_len = len(self.contents) 

743 output = None 

744 

745 while pointer < contents_len: 

746 # We pass the current class as the spec so content semantics are preserved 

747 sub_value, pointer = _parse_build(self.contents, pointer, spec=self.__class__) 

748 if output is None: 

749 output = sub_value._merge_chunks() 

750 else: 

751 output += sub_value._merge_chunks() 

752 

753 if output is None: 

754 return self._as_chunk() 

755 

756 return output 

757 

758 def _as_chunk(self): 

759 """ 

760 A method to return a chunk of data that can be combined for 

761 constructed method values 

762 

763 :return: 

764 A native Python value that can be added together. Examples include 

765 byte strings, unicode strings or tuples. 

766 """ 

767 

768 return self.contents 

769 

770 def _setable_native(self): 

771 """ 

772 Returns a native value that can be round-tripped into .set(), to 

773 result in a DER encoding. This differs from .native in that .native 

774 is designed for the end use, and may account for the fact that the 

775 merged value is further parsed as ASN.1, such as in the case of 

776 ParsableOctetString() and ParsableOctetBitString(). 

777 

778 :return: 

779 A python value that is valid to pass to .set() 

780 """ 

781 

782 return self.native 

783 

784 def _copy(self, other, copy_func): 

785 """ 

786 Copies the contents of another Constructable object to itself 

787 

788 :param object: 

789 Another instance of the same class 

790 

791 :param copy_func: 

792 An reference of copy.copy() or copy.deepcopy() to use when copying 

793 lists, dicts and objects 

794 """ 

795 

796 super(Constructable, self)._copy(other, copy_func) 

797 # We really don't want to dump BER encodings, so if we see an 

798 # indefinite encoding, let's re-encode it 

799 if other._indefinite: 

800 self.set(other._setable_native()) 

801 

802 

803class Void(Asn1Value): 

804 """ 

805 A representation of an optional value that is not present. Has .native 

806 property and .dump() method to be compatible with other value classes. 

807 """ 

808 

809 contents = b'' 

810 

811 def __eq__(self, other): 

812 """ 

813 :param other: 

814 The other Primitive to compare to 

815 

816 :return: 

817 A boolean 

818 """ 

819 

820 return other.__class__ == self.__class__ 

821 

822 def __nonzero__(self): 

823 return False 

824 

825 def __len__(self): 

826 return 0 

827 

828 def __iter__(self): 

829 return iter(()) 

830 

831 @property 

832 def native(self): 

833 """ 

834 The native Python datatype representation of this value 

835 

836 :return: 

837 None 

838 """ 

839 

840 return None 

841 

842 def dump(self, force=False): 

843 """ 

844 Encodes the value using DER 

845 

846 :param force: 

847 If the encoded contents already exist, clear them and regenerate 

848 to ensure they are in DER format instead of BER format 

849 

850 :return: 

851 A byte string of the DER-encoded value 

852 """ 

853 

854 return b'' 

855 

856 

857VOID = Void() 

858 

859 

860class Any(Asn1Value): 

861 """ 

862 A value class that can contain any value, and allows for easy parsing of 

863 the underlying encoded value using a spec. This is normally contained in 

864 a Structure that has an ObjectIdentifier field and _oid_pair and _oid_specs 

865 defined. 

866 """ 

867 

868 # The parsed value object 

869 _parsed = None 

870 

871 def __init__(self, value=None, **kwargs): 

872 """ 

873 Sets the value of the object before passing to Asn1Value.__init__() 

874 

875 :param value: 

876 An Asn1Value object that will be set as the parsed value 

877 """ 

878 

879 Asn1Value.__init__(self, **kwargs) 

880 

881 try: 

882 if value is not None: 

883 if not isinstance(value, Asn1Value): 

884 raise TypeError(unwrap( 

885 ''' 

886 value must be an instance of Asn1Value, not %s 

887 ''', 

888 type_name(value) 

889 )) 

890 

891 self._parsed = (value, value.__class__, None) 

892 self.contents = value.dump() 

893 

894 except (ValueError, TypeError) as e: 

895 args = e.args[1:] 

896 e.args = (e.args[0] + '\n while constructing %s' % type_name(self),) + args 

897 raise e 

898 

899 @property 

900 def native(self): 

901 """ 

902 The native Python datatype representation of this value 

903 

904 :return: 

905 The .native value from the parsed value object 

906 """ 

907 

908 if self._parsed is None: 

909 self.parse() 

910 

911 return self._parsed[0].native 

912 

913 @property 

914 def parsed(self): 

915 """ 

916 Returns the parsed object from .parse() 

917 

918 :return: 

919 The object returned by .parse() 

920 """ 

921 

922 if self._parsed is None: 

923 self.parse() 

924 

925 return self._parsed[0] 

926 

927 def parse(self, spec=None, spec_params=None): 

928 """ 

929 Parses the contents generically, or using a spec with optional params 

930 

931 :param spec: 

932 A class derived from Asn1Value that defines what class_ and tag the 

933 value should have, and the semantics of the encoded value. The 

934 return value will be of this type. If omitted, the encoded value 

935 will be decoded using the standard universal tag based on the 

936 encoded tag number. 

937 

938 :param spec_params: 

939 A dict of params to pass to the spec object 

940 

941 :return: 

942 An object of the type spec, or if not present, a child of Asn1Value 

943 """ 

944 

945 if self._parsed is None or self._parsed[1:3] != (spec, spec_params): 

946 try: 

947 passed_params = spec_params or {} 

948 _tag_type_to_explicit_implicit(passed_params) 

949 if self.explicit is not None: 

950 if 'explicit' in passed_params: 

951 passed_params['explicit'] = self.explicit + passed_params['explicit'] 

952 else: 

953 passed_params['explicit'] = self.explicit 

954 contents = self._header + self.contents + self._trailer 

955 parsed_value, _ = _parse_build( 

956 contents, 

957 spec=spec, 

958 spec_params=passed_params 

959 ) 

960 self._parsed = (parsed_value, spec, spec_params) 

961 

962 # Once we've parsed the Any value, clear any attributes from this object 

963 # since they are now duplicate 

964 self.tag = None 

965 self.explicit = None 

966 self.implicit = False 

967 self._header = b'' 

968 self.contents = contents 

969 self._trailer = b'' 

970 

971 except (ValueError, TypeError) as e: 

972 args = e.args[1:] 

973 e.args = (e.args[0] + '\n while parsing %s' % type_name(self),) + args 

974 raise e 

975 return self._parsed[0] 

976 

977 def _copy(self, other, copy_func): 

978 """ 

979 Copies the contents of another Any object to itself 

980 

981 :param object: 

982 Another instance of the same class 

983 

984 :param copy_func: 

985 An reference of copy.copy() or copy.deepcopy() to use when copying 

986 lists, dicts and objects 

987 """ 

988 

989 super(Any, self)._copy(other, copy_func) 

990 self._parsed = copy_func(other._parsed) 

991 

992 def dump(self, force=False): 

993 """ 

994 Encodes the value using DER 

995 

996 :param force: 

997 If the encoded contents already exist, clear them and regenerate 

998 to ensure they are in DER format instead of BER format 

999 

1000 :return: 

1001 A byte string of the DER-encoded value 

1002 """ 

1003 

1004 if self._parsed is None: 

1005 self.parse() 

1006 

1007 return self._parsed[0].dump(force=force) 

1008 

1009 

1010class Choice(Asn1Value): 

1011 """ 

1012 A class to handle when a value may be one of several options 

1013 """ 

1014 

1015 # The index in _alternatives of the validated alternative 

1016 _choice = None 

1017 

1018 # The name of the chosen alternative 

1019 _name = None 

1020 

1021 # The Asn1Value object for the chosen alternative 

1022 _parsed = None 

1023 

1024 # Choice overrides .contents to be a property so that the code expecting 

1025 # the .contents attribute will get the .contents of the chosen alternative 

1026 _contents = None 

1027 

1028 # A list of tuples in one of the following forms. 

1029 # 

1030 # Option 1, a unicode string field name and a value class 

1031 # 

1032 # ("name", Asn1ValueClass) 

1033 # 

1034 # Option 2, same as Option 1, but with a dict of class params 

1035 # 

1036 # ("name", Asn1ValueClass, {'explicit': 5}) 

1037 _alternatives = None 

1038 

1039 # A dict that maps tuples of (class_, tag) to an index in _alternatives 

1040 _id_map = None 

1041 

1042 # A dict that maps alternative names to an index in _alternatives 

1043 _name_map = None 

1044 

1045 @classmethod 

1046 def load(cls, encoded_data, strict=False, **kwargs): 

1047 """ 

1048 Loads a BER/DER-encoded byte string using the current class as the spec 

1049 

1050 :param encoded_data: 

1051 A byte string of BER or DER encoded data 

1052 

1053 :param strict: 

1054 A boolean indicating if trailing data should be forbidden - if so, a 

1055 ValueError will be raised when trailing data exists 

1056 

1057 :return: 

1058 A instance of the current class 

1059 """ 

1060 

1061 if not isinstance(encoded_data, byte_cls): 

1062 raise TypeError('encoded_data must be a byte string, not %s' % type_name(encoded_data)) 

1063 

1064 value, _ = _parse_build(encoded_data, spec=cls, spec_params=kwargs, strict=strict) 

1065 return value 

1066 

1067 def _setup(self): 

1068 """ 

1069 Generates _id_map from _alternatives to allow validating contents 

1070 """ 

1071 

1072 cls = self.__class__ 

1073 cls._id_map = {} 

1074 cls._name_map = {} 

1075 for index, info in enumerate(cls._alternatives): 

1076 if len(info) < 3: 

1077 info = info + ({},) 

1078 cls._alternatives[index] = info 

1079 id_ = _build_id_tuple(info[2], info[1]) 

1080 cls._id_map[id_] = index 

1081 cls._name_map[info[0]] = index 

1082 

1083 def __init__(self, name=None, value=None, **kwargs): 

1084 """ 

1085 Checks to ensure implicit tagging is not being used since it is 

1086 incompatible with Choice, then forwards on to Asn1Value.__init__() 

1087 

1088 :param name: 

1089 The name of the alternative to be set - used with value. 

1090 Alternatively this may be a dict with a single key being the name 

1091 and the value being the value, or a two-element tuple of the name 

1092 and the value. 

1093 

1094 :param value: 

1095 The alternative value to set - used with name 

1096 

1097 :raises: 

1098 ValueError - when implicit param is passed (or legacy tag_type param is "implicit") 

1099 """ 

1100 

1101 _tag_type_to_explicit_implicit(kwargs) 

1102 

1103 Asn1Value.__init__(self, **kwargs) 

1104 

1105 try: 

1106 if kwargs.get('implicit') is not None: 

1107 raise ValueError(unwrap( 

1108 ''' 

1109 The Choice type can not be implicitly tagged even if in an 

1110 implicit module - due to its nature any tagging must be 

1111 explicit 

1112 ''' 

1113 )) 

1114 

1115 if name is not None: 

1116 if isinstance(name, dict): 

1117 if len(name) != 1: 

1118 raise ValueError(unwrap( 

1119 ''' 

1120 When passing a dict as the "name" argument to %s, 

1121 it must have a single key/value - however %d were 

1122 present 

1123 ''', 

1124 type_name(self), 

1125 len(name) 

1126 )) 

1127 name, value = list(name.items())[0] 

1128 

1129 if isinstance(name, tuple): 

1130 if len(name) != 2: 

1131 raise ValueError(unwrap( 

1132 ''' 

1133 When passing a tuple as the "name" argument to %s, 

1134 it must have two elements, the name and value - 

1135 however %d were present 

1136 ''', 

1137 type_name(self), 

1138 len(name) 

1139 )) 

1140 value = name[1] 

1141 name = name[0] 

1142 

1143 if name not in self._name_map: 

1144 raise ValueError(unwrap( 

1145 ''' 

1146 The name specified, "%s", is not a valid alternative 

1147 for %s 

1148 ''', 

1149 name, 

1150 type_name(self) 

1151 )) 

1152 

1153 self._choice = self._name_map[name] 

1154 _, spec, params = self._alternatives[self._choice] 

1155 

1156 if not isinstance(value, spec): 

1157 value = spec(value, **params) 

1158 else: 

1159 value = _fix_tagging(value, params) 

1160 self._parsed = value 

1161 

1162 except (ValueError, TypeError) as e: 

1163 args = e.args[1:] 

1164 e.args = (e.args[0] + '\n while constructing %s' % type_name(self),) + args 

1165 raise e 

1166 

1167 @property 

1168 def contents(self): 

1169 """ 

1170 :return: 

1171 A byte string of the DER-encoded contents of the chosen alternative 

1172 """ 

1173 

1174 if self._parsed is not None: 

1175 return self._parsed.contents 

1176 

1177 return self._contents 

1178 

1179 @contents.setter 

1180 def contents(self, value): 

1181 """ 

1182 :param value: 

1183 A byte string of the DER-encoded contents of the chosen alternative 

1184 """ 

1185 

1186 self._contents = value 

1187 

1188 @property 

1189 def name(self): 

1190 """ 

1191 :return: 

1192 A unicode string of the field name of the chosen alternative 

1193 """ 

1194 if not self._name: 

1195 self._name = self._alternatives[self._choice][0] 

1196 return self._name 

1197 

1198 def parse(self): 

1199 """ 

1200 Parses the detected alternative 

1201 

1202 :return: 

1203 An Asn1Value object of the chosen alternative 

1204 """ 

1205 

1206 if self._parsed is None: 

1207 try: 

1208 _, spec, params = self._alternatives[self._choice] 

1209 self._parsed, _ = _parse_build(self._contents, spec=spec, spec_params=params) 

1210 except (ValueError, TypeError) as e: 

1211 args = e.args[1:] 

1212 e.args = (e.args[0] + '\n while parsing %s' % type_name(self),) + args 

1213 raise e 

1214 return self._parsed 

1215 

1216 @property 

1217 def chosen(self): 

1218 """ 

1219 :return: 

1220 An Asn1Value object of the chosen alternative 

1221 """ 

1222 

1223 return self.parse() 

1224 

1225 @property 

1226 def native(self): 

1227 """ 

1228 The native Python datatype representation of this value 

1229 

1230 :return: 

1231 The .native value from the contained value object 

1232 """ 

1233 

1234 return self.chosen.native 

1235 

1236 def validate(self, class_, tag, contents): 

1237 """ 

1238 Ensures that the class and tag specified exist as an alternative 

1239 

1240 :param class_: 

1241 The integer class_ from the encoded value header 

1242 

1243 :param tag: 

1244 The integer tag from the encoded value header 

1245 

1246 :param contents: 

1247 A byte string of the contents of the value - used when the object 

1248 is explicitly tagged 

1249 

1250 :raises: 

1251 ValueError - when value is not a valid alternative 

1252 """ 

1253 

1254 id_ = (class_, tag) 

1255 

1256 if self.explicit is not None: 

1257 if self.explicit[-1] != id_: 

1258 raise ValueError(unwrap( 

1259 ''' 

1260 %s was explicitly tagged, but the value provided does not 

1261 match the class and tag 

1262 ''', 

1263 type_name(self) 

1264 )) 

1265 

1266 ((class_, _, tag, _, _, _), _) = _parse(contents, len(contents)) 

1267 id_ = (class_, tag) 

1268 

1269 if id_ in self._id_map: 

1270 self._choice = self._id_map[id_] 

1271 return 

1272 

1273 # This means the Choice was implicitly tagged 

1274 if self.class_ is not None and self.tag is not None: 

1275 if len(self._alternatives) > 1: 

1276 raise ValueError(unwrap( 

1277 ''' 

1278 %s was implicitly tagged, but more than one alternative 

1279 exists 

1280 ''', 

1281 type_name(self) 

1282 )) 

1283 if id_ == (self.class_, self.tag): 

1284 self._choice = 0 

1285 return 

1286 

1287 asn1 = self._format_class_tag(class_, tag) 

1288 asn1s = [self._format_class_tag(pair[0], pair[1]) for pair in self._id_map] 

1289 

1290 raise ValueError(unwrap( 

1291 ''' 

1292 Value %s did not match the class and tag of any of the alternatives 

1293 in %s: %s 

1294 ''', 

1295 asn1, 

1296 type_name(self), 

1297 ', '.join(asn1s) 

1298 )) 

1299 

1300 def _format_class_tag(self, class_, tag): 

1301 """ 

1302 :return: 

1303 A unicode string of a human-friendly representation of the class and tag 

1304 """ 

1305 

1306 return '[%s %s]' % (CLASS_NUM_TO_NAME_MAP[class_].upper(), tag) 

1307 

1308 def _copy(self, other, copy_func): 

1309 """ 

1310 Copies the contents of another Choice object to itself 

1311 

1312 :param object: 

1313 Another instance of the same class 

1314 

1315 :param copy_func: 

1316 An reference of copy.copy() or copy.deepcopy() to use when copying 

1317 lists, dicts and objects 

1318 """ 

1319 

1320 super(Choice, self)._copy(other, copy_func) 

1321 self._choice = other._choice 

1322 self._name = other._name 

1323 self._parsed = copy_func(other._parsed) 

1324 

1325 def dump(self, force=False): 

1326 """ 

1327 Encodes the value using DER 

1328 

1329 :param force: 

1330 If the encoded contents already exist, clear them and regenerate 

1331 to ensure they are in DER format instead of BER format 

1332 

1333 :return: 

1334 A byte string of the DER-encoded value 

1335 """ 

1336 

1337 # If the length is indefinite, force the re-encoding 

1338 if self._header is not None and self._header[-1:] == b'\x80': 

1339 force = True 

1340 

1341 self._contents = self.chosen.dump(force=force) 

1342 if self._header is None or force: 

1343 self._header = b'' 

1344 if self.explicit is not None: 

1345 for class_, tag in self.explicit: 

1346 self._header = _dump_header(class_, 1, tag, self._header + self._contents) + self._header 

1347 return self._header + self._contents 

1348 

1349 

1350class Concat(object): 

1351 """ 

1352 A class that contains two or more encoded child values concatentated 

1353 together. THIS IS NOT PART OF THE ASN.1 SPECIFICATION! This exists to handle 

1354 the x509.TrustedCertificate() class for OpenSSL certificates containing 

1355 extra information. 

1356 """ 

1357 

1358 # A list of the specs of the concatenated values 

1359 _child_specs = None 

1360 

1361 _children = None 

1362 

1363 @classmethod 

1364 def load(cls, encoded_data, strict=False): 

1365 """ 

1366 Loads a BER/DER-encoded byte string using the current class as the spec 

1367 

1368 :param encoded_data: 

1369 A byte string of BER or DER encoded data 

1370 

1371 :param strict: 

1372 A boolean indicating if trailing data should be forbidden - if so, a 

1373 ValueError will be raised when trailing data exists 

1374 

1375 :return: 

1376 A Concat object 

1377 """ 

1378 

1379 return cls(contents=encoded_data, strict=strict) 

1380 

1381 def __init__(self, value=None, contents=None, strict=False): 

1382 """ 

1383 :param value: 

1384 A native Python datatype to initialize the object value with 

1385 

1386 :param contents: 

1387 A byte string of the encoded contents of the value 

1388 

1389 :param strict: 

1390 A boolean indicating if trailing data should be forbidden - if so, a 

1391 ValueError will be raised when trailing data exists in contents 

1392 

1393 :raises: 

1394 ValueError - when an error occurs with one of the children 

1395 TypeError - when an error occurs with one of the children 

1396 """ 

1397 

1398 if contents is not None: 

1399 try: 

1400 contents_len = len(contents) 

1401 self._children = [] 

1402 

1403 offset = 0 

1404 for spec in self._child_specs: 

1405 if offset < contents_len: 

1406 child_value, offset = _parse_build(contents, pointer=offset, spec=spec) 

1407 else: 

1408 child_value = spec() 

1409 self._children.append(child_value) 

1410 

1411 if strict and offset != contents_len: 

1412 extra_bytes = contents_len - offset 

1413 raise ValueError('Extra data - %d bytes of trailing data were provided' % extra_bytes) 

1414 

1415 except (ValueError, TypeError) as e: 

1416 args = e.args[1:] 

1417 e.args = (e.args[0] + '\n while constructing %s' % type_name(self),) + args 

1418 raise e 

1419 

1420 if value is not None: 

1421 if self._children is None: 

1422 self._children = [None] * len(self._child_specs) 

1423 for index, data in enumerate(value): 

1424 self.__setitem__(index, data) 

1425 

1426 def __str__(self): 

1427 """ 

1428 Since str is different in Python 2 and 3, this calls the appropriate 

1429 method, __unicode__() or __bytes__() 

1430 

1431 :return: 

1432 A unicode string 

1433 """ 

1434 

1435 if _PY2: 

1436 return self.__bytes__() 

1437 else: 

1438 return self.__unicode__() 

1439 

1440 def __bytes__(self): 

1441 """ 

1442 A byte string of the DER-encoded contents 

1443 """ 

1444 

1445 return self.dump() 

1446 

1447 def __unicode__(self): 

1448 """ 

1449 :return: 

1450 A unicode string 

1451 """ 

1452 

1453 return repr(self) 

1454 

1455 def __repr__(self): 

1456 """ 

1457 :return: 

1458 A unicode string 

1459 """ 

1460 

1461 return '<%s %s %s>' % (type_name(self), id(self), repr(self.dump())) 

1462 

1463 def __copy__(self): 

1464 """ 

1465 Implements the copy.copy() interface 

1466 

1467 :return: 

1468 A new shallow copy of the Concat object 

1469 """ 

1470 

1471 new_obj = self.__class__() 

1472 new_obj._copy(self, copy.copy) 

1473 return new_obj 

1474 

1475 def __deepcopy__(self, memo): 

1476 """ 

1477 Implements the copy.deepcopy() interface 

1478 

1479 :param memo: 

1480 A dict for memoization 

1481 

1482 :return: 

1483 A new deep copy of the Concat object and all child objects 

1484 """ 

1485 

1486 new_obj = self.__class__() 

1487 memo[id(self)] = new_obj 

1488 new_obj._copy(self, copy.deepcopy) 

1489 return new_obj 

1490 

1491 def copy(self): 

1492 """ 

1493 Copies the object 

1494 

1495 :return: 

1496 A Concat object 

1497 """ 

1498 

1499 return copy.deepcopy(self) 

1500 

1501 def _copy(self, other, copy_func): 

1502 """ 

1503 Copies the contents of another Concat object to itself 

1504 

1505 :param object: 

1506 Another instance of the same class 

1507 

1508 :param copy_func: 

1509 An reference of copy.copy() or copy.deepcopy() to use when copying 

1510 lists, dicts and objects 

1511 """ 

1512 

1513 if self.__class__ != other.__class__: 

1514 raise TypeError(unwrap( 

1515 ''' 

1516 Can not copy values from %s object to %s object 

1517 ''', 

1518 type_name(other), 

1519 type_name(self) 

1520 )) 

1521 

1522 self._children = copy_func(other._children) 

1523 

1524 def debug(self, nest_level=1): 

1525 """ 

1526 Show the binary data and parsed data in a tree structure 

1527 """ 

1528 

1529 prefix = ' ' * nest_level 

1530 print('%s%s Object #%s' % (prefix, type_name(self), id(self))) 

1531 print('%s Children:' % (prefix,)) 

1532 for child in self._children: 

1533 child.debug(nest_level + 2) 

1534 

1535 def dump(self, force=False): 

1536 """ 

1537 Encodes the value using DER 

1538 

1539 :param force: 

1540 If the encoded contents already exist, clear them and regenerate 

1541 to ensure they are in DER format instead of BER format 

1542 

1543 :return: 

1544 A byte string of the DER-encoded value 

1545 """ 

1546 

1547 contents = b'' 

1548 for child in self._children: 

1549 contents += child.dump(force=force) 

1550 return contents 

1551 

1552 @property 

1553 def contents(self): 

1554 """ 

1555 :return: 

1556 A byte string of the DER-encoded contents of the children 

1557 """ 

1558 

1559 return self.dump() 

1560 

1561 def __len__(self): 

1562 """ 

1563 :return: 

1564 Integer 

1565 """ 

1566 

1567 return len(self._children) 

1568 

1569 def __getitem__(self, key): 

1570 """ 

1571 Allows accessing children by index 

1572 

1573 :param key: 

1574 An integer of the child index 

1575 

1576 :raises: 

1577 KeyError - when an index is invalid 

1578 

1579 :return: 

1580 The Asn1Value object of the child specified 

1581 """ 

1582 

1583 if key > len(self._child_specs) - 1 or key < 0: 

1584 raise KeyError(unwrap( 

1585 ''' 

1586 No child is definition for position %d of %s 

1587 ''', 

1588 key, 

1589 type_name(self) 

1590 )) 

1591 

1592 return self._children[key] 

1593 

1594 def __setitem__(self, key, value): 

1595 """ 

1596 Allows settings children by index 

1597 

1598 :param key: 

1599 An integer of the child index 

1600 

1601 :param value: 

1602 An Asn1Value object to set the child to 

1603 

1604 :raises: 

1605 KeyError - when an index is invalid 

1606 ValueError - when the value is not an instance of Asn1Value 

1607 """ 

1608 

1609 if key > len(self._child_specs) - 1 or key < 0: 

1610 raise KeyError(unwrap( 

1611 ''' 

1612 No child is defined for position %d of %s 

1613 ''', 

1614 key, 

1615 type_name(self) 

1616 )) 

1617 

1618 if not isinstance(value, Asn1Value): 

1619 raise ValueError(unwrap( 

1620 ''' 

1621 Value for child %s of %s is not an instance of 

1622 asn1crypto.core.Asn1Value 

1623 ''', 

1624 key, 

1625 type_name(self) 

1626 )) 

1627 

1628 self._children[key] = value 

1629 

1630 def __iter__(self): 

1631 """ 

1632 :return: 

1633 An iterator of child values 

1634 """ 

1635 

1636 return iter(self._children) 

1637 

1638 

1639class Primitive(Asn1Value): 

1640 """ 

1641 Sets the class_ and method attributes for primitive, universal values 

1642 """ 

1643 

1644 class_ = 0 

1645 

1646 method = 0 

1647 

1648 def __init__(self, value=None, default=None, contents=None, **kwargs): 

1649 """ 

1650 Sets the value of the object before passing to Asn1Value.__init__() 

1651 

1652 :param value: 

1653 A native Python datatype to initialize the object value with 

1654 

1655 :param default: 

1656 The default value if no value is specified 

1657 

1658 :param contents: 

1659 A byte string of the encoded contents of the value 

1660 """ 

1661 

1662 Asn1Value.__init__(self, **kwargs) 

1663 

1664 try: 

1665 if contents is not None: 

1666 self.contents = contents 

1667 

1668 elif value is not None: 

1669 self.set(value) 

1670 

1671 elif default is not None: 

1672 self.set(default) 

1673 

1674 except (ValueError, TypeError) as e: 

1675 args = e.args[1:] 

1676 e.args = (e.args[0] + '\n while constructing %s' % type_name(self),) + args 

1677 raise e 

1678 

1679 def set(self, value): 

1680 """ 

1681 Sets the value of the object 

1682 

1683 :param value: 

1684 A byte string 

1685 """ 

1686 

1687 if not isinstance(value, byte_cls): 

1688 raise TypeError(unwrap( 

1689 ''' 

1690 %s value must be a byte string, not %s 

1691 ''', 

1692 type_name(self), 

1693 type_name(value) 

1694 )) 

1695 

1696 self._native = value 

1697 self.contents = value 

1698 self._header = None 

1699 if self._trailer != b'': 

1700 self._trailer = b'' 

1701 

1702 def dump(self, force=False): 

1703 """ 

1704 Encodes the value using DER 

1705 

1706 :param force: 

1707 If the encoded contents already exist, clear them and regenerate 

1708 to ensure they are in DER format instead of BER format 

1709 

1710 :return: 

1711 A byte string of the DER-encoded value 

1712 """ 

1713 

1714 # If the length is indefinite, force the re-encoding 

1715 if self._header is not None and self._header[-1:] == b'\x80': 

1716 force = True 

1717 

1718 if force: 

1719 native = self.native 

1720 self.contents = None 

1721 self.set(native) 

1722 

1723 return Asn1Value.dump(self) 

1724 

1725 def __ne__(self, other): 

1726 return not self == other 

1727 

1728 def __eq__(self, other): 

1729 """ 

1730 :param other: 

1731 The other Primitive to compare to 

1732 

1733 :return: 

1734 A boolean 

1735 """ 

1736 

1737 if not isinstance(other, Primitive): 

1738 return False 

1739 

1740 if self.contents != other.contents: 

1741 return False 

1742 

1743 # We compare class tag numbers since object tag numbers could be 

1744 # different due to implicit or explicit tagging 

1745 if self.__class__.tag != other.__class__.tag: 

1746 return False 

1747 

1748 if self.__class__ == other.__class__ and self.contents == other.contents: 

1749 return True 

1750 

1751 # If the objects share a common base class that is not too low-level 

1752 # then we can compare the contents 

1753 self_bases = (set(self.__class__.__bases__) | set([self.__class__])) - set([Asn1Value, Primitive, ValueMap]) 

1754 other_bases = (set(other.__class__.__bases__) | set([other.__class__])) - set([Asn1Value, Primitive, ValueMap]) 

1755 if self_bases | other_bases: 

1756 return self.contents == other.contents 

1757 

1758 # When tagging is going on, do the extra work of constructing new 

1759 # objects to see if the dumped representation are the same 

1760 if self.implicit or self.explicit or other.implicit or other.explicit: 

1761 return self.untag().dump() == other.untag().dump() 

1762 

1763 return self.dump() == other.dump() 

1764 

1765 

1766class AbstractString(Constructable, Primitive): 

1767 """ 

1768 A base class for all strings that have a known encoding. In general, we do 

1769 not worry ourselves with confirming that the decoded values match a specific 

1770 set of characters, only that they are decoded into a Python unicode string 

1771 """ 

1772 

1773 # The Python encoding name to use when decoding or encoded the contents 

1774 _encoding = 'latin1' 

1775 

1776 # Instance attribute of (possibly-merged) unicode string 

1777 _unicode = None 

1778 

1779 def set(self, value): 

1780 """ 

1781 Sets the value of the string 

1782 

1783 :param value: 

1784 A unicode string 

1785 """ 

1786 

1787 if not isinstance(value, str_cls): 

1788 raise TypeError(unwrap( 

1789 ''' 

1790 %s value must be a unicode string, not %s 

1791 ''', 

1792 type_name(self), 

1793 type_name(value) 

1794 )) 

1795 

1796 self._unicode = value 

1797 self.contents = value.encode(self._encoding) 

1798 self._header = None 

1799 if self._indefinite: 

1800 self._indefinite = False 

1801 self.method = 0 

1802 if self._trailer != b'': 

1803 self._trailer = b'' 

1804 

1805 def __unicode__(self): 

1806 """ 

1807 :return: 

1808 A unicode string 

1809 """ 

1810 

1811 if self.contents is None: 

1812 return '' 

1813 if self._unicode is None: 

1814 self._unicode = self._merge_chunks().decode(self._encoding) 

1815 return self._unicode 

1816 

1817 def _copy(self, other, copy_func): 

1818 """ 

1819 Copies the contents of another AbstractString object to itself 

1820 

1821 :param object: 

1822 Another instance of the same class 

1823 

1824 :param copy_func: 

1825 An reference of copy.copy() or copy.deepcopy() to use when copying 

1826 lists, dicts and objects 

1827 """ 

1828 

1829 super(AbstractString, self)._copy(other, copy_func) 

1830 self._unicode = other._unicode 

1831 

1832 @property 

1833 def native(self): 

1834 """ 

1835 The native Python datatype representation of this value 

1836 

1837 :return: 

1838 A unicode string or None 

1839 """ 

1840 

1841 if self.contents is None: 

1842 return None 

1843 

1844 return self.__unicode__() 

1845 

1846 

1847class Boolean(Primitive): 

1848 """ 

1849 Represents a boolean in both ASN.1 and Python 

1850 """ 

1851 

1852 tag = 1 

1853 

1854 def set(self, value): 

1855 """ 

1856 Sets the value of the object 

1857 

1858 :param value: 

1859 True, False or another value that works with bool() 

1860 """ 

1861 

1862 self._native = bool(value) 

1863 self.contents = b'\x00' if not value else b'\xff' 

1864 self._header = None 

1865 if self._trailer != b'': 

1866 self._trailer = b'' 

1867 

1868 # Python 2 

1869 def __nonzero__(self): 

1870 """ 

1871 :return: 

1872 True or False 

1873 """ 

1874 return self.__bool__() 

1875 

1876 def __bool__(self): 

1877 """ 

1878 :return: 

1879 True or False 

1880 """ 

1881 return self.contents != b'\x00' 

1882 

1883 @property 

1884 def native(self): 

1885 """ 

1886 The native Python datatype representation of this value 

1887 

1888 :return: 

1889 True, False or None 

1890 """ 

1891 

1892 if self.contents is None: 

1893 return None 

1894 

1895 if self._native is None: 

1896 self._native = self.__bool__() 

1897 return self._native 

1898 

1899 

1900class Integer(Primitive, ValueMap): 

1901 """ 

1902 Represents an integer in both ASN.1 and Python 

1903 """ 

1904 

1905 tag = 2 

1906 

1907 def set(self, value): 

1908 """ 

1909 Sets the value of the object 

1910 

1911 :param value: 

1912 An integer, or a unicode string if _map is set 

1913 

1914 :raises: 

1915 ValueError - when an invalid value is passed 

1916 """ 

1917 

1918 if isinstance(value, str_cls): 

1919 if self._map is None: 

1920 raise ValueError(unwrap( 

1921 ''' 

1922 %s value is a unicode string, but no _map provided 

1923 ''', 

1924 type_name(self) 

1925 )) 

1926 

1927 if value not in self._reverse_map: 

1928 raise ValueError(unwrap( 

1929 ''' 

1930 %s value, %s, is not present in the _map 

1931 ''', 

1932 type_name(self), 

1933 value 

1934 )) 

1935 

1936 value = self._reverse_map[value] 

1937 

1938 elif not isinstance(value, int_types): 

1939 raise TypeError(unwrap( 

1940 ''' 

1941 %s value must be an integer or unicode string when a name_map 

1942 is provided, not %s 

1943 ''', 

1944 type_name(self), 

1945 type_name(value) 

1946 )) 

1947 

1948 self._native = self._map[value] if self._map and value in self._map else value 

1949 

1950 self.contents = int_to_bytes(value, signed=True) 

1951 self._header = None 

1952 if self._trailer != b'': 

1953 self._trailer = b'' 

1954 

1955 def __int__(self): 

1956 """ 

1957 :return: 

1958 An integer 

1959 """ 

1960 return int_from_bytes(self.contents, signed=True) 

1961 

1962 @property 

1963 def native(self): 

1964 """ 

1965 The native Python datatype representation of this value 

1966 

1967 :return: 

1968 An integer or None 

1969 """ 

1970 

1971 if self.contents is None: 

1972 return None 

1973 

1974 if self._native is None: 

1975 self._native = self.__int__() 

1976 if self._map is not None and self._native in self._map: 

1977 self._native = self._map[self._native] 

1978 return self._native 

1979 

1980 

1981class _IntegerBitString(object): 

1982 """ 

1983 A mixin for IntegerBitString and BitString to parse the contents as an integer. 

1984 """ 

1985 

1986 # Tuple of 1s and 0s; set through native 

1987 _unused_bits = () 

1988 

1989 def _as_chunk(self): 

1990 """ 

1991 Parse the contents of a primitive BitString encoding as an integer value. 

1992 Allows reconstructing indefinite length values. 

1993 

1994 :raises: 

1995 ValueError - when an invalid value is passed 

1996 

1997 :return: 

1998 A list with one tuple (value, bits, unused_bits) where value is an integer 

1999 with the value of the BitString, bits is the bit count of value and 

2000 unused_bits is a tuple of 1s and 0s. 

2001 """ 

2002 

2003 if self._indefinite: 

2004 # return an empty chunk, for cases like \x23\x80\x00\x00 

2005 return [] 

2006 

2007 unused_bits_len = ord(self.contents[0]) if _PY2 else self.contents[0] 

2008 value = int_from_bytes(self.contents[1:]) 

2009 bits = (len(self.contents) - 1) * 8 

2010 

2011 if not unused_bits_len: 

2012 return [(value, bits, ())] 

2013 

2014 if len(self.contents) == 1: 

2015 # Disallowed by X.690 §8.6.2.3 

2016 raise ValueError('Empty bit string has {0} unused bits'.format(unused_bits_len)) 

2017 

2018 if unused_bits_len > 7: 

2019 # Disallowed by X.690 §8.6.2.2 

2020 raise ValueError('Bit string has {0} unused bits'.format(unused_bits_len)) 

2021 

2022 unused_bits = _int_to_bit_tuple(value & ((1 << unused_bits_len) - 1), unused_bits_len) 

2023 value >>= unused_bits_len 

2024 bits -= unused_bits_len 

2025 

2026 return [(value, bits, unused_bits)] 

2027 

2028 def _chunks_to_int(self): 

2029 """ 

2030 Combines the chunks into a single value. 

2031 

2032 :raises: 

2033 ValueError - when an invalid value is passed 

2034 

2035 :return: 

2036 A tuple (value, bits, unused_bits) where value is an integer with the 

2037 value of the BitString, bits is the bit count of value and unused_bits 

2038 is a tuple of 1s and 0s. 

2039 """ 

2040 

2041 if not self._indefinite: 

2042 # Fast path 

2043 return self._as_chunk()[0] 

2044 

2045 value = 0 

2046 total_bits = 0 

2047 unused_bits = () 

2048 

2049 # X.690 §8.6.3 allows empty indefinite encodings 

2050 for chunk, bits, unused_bits in self._merge_chunks(): 

2051 if total_bits & 7: 

2052 # Disallowed by X.690 §8.6.4 

2053 raise ValueError('Only last chunk in a bit string may have unused bits') 

2054 total_bits += bits 

2055 value = (value << bits) | chunk 

2056 

2057 return value, total_bits, unused_bits 

2058 

2059 def _copy(self, other, copy_func): 

2060 """ 

2061 Copies the contents of another _IntegerBitString object to itself 

2062 

2063 :param object: 

2064 Another instance of the same class 

2065 

2066 :param copy_func: 

2067 An reference of copy.copy() or copy.deepcopy() to use when copying 

2068 lists, dicts and objects 

2069 """ 

2070 

2071 super(_IntegerBitString, self)._copy(other, copy_func) 

2072 self._unused_bits = other._unused_bits 

2073 

2074 @property 

2075 def unused_bits(self): 

2076 """ 

2077 The unused bits of the bit string encoding. 

2078 

2079 :return: 

2080 A tuple of 1s and 0s 

2081 """ 

2082 

2083 # call native to set _unused_bits 

2084 self.native 

2085 

2086 return self._unused_bits 

2087 

2088 

2089class BitString(_IntegerBitString, Constructable, Castable, Primitive, ValueMap): 

2090 """ 

2091 Represents a bit string from ASN.1 as a Python tuple of 1s and 0s 

2092 """ 

2093 

2094 tag = 3 

2095 

2096 _size = None 

2097 

2098 def _setup(self): 

2099 """ 

2100 Generates _reverse_map from _map 

2101 """ 

2102 

2103 ValueMap._setup(self) 

2104 

2105 cls = self.__class__ 

2106 if cls._map is not None: 

2107 cls._size = max(self._map.keys()) + 1 

2108 

2109 def set(self, value): 

2110 """ 

2111 Sets the value of the object 

2112 

2113 :param value: 

2114 An integer or a tuple of integers 0 and 1 

2115 

2116 :raises: 

2117 ValueError - when an invalid value is passed 

2118 """ 

2119 

2120 if isinstance(value, set): 

2121 if self._map is None: 

2122 raise ValueError(unwrap( 

2123 ''' 

2124 %s._map has not been defined 

2125 ''', 

2126 type_name(self) 

2127 )) 

2128 

2129 bits = [0] * self._size 

2130 self._native = value 

2131 for index in range(0, self._size): 

2132 key = self._map.get(index) 

2133 if key is None: 

2134 continue 

2135 if key in value: 

2136 bits[index] = 1 

2137 

2138 value = ''.join(map(str_cls, bits)) 

2139 

2140 elif value.__class__ == tuple: 

2141 if self._map is None: 

2142 self._native = value 

2143 else: 

2144 self._native = set() 

2145 for index, bit in enumerate(value): 

2146 if bit: 

2147 name = self._map.get(index, index) 

2148 self._native.add(name) 

2149 value = ''.join(map(str_cls, value)) 

2150 

2151 else: 

2152 raise TypeError(unwrap( 

2153 ''' 

2154 %s value must be a tuple of ones and zeros or a set of unicode 

2155 strings, not %s 

2156 ''', 

2157 type_name(self), 

2158 type_name(value) 

2159 )) 

2160 

2161 if self._map is not None: 

2162 if len(value) > self._size: 

2163 raise ValueError(unwrap( 

2164 ''' 

2165 %s value must be at most %s bits long, specified was %s long 

2166 ''', 

2167 type_name(self), 

2168 self._size, 

2169 len(value) 

2170 )) 

2171 # A NamedBitList must have trailing zero bit truncated. See 

2172 # https://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf 

2173 # section 11.2, 

2174 # https://tools.ietf.org/html/rfc5280#page-134 and 

2175 # https://www.ietf.org/mail-archive/web/pkix/current/msg10443.html 

2176 value = value.rstrip('0') 

2177 size = len(value) 

2178 

2179 size_mod = size % 8 

2180 extra_bits = 0 

2181 if size_mod != 0: 

2182 extra_bits = 8 - size_mod 

2183 value += '0' * extra_bits 

2184 

2185 size_in_bytes = int(math.ceil(size / 8)) 

2186 

2187 if extra_bits: 

2188 extra_bits_byte = int_to_bytes(extra_bits) 

2189 else: 

2190 extra_bits_byte = b'\x00' 

2191 

2192 if value == '': 

2193 value_bytes = b'' 

2194 else: 

2195 value_bytes = int_to_bytes(int(value, 2)) 

2196 if len(value_bytes) != size_in_bytes: 

2197 value_bytes = (b'\x00' * (size_in_bytes - len(value_bytes))) + value_bytes 

2198 

2199 self.contents = extra_bits_byte + value_bytes 

2200 self._unused_bits = (0,) * extra_bits 

2201 self._header = None 

2202 if self._indefinite: 

2203 self._indefinite = False 

2204 self.method = 0 

2205 if self._trailer != b'': 

2206 self._trailer = b'' 

2207 

2208 def __getitem__(self, key): 

2209 """ 

2210 Retrieves a boolean version of one of the bits based on a name from the 

2211 _map 

2212 

2213 :param key: 

2214 The unicode string of one of the bit names 

2215 

2216 :raises: 

2217 ValueError - when _map is not set or the key name is invalid 

2218 

2219 :return: 

2220 A boolean if the bit is set 

2221 """ 

2222 

2223 is_int = isinstance(key, int_types) 

2224 if not is_int: 

2225 if not isinstance(self._map, dict): 

2226 raise ValueError(unwrap( 

2227 ''' 

2228 %s._map has not been defined 

2229 ''', 

2230 type_name(self) 

2231 )) 

2232 

2233 if key not in self._reverse_map: 

2234 raise ValueError(unwrap( 

2235 ''' 

2236 %s._map does not contain an entry for "%s" 

2237 ''', 

2238 type_name(self), 

2239 key 

2240 )) 

2241 

2242 if self._native is None: 

2243 self.native 

2244 

2245 if self._map is None: 

2246 if len(self._native) >= key + 1: 

2247 return bool(self._native[key]) 

2248 return False 

2249 

2250 if is_int: 

2251 key = self._map.get(key, key) 

2252 

2253 return key in self._native 

2254 

2255 def __setitem__(self, key, value): 

2256 """ 

2257 Sets one of the bits based on a name from the _map 

2258 

2259 :param key: 

2260 The unicode string of one of the bit names 

2261 

2262 :param value: 

2263 A boolean value 

2264 

2265 :raises: 

2266 ValueError - when _map is not set or the key name is invalid 

2267 """ 

2268 

2269 is_int = isinstance(key, int_types) 

2270 if not is_int: 

2271 if self._map is None: 

2272 raise ValueError(unwrap( 

2273 ''' 

2274 %s._map has not been defined 

2275 ''', 

2276 type_name(self) 

2277 )) 

2278 

2279 if key not in self._reverse_map: 

2280 raise ValueError(unwrap( 

2281 ''' 

2282 %s._map does not contain an entry for "%s" 

2283 ''', 

2284 type_name(self), 

2285 key 

2286 )) 

2287 

2288 if self._native is None: 

2289 self.native 

2290 

2291 if self._map is None: 

2292 new_native = list(self._native) 

2293 max_key = len(new_native) - 1 

2294 if key > max_key: 

2295 new_native.extend([0] * (key - max_key)) 

2296 new_native[key] = 1 if value else 0 

2297 self._native = tuple(new_native) 

2298 

2299 else: 

2300 if is_int: 

2301 key = self._map.get(key, key) 

2302 

2303 if value: 

2304 if key not in self._native: 

2305 self._native.add(key) 

2306 else: 

2307 if key in self._native: 

2308 self._native.remove(key) 

2309 

2310 self.set(self._native) 

2311 

2312 @property 

2313 def native(self): 

2314 """ 

2315 The native Python datatype representation of this value 

2316 

2317 :return: 

2318 If a _map is set, a set of names, or if no _map is set, a tuple of 

2319 integers 1 and 0. None if no value. 

2320 """ 

2321 

2322 # For BitString we default the value to be all zeros 

2323 if self.contents is None: 

2324 if self._map is None: 

2325 self.set(()) 

2326 else: 

2327 self.set(set()) 

2328 

2329 if self._native is None: 

2330 int_value, bit_count, self._unused_bits = self._chunks_to_int() 

2331 bits = _int_to_bit_tuple(int_value, bit_count) 

2332 

2333 if self._map: 

2334 self._native = set() 

2335 for index, bit in enumerate(bits): 

2336 if bit: 

2337 name = self._map.get(index, index) 

2338 self._native.add(name) 

2339 else: 

2340 self._native = bits 

2341 return self._native 

2342 

2343 

2344class OctetBitString(Constructable, Castable, Primitive): 

2345 """ 

2346 Represents a bit string in ASN.1 as a Python byte string 

2347 """ 

2348 

2349 tag = 3 

2350 

2351 # Instance attribute of (possibly-merged) byte string 

2352 _bytes = None 

2353 

2354 # Tuple of 1s and 0s; set through native 

2355 _unused_bits = () 

2356 

2357 def set(self, value): 

2358 """ 

2359 Sets the value of the object 

2360 

2361 :param value: 

2362 A byte string 

2363 

2364 :raises: 

2365 ValueError - when an invalid value is passed 

2366 """ 

2367 

2368 if not isinstance(value, byte_cls): 

2369 raise TypeError(unwrap( 

2370 ''' 

2371 %s value must be a byte string, not %s 

2372 ''', 

2373 type_name(self), 

2374 type_name(value) 

2375 )) 

2376 

2377 self._bytes = value 

2378 # Set the unused bits to 0 

2379 self.contents = b'\x00' + value 

2380 self._unused_bits = () 

2381 self._header = None 

2382 if self._indefinite: 

2383 self._indefinite = False 

2384 self.method = 0 

2385 if self._trailer != b'': 

2386 self._trailer = b'' 

2387 

2388 def __bytes__(self): 

2389 """ 

2390 :return: 

2391 A byte string 

2392 """ 

2393 

2394 if self.contents is None: 

2395 return b'' 

2396 if self._bytes is None: 

2397 if not self._indefinite: 

2398 self._bytes, self._unused_bits = self._as_chunk()[0] 

2399 else: 

2400 chunks = self._merge_chunks() 

2401 self._unused_bits = () 

2402 for chunk in chunks: 

2403 if self._unused_bits: 

2404 # Disallowed by X.690 §8.6.4 

2405 raise ValueError('Only last chunk in a bit string may have unused bits') 

2406 self._unused_bits = chunk[1] 

2407 self._bytes = b''.join(chunk[0] for chunk in chunks) 

2408 

2409 return self._bytes 

2410 

2411 def _copy(self, other, copy_func): 

2412 """ 

2413 Copies the contents of another OctetBitString object to itself 

2414 

2415 :param object: 

2416 Another instance of the same class 

2417 

2418 :param copy_func: 

2419 An reference of copy.copy() or copy.deepcopy() to use when copying 

2420 lists, dicts and objects 

2421 """ 

2422 

2423 super(OctetBitString, self)._copy(other, copy_func) 

2424 self._bytes = other._bytes 

2425 self._unused_bits = other._unused_bits 

2426 

2427 def _as_chunk(self): 

2428 """ 

2429 Allows reconstructing indefinite length values 

2430 

2431 :raises: 

2432 ValueError - when an invalid value is passed 

2433 

2434 :return: 

2435 List with one tuple, consisting of a byte string and an integer (unused bits) 

2436 """ 

2437 

2438 unused_bits_len = ord(self.contents[0]) if _PY2 else self.contents[0] 

2439 if not unused_bits_len: 

2440 return [(self.contents[1:], ())] 

2441 

2442 if len(self.contents) == 1: 

2443 # Disallowed by X.690 §8.6.2.3 

2444 raise ValueError('Empty bit string has {0} unused bits'.format(unused_bits_len)) 

2445 

2446 if unused_bits_len > 7: 

2447 # Disallowed by X.690 §8.6.2.2 

2448 raise ValueError('Bit string has {0} unused bits'.format(unused_bits_len)) 

2449 

2450 mask = (1 << unused_bits_len) - 1 

2451 last_byte = ord(self.contents[-1]) if _PY2 else self.contents[-1] 

2452 

2453 # zero out the unused bits in the last byte. 

2454 zeroed_byte = last_byte & ~mask 

2455 value = self.contents[1:-1] + (chr(zeroed_byte) if _PY2 else bytes((zeroed_byte,))) 

2456 

2457 unused_bits = _int_to_bit_tuple(last_byte & mask, unused_bits_len) 

2458 

2459 return [(value, unused_bits)] 

2460 

2461 @property 

2462 def native(self): 

2463 """ 

2464 The native Python datatype representation of this value 

2465 

2466 :return: 

2467 A byte string or None 

2468 """ 

2469 

2470 if self.contents is None: 

2471 return None 

2472 

2473 return self.__bytes__() 

2474 

2475 @property 

2476 def unused_bits(self): 

2477 """ 

2478 The unused bits of the bit string encoding. 

2479 

2480 :return: 

2481 A tuple of 1s and 0s 

2482 """ 

2483 

2484 # call native to set _unused_bits 

2485 self.native 

2486 

2487 return self._unused_bits 

2488 

2489 

2490class IntegerBitString(_IntegerBitString, Constructable, Castable, Primitive): 

2491 """ 

2492 Represents a bit string in ASN.1 as a Python integer 

2493 """ 

2494 

2495 tag = 3 

2496 

2497 def set(self, value): 

2498 """ 

2499 Sets the value of the object 

2500 

2501 :param value: 

2502 An integer 

2503 

2504 :raises: 

2505 ValueError - when an invalid value is passed 

2506 """ 

2507 

2508 if not isinstance(value, int_types): 

2509 raise TypeError(unwrap( 

2510 ''' 

2511 %s value must be a positive integer, not %s 

2512 ''', 

2513 type_name(self), 

2514 type_name(value) 

2515 )) 

2516 

2517 if value < 0: 

2518 raise ValueError(unwrap( 

2519 ''' 

2520 %s value must be a positive integer, not %d 

2521 ''', 

2522 type_name(self), 

2523 value 

2524 )) 

2525 

2526 self._native = value 

2527 # Set the unused bits to 0 

2528 self.contents = b'\x00' + int_to_bytes(value, signed=True) 

2529 self._unused_bits = () 

2530 self._header = None 

2531 if self._indefinite: 

2532 self._indefinite = False 

2533 self.method = 0 

2534 if self._trailer != b'': 

2535 self._trailer = b'' 

2536 

2537 @property 

2538 def native(self): 

2539 """ 

2540 The native Python datatype representation of this value 

2541 

2542 :return: 

2543 An integer or None 

2544 """ 

2545 

2546 if self.contents is None: 

2547 return None 

2548 

2549 if self._native is None: 

2550 self._native, __, self._unused_bits = self._chunks_to_int() 

2551 

2552 return self._native 

2553 

2554 

2555class OctetString(Constructable, Castable, Primitive): 

2556 """ 

2557 Represents a byte string in both ASN.1 and Python 

2558 """ 

2559 

2560 tag = 4 

2561 

2562 # Instance attribute of (possibly-merged) byte string 

2563 _bytes = None 

2564 

2565 def set(self, value): 

2566 """ 

2567 Sets the value of the object 

2568 

2569 :param value: 

2570 A byte string 

2571 """ 

2572 

2573 if not isinstance(value, byte_cls): 

2574 raise TypeError(unwrap( 

2575 ''' 

2576 %s value must be a byte string, not %s 

2577 ''', 

2578 type_name(self), 

2579 type_name(value) 

2580 )) 

2581 

2582 self._bytes = value 

2583 self.contents = value 

2584 self._header = None 

2585 if self._indefinite: 

2586 self._indefinite = False 

2587 self.method = 0 

2588 if self._trailer != b'': 

2589 self._trailer = b'' 

2590 

2591 def __bytes__(self): 

2592 """ 

2593 :return: 

2594 A byte string 

2595 """ 

2596 

2597 if self.contents is None: 

2598 return b'' 

2599 if self._bytes is None: 

2600 self._bytes = self._merge_chunks() 

2601 return self._bytes 

2602 

2603 def _copy(self, other, copy_func): 

2604 """ 

2605 Copies the contents of another OctetString object to itself 

2606 

2607 :param object: 

2608 Another instance of the same class 

2609 

2610 :param copy_func: 

2611 An reference of copy.copy() or copy.deepcopy() to use when copying 

2612 lists, dicts and objects 

2613 """ 

2614 

2615 super(OctetString, self)._copy(other, copy_func) 

2616 self._bytes = other._bytes 

2617 

2618 @property 

2619 def native(self): 

2620 """ 

2621 The native Python datatype representation of this value 

2622 

2623 :return: 

2624 A byte string or None 

2625 """ 

2626 

2627 if self.contents is None: 

2628 return None 

2629 

2630 return self.__bytes__() 

2631 

2632 

2633class IntegerOctetString(Constructable, Castable, Primitive): 

2634 """ 

2635 Represents a byte string in ASN.1 as a Python integer 

2636 """ 

2637 

2638 tag = 4 

2639 

2640 # An explicit length in bytes the integer should be encoded to. This should 

2641 # generally not be used since DER defines a canonical encoding, however some 

2642 # use of this, such as when storing elliptic curve private keys, requires an 

2643 # exact number of bytes, even if the leading bytes are null. 

2644 _encoded_width = None 

2645 

2646 def set(self, value): 

2647 """ 

2648 Sets the value of the object 

2649 

2650 :param value: 

2651 An integer 

2652 

2653 :raises: 

2654 ValueError - when an invalid value is passed 

2655 """ 

2656 

2657 if not isinstance(value, int_types): 

2658 raise TypeError(unwrap( 

2659 ''' 

2660 %s value must be a positive integer, not %s 

2661 ''', 

2662 type_name(self), 

2663 type_name(value) 

2664 )) 

2665 

2666 if value < 0: 

2667 raise ValueError(unwrap( 

2668 ''' 

2669 %s value must be a positive integer, not %d 

2670 ''', 

2671 type_name(self), 

2672 value 

2673 )) 

2674 

2675 self._native = value 

2676 self.contents = int_to_bytes(value, signed=False, width=self._encoded_width) 

2677 self._header = None 

2678 if self._indefinite: 

2679 self._indefinite = False 

2680 self.method = 0 

2681 if self._trailer != b'': 

2682 self._trailer = b'' 

2683 

2684 @property 

2685 def native(self): 

2686 """ 

2687 The native Python datatype representation of this value 

2688 

2689 :return: 

2690 An integer or None 

2691 """ 

2692 

2693 if self.contents is None: 

2694 return None 

2695 

2696 if self._native is None: 

2697 self._native = int_from_bytes(self._merge_chunks()) 

2698 return self._native 

2699 

2700 def set_encoded_width(self, width): 

2701 """ 

2702 Set the explicit enoding width for the integer 

2703 

2704 :param width: 

2705 An integer byte width to encode the integer to 

2706 """ 

2707 

2708 self._encoded_width = width 

2709 # Make sure the encoded value is up-to-date with the proper width 

2710 if self.contents is not None and len(self.contents) != width: 

2711 self.set(self.native) 

2712 

2713 

2714class ParsableOctetString(Constructable, Castable, Primitive): 

2715 

2716 tag = 4 

2717 

2718 _parsed = None 

2719 

2720 # Instance attribute of (possibly-merged) byte string 

2721 _bytes = None 

2722 

2723 def __init__(self, value=None, parsed=None, **kwargs): 

2724 """ 

2725 Allows providing a parsed object that will be serialized to get the 

2726 byte string value 

2727 

2728 :param value: 

2729 A native Python datatype to initialize the object value with 

2730 

2731 :param parsed: 

2732 If value is None and this is an Asn1Value object, this will be 

2733 set as the parsed value, and the value will be obtained by calling 

2734 .dump() on this object. 

2735 """ 

2736 

2737 set_parsed = False 

2738 if value is None and parsed is not None and isinstance(parsed, Asn1Value): 

2739 value = parsed.dump() 

2740 set_parsed = True 

2741 

2742 Primitive.__init__(self, value=value, **kwargs) 

2743 

2744 if set_parsed: 

2745 self._parsed = (parsed, parsed.__class__, None) 

2746 

2747 def set(self, value): 

2748 """ 

2749 Sets the value of the object 

2750 

2751 :param value: 

2752 A byte string 

2753 """ 

2754 

2755 if not isinstance(value, byte_cls): 

2756 raise TypeError(unwrap( 

2757 ''' 

2758 %s value must be a byte string, not %s 

2759 ''', 

2760 type_name(self), 

2761 type_name(value) 

2762 )) 

2763 

2764 self._bytes = value 

2765 self.contents = value 

2766 self._header = None 

2767 if self._indefinite: 

2768 self._indefinite = False 

2769 self.method = 0 

2770 if self._trailer != b'': 

2771 self._trailer = b'' 

2772 

2773 def parse(self, spec=None, spec_params=None): 

2774 """ 

2775 Parses the contents generically, or using a spec with optional params 

2776 

2777 :param spec: 

2778 A class derived from Asn1Value that defines what class_ and tag the 

2779 value should have, and the semantics of the encoded value. The 

2780 return value will be of this type. If omitted, the encoded value 

2781 will be decoded using the standard universal tag based on the 

2782 encoded tag number. 

2783 

2784 :param spec_params: 

2785 A dict of params to pass to the spec object 

2786 

2787 :return: 

2788 An object of the type spec, or if not present, a child of Asn1Value 

2789 """ 

2790 

2791 if self._parsed is None or self._parsed[1:3] != (spec, spec_params): 

2792 parsed_value, _ = _parse_build(self.__bytes__(), spec=spec, spec_params=spec_params) 

2793 self._parsed = (parsed_value, spec, spec_params) 

2794 return self._parsed[0] 

2795 

2796 def __bytes__(self): 

2797 """ 

2798 :return: 

2799 A byte string 

2800 """ 

2801 

2802 if self.contents is None: 

2803 return b'' 

2804 if self._bytes is None: 

2805 self._bytes = self._merge_chunks() 

2806 return self._bytes 

2807 

2808 def _setable_native(self): 

2809 """ 

2810 Returns a byte string that can be passed into .set() 

2811 

2812 :return: 

2813 A python value that is valid to pass to .set() 

2814 """ 

2815 

2816 return self.__bytes__() 

2817 

2818 def _copy(self, other, copy_func): 

2819 """ 

2820 Copies the contents of another ParsableOctetString object to itself 

2821 

2822 :param object: 

2823 Another instance of the same class 

2824 

2825 :param copy_func: 

2826 An reference of copy.copy() or copy.deepcopy() to use when copying 

2827 lists, dicts and objects 

2828 """ 

2829 

2830 super(ParsableOctetString, self)._copy(other, copy_func) 

2831 self._bytes = other._bytes 

2832 self._parsed = copy_func(other._parsed) 

2833 

2834 @property 

2835 def native(self): 

2836 """ 

2837 The native Python datatype representation of this value 

2838 

2839 :return: 

2840 A byte string or None 

2841 """ 

2842 

2843 if self.contents is None: 

2844 return None 

2845 

2846 if self._parsed is not None: 

2847 return self._parsed[0].native 

2848 else: 

2849 return self.__bytes__() 

2850 

2851 @property 

2852 def parsed(self): 

2853 """ 

2854 Returns the parsed object from .parse() 

2855 

2856 :return: 

2857 The object returned by .parse() 

2858 """ 

2859 

2860 if self._parsed is None: 

2861 self.parse() 

2862 

2863 return self._parsed[0] 

2864 

2865 def dump(self, force=False): 

2866 """ 

2867 Encodes the value using DER 

2868 

2869 :param force: 

2870 If the encoded contents already exist, clear them and regenerate 

2871 to ensure they are in DER format instead of BER format 

2872 

2873 :return: 

2874 A byte string of the DER-encoded value 

2875 """ 

2876 

2877 # If the length is indefinite, force the re-encoding 

2878 if self._indefinite: 

2879 force = True 

2880 

2881 if force: 

2882 if self._parsed is not None: 

2883 native = self.parsed.dump(force=force) 

2884 else: 

2885 native = self.native 

2886 self.contents = None 

2887 self.set(native) 

2888 

2889 return Asn1Value.dump(self) 

2890 

2891 

2892class ParsableOctetBitString(ParsableOctetString): 

2893 

2894 tag = 3 

2895 

2896 def set(self, value): 

2897 """ 

2898 Sets the value of the object 

2899 

2900 :param value: 

2901 A byte string 

2902 

2903 :raises: 

2904 ValueError - when an invalid value is passed 

2905 """ 

2906 

2907 if not isinstance(value, byte_cls): 

2908 raise TypeError(unwrap( 

2909 ''' 

2910 %s value must be a byte string, not %s 

2911 ''', 

2912 type_name(self), 

2913 type_name(value) 

2914 )) 

2915 

2916 self._bytes = value 

2917 # Set the unused bits to 0 

2918 self.contents = b'\x00' + value 

2919 self._header = None 

2920 if self._indefinite: 

2921 self._indefinite = False 

2922 self.method = 0 

2923 if self._trailer != b'': 

2924 self._trailer = b'' 

2925 

2926 def _as_chunk(self): 

2927 """ 

2928 Allows reconstructing indefinite length values 

2929 

2930 :raises: 

2931 ValueError - when an invalid value is passed 

2932 

2933 :return: 

2934 A byte string 

2935 """ 

2936 

2937 unused_bits_len = ord(self.contents[0]) if _PY2 else self.contents[0] 

2938 if unused_bits_len: 

2939 raise ValueError('ParsableOctetBitString should have no unused bits') 

2940 

2941 return self.contents[1:] 

2942 

2943 

2944class Null(Primitive): 

2945 """ 

2946 Represents a null value in ASN.1 as None in Python 

2947 """ 

2948 

2949 tag = 5 

2950 

2951 contents = b'' 

2952 

2953 def set(self, value): 

2954 """ 

2955 Sets the value of the object 

2956 

2957 :param value: 

2958 None 

2959 """ 

2960 

2961 self.contents = b'' 

2962 

2963 @property 

2964 def native(self): 

2965 """ 

2966 The native Python datatype representation of this value 

2967 

2968 :return: 

2969 None 

2970 """ 

2971 

2972 return None 

2973 

2974 

2975class ObjectIdentifier(Primitive, ValueMap): 

2976 """ 

2977 Represents an object identifier in ASN.1 as a Python unicode dotted 

2978 integer string 

2979 """ 

2980 

2981 tag = 6 

2982 

2983 # A unicode string of the dotted form of the object identifier 

2984 _dotted = None 

2985 

2986 @classmethod 

2987 def map(cls, value): 

2988 """ 

2989 Converts a dotted unicode string OID into a mapped unicode string 

2990 

2991 :param value: 

2992 A dotted unicode string OID 

2993 

2994 :raises: 

2995 ValueError - when no _map dict has been defined on the class 

2996 TypeError - when value is not a unicode string 

2997 

2998 :return: 

2999 A mapped unicode string 

3000 """ 

3001 

3002 if cls._map is None: 

3003 raise ValueError(unwrap( 

3004 ''' 

3005 %s._map has not been defined 

3006 ''', 

3007 type_name(cls) 

3008 )) 

3009 

3010 if not isinstance(value, str_cls): 

3011 raise TypeError(unwrap( 

3012 ''' 

3013 value must be a unicode string, not %s 

3014 ''', 

3015 type_name(value) 

3016 )) 

3017 

3018 return cls._map.get(value, value) 

3019 

3020 @classmethod 

3021 def unmap(cls, value): 

3022 """ 

3023 Converts a mapped unicode string value into a dotted unicode string OID 

3024 

3025 :param value: 

3026 A mapped unicode string OR dotted unicode string OID 

3027 

3028 :raises: 

3029 ValueError - when no _map dict has been defined on the class or the value can't be unmapped 

3030 TypeError - when value is not a unicode string 

3031 

3032 :return: 

3033 A dotted unicode string OID 

3034 """ 

3035 

3036 if cls not in _SETUP_CLASSES: 

3037 cls()._setup() 

3038 _SETUP_CLASSES[cls] = True 

3039 

3040 if cls._map is None: 

3041 raise ValueError(unwrap( 

3042 ''' 

3043 %s._map has not been defined 

3044 ''', 

3045 type_name(cls) 

3046 )) 

3047 

3048 if not isinstance(value, str_cls): 

3049 raise TypeError(unwrap( 

3050 ''' 

3051 value must be a unicode string, not %s 

3052 ''', 

3053 type_name(value) 

3054 )) 

3055 

3056 if value in cls._reverse_map: 

3057 return cls._reverse_map[value] 

3058 

3059 if not _OID_RE.match(value): 

3060 raise ValueError(unwrap( 

3061 ''' 

3062 %s._map does not contain an entry for "%s" 

3063 ''', 

3064 type_name(cls), 

3065 value 

3066 )) 

3067 

3068 return value 

3069 

3070 def set(self, value): 

3071 """ 

3072 Sets the value of the object 

3073 

3074 :param value: 

3075 A unicode string. May be a dotted integer string, or if _map is 

3076 provided, one of the mapped values. 

3077 

3078 :raises: 

3079 ValueError - when an invalid value is passed 

3080 """ 

3081 

3082 if not isinstance(value, str_cls): 

3083 raise TypeError(unwrap( 

3084 ''' 

3085 %s value must be a unicode string, not %s 

3086 ''', 

3087 type_name(self), 

3088 type_name(value) 

3089 )) 

3090 

3091 self._native = value 

3092 

3093 if self._map is not None: 

3094 if value in self._reverse_map: 

3095 value = self._reverse_map[value] 

3096 

3097 self.contents = b'' 

3098 first = None 

3099 for index, part in enumerate(value.split('.')): 

3100 part = int(part) 

3101 

3102 # The first two parts are merged into a single byte 

3103 if index == 0: 

3104 first = part 

3105 continue 

3106 elif index == 1: 

3107 if first > 2: 

3108 raise ValueError(unwrap( 

3109 ''' 

3110 First arc must be one of 0, 1 or 2, not %s 

3111 ''', 

3112 repr(first) 

3113 )) 

3114 elif first < 2 and part >= 40: 

3115 raise ValueError(unwrap( 

3116 ''' 

3117 Second arc must be less than 40 if first arc is 0 or 

3118 1, not %s 

3119 ''', 

3120 repr(part) 

3121 )) 

3122 part = (first * 40) + part 

3123 

3124 encoded_part = chr_cls(0x7F & part) 

3125 part = part >> 7 

3126 while part > 0: 

3127 encoded_part = chr_cls(0x80 | (0x7F & part)) + encoded_part 

3128 part = part >> 7 

3129 self.contents += encoded_part 

3130 

3131 self._header = None 

3132 if self._trailer != b'': 

3133 self._trailer = b'' 

3134 

3135 def __unicode__(self): 

3136 """ 

3137 :return: 

3138 A unicode string 

3139 """ 

3140 

3141 return self.dotted 

3142 

3143 @property 

3144 def dotted(self): 

3145 """ 

3146 :return: 

3147 A unicode string of the object identifier in dotted notation, thus 

3148 ignoring any mapped value 

3149 """ 

3150 

3151 if self._dotted is None: 

3152 output = [] 

3153 

3154 part = 0 

3155 for byte in self.contents: 

3156 if _PY2: 

3157 byte = ord(byte) 

3158 part = part * 128 

3159 part += byte & 127 

3160 # Last byte in subidentifier has the eighth bit set to 0 

3161 if byte & 0x80 == 0: 

3162 if len(output) == 0: 

3163 if part >= 80: 

3164 output.append(str_cls(2)) 

3165 output.append(str_cls(part - 80)) 

3166 elif part >= 40: 

3167 output.append(str_cls(1)) 

3168 output.append(str_cls(part - 40)) 

3169 else: 

3170 output.append(str_cls(0)) 

3171 output.append(str_cls(part)) 

3172 else: 

3173 output.append(str_cls(part)) 

3174 part = 0 

3175 

3176 self._dotted = '.'.join(output) 

3177 return self._dotted 

3178 

3179 @property 

3180 def native(self): 

3181 """ 

3182 The native Python datatype representation of this value 

3183 

3184 :return: 

3185 A unicode string or None. If _map is not defined, the unicode string 

3186 is a string of dotted integers. If _map is defined and the dotted 

3187 string is present in the _map, the mapped value is returned. 

3188 """ 

3189 

3190 if self.contents is None: 

3191 return None 

3192 

3193 if self._native is None: 

3194 self._native = self.dotted 

3195 if self._map is not None and self._native in self._map: 

3196 self._native = self._map[self._native] 

3197 return self._native 

3198 

3199 

3200class ObjectDescriptor(Primitive): 

3201 """ 

3202 Represents an object descriptor from ASN.1 - no Python implementation 

3203 """ 

3204 

3205 tag = 7 

3206 

3207 

3208class InstanceOf(Primitive): 

3209 """ 

3210 Represents an instance from ASN.1 - no Python implementation 

3211 """ 

3212 

3213 tag = 8 

3214 

3215 

3216class Real(Primitive): 

3217 """ 

3218 Represents a real number from ASN.1 - no Python implementation 

3219 """ 

3220 

3221 tag = 9 

3222 

3223 

3224class Enumerated(Integer): 

3225 """ 

3226 Represents a enumerated list of integers from ASN.1 as a Python 

3227 unicode string 

3228 """ 

3229 

3230 tag = 10 

3231 

3232 def set(self, value): 

3233 """ 

3234 Sets the value of the object 

3235 

3236 :param value: 

3237 An integer or a unicode string from _map 

3238 

3239 :raises: 

3240 ValueError - when an invalid value is passed 

3241 """ 

3242 

3243 if not isinstance(value, int_types) and not isinstance(value, str_cls): 

3244 raise TypeError(unwrap( 

3245 ''' 

3246 %s value must be an integer or a unicode string, not %s 

3247 ''', 

3248 type_name(self), 

3249 type_name(value) 

3250 )) 

3251 

3252 if isinstance(value, str_cls): 

3253 if value not in self._reverse_map: 

3254 raise ValueError(unwrap( 

3255 ''' 

3256 %s value "%s" is not a valid value 

3257 ''', 

3258 type_name(self), 

3259 value 

3260 )) 

3261 

3262 value = self._reverse_map[value] 

3263 

3264 elif value not in self._map: 

3265 raise ValueError(unwrap( 

3266 ''' 

3267 %s value %s is not a valid value 

3268 ''', 

3269 type_name(self), 

3270 value 

3271 )) 

3272 

3273 Integer.set(self, value) 

3274 

3275 @property 

3276 def native(self): 

3277 """ 

3278 The native Python datatype representation of this value 

3279 

3280 :return: 

3281 A unicode string or None 

3282 """ 

3283 

3284 if self.contents is None: 

3285 return None 

3286 

3287 if self._native is None: 

3288 self._native = self._map[self.__int__()] 

3289 return self._native 

3290 

3291 

3292class UTF8String(AbstractString): 

3293 """ 

3294 Represents a UTF-8 string from ASN.1 as a Python unicode string 

3295 """ 

3296 

3297 tag = 12 

3298 _encoding = 'utf-8' 

3299 

3300 

3301class RelativeOid(ObjectIdentifier): 

3302 """ 

3303 Represents an object identifier in ASN.1 as a Python unicode dotted 

3304 integer string 

3305 """ 

3306 

3307 tag = 13 

3308 

3309 

3310class Sequence(Asn1Value): 

3311 """ 

3312 Represents a sequence of fields from ASN.1 as a Python object with a 

3313 dict-like interface 

3314 """ 

3315 

3316 tag = 16 

3317 

3318 class_ = 0 

3319 method = 1 

3320 

3321 # A list of child objects, in order of _fields 

3322 children = None 

3323 

3324 # Sequence overrides .contents to be a property so that the mutated state 

3325 # of child objects can be checked to ensure everything is up-to-date 

3326 _contents = None 

3327 

3328 # Variable to track if the object has been mutated 

3329 _mutated = False 

3330 

3331 # A list of tuples in one of the following forms. 

3332 # 

3333 # Option 1, a unicode string field name and a value class 

3334 # 

3335 # ("name", Asn1ValueClass) 

3336 # 

3337 # Option 2, same as Option 1, but with a dict of class params 

3338 # 

3339 # ("name", Asn1ValueClass, {'explicit': 5}) 

3340 _fields = [] 

3341 

3342 # A dict with keys being the name of a field and the value being a unicode 

3343 # string of the method name on self to call to get the spec for that field 

3344 _spec_callbacks = None 

3345 

3346 # A dict that maps unicode string field names to an index in _fields 

3347 _field_map = None 

3348 

3349 # A list in the same order as _fields that has tuples in the form (class_, tag) 

3350 _field_ids = None 

3351 

3352 # An optional 2-element tuple that defines the field names of an OID field 

3353 # and the field that the OID should be used to help decode. Works with the 

3354 # _oid_specs attribute. 

3355 _oid_pair = None 

3356 

3357 # A dict with keys that are unicode string OID values and values that are 

3358 # Asn1Value classes to use for decoding a variable-type field. 

3359 _oid_specs = None 

3360 

3361 # A 2-element tuple of the indexes in _fields of the OID and value fields 

3362 _oid_nums = None 

3363 

3364 # Predetermined field specs to optimize away calls to _determine_spec() 

3365 _precomputed_specs = None 

3366 

3367 def __init__(self, value=None, default=None, **kwargs): 

3368 """ 

3369 Allows setting field values before passing everything else along to 

3370 Asn1Value.__init__() 

3371 

3372 :param value: 

3373 A native Python datatype to initialize the object value with 

3374 

3375 :param default: 

3376 The default value if no value is specified 

3377 """ 

3378 

3379 Asn1Value.__init__(self, **kwargs) 

3380 

3381 check_existing = False 

3382 if value is None and default is not None: 

3383 check_existing = True 

3384 if self.children is None: 

3385 if self.contents is None: 

3386 check_existing = False 

3387 else: 

3388 self._parse_children() 

3389 value = default 

3390 

3391 if value is not None: 

3392 try: 

3393 # Fields are iterated in definition order to allow things like 

3394 # OID-based specs. Otherwise sometimes the value would be processed 

3395 # before the OID field, resulting in invalid value object creation. 

3396 if self._fields: 

3397 keys = [info[0] for info in self._fields] 

3398 unused_keys = set(value.keys()) 

3399 else: 

3400 keys = value.keys() 

3401 unused_keys = set(keys) 

3402 

3403 for key in keys: 

3404 # If we are setting defaults, but a real value has already 

3405 # been set for the field, then skip it 

3406 if check_existing: 

3407 index = self._field_map[key] 

3408 if index < len(self.children) and self.children[index] is not VOID: 

3409 if key in unused_keys: 

3410 unused_keys.remove(key) 

3411 continue 

3412 

3413 if key in value: 

3414 self.__setitem__(key, value[key]) 

3415 unused_keys.remove(key) 

3416 

3417 if len(unused_keys): 

3418 raise ValueError(unwrap( 

3419 ''' 

3420 One or more unknown fields was passed to the constructor 

3421 of %s: %s 

3422 ''', 

3423 type_name(self), 

3424 ', '.join(sorted(list(unused_keys))) 

3425 )) 

3426 

3427 except (ValueError, TypeError) as e: 

3428 args = e.args[1:] 

3429 e.args = (e.args[0] + '\n while constructing %s' % type_name(self),) + args 

3430 raise e 

3431 

3432 @property 

3433 def contents(self): 

3434 """ 

3435 :return: 

3436 A byte string of the DER-encoded contents of the sequence 

3437 """ 

3438 

3439 if self.children is None: 

3440 return self._contents 

3441 

3442 if self._is_mutated(): 

3443 self._set_contents() 

3444 

3445 return self._contents 

3446 

3447 @contents.setter 

3448 def contents(self, value): 

3449 """ 

3450 :param value: 

3451 A byte string of the DER-encoded contents of the sequence 

3452 """ 

3453 

3454 self._contents = value 

3455 

3456 def _is_mutated(self): 

3457 """ 

3458 :return: 

3459 A boolean - if the sequence or any children (recursively) have been 

3460 mutated 

3461 """ 

3462 

3463 mutated = self._mutated 

3464 if self.children is not None: 

3465 for child in self.children: 

3466 if isinstance(child, Sequence) or isinstance(child, SequenceOf): 

3467 mutated = mutated or child._is_mutated() 

3468 

3469 return mutated 

3470 

3471 def _lazy_child(self, index): 

3472 """ 

3473 Builds a child object if the child has only been parsed into a tuple so far 

3474 """ 

3475 

3476 child = self.children[index] 

3477 if child.__class__ == tuple: 

3478 child = self.children[index] = _build(*child) 

3479 return child 

3480 

3481 def __len__(self): 

3482 """ 

3483 :return: 

3484 Integer 

3485 """ 

3486 # We inline this check to prevent method invocation each time 

3487 if self.children is None: 

3488 self._parse_children() 

3489 

3490 return len(self.children) 

3491 

3492 def __getitem__(self, key): 

3493 """ 

3494 Allows accessing fields by name or index 

3495 

3496 :param key: 

3497 A unicode string of the field name, or an integer of the field index 

3498 

3499 :raises: 

3500 KeyError - when a field name or index is invalid 

3501 

3502 :return: 

3503 The Asn1Value object of the field specified 

3504 """ 

3505 

3506 # We inline this check to prevent method invocation each time 

3507 if self.children is None: 

3508 self._parse_children() 

3509 

3510 if not isinstance(key, int_types): 

3511 if key not in self._field_map: 

3512 raise KeyError(unwrap( 

3513 ''' 

3514 No field named "%s" defined for %s 

3515 ''', 

3516 key, 

3517 type_name(self) 

3518 )) 

3519 key = self._field_map[key] 

3520 

3521 if key >= len(self.children): 

3522 raise KeyError(unwrap( 

3523 ''' 

3524 No field numbered %s is present in this %s 

3525 ''', 

3526 key, 

3527 type_name(self) 

3528 )) 

3529 

3530 try: 

3531 return self._lazy_child(key) 

3532 

3533 except (ValueError, TypeError) as e: 

3534 args = e.args[1:] 

3535 e.args = (e.args[0] + '\n while parsing %s' % type_name(self),) + args 

3536 raise e 

3537 

3538 def __setitem__(self, key, value): 

3539 """ 

3540 Allows settings fields by name or index 

3541 

3542 :param key: 

3543 A unicode string of the field name, or an integer of the field index 

3544 

3545 :param value: 

3546 A native Python datatype to set the field value to. This method will 

3547 construct the appropriate Asn1Value object from _fields. 

3548 

3549 :raises: 

3550 ValueError - when a field name or index is invalid 

3551 """ 

3552 

3553 # We inline this check to prevent method invocation each time 

3554 if self.children is None: 

3555 self._parse_children() 

3556 

3557 if not isinstance(key, int_types): 

3558 if key not in self._field_map: 

3559 raise KeyError(unwrap( 

3560 ''' 

3561 No field named "%s" defined for %s 

3562 ''', 

3563 key, 

3564 type_name(self) 

3565 )) 

3566 key = self._field_map[key] 

3567 

3568 field_name, field_spec, value_spec, field_params, _ = self._determine_spec(key) 

3569 

3570 new_value = self._make_value(field_name, field_spec, value_spec, field_params, value) 

3571 

3572 invalid_value = False 

3573 if isinstance(new_value, Any): 

3574 invalid_value = new_value.parsed is None 

3575 else: 

3576 invalid_value = new_value.contents is None 

3577 

3578 if invalid_value: 

3579 raise ValueError(unwrap( 

3580 ''' 

3581 Value for field "%s" of %s is not set 

3582 ''', 

3583 field_name, 

3584 type_name(self) 

3585 )) 

3586 

3587 self.children[key] = new_value 

3588 

3589 if self._native is not None: 

3590 self._native[self._fields[key][0]] = self.children[key].native 

3591 self._mutated = True 

3592 

3593 def __delitem__(self, key): 

3594 """ 

3595 Allows deleting optional or default fields by name or index 

3596 

3597 :param key: 

3598 A unicode string of the field name, or an integer of the field index 

3599 

3600 :raises: 

3601 ValueError - when a field name or index is invalid, or the field is not optional or defaulted 

3602 """ 

3603 

3604 # We inline this check to prevent method invocation each time 

3605 if self.children is None: 

3606 self._parse_children() 

3607 

3608 if not isinstance(key, int_types): 

3609 if key not in self._field_map: 

3610 raise KeyError(unwrap( 

3611 ''' 

3612 No field named "%s" defined for %s 

3613 ''', 

3614 key, 

3615 type_name(self) 

3616 )) 

3617 key = self._field_map[key] 

3618 

3619 name, _, params = self._fields[key] 

3620 if not params or ('default' not in params and 'optional' not in params): 

3621 raise ValueError(unwrap( 

3622 ''' 

3623 Can not delete the value for the field "%s" of %s since it is 

3624 not optional or defaulted 

3625 ''', 

3626 name, 

3627 type_name(self) 

3628 )) 

3629 

3630 if 'optional' in params: 

3631 self.children[key] = VOID 

3632 if self._native is not None: 

3633 self._native[name] = None 

3634 else: 

3635 self.__setitem__(key, None) 

3636 self._mutated = True 

3637 

3638 def __iter__(self): 

3639 """ 

3640 :return: 

3641 An iterator of field key names 

3642 """ 

3643 

3644 for info in self._fields: 

3645 yield info[0] 

3646 

3647 def _set_contents(self, force=False): 

3648 """ 

3649 Updates the .contents attribute of the value with the encoded value of 

3650 all of the child objects 

3651 

3652 :param force: 

3653 Ensure all contents are in DER format instead of possibly using 

3654 cached BER-encoded data 

3655 """ 

3656 

3657 if self.children is None: 

3658 self._parse_children() 

3659 

3660 contents = BytesIO() 

3661 for index, info in enumerate(self._fields): 

3662 child = self.children[index] 

3663 if child is None: 

3664 child_dump = b'' 

3665 elif child.__class__ == tuple: 

3666 if force: 

3667 child_dump = self._lazy_child(index).dump(force=force) 

3668 else: 

3669 child_dump = child[3] + child[4] + child[5] 

3670 else: 

3671 child_dump = child.dump(force=force) 

3672 # Skip values that are the same as the default 

3673 if info[2] and 'default' in info[2]: 

3674 default_value = info[1](**info[2]) 

3675 if default_value.dump() == child_dump: 

3676 continue 

3677 contents.write(child_dump) 

3678 self._contents = contents.getvalue() 

3679 

3680 self._header = None 

3681 if self._trailer != b'': 

3682 self._trailer = b'' 

3683 

3684 def _setup(self): 

3685 """ 

3686 Generates _field_map, _field_ids and _oid_nums for use in parsing 

3687 """ 

3688 

3689 cls = self.__class__ 

3690 cls._field_map = {} 

3691 cls._field_ids = [] 

3692 cls._precomputed_specs = [] 

3693 for index, field in enumerate(cls._fields): 

3694 if len(field) < 3: 

3695 field = field + ({},) 

3696 cls._fields[index] = field 

3697 cls._field_map[field[0]] = index 

3698 cls._field_ids.append(_build_id_tuple(field[2], field[1])) 

3699 

3700 if cls._oid_pair is not None: 

3701 cls._oid_nums = (cls._field_map[cls._oid_pair[0]], cls._field_map[cls._oid_pair[1]]) 

3702 

3703 for index, field in enumerate(cls._fields): 

3704 has_callback = cls._spec_callbacks is not None and field[0] in cls._spec_callbacks 

3705 is_mapped_oid = cls._oid_nums is not None and cls._oid_nums[1] == index 

3706 if has_callback or is_mapped_oid: 

3707 cls._precomputed_specs.append(None) 

3708 else: 

3709 cls._precomputed_specs.append((field[0], field[1], field[1], field[2], None)) 

3710 

3711 def _determine_spec(self, index): 

3712 """ 

3713 Determine how a value for a field should be constructed 

3714 

3715 :param index: 

3716 The field number 

3717 

3718 :return: 

3719 A tuple containing the following elements: 

3720 - unicode string of the field name 

3721 - Asn1Value class of the field spec 

3722 - Asn1Value class of the value spec 

3723 - None or dict of params to pass to the field spec 

3724 - None or Asn1Value class indicating the value spec was derived from an OID or a spec callback 

3725 """ 

3726 

3727 name, field_spec, field_params = self._fields[index] 

3728 value_spec = field_spec 

3729 spec_override = None 

3730 

3731 if self._spec_callbacks is not None and name in self._spec_callbacks: 

3732 callback = self._spec_callbacks[name] 

3733 spec_override = callback(self) 

3734 if spec_override: 

3735 # Allow a spec callback to specify both the base spec and 

3736 # the override, for situations such as OctetString and parse_as 

3737 if spec_override.__class__ == tuple and len(spec_override) == 2: 

3738 field_spec, value_spec = spec_override 

3739 if value_spec is None: 

3740 value_spec = field_spec 

3741 spec_override = None 

3742 # When no field spec is specified, use a single return value as that 

3743 elif field_spec is None: 

3744 field_spec = spec_override 

3745 value_spec = field_spec 

3746 spec_override = None 

3747 else: 

3748 value_spec = spec_override 

3749 

3750 elif self._oid_nums is not None and self._oid_nums[1] == index: 

3751 oid = self._lazy_child(self._oid_nums[0]).native 

3752 if oid in self._oid_specs: 

3753 spec_override = self._oid_specs[oid] 

3754 value_spec = spec_override 

3755 

3756 return (name, field_spec, value_spec, field_params, spec_override) 

3757 

3758 def _make_value(self, field_name, field_spec, value_spec, field_params, value): 

3759 """ 

3760 Contructs an appropriate Asn1Value object for a field 

3761 

3762 :param field_name: 

3763 A unicode string of the field name 

3764 

3765 :param field_spec: 

3766 An Asn1Value class that is the field spec 

3767 

3768 :param value_spec: 

3769 An Asn1Value class that is the vaue spec 

3770 

3771 :param field_params: 

3772 None or a dict of params for the field spec 

3773 

3774 :param value: 

3775 The value to construct an Asn1Value object from 

3776 

3777 :return: 

3778 An instance of a child class of Asn1Value 

3779 """ 

3780 

3781 if value is None and 'optional' in field_params: 

3782 return VOID 

3783 

3784 specs_different = field_spec != value_spec 

3785 is_any = issubclass(field_spec, Any) 

3786 

3787 if issubclass(value_spec, Choice): 

3788 is_asn1value = isinstance(value, Asn1Value) 

3789 is_tuple = isinstance(value, tuple) and len(value) == 2 

3790 is_dict = isinstance(value, dict) and len(value) == 1 

3791 if not is_asn1value and not is_tuple and not is_dict: 

3792 raise ValueError(unwrap( 

3793 ''' 

3794 Can not set a native python value to %s, which has the 

3795 choice type of %s - value must be an instance of Asn1Value 

3796 ''', 

3797 field_name, 

3798 type_name(value_spec) 

3799 )) 

3800 if is_tuple or is_dict: 

3801 value = value_spec(value) 

3802 if not isinstance(value, value_spec): 

3803 wrapper = value_spec() 

3804 wrapper.validate(value.class_, value.tag, value.contents) 

3805 wrapper._parsed = value 

3806 new_value = wrapper 

3807 else: 

3808 new_value = value 

3809 

3810 elif isinstance(value, field_spec): 

3811 new_value = value 

3812 if specs_different: 

3813 new_value.parse(value_spec) 

3814 

3815 elif (not specs_different or is_any) and not isinstance(value, value_spec): 

3816 if (not is_any or specs_different) and isinstance(value, Asn1Value): 

3817 raise TypeError(unwrap( 

3818 ''' 

3819 %s value must be %s, not %s 

3820 ''', 

3821 field_name, 

3822 type_name(value_spec), 

3823 type_name(value) 

3824 )) 

3825 new_value = value_spec(value, **field_params) 

3826 

3827 else: 

3828 if isinstance(value, value_spec): 

3829 new_value = value 

3830 else: 

3831 if isinstance(value, Asn1Value): 

3832 raise TypeError(unwrap( 

3833 ''' 

3834 %s value must be %s, not %s 

3835 ''', 

3836 field_name, 

3837 type_name(value_spec), 

3838 type_name(value) 

3839 )) 

3840 new_value = value_spec(value) 

3841 

3842 # For when the field is OctetString or OctetBitString with embedded 

3843 # values we need to wrap the value in the field spec to get the 

3844 # appropriate encoded value. 

3845 if specs_different and not is_any: 

3846 wrapper = field_spec(value=new_value.dump(), **field_params) 

3847 wrapper._parsed = (new_value, new_value.__class__, None) 

3848 new_value = wrapper 

3849 

3850 new_value = _fix_tagging(new_value, field_params) 

3851 

3852 return new_value 

3853 

3854 def _parse_children(self, recurse=False): 

3855 """ 

3856 Parses the contents and generates Asn1Value objects based on the 

3857 definitions from _fields. 

3858 

3859 :param recurse: 

3860 If child objects that are Sequence or SequenceOf objects should 

3861 be recursively parsed 

3862 

3863 :raises: 

3864 ValueError - when an error occurs parsing child objects 

3865 """ 

3866 

3867 cls = self.__class__ 

3868 if self._contents is None: 

3869 if self._fields: 

3870 self.children = [VOID] * len(self._fields) 

3871 for index, (_, _, params) in enumerate(self._fields): 

3872 if 'default' in params: 

3873 if cls._precomputed_specs[index]: 

3874 field_name, field_spec, value_spec, field_params, _ = cls._precomputed_specs[index] 

3875 else: 

3876 field_name, field_spec, value_spec, field_params, _ = self._determine_spec(index) 

3877 self.children[index] = self._make_value(field_name, field_spec, value_spec, field_params, None) 

3878 return 

3879 

3880 try: 

3881 self.children = [] 

3882 contents_length = len(self._contents) 

3883 child_pointer = 0 

3884 field = 0 

3885 field_len = len(self._fields) 

3886 parts = None 

3887 again = child_pointer < contents_length 

3888 while again: 

3889 if parts is None: 

3890 parts, child_pointer = _parse(self._contents, contents_length, pointer=child_pointer) 

3891 again = child_pointer < contents_length 

3892 

3893 if field < field_len: 

3894 _, field_spec, value_spec, field_params, spec_override = ( 

3895 cls._precomputed_specs[field] or self._determine_spec(field)) 

3896 

3897 # If the next value is optional or default, allow it to be absent 

3898 if field_params and ('optional' in field_params or 'default' in field_params): 

3899 if self._field_ids[field] != (parts[0], parts[2]) and field_spec != Any: 

3900 

3901 # See if the value is a valid choice before assuming 

3902 # that we have a missing optional or default value 

3903 choice_match = False 

3904 if issubclass(field_spec, Choice): 

3905 try: 

3906 tester = field_spec(**field_params) 

3907 tester.validate(parts[0], parts[2], parts[4]) 

3908 choice_match = True 

3909 except (ValueError): 

3910 pass 

3911 

3912 if not choice_match: 

3913 if 'optional' in field_params: 

3914 self.children.append(VOID) 

3915 else: 

3916 self.children.append(field_spec(**field_params)) 

3917 field += 1 

3918 again = True 

3919 continue 

3920 

3921 if field_spec is None or (spec_override and issubclass(field_spec, Any)): 

3922 field_spec = value_spec 

3923 spec_override = None 

3924 

3925 if spec_override: 

3926 child = parts + (field_spec, field_params, value_spec) 

3927 else: 

3928 child = parts + (field_spec, field_params) 

3929 

3930 # Handle situations where an optional or defaulted field definition is incorrect 

3931 elif field_len > 0 and field + 1 <= field_len: 

3932 missed_fields = [] 

3933 prev_field = field - 1 

3934 while prev_field >= 0: 

3935 prev_field_info = self._fields[prev_field] 

3936 if len(prev_field_info) < 3: 

3937 break 

3938 if 'optional' in prev_field_info[2] or 'default' in prev_field_info[2]: 

3939 missed_fields.append(prev_field_info[0]) 

3940 prev_field -= 1 

3941 plural = 's' if len(missed_fields) > 1 else '' 

3942 missed_field_names = ', '.join(missed_fields) 

3943 raise ValueError(unwrap( 

3944 ''' 

3945 Data for field %s (%s class, %s method, tag %s) does 

3946 not match the field definition%s of %s 

3947 ''', 

3948 field + 1, 

3949 CLASS_NUM_TO_NAME_MAP.get(parts[0]), 

3950 METHOD_NUM_TO_NAME_MAP.get(parts[1]), 

3951 parts[2], 

3952 plural, 

3953 missed_field_names 

3954 )) 

3955 

3956 else: 

3957 child = parts 

3958 

3959 if recurse: 

3960 child = _build(*child) 

3961 if isinstance(child, (Sequence, SequenceOf)): 

3962 child._parse_children(recurse=True) 

3963 

3964 self.children.append(child) 

3965 field += 1 

3966 parts = None 

3967 

3968 index = len(self.children) 

3969 while index < field_len: 

3970 name, field_spec, field_params = self._fields[index] 

3971 if 'default' in field_params: 

3972 self.children.append(field_spec(**field_params)) 

3973 elif 'optional' in field_params: 

3974 self.children.append(VOID) 

3975 else: 

3976 raise ValueError(unwrap( 

3977 ''' 

3978 Field "%s" is missing from structure 

3979 ''', 

3980 name 

3981 )) 

3982 index += 1 

3983 

3984 except (ValueError, TypeError) as e: 

3985 self.children = None 

3986 args = e.args[1:] 

3987 e.args = (e.args[0] + '\n while parsing %s' % type_name(self),) + args 

3988 raise e 

3989 

3990 def spec(self, field_name): 

3991 """ 

3992 Determines the spec to use for the field specified. Depending on how 

3993 the spec is determined (_oid_pair or _spec_callbacks), it may be 

3994 necessary to set preceding field values before calling this. Usually 

3995 specs, if dynamic, are controlled by a preceding ObjectIdentifier 

3996 field. 

3997 

3998 :param field_name: 

3999 A unicode string of the field name to get the spec for 

4000 

4001 :return: 

4002 A child class of asn1crypto.core.Asn1Value that the field must be 

4003 encoded using 

4004 """ 

4005 

4006 if not isinstance(field_name, str_cls): 

4007 raise TypeError(unwrap( 

4008 ''' 

4009 field_name must be a unicode string, not %s 

4010 ''', 

4011 type_name(field_name) 

4012 )) 

4013 

4014 if self._fields is None: 

4015 raise ValueError(unwrap( 

4016 ''' 

4017 Unable to retrieve spec for field %s in the class %s because 

4018 _fields has not been set 

4019 ''', 

4020 repr(field_name), 

4021 type_name(self) 

4022 )) 

4023 

4024 index = self._field_map[field_name] 

4025 info = self._determine_spec(index) 

4026 

4027 return info[2] 

4028 

4029 @property 

4030 def native(self): 

4031 """ 

4032 The native Python datatype representation of this value 

4033 

4034 :return: 

4035 An OrderedDict or None. If an OrderedDict, all child values are 

4036 recursively converted to native representation also. 

4037 """ 

4038 

4039 if self.contents is None: 

4040 return None 

4041 

4042 if self._native is None: 

4043 if self.children is None: 

4044 self._parse_children(recurse=True) 

4045 try: 

4046 self._native = OrderedDict() 

4047 for index, child in enumerate(self.children): 

4048 if child.__class__ == tuple: 

4049 child = _build(*child) 

4050 self.children[index] = child 

4051 try: 

4052 name = self._fields[index][0] 

4053 except (IndexError): 

4054 name = str_cls(index) 

4055 self._native[name] = child.native 

4056 except (ValueError, TypeError) as e: 

4057 self._native = None 

4058 args = e.args[1:] 

4059 e.args = (e.args[0] + '\n while parsing %s' % type_name(self),) + args 

4060 raise e 

4061 return self._native 

4062 

4063 def _copy(self, other, copy_func): 

4064 """ 

4065 Copies the contents of another Sequence object to itself 

4066 

4067 :param object: 

4068 Another instance of the same class 

4069 

4070 :param copy_func: 

4071 An reference of copy.copy() or copy.deepcopy() to use when copying 

4072 lists, dicts and objects 

4073 """ 

4074 

4075 super(Sequence, self)._copy(other, copy_func) 

4076 if self.children is not None: 

4077 self.children = [] 

4078 for child in other.children: 

4079 if child.__class__ == tuple: 

4080 self.children.append(child) 

4081 else: 

4082 self.children.append(child.copy()) 

4083 

4084 def debug(self, nest_level=1): 

4085 """ 

4086 Show the binary data and parsed data in a tree structure 

4087 """ 

4088 

4089 if self.children is None: 

4090 self._parse_children() 

4091 

4092 prefix = ' ' * nest_level 

4093 _basic_debug(prefix, self) 

4094 for field_name in self: 

4095 child = self._lazy_child(self._field_map[field_name]) 

4096 if child is not VOID: 

4097 print('%s Field "%s"' % (prefix, field_name)) 

4098 child.debug(nest_level + 3) 

4099 

4100 def dump(self, force=False): 

4101 """ 

4102 Encodes the value using DER 

4103 

4104 :param force: 

4105 If the encoded contents already exist, clear them and regenerate 

4106 to ensure they are in DER format instead of BER format 

4107 

4108 :return: 

4109 A byte string of the DER-encoded value 

4110 """ 

4111 

4112 # If the length is indefinite, force the re-encoding 

4113 if self._header is not None and self._header[-1:] == b'\x80': 

4114 force = True 

4115 

4116 # We can't force encoding if we don't have a spec 

4117 if force and self._fields == [] and self.__class__ is Sequence: 

4118 force = False 

4119 

4120 if force: 

4121 self._set_contents(force=force) 

4122 

4123 if self._fields and self.children is not None: 

4124 for index, (field_name, _, params) in enumerate(self._fields): 

4125 if self.children[index] is not VOID: 

4126 continue 

4127 if 'default' in params or 'optional' in params: 

4128 continue 

4129 raise ValueError(unwrap( 

4130 ''' 

4131 Field "%s" is missing from structure 

4132 ''', 

4133 field_name 

4134 )) 

4135 

4136 return Asn1Value.dump(self) 

4137 

4138 

4139class SequenceOf(Asn1Value): 

4140 """ 

4141 Represents a sequence (ordered) of a single type of values from ASN.1 as a 

4142 Python object with a list-like interface 

4143 """ 

4144 

4145 tag = 16 

4146 

4147 class_ = 0 

4148 method = 1 

4149 

4150 # A list of child objects 

4151 children = None 

4152 

4153 # SequenceOf overrides .contents to be a property so that the mutated state 

4154 # of child objects can be checked to ensure everything is up-to-date 

4155 _contents = None 

4156 

4157 # Variable to track if the object has been mutated 

4158 _mutated = False 

4159 

4160 # An Asn1Value class to use when parsing children 

4161 _child_spec = None 

4162 

4163 def __init__(self, value=None, default=None, contents=None, spec=None, **kwargs): 

4164 """ 

4165 Allows setting child objects and the _child_spec via the spec parameter 

4166 before passing everything else along to Asn1Value.__init__() 

4167 

4168 :param value: 

4169 A native Python datatype to initialize the object value with 

4170 

4171 :param default: 

4172 The default value if no value is specified 

4173 

4174 :param contents: 

4175 A byte string of the encoded contents of the value 

4176 

4177 :param spec: 

4178 A class derived from Asn1Value to use to parse children 

4179 """ 

4180 

4181 if spec: 

4182 self._child_spec = spec 

4183 

4184 Asn1Value.__init__(self, **kwargs) 

4185 

4186 try: 

4187 if contents is not None: 

4188 self.contents = contents 

4189 else: 

4190 if value is None and default is not None: 

4191 value = default 

4192 

4193 if value is not None: 

4194 for index, child in enumerate(value): 

4195 self.__setitem__(index, child) 

4196 

4197 # Make sure a blank list is serialized 

4198 if self.contents is None: 

4199 self._set_contents() 

4200 

4201 except (ValueError, TypeError) as e: 

4202 args = e.args[1:] 

4203 e.args = (e.args[0] + '\n while constructing %s' % type_name(self),) + args 

4204 raise e 

4205 

4206 @property 

4207 def contents(self): 

4208 """ 

4209 :return: 

4210 A byte string of the DER-encoded contents of the sequence 

4211 """ 

4212 

4213 if self.children is None: 

4214 return self._contents 

4215 

4216 if self._is_mutated(): 

4217 self._set_contents() 

4218 

4219 return self._contents 

4220 

4221 @contents.setter 

4222 def contents(self, value): 

4223 """ 

4224 :param value: 

4225 A byte string of the DER-encoded contents of the sequence 

4226 """ 

4227 

4228 self._contents = value 

4229 

4230 def _is_mutated(self): 

4231 """ 

4232 :return: 

4233 A boolean - if the sequence or any children (recursively) have been 

4234 mutated 

4235 """ 

4236 

4237 mutated = self._mutated 

4238 if self.children is not None: 

4239 for child in self.children: 

4240 if isinstance(child, Sequence) or isinstance(child, SequenceOf): 

4241 mutated = mutated or child._is_mutated() 

4242 

4243 return mutated 

4244 

4245 def _lazy_child(self, index): 

4246 """ 

4247 Builds a child object if the child has only been parsed into a tuple so far 

4248 """ 

4249 

4250 child = self.children[index] 

4251 if child.__class__ == tuple: 

4252 child = _build(*child) 

4253 self.children[index] = child 

4254 return child 

4255 

4256 def _make_value(self, value): 

4257 """ 

4258 Constructs a _child_spec value from a native Python data type, or 

4259 an appropriate Asn1Value object 

4260 

4261 :param value: 

4262 A native Python value, or some child of Asn1Value 

4263 

4264 :return: 

4265 An object of type _child_spec 

4266 """ 

4267 

4268 if isinstance(value, self._child_spec): 

4269 new_value = value 

4270 

4271 elif issubclass(self._child_spec, Any): 

4272 if isinstance(value, Asn1Value): 

4273 new_value = value 

4274 else: 

4275 raise ValueError(unwrap( 

4276 ''' 

4277 Can not set a native python value to %s where the 

4278 _child_spec is Any - value must be an instance of Asn1Value 

4279 ''', 

4280 type_name(self) 

4281 )) 

4282 

4283 elif issubclass(self._child_spec, Choice): 

4284 if not isinstance(value, Asn1Value): 

4285 raise ValueError(unwrap( 

4286 ''' 

4287 Can not set a native python value to %s where the 

4288 _child_spec is the choice type %s - value must be an 

4289 instance of Asn1Value 

4290 ''', 

4291 type_name(self), 

4292 self._child_spec.__name__ 

4293 )) 

4294 if not isinstance(value, self._child_spec): 

4295 wrapper = self._child_spec() 

4296 wrapper.validate(value.class_, value.tag, value.contents) 

4297 wrapper._parsed = value 

4298 value = wrapper 

4299 new_value = value 

4300 

4301 else: 

4302 return self._child_spec(value=value) 

4303 

4304 params = {} 

4305 if self._child_spec.explicit: 

4306 params['explicit'] = self._child_spec.explicit 

4307 if self._child_spec.implicit: 

4308 params['implicit'] = (self._child_spec.class_, self._child_spec.tag) 

4309 return _fix_tagging(new_value, params) 

4310 

4311 def __len__(self): 

4312 """ 

4313 :return: 

4314 An integer 

4315 """ 

4316 # We inline this checks to prevent method invocation each time 

4317 if self.children is None: 

4318 self._parse_children() 

4319 

4320 return len(self.children) 

4321 

4322 def __getitem__(self, key): 

4323 """ 

4324 Allows accessing children via index 

4325 

4326 :param key: 

4327 Integer index of child 

4328 """ 

4329 

4330 # We inline this checks to prevent method invocation each time 

4331 if self.children is None: 

4332 self._parse_children() 

4333 

4334 return self._lazy_child(key) 

4335 

4336 def __setitem__(self, key, value): 

4337 """ 

4338 Allows overriding a child via index 

4339 

4340 :param key: 

4341 Integer index of child 

4342 

4343 :param value: 

4344 Native python datatype that will be passed to _child_spec to create 

4345 new child object 

4346 """ 

4347 

4348 # We inline this checks to prevent method invocation each time 

4349 if self.children is None: 

4350 self._parse_children() 

4351 

4352 new_value = self._make_value(value) 

4353 

4354 # If adding at the end, create a space for the new value 

4355 if key == len(self.children): 

4356 self.children.append(None) 

4357 if self._native is not None: 

4358 self._native.append(None) 

4359 

4360 self.children[key] = new_value 

4361 

4362 if self._native is not None: 

4363 self._native[key] = self.children[key].native 

4364 

4365 self._mutated = True 

4366 

4367 def __delitem__(self, key): 

4368 """ 

4369 Allows removing a child via index 

4370 

4371 :param key: 

4372 Integer index of child 

4373 """ 

4374 

4375 # We inline this checks to prevent method invocation each time 

4376 if self.children is None: 

4377 self._parse_children() 

4378 

4379 self.children.pop(key) 

4380 if self._native is not None: 

4381 self._native.pop(key) 

4382 

4383 self._mutated = True 

4384 

4385 def __iter__(self): 

4386 """ 

4387 :return: 

4388 An iter() of child objects 

4389 """ 

4390 

4391 # We inline this checks to prevent method invocation each time 

4392 if self.children is None: 

4393 self._parse_children() 

4394 

4395 for index in range(0, len(self.children)): 

4396 yield self._lazy_child(index) 

4397 

4398 def __contains__(self, item): 

4399 """ 

4400 :param item: 

4401 An object of the type cls._child_spec 

4402 

4403 :return: 

4404 A boolean if the item is contained in this SequenceOf 

4405 """ 

4406 

4407 if item is None or item is VOID: 

4408 return False 

4409 

4410 if not isinstance(item, self._child_spec): 

4411 raise TypeError(unwrap( 

4412 ''' 

4413 Checking membership in %s is only available for instances of 

4414 %s, not %s 

4415 ''', 

4416 type_name(self), 

4417 type_name(self._child_spec), 

4418 type_name(item) 

4419 )) 

4420 

4421 for child in self: 

4422 if child == item: 

4423 return True 

4424 

4425 return False 

4426 

4427 def append(self, value): 

4428 """ 

4429 Allows adding a child to the end of the sequence 

4430 

4431 :param value: 

4432 Native python datatype that will be passed to _child_spec to create 

4433 new child object 

4434 """ 

4435 

4436 # We inline this checks to prevent method invocation each time 

4437 if self.children is None: 

4438 self._parse_children() 

4439 

4440 self.children.append(self._make_value(value)) 

4441 

4442 if self._native is not None: 

4443 self._native.append(self.children[-1].native) 

4444 

4445 self._mutated = True 

4446 

4447 def _set_contents(self, force=False): 

4448 """ 

4449 Encodes all child objects into the contents for this object 

4450 

4451 :param force: 

4452 Ensure all contents are in DER format instead of possibly using 

4453 cached BER-encoded data 

4454 """ 

4455 

4456 if self.children is None: 

4457 self._parse_children() 

4458 

4459 contents = BytesIO() 

4460 for child in self: 

4461 contents.write(child.dump(force=force)) 

4462 self._contents = contents.getvalue() 

4463 self._header = None 

4464 if self._trailer != b'': 

4465 self._trailer = b'' 

4466 

4467 def _parse_children(self, recurse=False): 

4468 """ 

4469 Parses the contents and generates Asn1Value objects based on the 

4470 definitions from _child_spec. 

4471 

4472 :param recurse: 

4473 If child objects that are Sequence or SequenceOf objects should 

4474 be recursively parsed 

4475 

4476 :raises: 

4477 ValueError - when an error occurs parsing child objects 

4478 """ 

4479 

4480 try: 

4481 self.children = [] 

4482 if self._contents is None: 

4483 return 

4484 contents_length = len(self._contents) 

4485 child_pointer = 0 

4486 while child_pointer < contents_length: 

4487 parts, child_pointer = _parse(self._contents, contents_length, pointer=child_pointer) 

4488 if self._child_spec: 

4489 child = parts + (self._child_spec,) 

4490 else: 

4491 child = parts 

4492 if recurse: 

4493 child = _build(*child) 

4494 if isinstance(child, (Sequence, SequenceOf)): 

4495 child._parse_children(recurse=True) 

4496 self.children.append(child) 

4497 except (ValueError, TypeError) as e: 

4498 self.children = None 

4499 args = e.args[1:] 

4500 e.args = (e.args[0] + '\n while parsing %s' % type_name(self),) + args 

4501 raise e 

4502 

4503 def spec(self): 

4504 """ 

4505 Determines the spec to use for child values. 

4506 

4507 :return: 

4508 A child class of asn1crypto.core.Asn1Value that child values must be 

4509 encoded using 

4510 """ 

4511 

4512 return self._child_spec 

4513 

4514 @property 

4515 def native(self): 

4516 """ 

4517 The native Python datatype representation of this value 

4518 

4519 :return: 

4520 A list or None. If a list, all child values are recursively 

4521 converted to native representation also. 

4522 """ 

4523 

4524 if self.contents is None: 

4525 return None 

4526 

4527 if self._native is None: 

4528 if self.children is None: 

4529 self._parse_children(recurse=True) 

4530 try: 

4531 self._native = [child.native for child in self] 

4532 except (ValueError, TypeError) as e: 

4533 args = e.args[1:] 

4534 e.args = (e.args[0] + '\n while parsing %s' % type_name(self),) + args 

4535 raise e 

4536 return self._native 

4537 

4538 def _copy(self, other, copy_func): 

4539 """ 

4540 Copies the contents of another SequenceOf object to itself 

4541 

4542 :param object: 

4543 Another instance of the same class 

4544 

4545 :param copy_func: 

4546 An reference of copy.copy() or copy.deepcopy() to use when copying 

4547 lists, dicts and objects 

4548 """ 

4549 

4550 super(SequenceOf, self)._copy(other, copy_func) 

4551 if self.children is not None: 

4552 self.children = [] 

4553 for child in other.children: 

4554 if child.__class__ == tuple: 

4555 self.children.append(child) 

4556 else: 

4557 self.children.append(child.copy()) 

4558 

4559 def debug(self, nest_level=1): 

4560 """ 

4561 Show the binary data and parsed data in a tree structure 

4562 """ 

4563 

4564 if self.children is None: 

4565 self._parse_children() 

4566 

4567 prefix = ' ' * nest_level 

4568 _basic_debug(prefix, self) 

4569 for child in self: 

4570 child.debug(nest_level + 1) 

4571 

4572 def dump(self, force=False): 

4573 """ 

4574 Encodes the value using DER 

4575 

4576 :param force: 

4577 If the encoded contents already exist, clear them and regenerate 

4578 to ensure they are in DER format instead of BER format 

4579 

4580 :return: 

4581 A byte string of the DER-encoded value 

4582 """ 

4583 

4584 # If the length is indefinite, force the re-encoding 

4585 if self._header is not None and self._header[-1:] == b'\x80': 

4586 force = True 

4587 

4588 if force: 

4589 self._set_contents(force=force) 

4590 

4591 return Asn1Value.dump(self) 

4592 

4593 

4594class Set(Sequence): 

4595 """ 

4596 Represents a set of fields (unordered) from ASN.1 as a Python object with a 

4597 dict-like interface 

4598 """ 

4599 

4600 method = 1 

4601 class_ = 0 

4602 tag = 17 

4603 

4604 # A dict of 2-element tuples in the form (class_, tag) as keys and integers 

4605 # as values that are the index of the field in _fields 

4606 _field_ids = None 

4607 

4608 def _setup(self): 

4609 """ 

4610 Generates _field_map, _field_ids and _oid_nums for use in parsing 

4611 """ 

4612 

4613 cls = self.__class__ 

4614 cls._field_map = {} 

4615 cls._field_ids = {} 

4616 cls._precomputed_specs = [] 

4617 for index, field in enumerate(cls._fields): 

4618 if len(field) < 3: 

4619 field = field + ({},) 

4620 cls._fields[index] = field 

4621 cls._field_map[field[0]] = index 

4622 cls._field_ids[_build_id_tuple(field[2], field[1])] = index 

4623 

4624 if cls._oid_pair is not None: 

4625 cls._oid_nums = (cls._field_map[cls._oid_pair[0]], cls._field_map[cls._oid_pair[1]]) 

4626 

4627 for index, field in enumerate(cls._fields): 

4628 has_callback = cls._spec_callbacks is not None and field[0] in cls._spec_callbacks 

4629 is_mapped_oid = cls._oid_nums is not None and cls._oid_nums[1] == index 

4630 if has_callback or is_mapped_oid: 

4631 cls._precomputed_specs.append(None) 

4632 else: 

4633 cls._precomputed_specs.append((field[0], field[1], field[1], field[2], None)) 

4634 

4635 def _parse_children(self, recurse=False): 

4636 """ 

4637 Parses the contents and generates Asn1Value objects based on the 

4638 definitions from _fields. 

4639 

4640 :param recurse: 

4641 If child objects that are Sequence or SequenceOf objects should 

4642 be recursively parsed 

4643 

4644 :raises: 

4645 ValueError - when an error occurs parsing child objects 

4646 """ 

4647 

4648 cls = self.__class__ 

4649 if self._contents is None: 

4650 if self._fields: 

4651 self.children = [VOID] * len(self._fields) 

4652 for index, (_, _, params) in enumerate(self._fields): 

4653 if 'default' in params: 

4654 if cls._precomputed_specs[index]: 

4655 field_name, field_spec, value_spec, field_params, _ = cls._precomputed_specs[index] 

4656 else: 

4657 field_name, field_spec, value_spec, field_params, _ = self._determine_spec(index) 

4658 self.children[index] = self._make_value(field_name, field_spec, value_spec, field_params, None) 

4659 return 

4660 

4661 try: 

4662 child_map = {} 

4663 contents_length = len(self.contents) 

4664 child_pointer = 0 

4665 seen_field = 0 

4666 while child_pointer < contents_length: 

4667 parts, child_pointer = _parse(self.contents, contents_length, pointer=child_pointer) 

4668 

4669 id_ = (parts[0], parts[2]) 

4670 

4671 field = self._field_ids.get(id_) 

4672 if field is None: 

4673 raise ValueError(unwrap( 

4674 ''' 

4675 Data for field %s (%s class, %s method, tag %s) does 

4676 not match any of the field definitions 

4677 ''', 

4678 seen_field, 

4679 CLASS_NUM_TO_NAME_MAP.get(parts[0]), 

4680 METHOD_NUM_TO_NAME_MAP.get(parts[1]), 

4681 parts[2], 

4682 )) 

4683 

4684 _, field_spec, value_spec, field_params, spec_override = ( 

4685 cls._precomputed_specs[field] or self._determine_spec(field)) 

4686 

4687 if field_spec is None or (spec_override and issubclass(field_spec, Any)): 

4688 field_spec = value_spec 

4689 spec_override = None 

4690 

4691 if spec_override: 

4692 child = parts + (field_spec, field_params, value_spec) 

4693 else: 

4694 child = parts + (field_spec, field_params) 

4695 

4696 if recurse: 

4697 child = _build(*child) 

4698 if isinstance(child, (Sequence, SequenceOf)): 

4699 child._parse_children(recurse=True) 

4700 

4701 child_map[field] = child 

4702 seen_field += 1 

4703 

4704 total_fields = len(self._fields) 

4705 

4706 for index in range(0, total_fields): 

4707 if index in child_map: 

4708 continue 

4709 

4710 name, field_spec, value_spec, field_params, spec_override = ( 

4711 cls._precomputed_specs[index] or self._determine_spec(index)) 

4712 

4713 if field_spec is None or (spec_override and issubclass(field_spec, Any)): 

4714 field_spec = value_spec 

4715 spec_override = None 

4716 

4717 missing = False 

4718 

4719 if not field_params: 

4720 missing = True 

4721 elif 'optional' not in field_params and 'default' not in field_params: 

4722 missing = True 

4723 elif 'optional' in field_params: 

4724 child_map[index] = VOID 

4725 elif 'default' in field_params: 

4726 child_map[index] = field_spec(**field_params) 

4727 

4728 if missing: 

4729 raise ValueError(unwrap( 

4730 ''' 

4731 Missing required field "%s" from %s 

4732 ''', 

4733 name, 

4734 type_name(self) 

4735 )) 

4736 

4737 self.children = [] 

4738 for index in range(0, total_fields): 

4739 self.children.append(child_map[index]) 

4740 

4741 except (ValueError, TypeError) as e: 

4742 args = e.args[1:] 

4743 e.args = (e.args[0] + '\n while parsing %s' % type_name(self),) + args 

4744 raise e 

4745 

4746 def _set_contents(self, force=False): 

4747 """ 

4748 Encodes all child objects into the contents for this object. 

4749 

4750 This method is overridden because a Set needs to be encoded by 

4751 removing defaulted fields and then sorting the fields by tag. 

4752 

4753 :param force: 

4754 Ensure all contents are in DER format instead of possibly using 

4755 cached BER-encoded data 

4756 """ 

4757 

4758 if self.children is None: 

4759 self._parse_children() 

4760 

4761 child_tag_encodings = [] 

4762 for index, child in enumerate(self.children): 

4763 child_encoding = child.dump(force=force) 

4764 

4765 # Skip encoding defaulted children 

4766 name, spec, field_params = self._fields[index] 

4767 if 'default' in field_params: 

4768 if spec(**field_params).dump() == child_encoding: 

4769 continue 

4770 

4771 child_tag_encodings.append((child.tag, child_encoding)) 

4772 child_tag_encodings.sort(key=lambda ct: ct[0]) 

4773 

4774 self._contents = b''.join([ct[1] for ct in child_tag_encodings]) 

4775 self._header = None 

4776 if self._trailer != b'': 

4777 self._trailer = b'' 

4778 

4779 

4780class SetOf(SequenceOf): 

4781 """ 

4782 Represents a set (unordered) of a single type of values from ASN.1 as a 

4783 Python object with a list-like interface 

4784 """ 

4785 

4786 tag = 17 

4787 

4788 def _set_contents(self, force=False): 

4789 """ 

4790 Encodes all child objects into the contents for this object. 

4791 

4792 This method is overridden because a SetOf needs to be encoded by 

4793 sorting the child encodings. 

4794 

4795 :param force: 

4796 Ensure all contents are in DER format instead of possibly using 

4797 cached BER-encoded data 

4798 """ 

4799 

4800 if self.children is None: 

4801 self._parse_children() 

4802 

4803 child_encodings = [] 

4804 for child in self: 

4805 child_encodings.append(child.dump(force=force)) 

4806 

4807 self._contents = b''.join(sorted(child_encodings)) 

4808 self._header = None 

4809 if self._trailer != b'': 

4810 self._trailer = b'' 

4811 

4812 

4813class EmbeddedPdv(Sequence): 

4814 """ 

4815 A sequence structure 

4816 """ 

4817 

4818 tag = 11 

4819 

4820 

4821class NumericString(AbstractString): 

4822 """ 

4823 Represents a numeric string from ASN.1 as a Python unicode string 

4824 """ 

4825 

4826 tag = 18 

4827 _encoding = 'latin1' 

4828 

4829 

4830class PrintableString(AbstractString): 

4831 """ 

4832 Represents a printable string from ASN.1 as a Python unicode string 

4833 """ 

4834 

4835 tag = 19 

4836 _encoding = 'latin1' 

4837 

4838 

4839class TeletexString(AbstractString): 

4840 """ 

4841 Represents a teletex string from ASN.1 as a Python unicode string 

4842 """ 

4843 

4844 tag = 20 

4845 _encoding = 'teletex' 

4846 

4847 

4848class VideotexString(OctetString): 

4849 """ 

4850 Represents a videotex string from ASN.1 as a Python byte string 

4851 """ 

4852 

4853 tag = 21 

4854 

4855 

4856class IA5String(AbstractString): 

4857 """ 

4858 Represents an IA5 string from ASN.1 as a Python unicode string 

4859 """ 

4860 

4861 tag = 22 

4862 _encoding = 'ascii' 

4863 

4864 

4865class AbstractTime(AbstractString): 

4866 """ 

4867 Represents a time from ASN.1 as a Python datetime.datetime object 

4868 """ 

4869 

4870 @property 

4871 def _parsed_time(self): 

4872 """ 

4873 The parsed datetime string. 

4874 

4875 :raises: 

4876 ValueError - when an invalid value is passed 

4877 

4878 :return: 

4879 A dict with the parsed values 

4880 """ 

4881 

4882 string = str_cls(self) 

4883 

4884 m = self._TIMESTRING_RE.match(string) 

4885 if not m: 

4886 raise ValueError(unwrap( 

4887 ''' 

4888 Error parsing %s to a %s 

4889 ''', 

4890 string, 

4891 type_name(self), 

4892 )) 

4893 

4894 groups = m.groupdict() 

4895 

4896 tz = None 

4897 if groups['zulu']: 

4898 tz = timezone.utc 

4899 elif groups['dsign']: 

4900 sign = 1 if groups['dsign'] == '+' else -1 

4901 tz = create_timezone(sign * timedelta( 

4902 hours=int(groups['dhour']), 

4903 minutes=int(groups['dminute'] or 0) 

4904 )) 

4905 

4906 if groups['fraction']: 

4907 # Compute fraction in microseconds 

4908 fract = Fraction( 

4909 int(groups['fraction']), 

4910 10 ** len(groups['fraction']) 

4911 ) * 1000000 

4912 

4913 if groups['minute'] is None: 

4914 fract *= 3600 

4915 elif groups['second'] is None: 

4916 fract *= 60 

4917 

4918 fract_usec = int(fract.limit_denominator(1)) 

4919 

4920 else: 

4921 fract_usec = 0 

4922 

4923 return { 

4924 'year': int(groups['year']), 

4925 'month': int(groups['month']), 

4926 'day': int(groups['day']), 

4927 'hour': int(groups['hour']), 

4928 'minute': int(groups['minute'] or 0), 

4929 'second': int(groups['second'] or 0), 

4930 'tzinfo': tz, 

4931 'fraction': fract_usec, 

4932 } 

4933 

4934 @property 

4935 def native(self): 

4936 """ 

4937 The native Python datatype representation of this value 

4938 

4939 :return: 

4940 A datetime.datetime object, asn1crypto.util.extended_datetime object or 

4941 None. The datetime object is usually timezone aware. If it's naive, then 

4942 it's in the sender's local time; see X.680 sect. 42.3 

4943 """ 

4944 

4945 if self.contents is None: 

4946 return None 

4947 

4948 if self._native is None: 

4949 parsed = self._parsed_time 

4950 

4951 fraction = parsed.pop('fraction', 0) 

4952 

4953 value = self._get_datetime(parsed) 

4954 

4955 if fraction: 

4956 value += timedelta(microseconds=fraction) 

4957 

4958 self._native = value 

4959 

4960 return self._native 

4961 

4962 

4963class UTCTime(AbstractTime): 

4964 """ 

4965 Represents a UTC time from ASN.1 as a timezone aware Python datetime.datetime object 

4966 """ 

4967 

4968 tag = 23 

4969 

4970 # Regular expression for UTCTime as described in X.680 sect. 43 and ISO 8601 

4971 _TIMESTRING_RE = re.compile(r''' 

4972 ^ 

4973 # YYMMDD 

4974 (?P<year>\d{2}) 

4975 (?P<month>\d{2}) 

4976 (?P<day>\d{2}) 

4977 

4978 # hhmm or hhmmss 

4979 (?P<hour>\d{2}) 

4980 (?P<minute>\d{2}) 

4981 (?P<second>\d{2})? 

4982 

4983 # Matches nothing, needed because GeneralizedTime uses this. 

4984 (?P<fraction>) 

4985 

4986 # Z or [-+]hhmm 

4987 (?: 

4988 (?P<zulu>Z) 

4989 | 

4990 (?: 

4991 (?P<dsign>[-+]) 

4992 (?P<dhour>\d{2}) 

4993 (?P<dminute>\d{2}) 

4994 ) 

4995 ) 

4996 $ 

4997 ''', re.X) 

4998 

4999 def set(self, value): 

5000 """ 

5001 Sets the value of the object 

5002 

5003 :param value: 

5004 A unicode string or a datetime.datetime object 

5005 

5006 :raises: 

5007 ValueError - when an invalid value is passed 

5008 """ 

5009 

5010 if isinstance(value, datetime): 

5011 if not value.tzinfo: 

5012 raise ValueError('Must be timezone aware') 

5013 

5014 # Convert value to UTC. 

5015 value = value.astimezone(utc_with_dst) 

5016 

5017 if not 1950 <= value.year <= 2049: 

5018 raise ValueError('Year of the UTCTime is not in range [1950, 2049], use GeneralizedTime instead') 

5019 

5020 value = value.strftime('%y%m%d%H%M%SZ') 

5021 if _PY2: 

5022 value = value.decode('ascii') 

5023 

5024 AbstractString.set(self, value) 

5025 # Set it to None and let the class take care of converting the next 

5026 # time that .native is called 

5027 self._native = None 

5028 

5029 def _get_datetime(self, parsed): 

5030 """ 

5031 Create a datetime object from the parsed time. 

5032 

5033 :return: 

5034 An aware datetime.datetime object 

5035 """ 

5036 

5037 # X.680 only specifies that UTCTime is not using a century. 

5038 # So "18" could as well mean 2118 or 1318. 

5039 # X.509 and CMS specify to use UTCTime for years earlier than 2050. 

5040 # Assume that UTCTime is only used for years [1950, 2049]. 

5041 if parsed['year'] < 50: 

5042 parsed['year'] += 2000 

5043 else: 

5044 parsed['year'] += 1900 

5045 

5046 return datetime(**parsed) 

5047 

5048 

5049class GeneralizedTime(AbstractTime): 

5050 """ 

5051 Represents a generalized time from ASN.1 as a Python datetime.datetime 

5052 object or asn1crypto.util.extended_datetime object in UTC 

5053 """ 

5054 

5055 tag = 24 

5056 

5057 # Regular expression for GeneralizedTime as described in X.680 sect. 42 and ISO 8601 

5058 _TIMESTRING_RE = re.compile(r''' 

5059 ^ 

5060 # YYYYMMDD 

5061 (?P<year>\d{4}) 

5062 (?P<month>\d{2}) 

5063 (?P<day>\d{2}) 

5064 

5065 # hh or hhmm or hhmmss 

5066 (?P<hour>\d{2}) 

5067 (?: 

5068 (?P<minute>\d{2}) 

5069 (?P<second>\d{2})? 

5070 )? 

5071 

5072 # Optional fraction; [.,]dddd (one or more decimals) 

5073 # If Seconds are given, it's fractions of Seconds. 

5074 # Else if Minutes are given, it's fractions of Minutes. 

5075 # Else it's fractions of Hours. 

5076 (?: 

5077 [,.] 

5078 (?P<fraction>\d+) 

5079 )? 

5080 

5081 # Optional timezone. If left out, the time is in local time. 

5082 # Z or [-+]hh or [-+]hhmm 

5083 (?: 

5084 (?P<zulu>Z) 

5085 | 

5086 (?: 

5087 (?P<dsign>[-+]) 

5088 (?P<dhour>\d{2}) 

5089 (?P<dminute>\d{2})? 

5090 ) 

5091 )? 

5092 $ 

5093 ''', re.X) 

5094 

5095 def set(self, value): 

5096 """ 

5097 Sets the value of the object 

5098 

5099 :param value: 

5100 A unicode string, a datetime.datetime object or an 

5101 asn1crypto.util.extended_datetime object 

5102 

5103 :raises: 

5104 ValueError - when an invalid value is passed 

5105 """ 

5106 

5107 if isinstance(value, (datetime, extended_datetime)): 

5108 if not value.tzinfo: 

5109 raise ValueError('Must be timezone aware') 

5110 

5111 # Convert value to UTC. 

5112 value = value.astimezone(utc_with_dst) 

5113 

5114 if value.microsecond: 

5115 fraction = '.' + str(value.microsecond).zfill(6).rstrip('0') 

5116 else: 

5117 fraction = '' 

5118 

5119 value = value.strftime('%Y%m%d%H%M%S') + fraction + 'Z' 

5120 if _PY2: 

5121 value = value.decode('ascii') 

5122 

5123 AbstractString.set(self, value) 

5124 # Set it to None and let the class take care of converting the next 

5125 # time that .native is called 

5126 self._native = None 

5127 

5128 def _get_datetime(self, parsed): 

5129 """ 

5130 Create a datetime object from the parsed time. 

5131 

5132 :return: 

5133 A datetime.datetime object or asn1crypto.util.extended_datetime object. 

5134 It may or may not be aware. 

5135 """ 

5136 

5137 if parsed['year'] == 0: 

5138 # datetime does not support year 0. Use extended_datetime instead. 

5139 return extended_datetime(**parsed) 

5140 else: 

5141 return datetime(**parsed) 

5142 

5143 

5144class GraphicString(AbstractString): 

5145 """ 

5146 Represents a graphic string from ASN.1 as a Python unicode string 

5147 """ 

5148 

5149 tag = 25 

5150 # This is technically not correct since this type can contain any charset 

5151 _encoding = 'latin1' 

5152 

5153 

5154class VisibleString(AbstractString): 

5155 """ 

5156 Represents a visible string from ASN.1 as a Python unicode string 

5157 """ 

5158 

5159 tag = 26 

5160 _encoding = 'latin1' 

5161 

5162 

5163class GeneralString(AbstractString): 

5164 """ 

5165 Represents a general string from ASN.1 as a Python unicode string 

5166 """ 

5167 

5168 tag = 27 

5169 # This is technically not correct since this type can contain any charset 

5170 _encoding = 'latin1' 

5171 

5172 

5173class UniversalString(AbstractString): 

5174 """ 

5175 Represents a universal string from ASN.1 as a Python unicode string 

5176 """ 

5177 

5178 tag = 28 

5179 _encoding = 'utf-32-be' 

5180 

5181 

5182class CharacterString(AbstractString): 

5183 """ 

5184 Represents a character string from ASN.1 as a Python unicode string 

5185 """ 

5186 

5187 tag = 29 

5188 # This is technically not correct since this type can contain any charset 

5189 _encoding = 'latin1' 

5190 

5191 

5192class BMPString(AbstractString): 

5193 """ 

5194 Represents a BMP string from ASN.1 as a Python unicode string 

5195 """ 

5196 

5197 tag = 30 

5198 _encoding = 'utf-16-be' 

5199 

5200 

5201def _basic_debug(prefix, self): 

5202 """ 

5203 Prints out basic information about an Asn1Value object. Extracted for reuse 

5204 among different classes that customize the debug information. 

5205 

5206 :param prefix: 

5207 A unicode string of spaces to prefix output line with 

5208 

5209 :param self: 

5210 The object to print the debugging information about 

5211 """ 

5212 

5213 print('%s%s Object #%s' % (prefix, type_name(self), id(self))) 

5214 if self._header: 

5215 print('%s Header: 0x%s' % (prefix, binascii.hexlify(self._header or b'').decode('utf-8'))) 

5216 

5217 has_header = self.method is not None and self.class_ is not None and self.tag is not None 

5218 if has_header: 

5219 method_name = METHOD_NUM_TO_NAME_MAP.get(self.method) 

5220 class_name = CLASS_NUM_TO_NAME_MAP.get(self.class_) 

5221 

5222 if self.explicit is not None: 

5223 for class_, tag in self.explicit: 

5224 print( 

5225 '%s %s tag %s (explicitly tagged)' % 

5226 ( 

5227 prefix, 

5228 CLASS_NUM_TO_NAME_MAP.get(class_), 

5229 tag 

5230 ) 

5231 ) 

5232 if has_header: 

5233 print('%s %s %s %s' % (prefix, method_name, class_name, self.tag)) 

5234 

5235 elif self.implicit: 

5236 if has_header: 

5237 print('%s %s %s tag %s (implicitly tagged)' % (prefix, method_name, class_name, self.tag)) 

5238 

5239 elif has_header: 

5240 print('%s %s %s tag %s' % (prefix, method_name, class_name, self.tag)) 

5241 

5242 if self._trailer: 

5243 print('%s Trailer: 0x%s' % (prefix, binascii.hexlify(self._trailer or b'').decode('utf-8'))) 

5244 

5245 print('%s Data: 0x%s' % (prefix, binascii.hexlify(self.contents or b'').decode('utf-8'))) 

5246 

5247 

5248def _tag_type_to_explicit_implicit(params): 

5249 """ 

5250 Converts old-style "tag_type" and "tag" params to "explicit" and "implicit" 

5251 

5252 :param params: 

5253 A dict of parameters to convert from tag_type/tag to explicit/implicit 

5254 """ 

5255 

5256 if 'tag_type' in params: 

5257 if params['tag_type'] == 'explicit': 

5258 params['explicit'] = (params.get('class', 2), params['tag']) 

5259 elif params['tag_type'] == 'implicit': 

5260 params['implicit'] = (params.get('class', 2), params['tag']) 

5261 del params['tag_type'] 

5262 del params['tag'] 

5263 if 'class' in params: 

5264 del params['class'] 

5265 

5266 

5267def _fix_tagging(value, params): 

5268 """ 

5269 Checks if a value is properly tagged based on the spec, and re/untags as 

5270 necessary 

5271 

5272 :param value: 

5273 An Asn1Value object 

5274 

5275 :param params: 

5276 A dict of spec params 

5277 

5278 :return: 

5279 An Asn1Value that is properly tagged 

5280 """ 

5281 

5282 _tag_type_to_explicit_implicit(params) 

5283 

5284 retag = False 

5285 if 'implicit' not in params: 

5286 if value.implicit is not False: 

5287 retag = True 

5288 else: 

5289 if isinstance(params['implicit'], tuple): 

5290 class_, tag = params['implicit'] 

5291 else: 

5292 tag = params['implicit'] 

5293 class_ = 'context' 

5294 if value.implicit is False: 

5295 retag = True 

5296 elif value.class_ != CLASS_NAME_TO_NUM_MAP[class_] or value.tag != tag: 

5297 retag = True 

5298 

5299 if params.get('explicit') != value.explicit: 

5300 retag = True 

5301 

5302 if retag: 

5303 return value.retag(params) 

5304 return value 

5305 

5306 

5307def _build_id_tuple(params, spec): 

5308 """ 

5309 Builds a 2-element tuple used to identify fields by grabbing the class_ 

5310 and tag from an Asn1Value class and the params dict being passed to it 

5311 

5312 :param params: 

5313 A dict of params to pass to spec 

5314 

5315 :param spec: 

5316 An Asn1Value class 

5317 

5318 :return: 

5319 A 2-element integer tuple in the form (class_, tag) 

5320 """ 

5321 

5322 # Handle situations where the spec is not known at setup time 

5323 if spec is None: 

5324 return (None, None) 

5325 

5326 required_class = spec.class_ 

5327 required_tag = spec.tag 

5328 

5329 _tag_type_to_explicit_implicit(params) 

5330 

5331 if 'explicit' in params: 

5332 if isinstance(params['explicit'], tuple): 

5333 required_class, required_tag = params['explicit'] 

5334 else: 

5335 required_class = 2 

5336 required_tag = params['explicit'] 

5337 elif 'implicit' in params: 

5338 if isinstance(params['implicit'], tuple): 

5339 required_class, required_tag = params['implicit'] 

5340 else: 

5341 required_class = 2 

5342 required_tag = params['implicit'] 

5343 if required_class is not None and not isinstance(required_class, int_types): 

5344 required_class = CLASS_NAME_TO_NUM_MAP[required_class] 

5345 

5346 required_class = params.get('class_', required_class) 

5347 required_tag = params.get('tag', required_tag) 

5348 

5349 return (required_class, required_tag) 

5350 

5351 

5352def _int_to_bit_tuple(value, bits): 

5353 """ 

5354 Format value as a tuple of 1s and 0s. 

5355 

5356 :param value: 

5357 A non-negative integer to format 

5358 

5359 :param bits: 

5360 Number of bits in the output 

5361 

5362 :return: 

5363 A tuple of 1s and 0s with bits members. 

5364 """ 

5365 

5366 if not value and not bits: 

5367 return () 

5368 

5369 result = tuple(map(int, format(value, '0{0}b'.format(bits)))) 

5370 if len(result) != bits: 

5371 raise ValueError('Result too large: {0} > {1}'.format(len(result), bits)) 

5372 

5373 return result 

5374 

5375 

5376_UNIVERSAL_SPECS = { 

5377 1: Boolean, 

5378 2: Integer, 

5379 3: BitString, 

5380 4: OctetString, 

5381 5: Null, 

5382 6: ObjectIdentifier, 

5383 7: ObjectDescriptor, 

5384 8: InstanceOf, 

5385 9: Real, 

5386 10: Enumerated, 

5387 11: EmbeddedPdv, 

5388 12: UTF8String, 

5389 13: RelativeOid, 

5390 16: Sequence, 

5391 17: Set, 

5392 18: NumericString, 

5393 19: PrintableString, 

5394 20: TeletexString, 

5395 21: VideotexString, 

5396 22: IA5String, 

5397 23: UTCTime, 

5398 24: GeneralizedTime, 

5399 25: GraphicString, 

5400 26: VisibleString, 

5401 27: GeneralString, 

5402 28: UniversalString, 

5403 29: CharacterString, 

5404 30: BMPString 

5405} 

5406 

5407 

5408def _build(class_, method, tag, header, contents, trailer, spec=None, spec_params=None, nested_spec=None): 

5409 """ 

5410 Builds an Asn1Value object generically, or using a spec with optional params 

5411 

5412 :param class_: 

5413 An integer representing the ASN.1 class 

5414 

5415 :param method: 

5416 An integer representing the ASN.1 method 

5417 

5418 :param tag: 

5419 An integer representing the ASN.1 tag 

5420 

5421 :param header: 

5422 A byte string of the ASN.1 header (class, method, tag, length) 

5423 

5424 :param contents: 

5425 A byte string of the ASN.1 value 

5426 

5427 :param trailer: 

5428 A byte string of any ASN.1 trailer (only used by indefinite length encodings) 

5429 

5430 :param spec: 

5431 A class derived from Asn1Value that defines what class_ and tag the 

5432 value should have, and the semantics of the encoded value. The 

5433 return value will be of this type. If omitted, the encoded value 

5434 will be decoded using the standard universal tag based on the 

5435 encoded tag number. 

5436 

5437 :param spec_params: 

5438 A dict of params to pass to the spec object 

5439 

5440 :param nested_spec: 

5441 For certain Asn1Value classes (such as OctetString and BitString), the 

5442 contents can be further parsed and interpreted as another Asn1Value. 

5443 This parameter controls the spec for that sub-parsing. 

5444 

5445 :return: 

5446 An object of the type spec, or if not specified, a child of Asn1Value 

5447 """ 

5448 

5449 if spec_params is not None: 

5450 _tag_type_to_explicit_implicit(spec_params) 

5451 

5452 if header is None: 

5453 return VOID 

5454 

5455 header_set = False 

5456 

5457 # If an explicit specification was passed in, make sure it matches 

5458 if spec is not None: 

5459 # If there is explicit tagging and contents, we have to split 

5460 # the header and trailer off before we do the parsing 

5461 no_explicit = spec_params and 'no_explicit' in spec_params 

5462 if not no_explicit and (spec.explicit or (spec_params and 'explicit' in spec_params)): 

5463 if spec_params: 

5464 value = spec(**spec_params) 

5465 else: 

5466 value = spec() 

5467 original_explicit = value.explicit 

5468 explicit_info = reversed(original_explicit) 

5469 parsed_class = class_ 

5470 parsed_method = method 

5471 parsed_tag = tag 

5472 to_parse = contents 

5473 explicit_header = header 

5474 explicit_trailer = trailer or b'' 

5475 for expected_class, expected_tag in explicit_info: 

5476 if parsed_class != expected_class: 

5477 raise ValueError(unwrap( 

5478 ''' 

5479 Error parsing %s - explicitly-tagged class should have been 

5480 %s, but %s was found 

5481 ''', 

5482 type_name(value), 

5483 CLASS_NUM_TO_NAME_MAP.get(expected_class), 

5484 CLASS_NUM_TO_NAME_MAP.get(parsed_class, parsed_class) 

5485 )) 

5486 if parsed_method != 1: 

5487 raise ValueError(unwrap( 

5488 ''' 

5489 Error parsing %s - explicitly-tagged method should have 

5490 been %s, but %s was found 

5491 ''', 

5492 type_name(value), 

5493 METHOD_NUM_TO_NAME_MAP.get(1), 

5494 METHOD_NUM_TO_NAME_MAP.get(parsed_method, parsed_method) 

5495 )) 

5496 if parsed_tag != expected_tag: 

5497 raise ValueError(unwrap( 

5498 ''' 

5499 Error parsing %s - explicitly-tagged tag should have been 

5500 %s, but %s was found 

5501 ''', 

5502 type_name(value), 

5503 expected_tag, 

5504 parsed_tag 

5505 )) 

5506 info, _ = _parse(to_parse, len(to_parse)) 

5507 parsed_class, parsed_method, parsed_tag, parsed_header, to_parse, parsed_trailer = info 

5508 

5509 if not isinstance(value, Choice): 

5510 explicit_header += parsed_header 

5511 explicit_trailer = parsed_trailer + explicit_trailer 

5512 

5513 value = _build(*info, spec=spec, spec_params={'no_explicit': True}) 

5514 value._header = explicit_header 

5515 value._trailer = explicit_trailer 

5516 value.explicit = original_explicit 

5517 header_set = True 

5518 else: 

5519 if spec_params: 

5520 value = spec(contents=contents, **spec_params) 

5521 else: 

5522 value = spec(contents=contents) 

5523 

5524 if spec is Any: 

5525 pass 

5526 

5527 elif isinstance(value, Choice): 

5528 value.validate(class_, tag, contents) 

5529 try: 

5530 # Force parsing the Choice now 

5531 value.contents = header + value.contents 

5532 header = b'' 

5533 value.parse() 

5534 except (ValueError, TypeError) as e: 

5535 args = e.args[1:] 

5536 e.args = (e.args[0] + '\n while parsing %s' % type_name(value),) + args 

5537 raise e 

5538 

5539 else: 

5540 if class_ != value.class_: 

5541 raise ValueError(unwrap( 

5542 ''' 

5543 Error parsing %s - class should have been %s, but %s was 

5544 found 

5545 ''', 

5546 type_name(value), 

5547 CLASS_NUM_TO_NAME_MAP.get(value.class_), 

5548 CLASS_NUM_TO_NAME_MAP.get(class_, class_) 

5549 )) 

5550 if method != value.method: 

5551 # Allow parsing a primitive method as constructed if the value 

5552 # is indefinite length. This is to allow parsing BER. 

5553 ber_indef = method == 1 and value.method == 0 and trailer == b'\x00\x00' 

5554 if not ber_indef or not isinstance(value, Constructable): 

5555 raise ValueError(unwrap( 

5556 ''' 

5557 Error parsing %s - method should have been %s, but %s was found 

5558 ''', 

5559 type_name(value), 

5560 METHOD_NUM_TO_NAME_MAP.get(value.method), 

5561 METHOD_NUM_TO_NAME_MAP.get(method, method) 

5562 )) 

5563 else: 

5564 value.method = method 

5565 value._indefinite = True 

5566 if tag != value.tag: 

5567 if isinstance(value._bad_tag, tuple): 

5568 is_bad_tag = tag in value._bad_tag 

5569 else: 

5570 is_bad_tag = tag == value._bad_tag 

5571 if not is_bad_tag: 

5572 raise ValueError(unwrap( 

5573 ''' 

5574 Error parsing %s - tag should have been %s, but %s was found 

5575 ''', 

5576 type_name(value), 

5577 value.tag, 

5578 tag 

5579 )) 

5580 

5581 # For explicitly tagged, un-speced parsings, we use a generic container 

5582 # since we will be parsing the contents and discarding the outer object 

5583 # anyway a little further on 

5584 elif spec_params and 'explicit' in spec_params: 

5585 original_value = Asn1Value(contents=contents, **spec_params) 

5586 original_explicit = original_value.explicit 

5587 

5588 to_parse = contents 

5589 explicit_header = header 

5590 explicit_trailer = trailer or b'' 

5591 for expected_class, expected_tag in reversed(original_explicit): 

5592 info, _ = _parse(to_parse, len(to_parse)) 

5593 _, _, _, parsed_header, to_parse, parsed_trailer = info 

5594 explicit_header += parsed_header 

5595 explicit_trailer = parsed_trailer + explicit_trailer 

5596 value = _build(*info, spec=spec, spec_params={'no_explicit': True}) 

5597 value._header = header + value._header 

5598 value._trailer += trailer or b'' 

5599 value.explicit = original_explicit 

5600 header_set = True 

5601 

5602 # If no spec was specified, allow anything and just process what 

5603 # is in the input data 

5604 else: 

5605 if tag not in _UNIVERSAL_SPECS: 

5606 raise ValueError(unwrap( 

5607 ''' 

5608 Unknown element - %s class, %s method, tag %s 

5609 ''', 

5610 CLASS_NUM_TO_NAME_MAP.get(class_), 

5611 METHOD_NUM_TO_NAME_MAP.get(method), 

5612 tag 

5613 )) 

5614 

5615 spec = _UNIVERSAL_SPECS[tag] 

5616 

5617 value = spec(contents=contents, class_=class_) 

5618 ber_indef = method == 1 and value.method == 0 and trailer == b'\x00\x00' 

5619 if ber_indef and isinstance(value, Constructable): 

5620 value._indefinite = True 

5621 value.method = method 

5622 

5623 if not header_set: 

5624 value._header = header 

5625 value._trailer = trailer or b'' 

5626 

5627 # Destroy any default value that our contents have overwritten 

5628 value._native = None 

5629 

5630 if nested_spec: 

5631 try: 

5632 value.parse(nested_spec) 

5633 except (ValueError, TypeError) as e: 

5634 args = e.args[1:] 

5635 e.args = (e.args[0] + '\n while parsing %s' % type_name(value),) + args 

5636 raise e 

5637 

5638 return value 

5639 

5640 

5641def _parse_build(encoded_data, pointer=0, spec=None, spec_params=None, strict=False): 

5642 """ 

5643 Parses a byte string generically, or using a spec with optional params 

5644 

5645 :param encoded_data: 

5646 A byte string that contains BER-encoded data 

5647 

5648 :param pointer: 

5649 The index in the byte string to parse from 

5650 

5651 :param spec: 

5652 A class derived from Asn1Value that defines what class_ and tag the 

5653 value should have, and the semantics of the encoded value. The 

5654 return value will be of this type. If omitted, the encoded value 

5655 will be decoded using the standard universal tag based on the 

5656 encoded tag number. 

5657 

5658 :param spec_params: 

5659 A dict of params to pass to the spec object 

5660 

5661 :param strict: 

5662 A boolean indicating if trailing data should be forbidden - if so, a 

5663 ValueError will be raised when trailing data exists 

5664 

5665 :return: 

5666 A 2-element tuple: 

5667 - 0: An object of the type spec, or if not specified, a child of Asn1Value 

5668 - 1: An integer indicating how many bytes were consumed 

5669 """ 

5670 

5671 encoded_len = len(encoded_data) 

5672 info, new_pointer = _parse(encoded_data, encoded_len, pointer) 

5673 if strict and new_pointer != pointer + encoded_len: 

5674 extra_bytes = pointer + encoded_len - new_pointer 

5675 raise ValueError('Extra data - %d bytes of trailing data were provided' % extra_bytes) 

5676 return (_build(*info, spec=spec, spec_params=spec_params), new_pointer)