pyasn1 0.4.3, pyasn1_modules 0.2.2

This commit is contained in:
Jay Lee
2018-07-04 20:14:52 -04:00
parent 19018e4854
commit 044686b564
57 changed files with 3047 additions and 1612 deletions

View File

@ -1,7 +1,7 @@
import sys import sys
# http://www.python.org/dev/peps/pep-0396/ # https://www.python.org/dev/peps/pep-0396/
__version__ = '0.3.7' __version__ = '0.4.3'
if sys.version_info[:2] < (2, 4): if sys.version_info[:2] < (2, 4):
raise RuntimeError('PyASN1 requires Python 2.4 or later') raise RuntimeError('PyASN1 requires Python 2.4 or later')

View File

@ -1,14 +1,20 @@
# #
# This file is part of pyasn1 software. # This file is part of pyasn1 software.
# #
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com> # Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
# License: http://pyasn1.sf.net/license.html # License: http://snmplabs.com/pyasn1/license.html
# #
from pyasn1.type import base, tag, univ, char, useful, tagmap from pyasn1 import debug
from pyasn1 import error
from pyasn1.codec.ber import eoo from pyasn1.codec.ber import eoo
from pyasn1.compat.octets import oct2int, octs2ints, ints2octs, null
from pyasn1.compat.integer import from_bytes from pyasn1.compat.integer import from_bytes
from pyasn1 import debug, error from pyasn1.compat.octets import oct2int, octs2ints, ints2octs, null
from pyasn1.type import base
from pyasn1.type import char
from pyasn1.type import tag
from pyasn1.type import tagmap
from pyasn1.type import univ
from pyasn1.type import useful
__all__ = ['decode'] __all__ = ['decode']
@ -36,8 +42,10 @@ class AbstractSimpleDecoder(AbstractDecoder):
def substrateCollector(asn1Object, substrate, length): def substrateCollector(asn1Object, substrate, length):
return substrate[:length], substrate[length:] return substrate[:length], substrate[length:]
def _createComponent(self, asn1Spec, tagSet, value=noValue): def _createComponent(self, asn1Spec, tagSet, value, **options):
if asn1Spec is None: if options.get('native'):
return value
elif asn1Spec is None:
return self.protoComponent.clone(value, tagSet=tagSet) return self.protoComponent.clone(value, tagSet=tagSet)
elif value is noValue: elif value is noValue:
return asn1Spec return asn1Spec
@ -54,7 +62,7 @@ class ExplicitTagDecoder(AbstractSimpleDecoder):
**options): **options):
if substrateFun: if substrateFun:
return substrateFun( return substrateFun(
self._createComponent(asn1Spec, tagSet, ''), self._createComponent(asn1Spec, tagSet, '', **options),
substrate, length substrate, length
) )
@ -70,7 +78,7 @@ class ExplicitTagDecoder(AbstractSimpleDecoder):
**options): **options):
if substrateFun: if substrateFun:
return substrateFun( return substrateFun(
self._createComponent(asn1Spec, tagSet, ''), self._createComponent(asn1Spec, tagSet, '', **options),
substrate, length substrate, length
) )
@ -101,18 +109,18 @@ class IntegerDecoder(AbstractSimpleDecoder):
head, tail = substrate[:length], substrate[length:] head, tail = substrate[:length], substrate[length:]
if not head: if not head:
return self._createComponent(asn1Spec, tagSet, 0), tail return self._createComponent(asn1Spec, tagSet, 0, **options), tail
value = from_bytes(head, signed=True) value = from_bytes(head, signed=True)
return self._createComponent(asn1Spec, tagSet, value), tail return self._createComponent(asn1Spec, tagSet, value, **options), tail
class BooleanDecoder(IntegerDecoder): class BooleanDecoder(IntegerDecoder):
protoComponent = univ.Boolean(0) protoComponent = univ.Boolean(0)
def _createComponent(self, asn1Spec, tagSet, value=noValue): def _createComponent(self, asn1Spec, tagSet, value, **options):
return IntegerDecoder._createComponent(self, asn1Spec, tagSet, value and 1 or 0) return IntegerDecoder._createComponent(self, asn1Spec, tagSet, value and 1 or 0, **options)
class BitStringDecoder(AbstractSimpleDecoder): class BitStringDecoder(AbstractSimpleDecoder):
@ -124,53 +132,86 @@ class BitStringDecoder(AbstractSimpleDecoder):
decodeFun=None, substrateFun=None, decodeFun=None, substrateFun=None,
**options): **options):
head, tail = substrate[:length], substrate[length:] head, tail = substrate[:length], substrate[length:]
if substrateFun:
return substrateFun(self._createComponent(asn1Spec, tagSet, noValue, **options),
substrate, length)
if not head:
raise error.PyAsn1Error('Empty BIT STRING substrate')
if tagSet[0].tagFormat == tag.tagFormatSimple: # XXX what tag to check? if tagSet[0].tagFormat == tag.tagFormatSimple: # XXX what tag to check?
if not head:
raise error.PyAsn1Error('Empty substrate')
trailingBits = oct2int(head[0]) trailingBits = oct2int(head[0])
if trailingBits > 7: if trailingBits > 7:
raise error.PyAsn1Error( raise error.PyAsn1Error(
'Trailing bits overflow %s' % trailingBits 'Trailing bits overflow %s' % trailingBits
) )
head = head[1:]
value = self.protoComponent.fromOctetString(head, trailingBits) value = self.protoComponent.fromOctetString(head[1:], internalFormat=True, padding=trailingBits)
return self._createComponent(asn1Spec, tagSet, value), tail
return self._createComponent(asn1Spec, tagSet, value, **options), tail
if not self.supportConstructedForm: if not self.supportConstructedForm:
raise error.PyAsn1Error('Constructed encoding form prohibited at %s' % self.__class__.__name__) raise error.PyAsn1Error('Constructed encoding form prohibited at %s' % self.__class__.__name__)
bitString = self._createComponent(asn1Spec, tagSet) # All inner fragments are of the same type, treat them as octet string
substrateFun = self.substrateCollector
if substrateFun: bitString = self.protoComponent.fromOctetString(null, internalFormat=True)
return substrateFun(bitString, substrate, length)
while head: while head:
component, head = decodeFun(head, self.protoComponent, **options) component, head = decodeFun(head, self.protoComponent,
bitString += component substrateFun=substrateFun, **options)
return bitString, tail trailingBits = oct2int(component[0])
if trailingBits > 7:
raise error.PyAsn1Error(
'Trailing bits overflow %s' % trailingBits
)
bitString = self.protoComponent.fromOctetString(
component[1:], internalFormat=True,
prepend=bitString, padding=trailingBits
)
return self._createComponent(asn1Spec, tagSet, bitString, **options), tail
def indefLenValueDecoder(self, substrate, asn1Spec, def indefLenValueDecoder(self, substrate, asn1Spec,
tagSet=None, length=None, state=None, tagSet=None, length=None, state=None,
decodeFun=None, substrateFun=None, decodeFun=None, substrateFun=None,
**options): **options):
bitString = self._createComponent(asn1Spec, tagSet)
if substrateFun: if substrateFun:
return substrateFun(bitString, substrate, length) return substrateFun(self._createComponent(asn1Spec, tagSet, noValue, **options), substrate, length)
# All inner fragments are of the same type, treat them as octet string
substrateFun = self.substrateCollector
bitString = self.protoComponent.fromOctetString(null, internalFormat=True)
while substrate: while substrate:
component, substrate = decodeFun(substrate, self.protoComponent, component, substrate = decodeFun(substrate, self.protoComponent,
substrateFun=substrateFun,
allowEoo=True, **options) allowEoo=True, **options)
if component is eoo.endOfOctets: if component is eoo.endOfOctets:
break break
bitString += component trailingBits = oct2int(component[0])
if trailingBits > 7:
raise error.PyAsn1Error(
'Trailing bits overflow %s' % trailingBits
)
bitString = self.protoComponent.fromOctetString(
component[1:], internalFormat=True,
prepend=bitString, padding=trailingBits
)
else: else:
raise error.SubstrateUnderrunError('No EOO seen before substrate ends') raise error.SubstrateUnderrunError('No EOO seen before substrate ends')
return bitString, substrate return self._createComponent(asn1Spec, tagSet, bitString, **options), substrate
class OctetStringDecoder(AbstractSimpleDecoder): class OctetStringDecoder(AbstractSimpleDecoder):
@ -184,11 +225,11 @@ class OctetStringDecoder(AbstractSimpleDecoder):
head, tail = substrate[:length], substrate[length:] head, tail = substrate[:length], substrate[length:]
if substrateFun: if substrateFun:
return substrateFun(self._createComponent(asn1Spec, tagSet), return substrateFun(self._createComponent(asn1Spec, tagSet, noValue, **options),
substrate, length) substrate, length)
if tagSet[0].tagFormat == tag.tagFormatSimple: # XXX what tag to check? if tagSet[0].tagFormat == tag.tagFormatSimple: # XXX what tag to check?
return self._createComponent(asn1Spec, tagSet, head), tail return self._createComponent(asn1Spec, tagSet, head, **options), tail
if not self.supportConstructedForm: if not self.supportConstructedForm:
raise error.PyAsn1Error('Constructed encoding form prohibited at %s' % self.__class__.__name__) raise error.PyAsn1Error('Constructed encoding form prohibited at %s' % self.__class__.__name__)
@ -204,14 +245,14 @@ class OctetStringDecoder(AbstractSimpleDecoder):
**options) **options)
header += component header += component
return self._createComponent(asn1Spec, tagSet, header), tail return self._createComponent(asn1Spec, tagSet, header, **options), tail
def indefLenValueDecoder(self, substrate, asn1Spec, def indefLenValueDecoder(self, substrate, asn1Spec,
tagSet=None, length=None, state=None, tagSet=None, length=None, state=None,
decodeFun=None, substrateFun=None, decodeFun=None, substrateFun=None,
**options): **options):
if substrateFun and substrateFun is not self.substrateCollector: if substrateFun and substrateFun is not self.substrateCollector:
asn1Object = self._createComponent(asn1Spec, tagSet) asn1Object = self._createComponent(asn1Spec, tagSet, noValue, **options)
return substrateFun(asn1Object, substrate, length) return substrateFun(asn1Object, substrate, length)
# All inner fragments are of the same type, treat them as octet string # All inner fragments are of the same type, treat them as octet string
@ -232,7 +273,7 @@ class OctetStringDecoder(AbstractSimpleDecoder):
'No EOO seen before substrate ends' 'No EOO seen before substrate ends'
) )
return self._createComponent(asn1Spec, tagSet, header), substrate return self._createComponent(asn1Spec, tagSet, header, **options), substrate
class NullDecoder(AbstractSimpleDecoder): class NullDecoder(AbstractSimpleDecoder):
@ -248,7 +289,7 @@ class NullDecoder(AbstractSimpleDecoder):
head, tail = substrate[:length], substrate[length:] head, tail = substrate[:length], substrate[length:]
component = self._createComponent(asn1Spec, tagSet) component = self._createComponent(asn1Spec, tagSet, '', **options)
if head: if head:
raise error.PyAsn1Error('Unexpected %d-octet substrate for Null' % length) raise error.PyAsn1Error('Unexpected %d-octet substrate for Null' % length)
@ -296,7 +337,7 @@ class ObjectIdentifierDecoder(AbstractSimpleDecoder):
elif subId == 128: elif subId == 128:
# ASN.1 spec forbids leading zeros (0x80) in OID # ASN.1 spec forbids leading zeros (0x80) in OID
# encoding, tolerating it opens a vulnerability. See # encoding, tolerating it opens a vulnerability. See
# http://www.cosic.esat.kuleuven.be/publications/article-1432.pdf # https://www.esat.kuleuven.be/cosic/publications/article-1432.pdf
# page 7 # page 7
raise error.PyAsn1Error('Invalid octet 0x80 in OID encoding') raise error.PyAsn1Error('Invalid octet 0x80 in OID encoding')
@ -310,7 +351,7 @@ class ObjectIdentifierDecoder(AbstractSimpleDecoder):
else: else:
raise error.PyAsn1Error('Malformed first OID octet: %s' % head[0]) raise error.PyAsn1Error('Malformed first OID octet: %s' % head[0])
return self._createComponent(asn1Spec, tagSet, oid), tail return self._createComponent(asn1Spec, tagSet, oid, **options), tail
class RealDecoder(AbstractSimpleDecoder): class RealDecoder(AbstractSimpleDecoder):
@ -326,7 +367,7 @@ class RealDecoder(AbstractSimpleDecoder):
head, tail = substrate[:length], substrate[length:] head, tail = substrate[:length], substrate[length:]
if not head: if not head:
return self._createComponent(asn1Spec, tagSet, 0.0), tail return self._createComponent(asn1Spec, tagSet, 0.0, **options), tail
fo = oct2int(head[0]) fo = oct2int(head[0])
head = head[1:] head = head[1:]
@ -386,7 +427,7 @@ class RealDecoder(AbstractSimpleDecoder):
raise error.SubstrateUnderrunError( raise error.SubstrateUnderrunError(
'Unknown encoding (tag %s)' % fo 'Unknown encoding (tag %s)' % fo
) )
return self._createComponent(asn1Spec, tagSet, value), tail return self._createComponent(asn1Spec, tagSet, value, **options), tail
class AbstractConstructedDecoder(AbstractDecoder): class AbstractConstructedDecoder(AbstractDecoder):
@ -415,10 +456,9 @@ class UniversalConstructedTypeDecoder(AbstractConstructedDecoder):
# Now we have to guess is it SEQUENCE/SET or SEQUENCE OF/SET OF # Now we have to guess is it SEQUENCE/SET or SEQUENCE OF/SET OF
# The heuristics is: # The heuristics is:
# * 0-1 component -> likely SEQUENCE OF/SET OF # * 1+ components of different types -> likely SEQUENCE/SET
# * 1+ components of the same type -> likely SEQUENCE OF/SET OF # * otherwise -> likely SEQUENCE OF/SET OF
# * otherwise -> likely SEQUENCE/SET if len(componentTypes) > 1:
if len(components) > 1 or len(componentTypes) > 1:
protoComponent = self.protoRecordComponent protoComponent = self.protoRecordComponent
else: else:
protoComponent = self.protoSequenceComponent protoComponent = self.protoSequenceComponent
@ -467,34 +507,34 @@ class UniversalConstructedTypeDecoder(AbstractConstructedDecoder):
asn1Object = asn1Spec.clone() asn1Object = asn1Spec.clone()
if asn1Object.typeId in (univ.Sequence.typeId, univ.Set.typeId): if asn1Spec.typeId in (univ.Sequence.typeId, univ.Set.typeId):
namedTypes = asn1Object.componentType namedTypes = asn1Spec.componentType
isSetType = asn1Object.typeId == univ.Set.typeId isSetType = asn1Spec.typeId == univ.Set.typeId
isDeterministic = not isSetType and not namedTypes.hasOptionalOrDefault isDeterministic = not isSetType and not namedTypes.hasOptionalOrDefault
seenIndices = set() seenIndices = set()
idx = 0 idx = 0
while head: while head:
if not namedTypes: if not namedTypes:
asn1Spec = None componentType = None
elif isSetType: elif isSetType:
asn1Spec = namedTypes.tagMapUnique componentType = namedTypes.tagMapUnique
else: else:
try: try:
if isDeterministic: if isDeterministic:
asn1Spec = namedTypes[idx].asn1Object componentType = namedTypes[idx].asn1Object
elif namedTypes[idx].isOptional or namedTypes[idx].isDefaulted: elif namedTypes[idx].isOptional or namedTypes[idx].isDefaulted:
asn1Spec = namedTypes.getTagMapNearPosition(idx) componentType = namedTypes.getTagMapNearPosition(idx)
else: else:
asn1Spec = namedTypes[idx].asn1Object componentType = namedTypes[idx].asn1Object
except IndexError: except IndexError:
raise error.PyAsn1Error( raise error.PyAsn1Error(
'Excessive components decoded at %r' % (asn1Object,) 'Excessive components decoded at %r' % (asn1Spec,)
) )
component, head = decodeFun(head, asn1Spec, **options) component, head = decodeFun(head, componentType, **options)
if not isDeterministic and namedTypes: if not isDeterministic and namedTypes:
if isSetType: if isSetType:
@ -514,14 +554,54 @@ class UniversalConstructedTypeDecoder(AbstractConstructedDecoder):
if namedTypes: if namedTypes:
if not namedTypes.requiredComponents.issubset(seenIndices): if not namedTypes.requiredComponents.issubset(seenIndices):
raise error.PyAsn1Error('ASN.1 object %s has uninitialized components' % asn1Object.__class__.__name__) raise error.PyAsn1Error('ASN.1 object %s has uninitialized components' % asn1Object.__class__.__name__)
if namedTypes.hasOpenTypes:
openTypes = options.get('openTypes', {})
if openTypes or options.get('decodeOpenTypes', False):
for idx, namedType in enumerate(namedTypes.namedTypes):
if not namedType.openType:
continue
if namedType.isOptional and not asn1Object.getComponentByPosition(idx).isValue:
continue
governingValue = asn1Object.getComponentByName(
namedType.openType.name
)
try:
openType = openTypes[governingValue]
except KeyError:
try:
openType = namedType.openType[governingValue]
except KeyError:
continue
component, rest = decodeFun(
asn1Object.getComponentByPosition(idx).asOctets(),
asn1Spec=openType
)
asn1Object.setComponentByPosition(idx, component)
else: else:
asn1Object.verifySizeSpec() asn1Object.verifySizeSpec()
else: else:
asn1Spec = asn1Object.componentType asn1Object = asn1Spec.clone()
componentType = asn1Spec.componentType
idx = 0 idx = 0
while head: while head:
component, head = decodeFun(head, asn1Spec, **options) component, head = decodeFun(head, componentType, **options)
asn1Object.setComponentByPosition( asn1Object.setComponentByPosition(
idx, component, idx, component,
verifyConstraints=False, verifyConstraints=False,
@ -529,8 +609,6 @@ class UniversalConstructedTypeDecoder(AbstractConstructedDecoder):
) )
idx += 1 idx += 1
asn1Object.verifySizeSpec()
return asn1Object, tail return asn1Object, tail
def indefLenValueDecoder(self, substrate, asn1Spec, def indefLenValueDecoder(self, substrate, asn1Spec,
@ -557,7 +635,7 @@ class UniversalConstructedTypeDecoder(AbstractConstructedDecoder):
asn1Object = asn1Spec.clone() asn1Object = asn1Spec.clone()
if asn1Object.typeId in (univ.Sequence.typeId, univ.Set.typeId): if asn1Spec.typeId in (univ.Sequence.typeId, univ.Set.typeId):
namedTypes = asn1Object.componentType namedTypes = asn1Object.componentType
@ -611,16 +689,59 @@ class UniversalConstructedTypeDecoder(AbstractConstructedDecoder):
if namedTypes: if namedTypes:
if not namedTypes.requiredComponents.issubset(seenIndices): if not namedTypes.requiredComponents.issubset(seenIndices):
raise error.PyAsn1Error('ASN.1 object %s has uninitialized components' % asn1Object.__class__.__name__) raise error.PyAsn1Error('ASN.1 object %s has uninitialized components' % asn1Object.__class__.__name__)
else:
asn1Object.verifySizeSpec() if namedTypes.hasOpenTypes:
openTypes = options.get('openTypes', None)
if openTypes or options.get('decodeOpenTypes', False):
for idx, namedType in enumerate(namedTypes.namedTypes):
if not namedType.openType:
continue
if namedType.isOptional and not asn1Object.getComponentByPosition(idx).isValue:
continue
governingValue = asn1Object.getComponentByName(
namedType.openType.name
)
try:
openType = openTypes[governingValue]
except KeyError:
try:
openType = namedType.openType[governingValue]
except KeyError:
continue
component, rest = decodeFun(
asn1Object.getComponentByPosition(idx).asOctets(),
asn1Spec=openType, allowEoo=True
)
if component is not eoo.endOfOctets:
asn1Object.setComponentByPosition(idx, component)
else:
asn1Object.verifySizeSpec()
else: else:
asn1Spec = asn1Object.componentType asn1Object = asn1Spec.clone()
componentType = asn1Spec.componentType
idx = 0 idx = 0
while substrate: while substrate:
component, substrate = decodeFun(substrate, asn1Spec, allowEoo=True, **options) component, substrate = decodeFun(substrate, componentType, allowEoo=True, **options)
if component is eoo.endOfOctets: if component is eoo.endOfOctets:
break break
asn1Object.setComponentByPosition( asn1Object.setComponentByPosition(
idx, component, idx, component,
verifyConstraints=False, verifyConstraints=False,
@ -631,7 +752,6 @@ class UniversalConstructedTypeDecoder(AbstractConstructedDecoder):
raise error.SubstrateUnderrunError( raise error.SubstrateUnderrunError(
'No EOO seen before substrate ends' 'No EOO seen before substrate ends'
) )
asn1Object.verifySizeSpec()
return asn1Object, substrate return asn1Object, substrate
@ -671,28 +791,35 @@ class ChoiceDecoder(AbstractConstructedDecoder):
decodeFun=None, substrateFun=None, decodeFun=None, substrateFun=None,
**options): **options):
head, tail = substrate[:length], substrate[length:] head, tail = substrate[:length], substrate[length:]
if asn1Spec is None: if asn1Spec is None:
asn1Object = self.protoComponent.clone(tagSet=tagSet) asn1Object = self.protoComponent.clone(tagSet=tagSet)
else: else:
asn1Object = asn1Spec.clone() asn1Object = asn1Spec.clone()
if substrateFun: if substrateFun:
return substrateFun(asn1Object, substrate, length) return substrateFun(asn1Object, substrate, length)
if asn1Object.tagSet == tagSet: # explicitly tagged Choice if asn1Object.tagSet == tagSet: # explicitly tagged Choice
component, head = decodeFun( component, head = decodeFun(
head, asn1Object.componentTagMap, **options head, asn1Object.componentTagMap, **options
) )
else: else:
component, head = decodeFun( component, head = decodeFun(
head, asn1Object.componentTagMap, head, asn1Object.componentTagMap,
tagSet, length, state, **options tagSet, length, state, **options
) )
effectiveTagSet = component.effectiveTagSet effectiveTagSet = component.effectiveTagSet
asn1Object.setComponentByType( asn1Object.setComponentByType(
effectiveTagSet, component, effectiveTagSet, component,
verifyConstraints=False, verifyConstraints=False,
matchTags=False, matchConstraints=False, matchTags=False, matchConstraints=False,
innerFlag=False innerFlag=False
) )
return asn1Object, tail return asn1Object, tail
def indefLenValueDecoder(self, substrate, asn1Spec, def indefLenValueDecoder(self, substrate, asn1Spec,
@ -703,8 +830,10 @@ class ChoiceDecoder(AbstractConstructedDecoder):
asn1Object = self.protoComponent.clone(tagSet=tagSet) asn1Object = self.protoComponent.clone(tagSet=tagSet)
else: else:
asn1Object = asn1Spec.clone() asn1Object = asn1Spec.clone()
if substrateFun: if substrateFun:
return substrateFun(asn1Object, substrate, length) return substrateFun(asn1Object, substrate, length)
if asn1Object.tagSet == tagSet: # explicitly tagged Choice if asn1Object.tagSet == tagSet: # explicitly tagged Choice
component, substrate = decodeFun( component, substrate = decodeFun(
substrate, asn1Object.componentType.tagMapUnique, **options substrate, asn1Object.componentType.tagMapUnique, **options
@ -715,18 +844,22 @@ class ChoiceDecoder(AbstractConstructedDecoder):
) )
if eooMarker is not eoo.endOfOctets: if eooMarker is not eoo.endOfOctets:
raise error.PyAsn1Error('No EOO seen before substrate ends') raise error.PyAsn1Error('No EOO seen before substrate ends')
else: else:
component, substrate = decodeFun( component, substrate = decodeFun(
substrate, asn1Object.componentType.tagMapUnique, substrate, asn1Object.componentType.tagMapUnique,
tagSet, length, state, **options tagSet, length, state, **options
) )
effectiveTagSet = component.effectiveTagSet effectiveTagSet = component.effectiveTagSet
asn1Object.setComponentByType( asn1Object.setComponentByType(
effectiveTagSet, component, effectiveTagSet, component,
verifyConstraints=False, verifyConstraints=False,
matchTags=False, matchConstraints=False, matchTags=False, matchConstraints=False,
innerFlag=False innerFlag=False
) )
return asn1Object, substrate return asn1Object, substrate
@ -745,12 +878,12 @@ class AnyDecoder(AbstractSimpleDecoder):
substrate = fullSubstrate substrate = fullSubstrate
if substrateFun: if substrateFun:
return substrateFun(self._createComponent(asn1Spec, tagSet), return substrateFun(self._createComponent(asn1Spec, tagSet, noValue, **options),
substrate, length) substrate, length)
head, tail = substrate[:length], substrate[length:] head, tail = substrate[:length], substrate[length:]
return self._createComponent(asn1Spec, tagSet, value=head), tail return self._createComponent(asn1Spec, tagSet, head, **options), tail
def indefLenValueDecoder(self, substrate, asn1Spec, def indefLenValueDecoder(self, substrate, asn1Spec,
tagSet=None, length=None, state=None, tagSet=None, length=None, state=None,
@ -769,7 +902,7 @@ class AnyDecoder(AbstractSimpleDecoder):
asn1Spec = self.protoComponent asn1Spec = self.protoComponent
if substrateFun and substrateFun is not self.substrateCollector: if substrateFun and substrateFun is not self.substrateCollector:
asn1Object = self._createComponent(asn1Spec, tagSet) asn1Object = self._createComponent(asn1Spec, tagSet, noValue, **options)
return substrateFun(asn1Object, header + substrate, length + len(header)) return substrateFun(asn1Object, header + substrate, length + len(header))
# All inner fragments are of the same type, treat them as octet string # All inner fragments are of the same type, treat them as octet string
@ -789,7 +922,7 @@ class AnyDecoder(AbstractSimpleDecoder):
if substrateFun: if substrateFun:
return header, substrate return header, substrate
else: else:
return self._createComponent(asn1Spec, tagSet, header), substrate return self._createComponent(asn1Spec, tagSet, header, **options), substrate
# character string types # character string types
@ -1159,8 +1292,10 @@ class Decoder(object):
self, substrateFun, self, substrateFun,
**options **options
) )
if logger: if logger:
logger('codec %s yields type %s, value:\n%s\n...remaining substrate is: %s' % (concreteDecoder.__class__.__name__, value.__class__.__name__, isinstance(value, base.Asn1Item) and value.prettyPrint() or value, substrate and debug.hexdump(substrate) or '<none>')) logger('codec %s yields type %s, value:\n%s\n...remaining substrate is: %s' % (concreteDecoder.__class__.__name__, value.__class__.__name__, isinstance(value, base.Asn1Item) and value.prettyPrint() or value, substrate and debug.hexdump(substrate) or '<none>'))
state = stStop state = stStop
break break
if state is stTryAsExplicitTag: if state is stTryAsExplicitTag:
@ -1190,15 +1325,17 @@ class Decoder(object):
#: Turns BER octet stream into an ASN.1 object. #: Turns BER octet stream into an ASN.1 object.
#: #:
#: Takes BER octetstream and decode it into an ASN.1 object #: Takes BER octet-stream and decode it into an ASN.1 object
#: (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) which #: (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) which
#: may be a scalar or an arbitrary nested structure. #: may be a scalar or an arbitrary nested structure.
#: #:
#: Parameters #: Parameters
#: ---------- #: ----------
#: substrate: :py:class:`bytes` (Python 3) or :py:class:`str` (Python 2) #: substrate: :py:class:`bytes` (Python 3) or :py:class:`str` (Python 2)
#: BER octetstream #: BER octet-stream
#: #:
#: Keyword Args
#: ------------
#: asn1Spec: any pyasn1 type object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative #: asn1Spec: any pyasn1 type object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative
#: A pyasn1 type object to act as a template guiding the decoder. Depending on the ASN.1 structure #: A pyasn1 type object to act as a template guiding the decoder. Depending on the ASN.1 structure
#: being decoded, *asn1Spec* may or may not be required. Most common reason for #: being decoded, *asn1Spec* may or may not be required. Most common reason for
@ -1212,8 +1349,30 @@ class Decoder(object):
#: #:
#: Raises #: Raises
#: ------ #: ------
#: : :py:class:`pyasn1.error.PyAsn1Error` #: :py:class:`~pyasn1.error.PyAsn1Error`
#: On decoding errors #: On decoding errors
#:
#: Examples
#: --------
#: Decode BER serialisation without ASN.1 schema
#:
#: .. code-block:: pycon
#:
#: >>> s, _ = decode(b'0\t\x02\x01\x01\x02\x01\x02\x02\x01\x03')
#: >>> str(s)
#: SequenceOf:
#: 1 2 3
#:
#: Decode BER serialisation with ASN.1 schema
#:
#: .. code-block:: pycon
#:
#: >>> seq = SequenceOf(componentType=Integer())
#: >>> s, _ = decode(b'0\t\x02\x01\x01\x02\x01\x02\x02\x01\x03', asn1Spec=seq)
#: >>> str(s)
#: SequenceOf:
#: 1 2 3
#:
decode = Decoder(tagMap, typeMap) decode = Decoder(tagMap, typeMap)
# XXX # XXX

View File

@ -1,20 +1,25 @@
# #
# This file is part of pyasn1 software. # This file is part of pyasn1 software.
# #
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com> # Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
# License: http://pyasn1.sf.net/license.html # License: http://snmplabs.com/pyasn1/license.html
# #
from pyasn1.type import tag, univ, char, useful from pyasn1 import debug
from pyasn1 import error
from pyasn1.codec.ber import eoo from pyasn1.codec.ber import eoo
from pyasn1.compat.octets import int2oct, oct2int, ints2octs, null, str2octs
from pyasn1.compat.integer import to_bytes from pyasn1.compat.integer import to_bytes
from pyasn1 import debug, error from pyasn1.compat.octets import (int2oct, oct2int, ints2octs, null,
str2octs, isOctetsType)
from pyasn1.type import char
from pyasn1.type import tag
from pyasn1.type import univ
from pyasn1.type import useful
__all__ = ['encode'] __all__ = ['encode']
class AbstractItemEncoder(object): class AbstractItemEncoder(object):
supportIndefLenMode = 1 supportIndefLenMode = True
# An outcome of otherwise legit call `encodeFun(eoo.endOfOctets)` # An outcome of otherwise legit call `encodeFun(eoo.endOfOctets)`
eooIntegerSubstrate = (0, 0) eooIntegerSubstrate = (0, 0)
@ -51,17 +56,20 @@ class AbstractItemEncoder(object):
raise error.PyAsn1Error('Length octets overflow (%d)' % substrateLen) raise error.PyAsn1Error('Length octets overflow (%d)' % substrateLen)
return (0x80 | substrateLen,) + substrate return (0x80 | substrateLen,) + substrate
def encodeValue(self, value, encodeFun, **options): def encodeValue(self, value, asn1Spec, encodeFun, **options):
raise error.PyAsn1Error('Not implemented') raise error.PyAsn1Error('Not implemented')
def encode(self, value, encodeFun, **options): def encode(self, value, asn1Spec=None, encodeFun=None, **options):
tagSet = value.tagSet if asn1Spec is None:
tagSet = value.tagSet
else:
tagSet = asn1Spec.tagSet
# untagged item? # untagged item?
if not tagSet: if not tagSet:
substrate, isConstructed, isOctets = self.encodeValue( substrate, isConstructed, isOctets = self.encodeValue(
value, encodeFun, **options value, asn1Spec, encodeFun, **options
) )
return substrate return substrate
@ -74,10 +82,10 @@ class AbstractItemEncoder(object):
# base tag? # base tag?
if not idx: if not idx:
substrate, isConstructed, isOctets = self.encodeValue( substrate, isConstructed, isOctets = self.encodeValue(
value, encodeFun, **options value, asn1Spec, encodeFun, **options
) )
if options.get('ifNotEmpty', False) and not substrate: if not substrate and isConstructed and options.get('ifNotEmpty', False):
return substrate return substrate
# primitive form implies definite mode # primitive form implies definite mode
@ -106,14 +114,14 @@ class AbstractItemEncoder(object):
class EndOfOctetsEncoder(AbstractItemEncoder): class EndOfOctetsEncoder(AbstractItemEncoder):
def encodeValue(self, value, encodeFun, **options): def encodeValue(self, value, asn1Spec, encodeFun, **options):
return null, False, True return null, False, True
class BooleanEncoder(AbstractItemEncoder): class BooleanEncoder(AbstractItemEncoder):
supportIndefLenMode = False supportIndefLenMode = False
def encodeValue(self, value, encodeFun, **options): def encodeValue(self, value, asn1Spec, encodeFun, **options):
return value and (1,) or (0,), False, False return value and (1,) or (0,), False, False
@ -121,7 +129,7 @@ class IntegerEncoder(AbstractItemEncoder):
supportIndefLenMode = False supportIndefLenMode = False
supportCompactZero = False supportCompactZero = False
def encodeValue(self, value, encodeFun, **options): def encodeValue(self, value, asn1Spec, encodeFun, **options):
if value == 0: if value == 0:
# de-facto way to encode zero # de-facto way to encode zero
if self.supportCompactZero: if self.supportCompactZero:
@ -133,7 +141,11 @@ class IntegerEncoder(AbstractItemEncoder):
class BitStringEncoder(AbstractItemEncoder): class BitStringEncoder(AbstractItemEncoder):
def encodeValue(self, value, encodeFun, **options): def encodeValue(self, value, asn1Spec, encodeFun, **options):
if asn1Spec is not None:
# TODO: try to avoid ASN.1 schema instantiation
value = asn1Spec.clone(value)
valueLength = len(value) valueLength = len(value)
if valueLength % 8: if valueLength % 8:
alignedValue = value << (8 - valueLength % 8) alignedValue = value << (8 - valueLength % 8)
@ -145,39 +157,79 @@ class BitStringEncoder(AbstractItemEncoder):
substrate = alignedValue.asOctets() substrate = alignedValue.asOctets()
return int2oct(len(substrate) * 8 - valueLength) + substrate, False, True return int2oct(len(substrate) * 8 - valueLength) + substrate, False, True
baseTag = value.tagSet.baseTag
# strip off explicit tags # strip off explicit tags
alignedValue = alignedValue.clone( if baseTag:
tagSet=tag.TagSet(value.tagSet.baseTag, value.tagSet.baseTag) tagSet = tag.TagSet(baseTag, baseTag)
) else:
tagSet = tag.TagSet()
alignedValue = alignedValue.clone(tagSet=tagSet)
stop = 0 stop = 0
substrate = null substrate = null
while stop < valueLength: while stop < valueLength:
start = stop start = stop
stop = min(start + maxChunkSize * 8, valueLength) stop = min(start + maxChunkSize * 8, valueLength)
substrate += encodeFun(alignedValue[start:stop], **options) substrate += encodeFun(alignedValue[start:stop], asn1Spec, **options)
return substrate, True, True return substrate, True, True
class OctetStringEncoder(AbstractItemEncoder): class OctetStringEncoder(AbstractItemEncoder):
def encodeValue(self, value, encodeFun, **options):
maxChunkSize = options.get('maxChunkSize', 0) def encodeValue(self, value, asn1Spec, encodeFun, **options):
if not maxChunkSize or len(value) <= maxChunkSize:
return value.asOctets(), False, True if asn1Spec is None:
substrate = value.asOctets()
elif not isOctetsType(value):
substrate = asn1Spec.clone(value).asOctets()
else: else:
# will strip off explicit tags substrate = value
baseTagSet = tag.TagSet(value.tagSet.baseTag, value.tagSet.baseTag)
maxChunkSize = options.get('maxChunkSize', 0)
if not maxChunkSize or len(substrate) <= maxChunkSize:
return substrate, False, True
else:
# strip off explicit tags for inner chunks
if asn1Spec is None:
baseTag = value.tagSet.baseTag
# strip off explicit tags
if baseTag:
tagSet = tag.TagSet(baseTag, baseTag)
else:
tagSet = tag.TagSet()
asn1Spec = value.clone(tagSet=tagSet)
elif not isOctetsType(value):
baseTag = asn1Spec.tagSet.baseTag
# strip off explicit tags
if baseTag:
tagSet = tag.TagSet(baseTag, baseTag)
else:
tagSet = tag.TagSet()
asn1Spec = asn1Spec.clone(tagSet=tagSet)
pos = 0 pos = 0
substrate = null substrate = null
while True: while True:
chunk = value.clone(value[pos:pos + maxChunkSize], chunk = value[pos:pos + maxChunkSize]
tagSet=baseTagSet)
if not chunk: if not chunk:
break break
substrate += encodeFun(chunk, **options)
substrate += encodeFun(chunk, asn1Spec, **options)
pos += maxChunkSize pos += maxChunkSize
return substrate, True, True return substrate, True, True
@ -186,14 +238,17 @@ class OctetStringEncoder(AbstractItemEncoder):
class NullEncoder(AbstractItemEncoder): class NullEncoder(AbstractItemEncoder):
supportIndefLenMode = False supportIndefLenMode = False
def encodeValue(self, value, encodeFun, **options): def encodeValue(self, value, asn1Spec, encodeFun, **options):
return null, False, True return null, False, True
class ObjectIdentifierEncoder(AbstractItemEncoder): class ObjectIdentifierEncoder(AbstractItemEncoder):
supportIndefLenMode = False supportIndefLenMode = False
def encodeValue(self, value, encodeFun, **options): def encodeValue(self, value, asn1Spec, encodeFun, **options):
if asn1Spec is not None:
value = asn1Spec.clone(value)
oid = value.asTuple() oid = value.asTuple()
# Build the first pair # Build the first pair
@ -291,7 +346,10 @@ class RealEncoder(AbstractItemEncoder):
encbase = encBase[i] encbase = encBase[i]
return sign, m, encbase, e return sign, m, encbase, e
def encodeValue(self, value, encodeFun, **options): def encodeValue(self, value, asn1Spec, encodeFun, **options):
if asn1Spec is not None:
value = asn1Spec.clone(value)
if value.isPlusInf: if value.isPlusInf:
return (0x40,), False, False return (0x40,), False, False
if value.isMinusInf: if value.isMinusInf:
@ -362,44 +420,116 @@ class RealEncoder(AbstractItemEncoder):
class SequenceEncoder(AbstractItemEncoder): class SequenceEncoder(AbstractItemEncoder):
def encodeValue(self, value, encodeFun, **options): omitEmptyOptionals = False
value.verifySizeSpec()
# TODO: handling three flavors of input is too much -- split over codecs
def encodeValue(self, value, asn1Spec, encodeFun, **options):
namedTypes = value.componentType
substrate = null substrate = null
idx = len(value) if asn1Spec is None:
while idx > 0: # instance of ASN.1 schema
idx -= 1 value.verifySizeSpec()
if namedTypes:
if namedTypes[idx].isOptional and not value[idx].isValue: namedTypes = value.componentType
for idx, component in enumerate(value.values()):
if namedTypes:
namedType = namedTypes[idx]
if namedType.isOptional and not component.isValue:
continue
if namedType.isDefaulted and component == namedType.asn1Object:
continue
if self.omitEmptyOptionals:
options.update(ifNotEmpty=namedType.isOptional)
chunk = encodeFun(component, asn1Spec, **options)
# wrap open type blob if needed
if namedTypes and namedType.openType:
wrapType = namedType.asn1Object
if wrapType.tagSet and not wrapType.isSameTypeWith(component):
chunk = encodeFun(chunk, wrapType, **options)
substrate += chunk
else:
# bare Python value + ASN.1 schema
for idx, namedType in enumerate(asn1Spec.componentType.namedTypes):
try:
component = value[namedType.name]
except KeyError:
raise error.PyAsn1Error('Component name "%s" not found in %r' % (namedType.name, value))
if namedType.isOptional and namedType.name not in value:
continue continue
if namedTypes[idx].isDefaulted and value[idx] == namedTypes[idx].asn1Object:
if namedType.isDefaulted and component == namedType.asn1Object:
continue continue
substrate = encodeFun(value[idx], **options) + substrate
if self.omitEmptyOptionals:
options.update(ifNotEmpty=namedType.isOptional)
chunk = encodeFun(component, asn1Spec[idx], **options)
# wrap open type blob if needed
if namedType.openType:
wrapType = namedType.asn1Object
if wrapType.tagSet and not wrapType.isSameTypeWith(component):
chunk = encodeFun(chunk, wrapType, **options)
substrate += chunk
return substrate, True, True return substrate, True, True
class SequenceOfEncoder(AbstractItemEncoder): class SequenceOfEncoder(AbstractItemEncoder):
def encodeValue(self, value, encodeFun, **options): def encodeValue(self, value, asn1Spec, encodeFun, **options):
value.verifySizeSpec() if asn1Spec is None:
value.verifySizeSpec()
else:
asn1Spec = asn1Spec.componentType
substrate = null substrate = null
idx = len(value)
while idx > 0: for idx, component in enumerate(value):
idx -= 1 substrate += encodeFun(value[idx], asn1Spec, **options)
substrate = encodeFun(value[idx], **options) + substrate
return substrate, True, True return substrate, True, True
class ChoiceEncoder(AbstractItemEncoder): class ChoiceEncoder(AbstractItemEncoder):
def encodeValue(self, value, encodeFun, **options): def encodeValue(self, value, asn1Spec, encodeFun, **options):
return encodeFun(value.getComponent(), **options), True, True if asn1Spec is None:
component = value.getComponent()
else:
names = [namedType.name for namedType in asn1Spec.componentType.namedTypes
if namedType.name in value]
if len(names) != 1:
raise error.PyAsn1Error('%s components for Choice at %r' % (len(names) and 'Multiple ' or 'None ', value))
name = names[0]
component = value[name]
asn1Spec = asn1Spec[name]
return encodeFun(component, asn1Spec, **options), True, True
class AnyEncoder(OctetStringEncoder): class AnyEncoder(OctetStringEncoder):
def encodeValue(self, value, encodeFun, **options): def encodeValue(self, value, asn1Spec, encodeFun, **options):
return value.asOctets(), not options.get('defMode', True), True if asn1Spec is None:
value = value.asOctets()
elif not isOctetsType(value):
value = asn1Spec.clone(value).asOctets()
return value, not options.get('defMode', True), True
tagMap = { tagMap = {
@ -479,7 +609,16 @@ class Encoder(object):
self.__tagMap = tagMap self.__tagMap = tagMap
self.__typeMap = typeMap self.__typeMap = typeMap
def __call__(self, value, **options): def __call__(self, value, asn1Spec=None, **options):
try:
if asn1Spec is None:
typeId = value.typeId
else:
typeId = asn1Spec.typeId
except AttributeError:
raise error.PyAsn1Error('Value %r is not ASN.1 type instance '
'and "asn1Spec" not given' % (value,))
if debug.logger & debug.flagEncoder: if debug.logger & debug.flagEncoder:
logger = debug.logger logger = debug.logger
@ -487,7 +626,8 @@ class Encoder(object):
logger = None logger = None
if logger: if logger:
logger('encoder called in %sdef mode, chunk size %s for type %s, value:\n%s' % (not options.get('defMode', True) and 'in' or '', options.get('maxChunkSize', 0), value.prettyPrintType(), value.prettyPrint())) logger('encoder called in %sdef mode, chunk size %s for '
'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))
if self.fixedDefLengthMode is not None: if self.fixedDefLengthMode is not None:
options.update(defMode=self.fixedDefLengthMode) options.update(defMode=self.fixedDefLengthMode)
@ -495,25 +635,32 @@ class Encoder(object):
if self.fixedChunkSize is not None: if self.fixedChunkSize is not None:
options.update(maxChunkSize=self.fixedChunkSize) options.update(maxChunkSize=self.fixedChunkSize)
tagSet = value.tagSet
try: try:
concreteEncoder = self.__typeMap[value.typeId] concreteEncoder = self.__typeMap[typeId]
if logger:
logger('using value codec %s chosen by type ID %s' % (concreteEncoder.__class__.__name__, typeId))
except KeyError: except KeyError:
if asn1Spec is None:
tagSet = value.tagSet
else:
tagSet = asn1Spec.tagSet
# use base type for codec lookup to recover untagged types # use base type for codec lookup to recover untagged types
baseTagSet = tag.TagSet(value.tagSet.baseTag, value.tagSet.baseTag) baseTagSet = tag.TagSet(tagSet.baseTag, tagSet.baseTag)
try: try:
concreteEncoder = self.__tagMap[baseTagSet] concreteEncoder = self.__tagMap[baseTagSet]
except KeyError: except KeyError:
raise error.PyAsn1Error('No encoder for %s' % (value,)) raise error.PyAsn1Error('No encoder for %r (%s)' % (value, tagSet))
if logger: if logger:
logger('using value codec %s chosen by %s' % (concreteEncoder.__class__.__name__, tagSet)) logger('using value codec %s chosen by tagSet %s' % (concreteEncoder.__class__.__name__, tagSet))
substrate = concreteEncoder.encode(value, self, **options) substrate = concreteEncoder.encode(value, asn1Spec, self, **options)
if logger: if logger:
logger('codec %s built %s octets of substrate: %s\nencoder completed' % (concreteEncoder, len(substrate), debug.hexdump(substrate))) logger('codec %s built %s octets of substrate: %s\nencoder completed' % (concreteEncoder, len(substrate), debug.hexdump(substrate)))
@ -527,8 +674,14 @@ class Encoder(object):
#: #:
#: Parameters #: Parameters
#: ---------- #: ----------
# value: any pyasn1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) #: value: either a Python or pyasn1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative)
#: A pyasn1 object to encode #: A Python or pyasn1 object to encode. If Python object is given, `asnSpec`
#: parameter is required to guide the encoding process.
#:
#: Keyword Args
#: ------------
#: asn1Spec:
#: Optional ASN.1 schema or value object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative
#: #:
#: defMode: :py:class:`bool` #: defMode: :py:class:`bool`
#: If `False`, produces indefinite length encoding #: If `False`, produces indefinite length encoding
@ -543,6 +696,26 @@ class Encoder(object):
#: #:
#: Raises #: Raises
#: ------ #: ------
#: : :py:class:`pyasn1.error.PyAsn1Error` #: :py:class:`~pyasn1.error.PyAsn1Error`
#: On encoding errors #: On encoding errors
#:
#: Examples
#: --------
#: Encode Python value into BER with ASN.1 schema
#:
#: .. code-block:: pycon
#:
#: >>> seq = SequenceOf(componentType=Integer())
#: >>> encode([1, 2, 3], asn1Spec=seq)
#: b'0\t\x02\x01\x01\x02\x01\x02\x02\x01\x03'
#:
#: Encode ASN.1 value object into BER
#:
#: .. code-block:: pycon
#:
#: >>> seq = SequenceOf(componentType=Integer())
#: >>> seq.extend([1, 2, 3])
#: >>> encode(seq)
#: b'0\t\x02\x01\x01\x02\x01\x02\x02\x01\x03'
#:
encode = Encoder(tagMap, typeMap) encode = Encoder(tagMap, typeMap)

View File

@ -1,10 +1,13 @@
# #
# This file is part of pyasn1 software. # This file is part of pyasn1 software.
# #
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com> # Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
# License: http://pyasn1.sf.net/license.html # License: http://snmplabs.com/pyasn1/license.html
# #
from pyasn1.type import base, tag from pyasn1.type import base
from pyasn1.type import tag
__all__ = ['endOfOctets']
class EndOfOctets(base.AbstractSimpleAsn1Item): class EndOfOctets(base.AbstractSimpleAsn1Item):

View File

@ -1,13 +1,13 @@
# #
# This file is part of pyasn1 software. # This file is part of pyasn1 software.
# #
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com> # Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
# License: http://pyasn1.sf.net/license.html # License: http://snmplabs.com/pyasn1/license.html
# #
from pyasn1.type import univ from pyasn1 import error
from pyasn1.codec.ber import decoder from pyasn1.codec.ber import decoder
from pyasn1.compat.octets import oct2int from pyasn1.compat.octets import oct2int
from pyasn1 import error from pyasn1.type import univ
__all__ = ['decode'] __all__ = ['decode']
@ -25,14 +25,14 @@ class BooleanDecoder(decoder.AbstractSimpleDecoder):
byte = oct2int(head[0]) byte = oct2int(head[0])
# CER/DER specifies encoding of TRUE as 0xFF and FALSE as 0x0, while # CER/DER specifies encoding of TRUE as 0xFF and FALSE as 0x0, while
# BER allows any non-zero value as TRUE; cf. sections 8.2.2. and 11.1 # BER allows any non-zero value as TRUE; cf. sections 8.2.2. and 11.1
# in http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf # in https://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf
if byte == 0xff: if byte == 0xff:
value = 1 value = 1
elif byte == 0x00: elif byte == 0x00:
value = 0 value = 0
else: else:
raise error.PyAsn1Error('Unexpected Boolean payload: %s' % byte) raise error.PyAsn1Error('Unexpected Boolean payload: %s' % byte)
return self._createComponent(asn1Spec, tagSet, value), tail return self._createComponent(asn1Spec, tagSet, value, **options), tail
# TODO: prohibit non-canonical encoding # TODO: prohibit non-canonical encoding
BitStringDecoder = decoder.BitStringDecoder BitStringDecoder = decoder.BitStringDecoder
@ -63,15 +63,17 @@ class Decoder(decoder.Decoder):
#: Turns CER octet stream into an ASN.1 object. #: Turns CER octet stream into an ASN.1 object.
#: #:
#: Takes CER octetstream and decode it into an ASN.1 object #: Takes CER octet-stream and decode it into an ASN.1 object
#: (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) which #: (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) which
#: may be a scalar or an arbitrary nested structure. #: may be a scalar or an arbitrary nested structure.
#: #:
#: Parameters #: Parameters
#: ---------- #: ----------
#: substrate: :py:class:`bytes` (Python 3) or :py:class:`str` (Python 2) #: substrate: :py:class:`bytes` (Python 3) or :py:class:`str` (Python 2)
#: CER octetstream #: CER octet-stream
#: #:
#: Keyword Args
#: ------------
#: asn1Spec: any pyasn1 type object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative #: asn1Spec: any pyasn1 type object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative
#: A pyasn1 type object to act as a template guiding the decoder. Depending on the ASN.1 structure #: A pyasn1 type object to act as a template guiding the decoder. Depending on the ASN.1 structure
#: being decoded, *asn1Spec* may or may not be required. Most common reason for #: being decoded, *asn1Spec* may or may not be required. Most common reason for
@ -85,6 +87,28 @@ class Decoder(decoder.Decoder):
#: #:
#: Raises #: Raises
#: ------ #: ------
#: : :py:class:`pyasn1.error.PyAsn1Error` #: :py:class:`~pyasn1.error.PyAsn1Error`
#: On decoding errors #: On decoding errors
#:
#: Examples
#: --------
#: Decode CER serialisation without ASN.1 schema
#:
#: .. code-block:: pycon
#:
#: >>> s, _ = decode(b'0\x80\x02\x01\x01\x02\x01\x02\x02\x01\x03\x00\x00')
#: >>> str(s)
#: SequenceOf:
#: 1 2 3
#:
#: Decode CER serialisation with ASN.1 schema
#:
#: .. code-block:: pycon
#:
#: >>> seq = SequenceOf(componentType=Integer())
#: >>> s, _ = decode(b'0\x80\x02\x01\x01\x02\x01\x02\x02\x01\x03\x00\x00', asn1Spec=seq)
#: >>> str(s)
#: SequenceOf:
#: 1 2 3
#:
decode = Decoder(tagMap, decoder.typeMap) decode = Decoder(tagMap, decoder.typeMap)

View File

@ -1,20 +1,20 @@
# #
# This file is part of pyasn1 software. # This file is part of pyasn1 software.
# #
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com> # Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
# License: http://pyasn1.sf.net/license.html # License: http://snmplabs.com/pyasn1/license.html
# #
from pyasn1.type import univ from pyasn1 import error
from pyasn1.type import useful
from pyasn1.codec.ber import encoder from pyasn1.codec.ber import encoder
from pyasn1.compat.octets import str2octs, null from pyasn1.compat.octets import str2octs, null
from pyasn1 import error from pyasn1.type import univ
from pyasn1.type import useful
__all__ = ['encode'] __all__ = ['encode']
class BooleanEncoder(encoder.IntegerEncoder): class BooleanEncoder(encoder.IntegerEncoder):
def encodeValue(self, value, encodeFun, **options): def encodeValue(self, value, asn1Spec, encodeFun, **options):
if value == 0: if value == 0:
substrate = (0,) substrate = (0,)
else: else:
@ -38,7 +38,7 @@ class TimeEncoderMixIn(object):
minLength = 12 minLength = 12
maxLength = 19 maxLength = 19
def encodeValue(self, value, encodeFun, **options): def encodeValue(self, value, asn1Spec, encodeFun, **options):
# Encoding constraints: # Encoding constraints:
# - minutes are mandatory, seconds are optional # - minutes are mandatory, seconds are optional
# - subseconds must NOT be zero # - subseconds must NOT be zero
@ -46,6 +46,9 @@ class TimeEncoderMixIn(object):
# - time in UTC (Z) # - time in UTC (Z)
# - only dot is allowed for fractions # - only dot is allowed for fractions
if asn1Spec is not None:
value = asn1Spec.clone(value)
octets = value.asOctets() octets = value.asOctets()
if not self.minLength < len(octets) < self.maxLength: if not self.minLength < len(octets) < self.maxLength:
@ -63,7 +66,7 @@ class TimeEncoderMixIn(object):
options.update(maxChunkSize=1000) options.update(maxChunkSize=1000)
return encoder.OctetStringEncoder.encodeValue( return encoder.OctetStringEncoder.encodeValue(
self, value, encodeFun, **options self, value, asn1Spec, encodeFun, **options
) )
@ -77,88 +80,140 @@ class UTCTimeEncoder(TimeEncoderMixIn, encoder.OctetStringEncoder):
maxLength = 14 maxLength = 14
class SetOfEncoder(encoder.SequenceOfEncoder): class SetEncoder(encoder.SequenceEncoder):
@staticmethod @staticmethod
def _sortComponents(components): def _componentSortKey(componentAndType):
# sort by tags regardless of the Choice value (static sort) """Sort SET components by tag
return sorted(components, key=lambda x: isinstance(x, univ.Choice) and x.minTagSet or x.tagSet)
def encodeValue(self, value, encodeFun, **options): Sort regardless of the Choice value (static sort)
value.verifySizeSpec() """
substrate = null component, asn1Spec = componentAndType
idx = len(value)
if value.typeId == univ.Set.typeId:
namedTypes = value.componentType
comps = []
compsMap = {}
while idx > 0:
idx -= 1
if namedTypes:
if namedTypes[idx].isOptional and not value[idx].isValue:
continue
if namedTypes[idx].isDefaulted and value[idx] == namedTypes[idx].asn1Object:
continue
comps.append(value[idx]) if asn1Spec is None:
compsMap[id(value[idx])] = namedTypes and namedTypes[idx].isOptional asn1Spec = component
for comp in self._sortComponents(comps): if asn1Spec.typeId == univ.Choice.typeId and not asn1Spec.tagSet:
options.update(ifNotEmpty=compsMap[id(comp)]) if asn1Spec.tagSet:
substrate += encodeFun(comp, **options) return asn1Spec.tagSet
else:
return asn1Spec.componentType.minTagSet
else: else:
components = [encodeFun(x, **options) for x in value] return asn1Spec.tagSet
# sort by serialized and padded components def encodeValue(self, value, asn1Spec, encodeFun, **options):
if len(components) > 1:
zero = str2octs('\x00') substrate = null
maxLen = max(map(len, components))
paddedComponents = [ comps = []
(x.ljust(maxLen, zero), x) for x in components compsMap = {}
if asn1Spec is None:
# instance of ASN.1 schema
value.verifySizeSpec()
namedTypes = value.componentType
for idx, component in enumerate(value.values()):
if namedTypes:
namedType = namedTypes[idx]
if namedType.isOptional and not component.isValue:
continue
if namedType.isDefaulted and component == namedType.asn1Object:
continue
compsMap[id(component)] = namedType
else:
compsMap[id(component)] = None
comps.append((component, asn1Spec))
else:
# bare Python value + ASN.1 schema
for idx, namedType in enumerate(asn1Spec.componentType.namedTypes):
try:
component = value[namedType.name]
except KeyError:
raise error.PyAsn1Error('Component name "%s" not found in %r' % (namedType.name, value))
if namedType.isOptional and namedType.name not in value:
continue
if namedType.isDefaulted and component == namedType.asn1Object:
continue
compsMap[id(component)] = namedType
comps.append((component, asn1Spec[idx]))
for comp, compType in sorted(comps, key=self._componentSortKey):
namedType = compsMap[id(comp)]
if namedType:
options.update(ifNotEmpty=namedType.isOptional)
chunk = encodeFun(comp, compType, **options)
# wrap open type blob if needed
if namedType and namedType.openType:
wrapType = namedType.asn1Object
if wrapType.tagSet and not wrapType.isSameTypeWith(comp):
chunk = encodeFun(chunk, wrapType, **options)
substrate += chunk
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]) paddedComponents.sort(key=lambda x: x[0])
components = [x[1] for x in paddedComponents] components = [x[1] for x in paddedComponents]
substrate = null.join(components) substrate = null.join(components)
return substrate, True, True return substrate, True, True
class SequenceEncoder(encoder.SequenceEncoder): class SequenceEncoder(encoder.SequenceEncoder):
def encodeValue(self, value, encodeFun, **options): omitEmptyOptionals = True
value.verifySizeSpec()
namedTypes = value.componentType
substrate = null
idx = len(value)
while idx > 0:
idx -= 1
if namedTypes:
if namedTypes[idx].isOptional and not value[idx].isValue:
continue
if namedTypes[idx].isDefaulted and value[idx] == namedTypes[idx].asn1Object:
continue
options.update(ifNotEmpty=namedTypes and namedTypes[idx].isOptional)
substrate = encodeFun(value[idx], **options) + substrate
return substrate, True, True
class SequenceOfEncoder(encoder.SequenceOfEncoder): class SequenceOfEncoder(encoder.SequenceOfEncoder):
def encodeValue(self, value, encodeFun, **options): 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 substrate = null
idx = len(value)
if options.get('ifNotEmpty', False) and not idx: for idx, component in enumerate(value):
return substrate, True, True substrate += encodeFun(value[idx], asn1Spec, **options)
value.verifySizeSpec()
while idx > 0:
idx -= 1
substrate = encodeFun(value[idx], **options) + substrate
return substrate, True, True return substrate, True, True
@ -180,7 +235,7 @@ typeMap.update({
useful.GeneralizedTime.typeId: GeneralizedTimeEncoder(), useful.GeneralizedTime.typeId: GeneralizedTimeEncoder(),
useful.UTCTime.typeId: UTCTimeEncoder(), useful.UTCTime.typeId: UTCTimeEncoder(),
# Sequence & Set have same tags as SequenceOf & SetOf # Sequence & Set have same tags as SequenceOf & SetOf
univ.Set.typeId: SetOfEncoder(), univ.Set.typeId: SetEncoder(),
univ.SetOf.typeId: SetOfEncoder(), univ.SetOf.typeId: SetOfEncoder(),
univ.Sequence.typeId: SequenceEncoder(), univ.Sequence.typeId: SequenceEncoder(),
univ.SequenceOf.typeId: SequenceOfEncoder() univ.SequenceOf.typeId: SequenceOfEncoder()
@ -198,24 +253,44 @@ class Encoder(encoder.Encoder):
#: #:
#: Parameters #: Parameters
#: ---------- #: ----------
# value: any pyasn1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) #: value: either a Python or pyasn1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative)
#: A pyasn1 object to encode #: A Python or pyasn1 object to encode. If Python object is given, `asnSpec`
#: parameter is required to guide the encoding process.
#: #:
#: defMode: :py:class:`bool` #: Keyword Args
#: If `False`, produces indefinite length encoding #: ------------
#: #: asn1Spec:
#: maxChunkSize: :py:class:`int` #: Optional ASN.1 schema or value object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative
#: Maximum chunk size in chunked encoding mode (0 denotes unlimited chunk size)
#: #:
#: Returns #: Returns
#: ------- #: -------
#: : :py:class:`bytes` (Python 3) or :py:class:`str` (Python 2) #: : :py:class:`bytes` (Python 3) or :py:class:`str` (Python 2)
#: Given ASN.1 object encoded into BER octetstream #: Given ASN.1 object encoded into BER octet-stream
#: #:
#: Raises #: Raises
#: ------ #: ------
#: : :py:class:`pyasn1.error.PyAsn1Error` #: :py:class:`~pyasn1.error.PyAsn1Error`
#: On encoding errors #: On encoding errors
#:
#: Examples
#: --------
#: Encode Python value into CER with ASN.1 schema
#:
#: .. code-block:: pycon
#:
#: >>> seq = SequenceOf(componentType=Integer())
#: >>> encode([1, 2, 3], asn1Spec=seq)
#: b'0\x80\x02\x01\x01\x02\x01\x02\x02\x01\x03\x00\x00'
#:
#: Encode ASN.1 value object into CER
#:
#: .. code-block:: pycon
#:
#: >>> seq = SequenceOf(componentType=Integer())
#: >>> seq.extend([1, 2, 3])
#: >>> encode(seq)
#: b'0\x80\x02\x01\x01\x02\x01\x02\x02\x01\x03\x00\x00'
#:
encode = Encoder(tagMap, typeMap) encode = Encoder(tagMap, typeMap)
# EncoderFactory queries class instance and builds a map of tags -> encoders # EncoderFactory queries class instance and builds a map of tags -> encoders

View File

@ -1,11 +1,11 @@
# #
# This file is part of pyasn1 software. # This file is part of pyasn1 software.
# #
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com> # Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
# License: http://pyasn1.sf.net/license.html # License: http://snmplabs.com/pyasn1/license.html
# #
from pyasn1.type import univ
from pyasn1.codec.cer import decoder from pyasn1.codec.cer import decoder
from pyasn1.type import univ
__all__ = ['decode'] __all__ = ['decode']
@ -43,15 +43,17 @@ class Decoder(decoder.Decoder):
#: Turns DER octet stream into an ASN.1 object. #: Turns DER octet stream into an ASN.1 object.
#: #:
#: Takes DER octetstream and decode it into an ASN.1 object #: Takes DER octet-stream and decode it into an ASN.1 object
#: (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) which #: (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) which
#: may be a scalar or an arbitrary nested structure. #: may be a scalar or an arbitrary nested structure.
#: #:
#: Parameters #: Parameters
#: ---------- #: ----------
#: substrate: :py:class:`bytes` (Python 3) or :py:class:`str` (Python 2) #: substrate: :py:class:`bytes` (Python 3) or :py:class:`str` (Python 2)
#: DER octetstream #: DER octet-stream
#: #:
#: Keyword Args
#: ------------
#: asn1Spec: any pyasn1 type object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative #: asn1Spec: any pyasn1 type object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative
#: A pyasn1 type object to act as a template guiding the decoder. Depending on the ASN.1 structure #: A pyasn1 type object to act as a template guiding the decoder. Depending on the ASN.1 structure
#: being decoded, *asn1Spec* may or may not be required. Most common reason for #: being decoded, *asn1Spec* may or may not be required. Most common reason for
@ -65,6 +67,28 @@ class Decoder(decoder.Decoder):
#: #:
#: Raises #: Raises
#: ------ #: ------
#: : :py:class:`pyasn1.error.PyAsn1Error` #: :py:class:`~pyasn1.error.PyAsn1Error`
#: On decoding errors #: On decoding errors
#:
#: Examples
#: --------
#: Decode DER serialisation without ASN.1 schema
#:
#: .. code-block:: pycon
#:
#: >>> s, _ = decode(b'0\t\x02\x01\x01\x02\x01\x02\x02\x01\x03')
#: >>> str(s)
#: SequenceOf:
#: 1 2 3
#:
#: Decode DER serialisation with ASN.1 schema
#:
#: .. code-block:: pycon
#:
#: >>> seq = SequenceOf(componentType=Integer())
#: >>> s, _ = decode(b'0\t\x02\x01\x01\x02\x01\x02\x02\x01\x03', asn1Spec=seq)
#: >>> str(s)
#: SequenceOf:
#: 1 2 3
#:
decode = Decoder(tagMap, typeMap) decode = Decoder(tagMap, typeMap)

View File

@ -1,32 +1,57 @@
# #
# This file is part of pyasn1 software. # This file is part of pyasn1 software.
# #
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com> # Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
# License: http://pyasn1.sf.net/license.html # License: http://snmplabs.com/pyasn1/license.html
# #
from pyasn1.type import univ from pyasn1 import error
from pyasn1.codec.cer import encoder from pyasn1.codec.cer import encoder
from pyasn1.type import univ
__all__ = ['encode'] __all__ = ['encode']
class SetOfEncoder(encoder.SetOfEncoder): class SetEncoder(encoder.SetEncoder):
@staticmethod @staticmethod
def _sortComponents(components): def _componentSortKey(componentAndType):
# sort by tags depending on the actual Choice value (dynamic sort) """Sort SET components by tag
return sorted(components, key=lambda x: isinstance(x, univ.Choice) and x.getComponent().tagSet or x.tagSet)
Sort depending on the actual Choice value (dynamic sort)
"""
component, asn1Spec = componentAndType
if asn1Spec is None:
compType = component
else:
compType = asn1Spec
if compType.typeId == univ.Choice.typeId and not compType.tagSet:
if asn1Spec is None:
return component.getComponent().tagSet
else:
# TODO: move out of sorting key function
names = [namedType.name for namedType in asn1Spec.componentType.namedTypes
if namedType.name in component]
if len(names) != 1:
raise error.PyAsn1Error(
'%s components for Choice at %r' % (len(names) and 'Multiple ' or 'None ', component))
# TODO: support nested CHOICE ordering
return asn1Spec[names[0]].tagSet
else:
return compType.tagSet
tagMap = encoder.tagMap.copy() tagMap = encoder.tagMap.copy()
tagMap.update({ tagMap.update({
# Set & SetOf have same tags # Set & SetOf have same tags
univ.SetOf.tagSet: SetOfEncoder() univ.Set.tagSet: SetEncoder()
}) })
typeMap = encoder.typeMap.copy() typeMap = encoder.typeMap.copy()
typeMap.update({ typeMap.update({
# Set & SetOf have same tags # Set & SetOf have same tags
univ.Set.typeId: SetOfEncoder(), univ.Set.typeId: SetEncoder()
univ.SetOf.typeId: SetOfEncoder()
}) })
@ -41,22 +66,42 @@ class Encoder(encoder.Encoder):
#: #:
#: Parameters #: Parameters
#: ---------- #: ----------
# value: any pyasn1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) #: value: either a Python or pyasn1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative)
#: A pyasn1 object to encode #: A Python or pyasn1 object to encode. If Python object is given, `asnSpec`
#: parameter is required to guide the encoding process.
#: #:
#: defMode: :py:class:`bool` #: Keyword Args
#: If `False`, produces indefinite length encoding #: ------------
#: #: asn1Spec:
#: maxChunkSize: :py:class:`int` #: Optional ASN.1 schema or value object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative
#: Maximum chunk size in chunked encoding mode (0 denotes unlimited chunk size)
#: #:
#: Returns #: Returns
#: ------- #: -------
#: : :py:class:`bytes` (Python 3) or :py:class:`str` (Python 2) #: : :py:class:`bytes` (Python 3) or :py:class:`str` (Python 2)
#: Given ASN.1 object encoded into BER octetstream #: Given ASN.1 object encoded into BER octet-stream
#: #:
#: Raises #: Raises
#: ------ #: ------
#: : :py:class:`pyasn1.error.PyAsn1Error` #: :py:class:`~pyasn1.error.PyAsn1Error`
#: On encoding errors #: On encoding errors
#:
#: Examples
#: --------
#: Encode Python value into DER with ASN.1 schema
#:
#: .. code-block:: pycon
#:
#: >>> seq = SequenceOf(componentType=Integer())
#: >>> encode([1, 2, 3], asn1Spec=seq)
#: b'0\t\x02\x01\x01\x02\x01\x02\x02\x01\x03'
#:
#: Encode ASN.1 value object into DER
#:
#: .. code-block:: pycon
#:
#: >>> seq = SequenceOf(componentType=Integer())
#: >>> seq.extend([1, 2, 3])
#: >>> encode(seq)
#: b'0\t\x02\x01\x01\x02\x01\x02\x02\x01\x03'
#:
encode = Encoder(tagMap, typeMap) encode = Encoder(tagMap, typeMap)

View File

@ -1,11 +1,16 @@
# #
# This file is part of pyasn1 software. # This file is part of pyasn1 software.
# #
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com> # Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
# License: http://pyasn1.sf.net/license.html # License: http://snmplabs.com/pyasn1/license.html
# #
from pyasn1.type import base, univ, char, useful, tag from pyasn1 import debug
from pyasn1 import debug, error from pyasn1 import error
from pyasn1.type import base
from pyasn1.type import char
from pyasn1.type import tag
from pyasn1.type import univ
from pyasn1.type import useful
__all__ = ['decode'] __all__ = ['decode']
@ -177,6 +182,8 @@ class Decoder(object):
#: pyObject: :py:class:`object` #: pyObject: :py:class:`object`
#: A scalar or nested Python objects #: A scalar or nested Python objects
#: #:
#: Keyword Args
#: ------------
#: asn1Spec: any pyasn1 type object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative #: asn1Spec: any pyasn1 type object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative
#: A pyasn1 type object to act as a template guiding the decoder. It is required #: A pyasn1 type object to act as a template guiding the decoder. It is required
#: for successful interpretation of Python objects mapping into their ASN.1 #: for successful interpretation of Python objects mapping into their ASN.1
@ -189,6 +196,19 @@ class Decoder(object):
#: #:
#: Raises #: Raises
#: ------ #: ------
#: : :py:class:`pyasn1.error.PyAsn1Error` #: :py:class:`~pyasn1.error.PyAsn1Error`
#: On decoding errors #: On decoding errors
#:
#: Examples
#: --------
#: Decode native Python object into ASN.1 objects with ASN.1 schema
#:
#: .. code-block:: pycon
#:
#: >>> seq = SequenceOf(componentType=Integer())
#: >>> s, _ = decode([1, 2, 3], asn1Spec=seq)
#: >>> str(s)
#: SequenceOf:
#: 1 2 3
#:
decode = Decoder(tagMap, typeMap) decode = Decoder(tagMap, typeMap)

View File

@ -1,8 +1,8 @@
# #
# This file is part of pyasn1 software. # This file is part of pyasn1 software.
# #
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com> # Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
# License: http://pyasn1.sf.net/license.html # License: http://snmplabs.com/pyasn1/license.html
# #
try: try:
from collections import OrderedDict from collections import OrderedDict
@ -10,8 +10,13 @@ try:
except ImportError: except ImportError:
OrderedDict = dict OrderedDict = dict
from pyasn1.type import base, univ, tag, char, useful from pyasn1 import debug
from pyasn1 import debug, error from pyasn1 import error
from pyasn1.type import base
from pyasn1.type import char
from pyasn1.type import tag
from pyasn1.type import univ
from pyasn1.type import useful
__all__ = ['encode'] __all__ = ['encode']
@ -43,7 +48,7 @@ class OctetStringEncoder(AbstractItemEncoder):
class TextStringEncoder(AbstractItemEncoder): class TextStringEncoder(AbstractItemEncoder):
def encode(self, value, encodeFun, **options): def encode(self, value, encodeFun, **options):
return value.prettyPrint() return str(value)
class NullEncoder(AbstractItemEncoder): class NullEncoder(AbstractItemEncoder):
@ -207,6 +212,18 @@ class Encoder(object):
#: #:
#: Raises #: Raises
#: ------ #: ------
#: : :py:class:`pyasn1.error.PyAsn1Error` #: :py:class:`~pyasn1.error.PyAsn1Error`
#: On encoding errors #: On encoding errors
#:
#: Examples
#: --------
#: Encode ASN.1 value object into native Python types
#:
#: .. code-block:: pycon
#:
#: >>> seq = SequenceOf(componentType=Integer())
#: >>> seq.extend([1, 2, 3])
#: >>> encode(seq)
#: [1, 2, 3]
#:
encode = Encoder(tagMap, typeMap) encode = Encoder(tagMap, typeMap)

View File

@ -1,8 +1,8 @@
# #
# This file is part of pyasn1 software. # This file is part of pyasn1 software.
# #
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com> # Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
# License: http://pyasn1.sf.net/license.html # License: http://snmplabs.com/pyasn1/license.html
# #
from sys import version_info from sys import version_info

View File

@ -1,8 +1,8 @@
# #
# This file is part of pyasn1 software. # This file is part of pyasn1 software.
# #
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com> # Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
# License: http://pyasn1.sf.net/license.html # License: http://snmplabs.com/pyasn1/license.html
# #
from sys import version_info from sys import version_info

View File

@ -1,12 +1,12 @@
# #
# This file is part of pyasn1 software. # This file is part of pyasn1 software.
# #
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com> # Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
# License: http://pyasn1.sf.net/license.html # License: http://snmplabs.com/pyasn1/license.html
# #
from sys import version_info
from datetime import datetime
import time import time
from datetime import datetime
from sys import version_info
__all__ = ['strptime'] __all__ = ['strptime']

View File

@ -1,12 +1,14 @@
# #
# This file is part of pyasn1 software. # This file is part of pyasn1 software.
# #
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com> # Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
# License: http://pyasn1.sf.net/license.html # License: http://snmplabs.com/pyasn1/license.html
# #
import sys import sys
try: try:
import platform import platform
implementation = platform.python_implementation() implementation = platform.python_implementation()
except (ImportError, AttributeError): except (ImportError, AttributeError):

View File

@ -1,8 +1,8 @@
# #
# This file is part of pyasn1 software. # This file is part of pyasn1 software.
# #
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com> # Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
# License: http://pyasn1.sf.net/license.html # License: http://snmplabs.com/pyasn1/license.html
# #
from sys import version_info from sys import version_info

View File

@ -1,8 +1,8 @@
# #
# This file is part of pyasn1 software. # This file is part of pyasn1 software.
# #
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com> # Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
# License: http://pyasn1.sf.net/license.html # License: http://snmplabs.com/pyasn1/license.html
# #
from sys import version_info from sys import version_info

View File

@ -1,13 +1,14 @@
# #
# This file is part of pyasn1 software. # This file is part of pyasn1 software.
# #
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com> # Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
# License: http://pyasn1.sf.net/license.html # License: http://snmplabs.com/pyasn1/license.html
# #
import logging import logging
from pyasn1.compat.octets import octs2ints
from pyasn1 import error
from pyasn1 import __version__ from pyasn1 import __version__
from pyasn1 import error
from pyasn1.compat.octets import octs2ints
__all__ = ['Debug', 'setLogger', 'hexdump'] __all__ = ['Debug', 'setLogger', 'hexdump']
@ -17,6 +18,7 @@ flagDecoder = 0x0002
flagAll = 0xffff flagAll = 0xffff
flagMap = { flagMap = {
'none': flagNone,
'encoder': flagEncoder, 'encoder': flagEncoder,
'decoder': flagDecoder, 'decoder': flagDecoder,
'all': flagAll 'all': flagAll

View File

@ -1,18 +1,29 @@
# #
# This file is part of pyasn1 software. # This file is part of pyasn1 software.
# #
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com> # Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
# License: http://pyasn1.sf.net/license.html # License: http://snmplabs.com/pyasn1/license.html
# #
class PyAsn1Error(Exception): class PyAsn1Error(Exception):
pass """Create pyasn1 exception object
The `PyAsn1Error` exception represents generic, usually fatal, error.
"""
class ValueConstraintError(PyAsn1Error): class ValueConstraintError(PyAsn1Error):
pass """Create pyasn1 exception object
The `ValueConstraintError` exception indicates an ASN.1 value
constraint violation.
"""
class SubstrateUnderrunError(PyAsn1Error): class SubstrateUnderrunError(PyAsn1Error):
pass """Create pyasn1 exception object
The `SubstrateUnderrunError` exception indicates insufficient serialised
data on input of a deserialisation routine.
"""

View File

@ -1,13 +1,16 @@
# #
# This file is part of pyasn1 software. # This file is part of pyasn1 software.
# #
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com> # Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
# License: http://pyasn1.sf.net/license.html # License: http://snmplabs.com/pyasn1/license.html
# #
import sys import sys
from pyasn1.type import constraint, tagmap, tag
from pyasn1.compat import calling
from pyasn1 import error from pyasn1 import error
from pyasn1.compat import calling
from pyasn1.type import constraint
from pyasn1.type import tag
from pyasn1.type import tagmap
__all__ = ['Asn1Item', 'Asn1ItemBase', 'AbstractSimpleAsn1Item', 'AbstractConstructedAsn1Item'] __all__ = ['Asn1Item', 'Asn1ItemBase', 'AbstractSimpleAsn1Item', 'AbstractConstructedAsn1Item']
@ -52,6 +55,9 @@ class Asn1ItemBase(Asn1Item):
self.__dict__[name] = value self.__dict__[name] = value
def __str__(self):
return self.prettyPrint()
@property @property
def readOnly(self): def readOnly(self):
return self._readOnly return self._readOnly
@ -75,7 +81,7 @@ class Asn1ItemBase(Asn1Item):
(:py:mod:`~pyasn1.type.constraint`) are examined when carrying (:py:mod:`~pyasn1.type.constraint`) are examined when carrying
out ASN.1 types comparison. out ASN.1 types comparison.
No Python inheritance relationship between PyASN1 objects is considered. Python class inheritance relationship is NOT considered.
Parameters Parameters
---------- ----------
@ -94,18 +100,17 @@ class Asn1ItemBase(Asn1Item):
def isSuperTypeOf(self, other, matchTags=True, matchConstraints=True): def isSuperTypeOf(self, other, matchTags=True, matchConstraints=True):
"""Examine |ASN.1| type for subtype relationship with other ASN.1 type. """Examine |ASN.1| type for subtype relationship with other ASN.1 type.
ASN.1 tags (:py:mod:`~pyasn1.type.tag`) and constraints ASN.1 tags (:py:mod:`~pyasn1.type.tag`) and constraints
(:py:mod:`~pyasn1.type.constraint`) are examined when carrying (:py:mod:`~pyasn1.type.constraint`) are examined when carrying
out ASN.1 types comparison. out ASN.1 types comparison.
No Python inheritance relationship between PyASN1 objects is considered. Python class inheritance relationship is NOT considered.
Parameters Parameters
---------- ----------
other: a pyasn1 type object other: a pyasn1 type object
Class instance representing ASN.1 type. Class instance representing ASN.1 type.
Returns Returns
------- -------
@ -120,10 +125,13 @@ class Asn1ItemBase(Asn1Item):
@staticmethod @staticmethod
def isNoValue(*values): def isNoValue(*values):
for value in values: for value in values:
if value is not None and value is not noValue: if value is not noValue:
return False return False
return True return True
def prettyPrint(self, scope=0):
raise NotImplementedError()
# backward compatibility # backward compatibility
def getTagSet(self): def getTagSet(self):
@ -145,15 +153,42 @@ class Asn1ItemBase(Asn1Item):
class NoValue(object): class NoValue(object):
"""Create a singleton instance of NoValue class. """Create a singleton instance of NoValue class.
NoValue object can be used as an initializer on PyASN1 type class The *NoValue* sentinel object represents an instance of ASN.1 schema
instantiation to represent ASN.1 type rather than ASN.1 data value. object as opposed to ASN.1 value object.
No operations other than type comparison can be performed on Only ASN.1 schema-related operations can be performed on ASN.1
a PyASN1 type object. schema objects.
Warning
-------
Any operation attempted on the *noValue* object will raise the
*PyAsn1Error* exception.
""" """
skipMethods = ('__getattribute__', '__getattr__', '__setattr__', '__delattr__', skipMethods = set(
'__class__', '__init__', '__del__', '__new__', '__repr__', ('__slots__',
'__qualname__', '__objclass__', 'im_class', '__sizeof__') # attributes
'__getattribute__',
'__getattr__',
'__setattr__',
'__delattr__',
# class instance
'__class__',
'__init__',
'__del__',
'__new__',
'__repr__',
'__qualname__',
'__objclass__',
'im_class',
'__sizeof__',
# pickle protocol
'__reduce__',
'__reduce_ex__',
'__getnewargs__',
'__getinitargs__',
'__getstate__',
'__setstate__')
)
_instance = None _instance = None
@ -161,7 +196,7 @@ class NoValue(object):
if cls._instance is None: if cls._instance is None:
def getPlug(name): def getPlug(name):
def plug(self, *args, **kw): def plug(self, *args, **kw):
raise error.PyAsn1Error('Uninitialized ASN.1 value ("%s" attribute looked up)' % name) raise error.PyAsn1Error('Attempted "%s" operation on ASN.1 schema object' % name)
return plug return plug
op_names = [name op_names = [name
@ -181,11 +216,13 @@ class NoValue(object):
def __getattr__(self, attr): def __getattr__(self, attr):
if attr in self.skipMethods: if attr in self.skipMethods:
raise AttributeError('attribute %s not present' % attr) raise AttributeError('Attribute %s not present' % attr)
raise error.PyAsn1Error('No value for "%s"' % attr)
raise error.PyAsn1Error('Attempted "%s" operation on ASN.1 schema object' % attr)
def __repr__(self): def __repr__(self):
return '%s()' % self.__class__.__name__ return '<%s object at 0x%x>' % (self.__class__.__name__, id(self))
noValue = NoValue() noValue = NoValue()
@ -197,7 +234,7 @@ class AbstractSimpleAsn1Item(Asn1ItemBase):
def __init__(self, value=noValue, **kwargs): def __init__(self, value=noValue, **kwargs):
Asn1ItemBase.__init__(self, **kwargs) Asn1ItemBase.__init__(self, **kwargs)
if value is noValue or value is None: if value is noValue:
value = self.defaultValue value = self.defaultValue
else: else:
value = self.prettyIn(value) value = self.prettyIn(value)
@ -211,17 +248,21 @@ class AbstractSimpleAsn1Item(Asn1ItemBase):
self._value = value self._value = value
def __repr__(self): def __repr__(self):
representation = [] representation = '%s %s object at 0x%x' % (
if self._value is not self.defaultValue: self.__class__.__name__, self.isValue and 'value' or 'schema', id(self)
representation.append(self.prettyOut(self._value)) )
if self.tagSet is not self.__class__.tagSet:
representation.append('tagSet=%r' % (self.tagSet,))
if self.subtypeSpec is not self.__class__.subtypeSpec:
representation.append('subtypeSpec=%r' % (self.subtypeSpec,))
return '%s(%s)' % (self.__class__.__name__, ', '.join(representation))
def __str__(self): for attr, value in self.readOnly.items():
return str(self._value) if value:
representation += ' %s %s' % (attr, value)
if self.isValue:
value = self.prettyPrint()
if len(value) > 32:
value = value[:16] + '...' + value[-16:]
representation += ' payload [%s]' % value
return '<%s>' % representation
def __eq__(self, other): def __eq__(self, other):
return self is other and True or self._value == other return self is other and True or self._value == other
@ -253,53 +294,50 @@ class AbstractSimpleAsn1Item(Asn1ItemBase):
@property @property
def isValue(self): def isValue(self):
"""Indicate if |ASN.1| object represents ASN.1 type or ASN.1 value. """Indicate that |ASN.1| object represents ASN.1 value.
In other words, if *isValue* is `True`, then the ASN.1 object is If *isValue* is `False` then this object represents just ASN.1 schema.
initialized.
If *isValue* is `True` then, in addition to its ASN.1 schema features,
this object can also be used like a Python built-in object (e.g. `int`,
`str`, `dict` etc.).
Returns Returns
------- -------
: :class:`bool` : :class:`bool`
:class:`True` if object represents ASN.1 value and type, :class:`False` if object represents just ASN.1 schema.
:class:`False` if object represents just ASN.1 type. :class:`True` if object represents ASN.1 schema and can be used as a normal value.
Note Note
---- ----
There is an important distinction between PyASN1 type and value objects. There is an important distinction between PyASN1 schema and value objects.
The PyASN1 type objects can only participate in ASN.1 type The PyASN1 schema objects can only participate in ASN.1 schema-related
operations (subtyping, comparison etc) and serve as a operations (e.g. defining or testing the structure of the data). Most
blueprint for serialization codecs to resolve ambiguous types. obvious uses of ASN.1 schema is to guide serialisation codecs whilst
encoding/decoding serialised ASN.1 contents.
The PyASN1 value objects can additionally participate in most The PyASN1 value objects can **additionally** participate in many operations
of built-in Python operations. involving regular Python objects (e.g. arithmetic, comprehension etc).
""" """
return self._value is not noValue return self._value is not noValue
def clone(self, value=noValue, **kwargs): def clone(self, value=noValue, **kwargs):
"""Create a copy of a |ASN.1| type or object. """Create a modified version of |ASN.1| schema or value object.
Any parameters to the *clone()* method will replace corresponding The `clone()` method accepts the same set arguments as |ASN.1|
properties of the |ASN.1| object. class takes on instantiation except that all arguments
of the `clone()` method are optional.
Parameters Whatever arguments are supplied, they are used to create a copy
---------- of `self` taking precedence over the ones used to instantiate `self`.
value: :class:`tuple`, :class:`str` or |ASN.1| object
Initialization value to pass to new ASN.1 object instead of
inheriting one from the caller.
tagSet: :py:class:`~pyasn1.type.tag.TagSet` Note
Object representing ASN.1 tag(s) to use in new object instead of inheriting from the caller ----
Due to the immutable nature of the |ASN.1| object, if no arguments
subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` are supplied, no new |ASN.1| object will be created and `self` will
Object representing ASN.1 subtype constraint(s) to use in new object instead of inheriting from the caller be returned instead.
Returns
-------
:
new instance of |ASN.1| type/value
""" """
if value is noValue or value is None: if value is noValue:
if not kwargs: if not kwargs:
return self return self
@ -311,37 +349,53 @@ class AbstractSimpleAsn1Item(Asn1ItemBase):
return self.__class__(value, **initilaizers) return self.__class__(value, **initilaizers)
def subtype(self, value=noValue, **kwargs): def subtype(self, value=noValue, **kwargs):
"""Create a copy of a |ASN.1| type or object. """Create a specialization of |ASN.1| schema or value object.
Any parameters to the *subtype()* method will be added to the corresponding The subtype relationship between ASN.1 types has no correlation with
properties of the |ASN.1| object. subtype relationship between Python types. ASN.1 type is mainly identified
by its tag(s) (:py:class:`~pyasn1.type.tag.TagSet`) and value range
constraints (:py:class:`~pyasn1.type.constraint.ConstraintsIntersection`).
These ASN.1 type properties are implemented as |ASN.1| attributes.
Parameters The `subtype()` method accepts the same set arguments as |ASN.1|
---------- class takes on instantiation except that all parameters
value: :class:`tuple`, :class:`str` or |ASN.1| object of the `subtype()` method are optional.
Initialization value to pass to new ASN.1 object instead of
inheriting one from the caller.
implicitTag: :py:class:`~pyasn1.type.tag.Tag` With the exception of the arguments described below, the rest of
Implicitly apply given ASN.1 tag object to caller's supplied arguments they are used to create a copy of `self` taking
:py:class:`~pyasn1.type.tag.TagSet`, then use the result as precedence over the ones used to instantiate `self`.
new object's ASN.1 tag(s).
explicitTag: :py:class:`~pyasn1.type.tag.Tag` The following arguments to `subtype()` create a ASN.1 subtype out of
Explicitly apply given ASN.1 tag object to caller's |ASN.1| type:
:py:class:`~pyasn1.type.tag.TagSet`, then use the result as
new object's ASN.1 tag(s).
subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` Other Parameters
Add ASN.1 constraints object to one of the caller, then ----------------
use the result as new object's ASN.1 constraints. implicitTag: :py:class:`~pyasn1.type.tag.Tag`
Implicitly apply given ASN.1 tag object to `self`'s
:py:class:`~pyasn1.type.tag.TagSet`, then use the result as
new object's ASN.1 tag(s).
Returns explicitTag: :py:class:`~pyasn1.type.tag.Tag`
------- Explicitly apply given ASN.1 tag object to `self`'s
: :py:class:`~pyasn1.type.tag.TagSet`, then use the result as
new instance of |ASN.1| type/value new object's ASN.1 tag(s).
subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
Add ASN.1 constraints object to one of the `self`'s, then
use the result as new object's ASN.1 constraints.
Returns
-------
:
new instance of |ASN.1| schema or value object
Note
----
Due to the immutable nature of the |ASN.1| object, if no arguments
are supplied, no new |ASN.1| object will be created and `self` will
be returned instead.
""" """
if value is noValue or value is None: if value is noValue:
if not kwargs: if not kwargs:
return self return self
@ -369,21 +423,7 @@ class AbstractSimpleAsn1Item(Asn1ItemBase):
return str(value) return str(value)
def prettyPrint(self, scope=0): def prettyPrint(self, scope=0):
"""Provide human-friendly printable object representation. return self.prettyOut(self._value)
Returns
-------
: :class:`str`
human-friendly type and/or value representation.
"""
if self.isValue:
return self.prettyOut(self._value)
else:
return '<no value>'
# XXX Compatibility stub
def prettyPrinter(self, scope=0):
return self.prettyPrint(scope)
# noinspection PyUnusedLocal # noinspection PyUnusedLocal
def prettyPrintType(self, scope=0): def prettyPrintType(self, scope=0):
@ -408,22 +448,6 @@ class AbstractSimpleAsn1Item(Asn1ItemBase):
# of types for Sequence/Set/Choice. # of types for Sequence/Set/Choice.
# #
def setupComponent():
"""Returns a sentinel value.
Indicates to a constructed type to set up its inner component so that it
can be referred to. This is useful in situation when you want to populate
descendants of a constructed type what requires being able to refer to
their parent types along the way.
Example
-------
>>> constructed['record'] = setupComponent()
>>> constructed['record']['scalar'] = 42
"""
return noValue
class AbstractConstructedAsn1Item(Asn1ItemBase): class AbstractConstructedAsn1Item(Asn1ItemBase):
@ -446,20 +470,18 @@ class AbstractConstructedAsn1Item(Asn1ItemBase):
self._componentValues = [] self._componentValues = []
def __repr__(self): def __repr__(self):
representation = [] representation = '%s %s object at 0x%x' % (
if self.componentType is not self.__class__.componentType: self.__class__.__name__, self.isValue and 'value' or 'schema', id(self)
representation.append('componentType=%r' % (self.componentType,)) )
if self.tagSet is not self.__class__.tagSet:
representation.append('tagSet=%r' % (self.tagSet,)) for attr, value in self.readOnly.items():
if self.subtypeSpec is not self.__class__.subtypeSpec: if value is not noValue:
representation.append('subtypeSpec=%r' % (self.subtypeSpec,)) representation += ' %s=%r' % (attr, value)
representation = '%s(%s)' % (self.__class__.__name__, ', '.join(representation))
if self._componentValues: if self.isValue and self._componentValues:
for idx, component in enumerate(self._componentValues): representation += ' payload [%s]' % ', '.join([repr(x) for x in self._componentValues])
if component is None or component is noValue:
continue return '<%s>' % representation
representation += '.setComponentByPosition(%d, %s)' % (idx, repr(component))
return representation
def __eq__(self, other): def __eq__(self, other):
return self is other and True or self._componentValues == other return self is other and True or self._componentValues == other
@ -486,31 +508,35 @@ class AbstractConstructedAsn1Item(Asn1ItemBase):
def __bool__(self): def __bool__(self):
return self._componentValues and True or False return self._componentValues and True or False
def __len__(self):
return len(self._componentValues)
def _cloneComponentValues(self, myClone, cloneValueFlag): def _cloneComponentValues(self, myClone, cloneValueFlag):
pass pass
def clone(self, **kwargs): def clone(self, **kwargs):
"""Create a copy of a |ASN.1| type or object. """Create a modified version of |ASN.1| schema object.
Any parameters to the *clone()* method will replace corresponding The `clone()` method accepts the same set arguments as |ASN.1|
properties of the |ASN.1| object. class takes on instantiation except that all arguments
of the `clone()` method are optional.
Parameters Whatever arguments are supplied, they are used to create a copy
---------- of `self` taking precedence over the ones used to instantiate `self`.
tagSet: :py:class:`~pyasn1.type.tag.TagSet`
Object representing non-default ASN.1 tag(s)
subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` Possible values of `self` are never copied over thus `clone()` can
Object representing non-default ASN.1 subtype constraint(s) only create a new schema object.
sizeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
Object representing non-default ASN.1 size constraint(s)
Returns Returns
------- -------
: :
new instance of |ASN.1| type/value new instance of |ASN.1| type/value
Note
----
Due to the mutable nature of the |ASN.1| object, even if no arguments
are supplied, new |ASN.1| object will always be created as a shallow
copy of `self`.
""" """
cloneValueFlag = kwargs.pop('cloneValueFlag', False) cloneValueFlag = kwargs.pop('cloneValueFlag', False)
@ -525,27 +551,46 @@ class AbstractConstructedAsn1Item(Asn1ItemBase):
return clone return clone
def subtype(self, **kwargs): def subtype(self, **kwargs):
"""Create a copy of a |ASN.1| type or object. """Create a specialization of |ASN.1| schema object.
Any parameters to the *subtype()* method will be added to the corresponding The `subtype()` method accepts the same set arguments as |ASN.1|
properties of the |ASN.1| object. class takes on instantiation except that all parameters
of the `subtype()` method are optional.
Parameters With the exception of the arguments described below, the rest of
---------- supplied arguments they are used to create a copy of `self` taking
tagSet: :py:class:`~pyasn1.type.tag.TagSet` precedence over the ones used to instantiate `self`.
Object representing non-default ASN.1 tag(s)
The following arguments to `subtype()` create a ASN.1 subtype out of
|ASN.1| type.
Other Parameters
----------------
implicitTag: :py:class:`~pyasn1.type.tag.Tag`
Implicitly apply given ASN.1 tag object to `self`'s
:py:class:`~pyasn1.type.tag.TagSet`, then use the result as
new object's ASN.1 tag(s).
explicitTag: :py:class:`~pyasn1.type.tag.Tag`
Explicitly apply given ASN.1 tag object to `self`'s
:py:class:`~pyasn1.type.tag.TagSet`, then use the result as
new object's ASN.1 tag(s).
subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
Object representing non-default ASN.1 subtype constraint(s) Add ASN.1 constraints object to one of the `self`'s, then
use the result as new object's ASN.1 constraints.
sizeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
Object representing non-default ASN.1 size constraint(s)
Returns Returns
------- -------
: :
new instance of |ASN.1| type/value new instance of |ASN.1| type/value
Note
----
Due to the immutable nature of the |ASN.1| object, if no arguments
are supplied, no new |ASN.1| object will be created and `self` will
be returned instead.
""" """
initializers = self.readOnly.copy() initializers = self.readOnly.copy()
@ -586,9 +631,6 @@ class AbstractConstructedAsn1Item(Asn1ItemBase):
self[k] = kwargs[k] self[k] = kwargs[k]
return self return self
def __len__(self):
return len(self._componentValues)
def clear(self): def clear(self):
self._componentValues = [] self._componentValues = []

View File

@ -1,13 +1,14 @@
# #
# This file is part of pyasn1 software. # This file is part of pyasn1 software.
# #
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com> # Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
# License: http://pyasn1.sf.net/license.html # License: http://snmplabs.com/pyasn1/license.html
# #
import sys import sys
from pyasn1.type import univ, tag
from pyasn1 import error
from pyasn1 import error
from pyasn1.type import tag
from pyasn1.type import univ
__all__ = ['NumericString', 'PrintableString', 'TeletexString', 'T61String', 'VideotexString', __all__ = ['NumericString', 'PrintableString', 'TeletexString', 'T61String', 'VideotexString',
'IA5String', 'GraphicString', 'VisibleString', 'ISO646String', 'IA5String', 'GraphicString', 'VisibleString', 'ISO646String',
@ -18,16 +19,16 @@ noValue = univ.noValue
class AbstractCharacterString(univ.OctetString): class AbstractCharacterString(univ.OctetString):
"""Creates |ASN.1| type or object. """Creates |ASN.1| schema or value object.
|ASN.1| objects are immutable and duck-type Python 2 :class:`unicode` or Python 3 :class:`str`. |ASN.1| objects are immutable and duck-type Python 2 :class:`unicode` or Python 3 :class:`str`.
When used in octet-stream context, |ASN.1| type assumes "|encoding|" encoding. When used in octet-stream context, |ASN.1| type assumes "|encoding|" encoding.
Parameters Keyword Args
---------- ------------
value: :class:`unicode`, :class:`str`, :class:`bytes` or |ASN.1| object value: :class:`unicode`, :class:`str`, :class:`bytes` or |ASN.1| object
unicode object (Python 2) or string (Python 3), alternatively string unicode object (Python 2) or string (Python 3), alternatively string
(Python 2) or bytes (Python 3) representing octet-stream of serialized (Python 2) or bytes (Python 3) representing octet-stream of serialised
unicode string (note `encoding` parameter) or |ASN.1| class instance. unicode string (note `encoding` parameter) or |ASN.1| class instance.
tagSet: :py:class:`~pyasn1.type.tag.TagSet` tagSet: :py:class:`~pyasn1.type.tag.TagSet`
@ -43,14 +44,16 @@ class AbstractCharacterString(univ.OctetString):
Raises Raises
------ ------
: :py:class:`pyasn1.error.PyAsn1Error` :py:class:`~pyasn1.error.PyAsn1Error`
On constraint violation or bad initializer. On constraint violation or bad initializer.
""" """
if sys.version_info[0] <= 2: if sys.version_info[0] <= 2:
def __str__(self): def __str__(self):
try: try:
# `str` is Py2 text representation
return self._value.encode(self.encoding) return self._value.encode(self.encoding)
except UnicodeEncodeError: except UnicodeEncodeError:
raise error.PyAsn1Error( raise error.PyAsn1Error(
"Can't encode string '%s' with codec %s" % (self._value, self.encoding) "Can't encode string '%s' with codec %s" % (self._value, self.encoding)
@ -85,6 +88,7 @@ class AbstractCharacterString(univ.OctetString):
else: else:
def __str__(self): def __str__(self):
# `unicode` is Py3 text representation
return str(self._value) return str(self._value)
def __bytes__(self): def __bytes__(self):
@ -119,82 +123,25 @@ class AbstractCharacterString(univ.OctetString):
def asNumbers(self, padding=True): def asNumbers(self, padding=True):
return tuple(bytes(self)) return tuple(bytes(self))
#
# See OctetString.prettyPrint() for the explanation
#
def prettyOut(self, value): def prettyOut(self, value):
return value return value
def prettyPrint(self, scope=0):
# first see if subclass has its own .prettyOut()
value = self.prettyOut(self._value)
if value is not self._value:
return value
return AbstractCharacterString.__str__(self)
def __reversed__(self): def __reversed__(self):
return reversed(self._value) return reversed(self._value)
def clone(self, value=noValue, **kwargs):
"""Creates a copy of a |ASN.1| type or object.
Any parameters to the *clone()* method will replace corresponding
properties of the |ASN.1| object.
Parameters
----------
value: :class:`unicode`, :class:`str`, :class:`bytes` or |ASN.1| object
unicode object (Python 2) or string (Python 3), alternatively string
(Python 2) or bytes (Python 3) representing octet-stream of serialized
unicode string (note `encoding` parameter) or |ASN.1| class instance.
tagSet: :py:class:`~pyasn1.type.tag.TagSet`
Object representing non-default ASN.1 tag(s)
subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
Object representing non-default ASN.1 subtype constraint(s)
encoding: :py:class:`str`
Unicode codec ID to encode/decode :py:class:`unicode` (Python 2) or
:py:class:`str` (Python 3) the payload when |ASN.1| object is used
in octet-stream context.
Returns
-------
:
new instance of |ASN.1| type/value
"""
return univ.OctetString.clone(self, value, **kwargs)
def subtype(self, value=noValue, **kwargs):
"""Creates a copy of a |ASN.1| type or object.
Any parameters to the *subtype()* method will be added to the corresponding
properties of the |ASN.1| object.
Parameters
----------
value: :class:`unicode`, :class:`str`, :class:`bytes` or |ASN.1| object
unicode object (Python 2) or string (Python 3), alternatively string
(Python 2) or bytes (Python 3) representing octet-stream of serialized
unicode string (note `encoding` parameter) or |ASN.1| class instance.
implicitTag: :py:class:`~pyasn1.type.tag.Tag`
Implicitly apply given ASN.1 tag object to caller's
:py:class:`~pyasn1.type.tag.TagSet`, then use the result as
new object's ASN.1 tag(s).
explicitTag: :py:class:`~pyasn1.type.tag.Tag`
Explicitly apply given ASN.1 tag object to caller's
:py:class:`~pyasn1.type.tag.TagSet`, then use the result as
new object's ASN.1 tag(s).
subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
Object representing non-default ASN.1 subtype constraint(s)
encoding: :py:class:`str`
Unicode codec ID to encode/decode :py:class:`unicode` (Python 2) or
:py:class:`str` (Python 3) the payload when |ASN.1| object is used
in octet-stream context.
Returns
-------
:
new instance of |ASN.1| type/value
"""
return univ.OctetString.subtype(self, value, **kwargs)
class NumericString(AbstractCharacterString): class NumericString(AbstractCharacterString):
__doc__ = AbstractCharacterString.__doc__ __doc__ = AbstractCharacterString.__doc__

View File

@ -1,26 +1,23 @@
# #
# This file is part of pyasn1 software. # This file is part of pyasn1 software.
# #
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com> # Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
# License: http://pyasn1.sf.net/license.html # License: http://snmplabs.com/pyasn1/license.html
# #
# Original concept and code by Mike C. Fletcher. # Original concept and code by Mike C. Fletcher.
# #
import sys import sys
from pyasn1.type import error from pyasn1.type import error
__all__ = ['SingleValueConstraint', 'ContainedSubtypeConstraint', 'ValueRangeConstraint', __all__ = ['SingleValueConstraint', 'ContainedSubtypeConstraint',
'ValueSizeConstraint', 'PermittedAlphabetConstraint', 'InnerTypeConstraint', 'ValueRangeConstraint', 'ValueSizeConstraint',
'ConstraintsExclusion', 'ConstraintsIntersection', 'ConstraintsUnion'] 'PermittedAlphabetConstraint', 'InnerTypeConstraint',
'ConstraintsExclusion', 'ConstraintsIntersection',
'ConstraintsUnion']
class AbstractConstraint(object): class AbstractConstraint(object):
"""Abstract base-class for constraint objects
Constraints should be stored in a simple sequence in the
namespace of their client Asn1Item sub-classes in cases
when ASN.1 constraint is define.
"""
def __init__(self, *values): def __init__(self, *values):
self._valueMap = set() self._valueMap = set()
@ -40,10 +37,12 @@ class AbstractConstraint(object):
) )
def __repr__(self): def __repr__(self):
return '%s(%s)' % ( representation = '%s object at 0x%x' % (self.__class__.__name__, id(self))
self.__class__.__name__,
', '.join([repr(x) for x in self._values]) if self._values:
) representation += ' consts %s' % ', '.join([repr(x) for x in self._values])
return '<%s>' % representation
def __eq__(self, other): def __eq__(self, other):
return self is other and True or self._values == other return self is other and True or self._values == other
@ -96,9 +95,39 @@ class AbstractConstraint(object):
otherConstraint == self or otherConstraint == self or
otherConstraint in self._valueMap) otherConstraint in self._valueMap)
class SingleValueConstraint(AbstractConstraint):
"""Value must be part of defined values constraint"""
class SingleValueConstraint(AbstractConstraint):
"""Create a SingleValueConstraint object.
The SingleValueConstraint satisfies any value that
is present in the set of permitted values.
The SingleValueConstraint object can be applied to
any ASN.1 type.
Parameters
----------
\*values: :class:`int`
Full set of values permitted by this constraint object.
Examples
--------
.. code-block:: python
class DivisorOfSix(Integer):
'''
ASN.1 specification:
Divisor-Of-6 ::= INTEGER (1 | 2 | 3 | 6)
'''
subtypeSpec = SingleValueConstraint(1, 2, 3, 6)
# this will succeed
divisor_of_six = DivisorOfSix(1)
# this will raise ValueConstraintError
divisor_of_six = DivisorOfSix(7)
"""
def _setValues(self, values): def _setValues(self, values):
self._values = values self._values = values
self._set = set(values) self._set = set(values)
@ -109,16 +138,85 @@ class SingleValueConstraint(AbstractConstraint):
class ContainedSubtypeConstraint(AbstractConstraint): class ContainedSubtypeConstraint(AbstractConstraint):
"""Value must satisfy all of defined set of constraints""" """Create a ContainedSubtypeConstraint object.
The ContainedSubtypeConstraint satisfies any value that
is present in the set of permitted values and also
satisfies included constraints.
The ContainedSubtypeConstraint object can be applied to
any ASN.1 type.
Parameters
----------
\*values:
Full set of values and constraint objects permitted
by this constraint object.
Examples
--------
.. code-block:: python
class DivisorOfEighteen(Integer):
'''
ASN.1 specification:
Divisors-of-18 ::= INTEGER (INCLUDES Divisors-of-6 | 9 | 18)
'''
subtypeSpec = ContainedSubtypeConstraint(
SingleValueConstraint(1, 2, 3, 6), 9, 18
)
# this will succeed
divisor_of_eighteen = DivisorOfEighteen(9)
# this will raise ValueConstraintError
divisor_of_eighteen = DivisorOfEighteen(10)
"""
def _testValue(self, value, idx): def _testValue(self, value, idx):
for c in self._values: for constraint in self._values:
c(value, idx) if isinstance(constraint, AbstractConstraint):
constraint(value, idx)
elif value not in self._set:
raise error.ValueConstraintError(value)
class ValueRangeConstraint(AbstractConstraint): class ValueRangeConstraint(AbstractConstraint):
"""Value must be within start and stop values (inclusive)""" """Create a ValueRangeConstraint object.
The ValueRangeConstraint satisfies any value that
falls in the range of permitted values.
The ValueRangeConstraint object can only be applied
to :class:`~pyasn1.type.univ.Integer` and
:class:`~pyasn1.type.univ.Real` types.
Parameters
----------
start: :class:`int`
Minimum permitted value in the range (inclusive)
end: :class:`int`
Maximum permitted value in the range (inclusive)
Examples
--------
.. code-block:: python
class TeenAgeYears(Integer):
'''
ASN.1 specification:
TeenAgeYears ::= INTEGER (13 .. 19)
'''
subtypeSpec = ValueRangeConstraint(13, 19)
# this will succeed
teen_year = TeenAgeYears(18)
# this will raise ValueConstraintError
teen_year = TeenAgeYears(20)
"""
def _testValue(self, value, idx): def _testValue(self, value, idx):
if value < self.start or value > self.stop: if value < self.start or value > self.stop:
raise error.ValueConstraintError(value) raise error.ValueConstraintError(value)
@ -140,8 +238,59 @@ class ValueRangeConstraint(AbstractConstraint):
class ValueSizeConstraint(ValueRangeConstraint): class ValueSizeConstraint(ValueRangeConstraint):
"""len(value) must be within start and stop values (inclusive)""" """Create a ValueSizeConstraint object.
The ValueSizeConstraint satisfies any value for
as long as its size falls within the range of
permitted sizes.
The ValueSizeConstraint object can be applied
to :class:`~pyasn1.type.univ.BitString`,
:class:`~pyasn1.type.univ.OctetString` (including
all :ref:`character ASN.1 types <type.char>`),
:class:`~pyasn1.type.univ.SequenceOf`
and :class:`~pyasn1.type.univ.SetOf` types.
Parameters
----------
minimum: :class:`int`
Minimum permitted size of the value (inclusive)
maximum: :class:`int`
Maximum permitted size of the value (inclusive)
Examples
--------
.. code-block:: python
class BaseballTeamRoster(SetOf):
'''
ASN.1 specification:
BaseballTeamRoster ::= SET SIZE (1..25) OF PlayerNames
'''
componentType = PlayerNames()
subtypeSpec = ValueSizeConstraint(1, 25)
# this will succeed
team = BaseballTeamRoster()
team.extend(['Jan', 'Matej'])
encode(team)
# this will raise ValueConstraintError
team = BaseballTeamRoster()
team.extend(['Jan'] * 26)
encode(team)
Note
----
Whenever ValueSizeConstraint is applied to mutable types
(e.g. :class:`~pyasn1.type.univ.SequenceOf`,
:class:`~pyasn1.type.univ.SetOf`), constraint
validation only happens at the serialisation phase rather
than schema instantiation phase (as it is with immutable
types).
"""
def _testValue(self, value, idx): def _testValue(self, value, idx):
valueSize = len(value) valueSize = len(value)
if valueSize < self.start or valueSize > self.stop: if valueSize < self.start or valueSize > self.stop:
@ -149,6 +298,40 @@ class ValueSizeConstraint(ValueRangeConstraint):
class PermittedAlphabetConstraint(SingleValueConstraint): class PermittedAlphabetConstraint(SingleValueConstraint):
"""Create a PermittedAlphabetConstraint object.
The PermittedAlphabetConstraint satisfies any character
string for as long as all its characters are present in
the set of permitted characters.
The PermittedAlphabetConstraint object can only be applied
to the :ref:`character ASN.1 types <type.char>` such as
:class:`~pyasn1.type.char.IA5String`.
Parameters
----------
\*alphabet: :class:`str`
Full set of characters permitted by this constraint object.
Examples
--------
.. code-block:: python
class BooleanValue(IA5String):
'''
ASN.1 specification:
BooleanValue ::= IA5String (FROM ('T' | 'F'))
'''
subtypeSpec = PermittedAlphabetConstraint('T', 'F')
# this will succeed
truth = BooleanValue('T')
truth = BooleanValue('TF')
# this will raise ValueConstraintError
garbage = BooleanValue('TAF')
"""
def _setValues(self, values): def _setValues(self, values):
self._values = values self._values = values
self._set = set(values) self._set = set(values)
@ -160,7 +343,7 @@ class PermittedAlphabetConstraint(SingleValueConstraint):
# This is a bit kludgy, meaning two op modes within a single constraint # This is a bit kludgy, meaning two op modes within a single constraint
class InnerTypeConstraint(AbstractConstraint): class InnerTypeConstraint(AbstractConstraint):
"""Value must satisfy type and presense constraints""" """Value must satisfy the type and presence constraints"""
def _testValue(self, value, idx): def _testValue(self, value, idx):
if self.__singleTypeConstraint: if self.__singleTypeConstraint:
@ -184,11 +367,50 @@ class InnerTypeConstraint(AbstractConstraint):
AbstractConstraint._setValues(self, values) AbstractConstraint._setValues(self, values)
# Boolean ops on constraints # Logic operations on constraints
class ConstraintsExclusion(AbstractConstraint): class ConstraintsExclusion(AbstractConstraint):
"""Value must not fit the single constraint""" """Create a ConstraintsExclusion logic operator object.
The ConstraintsExclusion logic operator succeeds when the
value does *not* satisfy the operand constraint.
The ConstraintsExclusion object can be applied to
any constraint and logic operator object.
Parameters
----------
constraint:
Constraint or logic operator object.
Examples
--------
.. code-block:: python
class Lipogramme(IA5STRING):
'''
ASN.1 specification:
Lipogramme ::=
IA5String (FROM (ALL EXCEPT ("e"|"E")))
'''
subtypeSpec = ConstraintsExclusion(
PermittedAlphabetConstraint('e', 'E')
)
# this will succeed
lipogramme = Lipogramme('A work of fiction?')
# this will raise ValueConstraintError
lipogramme = Lipogramme('Eel')
Warning
-------
The above example involving PermittedAlphabetConstraint might
not work due to the way how PermittedAlphabetConstraint works.
The other constraints might work with ConstraintsExclusion
though.
"""
def _testValue(self, value, idx): def _testValue(self, value, idx):
try: try:
self._values[0](value, idx) self._values[0](value, idx)
@ -200,11 +422,11 @@ class ConstraintsExclusion(AbstractConstraint):
def _setValues(self, values): def _setValues(self, values):
if len(values) != 1: if len(values) != 1:
raise error.PyAsn1Error('Single constraint expected') raise error.PyAsn1Error('Single constraint expected')
AbstractConstraint._setValues(self, values) AbstractConstraint._setValues(self, values)
class AbstractConstraintSet(AbstractConstraint): class AbstractConstraintSet(AbstractConstraint):
"""Value must not satisfy the single constraint"""
def __getitem__(self, idx): def __getitem__(self, idx):
return self._values[idx] return self._values[idx]
@ -232,16 +454,88 @@ class AbstractConstraintSet(AbstractConstraint):
class ConstraintsIntersection(AbstractConstraintSet): class ConstraintsIntersection(AbstractConstraintSet):
"""Value must satisfy all constraints""" """Create a ConstraintsIntersection logic operator object.
The ConstraintsIntersection logic operator only succeeds
if *all* its operands succeed.
The ConstraintsIntersection object can be applied to
any constraint and logic operator objects.
The ConstraintsIntersection object duck-types the immutable
container object like Python :py:class:`tuple`.
Parameters
----------
\*constraints:
Constraint or logic operator objects.
Examples
--------
.. code-block:: python
class CapitalAndSmall(IA5String):
'''
ASN.1 specification:
CapitalAndSmall ::=
IA5String (FROM ("A".."Z"|"a".."z"))
'''
subtypeSpec = ConstraintsIntersection(
PermittedAlphabetConstraint('A', 'Z'),
PermittedAlphabetConstraint('a', 'z')
)
# this will succeed
capital_and_small = CapitalAndSmall('Hello')
# this will raise ValueConstraintError
capital_and_small = CapitalAndSmall('hello')
"""
def _testValue(self, value, idx): def _testValue(self, value, idx):
for constraint in self._values: for constraint in self._values:
constraint(value, idx) constraint(value, idx)
class ConstraintsUnion(AbstractConstraintSet): class ConstraintsUnion(AbstractConstraintSet):
"""Value must satisfy at least one constraint""" """Create a ConstraintsUnion logic operator object.
The ConstraintsUnion logic operator only succeeds if
*at least a single* operand succeeds.
The ConstraintsUnion object can be applied to
any constraint and logic operator objects.
The ConstraintsUnion object duck-types the immutable
container object like Python :py:class:`tuple`.
Parameters
----------
\*constraints:
Constraint or logic operator objects.
Examples
--------
.. code-block:: python
class CapitalOrSmall(IA5String):
'''
ASN.1 specification:
CapitalOrSmall ::=
IA5String (FROM ("A".."Z") | FROM ("a".."z"))
'''
subtypeSpec = ConstraintsIntersection(
PermittedAlphabetConstraint('A', 'Z'),
PermittedAlphabetConstraint('a', 'z')
)
# this will succeed
capital_or_small = CapitalAndSmall('Hello')
# this will raise ValueConstraintError
capital_or_small = CapitalOrSmall('hello!')
"""
def _testValue(self, value, idx): def _testValue(self, value, idx):
for constraint in self._values: for constraint in self._values:
try: try:
@ -250,9 +544,13 @@ class ConstraintsUnion(AbstractConstraintSet):
pass pass
else: else:
return return
raise error.ValueConstraintError( raise error.ValueConstraintError(
'all of %s failed for \"%s\"' % (self._values, value) 'all of %s failed for "%s"' % (self._values, value)
) )
# XXX # TODO:
# refactor InnerTypeConstraint
# add tests for type check # add tests for type check
# implement other constraint types
# make constraint validation easy to skip

View File

@ -1,8 +1,8 @@
# #
# This file is part of pyasn1 software. # This file is part of pyasn1 software.
# #
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com> # Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
# License: http://pyasn1.sf.net/license.html # License: http://snmplabs.com/pyasn1/license.html
# #
from pyasn1.error import PyAsn1Error from pyasn1.error import PyAsn1Error

View File

@ -1,14 +1,23 @@
# #
# This file is part of pyasn1 software. # This file is part of pyasn1 software.
# #
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com> # Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
# License: http://pyasn1.sf.net/license.html # License: http://snmplabs.com/pyasn1/license.html
# #
import sys import sys
from pyasn1.type import tag, tagmap
from pyasn1 import error
__all__ = ['NamedType', 'OptionalNamedType', 'DefaultedNamedType', 'NamedTypes'] from pyasn1 import error
from pyasn1.type import tag
from pyasn1.type import tagmap
__all__ = ['NamedType', 'OptionalNamedType', 'DefaultedNamedType',
'NamedTypes']
try:
any
except NameError:
any = lambda x: bool(filter(bool, x))
class NamedType(object): class NamedType(object):
@ -30,13 +39,19 @@ class NamedType(object):
isOptional = False isOptional = False
isDefaulted = False isDefaulted = False
def __init__(self, name, asn1Object): def __init__(self, name, asn1Object, openType=None):
self.__name = name self.__name = name
self.__type = asn1Object self.__type = asn1Object
self.__nameAndType = name, asn1Object self.__nameAndType = name, asn1Object
self.__openType = openType
def __repr__(self): def __repr__(self):
return '%s(%r, %r)' % (self.__class__.__name__, self.__name, self.__type) representation = '%s=%r' % (self.name, self.asn1Object)
if self.openType:
representation += ' openType: %r' % self.openType
return '<%s object at 0x%x type %s>' % (self.__class__.__name__, id(self), representation)
def __eq__(self, other): def __eq__(self, other):
return self.__nameAndType == other return self.__nameAndType == other
@ -68,11 +83,15 @@ class NamedType(object):
@property @property
def name(self): def name(self):
return self.__name return self.__name
@property @property
def asn1Object(self): def asn1Object(self):
return self.__type return self.__type
@property
def openType(self):
return self.__openType
# Backward compatibility # Backward compatibility
def getName(self): def getName(self):
@ -105,6 +124,31 @@ class NamedTypes(object):
Parameters Parameters
---------- ----------
*namedTypes: :class:`~pyasn1.type.namedtype.NamedType` *namedTypes: :class:`~pyasn1.type.namedtype.NamedType`
Examples
--------
.. code-block:: python
class Description(Sequence):
'''
ASN.1 specification:
Description ::= SEQUENCE {
surname IA5String,
first-name IA5String OPTIONAL,
age INTEGER DEFAULT 40
}
'''
componentType = NamedTypes(
NamedType('surname', IA5String()),
OptionalNamedType('first-name', IA5String()),
DefaultedNamedType('age', Integer(40))
)
descr = Description()
descr['surname'] = 'Smith'
descr['first-name'] = 'John'
""" """
def __init__(self, *namedTypes, **kwargs): def __init__(self, *namedTypes, **kwargs):
self.__namedTypes = namedTypes self.__namedTypes = namedTypes
@ -115,8 +159,11 @@ class NamedTypes(object):
self.__ambiguousTypes = 'terminal' not in kwargs and self.__computeAmbiguousTypes() or {} self.__ambiguousTypes = 'terminal' not in kwargs and self.__computeAmbiguousTypes() or {}
self.__uniqueTagMap = self.__computeTagMaps(unique=True) self.__uniqueTagMap = self.__computeTagMaps(unique=True)
self.__nonUniqueTagMap = self.__computeTagMaps(unique=False) self.__nonUniqueTagMap = self.__computeTagMaps(unique=False)
self.__hasOptionalOrDefault = bool([True for namedType in self.__namedTypes self.__hasOptionalOrDefault = any([True for namedType in self.__namedTypes
if namedType.isDefaulted or namedType.isOptional]) if namedType.isDefaulted or namedType.isOptional])
self.__hasOpenTypes = any([True for namedType in self.__namedTypes
if namedType.openType])
self.__requiredComponents = frozenset( self.__requiredComponents = frozenset(
[idx for idx, nt in enumerate(self.__namedTypes) if not nt.isOptional and not nt.isDefaulted] [idx for idx, nt in enumerate(self.__namedTypes) if not nt.isOptional and not nt.isDefaulted]
) )
@ -125,9 +172,8 @@ class NamedTypes(object):
self.__items = tuple([(namedType.name, namedType.asn1Object) for namedType in self.__namedTypes]) self.__items = tuple([(namedType.name, namedType.asn1Object) for namedType in self.__namedTypes])
def __repr__(self): def __repr__(self):
return '%s(%s)' % ( representation = ', '.join(['%r' % x for x in self.__namedTypes])
self.__class__.__name__, ', '.join([repr(x) for x in self.__namedTypes]) return '<%s object at 0x%x types %s>' % (self.__class__.__name__, id(self), representation)
)
def __eq__(self, other): def __eq__(self, other):
return self.__namedTypes == other return self.__namedTypes == other
@ -331,7 +377,7 @@ class NamedTypes(object):
def getTagMapNearPosition(self, idx): def getTagMapNearPosition(self, idx):
"""Return ASN.1 types that are allowed at or past given field position. """Return ASN.1 types that are allowed at or past given field position.
Some ASN.1 serialization allow for skipping optional and defaulted fields. Some ASN.1 serialisation allow for skipping optional and defaulted fields.
Some constructed ASN.1 types allow reordering of the fields. When recovering Some constructed ASN.1 types allow reordering of the fields. When recovering
such objects it may be important to know which types can possibly be such objects it may be important to know which types can possibly be
present at any given position in the field sets. present at any given position in the field sets.
@ -360,7 +406,7 @@ class NamedTypes(object):
def getPositionNearType(self, tagSet, idx): def getPositionNearType(self, tagSet, idx):
"""Return the closest field position where given ASN.1 type is allowed. """Return the closest field position where given ASN.1 type is allowed.
Some ASN.1 serialization allow for skipping optional and defaulted fields. Some ASN.1 serialisation allow for skipping optional and defaulted fields.
Some constructed ASN.1 types allow reordering of the fields. When recovering Some constructed ASN.1 types allow reordering of the fields. When recovering
such objects it may be important to know at which field position, in field set, such objects it may be important to know at which field position, in field set,
given *tagSet* is allowed at or past *idx* position. given *tagSet* is allowed at or past *idx* position.
@ -410,7 +456,7 @@ class NamedTypes(object):
def minTagSet(self): def minTagSet(self):
"""Return the minimal TagSet among ASN.1 type in callee *NamedTypes*. """Return the minimal TagSet among ASN.1 type in callee *NamedTypes*.
Some ASN.1 types/serialization protocols require ASN.1 types to be Some ASN.1 types/serialisation protocols require ASN.1 types to be
arranged based on their numerical tag value. The *minTagSet* property arranged based on their numerical tag value. The *minTagSet* property
returns that. returns that.
@ -452,7 +498,6 @@ class NamedTypes(object):
Example Example
------- -------
.. code-block:: python .. code-block:: python
OuterType ::= CHOICE { OuterType ::= CHOICE {
@ -477,7 +522,6 @@ class NamedTypes(object):
Example Example
------- -------
.. code-block:: python .. code-block:: python
OuterType ::= CHOICE { OuterType ::= CHOICE {
@ -502,9 +546,13 @@ class NamedTypes(object):
def hasOptionalOrDefault(self): def hasOptionalOrDefault(self):
return self.__hasOptionalOrDefault return self.__hasOptionalOrDefault
@property
def hasOpenTypes(self):
return self.__hasOpenTypes
@property @property
def namedTypes(self): def namedTypes(self):
return iter(self.__namedTypes) return tuple(self.__namedTypes)
@property @property
def requiredComponents(self): def requiredComponents(self):

View File

@ -1,8 +1,8 @@
# #
# This file is part of pyasn1 software. # This file is part of pyasn1 software.
# #
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com> # Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
# License: http://pyasn1.sf.net/license.html # License: http://snmplabs.com/pyasn1/license.html
# #
# ASN.1 named integers # ASN.1 named integers
# #
@ -23,26 +23,34 @@ class NamedValues(object):
Parameters Parameters
---------- ----------
\*args: variable number of two-element :py:class:`tuple`
\*args: variable number of two-element :py:class:`tuple`
\*\*kwargs: keyword parameters of:
name: :py:class:`str` name: :py:class:`str`
Value name Value label
value: :py:class:`int` value: :py:class:`int`
A numerical value Numeric value
Keyword Args
------------
name: :py:class:`str`
Value label
value: :py:class:`int`
Numeric value
Examples Examples
-------- --------
>>> nv = namedval.NamedValues('a', 'b', ('c', 0), d=1) .. code-block:: pycon
>>> nv
>>> {'c': 0, 'd': 1, 'a': 2, 'b': 3} >>> nv = NamedValues('a', 'b', ('c', 0), d=1)
>>> nv[0] >>> nv
'c' >>> {'c': 0, 'd': 1, 'a': 2, 'b': 3}
>>> nv['a'] >>> nv[0]
2 'c'
>>> nv['a']
2
""" """
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self.__names = {} self.__names = {}
@ -96,10 +104,12 @@ class NamedValues(object):
number += 1 number += 1
def __repr__(self): def __repr__(self):
return '%s(%r)' % (self.__class__.__name__, tuple(self.items())) representation = ', '.join(['%s=%d' % x for x in self.items()])
def __str__(self): if len(representation) > 64:
return str(self.items()) representation = representation[:32] + '...' + representation[-32:]
return '<%s object 0x%x enums %s>' % (self.__class__.__name__, id(self), representation)
def __eq__(self, other): def __eq__(self, other):
return dict(self) == other return dict(self) == other

View File

@ -0,0 +1,75 @@
#
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
# License: http://snmplabs.com/pyasn1/license.html
#
__all__ = ['OpenType']
class OpenType(object):
"""Create ASN.1 type map indexed by a value
The *DefinedBy* object models the ASN.1 *DEFINED BY* clause which maps
values to ASN.1 types in the context of the ASN.1 SEQUENCE/SET type.
OpenType objects are duck-type a read-only Python :class:`dict` objects,
however the passed `typeMap` is stored by reference.
Parameters
----------
name: :py:class:`str`
Field name
typeMap: :py:class:`dict`
A map of value->ASN.1 type. It's stored by reference and can be
mutated later to register new mappings.
Examples
--------
.. code-block:: python
openType = OpenType(
'id',
{1: Integer(),
2: OctetString()}
)
Sequence(
componentType=NamedTypes(
NamedType('id', Integer()),
NamedType('blob', Any(), openType=openType)
)
)
"""
def __init__(self, name, typeMap=None):
self.__name = name
if typeMap is None:
self.__typeMap = {}
else:
self.__typeMap = typeMap
@property
def name(self):
return self.__name
# Python dict protocol
def values(self):
return self.__typeMap.values()
def keys(self):
return self.__typeMap.keys()
def items(self):
return self.__typeMap.items()
def __contains__(self, key):
return key in self.__typeMap
def __getitem__(self, key):
return self.__typeMap[key]
def __iter__(self):
return iter(self.__typeMap)

View File

@ -1,15 +1,15 @@
# #
# This file is part of pyasn1 software. # This file is part of pyasn1 software.
# #
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com> # Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
# License: http://pyasn1.sf.net/license.html # License: http://snmplabs.com/pyasn1/license.html
# #
from pyasn1 import error from pyasn1 import error
__all__ = ['tagClassUniversal', 'tagClassApplication', 'tagClassContext', __all__ = ['tagClassUniversal', 'tagClassApplication', 'tagClassContext',
'tagClassPrivate', 'tagFormatSimple', 'tagFormatConstructed', 'tagClassPrivate', 'tagFormatSimple', 'tagFormatConstructed',
'tagCategoryImplicit', 'tagCategoryExplicit', 'tagCategoryUntagged', 'tagCategoryImplicit', 'tagCategoryExplicit',
'Tag', 'TagSet'] 'tagCategoryUntagged', 'Tag', 'TagSet']
#: Identifier for ASN.1 class UNIVERSAL #: Identifier for ASN.1 class UNIVERSAL
tagClassUniversal = 0x00 tagClassUniversal = 0x00
@ -63,13 +63,9 @@ class Tag(object):
self.__tagClassId = tagClass, tagId self.__tagClassId = tagClass, tagId
self.__hash = hash(self.__tagClassId) self.__hash = hash(self.__tagClassId)
def __str__(self):
return '[%s:%s:%s]' % (self.__tagClass, self.__tagFormat, self.__tagId)
def __repr__(self): def __repr__(self):
return '%s(tagClass=%s, tagFormat=%s, tagId=%s)' % ( representation = '[%s:%s:%s]' % (self.__tagClass, self.__tagFormat, self.__tagId)
(self.__class__.__name__, self.__tagClass, self.__tagFormat, self.__tagId) return '<%s object at 0x%x tag %s>' % (self.__class__.__name__, id(self), representation)
)
def __eq__(self, other): def __eq__(self, other):
return self.__tagClassId == other return self.__tagClassId == other
@ -168,6 +164,23 @@ class TagSet(object):
*superTags: :class:`~pyasn1.type.tag.Tag` *superTags: :class:`~pyasn1.type.tag.Tag`
Additional *Tag* objects taking part in subtyping. Additional *Tag* objects taking part in subtyping.
Examples
--------
.. code-block:: python
class OrderNumber(NumericString):
'''
ASN.1 specification
Order-number ::=
[APPLICATION 5] IMPLICIT NumericString
'''
tagSet = NumericString.tagSet.tagImplicitly(
Tag(tagClassApplication, tagFormatSimple, 5)
)
orderNumber = OrderNumber('1234')
""" """
def __init__(self, baseTag=(), *superTags): def __init__(self, baseTag=(), *superTags):
self.__baseTag = baseTag self.__baseTag = baseTag
@ -178,13 +191,15 @@ class TagSet(object):
self.__lenOfSuperTags = len(superTags) self.__lenOfSuperTags = len(superTags)
self.__hash = hash(self.__superTagsClassId) self.__hash = hash(self.__superTagsClassId)
def __str__(self):
return self.__superTags and '+'.join([str(x) for x in self.__superTags]) or '[untagged]'
def __repr__(self): def __repr__(self):
return '%s(%s)' % ( representation = '-'.join(['%s:%s:%s' % (x.tagClass, x.tagFormat, x.tagId)
self.__class__.__name__, '(), ' + ', '.join([repr(x) for x in self.__superTags]) for x in self.__superTags])
) if representation:
representation = 'tags ' + representation
else:
representation = 'untagged'
return '<%s object at 0x%x %s>' % (self.__class__.__name__, id(self), representation)
def __add__(self, superTag): def __add__(self, superTag):
return self.__class__(self.__baseTag, *self.__superTags + (superTag,)) return self.__class__(self.__baseTag, *self.__superTags + (superTag,))

View File

@ -1,8 +1,8 @@
# #
# This file is part of pyasn1 software. # This file is part of pyasn1 software.
# #
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com> # Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
# License: http://pyasn1.sf.net/license.html # License: http://snmplabs.com/pyasn1/license.html
# #
from pyasn1 import error from pyasn1 import error
@ -56,24 +56,18 @@ class TagMap(object):
return iter(self.__presentTypes) return iter(self.__presentTypes)
def __repr__(self): def __repr__(self):
s = self.__class__.__name__ + '(' representation = '%s object at 0x%x' % (self.__class__.__name__, id(self))
if self.__presentTypes:
s += 'presentTypes=%r, ' % (self.__presentTypes,)
if self.__skipTypes:
s += 'skipTypes=%r, ' % (self.__skipTypes,)
if self.__defaultType is not None:
s += 'defaultType=%r' % (self.__defaultType,)
return s + ')'
def __str__(self):
s = self.__class__.__name__ + ': '
if self.__presentTypes: if self.__presentTypes:
s += 'presentTypes: %s, ' % ', '.join([x.prettyPrintType() for x in self.__presentTypes.values()]) representation += ' present %s' % repr(self.__presentTypes)
if self.__skipTypes: if self.__skipTypes:
s += 'skipTypes: %s, ' % ', '.join([x.prettyPrintType() for x in self.__skipTypes.values()]) representation += ' skip %s' % repr(self.__skipTypes)
if self.__defaultType is not None: if self.__defaultType is not None:
s += 'defaultType: %s, ' % self.__defaultType.prettyPrintType() representation += ' default %s' % repr(self.__defaultType)
return s
return '<%s>' % representation
@property @property
def presentTypes(self): def presentTypes(self):

File diff suppressed because it is too large Load Diff

View File

@ -1,13 +1,17 @@
# #
# This file is part of pyasn1 software. # This file is part of pyasn1 software.
# #
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com> # Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
# License: http://pyasn1.sf.net/license.html # License: http://snmplabs.com/pyasn1/license.html
# #
import datetime import datetime
from pyasn1.type import univ, char, tag
from pyasn1.compat import string, dateandtime
from pyasn1 import error from pyasn1 import error
from pyasn1.compat import dateandtime
from pyasn1.compat import string
from pyasn1.type import char
from pyasn1.type import tag
from pyasn1.type import univ
__all__ = ['ObjectDescriptor', 'GeneralizedTime', 'UTCTime'] __all__ = ['ObjectDescriptor', 'GeneralizedTime', 'UTCTime']
@ -61,7 +65,7 @@ class TimeMixIn(object):
Returns Returns
------- -------
: :
new instance of :py:class:`datetime.datetime` object new instance of :py:class:`datetime.datetime` object
""" """
text = str(self) text = str(self)
if text.endswith('Z'): if text.endswith('Z'):
@ -100,7 +104,7 @@ class TimeMixIn(object):
text, _, ms = string.partition(text, ',') text, _, ms = string.partition(text, ',')
try: try:
ms = int(ms) * 10000 ms = int(ms) * 1000
except ValueError: except ValueError:
raise error.PyAsn1Error('bad sub-second time specification %s' % self) raise error.PyAsn1Error('bad sub-second time specification %s' % self)
@ -127,10 +131,10 @@ class TimeMixIn(object):
Parameters Parameters
---------- ----------
dt : :py:class:`datetime.datetime` object dt: :py:class:`datetime.datetime` object
The `datetime.datetime` object to initialize the |ASN.1| object from The `datetime.datetime` object to initialize the |ASN.1| object
from
Returns Returns
------- -------
: :
@ -138,7 +142,7 @@ class TimeMixIn(object):
""" """
text = dt.strftime(cls._yearsDigits == 4 and '%Y%m%d%H%M%S' or '%y%m%d%H%M%S') text = dt.strftime(cls._yearsDigits == 4 and '%Y%m%d%H%M%S' or '%y%m%d%H%M%S')
if cls._hasSubsecond: if cls._hasSubsecond:
text += '.%d' % (dt.microsecond // 10000) text += '.%d' % (dt.microsecond // 1000)
if dt.utcoffset(): if dt.utcoffset():
seconds = dt.utcoffset().seconds seconds = dt.utcoffset().seconds

View File

@ -1,2 +1,2 @@
# http://www.python.org/dev/peps/pep-0396/ # http://www.python.org/dev/peps/pep-0396/
__version__ = '0.1.4' __version__ = '0.2.2'

View File

@ -1,8 +1,8 @@
# #
# This file is part of pyasn1-modules software. # This file is part of pyasn1-modules software.
# #
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com> # Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
# License: http://pyasn1.sf.net/license.html # License: http://snmplabs.com/pyasn1/license.html
# #
import base64 import base64
import sys import sys

View File

@ -1,8 +1,8 @@
# #
# This file is part of pyasn1-modules software. # This file is part of pyasn1-modules software.
# #
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com> # Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
# License: http://pyasn1.sf.net/license.html # License: http://snmplabs.com/pyasn1/license.html
# #
# SNMPv1 message syntax # SNMPv1 message syntax
# #
@ -12,7 +12,10 @@
# Sample captures from: # Sample captures from:
# http://wiki.wireshark.org/SampleCaptures/ # http://wiki.wireshark.org/SampleCaptures/
# #
from pyasn1.type import univ, namedtype, tag, constraint from pyasn1.type import constraint
from pyasn1.type import namedtype
from pyasn1.type import tag
from pyasn1.type import univ
class ObjectName(univ.ObjectIdentifier): class ObjectName(univ.ObjectIdentifier):

View File

@ -1,8 +1,8 @@
# #
# This file is part of pyasn1-modules software. # This file is part of pyasn1-modules software.
# #
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com> # Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
# License: http://pyasn1.sf.net/license.html # License: http://snmplabs.com/pyasn1/license.html
# #
# SNMPv1 message syntax # SNMPv1 message syntax
# #
@ -12,7 +12,11 @@
# Sample captures from: # Sample captures from:
# http://wiki.wireshark.org/SampleCaptures/ # http://wiki.wireshark.org/SampleCaptures/
# #
from pyasn1.type import univ, namedtype, namedval, tag from pyasn1.type import namedtype
from pyasn1.type import namedval
from pyasn1.type import tag
from pyasn1.type import univ
from pyasn1_modules import rfc1155 from pyasn1_modules import rfc1155

View File

@ -1,15 +1,17 @@
# #
# This file is part of pyasn1-modules software. # This file is part of pyasn1-modules software.
# #
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com> # Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
# License: http://pyasn1.sf.net/license.html # License: http://snmplabs.com/pyasn1/license.html
# #
# SNMPv2c message syntax # SNMPv2c message syntax
# #
# ASN.1 source from: # ASN.1 source from:
# http://www.ietf.org/rfc/rfc1901.txt # http://www.ietf.org/rfc/rfc1901.txt
# #
from pyasn1.type import univ, namedtype, namedval from pyasn1.type import namedtype
from pyasn1.type import namedval
from pyasn1.type import univ
class Message(univ.Sequence): class Message(univ.Sequence):

View File

@ -1,15 +1,18 @@
# #
# This file is part of pyasn1-modules software. # This file is part of pyasn1-modules software.
# #
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com> # Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
# License: http://pyasn1.sf.net/license.html # License: http://snmplabs.com/pyasn1/license.html
# #
# SNMPv2c message syntax # SNMPv2c message syntax
# #
# ASN.1 source from: # ASN.1 source from:
# http://www.ietf.org/rfc/rfc1902.txt # http://www.ietf.org/rfc/rfc1902.txt
# #
from pyasn1.type import univ, namedtype, tag, constraint from pyasn1.type import constraint
from pyasn1.type import namedtype
from pyasn1.type import tag
from pyasn1.type import univ
class Integer(univ.Integer): class Integer(univ.Integer):

View File

@ -1,15 +1,20 @@
# #
# This file is part of pyasn1-modules software. # This file is part of pyasn1-modules software.
# #
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com> # Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
# License: http://pyasn1.sf.net/license.html # License: http://snmplabs.com/pyasn1/license.html
# #
# SNMPv2c PDU syntax # SNMPv2c PDU syntax
# #
# ASN.1 source from: # ASN.1 source from:
# http://www.ietf.org/rfc/rfc1905.txt # http://www.ietf.org/rfc/rfc1905.txt
# #
from pyasn1.type import univ, namedtype, namedval, tag, constraint from pyasn1.type import constraint
from pyasn1.type import namedtype
from pyasn1.type import namedval
from pyasn1.type import tag
from pyasn1.type import univ
from pyasn1_modules import rfc1902 from pyasn1_modules import rfc1902
max_bindings = rfc1902.Integer(2147483647) max_bindings = rfc1902.Integer(2147483647)

View File

@ -1,8 +1,8 @@
# #
# This file is part of pyasn1-modules software. # This file is part of pyasn1-modules software.
# #
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com> # Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
# License: http://pyasn1.sf.net/license.html # License: http://snmplabs.com/pyasn1/license.html
# #
# LDAP message syntax # LDAP message syntax
# #
@ -12,7 +12,11 @@
# Sample captures from: # Sample captures from:
# http://wiki.wireshark.org/SampleCaptures/ # http://wiki.wireshark.org/SampleCaptures/
# #
from pyasn1.type import tag, namedtype, namedval, univ, constraint from pyasn1.type import constraint
from pyasn1.type import namedtype
from pyasn1.type import namedval
from pyasn1.type import tag
from pyasn1.type import univ
maxInt = univ.Integer(2147483647) maxInt = univ.Integer(2147483647)

View File

@ -1,8 +1,8 @@
# #
# This file is part of pyasn1-modules software. # This file is part of pyasn1-modules software.
# #
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com> # Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
# License: http://pyasn1.sf.net/license.html # License: http://snmplabs.com/pyasn1/license.html
# #
# PKCS#10 syntax # PKCS#10 syntax
# #

View File

@ -1,8 +1,8 @@
# #
# This file is part of pyasn1-modules software. # This file is part of pyasn1-modules software.
# #
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com> # Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
# License: http://pyasn1.sf.net/license.html # License: http://snmplabs.com/pyasn1/license.html
# #
# PKCS#7 message syntax # PKCS#7 message syntax
# #
@ -25,7 +25,8 @@ class Attribute(univ.Sequence):
class AttributeValueAssertion(univ.Sequence): class AttributeValueAssertion(univ.Sequence):
componentType = namedtype.NamedTypes( componentType = namedtype.NamedTypes(
namedtype.NamedType('attributeType', AttributeType()), namedtype.NamedType('attributeType', AttributeType()),
namedtype.NamedType('attributeValue', AttributeValue()) namedtype.NamedType('attributeValue', AttributeValue(),
openType=opentype.OpenType('type', certificateAttributesMap))
) )
@ -50,12 +51,19 @@ class EncryptedContent(univ.OctetString):
pass pass
contentTypeMap = {}
class EncryptedContentInfo(univ.Sequence): class EncryptedContentInfo(univ.Sequence):
componentType = namedtype.NamedTypes( componentType = namedtype.NamedTypes(
namedtype.NamedType('contentType', ContentType()), namedtype.NamedType('contentType', ContentType()),
namedtype.NamedType('contentEncryptionAlgorithm', ContentEncryptionAlgorithmIdentifier()), namedtype.NamedType('contentEncryptionAlgorithm', ContentEncryptionAlgorithmIdentifier()),
namedtype.OptionalNamedType('encryptedContent', EncryptedContent().subtype( namedtype.OptionalNamedType(
implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))) 'encryptedContent', EncryptedContent().subtype(
implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0)
),
openType=opentype.OpenType('contentType', contentTypeMap)
)
) )
@ -85,8 +93,11 @@ class Digest(univ.OctetString):
class ContentInfo(univ.Sequence): class ContentInfo(univ.Sequence):
componentType = namedtype.NamedTypes( componentType = namedtype.NamedTypes(
namedtype.NamedType('contentType', ContentType()), namedtype.NamedType('contentType', ContentType()),
namedtype.OptionalNamedType('content', univ.Any().subtype( namedtype.OptionalNamedType(
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))) 'content',
univ.Any().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0)),
openType=opentype.OpenType('contentType', contentTypeMap)
)
) )
@ -270,3 +281,14 @@ class SignedData(univ.Sequence):
class Data(univ.OctetString): class Data(univ.OctetString):
pass pass
_contentTypeMapUpdate = {
data: Data(),
signedData: SignedData(),
envelopedData: EnvelopedData(),
signedAndEnvelopedData: SignedAndEnvelopedData(),
digestedData: DigestedData(),
encryptedData: EncryptedData()
}
contentTypeMap.update(_contentTypeMapUpdate)

View File

@ -1,8 +1,8 @@
# #
# This file is part of pyasn1-modules software. # This file is part of pyasn1-modules software.
# #
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com> # Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
# License: http://pyasn1.sf.net/license.html # License: http://snmplabs.com/pyasn1/license.html
# #
# PKCS#1 syntax # PKCS#1 syntax
# #
@ -11,7 +11,10 @@
# #
# Sample captures could be obtained with "openssl genrsa" command # Sample captures could be obtained with "openssl genrsa" command
# #
from pyasn1.type import tag, namedtype, univ from pyasn1.type import namedtype
from pyasn1.type import tag
from pyasn1.type import univ
from pyasn1_modules.rfc2459 import AlgorithmIdentifier from pyasn1_modules.rfc2459 import AlgorithmIdentifier
pkcs_1 = univ.ObjectIdentifier('1.2.840.113549.1.1') pkcs_1 = univ.ObjectIdentifier('1.2.840.113549.1.1')

View File

@ -1,8 +1,8 @@
# #
# This file is part of pyasn1-modules software. # This file is part of pyasn1-modules software.
# #
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com> # Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
# License: http://pyasn1.sf.net/license.html # License: http://snmplabs.com/pyasn1/license.html
# #
# X.509 message syntax # X.509 message syntax
# #
@ -13,7 +13,14 @@
# Sample captures from: # Sample captures from:
# http://wiki.wireshark.org/SampleCaptures/ # http://wiki.wireshark.org/SampleCaptures/
# #
from pyasn1.type import tag, namedtype, namedval, univ, constraint, char, useful from pyasn1.type import char
from pyasn1.type import constraint
from pyasn1.type import namedtype
from pyasn1.type import namedval
from pyasn1.type import opentype
from pyasn1.type import tag
from pyasn1.type import univ
from pyasn1.type import useful
MAX = float('inf') MAX = float('inf')
@ -84,26 +91,6 @@ id_ad_ocsp = univ.ObjectIdentifier('1.3.6.1.5.5.7.48.1')
id_ad_caIssuers = univ.ObjectIdentifier('1.3.6.1.5.5.7.48.2') id_ad_caIssuers = univ.ObjectIdentifier('1.3.6.1.5.5.7.48.2')
class AttributeValue(univ.Any):
pass
class AttributeType(univ.ObjectIdentifier):
pass
class AttributeTypeAndValue(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.NamedType('type', AttributeType()),
namedtype.NamedType('value', AttributeValue())
)
class Attribute(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.NamedType('type', AttributeType()),
namedtype.NamedType('vals', univ.SetOf(componentType=AttributeValue()))
)
id_at = univ.ObjectIdentifier('2.5.4') id_at = univ.ObjectIdentifier('2.5.4')
@ -277,19 +264,6 @@ class DSAPrivateKey(univ.Sequence):
# ---- # ----
class RelativeDistinguishedName(univ.SetOf):
componentType = AttributeTypeAndValue()
class RDNSequence(univ.SequenceOf):
componentType = RelativeDistinguishedName()
class Name(univ.Choice):
componentType = namedtype.NamedTypes(
namedtype.NamedType('', RDNSequence())
)
class DirectoryString(univ.Choice): class DirectoryString(univ.Choice):
componentType = namedtype.NamedTypes( componentType = namedtype.NamedTypes(
@ -316,111 +290,6 @@ class AlgorithmIdentifier(univ.Sequence):
) )
class Extension(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.NamedType('extnID', univ.ObjectIdentifier()),
namedtype.DefaultedNamedType('critical', univ.Boolean('False')),
namedtype.NamedType('extnValue', univ.Any())
)
class Extensions(univ.SequenceOf):
componentType = Extension()
sizeSpec = univ.SequenceOf.sizeSpec + constraint.ValueSizeConstraint(1, MAX)
class SubjectPublicKeyInfo(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.NamedType('algorithm', AlgorithmIdentifier()),
namedtype.NamedType('subjectPublicKey', univ.BitString())
)
class UniqueIdentifier(univ.BitString):
pass
class Time(univ.Choice):
componentType = namedtype.NamedTypes(
namedtype.NamedType('utcTime', useful.UTCTime()),
namedtype.NamedType('generalTime', useful.GeneralizedTime())
)
class Validity(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.NamedType('notBefore', Time()),
namedtype.NamedType('notAfter', Time())
)
class CertificateSerialNumber(univ.Integer):
pass
class Version(univ.Integer):
namedValues = namedval.NamedValues(
('v1', 0), ('v2', 1), ('v3', 2)
)
class TBSCertificate(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.DefaultedNamedType('version', Version('v1').subtype(
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))),
namedtype.NamedType('serialNumber', CertificateSerialNumber()),
namedtype.NamedType('signature', AlgorithmIdentifier()),
namedtype.NamedType('issuer', Name()),
namedtype.NamedType('validity', Validity()),
namedtype.NamedType('subject', Name()),
namedtype.NamedType('subjectPublicKeyInfo', SubjectPublicKeyInfo()),
namedtype.OptionalNamedType('issuerUniqueID', UniqueIdentifier().subtype(
implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1))),
namedtype.OptionalNamedType('subjectUniqueID', UniqueIdentifier().subtype(
implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 2))),
namedtype.OptionalNamedType('extensions', Extensions().subtype(
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 3)))
)
class Certificate(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.NamedType('tbsCertificate', TBSCertificate()),
namedtype.NamedType('signatureAlgorithm', AlgorithmIdentifier()),
namedtype.NamedType('signatureValue', univ.BitString())
)
# CRL structures
class RevokedCertificate(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.NamedType('userCertificate', CertificateSerialNumber()),
namedtype.NamedType('revocationDate', Time()),
namedtype.OptionalNamedType('crlEntryExtensions', Extensions())
)
class TBSCertList(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.OptionalNamedType('version', Version()),
namedtype.NamedType('signature', AlgorithmIdentifier()),
namedtype.NamedType('issuer', Name()),
namedtype.NamedType('thisUpdate', Time()),
namedtype.OptionalNamedType('nextUpdate', Time()),
namedtype.OptionalNamedType('revokedCertificates', univ.SequenceOf(componentType=RevokedCertificate())),
namedtype.OptionalNamedType('crlExtensions', Extensions().subtype(
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0)))
)
class CertificateList(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.NamedType('tbsCertList', TBSCertList()),
namedtype.NamedType('signatureAlgorithm', AlgorithmIdentifier()),
namedtype.NamedType('signature', univ.BitString())
)
# Algorithm OIDs and parameter structures # Algorithm OIDs and parameter structures
@ -972,11 +841,6 @@ class BasicConstraints(univ.Sequence):
id_ce_subjectDirectoryAttributes = univ.ObjectIdentifier('2.5.29.9') id_ce_subjectDirectoryAttributes = univ.ObjectIdentifier('2.5.29.9')
class SubjectDirectoryAttributes(univ.SequenceOf):
componentType = Attribute()
subtypeSpec = univ.SequenceOf.subtypeSpec + constraint.ValueSizeConstraint(1, MAX)
class EDIPartyName(univ.Sequence): class EDIPartyName(univ.Sequence):
componentType = namedtype.NamedTypes( componentType = namedtype.NamedTypes(
namedtype.OptionalNamedType('nameAssigner', DirectoryString().subtype( namedtype.OptionalNamedType('nameAssigner', DirectoryString().subtype(
@ -986,76 +850,10 @@ class EDIPartyName(univ.Sequence):
) )
class AnotherName(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.NamedType('type-id', univ.ObjectIdentifier()),
namedtype.NamedType('value',
univ.Any().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0)))
)
class GeneralName(univ.Choice):
componentType = namedtype.NamedTypes(
namedtype.NamedType('otherName',
AnotherName().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))),
namedtype.NamedType('rfc822Name',
char.IA5String().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1))),
namedtype.NamedType('dNSName',
char.IA5String().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 2))),
namedtype.NamedType('x400Address',
ORAddress().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 3))),
namedtype.NamedType('directoryName',
Name().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 4))),
namedtype.NamedType('ediPartyName',
EDIPartyName().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 5))),
namedtype.NamedType('uniformResourceIdentifier',
char.IA5String().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 6))),
namedtype.NamedType('iPAddress', univ.OctetString().subtype(
implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 7))),
namedtype.NamedType('registeredID', univ.ObjectIdentifier().subtype(
implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 8)))
)
class GeneralNames(univ.SequenceOf):
componentType = GeneralName()
subtypeSpec = univ.SequenceOf.subtypeSpec + constraint.ValueSizeConstraint(1, MAX)
class AccessDescription(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.NamedType('accessMethod', univ.ObjectIdentifier()),
namedtype.NamedType('accessLocation', GeneralName())
)
class AuthorityInfoAccessSyntax(univ.SequenceOf):
componentType = AccessDescription()
subtypeSpec = univ.SequenceOf.subtypeSpec + constraint.ValueSizeConstraint(1, MAX)
id_ce_deltaCRLIndicator = univ.ObjectIdentifier('2.5.29.27') id_ce_deltaCRLIndicator = univ.ObjectIdentifier('2.5.29.27')
class DistributionPointName(univ.Choice):
componentType = namedtype.NamedTypes(
namedtype.NamedType('fullName', GeneralNames().subtype(
implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))),
namedtype.NamedType('nameRelativeToCRLIssuer', RelativeDistinguishedName().subtype(
implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1)))
)
class DistributionPoint(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.OptionalNamedType('distributionPoint', DistributionPointName().subtype(
implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))),
namedtype.OptionalNamedType('reasons', ReasonFlags().subtype(
implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1))),
namedtype.OptionalNamedType('cRLIssuer', GeneralNames().subtype(
implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 2)))
)
class BaseDistance(univ.Integer): class BaseDistance(univ.Integer):
subtypeSpec = univ.Integer.subtypeSpec + constraint.ValueRangeConstraint(0, MAX) subtypeSpec = univ.Integer.subtypeSpec + constraint.ValueRangeConstraint(0, MAX)
@ -1064,56 +862,14 @@ class BaseDistance(univ.Integer):
id_ce_cRLDistributionPoints = univ.ObjectIdentifier('2.5.29.31') id_ce_cRLDistributionPoints = univ.ObjectIdentifier('2.5.29.31')
class CRLDistPointsSyntax(univ.SequenceOf):
componentType = DistributionPoint()
subtypeSpec = univ.SequenceOf.subtypeSpec + constraint.ValueSizeConstraint(1, MAX)
id_ce_issuingDistributionPoint = univ.ObjectIdentifier('2.5.29.28') id_ce_issuingDistributionPoint = univ.ObjectIdentifier('2.5.29.28')
class IssuingDistributionPoint(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.OptionalNamedType('distributionPoint', DistributionPointName().subtype(
implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))),
namedtype.NamedType('onlyContainsUserCerts', univ.Boolean(False).subtype(
implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1))),
namedtype.NamedType('onlyContainsCACerts', univ.Boolean(False).subtype(
implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 2))),
namedtype.OptionalNamedType('onlySomeReasons', ReasonFlags().subtype(
implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 3))),
namedtype.NamedType('indirectCRL', univ.Boolean(False).subtype(
implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 4)))
)
class GeneralSubtree(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.NamedType('base', GeneralName()),
namedtype.DefaultedNamedType('minimum', BaseDistance(0).subtype(
implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))),
namedtype.OptionalNamedType('maximum', BaseDistance().subtype(
implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1)))
)
class GeneralSubtrees(univ.SequenceOf):
componentType = GeneralSubtree()
subtypeSpec = univ.SequenceOf.subtypeSpec + constraint.ValueSizeConstraint(1, MAX)
id_ce_nameConstraints = univ.ObjectIdentifier('2.5.29.30') id_ce_nameConstraints = univ.ObjectIdentifier('2.5.29.30')
class NameConstraints(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.OptionalNamedType('permittedSubtrees', GeneralSubtrees().subtype(
implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))),
namedtype.OptionalNamedType('excludedSubtrees', GeneralSubtrees().subtype(
implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1)))
)
class DisplayText(univ.Choice): class DisplayText(univ.Choice):
componentType = namedtype.NamedTypes( componentType = namedtype.NamedTypes(
namedtype.NamedType('visibleString', namedtype.NamedType('visibleString',
@ -1232,6 +988,110 @@ class SubjectKeyIdentifier(KeyIdentifier):
pass pass
id_ce_certificateIssuer = univ.ObjectIdentifier('2.5.29.29')
id_ce_subjectAltName = univ.ObjectIdentifier('2.5.29.17')
id_ce_issuerAltName = univ.ObjectIdentifier('2.5.29.18')
class AttributeValue(univ.Any):
pass
class AttributeType(univ.ObjectIdentifier):
pass
certificateAttributesMap = {}
class AttributeTypeAndValue(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.NamedType('type', AttributeType()),
namedtype.NamedType('value', AttributeValue(),
openType=opentype.OpenType('type', certificateAttributesMap))
)
class Attribute(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.NamedType('type', AttributeType()),
namedtype.NamedType('vals', univ.SetOf(componentType=AttributeValue()))
)
class SubjectDirectoryAttributes(univ.SequenceOf):
componentType = Attribute()
subtypeSpec = univ.SequenceOf.subtypeSpec + constraint.ValueSizeConstraint(1, MAX)
class RelativeDistinguishedName(univ.SetOf):
componentType = AttributeTypeAndValue()
class RDNSequence(univ.SequenceOf):
componentType = RelativeDistinguishedName()
class Name(univ.Choice):
componentType = namedtype.NamedTypes(
namedtype.NamedType('', RDNSequence())
)
class CertificateSerialNumber(univ.Integer):
pass
class AnotherName(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.NamedType('type-id', univ.ObjectIdentifier()),
namedtype.NamedType('value',
univ.Any().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0)))
)
class GeneralName(univ.Choice):
componentType = namedtype.NamedTypes(
namedtype.NamedType('otherName',
AnotherName().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))),
namedtype.NamedType('rfc822Name',
char.IA5String().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1))),
namedtype.NamedType('dNSName',
char.IA5String().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 2))),
namedtype.NamedType('x400Address',
ORAddress().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 3))),
namedtype.NamedType('directoryName',
Name().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 4))),
namedtype.NamedType('ediPartyName',
EDIPartyName().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 5))),
namedtype.NamedType('uniformResourceIdentifier',
char.IA5String().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 6))),
namedtype.NamedType('iPAddress', univ.OctetString().subtype(
implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 7))),
namedtype.NamedType('registeredID', univ.ObjectIdentifier().subtype(
implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 8)))
)
class GeneralNames(univ.SequenceOf):
componentType = GeneralName()
subtypeSpec = univ.SequenceOf.subtypeSpec + constraint.ValueSizeConstraint(1, MAX)
class AccessDescription(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.NamedType('accessMethod', univ.ObjectIdentifier()),
namedtype.NamedType('accessLocation', GeneralName())
)
class AuthorityInfoAccessSyntax(univ.SequenceOf):
componentType = AccessDescription()
subtypeSpec = univ.SequenceOf.subtypeSpec + constraint.ValueSizeConstraint(1, MAX)
class AuthorityKeyIdentifier(univ.Sequence): class AuthorityKeyIdentifier(univ.Sequence):
componentType = namedtype.NamedTypes( componentType = namedtype.NamedTypes(
namedtype.OptionalNamedType('keyIdentifier', KeyIdentifier().subtype( namedtype.OptionalNamedType('keyIdentifier', KeyIdentifier().subtype(
@ -1243,30 +1103,189 @@ class AuthorityKeyIdentifier(univ.Sequence):
) )
id_ce_certificateIssuer = univ.ObjectIdentifier('2.5.29.29') class DistributionPointName(univ.Choice):
componentType = namedtype.NamedTypes(
namedtype.NamedType('fullName', GeneralNames().subtype(
implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))),
namedtype.NamedType('nameRelativeToCRLIssuer', RelativeDistinguishedName().subtype(
implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1)))
)
class DistributionPoint(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.OptionalNamedType('distributionPoint', DistributionPointName().subtype(
implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))),
namedtype.OptionalNamedType('reasons', ReasonFlags().subtype(
implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1))),
namedtype.OptionalNamedType('cRLIssuer', GeneralNames().subtype(
implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 2)))
)
class CRLDistPointsSyntax(univ.SequenceOf):
componentType = DistributionPoint()
subtypeSpec = univ.SequenceOf.subtypeSpec + constraint.ValueSizeConstraint(1, MAX)
class IssuingDistributionPoint(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.OptionalNamedType('distributionPoint', DistributionPointName().subtype(
implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))),
namedtype.NamedType('onlyContainsUserCerts', univ.Boolean(False).subtype(
implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1))),
namedtype.NamedType('onlyContainsCACerts', univ.Boolean(False).subtype(
implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 2))),
namedtype.OptionalNamedType('onlySomeReasons', ReasonFlags().subtype(
implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 3))),
namedtype.NamedType('indirectCRL', univ.Boolean(False).subtype(
implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 4)))
)
class GeneralSubtree(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.NamedType('base', GeneralName()),
namedtype.DefaultedNamedType('minimum', BaseDistance(0).subtype(
implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))),
namedtype.OptionalNamedType('maximum', BaseDistance().subtype(
implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1)))
)
class GeneralSubtrees(univ.SequenceOf):
componentType = GeneralSubtree()
subtypeSpec = univ.SequenceOf.subtypeSpec + constraint.ValueSizeConstraint(1, MAX)
class NameConstraints(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.OptionalNamedType('permittedSubtrees', GeneralSubtrees().subtype(
implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))),
namedtype.OptionalNamedType('excludedSubtrees', GeneralSubtrees().subtype(
implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1)))
)
class CertificateIssuer(GeneralNames): class CertificateIssuer(GeneralNames):
pass pass
id_ce_subjectAltName = univ.ObjectIdentifier('2.5.29.17')
class SubjectAltName(GeneralNames): class SubjectAltName(GeneralNames):
pass pass
id_ce_issuerAltName = univ.ObjectIdentifier('2.5.29.18')
class IssuerAltName(GeneralNames): class IssuerAltName(GeneralNames):
pass pass
certificateExtensionsMap = {}
class Extension(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.NamedType('extnID', univ.ObjectIdentifier()),
namedtype.DefaultedNamedType('critical', univ.Boolean('False')),
namedtype.NamedType('extnValue', univ.OctetString(),
openType=opentype.OpenType('extnID', certificateExtensionsMap))
)
class Extensions(univ.SequenceOf):
componentType = Extension()
sizeSpec = univ.SequenceOf.sizeSpec + constraint.ValueSizeConstraint(1, MAX)
class SubjectPublicKeyInfo(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.NamedType('algorithm', AlgorithmIdentifier()),
namedtype.NamedType('subjectPublicKey', univ.BitString())
)
class UniqueIdentifier(univ.BitString):
pass
class Time(univ.Choice):
componentType = namedtype.NamedTypes(
namedtype.NamedType('utcTime', useful.UTCTime()),
namedtype.NamedType('generalTime', useful.GeneralizedTime())
)
class Validity(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.NamedType('notBefore', Time()),
namedtype.NamedType('notAfter', Time())
)
class Version(univ.Integer):
namedValues = namedval.NamedValues(
('v1', 0), ('v2', 1), ('v3', 2)
)
class TBSCertificate(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.DefaultedNamedType('version', Version('v1').subtype(
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))),
namedtype.NamedType('serialNumber', CertificateSerialNumber()),
namedtype.NamedType('signature', AlgorithmIdentifier()),
namedtype.NamedType('issuer', Name()),
namedtype.NamedType('validity', Validity()),
namedtype.NamedType('subject', Name()),
namedtype.NamedType('subjectPublicKeyInfo', SubjectPublicKeyInfo()),
namedtype.OptionalNamedType('issuerUniqueID', UniqueIdentifier().subtype(
implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1))),
namedtype.OptionalNamedType('subjectUniqueID', UniqueIdentifier().subtype(
implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 2))),
namedtype.OptionalNamedType('extensions', Extensions().subtype(
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 3)))
)
class Certificate(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.NamedType('tbsCertificate', TBSCertificate()),
namedtype.NamedType('signatureAlgorithm', AlgorithmIdentifier()),
namedtype.NamedType('signatureValue', univ.BitString())
)
# CRL structures
class RevokedCertificate(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.NamedType('userCertificate', CertificateSerialNumber()),
namedtype.NamedType('revocationDate', Time()),
namedtype.OptionalNamedType('crlEntryExtensions', Extensions())
)
class TBSCertList(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.OptionalNamedType('version', Version()),
namedtype.NamedType('signature', AlgorithmIdentifier()),
namedtype.NamedType('issuer', Name()),
namedtype.NamedType('thisUpdate', Time()),
namedtype.OptionalNamedType('nextUpdate', Time()),
namedtype.OptionalNamedType('revokedCertificates', univ.SequenceOf(componentType=RevokedCertificate())),
namedtype.OptionalNamedType('crlExtensions', Extensions().subtype(
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0)))
)
class CertificateList(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.NamedType('tbsCertList', TBSCertList()),
namedtype.NamedType('signatureAlgorithm', AlgorithmIdentifier()),
namedtype.NamedType('signature', univ.BitString())
)
# map of AttributeType -> AttributeValue # map of AttributeType -> AttributeValue
certificateAttributesMap = { _certificateAttributesMapUpdate = {
id_at_name: X520name(), id_at_name: X520name(),
id_at_surname: X520name(), id_at_surname: X520name(),
id_at_givenName: X520name(), id_at_givenName: X520name(),
@ -1283,14 +1302,18 @@ certificateAttributesMap = {
emailAddress: Pkcs9email(), emailAddress: Pkcs9email(),
} }
certificateAttributesMap.update(_certificateAttributesMapUpdate)
# map of Certificate Extension OIDs to Extensions # map of Certificate Extension OIDs to Extensions
certificateExtensionsMap = { _certificateExtensionsMapUpdate = {
id_ce_authorityKeyIdentifier: AuthorityKeyIdentifier(), id_ce_authorityKeyIdentifier: AuthorityKeyIdentifier(),
id_ce_subjectKeyIdentifier: SubjectKeyIdentifier(), id_ce_subjectKeyIdentifier: SubjectKeyIdentifier(),
id_ce_keyUsage: KeyUsage(), id_ce_keyUsage: KeyUsage(),
id_ce_privateKeyUsagePeriod: PrivateKeyUsagePeriod(), id_ce_privateKeyUsagePeriod: PrivateKeyUsagePeriod(),
id_ce_certificatePolicies: PolicyInformation(), # could be a sequence of concat'ed objects? # TODO
# id_ce_certificatePolicies: PolicyInformation(), # could be a sequence of concat'ed objects?
id_ce_policyMappings: PolicyMappings(), id_ce_policyMappings: PolicyMappings(),
id_ce_subjectAltName: SubjectAltName(), id_ce_subjectAltName: SubjectAltName(),
id_ce_issuerAltName: IssuerAltName(), id_ce_issuerAltName: IssuerAltName(),
@ -1309,3 +1332,6 @@ certificateExtensionsMap = {
id_ce_invalidityDate: useful.GeneralizedTime(), id_ce_invalidityDate: useful.GeneralizedTime(),
id_ce_certificateIssuer: GeneralNames(), id_ce_certificateIssuer: GeneralNames(),
} }
certificateExtensionsMap.update(_certificateExtensionsMapUpdate)

View File

@ -1,8 +1,8 @@
# #
# This file is part of pyasn1-modules software. # This file is part of pyasn1-modules software.
# #
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com> # Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
# License: http://pyasn1.sf.net/license.html # License: http://snmplabs.com/pyasn1/license.html
# #
# X.509 certificate Request Message Format (CRMF) syntax # X.509 certificate Request Message Format (CRMF) syntax
# #
@ -11,8 +11,8 @@
# #
# Sample captures could be obtained with OpenSSL # Sample captures could be obtained with OpenSSL
# #
from pyasn1_modules.rfc2459 import *
from pyasn1_modules import rfc2315 from pyasn1_modules import rfc2315
from pyasn1_modules.rfc2459 import *
MAX = float('inf') MAX = float('inf')

View File

@ -1,8 +1,8 @@
# #
# This file is part of pyasn1-modules software. # This file is part of pyasn1-modules software.
# #
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com> # Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
# License: http://pyasn1.sf.net/license.html # License: http://snmplabs.com/pyasn1/license.html
# #
# OCSP request/response syntax # OCSP request/response syntax
# #
@ -21,7 +21,12 @@
# * dates are left as strings in GeneralizedTime format -- datetime.datetime # * dates are left as strings in GeneralizedTime format -- datetime.datetime
# would be nicer # would be nicer
# #
from pyasn1.type import tag, namedtype, namedval, univ, useful from pyasn1.type import namedtype
from pyasn1.type import namedval
from pyasn1.type import tag
from pyasn1.type import univ
from pyasn1.type import useful
from pyasn1_modules import rfc2459 from pyasn1_modules import rfc2459
@ -124,9 +129,9 @@ class KeyHash(univ.OctetString):
class ResponderID(univ.Choice): class ResponderID(univ.Choice):
componentType = namedtype.NamedTypes( componentType = namedtype.NamedTypes(
namedtype.NamedType('byName', namedtype.NamedType('byName',
rfc2459.Name().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1))), rfc2459.Name().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1))),
namedtype.NamedType('byKey', namedtype.NamedType('byKey',
KeyHash().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 2))) KeyHash().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 2)))
) )

View File

@ -0,0 +1,124 @@
# coding: utf-8
#
# This file is part of pyasn1-modules software.
#
# Created by Joel Johnson with asn1ate tool.
# Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
# License: http://snmplabs.com/pyasn1/license.html
#
# PKCS #10: Certification Request Syntax Specification
#
# ASN.1 source from:
# http://www.ietf.org/rfc/rfc2986.txt
#
from pyasn1.type import univ
from pyasn1.type import char
from pyasn1.type import namedtype
from pyasn1.type import namedval
from pyasn1.type import opentype
from pyasn1.type import tag
from pyasn1.type import constraint
from pyasn1.type import useful
MAX = float('inf')
class AttributeType(univ.ObjectIdentifier):
pass
class AttributeValue(univ.Any):
pass
certificateAttributesMap = {}
class AttributeTypeAndValue(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.NamedType('type', AttributeType()),
namedtype.NamedType(
'value', AttributeValue(),
openType=opentype.OpenType('type', certificateAttributesMap)
)
)
class Attribute(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.NamedType('type', AttributeType()),
namedtype.NamedType('values',
univ.SetOf(componentType=AttributeValue()),
openType=opentype.OpenType('type', certificateAttributesMap))
)
class Attributes(univ.SetOf):
pass
Attributes.componentType = Attribute()
class RelativeDistinguishedName(univ.SetOf):
pass
RelativeDistinguishedName.componentType = AttributeTypeAndValue()
RelativeDistinguishedName.subtypeSpec = constraint.ValueSizeConstraint(1, MAX)
class RDNSequence(univ.SequenceOf):
pass
RDNSequence.componentType = RelativeDistinguishedName()
class Name(univ.Choice):
pass
Name.componentType = namedtype.NamedTypes(
namedtype.NamedType('rdnSequence', RDNSequence())
)
class AlgorithmIdentifier(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.NamedType('algorithm', univ.ObjectIdentifier()),
namedtype.OptionalNamedType('parameters', univ.Any())
)
class SubjectPublicKeyInfo(univ.Sequence):
pass
SubjectPublicKeyInfo.componentType = namedtype.NamedTypes(
namedtype.NamedType('algorithm', AlgorithmIdentifier()),
namedtype.NamedType('subjectPublicKey', univ.BitString())
)
class CertificationRequestInfo(univ.Sequence):
pass
CertificationRequestInfo.componentType = namedtype.NamedTypes(
namedtype.NamedType('version', univ.Integer()),
namedtype.NamedType('subject', Name()),
namedtype.NamedType('subjectPKInfo', SubjectPublicKeyInfo()),
namedtype.NamedType('attributes', Attributes().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0)))
)
class CertificationRequest(univ.Sequence):
pass
CertificationRequest.componentType = namedtype.NamedTypes(
namedtype.NamedType('certificationRequestInfo', CertificationRequestInfo()),
namedtype.NamedType('signatureAlgorithm', AlgorithmIdentifier()),
namedtype.NamedType('signature', univ.BitString())
)

View File

@ -2,11 +2,13 @@
# This file is part of pyasn1-modules. # This file is part of pyasn1-modules.
# #
# Copyright (c) 2017, Danielle Madeley <danielle@madeley.id.au> # Copyright (c) 2017, Danielle Madeley <danielle@madeley.id.au>
# License: http://pyasn1.sf.net/license.html # License: http://snmplabs.com/pyasn1/license.html
# #
# Derived from RFC 3279 # Derived from RFC 3279
# #
from pyasn1.type import univ, char, namedtype, namedval, tag, constraint, useful from pyasn1.type import namedtype
from pyasn1.type import namedval
from pyasn1.type import univ
def _OID(*components): def _OID(*components):

View File

@ -3,8 +3,8 @@
# This file is part of pyasn1-modules software. # This file is part of pyasn1-modules software.
# #
# Created by Stanisław Pitucha with asn1ate tool. # Created by Stanisław Pitucha with asn1ate tool.
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com> # Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
# License: http://pyasn1.sf.net/license.html # License: http://snmplabs.com/pyasn1/license.html
# #
# Internet X.509 Public Key Infrastructure Certificate and Certificate # Internet X.509 Public Key Infrastructure Certificate and Certificate
# Revocation List (CRL) Profile # Revocation List (CRL) Profile
@ -12,7 +12,13 @@
# ASN.1 source from: # ASN.1 source from:
# http://www.ietf.org/rfc/rfc3280.txt # http://www.ietf.org/rfc/rfc3280.txt
# #
from pyasn1.type import univ, char, namedtype, namedval, tag, constraint, useful from pyasn1.type import char
from pyasn1.type import constraint
from pyasn1.type import namedtype
from pyasn1.type import namedval
from pyasn1.type import tag
from pyasn1.type import univ
from pyasn1.type import useful
MAX = float('inf') MAX = float('inf')

View File

@ -3,20 +3,20 @@
# This file is part of pyasn1-modules software. # This file is part of pyasn1-modules software.
# #
# Created by Stanisław Pitucha with asn1ate tool. # Created by Stanisław Pitucha with asn1ate tool.
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com> # Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
# License: http://pyasn1.sf.net/license.html # License: http://snmplabs.com/pyasn1/license.html
# #
# An Internet Attribute Certificate Profile for Authorization # An Internet Attribute Certificate Profile for Authorization
# #
# ASN.1 source from: # ASN.1 source from:
# http://www.ietf.org/rfc/rfc3281.txt # http://www.ietf.org/rfc/rfc3281.txt
# #
from pyasn1.type import univ
from pyasn1.type import char from pyasn1.type import char
from pyasn1.type import constraint
from pyasn1.type import namedtype from pyasn1.type import namedtype
from pyasn1.type import namedval from pyasn1.type import namedval
from pyasn1.type import tag from pyasn1.type import tag
from pyasn1.type import constraint from pyasn1.type import univ
from pyasn1.type import useful from pyasn1.type import useful
from pyasn1_modules import rfc3280 from pyasn1_modules import rfc3280

View File

@ -1,15 +1,18 @@
# #
# This file is part of pyasn1-modules software. # This file is part of pyasn1-modules software.
# #
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com> # Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
# License: http://pyasn1.sf.net/license.html # License: http://snmplabs.com/pyasn1/license.html
# #
# SNMPv3 message syntax # SNMPv3 message syntax
# #
# ASN.1 source from: # ASN.1 source from:
# http://www.ietf.org/rfc/rfc3412.txt # http://www.ietf.org/rfc/rfc3412.txt
# #
from pyasn1.type import univ, namedtype, constraint from pyasn1.type import constraint
from pyasn1.type import namedtype
from pyasn1.type import univ
from pyasn1_modules import rfc1905 from pyasn1_modules import rfc1905

View File

@ -1,15 +1,17 @@
# #
# This file is part of pyasn1-modules software. # This file is part of pyasn1-modules software.
# #
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com> # Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
# License: http://pyasn1.sf.net/license.html # License: http://snmplabs.com/pyasn1/license.html
# #
# SNMPv3 message syntax # SNMPv3 message syntax
# #
# ASN.1 source from: # ASN.1 source from:
# http://www.ietf.org/rfc/rfc3414.txt # http://www.ietf.org/rfc/rfc3414.txt
# #
from pyasn1.type import univ, namedtype, constraint from pyasn1.type import constraint
from pyasn1.type import namedtype
from pyasn1.type import univ
class UsmSecurityParameters(univ.Sequence): class UsmSecurityParameters(univ.Sequence):

View File

@ -1,8 +1,8 @@
# #
# This file is part of pyasn1-modules software. # This file is part of pyasn1-modules software.
# #
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com> # Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
# License: http://pyasn1.sf.net/license.html # License: http://snmplabs.com/pyasn1/license.html
# #
# PKCS#1 syntax # PKCS#1 syntax
# #
@ -11,7 +11,9 @@
# #
# Sample captures could be obtained with "openssl genrsa" command # Sample captures could be obtained with "openssl genrsa" command
# #
from pyasn1.type import constraint, namedval from pyasn1.type import constraint
from pyasn1.type import namedval
from pyasn1_modules.rfc2437 import * from pyasn1_modules.rfc2437 import *

View File

@ -3,15 +3,20 @@
# This file is part of pyasn1-modules software. # This file is part of pyasn1-modules software.
# #
# Created by Stanisław Pitucha with asn1ate tool. # Created by Stanisław Pitucha with asn1ate tool.
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com> # Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
# License: http://pyasn1.sf.net/license.html # License: http://snmplabs.com/pyasn1/license.html
# #
# Cryptographic Message Syntax (CMS) # Cryptographic Message Syntax (CMS)
# #
# ASN.1 source from: # ASN.1 source from:
# http://www.ietf.org/rfc/rfc3852.txt # http://www.ietf.org/rfc/rfc3852.txt
# #
from pyasn1.type import univ, namedtype, namedval, tag, constraint, useful from pyasn1.type import constraint
from pyasn1.type import namedtype
from pyasn1.type import namedval
from pyasn1.type import tag
from pyasn1.type import univ
from pyasn1.type import useful
from pyasn1_modules import rfc3280 from pyasn1_modules import rfc3280
from pyasn1_modules import rfc3281 from pyasn1_modules import rfc3281

View File

@ -1,15 +1,24 @@
# #
# This file is part of pyasn1-modules software. # This file is part of pyasn1-modules software.
# #
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com> # Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
# License: http://pyasn1.sf.net/license.html # License: http://snmplabs.com/pyasn1/license.html
# #
# Certificate Management Protocol structures as per RFC4210 # Certificate Management Protocol structures as per RFC4210
# #
# Based on Alex Railean's work # Based on Alex Railean's work
# #
from pyasn1.type import tag, namedtype, namedval, univ, constraint, char, useful from pyasn1.type import char
from pyasn1_modules import rfc2459, rfc2511, rfc2314 from pyasn1.type import constraint
from pyasn1.type import namedtype
from pyasn1.type import namedval
from pyasn1.type import tag
from pyasn1.type import univ
from pyasn1.type import useful
from pyasn1_modules import rfc2314
from pyasn1_modules import rfc2459
from pyasn1_modules import rfc2511
MAX = float('inf') MAX = float('inf')

View File

@ -3,8 +3,8 @@
# This file is part of pyasn1-modules software. # This file is part of pyasn1-modules software.
# #
# Created by Stanisław Pitucha with asn1ate tool. # Created by Stanisław Pitucha with asn1ate tool.
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com> # Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
# License: http://pyasn1.sf.net/license.html # License: http://snmplabs.com/pyasn1/license.html
# #
# Internet X.509 Public Key Infrastructure Certificate Request # Internet X.509 Public Key Infrastructure Certificate Request
# Message Format (CRMF) # Message Format (CRMF)
@ -12,7 +12,12 @@
# ASN.1 source from: # ASN.1 source from:
# http://www.ietf.org/rfc/rfc4211.txt # http://www.ietf.org/rfc/rfc4211.txt
# #
from pyasn1.type import univ, char, namedtype, namedval, tag, constraint from pyasn1.type import char
from pyasn1.type import constraint
from pyasn1.type import namedtype
from pyasn1.type import namedval
from pyasn1.type import tag
from pyasn1.type import univ
from pyasn1_modules import rfc3280 from pyasn1_modules import rfc3280
from pyasn1_modules import rfc3852 from pyasn1_modules import rfc3852

View File

@ -1,8 +1,8 @@
# #
# This file is part of pyasn1-modules software. # This file is part of pyasn1-modules software.
# #
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com> # Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
# License: http://pyasn1.sf.net/license.html # License: http://snmplabs.com/pyasn1/license.html
# #
# PKCS#8 syntax # PKCS#8 syntax
# #
@ -11,8 +11,8 @@
# #
# Sample captures could be obtained with "openssl pkcs8 -topk8" command # Sample captures could be obtained with "openssl pkcs8 -topk8" command
# #
from pyasn1_modules.rfc2459 import *
from pyasn1_modules import rfc2251 from pyasn1_modules import rfc2251
from pyasn1_modules.rfc2459 import *
class KeyEncryptionAlgorithms(AlgorithmIdentifier): class KeyEncryptionAlgorithms(AlgorithmIdentifier):

View File

@ -3,8 +3,8 @@
# This file is part of pyasn1-modules software. # This file is part of pyasn1-modules software.
# #
# Created by Stanisław Pitucha with asn1ate tool. # Created by Stanisław Pitucha with asn1ate tool.
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com> # Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
# License: http://pyasn1.sf.net/license.html # License: http://snmplabs.com/pyasn1/license.html
# #
# Internet X.509 Public Key Infrastructure Certificate and Certificate # Internet X.509 Public Key Infrastructure Certificate and Certificate
# Revocation List (CRL) Profile # Revocation List (CRL) Profile
@ -12,16 +12,18 @@
# ASN.1 source from: # ASN.1 source from:
# http://www.ietf.org/rfc/rfc5280.txt # http://www.ietf.org/rfc/rfc5280.txt
# #
from pyasn1.type import univ
from pyasn1.type import char from pyasn1.type import char
from pyasn1.type import constraint
from pyasn1.type import namedtype from pyasn1.type import namedtype
from pyasn1.type import namedval from pyasn1.type import namedval
from pyasn1.type import opentype
from pyasn1.type import tag from pyasn1.type import tag
from pyasn1.type import constraint from pyasn1.type import univ
from pyasn1.type import useful from pyasn1.type import useful
MAX = float('inf') MAX = float('inf')
def _buildOid(*components): def _buildOid(*components):
output = [] output = []
for x in tuple(components): for x in tuple(components):
@ -279,13 +281,10 @@ class CertificateSerialNumber(univ.Integer):
class AlgorithmIdentifier(univ.Sequence): class AlgorithmIdentifier(univ.Sequence):
pass componentType = namedtype.NamedTypes(
namedtype.NamedType('algorithm', univ.ObjectIdentifier()),
namedtype.OptionalNamedType('parameters', univ.Any())
AlgorithmIdentifier.componentType = namedtype.NamedTypes( )
namedtype.NamedType('algorithm', univ.ObjectIdentifier()),
namedtype.OptionalNamedType('parameters', univ.Any())
)
class Time(univ.Choice): class Time(univ.Choice):
@ -302,14 +301,17 @@ class AttributeValue(univ.Any):
pass pass
certificateAttributesMap = {}
class AttributeTypeAndValue(univ.Sequence): class AttributeTypeAndValue(univ.Sequence):
pass componentType = namedtype.NamedTypes(
namedtype.NamedType('type', AttributeType()),
namedtype.NamedType(
AttributeTypeAndValue.componentType = namedtype.NamedTypes( 'value', AttributeValue(),
namedtype.NamedType('type', AttributeType()), openType=opentype.OpenType('type', certificateAttributesMap)
namedtype.NamedType('value', AttributeValue()) )
) )
class RelativeDistinguishedName(univ.SetOf): class RelativeDistinguishedName(univ.SetOf):
@ -379,18 +381,21 @@ class PhysicalDeliveryOfficeName(PDSParameter):
ub_extension_attributes = univ.Integer(256) ub_extension_attributes = univ.Integer(256)
certificateExtensionsMap = {
}
class ExtensionAttribute(univ.Sequence): class ExtensionAttribute(univ.Sequence):
pass componentType = namedtype.NamedTypes(
namedtype.NamedType(
'extension-attribute-type',
ExtensionAttribute.componentType = namedtype.NamedTypes( univ.Integer().subtype(subtypeSpec=constraint.ValueRangeConstraint(0, ub_extension_attributes)).subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))),
namedtype.NamedType('extension-attribute-type', univ.Integer().subtype( namedtype.NamedType(
subtypeSpec=constraint.ValueRangeConstraint(0, ub_extension_attributes)).subtype( 'extension-attribute-value',
implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))), univ.Any().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1)),
namedtype.NamedType('extension-attribute-value', openType=opentype.OpenType('type', certificateExtensionsMap))
univ.Any().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1))) )
)
id_qt = _buildOid(id_pkix, 2) id_qt = _buildOid(id_pkix, 2)
@ -737,13 +742,12 @@ X520SerialNumber.subtypeSpec = constraint.ValueSizeConstraint(1, ub_serial_numbe
class Attribute(univ.Sequence): class Attribute(univ.Sequence):
pass componentType = namedtype.NamedTypes(
namedtype.NamedType('type', AttributeType()),
namedtype.NamedType('values',
Attribute.componentType = namedtype.NamedTypes( univ.SetOf(componentType=AttributeValue()),
namedtype.NamedType('type', AttributeType()), openType=opentype.OpenType('type', certificateAttributesMap))
namedtype.NamedType('values', univ.SetOf(componentType=AttributeValue())) )
)
ub_common_name = univ.Integer(64) ub_common_name = univ.Integer(64)
@ -1066,14 +1070,20 @@ PrivateKeyUsagePeriod.componentType = namedtype.NamedTypes(
) )
anotherNameMap = {
}
class AnotherName(univ.Sequence): class AnotherName(univ.Sequence):
pass componentType = namedtype.NamedTypes(
namedtype.NamedType('type-id', univ.ObjectIdentifier()),
namedtype.NamedType(
AnotherName.componentType = namedtype.NamedTypes( 'value',
namedtype.NamedType('type-id', univ.ObjectIdentifier()), univ.Any().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0)),
namedtype.NamedType('value', univ.Any().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))) openType=opentype.OpenType('type-id', anotherNameMap)
) )
)
class EDIPartyName(univ.Sequence): class EDIPartyName(univ.Sequence):
@ -1311,14 +1321,19 @@ class PolicyQualifierId(univ.ObjectIdentifier):
pass pass
policyQualifierInfoMap = {
}
class PolicyQualifierInfo(univ.Sequence): class PolicyQualifierInfo(univ.Sequence):
pass componentType = namedtype.NamedTypes(
namedtype.NamedType('policyQualifierId', PolicyQualifierId()),
namedtype.NamedType(
PolicyQualifierInfo.componentType = namedtype.NamedTypes( 'qualifier', univ.Any(),
namedtype.NamedType('policyQualifierId', PolicyQualifierId()), openType=opentype.OpenType('policyQualifierId', policyQualifierInfoMap)
namedtype.NamedType('qualifier', univ.Any()) )
) )
class CertPolicyId(univ.ObjectIdentifier): class CertPolicyId(univ.ObjectIdentifier):
@ -1549,7 +1564,7 @@ id_ce_inhibitAnyPolicy = _buildOid(id_ce, 54)
# map of AttributeType -> AttributeValue # map of AttributeType -> AttributeValue
certificateAttributesMap = { _certificateAttributesMapUpdate = {
id_at_name: X520name(), id_at_name: X520name(),
id_at_surname: X520name(), id_at_surname: X520name(),
id_at_givenName: X520name(), id_at_givenName: X520name(),
@ -1569,9 +1584,12 @@ certificateAttributesMap = {
id_emailAddress: EmailAddress(), id_emailAddress: EmailAddress(),
} }
certificateAttributesMap.update(_certificateAttributesMapUpdate)
# map of Certificate Extension OIDs to Extensions # map of Certificate Extension OIDs to Extensions
certificateExtensionsMap = { _certificateExtensionsMap = {
id_ce_authorityKeyIdentifier: AuthorityKeyIdentifier(), id_ce_authorityKeyIdentifier: AuthorityKeyIdentifier(),
id_ce_subjectKeyIdentifier: SubjectKeyIdentifier(), id_ce_subjectKeyIdentifier: SubjectKeyIdentifier(),
id_ce_keyUsage: KeyUsage(), id_ce_keyUsage: KeyUsage(),
@ -1595,3 +1613,5 @@ certificateExtensionsMap = {
id_ce_invalidityDate: useful.GeneralizedTime(), id_ce_invalidityDate: useful.GeneralizedTime(),
id_ce_certificateIssuer: GeneralNames(), id_ce_certificateIssuer: GeneralNames(),
} }
certificateExtensionsMap.update(_certificateExtensionsMap)

View File

@ -3,8 +3,8 @@
# This file is part of pyasn1-modules software. # This file is part of pyasn1-modules software.
# #
# Created by Stanisław Pitucha with asn1ate tool. # Created by Stanisław Pitucha with asn1ate tool.
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com> # Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
# License: http://pyasn1.sf.net/license.html # License: http://snmplabs.com/pyasn1/license.html
# #
# Cryptographic Message Syntax (CMS) # Cryptographic Message Syntax (CMS)
# #

View File

@ -3,15 +3,21 @@
# This file is part of pyasn1-modules software. # This file is part of pyasn1-modules software.
# #
# Created by Stanisław Pitucha with asn1ate tool. # Created by Stanisław Pitucha with asn1ate tool.
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com> # Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
# License: http://pyasn1.sf.net/license.html # License: http://snmplabs.com/pyasn1/license.html
# #
# Certificate Management over CMS (CMC) Updates # Certificate Management over CMS (CMC) Updates
# #
# ASN.1 source from: # ASN.1 source from:
# http://www.ietf.org/rfc/rfc6402.txt # http://www.ietf.org/rfc/rfc6402.txt
# #
from pyasn1.type import univ, char, namedtype, namedval, tag, constraint, useful from pyasn1.type import char
from pyasn1.type import constraint
from pyasn1.type import namedtype
from pyasn1.type import namedval
from pyasn1.type import tag
from pyasn1.type import univ
from pyasn1.type import useful
from pyasn1_modules import rfc4211 from pyasn1_modules import rfc4211
from pyasn1_modules import rfc5280 from pyasn1_modules import rfc5280