summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIlya Etingof <etingof@gmail.com>2017-09-13 15:55:06 +0200
committerIlya Etingof <etingof@gmail.com>2017-09-13 15:55:06 +0200
commit1183c6c9724de537971903a66b537144fe39111f (patch)
tree1866c4836169b604b2f95fce58b0606958641f02
parent5359bf1df4e64c1f2f19bff69670ed2f213d8c21 (diff)
downloadpyasn1-git-1183c6c9724de537971903a66b537144fe39111f.tar.gz
ASN.1 codecs to silently enforce proper length/chunk modes
-rw-r--r--CHANGES.rst3
-rw-r--r--pyasn1/codec/ber/encoder.py11
-rw-r--r--pyasn1/codec/cer/encoder.py25
-rw-r--r--pyasn1/codec/der/encoder.py24
-rw-r--r--tests/codec/der/test_encoder.py23
5 files changed, 26 insertions, 60 deletions
diff --git a/CHANGES.rst b/CHANGES.rst
index b1bfea4..7d7ff33 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -5,6 +5,9 @@ Revision 0.3.5, released XX-09-2017
- Codecs signatures unified and pass **options through the call chain
- Explicit tag encoding optimized to avoid unnecessary copying
- End-of-octets sentinel encoding optimized
+- Refactored ASN.1 codecs properties to silently enforce proper length and
+ chunk size encoding modes
+- Fixed DER encoder to always produce primitive encoding
Revision 0.3.4, released 07-09-2017
-----------------------------------
diff --git a/pyasn1/codec/ber/encoder.py b/pyasn1/codec/ber/encoder.py
index dee13e5..b43e209 100644
--- a/pyasn1/codec/ber/encoder.py
+++ b/pyasn1/codec/ber/encoder.py
@@ -460,7 +460,8 @@ typeMap = {
class Encoder(object):
- supportIndefLength = True
+ fixedDefLengthMode = None
+ fixedChunkSize = None
# noinspection PyDefaultArgument
def __init__(self, tagMap, typeMap={}):
@@ -468,8 +469,6 @@ class Encoder(object):
self.__typeMap = typeMap
def __call__(self, value, **options):
- if not options.get('defMode', True) and not self.supportIndefLength:
- raise error.PyAsn1Error('Indefinite length encoding not supported by this codec')
if debug.logger & debug.flagEncoder:
logger = debug.logger
@@ -479,6 +478,12 @@ class Encoder(object):
if logger:
logger('encoder called in %sdef mode, chunk size %s for type %s, value:\n%s' % (not defMode and 'in' or '', maxChunkSize, value.prettyPrintType(), value.prettyPrint()))
+ if self.fixedDefLengthMode is not None:
+ options.update(defMode=self.fixedDefLengthMode)
+
+ if self.fixedChunkSize is not None:
+ options.update(maxChunkSize=self.fixedChunkSize)
+
tagSet = value.tagSet
try:
diff --git a/pyasn1/codec/cer/encoder.py b/pyasn1/codec/cer/encoder.py
index 50cb346..dd3e2b4 100644
--- a/pyasn1/codec/cer/encoder.py
+++ b/pyasn1/codec/cer/encoder.py
@@ -22,22 +22,6 @@ class BooleanEncoder(encoder.IntegerEncoder):
return substrate, False, False
-class BitStringEncoder(encoder.BitStringEncoder):
- def encodeValue(self, value, encodeFun, **options):
- options.update(maxChunkSize=1000)
- return encoder.BitStringEncoder.encodeValue(
- self, value, encodeFun, **options
- )
-
-
-class OctetStringEncoder(encoder.OctetStringEncoder):
- def encodeValue(self, value, encodeFun, **options):
- options.update(maxChunkSize=1000)
- return encoder.OctetStringEncoder.encodeValue(
- self, value, encodeFun, **options
- )
-
-
class RealEncoder(encoder.RealEncoder):
def _chooseEncBase(self, value):
m, b, e = value
@@ -83,7 +67,7 @@ class TimeEncoderMixIn(object):
)
-class GeneralizedTimeEncoder(TimeEncoderMixIn, OctetStringEncoder):
+class GeneralizedTimeEncoder(TimeEncoderMixIn, encoder.OctetStringEncoder):
minLength = 12
maxLength = 19
@@ -181,8 +165,6 @@ class SequenceOfEncoder(encoder.SequenceOfEncoder):
tagMap = encoder.tagMap.copy()
tagMap.update({
univ.Boolean.tagSet: BooleanEncoder(),
- univ.BitString.tagSet: BitStringEncoder(),
- univ.OctetString.tagSet: OctetStringEncoder(),
univ.Real.tagSet: RealEncoder(),
useful.GeneralizedTime.tagSet: GeneralizedTimeEncoder(),
useful.UTCTime.tagSet: UTCTimeEncoder(),
@@ -194,8 +176,6 @@ tagMap.update({
typeMap = encoder.typeMap.copy()
typeMap.update({
univ.Boolean.typeId: BooleanEncoder(),
- univ.BitString.typeId: BitStringEncoder(),
- univ.OctetString.typeId: OctetStringEncoder(),
univ.Real.typeId: RealEncoder(),
useful.GeneralizedTime.typeId: GeneralizedTimeEncoder(),
useful.UTCTime.typeId: UTCTimeEncoder(),
@@ -208,7 +188,8 @@ typeMap.update({
class Encoder(encoder.Encoder):
- supportIndefLength = True
+ fixedDefLengthMode = False
+ fixedChunkSize = 1000
def __call__(self, value, **options):
if 'defMode' not in options:
diff --git a/pyasn1/codec/der/encoder.py b/pyasn1/codec/der/encoder.py
index 59dd512..d2992a9 100644
--- a/pyasn1/codec/der/encoder.py
+++ b/pyasn1/codec/der/encoder.py
@@ -10,18 +10,6 @@ from pyasn1.codec.cer import encoder
__all__ = ['encode']
-class BitStringEncoder(encoder.BitStringEncoder):
- def encodeValue(self, value, encodeFun, **options):
- return encoder.BitStringEncoder.encodeValue(
- self, value, encodeFun, **options
- )
-
-class OctetStringEncoder(encoder.OctetStringEncoder):
- def encodeValue(self, value, encodeFun, **options):
- return encoder.OctetStringEncoder.encodeValue(
- self, value, encodeFun, **options
- )
-
class SetOfEncoder(encoder.SetOfEncoder):
@staticmethod
def _sortComponents(components):
@@ -30,16 +18,12 @@ class SetOfEncoder(encoder.SetOfEncoder):
tagMap = encoder.tagMap.copy()
tagMap.update({
- univ.BitString.tagSet: BitStringEncoder(),
- univ.OctetString.tagSet: OctetStringEncoder(),
# Set & SetOf have same tags
univ.SetOf.tagSet: SetOfEncoder()
})
typeMap = encoder.typeMap.copy()
typeMap.update({
- univ.BitString.typeId: BitStringEncoder(),
- univ.OctetString.typeId: OctetStringEncoder(),
# Set & SetOf have same tags
univ.Set.typeId: SetOfEncoder(),
univ.SetOf.typeId: SetOfEncoder()
@@ -47,12 +31,8 @@ typeMap.update({
class Encoder(encoder.Encoder):
- supportIndefLength = False
-
- def __call__(self, value, **options):
- if 'defMode' not in options:
- options.update(defMode=True)
- return encoder.Encoder.__call__(self, value, **options)
+ fixedDefLengthMode = True
+ fixedChunkSize = 0
#: Turns ASN.1 object into DER octet stream.
#:
diff --git a/tests/codec/der/test_encoder.py b/tests/codec/der/test_encoder.py
index d30dfc1..354781a 100644
--- a/tests/codec/der/test_encoder.py
+++ b/tests/codec/der/test_encoder.py
@@ -17,31 +17,28 @@ from pyasn1.error import PyAsn1Error
class OctetStringEncoderTestCase(unittest.TestCase):
- def testShortMode(self):
+ def testDefModeShort(self):
assert encoder.encode(
univ.OctetString('Quick brown fox')
) == ints2octs((4, 15, 81, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 32, 102, 111, 120))
- def testIndefMode(self):
- try:
- encoder.encode(univ.OctetString('Quick brown'), defMode=False)
- except PyAsn1Error:
- pass
- else:
- assert 0, 'Indefinite length encoding tolerated'
-
- def testChunkedMode(self):
+ def testDefModeLong(self):
assert encoder.encode(
- univ.OctetString('Quick brown'), maxChunkSize=2
- ) == ints2octs((4, 11, 81, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110))
+ univ.OctetString('Q' * 10000)
+ ) == ints2octs((4, 130, 39, 16) + (81,) * 10000)
class BitStringEncoderTestCase(unittest.TestCase):
- def testShortMode(self):
+ def testDefModeShort(self):
assert encoder.encode(
univ.BitString((1,))
) == ints2octs((3, 2, 7, 128))
+ def testDefModeLong(self):
+ assert encoder.encode(
+ univ.BitString((1,) * 80000)
+ ) == ints2octs((3, 130, 39, 17, 0) + (255,) * 10000)
+
class SetOfEncoderTestCase(unittest.TestCase):
def setUp(self):