You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

encoder.py 27KB

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