diff options
author | Ilya Etingof <etingof@gmail.com> | 2019-07-12 22:42:04 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-07-12 22:42:04 +0200 |
commit | 62efcb94b15ca7fbd5261ca999bf5eca5680de5f (patch) | |
tree | 94cd7ed5091c5f1421ba6b186116bbc86303ca23 /pyasn1/codec | |
parent | 7b3f79cac2ce765537baa406762d59eae47de04c (diff) | |
download | pyasn1-62efcb94b15ca7fbd5261ca999bf5eca5680de5f.tar.gz |
Fix CER/DER encoders to respect open types (#167)
* Fix CER/DER encoders to respect open types
Added a bunch of unit tests to CER/DER codecs covering open types.
Diffstat (limited to 'pyasn1/codec')
-rw-r--r-- | pyasn1/codec/ber/encoder.py | 80 | ||||
-rw-r--r-- | pyasn1/codec/cer/encoder.py | 76 |
2 files changed, 72 insertions, 84 deletions
diff --git a/pyasn1/codec/ber/encoder.py b/pyasn1/codec/ber/encoder.py index b17fca8..fbad7e7 100644 --- a/pyasn1/codec/ber/encoder.py +++ b/pyasn1/codec/ber/encoder.py @@ -559,20 +559,20 @@ class SequenceEncoder(AbstractItemEncoder): options.update(ifNotEmpty=namedType.isOptional) # wrap open type blob if needed - if (namedTypes and namedType.openType - and namedType.asn1Object.tagSet): + if namedTypes and namedType.openType: - if component.typeId in ( - univ.SetOf.typeId, univ.SequenceOf.typeId): - substrate += encodeFun( + wrapType = namedType.asn1Object + + if wrapType.typeId in ( + univ.SetOf.typeId, univ.SequenceOf.typeId): + + substrate += encodeFun( component, asn1Spec, - **dict(options, openType=True)) + **dict(options, wrapType=wrapType.componentType)) else: chunk = encodeFun(component, asn1Spec, **options) - wrapType = namedType.asn1Object - if wrapType.isSameTypeWith(component): substrate += chunk @@ -609,67 +609,69 @@ class SequenceEncoder(AbstractItemEncoder): if omitEmptyOptionals: options.update(ifNotEmpty=namedType.isOptional) + componentSpec = namedType.asn1Object + # wrap open type blob if needed - if namedType.openType and namedType.asn1Object.tagSet: + if namedType.openType: - if component.typeId in ( - univ.SetOf.typeId, univ.SequenceOf.typeId): - substrate += encodeFun( - component, asn1Spec[idx], - **dict(options, openType=True)) + if componentSpec.typeId in ( + univ.SetOf.typeId, univ.SequenceOf.typeId): - else: - chunk = encodeFun(component, asn1Spec[idx], **options) + substrate += encodeFun( + component, componentSpec, + **dict(options, wrapType=componentSpec.componentType)) - wrapType = namedType.asn1Object + else: + chunk = encodeFun(component, componentSpec, **options) - if wrapType.isSameTypeWith(component): + if componentSpec.isSameTypeWith(component): substrate += chunk else: - substrate += encodeFun(chunk, wrapType, **options) + substrate += encodeFun(chunk, componentSpec, **options) if LOG: - LOG('wrapped with wrap type %r' % (wrapType,)) + LOG('wrapped with wrap type %r' % (componentSpec,)) else: - substrate += encodeFun(component, asn1Spec[idx], **options) + substrate += encodeFun(component, componentSpec, **options) return substrate, True, True class SequenceOfEncoder(AbstractItemEncoder): - def encodeValue(self, value, asn1Spec, encodeFun, **options): + def _encodeComponents(self, value, asn1Spec, encodeFun, **options): + if asn1Spec is None: value.verifySizeSpec() - wrapType = value.componentType - else: - asn1Spec = wrapType = asn1Spec.componentType + asn1Spec = asn1Spec.componentType - openType = options.pop('openType', False) + chunks = [] - substrate = null + wrapType = options.pop('wrapType', None) for idx, component in enumerate(value): - if openType: - # do not use asn1Spec even if given because it's a wrapper - chunk = encodeFun(component, **options) + chunk = encodeFun(component, asn1Spec, **options) - if not wrapType.isSameTypeWith(component): - # wrap encoded value with wrapper container (e.g. ANY) - chunk = encodeFun(chunk, wrapType, **options) + if (wrapType is not None and + not wrapType.isSameTypeWith(component)): + # wrap encoded value with wrapper container (e.g. ANY) + chunk = encodeFun(chunk, wrapType, **options) - if LOG: - LOG('wrapped with wrap type %r' % (wrapType,)) + if LOG: + LOG('wrapped with wrap type %r' % (wrapType,)) - else: - chunk = encodeFun(component, asn1Spec, **options) + chunks.append(chunk) - substrate += chunk + return chunks - return substrate, True, True + def encodeValue(self, value, asn1Spec, encodeFun, **options): + chunks = self._encodeComponents( + value, asn1Spec, encodeFun, **options) + + return null.join(chunks), True, True class ChoiceEncoder(AbstractItemEncoder): diff --git a/pyasn1/codec/cer/encoder.py b/pyasn1/codec/cer/encoder.py index 3fdcc1d..d7a1dfe 100644 --- a/pyasn1/codec/cer/encoder.py +++ b/pyasn1/codec/cer/encoder.py @@ -109,6 +109,37 @@ class UTCTimeEncoder(TimeEncoderMixIn, encoder.OctetStringEncoder): MAX_LENGTH = 14 +class SetOfEncoder(encoder.SequenceOfEncoder): + def encodeValue(self, value, asn1Spec, encodeFun, **options): + chunks = self._encodeComponents( + value, asn1Spec, encodeFun, **options) + + # sort by serialised and padded components + if len(chunks) > 1: + zero = str2octs('\x00') + maxLen = max(map(len, chunks)) + paddedChunks = [ + (x.ljust(maxLen, zero), x) for x in chunks + ] + paddedChunks.sort(key=lambda x: x[0]) + + chunks = [x[1] for x in paddedChunks] + + return null.join(chunks), True, True + + +class SequenceOfEncoder(encoder.SequenceOfEncoder): + def encodeValue(self, value, asn1Spec, encodeFun, **options): + + if options.get('ifNotEmpty', False) and not len(value): + return null, True, True + + chunks = self._encodeComponents( + value, asn1Spec, encodeFun, **options) + + return null.join(chunks), True, True + + class SetEncoder(encoder.SequenceEncoder): @staticmethod def _componentSortKey(componentAndType): @@ -197,55 +228,10 @@ class SetEncoder(encoder.SequenceEncoder): return substrate, True, True -class SetOfEncoder(encoder.SequenceOfEncoder): - def encodeValue(self, value, asn1Spec, encodeFun, **options): - if asn1Spec is None: - value.verifySizeSpec() - else: - asn1Spec = asn1Spec.componentType - - components = [encodeFun(x, asn1Spec, **options) - for x in value] - - # sort by serialised and padded components - if len(components) > 1: - zero = str2octs('\x00') - maxLen = max(map(len, components)) - paddedComponents = [ - (x.ljust(maxLen, zero), x) for x in components - ] - paddedComponents.sort(key=lambda x: x[0]) - - components = [x[1] for x in paddedComponents] - - substrate = null.join(components) - - return substrate, True, True - - class SequenceEncoder(encoder.SequenceEncoder): omitEmptyOptionals = True -class SequenceOfEncoder(encoder.SequenceOfEncoder): - def encodeValue(self, value, asn1Spec, encodeFun, **options): - - if options.get('ifNotEmpty', False) and not len(value): - return null, True, True - - if asn1Spec is None: - value.verifySizeSpec() - else: - asn1Spec = asn1Spec.componentType - - substrate = null - - for idx, component in enumerate(value): - substrate += encodeFun(value[idx], asn1Spec, **options) - - return substrate, True, True - - tagMap = encoder.tagMap.copy() tagMap.update({ univ.Boolean.tagSet: BooleanEncoder(), |