summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorelie <elie>2015-04-25 22:57:21 +0000
committerelie <elie>2015-04-25 22:57:21 +0000
commited29b5a505ec315c7446e732aec36394b104424d (patch)
tree8cc588f7346c3dbc9b8893b80f802b0eaa6c4fed
parentf2f35576877b143bfd870f4600359ee21c7d81a8 (diff)
downloadpyasn1-ed29b5a505ec315c7446e732aec36394b104424d.tar.gz
DER codec hardened not to tolerate indefinite length encoding/decoding
-rw-r--r--CHANGES1
-rw-r--r--THANKS4
-rw-r--r--pyasn1/codec/ber/decoder.py5
-rw-r--r--pyasn1/codec/ber/encoder.py5
-rw-r--r--pyasn1/codec/cer/encoder.py10
-rw-r--r--pyasn1/codec/der/decoder.py3
-rw-r--r--pyasn1/codec/der/encoder.py7
-rw-r--r--test/codec/der/test_decoder.py11
-rw-r--r--test/codec/der/test_encoder.py7
9 files changed, 42 insertions, 11 deletions
diff --git a/CHANGES b/CHANGES
index 4b06b4b..5d4e7c5 100644
--- a/CHANGES
+++ b/CHANGES
@@ -58,6 +58,7 @@ Revision 0.1.8rc2
* require strict two-zeros sentinel encoding
* recognize EOO sentinel only when explicitly requested by caller
of the decoder (via allowEoo=True parameter)
+- DER codec hardened not to tolerate indefinite length encoding/decoding.
Revision 0.1.7
--------------
diff --git a/THANKS b/THANKS
index 4de1713..93d1314 100644
--- a/THANKS
+++ b/THANKS
@@ -2,3 +2,7 @@ Denis S. Otkidach
Gregory Golberg
Bud P. Bruegger
Jacek Konieczny
+Tanya Tereschenko
+Matěj Cepl
+Alex Gaynor
+Geoffrey Thomas
diff --git a/pyasn1/codec/ber/decoder.py b/pyasn1/codec/ber/decoder.py
index 6794f5e..61bfbce 100644
--- a/pyasn1/codec/ber/decoder.py
+++ b/pyasn1/codec/ber/decoder.py
@@ -598,6 +598,7 @@ class Decoder:
defaultErrorState = stErrorCondition
# defaultErrorState = stDumpRawValue
defaultRawDecoder = AnyDecoder()
+ supportIndefLength = True
def __init__(self, tagMap, typeMap={}):
self.__tagMap = tagMap
self.__typeMap = typeMap
@@ -630,7 +631,7 @@ class Decoder:
# Look for end-of-octets sentinel
if t == 0:
if substrate and oct2int(substrate[0]) == 0:
- if allowEoo:
+ if allowEoo and self.supportIndefLength:
debug.logger and debug.logger & debug.flagDecoder and debug.logger('end-of-octets sentinel found')
value, substrate = eoo.endOfOctets, substrate[1:]
state = stStop
@@ -704,6 +705,8 @@ class Decoder:
raise error.SubstrateUnderrunError(
'%d-octet short' % (length - len(substrate))
)
+ if length == -1 and not self.supportIndefLength:
+ error.PyAsn1Error('Indefinite length encoding not supported by this codec')
state = stGetValueDecoder
debug.logger and debug.logger & debug.flagDecoder and debug.logger('value length decoded into %d, payload substrate is: %s' % (length, debug.hexdump(length == -1 and substrate or substrate[:length])))
if state == stGetValueDecoder:
diff --git a/pyasn1/codec/ber/encoder.py b/pyasn1/codec/ber/encoder.py
index 7f204c8..0fb4ae7 100644
--- a/pyasn1/codec/ber/encoder.py
+++ b/pyasn1/codec/ber/encoder.py
@@ -400,11 +400,14 @@ typeMap = {
}
class Encoder:
+ supportIndefLength = True
def __init__(self, tagMap, typeMap={}):
self.__tagMap = tagMap
self.__typeMap = typeMap
- def __call__(self, value, defMode=1, maxChunkSize=0):
+ def __call__(self, value, defMode=True, maxChunkSize=0):
+ if not defMode and not self.supportIndefLength:
+ raise error.PyAsn1Error('Indefinite length encoding not supported by this codec')
debug.logger & debug.flagEncoder and debug.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()))
tagSet = value.getTagSet()
if len(tagSet) > 1:
diff --git a/pyasn1/codec/cer/encoder.py b/pyasn1/codec/cer/encoder.py
index d834931..b432b96 100644
--- a/pyasn1/codec/cer/encoder.py
+++ b/pyasn1/codec/cer/encoder.py
@@ -15,13 +15,13 @@ class BitStringEncoder(encoder.BitStringEncoder):
def encodeValue(self, encodeFun, client, defMode, maxChunkSize):
return encoder.BitStringEncoder.encodeValue(
self, encodeFun, client, defMode, 1000
- )
+ )
class OctetStringEncoder(encoder.OctetStringEncoder):
def encodeValue(self, encodeFun, client, defMode, maxChunkSize):
return encoder.OctetStringEncoder.encodeValue(
self, encodeFun, client, defMode, 1000
- )
+ )
class RealEncoder(encoder.RealEncoder):
def _chooseEncBase(self, value):
@@ -75,16 +75,16 @@ tagMap.update({
univ.OctetString.tagSet: OctetStringEncoder(),
univ.Real.tagSet: RealEncoder(),
univ.SetOf().tagSet: SetOfEncoder() # conflcts with Set
- })
+})
typeMap = encoder.typeMap.copy()
typeMap.update({
univ.Set.typeId: SetOfEncoder(),
univ.SetOf.typeId: SetOfEncoder()
- })
+})
class Encoder(encoder.Encoder):
- def __call__(self, client, defMode=0, maxChunkSize=0):
+ def __call__(self, client, defMode=False, maxChunkSize=0):
return encoder.Encoder.__call__(self, client, defMode, maxChunkSize)
encode = Encoder(tagMap, typeMap)
diff --git a/pyasn1/codec/der/decoder.py b/pyasn1/codec/der/decoder.py
index 1ecdf5c..ea58d6d 100644
--- a/pyasn1/codec/der/decoder.py
+++ b/pyasn1/codec/der/decoder.py
@@ -3,6 +3,7 @@ from pyasn1.codec.cer import decoder
tagMap = decoder.tagMap
typeMap = decoder.typeMap
-Decoder = decoder.Decoder
+class Decoder(decoder.Decoder):
+ supportIndefLength = False
decode = Decoder(tagMap, typeMap)
diff --git a/pyasn1/codec/der/encoder.py b/pyasn1/codec/der/encoder.py
index 4e5faef..0219ae7 100644
--- a/pyasn1/codec/der/encoder.py
+++ b/pyasn1/codec/der/encoder.py
@@ -17,12 +17,13 @@ tagMap.update({
univ.OctetString.tagSet: encoder.encoder.OctetStringEncoder(),
# Set & SetOf have same tags
univ.SetOf().tagSet: SetOfEncoder()
- })
+})
typeMap = encoder.typeMap
class Encoder(encoder.Encoder):
- def __call__(self, client, defMode=1, maxChunkSize=0):
+ supportIndefLength = False
+ def __call__(self, client, defMode=True, maxChunkSize=0):
return encoder.Encoder.__call__(self, client, defMode, maxChunkSize)
-
+
encode = Encoder(tagMap, typeMap)
diff --git a/test/codec/der/test_decoder.py b/test/codec/der/test_decoder.py
index 5c9a194..a0b7b8a 100644
--- a/test/codec/der/test_decoder.py
+++ b/test/codec/der/test_decoder.py
@@ -1,5 +1,6 @@
from pyasn1.type import univ
from pyasn1.codec.der import decoder
+from pyasn1.compat.octets import ints2octs
from pyasn1.error import PyAsn1Error
from sys import version_info
if version_info[0:2] < (2, 7) or \
@@ -17,4 +18,14 @@ class OctetStringDecoderTestCase(unittest.TestCase):
'\004\017Quick brown fox'.encode()
) == ('Quick brown fox'.encode(), ''.encode())
+ def testIndefMode(self):
+ try:
+ decoder.decode(
+ ints2octs((36, 128, 4, 15, 81, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 32, 102, 111, 120, 0, 0))
+ )
+ except PyAsn1Error:
+ pass
+ else:
+ assert 1, 'indefinite length encoding tolerated'
+
if __name__ == '__main__': unittest.main()
diff --git a/test/codec/der/test_encoder.py b/test/codec/der/test_encoder.py
index 787da7b..0044536 100644
--- a/test/codec/der/test_encoder.py
+++ b/test/codec/der/test_encoder.py
@@ -17,6 +17,13 @@ class OctetStringEncoderTestCase(unittest.TestCase):
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:
+ assert encoder.encode(univ.OctetString('Quick brown'), defMode=0)
+ except PyAsn1Error:
+ pass
+ else:
+ assert 1, 'Indefinite length encoding tolerated'
class BitStringEncoderTestCase(unittest.TestCase):
def testShortMode(self):