summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorelie <elie>2005-06-14 06:59:38 +0000
committerelie <elie>2005-06-14 06:59:38 +0000
commit3dfa1b281dfd1f1d8a8d955f56042be9b093a912 (patch)
treeda5b6711a73ca89caa0e7dd93cbecdacf4b0d831
downloadpyasn1-3dfa1b281dfd1f1d8a8d955f56042be9b093a912.tar.gz
Initial revision
-rw-r--r--CHANGES9
-rw-r--r--LICENSE28
-rw-r--r--MANIFEST54
-rw-r--r--README69
-rw-r--r--TODO44
-rw-r--r--doc/notes.html382
-rw-r--r--examples/snmp.py171
-rw-r--r--examples/x509.py147
-rw-r--r--pyasn1/__init__.py1
-rw-r--r--pyasn1/codec/__init__.py0
-rw-r--r--pyasn1/codec/ber/__init__.py0
-rw-r--r--pyasn1/codec/ber/decoder.py480
-rw-r--r--pyasn1/codec/ber/encoder.py251
-rw-r--r--pyasn1/codec/ber/eoo.py7
-rw-r--r--pyasn1/codec/cer/__init__.py0
-rw-r--r--pyasn1/codec/cer/decoder.py28
-rw-r--r--pyasn1/codec/cer/encoder.py86
-rw-r--r--pyasn1/codec/der/__init__.py0
-rw-r--r--pyasn1/codec/der/decoder.py5
-rw-r--r--pyasn1/codec/der/encoder.py25
-rw-r--r--pyasn1/error.py3
-rw-r--r--pyasn1/type/__init__.py0
-rw-r--r--pyasn1/type/base.py210
-rw-r--r--pyasn1/type/char.py57
-rw-r--r--pyasn1/type/constraint.py185
-rw-r--r--pyasn1/type/error.py3
-rw-r--r--pyasn1/type/namedtype.py130
-rw-r--r--pyasn1/type/namedval.py42
-rw-r--r--pyasn1/type/tag.py109
-rw-r--r--pyasn1/type/univ.py616
-rw-r--r--pyasn1/type/useful.py12
-rw-r--r--setup.py18
-rw-r--r--test/__init__.py0
-rw-r--r--test/codec/__init__.py0
-rw-r--r--test/codec/ber/__init__.py0
-rw-r--r--test/codec/ber/decoder.py301
-rw-r--r--test/codec/ber/encoder.py240
-rw-r--r--test/codec/ber/suite.py17
-rw-r--r--test/codec/cer/__init__.py0
-rw-r--r--test/codec/cer/decoder.py26
-rw-r--r--test/codec/cer/encoder.py102
-rw-r--r--test/codec/cer/suite.py17
-rw-r--r--test/codec/der/__init__.py0
-rw-r--r--test/codec/der/decoder.py16
-rw-r--r--test/codec/der/encoder.py39
-rw-r--r--test/codec/der/suite.py17
-rw-r--r--test/suite.py23
-rw-r--r--test/type/__init__.py0
-rw-r--r--test/type/constraint.py217
-rw-r--r--test/type/namedtype.py83
-rw-r--r--test/type/suite.py17
-rw-r--r--test/type/tag.py103
-rw-r--r--test/type/univ.py359
53 files changed, 4749 insertions, 0 deletions
diff --git a/CHANGES b/CHANGES
new file mode 100644
index 0000000..737ba87
--- /dev/null
+++ b/CHANGES
@@ -0,0 +1,9 @@
+Wed Apr 6 18:48:40 MSD 2005
+----------------------------
+
+* error.Asn1Error replaced with error.PyAsn1Error
+
+Mon Apr 4 08:37:02 MSD 2005
+----------------------------
+
+* Initial public alpha release
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..bf9618c
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,28 @@
+Copyright (c) 2005, Ilya Etingof <ilya@glas.net>, all rights reserved.
+
+THIS SOFTWARE IS NOT FAULT TOLERANT AND SHOULD NOT BE USED IN ANY SITUATION
+ENDANGERING HUMAN LIFE OR PROPERTY.
+
+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.
+
+ * The name of the authors may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+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 REGENTS 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.
diff --git a/MANIFEST b/MANIFEST
new file mode 100644
index 0000000..b92d5c8
--- /dev/null
+++ b/MANIFEST
@@ -0,0 +1,54 @@
+CHANGES
+MANIFEST
+README
+LICENSE
+doc/notes.html
+pyasn1/v1/__init__.py
+pyasn1/v1/error.py
+pyasn1/v1/codec/ber/decoder.py
+pyasn1/v1/codec/ber/encoder.py
+pyasn1/v1/codec/ber/__init__.py
+pyasn1/v1/codec/ber/eoo.py
+pyasn1/v1/codec/cer/__init__.py
+pyasn1/v1/codec/cer/encoder.py
+pyasn1/v1/codec/cer/decoder.py
+pyasn1/v1/codec/der/__init__.py
+pyasn1/v1/codec/der/decoder.py
+pyasn1/v1/codec/der/encoder.py
+pyasn1/v1/codec/__init__.py
+pyasn1/v1/type/base.py
+pyasn1/v1/type/tag.py
+pyasn1/v1/type/univ.py
+pyasn1/v1/type/__init__.py
+pyasn1/v1/type/namedtype.py
+pyasn1/v1/type/namedval.py
+pyasn1/v1/type/error.py
+pyasn1/v1/type/constraint.py
+pyasn1/v1/type/char.py
+pyasn1/v1/type/useful.py
+pyasn1/__init__.py
+test/__init__.py
+test/suite.py
+test/codec/ber/__init__.py
+test/codec/ber/encoder.py
+test/codec/ber/suite.py
+test/codec/ber/decoder.py
+test/codec/__init__.py
+test/codec/cer/__init__.py
+test/codec/cer/encoder.py
+test/codec/cer/suite.py
+test/codec/cer/decoder.py
+test/codec/der/__init__.py
+test/codec/der/encoder.py
+test/codec/der/suite.py
+test/codec/der/decoder.py
+test/type/univ.py
+test/type/__init__.py
+test/type/suite.py
+test/type/tag.py
+test/type/constraint.py
+test/type/namedtype.py
+examples/x509.py
+examples/snmp.py
+TODO
+setup.py
diff --git a/README b/README
new file mode 100644
index 0000000..3574b33
--- /dev/null
+++ b/README
@@ -0,0 +1,69 @@
+
+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.
+
+WARNING! WARNING! WARNING!
+--------------------------
+
+This is an alpha release. The code is not too reliable and API is not
+quite stable. Though, dramatic changes to the API are not expected.
+
+FEATURES
+--------
+
+* Generic implementation of ASN.1 types (X.208)
+* Fully standard compliant BER/CER/DER codecs
+* 100% Python, works with Python 1.5 and later
+* 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 distutils for installation:
+
+$ tar zxf pyasn1-0.0.1a.tar.gz
+$ cd pyasn1-0.0.1a
+$ python setup.py install
+$ cd test
+$ python suite.py # to make sure everything works alright
+
+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/notes.html
+file in the distribution.
+
+Also refer to example modules -- one of them (x509.py) handles SSL
+certificate format.
+
+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
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..24d611c
--- /dev/null
+++ b/TODO
@@ -0,0 +1,44 @@
+
+* Implement the rest of ASN.1 types (Real etc)
+* Support large tag numbers at codecs
+* 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)
+* verify error cases in test suite
+* present subtypes ?
+* component presence check wont work at innertypeconst
+* optimize en/decoders
+* add the rest of ASN1 types/codecs
+* type vs value, defaultValue
+
+ber.encoder:
+* Asn1Item.clone() / shallowcopy issue
+* large tags encoder
+* 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:
+
+* profile
+* windows
+* how untagged TagSet should be initialized?
diff --git a/doc/notes.html b/doc/notes.html
new file mode 100644
index 0000000..5b0eab3
--- /dev/null
+++ b/doc/notes.html
@@ -0,0 +1,382 @@
+<html>
+<title>
+ASN.1 tools for Python
+</title>
+<body>
+<center>
+<table width=70%>
+<tr>
+<td>
+<h3>
+ASN.1 tools for Python
+</h3>
+
+<p>
+Whenever data structures are described in some machine and programming language
+independent and unambiguous way, such specification is called
+<a href=http://en.wikipedia.org/wiki/Abstract_syntax>abstract syntax</a>,
+by contrast with machine/language specific methods, which are called 'concrete'
+or 'transfer' syntaxes.
+</p>
+
+<p>
+Abstract syntaxes appear useful in networking as a tool for engineering
+protocols in a clear and portable way. Moreover, once a protocol
+is described in some abstract language, protocol parsers and builders
+could be automatically generated for various computing
+architectures/programming languages, thus saving engineers from implementing
+low-level transport details by hand.
+</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> defining particular implementation of abstract data
+description language accompanied by a collection of transfer encoding methods.
+Perhaps the most widely used among these data serialization methods is Basic
+Encoding Rules (
+<a href=http://en.wikipedia.org/wiki/Basic_encoding_rules>BER</a>
+) together with its derivatives (
+<a href=http://en.wikipedia.org/wiki/Distinguished_encoding_rules>DER</a>
+and
+<a href=http://en.wikipedia.org/wiki/Canonical_encoding_rules>CER</a>
+), while Packed Encoding Rules
+<a href=http://en.wikipedia.org/wiki/Packed_encoding_rules>PER</a>
+) aims at most compact data representation whilst in the wire.
+</p>
+
+<p>
+This project is dedicated to implementation of ASN.1 types (concrete
+syntax) and codecs (transfer syntaxes) for Python programming environment.
+ASN.1 compiler is planned for implementation in the future.
+</p>
+
+<h3>
+Data model for ASN.1 types
+</h3>
+
+<p>
+The ASN.1 standard defines a set of <i>primitive</i>, scalar data types
+(such as Integer, String etc) and a few <i>constructed</i> types, each
+holding one or many other ASN.1 types as its components (constructed
+types may be viewed as Pascal "records" or C "struct"ures).
+</p>
+
+<p>
+In pyasn1, those primitive ASN.1 types are implemented as
+immutable scalar objects. They could be used just like corresponding
+native Python types (integers, strings etc).
+</p>
+
+<pre>
+>>> from pyasn1.type import univ
+>>> univ.Integer(12) - 2
+10
+>>> univ.OctetString('abc') == 'abc'
+True
+>>>
+</pre>
+
+<p>
+In ASN.1, constructed types (Sequence, SequenceOf, Set, SetOf, Choice)
+differ from each other by allowed components combination and ordering, which
+also projects to component addressing methods.
+</p>
+
+<p>
+In this Python implementation, constructed ASN.1 types behave like
+Python sequence, and also support additional component addressing methods,
+specific to particular constructed type.
+</p>
+
+<p>
+Components of <i>Sequence</i>s can be addressed by their position in sequence:
+</p>
+
+<pre>
+>>> from pyasn1.type import univ, namedtype
+>>> seq = univ.Sequence(componentType=namedtype.NamedTypes(namedtype.NamedType('version', univ.Integer())))
+>>> seq.setComponentByPosition(0, univ.Integer())
+>>> seq.getComponentByPosition(0)
+Integer(0)
+>>>
+</pre>
+
+<p>
+and by [textual] component type name (also valid for <i>Set</i> and
+<i>Choice</i>),
+</p>
+
+<pre>
+>>> seq.getComponentByName('version')
+Integer(0)
+>>>
+</pre>
+
+<p>
+as well as by type for Set and Choice:
+</p>
+
+<pre>
+>>> set = univ.Set(componentType=namedtype.NamedTypes(namedtype.NamedType('version', univ.Integer())))
+>>> set.setComponentByPosition(0, univ.Integer())
+>>> set.getComponentByType(univ.Integer().getTagSet())
+Integer(0)
+>>>
+</pre>
+
+<p>
+ASN.1 types are identified by a numeric ID called <i>tag</i>. In pyasn1,
+tags are implemented as immutable objects referred by ASN.1 type objects:
+</p>
+
+<pre>
+from pyasn1.type import tag
+>>> tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 3)
+Tag(tagClass=0, tagFormat=0, tagId=3)
+>>>
+</pre>
+
+<p>
+For the purpose of making same-typed objects distinguishable from one
+another, the standard allows for assigning custom tags to
+ASN.1 types. These <i>tagged types</i> preserve all properties of their
+parent type but possess different IDs.
+</p>
+
+<p>
+There are two methods of tagging: <i>implicit</i> and <i>explicit</i>. The
+first one replaces base tag with arbitrary custom tag thus dropping all
+previously existing tag information for type:
+</p>
+
+<pre>
+>>> t = tag.TagSet(tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 3))
+>>> t.tagImplicitly(tag.Tag(tag.tagClassPrivate, tag.tagFormatSimple, 32))
+TagSet(Tag(tagClass=192, tagFormat=0, tagId=32))
+>>>
+</pre>
+
+<p>
+The explicit tag is build by appending new custom tag to already
+existing set of type's tags. Important property of explicit tagging
+is that it preserves base type information.
+</p>
+
+<pre>
+>>> t = tag.TagSet(tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 3)
+>>> t.tagExplicitly(tag.Tag(tag.tagClassPrivate, tag.tagFormatSimple, 32))
+TagSet(Tag(tagClass=192, tagFormat=32, tagId=32), Tag(tagClass=0, tagFormat=0, tagId=3))
+>>>
+</pre>
+
+<p>
+Besides tags, certain restrictions may be put upon ASN.1 types' values thus
+creating <i>subtypes</i> from base types (in computer science, a
+<a href=http://en.wikipedia.org/wiki/Data_type>data type</a>
+is a name of a collection of possible values). These restrictions are called
+<i>subtype constraints</i> in the ASN.1 standard.
+</p>
+
+<p>
+Several different flavors of <i>constraints</i> exist. Some obvious
+include <i>ValueRangeConstraint</i>, <i>ValueSizeConstraint</i> and others.
+In pyasn1, constraints take shape of immutable objects capable
+of evaluating given value against constraint's specific logic.
+</p>
+
+<pre>
+>>> from pyasn1.type import constraint
+>>> constraint.ValueRangeConstraint(1,2)
+ValueRangeConstraint(1,2)
+>>>
+</pre>
+
+<p>
+Multiple constraints can be combined altogether into sets with three basic
+boolean operations (<i>ConstraintsUnion</i>, <i>ConstraintsIntersection</i> and
+<i>ConstraintsExclusion</i>), which could be applied recursively.
+</p>
+
+<pre>
+>>> c = constraint.ConstraintsUnion(constraint.SingleValueConstraint(4), constraint.ValueRangeConstraint(-1, 2))
+>>> c(1)
+>>> c(3)
+pyasn1.type.error.ValueConstraintError: ConstraintsUnion(SingleValueConstraint(4), ValueRangeConstraint(-1, 2)) failed at: all of (SingleValueConstraint(4), ValueRangeConstraint(-1, 2)) failed for 5
+>>>
+</pre>
+
+<p>
+A constrainted ASN.1 type would then hold a reference to a top-most constraint
+object in a set and pass it a value, being assigned, for verification.
+</p>
+
+<p>
+By evaluating the inclusion of all tags and constraints of one type in
+tag and constraint sets of another, it's possible to figure out the
+relationships between types. By way of background, types matching is used
+in constructed types for by-type component addressing.
+</p>
+
+<pre>
+>>> i1 = univ.Integer(subtypeSpec=constraint.SingleValueConstraint(0,3))
+>>> i2 = univ.Integer(subtypeSpec=constraint.ConstraintsIntersection(constraint.SingleValueConstraint(0,3),
+ constraint.SingleValueConstraint(6,8)))
+>>> i1.isSameTypeWith(i2)
+False
+>>> i1.isSuperTypeOf(i2)
+True
+>>>
+</pre>
+
+<p>
+While complete documentation on the API to all these ASN.1 items is not
+yet written, please, refer to example uses and source code for additional
+information.
+</p>
+
+<h3>
+Codec notes
+</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>
+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.
+</p>
+
+<p>
+Codec restartability is especially important when application deals with large
+volumes of data and/or runs on low RAM.
+</p>
+
+<p>
+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 BER codec and its derivates -- CER and
+DER. Encoder is used for transforming ASN.1 object into substrate:
+</p>
+
+<pre>
+>>> from pyasn1.type import univ
+>>> from pyasn1.codec.ber import encoder
+>>> encoder.encode(univ.Integer(12))
+'\x02\x01\x0c'
+>>>
+</pre>
+
+<p>
+while decoder recovers ASN.1 objects from substrate:
+</p>
+
+<pre>
+>>> from pyasn1.codec.ber import decoder
+>>> decoder.decode('\x02\x01\x0c')
+Integer(12), ''
+>>>
+</pre>
+
+<p>
+Depending of encoding and tagging methods used, decoder may require
+to know ASN.1 syntax of data structure to be decoded. For example,
+PER-encoded or implicitly tagged values would not recover from substrate
+without knowing ASN.1 syntax of encoded data. Whenever decoder is
+given ASN.1 specification, this operation mode will be referred to as
+<i>guided</i> throughout this document.
+</p>
+
+<p>
+The ASN.1 specification passed to decoder running in guided mode is simply
+a reference to the top-most ASN.1 type object of the concrete specification.
+Decoder would neither modify this specification object in any way nor use
+its current values, but rather use it as a pattern when creating new objects:
+</p>
+
+<pre>
+>>> from pyasn1.codec.ber import decoder
+>>> decoder.decode('\x02\x01\x0c', asn1Spec=univ.Integer())
+Integer(12), ''
+>>>
+</pre>
+
+<p>
+One of the properties of BER codec is its use of either definite or indefinite
+length specification for serialized data. Although indefinite length form
+is especially important for stateful codec (which could produce&consume
+substrate in chunks), pyasn1 codecs fully support both length forms.
+</p>
+
+<p>
+Constructed encoding is another feature of BER, closely related to indefinite
+length form. In essence, large scalar value (such as ASN.1 <i>character</i> or
+<i>BitString</i> type) could be chopped into smaller chunks by encoder and
+transmitted incrementally.
+</p>
+
+<p>
+The following code would BER encode ASN.1 <i>OctetString</i> object using
+constructed (chopped by 4th octet) and indefinite length form:
+</p>
+
+<pre>
+>>> from pyasn1.type import univ
+>>> from pyasn1.codec.ber import encoder
+>>> encoder.encode(univ.OctetString('Quick brown fox'), defMode=0, maxChunkSize=4)
+'$\x80\x04\x04Quic\x04\x04k br\x04\x04own \x04\x03fox\x00\x00'
+>>>
+</pre>
+
+<p>
+Nothing special is required on decoding side to recover from various encoding
+forms. BER decoder transparently handles all of them.
+</p>
+
+<h3>
+Availability
+</h3>
+
+<p>
+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 <a href=http://www.sf.net/projects/pyasn1/>project home</a>.
+</p>
+
+<h3>
+Feedback
+</h3>
+
+<p>
+Comments and fixes are welcome at
+<a href="mailto:ilya@glas.net">ilya@glas.net</a>
+.
+</p>
+
+</td>
+</tr>
+</table>
+</center>
+</body>
+</html>
diff --git a/examples/snmp.py b/examples/snmp.py
new file mode 100644
index 0000000..7ee73ef
--- /dev/null
+++ b/examples/snmp.py
@@ -0,0 +1,171 @@
+# SNMP message syntax
+
+# Would be autogenerated by an ASN.1 parser from here:
+
+from pyasn1.type import univ, namedtype, namedval, tag, constraint
+from pyasn1.codec.ber import encoder, decoder
+
+class Version(univ.Integer):
+ namedValues = namedval.NamedValues(
+ ('version-1', 0)
+ )
+ defaultValue = 0
+
+class Community(univ.OctetString): pass
+
+class RequestID(univ.Integer): pass
+class ErrorStatus(univ.Integer):
+ namedValues = namedval.NamedValues(
+ ('noError', 0),
+ ('tooBig', 1),
+ ('noSuchName', 2),
+ ('badValue', 3),
+ ('readOnly', 4),
+ ('genErr', 5)
+ )
+class ErrorIndex(univ.Integer): pass
+
+class ObjectName(univ.ObjectIdentifier): pass
+
+class SimpleSyntax(univ.Choice):
+ componentType = namedtype.NamedTypes(
+ namedtype.NamedType('number', univ.Integer()),
+ namedtype.NamedType('string', univ.OctetString()),
+ namedtype.NamedType('object', univ.ObjectIdentifier()),
+ namedtype.NamedType('empty', univ.Null())
+ )
+
+class IpAddress(univ.OctetString):
+ tagSet = univ.OctetString.tagSet.tagImplicitly(
+ tag.Tag(tag.tagClassApplication, tag.tagFormatSimple, 0)
+ )
+ subtypeSpec = univ.Integer.subtypeSpec + constraint.ValueSizeConstraint(
+ 4, 4
+ )
+class NetworkAddress(univ.Choice):
+ componentType = namedtype.NamedTypes(
+ namedtype.NamedType('internet', IpAddress())
+ )
+
+class Counter(univ.Integer):
+ tagSet = univ.Integer.tagSet.tagImplicitly(
+ tag.Tag(tag.tagClassApplication, tag.tagFormatSimple, 1)
+ )
+ subtypeSpec = univ.Integer.subtypeSpec + constraint.ValueRangeConstraint(
+ 0, 4294967295L
+ )
+class Gauge(univ.Integer):
+ tagSet = univ.Integer.tagSet.tagImplicitly(
+ tag.Tag(tag.tagClassApplication, tag.tagFormatSimple, 2)
+ )
+ subtypeSpec = univ.Integer.subtypeSpec + constraint.ValueRangeConstraint(
+ 0, 4294967295L
+ )
+class TimeTicks(univ.Integer):
+ tagSet = univ.Integer.tagSet.tagImplicitly(
+ tag.Tag(tag.tagClassApplication, tag.tagFormatSimple, 3)
+ )
+ subtypeSpec = univ.Integer.subtypeSpec + constraint.ValueRangeConstraint(
+ 0, 4294967295L
+ )
+class Opaque(univ.OctetString):
+ tagSet = univ.OctetString.tagSet.tagImplicitly(
+ tag.Tag(tag.tagClassApplication, tag.tagFormatSimple, 4)
+ )
+
+class ApplicationSyntax(univ.Choice):
+ componentType = namedtype.NamedTypes(
+ namedtype.NamedType('address', NetworkAddress()),
+ namedtype.NamedType('counter', Counter()),
+ namedtype.NamedType('gauge', Gauge()),
+ namedtype.NamedType('ticks', TimeTicks()),
+ namedtype.NamedType('arbitrary', Opaque())
+ )
+
+class ObjectSyntax(univ.Choice):
+ componentType = namedtype.NamedTypes(
+ namedtype.NamedType('simple', SimpleSyntax()),
+ namedtype.NamedType('application-wide', ApplicationSyntax())
+ )
+
+class VarBind(univ.Sequence):
+ componentType = namedtype.NamedTypes(
+ namedtype.NamedType('name', ObjectName()),
+ namedtype.NamedType('value', ObjectSyntax())
+ )
+class VarBindList(univ.SequenceOf):
+ componentType = VarBind()
+
+class _RequestBase(univ.Sequence):
+ componentType = namedtype.NamedTypes(
+ namedtype.NamedType('request-id', RequestID()),
+ namedtype.NamedType('error-status', ErrorStatus()),
+ namedtype.NamedType('error-index', ErrorIndex()),
+ namedtype.NamedType('variable-bindings', VarBindList())
+ )
+
+class GetRequestPDU(_RequestBase):
+ tagSet = _RequestBase.tagSet.tagImplicitly(
+ tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0)
+ )
+class GetNextRequestPDU(_RequestBase):
+ tagSet = _RequestBase.tagSet.tagImplicitly(
+ tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1)
+ )
+class GetResponsePDU(_RequestBase):
+ tagSet = _RequestBase.tagSet.tagImplicitly(
+ tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 2)
+ )
+class SetRequestPDU(_RequestBase):
+ tagSet = _RequestBase.tagSet.tagImplicitly(
+ tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 3)
+ )
+
+class TrapPDU(univ.Sequence):
+ componentType = namedtype.NamedTypes(
+ namedtype.NamedType('enterprise', univ.ObjectIdentifier()),
+ namedtype.NamedType('agent-addr', NetworkAddress()),
+ namedtype.NamedType('generic-trap', univ.Integer().clone(namedValues=namedval.NamedValues(('coldStart', 0), ('warmStart', 1), ('linkDown', 2), ('linkUp', 3), ('authenticationFailure', 4), ('egpNeighborLoss', 5), ('enterpriseSpecific', 6)))),
+ namedtype.NamedType('specific-trap', univ.Integer()),
+ namedtype.NamedType('time-stamp', TimeTicks()),
+ namedtype.NamedType('variable-bindings', VarBindList())
+ )
+
+class Pdus(univ.Choice):
+ componentType = namedtype.NamedTypes(
+ namedtype.NamedType('get-request', GetRequestPDU()),
+ namedtype.NamedType('get-next-request', GetNextRequestPDU()),
+ namedtype.NamedType('get-response', GetResponsePDU()),
+ namedtype.NamedType('set-request', SetRequestPDU()),
+ namedtype.NamedType('trap', TrapPDU())
+ )
+
+class Message(univ.Sequence):
+ componentType = namedtype.NamedTypes(
+ namedtype.NamedType('version', Version()),
+ namedtype.NamedType('community', Community()),
+ namedtype.NamedType('data', Pdus())
+ )
+
+# ...would be autogenerated up to here
+
+def mkRequest():
+ msg = Message()
+ msg.setComponentByPosition(0)
+ msg.setComponentByPosition(1, 'public')
+ # pdu
+ pdus = msg.setComponentByPosition(2).getComponentByPosition(2)
+ pdu = pdus.setComponentByPosition(0).getComponentByPosition(0)
+ pdu.setComponentByPosition(0, 123)
+ pdu.setComponentByPosition(1)
+ pdu.setComponentByPosition(2)
+ vbl = pdu.setComponentByPosition(3).getComponentByPosition(3)
+ vb = vbl.setComponentByPosition(0).getComponentByPosition(0)
+ vb.setComponentByPosition(0, (1,3,6,1,2,1,1,1,0))
+ v = vb.setComponentByPosition(1).getComponentByPosition(1).setComponentByPosition(0).getComponentByPosition(0).setComponentByPosition(3).getComponentByPosition(3)
+ return msg
+
+msg = mkRequest()
+rMsg = decoder.decode(encoder.encode(msg), asn1Spec=msg)[0]
+#rMsg = decoder.decode(encoder.encode(msg))[0]
+print rMsg.prettyPrinter()
diff --git a/examples/x509.py b/examples/x509.py
new file mode 100644
index 0000000..7717a46
--- /dev/null
+++ b/examples/x509.py
@@ -0,0 +1,147 @@
+# Read ASN.1/PEM X.509 certificates on stdin, parse each into plain text,
+# then build substrate from it
+import sys, string, base64
+from pyasn1.type import tag,namedtype,namedval,univ,constraint,char,useful
+from pyasn1.codec.der import decoder, encoder
+from pyasn1 import error
+
+# Would be autogenerated from ASN.1 source by a ASN.1 parser
+# X.509 spec (rfc2459)
+
+MAX = 64 # XXX ?
+
+class DirectoryString(univ.Choice):
+ componentType = namedtype.NamedTypes(
+ namedtype.NamedType('teletexString', char.TeletexString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, MAX))),
+ namedtype.NamedType('printableString', char.PrintableString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, MAX))),
+ namedtype.NamedType('universalString', char.UniversalString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, MAX))),
+ namedtype.NamedType('utf8String', char.UTF8String().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, MAX))),
+ namedtype.NamedType('bmpString', char.BMPString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, MAX))),
+ namedtype.NamedType('ia5String', char.IA5String().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, MAX))) # hm, this should not be here!? XXX
+ )
+
+class AttributeValue(DirectoryString): pass
+
+class AttributeType(univ.ObjectIdentifier): pass
+
+class AttributeTypeAndValue(univ.Sequence):
+ componentType = namedtype.NamedTypes(
+ namedtype.NamedType('type', AttributeType()),
+ namedtype.NamedType('value', AttributeValue())
+ )
+
+class RelativeDistinguishedName(univ.SetOf):
+ componentType = AttributeTypeAndValue()
+
+class RDNSequence(univ.SequenceOf):
+ componentType = RelativeDistinguishedName()
+
+class Name(univ.Choice):
+ componentType = namedtype.NamedTypes(
+ namedtype.NamedType('', RDNSequence())
+ )
+
+class AlgorithmIdentifier(univ.Sequence):
+ componentType = namedtype.NamedTypes(
+ namedtype.NamedType('algorithm', univ.ObjectIdentifier()),
+ namedtype.OptionalNamedType('parameters', univ.Null())
+ # XXX syntax screwed?
+# namedtype.OptionalNamedType('parameters', univ.ObjectIdentifier())
+ )
+
+class Extension(univ.Sequence):
+ componentType = namedtype.NamedTypes(
+ namedtype.NamedType('extnID', univ.ObjectIdentifier()),
+ namedtype.DefaultedNamedType('critical', univ.Boolean('False')),
+ namedtype.NamedType('extnValue', univ.OctetString())
+ )
+
+class Extensions(univ.SequenceOf):
+ componentType = Extension()
+ sizeSpec = univ.SequenceOf.sizeSpec + constraint.ValueSizeConstraint(1, MAX)
+
+class SubjectPublicKeyInfo(univ.Sequence):
+ componentType = namedtype.NamedTypes(
+ namedtype.NamedType('algorithm', AlgorithmIdentifier()),
+ namedtype.NamedType('subjectPublicKey', univ.BitString())
+ )
+
+class UniqueIdentifier(univ.BitString): pass
+
+class Time(univ.Choice):
+ componentType = namedtype.NamedTypes(
+ namedtype.NamedType('utcTime', useful.UTCTime()),
+ namedtype.NamedType('generalTime', useful.GeneralizedTime())
+ )
+
+class Validity(univ.Sequence):
+ componentType = namedtype.NamedTypes(
+ namedtype.NamedType('notBefore', Time()),
+ namedtype.NamedType('notAfter', Time())
+ )
+
+class CertificateSerialNumber(univ.Integer): pass
+
+class Version(univ.Integer):
+ namedValues = namedval.NamedValues(
+ ('v1', 0), ('v2', 1), ('v3', 2)
+ )
+
+class TBSCertificate(univ.Sequence):
+ componentType = namedtype.NamedTypes(
+ namedtype.DefaultedNamedType('version', Version('v1', tagSet=Version.tagSet.tagExplicitly(tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0)))),
+ namedtype.NamedType('serialNumber', CertificateSerialNumber()),
+ namedtype.NamedType('signature', AlgorithmIdentifier()),
+ namedtype.NamedType('issuer', Name()),
+ namedtype.NamedType('validity', Validity()),
+ namedtype.NamedType('subject', Name()),
+ namedtype.NamedType('subjectPublicKeyInfo', SubjectPublicKeyInfo()),
+ namedtype.OptionalNamedType('issuerUniqueID', UniqueIdentifier().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1))),
+ namedtype.OptionalNamedType('subjectUniqueID', UniqueIdentifier().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 2))),
+ namedtype.OptionalNamedType('extensions', Extensions().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 3)))
+ )
+
+class Certificate(univ.Sequence):
+ componentType = namedtype.NamedTypes(
+ namedtype.NamedType('tbsCertificate', TBSCertificate()),
+ namedtype.NamedType('signatureAlgorithm', AlgorithmIdentifier()),
+ namedtype.NamedType('signatureValue', univ.BitString())
+ )
+
+# end of ASN.1 data structures
+
+certType = Certificate()
+
+# Read PEM certs from stdin and print them out in plain text
+
+stSpam, stHam, stDump = 0, 1, 2
+state = stSpam
+certCnt = 0
+
+for certLine in sys.stdin.readlines():
+ certLine = string.strip(certLine)
+ if state == stSpam:
+ if state == stSpam:
+ if certLine == '-----BEGIN CERTIFICATE-----':
+ certLines = []
+ state = stHam
+ continue
+ if state == stHam:
+ if certLine == '-----END CERTIFICATE-----':
+ state = stDump
+ else:
+ certLines.append(certLine)
+ if state == stDump:
+ substrate = ''
+ for certLine in certLines:
+ substrate = substrate + base64.b64decode(certLine)
+
+ cert = decoder.decode(substrate, asn1Spec=certType)[0]
+ print cert.prettyPrinter()
+
+ assert encoder.encode(cert) == substrate, 'cert recode fails'
+
+ certCnt = certCnt + 1
+ state = stSpam
+
+print '*** %s PEM cert(s) de/serialized' % certCnt
diff --git a/pyasn1/__init__.py b/pyasn1/__init__.py
new file mode 100644
index 0000000..7de39fe
--- /dev/null
+++ b/pyasn1/__init__.py
@@ -0,0 +1 @@
+majorVersionId = '1'
diff --git a/pyasn1/codec/__init__.py b/pyasn1/codec/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/pyasn1/codec/__init__.py
diff --git a/pyasn1/codec/ber/__init__.py b/pyasn1/codec/ber/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/pyasn1/codec/ber/__init__.py
diff --git a/pyasn1/codec/ber/decoder.py b/pyasn1/codec/ber/decoder.py
new file mode 100644
index 0000000..d2b83df
--- /dev/null
+++ b/pyasn1/codec/ber/decoder.py
@@ -0,0 +1,480 @@
+# BER decoder
+import types
+from pyasn1.type import tag, univ, char, useful
+from pyasn1.codec.ber import eoo
+from pyasn1 import error
+
+class AbstractDecoder:
+ protoComponent = None
+ def _createComponent(self, tagSet, asn1Spec):
+ if asn1Spec is None:
+ return self.protoComponent(tagSet=tagSet)
+ else:
+ return asn1Spec.clone()
+
+ def valueDecoder(self, substrate, asn1Spec, tagSet,
+ length, state, decodeFun):
+ raise error.PyAsn1Error('Decoder not implemented for %s' % tagSet)
+
+class EndOfOctetsDecoder(AbstractDecoder):
+ def valueDecoder(self, substrate, asn1Spec, tagSet,
+ length, state, decodeFun):
+ return eoo.endOfOctets, substrate
+
+class IntegerDecoder(AbstractDecoder):
+ protoComponent = univ.Integer
+ def valueDecoder(self, substrate, asn1Spec, tagSet, length,
+ state, decodeFun):
+ if not substrate:
+ raise error.PyAsn1Error('Empty substrate')
+ bytes = map(ord, substrate)
+ if bytes[0] & 0x80:
+ bytes.insert(0, -1L)
+ value = 0L
+ for byte in bytes:
+ value = value << 8 | byte
+ try:
+ value = int(value)
+ except OverflowError:
+ pass
+ return self._createComponent(tagSet, asn1Spec).clone(value), substrate
+
+class BooleanDecoder(IntegerDecoder):
+ protoComponent = univ.Boolean
+
+class BitStringDecoder(AbstractDecoder):
+ protoComponent = univ.BitString
+ def valueDecoder(self, substrate, asn1Spec, tagSet, length,
+ state, decodeFun):
+ r = self._createComponent(tagSet, asn1Spec) # XXX use default tagset
+ if tagSet[0][1] == tag.tagFormatSimple: # XXX what tag to check?
+ if not substrate:
+ raise error.PyAsn1Error('Missing initial octet')
+ trailingBits = ord(substrate[0])
+ if trailingBits > 7:
+ raise error.PyAsn1Error(
+ 'Trailing bits overflow %s' % trailingBits
+ )
+ substrate = substrate[1:]
+ p = 0; l = len(substrate); b = []
+ while p < l:
+ if p == l:
+ j = 7-trailingBits
+ else:
+ j = 7
+ o = ord(substrate[p])
+ while j >= 0:
+ b.append((o>>j)&0x01)
+ j = j - 1
+ p = p + 1
+ return r.clone(tuple(b)), ''
+ if r: r = r.clone(value=())
+ if not decodeFun:
+ return r, substrate
+ while substrate:
+ component, substrate = decodeFun(substrate)
+ r = r + component
+ return r, substrate
+
+ def indefLenValueDecoder(self, substrate, asn1Spec, tagSet,
+ length, state, decodeFun):
+ r = self._createComponent(tagSet, asn1Spec) # XXX use default tagset
+ if r: r = r.clone(value='')
+ if not decodeFun:
+ return r, substrate
+ while substrate:
+ component, substrate = decodeFun(substrate)
+ if component == eoo.endOfOctets:
+ break
+ r = r + component
+ else:
+ raise error.SubstrateUnderrunError(
+ 'No EOO seen before substrate ends'
+ )
+ return r, substrate
+
+class OctetStringDecoder(AbstractDecoder):
+ protoComponent = univ.OctetString
+ def valueDecoder(self, substrate, asn1Spec, tagSet, length,
+ state, decodeFun):
+ r = self._createComponent(tagSet, asn1Spec) # XXX use default tagset
+ if tagSet[0][1] == tag.tagFormatSimple: # XXX what tag to check?
+ return r.clone(str(substrate)), ''
+ if r: r = r.clone(value='')
+ if not decodeFun:
+ return r, substrate
+ while substrate:
+ component, substrate = decodeFun(substrate)
+ r = r + component
+ return r, substrate
+
+ def indefLenValueDecoder(self, substrate, asn1Spec, tagSet,
+ length, state, decodeFun):
+ r = self._createComponent(tagSet, asn1Spec) # XXX use default tagset
+ if r: r = r.clone(value='')
+ if not decodeFun:
+ return r, substrate
+ while substrate:
+ component, substrate = decodeFun(substrate)
+ if component == eoo.endOfOctets:
+ break
+ r = r + component
+ else:
+ raise error.SubstrateUnderrunError(
+ 'No EOO seen before substrate ends'
+ )
+ return r, substrate
+
+class NullDecoder(AbstractDecoder):
+ protoComponent = univ.Null
+ def valueDecoder(self, substrate, asn1Spec, tagSet,
+ length, state, decodeFun):
+ r = self._createComponent(tagSet, asn1Spec) # XXX use default tagset
+ if substrate:
+ raise error.PyAsn1Error('Unexpected substrate for Null')
+ return r, substrate
+
+class ObjectIdentifierDecoder(AbstractDecoder):
+ protoComponent = univ.ObjectIdentifier
+ def valueDecoder(self, substrate, asn1Spec, tagSet, length,
+ state, decodeFun):
+ r = self._createComponent(tagSet, asn1Spec) # XXX use default tagset
+ if not substrate:
+ raise error.PyAsn1Error('Empty substrate')
+ oid = []; index = 0
+ # Get the first subid
+ subId = ord(substrate[index])
+ oid.append(int(subId / 40))
+ oid.append(int(subId % 40))
+
+ index = index + 1
+ substrateLen = len(substrate)
+
+ while index < substrateLen:
+ subId = ord(substrate[index])
+ if subId < 128:
+ oid.append(subId)
+ index = index + 1
+ else:
+ # Construct subid from a number of octets
+ nextSubId = subId
+ subId = 0
+ while nextSubId >= 128 and index < substrateLen:
+ subId = (subId << 7) + (nextSubId & 0x7F)
+ index = index + 1
+ nextSubId = ord(substrate[index])
+ if index == substrateLen:
+ raise error.SubstrateUnderrunError(
+ 'Short substrate for OID %s' % oid
+ )
+ subId = (subId << 7) + nextSubId
+ oid.append(subId)
+ index = index + 1
+ return r.clone(tuple(oid)), substrate[index:]
+
+class SequenceDecoder(AbstractDecoder):
+ protoComponent = univ.Sequence
+ def _getAsn1SpecByPosition(self, t, idx):
+ if t.getComponentType() is not None:
+ if hasattr(t, 'getComponentTypeMapNearPosition'):
+ return t.getComponentTypeMapNearPosition(idx) # Sequence
+ elif hasattr(t, 'getComponentTypeMap'): # XXX
+ return t.getComponentTypeMap() # SequenceOf
+ # or no asn1Specs
+ def _getPositionByType(self, t, c, idx):
+ if t.getComponentType() is not None:
+ if hasattr(t, 'getComponentPositionNearType'):
+ effectiveTagSet = getattr(
+ c, 'getEffectiveTagSet', c.getTagSet
+ )()
+ return t.getComponentPositionNearType(effectiveTagSet, idx) # Sequence
+ return idx # SequenceOf or w/o asn1Specs
+
+ def valueDecoder(self, substrate, asn1Spec, tagSet,
+ length, state, decodeFun):
+ r = self._createComponent(tagSet, asn1Spec)
+ idx = 0
+ if not decodeFun:
+ return r, substrate
+ while substrate:
+ asn1Spec = self._getAsn1SpecByPosition(r, idx)
+ component, substrate = decodeFun(
+ substrate, asn1Spec
+ )
+ idx = self._getPositionByType(r, component, idx)
+ r.setComponentByPosition(idx, component)
+ idx = idx + 1
+ if hasattr(r, 'setDefaultComponents'):
+ r.setDefaultComponents()
+ r.verifySizeSpec()
+ return r, substrate
+
+ def indefLenValueDecoder(self, substrate, asn1Spec, tagSet,
+ length, state, decodeFun):
+ r = self._createComponent(tagSet, asn1Spec)
+ idx = 0
+ while substrate:
+ try:
+ asn1Spec = self._getAsn1SpecByPosition(r, idx)
+ except error.PyAsn1Error:
+ asn1Spec = None # XXX
+ if not decodeFun:
+ return r, substrate
+ component, substrate = decodeFun(substrate, asn1Spec)
+ if component == eoo.endOfOctets:
+ break
+ idx = self._getPositionByType(r, component, idx)
+ r.setComponentByPosition(idx, component)
+ idx = idx + 1
+ else:
+ raise error.SubstrateUnderrunError(
+ 'No EOO seen before substrate ends'
+ )
+ if hasattr(r, 'setDefaultComponents'):
+ r.setDefaultComponents()
+ r.verifySizeSpec()
+ return r, substrate
+
+class SetDecoder(SequenceDecoder):
+ protoComponent = univ.Set
+ def _getAsn1SpecByPosition(self, t, idx):
+ if t.getComponentType() is not None:
+ if hasattr(t, 'getComponentTypeMap'):
+ return t.getComponentTypeMap() # Set/SetOf
+ # or no asn1Specs
+ def _getPositionByType(self, t, c, idx):
+ if t.getComponentType() is not None:
+ if t.getComponentType() and hasattr(t, 'getComponentPositionByType'):
+ effectiveTagSet = getattr(
+ c, 'getEffectiveTagSet', c.getTagSet
+ )()
+ return t.getComponentPositionByType(effectiveTagSet) # Set
+ return idx # SetOf or w/o asn1Specs
+
+class ChoiceDecoder(AbstractDecoder):
+ protoComponent = univ.Choice
+ def valueDecoder(self, substrate, asn1Spec, tagSet,
+ length, state, decodeFun):
+ r = self._createComponent(tagSet, asn1Spec)
+ if not decodeFun:
+ return r, substrate
+ component, substrate = decodeFun(
+ substrate, r.getComponentTypeMap(), tagSet, length, state
+ )
+ effectiveTagSet = getattr(
+ component, 'getEffectiveTagSet', component.getTagSet
+ )()
+ r.setComponentByType(effectiveTagSet, component)
+ return r, substrate
+
+ indefLenValueDecoder = valueDecoder
+
+# 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
+
+codecMap = {
+ 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.Sequence.tagSet: SequenceDecoder(),
+ univ.Set.tagSet: SetDecoder(),
+ univ.Choice.tagSet: ChoiceDecoder(),
+ # 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()
+ }
+
+( stDecodeTag, stDecodeLength, stGetValueDecoder, stGetValueDecoderByAsn1Spec,
+ stGetValueDecoderByTag, stTryAsExplicitTag, stDecodeValue, stStop ) = range(8)
+
+class Decoder:
+ def __init__(self, codecMap):
+ self.__codecMap = codecMap
+ def __call__(self, substrate, asn1Spec=None, tagSet=None,
+ length=None, state=stDecodeTag, recursiveFlag=1):
+ # Decode tag & length
+ while state != stStop:
+ if state == stDecodeTag:
+ # Decode tag
+ lenOfStream = len(substrate)
+ if lenOfStream < 2:
+ raise error.SubstrateUnderrunError(
+ 'Short octet stream (%d octets)' % lenOfStream
+ )
+ t = ord(substrate[0])
+ lastTag = tag.Tag(
+ tagClass=(t&0xC0),
+ tagFormat=(t&0x20),
+ tagId=t&0x1F
+ )
+ if tagSet is None:
+ tagSet = tag.TagSet((), lastTag) # base tag is not recovered
+ else:
+ tagSet = lastTag + tagSet
+ substrate = substrate[1:]
+ state = stDecodeLength
+ if state == stDecodeLength:
+ # Decode length (we know there's at least 2 bytes from above)
+ firstOctet = ord(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) | ord(char)
+ size = size + 1
+ state = stGetValueDecoder
+ substrate = substrate[size:]
+ if length != -1 and len(substrate) < length:
+ raise error.SubstrateUnderrunError(
+ '%d-octet short' % (length - len(substrate))
+ )
+ 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 wire.
+ #
+ if state == stGetValueDecoderByTag:
+ concreteDecoder = self.__codecMap.get(tagSet)
+ if concreteDecoder:
+ state = stDecodeValue
+ else:
+ concreteDecoder = self.__codecMap.get(tagSet[:1])
+ if concreteDecoder:
+ state = stDecodeValue
+ else:
+ state = stTryAsExplicitTag
+ if state == stGetValueDecoderByAsn1Spec:
+ if tagSet == eoo.endOfOctets.getTagSet():
+ concreteDecoder = self.__codecMap[tagSet]
+ state = stDecodeValue
+ continue
+ if type(asn1Spec) == types.DictType:
+ __chosenSpec = asn1Spec.get(tagSet)
+ elif asn1Spec is not None:
+ __chosenSpec = asn1Spec
+ else:
+ __chosenSpec = None
+ if __chosenSpec is None or not\
+ __chosenSpec.getTypeMap().has_key(tagSet):
+ state = stTryAsExplicitTag
+ else:
+ # use base type for codec lookup to recover untagged types
+ baseTag = __chosenSpec.getTagSet().getBaseTag()
+ if baseTag: # XXX ugly
+ baseTagSet = tag.TagSet(baseTag, baseTag)
+ else:
+ baseTagSet = tag.TagSet()
+ concreteDecoder = self.__codecMap.get( # tagged subtype
+ baseTagSet
+ )
+ if concreteDecoder:
+ asn1Spec = __chosenSpec
+ state = stDecodeValue
+ else:
+ state = stTryAsExplicitTag
+ if state == stTryAsExplicitTag:
+ if lastTag[1] == tag.tagFormatConstructed and \
+ lastTag[0] != tag.tagClassUniversal:
+ # Assume explicit tagging
+ state = stDecodeTag
+ else:
+ raise error.PyAsn1Error(
+ '%s not in asn1Spec: %s' % (tagSet, asn1Spec)
+ )
+ if state == stDecodeValue:
+ if recursiveFlag:
+ decodeFun = self
+ else:
+ decodeFun = None
+ if length == -1: # indef length
+ value, substrate = concreteDecoder.indefLenValueDecoder(
+ substrate, asn1Spec, tagSet, length,
+ stGetValueDecoder, decodeFun
+ )
+ else:
+ value, _substrate = concreteDecoder.valueDecoder(
+ substrate[:length], asn1Spec, tagSet,
+ length, stGetValueDecoder, decodeFun
+ )
+ if recursiveFlag:
+ substrate = substrate[length:]
+ else:
+ substrate = _substrate
+ state = stStop
+ return value, substrate
+
+decode = Decoder(codecMap)
+
+# XXX
+# non-recursive decoding; return position rather than substrate
diff --git a/pyasn1/codec/ber/encoder.py b/pyasn1/codec/ber/encoder.py
new file mode 100644
index 0000000..f1130f9
--- /dev/null
+++ b/pyasn1/codec/ber/encoder.py
@@ -0,0 +1,251 @@
+# BER encoder
+import string
+from pyasn1.type import tag, univ, char, useful
+from pyasn1.codec.ber import eoo
+from pyasn1 import error
+
+class Error(Exception): pass
+
+class AbstractItemEncoder:
+ supportIndefLenMode = 1
+ def _encodeTag(self, t, isConstructed):
+ if isConstructed:
+ return chr(t[0]|t[1]|t[2]|tag.tagFormatConstructed)
+ else:
+ return chr(t[0]|t[1]|t[2])
+
+ def _encodeLength(self, length, defMode):
+ if not defMode and self.supportIndefLenMode:
+ return chr(0x80)
+ if length < 0x80:
+ return chr(length)
+ elif length < 0xFF:
+ return '\x81%c' % length
+ elif length < 0xFFFF:
+ return '\x82%c%c' % (
+ (length >> 8) & 0xFF, length & 0xFF
+ )
+ elif length < 0xFFFFFF:
+ return '\x83%c%c%c' % (
+ (length >> 16) & 0xFF,
+ (length >> 8) & 0xFF,
+ length & 0xFF
+ )
+ #...more octets may be added
+ else:
+ raise Error(
+ 'Too large length (%d)' % length
+ )
+
+ def _encodeValue(self, encodeFun, value, defMode, maxChunkSize):
+ raise Error('Not implemented')
+
+ def _encodeEndOfOctets(self, encodeFun, defMode):
+ if defMode or not self.supportIndefLenMode:
+ return ''
+ 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 '', 0
+
+class ExplicitlyTaggedItemEncoder(AbstractItemEncoder):
+ def _encodeValue(self, encodeFun, value, defMode, maxChunkSize):
+ return encodeFun(value.clone(tagSet=value.getTagSet()[:-1]),
+ defMode, maxChunkSize), 1
+
+explicitlyTaggedItemEncoder = ExplicitlyTaggedItemEncoder()
+
+class IntegerEncoder(AbstractItemEncoder):
+ supportIndefLenMode = 0
+ def _encodeValue(self, encodeFun, value, defMode, maxChunkSize):
+ substrate = ''
+ value = long(value) # to save on ops on asn1 type
+ # The 0 and -1 values need to be handled separately since
+ # they are the terminating cases of the positive and negative
+ # cases repectively.
+ if value == 0:
+ substrate = '\000'
+ elif value == -1:
+ substrate = '\377'
+ elif value < 0:
+ while value <> -1:
+ substrate = chr(value & 0xff) + substrate
+ value = value >> 8
+ if ord(substrate[0]) & 0x80 == 0:
+ substrate = chr(0xff) + substrate
+ else:
+ while value > 0:
+ substrate = chr(value & 0xff) + substrate
+ value = value >> 8
+ if ord(substrate[0]) & 0x80 <> 0:
+ substrate = chr(0x00) + substrate
+ return substrate, 0
+
+class BitStringEncoder(AbstractItemEncoder):
+ def _encodeValue(self, encodeFun, value, defMode, maxChunkSize):
+ maxChunkSize = maxChunkSize*8L # count in octets
+ if len(value) <= maxChunkSize:
+ r = {}; l = len(value); p = j = 0
+ while p < l:
+ i, j = divmod(p, 8)
+ r[i] = r.get(i,0) | value[p]<<(7-j)
+ p = p + 1
+ keys = r.keys(); keys.sort()
+ return chr(7-j) + string.join(
+ map(lambda k,r=r: chr(r[k]), keys),''
+ ), 0
+ else:
+ pos = 0; substrate = ''
+ while 1:
+ v = value.clone(value=value[pos:pos+maxChunkSize])
+ 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 len(value) <= maxChunkSize:
+ return str(value), 0
+ else:
+ pos = 0; substrate = ''
+ while 1:
+ v = value.clone(value=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 '', 0
+
+class ObjectIdentifierEncoder(AbstractItemEncoder):
+ supportIndefLenMode = 0
+ def _encodeValue(self, encodeFun, value, defMode, maxChunkSize):
+ oid = tuple(value)
+ if len(oid) < 2:
+ raise error.PyAsn1Error('Short OID %s' % value)
+
+ # Build the first twos
+ index = 0
+ subid = oid[index] * 40
+ subid = subid + oid[index+1]
+ if 0 > subid > 0xff:
+ raise error.PyAsn1Error(
+ 'Initial sub-ID overflow %s in OID %s' % (oid[index:], value)
+ )
+ octets = [ chr(subid) ]
+ index = index + 2
+
+ # Cycle through subids
+ for subid in oid[index:]:
+ if subid > -1 and subid < 128:
+ # Optimize for the common case
+ octets.append(chr(subid & 0x7f))
+ elif subid < 0 or subid > 0xFFFFFFFFL:
+ raise error.PyAsn1Error(
+ 'SubId overflow %s in %s' % (subid, value)
+ )
+ else:
+ # Pack large Sub-Object IDs
+ res = [ chr(subid & 0x7f) ]
+ subid = subid >> 7
+ while subid > 0:
+ res.insert(0, chr(0x80 | (subid & 0x7f)))
+ subid = subid >> 7
+ # Convert packed Sub-Object ID to string and add packed
+ # it to resulted Object ID
+ octets.append(string.join(res, ''))
+ return string.join(octets, ''), 0
+
+class SequenceOfEncoder(AbstractItemEncoder):
+ def _encodeValue(self, encodeFun, value, defMode, maxChunkSize):
+ if hasattr(value, 'setDefaultComponents'):
+ value.setDefaultComponents()
+ value.verifySizeSpec()
+ substrate = ''; idx = len(value)
+ while idx > 0:
+ idx = idx - 1
+ if value[idx] is None: # Optional component
+ continue
+ if hasattr(value, 'getDefaultComponentByPosition'):
+ if value.getDefaultComponentByPosition(idx) == value[idx]:
+ continue
+ substrate = encodeFun(
+ value[idx], defMode, maxChunkSize
+ ) + substrate
+ return substrate, 1
+
+codecMap = {
+ eoo.endOfOctets.tagSet: EndOfOctetsEncoder(),
+ univ.Boolean.tagSet: IntegerEncoder(),
+ univ.Integer.tagSet: IntegerEncoder(),
+ univ.BitString.tagSet: BitStringEncoder(),
+ univ.OctetString.tagSet: OctetStringEncoder(),
+ univ.Null.tagSet: NullEncoder(),
+ univ.ObjectIdentifier.tagSet: ObjectIdentifierEncoder(),
+ # Sequence & Set have same tags as SequenceOf & SetOf
+ univ.SequenceOf.tagSet: SequenceOfEncoder(),
+ univ.SetOf.tagSet: SequenceOfEncoder(),
+ univ.Choice.tagSet: SequenceOfEncoder(),
+ # 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()
+ }
+
+class Encoder:
+ def __init__(self, codecMap):
+ self.__codecMap = codecMap
+
+ def __call__(self, value, defMode=1, maxChunkSize=0xffffffffl):
+ tagSet = value.getTagSet()
+ if len(tagSet) > 1:
+ concreteEncoder = explicitlyTaggedItemEncoder
+ else:
+ concreteEncoder = self.__codecMap.get(tagSet)
+ if not concreteEncoder:
+ concreteEncoder = self.__codecMap.get(
+ tag.TagSet(tagSet.getBaseTag(), tagSet.getBaseTag()) # XXX
+ )
+ if concreteEncoder:
+ return concreteEncoder.encode(
+ self, value, defMode, maxChunkSize
+ )
+ else:
+ raise Error('No encoder for %s' % value)
+
+encode = Encoder(codecMap)
diff --git a/pyasn1/codec/ber/eoo.py b/pyasn1/codec/ber/eoo.py
new file mode 100644
index 0000000..b37bd7f
--- /dev/null
+++ b/pyasn1/codec/ber/eoo.py
@@ -0,0 +1,7 @@
+from pyasn1.type import base, tag
+
+class EndOfOctets(base.AbstractSimpleAsn1Item):
+ tagSet = tag.initTagSet(
+ tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x00)
+ )
+endOfOctets = EndOfOctets()
diff --git a/pyasn1/codec/cer/__init__.py b/pyasn1/codec/cer/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/pyasn1/codec/cer/__init__.py
diff --git a/pyasn1/codec/cer/decoder.py b/pyasn1/codec/cer/decoder.py
new file mode 100644
index 0000000..b26fdfb
--- /dev/null
+++ b/pyasn1/codec/cer/decoder.py
@@ -0,0 +1,28 @@
+# CER decoder
+from pyasn1.type import univ
+from pyasn1.codec.ber import decoder
+from pyasn1 import error
+
+class BooleanDecoder(decoder.AbstractDecoder):
+ protoComponent = univ.Boolean
+ def valueDecoder(self, substrate, asn1Spec, tagSet, length,
+ state, decodeFun):
+ if not substrate:
+ raise error.PyAsn1Error('Empty substrate')
+ byte = ord(substrate[0])
+ if byte == 0xff:
+ value = 1
+ elif byte == 0x00:
+ value = 0
+ return self._createComponent(
+ tagSet, asn1Spec
+ ).clone(value), substrate[1:]
+
+codecMap = decoder.codecMap.copy()
+codecMap.update({
+ univ.Boolean.tagSet: BooleanDecoder(),
+ })
+
+class Decoder(decoder.Decoder): pass
+
+decode = Decoder(codecMap)
diff --git a/pyasn1/codec/cer/encoder.py b/pyasn1/codec/cer/encoder.py
new file mode 100644
index 0000000..75eaa5c
--- /dev/null
+++ b/pyasn1/codec/cer/encoder.py
@@ -0,0 +1,86 @@
+# CER encoder
+import string
+from pyasn1.type import univ
+from pyasn1.codec.ber import encoder
+
+class BooleanEncoder(encoder.IntegerEncoder):
+ def _encodeValue(self, encodeFun, client, defMode, maxChunkSize):
+ if client == 0:
+ substrate = '\000'
+ else:
+ substrate = '\777'
+ 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 _cmpSetComponents(self, c1, c2):
+ return cmp(
+ getattr(c1, 'getMinimalTagSet', c1.getTagSet)(),
+ getattr(c2, 'getMinimalTagSet', c2.getTagSet)()
+ )
+
+ def _encodeValue(self, encodeFun, client, defMode, maxChunkSize):
+ if hasattr(client, 'setDefaultComponents'):
+ client.setDefaultComponents()
+ client.verifySizeSpec()
+ # Guess client type basing on number of component types.
+ # This is certainly a hack but how do I distinguish one from
+ # another if they have the same tags&constraints?
+ substrate = ''; idx = len(client)
+ if len(client) > 1:
+ # 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(self._cmpSetComponents)
+ for c in comps:
+ substrate = 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 = string.join(compSubs, '')
+ return substrate, 1
+
+codecMap = encoder.codecMap.copy()
+codecMap.update({
+ univ.Boolean.tagSet: BooleanEncoder(),
+ univ.BitString.tagSet: BitStringEncoder(),
+ univ.OctetString.tagSet: OctetStringEncoder(),
+ # Set & SetOf have same tags
+ univ.SetOf().tagSet: SetOfEncoder()
+ })
+
+class Encoder(encoder.Encoder):
+ def __call__(self, client, defMode=0, maxChunkSize=0xffffffffl):
+ return encoder.Encoder.__call__(self, client, defMode, maxChunkSize)
+
+encode = Encoder(codecMap)
+
+# EncoderFactory queries class instance and builds a map of tags -> encoders
diff --git a/pyasn1/codec/der/__init__.py b/pyasn1/codec/der/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/pyasn1/codec/der/__init__.py
diff --git a/pyasn1/codec/der/decoder.py b/pyasn1/codec/der/decoder.py
new file mode 100644
index 0000000..9e3d7cd
--- /dev/null
+++ b/pyasn1/codec/der/decoder.py
@@ -0,0 +1,5 @@
+# DER decoder
+from pyasn1.type import univ
+from pyasn1.codec.cer import decoder
+
+decode = decoder.Decoder(decoder.codecMap)
diff --git a/pyasn1/codec/der/encoder.py b/pyasn1/codec/der/encoder.py
new file mode 100644
index 0000000..0289008
--- /dev/null
+++ b/pyasn1/codec/der/encoder.py
@@ -0,0 +1,25 @@
+# DER encoder
+from pyasn1.type import univ
+from pyasn1.codec.cer import encoder
+
+class SetOfEncoder(encoder.SetOfEncoder):
+ def _cmpSetComponents(self, c1, c2):
+ return cmp(
+ getattr(c1, 'getEffectiveTagSet', c1.getTagSet)(),
+ getattr(c2, 'getEffectiveTagSet', c2.getTagSet)()
+ )
+
+codecMap = encoder.codecMap.copy()
+codecMap.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()
+ })
+
+class Encoder(encoder.Encoder):
+ def __call__(self, client, defMode=1, maxChunkSize=0xffffffffl):
+ return encoder.Encoder.__call__(self, client, defMode, maxChunkSize)
+
+encode = Encoder(codecMap)
diff --git a/pyasn1/error.py b/pyasn1/error.py
new file mode 100644
index 0000000..91c7478
--- /dev/null
+++ b/pyasn1/error.py
@@ -0,0 +1,3 @@
+class PyAsn1Error(StandardError): pass
+class ValueConstraintError(PyAsn1Error): pass
+class SubstrateUnderrunError(PyAsn1Error): pass
diff --git a/pyasn1/type/__init__.py b/pyasn1/type/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/pyasn1/type/__init__.py
diff --git a/pyasn1/type/base.py b/pyasn1/type/base.py
new file mode 100644
index 0000000..da5790e
--- /dev/null
+++ b/pyasn1/type/base.py
@@ -0,0 +1,210 @@
+# Base classes for ASN.1 types
+try:
+ from sys import version_info
+except ImportError:
+ version_info = (0, 0) # a really early version
+from operator import getslice, setslice, delslice
+from string import join
+from types import SliceType
+from pyasn1.type import constraint
+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()
+
+ 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):
+ self._subtypeSpec(value, idx)
+
+ def getSubtypeSpec(self): return self._subtypeSpec
+
+ def getTagSet(self): return self._tagSet
+ def getTypeMap(self): return { 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())
+
+# Base class for "simple" ASN.1 objects. These are immutable.
+class AbstractSimpleAsn1Item(Asn1ItemBase):
+ defaultValue = None
+ def __init__(self, value=None, tagSet=None, subtypeSpec=None):
+ Asn1ItemBase.__init__(self, tagSet, subtypeSpec)
+ if value is None:
+ self._value = self.defaultValue
+ else:
+ value = self._prettyIn(value)
+ self._verifySubtypeSpec(value)
+ self._value = value
+ self.__hashedValue = hash(
+ (self._value, self._tagSet, self._subtypeSpec)
+ )
+
+ def __repr__(self):
+ return self.__class__.__name__ + '(' + repr(
+ self._prettyOut(self._value)
+ ) +')'
+ def __str__(self): return str(self._value)
+ def __cmp__(self, value): return cmp(self._value, value)
+ def __hash__(self): return self.__hashedValue
+
+ def __nonzero__(self): return bool(self._value)
+
+ 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 and self._value is not self.defaultValue:
+ 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 and self._value is not self.defaultValue:
+ 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 value
+
+ def prettyPrinter(self, scope=0): return self._prettyOut(self._value)
+
+#
+# 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 = []
+
+ def __repr__(self):
+ r = self.__class__.__name__ + '()'
+ for idx in range(len(self)):
+ if self._componentValues[idx] is None:
+ continue
+ r = r + '.setComponentByPosition(%s, %s)' % (
+ idx, repr(self._componentValues[idx])
+ )
+ return r
+
+ def __cmp__(self, other): return cmp(self._componentValues, other)
+
+ def getComponentTypeMap(self):
+ raise error.PyAsn1Error('Method not implemented')
+
+ def clone(self, componentType=None, tagSet=None, subtypeSpec=None,
+ sizeSpec=None):
+ if componentType is None:
+ componentType = self._componentType
+ if tagSet is None:
+ tagSet = self._tagSet
+ if subtypeSpec is None:
+ subtypeSpec = self._subtypeSpec
+ if sizeSpec is None:
+ sizeSpec = self._sizeSpec
+ r = self.__class__(componentType, tagSet, subtypeSpec, sizeSpec)
+ if componentType is self._componentType and \
+ self.getComponentType() is not None:
+ self._cloneComponentValues(r) # XXX when do we clone inner vals?
+ return r
+
+ def subtype(self, componentType=None, implicitTag=None, explicitTag=None,
+ subtypeSpec=None, sizeSpec=None):
+ if componentType is None:
+ componentType = self._componentType
+ 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__(componentType, tagSet, subtypeSpec, sizeSpec)
+ if componentType is self._componentType and \
+ self.getComponentType() is not None:
+ self._cloneComponentValues(r) # XXX when do we clone inner vals?
+ 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):
+ raise error.PyAsn1Error('Method not implemented')
+
+ def getComponentType(self): return self._componentType
+
+ def __getitem__(self, idx): return self._componentValues[idx]
+
+ def __len__(self): return len(self._componentValues)
+
+ def clear(self): self._componentValues = []
diff --git a/pyasn1/type/char.py b/pyasn1/type/char.py
new file mode 100644
index 0000000..25cd142
--- /dev/null
+++ b/pyasn1/type/char.py
@@ -0,0 +1,57 @@
+# 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)
+ )
+
+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)
+ )
+
+class BMPString(univ.OctetString):
+ tagSet = univ.OctetString.tagSet.tagImplicitly(
+ tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 30)
+ )
diff --git a/pyasn1/type/constraint.py b/pyasn1/type/constraint.py
new file mode 100644
index 0000000..c6bd135
--- /dev/null
+++ b/pyasn1/type/constraint.py
@@ -0,0 +1,185 @@
+"""
+ 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 types
+import string
+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._setValues(values)
+ self.__hashedValues = hash((self.__class__, self._values))
+ def __call__(self, value, idx=None):
+ try:
+ self._testValue(value, idx)
+ except error.ValueConstraintError, why:
+ raise error.ValueConstraintError('%s failed at: %s' % (
+ self, why
+ ))
+ def __repr__(self):
+ return '%s(%s)' % (
+ self.__class__.__name__,
+ string.join(map(lambda x: str(x), self._values), ', ')
+ )
+# def __cmp__(self, other):
+# return cmp((self.__class__, self._values), other)
+ def __eq__(self, other):
+ return self is other or self.__hashedValues == other
+ def __hash__(self): return self.__hashedValues
+ def _setValues(self, values): self._values = values
+ def _testValue(self, value, idx):
+ raise error.ValueConstraintError(value)
+
+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): pass
+
+# 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 not self.__multipleTypeConstraint.has_key(idx):
+ 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 type(v) == types.TupleType:
+ 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 apply(self.__class__, (value,) + self._values)
+ def __radd__(self, value):
+ return apply(self.__class__, self._values + (value,))
+
+ def __len__(self): return len(self._values)
+
+class ConstraintsIntersection(AbstractConstraintSet):
+ """Value must satisfy all constraints"""
+ def _testValue(self, value, idx):
+ for v in self._values:
+ v(value, idx)
+
+ # Constraints inclusion in sets
+
+ def _setValues(self, values):
+ self._values = values
+ self.__valuesMap = {}
+ for v in values: self.__valuesMap[v] = 1
+
+ def hasConstraint(self, constraint):
+ if self.__valuesMap.has_key(constraint):
+ return 1
+ else:
+ return 0
+
+ def isSuperTypeOf(self, constraintSet):
+ if self is constraintSet:
+ return 1
+ for c in self._values:
+ if not constraintSet.hasConstraint(c): # super type must have all
+ return 0 # its component constraints
+ return 1 # included by subtype
+
+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
diff --git a/pyasn1/type/error.py b/pyasn1/type/error.py
new file mode 100644
index 0000000..3e68484
--- /dev/null
+++ b/pyasn1/type/error.py
@@ -0,0 +1,3 @@
+from pyasn1.error import PyAsn1Error
+
+class ValueConstraintError(PyAsn1Error): pass
diff --git a/pyasn1/type/namedtype.py b/pyasn1/type/namedtype.py
new file mode 100644
index 0000000..4d86707
--- /dev/null
+++ b/pyasn1/type/namedtype.py
@@ -0,0 +1,130 @@
+# NamedType specification for constructed types
+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__, repr(self.__name), repr(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.__minTagSet = None
+ self.__typeMap = {}; self.__tagMap = {}; self.__nameMap = {}
+ self.__ambigiousTypes = {}
+
+ def __repr__(self):
+ r = '%s(' % self.__class__.__name__
+ for n in self.__namedTypes:
+ r = r + '%s, ' % repr(n)
+ return r + ')'
+
+ def __getitem__(self, idx): return self.__namedTypes[idx]
+
+ def __nonzero__(self): return bool(self.__namedTypes)
+ def __len__(self): return len(self.__namedTypes)
+
+ def getTypeByPosition(self, idx):
+ try:
+ return self.__namedTypes[idx].getType()
+ except IndexError:
+ raise error.PyAsn1Error('Type position out of range')
+ def getPositionByType(self, tagSet):
+ if not self.__tagMap:
+ idx = len(self.__namedTypes)
+ while idx > 0:
+ idx = idx - 1
+ for t in self.__namedTypes[idx].getType().getTypeMap().keys():
+ if self.__tagMap.has_key(t):
+ raise error.PyAsn1Error('Duplicate type %s' % t)
+ self.__tagMap[t] = idx
+ try:
+ return self.__tagMap[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.__nameMap:
+ idx = len(self.__namedTypes)
+ while idx > 0:
+ idx = idx - 1
+ n = self.__namedTypes[idx].getName()
+ if self.__nameMap.has_key(n):
+ raise error.PyAsn1Error('Duplicate name %s' % n)
+ self.__nameMap[n] = idx
+ try:
+ return self.__nameMap[name]
+ except KeyError:
+ raise error.PyAsn1Error('Name %s not found' % name)
+
+ def __buildAmbigiousTagMap(self):
+ ambigiousTypes = ()
+ idx = len(self.__namedTypes)
+ 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] = apply(NamedTypes, ambigiousTypes)
+
+ def getTypeMapNearPosition(self, idx):
+ if not self.__ambigiousTypes: self.__buildAmbigiousTagMap()
+ try:
+ return self.__ambigiousTypes[idx].getTypeMap()
+ 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 getTypeMap(self, uniq=None):
+ if not self.__typeMap:
+ for t in self.__namedTypes:
+ __type = t.getType()
+ typeMap = __type.getTypeMap()
+ if uniq:
+ for k in typeMap.keys():
+ if self.__typeMap.has_key(k):
+ raise error.PyAsn1Error(
+ 'Duplicate type %s in map %s'%(k,self.__typeMap)
+ )
+ self.__typeMap[k] = __type
+ else:
+ for k in typeMap.keys():
+ self.__typeMap[k] = __type
+ return self.__typeMap
diff --git a/pyasn1/type/namedval.py b/pyasn1/type/namedval.py
new file mode 100644
index 0000000..6cc14e6
--- /dev/null
+++ b/pyasn1/type/namedval.py
@@ -0,0 +1,42 @@
+# ASN.1 named integers
+from types import TupleType
+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 type(namedValue) == TupleType:
+ name, val = namedValue
+ else:
+ name = namedValue
+ val = automaticVal
+ if self.nameToValIdx.has_key(name):
+ raise error.PyAsn1Error('Duplicate name %s' % name)
+ self.nameToValIdx[name] = val
+ if self.valToNameIdx.has_key(val):
+ raise error.PyAsn1Error('Duplicate value %s' % name)
+ self.valToNameIdx[val] = name
+ self.namedValues = self.namedValues + ((name, val),)
+ automaticVal = automaticVal + 1
+ def __str__(self): return str(self.namedValues)
+
+ def getName(self, value): return self.valToNameIdx.get(value)
+ def getValue(self, name): return self.nameToValIdx.get(name)
+
+ def __getitem__(self, i): return self.namedValues[i]
+ def __len__(self): return len(self.namedValues)
+
+ def __add__(self, namedValues):
+ return apply(self.__class__, self.namedValues + namedValues)
+ def __radd__(self, namedValues):
+ return apply(self.__class__, namedValues + tuple(self))
+
+ def clone(self, *namedValues):
+ return apply(self.__class__, tuple(self) + namedValues)
+
+# XXX clone/subtype?
diff --git a/pyasn1/type/tag.py b/pyasn1/type/tag.py
new file mode 100644
index 0000000..764fed2
--- /dev/null
+++ b/pyasn1/type/tag.py
@@ -0,0 +1,109 @@
+# ASN.1 types tags
+try:
+ from sys import version_info
+except ImportError:
+ version_info = (0, 0) # a really early version
+from operator import getslice
+from types import SliceType
+from string import join
+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):
+ self.__tag = (tagClass, tagFormat, tagId)
+ self.__uniqTag = (tagClass, tagId)
+ self.__hashedUniqTag = hash(self.__uniqTag)
+ def __repr__(self):
+ return '%s(tagClass=%s, tagFormat=%s, tagId=%s)' % (
+ (self.__class__.__name__,) + self.__tag
+ )
+ def __cmp__(self, other): return cmp(self.__uniqTag, other)
+ def __eq__(self, other):
+ return self is other or self.__hashedUniqTag == other
+ def __hash__(self): return self.__hashedUniqTag
+ def __getitem__(self, idx): return self.__tag[idx]
+ def __and__(self, (tagClass, tagFormat, tagId)):
+ return self.__class__(
+ self.__tag&tagClass, self.__tag&tagFormat, self.__tag&tagId
+ )
+ def __or__(self, (tagClass, tagFormat, tagId)):
+ return self.__class__(
+ self.__tag[0]|tagClass, self.__tag[1]|tagFormat, self.__tag[2]|tagId
+ )
+
+class TagSet:
+ def __init__(self, baseTag=(), *superTags):
+ self.__baseTag = baseTag
+ self.__superTags = superTags
+ self.__hashedSuperTags = hash(superTags)
+ def __repr__(self):
+ return '%s(%s)' % (
+ self.__class__.__name__,
+ join(map(lambda x: repr(x), self.__superTags), ', ')
+ )
+
+ def __add__(self, superTag):
+ return apply(
+ self.__class__, (self.__baseTag,) + self.__superTags + (superTag,)
+ )
+ def __radd__(self, superTag):
+ return apply(
+ self.__class__, (self.__baseTag, superTag) + self.__superTags
+ )
+
+ def tagExplicitly(self, superTag):
+ tagClass, tagFormat, tagId = superTag
+ if tagClass == tagClassUniversal:
+ raise error.BadArgumentError(
+ '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 type(idx) == SliceType:
+ return apply(self.__class__,
+ (self.__baseTag,) + getslice(self.__superTags,
+ idx.start, idx.stop))
+ return self.__superTags[idx]
+ if version_info < (2, 0):
+ def __getslice__(self, i, j):
+ return self[max(0, i):max(0, j):]
+ def __cmp__(self, other): return cmp(self.__superTags, other)
+ def __eq__(self, other):
+ return self is other or self.__hashedSuperTags == other
+ def __hash__(self): return self.__hashedSuperTags
+ def __len__(self): return len(self.__superTags)
+ def isSuperTagSetOf(self, tagSet):
+ # XXX optimization?
+ l = len(self.__superTags)
+ if len(tagSet) < l:
+ return
+ idx = 0
+ while idx < l:
+ if self.__superTags[idx] != tagSet[idx]:
+ return
+ idx = idx + 1
+ return 1
+
+def initTagSet(tag): return TagSet(tag, tag)
diff --git a/pyasn1/type/univ.py b/pyasn1/type/univ.py
new file mode 100644
index 0000000..0142b38
--- /dev/null
+++ b/pyasn1/type/univ.py
@@ -0,0 +1,616 @@
+# ASN.1 "universal" data types
+import string
+import types
+import operator
+from pyasn1.type import base, tag, constraint, namedtype, namedval
+from pyasn1 import error
+
+# "Simple" ASN.1 types (yet incomplete)
+
+class Integer(base.AbstractSimpleAsn1Item):
+ tagSet = tag.initTagSet(
+ tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x02)
+ )
+ namedValues = namedval.NamedValues()
+ defaultValue = 0
+ def __init__(self, value=None, tagSet=None, subtypeSpec=None,
+ namedValues=None):
+ if namedValues is None:
+ self.__namedValues = self.namedValues
+ else:
+ self.__namedValues = namedValues
+ base.AbstractSimpleAsn1Item.__init__(
+ self, value, tagSet, subtypeSpec
+ )
+
+# def __getattr__(self, attr):
+# print 33, attr
+# return base.AbstractSimpleAsn1Item.__getattr__(self, attr)
+
+#XXX def __coerce__(self, other): return long(self), long(other)
+ def __and__(self, value): return self.clone(self._value & value)
+ def __rand__(self, value): return self.clone(value & self._value)
+ def __or__(self, value): return self.clone(self._value | value)
+ def __ror__(self, value): return self.clone(value | self._value)
+ def __xor__(self, value): return self.clone(self._value ^ value)
+ def __rxor__(self, value): return self.clone(value ^ self._value)
+ def __add__(self, value): return self.clone(self._value + value)
+ def __radd__(self, value): return self.clone(value + self._value)
+ def __sub__(self, value): return self.clone(self._value - value)
+ def __rsub__(self, value): return self.clone(value - self._value)
+ def __mul__(self, value): return self.clone(self._value * value)
+ def __rmul__(self, value): return self.clone(value * self._value)
+ def __div__(self, value): return self.clone(self._value / value)
+ def __rdiv__(self, value): return self.clone(value / self._value)
+ def __mod__(self, value): return self.clone(self._value % value)
+ def __rmod__(self, value): return self.clone(value % self._value)
+ def __pow__(self, value, modulo=None):
+ return self.clone(pow(self._value, value, modulo))
+ def __rpow__(self, value, modulo=None):
+ return self.clone(pow(value, self._value, modulo))
+ def __lshift__(self, value): return self.clone(self._value << value)
+ def __rshift__(self, value): return self.clone(self._value >> value)
+ def __int__(self): return int(self._value)
+ def __long__(self): return long(self._value)
+ def __float__(self): return float(self._value)
+ def __abs__(self): return abs(self._value)
+
+ def _prettyIn(self, value):
+ if type(value) != types.StringType:
+ return long(value)
+ r = self.__namedValues.getValue(value)
+ if r is not None:
+ return r
+ try:
+ return string.atoi(value)
+ except:
+ try:
+ return string.atol(value)
+ except:
+ raise error.PyAsn1Error(
+ 'Can\'t coerce %s into integer' % value
+ )
+
+ def _prettyOut(self, value):
+ r = self.__namedValues.getName(value)
+ if r is not None:
+ return '%s(%s)' % (r, value)
+ else:
+ return value
+
+ def getNamedValues(self): return self.__namedValues
+
+ def clone(self, value=None, tagSet=None, subtypeSpec=None,
+ namedValues=None):
+ if value is None and self._value is not self.defaultValue:
+ value = self._value
+ if tagSet is None:
+ tagSet = self._tagSet
+ if subtypeSpec is None:
+ subtypeSpec = self._subtypeSpec
+ if namedValues is None:
+ namedValues = self.__namedValues
+ return self.__class__(value, tagSet, subtypeSpec, namedValues)
+
+ def subtype(self, value=None, implicitTag=None, explicitTag=None,
+ subtypeSpec=None, namedValues=None):
+ if value is None and self._value is not self.defaultValue:
+ 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
+ if namedValues is None:
+ namedValues = self.__namedValues
+ else:
+ namedValues = namedValues + self.__namedValues
+ return self.__class__(value, tagSet, subtypeSpec, namedValues)
+
+class Boolean(Integer):
+ tagSet = tag.initTagSet(
+ tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x01),
+ )
+ subtypeSpec = Integer.subtypeSpec+constraint.SingleValueConstraint(0,1)
+ namedValues = Integer.namedValues.clone(('False', 0), ('True', 1))
+ defaultValue = 0
+
+class BitString(base.AbstractSimpleAsn1Item):
+ tagSet = tag.initTagSet(
+ tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x03)
+ )
+ namedValues = namedval.NamedValues()
+ defaultValue = ()
+ def __init__(self, value=None, tagSet=None, subtypeSpec=None,
+ namedValues=None):
+ if namedValues is None:
+ self.__namedValues = self.namedValues
+ else:
+ self.__namedValues = namedValues
+ base.AbstractSimpleAsn1Item.__init__(
+ self, value, tagSet, subtypeSpec
+ )
+
+ def clone(self, value=None, tagSet=None, subtypeSpec=None,
+ namedValues=None):
+ if value is None: value = self._value
+ if tagSet is None: tagSet = self._tagSet
+ if subtypeSpec is None: subtypeSpec = self._subtypeSpec
+ if namedValues is None: namedValues = self.__namedValues
+ return self.__class__(value, tagSet, subtypeSpec, namedValues)
+
+ def subtype(self, value=None, implicitTag=None, explicitTag=None,
+ subtypeSpec=None, namedValues=None):
+ if value is None and self._value is not self.defaultValue:
+ 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
+ if namedValues is None:
+ namedValues = self.__namedValues
+ else:
+ namedValues = namedValues + self.__namedValues
+ return self.__class__(value, tagSet, subtypeSpec, namedValues)
+
+ def __str__(self): return str(tuple(self))
+
+ # Immutable sequence object protocol
+
+ def __len__(self): return len(self._value)
+ def __getitem__(self, i):
+ if type(i) == types.SliceType:
+ return self.clone(operator.getslice(self._value, i.start, i.stop))
+ else:
+ return self._value[i]
+ def __add__(self, value): return self.clone(self._value + value)
+ def __radd__(self, value): return self.clone(value + self._value)
+ def __mul__(self, value): return self.clone(self._value * value)
+ def __rmul__(self, value): return self.__mul__(value)
+
+ # They won't be defined if version is at least 2.0 final
+ if base.version_info < (2, 0):
+ def __getslice__(self, i, j):
+ return self[max(0, i):max(0, j):]
+
+ def _prettyIn(self, value):
+ r = []
+ if not value:
+ return ()
+ elif type(value) != types.StringType:
+ return value
+ elif value[0] == '\'':
+ if value[-2:] == '\'B':
+ for v in value[1:-2]:
+ r.append(int(v))
+ elif value[-2:] == '\'H':
+ for v in value[1:-2]:
+ i = 4
+ v = string.atoi(v, 16)
+ while i:
+ i = i - 1
+ r.append((v>>i)&0x01)
+ else:
+ raise error.PyAsn1Error(
+ 'Bad bitstring value notation %s' % value
+ )
+ else:
+ for i in string.split(value, ','):
+ i = self.__namedValues.getValue(i)
+ if i is None:
+ raise error.PyAsn1Error(
+ 'Unknown identifier \'%s\'' % i
+ )
+ if i >= len(r):
+ r.extend([0]*(i-len(r)+1))
+ r[i] = 1
+ return tuple(r)
+
+ def _prettyOut(self, value):
+ return '\'%s\'B' % string.join(map(str, value), '')
+
+class OctetString(base.AbstractSimpleAsn1Item):
+ tagSet = tag.initTagSet(
+ tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x04)
+ )
+ defaultValue = ''
+
+ def _prettyIn(self, value): return str(value)
+ def _prettyOut(self, value): return repr(value)
+
+ # Immutable sequence object protocol
+
+ def __len__(self): return len(self._value)
+ def __getitem__(self, i):
+ if type(i) == types.SliceType:
+ return self.clone(operator.getslice(self._value, i.start, i.stop))
+ else:
+ return self._value[i]
+ def __add__(self, value): return self.clone(self._value + value)
+ def __radd__(self, value):
+ print self.__class__
+ print repr(value), repr(self._value)
+ return self.clone(value + self._value)
+ def __mul__(self, value): return self.clone(self._value * value)
+ def __rmul__(self, value): return self.__mul__(value)
+
+ # They won't be defined if version is at least 2.0 final
+ if base.version_info < (2, 0):
+ def __getslice__(self, i, j):
+ return self[max(0, i):max(0, j):]
+
+class Null(OctetString):
+ tagSet = tag.initTagSet(
+ tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x05)
+ )
+ subtypeSpec = OctetString.subtypeSpec+constraint.SingleValueConstraint('')
+ defaultValue = ''
+
+class ObjectIdentifier(base.AbstractSimpleAsn1Item):
+ tagSet = tag.initTagSet(
+ tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x06)
+ )
+ defaultValue = ()
+
+ def __add__(self, other): return self.clone(self._value + other)
+ def __radd__(self, other): return self.clone(other + self._value)
+
+ # Sequence object protocol
+
+ def __len__(self): return len(self._value)
+ def __getitem__(self, i):
+ if type(i) == types.SliceType:
+ return self.clone(
+ operator.getslice(self._value, i.start, i.stop)
+ )
+ else:
+ return self._value[i]
+
+ # They won't be defined if version is at least 2.0 final
+ if base.version_info < (2, 0):
+ def __getslice__(self, i, j):
+ return self[max(0, i):max(0, j):]
+
+ def index(self, suboid): return self._value.index(suboid)
+
+ def isPrefixOf(self, value):
+ """Returns true if argument OID resides deeper in the OID tree"""
+ l = len(self._value)
+ if l <= len(value):
+ if self._value[:l] == value[:l]:
+ return 1
+ return 0
+
+ def _prettyIn(self, value):
+ """Dotted -> tuple of numerics OID converter"""
+ if type(value) is types.TupleType:
+ return value
+ if type(value) is not types.StringType:
+ return tuple(value)
+ r = []
+ for element in filter(None, string.split(value, '.')):
+ try:
+ r.append(string.atoi(element, 0))
+ except string.atoi_error:
+ try:
+ r.append(string.atol(element, 0))
+ except string.atol_error, why:
+ raise error.PyAsn1Error(
+ 'Malformed Object ID %s at %s: %s' %
+ (str(value), self.__class__.__name__, why)
+ )
+ return tuple(r)
+
+ def _prettyOut(self, value):
+ """Tuple of numerics -> dotted string OID converter"""
+ r = []
+ for subOid in value:
+ r.append(str(subOid))
+ if r[-1] and r[-1][-1] == 'L':
+ r[-1][-1] = r[-1][:-1]
+ return string.join(r, '.')
+
+class Real(base.AbstractSimpleAsn1Item):
+ tagSet = tag.initTagSet(
+ tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x09)
+ )
+ defaultValue = 0.0
+
+class Enumerated(base.AbstractSimpleAsn1Item):
+ tagSet = tag.initTagSet(
+ tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x10)
+ )
+ defaultValue = 0
+
+# "Structured" ASN.1 types
+
+class SetOf(base.AbstractConstructedAsn1Item):
+ componentType = None
+ tagSet = tag.initTagSet(
+ tag.Tag(tag.tagClassUniversal, tag.tagFormatConstructed, 0x11)
+ )
+
+ def _cloneComponentValues(self, myClone):
+ idx = 0; l = len(self._componentValues)
+ while idx < l:
+ if self._componentValues[idx] is not None:
+ myClone.setComponentByPosition(
+ idx, self._componentValues[idx].clone()
+ )
+ idx = idx + 1
+
+ def _verifyComponent(self, idx, value):
+ if self._componentType is not None and \
+ not self._componentType.isSuperTypeOf(value):
+ raise error.PyAsn1Error('Component type error %s' % value)
+
+ def getComponentByPosition(self, idx): return self._componentValues[idx]
+ def setComponentByPosition(self, idx, value=None):
+ l = len(self._componentValues)
+ if idx >= l:
+ self._componentValues = self._componentValues + (idx-l+1)*[None]
+ if value is None:
+ if self._componentValues[idx] is None:
+ if self._componentType is None:
+ raise error.PyAsn1Error('Component type not defined')
+ self._componentValues[idx] = self._componentType.clone()
+ return self
+ elif type(value) != types.InstanceType:
+ if self._componentType is None:
+ raise error.PyAsn1Error('Component type not defined')
+ if isinstance(self._componentType, base.AbstractSimpleAsn1Item):
+ value = self._componentType.clone(value=value)
+ else:
+ raise error.PyAsn1Error('Instance value required')
+ if self._componentType:
+ self._verifyComponent(idx, value)
+ self._verifySubtypeSpec(value, idx)
+ self._componentValues[idx] = value
+ return self
+
+ def getComponentTypeMap(self):
+ if self._componentType is not None:
+ return self._componentType.getTypeMap()
+
+ def prettyPrinter(self, scope=0):
+ scope = scope + 1
+ r = self.__class__.__name__ + ':\n'
+ for idx in range(len(self._componentValues)):
+ r = r + ' '*scope + self._componentValues[idx].prettyPrinter(scope)
+ return r
+
+class SequenceOf(SetOf):
+ tagSet = tag.initTagSet(
+ tag.Tag(tag.tagClassUniversal, tag.tagFormatConstructed, 0x10)
+ )
+
+class SequenceAndSetBase(base.AbstractConstructedAsn1Item):
+ componentType = namedtype.NamedTypes()
+ def _cloneComponentValues(self, myClone):
+ idx = 0; l = len(self._componentValues)
+ while idx < l:
+ if self._componentValues[idx] is not None:
+ myClone.setComponentByPosition(
+ idx, self._componentValues[idx].clone()
+ )
+ idx = idx + 1
+
+ def _verifyComponent(self, idx, value):
+ componentType = self._componentType
+ if componentType:
+ if idx >= len(componentType):
+ raise error.PyAsn1Error(
+ 'Component type error out of range'
+ )
+ t = componentType[idx].getType()
+ if not t.isSuperTypeOf(value):
+ raise error.PyAsn1Error('Component type error %s vs %s' %
+ (t.getTagSet(), value.getTagSet()))
+
+ def getComponentByName(self, name):
+ return self.getComponentByPosition(
+ self._componentType.getPositionByName(name)
+ )
+ def setComponentByName(self, name, value=None):
+ return self.setComponentByPosition(
+ self._componentType.getPositionByName(name), value
+ )
+
+ def getComponentByPosition(self, idx):
+ try:
+ return self._componentValues[idx]
+ except IndexError:
+ if idx < len(self._componentType):
+ return
+ raise
+ def setComponentByPosition(self, idx, value=None):
+ l = len(self._componentValues)
+ if idx >= l:
+ self._componentValues = self._componentValues + (idx-l+1)*[None]
+ if value is None:
+ if self._componentValues[idx] is None:
+ self._componentValues[idx] = self._componentType.getTypeByPosition(idx).clone()
+ return self
+ elif type(value) != types.InstanceType:
+ t = self._componentType.getTypeByPosition(idx)
+ if isinstance(t, base.AbstractSimpleAsn1Item):
+ value = t.clone(value=value)
+ else:
+ raise error.PyAsn1Error('Instance value required')
+ if self._componentType:
+ self._verifyComponent(idx, value)
+ self._verifySubtypeSpec(value, idx)
+ self._componentValues[idx] = value
+ return self
+
+ def getDefaultComponentByPosition(self, idx):
+ if self._componentType[idx].isDefaulted:
+ return self._componentType[idx].getType()
+
+ def getComponentType(self):
+ if self._componentType:
+ return self._componentType
+
+ def setDefaultComponents(self):
+ idx = len(self._componentType)
+ while idx:
+ idx = idx - 1
+ if self._componentType[idx].isDefaulted:
+ if self.getComponentByPosition(idx) is None:
+ self.setComponentByPosition(idx)
+ elif not self._componentType[idx].isOptional:
+ if self.getComponentByPosition(idx) is None:
+ raise error.PyAsn1Error(
+ 'Uninitialized component #%s at %s' % (idx, repr(self))
+ )
+
+ def prettyPrinter(self, scope=0):
+ scope = scope+1
+ r = self.__class__.__name__ + ':\n'
+ for idx in range(len(self._componentValues)):
+ if self._componentValues[idx] is not None:
+ r = r + ' '*scope
+ componentType = self.getComponentType()
+ if componentType is None:
+ r = r + '??'
+ else:
+ r = r + componentType.getNameByPosition(idx)
+ r = '%s=%s\n' % (
+ r, self._componentValues[idx].prettyPrinter(scope)
+ )
+ return r
+
+class Sequence(SequenceAndSetBase):
+ tagSet = tag.initTagSet(
+ tag.Tag(tag.tagClassUniversal, tag.tagFormatConstructed, 0x10)
+ )
+
+ def getComponentTypeMapNearPosition(self, idx):
+ return self._componentType.getTypeMapNearPosition(idx)
+
+ def getComponentPositionNearType(self, tagSet, idx):
+ return self._componentType.getPositionNearType(tagSet, idx)
+
+class Set(SequenceAndSetBase):
+ tagSet = tag.initTagSet(
+ tag.Tag(tag.tagClassUniversal, tag.tagFormatConstructed, 0x11)
+ )
+
+ def getComponentByType(self, tagSet, innerFlag=0):
+ c = self.getComponentByPosition(
+ self._componentType.getPositionByType(tagSet)
+ )
+ if innerFlag and hasattr(c, 'getComponent'):
+ # get inner component by inner tagSet
+ return c.getComponent(True)
+ else:
+ # get outer component by inner tagSet
+ return c
+
+ def setComponentByType(self, tagSet, value=None, innerFlag=0):
+ idx = self._componentType.getPositionByType(tagSet)
+ t = self._componentType.getTypeByPosition(idx)
+ if innerFlag: # set inner component by inner tagSet
+ if t.getTagSet():
+ self.setComponentByPosition(idx, value)
+ else:
+ t = self.setComponentByPosition(idx).getComponentByPosition(idx)
+ t.setComponentByType(tagSet, value, innerFlag)
+ else: # set outer component by inner tagSet
+ self.setComponentByPosition(idx, value)
+
+ def getComponentTypeMap(self): return self._componentType.getTypeMap(1)
+
+ def getComponentPositionByType(self, tagSet):
+ return self._componentType.getPositionByType(tagSet)
+
+class Choice(Set):
+ tagSet = tag.TagSet() # untagged
+ sizeSpec = constraint.ConstraintsIntersection(
+ constraint.ValueSizeConstraint(1, 1)
+ )
+
+ def __cmp__(self, other):
+ if self._componentValues:
+ return cmp(self._componentValues[self._currentIdx], other)
+ return -1
+
+ def verifySizeSpec(self): self._sizeSpec(
+ ' '*int(self.getComponent() is not None) # hackerish XXX
+ )
+
+ def _cloneComponentValues(self, myClone):
+ try:
+ c = self.getComponent()
+ except error.PyAsn1Error:
+ pass
+ else:
+ tagSet = getattr(c, 'getEffectiveTagSet', c.getTagSet)()
+ myClone.setComponentByType(tagSet, c.clone())
+
+ def setComponentByPosition(self, idx, value=None):
+ l = len(self._componentValues)
+ if idx >= l:
+ self._componentValues = self._componentValues + (idx-l+1)*[None]
+ if hasattr(self, '_currentIdx'):
+ self._componentValues[self._currentIdx] = None
+ if value is None:
+ if self._componentValues[idx] is None:
+ self._componentValues[idx] = self._componentType.getTypeByPosition(idx).clone()
+ self._currentIdx = idx
+ return self
+ elif type(value) != types.InstanceType:
+ value = self._componentType.getTypeByPosition(idx).clone(
+ value=value
+ )
+ if self._componentType:
+ self._verifyComponent(idx, value)
+ self._verifySubtypeSpec(value, idx)
+ self._componentValues[idx] = value
+ self._currentIdx = idx
+ return self
+
+ def getMinTagSet(self):
+ if self._tagSet:
+ return self._tagSet
+ else:
+ return self._componentType.genMinTagSet()
+
+ def getEffectiveTagSet(self):
+ if self._tagSet:
+ return self._tagSet
+ else:
+ c = self.getComponent()
+ return getattr(c, 'getEffectiveTagSet', c.getTagSet)()
+
+ def getTypeMap(self):
+ if self._tagSet:
+ return Set.getTypeMap(self)
+ else:
+ return Set.getComponentTypeMap(self)
+
+ def getComponent(self, innerFlag=0):
+ if hasattr(self, '_currentIdx'):
+ c = self._componentValues[self._currentIdx]
+ if innerFlag and hasattr(c, 'getComponent'):
+ return c.getComponent(innerFlag)
+ else:
+ return c
+ else:
+ raise error.PyAsn1Error('Component not chosen')
+
+ def setDefaultComponents(self): pass
+
+# XXX
+# coercion rules?
diff --git a/pyasn1/type/useful.py b/pyasn1/type/useful.py
new file mode 100644
index 0000000..a7139c2
--- /dev/null
+++ b/pyasn1/type/useful.py
@@ -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)
+ )
diff --git a/setup.py b/setup.py
new file mode 100644
index 0000000..d47573e
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,18 @@
+#!/usr/bin/env python
+from distutils.core import setup
+
+setup(name="pyasn1",
+ version="0.0.2a",
+ description="ASN.1 library for Python",
+ author="Ilya Etingof",
+ author_email="ilya@glas.net ",
+ url="http://sourceforge.net/projects/pyasn1/",
+ packages = [ 'pyasn1',
+ 'pyasn1.v1',
+ 'pyasn1.v1.type',
+ 'pyasn1.v1.codec',
+ 'pyasn1.v1.codec.ber',
+ 'pyasn1.v1.codec.cer',
+ 'pyasn1.v1.codec.der' ],
+ license="BSD"
+ )
diff --git a/test/__init__.py b/test/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/__init__.py
diff --git a/test/codec/__init__.py b/test/codec/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/codec/__init__.py
diff --git a/test/codec/ber/__init__.py b/test/codec/ber/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/codec/ber/__init__.py
diff --git a/test/codec/ber/decoder.py b/test/codec/ber/decoder.py
new file mode 100644
index 0000000..16eb771
--- /dev/null
+++ b/test/codec/ber/decoder.py
@@ -0,0 +1,301 @@
+from pyasn1.type import tag, namedtype, univ
+from pyasn1.codec.ber import decoder
+from pyasn1 import error
+try:
+ import unittest
+except ImportError:
+ raise error.PyAsn1Error(
+ 'PyUnit package\'s missing. See http://pyunit.sourceforge.net/'
+ )
+
+class IntegerDecoderTestCase(unittest.TestCase):
+ def testPosInt(self):
+ assert decoder.decode('\x02\x01\x0c') == (12, '')
+ def testNegInt(self):
+ assert decoder.decode('\x02\x01\xf4') == (-12, '')
+ def testZero(self):
+ assert decoder.decode('\x02\x01\x00') == (0, '')
+ def testMinusOne(self):
+ assert decoder.decode('\x02\x01\xff') == (-1, '')
+ def testPosLong(self):
+ assert decoder.decode(
+ '\x02\t\x00\xff\xff\xff\xff\xff\xff\xff\xff'
+ ) == (0xffffffffffffffffl, '')
+ def testNegLong(self):
+ assert decoder.decode(
+ '\x02\t\xff\x00\x00\x00\x00\x00\x00\x00\x01'
+ ) == (-0xffffffffffffffffl, '')
+ def testSpec(self):
+ try:
+ decoder.decode(
+ '\x02\x01\x0c', asn1Spec=univ.Null()
+ ) == (12, '')
+ except error.PyAsn1Error:
+ pass
+ else:
+ assert 0, 'wrong asn1Spec worked out'
+ assert decoder.decode(
+ '\x02\x01\x0c', asn1Spec=univ.Integer()
+ ) == (12, '')
+
+class BooleanDecoderTestCase(unittest.TestCase):
+ def testTrue(self):
+ assert decoder.decode('\x01\x01\x01') == (1, '')
+ def testExtraTrue(self):
+ assert decoder.decode('\x01\x01\x01\0x22') == (1, '\0x22')
+ def testFalse(self):
+ assert decoder.decode('\x01\x01\x00') == (0, '')
+
+class BitStringDecoderTestCase(unittest.TestCase):
+ def testDefMode(self):
+ assert decoder.decode(
+ '\x03\x03\x00\xa9\x8a'
+ ) == ((1,0,1,0,1,0,0,1,1,0,0,0,1,0,1,0), '')
+ def testIndefMode(self):
+ assert decoder.decode(
+ '#\x80\x03\x03\x00\xa9\x8a\x00\x00'
+ ) == ((1,0,1,0,1,0,0,1,1,0,0,0,1,0,1,0), '')
+
+ def testDefModeChunked(self):
+ assert decoder.decode(
+ '#\x08\x03\x02\x00\xa9\x03\x02\x00\x8a'
+ ) == ((1,0,1,0,1,0,0,1,1,0,0,0,1,0,1,0), '')
+ def testIndefModeChunked(self):
+ assert decoder.decode(
+ '#\x80\x03\x02\x00\xa9\x03\x02\x00\x8a\x00\x00'
+ ) == ((1,0,1,0,1,0,0,1,1,0,0,0,1,0,1,0), '')
+
+class OctetStringDecoderTestCase(unittest.TestCase):
+ def testDefMode(self):
+ assert decoder.decode(
+ '\x04\x0fQuick brown fox'
+ ) == ('Quick brown fox', '')
+ def testIndefMode(self):
+ assert decoder.decode(
+ '$\x80\x04\x0fQuick brown fox\x00\x00'
+ ) == ('Quick brown fox', '')
+ def testDefModeChunked(self):
+ assert decoder.decode(
+ '$\x17\x04\x04Quic\x04\x04k br\x04\x04own \x04\x03fox'
+ ) == ('Quick brown fox', '')
+ def testIndefModeChunked(self):
+ assert decoder.decode(
+ '$\x80\x04\x04Quic\x04\x04k br\x04\x04own \x04\x03fox\x00\x00'
+ ) == ('Quick brown fox', '')
+
+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(
+ 'e\x11\x04\x0fQuick brown fox'
+ )[0])
+ def testIndefMode(self):
+ assert self.o.isSameTypeWith(decoder.decode(
+ 'e\x80$\x80\x04\x0fQuick brown fox\x00\x00\x00\x00'
+ )[0])
+ def testDefModeChunked(self):
+ assert self.o.isSameTypeWith(decoder.decode(
+ 'e\x19$\x17\x04\x04Quic\x04\x04k br\x04\x04own \x04\x03fox'
+ )[0])
+ def testIndefModeChunked(self):
+ assert self.o.isSameTypeWith(decoder.decode(
+ 'e\x80$\x80\x04\x04Quic\x04\x04k br\x04\x04own \x04\x03fox\x00\x00\x00\x00'
+ )[0])
+
+class NullDecoderTestCase(unittest.TestCase):
+ def testNull(self):
+ assert decoder.decode('\x05\x00') == ('', '')
+
+class ObjectIdentifierDecoderTestCase(unittest.TestCase):
+ def testNull(self):
+ assert decoder.decode(
+ '\x06\x06+\x06\x00\xbf\xff~'
+ ) == ((1,3,6,0,0xffffe), '')
+
+class SequenceDecoderTestCase(unittest.TestCase):
+ def setUp(self):
+ self.s = univ.Sequence(componentType=namedtype.NamedTypes(
+ namedtype.NamedType('place-holder', univ.Null()),
+ namedtype.NamedType('first-name', univ.OctetString()),
+ namedtype.NamedType('age', univ.Integer(33)),
+ ))
+ self.s.setComponentByPosition(0, univ.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(
+ '0\x12\x05\x00\x04\x0bquick brown\x02\x01\x01',
+ ) == (self.s, '')
+
+ def testWithOptionalAndDefaultedIndefMode(self):
+ assert decoder.decode(
+ '0\x80\x05\x00$\x80\x04\x0bquick brown\x00\x00\x02\x01\x01\x00\x00'
+ ) == (self.s, '')
+
+ def testWithOptionalAndDefaultedDefModeChunked(self):
+ assert decoder.decode(
+ '0\x18\x05\x00$\x11\x04\x04quic\x04\x04k br\x04\x03own\x02\x01\x01'
+ ) == (self.s, '')
+
+ def testWithOptionalAndDefaultedIndefModeChunked(self):
+ assert decoder.decode(
+ '0\x80\x05\x00$\x80\x04\x04quic\x04\x04k br\x04\x03own\x00\x00\x02\x01\x01\x00\x00'
+ ) == (self.s, '')
+
+class GuidedSequenceDecoderTestCase(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, univ.Null())
+ self.s.setDefaultComponents()
+
+ def __initWithOptional(self):
+ self.s.clear()
+ self.s.setComponentByPosition(0, univ.Null())
+ self.s.setComponentByPosition(1, univ.OctetString('quick brown'))
+ self.s.setDefaultComponents()
+
+ def __initWithDefaulted(self):
+ self.s.clear()
+ self.s.setComponentByPosition(0, univ.Null())
+ self.s.setComponentByPosition(2, univ.Integer(1))
+ self.s.setDefaultComponents()
+
+ 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))
+ self.s.setDefaultComponents()
+
+ def testDefMode(self):
+ self.__init()
+ assert decoder.decode(
+ '0\x02\x05\x00', asn1Spec=self.s
+ ) == (self.s, '')
+
+ def testIndefMode(self):
+ self.__init()
+ assert decoder.decode(
+ '0\x80\x05\x00\x00\x00', asn1Spec=self.s
+ ) == (self.s, '')
+
+ def testDefModeChunked(self):
+ self.__init()
+ assert decoder.decode(
+ '0\x02\x05\x00', asn1Spec=self.s
+ ) == (self.s, '')
+
+ def testIndefModeChunked(self):
+ self.__init()
+ assert decoder.decode(
+ '0\x80\x05\x00\x00\x00', asn1Spec=self.s
+ ) == (self.s, '')
+
+ def testWithOptionalDefMode(self):
+ self.__initWithOptional()
+ assert decoder.decode(
+ '0\x0f\x05\x00\x04\x0bquick brown', asn1Spec=self.s
+ ) == (self.s, '')
+
+ def testWithOptionaIndefMode(self):
+ self.__initWithOptional()
+ assert decoder.decode(
+ '0\x80\x05\x00$\x80\x04\x0bquick brown\x00\x00\x00\x00',
+ asn1Spec=self.s
+ ) == (self.s, '')
+
+ def testWithOptionalDefModeChunked(self):
+ self.__initWithOptional()
+ assert decoder.decode(
+ '0\x15\x05\x00$\x11\x04\x04quic\x04\x04k br\x04\x03own',
+ asn1Spec=self.s
+ ) == (self.s, '')
+
+ def testWithOptionalIndefModeChunked(self):
+ self.__initWithOptional()
+ assert decoder.decode(
+ '0\x80\x05\x00$\x80\x04\x04quic\x04\x04k br\x04\x03own\x00\x00\x00\x00',
+ asn1Spec=self.s
+ ) == (self.s, '')
+
+ def testWithDefaultedDefMode(self):
+ self.__initWithDefaulted()
+ assert decoder.decode(
+ '0\x05\x05\x00\x02\x01\x01', asn1Spec=self.s
+ ) == (self.s, '')
+
+ def testWithDefaultedIndefMode(self):
+ self.__initWithDefaulted()
+ assert decoder.decode(
+ '0\x80\x05\x00\x02\x01\x01\x00\x00', asn1Spec=self.s
+ ) == (self.s, '')
+
+ def testWithDefaultedDefModeChunked(self):
+ self.__initWithDefaulted()
+ assert decoder.decode(
+ '0\x05\x05\x00\x02\x01\x01', asn1Spec=self.s
+ ) == (self.s, '')
+
+ def testWithDefaultedIndefModeChunked(self):
+ self.__initWithDefaulted()
+ assert decoder.decode(
+ '0\x80\x05\x00\x02\x01\x01\x00\x00', asn1Spec=self.s
+ ) == (self.s, '')
+
+ def testWithOptionalAndDefaultedDefMode(self):
+ self.__initWithOptionalAndDefaulted()
+ assert decoder.decode(
+ '0\x12\x05\x00\x04\x0bquick brown\x02\x01\x01', asn1Spec=self.s
+ ) == (self.s, '')
+
+ def testWithOptionalAndDefaultedIndefMode(self):
+ self.__initWithOptionalAndDefaulted()
+ assert decoder.decode(
+ '0\x80\x05\x00$\x80\x04\x0bquick brown\x00\x00\x02\x01\x01\x00\x00', asn1Spec=self.s
+ ) == (self.s, '')
+
+ def testWithOptionalAndDefaultedDefModeChunked(self):
+ self.__initWithOptionalAndDefaulted()
+ assert decoder.decode(
+ '0\x18\x05\x00$\x11\x04\x04quic\x04\x04k br\x04\x03own\x02\x01\x01', asn1Spec=self.s
+ ) == (self.s, '')
+
+ def testWithOptionalAndDefaultedIndefModeChunked(self):
+ self.__initWithOptionalAndDefaulted()
+ assert decoder.decode(
+ '0\x80\x05\x00$\x80\x04\x04quic\x04\x04k br\x04\x03own\x00\x00\x02\x01\x01\x00\x00', asn1Spec=self.s
+ ) == (self.s, '')
+
+class ChoiceDecoderTestCase(unittest.TestCase):
+ def setUp(self):
+ self.s = univ.Choice(componentType=namedtype.NamedTypes(
+ namedtype.NamedType('place-holder', univ.Null()),
+ namedtype.NamedType('number', univ.Integer())
+ ))
+
+ def testBySpec(self):
+ self.s.setComponentByPosition(0, univ.Null())
+ assert decoder.decode(
+ '\x05\x00', asn1Spec=self.s
+ ) == (self.s, '')
+
+ def testWithoutSpec(self):
+ self.s.setComponentByPosition(0, univ.Null())
+ assert decoder.decode('\x05\x00') == (self.s, '')
+ assert decoder.decode('\x05\x00') == (univ.Null(), '')
+
+if __name__ == '__main__': unittest.main()
diff --git a/test/codec/ber/encoder.py b/test/codec/ber/encoder.py
new file mode 100644
index 0000000..dc86f7e
--- /dev/null
+++ b/test/codec/ber/encoder.py
@@ -0,0 +1,240 @@
+from pyasn1.type import tag, namedtype, univ
+from pyasn1.codec.ber import encoder
+from pyasn1 import error
+try:
+ import unittest
+except ImportError:
+ raise error.PyAsn1Error(
+ 'PyUnit package\'s missing. See http://pyunit.sourceforge.net/'
+ )
+
+class IntegerEncoderTestCase(unittest.TestCase):
+ def testPosInt(self):
+ assert encoder.encode(univ.Integer(12)) == '\x02\x01\x0c'
+ def testNegInt(self):
+ assert encoder.encode(univ.Integer(-12)) == '\x02\x01\xf4'
+ def testZero(self):
+ assert encoder.encode(univ.Integer(0)) == '\x02\x01\x00'
+ def testMinusOne(self):
+ assert encoder.encode(univ.Integer(-1)) == '\x02\x01\xff'
+ def testPosLong(self):
+ assert encoder.encode(
+ univ.Integer(0xffffffffffffffffl)
+ ) == '\x02\t\x00\xff\xff\xff\xff\xff\xff\xff\xff'
+ def testNegLong(self):
+ assert encoder.encode(
+ univ.Integer(-0xffffffffffffffffl)
+ ) == '\x02\t\xff\x00\x00\x00\x00\x00\x00\x00\x01'
+
+class BooleanEncoderTestCase(unittest.TestCase):
+ def testTrue(self):
+ assert encoder.encode(univ.Boolean(1)) == '\x01\x01\x01'
+ def testFalse(self):
+ assert encoder.encode(univ.Boolean(0)) == '\x01\x01\x00'
+
+class BitStringEncoderTestCase(unittest.TestCase):
+ def setUp(self):
+ self.b = univ.BitString("'A98A'H")
+ def testDefMode(self):
+ assert encoder.encode(self.b) == '\x03\x03\x00\xa9\x8a'
+
+ def testIndefMode(self):
+ assert encoder.encode(
+ self.b, defMode=0
+ ) == '\x03\x03\x00\xa9\x8a'
+
+ def testDefModeChunked(self):
+ assert encoder.encode(
+ self.b, maxChunkSize=1
+ ) == '#\x08\x03\x02\x00\xa9\x03\x02\x00\x8a'
+
+ def testIndefModeChunked(self):
+ assert encoder.encode(
+ self.b, defMode=0, maxChunkSize=1
+ ) == '#\x80\x03\x02\x00\xa9\x03\x02\x00\x8a\x00\x00'
+
+class OctetStringEncoderTestCase(unittest.TestCase):
+ def setUp(self):
+ self.o = univ.OctetString('Quick brown fox')
+ def testDefMode(self):
+ assert encoder.encode(self.o) == '\x04\x0fQuick brown fox'
+ def testIndefMode(self):
+ assert encoder.encode(
+ self.o, defMode=0
+ ) == '\x04\x0fQuick brown fox'
+ def testDefModeChunked(self):
+ assert encoder.encode(
+ self.o, maxChunkSize=4
+ ) == '$\x17\x04\x04Quic\x04\x04k br\x04\x04own \x04\x03fox'
+ def testIndefModeChunked(self):
+ assert encoder.encode(
+ self.o, defMode=0, maxChunkSize=4
+ ) == '$\x80\x04\x04Quic\x04\x04k br\x04\x04own \x04\x03fox\x00\x00'
+
+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) == 'e\x11\x04\x0fQuick brown fox'
+ def testIndefMode(self):
+ assert encoder.encode(
+ self.o, defMode=0
+ ) == 'e\x80\x04\x0fQuick brown fox\x00\x00'
+ def testDefModeChunked(self):
+ assert encoder.encode(
+ self.o, defMode=1, maxChunkSize=4
+ ) == 'e\x19$\x17\x04\x04Quic\x04\x04k br\x04\x04own \x04\x03fox'
+ def testIndefModeChunked(self):
+ assert encoder.encode(
+ self.o, defMode=0, maxChunkSize=4
+ ) == 'e\x80$\x80\x04\x04Quic\x04\x04k br\x04\x04own \x04\x03fox\x00\x00\x00\x00'
+
+class NullEncoderTestCase(unittest.TestCase):
+ def testNull(self):
+ assert encoder.encode(univ.Null()) == '\x05\x00'
+
+class ObjectIdentifierEncoderTestCase(unittest.TestCase):
+ def testNull(self):
+ assert encoder.encode(
+ univ.ObjectIdentifier((1,3,6,0,0xffffe))
+ ) == '\x06\x06+\x06\x00\xbf\xff~'
+
+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) == '0\x02\x05\x00'
+
+ def testIndefMode(self):
+ self.__init()
+ assert encoder.encode(
+ self.s, defMode=0
+ ) == '0\x80\x05\x00\x00\x00'
+
+ def testDefModeChunked(self):
+ self.__init()
+ assert encoder.encode(
+ self.s, defMode=1, maxChunkSize=4
+ ) == '0\x02\x05\x00'
+
+ def testIndefModeChunked(self):
+ self.__init()
+ assert encoder.encode(
+ self.s, defMode=0, maxChunkSize=4
+ ) == '0\x80\x05\x00\x00\x00'
+
+ def testWithOptionalDefMode(self):
+ self.__initWithOptional()
+ assert encoder.encode(self.s) == '0\x0f\x05\x00\x04\x0bquick brown'
+
+ def testWithOptionalIndefMode(self):
+ self.__initWithOptional()
+ assert encoder.encode(
+ self.s, defMode=0
+ ) == '0\x80\x05\x00\x04\x0bquick brown\x00\x00'
+
+ def testWithOptionalDefModeChunked(self):
+ self.__initWithOptional()
+ assert encoder.encode(
+ self.s, defMode=1, maxChunkSize=4
+ ) == '0\x15\x05\x00$\x11\x04\x04quic\x04\x04k br\x04\x03own'
+
+ def testWithOptionalIndefModeChunked(self):
+ self.__initWithOptional()
+ assert encoder.encode(
+ self.s, defMode=0, maxChunkSize=4
+ ) == '0\x80\x05\x00$\x80\x04\x04quic\x04\x04k br\x04\x03own\x00\x00\x00\x00'
+
+ def testWithDefaultedDefMode(self):
+ self.__initWithDefaulted()
+ assert encoder.encode(self.s) == '0\x05\x05\x00\x02\x01\x01'
+
+ def testWithDefaultedIndefMode(self):
+ self.__initWithDefaulted()
+ assert encoder.encode(
+ self.s, defMode=0
+ ) == '0\x80\x05\x00\x02\x01\x01\x00\x00'
+
+ def testWithDefaultedDefModeChunked(self):
+ self.__initWithDefaulted()
+ assert encoder.encode(
+ self.s, defMode=1, maxChunkSize=4
+ ) == '0\x05\x05\x00\x02\x01\x01'
+
+ def testWithDefaultedIndefModeChunked(self):
+ self.__initWithDefaulted()
+ assert encoder.encode(
+ self.s, defMode=0, maxChunkSize=4
+ ) == '0\x80\x05\x00\x02\x01\x01\x00\x00'
+
+ def testWithOptionalAndDefaultedDefMode(self):
+ self.__initWithOptionalAndDefaulted()
+ assert encoder.encode(self.s) == '0\x12\x05\x00\x04\x0bquick brown\x02\x01\x01'
+
+ def testWithOptionalAndDefaultedIndefMode(self):
+ self.__initWithOptionalAndDefaulted()
+ assert encoder.encode(
+ self.s, defMode=0
+ ) == '0\x80\x05\x00\x04\x0bquick brown\x02\x01\x01\x00\x00'
+
+ def testWithOptionalAndDefaultedDefModeChunked(self):
+ self.__initWithOptionalAndDefaulted()
+ assert encoder.encode(
+ self.s, defMode=1, maxChunkSize=4
+ ) == '0\x18\x05\x00$\x11\x04\x04quic\x04\x04k br\x04\x03own\x02\x01\x01'
+
+ def testWithOptionalAndDefaultedIndefModeChunked(self):
+ self.__initWithOptionalAndDefaulted()
+ assert encoder.encode(
+ self.s, defMode=0, maxChunkSize=4
+ ) == '0\x80\x05\x00$\x80\x04\x04quic\x04\x04k br\x04\x03own\x00\x00\x02\x01\x01\x00\x00'
+
+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())
+ ))
+
+ def testEmpty(self):
+ try:
+ encoder.encode(self.s)
+ except error.PyAsn1Error:
+ pass
+ else:
+ assert 0, 'encoded unset choice'
+
+ def testFilled(self):
+ self.s.setComponentByPosition(0, univ.Null())
+ assert encoder.encode(self.s) == '\x05\x00'
+
+if __name__ == '__main__': unittest.main()
diff --git a/test/codec/ber/suite.py b/test/codec/ber/suite.py
new file mode 100644
index 0000000..d68c51d
--- /dev/null
+++ b/test/codec/ber/suite.py
@@ -0,0 +1,17 @@
+import encoder, decoder
+from pyasn1 import error
+try:
+ import unittest
+except ImportError:
+ raise error.PyAsn1Error(
+ 'PyUnit package\'s missing. See http://pyunit.sourceforge.net/'
+ )
+
+suite = unittest.TestSuite()
+loader = unittest.TestLoader()
+for m in (encoder, decoder):
+ suite.addTest(loader.loadTestsFromModule(m))
+
+def runTests(): unittest.TextTestRunner(verbosity=2).run(suite)
+
+if __name__ == '__main__': runTests()
diff --git a/test/codec/cer/__init__.py b/test/codec/cer/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/codec/cer/__init__.py
diff --git a/test/codec/cer/decoder.py b/test/codec/cer/decoder.py
new file mode 100644
index 0000000..c37baf5
--- /dev/null
+++ b/test/codec/cer/decoder.py
@@ -0,0 +1,26 @@
+from pyasn1.type import univ
+from pyasn1.codec.cer import decoder
+try:
+ import unittest
+except ImportError:
+ raise error.PyAsn1Error(
+ 'PyUnit package\'s missing. See http://pyunit.sourceforge.net/'
+ )
+
+class BooleanDecoderTestCase(unittest.TestCase):
+ def testTrue(self):
+ assert decoder.decode('\x01\x01\xff') == (1, '')
+ def testFalse(self):
+ assert decoder.decode('\x01\x01\x00') == (0, '')
+
+class OctetStringDecoderTestCase(unittest.TestCase):
+ def testShortMode(self):
+ assert decoder.decode(
+ '\x04\x0fQuick brown fox'
+ ) == ('Quick brown fox', '')
+ def testLongMode(self):
+ assert decoder.decode(
+ '$\x80\x04\x82\x03\xe8' + 'Q'*1000 + '\x04\x01Q\x00\x00'
+ ) == ('Q'*1001, '')
+
+if __name__ == '__main__': unittest.main()
diff --git a/test/codec/cer/encoder.py b/test/codec/cer/encoder.py
new file mode 100644
index 0000000..a045831
--- /dev/null
+++ b/test/codec/cer/encoder.py
@@ -0,0 +1,102 @@
+from pyasn1.type import namedtype, univ
+from pyasn1.codec.cer import encoder
+try:
+ import unittest
+except ImportError:
+ raise error.PyAsn1Error(
+ 'PyUnit package\'s missing. See http://pyunit.sourceforge.net/'
+ )
+
+class BooleanEncoderTestCase(unittest.TestCase):
+ def testTrue(self):
+ assert encoder.encode(univ.Boolean(1)) == '\x01\x01\xff'
+ def testFalse(self):
+ assert encoder.encode(univ.Boolean(0)) == '\x01\x01\x00'
+
+class BitStringEncoderTestCase(unittest.TestCase):
+ def testShortMode(self):
+ assert encoder.encode(
+ univ.BitString((1,0)*501)
+ ) == '\x03\x7f\x06' + '\xaa' * 125 + '\x80'
+
+ def testLongMode(self):
+ assert encoder.encode(
+ univ.BitString((1,0)*501)
+ ) == '\x03\x7f\x06' + '\xaa' * 125 + '\x80'
+
+class OctetStringEncoderTestCase(unittest.TestCase):
+ def testShortMode(self):
+ assert encoder.encode(
+ univ.OctetString('Quick brown fox')
+ ) == '\x04\x0fQuick brown fox'
+ def testLongMode(self):
+ assert encoder.encode(
+ univ.OctetString('Q'*1001)
+ ) == '$\x80\x04\x82\x03\xe8' + 'Q'*1000 + '\x04\x01Q\x00\x00'
+
+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) == '1\x80\x05\x00\x00\x00'
+
+ def testWithOptionalIndefMode(self):
+ self.__initWithOptional()
+ assert encoder.encode(
+ self.s
+ ) == '1\x80\x04\x0bquick brown\x05\x00\x00\x00'
+
+ def testWithDefaultedIndefMode(self):
+ self.__initWithDefaulted()
+ assert encoder.encode(
+ self.s
+ ) == '1\x80\x02\x01\x01\x05\x00\x00\x00'
+
+ def testWithOptionalAndDefaultedIndefMode(self):
+ self.__initWithOptionalAndDefaulted()
+ assert encoder.encode(
+ self.s
+ ) == '1\x80\x02\x01\x01\x04\x0bquick brown\x05\x00\x00\x00'
+
+class SetWithChoiceEncoderTestCase(unittest.TestCase):
+ def setUp(self):
+ c = univ.Choice(componentType=namedtype.NamedTypes(
+ namedtype.NamedType('actual', univ.Boolean())
+ ))
+ 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) == '1\x80\x01\x01\xff\x05\x00\x00\x00'
+
+if __name__ == '__main__': unittest.main()
diff --git a/test/codec/cer/suite.py b/test/codec/cer/suite.py
new file mode 100644
index 0000000..4cbf2d6
--- /dev/null
+++ b/test/codec/cer/suite.py
@@ -0,0 +1,17 @@
+from pyasn1 import error
+import encoder, decoder
+try:
+ import unittest
+except ImportError:
+ raise error.PyAsn1Error(
+ 'PyUnit package\'s missing. See http://pyunit.sourceforge.net/'
+ )
+
+suite = unittest.TestSuite()
+loader = unittest.TestLoader()
+for m in (encoder, decoder):
+ suite.addTest(loader.loadTestsFromModule(m))
+
+def runTests(): unittest.TextTestRunner(verbosity=2).run(suite)
+
+if __name__ == '__main__': runTests()
diff --git a/test/codec/der/__init__.py b/test/codec/der/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/codec/der/__init__.py
diff --git a/test/codec/der/decoder.py b/test/codec/der/decoder.py
new file mode 100644
index 0000000..1db0f97
--- /dev/null
+++ b/test/codec/der/decoder.py
@@ -0,0 +1,16 @@
+from pyasn1.type import univ
+from pyasn1.codec.der import decoder
+try:
+ import unittest
+except ImportError:
+ raise error.PyAsn1Error(
+ 'PyUnit package\'s missing. See http://pyunit.sourceforge.net/'
+ )
+
+class OctetStringDecoderTestCase(unittest.TestCase):
+ def testShortMode(self):
+ assert decoder.decode(
+ '\x04\x0fQuick brown fox'
+ ) == ('Quick brown fox', '')
+
+if __name__ == '__main__': unittest.main()
diff --git a/test/codec/der/encoder.py b/test/codec/der/encoder.py
new file mode 100644
index 0000000..8f41ebd
--- /dev/null
+++ b/test/codec/der/encoder.py
@@ -0,0 +1,39 @@
+from pyasn1.type import namedtype, univ
+from pyasn1.codec.der import encoder
+try:
+ import unittest
+except ImportError:
+ raise error.PyAsn1Error(
+ 'PyUnit package\'s missing. See http://pyunit.sourceforge.net/'
+ )
+
+class OctetStringEncoderTestCase(unittest.TestCase):
+ def testShortMode(self):
+ assert encoder.encode(
+ univ.OctetString('Quick brown fox')
+ ) == '\x04\x0fQuick brown fox'
+
+class BitStringEncoderTestCase(unittest.TestCase):
+ def testShortMode(self):
+ assert encoder.encode(
+ univ.BitString((1,))
+ ) == '\x03\x02\x07\x80'
+
+class SetWithChoiceEncoderTestCase(unittest.TestCase):
+ def setUp(self):
+ c = univ.Choice(componentType=namedtype.NamedTypes(
+ namedtype.NamedType('name', univ.OctetString()),
+ namedtype.NamedType('amount', univ.Integer())
+ ))
+ 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) == '1\x07\x04\x03ann\x05\x00'
+
+if __name__ == '__main__': unittest.main()
diff --git a/test/codec/der/suite.py b/test/codec/der/suite.py
new file mode 100644
index 0000000..4cbf2d6
--- /dev/null
+++ b/test/codec/der/suite.py
@@ -0,0 +1,17 @@
+from pyasn1 import error
+import encoder, decoder
+try:
+ import unittest
+except ImportError:
+ raise error.PyAsn1Error(
+ 'PyUnit package\'s missing. See http://pyunit.sourceforge.net/'
+ )
+
+suite = unittest.TestSuite()
+loader = unittest.TestLoader()
+for m in (encoder, decoder):
+ suite.addTest(loader.loadTestsFromModule(m))
+
+def runTests(): unittest.TextTestRunner(verbosity=2).run(suite)
+
+if __name__ == '__main__': runTests()
diff --git a/test/suite.py b/test/suite.py
new file mode 100644
index 0000000..7125ac1
--- /dev/null
+++ b/test/suite.py
@@ -0,0 +1,23 @@
+import type.suite
+import codec.ber.suite
+import codec.cer.suite
+import codec.der.suite
+try:
+ import unittest
+except ImportError:
+ raise error.PyAsn1Error(
+ 'PyUnit package\'s missing. See http://pyunit.sourceforge.net/'
+ )
+
+suite = unittest.TestSuite()
+for m in (
+ type.suite,
+ codec.ber.suite,
+ codec.cer.suite,
+ codec.der.suite
+ ):
+ suite.addTest(getattr(m, 'suite'))
+
+def runTests(): unittest.TextTestRunner(verbosity=2).run(suite)
+
+if __name__ == '__main__': runTests()
diff --git a/test/type/__init__.py b/test/type/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/type/__init__.py
diff --git a/test/type/constraint.py b/test/type/constraint.py
new file mode 100644
index 0000000..ea02e29
--- /dev/null
+++ b/test/type/constraint.py
@@ -0,0 +1,217 @@
+from pyasn1.type import constraint, error
+#from pyasn1.test import unittest
+try:
+ import unittest
+except ImportError:
+ raise error.PyAsn1Error(
+ 'PyUnit package\'s missing. See http://pyunit.sourceforge.net/'
+ )
+
+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 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 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'
+
+# Booleans
+
+class ConstraintsUnionTestCase(unittest.TestCase):
+ def setUp(self):
+ self.c1 = constraint.ConstraintsUnion(
+ constraint.SingleValueConstraint(4),
+ constraint.ValueRangeConstraint(2, 4)
+ )
+
+ def testGoodVal(self):
+ try:
+ self.c1(2)
+ 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'
+
+if __name__ == '__main__': unittest.main()
+
+# how to apply size constriants to constructed types?
diff --git a/test/type/namedtype.py b/test/type/namedtype.py
new file mode 100644
index 0000000..12a3f0e
--- /dev/null
+++ b/test/type/namedtype.py
@@ -0,0 +1,83 @@
+from pyasn1.type import namedtype, univ, error
+try:
+ import unittest
+except ImportError:
+ raise error.PyAsn1Error(
+ 'PyUnit package\'s missing. See http://pyunit.sourceforge.net/'
+ )
+
+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()),
+ 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.getTypeMapNearPosition(0) == {
+ univ.OctetString.tagSet: univ.OctetString()
+ }
+ assert self.e.getTypeMapNearPosition(1) == {
+ univ.Integer.tagSet: univ.Integer(),
+ univ.OctetString.tagSet: univ.OctetString()
+ }
+ assert self.e.getTypeMapNearPosition(2) == {
+ univ.OctetString.tagSet: univ.OctetString()
+ }
+
+ def testGetTypeMap(self):
+ assert self.e.getTypeMap() == {
+ univ.OctetString.tagSet: univ.OctetString(),
+ univ.Integer.tagSet: univ.Integer()
+ }
+
+ def testGetTypeMapWithDups(self):
+ try:
+ self.e.getTypeMap(1)
+ except error.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())
+ )
+
+ def testGetTypeByPosition(self):
+ assert self.e.getTypeByPosition(0) == univ.OctetString(), \
+ 'getTypeByPosition() fails'
+
+if __name__ == '__main__': unittest.main()
diff --git a/test/type/suite.py b/test/type/suite.py
new file mode 100644
index 0000000..67d89f2
--- /dev/null
+++ b/test/type/suite.py
@@ -0,0 +1,17 @@
+from pyasn1 import error
+import tag, constraint, namedtype, univ
+try:
+ import unittest
+except ImportError:
+ raise error.PyAsn1Error(
+ 'PyUnit package\'s missing. See http://pyunit.sourceforge.net/'
+ )
+
+suite = unittest.TestSuite()
+loader = unittest.TestLoader()
+for m in (tag, constraint, namedtype, univ):
+ suite.addTest(loader.loadTestsFromModule(m))
+
+def runTests(): unittest.TextTestRunner(verbosity=2).run(suite)
+
+if __name__ == '__main__': runTests()
diff --git a/test/type/tag.py b/test/type/tag.py
new file mode 100644
index 0000000..310b755
--- /dev/null
+++ b/test/type/tag.py
@@ -0,0 +1,103 @@
+from pyasn1.type import tag
+try:
+ import unittest
+except ImportError:
+ raise error.PyAsn1Error(
+ 'PyUnit package\'s missing. See http://pyunit.sourceforge.net/'
+ )
+
+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()
diff --git a/test/type/univ.py b/test/type/univ.py
new file mode 100644
index 0000000..9a1d441
--- /dev/null
+++ b/test/type/univ.py
@@ -0,0 +1,359 @@
+from pyasn1.type import univ, tag, constraint, namedtype, namedval, error
+try:
+ import unittest
+except ImportError:
+ raise error.PyAsn1Error(
+ 'PyUnit package\'s missing. See http://pyunit.sourceforge.net/'
+ )
+
+class IntegerTestCase(unittest.TestCase):
+ def testStr(self): assert str(univ.Integer(1)) == '1', '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 testStr(self): assert str(univ.Boolean(1)) == '1', '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 testStr(self):
+ assert str(univ.OctetString('q')) == 'q', '__str__() fails'
+ def testSeq(self):
+ assert univ.OctetString('q')[0] == 'q','__getitem__() fails'
+ def testAdd(self):
+ assert univ.OctetString() + 'q' == 'q', '__add__() fails'
+ def testRadd(self):
+ assert 'b' + univ.OctetString('q') == 'bq', '__radd__() fails'
+ def testMul(self):
+ assert univ.OctetString('a') * 2 == 'aa', '__mul__() fails'
+ def testRmul(self):
+ assert 2 * univ.OctetString('b') == '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 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] == 'abc', 'set by idx fails'
+ self.s1.setComponentByPosition(0, 'cba')
+ assert self.s1[0] == '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('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 testGetComponentTypeMap(self):
+ assert self.s1.getComponentTypeMap() == {
+ 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)
+ )
+
+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') == 'abc', 'set by name fails'
+ def testGetNearPosition(self):
+ assert self.s1.getComponentTypeMapNearPosition(1) == {
+ 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
+
+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] == 'abc', 'set by idx fails'
+ self.s1.setComponentByPosition(0, self.s1[0].clone('cba'))
+ assert self.s1[0] == '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
+ ) == 'abc', 'set by name fails'
+ def testByTypeWithInstance(self):
+ self.s1.setComponentByType(univ.OctetString.tagSet, univ.OctetString('abc'))
+ assert self.s1.getComponentByType(
+ univ.OctetString.tagSet
+ ) == 'abc', 'set by name fails'
+ def testGetTypeMap(self):
+ assert self.s1.getTypeMap() == {
+ univ.Set.tagSet: univ.Set()
+ }
+ def testGetComponentTypeMap(self):
+ assert self.s1.getComponentTypeMap() == {
+ 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
+ ) == 'abc'
+ def testOuterByTypeWithInstanceValue(self):
+ self.s1.setComponentByType(
+ univ.OctetString.tagSet, univ.OctetString('abc')
+ )
+ assert self.s1.getComponentByType(
+ univ.OctetString.tagSet
+ ) == '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 == 'abc', '__cmp__() fails'
+ def testGetComponent(self):
+ self.s1.setComponentByType(univ.OctetString.tagSet, 'abc')
+ assert self.s1.getComponent() == 'abc', 'getComponent() fails'
+ def testSetComponentByPosition(self):
+ self.s1.setComponentByPosition(0, univ.OctetString('Jim'))
+ assert self.s1 == 'Jim'
+
+if __name__ == '__main__': unittest.main()