1# 2# This file is part of pyasn1 software. 3# 4# Copyright (c) 2005-2019, Ilya Etingof <etingof@gmail.com> 5# License: http://snmplabs.com/pyasn1/license.html 6# 7import sys 8 9from pyasn1 import debug 10from pyasn1 import error 11from pyasn1.codec.ber import eoo 12from pyasn1.compat.integer import to_bytes 13from pyasn1.compat.octets import (int2oct, oct2int, ints2octs, null, 14 str2octs, isOctetsType) 15from pyasn1.type import char 16from pyasn1.type import tag 17from pyasn1.type import univ 18from pyasn1.type import useful 19 20__all__ = ['encode'] 21 22LOG = debug.registerLoggee(__name__, flags=debug.DEBUG_ENCODER) 23 24 25class AbstractItemEncoder(object): 26 supportIndefLenMode = True 27 28 # An outcome of otherwise legit call `encodeFun(eoo.endOfOctets)` 29 eooIntegerSubstrate = (0, 0) 30 eooOctetsSubstrate = ints2octs(eooIntegerSubstrate) 31 32 # noinspection PyMethodMayBeStatic 33 def encodeTag(self, singleTag, isConstructed): 34 tagClass, tagFormat, tagId = singleTag 35 encodedTag = tagClass | tagFormat 36 if isConstructed: 37 encodedTag |= tag.tagFormatConstructed 38 39 if tagId < 31: 40 return encodedTag | tagId, 41 42 else: 43 substrate = tagId & 0x7f, 44 45 tagId >>= 7 46 47 while tagId: 48 substrate = (0x80 | (tagId & 0x7f),) + substrate 49 tagId >>= 7 50 51 return (encodedTag | 0x1F,) + substrate 52 53 def encodeLength(self, length, defMode): 54 if not defMode and self.supportIndefLenMode: 55 return (0x80,) 56 57 if length < 0x80: 58 return length, 59 60 else: 61 substrate = () 62 while length: 63 substrate = (length & 0xff,) + substrate 64 length >>= 8 65 66 substrateLen = len(substrate) 67 68 if substrateLen > 126: 69 raise error.PyAsn1Error('Length octets overflow (%d)' % substrateLen) 70 71 return (0x80 | substrateLen,) + substrate 72 73 def encodeValue(self, value, asn1Spec, encodeFun, **options): 74 raise error.PyAsn1Error('Not implemented') 75 76 def encode(self, value, asn1Spec=None, encodeFun=None, **options): 77 78 if asn1Spec is None: 79 tagSet = value.tagSet 80 else: 81 tagSet = asn1Spec.tagSet 82 83 # untagged item? 84 if not tagSet: 85 substrate, isConstructed, isOctets = self.encodeValue( 86 value, asn1Spec, encodeFun, **options 87 ) 88 return substrate 89 90 defMode = options.get('defMode', True) 91 92 substrate = null 93 94 for idx, singleTag in enumerate(tagSet.superTags): 95 96 defModeOverride = defMode 97 98 # base tag? 99 if not idx: 100 try: 101 substrate, isConstructed, isOctets = self.encodeValue( 102 value, asn1Spec, encodeFun, **options 103 ) 104 105 except error.PyAsn1Error: 106 exc = sys.exc_info() 107 raise error.PyAsn1Error( 108 'Error encoding %r: %s' % (value, exc[1])) 109 110 if LOG: 111 LOG('encoded %svalue %s into %s' % ( 112 isConstructed and 'constructed ' or '', value, substrate 113 )) 114 115 if not substrate and isConstructed and options.get('ifNotEmpty', False): 116 return substrate 117 118 if not isConstructed: 119 defModeOverride = True 120 121 if LOG: 122 LOG('overridden encoding mode into definitive for primitive type') 123 124 header = self.encodeTag(singleTag, isConstructed) 125 126 if LOG: 127 LOG('encoded %stag %s into %s' % ( 128 isConstructed and 'constructed ' or '', 129 singleTag, debug.hexdump(ints2octs(header)))) 130 131 header += self.encodeLength(len(substrate), defModeOverride) 132 133 if LOG: 134 LOG('encoded %s octets (tag + payload) into %s' % ( 135 len(substrate), debug.hexdump(ints2octs(header)))) 136 137 if isOctets: 138 substrate = ints2octs(header) + substrate 139 140 if not defModeOverride: 141 substrate += self.eooOctetsSubstrate 142 143 else: 144 substrate = header + substrate 145 146 if not defModeOverride: 147 substrate += self.eooIntegerSubstrate 148 149 if not isOctets: 150 substrate = ints2octs(substrate) 151 152 return substrate 153 154 155class EndOfOctetsEncoder(AbstractItemEncoder): 156 def encodeValue(self, value, asn1Spec, encodeFun, **options): 157 return null, False, True 158 159 160class BooleanEncoder(AbstractItemEncoder): 161 supportIndefLenMode = False 162 163 def encodeValue(self, value, asn1Spec, encodeFun, **options): 164 return value and (1,) or (0,), False, False 165 166 167class IntegerEncoder(AbstractItemEncoder): 168 supportIndefLenMode = False 169 supportCompactZero = False 170 171 def encodeValue(self, value, asn1Spec, encodeFun, **options): 172 if value == 0: 173 if LOG: 174 LOG('encoding %spayload for zero INTEGER' % ( 175 self.supportCompactZero and 'no ' or '' 176 )) 177 178 # de-facto way to encode zero 179 if self.supportCompactZero: 180 return (), False, False 181 else: 182 return (0,), False, False 183 184 return to_bytes(int(value), signed=True), False, True 185 186 187class BitStringEncoder(AbstractItemEncoder): 188 def encodeValue(self, value, asn1Spec, encodeFun, **options): 189 if asn1Spec is not None: 190 # TODO: try to avoid ASN.1 schema instantiation 191 value = asn1Spec.clone(value) 192 193 valueLength = len(value) 194 if valueLength % 8: 195 alignedValue = value << (8 - valueLength % 8) 196 else: 197 alignedValue = value 198 199 maxChunkSize = options.get('maxChunkSize', 0) 200 if not maxChunkSize or len(alignedValue) <= maxChunkSize * 8: 201 substrate = alignedValue.asOctets() 202 return int2oct(len(substrate) * 8 - valueLength) + substrate, False, True 203 204 if LOG: 205 LOG('encoding into up to %s-octet chunks' % maxChunkSize) 206 207 baseTag = value.tagSet.baseTag 208 209 # strip off explicit tags 210 if baseTag: 211 tagSet = tag.TagSet(baseTag, baseTag) 212 213 else: 214 tagSet = tag.TagSet() 215 216 alignedValue = alignedValue.clone(tagSet=tagSet) 217 218 stop = 0 219 substrate = null 220 while stop < valueLength: 221 start = stop 222 stop = min(start + maxChunkSize * 8, valueLength) 223 substrate += encodeFun(alignedValue[start:stop], asn1Spec, **options) 224 225 return substrate, True, True 226 227 228class OctetStringEncoder(AbstractItemEncoder): 229 230 def encodeValue(self, value, asn1Spec, encodeFun, **options): 231 232 if asn1Spec is None: 233 substrate = value.asOctets() 234 235 elif not isOctetsType(value): 236 substrate = asn1Spec.clone(value).asOctets() 237 238 else: 239 substrate = value 240 241 maxChunkSize = options.get('maxChunkSize', 0) 242 243 if not maxChunkSize or len(substrate) <= maxChunkSize: 244 return substrate, False, True 245 246 if LOG: 247 LOG('encoding into up to %s-octet chunks' % maxChunkSize) 248 249 # strip off explicit tags for inner chunks 250 251 if asn1Spec is None: 252 baseTag = value.tagSet.baseTag 253 254 # strip off explicit tags 255 if baseTag: 256 tagSet = tag.TagSet(baseTag, baseTag) 257 258 else: 259 tagSet = tag.TagSet() 260 261 asn1Spec = value.clone(tagSet=tagSet) 262 263 elif not isOctetsType(value): 264 baseTag = asn1Spec.tagSet.baseTag 265 266 # strip off explicit tags 267 if baseTag: 268 tagSet = tag.TagSet(baseTag, baseTag) 269 270 else: 271 tagSet = tag.TagSet() 272 273 asn1Spec = asn1Spec.clone(tagSet=tagSet) 274 275 pos = 0 276 substrate = null 277 278 while True: 279 chunk = value[pos:pos + maxChunkSize] 280 if not chunk: 281 break 282 283 substrate += encodeFun(chunk, asn1Spec, **options) 284 pos += maxChunkSize 285 286 return substrate, True, True 287 288 289class NullEncoder(AbstractItemEncoder): 290 supportIndefLenMode = False 291 292 def encodeValue(self, value, asn1Spec, encodeFun, **options): 293 return null, False, True 294 295 296class ObjectIdentifierEncoder(AbstractItemEncoder): 297 supportIndefLenMode = False 298 299 def encodeValue(self, value, asn1Spec, encodeFun, **options): 300 if asn1Spec is not None: 301 value = asn1Spec.clone(value) 302 303 oid = value.asTuple() 304 305 # Build the first pair 306 try: 307 first = oid[0] 308 second = oid[1] 309 310 except IndexError: 311 raise error.PyAsn1Error('Short OID %s' % (value,)) 312 313 if 0 <= second <= 39: 314 if first == 1: 315 oid = (second + 40,) + oid[2:] 316 elif first == 0: 317 oid = (second,) + oid[2:] 318 elif first == 2: 319 oid = (second + 80,) + oid[2:] 320 else: 321 raise error.PyAsn1Error('Impossible first/second arcs at %s' % (value,)) 322 323 elif first == 2: 324 oid = (second + 80,) + oid[2:] 325 326 else: 327 raise error.PyAsn1Error('Impossible first/second arcs at %s' % (value,)) 328 329 octets = () 330 331 # Cycle through subIds 332 for subOid in oid: 333 if 0 <= subOid <= 127: 334 # Optimize for the common case 335 octets += (subOid,) 336 337 elif subOid > 127: 338 # Pack large Sub-Object IDs 339 res = (subOid & 0x7f,) 340 subOid >>= 7 341 342 while subOid: 343 res = (0x80 | (subOid & 0x7f),) + res 344 subOid >>= 7 345 346 # Add packed Sub-Object ID to resulted Object ID 347 octets += res 348 349 else: 350 raise error.PyAsn1Error('Negative OID arc %s at %s' % (subOid, value)) 351 352 return octets, False, False 353 354 355class RealEncoder(AbstractItemEncoder): 356 supportIndefLenMode = 0 357 binEncBase = 2 # set to None to choose encoding base automatically 358 359 @staticmethod 360 def _dropFloatingPoint(m, encbase, e): 361 ms, es = 1, 1 362 if m < 0: 363 ms = -1 # mantissa sign 364 365 if e < 0: 366 es = -1 # exponent sign 367 368 m *= ms 369 370 if encbase == 8: 371 m *= 2 ** (abs(e) % 3 * es) 372 e = abs(e) // 3 * es 373 374 elif encbase == 16: 375 m *= 2 ** (abs(e) % 4 * es) 376 e = abs(e) // 4 * es 377 378 while True: 379 if int(m) != m: 380 m *= encbase 381 e -= 1 382 continue 383 break 384 385 return ms, int(m), encbase, e 386 387 def _chooseEncBase(self, value): 388 m, b, e = value 389 encBase = [2, 8, 16] 390 if value.binEncBase in encBase: 391 return self._dropFloatingPoint(m, value.binEncBase, e) 392 393 elif self.binEncBase in encBase: 394 return self._dropFloatingPoint(m, self.binEncBase, e) 395 396 # auto choosing base 2/8/16 397 mantissa = [m, m, m] 398 exponent = [e, e, e] 399 sign = 1 400 encbase = 2 401 e = float('inf') 402 403 for i in range(3): 404 (sign, 405 mantissa[i], 406 encBase[i], 407 exponent[i]) = self._dropFloatingPoint(mantissa[i], encBase[i], exponent[i]) 408 409 if abs(exponent[i]) < abs(e) or (abs(exponent[i]) == abs(e) and mantissa[i] < m): 410 e = exponent[i] 411 m = int(mantissa[i]) 412 encbase = encBase[i] 413 414 if LOG: 415 LOG('automatically chosen REAL encoding base %s, sign %s, mantissa %s, ' 416 'exponent %s' % (encbase, sign, m, e)) 417 418 return sign, m, encbase, e 419 420 def encodeValue(self, value, asn1Spec, encodeFun, **options): 421 if asn1Spec is not None: 422 value = asn1Spec.clone(value) 423 424 if value.isPlusInf: 425 return (0x40,), False, False 426 427 if value.isMinusInf: 428 return (0x41,), False, False 429 430 m, b, e = value 431 432 if not m: 433 return null, False, True 434 435 if b == 10: 436 if LOG: 437 LOG('encoding REAL into character form') 438 439 return str2octs('\x03%dE%s%d' % (m, e == 0 and '+' or '', e)), False, True 440 441 elif b == 2: 442 fo = 0x80 # binary encoding 443 ms, m, encbase, e = self._chooseEncBase(value) 444 445 if ms < 0: # mantissa sign 446 fo |= 0x40 # sign bit 447 448 # exponent & mantissa normalization 449 if encbase == 2: 450 while m & 0x1 == 0: 451 m >>= 1 452 e += 1 453 454 elif encbase == 8: 455 while m & 0x7 == 0: 456 m >>= 3 457 e += 1 458 fo |= 0x10 459 460 else: # encbase = 16 461 while m & 0xf == 0: 462 m >>= 4 463 e += 1 464 fo |= 0x20 465 466 sf = 0 # scale factor 467 468 while m & 0x1 == 0: 469 m >>= 1 470 sf += 1 471 472 if sf > 3: 473 raise error.PyAsn1Error('Scale factor overflow') # bug if raised 474 475 fo |= sf << 2 476 eo = null 477 if e == 0 or e == -1: 478 eo = int2oct(e & 0xff) 479 480 else: 481 while e not in (0, -1): 482 eo = int2oct(e & 0xff) + eo 483 e >>= 8 484 485 if e == 0 and eo and oct2int(eo[0]) & 0x80: 486 eo = int2oct(0) + eo 487 488 if e == -1 and eo and not (oct2int(eo[0]) & 0x80): 489 eo = int2oct(0xff) + eo 490 491 n = len(eo) 492 if n > 0xff: 493 raise error.PyAsn1Error('Real exponent overflow') 494 495 if n == 1: 496 pass 497 498 elif n == 2: 499 fo |= 1 500 501 elif n == 3: 502 fo |= 2 503 504 else: 505 fo |= 3 506 eo = int2oct(n & 0xff) + eo 507 508 po = null 509 510 while m: 511 po = int2oct(m & 0xff) + po 512 m >>= 8 513 514 substrate = int2oct(fo) + eo + po 515 516 return substrate, False, True 517 518 else: 519 raise error.PyAsn1Error('Prohibited Real base %s' % b) 520 521 522class SequenceEncoder(AbstractItemEncoder): 523 omitEmptyOptionals = False 524 525 # TODO: handling three flavors of input is too much -- split over codecs 526 527 def encodeValue(self, value, asn1Spec, encodeFun, **options): 528 529 substrate = null 530 531 omitEmptyOptionals = options.get( 532 'omitEmptyOptionals', self.omitEmptyOptionals) 533 534 if LOG: 535 LOG('%sencoding empty OPTIONAL components' % ( 536 omitEmptyOptionals and 'not ' or '')) 537 538 if asn1Spec is None: 539 # instance of ASN.1 schema 540 inconsistency = value.isInconsistent 541 if inconsistency: 542 raise inconsistency 543 544 namedTypes = value.componentType 545 546 for idx, component in enumerate(value.values()): 547 if namedTypes: 548 namedType = namedTypes[idx] 549 550 if namedType.isOptional and not component.isValue: 551 if LOG: 552 LOG('not encoding OPTIONAL component %r' % (namedType,)) 553 continue 554 555 if namedType.isDefaulted and component == namedType.asn1Object: 556 if LOG: 557 LOG('not encoding DEFAULT component %r' % (namedType,)) 558 continue 559 560 if omitEmptyOptionals: 561 options.update(ifNotEmpty=namedType.isOptional) 562 563 # wrap open type blob if needed 564 if namedTypes and namedType.openType: 565 566 wrapType = namedType.asn1Object 567 568 if wrapType.typeId in ( 569 univ.SetOf.typeId, univ.SequenceOf.typeId): 570 571 substrate += encodeFun( 572 component, asn1Spec, 573 **dict(options, wrapType=wrapType.componentType)) 574 575 else: 576 chunk = encodeFun(component, asn1Spec, **options) 577 578 if wrapType.isSameTypeWith(component): 579 substrate += chunk 580 581 else: 582 substrate += encodeFun(chunk, wrapType, **options) 583 584 if LOG: 585 LOG('wrapped with wrap type %r' % (wrapType,)) 586 587 else: 588 substrate += encodeFun(component, asn1Spec, **options) 589 590 else: 591 # bare Python value + ASN.1 schema 592 for idx, namedType in enumerate(asn1Spec.componentType.namedTypes): 593 594 try: 595 component = value[namedType.name] 596 597 except KeyError: 598 raise error.PyAsn1Error('Component name "%s" not found in %r' % ( 599 namedType.name, value)) 600 601 if namedType.isOptional and namedType.name not in value: 602 if LOG: 603 LOG('not encoding OPTIONAL component %r' % (namedType,)) 604 continue 605 606 if namedType.isDefaulted and component == namedType.asn1Object: 607 if LOG: 608 LOG('not encoding DEFAULT component %r' % (namedType,)) 609 continue 610 611 if omitEmptyOptionals: 612 options.update(ifNotEmpty=namedType.isOptional) 613 614 componentSpec = namedType.asn1Object 615 616 # wrap open type blob if needed 617 if namedType.openType: 618 619 if componentSpec.typeId in ( 620 univ.SetOf.typeId, univ.SequenceOf.typeId): 621 622 substrate += encodeFun( 623 component, componentSpec, 624 **dict(options, wrapType=componentSpec.componentType)) 625 626 else: 627 chunk = encodeFun(component, componentSpec, **options) 628 629 if componentSpec.isSameTypeWith(component): 630 substrate += chunk 631 632 else: 633 substrate += encodeFun(chunk, componentSpec, **options) 634 635 if LOG: 636 LOG('wrapped with wrap type %r' % (componentSpec,)) 637 638 else: 639 substrate += encodeFun(component, componentSpec, **options) 640 641 return substrate, True, True 642 643 644class SequenceOfEncoder(AbstractItemEncoder): 645 def _encodeComponents(self, value, asn1Spec, encodeFun, **options): 646 647 if asn1Spec is None: 648 inconsistency = value.isInconsistent 649 if inconsistency: 650 raise inconsistency 651 652 else: 653 asn1Spec = asn1Spec.componentType 654 655 chunks = [] 656 657 wrapType = options.pop('wrapType', None) 658 659 for idx, component in enumerate(value): 660 chunk = encodeFun(component, asn1Spec, **options) 661 662 if (wrapType is not None and 663 not wrapType.isSameTypeWith(component)): 664 # wrap encoded value with wrapper container (e.g. ANY) 665 chunk = encodeFun(chunk, wrapType, **options) 666 667 if LOG: 668 LOG('wrapped with wrap type %r' % (wrapType,)) 669 670 chunks.append(chunk) 671 672 return chunks 673 674 def encodeValue(self, value, asn1Spec, encodeFun, **options): 675 chunks = self._encodeComponents( 676 value, asn1Spec, encodeFun, **options) 677 678 return null.join(chunks), True, True 679 680 681class ChoiceEncoder(AbstractItemEncoder): 682 def encodeValue(self, value, asn1Spec, encodeFun, **options): 683 if asn1Spec is None: 684 component = value.getComponent() 685 else: 686 names = [namedType.name for namedType in asn1Spec.componentType.namedTypes 687 if namedType.name in value] 688 if len(names) != 1: 689 raise error.PyAsn1Error('%s components for Choice at %r' % (len(names) and 'Multiple ' or 'None ', value)) 690 691 name = names[0] 692 693 component = value[name] 694 asn1Spec = asn1Spec[name] 695 696 return encodeFun(component, asn1Spec, **options), True, True 697 698 699class AnyEncoder(OctetStringEncoder): 700 def encodeValue(self, value, asn1Spec, encodeFun, **options): 701 if asn1Spec is None: 702 value = value.asOctets() 703 elif not isOctetsType(value): 704 value = asn1Spec.clone(value).asOctets() 705 706 return value, not options.get('defMode', True), True 707 708 709tagMap = { 710 eoo.endOfOctets.tagSet: EndOfOctetsEncoder(), 711 univ.Boolean.tagSet: BooleanEncoder(), 712 univ.Integer.tagSet: IntegerEncoder(), 713 univ.BitString.tagSet: BitStringEncoder(), 714 univ.OctetString.tagSet: OctetStringEncoder(), 715 univ.Null.tagSet: NullEncoder(), 716 univ.ObjectIdentifier.tagSet: ObjectIdentifierEncoder(), 717 univ.Enumerated.tagSet: IntegerEncoder(), 718 univ.Real.tagSet: RealEncoder(), 719 # Sequence & Set have same tags as SequenceOf & SetOf 720 univ.SequenceOf.tagSet: SequenceOfEncoder(), 721 univ.SetOf.tagSet: SequenceOfEncoder(), 722 univ.Choice.tagSet: ChoiceEncoder(), 723 # character string types 724 char.UTF8String.tagSet: OctetStringEncoder(), 725 char.NumericString.tagSet: OctetStringEncoder(), 726 char.PrintableString.tagSet: OctetStringEncoder(), 727 char.TeletexString.tagSet: OctetStringEncoder(), 728 char.VideotexString.tagSet: OctetStringEncoder(), 729 char.IA5String.tagSet: OctetStringEncoder(), 730 char.GraphicString.tagSet: OctetStringEncoder(), 731 char.VisibleString.tagSet: OctetStringEncoder(), 732 char.GeneralString.tagSet: OctetStringEncoder(), 733 char.UniversalString.tagSet: OctetStringEncoder(), 734 char.BMPString.tagSet: OctetStringEncoder(), 735 # useful types 736 useful.ObjectDescriptor.tagSet: OctetStringEncoder(), 737 useful.GeneralizedTime.tagSet: OctetStringEncoder(), 738 useful.UTCTime.tagSet: OctetStringEncoder() 739} 740 741# Put in ambiguous & non-ambiguous types for faster codec lookup 742typeMap = { 743 univ.Boolean.typeId: BooleanEncoder(), 744 univ.Integer.typeId: IntegerEncoder(), 745 univ.BitString.typeId: BitStringEncoder(), 746 univ.OctetString.typeId: OctetStringEncoder(), 747 univ.Null.typeId: NullEncoder(), 748 univ.ObjectIdentifier.typeId: ObjectIdentifierEncoder(), 749 univ.Enumerated.typeId: IntegerEncoder(), 750 univ.Real.typeId: RealEncoder(), 751 # Sequence & Set have same tags as SequenceOf & SetOf 752 univ.Set.typeId: SequenceEncoder(), 753 univ.SetOf.typeId: SequenceOfEncoder(), 754 univ.Sequence.typeId: SequenceEncoder(), 755 univ.SequenceOf.typeId: SequenceOfEncoder(), 756 univ.Choice.typeId: ChoiceEncoder(), 757 univ.Any.typeId: AnyEncoder(), 758 # character string types 759 char.UTF8String.typeId: OctetStringEncoder(), 760 char.NumericString.typeId: OctetStringEncoder(), 761 char.PrintableString.typeId: OctetStringEncoder(), 762 char.TeletexString.typeId: OctetStringEncoder(), 763 char.VideotexString.typeId: OctetStringEncoder(), 764 char.IA5String.typeId: OctetStringEncoder(), 765 char.GraphicString.typeId: OctetStringEncoder(), 766 char.VisibleString.typeId: OctetStringEncoder(), 767 char.GeneralString.typeId: OctetStringEncoder(), 768 char.UniversalString.typeId: OctetStringEncoder(), 769 char.BMPString.typeId: OctetStringEncoder(), 770 # useful types 771 useful.ObjectDescriptor.typeId: OctetStringEncoder(), 772 useful.GeneralizedTime.typeId: OctetStringEncoder(), 773 useful.UTCTime.typeId: OctetStringEncoder() 774} 775 776 777class Encoder(object): 778 fixedDefLengthMode = None 779 fixedChunkSize = None 780 781 # noinspection PyDefaultArgument 782 def __init__(self, tagMap, typeMap={}): 783 self.__tagMap = tagMap 784 self.__typeMap = typeMap 785 786 def __call__(self, value, asn1Spec=None, **options): 787 try: 788 if asn1Spec is None: 789 typeId = value.typeId 790 else: 791 typeId = asn1Spec.typeId 792 793 except AttributeError: 794 raise error.PyAsn1Error('Value %r is not ASN.1 type instance ' 795 'and "asn1Spec" not given' % (value,)) 796 797 if LOG: 798 LOG('encoder called in %sdef mode, chunk size %s for ' 799 'type %s, value:\n%s' % (not options.get('defMode', True) and 'in' or '', options.get('maxChunkSize', 0), asn1Spec is None and value.prettyPrintType() or asn1Spec.prettyPrintType(), value)) 800 801 if self.fixedDefLengthMode is not None: 802 options.update(defMode=self.fixedDefLengthMode) 803 804 if self.fixedChunkSize is not None: 805 options.update(maxChunkSize=self.fixedChunkSize) 806 807 808 try: 809 concreteEncoder = self.__typeMap[typeId] 810 811 if LOG: 812 LOG('using value codec %s chosen by type ID %s' % (concreteEncoder.__class__.__name__, typeId)) 813 814 except KeyError: 815 if asn1Spec is None: 816 tagSet = value.tagSet 817 else: 818 tagSet = asn1Spec.tagSet 819 820 # use base type for codec lookup to recover untagged types 821 baseTagSet = tag.TagSet(tagSet.baseTag, tagSet.baseTag) 822 823 try: 824 concreteEncoder = self.__tagMap[baseTagSet] 825 826 except KeyError: 827 raise error.PyAsn1Error('No encoder for %r (%s)' % (value, tagSet)) 828 829 if LOG: 830 LOG('using value codec %s chosen by tagSet %s' % (concreteEncoder.__class__.__name__, tagSet)) 831 832 substrate = concreteEncoder.encode(value, asn1Spec, self, **options) 833 834 if LOG: 835 LOG('codec %s built %s octets of substrate: %s\nencoder completed' % (concreteEncoder, len(substrate), debug.hexdump(substrate))) 836 837 return substrate 838 839#: Turns ASN.1 object into BER octet stream. 840#: 841#: Takes any ASN.1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) 842#: walks all its components recursively and produces a BER octet stream. 843#: 844#: Parameters 845#: ---------- 846#: value: either a Python or pyasn1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) 847#: A Python or pyasn1 object to encode. If Python object is given, `asnSpec` 848#: parameter is required to guide the encoding process. 849#: 850#: Keyword Args 851#: ------------ 852#: asn1Spec: 853#: Optional ASN.1 schema or value object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative 854#: 855#: defMode: :py:class:`bool` 856#: If :obj:`False`, produces indefinite length encoding 857#: 858#: maxChunkSize: :py:class:`int` 859#: Maximum chunk size in chunked encoding mode (0 denotes unlimited chunk size) 860#: 861#: Returns 862#: ------- 863#: : :py:class:`bytes` (Python 3) or :py:class:`str` (Python 2) 864#: Given ASN.1 object encoded into BER octetstream 865#: 866#: Raises 867#: ------ 868#: ~pyasn1.error.PyAsn1Error 869#: On encoding errors 870#: 871#: Examples 872#: -------- 873#: Encode Python value into BER with ASN.1 schema 874#: 875#: .. code-block:: pycon 876#: 877#: >>> seq = SequenceOf(componentType=Integer()) 878#: >>> encode([1, 2, 3], asn1Spec=seq) 879#: b'0\t\x02\x01\x01\x02\x01\x02\x02\x01\x03' 880#: 881#: Encode ASN.1 value object into BER 882#: 883#: .. code-block:: pycon 884#: 885#: >>> seq = SequenceOf(componentType=Integer()) 886#: >>> seq.extend([1, 2, 3]) 887#: >>> encode(seq) 888#: b'0\t\x02\x01\x01\x02\x01\x02\x02\x01\x03' 889#: 890encode = Encoder(tagMap, typeMap) 891