Bug 1091668 - Import pyasn1-0.1.7; r=ted, r=gerv

This commit is contained in:
Mike Shal
2014-11-03 10:46:46 -05:00
parent f25a15f18e
commit 4d7bde0953
70 changed files with 11084 additions and 0 deletions

278
python/pyasn1/CHANGES Normal file
View 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
python/pyasn1/LICENSE Normal file
View 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.

View File

@@ -0,0 +1,3 @@
include CHANGES README LICENSE THANKS TODO
recursive-include test *.py
recursive-include doc *.html

26
python/pyasn1/PKG-INFO Normal file
View 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
python/pyasn1/README Normal file
View 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
python/pyasn1/THANKS Normal file
View File

@@ -0,0 +1,4 @@
Denis S. Otkidach
Gregory Golberg
Bud P. Bruegger
Jacek Konieczny

36
python/pyasn1/TODO Normal file
View 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?

View File

@@ -0,0 +1,503 @@
<html>
<title>
PyASN1 codecs
</title>
<head>
</head>
<body>
<center>
<table width=60%>
<tr>
<td>
<h3>
2. PyASN1 Codecs
</h3>
<p>
In ASN.1 context,
<a href=http://en.wikipedia.org/wiki/Codec>codec</a>
is a program that transforms between concrete data structures and a stream
of octets, suitable for transmission over the wire. This serialized form of
data is sometimes called <i>substrate</i> or <i>essence</i>.
</p>
<p>
In pyasn1 implementation, substrate takes shape of Python 3 bytes or
Python 2 string objects.
</p>
<p>
One of the properties of a codec is its ability to cope with incomplete
data and/or substrate what implies codec to be stateful. In other words,
when decoder runs out of substrate and data item being recovered is still
incomplete, stateful codec would suspend and complete data item recovery
whenever the rest of substrate becomes available. Similarly, stateful encoder
would encode data items in multiple steps waiting for source data to
arrive. Codec restartability is especially important when application deals
with large volumes of data and/or runs on low RAM. For an interesting
discussion on codecs options and design choices, refer to
<a href=http://directory.apache.org/subprojects/asn1/>Apache ASN.1 project</a>
.
</p>
<p>
As of this writing, codecs implemented in pyasn1 are all stateless, mostly
to keep the code simple.
</p>
<p>
The pyasn1 package currently supports
<a href=http://en.wikipedia.org/wiki/Basic_encoding_rules>BER</a> codec and
its variations --
<a href=http://en.wikipedia.org/wiki/Canonical_encoding_rules>CER</a> and
<a href=http://en.wikipedia.org/wiki/Distinguished_encoding_rules>DER</a>.
More ASN.1 codecs are planned for implementation in the future.
</p>
<a name="2.1"></a>
<h4>
2.1 Encoders
</h4>
<p>
Encoder is used for transforming pyasn1 value objects into substrate. Only
pyasn1 value objects could be serialized, attempts to process pyasn1 type
objects will cause encoder failure.
</p>
<p>
The following code will create a pyasn1 Integer object and serialize it with
BER encoder:
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
>>> from pyasn1.type import univ
>>> from pyasn1.codec.ber import encoder
>>> encoder.encode(univ.Integer(123456))
b'\x02\x03\x01\xe2@'
>>>
</pre>
</td></tr></table>
<p>
BER standard also defines a so-called <i>indefinite length</i> encoding form
which makes large data items processing more memory efficient. It is mostly
useful when encoder does not have the whole value all at once and the
length of the value can not be determined at the beginning of encoding.
</p>
<p>
<i>Constructed encoding</i> is another feature of BER closely related to the
indefinite length form. In essence, a large scalar value (such as ASN.1
character BitString type) could be chopped into smaller chunks by encoder
and transmitted incrementally to limit memory consumption. Unlike indefinite
length case, the length of the whole value must be known in advance when
using constructed, definite length encoding form.
</p>
<p>
Since pyasn1 codecs are not restartable, pyasn1 encoder may only encode data
item all at once. However, even in this case, generating indefinite length
encoding may help a low-memory receiver, running a restartable decoder,
to process a large data item.
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
>>> from pyasn1.type import univ
>>> from pyasn1.codec.ber import encoder
>>> encoder.encode(
... univ.OctetString('The quick brown fox jumps over the lazy dog'),
... defMode=False,
... maxChunkSize=8
... )
b'$\x80\x04\x08The quic\x04\x08k brown \x04\x08fox jump\x04\x08s over \
t\x04\x08he lazy \x04\x03dog\x00\x00'
>>>
>>> encoder.encode(
... univ.OctetString('The quick brown fox jumps over the lazy dog'),
... maxChunkSize=8
... )
b'$7\x04\x08The quic\x04\x08k brown \x04\x08fox jump\x04\x08s over \
t\x04\x08he lazy \x04\x03dog'
</pre>
</td></tr></table>
<p>
The <b>defMode</b> encoder parameter disables definite length encoding mode,
while the optional <b>maxChunkSize</b> parameter specifies desired
substrate chunk size that influences memory requirements at the decoder's end.
</p>
<p>
To use CER or DER encoders one needs to explicitly import and call them - the
APIs are all compatible.
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
>>> from pyasn1.type import univ
>>> from pyasn1.codec.ber import encoder as ber_encoder
>>> from pyasn1.codec.cer import encoder as cer_encoder
>>> from pyasn1.codec.der import encoder as der_encoder
>>> ber_encoder.encode(univ.Boolean(True))
b'\x01\x01\x01'
>>> cer_encoder.encode(univ.Boolean(True))
b'\x01\x01\xff'
>>> der_encoder.encode(univ.Boolean(True))
b'\x01\x01\xff'
>>>
</pre>
</td></tr></table>
<a name="2.2"></a>
<h4>
2.2 Decoders
</h4>
<p>
In the process of decoding, pyasn1 value objects are created and linked to
each other, based on the information containted in the substrate. Thus,
the original pyasn1 value object(s) are recovered.
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
>>> from pyasn1.type import univ
>>> from pyasn1.codec.ber import encoder, decoder
>>> substrate = encoder.encode(univ.Boolean(True))
>>> decoder.decode(substrate)
(Boolean('True(1)'), b'')
>>>
</pre>
</td></tr></table>
<p>
Commenting on the code snippet above, pyasn1 decoder accepts substrate
as an argument and returns a tuple of pyasn1 value object (possibly
a top-level one in case of constructed object) and unprocessed part
of input substrate.
</p>
<p>
All pyasn1 decoders can handle both definite and indefinite length
encoding modes automatically, explicit switching into one mode
to another is not required.
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
>>> from pyasn1.type import univ
>>> from pyasn1.codec.ber import encoder, decoder
>>> substrate = encoder.encode(
... univ.OctetString('The quick brown fox jumps over the lazy dog'),
... defMode=False,
... maxChunkSize=8
... )
>>> decoder.decode(substrate)
(OctetString(b'The quick brown fox jumps over the lazy dog'), b'')
>>>
</pre>
</td></tr></table>
<p>
Speaking of BER/CER/DER encoding, in many situations substrate may not contain
all necessary information needed for complete and accurate ASN.1 values
recovery. The most obvious cases include implicitly tagged ASN.1 types
and constrained types.
</p>
<p>
As discussed earlier in this handbook, when an ASN.1 type is implicitly
tagged, previous outermost tag is lost and never appears in substrate.
If it is the base tag that gets lost, decoder is unable to pick type-specific
value decoder at its table of built-in types, and therefore recover
the value part, based only on the information contained in substrate. The
approach taken by pyasn1 decoder is to use a prototype pyasn1 type object (or
a set of them) to <i>guide</i> the decoding process by matching [possibly
incomplete] tags recovered from substrate with those found in prototype pyasn1
type objects (also called pyasn1 specification object further in this paper).
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
>>> from pyasn1.codec.ber import decoder
>>> decoder.decode(b'\x02\x01\x0c', asn1Spec=univ.Integer())
Integer(12), b''
>>>
</pre>
</td></tr></table>
<p>
Decoder would neither modify pyasn1 specification object nor use
its current values (if it's a pyasn1 value object), but rather use it as
a hint for choosing proper decoder and as a pattern for creating new objects:
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
>>> from pyasn1.type import univ, tag
>>> from pyasn1.codec.ber import encoder, decoder
>>> i = univ.Integer(12345).subtype(
... implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 40)
... )
>>> substrate = encoder.encode(i)
>>> substrate
b'\x9f(\x0209'
>>> decoder.decode(substrate)
Traceback (most recent call last):
...
pyasn1.error.PyAsn1Error:
TagSet(Tag(tagClass=128, tagFormat=0, tagId=40)) not in asn1Spec
>>> decoder.decode(substrate, asn1Spec=i)
(Integer(12345), b'')
>>>
</pre>
</td></tr></table>
<p>
Notice in the example above, that an attempt to run decoder without passing
pyasn1 specification object fails because recovered tag does not belong
to any of the built-in types.
</p>
<p>
Another important feature of guided decoder operation is the use of
values constraints possibly present in pyasn1 specification object.
To explain this, we will decode a random integer object into generic Integer
and the constrained one.
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
>>> from pyasn1.type import univ, constraint
>>> from pyasn1.codec.ber import encoder, decoder
>>> class DialDigit(univ.Integer):
... subtypeSpec = constraint.ValueRangeConstraint(0,9)
>>> substrate = encoder.encode(univ.Integer(13))
>>> decoder.decode(substrate)
(Integer(13), b'')
>>> decoder.decode(substrate, asn1Spec=DialDigit())
Traceback (most recent call last):
...
pyasn1.type.error.ValueConstraintError:
ValueRangeConstraint(0, 9) failed at: 13
>>>
</pre>
</td></tr></table>
<p>
Similarily to encoders, to use CER or DER decoders application has to
explicitly import and call them - all APIs are compatible.
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
>>> from pyasn1.type import univ
>>> from pyasn1.codec.ber import encoder as ber_encoder
>>> substrate = ber_encoder.encode(univ.OctetString('http://pyasn1.sf.net'))
>>>
>>> from pyasn1.codec.ber import decoder as ber_decoder
>>> from pyasn1.codec.cer import decoder as cer_decoder
>>> from pyasn1.codec.der import decoder as der_decoder
>>>
>>> ber_decoder.decode(substrate)
(OctetString(b'http://pyasn1.sf.net'), b'')
>>> cer_decoder.decode(substrate)
(OctetString(b'http://pyasn1.sf.net'), b'')
>>> der_decoder.decode(substrate)
(OctetString(b'http://pyasn1.sf.net'), b'')
>>>
</pre>
</td></tr></table>
<a name="2.2.1"></a>
<h4>
2.2.1 Decoding untagged types
</h4>
<p>
It has already been mentioned, that ASN.1 has two "special case" types:
CHOICE and ANY. They are different from other types in part of
tagging - unless these two are additionally tagged, neither of them will
have their own tag. Therefore these types become invisible in substrate
and can not be recovered without passing pyasn1 specification object to
decoder.
</p>
<p>
To explain the issue, we will first prepare a Choice object to deal with:
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
>>> from pyasn1.type import univ, namedtype
>>> class CodeOrMessage(univ.Choice):
... componentType = namedtype.NamedTypes(
... namedtype.NamedType('code', univ.Integer()),
... namedtype.NamedType('message', univ.OctetString())
... )
>>>
>>> codeOrMessage = CodeOrMessage()
>>> codeOrMessage.setComponentByName('message', 'my string value')
>>> print(codeOrMessage.prettyPrint())
CodeOrMessage:
message=b'my string value'
>>>
</pre>
</td></tr></table>
<p>
Let's now encode this Choice object and then decode its substrate
with and without pyasn1 specification object:
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
>>> from pyasn1.codec.ber import encoder, decoder
>>> substrate = encoder.encode(codeOrMessage)
>>> substrate
b'\x04\x0fmy string value'
>>> encoder.encode(univ.OctetString('my string value'))
b'\x04\x0fmy string value'
>>>
>>> decoder.decode(substrate)
(OctetString(b'my string value'), b'')
>>> codeOrMessage, substrate = decoder.decode(substrate, asn1Spec=CodeOrMessage())
>>> print(codeOrMessage.prettyPrint())
CodeOrMessage:
message=b'my string value'
>>>
</pre>
</td></tr></table>
<p>
First thing to notice in the listing above is that the substrate produced
for our Choice value object is equivalent to the substrate for an OctetString
object initialized to the same value. In other words, any information about
the Choice component is absent in encoding.
</p>
<p>
Sure enough, that kind of substrate will decode into an OctetString object,
unless original Choice type object is passed to decoder to guide the decoding
process.
</p>
<p>
Similarily untagged ANY type behaves differently on decoding phase - when
decoder bumps into an Any object in pyasn1 specification, it stops decoding
and puts all the substrate into a new Any value object in form of an octet
string. Concerned application could then re-run decoder with an additional,
more exact pyasn1 specification object to recover the contents of Any
object.
</p>
<p>
As it was mentioned elsewhere in this paper, Any type allows for incomplete
or changing ASN.1 specification to be handled gracefully by decoder and
applications.
</p>
<p>
To illustrate the working of Any type, we'll have to make the stage
by encoding a pyasn1 object and then putting its substrate into an any
object.
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
>>> from pyasn1.type import univ
>>> from pyasn1.codec.ber import encoder, decoder
>>> innerSubstrate = encoder.encode(univ.Integer(1234))
>>> innerSubstrate
b'\x02\x02\x04\xd2'
>>> any = univ.Any(innerSubstrate)
>>> any
Any(b'\x02\x02\x04\xd2')
>>> substrate = encoder.encode(any)
>>> substrate
b'\x02\x02\x04\xd2'
>>>
</pre>
</td></tr></table>
<p>
As with Choice type encoding, there is no traces of Any type in substrate.
Obviously, the substrate we are dealing with, will decode into the inner
[Integer] component, unless pyasn1 specification is given to guide the
decoder. Continuing previous code:
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
>>> from pyasn1.type import univ
>>> from pyasn1.codec.ber import encoder, decoder
>>> decoder.decode(substrate)
(Integer(1234), b'')
>>> any, substrate = decoder.decode(substrate, asn1Spec=univ.Any())
>>> any
Any(b'\x02\x02\x04\xd2')
>>> decoder.decode(str(any))
(Integer(1234), b'')
>>>
</pre>
</td></tr></table>
<p>
Both CHOICE and ANY types are widely used in practice. Reader is welcome to
take a look at
<a href=http://www.cs.auckland.ac.nz/~pgut001/pubs/x509guide.txt>
ASN.1 specifications of X.509 applications</a> for more information.
</p>
<a name="2.2.2"></a>
<h4>
2.2.2 Ignoring unknown types
</h4>
<p>
When dealing with a loosely specified ASN.1 structure, the receiving
end may not be aware of some types present in the substrate. It may be
convenient then to turn decoder into a recovery mode. Whilst there, decoder
will not bail out when hit an unknown tag but rather treat it as an Any
type.
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
>>> from pyasn1.type import univ, tag
>>> from pyasn1.codec.ber import encoder, decoder
>>> taggedInt = univ.Integer(12345).subtype(
... implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 40)
... )
>>> substrate = encoder.encode(taggedInt)
>>> decoder.decode(substrate)
Traceback (most recent call last):
...
pyasn1.error.PyAsn1Error: TagSet(Tag(tagClass=128, tagFormat=0, tagId=40)) not in asn1Spec
>>>
>>> decoder.decode.defaultErrorState = decoder.stDumpRawValue
>>> decoder.decode(substrate)
(Any(b'\x9f(\x0209'), '')
>>>
</pre>
</td></tr></table>
<p>
It's also possible to configure a custom decoder, to handle unknown tags
found in substrate. This can be done by means of <b>defaultRawDecoder</b>
attribute holding a reference to type decoder object. Refer to the source
for API details.
</p>
<hr>
</td>
</tr>
</table>
</center>
</body>
</html>

View File

@@ -0,0 +1,436 @@
<html>
<title>
PyASN1 subtype constraints
</title>
<head>
</head>
<body>
<center>
<table width=60%>
<tr>
<td>
<h4>
1.4 PyASN1 subtype constraints
</h4>
<p>
Most ASN.1 types can correspond to an infinite set of values. To adapt to
particular application's data model and needs, ASN.1 provides a mechanism
for limiting the infinite set to values, that make sense in particular case.
</p>
<p>
Imposing value constraints on an ASN.1 type can also be seen as creating
a subtype from its base type.
</p>
<p>
In pyasn1, constraints take shape of immutable objects capable
of evaluating given value against constraint-specific requirements.
Constraint object is a property of pyasn1 type. Like TagSet property,
associated with every pyasn1 type, constraints can never be modified
in place. The only way to modify pyasn1 type constraint is to associate
new constraint object to a new pyasn1 type object.
</p>
<p>
A handful of different flavors of <i>constraints</i> are defined in ASN.1.
We will discuss them one by one in the following chapters and also explain
how to combine and apply them to types.
</p>
<a name="1.4.1"></a>
<h4>
1.4.1 Single value constraint
</h4>
<p>
This kind of constraint allows for limiting type to a finite, specified set
of values.
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
DialButton ::= OCTET STRING (
"0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
)
</pre>
</td></tr></table>
<p>
Its pyasn1 implementation would look like:
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
>>> from pyasn1.type import constraint
>>> c = constraint.SingleValueConstraint(
'0','1','2','3','4','5','6','7','8','9'
)
>>> c
SingleValueConstraint(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
>>> c('0')
>>> c('A')
Traceback (most recent call last):
...
pyasn1.type.error.ValueConstraintError:
SingleValueConstraint(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) failed at: A
>>>
</pre>
</td></tr></table>
<p>
As can be seen in the snippet above, if a value violates the constraint, an
exception will be thrown. A constrainted pyasn1 type object holds a
reference to a constraint object (or their combination, as will be explained
later) and calls it for value verification.
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
>>> from pyasn1.type import univ, constraint
>>> class DialButton(univ.OctetString):
... subtypeSpec = constraint.SingleValueConstraint(
... '0','1','2','3','4','5','6','7','8','9'
... )
>>> DialButton('0')
DialButton(b'0')
>>> DialButton('A')
Traceback (most recent call last):
...
pyasn1.type.error.ValueConstraintError:
SingleValueConstraint(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) failed at: A
>>>
</pre>
</td></tr></table>
<p>
Constrained pyasn1 value object can never hold a violating value.
</p>
<a name="1.4.2"></a>
<h4>
1.4.2 Value range constraint
</h4>
<p>
A pair of values, compliant to a type to be constrained, denote low and upper
bounds of allowed range of values of a type.
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
Teenagers ::= INTEGER (13..19)
</pre>
</td></tr></table>
<p>
And in pyasn1 terms:
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
>>> from pyasn1.type import univ, constraint
>>> class Teenagers(univ.Integer):
... subtypeSpec = constraint.ValueRangeConstraint(13, 19)
>>> Teenagers(14)
Teenagers(14)
>>> Teenagers(20)
Traceback (most recent call last):
...
pyasn1.type.error.ValueConstraintError:
ValueRangeConstraint(13, 19) failed at: 20
>>>
</pre>
</td></tr></table>
<p>
Value range constraint usually applies numeric types.
</p>
<a name="1.4.3"></a>
<h4>
1.4.3 Size constraint
</h4>
<p>
It is sometimes convenient to set or limit the allowed size of a data item
to be sent from one application to another to manage bandwidth and memory
consumption issues. Size constraint specifies the lower and upper bounds
of the size of a valid value.
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
TwoBits ::= BIT STRING (SIZE (2))
</pre>
</td></tr></table>
<p>
Express the same grammar in pyasn1:
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
>>> from pyasn1.type import univ, constraint
>>> class TwoBits(univ.BitString):
... subtypeSpec = constraint.ValueSizeConstraint(2, 2)
>>> TwoBits((1,1))
TwoBits("'11'B")
>>> TwoBits((1,1,0))
Traceback (most recent call last):
...
pyasn1.type.error.ValueConstraintError:
ValueSizeConstraint(2, 2) failed at: (1, 1, 0)
>>>
</pre>
</td></tr></table>
<p>
Size constraint can be applied to potentially massive values - bit or octet
strings, SEQUENCE OF/SET OF values.
</p>
<a name="1.4.4"></a>
<h4>
1.4.4 Alphabet constraint
</h4>
<p>
The permitted alphabet constraint is similar to Single value constraint
but constraint applies to individual characters of a value.
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
MorseCode ::= PrintableString (FROM ("."|"-"|" "))
</pre>
</td></tr></table>
<p>
And in pyasn1:
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
>>> from pyasn1.type import char, constraint
>>> class MorseCode(char.PrintableString):
... subtypeSpec = constraint.PermittedAlphabetConstraint(".", "-", " ")
>>> MorseCode("...---...")
MorseCode('...---...')
>>> MorseCode("?")
Traceback (most recent call last):
...
pyasn1.type.error.ValueConstraintError:
PermittedAlphabetConstraint(".", "-", " ") failed at: "?"
>>>
</pre>
</td></tr></table>
<p>
Current implementation does not handle ranges of characters in constraint
(FROM "A".."Z" syntax), one has to list the whole set in a range.
</p>
<a name="1.4.5"></a>
<h4>
1.4.5 Constraint combinations
</h4>
<p>
Up to this moment, we used a single constraint per ASN.1 type. The standard,
however, allows for combining multiple individual constraints into
intersections, unions and exclusions.
</p>
<p>
In pyasn1 data model, all of these methods of constraint combinations are
implemented as constraint-like objects holding individual constraint (or
combination) objects. Like terminal constraint objects, combination objects
are capable to perform value verification at its set of enclosed constraints
according to the logic of particular combination.
</p>
<p>
Constraints intersection verification succeeds only if a value is
compliant to each constraint in a set. To begin with, the following
specification will constitute a valid telephone number:
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
PhoneNumber ::= NumericString (FROM ("0".."9")) (SIZE 11)
</pre>
</td></tr></table>
<p>
Constraint intersection object serves the logic above:
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
>>> from pyasn1.type import char, constraint
>>> class PhoneNumber(char.NumericString):
... subtypeSpec = constraint.ConstraintsIntersection(
... constraint.PermittedAlphabetConstraint('0','1','2','3','4','5','6','7','8','9'),
... constraint.ValueSizeConstraint(11, 11)
... )
>>> PhoneNumber('79039343212')
PhoneNumber('79039343212')
>>> PhoneNumber('?9039343212')
Traceback (most recent call last):
...
pyasn1.type.error.ValueConstraintError:
ConstraintsIntersection(
PermittedAlphabetConstraint('0','1','2','3','4','5','6','7','8','9'),
ValueSizeConstraint(11, 11)) failed at:
PermittedAlphabetConstraint('0','1','2','3','4','5','6','7','8','9') failed at: "?039343212"
>>> PhoneNumber('9343212')
Traceback (most recent call last):
...
pyasn1.type.error.ValueConstraintError:
ConstraintsIntersection(
PermittedAlphabetConstraint('0','1','2','3','4','5','6','7','8','9'),
ValueSizeConstraint(11, 11)) failed at:
ValueSizeConstraint(10, 10) failed at: "9343212"
>>>
</pre>
</td></tr></table>
<p>
Union of constraints works by making sure that a value is compliant
to any of the constraint in a set. For instance:
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
CapitalOrSmall ::= IA5String (FROM ('A','B','C') | FROM ('a','b','c'))
</pre>
</td></tr></table>
<p>
It's important to note, that a value must fully comply to any single
constraint in a set. In the specification above, a value of all small or
all capital letters is compliant, but a mix of small&capitals is not.
Here's its pyasn1 analogue:
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
>>> from pyasn1.type import char, constraint
>>> class CapitalOrSmall(char.IA5String):
... subtypeSpec = constraint.ConstraintsUnion(
... constraint.PermittedAlphabetConstraint('A','B','C'),
... constraint.PermittedAlphabetConstraint('a','b','c')
... )
>>> CapitalOrSmall('ABBA')
CapitalOrSmall('ABBA')
>>> CapitalOrSmall('abba')
CapitalOrSmall('abba')
>>> CapitalOrSmall('Abba')
Traceback (most recent call last):
...
pyasn1.type.error.ValueConstraintError:
ConstraintsUnion(PermittedAlphabetConstraint('A', 'B', 'C'),
PermittedAlphabetConstraint('a', 'b', 'c')) failed at: failed for "Abba"
>>>
</pre>
</td></tr></table>
<p>
Finally, the exclusion constraint simply negates the logic of value
verification at a constraint. In the following example, any integer value
is allowed in a type but not zero.
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
NoZero ::= INTEGER (ALL EXCEPT 0)
</pre>
</td></tr></table>
<p>
In pyasn1 the above definition would read:
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
>>> from pyasn1.type import univ, constraint
>>> class NoZero(univ.Integer):
... subtypeSpec = constraint.ConstraintsExclusion(
... constraint.SingleValueConstraint(0)
... )
>>> NoZero(1)
NoZero(1)
>>> NoZero(0)
Traceback (most recent call last):
...
pyasn1.type.error.ValueConstraintError:
ConstraintsExclusion(SingleValueConstraint(0)) failed at: 0
>>>
</pre>
</td></tr></table>
<p>
The depth of such a constraints tree, built with constraint combination objects
at its nodes, has not explicit limit. Value verification is performed in a
recursive manner till a definite solution is found.
</p>
<a name="1.5"></a>
<h4>
1.5 Types relationships
</h4>
<p>
In the course of data processing in an application, it is sometimes
convenient to figure out the type relationships between pyasn1 type or
value objects. Formally, two things influence pyasn1 types relationship:
<i>tag set</i> and <i>subtype constraints</i>. One pyasn1 type is considered
to be a derivative of another if their TagSet and Constraint objects are
a derivation of one another.
</p>
<p>
The following example illustrates the concept (we use the same tagset but
different constraints for simplicity):
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
>>> from pyasn1.type import univ, constraint
>>> i1 = univ.Integer(subtypeSpec=constraint.ValueRangeConstraint(3,8))
>>> i2 = univ.Integer(subtypeSpec=constraint.ConstraintsIntersection(
... constraint.ValueRangeConstraint(3,8),
... constraint.ValueRangeConstraint(4,7)
... ) )
>>> i1.isSameTypeWith(i2)
False
>>> i1.isSuperTypeOf(i2)
True
>>> i1.isSuperTypeOf(i1)
True
>>> i2.isSuperTypeOf(i1)
False
>>>
</pre>
</td></tr></table>
<p>
As can be seen in the above code snippet, there are two methods of any pyasn1
type/value object that test types for their relationship:
<b>isSameTypeWith</b>() and <b>isSuperTypeOf</b>(). The former is
self-descriptive while the latter yields true if the argument appears
to be a pyasn1 object which has tagset and constraints derived from those
of the object being called.
</p>
<hr>
</td>
</tr>
</table>
</center>
</body>
</html>

View File

@@ -0,0 +1,377 @@
<html>
<title>
PyASN1 Constructed types
</title>
<head>
</head>
<body>
<center>
<table width=60%>
<tr>
<td>
<h4>
1.3 PyASN1 Constructed types
</h4>
<p>
Besides scalar types, ASN.1 specifies so-called constructed ones - these
are capable of holding one or more values of other types, both scalar
and constructed.
</p>
<p>
In pyasn1 implementation, constructed ASN.1 types behave like
Python sequences, and also support additional component addressing methods,
specific to particular constructed type.
</p>
<a name="1.3.1"></a>
<h4>
1.3.1 Sequence and Set types
</h4>
<p>
The Sequence and Set types have many similar properties:
</p>
<ul>
<li>they can hold any number of inner components of different types
<li>every component has a human-friendly identifier
<li>any component can have a default value
<li>some components can be absent.
</ul>
<p>
However, Sequence type guarantees the ordering of Sequence value components
to match their declaration order. By contrast, components of the
Set type can be ordered to best suite application's needs.
<p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
Record ::= SEQUENCE {
id INTEGER,
room [0] INTEGER OPTIONAL,
house [1] INTEGER DEFAULT 0
}
</pre>
</td></tr></table>
<p>
Up to this moment, the only method we used for creating new pyasn1 types
is Python sub-classing. With this method, a new, named Python class is created
what mimics type derivation in ASN.1 grammar. However, ASN.1 also allows for
defining anonymous subtypes (room and house components in the example above).
To support anonymous subtyping in pyasn1, a cloning operation on an existing
pyasn1 type object can be invoked what creates a new instance of original
object with possibly modified properties.
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
>>> from pyasn1.type import univ, namedtype, tag
>>> class Record(univ.Sequence):
... componentType = namedtype.NamedTypes(
... namedtype.NamedType('id', univ.Integer()),
... namedtype.OptionalNamedType(
... 'room',
... univ.Integer().subtype(
... implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0)
... )
... ),
... namedtype.DefaultedNamedType(
... 'house',
... univ.Integer(0).subtype(
... implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1)
... )
... )
... )
>>>
</pre>
</td></tr></table>
<p>
All pyasn1 constructed type classes have a class attribute <b>componentType</b>
that represent default type specification. Its value is a NamedTypes object.
</p>
<p>
The NamedTypes class instance holds a sequence of NameType, OptionalNamedType
or DefaultedNamedType objects which, in turn, refer to pyasn1 type objects that
represent inner SEQUENCE components specification.
</p>
<p>
Finally, invocation of a subtype() method of pyasn1 type objects in the code
above returns an implicitly tagged copy of original object.
</p>
<p>
Once a SEQUENCE or SET type is decleared with pyasn1, it can be instantiated
and initialized (continuing the above code):
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
>>> record = Record()
>>> record.setComponentByName('id', 123)
>>> print(record.prettyPrint())
Record:
id=123
>>>
>>> record.setComponentByPosition(1, 321)
>>> print(record.prettyPrint())
Record:
id=123
room=321
>>>
>>> record.setDefaultComponents()
>>> print(record.prettyPrint())
Record:
id=123
room=321
house=0
</pre>
</td></tr></table>
<p>
Inner components of pyasn1 Sequence/Set objects could be accessed using the
following methods:
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
>>> record.getComponentByName('id')
Integer(123)
>>> record.getComponentByPosition(1)
Integer(321)
>>> record[2]
Integer(0)
>>> for idx in range(len(record)):
... print(record.getNameByPosition(idx), record.getComponentByPosition(idx))
id 123
room 321
house 0
>>>
</pre>
</td></tr></table>
<p>
The Set type share all the properties of Sequence type, and additionally
support by-tag component addressing (as all Set components have distinct
types).
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
>>> from pyasn1.type import univ, namedtype, tag
>>> class Gamer(univ.Set):
... componentType = namedtype.NamedTypes(
... namedtype.NamedType('score', univ.Integer()),
... namedtype.NamedType('player', univ.OctetString()),
... namedtype.NamedType('id', univ.ObjectIdentifier())
... )
>>> gamer = Gamer()
>>> gamer.setComponentByType(univ.Integer().getTagSet(), 121343)
>>> gamer.setComponentByType(univ.OctetString().getTagSet(), 'Pascal')
>>> gamer.setComponentByType(univ.ObjectIdentifier().getTagSet(), (1,3,7,2))
>>> print(gamer.prettyPrint())
Gamer:
score=121343
player=b'Pascal'
id=1.3.7.2
>>>
</pre>
</td></tr></table>
<a name="1.3.2"></a>
<h4>
1.3.2 SequenceOf and SetOf types
</h4>
<p>
Both, SequenceOf and SetOf types resemble an unlimited size list of components.
All the components must be of the same type.
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
Progression ::= SEQUENCE OF INTEGER
arithmeticProgression Progression ::= { 1, 3, 5, 7 }
</pre>
</td></tr></table>
<p>
SequenceOf and SetOf types are expressed by the very similar pyasn1 type
objects. Their components can only be addressed by position and they
both have a property of automatic resize.
</p>
<p>
To specify inner component type, the <b>componentType</b> class attribute
should refer to another pyasn1 type object.
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
>>> from pyasn1.type import univ
>>> class Progression(univ.SequenceOf):
... componentType = univ.Integer()
>>> arithmeticProgression = Progression()
>>> arithmeticProgression.setComponentByPosition(1, 111)
>>> print(arithmeticProgression.prettyPrint())
Progression:
-empty- 111
>>> arithmeticProgression.setComponentByPosition(0, 100)
>>> print(arithmeticProgression.prettyPrint())
Progression:
100 111
>>>
>>> for idx in range(len(arithmeticProgression)):
... arithmeticProgression.getComponentByPosition(idx)
Integer(100)
Integer(111)
>>>
</pre>
</td></tr></table>
<p>
Any scalar or constructed pyasn1 type object can serve as an inner component.
Missing components are prohibited in SequenceOf/SetOf value objects.
</p>
<a name="1.3.3"></a>
<h4>
1.3.3 Choice type
</h4>
<p>
Values of ASN.1 CHOICE type can contain only a single value of a type from a
list of possible alternatives. Alternatives must be ASN.1 types with
distinct tags for the whole structure to remain unambiguous. Unlike most
other types, CHOICE is an untagged one, e.g. it has no base tag of its own.
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
CodeOrMessage ::= CHOICE {
code INTEGER,
message OCTET STRING
}
</pre>
</td></tr></table>
<p>
In pyasn1 implementation, Choice object behaves like Set but accepts only
a single inner component at a time. It also offers a few additional methods
specific to its behaviour.
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
>>> from pyasn1.type import univ, namedtype
>>> class CodeOrMessage(univ.Choice):
... componentType = namedtype.NamedTypes(
... namedtype.NamedType('code', univ.Integer()),
... namedtype.NamedType('message', univ.OctetString())
... )
>>>
>>> codeOrMessage = CodeOrMessage()
>>> print(codeOrMessage.prettyPrint())
CodeOrMessage:
>>> codeOrMessage.setComponentByName('code', 123)
>>> print(codeOrMessage.prettyPrint())
CodeOrMessage:
code=123
>>> codeOrMessage.setComponentByName('message', 'my string value')
>>> print(codeOrMessage.prettyPrint())
CodeOrMessage:
message=b'my string value'
>>>
</pre>
</td></tr></table>
<p>
Since there could be only a single inner component value in the pyasn1 Choice
value object, either of the following methods could be used for fetching it
(continuing previous code):
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
>>> codeOrMessage.getName()
'message'
>>> codeOrMessage.getComponent()
OctetString(b'my string value')
>>>
</pre>
</td></tr></table>
<a name="1.3.4"></a>
<h4>
1.3.4 Any type
</h4>
<p>
The ASN.1 ANY type is a kind of wildcard or placeholder that matches
any other type without knowing it in advance. Like CHOICE type, ANY
has no base tag.
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
Error ::= SEQUENCE {
code INTEGER,
parameter ANY DEFINED BY code
}
</pre>
</td></tr></table>
<p>
The ANY type is frequently used in specifications, where exact type is not
yet agreed upon between communicating parties or the number of possible
alternatives of a type is infinite.
Sometimes an auxiliary selector is kept around to help parties indicate
the kind of ANY payload in effect ("code" in the example above).
</p>
<p>
Values of the ANY type contain serialized ASN.1 value(s) in form of
an octet string. Therefore pyasn1 Any value object share the properties of
pyasn1 OctetString object.
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
>>> from pyasn1.type import univ
>>> someValue = univ.Any(b'\x02\x01\x01')
>>> someValue
Any(b'\x02\x01\x01')
>>> str(someValue)
'\x02\x01\x01'
>>> bytes(someValue)
b'\x02\x01\x01'
>>>
</pre>
</td></tr></table>
<p>
Receiving application is supposed to explicitly deserialize the content of Any
value object, possibly using auxiliary selector for figuring out its ASN.1
type to pick appropriate decoder.
</p>
<p>
There will be some more talk and code snippets covering Any type in the codecs
chapters that follow.
</p>
<hr>
</td>
</tr>
</table>
</center>
</body>
</html>

View File

@@ -0,0 +1,156 @@
<html>
<title>
PyASN1 reference manual
</title>
<head>
</head>
<body>
<center>
<table width=60%>
<tr>
<td>
<h3>
PyASN1 reference manual
</h3>
<p align=right>
<i>written by <a href=mailto:ilya@glas.net>Ilya Etingof</a>, 2011-2012</i>
</p>
<p>
Free and open-source pyasn1 library makes it easier for programmers and
network engineers to develop, debug and experiment with ASN.1-based protocols
using Python programming language as a tool.
</p>
<p>
Abstract Syntax Notation One
(<a href=http://en.wikipedia.org/wiki/Abstract_Syntax_Notation_1x>ASN.1</a>)
is a set of
<a href=http://www.itu.int/ITU-T/studygroups/com17/languages/X.680-X.693-0207w.zip>
ITU standards</a> concered with provisioning instrumentation for developing
data exchange protocols in a robust, clear and interoperabable way for
various IT systems and applications. Most of the efforts are targeting the
following areas:
<ul>
<li>Data structures: the standard introduces a collection of basic data types
(similar to integers, bits, strings, arrays and records in a programming
language) that can be used for defining complex, possibly nested data
structures representing domain-specific data units.
<li>Serialization protocols: domain-specific data units expressed in ASN.1
types could be converted into a series of octets for storage or transmission
over the wire and then recovered back into their structured form on the
receiving end. This process is immune to various hardware and software
related dependencies.
<li>Data description language: could be used to describe particular set of
domain-specific data structures and their relationships. Such a description
could be passed to an ASN.1 compiler for automated generation of program
code that represents ASN.1 data structures in language-native environment
and handles data serialization issues.
</ul>
</p>
<p>
This tutorial and algorithms, implemented by pyasn1 library, are
largely based on the information read in the book
<a href="http://www.oss.com/asn1/dubuisson.html">
ASN.1 - Communication between heterogeneous systems</a>
by Olivier Dubuisson. Another relevant resource is
<a href=ftp://ftp.rsasecurity.com/pub/pkcs/ascii/layman.asc>
A Layman's Guide to a Subset of ASN.1, BER, and DER</a> by Burton S. Kaliski.
It's advised to refer to these books for more in-depth knowledge on the
subject of ASN.1.
</p>
<p>
As of this writing, pyasn1 library implements most of standard ASN.1 data
structures in a rather detailed and feature-rich manner. Another highly
important capability of the library is its data serialization facilities.
The last component of the standard - ASN.1 compiler is planned for
implementation in the future.
</p>
</p>
The pyasn1 library was designed to follow the pre-1995 ASN.1 specification
(also known as X.208). Later, post 1995, revision (X.680) introduced
significant changes most of which have not yet been supported by pyasn1.
</p>
<h3>
Table of contents
</h3>
<p>
<ul>
<li><a href="scalar.html">1. Data model for ASN.1 types</a>
<li><a href="scalar.html#1.1">1.1 Scalar types</a>
<li><a href="scalar.html#1.1.1">1.1.1 Boolean type</a>
<li><a href="scalar.html#1.1.2">1.1.2 Null type</a>
<li><a href="scalar.html#1.1.3">1.1.3 Integer type</a>
<li><a href="scalar.html#1.1.4">1.1.4 Enumerated type</a>
<li><a href="scalar.html#1.1.5">1.1.5 Real type</a>
<li><a href="scalar.html#1.1.6">1.1.6 Bit string type</a>
<li><a href="scalar.html#1.1.7">1.1.7 OctetString type</a>
<li><a href="scalar.html#1.1.8">1.1.8 ObjectIdentifier type</a>
<li><a href="scalar.html#1.1.9">1.1.9 Character string types</a>
<li><a href="scalar.html#1.1.10">1.1.10 Useful types</a>
<li><a href="tagging.html">1.2 Tagging</a>
<li><a href="constructed.html">1.3 Constructed types</a>
<li><a href="constructed.html#1.3.1">1.3.1 Sequence and Set types</a>
<li><a href="constructed.html#1.3.2">1.3.2 SequenceOf and SetOf types</a>
<li><a href="constructed.html#1.3.3">1.3.3 Choice type</a>
<li><a href="constructed.html#1.3.4">1.3.4 Any type</a>
<li><a href="constraints.html">1.4 Subtype constraints</a>
<li><a href="constraints.html#1.4.1">1.4.1 Single value constraint</a>
<li><a href="constraints.html#1.4.2">1.4.2 Value range constraint</a>
<li><a href="constraints.html#1.4.3">1.4.3 Size constraint</a>
<li><a href="constraints.html#1.4.4">1.4.4 Alphabet constraint</a>
<li><a href="constraints.html#1.4.5">1.4.5 Constraint combinations</a>
<li><a href="constraints.html#1.5">1.5 Types relationships</a>
<li><a href="codecs.html">2. Codecs</a>
<li><a href="codecs.html#2.1">2.1 Encoders</a>
<li><a href="codecs.html#2.2">2.2 Decoders</a>
<li><a href="codecs.html#2.2.1">2.2.1 Decoding untagged types</a>
<li><a href="codecs.html#2.2.2">2.2.2 Ignoring unknown types</a>
</ul>
<p>
Although pyasn1 software is almost a decade old and used in many production
environments, it still may have bugs and non-implemented pieces. Anyone
who happens to run into such defect is welcome to complain to
<a href=mailto:pyasn1-users@lists.sourceforge.net>pyasn1 mailing list</a>
or better yet fix the issue and send
<a href=mailto:ilya@glas.net>me</a> the patch.
</p>
<p>
Typically, pyasn1 is used for building arbitrary protocol support into
various applications. This involves manual translation of ASN.1 data
structures into their pyasn1 implementations. To save time and effort,
data structures for some of the popular protocols are pre-programmed
and kept for further re-use in form of the
<a href=http://sourceforge.net/projects/pyasn1/files/pyasn1-modules/>
pyasn1-modules package</a>. For instance, many structures for PKI (X.509,
PKCS#*, CRMF, OCSP), LDAP and SNMP are present.
Applications authors are advised to import and use relevant modules
from that package whenever needed protocol structures are already
there. New protocol modules contributions are welcome.
</p>
<p>
And finally, the latest pyasn1 package revision is available for free
download from
<a href=http://sourceforge.net/projects/pyasn1/>project home</a> and
also from the
<a href=http://pypi.python.org/pypi>Python package repository</a>.
</p>
<hr>
</td>
</tr>
</table>
</center>
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,794 @@
<html>
<title>
PyASN1 data model and scalar types
</title>
<head>
</head>
<body>
<center>
<table width=60%>
<tr>
<td>
<h3>
1. Data model for ASN.1 types
</h3>
<p>
All ASN.1 types could be categorized into two groups: scalar (also called
simple or primitive) and constructed. The first group is populated by
well-known types like Integer or String. Members of constructed group
hold other types (simple or constructed) as their inner components, thus
they are semantically close to a programming language records or lists.
</p>
<p>
In pyasn1, all ASN.1 types and values are implemented as Python objects.
The same pyasn1 object can represent either ASN.1 type and/or value
depending of the presense of value initializer on object instantiation.
We will further refer to these as <i>pyasn1 type object</i> versus <i>pyasn1
value object</i>.
</p>
<p>
Primitive ASN.1 types are implemented as immutable scalar objects. There values
could be used just like corresponding native Python values (integers,
strings/bytes etc) and freely mixed with them in expressions.
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
>>> from pyasn1.type import univ
>>> asn1IntegerValue = univ.Integer(12)
>>> asn1IntegerValue - 2
10
>>> univ.OctetString('abc') == 'abc'
True # Python 2
>>> univ.OctetString(b'abc') == b'abc'
True # Python 3
</pre>
</td></tr></table>
<p>
It would be an error to perform an operation on a pyasn1 type object
as it holds no value to deal with:
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
>>> from pyasn1.type import univ
>>> asn1IntegerType = univ.Integer()
>>> asn1IntegerType - 2
...
pyasn1.error.PyAsn1Error: No value for __coerce__()
</pre>
</td></tr></table>
<a name="1.1"></a>
<h4>
1.1 Scalar types
</h4>
<p>
In the sub-sections that follow we will explain pyasn1 mapping to those
primitive ASN.1 types. Both, ASN.1 notation and corresponding pyasn1
syntax will be given in each case.
</p>
<a name="1.1.1"></a>
<h4>
1.1.1 Boolean type
</h4>
<p>
This is the simplest type those values could be either True or False.
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
;; type specification
FunFactorPresent ::= BOOLEAN
;; values declaration and assignment
pythonFunFactor FunFactorPresent ::= TRUE
cobolFunFactor FunFactorPresent :: FALSE
</pre>
</td></tr></table>
<p>
And here's pyasn1 version of it:
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
>>> from pyasn1.type import univ
>>> class FunFactorPresent(univ.Boolean): pass
...
>>> pythonFunFactor = FunFactorPresent(True)
>>> cobolFunFactor = FunFactorPresent(False)
>>> pythonFunFactor
FunFactorPresent('True(1)')
>>> cobolFunFactor
FunFactorPresent('False(0)')
>>> pythonFunFactor == cobolFunFactor
False
>>>
</pre>
</td></tr></table>
<a name="1.1.2"></a>
<h4>
1.1.2 Null type
</h4>
<p>
The NULL type is sometimes used to express the absense of any information.
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
;; type specification
Vote ::= CHOICE {
agreed BOOLEAN,
skip NULL
}
</td></tr></table>
;; value declaration and assignment
myVote Vote ::= skip:NULL
</pre>
<p>
We will explain the CHOICE type later in this paper, meanwhile the NULL
type:
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
>>> from pyasn1.type import univ
>>> skip = univ.Null()
>>> skip
Null('')
>>>
</pre>
</td></tr></table>
<a name="1.1.3"></a>
<h4>
1.1.3 Integer type
</h4>
<p>
ASN.1 defines the values of Integer type as negative or positive of whatever
length. This definition plays nicely with Python as the latter places no
limit on Integers. However, some ASN.1 implementations may impose certain
limits of integer value ranges. Keep that in mind when designing new
data structures.
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
;; values specification
age-of-universe INTEGER ::= 13750000000
mean-martian-surface-temperature INTEGER ::= -63
</pre>
</td></tr></table>
<p>
A rather strigntforward mapping into pyasn1:
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
>>> from pyasn1.type import univ
>>> ageOfUniverse = univ.Integer(13750000000)
>>> ageOfUniverse
Integer(13750000000)
>>>
>>> meanMartianSurfaceTemperature = univ.Integer(-63)
>>> meanMartianSurfaceTemperature
Integer(-63)
>>>
</pre>
</td></tr></table>
<p>
ASN.1 allows to assign human-friendly names to particular values of
an INTEGER type.
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
Temperature ::= INTEGER {
freezing(0),
boiling(100)
}
</pre>
</td></tr></table>
<p>
The Temperature type expressed in pyasn1:
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
>>> from pyasn1.type import univ, namedval
>>> class Temperature(univ.Integer):
... namedValues = namedval.NamedValues(('freezing', 0), ('boiling', 100))
...
>>> t = Temperature(0)
>>> t
Temperature('freezing(0)')
>>> t + 1
Temperature(1)
>>> t + 100
Temperature('boiling(100)')
>>> t = Temperature('boiling')
>>> t
Temperature('boiling(100)')
>>> Temperature('boiling') / 2
Temperature(50)
>>> -1 < Temperature('freezing')
True
>>> 47 > Temperature('boiling')
False
>>>
</pre>
</td></tr></table>
<p>
These values labels have no effect on Integer type operations, any value
still could be assigned to a type (information on value constraints will
follow further in this paper).
</p>
<a name="1.1.4"></a>
<h4>
1.1.4 Enumerated type
</h4>
<p>
ASN.1 Enumerated type differs from an Integer type in a number of ways.
Most important is that its instance can only hold a value that belongs
to a set of values specified on type declaration.
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
error-status ::= ENUMERATED {
no-error(0),
authentication-error(10),
authorization-error(20),
general-failure(51)
}
</pre>
</td></tr></table>
<p>
When constructing Enumerated type we will use two pyasn1 features: values
labels (as mentioned above) and value constraint (will be described in
more details later on).
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
>>> from pyasn1.type import univ, namedval, constraint
>>> class ErrorStatus(univ.Enumerated):
... namedValues = namedval.NamedValues(
... ('no-error', 0),
... ('authentication-error', 10),
... ('authorization-error', 20),
... ('general-failure', 51)
... )
... subtypeSpec = univ.Enumerated.subtypeSpec + \
... constraint.SingleValueConstraint(0, 10, 20, 51)
...
>>> errorStatus = univ.ErrorStatus('no-error')
>>> errorStatus
ErrorStatus('no-error(0)')
>>> errorStatus == univ.ErrorStatus('general-failure')
False
>>> univ.ErrorStatus('non-existing-state')
Traceback (most recent call last):
...
pyasn1.error.PyAsn1Error: Can't coerce non-existing-state into integer
>>>
</pre>
</td></tr></table>
<p>
Particular integer values associated with Enumerated value states
have no meaning. They should not be used as such or in any kind of
math operation. Those integer values are only used by codecs to
transfer state from one entity to another.
</p>
<a name="1.1.5"></a>
<h4>
1.1.5 Real type
</h4>
<p>
Values of the Real type are a three-component tuple of mantissa, base and
exponent. All three are integers.
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
pi ::= REAL { mantissa 314159, base 10, exponent -5 }
</pre>
</td></tr></table>
<p>
Corresponding pyasn1 objects can be initialized with either a three-component
tuple or a Python float. Infinite values could be expressed in a way,
compatible with Python float type.
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
>>> from pyasn1.type import univ
>>> pi = univ.Real((314159, 10, -5))
>>> pi
Real((314159, 10,-5))
>>> float(pi)
3.14159
>>> pi == univ.Real(3.14159)
True
>>> univ.Real('inf')
Real('inf')
>>> univ.Real('-inf') == float('-inf')
True
>>>
</pre>
</td></tr></table>
<p>
If a Real object is initialized from a Python float or yielded by a math
operation, the base is set to decimal 10 (what affects encoding).
</p>
<a name="1.1.6"></a>
<h4>
1.1.6 Bit string type
</h4>
<p>
ASN.1 BIT STRING type holds opaque binary data of an arbitrarily length.
A BIT STRING value could be initialized by either a binary (base 2) or
hex (base 16) value.
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
public-key BIT STRING ::= '1010111011110001010110101101101
1011000101010000010110101100010
0110101010000111101010111111110'B
signature BIT STRING ::= 'AF01330CD932093392100B39FF00DE0'H
</pre>
</td></tr></table>
<p>
The pyasn1 BitString objects can initialize from native ASN.1 notation
(base 2 or base 16 strings) or from a Python tuple of binary components.
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
>>> from pyasn1.type import univ
>>> publicKey = univ.BitString(
... "'1010111011110001010110101101101"
... "1011000101010000010110101100010"
... "0110101010000111101010111111110'B"
)
>>> publicKey
BitString("'10101110111100010101101011011011011000101010000010110101100010\
0110101010000111101010111111110'B")
>>> signature = univ.BitString(
... "'AF01330CD932093392100B39FF00DE0'H"
... )
>>> signature
BitString("'101011110000000100110011000011001101100100110010000010010011001\
1100100100001000000001011001110011111111100000000110111100000'B")
>>> fingerprint = univ.BitString(
... (1, 0, 1, 1 ,0, 1, 1, 1, 0, 1, 0, 1)
... )
>>> fingerprint
BitString("'101101110101'B")
>>>
</pre>
</td></tr></table>
<p>
Another BIT STRING initialization method supported by ASN.1 notation
is to specify only 1-th bits along with their human-friendly label
and bit offset relative to the beginning of the bit string. With this
method, all not explicitly mentioned bits are doomed to be zeros.
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
bit-mask BIT STRING ::= {
read-flag(0),
write-flag(2),
run-flag(4)
}
</pre>
</td></tr></table>
<p>
To express this in pyasn1, we will employ the named values feature (as with
Enumeration type).
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
>>> from pyasn1.type import univ, namedval
>>> class BitMask(univ.BitString):
... namedValues = namedval.NamedValues(
... ('read-flag', 0),
... ('write-flag', 2),
... ('run-flag', 4)
... )
>>> bitMask = BitMask('read-flag,run-flag')
>>> bitMask
BitMask("'10001'B")
>>> tuple(bitMask)
(1, 0, 0, 0, 1)
>>> bitMask[4]
1
>>>
</pre>
</td></tr></table>
<p>
The BitString objects mimic the properties of Python tuple type in part
of immutable sequence object protocol support.
</p>
<a name="1.1.7"></a>
<h4>
1.1.7 OctetString type
</h4>
<p>
The OCTET STRING type is a confusing subject. According to ASN.1
specification, this type is similar to BIT STRING, the major difference
is that the former operates in 8-bit chunks of data. What is important
to note, is that OCTET STRING was NOT designed to handle text strings - the
standard provides many other types specialized for text content. For that
reason, ASN.1 forbids to initialize OCTET STRING values with "quoted text
strings", only binary or hex initializers, similar to BIT STRING ones,
are allowed.
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
thumbnail OCTET STRING ::= '1000010111101110101111000000111011'B
thumbnail OCTET STRING ::= 'FA9823C43E43510DE3422'H
</pre>
</td></tr></table>
<p>
However, ASN.1 users (e.g. protocols designers) seem to ignore the original
purpose of the OCTET STRING type - they used it for handling all kinds of
data, including text strings.
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
welcome-message OCTET STRING ::= "Welcome to ASN.1 wilderness!"
</pre>
</td></tr></table>
<p>
In pyasn1, we have taken a liberal approach and allowed both BIT STRING
style and quoted text initializers for the OctetString objects. To avoid
possible collisions, quoted text is the default initialization syntax.
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
>>> from pyasn1.type import univ
>>> thumbnail = univ.OctetString(
... binValue='1000010111101110101111000000111011'
... )
>>> thumbnail
OctetString(hexValue='85eebcec0')
>>> thumbnail = univ.OctetString(
... hexValue='FA9823C43E43510DE3422'
... )
>>> thumbnail
OctetString(hexValue='fa9823c43e4351de34220')
>>>
</pre>
</td></tr></table>
<p>
Most frequent usage of the OctetString class is to instantiate it with
a text string.
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
>>> from pyasn1.type import univ
>>> welcomeMessage = univ.OctetString('Welcome to ASN.1 wilderness!')
>>> welcomeMessage
OctetString(b'Welcome to ASN.1 wilderness!')
>>> print('%s' % welcomeMessage)
Welcome to ASN.1 wilderness!
>>> welcomeMessage[11:16]
OctetString(b'ASN.1')
>>>
</pre>
</td></tr></table>
<p>
OctetString objects support the immutable sequence object protocol.
In other words, they behave like Python 3 bytes (or Python 2 strings).
</p>
<p>
When running pyasn1 on Python 3, it's better to use the bytes objects for
OctetString instantiation, as it's more reliable and efficient.
</p>
<p>
Additionally, OctetString's can also be instantiated with a sequence of
8-bit integers (ASCII codes).
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
>>> univ.OctetString((77, 101, 101, 103, 111))
OctetString(b'Meego')
</pre>
</td></tr></table>
<p>
It is sometimes convenient to express OctetString instances as 8-bit
characters (Python 3 bytes or Python 2 strings) or 8-bit integers.
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
>>> octetString = univ.OctetString('ABCDEF')
>>> octetString.asNumbers()
(65, 66, 67, 68, 69, 70)
>>> octetString.asOctets()
b'ABCDEF'
</pre>
</td></tr></table>
<a name="1.1.8"></a>
<h4>
1.1.8 ObjectIdentifier type
</h4>
<p>
Values of the OBJECT IDENTIFIER type are sequences of integers that could
be used to identify virtually anything in the world. Various ASN.1-based
protocols employ OBJECT IDENTIFIERs for their own identification needs.
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
internet-id OBJECT IDENTIFIER ::= {
iso(1) identified-organization(3) dod(6) internet(1)
}
</pre>
</td></tr></table>
<p>
One of the natural ways to map OBJECT IDENTIFIER type into a Python
one is to use Python tuples of integers. So this approach is taken by
pyasn1.
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
>>> from pyasn1.type import univ
>>> internetId = univ.ObjectIdentifier((1, 3, 6, 1))
>>> internetId
ObjectIdentifier('1.3.6.1')
>>> internetId[2]
6
>>> internetId[1:3]
ObjectIdentifier('3.6')
</pre>
</td></tr></table>
<p>
A more human-friendly "dotted" notation is also supported.
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
>>> from pyasn1.type import univ
>>> univ.ObjectIdentifier('1.3.6.1')
ObjectIdentifier('1.3.6.1')
</pre>
</td></tr></table>
<p>
Symbolic names of the arcs of object identifier, sometimes present in
ASN.1 specifications, are not preserved and used in pyasn1 objects.
</p>
<p>
The ObjectIdentifier objects mimic the properties of Python tuple type in
part of immutable sequence object protocol support.
</p>
<a name="1.1.9"></a>
<h4>
1.1.9 Character string types
</h4>
<p>
ASN.1 standard introduces a diverse set of text-specific types. All of them
were designed to handle various types of characters. Some of these types seem
be obsolete nowdays, as their target technologies are gone. Another issue
to be aware of is that raw OCTET STRING type is sometimes used in practice
by ASN.1 users instead of specialized character string types, despite
explicit prohibition imposed by ASN.1 specification.
</p>
<p>
The two types are specific to ASN.1 are NumericString and PrintableString.
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
welcome-message ::= PrintableString {
"Welcome to ASN.1 text types"
}
dial-pad-numbers ::= NumericString {
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"
}
</pre>
</td></tr></table>
<p>
Their pyasn1 implementations are:
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
>>> from pyasn1.type import char
>>> '%s' % char.PrintableString("Welcome to ASN.1 text types")
'Welcome to ASN.1 text types'
>>> dialPadNumbers = char.NumericString(
"0" "1" "2" "3" "4" "5" "6" "7" "8" "9"
)
>>> dialPadNumbers
NumericString(b'0123456789')
>>>
</pre>
</td></tr></table>
<p>
The following types came to ASN.1 from ISO standards on character sets.
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
>>> from pyasn1.type import char
>>> char.VisibleString("abc")
VisibleString(b'abc')
>>> char.IA5String('abc')
IA5String(b'abc')
>>> char.TeletexString('abc')
TeletexString(b'abc')
>>> char.VideotexString('abc')
VideotexString(b'abc')
>>> char.GraphicString('abc')
GraphicString(b'abc')
>>> char.GeneralString('abc')
GeneralString(b'abc')
>>>
</pre>
</td></tr></table>
<p>
The last three types are relatively recent addition to the family of
character string types: UniversalString, BMPString, UTF8String.
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
>>> from pyasn1.type import char
>>> char.UniversalString("abc")
UniversalString(b'abc')
>>> char.BMPString('abc')
BMPString(b'abc')
>>> char.UTF8String('abc')
UTF8String(b'abc')
>>> utf8String = char.UTF8String('У попа была собака')
>>> utf8String
UTF8String(b'\xd0\xa3 \xd0\xbf\xd0\xbe\xd0\xbf\xd0\xb0 \xd0\xb1\xd1\x8b\xd0\xbb\xd0\xb0 \
\xd1\x81\xd0\xbe\xd0\xb1\xd0\xb0\xd0\xba\xd0\xb0')
>>> print(utf8String)
У попа была собака
>>>
</pre>
</td></tr></table>
<p>
In pyasn1, all character type objects behave like Python strings. None of
them is currently constrained in terms of valid alphabet so it's up to
the data source to keep an eye on data validation for these types.
</p>
<a name="1.1.10"></a>
<h4>
1.1.10 Useful types
</h4>
<p>
There are three so-called useful types defined in the standard:
ObjectDescriptor, GeneralizedTime, UTCTime. They all are subtypes
of GraphicString or VisibleString types therefore useful types are
character string types.
</p>
<p>
It's advised by the ASN.1 standard to have an instance of ObjectDescriptor
type holding a human-readable description of corresponding instance of
OBJECT IDENTIFIER type. There are no formal linkage between these instances
and provision for ObjectDescriptor uniqueness in the standard.
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
>>> from pyasn1.type import useful
>>> descrBER = useful.ObjectDescriptor(
"Basic encoding of a single ASN.1 type"
)
>>>
</pre>
</td></tr></table>
<p>
GeneralizedTime and UTCTime types are designed to hold a human-readable
timestamp in a universal and unambiguous form. The former provides
more flexibility in notation while the latter is more strict but has
Y2K issues.
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
;; Mar 8 2010 12:00:00 MSK
moscow-time GeneralizedTime ::= "20110308120000.0"
;; Mar 8 2010 12:00:00 UTC
utc-time GeneralizedTime ::= "201103081200Z"
;; Mar 8 1999 12:00:00 UTC
utc-time UTCTime ::= "9803081200Z"
</pre>
</td></tr></table>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
>>> from pyasn1.type import useful
>>> moscowTime = useful.GeneralizedTime("20110308120000.0")
>>> utcTime = useful.UTCTime("9803081200Z")
>>>
</pre>
</td></tr></table>
<p>
Despite their intended use, these types possess no special, time-related,
handling in pyasn1. They are just printable strings.
</p>
<hr>
</td>
</tr>
</table>
</center>
</body>
</html>

View File

@@ -0,0 +1,233 @@
<html>
<title>
Tagging in PyASN1
</title>
<head>
</head>
<body>
<center>
<table width=60%>
<tr>
<td>
<a name="1.2"></a>
<h4>
1.2 Tagging in PyASN1
</h4>
<p>
In order to continue with the Constructed ASN.1 types, we will first have
to introduce the concept of tagging (and its pyasn1 implementation), as
some of the Constructed types rely upon the tagging feature.
</p>
<p>
When a value is coming into an ASN.1-based system (received from a network
or read from some storage), the receiving entity has to determine the
type of the value to interpret and verify it accordingly.
</p>
<p>
Historically, the first data serialization protocol introduced in
ASN.1 was BER (Basic Encoding Rules). According to BER, any serialized
value is packed into a triplet of (Type, Length, Value) where Type is a
code that identifies the value (which is called <i>tag</i> in ASN.1),
length is the number of bytes occupied by the value in its serialized form
and value is ASN.1 value in a form suitable for serial transmission or storage.
</p>
<p>
For that reason almost every ASN.1 type has a tag (which is actually a
BER type) associated with it by default.
</p>
<p>
An ASN.1 tag could be viewed as a tuple of three numbers:
(Class, Format, Number). While Number identifies a tag, Class component
is used to create scopes for Numbers. Four scopes are currently defined:
UNIVERSAL, context-specific, APPLICATION and PRIVATE. The Format component
is actually a one-bit flag - zero for tags associated with scalar types,
and one for constructed types (will be discussed later on).
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
MyIntegerType ::= [12] INTEGER
MyOctetString ::= [APPLICATION 0] OCTET STRING
</pre>
</td></tr></table>
<p>
In pyasn1, tags are implemented as immutable, tuple-like objects:
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
>>> from pyasn1.type import tag
>>> myTag = tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 10)
>>> myTag
Tag(tagClass=128, tagFormat=0, tagId=10)
>>> tuple(myTag)
(128, 0, 10)
>>> myTag[2]
10
>>> myTag == tag.Tag(tag.tagClassApplication, tag.tagFormatSimple, 10)
False
>>>
</pre>
</td></tr></table>
<p>
Default tag, associated with any ASN.1 type, could be extended or replaced
to make new type distinguishable from its ancestor. The standard provides
two modes of tag mangling - IMPLICIT and EXPLICIT.
</p>
<p>
EXPLICIT mode works by appending new tag to the existing ones thus creating
an ordered set of tags. This set will be considered as a whole for type
identification and encoding purposes. Important property of EXPLICIT tagging
mode is that it preserves base type information in encoding what makes it
possible to completely recover type information from encoding.
</p>
<p>
When tagging in IMPLICIT mode, the outermost existing tag is dropped and
replaced with a new one.
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
MyIntegerType ::= [12] IMPLICIT INTEGER
MyOctetString ::= [APPLICATION 0] EXPLICIT OCTET STRING
</pre>
</td></tr></table>
<p>
To model both modes of tagging, a specialized container TagSet object (holding
zero, one or more Tag objects) is used in pyasn1.
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
>>> from pyasn1.type import tag
>>> tagSet = tag.TagSet(
... # base tag
... tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 10),
... # effective tag
... tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 10)
... )
>>> tagSet
TagSet(Tag(tagClass=128, tagFormat=0, tagId=10))
>>> tagSet.getBaseTag()
Tag(tagClass=128, tagFormat=0, tagId=10)
>>> tagSet = tagSet.tagExplicitly(
... tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 20)
... )
>>> tagSet
TagSet(Tag(tagClass=128, tagFormat=0, tagId=10),
Tag(tagClass=128, tagFormat=32, tagId=20))
>>> tagSet = tagSet.tagExplicitly(
... tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 30)
... )
>>> tagSet
TagSet(Tag(tagClass=128, tagFormat=0, tagId=10),
Tag(tagClass=128, tagFormat=32, tagId=20),
Tag(tagClass=128, tagFormat=32, tagId=30))
>>> tagSet = tagSet.tagImplicitly(
... tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 40)
... )
>>> tagSet
TagSet(Tag(tagClass=128, tagFormat=0, tagId=10),
Tag(tagClass=128, tagFormat=32, tagId=20),
Tag(tagClass=128, tagFormat=32, tagId=40))
>>>
</pre>
</td></tr></table>
<p>
As a side note: the "base tag" concept (accessible through the getBaseTag()
method) is specific to pyasn1 -- the base tag is used to identify the original
ASN.1 type of an object in question. Base tag is never occurs in encoding
and is mostly used internally by pyasn1 for choosing type-specific data
processing algorithms. The "effective tag" is the one that always appears in
encoding and is used on tagSets comparation.
</p>
<p>
Any two TagSet objects could be compared to see if one is a derivative
of the other. Figuring this out is also useful in cases when a type-specific
data processing algorithms are to be chosen.
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
>>> from pyasn1.type import tag
>>> tagSet1 = tag.TagSet(
... # base tag
... tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 10)
... # effective tag
... tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 10)
... )
>>> tagSet2 = tagSet1.tagExplicitly(
... tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 20)
... )
>>> tagSet1.isSuperTagSetOf(tagSet2)
True
>>> tagSet2.isSuperTagSetOf(tagSet1)
False
>>>
</pre>
</td></tr></table>
<p>
We will complete this discussion on tagging with a real-world example. The
following ASN.1 tagged type:
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
MyIntegerType ::= [12] EXPLICIT INTEGER
</pre>
</td></tr></table>
<p>
could be expressed in pyasn1 like this:
</p>
<table bgcolor="lightgray" border=0 width=100%><TR><TD>
<pre>
>>> from pyasn1.type import univ, tag
>>> class MyIntegerType(univ.Integer):
... tagSet = univ.Integer.tagSet.tagExplicitly(
... tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 12)
... )
>>> myInteger = MyIntegerType(12345)
>>> myInteger.getTagSet()
TagSet(Tag(tagClass=0, tagFormat=0, tagId=2),
Tag(tagClass=128, tagFormat=32, tagId=12))
>>>
</pre>
</td></tr></table>
<p>
Referring to the above code, the tagSet class attribute is a property of any
pyasn1 type object that assigns default tagSet to a pyasn1 value object. This
default tagSet specification can be ignored and effectively replaced by some
other tagSet value passed on object instantiation.
</p>
<p>
It's important to understand that the tag set property of pyasn1 type/value
object can never be modifed in place. In other words, a pyasn1 type/value
object can never change its tags. The only way is to create a new pyasn1
type/value object and associate different tag set with it.
</p>
<hr>
</td>
</tr>
</table>
</center>
</body>
</html>

View 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

View File

@@ -0,0 +1,68 @@
CHANGES
LICENSE
MANIFEST.in
README
THANKS
TODO
setup.py
doc/codecs.html
doc/constraints.html
doc/constructed.html
doc/intro.html
doc/pyasn1-tutorial.html
doc/scalar.html
doc/tagging.html
pyasn1/__init__.py
pyasn1/debug.py
pyasn1/error.py
pyasn1.egg-info/PKG-INFO
pyasn1.egg-info/SOURCES.txt
pyasn1.egg-info/dependency_links.txt
pyasn1.egg-info/top_level.txt
pyasn1.egg-info/zip-safe
pyasn1/codec/__init__.py
pyasn1/codec/ber/__init__.py
pyasn1/codec/ber/decoder.py
pyasn1/codec/ber/encoder.py
pyasn1/codec/ber/eoo.py
pyasn1/codec/cer/__init__.py
pyasn1/codec/cer/decoder.py
pyasn1/codec/cer/encoder.py
pyasn1/codec/der/__init__.py
pyasn1/codec/der/decoder.py
pyasn1/codec/der/encoder.py
pyasn1/compat/__init__.py
pyasn1/compat/octets.py
pyasn1/type/__init__.py
pyasn1/type/base.py
pyasn1/type/char.py
pyasn1/type/constraint.py
pyasn1/type/error.py
pyasn1/type/namedtype.py
pyasn1/type/namedval.py
pyasn1/type/tag.py
pyasn1/type/tagmap.py
pyasn1/type/univ.py
pyasn1/type/useful.py
test/__init__.py
test/suite.py
test/codec/__init__.py
test/codec/suite.py
test/codec/ber/__init__.py
test/codec/ber/suite.py
test/codec/ber/test_decoder.py
test/codec/ber/test_encoder.py
test/codec/cer/__init__.py
test/codec/cer/suite.py
test/codec/cer/test_decoder.py
test/codec/cer/test_encoder.py
test/codec/der/__init__.py
test/codec/der/suite.py
test/codec/der/test_decoder.py
test/codec/der/test_encoder.py
test/type/__init__.py
test/type/suite.py
test/type/test_constraint.py
test/type/test_namedtype.py
test/type/test_tag.py
test/type/test_univ.py

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1 @@
pyasn1

View File

@@ -0,0 +1 @@

View 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')

View File

@@ -0,0 +1 @@
# This file is necessary to make this directory a package.

View File

@@ -0,0 +1 @@
# This file is necessary to make this directory a package.

View 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

View 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)

View 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()

View File

@@ -0,0 +1 @@
# This file is necessary to make this directory a package.

View 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)

View 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

View File

@@ -0,0 +1 @@
# This file is necessary to make this directory a package.

View 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)

View 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)

View File

@@ -0,0 +1 @@
# This file is necessary to make this directory a package.

View 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)

View 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()

View File

@@ -0,0 +1,3 @@
class PyAsn1Error(Exception): pass
class ValueConstraintError(PyAsn1Error): pass
class SubstrateUnderrunError(PyAsn1Error): pass

View File

@@ -0,0 +1 @@
# This file is necessary to make this directory a package.

View 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

View 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"

View 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

View File

@@ -0,0 +1,3 @@
from pyasn1.error import PyAsn1Error
class ValueConstraintError(PyAsn1Error): pass

View 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]

View 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?

View 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)

View 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

File diff suppressed because it is too large Load Diff

View 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)
)

5
python/pyasn1/setup.cfg Normal file
View File

@@ -0,0 +1,5 @@
[egg_info]
tag_build =
tag_date = 0
tag_svn_revision = 0

115
python/pyasn1/setup.py Normal file
View File

@@ -0,0 +1,115 @@
#!/usr/bin/env python
"""ASN.1 types and codecs
A pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208).
"""
import os
import sys
classifiers = """\
Development Status :: 5 - Production/Stable
Environment :: Console
Intended Audience :: Developers
Intended Audience :: Education
Intended Audience :: Information Technology
Intended Audience :: Science/Research
Intended Audience :: System Administrators
Intended Audience :: Telecommunications Industry
License :: OSI Approved :: BSD License
Natural Language :: English
Operating System :: OS Independent
Programming Language :: Python :: 2
Programming Language :: Python :: 3
Topic :: Communications
Topic :: Security :: Cryptography
Topic :: Software Development :: Libraries :: Python Modules
"""
def howto_install_distribute():
print("""
Error: You need the distribute Python package!
It's very easy to install it, just type (as root on Linux):
wget http://python-distribute.org/distribute_setup.py
python distribute_setup.py
Then you could make eggs from this package.
""")
def howto_install_setuptools():
print("""
Error: You need setuptools Python package!
It's very easy to install it, just type (as root on Linux):
wget http://peak.telecommunity.com/dist/ez_setup.py
python ez_setup.py
Then you could make eggs from this package.
""")
try:
from setuptools import setup, Command
params = {
'zip_safe': True
}
except ImportError:
for arg in sys.argv:
if arg.find('egg') != -1:
if sys.version_info[0] > 2:
howto_install_distribute()
else:
howto_install_setuptools()
sys.exit(1)
from distutils.core import setup, Command
params = {}
doclines = [ x.strip() for x in __doc__.split('\n') if x ]
params.update( {
'name': 'pyasn1',
'version': open(os.path.join('pyasn1','__init__.py')).read().split('\'')[1],
'description': doclines[0],
'long_description': ' '.join(doclines[1:]),
'maintainer': 'Ilya Etingof <ilya@glas.net>',
'author': 'Ilya Etingof',
'author_email': 'ilya@glas.net',
'url': 'http://sourceforge.net/projects/pyasn1/',
'platforms': ['any'],
'classifiers': [ x for x in classifiers.split('\n') if x ],
'license': 'BSD',
'packages': [ 'pyasn1',
'pyasn1.type',
'pyasn1.compat',
'pyasn1.codec',
'pyasn1.codec.ber',
'pyasn1.codec.cer',
'pyasn1.codec.der' ]
} )
# handle unittest discovery feature
if sys.version_info[0:2] < (2, 7) or \
sys.version_info[0:2] in ( (3, 0), (3, 1) ):
try:
import unittest2 as unittest
except ImportError:
unittest = None
else:
import unittest
if unittest:
class PyTest(Command):
user_options = []
def initialize_options(self): pass
def finalize_options(self): pass
def run(self):
suite = unittest.defaultTestLoader.discover('.')
unittest.TextTestRunner(verbosity=2).run(suite)
params['cmdclass'] = { 'test': PyTest }
setup(**params)

View File

@@ -0,0 +1 @@
# This file is necessary to make this directory a package.

View File

@@ -0,0 +1 @@
# This file is necessary to make this directory a package.

View File

@@ -0,0 +1 @@
# This file is necessary to make this directory a package.

View File

@@ -0,0 +1,22 @@
from sys import path, version_info
from os.path import sep
path.insert(1, path[0]+sep+'ber')
import test_encoder, test_decoder
from pyasn1.error import PyAsn1Error
if version_info[0:2] < (2, 7) or \
version_info[0:2] in ( (3, 0), (3, 1) ):
try:
import unittest2 as unittest
except ImportError:
import unittest
else:
import unittest
suite = unittest.TestSuite()
loader = unittest.TestLoader()
for m in (test_encoder, test_decoder):
suite.addTest(loader.loadTestsFromModule(m))
def runTests(): unittest.TextTestRunner(verbosity=2).run(suite)
if __name__ == '__main__': runTests()

View File

@@ -0,0 +1,535 @@
from pyasn1.type import tag, namedtype, univ
from pyasn1.codec.ber import decoder
from pyasn1.compat.octets import ints2octs, str2octs, null
from pyasn1.error import PyAsn1Error
from sys import version_info
if version_info[0:2] < (2, 7) or \
version_info[0:2] in ( (3, 0), (3, 1) ):
try:
import unittest2 as unittest
except ImportError:
import unittest
else:
import unittest
class LargeTagDecoderTestCase(unittest.TestCase):
def testLargeTag(self):
assert decoder.decode(ints2octs((127, 141, 245, 182, 253, 47, 3, 2, 1, 1))) == (1, null)
class IntegerDecoderTestCase(unittest.TestCase):
def testPosInt(self):
assert decoder.decode(ints2octs((2, 1, 12))) == (12, null)
def testNegInt(self):
assert decoder.decode(ints2octs((2, 1, 244))) == (-12, null)
def testZero(self):
assert decoder.decode(ints2octs((2, 0))) == (0, null)
def testZeroLong(self):
assert decoder.decode(ints2octs((2, 1, 0))) == (0, null)
def testMinusOne(self):
assert decoder.decode(ints2octs((2, 1, 255))) == (-1, null)
def testPosLong(self):
assert decoder.decode(
ints2octs((2, 9, 0, 255, 255, 255, 255, 255, 255, 255, 255))
) == (0xffffffffffffffff, null)
def testNegLong(self):
assert decoder.decode(
ints2octs((2, 9, 255, 0, 0, 0, 0, 0, 0, 0, 1))
) == (-0xffffffffffffffff, null)
def testSpec(self):
try:
decoder.decode(
ints2octs((2, 1, 12)), asn1Spec=univ.Null()
) == (12, null)
except PyAsn1Error:
pass
else:
assert 0, 'wrong asn1Spec worked out'
assert decoder.decode(
ints2octs((2, 1, 12)), asn1Spec=univ.Integer()
) == (12, null)
def testTagFormat(self):
try:
decoder.decode(ints2octs((34, 1, 12)))
except PyAsn1Error:
pass
else:
assert 0, 'wrong tagFormat worked out'
class BooleanDecoderTestCase(unittest.TestCase):
def testTrue(self):
assert decoder.decode(ints2octs((1, 1, 1))) == (1, null)
def testTrueNeg(self):
assert decoder.decode(ints2octs((1, 1, 255))) == (1, null)
def testExtraTrue(self):
assert decoder.decode(ints2octs((1, 1, 1, 0, 120, 50, 50))) == (1, ints2octs((0, 120, 50, 50)))
def testFalse(self):
assert decoder.decode(ints2octs((1, 1, 0))) == (0, null)
def testTagFormat(self):
try:
decoder.decode(ints2octs((33, 1, 1)))
except PyAsn1Error:
pass
else:
assert 0, 'wrong tagFormat worked out'
class BitStringDecoderTestCase(unittest.TestCase):
def testDefMode(self):
assert decoder.decode(
ints2octs((3, 3, 1, 169, 138))
) == ((1,0,1,0,1,0,0,1,1,0,0,0,1,0,1), null)
def testIndefMode(self):
assert decoder.decode(
ints2octs((3, 3, 1, 169, 138))
) == ((1,0,1,0,1,0,0,1,1,0,0,0,1,0,1), null)
def testDefModeChunked(self):
assert decoder.decode(
ints2octs((35, 8, 3, 2, 0, 169, 3, 2, 1, 138))
) == ((1,0,1,0,1,0,0,1,1,0,0,0,1,0,1), null)
def testIndefModeChunked(self):
assert decoder.decode(
ints2octs((35, 128, 3, 2, 0, 169, 3, 2, 1, 138, 0, 0))
) == ((1,0,1,0,1,0,0,1,1,0,0,0,1,0,1), null)
def testDefModeChunkedSubst(self):
assert decoder.decode(
ints2octs((35, 8, 3, 2, 0, 169, 3, 2, 1, 138)),
substrateFun=lambda a,b,c: (b,c)
) == (ints2octs((3, 2, 0, 169, 3, 2, 1, 138)), 8)
def testIndefModeChunkedSubst(self):
assert decoder.decode(
ints2octs((35, 128, 3, 2, 0, 169, 3, 2, 1, 138, 0, 0)),
substrateFun=lambda a,b,c: (b,c)
) == (ints2octs((3, 2, 0, 169, 3, 2, 1, 138, 0, 0)), -1)
class OctetStringDecoderTestCase(unittest.TestCase):
def testDefMode(self):
assert decoder.decode(
ints2octs((4, 15, 81, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 32, 102, 111, 120))
) == (str2octs('Quick brown fox'), null)
def testIndefMode(self):
assert decoder.decode(
ints2octs((36, 128, 4, 15, 81, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 32, 102, 111, 120, 0, 0))
) == (str2octs('Quick brown fox'), null)
def testDefModeChunked(self):
assert decoder.decode(
ints2octs((36, 23, 4, 4, 81, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 4, 111, 119, 110, 32, 4, 3, 102, 111, 120))
) == (str2octs('Quick brown fox'), null)
def testIndefModeChunked(self):
assert decoder.decode(
ints2octs((36, 128, 4, 4, 81, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 4, 111, 119, 110, 32, 4, 3, 102, 111, 120, 0, 0))
) == (str2octs('Quick brown fox'), null)
def testDefModeChunkedSubst(self):
assert decoder.decode(
ints2octs((36, 23, 4, 4, 81, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 4, 111, 119, 110, 32, 4, 3, 102, 111, 120)),
substrateFun=lambda a,b,c: (b,c)
) == (ints2octs((4, 4, 81, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 4, 111, 119, 110, 32, 4, 3, 102, 111, 120)), 23)
def testIndefModeChunkedSubst(self):
assert decoder.decode(
ints2octs((36, 128, 4, 4, 81, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 4, 111, 119, 110, 32, 4, 3, 102, 111, 120, 0, 0)),
substrateFun=lambda a,b,c: (b,c)
) == (ints2octs((4, 4, 81, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 4, 111, 119, 110, 32, 4, 3, 102, 111, 120, 0, 0)), -1)
class ExpTaggedOctetStringDecoderTestCase(unittest.TestCase):
def setUp(self):
self.o = univ.OctetString(
'Quick brown fox',
tagSet=univ.OctetString.tagSet.tagExplicitly(
tag.Tag(tag.tagClassApplication, tag.tagFormatSimple, 5)
))
def testDefMode(self):
assert self.o.isSameTypeWith(decoder.decode(
ints2octs((101, 17, 4, 15, 81, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 32, 102, 111, 120))
)[0])
def testIndefMode(self):
v, s = decoder.decode(ints2octs((101, 128, 36, 128, 4, 15, 81, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 32, 102, 111, 120, 0, 0, 0, 0)))
assert self.o.isSameTypeWith(v)
assert not s
def testDefModeChunked(self):
v, s = decoder.decode(ints2octs((101, 25, 36, 23, 4, 4, 81, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 4, 111, 119, 110, 32, 4, 3, 102, 111, 120)))
assert self.o.isSameTypeWith(v)
assert not s
def testIndefModeChunked(self):
v, s = decoder.decode(ints2octs((101, 128, 36, 128, 4, 4, 81, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 4, 111, 119, 110, 32, 4, 3, 102, 111, 120, 0, 0, 0, 0)))
assert self.o.isSameTypeWith(v)
assert not s
def testDefModeSubst(self):
assert decoder.decode(
ints2octs((101, 17, 4, 15, 81, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 32, 102, 111, 120)),
substrateFun=lambda a,b,c: (b,c)
) == (ints2octs((4, 15, 81, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 32, 102, 111, 120)), 17)
def testIndefModeSubst(self):
assert decoder.decode(
ints2octs((101, 128, 36, 128, 4, 15, 81, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 32, 102, 111, 120, 0, 0, 0, 0)),
substrateFun=lambda a,b,c: (b,c)
) == (ints2octs((36, 128, 4, 15, 81, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 32, 102, 111, 120, 0, 0, 0, 0)), -1)
class NullDecoderTestCase(unittest.TestCase):
def testNull(self):
assert decoder.decode(ints2octs((5, 0))) == (null, null)
def testTagFormat(self):
try:
decoder.decode(ints2octs((37, 0)))
except PyAsn1Error:
pass
else:
assert 0, 'wrong tagFormat worked out'
class ObjectIdentifierDecoderTestCase(unittest.TestCase):
def testOID(self):
assert decoder.decode(
ints2octs((6, 6, 43, 6, 0, 191, 255, 126))
) == ((1,3,6,0,0xffffe), null)
def testEdges1(self):
assert decoder.decode(
ints2octs((6, 1, 255))
) == ((6,15), null)
def testEdges2(self):
assert decoder.decode(
ints2octs((6, 1, 239))
) == ((5,39), null)
def testEdges3(self):
assert decoder.decode(
ints2octs((6, 7, 43, 6, 143, 255, 255, 255, 127))
) == ((1, 3, 6, 4294967295), null)
def testNonLeading0x80(self):
assert decoder.decode(
ints2octs((6, 5, 85, 4, 129, 128, 0)),
) == ((2, 5, 4, 16384), null)
def testLeading0x80(self):
try:
decoder.decode(
ints2octs((6, 5, 85, 4, 128, 129, 0))
)
except PyAsn1Error:
pass
else:
assert 1, 'Leading 0x80 tolarated'
def testTagFormat(self):
try:
decoder.decode(ints2octs((38, 1, 239)))
except PyAsn1Error:
pass
else:
assert 0, 'wrong tagFormat worked out'
class RealDecoderTestCase(unittest.TestCase):
def testChar(self):
assert decoder.decode(
ints2octs((9, 7, 3, 49, 50, 51, 69, 49, 49))
) == (univ.Real((123, 10, 11)), null)
def testBin1(self):
assert decoder.decode(
ints2octs((9, 4, 128, 245, 4, 77))
) == (univ.Real((1101, 2, -11)), null)
def testBin2(self):
assert decoder.decode(
ints2octs((9, 4, 128, 11, 4, 77))
) == (univ.Real((1101, 2, 11)), null)
def testBin3(self):
assert decoder.decode(
ints2octs((9, 3, 192, 10, 123))
) == (univ.Real((-123, 2, 10)), null)
def testPlusInf(self):
assert decoder.decode(
ints2octs((9, 1, 64))
) == (univ.Real('inf'), null)
def testMinusInf(self):
assert decoder.decode(
ints2octs((9, 1, 65))
) == (univ.Real('-inf'), null)
def testEmpty(self):
assert decoder.decode(
ints2octs((9, 0))
) == (univ.Real(0.0), null)
def testTagFormat(self):
try:
decoder.decode(ints2octs((41, 0)))
except PyAsn1Error:
pass
else:
assert 0, 'wrong tagFormat worked out'
class SequenceDecoderTestCase(unittest.TestCase):
def setUp(self):
self.s = univ.Sequence(componentType=namedtype.NamedTypes(
namedtype.NamedType('place-holder', univ.Null(null)),
namedtype.NamedType('first-name', univ.OctetString(null)),
namedtype.NamedType('age', univ.Integer(33)),
))
self.s.setComponentByPosition(0, univ.Null(null))
self.s.setComponentByPosition(1, univ.OctetString('quick brown'))
self.s.setComponentByPosition(2, univ.Integer(1))
self.s.setDefaultComponents()
def testWithOptionalAndDefaultedDefMode(self):
assert decoder.decode(
ints2octs((48, 18, 5, 0, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 2, 1, 1))
) == (self.s, null)
def testWithOptionalAndDefaultedIndefMode(self):
assert decoder.decode(
ints2octs((48, 128, 5, 0, 36, 128, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 0, 0, 2, 1, 1, 0, 0))
) == (self.s, null)
def testWithOptionalAndDefaultedDefModeChunked(self):
assert decoder.decode(
ints2octs((48, 24, 5, 0, 36, 17, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110, 2, 1, 1))
) == (self.s, null)
def testWithOptionalAndDefaultedIndefModeChunked(self):
assert decoder.decode(
ints2octs((48, 128, 5, 0, 36, 128, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110, 0, 0, 2, 1, 1, 0, 0))
) == (self.s, null)
def testWithOptionalAndDefaultedDefModeSubst(self):
assert decoder.decode(
ints2octs((48, 18, 5, 0, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 2, 1, 1)),
substrateFun=lambda a,b,c: (b,c)
) == (ints2octs((5, 0, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 2, 1, 1)), 18)
def testWithOptionalAndDefaultedIndefModeSubst(self):
assert decoder.decode(
ints2octs((48, 128, 5, 0, 36, 128, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 0, 0, 2, 1, 1, 0, 0)),
substrateFun=lambda a,b,c: (b,c)
) == (ints2octs((5, 0, 36, 128, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 0, 0, 2, 1, 1, 0, 0)), -1)
def testTagFormat(self):
try:
decoder.decode(
ints2octs((16, 18, 5, 0, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 2, 1, 1))
)
except PyAsn1Error:
pass
else:
assert 0, 'wrong tagFormat worked out'
class GuidedSequenceDecoderTestCase(unittest.TestCase):
def setUp(self):
self.s = univ.Sequence(componentType=namedtype.NamedTypes(
namedtype.NamedType('place-holder', univ.Null(null)),
namedtype.OptionalNamedType('first-name', univ.OctetString(null)),
namedtype.DefaultedNamedType('age', univ.Integer(33)),
))
def __init(self):
self.s.clear()
self.s.setComponentByPosition(0, univ.Null(null))
self.s.setDefaultComponents()
def __initWithOptional(self):
self.s.clear()
self.s.setComponentByPosition(0, univ.Null(null))
self.s.setComponentByPosition(1, univ.OctetString('quick brown'))
self.s.setDefaultComponents()
def __initWithDefaulted(self):
self.s.clear()
self.s.setComponentByPosition(0, univ.Null(null))
self.s.setComponentByPosition(2, univ.Integer(1))
self.s.setDefaultComponents()
def __initWithOptionalAndDefaulted(self):
self.s.clear()
self.s.setComponentByPosition(0, univ.Null(null))
self.s.setComponentByPosition(1, univ.OctetString('quick brown'))
self.s.setComponentByPosition(2, univ.Integer(1))
self.s.setDefaultComponents()
def testDefMode(self):
self.__init()
assert decoder.decode(
ints2octs((48, 128, 5, 0, 0, 0)), asn1Spec=self.s
) == (self.s, null)
def testIndefMode(self):
self.__init()
assert decoder.decode(
ints2octs((48, 128, 5, 0, 0, 0)), asn1Spec=self.s
) == (self.s, null)
def testDefModeChunked(self):
self.__init()
assert decoder.decode(
ints2octs((48, 2, 5, 0)), asn1Spec=self.s
) == (self.s, null)
def testIndefModeChunked(self):
self.__init()
assert decoder.decode(
ints2octs((48, 128, 5, 0, 0, 0)), asn1Spec=self.s
) == (self.s, null)
def testWithOptionalDefMode(self):
self.__initWithOptional()
assert decoder.decode(
ints2octs((48, 15, 5, 0, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110)), asn1Spec=self.s
) == (self.s, null)
def testWithOptionaIndefMode(self):
self.__initWithOptional()
assert decoder.decode(
ints2octs((48, 128, 5, 0, 36, 128, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 0, 0, 0, 0)),
asn1Spec=self.s
) == (self.s, null)
def testWithOptionalDefModeChunked(self):
self.__initWithOptional()
assert decoder.decode(
ints2octs((48, 21, 5, 0, 36, 17, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110)),
asn1Spec=self.s
) == (self.s, null)
def testWithOptionalIndefModeChunked(self):
self.__initWithOptional()
assert decoder.decode(
ints2octs((48, 128, 5, 0, 36, 128, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110, 0, 0, 0, 0)),
asn1Spec=self.s
) == (self.s, null)
def testWithDefaultedDefMode(self):
self.__initWithDefaulted()
assert decoder.decode(
ints2octs((48, 5, 5, 0, 2, 1, 1)), asn1Spec=self.s
) == (self.s, null)
def testWithDefaultedIndefMode(self):
self.__initWithDefaulted()
assert decoder.decode(
ints2octs((48, 128, 5, 0, 2, 1, 1, 0, 0)), asn1Spec=self.s
) == (self.s, null)
def testWithDefaultedDefModeChunked(self):
self.__initWithDefaulted()
assert decoder.decode(
ints2octs((48, 5, 5, 0, 2, 1, 1)), asn1Spec=self.s
) == (self.s, null)
def testWithDefaultedIndefModeChunked(self):
self.__initWithDefaulted()
assert decoder.decode(
ints2octs((48, 128, 5, 0, 2, 1, 1, 0, 0)), asn1Spec=self.s
) == (self.s, null)
def testWithOptionalAndDefaultedDefMode(self):
self.__initWithOptionalAndDefaulted()
assert decoder.decode(
ints2octs((48, 18, 5, 0, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 2, 1, 1)), asn1Spec=self.s
) == (self.s, null)
def testWithOptionalAndDefaultedIndefMode(self):
self.__initWithOptionalAndDefaulted()
assert decoder.decode(
ints2octs((48, 128, 5, 0, 36, 128, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 0, 0, 2, 1, 1, 0, 0)), asn1Spec=self.s
) == (self.s, null)
def testWithOptionalAndDefaultedDefModeChunked(self):
self.__initWithOptionalAndDefaulted()
assert decoder.decode(
ints2octs((48, 24, 5, 0, 36, 17, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110, 2, 1, 1)), asn1Spec=self.s
) == (self.s, null)
def testWithOptionalAndDefaultedIndefModeChunked(self):
self.__initWithOptionalAndDefaulted()
assert decoder.decode(
ints2octs((48, 128, 5, 0, 36, 128, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110, 0, 0, 2, 1, 1, 0, 0)), asn1Spec=self.s
) == (self.s, null)
class ChoiceDecoderTestCase(unittest.TestCase):
def setUp(self):
self.s = univ.Choice(componentType=namedtype.NamedTypes(
namedtype.NamedType('place-holder', univ.Null(null)),
namedtype.NamedType('number', univ.Integer(0)),
namedtype.NamedType('string', univ.OctetString())
))
def testBySpec(self):
self.s.setComponentByPosition(0, univ.Null(null))
assert decoder.decode(
ints2octs((5, 0)), asn1Spec=self.s
) == (self.s, null)
def testWithoutSpec(self):
self.s.setComponentByPosition(0, univ.Null(null))
assert decoder.decode(ints2octs((5, 0))) == (self.s, null)
assert decoder.decode(ints2octs((5, 0))) == (univ.Null(null), null)
def testUndefLength(self):
self.s.setComponentByPosition(2, univ.OctetString('abcdefgh'))
assert decoder.decode(ints2octs((36, 128, 4, 3, 97, 98, 99, 4, 3, 100, 101, 102, 4, 2, 103, 104, 0, 0)), asn1Spec=self.s) == (self.s, null)
def testExplicitTag(self):
s = self.s.subtype(explicitTag=tag.Tag(tag.tagClassContext,
tag.tagFormatConstructed, 4))
s.setComponentByPosition(0, univ.Null(null))
assert decoder.decode(ints2octs((164, 2, 5, 0)), asn1Spec=s) == (s, null)
def testExplicitTagUndefLength(self):
s = self.s.subtype(explicitTag=tag.Tag(tag.tagClassContext,
tag.tagFormatConstructed, 4))
s.setComponentByPosition(0, univ.Null(null))
assert decoder.decode(ints2octs((164, 128, 5, 0, 0, 0)), asn1Spec=s) == (s, null)
class AnyDecoderTestCase(unittest.TestCase):
def setUp(self):
self.s = univ.Any()
def testByUntagged(self):
assert decoder.decode(
ints2octs((4, 3, 102, 111, 120)), asn1Spec=self.s
) == (univ.Any('\004\003fox'), null)
def testTaggedEx(self):
s = univ.Any('\004\003fox').subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 4))
assert decoder.decode(ints2octs((164, 5, 4, 3, 102, 111, 120)), asn1Spec=s) == (s, null)
def testTaggedIm(self):
s = univ.Any('\004\003fox').subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 4))
assert decoder.decode(ints2octs((132, 5, 4, 3, 102, 111, 120)), asn1Spec=s) == (s, null)
def testByUntaggedIndefMode(self):
assert decoder.decode(
ints2octs((4, 3, 102, 111, 120)), asn1Spec=self.s
) == (univ.Any('\004\003fox'), null)
def testTaggedExIndefMode(self):
s = univ.Any('\004\003fox').subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 4))
assert decoder.decode(ints2octs((164, 128, 4, 3, 102, 111, 120, 0, 0)), asn1Spec=s) == (s, null)
def testTaggedImIndefMode(self):
s = univ.Any('\004\003fox').subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 4))
assert decoder.decode(ints2octs((164, 128, 4, 3, 102, 111, 120, 0, 0)), asn1Spec=s) == (s, null)
def testByUntaggedSubst(self):
assert decoder.decode(
ints2octs((4, 3, 102, 111, 120)),
asn1Spec=self.s,
substrateFun=lambda a,b,c: (b,c)
) == (ints2octs((4, 3, 102, 111, 120)), 5)
def testTaggedExSubst(self):
assert decoder.decode(
ints2octs((164, 5, 4, 3, 102, 111, 120)),
asn1Spec=self.s,
substrateFun=lambda a,b,c: (b,c)
) == (ints2octs((164, 5, 4, 3, 102, 111, 120)), 7)
if __name__ == '__main__': unittest.main()

View File

@@ -0,0 +1,338 @@
from pyasn1.type import tag, namedtype, univ
from pyasn1.codec.ber import encoder
from pyasn1.compat.octets import ints2octs
from pyasn1.error import PyAsn1Error
from sys import version_info
if version_info[0:2] < (2, 7) or \
version_info[0:2] in ( (3, 0), (3, 1) ):
try:
import unittest2 as unittest
except ImportError:
import unittest
else:
import unittest
class LargeTagEncoderTestCase(unittest.TestCase):
def setUp(self):
self.o = univ.Integer().subtype(
value=1, explicitTag=tag.Tag(tag.tagClassApplication, tag.tagFormatSimple, 0xdeadbeaf)
)
def testEncoder(self):
assert encoder.encode(self.o) == ints2octs((127, 141, 245, 182, 253, 47, 3, 2, 1, 1))
class IntegerEncoderTestCase(unittest.TestCase):
def testPosInt(self):
assert encoder.encode(univ.Integer(12)) == ints2octs((2, 1, 12))
def testNegInt(self):
assert encoder.encode(univ.Integer(-12)) == ints2octs((2, 1, 244))
def testZero(self):
assert encoder.encode(univ.Integer(0)) == ints2octs((2, 1, 0))
def testCompactZero(self):
encoder.IntegerEncoder.supportCompactZero = True
substrate = encoder.encode(univ.Integer(0))
encoder.IntegerEncoder.supportCompactZero = False
assert substrate == ints2octs((2, 0))
def testMinusOne(self):
assert encoder.encode(univ.Integer(-1)) == ints2octs((2, 1, 255))
def testPosLong(self):
assert encoder.encode(
univ.Integer(0xffffffffffffffff)
) == ints2octs((2, 9, 0, 255, 255, 255, 255, 255, 255, 255, 255))
def testNegLong(self):
assert encoder.encode(
univ.Integer(-0xffffffffffffffff)
) == ints2octs((2, 9, 255, 0, 0, 0, 0, 0, 0, 0, 1))
class BooleanEncoderTestCase(unittest.TestCase):
def testTrue(self):
assert encoder.encode(univ.Boolean(1)) == ints2octs((1, 1, 1))
def testFalse(self):
assert encoder.encode(univ.Boolean(0)) == ints2octs((1, 1, 0))
class BitStringEncoderTestCase(unittest.TestCase):
def setUp(self):
self.b = univ.BitString((1,0,1,0,1,0,0,1,1,0,0,0,1,0,1))
def testDefMode(self):
assert encoder.encode(self.b) == ints2octs((3, 3, 1, 169, 138))
def testIndefMode(self):
assert encoder.encode(
self.b, defMode=0
) == ints2octs((3, 3, 1, 169, 138))
def testDefModeChunked(self):
assert encoder.encode(
self.b, maxChunkSize=1
) == ints2octs((35, 8, 3, 2, 0, 169, 3, 2, 1, 138))
def testIndefModeChunked(self):
assert encoder.encode(
self.b, defMode=0, maxChunkSize=1
) == ints2octs((35, 128, 3, 2, 0, 169, 3, 2, 1, 138, 0, 0))
def testEmptyValue(self):
assert encoder.encode(univ.BitString(())) == ints2octs((3, 1, 0))
class OctetStringEncoderTestCase(unittest.TestCase):
def setUp(self):
self.o = univ.OctetString('Quick brown fox')
def testDefMode(self):
assert encoder.encode(self.o) == ints2octs((4, 15, 81, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 32, 102, 111, 120))
def testIndefMode(self):
assert encoder.encode(
self.o, defMode=0
) == ints2octs((4, 15, 81, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 32, 102, 111, 120))
def testDefModeChunked(self):
assert encoder.encode(
self.o, maxChunkSize=4
) == ints2octs((36, 23, 4, 4, 81, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 4, 111, 119, 110, 32, 4, 3, 102, 111, 120))
def testIndefModeChunked(self):
assert encoder.encode(
self.o, defMode=0, maxChunkSize=4
) == ints2octs((36, 128, 4, 4, 81, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 4, 111, 119, 110, 32, 4, 3, 102, 111, 120, 0, 0))
class ExpTaggedOctetStringEncoderTestCase(unittest.TestCase):
def setUp(self):
self.o = univ.OctetString().subtype(
value='Quick brown fox',
explicitTag=tag.Tag(tag.tagClassApplication,tag.tagFormatSimple,5)
)
def testDefMode(self):
assert encoder.encode(self.o) == ints2octs((101, 17, 4, 15, 81, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 32, 102, 111, 120))
def testIndefMode(self):
assert encoder.encode(
self.o, defMode=0
) == ints2octs((101, 128, 4, 15, 81, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 32, 102, 111, 120, 0, 0))
def testDefModeChunked(self):
assert encoder.encode(
self.o, defMode=1, maxChunkSize=4
) == ints2octs((101, 25, 36, 23, 4, 4, 81, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 4, 111, 119, 110, 32, 4, 3, 102, 111, 120))
def testIndefModeChunked(self):
assert encoder.encode(
self.o, defMode=0, maxChunkSize=4
) == ints2octs((101, 128, 36, 128, 4, 4, 81, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 4, 111, 119, 110, 32, 4, 3, 102, 111, 120, 0, 0, 0, 0))
class NullEncoderTestCase(unittest.TestCase):
def testNull(self):
assert encoder.encode(univ.Null('')) == ints2octs((5, 0))
class ObjectIdentifierEncoderTestCase(unittest.TestCase):
def testNull(self):
assert encoder.encode(
univ.ObjectIdentifier((1,3,6,0,0xffffe))
) == ints2octs((6, 6, 43, 6, 0, 191, 255, 126))
class RealEncoderTestCase(unittest.TestCase):
def testChar(self):
assert encoder.encode(
univ.Real((123, 10, 11))
) == ints2octs((9, 7, 3, 49, 50, 51, 69, 49, 49))
def testBin1(self):
assert encoder.encode(
univ.Real((1101, 2, 11))
) == ints2octs((9, 4, 128, 11, 4, 77))
def testBin2(self):
assert encoder.encode(
univ.Real((1101, 2, -11))
) == ints2octs((9, 4, 128, 245, 4, 77))
def testPlusInf(self):
assert encoder.encode(univ.Real('inf')) == ints2octs((9, 1, 64))
def testMinusInf(self):
assert encoder.encode(univ.Real('-inf')) == ints2octs((9, 1, 65))
def testZero(self):
assert encoder.encode(univ.Real(0)) == ints2octs((9, 0))
class SequenceEncoderTestCase(unittest.TestCase):
def setUp(self):
self.s = univ.Sequence(componentType=namedtype.NamedTypes(
namedtype.NamedType('place-holder', univ.Null('')),
namedtype.OptionalNamedType('first-name', univ.OctetString('')),
namedtype.DefaultedNamedType('age', univ.Integer(33)),
))
def __init(self):
self.s.clear()
self.s.setComponentByPosition(0)
def __initWithOptional(self):
self.s.clear()
self.s.setComponentByPosition(0)
self.s.setComponentByPosition(1, 'quick brown')
def __initWithDefaulted(self):
self.s.clear()
self.s.setComponentByPosition(0)
self.s.setComponentByPosition(2, 1)
def __initWithOptionalAndDefaulted(self):
self.s.clear()
self.s.setComponentByPosition(0, univ.Null(''))
self.s.setComponentByPosition(1, univ.OctetString('quick brown'))
self.s.setComponentByPosition(2, univ.Integer(1))
def testDefMode(self):
self.__init()
assert encoder.encode(self.s) == ints2octs((48, 2, 5, 0))
def testIndefMode(self):
self.__init()
assert encoder.encode(
self.s, defMode=0
) == ints2octs((48, 128, 5, 0, 0, 0))
def testDefModeChunked(self):
self.__init()
assert encoder.encode(
self.s, defMode=1, maxChunkSize=4
) == ints2octs((48, 2, 5, 0))
def testIndefModeChunked(self):
self.__init()
assert encoder.encode(
self.s, defMode=0, maxChunkSize=4
) == ints2octs((48, 128, 5, 0, 0, 0))
def testWithOptionalDefMode(self):
self.__initWithOptional()
assert encoder.encode(self.s) == ints2octs((48, 15, 5, 0, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110))
def testWithOptionalIndefMode(self):
self.__initWithOptional()
assert encoder.encode(
self.s, defMode=0
) == ints2octs((48, 128, 5, 0, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 0, 0))
def testWithOptionalDefModeChunked(self):
self.__initWithOptional()
assert encoder.encode(
self.s, defMode=1, maxChunkSize=4
) == ints2octs((48, 21, 5, 0, 36, 17, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110))
def testWithOptionalIndefModeChunked(self):
self.__initWithOptional()
assert encoder.encode(
self.s, defMode=0, maxChunkSize=4
) == ints2octs((48, 128, 5, 0, 36, 128, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110, 0, 0, 0, 0))
def testWithDefaultedDefMode(self):
self.__initWithDefaulted()
assert encoder.encode(self.s) == ints2octs((48, 5, 5, 0, 2, 1, 1))
def testWithDefaultedIndefMode(self):
self.__initWithDefaulted()
assert encoder.encode(
self.s, defMode=0
) == ints2octs((48, 128, 5, 0, 2, 1, 1, 0, 0))
def testWithDefaultedDefModeChunked(self):
self.__initWithDefaulted()
assert encoder.encode(
self.s, defMode=1, maxChunkSize=4
) == ints2octs((48, 5, 5, 0, 2, 1, 1))
def testWithDefaultedIndefModeChunked(self):
self.__initWithDefaulted()
assert encoder.encode(
self.s, defMode=0, maxChunkSize=4
) == ints2octs((48, 128, 5, 0, 2, 1, 1, 0, 0))
def testWithOptionalAndDefaultedDefMode(self):
self.__initWithOptionalAndDefaulted()
assert encoder.encode(self.s) == ints2octs((48, 18, 5, 0, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 2, 1, 1))
def testWithOptionalAndDefaultedIndefMode(self):
self.__initWithOptionalAndDefaulted()
assert encoder.encode(
self.s, defMode=0
) == ints2octs((48, 128, 5, 0, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 2, 1, 1, 0, 0))
def testWithOptionalAndDefaultedDefModeChunked(self):
self.__initWithOptionalAndDefaulted()
assert encoder.encode(
self.s, defMode=1, maxChunkSize=4
) == ints2octs((48, 24, 5, 0, 36, 17, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110, 2, 1, 1))
def testWithOptionalAndDefaultedIndefModeChunked(self):
self.__initWithOptionalAndDefaulted()
assert encoder.encode(
self.s, defMode=0, maxChunkSize=4
) == ints2octs((48, 128, 5, 0, 36, 128, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110, 0, 0, 2, 1, 1, 0, 0))
class ChoiceEncoderTestCase(unittest.TestCase):
def setUp(self):
self.s = univ.Choice(componentType=namedtype.NamedTypes(
namedtype.NamedType('place-holder', univ.Null('')),
namedtype.NamedType('number', univ.Integer(0)),
namedtype.NamedType('string', univ.OctetString())
))
def testEmpty(self):
try:
encoder.encode(self.s)
except PyAsn1Error:
pass
else:
assert 0, 'encoded unset choice'
def testFilled(self):
self.s.setComponentByPosition(0, univ.Null(''))
assert encoder.encode(self.s) == ints2octs((5, 0))
def testTagged(self):
s = self.s.subtype(
explicitTag=tag.Tag(tag.tagClassContext,tag.tagFormatConstructed,4)
)
s.setComponentByPosition(0, univ.Null(''))
assert encoder.encode(s) == ints2octs((164, 2, 5, 0))
def testUndefLength(self):
self.s.setComponentByPosition(2, univ.OctetString('abcdefgh'))
assert encoder.encode(self.s, defMode=False, maxChunkSize=3) == ints2octs((36, 128, 4, 3, 97, 98, 99, 4, 3, 100, 101, 102, 4, 2, 103, 104, 0, 0))
def testTaggedUndefLength(self):
s = self.s.subtype(
explicitTag=tag.Tag(tag.tagClassContext,tag.tagFormatConstructed,4)
)
s.setComponentByPosition(2, univ.OctetString('abcdefgh'))
assert encoder.encode(s, defMode=False, maxChunkSize=3) == ints2octs((164, 128, 36, 128, 4, 3, 97, 98, 99, 4, 3, 100, 101, 102, 4, 2, 103, 104, 0, 0, 0, 0))
class AnyEncoderTestCase(unittest.TestCase):
def setUp(self):
self.s = univ.Any(encoder.encode(univ.OctetString('fox')))
def testUntagged(self):
assert encoder.encode(self.s) == ints2octs((4, 3, 102, 111, 120))
def testTaggedEx(self):
s = self.s.subtype(
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 4)
)
assert encoder.encode(s) == ints2octs((164, 5, 4, 3, 102, 111, 120))
def testTaggedIm(self):
s = self.s.subtype(
implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 4)
)
assert encoder.encode(s) == ints2octs((132, 5, 4, 3, 102, 111, 120))
if __name__ == '__main__': unittest.main()

View File

@@ -0,0 +1 @@
# This file is necessary to make this directory a package.

View File

@@ -0,0 +1,22 @@
from sys import path, version_info
from os.path import sep
path.insert(1, path[0]+sep+'cer')
import test_encoder, test_decoder
from pyasn1.error import PyAsn1Error
if version_info[0:2] < (2, 7) or \
version_info[0:2] in ( (3, 0), (3, 1) ):
try:
import unittest2 as unittest
except ImportError:
import unittest
else:
import unittest
suite = unittest.TestSuite()
loader = unittest.TestLoader()
for m in (test_encoder, test_decoder):
suite.addTest(loader.loadTestsFromModule(m))
def runTests(): unittest.TextTestRunner(verbosity=2).run(suite)
if __name__ == '__main__': runTests()

View File

@@ -0,0 +1,31 @@
from pyasn1.type import univ
from pyasn1.codec.cer import decoder
from pyasn1.compat.octets import ints2octs, str2octs, null
from pyasn1.error import PyAsn1Error
from sys import version_info
if version_info[0:2] < (2, 7) or \
version_info[0:2] in ( (3, 0), (3, 1) ):
try:
import unittest2 as unittest
except ImportError:
import unittest
else:
import unittest
class BooleanDecoderTestCase(unittest.TestCase):
def testTrue(self):
assert decoder.decode(ints2octs((1, 1, 255))) == (1, null)
def testFalse(self):
assert decoder.decode(ints2octs((1, 1, 0))) == (0, null)
class OctetStringDecoderTestCase(unittest.TestCase):
def testShortMode(self):
assert decoder.decode(
ints2octs((4, 15, 81, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 32, 102, 111, 120)),
) == (str2octs('Quick brown fox'), null)
def testLongMode(self):
assert decoder.decode(
ints2octs((36, 128, 4, 130, 3, 232) + (81,)*1000 + (4, 1, 81, 0, 0))
) == (str2octs('Q'*1001), null)
if __name__ == '__main__': unittest.main()

View File

@@ -0,0 +1,107 @@
from pyasn1.type import namedtype, univ
from pyasn1.codec.cer import encoder
from pyasn1.compat.octets import ints2octs
from pyasn1.error import PyAsn1Error
from sys import version_info
if version_info[0:2] < (2, 7) or \
version_info[0:2] in ( (3, 0), (3, 1) ):
try:
import unittest2 as unittest
except ImportError:
import unittest
else:
import unittest
class BooleanEncoderTestCase(unittest.TestCase):
def testTrue(self):
assert encoder.encode(univ.Boolean(1)) == ints2octs((1, 1, 255))
def testFalse(self):
assert encoder.encode(univ.Boolean(0)) == ints2octs((1, 1, 0))
class BitStringEncoderTestCase(unittest.TestCase):
def testShortMode(self):
assert encoder.encode(
univ.BitString((1,0)*501)
) == ints2octs((3, 127, 6) + (170,) * 125 + (128,))
def testLongMode(self):
assert encoder.encode(
univ.BitString((1,0)*501)
) == ints2octs((3, 127, 6) + (170,) * 125 + (128,))
class OctetStringEncoderTestCase(unittest.TestCase):
def testShortMode(self):
assert encoder.encode(
univ.OctetString('Quick brown fox')
) == ints2octs((4, 15, 81, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 32, 102, 111, 120))
def testLongMode(self):
assert encoder.encode(
univ.OctetString('Q'*1001)
) == ints2octs((36, 128, 4, 130, 3, 232) + (81,)*1000 + (4, 1, 81, 0, 0))
class SetEncoderTestCase(unittest.TestCase):
def setUp(self):
self.s = univ.Set(componentType=namedtype.NamedTypes(
namedtype.NamedType('place-holder', univ.Null('')),
namedtype.OptionalNamedType('first-name', univ.OctetString('')),
namedtype.DefaultedNamedType('age', univ.Integer(33))
))
def __init(self):
self.s.clear()
self.s.setComponentByPosition(0)
def __initWithOptional(self):
self.s.clear()
self.s.setComponentByPosition(0)
self.s.setComponentByPosition(1, 'quick brown')
def __initWithDefaulted(self):
self.s.clear()
self.s.setComponentByPosition(0)
self.s.setComponentByPosition(2, 1)
def __initWithOptionalAndDefaulted(self):
self.s.clear()
self.s.setComponentByPosition(0, univ.Null(''))
self.s.setComponentByPosition(1, univ.OctetString('quick brown'))
self.s.setComponentByPosition(2, univ.Integer(1))
def testIndefMode(self):
self.__init()
assert encoder.encode(self.s) == ints2octs((49, 128, 5, 0, 0, 0))
def testWithOptionalIndefMode(self):
self.__initWithOptional()
assert encoder.encode(
self.s
) == ints2octs((49, 128, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 5, 0, 0, 0))
def testWithDefaultedIndefMode(self):
self.__initWithDefaulted()
assert encoder.encode(
self.s
) == ints2octs((49, 128, 2, 1, 1, 5, 0, 0, 0))
def testWithOptionalAndDefaultedIndefMode(self):
self.__initWithOptionalAndDefaulted()
assert encoder.encode(
self.s
) == ints2octs((49, 128, 2, 1, 1, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 5, 0, 0, 0))
class SetWithChoiceEncoderTestCase(unittest.TestCase):
def setUp(self):
c = univ.Choice(componentType=namedtype.NamedTypes(
namedtype.NamedType('actual', univ.Boolean(0))
))
self.s = univ.Set(componentType=namedtype.NamedTypes(
namedtype.NamedType('place-holder', univ.Null('')),
namedtype.NamedType('status', c)
))
def testIndefMode(self):
self.s.setComponentByPosition(0)
self.s.setComponentByName('status')
self.s.getComponentByName('status').setComponentByPosition(0, 1)
assert encoder.encode(self.s) == ints2octs((49, 128, 1, 1, 255, 5, 0, 0, 0))
if __name__ == '__main__': unittest.main()

View File

@@ -0,0 +1 @@
# This file is necessary to make this directory a package.

View File

@@ -0,0 +1,22 @@
from sys import path, version_info
from os.path import sep
path.insert(1, path[0]+sep+'der')
import test_encoder, test_decoder
from pyasn1.error import PyAsn1Error
if version_info[0:2] < (2, 7) or \
version_info[0:2] in ( (3, 0), (3, 1) ):
try:
import unittest2 as unittest
except ImportError:
import unittest
else:
import unittest
suite = unittest.TestSuite()
loader = unittest.TestLoader()
for m in (test_encoder, test_decoder):
suite.addTest(loader.loadTestsFromModule(m))
def runTests(): unittest.TextTestRunner(verbosity=2).run(suite)
if __name__ == '__main__': runTests()

View File

@@ -0,0 +1,20 @@
from pyasn1.type import univ
from pyasn1.codec.der import decoder
from pyasn1.error import PyAsn1Error
from sys import version_info
if version_info[0:2] < (2, 7) or \
version_info[0:2] in ( (3, 0), (3, 1) ):
try:
import unittest2 as unittest
except ImportError:
import unittest
else:
import unittest
class OctetStringDecoderTestCase(unittest.TestCase):
def testShortMode(self):
assert decoder.decode(
'\004\017Quick brown fox'.encode()
) == ('Quick brown fox'.encode(), ''.encode())
if __name__ == '__main__': unittest.main()

View File

@@ -0,0 +1,44 @@
from pyasn1.type import namedtype, univ
from pyasn1.codec.der import encoder
from pyasn1.compat.octets import ints2octs
from pyasn1.error import PyAsn1Error
from sys import version_info
if version_info[0:2] < (2, 7) or \
version_info[0:2] in ( (3, 0), (3, 1) ):
try:
import unittest2 as unittest
except ImportError:
import unittest
else:
import unittest
class OctetStringEncoderTestCase(unittest.TestCase):
def testShortMode(self):
assert encoder.encode(
univ.OctetString('Quick brown fox')
) == ints2octs((4, 15, 81, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 32, 102, 111, 120))
class BitStringEncoderTestCase(unittest.TestCase):
def testShortMode(self):
assert encoder.encode(
univ.BitString((1,))
) == ints2octs((3, 2, 7, 128))
class SetWithChoiceEncoderTestCase(unittest.TestCase):
def setUp(self):
c = univ.Choice(componentType=namedtype.NamedTypes(
namedtype.NamedType('name', univ.OctetString('')),
namedtype.NamedType('amount', univ.Integer(0))
))
self.s = univ.Set(componentType=namedtype.NamedTypes(
namedtype.NamedType('place-holder', univ.Null('')),
namedtype.NamedType('status', c)
))
def testDefMode(self):
self.s.setComponentByPosition(0)
self.s.setComponentByName('status')
self.s.getComponentByName('status').setComponentByPosition(0, 'ann')
assert encoder.encode(self.s) == ints2octs((49, 7, 4, 3, 97, 110, 110, 5, 0))
if __name__ == '__main__': unittest.main()

View File

@@ -0,0 +1,29 @@
from sys import path, version_info
from os.path import sep
path.insert(1, path[0]+sep+'codec'+sep+'ber')
import ber.suite
path.insert(1, path[0]+sep+'codec'+sep+'cer')
import cer.suite
path.insert(1, path[0]+sep+'codec'+sep+'der')
import der.suite
from pyasn1.error import PyAsn1Error
if version_info[0:2] < (2, 7) or \
version_info[0:2] in ( (3, 0), (3, 1) ):
try:
import unittest2 as unittest
except ImportError:
import unittest
else:
import unittest
suite = unittest.TestSuite()
for m in (
ber.suite,
cer.suite,
der.suite
):
suite.addTest(getattr(m, 'suite'))
def runTests(): unittest.TextTestRunner(verbosity=2).run(suite)
if __name__ == '__main__': runTests()

View File

@@ -0,0 +1,26 @@
from sys import path, version_info
from os.path import sep
path.insert(1, path[0]+sep+'type')
import type.suite
path.insert(1, path[0]+sep+'codec')
import codec.suite
from pyasn1.error import PyAsn1Error
if version_info[0:2] < (2, 7) or \
version_info[0:2] in ( (3, 0), (3, 1) ):
try:
import unittest2 as unittest
except ImportError:
import unittest
else:
import unittest
suite = unittest.TestSuite()
for m in (
type.suite,
codec.suite
):
suite.addTest(getattr(m, 'suite'))
def runTests(): unittest.TextTestRunner(verbosity=2).run(suite)
if __name__ == '__main__': runTests()

View File

@@ -0,0 +1 @@
# This file is necessary to make this directory a package.

View File

@@ -0,0 +1,20 @@
import test_tag, test_constraint, test_namedtype, test_univ
from pyasn1.error import PyAsn1Error
from sys import version_info
if version_info[0:2] < (2, 7) or \
version_info[0:2] in ( (3, 0), (3, 1) ):
try:
import unittest2 as unittest
except ImportError:
import unittest
else:
import unittest
suite = unittest.TestSuite()
loader = unittest.TestLoader()
for m in (test_tag, test_constraint, test_namedtype, test_univ):
suite.addTest(loader.loadTestsFromModule(m))
def runTests(): unittest.TextTestRunner(verbosity=2).run(suite)
if __name__ == '__main__': runTests()

View File

@@ -0,0 +1,280 @@
from pyasn1.type import constraint, error
from pyasn1.error import PyAsn1Error
from sys import version_info
if version_info[0:2] < (2, 7) or \
version_info[0:2] in ( (3, 0), (3, 1) ):
try:
import unittest2 as unittest
except ImportError:
import unittest
else:
import unittest
class SingleValueConstraintTestCase(unittest.TestCase):
def setUp(self):
self.c1 = constraint.SingleValueConstraint(1,2)
self.c2 = constraint.SingleValueConstraint(3,4)
def testCmp(self): assert self.c1 == self.c1, 'comparation fails'
def testHash(self): assert hash(self.c1) != hash(self.c2), 'hash() fails'
def testGoodVal(self):
try:
self.c1(1)
except error.ValueConstraintError:
assert 0, 'constraint check fails'
def testBadVal(self):
try:
self.c1(4)
except error.ValueConstraintError:
pass
else:
assert 0, 'constraint check fails'
class ContainedSubtypeConstraintTestCase(unittest.TestCase):
def setUp(self):
self.c1 = constraint.ContainedSubtypeConstraint(
constraint.SingleValueConstraint(12)
)
def testGoodVal(self):
try:
self.c1(12)
except error.ValueConstraintError:
assert 0, 'constraint check fails'
def testBadVal(self):
try:
self.c1(4)
except error.ValueConstraintError:
pass
else:
assert 0, 'constraint check fails'
class ValueRangeConstraintTestCase(unittest.TestCase):
def setUp(self):
self.c1 = constraint.ValueRangeConstraint(1,4)
def testGoodVal(self):
try:
self.c1(1)
except error.ValueConstraintError:
assert 0, 'constraint check fails'
def testBadVal(self):
try:
self.c1(-5)
except error.ValueConstraintError:
pass
else:
assert 0, 'constraint check fails'
class ValueSizeConstraintTestCase(unittest.TestCase):
def setUp(self):
self.c1 = constraint.ValueSizeConstraint(1,2)
def testGoodVal(self):
try:
self.c1('a')
except error.ValueConstraintError:
assert 0, 'constraint check fails'
def testBadVal(self):
try:
self.c1('abc')
except error.ValueConstraintError:
pass
else:
assert 0, 'constraint check fails'
class PermittedAlphabetConstraintTestCase(SingleValueConstraintTestCase):
def setUp(self):
self.c1 = constraint.PermittedAlphabetConstraint('A', 'B', 'C')
self.c2 = constraint.PermittedAlphabetConstraint('DEF')
def testGoodVal(self):
try:
self.c1('A')
except error.ValueConstraintError:
assert 0, 'constraint check fails'
def testBadVal(self):
try:
self.c1('E')
except error.ValueConstraintError:
pass
else:
assert 0, 'constraint check fails'
class ConstraintsIntersectionTestCase(unittest.TestCase):
def setUp(self):
self.c1 = constraint.ConstraintsIntersection(
constraint.SingleValueConstraint(4),
constraint.ValueRangeConstraint(2, 4)
)
def testCmp1(self):
assert constraint.SingleValueConstraint(4) in self.c1, '__cmp__() fails'
def testCmp2(self):
assert constraint.SingleValueConstraint(5) not in self.c1, \
'__cmp__() fails'
def testCmp3(self):
c = constraint.ConstraintsUnion(constraint.ConstraintsIntersection(
constraint.SingleValueConstraint(4),
constraint.ValueRangeConstraint(2, 4)
))
assert self.c1 in c, '__cmp__() fails'
def testCmp4(self):
c = constraint.ConstraintsUnion(
constraint.ConstraintsIntersection(constraint.SingleValueConstraint(5))
)
assert self.c1 not in c, '__cmp__() fails'
def testGoodVal(self):
try:
self.c1(4)
except error.ValueConstraintError:
assert 0, 'constraint check fails'
def testBadVal(self):
try:
self.c1(-5)
except error.ValueConstraintError:
pass
else:
assert 0, 'constraint check fails'
class InnerTypeConstraintTestCase(unittest.TestCase):
def testConst1(self):
c = constraint.InnerTypeConstraint(
constraint.SingleValueConstraint(4)
)
try:
c(4, 32)
except error.ValueConstraintError:
assert 0, 'constraint check fails'
try:
c(5, 32)
except error.ValueConstraintError:
pass
else:
assert 0, 'constraint check fails'
def testConst2(self):
c = constraint.InnerTypeConstraint(
(0, constraint.SingleValueConstraint(4), 'PRESENT'),
(1, constraint.SingleValueConstraint(4), 'ABSENT')
)
try:
c(4, 0)
except error.ValueConstraintError:
raise
assert 0, 'constraint check fails'
try:
c(4, 1)
except error.ValueConstraintError:
pass
else:
assert 0, 'constraint check fails'
try:
c(3, 0)
except error.ValueConstraintError:
pass
else:
assert 0, 'constraint check fails'
# Constraints compositions
class ConstraintsIntersectionTestCase(unittest.TestCase):
def setUp(self):
self.c1 = constraint.ConstraintsIntersection(
constraint.ValueRangeConstraint(1, 9),
constraint.ValueRangeConstraint(2, 5)
)
def testGoodVal(self):
try:
self.c1(3)
except error.ValueConstraintError:
assert 0, 'constraint check fails'
def testBadVal(self):
try:
self.c1(0)
except error.ValueConstraintError:
pass
else:
assert 0, 'constraint check fails'
class ConstraintsUnionTestCase(unittest.TestCase):
def setUp(self):
self.c1 = constraint.ConstraintsUnion(
constraint.SingleValueConstraint(5),
constraint.ValueRangeConstraint(1, 3)
)
def testGoodVal(self):
try:
self.c1(2)
self.c1(5)
except error.ValueConstraintError:
assert 0, 'constraint check fails'
def testBadVal(self):
try:
self.c1(-5)
except error.ValueConstraintError:
pass
else:
assert 0, 'constraint check fails'
class ConstraintsExclusionTestCase(unittest.TestCase):
def setUp(self):
self.c1 = constraint.ConstraintsExclusion(
constraint.ValueRangeConstraint(2, 4)
)
def testGoodVal(self):
try:
self.c1(6)
except error.ValueConstraintError:
assert 0, 'constraint check fails'
def testBadVal(self):
try:
self.c1(2)
except error.ValueConstraintError:
pass
else:
assert 0, 'constraint check fails'
# Constraints derivations
class DirectDerivationTestCase(unittest.TestCase):
def setUp(self):
self.c1 = constraint.SingleValueConstraint(5)
self.c2 = constraint.ConstraintsUnion(
self.c1, constraint.ValueRangeConstraint(1, 3)
)
def testGoodVal(self):
assert self.c1.isSuperTypeOf(self.c2), 'isSuperTypeOf failed'
assert not self.c1.isSubTypeOf(self.c2) , 'isSubTypeOf failed'
def testBadVal(self):
assert not self.c2.isSuperTypeOf(self.c1) , 'isSuperTypeOf failed'
assert self.c2.isSubTypeOf(self.c1) , 'isSubTypeOf failed'
class IndirectDerivationTestCase(unittest.TestCase):
def setUp(self):
self.c1 = constraint.ConstraintsIntersection(
constraint.ValueRangeConstraint(1, 30)
)
self.c2 = constraint.ConstraintsIntersection(
self.c1, constraint.ValueRangeConstraint(1, 20)
)
self.c2 = constraint.ConstraintsIntersection(
self.c2, constraint.ValueRangeConstraint(1, 10)
)
def testGoodVal(self):
assert self.c1.isSuperTypeOf(self.c2), 'isSuperTypeOf failed'
assert not self.c1.isSubTypeOf(self.c2) , 'isSubTypeOf failed'
def testBadVal(self):
assert not self.c2.isSuperTypeOf(self.c1) , 'isSuperTypeOf failed'
assert self.c2.isSubTypeOf(self.c1) , 'isSubTypeOf failed'
if __name__ == '__main__': unittest.main()
# how to apply size constriants to constructed types?

View File

@@ -0,0 +1,87 @@
from pyasn1.type import namedtype, univ
from pyasn1.error import PyAsn1Error
from sys import version_info
if version_info[0:2] < (2, 7) or \
version_info[0:2] in ( (3, 0), (3, 1) ):
try:
import unittest2 as unittest
except ImportError:
import unittest
else:
import unittest
class NamedTypeCaseBase(unittest.TestCase):
def setUp(self):
self.e = namedtype.NamedType('age', univ.Integer())
def testIter(self):
n, t = self.e
assert n == 'age' or t == univ.Integer(), 'unpack fails'
class NamedTypesCaseBase(unittest.TestCase):
def setUp(self):
self.e = namedtype.NamedTypes(
namedtype.NamedType('first-name', univ.OctetString('')),
namedtype.OptionalNamedType('age', univ.Integer(0)),
namedtype.NamedType('family-name', univ.OctetString(''))
)
def testIter(self):
for t in self.e:
break
else:
assert 0, '__getitem__() fails'
def testGetTypeByPosition(self):
assert self.e.getTypeByPosition(0) == univ.OctetString(''), \
'getTypeByPosition() fails'
def testGetNameByPosition(self):
assert self.e.getNameByPosition(0) == 'first-name', \
'getNameByPosition() fails'
def testGetPositionByName(self):
assert self.e.getPositionByName('first-name') == 0, \
'getPositionByName() fails'
def testGetTypesNearPosition(self):
assert self.e.getTagMapNearPosition(0).getPosMap() == {
univ.OctetString.tagSet: univ.OctetString('')
}
assert self.e.getTagMapNearPosition(1).getPosMap() == {
univ.Integer.tagSet: univ.Integer(0),
univ.OctetString.tagSet: univ.OctetString('')
}
assert self.e.getTagMapNearPosition(2).getPosMap() == {
univ.OctetString.tagSet: univ.OctetString('')
}
def testGetTagMap(self):
assert self.e.getTagMap().getPosMap() == {
univ.OctetString.tagSet: univ.OctetString(''),
univ.Integer.tagSet: univ.Integer(0)
}
def testGetTagMapWithDups(self):
try:
self.e.getTagMap(1)
except PyAsn1Error:
pass
else:
assert 0, 'Duped types not noticed'
def testGetPositionNearType(self):
assert self.e.getPositionNearType(univ.OctetString.tagSet, 0) == 0
assert self.e.getPositionNearType(univ.Integer.tagSet, 1) == 1
assert self.e.getPositionNearType(univ.OctetString.tagSet, 2) == 2
class OrderedNamedTypesCaseBase(unittest.TestCase):
def setUp(self):
self.e = namedtype.NamedTypes(
namedtype.NamedType('first-name', univ.OctetString('')),
namedtype.NamedType('age', univ.Integer(0))
)
def testGetTypeByPosition(self):
assert self.e.getTypeByPosition(0) == univ.OctetString(''), \
'getTypeByPosition() fails'
if __name__ == '__main__': unittest.main()

View File

@@ -0,0 +1,107 @@
from pyasn1.type import tag
from pyasn1.error import PyAsn1Error
from sys import version_info
if version_info[0:2] < (2, 7) or \
version_info[0:2] in ( (3, 0), (3, 1) ):
try:
import unittest2 as unittest
except ImportError:
import unittest
else:
import unittest
class TagTestCaseBase(unittest.TestCase):
def setUp(self):
self.t1 = tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 3)
self.t2 = tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 3)
class TagCmpTestCase(TagTestCaseBase):
def testCmp(self):
assert self.t1 == self.t2, 'tag comparation fails'
def testHash(self):
assert hash(self.t1) == hash(self.t2), 'tag hash comparation fails'
def testSequence(self):
assert self.t1[0] == self.t2[0] and \
self.t1[1] == self.t2[1] and \
self.t1[2] == self.t2[2], 'tag sequence protocol fails'
class TagSetTestCaseBase(unittest.TestCase):
def setUp(self):
self.ts1 = tag.initTagSet(
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 12)
)
self.ts2 = tag.initTagSet(
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 12)
)
class TagSetCmpTestCase(TagSetTestCaseBase):
def testCmp(self):
assert self.ts1 == self.ts2, 'tag set comparation fails'
def testHash(self):
assert hash(self.ts1) == hash(self.ts2), 'tag set hash comp. fails'
def testLen(self):
assert len(self.ts1) == len(self.ts2), 'tag length comparation fails'
class TaggingTestSuite(TagSetTestCaseBase):
def testImplicitTag(self):
t = self.ts1.tagImplicitly(
tag.Tag(tag.tagClassApplication, tag.tagFormatSimple, 14)
)
assert t == tag.TagSet(
tag.Tag(tag.tagClassApplication, tag.tagFormatSimple, 12),
tag.Tag(tag.tagClassApplication, tag.tagFormatSimple, 14)
), 'implicit tagging went wrong'
def testExplicitTag(self):
t = self.ts1.tagExplicitly(
tag.Tag(tag.tagClassPrivate, tag.tagFormatSimple, 32)
)
assert t == tag.TagSet(
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 12),
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 12),
tag.Tag(tag.tagClassPrivate, tag.tagFormatConstructed, 32)
), 'explicit tagging went wrong'
class TagSetAddTestSuite(TagSetTestCaseBase):
def testAdd(self):
t = self.ts1 + tag.Tag(tag.tagClassApplication, tag.tagFormatSimple, 2)
assert t == tag.TagSet(
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 12),
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 12),
tag.Tag(tag.tagClassApplication, tag.tagFormatSimple, 2)
), 'TagSet.__add__() fails'
def testRadd(self):
t = tag.Tag(tag.tagClassApplication, tag.tagFormatSimple, 2) + self.ts1
assert t == tag.TagSet(
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 12),
tag.Tag(tag.tagClassApplication, tag.tagFormatSimple, 2),
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 12)
), 'TagSet.__radd__() fails'
class SuperTagSetTestCase(TagSetTestCaseBase):
def testSuperTagCheck1(self):
assert self.ts1.isSuperTagSetOf(
tag.TagSet(
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 12),
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 12)
)), 'isSuperTagSetOf() fails'
def testSuperTagCheck2(self):
assert not self.ts1.isSuperTagSetOf(
tag.TagSet(
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 12),
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 13)
)), 'isSuperTagSetOf() fails'
def testSuperTagCheck3(self):
assert self.ts1.isSuperTagSetOf(
tag.TagSet((), tag.Tag(tag.tagClassUniversal,
tag.tagFormatSimple, 12))
), 'isSuperTagSetOf() fails'
if __name__ == '__main__': unittest.main()

View File

@@ -0,0 +1,479 @@
from pyasn1.type import univ, tag, constraint, namedtype, namedval, error
from pyasn1.compat.octets import str2octs, ints2octs
from pyasn1.error import PyAsn1Error
from sys import version_info
if version_info[0:2] < (2, 7) or \
version_info[0:2] in ( (3, 0), (3, 1) ):
try:
import unittest2 as unittest
except ImportError:
import unittest
else:
import unittest
class IntegerTestCase(unittest.TestCase):
def testStr(self): assert str(univ.Integer(1)) in ('1','1L'),'str() fails'
def testAnd(self): assert univ.Integer(1) & 0 == 0, '__and__() fails'
def testOr(self): assert univ.Integer(1) | 0 == 1, '__or__() fails'
def testXor(self): assert univ.Integer(1) ^ 0 == 1, '__xor__() fails'
def testRand(self): assert 0 & univ.Integer(1) == 0, '__rand__() fails'
def testRor(self): assert 0 | univ.Integer(1) == 1, '__ror__() fails'
def testRxor(self): assert 0 ^ univ.Integer(1) == 1, '__rxor__() fails'
def testAdd(self): assert univ.Integer(-4) + 6 == 2, '__add__() fails'
def testRadd(self): assert 4 + univ.Integer(5) == 9, '__radd__() fails'
def testSub(self): assert univ.Integer(3) - 6 == -3, '__sub__() fails'
def testRsub(self): assert 6 - univ.Integer(3) == 3, '__rsub__() fails'
def testMul(self): assert univ.Integer(3) * -3 == -9, '__mul__() fails'
def testRmul(self): assert 2 * univ.Integer(3) == 6, '__rmul__() fails'
def testDiv(self): assert univ.Integer(3) / 2 == 1, '__div__() fails'
def testRdiv(self): assert 6 / univ.Integer(3) == 2, '__rdiv__() fails'
def testMod(self): assert univ.Integer(3) % 2 == 1, '__mod__() fails'
def testRmod(self): assert 4 % univ.Integer(3) == 1, '__rmod__() fails'
def testPow(self): assert univ.Integer(3) ** 2 == 9, '__pow__() fails'
def testRpow(self): assert 2 ** univ.Integer(2) == 4, '__rpow__() fails'
def testLshift(self): assert univ.Integer(1) << 1 == 2, '<< fails'
def testRshift(self): assert univ.Integer(2) >> 1 == 1, '>> fails'
def testInt(self): assert int(univ.Integer(3)) == 3, '__int__() fails'
def testLong(self): assert int(univ.Integer(8)) == 8, '__long__() fails'
def testFloat(self): assert float(univ.Integer(4))==4.0,'__float__() fails'
def testPrettyIn(self): assert univ.Integer('3') == 3, 'prettyIn() fails'
def testTag(self):
assert univ.Integer().getTagSet() == tag.TagSet(
(),
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x02)
)
def testNamedVals(self):
i = univ.Integer(
'asn1', namedValues=univ.Integer.namedValues.clone(('asn1', 1))
)
assert i == 1, 'named val fails'
assert str(i) != 'asn1', 'named val __str__() fails'
class BooleanTestCase(unittest.TestCase):
def testTruth(self):
assert univ.Boolean(True) and univ.Boolean(1), 'Truth initializer fails'
def testFalse(self):
assert not univ.Boolean(False) and not univ.Boolean(0), 'False initializer fails'
def testStr(self):
assert str(univ.Boolean(1)) in ('1', '1L'), 'str() fails'
def testTag(self):
assert univ.Boolean().getTagSet() == tag.TagSet(
(),
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x01)
)
def testConstraints(self):
try:
univ.Boolean(2)
except error.ValueConstraintError:
pass
else:
assert 0, 'constraint fail'
def testSubtype(self):
assert univ.Integer().subtype(
value=1,
implicitTag=tag.Tag(tag.tagClassPrivate,tag.tagFormatSimple,2),
subtypeSpec=constraint.SingleValueConstraint(1,3)
) == univ.Integer(
value=1,
tagSet=tag.TagSet(tag.Tag(tag.tagClassPrivate,
tag.tagFormatSimple,2)),
subtypeSpec=constraint.ConstraintsIntersection(constraint.SingleValueConstraint(1,3))
)
class BitStringTestCase(unittest.TestCase):
def setUp(self):
self.b = univ.BitString(
namedValues=namedval.NamedValues(('Active', 0), ('Urgent', 1))
)
def testSet(self):
assert self.b.clone('Active') == (1,)
assert self.b.clone("'1010100110001010'B") == (1,0,1,0,1,0,0,1,1,0,0,0,1,0,1,0)
assert self.b.clone("'A98A'H") == (1,0,1,0,1,0,0,1,1,0,0,0,1,0,1,0)
assert self.b.clone((1,0,1)) == (1,0,1)
def testStr(self):
assert str(self.b.clone('Urgent,Active')) == '(1, 1)'
def testRepr(self):
assert repr(self.b.clone('Urgent,Active')) == 'BitString("\'11\'B")'
def testTag(self):
assert univ.BitString().getTagSet() == tag.TagSet(
(),
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x03)
)
def testLen(self): assert len(self.b.clone("'A98A'H")) == 16
def testIter(self):
assert self.b.clone("'A98A'H")[0] == 1
assert self.b.clone("'A98A'H")[1] == 0
assert self.b.clone("'A98A'H")[2] == 1
class OctetStringTestCase(unittest.TestCase):
def testInit(self):
assert univ.OctetString(str2octs('abcd')) == str2octs('abcd'), '__init__() fails'
def testBinStr(self):
assert univ.OctetString(binValue="1000010111101110101111000000111011") == ints2octs((133, 238, 188, 14, 192)), 'bin init fails'
def testHexStr(self):
assert univ.OctetString(hexValue="FA9823C43E43510DE3422") == ints2octs((250, 152, 35, 196, 62, 67, 81, 13, 227, 66, 32)), 'hex init fails'
def testTuple(self):
assert univ.OctetString((1,2,3,4,5)) == ints2octs((1,2,3,4,5)), 'tuple init failed'
def testStr(self):
assert str(univ.OctetString('q')) == 'q', '__str__() fails'
def testSeq(self):
assert univ.OctetString('q')[0] == str2octs('q')[0],'__getitem__() fails'
def testAsOctets(self):
assert univ.OctetString('abcd').asOctets() == str2octs('abcd'), 'testAsOctets() fails'
def testAsInts(self):
assert univ.OctetString('abcd').asNumbers() == (97, 98, 99, 100), 'testAsNumbers() fails'
def testEmpty(self):
try:
str(univ.OctetString())
except PyAsn1Error:
pass
else:
assert 0, 'empty OctetString() not reported'
def testAdd(self):
assert univ.OctetString('') + 'q' == str2octs('q'), '__add__() fails'
def testRadd(self):
assert 'b' + univ.OctetString('q') == str2octs('bq'), '__radd__() fails'
def testMul(self):
assert univ.OctetString('a') * 2 == str2octs('aa'), '__mul__() fails'
def testRmul(self):
assert 2 * univ.OctetString('b') == str2octs('bb'), '__rmul__() fails'
def testTag(self):
assert univ.OctetString().getTagSet() == tag.TagSet(
(),
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x04)
)
class Null(unittest.TestCase):
def testStr(self): assert str(univ.Null('')) == '', 'str() fails'
def testTag(self):
assert univ.Null().getTagSet() == tag.TagSet(
(),
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x05)
)
def testConstraints(self):
try:
univ.Null(2)
except error.ValueConstraintError:
pass
else:
assert 0, 'constraint fail'
class RealTestCase(unittest.TestCase):
def testStr(self): assert str(univ.Real(1.0)) == '1.0','str() fails'
def testRepr(self): assert repr(univ.Real(-4.1)) == 'Real((-41, 10, -1))','repr() fails'
def testAdd(self): assert univ.Real(-4.1) + 1.4 == -2.7, '__add__() fails'
def testRadd(self): assert 4 + univ.Real(0.5) == 4.5, '__radd__() fails'
def testSub(self): assert univ.Real(3.9) - 1.7 == 2.2, '__sub__() fails'
def testRsub(self): assert 6.1 - univ.Real(0.1) == 6, '__rsub__() fails'
def testMul(self): assert univ.Real(3.0) * -3 == -9, '__mul__() fails'
def testRmul(self): assert 2 * univ.Real(3.0) == 6, '__rmul__() fails'
def testDiv(self): assert univ.Real(3.0) / 2 == 1.5, '__div__() fails'
def testRdiv(self): assert 6 / univ.Real(3.0) == 2, '__rdiv__() fails'
def testMod(self): assert univ.Real(3.0) % 2 == 1, '__mod__() fails'
def testRmod(self): assert 4 % univ.Real(3.0) == 1, '__rmod__() fails'
def testPow(self): assert univ.Real(3.0) ** 2 == 9, '__pow__() fails'
def testRpow(self): assert 2 ** univ.Real(2.0) == 4, '__rpow__() fails'
def testInt(self): assert int(univ.Real(3.0)) == 3, '__int__() fails'
def testLong(self): assert int(univ.Real(8.0)) == 8, '__long__() fails'
def testFloat(self): assert float(univ.Real(4.0))==4.0,'__float__() fails'
def testPrettyIn(self): assert univ.Real((3,10,0)) == 3, 'prettyIn() fails'
# infinite float values
def testStrInf(self):
assert str(univ.Real('inf')) == 'inf','str() fails'
def testReprInf(self):
assert repr(univ.Real('inf')) == 'Real(\'inf\')','repr() fails'
def testAddInf(self):
assert univ.Real('inf') + 1 == float('inf'), '__add__() fails'
def testRaddInf(self):
assert 1 + univ.Real('inf') == float('inf'), '__radd__() fails'
def testIntInf(self):
try:
assert int(univ.Real('inf'))
except OverflowError:
pass
else:
assert 0, '__int__() fails'
def testLongInf(self):
try:
assert int(univ.Real('inf'))
except OverflowError:
pass
else:
assert 0, '__long__() fails'
assert int(univ.Real(8.0)) == 8, '__long__() fails'
def testFloatInf(self):
assert float(univ.Real('-inf')) == float('-inf'),'__float__() fails'
def testPrettyInInf(self):
assert univ.Real(float('inf')) == float('inf'), 'prettyIn() fails'
def testPlusInf(self):
assert univ.Real('inf').isPlusInfinity(), 'isPlusInfinity failed'
def testMinusInf(self):
assert univ.Real('-inf').isMinusInfinity(), 'isMinusInfinity failed'
def testTag(self):
assert univ.Real().getTagSet() == tag.TagSet(
(),
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x09)
)
class ObjectIdentifier(unittest.TestCase):
def testStr(self):
assert str(univ.ObjectIdentifier((1,3,6))) == '1.3.6'
def testEq(self):
assert univ.ObjectIdentifier((1,3,6)) == (1,3,6), '__cmp__() fails'
def testAdd(self):
assert univ.ObjectIdentifier((1,3)) + (6,)==(1,3,6),'__add__() fails'
def testRadd(self):
assert (1,) + univ.ObjectIdentifier((3,6))==(1,3,6),'__radd__() fails'
def testLen(self):
assert len(univ.ObjectIdentifier((1,3))) == 2,'__len__() fails'
def testPrefix(self):
o = univ.ObjectIdentifier('1.3.6')
assert o.isPrefixOf((1,3,6)), 'isPrefixOf() fails'
assert o.isPrefixOf((1,3,6,1)), 'isPrefixOf() fails'
assert not o.isPrefixOf((1,3)), 'isPrefixOf() fails'
def testInput(self):
assert univ.ObjectIdentifier('1.3.6')==(1,3,6),'prettyIn() fails'
def testTag(self):
assert univ.ObjectIdentifier().getTagSet() == tag.TagSet(
(),
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x06)
)
class SequenceOf(unittest.TestCase):
def setUp(self):
self.s1 = univ.SequenceOf(
componentType=univ.OctetString('')
)
self.s2 = self.s1.clone()
def testTag(self):
assert self.s1.getTagSet() == tag.TagSet(
(),
tag.Tag(tag.tagClassUniversal, tag.tagFormatConstructed, 0x10)
), 'wrong tagSet'
def testSeq(self):
self.s1.setComponentByPosition(0, univ.OctetString('abc'))
assert self.s1[0] == str2octs('abc'), 'set by idx fails'
self.s1[0] = 'cba'
assert self.s1[0] == str2octs('cba'), 'set by idx fails'
def testCmp(self):
self.s1.clear()
self.s1.setComponentByPosition(0, 'abc')
self.s2.clear()
self.s2.setComponentByPosition(0, univ.OctetString('abc'))
assert self.s1 == self.s2, '__cmp__() fails'
def testSubtypeSpec(self):
s = self.s1.clone(subtypeSpec=constraint.ConstraintsUnion(
constraint.SingleValueConstraint(str2octs('abc'))
))
try:
s.setComponentByPosition(0, univ.OctetString('abc'))
except:
assert 0, 'constraint fails'
try:
s.setComponentByPosition(1, univ.OctetString('Abc'))
except:
pass
else:
assert 0, 'constraint fails'
def testSizeSpec(self):
s = self.s1.clone(sizeSpec=constraint.ConstraintsUnion(
constraint.ValueSizeConstraint(1,1)
))
s.setComponentByPosition(0, univ.OctetString('abc'))
try:
s.verifySizeSpec()
except:
assert 0, 'size spec fails'
s.setComponentByPosition(1, univ.OctetString('abc'))
try:
s.verifySizeSpec()
except:
pass
else:
assert 0, 'size spec fails'
def testGetComponentTagMap(self):
assert self.s1.getComponentTagMap().getPosMap() == {
univ.OctetString.tagSet: univ.OctetString('')
}
def testSubtype(self):
self.s1.clear()
assert self.s1.subtype(
implicitTag=tag.Tag(tag.tagClassPrivate,tag.tagFormatSimple,2),
subtypeSpec=constraint.SingleValueConstraint(1,3),
sizeSpec=constraint.ValueSizeConstraint(0,1)
) == self.s1.clone(
tagSet=tag.TagSet(tag.Tag(tag.tagClassPrivate,
tag.tagFormatSimple,2)),
subtypeSpec=constraint.ConstraintsIntersection(constraint.SingleValueConstraint(1,3)),
sizeSpec=constraint.ValueSizeConstraint(0,1)
)
def testClone(self):
self.s1.setComponentByPosition(0, univ.OctetString('abc'))
s = self.s1.clone()
assert len(s) == 0
s = self.s1.clone(cloneValueFlag=1)
assert len(s) == 1
assert s.getComponentByPosition(0) == self.s1.getComponentByPosition(0)
class Sequence(unittest.TestCase):
def setUp(self):
self.s1 = univ.Sequence(componentType=namedtype.NamedTypes(
namedtype.NamedType('name', univ.OctetString('')),
namedtype.OptionalNamedType('nick', univ.OctetString('')),
namedtype.DefaultedNamedType('age', univ.Integer(34))
))
def testTag(self):
assert self.s1.getTagSet() == tag.TagSet(
(),
tag.Tag(tag.tagClassUniversal, tag.tagFormatConstructed, 0x10)
), 'wrong tagSet'
def testById(self):
self.s1.setComponentByName('name', univ.OctetString('abc'))
assert self.s1.getComponentByName('name') == str2octs('abc'), 'set by name fails'
def testByKey(self):
self.s1['name'] = 'abc'
assert self.s1['name'] == str2octs('abc'), 'set by key fails'
def testGetNearPosition(self):
assert self.s1.getComponentTagMapNearPosition(1).getPosMap() == {
univ.OctetString.tagSet: univ.OctetString(''),
univ.Integer.tagSet: univ.Integer(34)
}
assert self.s1.getComponentPositionNearType(
univ.OctetString.tagSet, 1
) == 1
def testGetDefaultComponentByPosition(self):
self.s1.clear()
assert self.s1.getDefaultComponentByPosition(0) == None
assert self.s1.getDefaultComponentByPosition(2) == univ.Integer(34)
def testSetDefaultComponents(self):
self.s1.clear()
assert self.s1.getComponentByPosition(2) == None
self.s1.setComponentByPosition(0, univ.OctetString('Ping'))
self.s1.setComponentByPosition(1, univ.OctetString('Pong'))
self.s1.setDefaultComponents()
assert self.s1.getComponentByPosition(2) == 34
def testClone(self):
self.s1.setComponentByPosition(0, univ.OctetString('abc'))
self.s1.setComponentByPosition(1, univ.OctetString('def'))
self.s1.setComponentByPosition(2, univ.Integer(123))
s = self.s1.clone()
assert s.getComponentByPosition(0) != self.s1.getComponentByPosition(0)
assert s.getComponentByPosition(1) != self.s1.getComponentByPosition(1)
assert s.getComponentByPosition(2) != self.s1.getComponentByPosition(2)
s = self.s1.clone(cloneValueFlag=1)
assert s.getComponentByPosition(0) == self.s1.getComponentByPosition(0)
assert s.getComponentByPosition(1) == self.s1.getComponentByPosition(1)
assert s.getComponentByPosition(2) == self.s1.getComponentByPosition(2)
class SetOf(unittest.TestCase):
def setUp(self):
self.s1 = univ.SetOf(componentType=univ.OctetString(''))
def testTag(self):
assert self.s1.getTagSet() == tag.TagSet(
(),
tag.Tag(tag.tagClassUniversal, tag.tagFormatConstructed, 0x11)
), 'wrong tagSet'
def testSeq(self):
self.s1.setComponentByPosition(0, univ.OctetString('abc'))
assert self.s1[0] == str2octs('abc'), 'set by idx fails'
self.s1.setComponentByPosition(0, self.s1[0].clone('cba'))
assert self.s1[0] == str2octs('cba'), 'set by idx fails'
class Set(unittest.TestCase):
def setUp(self):
self.s1 = univ.Set(componentType=namedtype.NamedTypes(
namedtype.NamedType('name', univ.OctetString('')),
namedtype.OptionalNamedType('null', univ.Null('')),
namedtype.DefaultedNamedType('age', univ.Integer(34))
))
self.s2 = self.s1.clone()
def testTag(self):
assert self.s1.getTagSet() == tag.TagSet(
(),
tag.Tag(tag.tagClassUniversal, tag.tagFormatConstructed, 0x11)
), 'wrong tagSet'
def testByTypeWithPythonValue(self):
self.s1.setComponentByType(univ.OctetString.tagSet, 'abc')
assert self.s1.getComponentByType(
univ.OctetString.tagSet
) == str2octs('abc'), 'set by name fails'
def testByTypeWithInstance(self):
self.s1.setComponentByType(univ.OctetString.tagSet, univ.OctetString('abc'))
assert self.s1.getComponentByType(
univ.OctetString.tagSet
) == str2octs('abc'), 'set by name fails'
def testGetTagMap(self):
assert self.s1.getTagMap().getPosMap() == {
univ.Set.tagSet: univ.Set()
}
def testGetComponentTagMap(self):
assert self.s1.getComponentTagMap().getPosMap() == {
univ.OctetString.tagSet: univ.OctetString(''),
univ.Null.tagSet: univ.Null(''),
univ.Integer.tagSet: univ.Integer(34)
}
def testGetPositionByType(self):
assert self.s1.getComponentPositionByType(
univ.Null().getTagSet()
) == 1
class Choice(unittest.TestCase):
def setUp(self):
innerComp = univ.Choice(componentType=namedtype.NamedTypes(
namedtype.NamedType('count', univ.Integer()),
namedtype.NamedType('flag', univ.Boolean())
))
self.s1 = univ.Choice(componentType=namedtype.NamedTypes(
namedtype.NamedType('name', univ.OctetString()),
namedtype.NamedType('sex', innerComp)
))
def testTag(self):
assert self.s1.getTagSet() == tag.TagSet(), 'wrong tagSet'
def testOuterByTypeWithPythonValue(self):
self.s1.setComponentByType(univ.OctetString.tagSet, 'abc')
assert self.s1.getComponentByType(
univ.OctetString.tagSet
) == str2octs('abc')
def testOuterByTypeWithInstanceValue(self):
self.s1.setComponentByType(
univ.OctetString.tagSet, univ.OctetString('abc')
)
assert self.s1.getComponentByType(
univ.OctetString.tagSet
) == str2octs('abc')
def testInnerByTypeWithPythonValue(self):
self.s1.setComponentByType(univ.Integer.tagSet, 123, 1)
assert self.s1.getComponentByType(
univ.Integer.tagSet, 1
) == 123
def testInnerByTypeWithInstanceValue(self):
self.s1.setComponentByType(
univ.Integer.tagSet, univ.Integer(123), 1
)
assert self.s1.getComponentByType(
univ.Integer.tagSet, 1
) == 123
def testCmp(self):
self.s1.setComponentByName('name', univ.OctetString('abc'))
assert self.s1 == str2octs('abc'), '__cmp__() fails'
def testGetComponent(self):
self.s1.setComponentByType(univ.OctetString.tagSet, 'abc')
assert self.s1.getComponent() == str2octs('abc'), 'getComponent() fails'
def testGetName(self):
self.s1.setComponentByType(univ.OctetString.tagSet, 'abc')
assert self.s1.getName() == 'name', 'getName() fails'
def testSetComponentByPosition(self):
self.s1.setComponentByPosition(0, univ.OctetString('Jim'))
assert self.s1 == str2octs('Jim')
def testClone(self):
self.s1.setComponentByPosition(0, univ.OctetString('abc'))
s = self.s1.clone()
assert len(s) == 0
s = self.s1.clone(cloneValueFlag=1)
assert len(s) == 1
assert s.getComponentByPosition(0) == self.s1.getComponentByPosition(0)
if __name__ == '__main__': unittest.main()