Version 0.3.5, Rev830, Full Tor mode support with hidden services, Onion stats in Sidebar, GeoDB download fix using Tor, Gray out disabled sites in Stats page, Tor hidden service status in stat page, Benchmark sha256, Skyts tracker out expodie in, 2 new tracker using ZeroNet protocol, Keep SSL cert option between restarts, SSL Certificate pinning support for connections, Site lock support for connections, Certificate pinned connections using implicit SSL, Flood protection whitelist support, Foreign keys support for DB layer, Not support for SQL query helper, 0 length file get bugfix, Pex onion address support, Faster port testing, Faster uPnP port opening, Need connections more often on owned sites, Delay ZeroHello startup message if port check or Tor manager not ready yet, Use lockfiles to avoid double start, Save original socket on proxy monkey patching to get ability to connect localhost directly, Handle atomic write errors, Broken gevent https workaround helper, Rsa crypt functions, Plugin to Bootstrap using ZeroNet protocol
This commit is contained in:
parent
c9578e9037
commit
e9d2cdfd37
99 changed files with 9476 additions and 267 deletions
278
src/lib/pyasn1/CHANGES
Normal file
278
src/lib/pyasn1/CHANGES
Normal file
|
@ -0,0 +1,278 @@
|
|||
Revision 0.1.7
|
||||
--------------
|
||||
|
||||
- License updated to vanilla BSD 2-Clause to ease package use
|
||||
(http://opensource.org/licenses/BSD-2-Clause).
|
||||
- Test suite made discoverable by unittest/unittest2 discovery feature.
|
||||
- Fix to decoder working on indefinite length substrate -- end-of-octets
|
||||
marker is now detected by both tag and value. Otherwise zero values may
|
||||
interfere with end-of-octets marker.
|
||||
- Fix to decoder to fail in cases where tagFormat indicates inappropriate
|
||||
format for the type (e.g. BOOLEAN is always PRIMITIVE, SET is always
|
||||
CONSTRUCTED and OCTET STRING is either of the two)
|
||||
- Fix to REAL type encoder to force primitive encoding form encoding.
|
||||
- Fix to CHOICE decoder to handle explicitly tagged, indefinite length
|
||||
mode encoding
|
||||
- Fix to REAL type decoder to handle negative REAL values correctly. Test
|
||||
case added.
|
||||
|
||||
Revision 0.1.6
|
||||
--------------
|
||||
|
||||
- The compact (valueless) way of encoding zero INTEGERs introduced in
|
||||
0.1.5 seems to fail miserably as the world is filled with broken
|
||||
BER decoders. So we had to back off the *encoder* for a while.
|
||||
There's still the IntegerEncoder.supportCompactZero flag which
|
||||
enables compact encoding form whenever it evaluates to True.
|
||||
- Report package version on debugging code initialization.
|
||||
|
||||
Revision 0.1.5
|
||||
--------------
|
||||
|
||||
- Documentation updated and split into chapters to better match
|
||||
web-site contents.
|
||||
- Make prettyPrint() working for non-initialized pyasn1 data objects. It
|
||||
used to throw an exception.
|
||||
- Fix to encoder to produce empty-payload INTEGER values for zeros
|
||||
- Fix to decoder to support empty-payload INTEGER and REAL values
|
||||
- Fix to unit test suites imports to be able to run each from
|
||||
their current directory
|
||||
|
||||
Revision 0.1.4
|
||||
--------------
|
||||
|
||||
- Built-in codec debugging facility added
|
||||
- Added some more checks to ObjectIdentifier BER encoder catching
|
||||
posible 2^8 overflow condition by two leading sub-OIDs
|
||||
- Implementations overriding the AbstractDecoder.valueDecoder method
|
||||
changed to return the rest of substrate behind the item being processed
|
||||
rather than the unprocessed substrate within the item (which is usually
|
||||
empty).
|
||||
- Decoder's recursiveFlag feature generalized as a user callback function
|
||||
which is passed an uninitialized object recovered from substrate and
|
||||
its uninterpreted payload.
|
||||
- Catch inappropriate substrate type passed to decoder.
|
||||
- Expose tagMap/typeMap/Decoder objects at DER decoder to uniform API.
|
||||
- Obsolete __init__.MajorVersionId replaced with __init__.__version__
|
||||
which is now in-sync with distutils.
|
||||
- Package classifiers updated.
|
||||
- The __init__.py's made non-empty (rumors are that they may be optimized
|
||||
out by package managers).
|
||||
- Bail out gracefully whenever Python version is older than 2.4.
|
||||
- Fix to Real codec exponent encoding (should be in 2's complement form),
|
||||
some more test cases added.
|
||||
- Fix in Boolean truth testing built-in methods
|
||||
- Fix to substrate underrun error handling at ObjectIdentifier BER decoder
|
||||
- Fix to BER Boolean decoder that allows other pre-computed
|
||||
values besides 0 and 1
|
||||
- Fix to leading 0x80 octet handling in DER/CER/DER ObjectIdentifier decoder.
|
||||
See http://www.cosic.esat.kuleuven.be/publications/article-1432.pdf
|
||||
|
||||
Revision 0.1.3
|
||||
--------------
|
||||
|
||||
- Include class name into asn1 value constraint violation exception.
|
||||
- Fix to OctetString.prettyOut() method that looses leading zero when
|
||||
building hex string.
|
||||
|
||||
Revision 0.1.2
|
||||
--------------
|
||||
|
||||
- Fix to __long__() to actually return longs on py2k
|
||||
- Fix to OctetString.__str__() workings of a non-initialized object.
|
||||
- Fix to quote initializer of OctetString.__repr__()
|
||||
- Minor fix towards ObjectIdentifier.prettyIn() reliability
|
||||
- ObjectIdentifier.__str__() is aliased to prettyPrint()
|
||||
- Exlicit repr() calls replaced with '%r'
|
||||
|
||||
Revision 0.1.1
|
||||
--------------
|
||||
|
||||
- Hex/bin string initializer to OctetString object reworked
|
||||
(in a backward-incompatible manner)
|
||||
- Fixed float() infinity compatibility issue (affects 2.5 and earlier)
|
||||
- Fixed a bug/typo at Boolean CER encoder.
|
||||
- Major overhawl for Python 2.4 -- 3.2 compatibility:
|
||||
+ get rid of old-style types
|
||||
+ drop string module usage
|
||||
+ switch to rich comparation
|
||||
+ drop explicit long integer type use
|
||||
+ map()/filter() replaced with list comprehension
|
||||
+ apply() replaced with */**args
|
||||
+ switched to use 'key' sort() callback function
|
||||
+ support both __nonzero__() and __bool__() methods
|
||||
+ modified not to use py3k-incompatible exception syntax
|
||||
+ getslice() operator fully replaced with getitem()
|
||||
+ dictionary operations made 2K/3K compatible
|
||||
+ base type for encoding substrate and OctetString-based types
|
||||
is now 'bytes' when running py3k and 'str' otherwise
|
||||
+ OctetString and derivatives now unicode compliant.
|
||||
+ OctetString now supports two python-neutral getters: asOcts() & asInts()
|
||||
+ print OctetString content in hex whenever it is not printable otherwise
|
||||
+ in test suite, implicit relative import replaced with the absolute one
|
||||
+ in test suite, string constants replaced with numerics
|
||||
|
||||
Revision 0.0.13
|
||||
---------------
|
||||
|
||||
- Fix to base10 normalization function that loops on univ.Real(0)
|
||||
|
||||
Revision 0.0.13b
|
||||
----------------
|
||||
|
||||
- ASN.1 Real type is now supported properly.
|
||||
- Objects of Constructed types now support __setitem__()
|
||||
- Set/Sequence objects can now be addressed by their field names (string index)
|
||||
and position (integer index).
|
||||
- Typo fix to ber.SetDecoder code that prevented guided decoding operation.
|
||||
- Fix to explicitly tagged items decoding support.
|
||||
- Fix to OctetString.prettyPrint() to better handle non-printable content.
|
||||
- Fix to repr() workings of Choice objects.
|
||||
|
||||
Revision 0.0.13a
|
||||
----------------
|
||||
|
||||
- Major codec re-design.
|
||||
- Documentation significantly improved.
|
||||
- ASN.1 Any type is now supported.
|
||||
- All example ASN.1 modules moved to separate pyasn1-modules package.
|
||||
- Fix to initial sub-OID overflow condition detection an encoder.
|
||||
- BitString initialization value verification improved.
|
||||
- The Set/Sequence.getNameByPosition() method implemented.
|
||||
- Fix to proper behaviour of PermittedAlphabetConstraint object.
|
||||
- Fix to improper Boolean substrate handling at CER/DER decoders.
|
||||
- Changes towards performance improvement:
|
||||
+ all dict.has_key() & dict.get() invocations replaced with modern syntax
|
||||
(this breaks compatibility with Python 2.1 and older).
|
||||
+ tag and tagset caches introduced to decoder
|
||||
+ decoder code improved to prevent unnecessary pyasn1 objects creation
|
||||
+ allow disabling components verification when setting components to
|
||||
structured types, this is used by decoder whilst running in guided mode.
|
||||
+ BER decoder for integer values now looks up a small set of pre-computed
|
||||
substrate values to save on decoding.
|
||||
+ a few pre-computed values configured to ObjectIdentifier BER encoder.
|
||||
+ ChoiceDecoder split-off SequenceOf one to save on unnecessary checks.
|
||||
+ replace slow hasattr()/getattr() calls with isinstance() introspection.
|
||||
+ track the number of initialized components of Constructed types to save
|
||||
on default/optional components initialization.
|
||||
+ added a shortcut ObjectIdentifier.asTuple() to be used instead of
|
||||
__getitem__() in hotspots.
|
||||
+ use Tag.asTuple() and pure integers at tag encoder.
|
||||
+ introduce and use in decoder the baseTagSet attribute of the built-in
|
||||
ASN.1 types.
|
||||
|
||||
Revision 0.0.12a
|
||||
----------------
|
||||
|
||||
- The individual tag/length/value processing methods of
|
||||
encoder.AbstractItemEncoder renamed (leading underscore stripped)
|
||||
to promote overloading in cases where partial substrate processing
|
||||
is required.
|
||||
- The ocsp.py, ldap.py example scripts added.
|
||||
- Fix to univ.ObjectIdentifier input value handler to disallow negative
|
||||
sub-IDs.
|
||||
|
||||
Revision 0.0.11a
|
||||
----------------
|
||||
|
||||
- Decoder can now treat values of unknown types as opaque OctetString.
|
||||
- Fix to Set/SetOf type decoder to handle uninitialized scalar SetOf
|
||||
components correctly.
|
||||
|
||||
Revision 0.0.10a
|
||||
----------------
|
||||
|
||||
- API versioning mechanics retired (pyasn1.v1 -> pyasn1) what makes
|
||||
it possible to zip-import pyasn1 sources (used by egg and py2exe).
|
||||
|
||||
Revision 0.0.9a
|
||||
---------------
|
||||
|
||||
- Allow any non-zero values in Boolean type BER decoder, as it's in
|
||||
accordnance with the standard.
|
||||
|
||||
Revision 0.0.8a
|
||||
---------------
|
||||
|
||||
- Integer.__index__() now supported (for Python 2.5+).
|
||||
- Fix to empty value encoding in BitString encoder, test case added.
|
||||
- Fix to SequenceOf decoder that prevents it skipping possible Choice
|
||||
typed inner component.
|
||||
- Choice.getName() method added for getting currently set component
|
||||
name.
|
||||
- OctetsString.prettyPrint() does a single str() against its value
|
||||
eliminating an extra quotes.
|
||||
|
||||
Revision 0.0.7a
|
||||
---------------
|
||||
|
||||
- Large tags (>31) now supported by codecs.
|
||||
- Fix to encoder to properly handle explicitly tagged untagged items.
|
||||
- All possible value lengths (up to 256^126) now supported by encoders.
|
||||
- Fix to Tag class constructor to prevent negative IDs.
|
||||
|
||||
Revision 0.0.6a
|
||||
---------------
|
||||
|
||||
- Make use of setuptools.
|
||||
- Constraints derivation verification (isSuperTypeOf()/isSubTypeOf()) fixed.
|
||||
- Fix to constraints comparation logic -- can't cmp() hash values as it
|
||||
may cause false positives due to hash conflicts.
|
||||
|
||||
Revision 0.0.5a
|
||||
---------------
|
||||
|
||||
- Integer BER codec reworked fixing negative values encoding bug.
|
||||
- clone() and subtype() methods of Constructed ASN.1 classes now
|
||||
accept optional cloneValueFlag flag which controls original value
|
||||
inheritance. The default is *not* to inherit original value for
|
||||
performance reasons (this may affect backward compatibility).
|
||||
Performance penalty may be huge on deeply nested Constructed objects
|
||||
re-creation.
|
||||
- Base ASN.1 types (pyasn1.type.univ.*) do not have default values
|
||||
anymore. They remain uninitialized acting as ASN.1 types. In
|
||||
this model, initialized ASN.1 types represent either types with
|
||||
default value installed or a type instance.
|
||||
- Decoders' prototypes are now class instances rather than classes.
|
||||
This is to simplify initial value installation to decoder's
|
||||
prototype value.
|
||||
- Bugfix to BitString BER decoder (trailing bits not regarded).
|
||||
- Bugfix to Constraints use as mapping keys.
|
||||
- Bugfix to Integer & BitString clone() methods
|
||||
- Bugix to the way to distinguish Set from SetOf at CER/DER SetOfEncoder
|
||||
- Adjustments to make it running on Python 1.5.
|
||||
- In tests, substrate constants converted from hex escaped literals into
|
||||
octals to overcome indefinite hex width issue occuring in young Python.
|
||||
- Minor performance optimization of TagSet.isSuperTagSetOf() method
|
||||
- examples/sshkey.py added
|
||||
|
||||
Revision 0.0.4a
|
||||
---------------
|
||||
|
||||
* Asn1ItemBase.prettyPrinter() -> *.prettyPrint()
|
||||
|
||||
Revision 0.0.3a
|
||||
---------------
|
||||
|
||||
* Simple ASN1 objects now hash to their Python value and don't
|
||||
depend upon tag/constraints/etc.
|
||||
* prettyIn & prettyOut methods of SimplleAsn1Object become public
|
||||
* many syntax fixes
|
||||
|
||||
Revision 0.0.2a
|
||||
---------------
|
||||
|
||||
* ConstraintsIntersection.isSuperTypeOf() and
|
||||
ConstraintsIntersection.hasConstraint() implemented
|
||||
* Bugfix to NamedValues initialization code
|
||||
* +/- operators added to NamedValues objects
|
||||
* Integer.__abs__() & Integer.subtype() added
|
||||
* ObjectIdentifier.prettyOut() fixes
|
||||
* Allow subclass components at SequenceAndSetBase
|
||||
* AbstractConstraint.__cmp__() dropped
|
||||
* error.Asn1Error replaced with error.PyAsn1Error
|
||||
|
||||
Revision 0.0.1a
|
||||
---------------
|
||||
|
||||
* Initial public alpha release
|
24
src/lib/pyasn1/LICENSE
Normal file
24
src/lib/pyasn1/LICENSE
Normal file
|
@ -0,0 +1,24 @@
|
|||
Copyright (c) 2005-2013, Ilya Etingof <ilya@glas.net>
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
26
src/lib/pyasn1/PKG-INFO
Normal file
26
src/lib/pyasn1/PKG-INFO
Normal file
|
@ -0,0 +1,26 @@
|
|||
Metadata-Version: 1.0
|
||||
Name: pyasn1
|
||||
Version: 0.1.7
|
||||
Summary: ASN.1 types and codecs
|
||||
Home-page: http://sourceforge.net/projects/pyasn1/
|
||||
Author: Ilya Etingof <ilya@glas.net>
|
||||
Author-email: ilya@glas.net
|
||||
License: BSD
|
||||
Description: A pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208).
|
||||
Platform: any
|
||||
Classifier: Development Status :: 5 - Production/Stable
|
||||
Classifier: Environment :: Console
|
||||
Classifier: Intended Audience :: Developers
|
||||
Classifier: Intended Audience :: Education
|
||||
Classifier: Intended Audience :: Information Technology
|
||||
Classifier: Intended Audience :: Science/Research
|
||||
Classifier: Intended Audience :: System Administrators
|
||||
Classifier: Intended Audience :: Telecommunications Industry
|
||||
Classifier: License :: OSI Approved :: BSD License
|
||||
Classifier: Natural Language :: English
|
||||
Classifier: Operating System :: OS Independent
|
||||
Classifier: Programming Language :: Python :: 2
|
||||
Classifier: Programming Language :: Python :: 3
|
||||
Classifier: Topic :: Communications
|
||||
Classifier: Topic :: Security :: Cryptography
|
||||
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
68
src/lib/pyasn1/README
Normal file
68
src/lib/pyasn1/README
Normal file
|
@ -0,0 +1,68 @@
|
|||
|
||||
ASN.1 library for Python
|
||||
------------------------
|
||||
|
||||
This is an implementation of ASN.1 types and codecs in Python programming
|
||||
language. It has been first written to support particular protocol (SNMP)
|
||||
but then generalized to be suitable for a wide range of protocols
|
||||
based on ASN.1 specification.
|
||||
|
||||
FEATURES
|
||||
--------
|
||||
|
||||
* Generic implementation of ASN.1 types (X.208)
|
||||
* Fully standard compliant BER/CER/DER codecs
|
||||
* 100% Python, works with Python 2.4 up to Python 3.3 (beta 1)
|
||||
* MT-safe
|
||||
|
||||
MISFEATURES
|
||||
-----------
|
||||
|
||||
* No ASN.1 compiler (by-hand ASN.1 spec compilation into Python code required)
|
||||
* Codecs are not restartable
|
||||
|
||||
INSTALLATION
|
||||
------------
|
||||
|
||||
The pyasn1 package uses setuptools/distutils for installation. Thus do
|
||||
either:
|
||||
|
||||
$ easy_install pyasn1
|
||||
|
||||
or
|
||||
|
||||
$ tar zxf pyasn1-0.1.3.tar.gz
|
||||
$ cd pyasn1-0.1.3
|
||||
$ python setup.py install
|
||||
$ cd test
|
||||
$ python suite.py # run unit tests
|
||||
|
||||
OPERATION
|
||||
---------
|
||||
|
||||
Perhaps a typical use would involve [by-hand] compilation of your ASN.1
|
||||
specification into pyasn1-backed Python code at your application.
|
||||
|
||||
For more information on pyasn1 APIs, please, refer to the
|
||||
doc/pyasn1-tutorial.html file in the distribution.
|
||||
|
||||
Also refer to example modules. Take a look at pyasn1-modules package -- maybe
|
||||
it already holds something useful to you.
|
||||
|
||||
AVAILABILITY
|
||||
------------
|
||||
|
||||
The pyasn1 package is distributed under terms and conditions of BSD-style
|
||||
license. See LICENSE file in the distribution. Source code is freely
|
||||
available from:
|
||||
|
||||
http://pyasn1.sf.net
|
||||
|
||||
|
||||
FEEDBACK
|
||||
--------
|
||||
|
||||
Please, send your comments and fixes to mailing lists at project web site.
|
||||
|
||||
=-=-=
|
||||
mailto: ilya@glas.net
|
4
src/lib/pyasn1/THANKS
Normal file
4
src/lib/pyasn1/THANKS
Normal file
|
@ -0,0 +1,4 @@
|
|||
Denis S. Otkidach
|
||||
Gregory Golberg
|
||||
Bud P. Bruegger
|
||||
Jacek Konieczny
|
36
src/lib/pyasn1/TODO
Normal file
36
src/lib/pyasn1/TODO
Normal file
|
@ -0,0 +1,36 @@
|
|||
* Specialize ASN.1 character and useful types
|
||||
* Come up with simpler API for deeply nested constructed objects
|
||||
addressing
|
||||
|
||||
ber.decoder:
|
||||
* suspend codec on underrun error ?
|
||||
* class-static components map (in simple type classes)
|
||||
* present subtypes ?
|
||||
* component presence check wont work at innertypeconst
|
||||
* add the rest of ASN1 types/codecs
|
||||
* type vs value, defaultValue
|
||||
|
||||
ber.encoder:
|
||||
* Asn1Item.clone() / shallowcopy issue
|
||||
* large length encoder?
|
||||
* codec restart
|
||||
* preserve compatible API whenever stateful codec gets implemented
|
||||
* restartable vs incremental
|
||||
* plan: make a stateless univeral decoder, then convert it to restartable
|
||||
then to incremental
|
||||
|
||||
type.useful:
|
||||
* may need to implement prettyIn/Out
|
||||
|
||||
type.char:
|
||||
* may need to implement constraints
|
||||
|
||||
type.univ:
|
||||
* simpler API to constructed objects: value init, recursive
|
||||
|
||||
type.namedtypes
|
||||
* type vs tagset name convention
|
||||
|
||||
general:
|
||||
|
||||
* how untagged TagSet should be initialized?
|
8
src/lib/pyasn1/__init__.py
Normal file
8
src/lib/pyasn1/__init__.py
Normal file
|
@ -0,0 +1,8 @@
|
|||
import sys
|
||||
|
||||
# http://www.python.org/dev/peps/pep-0396/
|
||||
__version__ = '0.1.7'
|
||||
|
||||
if sys.version_info[:2] < (2, 4):
|
||||
raise RuntimeError('PyASN1 requires Python 2.4 or later')
|
||||
|
1
src/lib/pyasn1/codec/__init__.py
Normal file
1
src/lib/pyasn1/codec/__init__.py
Normal file
|
@ -0,0 +1 @@
|
|||
# This file is necessary to make this directory a package.
|
1
src/lib/pyasn1/codec/ber/__init__.py
Normal file
1
src/lib/pyasn1/codec/ber/__init__.py
Normal file
|
@ -0,0 +1 @@
|
|||
# This file is necessary to make this directory a package.
|
808
src/lib/pyasn1/codec/ber/decoder.py
Normal file
808
src/lib/pyasn1/codec/ber/decoder.py
Normal file
|
@ -0,0 +1,808 @@
|
|||
# BER decoder
|
||||
from pyasn1.type import tag, base, univ, char, useful, tagmap
|
||||
from pyasn1.codec.ber import eoo
|
||||
from pyasn1.compat.octets import oct2int, octs2ints, isOctetsType
|
||||
from pyasn1 import debug, error
|
||||
|
||||
class AbstractDecoder:
|
||||
protoComponent = None
|
||||
def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet,
|
||||
length, state, decodeFun, substrateFun):
|
||||
raise error.PyAsn1Error('Decoder not implemented for %s' % (tagSet,))
|
||||
|
||||
def indefLenValueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet,
|
||||
length, state, decodeFun, substrateFun):
|
||||
raise error.PyAsn1Error('Indefinite length mode decoder not implemented for %s' % (tagSet,))
|
||||
|
||||
class AbstractSimpleDecoder(AbstractDecoder):
|
||||
tagFormats = (tag.tagFormatSimple,)
|
||||
def _createComponent(self, asn1Spec, tagSet, value=None):
|
||||
if tagSet[0][1] not in self.tagFormats:
|
||||
raise error.PyAsn1Error('Invalid tag format %r for %r' % (tagSet[0], self.protoComponent,))
|
||||
if asn1Spec is None:
|
||||
return self.protoComponent.clone(value, tagSet)
|
||||
elif value is None:
|
||||
return asn1Spec
|
||||
else:
|
||||
return asn1Spec.clone(value)
|
||||
|
||||
class AbstractConstructedDecoder(AbstractDecoder):
|
||||
tagFormats = (tag.tagFormatConstructed,)
|
||||
def _createComponent(self, asn1Spec, tagSet, value=None):
|
||||
if tagSet[0][1] not in self.tagFormats:
|
||||
raise error.PyAsn1Error('Invalid tag format %r for %r' % (tagSet[0], self.protoComponent,))
|
||||
if asn1Spec is None:
|
||||
return self.protoComponent.clone(tagSet)
|
||||
else:
|
||||
return asn1Spec.clone()
|
||||
|
||||
class EndOfOctetsDecoder(AbstractSimpleDecoder):
|
||||
def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet,
|
||||
length, state, decodeFun, substrateFun):
|
||||
return eoo.endOfOctets, substrate[length:]
|
||||
|
||||
class ExplicitTagDecoder(AbstractSimpleDecoder):
|
||||
protoComponent = univ.Any('')
|
||||
tagFormats = (tag.tagFormatConstructed,)
|
||||
def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet,
|
||||
length, state, decodeFun, substrateFun):
|
||||
if substrateFun:
|
||||
return substrateFun(
|
||||
self._createComponent(asn1Spec, tagSet, ''),
|
||||
substrate, length
|
||||
)
|
||||
head, tail = substrate[:length], substrate[length:]
|
||||
value, _ = decodeFun(head, asn1Spec, tagSet, length)
|
||||
return value, tail
|
||||
|
||||
def indefLenValueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet,
|
||||
length, state, decodeFun, substrateFun):
|
||||
if substrateFun:
|
||||
return substrateFun(
|
||||
self._createComponent(asn1Spec, tagSet, ''),
|
||||
substrate, length
|
||||
)
|
||||
value, substrate = decodeFun(substrate, asn1Spec, tagSet, length)
|
||||
terminator, substrate = decodeFun(substrate)
|
||||
if eoo.endOfOctets.isSameTypeWith(terminator) and \
|
||||
terminator == eoo.endOfOctets:
|
||||
return value, substrate
|
||||
else:
|
||||
raise error.PyAsn1Error('Missing end-of-octets terminator')
|
||||
|
||||
explicitTagDecoder = ExplicitTagDecoder()
|
||||
|
||||
class IntegerDecoder(AbstractSimpleDecoder):
|
||||
protoComponent = univ.Integer(0)
|
||||
precomputedValues = {
|
||||
'\x00': 0,
|
||||
'\x01': 1,
|
||||
'\x02': 2,
|
||||
'\x03': 3,
|
||||
'\x04': 4,
|
||||
'\x05': 5,
|
||||
'\x06': 6,
|
||||
'\x07': 7,
|
||||
'\x08': 8,
|
||||
'\x09': 9,
|
||||
'\xff': -1,
|
||||
'\xfe': -2,
|
||||
'\xfd': -3,
|
||||
'\xfc': -4,
|
||||
'\xfb': -5
|
||||
}
|
||||
|
||||
def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, length,
|
||||
state, decodeFun, substrateFun):
|
||||
head, tail = substrate[:length], substrate[length:]
|
||||
if not head:
|
||||
return self._createComponent(asn1Spec, tagSet, 0), tail
|
||||
if head in self.precomputedValues:
|
||||
value = self.precomputedValues[head]
|
||||
else:
|
||||
firstOctet = oct2int(head[0])
|
||||
if firstOctet & 0x80:
|
||||
value = -1
|
||||
else:
|
||||
value = 0
|
||||
for octet in head:
|
||||
value = value << 8 | oct2int(octet)
|
||||
return self._createComponent(asn1Spec, tagSet, value), tail
|
||||
|
||||
class BooleanDecoder(IntegerDecoder):
|
||||
protoComponent = univ.Boolean(0)
|
||||
def _createComponent(self, asn1Spec, tagSet, value=None):
|
||||
return IntegerDecoder._createComponent(self, asn1Spec, tagSet, value and 1 or 0)
|
||||
|
||||
class BitStringDecoder(AbstractSimpleDecoder):
|
||||
protoComponent = univ.BitString(())
|
||||
tagFormats = (tag.tagFormatSimple, tag.tagFormatConstructed)
|
||||
def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, length,
|
||||
state, decodeFun, substrateFun):
|
||||
head, tail = substrate[:length], substrate[length:]
|
||||
if tagSet[0][1] == tag.tagFormatSimple: # XXX what tag to check?
|
||||
if not head:
|
||||
raise error.PyAsn1Error('Empty substrate')
|
||||
trailingBits = oct2int(head[0])
|
||||
if trailingBits > 7:
|
||||
raise error.PyAsn1Error(
|
||||
'Trailing bits overflow %s' % trailingBits
|
||||
)
|
||||
head = head[1:]
|
||||
lsb = p = 0; l = len(head)-1; b = ()
|
||||
while p <= l:
|
||||
if p == l:
|
||||
lsb = trailingBits
|
||||
j = 7
|
||||
o = oct2int(head[p])
|
||||
while j >= lsb:
|
||||
b = b + ((o>>j)&0x01,)
|
||||
j = j - 1
|
||||
p = p + 1
|
||||
return self._createComponent(asn1Spec, tagSet, b), tail
|
||||
r = self._createComponent(asn1Spec, tagSet, ())
|
||||
if substrateFun:
|
||||
return substrateFun(r, substrate, length)
|
||||
while head:
|
||||
component, head = decodeFun(head)
|
||||
r = r + component
|
||||
return r, tail
|
||||
|
||||
def indefLenValueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet,
|
||||
length, state, decodeFun, substrateFun):
|
||||
r = self._createComponent(asn1Spec, tagSet, '')
|
||||
if substrateFun:
|
||||
return substrateFun(r, substrate, length)
|
||||
while substrate:
|
||||
component, substrate = decodeFun(substrate)
|
||||
if eoo.endOfOctets.isSameTypeWith(component) and \
|
||||
component == eoo.endOfOctets:
|
||||
break
|
||||
r = r + component
|
||||
else:
|
||||
raise error.SubstrateUnderrunError(
|
||||
'No EOO seen before substrate ends'
|
||||
)
|
||||
return r, substrate
|
||||
|
||||
class OctetStringDecoder(AbstractSimpleDecoder):
|
||||
protoComponent = univ.OctetString('')
|
||||
tagFormats = (tag.tagFormatSimple, tag.tagFormatConstructed)
|
||||
def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, length,
|
||||
state, decodeFun, substrateFun):
|
||||
head, tail = substrate[:length], substrate[length:]
|
||||
if tagSet[0][1] == tag.tagFormatSimple: # XXX what tag to check?
|
||||
return self._createComponent(asn1Spec, tagSet, head), tail
|
||||
r = self._createComponent(asn1Spec, tagSet, '')
|
||||
if substrateFun:
|
||||
return substrateFun(r, substrate, length)
|
||||
while head:
|
||||
component, head = decodeFun(head)
|
||||
r = r + component
|
||||
return r, tail
|
||||
|
||||
def indefLenValueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet,
|
||||
length, state, decodeFun, substrateFun):
|
||||
r = self._createComponent(asn1Spec, tagSet, '')
|
||||
if substrateFun:
|
||||
return substrateFun(r, substrate, length)
|
||||
while substrate:
|
||||
component, substrate = decodeFun(substrate)
|
||||
if eoo.endOfOctets.isSameTypeWith(component) and \
|
||||
component == eoo.endOfOctets:
|
||||
break
|
||||
r = r + component
|
||||
else:
|
||||
raise error.SubstrateUnderrunError(
|
||||
'No EOO seen before substrate ends'
|
||||
)
|
||||
return r, substrate
|
||||
|
||||
class NullDecoder(AbstractSimpleDecoder):
|
||||
protoComponent = univ.Null('')
|
||||
def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet,
|
||||
length, state, decodeFun, substrateFun):
|
||||
head, tail = substrate[:length], substrate[length:]
|
||||
r = self._createComponent(asn1Spec, tagSet)
|
||||
if head:
|
||||
raise error.PyAsn1Error('Unexpected %d-octet substrate for Null' % length)
|
||||
return r, tail
|
||||
|
||||
class ObjectIdentifierDecoder(AbstractSimpleDecoder):
|
||||
protoComponent = univ.ObjectIdentifier(())
|
||||
def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, length,
|
||||
state, decodeFun, substrateFun):
|
||||
head, tail = substrate[:length], substrate[length:]
|
||||
if not head:
|
||||
raise error.PyAsn1Error('Empty substrate')
|
||||
|
||||
# Get the first subid
|
||||
subId = oct2int(head[0])
|
||||
oid = divmod(subId, 40)
|
||||
|
||||
index = 1
|
||||
substrateLen = len(head)
|
||||
while index < substrateLen:
|
||||
subId = oct2int(head[index])
|
||||
index = index + 1
|
||||
if subId == 128:
|
||||
# ASN.1 spec forbids leading zeros (0x80) in sub-ID OID
|
||||
# encoding, tolerating it opens a vulnerability.
|
||||
# See http://www.cosic.esat.kuleuven.be/publications/article-1432.pdf page 7
|
||||
raise error.PyAsn1Error('Invalid leading 0x80 in sub-OID')
|
||||
elif subId > 128:
|
||||
# Construct subid from a number of octets
|
||||
nextSubId = subId
|
||||
subId = 0
|
||||
while nextSubId >= 128:
|
||||
subId = (subId << 7) + (nextSubId & 0x7F)
|
||||
if index >= substrateLen:
|
||||
raise error.SubstrateUnderrunError(
|
||||
'Short substrate for sub-OID past %s' % (oid,)
|
||||
)
|
||||
nextSubId = oct2int(head[index])
|
||||
index = index + 1
|
||||
subId = (subId << 7) + nextSubId
|
||||
oid = oid + (subId,)
|
||||
return self._createComponent(asn1Spec, tagSet, oid), tail
|
||||
|
||||
class RealDecoder(AbstractSimpleDecoder):
|
||||
protoComponent = univ.Real()
|
||||
def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet,
|
||||
length, state, decodeFun, substrateFun):
|
||||
head, tail = substrate[:length], substrate[length:]
|
||||
if not head:
|
||||
return self._createComponent(asn1Spec, tagSet, 0.0), tail
|
||||
fo = oct2int(head[0]); head = head[1:]
|
||||
if fo & 0x80: # binary enoding
|
||||
n = (fo & 0x03) + 1
|
||||
if n == 4:
|
||||
n = oct2int(head[0])
|
||||
eo, head = head[:n], head[n:]
|
||||
if not eo or not head:
|
||||
raise error.PyAsn1Error('Real exponent screwed')
|
||||
e = oct2int(eo[0]) & 0x80 and -1 or 0
|
||||
while eo: # exponent
|
||||
e <<= 8
|
||||
e |= oct2int(eo[0])
|
||||
eo = eo[1:]
|
||||
p = 0
|
||||
while head: # value
|
||||
p <<= 8
|
||||
p |= oct2int(head[0])
|
||||
head = head[1:]
|
||||
if fo & 0x40: # sign bit
|
||||
p = -p
|
||||
value = (p, 2, e)
|
||||
elif fo & 0x40: # infinite value
|
||||
value = fo & 0x01 and '-inf' or 'inf'
|
||||
elif fo & 0xc0 == 0: # character encoding
|
||||
try:
|
||||
if fo & 0x3 == 0x1: # NR1
|
||||
value = (int(head), 10, 0)
|
||||
elif fo & 0x3 == 0x2: # NR2
|
||||
value = float(head)
|
||||
elif fo & 0x3 == 0x3: # NR3
|
||||
value = float(head)
|
||||
else:
|
||||
raise error.SubstrateUnderrunError(
|
||||
'Unknown NR (tag %s)' % fo
|
||||
)
|
||||
except ValueError:
|
||||
raise error.SubstrateUnderrunError(
|
||||
'Bad character Real syntax'
|
||||
)
|
||||
else:
|
||||
raise error.SubstrateUnderrunError(
|
||||
'Unknown encoding (tag %s)' % fo
|
||||
)
|
||||
return self._createComponent(asn1Spec, tagSet, value), tail
|
||||
|
||||
class SequenceDecoder(AbstractConstructedDecoder):
|
||||
protoComponent = univ.Sequence()
|
||||
def _getComponentTagMap(self, r, idx):
|
||||
try:
|
||||
return r.getComponentTagMapNearPosition(idx)
|
||||
except error.PyAsn1Error:
|
||||
return
|
||||
|
||||
def _getComponentPositionByType(self, r, t, idx):
|
||||
return r.getComponentPositionNearType(t, idx)
|
||||
|
||||
def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet,
|
||||
length, state, decodeFun, substrateFun):
|
||||
head, tail = substrate[:length], substrate[length:]
|
||||
r = self._createComponent(asn1Spec, tagSet)
|
||||
idx = 0
|
||||
if substrateFun:
|
||||
return substrateFun(r, substrate, length)
|
||||
while head:
|
||||
asn1Spec = self._getComponentTagMap(r, idx)
|
||||
component, head = decodeFun(head, asn1Spec)
|
||||
idx = self._getComponentPositionByType(
|
||||
r, component.getEffectiveTagSet(), idx
|
||||
)
|
||||
r.setComponentByPosition(idx, component, asn1Spec is None)
|
||||
idx = idx + 1
|
||||
r.setDefaultComponents()
|
||||
r.verifySizeSpec()
|
||||
return r, tail
|
||||
|
||||
def indefLenValueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet,
|
||||
length, state, decodeFun, substrateFun):
|
||||
r = self._createComponent(asn1Spec, tagSet)
|
||||
if substrateFun:
|
||||
return substrateFun(r, substrate, length)
|
||||
idx = 0
|
||||
while substrate:
|
||||
asn1Spec = self._getComponentTagMap(r, idx)
|
||||
component, substrate = decodeFun(substrate, asn1Spec)
|
||||
if eoo.endOfOctets.isSameTypeWith(component) and \
|
||||
component == eoo.endOfOctets:
|
||||
break
|
||||
idx = self._getComponentPositionByType(
|
||||
r, component.getEffectiveTagSet(), idx
|
||||
)
|
||||
r.setComponentByPosition(idx, component, asn1Spec is None)
|
||||
idx = idx + 1
|
||||
else:
|
||||
raise error.SubstrateUnderrunError(
|
||||
'No EOO seen before substrate ends'
|
||||
)
|
||||
r.setDefaultComponents()
|
||||
r.verifySizeSpec()
|
||||
return r, substrate
|
||||
|
||||
class SequenceOfDecoder(AbstractConstructedDecoder):
|
||||
protoComponent = univ.SequenceOf()
|
||||
def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet,
|
||||
length, state, decodeFun, substrateFun):
|
||||
head, tail = substrate[:length], substrate[length:]
|
||||
r = self._createComponent(asn1Spec, tagSet)
|
||||
if substrateFun:
|
||||
return substrateFun(r, substrate, length)
|
||||
asn1Spec = r.getComponentType()
|
||||
idx = 0
|
||||
while head:
|
||||
component, head = decodeFun(head, asn1Spec)
|
||||
r.setComponentByPosition(idx, component, asn1Spec is None)
|
||||
idx = idx + 1
|
||||
r.verifySizeSpec()
|
||||
return r, tail
|
||||
|
||||
def indefLenValueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet,
|
||||
length, state, decodeFun, substrateFun):
|
||||
r = self._createComponent(asn1Spec, tagSet)
|
||||
if substrateFun:
|
||||
return substrateFun(r, substrate, length)
|
||||
asn1Spec = r.getComponentType()
|
||||
idx = 0
|
||||
while substrate:
|
||||
component, substrate = decodeFun(substrate, asn1Spec)
|
||||
if eoo.endOfOctets.isSameTypeWith(component) and \
|
||||
component == eoo.endOfOctets:
|
||||
break
|
||||
r.setComponentByPosition(idx, component, asn1Spec is None)
|
||||
idx = idx + 1
|
||||
else:
|
||||
raise error.SubstrateUnderrunError(
|
||||
'No EOO seen before substrate ends'
|
||||
)
|
||||
r.verifySizeSpec()
|
||||
return r, substrate
|
||||
|
||||
class SetDecoder(SequenceDecoder):
|
||||
protoComponent = univ.Set()
|
||||
def _getComponentTagMap(self, r, idx):
|
||||
return r.getComponentTagMap()
|
||||
|
||||
def _getComponentPositionByType(self, r, t, idx):
|
||||
nextIdx = r.getComponentPositionByType(t)
|
||||
if nextIdx is None:
|
||||
return idx
|
||||
else:
|
||||
return nextIdx
|
||||
|
||||
class SetOfDecoder(SequenceOfDecoder):
|
||||
protoComponent = univ.SetOf()
|
||||
|
||||
class ChoiceDecoder(AbstractConstructedDecoder):
|
||||
protoComponent = univ.Choice()
|
||||
tagFormats = (tag.tagFormatSimple, tag.tagFormatConstructed)
|
||||
def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet,
|
||||
length, state, decodeFun, substrateFun):
|
||||
head, tail = substrate[:length], substrate[length:]
|
||||
r = self._createComponent(asn1Spec, tagSet)
|
||||
if substrateFun:
|
||||
return substrateFun(r, substrate, length)
|
||||
if r.getTagSet() == tagSet: # explicitly tagged Choice
|
||||
component, head = decodeFun(
|
||||
head, r.getComponentTagMap()
|
||||
)
|
||||
else:
|
||||
component, head = decodeFun(
|
||||
head, r.getComponentTagMap(), tagSet, length, state
|
||||
)
|
||||
if isinstance(component, univ.Choice):
|
||||
effectiveTagSet = component.getEffectiveTagSet()
|
||||
else:
|
||||
effectiveTagSet = component.getTagSet()
|
||||
r.setComponentByType(effectiveTagSet, component, 0, asn1Spec is None)
|
||||
return r, tail
|
||||
|
||||
def indefLenValueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet,
|
||||
length, state, decodeFun, substrateFun):
|
||||
r = self._createComponent(asn1Spec, tagSet)
|
||||
if substrateFun:
|
||||
return substrateFun(r, substrate, length)
|
||||
if r.getTagSet() == tagSet: # explicitly tagged Choice
|
||||
component, substrate = decodeFun(substrate, r.getComponentTagMap())
|
||||
eooMarker, substrate = decodeFun(substrate) # eat up EOO marker
|
||||
if not eoo.endOfOctets.isSameTypeWith(eooMarker) or \
|
||||
eooMarker != eoo.endOfOctets:
|
||||
raise error.PyAsn1Error('No EOO seen before substrate ends')
|
||||
else:
|
||||
component, substrate= decodeFun(
|
||||
substrate, r.getComponentTagMap(), tagSet, length, state
|
||||
)
|
||||
if isinstance(component, univ.Choice):
|
||||
effectiveTagSet = component.getEffectiveTagSet()
|
||||
else:
|
||||
effectiveTagSet = component.getTagSet()
|
||||
r.setComponentByType(effectiveTagSet, component, 0, asn1Spec is None)
|
||||
return r, substrate
|
||||
|
||||
class AnyDecoder(AbstractSimpleDecoder):
|
||||
protoComponent = univ.Any()
|
||||
tagFormats = (tag.tagFormatSimple, tag.tagFormatConstructed)
|
||||
def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet,
|
||||
length, state, decodeFun, substrateFun):
|
||||
if asn1Spec is None or \
|
||||
asn1Spec is not None and tagSet != asn1Spec.getTagSet():
|
||||
# untagged Any container, recover inner header substrate
|
||||
length = length + len(fullSubstrate) - len(substrate)
|
||||
substrate = fullSubstrate
|
||||
if substrateFun:
|
||||
return substrateFun(self._createComponent(asn1Spec, tagSet),
|
||||
substrate, length)
|
||||
head, tail = substrate[:length], substrate[length:]
|
||||
return self._createComponent(asn1Spec, tagSet, value=head), tail
|
||||
|
||||
def indefLenValueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet,
|
||||
length, state, decodeFun, substrateFun):
|
||||
if asn1Spec is not None and tagSet == asn1Spec.getTagSet():
|
||||
# tagged Any type -- consume header substrate
|
||||
header = ''
|
||||
else:
|
||||
# untagged Any, recover header substrate
|
||||
header = fullSubstrate[:-len(substrate)]
|
||||
|
||||
r = self._createComponent(asn1Spec, tagSet, header)
|
||||
|
||||
# Any components do not inherit initial tag
|
||||
asn1Spec = self.protoComponent
|
||||
|
||||
if substrateFun:
|
||||
return substrateFun(r, substrate, length)
|
||||
while substrate:
|
||||
component, substrate = decodeFun(substrate, asn1Spec)
|
||||
if eoo.endOfOctets.isSameTypeWith(component) and \
|
||||
component == eoo.endOfOctets:
|
||||
break
|
||||
r = r + component
|
||||
else:
|
||||
raise error.SubstrateUnderrunError(
|
||||
'No EOO seen before substrate ends'
|
||||
)
|
||||
return r, substrate
|
||||
|
||||
# character string types
|
||||
class UTF8StringDecoder(OctetStringDecoder):
|
||||
protoComponent = char.UTF8String()
|
||||
class NumericStringDecoder(OctetStringDecoder):
|
||||
protoComponent = char.NumericString()
|
||||
class PrintableStringDecoder(OctetStringDecoder):
|
||||
protoComponent = char.PrintableString()
|
||||
class TeletexStringDecoder(OctetStringDecoder):
|
||||
protoComponent = char.TeletexString()
|
||||
class VideotexStringDecoder(OctetStringDecoder):
|
||||
protoComponent = char.VideotexString()
|
||||
class IA5StringDecoder(OctetStringDecoder):
|
||||
protoComponent = char.IA5String()
|
||||
class GraphicStringDecoder(OctetStringDecoder):
|
||||
protoComponent = char.GraphicString()
|
||||
class VisibleStringDecoder(OctetStringDecoder):
|
||||
protoComponent = char.VisibleString()
|
||||
class GeneralStringDecoder(OctetStringDecoder):
|
||||
protoComponent = char.GeneralString()
|
||||
class UniversalStringDecoder(OctetStringDecoder):
|
||||
protoComponent = char.UniversalString()
|
||||
class BMPStringDecoder(OctetStringDecoder):
|
||||
protoComponent = char.BMPString()
|
||||
|
||||
# "useful" types
|
||||
class GeneralizedTimeDecoder(OctetStringDecoder):
|
||||
protoComponent = useful.GeneralizedTime()
|
||||
class UTCTimeDecoder(OctetStringDecoder):
|
||||
protoComponent = useful.UTCTime()
|
||||
|
||||
tagMap = {
|
||||
eoo.endOfOctets.tagSet: EndOfOctetsDecoder(),
|
||||
univ.Integer.tagSet: IntegerDecoder(),
|
||||
univ.Boolean.tagSet: BooleanDecoder(),
|
||||
univ.BitString.tagSet: BitStringDecoder(),
|
||||
univ.OctetString.tagSet: OctetStringDecoder(),
|
||||
univ.Null.tagSet: NullDecoder(),
|
||||
univ.ObjectIdentifier.tagSet: ObjectIdentifierDecoder(),
|
||||
univ.Enumerated.tagSet: IntegerDecoder(),
|
||||
univ.Real.tagSet: RealDecoder(),
|
||||
univ.Sequence.tagSet: SequenceDecoder(), # conflicts with SequenceOf
|
||||
univ.Set.tagSet: SetDecoder(), # conflicts with SetOf
|
||||
univ.Choice.tagSet: ChoiceDecoder(), # conflicts with Any
|
||||
# character string types
|
||||
char.UTF8String.tagSet: UTF8StringDecoder(),
|
||||
char.NumericString.tagSet: NumericStringDecoder(),
|
||||
char.PrintableString.tagSet: PrintableStringDecoder(),
|
||||
char.TeletexString.tagSet: TeletexStringDecoder(),
|
||||
char.VideotexString.tagSet: VideotexStringDecoder(),
|
||||
char.IA5String.tagSet: IA5StringDecoder(),
|
||||
char.GraphicString.tagSet: GraphicStringDecoder(),
|
||||
char.VisibleString.tagSet: VisibleStringDecoder(),
|
||||
char.GeneralString.tagSet: GeneralStringDecoder(),
|
||||
char.UniversalString.tagSet: UniversalStringDecoder(),
|
||||
char.BMPString.tagSet: BMPStringDecoder(),
|
||||
# useful types
|
||||
useful.GeneralizedTime.tagSet: GeneralizedTimeDecoder(),
|
||||
useful.UTCTime.tagSet: UTCTimeDecoder()
|
||||
}
|
||||
|
||||
# Type-to-codec map for ambiguous ASN.1 types
|
||||
typeMap = {
|
||||
univ.Set.typeId: SetDecoder(),
|
||||
univ.SetOf.typeId: SetOfDecoder(),
|
||||
univ.Sequence.typeId: SequenceDecoder(),
|
||||
univ.SequenceOf.typeId: SequenceOfDecoder(),
|
||||
univ.Choice.typeId: ChoiceDecoder(),
|
||||
univ.Any.typeId: AnyDecoder()
|
||||
}
|
||||
|
||||
( stDecodeTag, stDecodeLength, stGetValueDecoder, stGetValueDecoderByAsn1Spec,
|
||||
stGetValueDecoderByTag, stTryAsExplicitTag, stDecodeValue,
|
||||
stDumpRawValue, stErrorCondition, stStop ) = [x for x in range(10)]
|
||||
|
||||
class Decoder:
|
||||
defaultErrorState = stErrorCondition
|
||||
# defaultErrorState = stDumpRawValue
|
||||
defaultRawDecoder = AnyDecoder()
|
||||
def __init__(self, tagMap, typeMap={}):
|
||||
self.__tagMap = tagMap
|
||||
self.__typeMap = typeMap
|
||||
self.__endOfOctetsTagSet = eoo.endOfOctets.getTagSet()
|
||||
# Tag & TagSet objects caches
|
||||
self.__tagCache = {}
|
||||
self.__tagSetCache = {}
|
||||
|
||||
def __call__(self, substrate, asn1Spec=None, tagSet=None,
|
||||
length=None, state=stDecodeTag, recursiveFlag=1,
|
||||
substrateFun=None):
|
||||
if debug.logger & debug.flagDecoder:
|
||||
debug.logger('decoder called at scope %s with state %d, working with up to %d octets of substrate: %s' % (debug.scope, state, len(substrate), debug.hexdump(substrate)))
|
||||
fullSubstrate = substrate
|
||||
while state != stStop:
|
||||
if state == stDecodeTag:
|
||||
# Decode tag
|
||||
if not substrate:
|
||||
raise error.SubstrateUnderrunError(
|
||||
'Short octet stream on tag decoding'
|
||||
)
|
||||
if not isOctetsType(substrate) and \
|
||||
not isinstance(substrate, univ.OctetString):
|
||||
raise error.PyAsn1Error('Bad octet stream type')
|
||||
|
||||
firstOctet = substrate[0]
|
||||
substrate = substrate[1:]
|
||||
if firstOctet in self.__tagCache:
|
||||
lastTag = self.__tagCache[firstOctet]
|
||||
else:
|
||||
t = oct2int(firstOctet)
|
||||
tagClass = t&0xC0
|
||||
tagFormat = t&0x20
|
||||
tagId = t&0x1F
|
||||
if tagId == 0x1F:
|
||||
tagId = 0
|
||||
while 1:
|
||||
if not substrate:
|
||||
raise error.SubstrateUnderrunError(
|
||||
'Short octet stream on long tag decoding'
|
||||
)
|
||||
t = oct2int(substrate[0])
|
||||
tagId = tagId << 7 | (t&0x7F)
|
||||
substrate = substrate[1:]
|
||||
if not t&0x80:
|
||||
break
|
||||
lastTag = tag.Tag(
|
||||
tagClass=tagClass, tagFormat=tagFormat, tagId=tagId
|
||||
)
|
||||
if tagId < 31:
|
||||
# cache short tags
|
||||
self.__tagCache[firstOctet] = lastTag
|
||||
if tagSet is None:
|
||||
if firstOctet in self.__tagSetCache:
|
||||
tagSet = self.__tagSetCache[firstOctet]
|
||||
else:
|
||||
# base tag not recovered
|
||||
tagSet = tag.TagSet((), lastTag)
|
||||
if firstOctet in self.__tagCache:
|
||||
self.__tagSetCache[firstOctet] = tagSet
|
||||
else:
|
||||
tagSet = lastTag + tagSet
|
||||
state = stDecodeLength
|
||||
debug.logger and debug.logger & debug.flagDecoder and debug.logger('tag decoded into %r, decoding length' % tagSet)
|
||||
if state == stDecodeLength:
|
||||
# Decode length
|
||||
if not substrate:
|
||||
raise error.SubstrateUnderrunError(
|
||||
'Short octet stream on length decoding'
|
||||
)
|
||||
firstOctet = oct2int(substrate[0])
|
||||
if firstOctet == 128:
|
||||
size = 1
|
||||
length = -1
|
||||
elif firstOctet < 128:
|
||||
length, size = firstOctet, 1
|
||||
else:
|
||||
size = firstOctet & 0x7F
|
||||
# encoded in size bytes
|
||||
length = 0
|
||||
lengthString = substrate[1:size+1]
|
||||
# missing check on maximum size, which shouldn't be a
|
||||
# problem, we can handle more than is possible
|
||||
if len(lengthString) != size:
|
||||
raise error.SubstrateUnderrunError(
|
||||
'%s<%s at %s' %
|
||||
(size, len(lengthString), tagSet)
|
||||
)
|
||||
for char in lengthString:
|
||||
length = (length << 8) | oct2int(char)
|
||||
size = size + 1
|
||||
substrate = substrate[size:]
|
||||
if length != -1 and len(substrate) < length:
|
||||
raise error.SubstrateUnderrunError(
|
||||
'%d-octet short' % (length - len(substrate))
|
||||
)
|
||||
state = stGetValueDecoder
|
||||
debug.logger and debug.logger & debug.flagDecoder and debug.logger('value length decoded into %d, payload substrate is: %s' % (length, debug.hexdump(length == -1 and substrate or substrate[:length])))
|
||||
if state == stGetValueDecoder:
|
||||
if asn1Spec is None:
|
||||
state = stGetValueDecoderByTag
|
||||
else:
|
||||
state = stGetValueDecoderByAsn1Spec
|
||||
#
|
||||
# There're two ways of creating subtypes in ASN.1 what influences
|
||||
# decoder operation. These methods are:
|
||||
# 1) Either base types used in or no IMPLICIT tagging has been
|
||||
# applied on subtyping.
|
||||
# 2) Subtype syntax drops base type information (by means of
|
||||
# IMPLICIT tagging.
|
||||
# The first case allows for complete tag recovery from substrate
|
||||
# while the second one requires original ASN.1 type spec for
|
||||
# decoding.
|
||||
#
|
||||
# In either case a set of tags (tagSet) is coming from substrate
|
||||
# in an incremental, tag-by-tag fashion (this is the case of
|
||||
# EXPLICIT tag which is most basic). Outermost tag comes first
|
||||
# from the wire.
|
||||
#
|
||||
if state == stGetValueDecoderByTag:
|
||||
if tagSet in self.__tagMap:
|
||||
concreteDecoder = self.__tagMap[tagSet]
|
||||
else:
|
||||
concreteDecoder = None
|
||||
if concreteDecoder:
|
||||
state = stDecodeValue
|
||||
else:
|
||||
_k = tagSet[:1]
|
||||
if _k in self.__tagMap:
|
||||
concreteDecoder = self.__tagMap[_k]
|
||||
else:
|
||||
concreteDecoder = None
|
||||
if concreteDecoder:
|
||||
state = stDecodeValue
|
||||
else:
|
||||
state = stTryAsExplicitTag
|
||||
if debug.logger and debug.logger & debug.flagDecoder:
|
||||
debug.logger('codec %s chosen by a built-in type, decoding %s' % (concreteDecoder and concreteDecoder.__class__.__name__ or "<none>", state == stDecodeValue and 'value' or 'as explicit tag'))
|
||||
debug.scope.push(concreteDecoder is None and '?' or concreteDecoder.protoComponent.__class__.__name__)
|
||||
if state == stGetValueDecoderByAsn1Spec:
|
||||
if isinstance(asn1Spec, (dict, tagmap.TagMap)):
|
||||
if tagSet in asn1Spec:
|
||||
__chosenSpec = asn1Spec[tagSet]
|
||||
else:
|
||||
__chosenSpec = None
|
||||
if debug.logger and debug.logger & debug.flagDecoder:
|
||||
debug.logger('candidate ASN.1 spec is a map of:')
|
||||
for t, v in asn1Spec.getPosMap().items():
|
||||
debug.logger(' %r -> %s' % (t, v.__class__.__name__))
|
||||
if asn1Spec.getNegMap():
|
||||
debug.logger('but neither of: ')
|
||||
for i in asn1Spec.getNegMap().items():
|
||||
debug.logger(' %r -> %s' % (t, v.__class__.__name__))
|
||||
debug.logger('new candidate ASN.1 spec is %s, chosen by %r' % (__chosenSpec is None and '<none>' or __chosenSpec.__class__.__name__, tagSet))
|
||||
else:
|
||||
__chosenSpec = asn1Spec
|
||||
debug.logger and debug.logger & debug.flagDecoder and debug.logger('candidate ASN.1 spec is %s' % asn1Spec.__class__.__name__)
|
||||
if __chosenSpec is not None and (
|
||||
tagSet == __chosenSpec.getTagSet() or \
|
||||
tagSet in __chosenSpec.getTagMap()
|
||||
):
|
||||
# use base type for codec lookup to recover untagged types
|
||||
baseTagSet = __chosenSpec.baseTagSet
|
||||
if __chosenSpec.typeId is not None and \
|
||||
__chosenSpec.typeId in self.__typeMap:
|
||||
# ambiguous type
|
||||
concreteDecoder = self.__typeMap[__chosenSpec.typeId]
|
||||
debug.logger and debug.logger & debug.flagDecoder and debug.logger('value decoder chosen for an ambiguous type by type ID %s' % (__chosenSpec.typeId,))
|
||||
elif baseTagSet in self.__tagMap:
|
||||
# base type or tagged subtype
|
||||
concreteDecoder = self.__tagMap[baseTagSet]
|
||||
debug.logger and debug.logger & debug.flagDecoder and debug.logger('value decoder chosen by base %r' % (baseTagSet,))
|
||||
else:
|
||||
concreteDecoder = None
|
||||
if concreteDecoder:
|
||||
asn1Spec = __chosenSpec
|
||||
state = stDecodeValue
|
||||
else:
|
||||
state = stTryAsExplicitTag
|
||||
elif tagSet == self.__endOfOctetsTagSet:
|
||||
concreteDecoder = self.__tagMap[tagSet]
|
||||
state = stDecodeValue
|
||||
debug.logger and debug.logger & debug.flagDecoder and debug.logger('end-of-octets found')
|
||||
else:
|
||||
concreteDecoder = None
|
||||
state = stTryAsExplicitTag
|
||||
if debug.logger and debug.logger & debug.flagDecoder:
|
||||
debug.logger('codec %s chosen by ASN.1 spec, decoding %s' % (state == stDecodeValue and concreteDecoder.__class__.__name__ or "<none>", state == stDecodeValue and 'value' or 'as explicit tag'))
|
||||
debug.scope.push(__chosenSpec is None and '?' or __chosenSpec.__class__.__name__)
|
||||
if state == stTryAsExplicitTag:
|
||||
if tagSet and \
|
||||
tagSet[0][1] == tag.tagFormatConstructed and \
|
||||
tagSet[0][0] != tag.tagClassUniversal:
|
||||
# Assume explicit tagging
|
||||
concreteDecoder = explicitTagDecoder
|
||||
state = stDecodeValue
|
||||
else:
|
||||
concreteDecoder = None
|
||||
state = self.defaultErrorState
|
||||
debug.logger and debug.logger & debug.flagDecoder and debug.logger('codec %s chosen, decoding %s' % (concreteDecoder and concreteDecoder.__class__.__name__ or "<none>", state == stDecodeValue and 'value' or 'as failure'))
|
||||
if state == stDumpRawValue:
|
||||
concreteDecoder = self.defaultRawDecoder
|
||||
debug.logger and debug.logger & debug.flagDecoder and debug.logger('codec %s chosen, decoding value' % concreteDecoder.__class__.__name__)
|
||||
state = stDecodeValue
|
||||
if state == stDecodeValue:
|
||||
if recursiveFlag == 0 and not substrateFun: # legacy
|
||||
substrateFun = lambda a,b,c: (a,b[:c])
|
||||
if length == -1: # indef length
|
||||
value, substrate = concreteDecoder.indefLenValueDecoder(
|
||||
fullSubstrate, substrate, asn1Spec, tagSet, length,
|
||||
stGetValueDecoder, self, substrateFun
|
||||
)
|
||||
else:
|
||||
value, substrate = concreteDecoder.valueDecoder(
|
||||
fullSubstrate, substrate, asn1Spec, tagSet, length,
|
||||
stGetValueDecoder, self, substrateFun
|
||||
)
|
||||
state = stStop
|
||||
debug.logger and debug.logger & debug.flagDecoder and debug.logger('codec %s yields type %s, value:\n%s\n...remaining substrate is: %s' % (concreteDecoder.__class__.__name__, value.__class__.__name__, value.prettyPrint(), substrate and debug.hexdump(substrate) or '<none>'))
|
||||
if state == stErrorCondition:
|
||||
raise error.PyAsn1Error(
|
||||
'%r not in asn1Spec: %r' % (tagSet, asn1Spec)
|
||||
)
|
||||
if debug.logger and debug.logger & debug.flagDecoder:
|
||||
debug.scope.pop()
|
||||
debug.logger('decoder left scope %s, call completed' % debug.scope)
|
||||
return value, substrate
|
||||
|
||||
decode = Decoder(tagMap, typeMap)
|
||||
|
||||
# XXX
|
||||
# non-recursive decoding; return position rather than substrate
|
353
src/lib/pyasn1/codec/ber/encoder.py
Normal file
353
src/lib/pyasn1/codec/ber/encoder.py
Normal file
|
@ -0,0 +1,353 @@
|
|||
# BER encoder
|
||||
from pyasn1.type import base, tag, univ, char, useful
|
||||
from pyasn1.codec.ber import eoo
|
||||
from pyasn1.compat.octets import int2oct, oct2int, ints2octs, null, str2octs
|
||||
from pyasn1 import debug, error
|
||||
|
||||
class Error(Exception): pass
|
||||
|
||||
class AbstractItemEncoder:
|
||||
supportIndefLenMode = 1
|
||||
def encodeTag(self, t, isConstructed):
|
||||
tagClass, tagFormat, tagId = t.asTuple() # this is a hotspot
|
||||
v = tagClass | tagFormat
|
||||
if isConstructed:
|
||||
v = v|tag.tagFormatConstructed
|
||||
if tagId < 31:
|
||||
return int2oct(v|tagId)
|
||||
else:
|
||||
s = int2oct(tagId&0x7f)
|
||||
tagId = tagId >> 7
|
||||
while tagId:
|
||||
s = int2oct(0x80|(tagId&0x7f)) + s
|
||||
tagId = tagId >> 7
|
||||
return int2oct(v|0x1F) + s
|
||||
|
||||
def encodeLength(self, length, defMode):
|
||||
if not defMode and self.supportIndefLenMode:
|
||||
return int2oct(0x80)
|
||||
if length < 0x80:
|
||||
return int2oct(length)
|
||||
else:
|
||||
substrate = null
|
||||
while length:
|
||||
substrate = int2oct(length&0xff) + substrate
|
||||
length = length >> 8
|
||||
substrateLen = len(substrate)
|
||||
if substrateLen > 126:
|
||||
raise Error('Length octets overflow (%d)' % substrateLen)
|
||||
return int2oct(0x80 | substrateLen) + substrate
|
||||
|
||||
def encodeValue(self, encodeFun, value, defMode, maxChunkSize):
|
||||
raise Error('Not implemented')
|
||||
|
||||
def _encodeEndOfOctets(self, encodeFun, defMode):
|
||||
if defMode or not self.supportIndefLenMode:
|
||||
return null
|
||||
else:
|
||||
return encodeFun(eoo.endOfOctets, defMode)
|
||||
|
||||
def encode(self, encodeFun, value, defMode, maxChunkSize):
|
||||
substrate, isConstructed = self.encodeValue(
|
||||
encodeFun, value, defMode, maxChunkSize
|
||||
)
|
||||
tagSet = value.getTagSet()
|
||||
if tagSet:
|
||||
if not isConstructed: # primitive form implies definite mode
|
||||
defMode = 1
|
||||
return self.encodeTag(
|
||||
tagSet[-1], isConstructed
|
||||
) + self.encodeLength(
|
||||
len(substrate), defMode
|
||||
) + substrate + self._encodeEndOfOctets(encodeFun, defMode)
|
||||
else:
|
||||
return substrate # untagged value
|
||||
|
||||
class EndOfOctetsEncoder(AbstractItemEncoder):
|
||||
def encodeValue(self, encodeFun, value, defMode, maxChunkSize):
|
||||
return null, 0
|
||||
|
||||
class ExplicitlyTaggedItemEncoder(AbstractItemEncoder):
|
||||
def encodeValue(self, encodeFun, value, defMode, maxChunkSize):
|
||||
if isinstance(value, base.AbstractConstructedAsn1Item):
|
||||
value = value.clone(tagSet=value.getTagSet()[:-1],
|
||||
cloneValueFlag=1)
|
||||
else:
|
||||
value = value.clone(tagSet=value.getTagSet()[:-1])
|
||||
return encodeFun(value, defMode, maxChunkSize), 1
|
||||
|
||||
explicitlyTaggedItemEncoder = ExplicitlyTaggedItemEncoder()
|
||||
|
||||
class BooleanEncoder(AbstractItemEncoder):
|
||||
supportIndefLenMode = 0
|
||||
_true = ints2octs((1,))
|
||||
_false = ints2octs((0,))
|
||||
def encodeValue(self, encodeFun, value, defMode, maxChunkSize):
|
||||
return value and self._true or self._false, 0
|
||||
|
||||
class IntegerEncoder(AbstractItemEncoder):
|
||||
supportIndefLenMode = 0
|
||||
supportCompactZero = False
|
||||
def encodeValue(self, encodeFun, value, defMode, maxChunkSize):
|
||||
if value == 0: # shortcut for zero value
|
||||
if self.supportCompactZero:
|
||||
# this seems to be a correct way for encoding zeros
|
||||
return null, 0
|
||||
else:
|
||||
# this seems to be a widespread way for encoding zeros
|
||||
return ints2octs((0,)), 0
|
||||
octets = []
|
||||
value = int(value) # to save on ops on asn1 type
|
||||
while 1:
|
||||
octets.insert(0, value & 0xff)
|
||||
if value == 0 or value == -1:
|
||||
break
|
||||
value = value >> 8
|
||||
if value == 0 and octets[0] & 0x80:
|
||||
octets.insert(0, 0)
|
||||
while len(octets) > 1 and \
|
||||
(octets[0] == 0 and octets[1] & 0x80 == 0 or \
|
||||
octets[0] == 0xff and octets[1] & 0x80 != 0):
|
||||
del octets[0]
|
||||
return ints2octs(octets), 0
|
||||
|
||||
class BitStringEncoder(AbstractItemEncoder):
|
||||
def encodeValue(self, encodeFun, value, defMode, maxChunkSize):
|
||||
if not maxChunkSize or len(value) <= maxChunkSize*8:
|
||||
r = {}; l = len(value); p = 0; j = 7
|
||||
while p < l:
|
||||
i, j = divmod(p, 8)
|
||||
r[i] = r.get(i,0) | value[p]<<(7-j)
|
||||
p = p + 1
|
||||
keys = list(r); keys.sort()
|
||||
return int2oct(7-j) + ints2octs([r[k] for k in keys]), 0
|
||||
else:
|
||||
pos = 0; substrate = null
|
||||
while 1:
|
||||
# count in octets
|
||||
v = value.clone(value[pos*8:pos*8+maxChunkSize*8])
|
||||
if not v:
|
||||
break
|
||||
substrate = substrate + encodeFun(v, defMode, maxChunkSize)
|
||||
pos = pos + maxChunkSize
|
||||
return substrate, 1
|
||||
|
||||
class OctetStringEncoder(AbstractItemEncoder):
|
||||
def encodeValue(self, encodeFun, value, defMode, maxChunkSize):
|
||||
if not maxChunkSize or len(value) <= maxChunkSize:
|
||||
return value.asOctets(), 0
|
||||
else:
|
||||
pos = 0; substrate = null
|
||||
while 1:
|
||||
v = value.clone(value[pos:pos+maxChunkSize])
|
||||
if not v:
|
||||
break
|
||||
substrate = substrate + encodeFun(v, defMode, maxChunkSize)
|
||||
pos = pos + maxChunkSize
|
||||
return substrate, 1
|
||||
|
||||
class NullEncoder(AbstractItemEncoder):
|
||||
supportIndefLenMode = 0
|
||||
def encodeValue(self, encodeFun, value, defMode, maxChunkSize):
|
||||
return null, 0
|
||||
|
||||
class ObjectIdentifierEncoder(AbstractItemEncoder):
|
||||
supportIndefLenMode = 0
|
||||
precomputedValues = {
|
||||
(1, 3, 6, 1, 2): (43, 6, 1, 2),
|
||||
(1, 3, 6, 1, 4): (43, 6, 1, 4)
|
||||
}
|
||||
def encodeValue(self, encodeFun, value, defMode, maxChunkSize):
|
||||
oid = value.asTuple()
|
||||
if oid[:5] in self.precomputedValues:
|
||||
octets = self.precomputedValues[oid[:5]]
|
||||
index = 5
|
||||
else:
|
||||
if len(oid) < 2:
|
||||
raise error.PyAsn1Error('Short OID %s' % (value,))
|
||||
|
||||
# Build the first twos
|
||||
if oid[0] > 6 or oid[1] > 39 or oid[0] == 6 and oid[1] > 15:
|
||||
raise error.PyAsn1Error(
|
||||
'Initial sub-ID overflow %s in OID %s' % (oid[:2], value)
|
||||
)
|
||||
octets = (oid[0] * 40 + oid[1],)
|
||||
index = 2
|
||||
|
||||
# Cycle through subids
|
||||
for subid in oid[index:]:
|
||||
if subid > -1 and subid < 128:
|
||||
# Optimize for the common case
|
||||
octets = octets + (subid & 0x7f,)
|
||||
elif subid < 0 or subid > 0xFFFFFFFF:
|
||||
raise error.PyAsn1Error(
|
||||
'SubId overflow %s in %s' % (subid, value)
|
||||
)
|
||||
else:
|
||||
# Pack large Sub-Object IDs
|
||||
res = (subid & 0x7f,)
|
||||
subid = subid >> 7
|
||||
while subid > 0:
|
||||
res = (0x80 | (subid & 0x7f),) + res
|
||||
subid = subid >> 7
|
||||
# Add packed Sub-Object ID to resulted Object ID
|
||||
octets += res
|
||||
|
||||
return ints2octs(octets), 0
|
||||
|
||||
class RealEncoder(AbstractItemEncoder):
|
||||
supportIndefLenMode = 0
|
||||
def encodeValue(self, encodeFun, value, defMode, maxChunkSize):
|
||||
if value.isPlusInfinity():
|
||||
return int2oct(0x40), 0
|
||||
if value.isMinusInfinity():
|
||||
return int2oct(0x41), 0
|
||||
m, b, e = value
|
||||
if not m:
|
||||
return null, 0
|
||||
if b == 10:
|
||||
return str2octs('\x03%dE%s%d' % (m, e == 0 and '+' or '', e)), 0
|
||||
elif b == 2:
|
||||
fo = 0x80 # binary enoding
|
||||
if m < 0:
|
||||
fo = fo | 0x40 # sign bit
|
||||
m = -m
|
||||
while int(m) != m: # drop floating point
|
||||
m *= 2
|
||||
e -= 1
|
||||
while m & 0x1 == 0: # mantissa normalization
|
||||
m >>= 1
|
||||
e += 1
|
||||
eo = null
|
||||
while e not in (0, -1):
|
||||
eo = int2oct(e&0xff) + eo
|
||||
e >>= 8
|
||||
if e == 0 and eo and oct2int(eo[0]) & 0x80:
|
||||
eo = int2oct(0) + eo
|
||||
n = len(eo)
|
||||
if n > 0xff:
|
||||
raise error.PyAsn1Error('Real exponent overflow')
|
||||
if n == 1:
|
||||
pass
|
||||
elif n == 2:
|
||||
fo |= 1
|
||||
elif n == 3:
|
||||
fo |= 2
|
||||
else:
|
||||
fo |= 3
|
||||
eo = int2oct(n//0xff+1) + eo
|
||||
po = null
|
||||
while m:
|
||||
po = int2oct(m&0xff) + po
|
||||
m >>= 8
|
||||
substrate = int2oct(fo) + eo + po
|
||||
return substrate, 0
|
||||
else:
|
||||
raise error.PyAsn1Error('Prohibited Real base %s' % b)
|
||||
|
||||
class SequenceEncoder(AbstractItemEncoder):
|
||||
def encodeValue(self, encodeFun, value, defMode, maxChunkSize):
|
||||
value.setDefaultComponents()
|
||||
value.verifySizeSpec()
|
||||
substrate = null; idx = len(value)
|
||||
while idx > 0:
|
||||
idx = idx - 1
|
||||
if value[idx] is None: # Optional component
|
||||
continue
|
||||
component = value.getDefaultComponentByPosition(idx)
|
||||
if component is not None and component == value[idx]:
|
||||
continue
|
||||
substrate = encodeFun(
|
||||
value[idx], defMode, maxChunkSize
|
||||
) + substrate
|
||||
return substrate, 1
|
||||
|
||||
class SequenceOfEncoder(AbstractItemEncoder):
|
||||
def encodeValue(self, encodeFun, value, defMode, maxChunkSize):
|
||||
value.verifySizeSpec()
|
||||
substrate = null; idx = len(value)
|
||||
while idx > 0:
|
||||
idx = idx - 1
|
||||
substrate = encodeFun(
|
||||
value[idx], defMode, maxChunkSize
|
||||
) + substrate
|
||||
return substrate, 1
|
||||
|
||||
class ChoiceEncoder(AbstractItemEncoder):
|
||||
def encodeValue(self, encodeFun, value, defMode, maxChunkSize):
|
||||
return encodeFun(value.getComponent(), defMode, maxChunkSize), 1
|
||||
|
||||
class AnyEncoder(OctetStringEncoder):
|
||||
def encodeValue(self, encodeFun, value, defMode, maxChunkSize):
|
||||
return value.asOctets(), defMode == 0
|
||||
|
||||
tagMap = {
|
||||
eoo.endOfOctets.tagSet: EndOfOctetsEncoder(),
|
||||
univ.Boolean.tagSet: BooleanEncoder(),
|
||||
univ.Integer.tagSet: IntegerEncoder(),
|
||||
univ.BitString.tagSet: BitStringEncoder(),
|
||||
univ.OctetString.tagSet: OctetStringEncoder(),
|
||||
univ.Null.tagSet: NullEncoder(),
|
||||
univ.ObjectIdentifier.tagSet: ObjectIdentifierEncoder(),
|
||||
univ.Enumerated.tagSet: IntegerEncoder(),
|
||||
univ.Real.tagSet: RealEncoder(),
|
||||
# Sequence & Set have same tags as SequenceOf & SetOf
|
||||
univ.SequenceOf.tagSet: SequenceOfEncoder(),
|
||||
univ.SetOf.tagSet: SequenceOfEncoder(),
|
||||
univ.Choice.tagSet: ChoiceEncoder(),
|
||||
# character string types
|
||||
char.UTF8String.tagSet: OctetStringEncoder(),
|
||||
char.NumericString.tagSet: OctetStringEncoder(),
|
||||
char.PrintableString.tagSet: OctetStringEncoder(),
|
||||
char.TeletexString.tagSet: OctetStringEncoder(),
|
||||
char.VideotexString.tagSet: OctetStringEncoder(),
|
||||
char.IA5String.tagSet: OctetStringEncoder(),
|
||||
char.GraphicString.tagSet: OctetStringEncoder(),
|
||||
char.VisibleString.tagSet: OctetStringEncoder(),
|
||||
char.GeneralString.tagSet: OctetStringEncoder(),
|
||||
char.UniversalString.tagSet: OctetStringEncoder(),
|
||||
char.BMPString.tagSet: OctetStringEncoder(),
|
||||
# useful types
|
||||
useful.GeneralizedTime.tagSet: OctetStringEncoder(),
|
||||
useful.UTCTime.tagSet: OctetStringEncoder()
|
||||
}
|
||||
|
||||
# Type-to-codec map for ambiguous ASN.1 types
|
||||
typeMap = {
|
||||
univ.Set.typeId: SequenceEncoder(),
|
||||
univ.SetOf.typeId: SequenceOfEncoder(),
|
||||
univ.Sequence.typeId: SequenceEncoder(),
|
||||
univ.SequenceOf.typeId: SequenceOfEncoder(),
|
||||
univ.Choice.typeId: ChoiceEncoder(),
|
||||
univ.Any.typeId: AnyEncoder()
|
||||
}
|
||||
|
||||
class Encoder:
|
||||
def __init__(self, tagMap, typeMap={}):
|
||||
self.__tagMap = tagMap
|
||||
self.__typeMap = typeMap
|
||||
|
||||
def __call__(self, value, defMode=1, maxChunkSize=0):
|
||||
debug.logger & debug.flagEncoder and debug.logger('encoder called in %sdef mode, chunk size %s for type %s, value:\n%s' % (not defMode and 'in' or '', maxChunkSize, value.__class__.__name__, value.prettyPrint()))
|
||||
tagSet = value.getTagSet()
|
||||
if len(tagSet) > 1:
|
||||
concreteEncoder = explicitlyTaggedItemEncoder
|
||||
else:
|
||||
if value.typeId is not None and value.typeId in self.__typeMap:
|
||||
concreteEncoder = self.__typeMap[value.typeId]
|
||||
elif tagSet in self.__tagMap:
|
||||
concreteEncoder = self.__tagMap[tagSet]
|
||||
else:
|
||||
tagSet = value.baseTagSet
|
||||
if tagSet in self.__tagMap:
|
||||
concreteEncoder = self.__tagMap[tagSet]
|
||||
else:
|
||||
raise Error('No encoder for %s' % (value,))
|
||||
debug.logger & debug.flagEncoder and debug.logger('using value codec %s chosen by %r' % (concreteEncoder.__class__.__name__, tagSet))
|
||||
substrate = concreteEncoder.encode(
|
||||
self, value, defMode, maxChunkSize
|
||||
)
|
||||
debug.logger & debug.flagEncoder and debug.logger('built %s octets of substrate: %s\nencoder completed' % (len(substrate), debug.hexdump(substrate)))
|
||||
return substrate
|
||||
|
||||
encode = Encoder(tagMap, typeMap)
|
8
src/lib/pyasn1/codec/ber/eoo.py
Normal file
8
src/lib/pyasn1/codec/ber/eoo.py
Normal file
|
@ -0,0 +1,8 @@
|
|||
from pyasn1.type import base, tag
|
||||
|
||||
class EndOfOctets(base.AbstractSimpleAsn1Item):
|
||||
defaultValue = 0
|
||||
tagSet = tag.initTagSet(
|
||||
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x00)
|
||||
)
|
||||
endOfOctets = EndOfOctets()
|
1
src/lib/pyasn1/codec/cer/__init__.py
Normal file
1
src/lib/pyasn1/codec/cer/__init__.py
Normal file
|
@ -0,0 +1 @@
|
|||
# This file is necessary to make this directory a package.
|
35
src/lib/pyasn1/codec/cer/decoder.py
Normal file
35
src/lib/pyasn1/codec/cer/decoder.py
Normal file
|
@ -0,0 +1,35 @@
|
|||
# CER decoder
|
||||
from pyasn1.type import univ
|
||||
from pyasn1.codec.ber import decoder
|
||||
from pyasn1.compat.octets import oct2int
|
||||
from pyasn1 import error
|
||||
|
||||
class BooleanDecoder(decoder.AbstractSimpleDecoder):
|
||||
protoComponent = univ.Boolean(0)
|
||||
def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, length,
|
||||
state, decodeFun, substrateFun):
|
||||
head, tail = substrate[:length], substrate[length:]
|
||||
if not head:
|
||||
raise error.PyAsn1Error('Empty substrate')
|
||||
byte = oct2int(head[0])
|
||||
# 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
|
||||
# in http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf
|
||||
if byte == 0xff:
|
||||
value = 1
|
||||
elif byte == 0x00:
|
||||
value = 0
|
||||
else:
|
||||
raise error.PyAsn1Error('Boolean CER violation: %s' % byte)
|
||||
return self._createComponent(asn1Spec, tagSet, value), tail
|
||||
|
||||
tagMap = decoder.tagMap.copy()
|
||||
tagMap.update({
|
||||
univ.Boolean.tagSet: BooleanDecoder()
|
||||
})
|
||||
|
||||
typeMap = decoder.typeMap
|
||||
|
||||
class Decoder(decoder.Decoder): pass
|
||||
|
||||
decode = Decoder(tagMap, decoder.typeMap)
|
87
src/lib/pyasn1/codec/cer/encoder.py
Normal file
87
src/lib/pyasn1/codec/cer/encoder.py
Normal file
|
@ -0,0 +1,87 @@
|
|||
# CER encoder
|
||||
from pyasn1.type import univ
|
||||
from pyasn1.codec.ber import encoder
|
||||
from pyasn1.compat.octets import int2oct, null
|
||||
|
||||
class BooleanEncoder(encoder.IntegerEncoder):
|
||||
def encodeValue(self, encodeFun, client, defMode, maxChunkSize):
|
||||
if client == 0:
|
||||
substrate = int2oct(0)
|
||||
else:
|
||||
substrate = int2oct(255)
|
||||
return substrate, 0
|
||||
|
||||
class BitStringEncoder(encoder.BitStringEncoder):
|
||||
def encodeValue(self, encodeFun, client, defMode, maxChunkSize):
|
||||
return encoder.BitStringEncoder.encodeValue(
|
||||
self, encodeFun, client, defMode, 1000
|
||||
)
|
||||
|
||||
class OctetStringEncoder(encoder.OctetStringEncoder):
|
||||
def encodeValue(self, encodeFun, client, defMode, maxChunkSize):
|
||||
return encoder.OctetStringEncoder.encodeValue(
|
||||
self, encodeFun, client, defMode, 1000
|
||||
)
|
||||
|
||||
# specialized RealEncoder here
|
||||
# specialized GeneralStringEncoder here
|
||||
# specialized GeneralizedTimeEncoder here
|
||||
# specialized UTCTimeEncoder here
|
||||
|
||||
class SetOfEncoder(encoder.SequenceOfEncoder):
|
||||
def encodeValue(self, encodeFun, client, defMode, maxChunkSize):
|
||||
if isinstance(client, univ.SequenceAndSetBase):
|
||||
client.setDefaultComponents()
|
||||
client.verifySizeSpec()
|
||||
substrate = null; idx = len(client)
|
||||
# This is certainly a hack but how else do I distinguish SetOf
|
||||
# from Set if they have the same tags&constraints?
|
||||
if isinstance(client, univ.SequenceAndSetBase):
|
||||
# Set
|
||||
comps = []
|
||||
while idx > 0:
|
||||
idx = idx - 1
|
||||
if client[idx] is None: # Optional component
|
||||
continue
|
||||
if client.getDefaultComponentByPosition(idx) == client[idx]:
|
||||
continue
|
||||
comps.append(client[idx])
|
||||
comps.sort(key=lambda x: isinstance(x, univ.Choice) and \
|
||||
x.getMinTagSet() or x.getTagSet())
|
||||
for c in comps:
|
||||
substrate += encodeFun(c, defMode, maxChunkSize)
|
||||
else:
|
||||
# SetOf
|
||||
compSubs = []
|
||||
while idx > 0:
|
||||
idx = idx - 1
|
||||
compSubs.append(
|
||||
encodeFun(client[idx], defMode, maxChunkSize)
|
||||
)
|
||||
compSubs.sort() # perhaps padding's not needed
|
||||
substrate = null
|
||||
for compSub in compSubs:
|
||||
substrate += compSub
|
||||
return substrate, 1
|
||||
|
||||
tagMap = encoder.tagMap.copy()
|
||||
tagMap.update({
|
||||
univ.Boolean.tagSet: BooleanEncoder(),
|
||||
univ.BitString.tagSet: BitStringEncoder(),
|
||||
univ.OctetString.tagSet: OctetStringEncoder(),
|
||||
univ.SetOf().tagSet: SetOfEncoder() # conflcts with Set
|
||||
})
|
||||
|
||||
typeMap = encoder.typeMap.copy()
|
||||
typeMap.update({
|
||||
univ.Set.typeId: SetOfEncoder(),
|
||||
univ.SetOf.typeId: SetOfEncoder()
|
||||
})
|
||||
|
||||
class Encoder(encoder.Encoder):
|
||||
def __call__(self, client, defMode=0, maxChunkSize=0):
|
||||
return encoder.Encoder.__call__(self, client, defMode, maxChunkSize)
|
||||
|
||||
encode = Encoder(tagMap, typeMap)
|
||||
|
||||
# EncoderFactory queries class instance and builds a map of tags -> encoders
|
1
src/lib/pyasn1/codec/der/__init__.py
Normal file
1
src/lib/pyasn1/codec/der/__init__.py
Normal file
|
@ -0,0 +1 @@
|
|||
# This file is necessary to make this directory a package.
|
9
src/lib/pyasn1/codec/der/decoder.py
Normal file
9
src/lib/pyasn1/codec/der/decoder.py
Normal file
|
@ -0,0 +1,9 @@
|
|||
# DER decoder
|
||||
from pyasn1.type import univ
|
||||
from pyasn1.codec.cer import decoder
|
||||
|
||||
tagMap = decoder.tagMap
|
||||
typeMap = decoder.typeMap
|
||||
Decoder = decoder.Decoder
|
||||
|
||||
decode = Decoder(tagMap, typeMap)
|
28
src/lib/pyasn1/codec/der/encoder.py
Normal file
28
src/lib/pyasn1/codec/der/encoder.py
Normal file
|
@ -0,0 +1,28 @@
|
|||
# DER encoder
|
||||
from pyasn1.type import univ
|
||||
from pyasn1.codec.cer import encoder
|
||||
|
||||
class SetOfEncoder(encoder.SetOfEncoder):
|
||||
def _cmpSetComponents(self, c1, c2):
|
||||
tagSet1 = isinstance(c1, univ.Choice) and \
|
||||
c1.getEffectiveTagSet() or c1.getTagSet()
|
||||
tagSet2 = isinstance(c2, univ.Choice) and \
|
||||
c2.getEffectiveTagSet() or c2.getTagSet()
|
||||
return cmp(tagSet1, tagSet2)
|
||||
|
||||
tagMap = encoder.tagMap.copy()
|
||||
tagMap.update({
|
||||
# Overload CER encodrs with BER ones (a bit hackerish XXX)
|
||||
univ.BitString.tagSet: encoder.encoder.BitStringEncoder(),
|
||||
univ.OctetString.tagSet: encoder.encoder.OctetStringEncoder(),
|
||||
# Set & SetOf have same tags
|
||||
univ.SetOf().tagSet: SetOfEncoder()
|
||||
})
|
||||
|
||||
typeMap = encoder.typeMap
|
||||
|
||||
class Encoder(encoder.Encoder):
|
||||
def __call__(self, client, defMode=1, maxChunkSize=0):
|
||||
return encoder.Encoder.__call__(self, client, defMode, maxChunkSize)
|
||||
|
||||
encode = Encoder(tagMap, typeMap)
|
1
src/lib/pyasn1/compat/__init__.py
Normal file
1
src/lib/pyasn1/compat/__init__.py
Normal file
|
@ -0,0 +1 @@
|
|||
# This file is necessary to make this directory a package.
|
20
src/lib/pyasn1/compat/octets.py
Normal file
20
src/lib/pyasn1/compat/octets.py
Normal file
|
@ -0,0 +1,20 @@
|
|||
from sys import version_info
|
||||
|
||||
if version_info[0] <= 2:
|
||||
int2oct = chr
|
||||
ints2octs = lambda s: ''.join([ int2oct(x) for x in s ])
|
||||
null = ''
|
||||
oct2int = ord
|
||||
octs2ints = lambda s: [ oct2int(x) for x in s ]
|
||||
str2octs = lambda x: x
|
||||
octs2str = lambda x: x
|
||||
isOctetsType = lambda s: isinstance(s, str)
|
||||
else:
|
||||
ints2octs = bytes
|
||||
int2oct = lambda x: ints2octs((x,))
|
||||
null = ints2octs()
|
||||
oct2int = lambda x: x
|
||||
octs2ints = lambda s: [ x for x in s ]
|
||||
str2octs = lambda x: x.encode()
|
||||
octs2str = lambda x: x.decode()
|
||||
isOctetsType = lambda s: isinstance(s, bytes)
|
65
src/lib/pyasn1/debug.py
Normal file
65
src/lib/pyasn1/debug.py
Normal file
|
@ -0,0 +1,65 @@
|
|||
import sys
|
||||
from pyasn1.compat.octets import octs2ints
|
||||
from pyasn1 import error
|
||||
from pyasn1 import __version__
|
||||
|
||||
flagNone = 0x0000
|
||||
flagEncoder = 0x0001
|
||||
flagDecoder = 0x0002
|
||||
flagAll = 0xffff
|
||||
|
||||
flagMap = {
|
||||
'encoder': flagEncoder,
|
||||
'decoder': flagDecoder,
|
||||
'all': flagAll
|
||||
}
|
||||
|
||||
class Debug:
|
||||
defaultPrinter = sys.stderr.write
|
||||
def __init__(self, *flags):
|
||||
self._flags = flagNone
|
||||
self._printer = self.defaultPrinter
|
||||
self('running pyasn1 version %s' % __version__)
|
||||
for f in flags:
|
||||
if f not in flagMap:
|
||||
raise error.PyAsn1Error('bad debug flag %s' % (f,))
|
||||
self._flags = self._flags | flagMap[f]
|
||||
self('debug category \'%s\' enabled' % f)
|
||||
|
||||
def __str__(self):
|
||||
return 'logger %s, flags %x' % (self._printer, self._flags)
|
||||
|
||||
def __call__(self, msg):
|
||||
self._printer('DBG: %s\n' % msg)
|
||||
|
||||
def __and__(self, flag):
|
||||
return self._flags & flag
|
||||
|
||||
def __rand__(self, flag):
|
||||
return flag & self._flags
|
||||
|
||||
logger = 0
|
||||
|
||||
def setLogger(l):
|
||||
global logger
|
||||
logger = l
|
||||
|
||||
def hexdump(octets):
|
||||
return ' '.join(
|
||||
[ '%s%.2X' % (n%16 == 0 and ('\n%.5d: ' % n) or '', x)
|
||||
for n,x in zip(range(len(octets)), octs2ints(octets)) ]
|
||||
)
|
||||
|
||||
class Scope:
|
||||
def __init__(self):
|
||||
self._list = []
|
||||
|
||||
def __str__(self): return '.'.join(self._list)
|
||||
|
||||
def push(self, token):
|
||||
self._list.append(token)
|
||||
|
||||
def pop(self):
|
||||
return self._list.pop()
|
||||
|
||||
scope = Scope()
|
3
src/lib/pyasn1/error.py
Normal file
3
src/lib/pyasn1/error.py
Normal file
|
@ -0,0 +1,3 @@
|
|||
class PyAsn1Error(Exception): pass
|
||||
class ValueConstraintError(PyAsn1Error): pass
|
||||
class SubstrateUnderrunError(PyAsn1Error): pass
|
1
src/lib/pyasn1/type/__init__.py
Normal file
1
src/lib/pyasn1/type/__init__.py
Normal file
|
@ -0,0 +1 @@
|
|||
# This file is necessary to make this directory a package.
|
249
src/lib/pyasn1/type/base.py
Normal file
249
src/lib/pyasn1/type/base.py
Normal file
|
@ -0,0 +1,249 @@
|
|||
# Base classes for ASN.1 types
|
||||
import sys
|
||||
from pyasn1.type import constraint, tagmap
|
||||
from pyasn1 import error
|
||||
|
||||
class Asn1Item: pass
|
||||
|
||||
class Asn1ItemBase(Asn1Item):
|
||||
# Set of tags for this ASN.1 type
|
||||
tagSet = ()
|
||||
|
||||
# A list of constraint.Constraint instances for checking values
|
||||
subtypeSpec = constraint.ConstraintsIntersection()
|
||||
|
||||
# Used for ambiguous ASN.1 types identification
|
||||
typeId = None
|
||||
|
||||
def __init__(self, tagSet=None, subtypeSpec=None):
|
||||
if tagSet is None:
|
||||
self._tagSet = self.tagSet
|
||||
else:
|
||||
self._tagSet = tagSet
|
||||
if subtypeSpec is None:
|
||||
self._subtypeSpec = self.subtypeSpec
|
||||
else:
|
||||
self._subtypeSpec = subtypeSpec
|
||||
|
||||
def _verifySubtypeSpec(self, value, idx=None):
|
||||
try:
|
||||
self._subtypeSpec(value, idx)
|
||||
except error.PyAsn1Error:
|
||||
c, i, t = sys.exc_info()
|
||||
raise c('%s at %s' % (i, self.__class__.__name__))
|
||||
|
||||
def getSubtypeSpec(self): return self._subtypeSpec
|
||||
|
||||
def getTagSet(self): return self._tagSet
|
||||
def getEffectiveTagSet(self): return self._tagSet # used by untagged types
|
||||
def getTagMap(self): return tagmap.TagMap({self._tagSet: self})
|
||||
|
||||
def isSameTypeWith(self, other):
|
||||
return self is other or \
|
||||
self._tagSet == other.getTagSet() and \
|
||||
self._subtypeSpec == other.getSubtypeSpec()
|
||||
def isSuperTypeOf(self, other):
|
||||
"""Returns true if argument is a ASN1 subtype of ourselves"""
|
||||
return self._tagSet.isSuperTagSetOf(other.getTagSet()) and \
|
||||
self._subtypeSpec.isSuperTypeOf(other.getSubtypeSpec())
|
||||
|
||||
class __NoValue:
|
||||
def __getattr__(self, attr):
|
||||
raise error.PyAsn1Error('No value for %s()' % attr)
|
||||
def __getitem__(self, i):
|
||||
raise error.PyAsn1Error('No value')
|
||||
|
||||
noValue = __NoValue()
|
||||
|
||||
# Base class for "simple" ASN.1 objects. These are immutable.
|
||||
class AbstractSimpleAsn1Item(Asn1ItemBase):
|
||||
defaultValue = noValue
|
||||
def __init__(self, value=None, tagSet=None, subtypeSpec=None):
|
||||
Asn1ItemBase.__init__(self, tagSet, subtypeSpec)
|
||||
if value is None or value is noValue:
|
||||
value = self.defaultValue
|
||||
if value is None or value is noValue:
|
||||
self.__hashedValue = value = noValue
|
||||
else:
|
||||
value = self.prettyIn(value)
|
||||
self._verifySubtypeSpec(value)
|
||||
self.__hashedValue = hash(value)
|
||||
self._value = value
|
||||
self._len = None
|
||||
|
||||
def __repr__(self):
|
||||
if self._value is noValue:
|
||||
return self.__class__.__name__ + '()'
|
||||
else:
|
||||
return self.__class__.__name__ + '(%s)' % (self.prettyOut(self._value),)
|
||||
def __str__(self): return str(self._value)
|
||||
def __eq__(self, other):
|
||||
return self is other and True or self._value == other
|
||||
def __ne__(self, other): return self._value != other
|
||||
def __lt__(self, other): return self._value < other
|
||||
def __le__(self, other): return self._value <= other
|
||||
def __gt__(self, other): return self._value > other
|
||||
def __ge__(self, other): return self._value >= other
|
||||
if sys.version_info[0] <= 2:
|
||||
def __nonzero__(self): return bool(self._value)
|
||||
else:
|
||||
def __bool__(self): return bool(self._value)
|
||||
def __hash__(self): return self.__hashedValue
|
||||
|
||||
def clone(self, value=None, tagSet=None, subtypeSpec=None):
|
||||
if value is None and tagSet is None and subtypeSpec is None:
|
||||
return self
|
||||
if value is None:
|
||||
value = self._value
|
||||
if tagSet is None:
|
||||
tagSet = self._tagSet
|
||||
if subtypeSpec is None:
|
||||
subtypeSpec = self._subtypeSpec
|
||||
return self.__class__(value, tagSet, subtypeSpec)
|
||||
|
||||
def subtype(self, value=None, implicitTag=None, explicitTag=None,
|
||||
subtypeSpec=None):
|
||||
if value is None:
|
||||
value = self._value
|
||||
if implicitTag is not None:
|
||||
tagSet = self._tagSet.tagImplicitly(implicitTag)
|
||||
elif explicitTag is not None:
|
||||
tagSet = self._tagSet.tagExplicitly(explicitTag)
|
||||
else:
|
||||
tagSet = self._tagSet
|
||||
if subtypeSpec is None:
|
||||
subtypeSpec = self._subtypeSpec
|
||||
else:
|
||||
subtypeSpec = subtypeSpec + self._subtypeSpec
|
||||
return self.__class__(value, tagSet, subtypeSpec)
|
||||
|
||||
def prettyIn(self, value): return value
|
||||
def prettyOut(self, value): return str(value)
|
||||
|
||||
def prettyPrint(self, scope=0):
|
||||
if self._value is noValue:
|
||||
return '<no value>'
|
||||
else:
|
||||
return self.prettyOut(self._value)
|
||||
|
||||
# XXX Compatibility stub
|
||||
def prettyPrinter(self, scope=0): return self.prettyPrint(scope)
|
||||
|
||||
#
|
||||
# Constructed types:
|
||||
# * There are five of them: Sequence, SequenceOf/SetOf, Set and Choice
|
||||
# * ASN1 types and values are represened by Python class instances
|
||||
# * Value initialization is made for defaulted components only
|
||||
# * Primary method of component addressing is by-position. Data model for base
|
||||
# type is Python sequence. Additional type-specific addressing methods
|
||||
# may be implemented for particular types.
|
||||
# * SequenceOf and SetOf types do not implement any additional methods
|
||||
# * Sequence, Set and Choice types also implement by-identifier addressing
|
||||
# * Sequence, Set and Choice types also implement by-asn1-type (tag) addressing
|
||||
# * Sequence and Set types may include optional and defaulted
|
||||
# components
|
||||
# * Constructed types hold a reference to component types used for value
|
||||
# verification and ordering.
|
||||
# * Component type is a scalar type for SequenceOf/SetOf types and a list
|
||||
# of types for Sequence/Set/Choice.
|
||||
#
|
||||
|
||||
class AbstractConstructedAsn1Item(Asn1ItemBase):
|
||||
componentType = None
|
||||
sizeSpec = constraint.ConstraintsIntersection()
|
||||
def __init__(self, componentType=None, tagSet=None,
|
||||
subtypeSpec=None, sizeSpec=None):
|
||||
Asn1ItemBase.__init__(self, tagSet, subtypeSpec)
|
||||
if componentType is None:
|
||||
self._componentType = self.componentType
|
||||
else:
|
||||
self._componentType = componentType
|
||||
if sizeSpec is None:
|
||||
self._sizeSpec = self.sizeSpec
|
||||
else:
|
||||
self._sizeSpec = sizeSpec
|
||||
self._componentValues = []
|
||||
self._componentValuesSet = 0
|
||||
|
||||
def __repr__(self):
|
||||
r = self.__class__.__name__ + '()'
|
||||
for idx in range(len(self._componentValues)):
|
||||
if self._componentValues[idx] is None:
|
||||
continue
|
||||
r = r + '.setComponentByPosition(%s, %r)' % (
|
||||
idx, self._componentValues[idx]
|
||||
)
|
||||
return r
|
||||
|
||||
def __eq__(self, other):
|
||||
return self is other and True or self._componentValues == other
|
||||
def __ne__(self, other): return self._componentValues != other
|
||||
def __lt__(self, other): return self._componentValues < other
|
||||
def __le__(self, other): return self._componentValues <= other
|
||||
def __gt__(self, other): return self._componentValues > other
|
||||
def __ge__(self, other): return self._componentValues >= other
|
||||
if sys.version_info[0] <= 2:
|
||||
def __nonzero__(self): return bool(self._componentValues)
|
||||
else:
|
||||
def __bool__(self): return bool(self._componentValues)
|
||||
|
||||
def getComponentTagMap(self):
|
||||
raise error.PyAsn1Error('Method not implemented')
|
||||
|
||||
def _cloneComponentValues(self, myClone, cloneValueFlag): pass
|
||||
|
||||
def clone(self, tagSet=None, subtypeSpec=None, sizeSpec=None,
|
||||
cloneValueFlag=None):
|
||||
if tagSet is None:
|
||||
tagSet = self._tagSet
|
||||
if subtypeSpec is None:
|
||||
subtypeSpec = self._subtypeSpec
|
||||
if sizeSpec is None:
|
||||
sizeSpec = self._sizeSpec
|
||||
r = self.__class__(self._componentType, tagSet, subtypeSpec, sizeSpec)
|
||||
if cloneValueFlag:
|
||||
self._cloneComponentValues(r, cloneValueFlag)
|
||||
return r
|
||||
|
||||
def subtype(self, implicitTag=None, explicitTag=None, subtypeSpec=None,
|
||||
sizeSpec=None, cloneValueFlag=None):
|
||||
if implicitTag is not None:
|
||||
tagSet = self._tagSet.tagImplicitly(implicitTag)
|
||||
elif explicitTag is not None:
|
||||
tagSet = self._tagSet.tagExplicitly(explicitTag)
|
||||
else:
|
||||
tagSet = self._tagSet
|
||||
if subtypeSpec is None:
|
||||
subtypeSpec = self._subtypeSpec
|
||||
else:
|
||||
subtypeSpec = subtypeSpec + self._subtypeSpec
|
||||
if sizeSpec is None:
|
||||
sizeSpec = self._sizeSpec
|
||||
else:
|
||||
sizeSpec = sizeSpec + self._sizeSpec
|
||||
r = self.__class__(self._componentType, tagSet, subtypeSpec, sizeSpec)
|
||||
if cloneValueFlag:
|
||||
self._cloneComponentValues(r, cloneValueFlag)
|
||||
return r
|
||||
|
||||
def _verifyComponent(self, idx, value): pass
|
||||
|
||||
def verifySizeSpec(self): self._sizeSpec(self)
|
||||
|
||||
def getComponentByPosition(self, idx):
|
||||
raise error.PyAsn1Error('Method not implemented')
|
||||
def setComponentByPosition(self, idx, value, verifyConstraints=True):
|
||||
raise error.PyAsn1Error('Method not implemented')
|
||||
|
||||
def getComponentType(self): return self._componentType
|
||||
|
||||
def __getitem__(self, idx): return self.getComponentByPosition(idx)
|
||||
def __setitem__(self, idx, value): self.setComponentByPosition(idx, value)
|
||||
|
||||
def __len__(self): return len(self._componentValues)
|
||||
|
||||
def clear(self):
|
||||
self._componentValues = []
|
||||
self._componentValuesSet = 0
|
||||
|
||||
def setDefaultComponents(self): pass
|
61
src/lib/pyasn1/type/char.py
Normal file
61
src/lib/pyasn1/type/char.py
Normal file
|
@ -0,0 +1,61 @@
|
|||
# ASN.1 "character string" types
|
||||
from pyasn1.type import univ, tag
|
||||
|
||||
class UTF8String(univ.OctetString):
|
||||
tagSet = univ.OctetString.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 12)
|
||||
)
|
||||
encoding = "utf-8"
|
||||
|
||||
class NumericString(univ.OctetString):
|
||||
tagSet = univ.OctetString.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 18)
|
||||
)
|
||||
|
||||
class PrintableString(univ.OctetString):
|
||||
tagSet = univ.OctetString.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 19)
|
||||
)
|
||||
|
||||
class TeletexString(univ.OctetString):
|
||||
tagSet = univ.OctetString.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 20)
|
||||
)
|
||||
|
||||
|
||||
class VideotexString(univ.OctetString):
|
||||
tagSet = univ.OctetString.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 21)
|
||||
)
|
||||
|
||||
class IA5String(univ.OctetString):
|
||||
tagSet = univ.OctetString.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 22)
|
||||
)
|
||||
|
||||
class GraphicString(univ.OctetString):
|
||||
tagSet = univ.OctetString.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 25)
|
||||
)
|
||||
|
||||
class VisibleString(univ.OctetString):
|
||||
tagSet = univ.OctetString.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 26)
|
||||
)
|
||||
|
||||
class GeneralString(univ.OctetString):
|
||||
tagSet = univ.OctetString.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 27)
|
||||
)
|
||||
|
||||
class UniversalString(univ.OctetString):
|
||||
tagSet = univ.OctetString.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 28)
|
||||
)
|
||||
encoding = "utf-32-be"
|
||||
|
||||
class BMPString(univ.OctetString):
|
||||
tagSet = univ.OctetString.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 30)
|
||||
)
|
||||
encoding = "utf-16-be"
|
200
src/lib/pyasn1/type/constraint.py
Normal file
200
src/lib/pyasn1/type/constraint.py
Normal file
|
@ -0,0 +1,200 @@
|
|||
#
|
||||
# ASN.1 subtype constraints classes.
|
||||
#
|
||||
# Constraints are relatively rare, but every ASN1 object
|
||||
# is doing checks all the time for whether they have any
|
||||
# constraints and whether they are applicable to the object.
|
||||
#
|
||||
# What we're going to do is define objects/functions that
|
||||
# can be called unconditionally if they are present, and that
|
||||
# are simply not present if there are no constraints.
|
||||
#
|
||||
# Original concept and code by Mike C. Fletcher.
|
||||
#
|
||||
import sys
|
||||
from pyasn1.type import error
|
||||
|
||||
class AbstractConstraint:
|
||||
"""Abstract base-class for constraint objects
|
||||
|
||||
Constraints should be stored in a simple sequence in the
|
||||
namespace of their client Asn1Item sub-classes.
|
||||
"""
|
||||
def __init__(self, *values):
|
||||
self._valueMap = {}
|
||||
self._setValues(values)
|
||||
self.__hashedValues = None
|
||||
def __call__(self, value, idx=None):
|
||||
try:
|
||||
self._testValue(value, idx)
|
||||
except error.ValueConstraintError:
|
||||
raise error.ValueConstraintError(
|
||||
'%s failed at: \"%s\"' % (self, sys.exc_info()[1])
|
||||
)
|
||||
def __repr__(self):
|
||||
return '%s(%s)' % (
|
||||
self.__class__.__name__,
|
||||
', '.join([repr(x) for x in self._values])
|
||||
)
|
||||
def __eq__(self, other):
|
||||
return self is other and True or self._values == other
|
||||
def __ne__(self, other): return self._values != other
|
||||
def __lt__(self, other): return self._values < other
|
||||
def __le__(self, other): return self._values <= other
|
||||
def __gt__(self, other): return self._values > other
|
||||
def __ge__(self, other): return self._values >= other
|
||||
if sys.version_info[0] <= 2:
|
||||
def __nonzero__(self): return bool(self._values)
|
||||
else:
|
||||
def __bool__(self): return bool(self._values)
|
||||
|
||||
def __hash__(self):
|
||||
if self.__hashedValues is None:
|
||||
self.__hashedValues = hash((self.__class__.__name__, self._values))
|
||||
return self.__hashedValues
|
||||
|
||||
def _setValues(self, values): self._values = values
|
||||
def _testValue(self, value, idx):
|
||||
raise error.ValueConstraintError(value)
|
||||
|
||||
# Constraints derivation logic
|
||||
def getValueMap(self): return self._valueMap
|
||||
def isSuperTypeOf(self, otherConstraint):
|
||||
return self in otherConstraint.getValueMap() or \
|
||||
otherConstraint is self or otherConstraint == self
|
||||
def isSubTypeOf(self, otherConstraint):
|
||||
return otherConstraint in self._valueMap or \
|
||||
otherConstraint is self or otherConstraint == self
|
||||
|
||||
class SingleValueConstraint(AbstractConstraint):
|
||||
"""Value must be part of defined values constraint"""
|
||||
def _testValue(self, value, idx):
|
||||
# XXX index vals for performance?
|
||||
if value not in self._values:
|
||||
raise error.ValueConstraintError(value)
|
||||
|
||||
class ContainedSubtypeConstraint(AbstractConstraint):
|
||||
"""Value must satisfy all of defined set of constraints"""
|
||||
def _testValue(self, value, idx):
|
||||
for c in self._values:
|
||||
c(value, idx)
|
||||
|
||||
class ValueRangeConstraint(AbstractConstraint):
|
||||
"""Value must be within start and stop values (inclusive)"""
|
||||
def _testValue(self, value, idx):
|
||||
if value < self.start or value > self.stop:
|
||||
raise error.ValueConstraintError(value)
|
||||
|
||||
def _setValues(self, values):
|
||||
if len(values) != 2:
|
||||
raise error.PyAsn1Error(
|
||||
'%s: bad constraint values' % (self.__class__.__name__,)
|
||||
)
|
||||
self.start, self.stop = values
|
||||
if self.start > self.stop:
|
||||
raise error.PyAsn1Error(
|
||||
'%s: screwed constraint values (start > stop): %s > %s' % (
|
||||
self.__class__.__name__,
|
||||
self.start, self.stop
|
||||
)
|
||||
)
|
||||
AbstractConstraint._setValues(self, values)
|
||||
|
||||
class ValueSizeConstraint(ValueRangeConstraint):
|
||||
"""len(value) must be within start and stop values (inclusive)"""
|
||||
def _testValue(self, value, idx):
|
||||
l = len(value)
|
||||
if l < self.start or l > self.stop:
|
||||
raise error.ValueConstraintError(value)
|
||||
|
||||
class PermittedAlphabetConstraint(SingleValueConstraint):
|
||||
def _setValues(self, values):
|
||||
self._values = ()
|
||||
for v in values:
|
||||
self._values = self._values + tuple(v)
|
||||
|
||||
def _testValue(self, value, idx):
|
||||
for v in value:
|
||||
if v not in self._values:
|
||||
raise error.ValueConstraintError(value)
|
||||
|
||||
# This is a bit kludgy, meaning two op modes within a single constraing
|
||||
class InnerTypeConstraint(AbstractConstraint):
|
||||
"""Value must satisfy type and presense constraints"""
|
||||
def _testValue(self, value, idx):
|
||||
if self.__singleTypeConstraint:
|
||||
self.__singleTypeConstraint(value)
|
||||
elif self.__multipleTypeConstraint:
|
||||
if idx not in self.__multipleTypeConstraint:
|
||||
raise error.ValueConstraintError(value)
|
||||
constraint, status = self.__multipleTypeConstraint[idx]
|
||||
if status == 'ABSENT': # XXX presense is not checked!
|
||||
raise error.ValueConstraintError(value)
|
||||
constraint(value)
|
||||
|
||||
def _setValues(self, values):
|
||||
self.__multipleTypeConstraint = {}
|
||||
self.__singleTypeConstraint = None
|
||||
for v in values:
|
||||
if isinstance(v, tuple):
|
||||
self.__multipleTypeConstraint[v[0]] = v[1], v[2]
|
||||
else:
|
||||
self.__singleTypeConstraint = v
|
||||
AbstractConstraint._setValues(self, values)
|
||||
|
||||
# Boolean ops on constraints
|
||||
|
||||
class ConstraintsExclusion(AbstractConstraint):
|
||||
"""Value must not fit the single constraint"""
|
||||
def _testValue(self, value, idx):
|
||||
try:
|
||||
self._values[0](value, idx)
|
||||
except error.ValueConstraintError:
|
||||
return
|
||||
else:
|
||||
raise error.ValueConstraintError(value)
|
||||
|
||||
def _setValues(self, values):
|
||||
if len(values) != 1:
|
||||
raise error.PyAsn1Error('Single constraint expected')
|
||||
AbstractConstraint._setValues(self, values)
|
||||
|
||||
class AbstractConstraintSet(AbstractConstraint):
|
||||
"""Value must not satisfy the single constraint"""
|
||||
def __getitem__(self, idx): return self._values[idx]
|
||||
|
||||
def __add__(self, value): return self.__class__(self, value)
|
||||
def __radd__(self, value): return self.__class__(self, value)
|
||||
|
||||
def __len__(self): return len(self._values)
|
||||
|
||||
# Constraints inclusion in sets
|
||||
|
||||
def _setValues(self, values):
|
||||
self._values = values
|
||||
for v in values:
|
||||
self._valueMap[v] = 1
|
||||
self._valueMap.update(v.getValueMap())
|
||||
|
||||
class ConstraintsIntersection(AbstractConstraintSet):
|
||||
"""Value must satisfy all constraints"""
|
||||
def _testValue(self, value, idx):
|
||||
for v in self._values:
|
||||
v(value, idx)
|
||||
|
||||
class ConstraintsUnion(AbstractConstraintSet):
|
||||
"""Value must satisfy at least one constraint"""
|
||||
def _testValue(self, value, idx):
|
||||
for v in self._values:
|
||||
try:
|
||||
v(value, idx)
|
||||
except error.ValueConstraintError:
|
||||
pass
|
||||
else:
|
||||
return
|
||||
raise error.ValueConstraintError(
|
||||
'all of %s failed for \"%s\"' % (self._values, value)
|
||||
)
|
||||
|
||||
# XXX
|
||||
# add tests for type check
|
3
src/lib/pyasn1/type/error.py
Normal file
3
src/lib/pyasn1/type/error.py
Normal file
|
@ -0,0 +1,3 @@
|
|||
from pyasn1.error import PyAsn1Error
|
||||
|
||||
class ValueConstraintError(PyAsn1Error): pass
|
132
src/lib/pyasn1/type/namedtype.py
Normal file
132
src/lib/pyasn1/type/namedtype.py
Normal file
|
@ -0,0 +1,132 @@
|
|||
# NamedType specification for constructed types
|
||||
import sys
|
||||
from pyasn1.type import tagmap
|
||||
from pyasn1 import error
|
||||
|
||||
class NamedType:
|
||||
isOptional = 0
|
||||
isDefaulted = 0
|
||||
def __init__(self, name, t):
|
||||
self.__name = name; self.__type = t
|
||||
def __repr__(self): return '%s(%s, %s)' % (
|
||||
self.__class__.__name__, self.__name, self.__type
|
||||
)
|
||||
def getType(self): return self.__type
|
||||
def getName(self): return self.__name
|
||||
def __getitem__(self, idx):
|
||||
if idx == 0: return self.__name
|
||||
if idx == 1: return self.__type
|
||||
raise IndexError()
|
||||
|
||||
class OptionalNamedType(NamedType):
|
||||
isOptional = 1
|
||||
class DefaultedNamedType(NamedType):
|
||||
isDefaulted = 1
|
||||
|
||||
class NamedTypes:
|
||||
def __init__(self, *namedTypes):
|
||||
self.__namedTypes = namedTypes
|
||||
self.__namedTypesLen = len(self.__namedTypes)
|
||||
self.__minTagSet = None
|
||||
self.__tagToPosIdx = {}; self.__nameToPosIdx = {}
|
||||
self.__tagMap = { False: None, True: None }
|
||||
self.__ambigiousTypes = {}
|
||||
|
||||
def __repr__(self):
|
||||
r = '%s(' % self.__class__.__name__
|
||||
for n in self.__namedTypes:
|
||||
r = r + '%r, ' % (n,)
|
||||
return r + ')'
|
||||
|
||||
def __getitem__(self, idx): return self.__namedTypes[idx]
|
||||
|
||||
if sys.version_info[0] <= 2:
|
||||
def __nonzero__(self): return bool(self.__namedTypesLen)
|
||||
else:
|
||||
def __bool__(self): return bool(self.__namedTypesLen)
|
||||
def __len__(self): return self.__namedTypesLen
|
||||
|
||||
def getTypeByPosition(self, idx):
|
||||
if idx < 0 or idx >= self.__namedTypesLen:
|
||||
raise error.PyAsn1Error('Type position out of range')
|
||||
else:
|
||||
return self.__namedTypes[idx].getType()
|
||||
|
||||
def getPositionByType(self, tagSet):
|
||||
if not self.__tagToPosIdx:
|
||||
idx = self.__namedTypesLen
|
||||
while idx > 0:
|
||||
idx = idx - 1
|
||||
tagMap = self.__namedTypes[idx].getType().getTagMap()
|
||||
for t in tagMap.getPosMap():
|
||||
if t in self.__tagToPosIdx:
|
||||
raise error.PyAsn1Error('Duplicate type %s' % (t,))
|
||||
self.__tagToPosIdx[t] = idx
|
||||
try:
|
||||
return self.__tagToPosIdx[tagSet]
|
||||
except KeyError:
|
||||
raise error.PyAsn1Error('Type %s not found' % (tagSet,))
|
||||
|
||||
def getNameByPosition(self, idx):
|
||||
try:
|
||||
return self.__namedTypes[idx].getName()
|
||||
except IndexError:
|
||||
raise error.PyAsn1Error('Type position out of range')
|
||||
def getPositionByName(self, name):
|
||||
if not self.__nameToPosIdx:
|
||||
idx = self.__namedTypesLen
|
||||
while idx > 0:
|
||||
idx = idx - 1
|
||||
n = self.__namedTypes[idx].getName()
|
||||
if n in self.__nameToPosIdx:
|
||||
raise error.PyAsn1Error('Duplicate name %s' % (n,))
|
||||
self.__nameToPosIdx[n] = idx
|
||||
try:
|
||||
return self.__nameToPosIdx[name]
|
||||
except KeyError:
|
||||
raise error.PyAsn1Error('Name %s not found' % (name,))
|
||||
|
||||
def __buildAmbigiousTagMap(self):
|
||||
ambigiousTypes = ()
|
||||
idx = self.__namedTypesLen
|
||||
while idx > 0:
|
||||
idx = idx - 1
|
||||
t = self.__namedTypes[idx]
|
||||
if t.isOptional or t.isDefaulted:
|
||||
ambigiousTypes = (t, ) + ambigiousTypes
|
||||
else:
|
||||
ambigiousTypes = (t, )
|
||||
self.__ambigiousTypes[idx] = NamedTypes(*ambigiousTypes)
|
||||
|
||||
def getTagMapNearPosition(self, idx):
|
||||
if not self.__ambigiousTypes: self.__buildAmbigiousTagMap()
|
||||
try:
|
||||
return self.__ambigiousTypes[idx].getTagMap()
|
||||
except KeyError:
|
||||
raise error.PyAsn1Error('Type position out of range')
|
||||
|
||||
def getPositionNearType(self, tagSet, idx):
|
||||
if not self.__ambigiousTypes: self.__buildAmbigiousTagMap()
|
||||
try:
|
||||
return idx+self.__ambigiousTypes[idx].getPositionByType(tagSet)
|
||||
except KeyError:
|
||||
raise error.PyAsn1Error('Type position out of range')
|
||||
|
||||
def genMinTagSet(self):
|
||||
if self.__minTagSet is None:
|
||||
for t in self.__namedTypes:
|
||||
__type = t.getType()
|
||||
tagSet = getattr(__type,'getMinTagSet',__type.getTagSet)()
|
||||
if self.__minTagSet is None or tagSet < self.__minTagSet:
|
||||
self.__minTagSet = tagSet
|
||||
return self.__minTagSet
|
||||
|
||||
def getTagMap(self, uniq=False):
|
||||
if self.__tagMap[uniq] is None:
|
||||
tagMap = tagmap.TagMap()
|
||||
for nt in self.__namedTypes:
|
||||
tagMap = tagMap.clone(
|
||||
nt.getType(), nt.getType().getTagMap(), uniq
|
||||
)
|
||||
self.__tagMap[uniq] = tagMap
|
||||
return self.__tagMap[uniq]
|
46
src/lib/pyasn1/type/namedval.py
Normal file
46
src/lib/pyasn1/type/namedval.py
Normal file
|
@ -0,0 +1,46 @@
|
|||
# ASN.1 named integers
|
||||
from pyasn1 import error
|
||||
|
||||
__all__ = [ 'NamedValues' ]
|
||||
|
||||
class NamedValues:
|
||||
def __init__(self, *namedValues):
|
||||
self.nameToValIdx = {}; self.valToNameIdx = {}
|
||||
self.namedValues = ()
|
||||
automaticVal = 1
|
||||
for namedValue in namedValues:
|
||||
if isinstance(namedValue, tuple):
|
||||
name, val = namedValue
|
||||
else:
|
||||
name = namedValue
|
||||
val = automaticVal
|
||||
if name in self.nameToValIdx:
|
||||
raise error.PyAsn1Error('Duplicate name %s' % (name,))
|
||||
self.nameToValIdx[name] = val
|
||||
if val in self.valToNameIdx:
|
||||
raise error.PyAsn1Error('Duplicate value %s=%s' % (name, val))
|
||||
self.valToNameIdx[val] = name
|
||||
self.namedValues = self.namedValues + ((name, val),)
|
||||
automaticVal = automaticVal + 1
|
||||
def __str__(self): return str(self.namedValues)
|
||||
|
||||
def getName(self, value):
|
||||
if value in self.valToNameIdx:
|
||||
return self.valToNameIdx[value]
|
||||
|
||||
def getValue(self, name):
|
||||
if name in self.nameToValIdx:
|
||||
return self.nameToValIdx[name]
|
||||
|
||||
def __getitem__(self, i): return self.namedValues[i]
|
||||
def __len__(self): return len(self.namedValues)
|
||||
|
||||
def __add__(self, namedValues):
|
||||
return self.__class__(*self.namedValues + namedValues)
|
||||
def __radd__(self, namedValues):
|
||||
return self.__class__(*namedValues + tuple(self))
|
||||
|
||||
def clone(self, *namedValues):
|
||||
return self.__class__(*tuple(self) + namedValues)
|
||||
|
||||
# XXX clone/subtype?
|
122
src/lib/pyasn1/type/tag.py
Normal file
122
src/lib/pyasn1/type/tag.py
Normal file
|
@ -0,0 +1,122 @@
|
|||
# ASN.1 types tags
|
||||
from operator import getitem
|
||||
from pyasn1 import error
|
||||
|
||||
tagClassUniversal = 0x00
|
||||
tagClassApplication = 0x40
|
||||
tagClassContext = 0x80
|
||||
tagClassPrivate = 0xC0
|
||||
|
||||
tagFormatSimple = 0x00
|
||||
tagFormatConstructed = 0x20
|
||||
|
||||
tagCategoryImplicit = 0x01
|
||||
tagCategoryExplicit = 0x02
|
||||
tagCategoryUntagged = 0x04
|
||||
|
||||
class Tag:
|
||||
def __init__(self, tagClass, tagFormat, tagId):
|
||||
if tagId < 0:
|
||||
raise error.PyAsn1Error(
|
||||
'Negative tag ID (%s) not allowed' % (tagId,)
|
||||
)
|
||||
self.__tag = (tagClass, tagFormat, tagId)
|
||||
self.uniq = (tagClass, tagId)
|
||||
self.__hashedUniqTag = hash(self.uniq)
|
||||
|
||||
def __repr__(self):
|
||||
return '%s(tagClass=%s, tagFormat=%s, tagId=%s)' % (
|
||||
(self.__class__.__name__,) + self.__tag
|
||||
)
|
||||
# These is really a hotspot -- expose public "uniq" attribute to save on
|
||||
# function calls
|
||||
def __eq__(self, other): return self.uniq == other.uniq
|
||||
def __ne__(self, other): return self.uniq != other.uniq
|
||||
def __lt__(self, other): return self.uniq < other.uniq
|
||||
def __le__(self, other): return self.uniq <= other.uniq
|
||||
def __gt__(self, other): return self.uniq > other.uniq
|
||||
def __ge__(self, other): return self.uniq >= other.uniq
|
||||
def __hash__(self): return self.__hashedUniqTag
|
||||
def __getitem__(self, idx): return self.__tag[idx]
|
||||
def __and__(self, otherTag):
|
||||
(tagClass, tagFormat, tagId) = otherTag
|
||||
return self.__class__(
|
||||
self.__tag&tagClass, self.__tag&tagFormat, self.__tag&tagId
|
||||
)
|
||||
def __or__(self, otherTag):
|
||||
(tagClass, tagFormat, tagId) = otherTag
|
||||
return self.__class__(
|
||||
self.__tag[0]|tagClass,
|
||||
self.__tag[1]|tagFormat,
|
||||
self.__tag[2]|tagId
|
||||
)
|
||||
def asTuple(self): return self.__tag # __getitem__() is slow
|
||||
|
||||
class TagSet:
|
||||
def __init__(self, baseTag=(), *superTags):
|
||||
self.__baseTag = baseTag
|
||||
self.__superTags = superTags
|
||||
self.__hashedSuperTags = hash(superTags)
|
||||
_uniq = ()
|
||||
for t in superTags:
|
||||
_uniq = _uniq + t.uniq
|
||||
self.uniq = _uniq
|
||||
self.__lenOfSuperTags = len(superTags)
|
||||
|
||||
def __repr__(self):
|
||||
return '%s(%s)' % (
|
||||
self.__class__.__name__,
|
||||
', '.join([repr(x) for x in self.__superTags])
|
||||
)
|
||||
|
||||
def __add__(self, superTag):
|
||||
return self.__class__(
|
||||
self.__baseTag, *self.__superTags + (superTag,)
|
||||
)
|
||||
def __radd__(self, superTag):
|
||||
return self.__class__(
|
||||
self.__baseTag, *(superTag,) + self.__superTags
|
||||
)
|
||||
|
||||
def tagExplicitly(self, superTag):
|
||||
tagClass, tagFormat, tagId = superTag
|
||||
if tagClass == tagClassUniversal:
|
||||
raise error.PyAsn1Error(
|
||||
'Can\'t tag with UNIVERSAL-class tag'
|
||||
)
|
||||
if tagFormat != tagFormatConstructed:
|
||||
superTag = Tag(tagClass, tagFormatConstructed, tagId)
|
||||
return self + superTag
|
||||
|
||||
def tagImplicitly(self, superTag):
|
||||
tagClass, tagFormat, tagId = superTag
|
||||
if self.__superTags:
|
||||
superTag = Tag(tagClass, self.__superTags[-1][1], tagId)
|
||||
return self[:-1] + superTag
|
||||
|
||||
def getBaseTag(self): return self.__baseTag
|
||||
def __getitem__(self, idx):
|
||||
if isinstance(idx, slice):
|
||||
return self.__class__(
|
||||
self.__baseTag, *getitem(self.__superTags, idx)
|
||||
)
|
||||
return self.__superTags[idx]
|
||||
def __eq__(self, other): return self.uniq == other.uniq
|
||||
def __ne__(self, other): return self.uniq != other.uniq
|
||||
def __lt__(self, other): return self.uniq < other.uniq
|
||||
def __le__(self, other): return self.uniq <= other.uniq
|
||||
def __gt__(self, other): return self.uniq > other.uniq
|
||||
def __ge__(self, other): return self.uniq >= other.uniq
|
||||
def __hash__(self): return self.__hashedSuperTags
|
||||
def __len__(self): return self.__lenOfSuperTags
|
||||
def isSuperTagSetOf(self, tagSet):
|
||||
if len(tagSet) < self.__lenOfSuperTags:
|
||||
return
|
||||
idx = self.__lenOfSuperTags - 1
|
||||
while idx >= 0:
|
||||
if self.__superTags[idx] != tagSet[idx]:
|
||||
return
|
||||
idx = idx - 1
|
||||
return 1
|
||||
|
||||
def initTagSet(tag): return TagSet(tag, tag)
|
52
src/lib/pyasn1/type/tagmap.py
Normal file
52
src/lib/pyasn1/type/tagmap.py
Normal file
|
@ -0,0 +1,52 @@
|
|||
from pyasn1 import error
|
||||
|
||||
class TagMap:
|
||||
def __init__(self, posMap={}, negMap={}, defType=None):
|
||||
self.__posMap = posMap.copy()
|
||||
self.__negMap = negMap.copy()
|
||||
self.__defType = defType
|
||||
|
||||
def __contains__(self, tagSet):
|
||||
return tagSet in self.__posMap or \
|
||||
self.__defType is not None and tagSet not in self.__negMap
|
||||
|
||||
def __getitem__(self, tagSet):
|
||||
if tagSet in self.__posMap:
|
||||
return self.__posMap[tagSet]
|
||||
elif tagSet in self.__negMap:
|
||||
raise error.PyAsn1Error('Key in negative map')
|
||||
elif self.__defType is not None:
|
||||
return self.__defType
|
||||
else:
|
||||
raise KeyError()
|
||||
|
||||
def __repr__(self):
|
||||
s = '%r/%r' % (self.__posMap, self.__negMap)
|
||||
if self.__defType is not None:
|
||||
s = s + '/%r' % (self.__defType,)
|
||||
return s
|
||||
|
||||
def clone(self, parentType, tagMap, uniq=False):
|
||||
if self.__defType is not None and tagMap.getDef() is not None:
|
||||
raise error.PyAsn1Error('Duplicate default value at %s' % (self,))
|
||||
if tagMap.getDef() is not None:
|
||||
defType = tagMap.getDef()
|
||||
else:
|
||||
defType = self.__defType
|
||||
|
||||
posMap = self.__posMap.copy()
|
||||
for k in tagMap.getPosMap():
|
||||
if uniq and k in posMap:
|
||||
raise error.PyAsn1Error('Duplicate positive key %s' % (k,))
|
||||
posMap[k] = parentType
|
||||
|
||||
negMap = self.__negMap.copy()
|
||||
negMap.update(tagMap.getNegMap())
|
||||
|
||||
return self.__class__(
|
||||
posMap, negMap, defType,
|
||||
)
|
||||
|
||||
def getPosMap(self): return self.__posMap.copy()
|
||||
def getNegMap(self): return self.__negMap.copy()
|
||||
def getDef(self): return self.__defType
|
1042
src/lib/pyasn1/type/univ.py
Normal file
1042
src/lib/pyasn1/type/univ.py
Normal file
File diff suppressed because it is too large
Load diff
12
src/lib/pyasn1/type/useful.py
Normal file
12
src/lib/pyasn1/type/useful.py
Normal file
|
@ -0,0 +1,12 @@
|
|||
# ASN.1 "useful" types
|
||||
from pyasn1.type import char, tag
|
||||
|
||||
class GeneralizedTime(char.VisibleString):
|
||||
tagSet = char.VisibleString.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 24)
|
||||
)
|
||||
|
||||
class UTCTime(char.VisibleString):
|
||||
tagSet = char.VisibleString.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 23)
|
||||
)
|
Loading…
Add table
Add a link
Reference in a new issue