summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorelie <elie>2015-04-26 12:17:48 +0000
committerelie <elie>2015-04-26 12:17:48 +0000
commit27da95be36046410dbd9138ff893792bb7e02417 (patch)
tree92a1ae94ce4cbd52c940b0b652b9b8f3adcbc082
parent11f85e7eca4d9b7f7aa1f566c954b0f6397e3aaf (diff)
downloadpyasn1-27da95be36046410dbd9138ff893792bb7e02417.tar.gz
more strict CER/DER encoders added for GeneralizedTime and UTCTime types
-rw-r--r--CHANGES3
-rw-r--r--pyasn1/codec/cer/encoder.py44
-rw-r--r--pyasn1/codec/der/encoder.py2
-rw-r--r--test/codec/cer/test_encoder.py69
4 files changed, 112 insertions, 6 deletions
diff --git a/CHANGES b/CHANGES
index 7fbe937..c6ecfc6 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,4 @@
-Revision 0.1.8rc2
+Revision 0.1.8rc3
-----------------
- ObjectIdentifier codec fixed to work properly with arc 0 and arc 2 values.
@@ -49,6 +49,7 @@ Revision 0.1.8rc2
- String typed float initializer to REAL type now supported.
- Float typed mantissa initializer to REAL type for base 2 added.
- Encoding bases 8 and 16 support for REAL type binary encoder added.
+- More strict CER/DER encoders added for GeneralizedTime and UTCTime types.
- Fix to REAL type binary decoder to handle different bases and scale factor.
- Fix to TagSet.repr() to include [obsolete] baseTag information.
- Fix to broken REAL type decoding handling.
diff --git a/pyasn1/codec/cer/encoder.py b/pyasn1/codec/cer/encoder.py
index b432b96..dad5955 100644
--- a/pyasn1/codec/cer/encoder.py
+++ b/pyasn1/codec/cer/encoder.py
@@ -1,7 +1,9 @@
# CER encoder
from pyasn1.type import univ
+from pyasn1.type import useful
from pyasn1.codec.ber import encoder
-from pyasn1.compat.octets import int2oct, null
+from pyasn1.compat.octets import int2oct, str2octs, null
+from pyasn1 import error
class BooleanEncoder(encoder.IntegerEncoder):
def encodeValue(self, encodeFun, client, defMode, maxChunkSize):
@@ -29,8 +31,42 @@ class RealEncoder(encoder.RealEncoder):
return self._dropFloatingPoint(m, b, e)
# specialized GeneralStringEncoder here
-# specialized GeneralizedTimeEncoder here
-# specialized UTCTimeEncoder here
+
+class GeneralizedTimeEncoder(OctetStringEncoder):
+ zchar = str2octs('Z')
+ zero = str2octs('0')
+ def encodeValue(self, encodeFun, client, defMode, maxChunkSize):
+ octets = client.asOctets()
+ if '+' in octets:
+ raise error.PyAsn1Error('Must be UTC time')
+ if '.' not in octets:
+ raise error.PyAsn1Error('Format must include fraction of second')
+ if octets and octets[-1] != self.zchar:
+ raise error.PyAsn1Error('Missing timezone specifier')
+ if len(octets) < 16:
+ raise error.PyAsn1Error('Bad UTC time length')
+ if octets[-2] == self.zero or \
+ octets[-3] != self.zero and octets[-2] == self.zero:
+ raise error.PyAsn1Error('Meningless zero in fraction of second')
+ return encoder.OctetStringEncoder.encodeValue(
+ self, encodeFun, client, defMode, 1000
+ )
+
+class UTCTimeEncoder(encoder.OctetStringEncoder):
+ zchar = str2octs('Z')
+ def encodeValue(self, encodeFun, client, defMode, maxChunkSize):
+ octets = client.asOctets()
+ if '+' in octets:
+ raise error.PyAsn1Error('Must be UTC time')
+ if '.' in octets:
+ raise error.PyAsn1Error('Must be no fraction of second')
+ if octets and octets[-1] != self.zchar:
+ client = client.clone(octets + self.zchar)
+ if len(client) != 13:
+ raise error.PyAsn1Error('Bad UTC time length')
+ return encoder.OctetStringEncoder.encodeValue(
+ self, encodeFun, client, defMode, 1000
+ )
class SetOfEncoder(encoder.SequenceOfEncoder):
def encodeValue(self, encodeFun, client, defMode, maxChunkSize):
@@ -74,6 +110,8 @@ tagMap.update({
univ.BitString.tagSet: BitStringEncoder(),
univ.OctetString.tagSet: OctetStringEncoder(),
univ.Real.tagSet: RealEncoder(),
+ useful.GeneralizedTime.tagSet: GeneralizedTimeEncoder(),
+ useful.UTCTime.tagSet: UTCTimeEncoder(),
univ.SetOf().tagSet: SetOfEncoder() # conflcts with Set
})
diff --git a/pyasn1/codec/der/encoder.py b/pyasn1/codec/der/encoder.py
index 0219ae7..2044df3 100644
--- a/pyasn1/codec/der/encoder.py
+++ b/pyasn1/codec/der/encoder.py
@@ -12,7 +12,7 @@ class SetOfEncoder(encoder.SetOfEncoder):
tagMap = encoder.tagMap.copy()
tagMap.update({
- # Overload CER encodrs with BER ones (a bit hackerish XXX)
+ # Overload CER encoders with BER ones (a bit hackerish XXX)
univ.BitString.tagSet: encoder.encoder.BitStringEncoder(),
univ.OctetString.tagSet: encoder.encoder.OctetStringEncoder(),
# Set & SetOf have same tags
diff --git a/test/codec/cer/test_encoder.py b/test/codec/cer/test_encoder.py
index a4f80aa..5434996 100644
--- a/test/codec/cer/test_encoder.py
+++ b/test/codec/cer/test_encoder.py
@@ -1,4 +1,4 @@
-from pyasn1.type import namedtype, univ
+from pyasn1.type import namedtype, univ, useful
from pyasn1.codec.cer import encoder
from pyasn1.compat.octets import ints2octs
from pyasn1.error import PyAsn1Error
@@ -104,4 +104,71 @@ class SetWithChoiceEncoderTestCase(unittest.TestCase):
self.s.getComponentByName('status').setComponentByPosition(0, 1)
assert encoder.encode(self.s) == ints2octs((49, 128, 1, 1, 255, 5, 0, 0, 0))
+class GeneralizedTimeEncoderTestCase(unittest.TestCase):
+ def testExtraZeroInSeconds(self):
+ try:
+ assert encoder.encode(
+ useful.GeneralizedTime('20150501120112.10Z')
+ )
+ except PyAsn1Error:
+ pass
+ else:
+ assert 0, 'Meaningless trailing zero in fraction part tolerated'
+
+ def testLocalTimezone(self):
+ try:
+ assert encoder.encode(
+ useful.GeneralizedTime('20150501120112.1+0200')
+ )
+ except PyAsn1Error:
+ pass
+ else:
+ assert 0, 'Local timezone tolerated'
+
+ def testMissingTimezone(self):
+ try:
+ assert encoder.encode(
+ useful.GeneralizedTime('20150501120112.1')
+ )
+ except PyAsn1Error:
+ pass
+ else:
+ assert 0, 'Missing timezone tolerated'
+
+ def testDecimalPoint(self):
+ try:
+ assert encoder.encode(
+ useful.GeneralizedTime('20150501120112Z')
+ )
+ except PyAsn1Error:
+ pass
+ else:
+ assert 0, 'Missing decimal point tolerated'
+
+class UTCTimeEncoderTestCase(unittest.TestCase):
+ def testFractionOfSecond(self):
+ try:
+ assert encoder.encode(
+ useful.UTCTime('150501120112.10Z')
+ )
+ except PyAsn1Error:
+ pass
+ else:
+ assert 0, 'Decimal point tolerated'
+
+ def testMissingTimezone(self):
+ assert encoder.encode(
+ useful.UTCTime('150501120112')
+ ) == ints2octs((23, 13, 49, 53, 48, 53, 48, 49, 49, 50, 48, 49, 49, 50, 90)), 'Missing timezone not added'
+
+ def testLocalTimezone(self):
+ try:
+ assert encoder.encode(
+ useful.UTCTime('150501120112+0200')
+ )
+ except PyAsn1Error:
+ pass
+ else:
+ assert 0, 'Local timezone tolerated'
+
if __name__ == '__main__': unittest.main()