feat: Add new gcloud commands, API clients, and third-party libraries across various services.

This commit is contained in:
2026-01-01 20:26:35 +01:00
parent 5e23cbece0
commit a19e592eb7
25221 changed files with 8324611 additions and 0 deletions

View File

@@ -0,0 +1,3 @@
skips:
- B603 # Ignore warnings about calling subprocess.Popen without shell=True
- B607 # Ignore warnings about calling subprocess.Popen without a full path to executable

View File

@@ -0,0 +1 @@
custom: https://pyasn1.readthedocs.io/

View File

@@ -0,0 +1,92 @@
---
name: CI
on:
push:
branches: [ "main", "v*" ]
pull_request:
branches: [ "main", "v*" ]
workflow_dispatch:
inputs:
tag:
description: tag to build
required: false
type: string
workflow_call:
inputs:
tag:
description: tag to build
required: true
type: string
permissions:
contents: read
env:
FORCE_COLOR: 1
jobs:
tests:
name: "Python ${{ matrix.python-version }}"
runs-on: "ubuntu-22.04"
strategy:
fail-fast: false
matrix:
python-version:
- "3.8"
- "3.9"
- "3.10"
- "3.11"
- "3.12"
- "3.13"
- "pypy-3.8"
- "pypy-3.9"
- "pypy-3.10"
steps:
- uses: "actions/checkout@v4"
with:
ref: ${{ inputs.tag || github.ref }}
- uses: "actions/setup-python@v5"
with:
python-version: "${{ matrix.python-version }}"
allow-prereleases: true
cache: "pip"
- name: "Update pip"
run: python -m pip install --upgrade pip setuptools wheel
- name: "Install tox dependencies"
run: python -m pip install --upgrade tox tox-gh-actions
- name: "Run tox for ${{ matrix.python-version }}"
run: "python -m tox"
sdist:
name: "Build sdist and wheel"
runs-on: "ubuntu-latest"
needs: tests
steps:
- uses: "actions/checkout@v4"
with:
ref: ${{ inputs.tag || github.ref }}
- uses: "actions/setup-python@v5"
with:
python-version: "3.x"
cache: "pip"
- name: "Update pip"
run: python -m pip install --upgrade pip setuptools wheel
- name: "Install 'build'"
run: python -m pip install --upgrade build
- name: "Run 'build'"
run: "python -m build"
- name: "Upload sdist artifact"
uses: actions/upload-artifact@v4
with:
name: sdist
path: |
dist/pyasn1*.tar.gz
if-no-files-found: error
- name: "Upload wheel artifact"
uses: actions/upload-artifact@v4
with:
name: wheel
path: |
dist/pyasn1*.whl
if-no-files-found: error

View File

@@ -0,0 +1,59 @@
---
name: Build and upload to PyPI
permissions:
contents: read
on:
workflow_dispatch:
inputs:
tag:
description: tag to build
required: true
type: string
testpypi:
description: upload to Test PyPI
type: boolean
default: false
pypi:
description: upload to PyPI
type: boolean
default: false
jobs:
tests:
uses: ./.github/workflows/main.yml
with:
tag: ${{ inputs.tag }}
pypi:
name: Build and upload to PyPI
runs-on: ubuntu-latest
needs: tests
steps:
- name: Checkout
uses: actions/checkout@v4
with:
ref: ${{ inputs.tag }}
- name: Set up Python 3.x
uses: actions/setup-python@v5
with:
python-version: "3.x"
- name: "Update pip"
run: python -m pip install --upgrade pip setuptools wheel
- name: "Install 'build' and 'twine'"
run: python -m pip install --upgrade build twine
- name: "Run 'build'"
run: "python -m build"
- name: "Run twine check"
run: "python -m twine check dist/*"
- name: Publish distribution to Test PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
password: ${{ secrets.TEST_PYPI_API_TOKEN }}
repository_url: https://test.pypi.org/legacy/
if: inputs.testpypi || false
- name: Publish distribution to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
password: ${{ secrets.PYPI_API_TOKEN }}
if: inputs.pypi || false

View File

@@ -0,0 +1,27 @@
# Python stuff
*.pyc
__pycache__
.coverage
.tox
# vim swapfiles
*.sw?
# python packaging
MANIFEST
dist/
build/
*.egg-info/
# PyCharm stuff
.idea/
# Sphinx template
docs/source/.templates/layout.html
# Eclipse stuff
.project
.pydevproject
# Virtual envs
venv*

View File

@@ -0,0 +1,15 @@
# Read the Docs configuration file for Sphinx projects
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
# Required
version: 2
# Set the OS, Python version and other tools you might need
build:
os: ubuntu-22.04
tools:
python: "3.11"
# Build documentation in the "docs/" directory with Sphinx
sphinx:
configuration: docs/source/conf.py

View File

@@ -0,0 +1,821 @@
Revision 0.6.1, released 10-09-2024
---------------------------------------
- Added support for Python 3.13 and updated GitHub Actions
[pr #73](https://github.com/pyasn1/pyasn1/pull/73/)
- Removed Python 2 support and related code
[pr #62](https://github.com/pyasn1/pyasn1/pull/62/)
[pr #61](https://github.com/pyasn1/pyasn1/pull/61/)
[pr #60](https://github.com/pyasn1/pyasn1/pull/60/)
- Improved error handling and consistency
[pr #71](https://github.com/pyasn1/pyasn1/pull/71/)
[pr #70](https://github.com/pyasn1/pyasn1/pull/70/)
- Runtime deprecation of `tagMap` and `typeMap` aliases
[pr #72](https://github.com/pyasn1/pyasn1/pull/72/)
- Fixed duplicated and missing declarations
[pr #64](https://github.com/pyasn1/pyasn1/pull/64/)
- Cleaned documentation and comments
[pr #63](https://github.com/pyasn1/pyasn1/pull/63/)
- Removed bdist_wheel universal flag from setup.cfg
[pr #69](https://github.com/pyasn1/pyasn1/pull/69/)
Revision 0.6.0, released 26-03-2024
---------------------------------------
- Added support for previously missing `RELATIVE-OID` construct
[pr #48](https://github.com/pyasn1/pyasn1/pull/48/)
- Updated link to Layman's Guide
Now it provides a link to links to a formatted PDF version of the paper,
at a stable domain (researchgate), using https
[pr #50](https://github.com/pyasn1/pyasn1/pull/50/)
- Removed support for EOL Python 2.7, 3.6, 3.7
[pr #56](https://github.com/pyasn1/pyasn1/pull/56/)
Revision 0.5.1, released 20-11-2023
---------------------------------------
- Added support for PyPy 3.10 and Python 3.12
[pr #32](https://github.com/pyasn1/pyasn1/pull/32/)
- Updated RTD configuration to include a dummy index.rst
redirecting to contents.html, ensuring compatibility with
third-party documentation and search indexes.
[pr #47](https://github.com/pyasn1/pyasn1/pull/47/)
- Fixed the API breakage wih decoder.decode(substrateFun=...).
A substrateFun passed to ``decoder.decode()`` can now be either
v0.4 Non-Streaming or v0.5 Streaming. pyasn1 will detect and
handle both cases transparently.
A substrateFun passed to one of the new streaming decoders is
still expected to be v0.5 Streaming only.
[pr #30](https://github.com/pyasn1/pyasn1/pull/30/)
[pr #39](https://github.com/pyasn1/pyasn1/pull/39/)
Revision 0.5.0, released 19-04-2023
---------------------------------------
- Change `RealEncoder.supportIndefLenMode` type to a boolean
[pr #21](https://github.com/pyasn1/pyasn1/pull/21/)
- Fix CI for py39 test environment
[pr #25](https://github.com/pyasn1/pyasn1/pull/25/)
- Replace all snmplabs.com links
[issue #4](https://github.com/pyasn1/pyasn1/issues/4)
- Use correct SPDX identifier for the license
[pr #16](https://github.com/pyasn1/pyasn1/pull/16)
- Re-add ``tagMap`` and ``typeMap`` module level attributes to all
encoder and decoder modules. They are aliases for ``TAG_MAP`` and
``TYPE_MAP``, [issue #9](https://github.com/pyasn1/pyasn1/issues/9).
- Restore API for passing for ``tagMap`` and ``typeMap`` arguments
to ``Encoder`` and ``Decoder`` classes by name and position,
[issue #12](https://github.com/pyasn1/pyasn1/issues/12).
- Re-add ``tagMap`` and ``typeMap`` module level attributes to all
encoder and decoder modules. They are aliases for ``TAG_MAP`` and
``TYPE_MAP``, [issue #9](https://github.com/pyasn1/pyasn1/issues/9).
- Restore API for passing for ``tagMap`` and ``typeMap`` arguments
to ``Encoder`` and ``Decoder`` classes by name and position,
- Make BER/CER/DER decoders streaming and suspendible
The goal of this change is to make the decoder yielding on input
data starvation and resuming from where it stopped whenever the
caller decides to try again (hopefully making sure that some more
input becomes available).
This change makes it possible for the decoder to operate on streams
of data (meaning that the entire DER blob might not be immediately
available on input).
On top of that, the decoder yields partially reconstructed ASN.1
object on input starvation making it possible for the caller to
inspect what has been decoded so far and possibly consume partial
ASN.1 data.
All these new feature are natively available through
`StreamingDecoder` class. Previously published API is implemented
as a thin wrapper on top of that ensuring backward compatibility.
- Added support for Python 3.8, 3.9, 3.10, 3.11
- Removed support for EOL Pythons 2.4, 2.5, 2.6, 3.2, 3.3, 3.4, 3.5
- Added support for PyPy 3.7, 3.8, 3.9
- Modernized packaging and testing. pyasn1 now uses ``setup.cfg``,
``pyproject.toml``, [build](https://pypi.org/project/build/), and
GitHub Actions.
- PyPI package ownership for `pyasn1` and `pyasn1-module` has been
transfered to *Christian Heimes* and *Simon Pichugin* in
[PyPI support ticket #2090](https://github.com/pypa/pypi-support/issues/2090).
- The upstream repositories for `pyasn1` and `pyasn1-modules` are now
in the GitHub organization https://github.com/pyasn1/.
Revision 0.4.8, released 16-11-2019
-----------------------------------
- Added ability of combining `SingleValueConstraint` and
`PermittedAlphabetConstraint` objects into one for proper modeling
`FROM ... EXCEPT ...` ASN.1 clause.
Revision 0.4.7, released 01-09-2019
-----------------------------------
- Added `isInconsistent` property to all constructed types. This property
conceptually replaces `verifySizeSpec` method to serve a more general
purpose e.g. ensuring all required fields are in a good shape. By default
this check invokes subtype constraints verification and is run by codecs
on value de/serialisation.
- Deprecate `subtypeSpec` attributes and keyword argument. It is now
recommended to pass `ValueSizeConstraint`, as well as all other constraints,
to `subtypeSpec`.
- Fixed a design bug in a way of how the items assigned to constructed
types are verified. Now if `Asn1Type`-based object is assigned, its
compatibility is verified based on having all tags and constraint
objects as the type in field definition. When a bare Python value is
assigned, then field type object is cloned and initialized with the
bare value (constraints verificaton would run at this moment).
- Added `WithComponentsConstraint` along with related
`ComponentPresentConstraint` and `ComponentAbsentConstraint` classes
to be used with `Sequence`/`Set` types representing
`SET ... WITH COMPONENTS ...` like ASN.1 constructs.
Revision 0.4.6, released 31-07-2019
-----------------------------------
- Added previously missing `SET OF ANY` construct encoding/decoding support.
- Added `omitEmptyOptionals` option which is respected by `Sequence`
and `Set` encoders. When `omitEmptyOptionals` is set to `True`, empty
initialized optional components are not encoded. Default is `False`.
- New elements to `SequenceOf`/`SetOf` objects can now be added at any
position - the requirement for the new elements to reside at the end
of the existing ones (i.e. s[len(s)] = 123) is removed.
- List-like slicing support added to `SequenceOf`/`SetOf` objects.
- Removed default initializer from `SequenceOf`/`SetOf` types to ensure
consistent behaviour with the rest of ASN.1 types. Before this change,
`SequenceOf`/`SetOf` instances immediately become value objects behaving
like an empty list. With this change, `SequenceOf`/`SetOf` objects
remain schema objects unless a component is added or `.clear()` is
called.
This change can potentially cause incompatibilities with existing
pyasn1 objects which assume `SequenceOf`/`SetOf` instances are value
objects right upon instantiation.
The behaviour of `Sequence`/`Set` types depends on the `componentType`
initializer: if on `componentType` is given, the behaviour is the
same as `SequenceOf`/`SetOf` have. IF `componentType` is given, but
neither optional nor defaulted components are present, the created
instance remains schema object, If, however, either optional or
defaulted component isi present, the created instance immediately
becomes a value object.
- Added `.reset()` method to all constructed types to turn value object
into a schema object.
- Added `PyAsn1UnicodeDecodeError`/`PyAsn1UnicodeDecodeError` exceptions
to help the caller treating unicode errors happening internally
to pyasn1 at the upper layers.
- Added support for subseconds CER/DER encoding edge cases in
`GeneralizedTime` codec.
- Fixed 3-digit fractional seconds value CER/DER encoding of
`GeneralizedTime`.
- Fixed `AnyDecoder` to accept possible `TagMap` as `asn1Spec`
to make dumping raw value operational
Revision 0.4.5, released 29-12-2018
-----------------------------------
- Debug logging refactored for more efficiency when disabled and
for more functionality when in use. Specifically, the global
LOG object can easily be used from any function/method, not just
from codec main loop as it used to be.
- More debug logging added to BER family of codecs to ease encoding
problems troubleshooting.
- Copyright notice extended to the year 2019
- Fixed defaulted constructed SEQUENCE component initialization.
Revision 0.4.4, released 26-07-2018
-----------------------------------
- Fixed native encoder type map to include all ASN.1 types
rather than just ambiguous ones
- Fixed crash in `.prettyPrint` of `Sequence` and `Set` occurring
at OPTIONAL components
Revision 0.4.3, released 23-05-2018
-----------------------------------
- Copyright notice extended to the year 2018
- Fixed GeneralizedTime.asDateTime to perform milliseconds conversion
correctly
Revision 0.4.2, released 23-11-2017
-----------------------------------
- Fixed explicit tag splitting in chunked encoding mode at
OctetString and BitString encoders
Revision 0.4.1, released 23-11-2017
-----------------------------------
- ANY DEFINED BY clause support implemented
- Encoders refactored to take either a value (as ASN.1 object)
or a Python value plus ASN.1 schema
- BitString decoder optimised for better performance when running on
constructed encoding
- Constructed types' .getComponentBy*() methods accept the `default`
parameter to return instead if schema object is to be returned
- Constructed types' .getComponentBy*() methods accept the `instantiate`
parameter to disable automatic inner component instantiation
- The ASN.1 types' `__repr__` implementation reworked for better readability
at the cost of not being `eval`-compliant
- Most ASN.1 types' `__str__` magic methods (except for OctetString and
character types) reworked to call `.prettyPrint()` rather than
`.prettyPrint` calling `__str__` as it was before. The intention is
to eventually deprecate `.prettyPrint()` in favor of `str()`.
The other related change is that `str()` of enumerations and boolean
types will return string label instead of number.
- Fixed Choice.clear() to fully reset internal state of the object
- Sphinx documentation rearranged, simplified and reworded
- The `isValue` singleton is now the only way to indicate ASN.1 schema
as opposed to ASN.1 schema instance. The legacy `None` initializer
support has been removed.
- Changed `Null` object initialization behaviour: previous default
value (`''`) is not set anymore. Thus `Null()` call produces a
ASN.1 schema object, while `Null('')` - value object.
- Migrated all docs and references from SourceForge
- Imports PEP8'ed
- Fixed ASN.1 encoder not to omit empty substrate produced for inner
component if the inner component belongs to the simple class (as
opposed to constructed class)
- Fixed CER/DER encoders to respect tagged CHOICE when ordering
SET components
- Fixed ASN.1 types not to interfere with the Pickle protocol
- Fixed Sequence/SequenceOf types decoding heuristics in schema-less
decoding mode
Revision 0.3.7, released 04-10-2017
-----------------------------------
- Fixed ASN.1 time types pickling/deepcopy'ing
Revision 0.3.6, released 21-09-2017
-----------------------------------
- End-of-octets encoding optimized at ASN.1 encoders
- The __getitem__/__setitem__ behavior of Set/Sequence and SetOf/SequenceOf
objects aligned with the canonical Mapping and Sequence protocols in part
- Fixed crash in ASN.1 encoder when encoding an explicitly tagged
component of a Sequence
Revision 0.3.5, released 16-09-2017
-----------------------------------
- Codecs signatures unified and pass the options kwargs through the
call chain
- Explicit tag encoding optimized to avoid unnecessary copying
- End-of-octets sentinel encoding optimized
- Refactored ASN.1 codecs properties to silently enforce proper
length and chunk size encoding modes
- Fixed DER encoder to always produce primitive encoding
- Fixed crash at SequenceOf native decoder
- Fixed Real.prettyPrint() to fail gracefully on overflow
- Fixed a couple of crashes when debug mode is enabled
Revision 0.3.4, released 07-09-2017
-----------------------------------
- Fixed Native encoder to handle SEQUENCE/SET objects without
the componentType property
- Added missing component-less SEQUENCE/SET objects dict duck-typing support
- Fixed unnecessary duplicate tags detection at NamesType.tagMap
- Fixed crash at SEQUENCE and SEQUENCE OF CER encoder when running
in schemaless mode
- Fixed Character types instantiation from OctetString type -- double
unicode decoding may have scrambled the data
Revision 0.3.3, released 27-08-2017
-----------------------------------
- Improved ASN.1 types instantiation performance
- Improved BER/CER/DER decoder performance by not unconditionally casting
substrate into str/bytes.
- Fixed exponential index size growth bug when building ambiguous
NamedTypes tree
- Fixed constructed types decoding failure at BER codec if running
in schema-less mode
- Fixed crash on prettyPrint'ing a SEQUENCE with no defined components
- Fixed SetOf ordering at CER/DER encoder
- Fixed crash on conditional binascii module import
- Fix to TagSet hash value build
Revision 0.3.2, released 04-08-2017
-----------------------------------
- Fixed SequenceOf/SetOf types initialization syntax to remain
backward compatible with pyasn1 0.2.*
- Rectified thread safety issues by moving lazy, run-time computation
into object initializer.
- Fixed .isValue property to return True for empty SetOf/SequenceOf
objects
- Fixed GeneralizedTime/UTCTime CER/DER codecs to actually get invoked
- Fixed DER/CER encoders handling optional SEQUENCE/SET fields containing
nested SEQUENCE/SET with optional fields.
- Fixed crash in SequenceOf/SetOf pretty printing and decoding (in some
cases)
- Fixed documentation markup issues.
Revision 0.3.1, released 26-07-2017
-----------------------------------
- ASN.1 types __init__(), .clone() and .subtype() signatures
refactored into keyword arguments to simplify their signatures.
- ASN.1 types initialization refactored to minimize the use of
relatively expensive isNoValue() call
- Lazily pre-populate list of values of Sequence/Set/Choice types
- NamedTypes comparison made more efficient
- More efficient constraints computation and code clean up
- The __getitem__() implementation of some ASN.1 types & tag object
refactored for better performance
- BER/CER/DER value encoders refactored to produce either tuple of
bytes or octet-stream depending on what is more optimal
- Reduced the frequency of expensive isinstance() calls
- Tag-related classes optimized, refactored into properties and
documented.
- The NamedValues implementation refactored to mimic Python dict, its use
in ASN.1 types refactored into properties and better documented.
WARNING: this change introduces a deviation from original API.
- NamedType family of classes overhauled, optimized and documented.
- The `componentType` attribute of constructed ASN.1 types turned
read-only on instances.
- Sequence/Set DER/CER/DER decoder optimized to skip the case of
reordered components handling when not necessary.
- Tags and constraints-related getter methods refactored into read-only
instance attributes.
- The .hasValue() method refactored into .isValue property. All ASN.1
objects now support them, not just scalars.
- The Real.{isInfinity, isPlusInfinity, isMinusInfinity} methods
refactored into properties and renamed into IsInf, IsPlusInf and isMinusInf
- The end-of-octets type refactored to ensure it is a singleton. Codecs
changed to rely on that for better performance.
- Codecs lookup made more efficient at BER/CER/DER decoder main loop by
assigning `typeId` to every ASN.1 type, not just ambiguous ones.
- The .getComponent*() methods of constructed ASN.1 types changed
to lazily instantiate underlying type rather than return `None`.
This should simplify its API as initialization like `X[0][1] = 2` becomes
possible.
WARNING: this change introduces a deviation from the original API.
- The .setComponent*() methods of SetOf/SequenceOf types changed not
to allow uninitialized "holes" inside the sequences of their components.
They now behave similarly to Python lists.
WARNING: this change introduces a deviation from the original API.
- Default and optional components en/decoding of Constructed type
refactored towards better efficiency and more control.
- OctetsString and Any decoder optimized to avoid creating ASN.1
objects for chunks of substrate. Instead they now join substrate
chunks together and create ASN.1 object from it just once.
- The GeneralizedTime and UTCTime types now support to/from Python
datetime object conversion.
- Unit tests added for the `compat` sub-package.
- Fixed BitString named bits initialization bug.
- Fixed non-functional tag cache (when running Python 2) at DER decoder.
- Fixed chunked encoding restriction on DER encoder.
- Fixed SET components ordering at DER encoder.
- Fixed BIT STRING & OCTET STRING encoding to be always non-chunked (e.g.
primitive) at DER encoder
- Fixed `compat.integer.from_bytes()` behaviour on empty input.
Revision 0.2.3, released 25-02-2017
-----------------------------------
- Improved SEQUENCE/SET/CHOICE decoding performance by maintaining a single shared
NamedType object for all instances of SEQUENCE/SET object.
- Improved INTEGER encoding/decoding by switching to Python's built-in
integer serialisation functions.
- Improved BitString performance by rebasing it onto Python int type and leveraging
fast Integer serialisation functions.
- BitString type usability improved in many ways: for example bitshifting and
numeric operation on BitString is now possible.
- Minor ObjectIdentifier type performance optimization.
- ASN.1 character types refactored to keep unicode contents internally
(rather than serialised octet stream) and duck-type it directly.
- ASN.1 OctetString initialized from a Python object performs bytes()
on it when running on Python 3 (used to do str() which is probably
less logical).
- Missing support for NoValue.__sizeof__ added.
- Added checks to make sure SEQUENCE/SET components being assigned
match the prototypes.
- Setter methods for constructed types consistently accept matchTags
and matchConstraints flags to control the strictness of inner
components compatibility verification. Previously, these checks
were tied to verifyConstraints flag, now they are all independent.
- General documentation improvements here and there.
- Fix to __reversed__() magic to make it returning an iterator.
- Test suite simplified and unified.
- The __all__ variable added to most of the Python modules.
- The "test" directory renamed into "tests" not to collide with
the "test" module.
Revision 0.2.2, released 07-02-2017
-----------------------------------
- FIX TO A SECURITY WEAKNESS: define length only decoders could have successfully
processed indefinite length serialisation.
- FIX TO A SECURITY WEAKNESS: canonical decoders (CER/DER) may have successfully
consumed non-canonical variations of (otherwise valid) serialisation.
- Broken Enumerated subtyping fixed.
Revision 0.2.1, released 05-02-2017
-----------------------------------
- FIX TO A SECURITY WEAKNESS: BER decoder improperly cached long tags.
- New "native" codec implemented to transform pyasn1 types to Python built-in types and back.
- Switched to new-style classes.
- Sphinx documentation added.
- BitString improvements:
* simple string of binary digits is now supported as initializer
* default str() yields string of binary digits (used to yield str(tuple())
* binValue and hexValue initializers added
* .asNumbers(), .asOctets() and asInteger() representation added
- Components of constructed ASN.1 types can now be populated with
uninitialized ASN.1 objects by assigning either noValue sentinel or
setupComponent() function return in addition to now-legacy None sentinel.
This should improve code readability.
- NoValue class improved to become a singleton and catch more kinds
of access to it.
- Compatibility wrappers str2octs() and oct2strs() fixed to run over
iso-8859-1 encoding.
- Integer changed to emit Real instance if division produces a float.
- True division operation now supported by Integer type.
- The __contains__(), __reverse__() methods implemented for container types
- Iterator protocol support implemented for all container types.
Warning, warning, warning: this change may potentially affect backward
compatibility when:
* user class overrides __getitem__() without overriding __iter__()
* when user code iterates over SEQUENCE object to get its components (now keys will be yielded)
- Almost complete Python list and dict protocols added to SequenceOf/SetOf and
Sequence/Set respectively
- Fix to divmod operation implementation in Integer type.
- Fix to IntegerDecoder's precomputed value map on Python 3.
- Fix to base ASN.1 types to run in "unicode_literals" mode.
- Fix to composite constraints "+" operands ordering (AbstractConstraintSet.__radd__)
- Fix to constraints merge in .subtype() -- on merge existing constraints are
expanded to accommodate new constraints, not the other way round. When existing
constraints are wrapped in ConstraintsIntersection composite, additional
constraints being added on subtyping effectively further narrow the set of
allowed values, which aligns well with the notion of subtyping.
- Fix to NamedTypes methods to handle .getTagMap() returning None
- Fix to Set/Sequence.setDefaultComponents() to return self
- Copyright notice added to non-trivial source code files.
- Author's email changed, copyright extended to 2017
Revision 0.1.9, released 28-09-2015
-----------------------------------
- Wheel distribution format now supported.
- Extensions added to text files, CVS attic flushed.
- Fix to make uninitialized pyasn1 objects failing properly on hash().
- Fix to ObjectIdentifier initialization from unicode string.
- Fix to CER/DER Boolean decoder - fail on non single-octet payload.
Revision 0.1.8, released 22-06-2015
-----------------------------------
- ObjectIdentifier codec fixed to work properly with arc 0 and arc 2 values.
- Explicit limit on ObjectIdentifier arc value size removed.
- Unicode initializer support added to OctetString type and derivatives.
- New prettyPrintType() abstract method implemented to base pyasn1 types
to facilitate encoding errors analysis.
- The __str__() method implemented to Tag, TagSet and TagMap classes to
ease encoding errors troubleshooting.
easing encoding errors
- Fix to SEQUENCE and SET types to give them their private componentTypes
collection (which is a NamedTypes object) so that they won't collide in
a MT execution environment.
- Missing T61String,ISO646String character types and ObjectDescriptor useful
type added.
- Distribute is gone, switched to setuptools completely.
- Missing NamedValues.__repr__() added.
- The base.NoValue() class, that indicates uninitialized ASN.1 object,
made public.
- The base.NoValue() class instances now support __repr__() what makes
possible to perform repr() on uninitialized pyasn1 types objects.
- When comparing ASN.1 types, by-tag and/or by-constraints matching
can now be performed with the isSuperTypeOf()/isSameTypeWith() optional
flags.
- Constructed types now verify their consistency by invoking
isSameTypeWith(matchTags=True, matchConstraints=False) and
isSuperTypeOf(matchTags=False, matchConstraints=True) for each of their
components rather than isSuperTypeOf() as it used to be. Constriants check
could be enforced to isSameTypeWith() with the strictConstraints=True
constructed classes attribute.
- Constructed types can now be initialized with new .setComponents() method
which accepts both var-args and keyword-args. Default repr() modified to
reflect this change.
- NamedTypes() and NamedValues() made comparable.
- Test coverage extended to cover pyasn1 types __repr__() function.
- The abs(Integer()) & abs(Real()) operation now returns respective pyasn1
type, not a Python type.
- More Python magic methods implementations added to Integer & Real classes
(e.g. __pos__, __neg__, __round__, __floor__, __ceil__, __trunc__)
- The Integer.__invert__ Python magic method implemented.
- The OctetString.__int__() and .__float__() magic methods implemented.
- Handle the case of null writer at Debug printer.
- BitString encoder/decoder performance improved.
- Built-in debugging is now based on Python logging module.
- Fix to NamedType.__repr__() to work properly.
- Fixes to __repr__() implementation of many built-in ASN.1 types to take into
account all of their initializers such as tagSet, subtypeSpec etc.
- String typed float initializer to REAL type now supported.
- Float typed mantissa initializer to REAL type for base 2 added.
- Encoding bases 8 and 16 support for REAL type binary encoder added.
- More strict CER/DER encoders added for GeneralizedTime and UTCTime types.
- Asn1Item.hasValue() added to easily distinguish initalized ASN.1 objects
from uninitialized ones (e.g. pure types).
- Fix to REAL type binary decoder to handle different bases and scale factor.
- Fix to TagSet.repr() to include [obsolete] baseTag information.
- Fix to broken REAL type decoding handling.
- Fix to BitString and OctetString decoders dealing with constructed
encoding -- it used to be possible to embed other types in substrate.
- DER codec hardened not to tolerate indefinite length encoding/decoding.
- Fix to end-of-octest sentinel handling:
+ require strict two-zeros sentinel encoding
+ recognize EOO sentinel only when explicitly requested by caller
of the decoder via allowEoo=True parameter (warning: API change)
Revision 0.1.7
--------------
- License updated to vanilla BSD 2-Clause to ease package use
(https://opensource.org/licenses/BSD-2-Clause).
- Test suite made discoverable by unittest/unittest2 discovery feature.
- Fix to decoder working on indefinite length substrate -- end-of-octets
marker is now detected by both tag and value. Otherwise zero values may
interfere with end-of-octets marker.
- Fix to decoder to fail in cases where tagFormat indicates inappropriate
format for the type (e.g. BOOLEAN is always PRIMITIVE, SET is always
CONSTRUCTED and OCTET STRING is either of the two)
- Fix to REAL type encoder to force primitive encoding form encoding.
- Fix to CHOICE decoder to handle explicitly tagged, indefinite length
mode encoding
- Fix to REAL type decoder to handle negative REAL values correctly. Test
case added.
Revision 0.1.6
--------------
- The compact (valueless) way of encoding zero INTEGERs introduced in
0.1.5 seems to fail miserably as the world is filled with broken
BER decoders. So we had to back off the *encoder* for a while.
There's still the IntegerEncoder.supportCompactZero flag which
enables compact encoding form whenever it evaluates to True.
- Report package version on debugging code initialization.
Revision 0.1.5
--------------
- Documentation updated and split into chapters to better match
web-site contents.
- Make prettyPrint() working for non-initialized pyasn1 data objects. It
used to throw an exception.
- Fix to encoder to produce empty-payload INTEGER values for zeros
- Fix to decoder to support empty-payload INTEGER and REAL values
- Fix to unit test suites imports to be able to run each from
their current directory
Revision 0.1.4
--------------
- Built-in codec debugging facility added
- Added some more checks to ObjectIdentifier BER encoder catching
posible 2^8 overflow condition by two leading sub-OIDs
- Implementations overriding the AbstractDecoder.valueDecoder method
changed to return the rest of substrate behind the item being processed
rather than the unprocessed substrate within the item (which is usually
empty).
- Decoder's recursiveFlag feature generalized as a user callback function
which is passed an uninitialized object recovered from substrate and
its uninterpreted payload.
- Catch inappropriate substrate type passed to decoder.
- Expose tagMap/typeMap/Decoder objects at DER decoder to uniform API.
- Obsolete __init__.MajorVersionId replaced with __init__.__version__
which is now in-sync with distutils.
- Package classifiers updated.
- The __init__.py's made non-empty (rumors are that they may be optimized
out by package managers).
- Bail out gracefully whenever Python version is older than 2.4.
- Fix to Real codec exponent encoding (should be in 2's complement form),
some more test cases added.
- Fix in Boolean truth testing built-in methods
- Fix to substrate underrun error handling at ObjectIdentifier BER decoder
- Fix to BER Boolean decoder that allows other pre-computed
values besides 0 and 1
- Fix to leading 0x80 octet handling in DER/CER/DER ObjectIdentifier decoder.
See https://www.esat.kuleuven.be/cosic/publications/article-1432.pdf
Revision 0.1.3
--------------
- Include class name into asn1 value constraint violation exception.
- Fix to OctetString.prettyOut() method that looses leading zero when
building hex string.
Revision 0.1.2
--------------
- Fix to __long__() to actually return longs on py2k
- Fix to OctetString.__str__() workings of a non-initialized object.
- Fix to quote initializer of OctetString.__repr__()
- Minor fix towards ObjectIdentifier.prettyIn() reliability
- ObjectIdentifier.__str__() is aliased to prettyPrint()
- Exlicit repr() calls replaced with '%r'
Revision 0.1.1
--------------
- Hex/bin string initializer to OctetString object reworked
(in a backward-incompatible manner)
- Fixed float() infinity compatibility issue (affects 2.5 and earlier)
- Fixed a bug/typo at Boolean CER encoder.
- Major overhawl for Python 2.4 -- 3.2 compatibility:
+ get rid of old-style types
+ drop string module usage
+ switch to rich comparation
+ drop explicit long integer type use
+ map()/filter() replaced with list comprehension
+ apply() replaced with \*/\*\*args
+ switched to use 'key' sort() callback function
+ support both __nonzero__() and __bool__() methods
+ modified not to use py3k-incompatible exception syntax
+ getslice() operator fully replaced with getitem()
+ dictionary operations made 2K/3K compatible
+ base type for encoding substrate and OctetString-based types
is now 'bytes' when running py3k and 'str' otherwise
+ OctetString and derivatives now unicode compliant.
+ OctetString now supports two python-neutral getters: asOcts() & asInts()
+ print OctetString content in hex whenever it is not printable otherwise
+ in test suite, implicit relative import replaced with the absolute one
+ in test suite, string constants replaced with numerics
Revision 0.0.13
---------------
- Fix to base10 normalization function that loops on univ.Real(0)
Revision 0.0.13b
----------------
- ASN.1 Real type is now supported properly.
- Objects of Constructed types now support __setitem__()
- Set/Sequence objects can now be addressed by their field names (string index)
and position (integer index).
- Typo fix to ber.SetDecoder code that prevented with schema decoding
operation.
- Fix to explicitly tagged items decoding support.
- Fix to OctetString.prettyPrint() to better handle non-printable content.
- Fix to repr() workings of Choice objects.
Revision 0.0.13a
----------------
- Major codec re-design.
- Documentation significantly improved.
- ASN.1 Any type is now supported.
- All example ASN.1 modules moved to separate pyasn1-modules package.
- Fix to initial sub-OID overflow condition detection an encoder.
- BitString initialization value verification improved.
- The Set/Sequence.getNameByPosition() method implemented.
- Fix to proper behaviour of PermittedAlphabetConstraint object.
- Fix to improper Boolean substrate handling at CER/DER decoders.
- Changes towards performance improvement:
+ all dict.has_key() & dict.get() invocations replaced with modern syntax
(this breaks compatibility with Python 2.1 and older).
+ tag and tagset caches introduced to decoder
+ decoder code improved to prevent unnecessary pyasn1 objects creation
+ allow disabling components verification when setting components to
structured types, this is used by decoder whilst running with schema
mode.
+ BER decoder for integer values now looks up a small set of pre-computed
substrate values to save on decoding.
+ a few pre-computed values configured to ObjectIdentifier BER encoder.
+ ChoiceDecoder split-off SequenceOf one to save on unnecessary checks.
+ replace slow hasattr()/getattr() calls with isinstance() introspection.
+ track the number of initialized components of Constructed types to save
on default/optional components initialization.
+ added a shortcut ObjectIdentifier.asTuple() to be used instead of
__getitem__() in hotspots.
+ use Tag.asTuple() and pure integers at tag encoder.
+ introduce and use in decoder the baseTagSet attribute of the built-in
ASN.1 types.
Revision 0.0.12a
----------------
- The individual tag/length/value processing methods of
encoder.AbstractItemEncoder renamed (leading underscore stripped)
to promote overloading in cases where partial substrate processing
is required.
- The ocsp.py, ldap.py example scripts added.
- Fix to univ.ObjectIdentifier input value handler to disallow negative
sub-IDs.
Revision 0.0.11a
----------------
- Decoder can now treat values of unknown types as opaque OctetString.
- Fix to Set/SetOf type decoder to handle uninitialized scalar SetOf
components correctly.
Revision 0.0.10a
----------------
- API versioning mechanics retired (pyasn1.v1 -> pyasn1) what makes
it possible to zip-import pyasn1 sources (used by egg and py2exe).
Revision 0.0.9a
---------------
- Allow any non-zero values in Boolean type BER decoder, as it's in
accordnance with the standard.
Revision 0.0.8a
---------------
- Integer.__index__() now supported (for Python 2.5+).
- Fix to empty value encoding in BitString encoder, test case added.
- Fix to SequenceOf decoder that prevents it skipping possible Choice
typed inner component.
- Choice.getName() method added for getting currently set component
name.
- OctetsString.prettyPrint() does a single str() against its value
eliminating an extra quotes.
Revision 0.0.7a
---------------
- Large tags (>31) now supported by codecs.
- Fix to encoder to properly handle explicitly tagged untagged items.
- All possible value lengths (up to 256^126) now supported by encoders.
- Fix to Tag class constructor to prevent negative IDs.
Revision 0.0.6a
---------------
- Make use of setuptools.
- Constraints derivation verification (isSuperTypeOf()/isSubTypeOf()) fixed.
- Fix to constraints comparation logic -- can't cmp() hash values as it
may cause false positives due to hash conflicts.
Revision 0.0.5a
---------------
- Integer BER codec reworked fixing negative values encoding bug.
- clone() and subtype() methods of Constructed ASN.1 classes now
accept optional cloneValueFlag flag which controls original value
inheritance. The default is *not* to inherit original value for
performance reasons (this may affect backward compatibility).
Performance penalty may be huge on deeply nested Constructed objects
re-creation.
- Base ASN.1 types (pyasn1.type.univ.*) do not have default values
anymore. They remain uninitialized acting as ASN.1 types. In
this model, initialized ASN.1 types represent either types with
default value installed or a type instance.
- Decoders' prototypes are now class instances rather than classes.
This is to simplify initial value installation to decoder's
prototype value.
- Bugfix to BitString BER decoder (trailing bits not regarded).
- Bugfix to Constraints use as mapping keys.
- Bugfix to Integer & BitString clone() methods
- Bugix to the way to distinguish Set from SetOf at CER/DER SetOfEncoder
- Adjustments to make it running on Python 1.5.
- In tests, substrate constants converted from hex escaped literals into
octals to overcome indefinite hex width issue occuring in young Python.
- Minor performance optimization of TagSet.isSuperTagSetOf() method
- examples/sshkey.py added
Revision 0.0.4a
---------------
* Asn1Type.prettyPrinter() -> \*.prettyPrint()
Revision 0.0.3a
---------------
* Simple ASN1 objects now hash to their Python value and don't
depend upon tag/constraints/etc.
* prettyIn & prettyOut methods of SimplleAsn1Object become public
* many syntax fixes
Revision 0.0.2a
---------------
* ConstraintsIntersection.isSuperTypeOf() and
ConstraintsIntersection.hasConstraint() implemented
* Bugfix to NamedValues initialization code
* +/- operators added to NamedValues objects
* Integer.__abs__() & Integer.subtype() added
* ObjectIdentifier.prettyOut() fixes
* Allow subclass components at SequenceAndSetBase
* AbstractConstraint.__cmp__() dropped
* error.Asn1Error replaced with error.PyAsn1Error
Revision 0.0.1a
---------------
* Initial public alpha release

View File

@@ -0,0 +1,24 @@
Copyright (c) 2005-2020, Ilya Etingof <etingof@gmail.com>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

View File

@@ -0,0 +1,5 @@
include *.rst *.md
recursive-include tests *.py
recursive-include docs Makefile *.rst *.svg conf.py
prune docs/build
prune docs/source/.templates

View File

@@ -0,0 +1,188 @@
ASN.1 library for Python
------------------------
[![PyPI](https://img.shields.io/pypi/v/pyasn1.svg?maxAge=2592000)](https://pypi.org/project/pyasn1)
[![Python Versions](https://img.shields.io/pypi/pyversions/pyasn1.svg)](https://pypi.org/project/pyasn1/)
[![Build status](https://github.com/pyasn1/pyasn1/actions/workflows/main.yml/badge.svg)](https://github.com/pyasn1/pyasn1/actions/workflows/main.yml)
[![Coverage Status](https://img.shields.io/codecov/c/github/pyasn1/pyasn1.svg)](https://codecov.io/github/pyasn1/pyasn1)
[![GitHub license](https://img.shields.io/badge/license-BSD-blue.svg)](https://raw.githubusercontent.com/pyasn1/pyasn1/master/LICENSE.txt)
This is a free and open source implementation of ASN.1 types and codecs
as a Python package. 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](https://www.itu.int/rec/dologin_pub.asp?lang=e&id=T-REC-X.208-198811-W!!PDF-E&type=items).
**NOTE:** The package is now maintained by *Christian Heimes* and
*Simon Pichugin* in project https://github.com/pyasn1/pyasn1.
Features
--------
* Generic implementation of ASN.1 types (X.208)
* Standards compliant BER/CER/DER codecs
* Can operate on streams of serialized data
* Dumps/loads ASN.1 structures from Python types
* 100% Python, works with Python 3.8+
* MT-safe
* Contributed ASN.1 compiler [Asn1ate](https://github.com/kimgr/asn1ate)
Why using pyasn1
----------------
ASN.1 solves the data serialisation problem. This solution was
designed long ago by the wise Ancients. Back then, they did not
have the luxury of wasting bits. That is why ASN.1 is designed
to serialise data structures of unbounded complexity into
something compact and efficient when it comes to processing
the data.
That probably explains why many network protocols and file formats
still rely on the 30+ years old technology. Including a number of
high-profile Internet protocols and file formats.
Quite a number of books cover the topic of ASN.1.
[Communication between heterogeneous systems](http://www.oss.com/asn1/dubuisson.html)
by Olivier Dubuisson is one of those high quality books freely
available on the Internet.
The pyasn1 package is designed to help Python programmers tackling
network protocols and file formats at the comfort of their Python
prompt. The tool struggles to capture all aspects of a rather
complicated ASN.1 system and to represent it on the Python terms.
How to use pyasn1
-----------------
With pyasn1 you can build Python objects from ASN.1 data structures.
For example, the following ASN.1 data structure:
```bash
Record ::= SEQUENCE {
id INTEGER,
room [0] INTEGER OPTIONAL,
house [1] INTEGER DEFAULT 0
}
```
Could be expressed in pyasn1 like this:
```python
class Record(Sequence):
componentType = NamedTypes(
NamedType('id', Integer()),
OptionalNamedType(
'room', Integer().subtype(
implicitTag=Tag(tagClassContext, tagFormatSimple, 0)
)
),
DefaultedNamedType(
'house', Integer(0).subtype(
implicitTag=Tag(tagClassContext, tagFormatSimple, 1)
)
)
)
```
It is in the spirit of ASN.1 to take abstract data description
and turn it into a programming language specific form.
Once you have your ASN.1 data structure expressed in Python, you
can use it along the lines of similar Python type (e.g. ASN.1
`SET` is similar to Python `dict`, `SET OF` to `list`):
```python
>>> record = Record()
>>> record['id'] = 123
>>> record['room'] = 321
>>> str(record)
Record:
id=123
room=321
>>>
```
Part of the power of ASN.1 comes from its serialisation features. You
can serialise your data structure and send it over the network.
```python
>>> from pyasn1.codec.der.encoder import encode
>>> substrate = encode(record)
>>> hexdump(substrate)
00000: 30 07 02 01 7B 80 02 01 41
```
Conversely, you can turn serialised ASN.1 content, as received from
network or read from a file, into a Python object which you can
introspect, modify, encode and send back.
```python
>>> from pyasn1.codec.der.decoder import decode
>>> received_record, rest_of_substrate = decode(substrate, asn1Spec=Record())
>>>
>>> for field in received_record:
>>> print('{} is {}'.format(field, received_record[field]))
id is 123
room is 321
house is 0
>>>
>>> record == received_record
True
>>> received_record.update(room=123)
>>> substrate = encode(received_record)
>>> hexdump(substrate)
00000: 30 06 02 01 7B 80 01 7B
```
The pyasn1 classes struggle to emulate their Python prototypes (e.g. int,
list, dict etc.). But ASN.1 types exhibit more complicated behaviour.
To make life easier for a Pythonista, they can turn their pyasn1
classes into Python built-ins:
```python
>>> from pyasn1.codec.native.encoder import encode
>>> encode(record)
{'id': 123, 'room': 321, 'house': 0}
```
Or vice-versa -- you can initialize an ASN.1 structure from a tree of
Python objects:
```python
>>> from pyasn1.codec.native.decoder import decode
>>> record = decode({'id': 123, 'room': 321, 'house': 0}, asn1Spec=Record())
>>> str(record)
Record:
id=123
room=321
>>>
```
With ASN.1 design, serialisation codecs are decoupled from data objects,
so you could turn every single ASN.1 object into many different
serialised forms. As of this moment, pyasn1 supports BER, DER, CER and
Python built-ins codecs. The extremely compact PER encoding is expected
to be introduced in the upcoming pyasn1 release.
More information on pyasn1 APIs can be found in the
[documentation](https://pyasn1.readthedocs.io/en/latest/pyasn1/contents.html),
compiled ASN.1 modules for different protocols and file formats
could be found in the pyasn1-modules
[repo](https://github.com/pyasn1/pyasn1-modules).
How to get pyasn1
-----------------
The pyasn1 package is distributed under terms and conditions of 2-clause
BSD [license](https://pyasn1.readthedocs.io/en/latest/license.html). Source code is freely
available as a GitHub [repo](https://github.com/pyasn1/pyasn1).
You could `pip install pyasn1` or download it from [PyPI](https://pypi.org/project/pyasn1).
If something does not work as expected,
[open an issue](https://github.com/epyasn1/pyasn1/issues) at GitHub or
post your question [on Stack Overflow](https://stackoverflow.com/questions/ask)
or try browsing pyasn1
[mailing list archives](https://sourceforge.net/p/pyasn1/mailman/pyasn1-users/).
Copyright (c) 2005-2020, [Ilya Etingof](mailto:etingof@gmail.com).
All rights reserved.

View File

@@ -0,0 +1,11 @@
Denis S. Otkidach
Gregory Golberg
Bud P. Bruegger
Jacek Konieczny
Tanya Tereschenko
Matěj Cepl
Alex Gaynor
Geoffrey Thomas
Daniel Bratell
Kim Gräsman
Russ Housley

View File

@@ -0,0 +1,92 @@
Things to be done
=================
Big things to tackle, anyone interested is welcome to fork pyasn1, work on
it and come up with a PR!
New codecs
----------
* PER
* OER
* XER
* LWER
* JSON (alinged with existing experimental schemas)
Lazy codecs
-----------
Implement a thin layer over base types to cache pieces
of substrate being decoded till the very moment of ASN.1
object access in the parse tree.
Codecs generator interface
--------------------------
For indefinite length or chunked encoding mode, make codecs
iterable producing/consuming substrate/objects.
ASN.1 schema compiler
---------------------
Ideally, the compiler should parse modern schema files and be
designed to emit code for arbitrary languages (including SQL).
Base types
----------
Implement X.680 constructs, including information schema.
Examples
--------
Add examples, including advanced/obscure use cases.
Documentation
-------------
Document more API, add notes and example snippets.
More fresh modules
------------------
Compile and ship more Pythonized ASN.1 modules for
various ASN.1-based protocols (e.g. Kerberos etc).
Refresh outdated modules in pyasn1-packages.
Minor, housekeeping things
--------------------------
* more PEP8'ing at places
* consider simplifying repr(), otherwise it tend to be too hard to grasp
* Specialize ASN.1 character and useful types
* ber.decoder:
* suspend codec on underrun error ?
* present subtypes ?
* component presence check wont work at innertypeconst
* type vs value, defaultValue
* ber.encoder:
* Asn1Item.clone() / shallowcopy issue
* large length encoder?
* lookup type by tag first to allow custom codecs for non-base types
* type.useful:
* may need to implement prettyIn/Out
* type.char:
* may need to implement constraints
* type.namedtypes
* type vs tagset name convention
* how untagged TagSet should be initialized?
* type and codecs for Real needs refactoring

View File

@@ -0,0 +1,2 @@
sphinx<1.5; python_version < '3.4'
sphinx; python_version >= '3.4'

View File

@@ -0,0 +1,192 @@
# Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = build
# User-friendly check for sphinx-build
ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
endif
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " applehelp to make an Apple Help Book"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " texinfo to make Texinfo files"
@echo " info to make Texinfo files and run them through makeinfo"
@echo " gettext to make PO message catalogs"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " xml to make Docutils-native XML files"
@echo " pseudoxml to make pseudoxml-XML files for display purposes"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
@echo " coverage to run coverage check of the documentation (if enabled)"
clean:
rm -rf $(BUILDDIR)/*
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/PyASN1.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/PyASN1.qhc"
applehelp:
$(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp
@echo
@echo "Build finished. The help book is in $(BUILDDIR)/applehelp."
@echo "N.B. You won't be able to view it unless you put it in" \
"~/Library/Documentation/Help or install it in your application" \
"bundle."
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/PyASN1"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/PyASN1"
@echo "# devhelp"
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
latexpdfja:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through platex and dvipdfmx..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
texinfo:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
@echo "Run \`make' in that directory to run these through makeinfo" \
"(use \`make info' here to do that automatically)."
info:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo "Running Texinfo files through makeinfo..."
make -C $(BUILDDIR)/texinfo info
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
gettext:
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
@echo
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."
coverage:
$(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage
@echo "Testing of coverage in the sources finished, look at the " \
"results in $(BUILDDIR)/coverage/python.txt."
xml:
$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
@echo
@echo "Build finished. The XML files are in $(BUILDDIR)/xml."
pseudoxml:
$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
@echo
@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."

View File

@@ -0,0 +1,10 @@
@import url("../pygments.css");
@import url("theme.css");
/* fix horizontal padding to accomodate adsense banners */
.wy-nav-content {
padding: 1.618em 2.236em;
height: 100%;
/* max-width: 800px; */
margin: auto;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@@ -0,0 +1,95 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg viewBox="0 0 788.22937 829.02386" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<filter id="j">
<feGaussianBlur stdDeviation="6.2732"/>
</filter>
<filter id="g">
<feGaussianBlur stdDeviation=".64973"/>
</filter>
<filter id="l" x="-.06193" y="-.19499" width="1.1239" height="1.39">
<feGaussianBlur stdDeviation="7.46855"/>
</filter>
<filter id="k" x="-.25093" y="-.14188" width="1.5019" height="1.2838">
<feGaussianBlur stdDeviation="3.07792"/>
</filter>
<filter id="i" x="-.03871" y="-.12187" width="1.0774" height="1.2437">
<feGaussianBlur stdDeviation="4.66785"/>
</filter>
<filter id="h" x="-.12783" y="-.07846" width="1.2557" height="1.1569">
<feGaussianBlur stdDeviation="1.708"/>
</filter>
<linearGradient id="e">
<stop stop-color="#817e7e" offset="0"/>
<stop stop-color="#f4ebeb" stop-opacity=".98824" offset=".5"/>
<stop stop-color="#241b1b" stop-opacity=".97826" offset="1"/>
</linearGradient>
<linearGradient id="f">
<stop stop-color="#1a5b78" offset="0"/>
<stop stop-color="#136890" offset="1"/>
</linearGradient>
<linearGradient id="r" x1="301.38" x2="318.52" y1="716.86" y2="106.67" gradientUnits="userSpaceOnUse">
<stop stop-color="#3aacfa" offset="0"/>
<stop stop-color="#2699d7" stop-opacity=".99608" offset=".83216"/>
<stop stop-color="#78c1e7" stop-opacity=".99216" offset=".98972"/>
<stop stop-color="#cae9f7" stop-opacity=".99216" offset="1"/>
</linearGradient>
<linearGradient id="q" x1="-6.9187" x2="583.27" gradientUnits="userSpaceOnUse">
<stop stop-color="#d4f6f7" offset="0"/>
<stop stop-color="#bdf0f2" offset=".5"/>
<stop stop-color="#76eaf0" offset=".75"/>
<stop stop-color="#465758" offset="1"/>
</linearGradient>
<linearGradient id="d" x1="172.72" x2="402.47" gradientUnits="userSpaceOnUse">
<stop stop-color="#2a9cf9" offset="0"/>
<stop stop-color="#afe2eb" offset="1"/>
</linearGradient>
<linearGradient id="c" x1="286.18" x2="292.27" y1="332.78" y2="297.07" gradientUnits="userSpaceOnUse">
<stop stop-color="#241b1b" offset="0"/>
<stop stop-color="#241b1b" stop-opacity="0" offset="1"/>
</linearGradient>
<linearGradient id="b" x1="291.93" x2="290.42" y1="654.44" y2="584.74" gradientUnits="userSpaceOnUse">
<stop stop-color="#4ec7ff" offset="0"/>
<stop stop-color="#177ba9" offset="1"/>
</linearGradient>
<linearGradient id="p" x1="166.1" x2="410.06" y1="529.93" y2="527.91" gradientUnits="userSpaceOnUse" xlink:href="#f"/>
<linearGradient id="o" x1="257.31" x2="320.16" gradientUnits="userSpaceOnUse" xlink:href="#e"/>
<linearGradient id="n" x1="229.49" x2="343.96" gradientUnits="userSpaceOnUse" xlink:href="#e"/>
<linearGradient id="m" x1="63.378" x2="507.69" y1="571" y2="567.46" gradientUnits="userSpaceOnUse" xlink:href="#f"/>
<radialGradient id="a" cx="288.79" cy="314.87" r="47.676" gradientTransform="matrix(.95889 0 0 .36279 11.873 202.26)" gradientUnits="userSpaceOnUse">
<stop stop-color="#f9faf8" offset="0"/>
<stop stop-color="#ccceca" stop-opacity=".67816" offset=".80581"/>
<stop stop-color="#a0a39d" stop-opacity=".98551" offset="1"/>
</radialGradient>
</defs>
<g transform="translate(36.408 -60.696)">
<path d="m217.12 214.13 1.8398 157.37s-68.072 76.035-114.07 139.69-123.27 152.07-110.39 206.89 147.18 111.4 270.45 109.63 316.44-30.06 318.28-100.79-88.31-185.67-121.43-229.87-101.19-123.78-101.19-123.78l-3.6796-159.14s-27.597 14.146-69.912 14.146-69.912-14.146-69.912-14.146z" fill="url(#q)" opacity=".59004"/>
<g transform="matrix(1.0193 0 0 .9797 275.35 -97.577)">
<path transform="matrix(1.0949 0 0 1.1946 -27.22 -91.679)" d="m433.86 608.91c0 25.384-64.786 45.962-144.7 45.962s-144.7-20.578-144.7-45.962 64.786-45.962 144.7-45.962 144.7 20.578 144.7 45.962z" filter="url(#l)"/>
<path d="m320.16 384.59c-20.034 6.3449-42.056 6.5046-62.156 0.15625 0.29535 26.623 0.5955 5.2459 0.875 31.875 6e-3 1.2834-0.46958 2.5635-1.3125 3.5312-27.411 31.834-52.856 65.234-76.938 99.75-17.564 25.17-36.956 49.209-44.688 77.531l-0.0312 0.0625c-2.7636 9.7018-0.36414 20.52 6.75 27.375l0.0937 0.0937c19.862 20.02 48.023 30.265 75.875 37.5 41.373 10.675 85.409 6.8178 128.31 1.0625v-0.0312c28.981-4.768 58.19-10.111 82.5-24.812-3e-5 -0.0104-3e-5 -0.0208 0-0.0312 4.5579-2.7227 8.8864-6.5506 11.625-10.781s3.9643-8.6335 3.0312-13.531c-0.0253-0.1242-0.0461-0.24931-0.0625-0.375-3.0304-25.717-17.046-49.326-30.906-72.375-0.0239-0.0398-0.0386-0.0852-0.0625-0.125-26.805-42.168-58.009-81.435-89.844-120.41-0.75007-0.90889-1.1862-2.072-1.2188-3.25-0.64083-27.08-1.2331-6.1494-1.8438-33.219z" fill="url(#p)"/>
<path d="m308.76 387.93c-15.75 1.6761-28.556 1.9621-44.482-1.3589 0.21917 26.636 0.31563 3.3544 0.52303 29.996 5e-3 1.284-0.34845 2.5647-0.97395 3.533-20.341 31.85-39.222 65.266-57.092 99.798-13.034 25.182-27.423 49.233-33.161 77.569l-0.0232 0.0625c-2.0508 9.7065-0.27021 20.53 5.0089 27.388l0.0696 0.0937c11.203 12.958 20.695 21.066 48.728 28.023s68.254 7.0598 102.79 2.5782c20.824-2.7021 47.44-9.1506 61.22-16.876-3e-5 -0.0104-3e-5 -0.0208 0-0.0312 3.3822-2.724 6.5943-6.5538 8.6265-10.786s2.9418-8.6377 2.2494-13.538c-0.0188-0.12426-0.0342-0.24943-0.0464-0.37518-2.2487-25.729-12.649-49.35-22.934-72.41-0.0178-0.0398-0.0286-0.0852-0.0464-0.12506-19.891-42.189-43.047-81.475-66.67-120.46-0.5566-0.90934-0.88028-2.073-0.90439-3.2516-0.47553-27.093 0.0951-3.1219-0.35803-30.204z" fill="url(#d)" filter="url(#j)"/>
<path transform="matrix(1 0 0 .9375 0 20.254)" d="m324.07 315.36c0 4.8113-15.991 8.7116-35.718 8.7116s-35.718-3.9003-35.718-8.7116 15.991-8.7116 35.718-8.7116 35.718 3.9003 35.718 8.7116z" fill="url(#c)"/>
<path transform="matrix(1 0 0 1.087 0 -51.618)" d="m433.86 608.91c0 25.384-64.786 45.962-144.7 45.962s-144.7-20.578-144.7-45.962 64.786-45.962 144.7-45.962 144.7 20.578 144.7 45.962z" fill="url(#b)" filter="url(#i)" opacity=".7"/>
<path transform="matrix(.74812 .4869 -.42145 .93332 324.55 94.283)" d="m105.06 429.6c0 15.342-4.7487 27.779-10.607 27.779s-10.607-12.437-10.607-27.779 4.7487-27.779 10.607-27.779 10.607 12.437 10.607 27.779z" fill="#fff" filter="url(#h)"/>
<path transform="matrix(.69501 .29687 -.29983 .73496 329.84 101.99)" d="m105.06 429.6c0 15.342-4.7487 27.779-10.607 27.779s-10.607-12.437-10.607-27.779 4.7487-27.779 10.607-27.779 10.607 12.437 10.607 27.779z" fill="#fff" filter="url(#k)"/>
<path d="m293.58 299.25c4.5514 0.12881 9.3278 0.24858 13.379 0.77697 5.2851 0.68931 10.077 1.7034 14.201 3.0024s7.6027 2.8509 10.281 4.932 4.6532 4.9568 4.3302 8.2969-2.8562 6.2388-5.9368 8.3199-6.8597 3.633-11.235 4.932c-8.7499 2.598-19.953 4.0562-32.144 4.0562s-23.083-1.4582-31.33-4.0562c-4.1238-1.299-7.6317-2.8509-10.31-4.932s-4.6509-4.9799-4.328-8.3199 2.8539-6.2158 5.9346-8.2969 6.8887-3.633 11.264-4.932c6.6932-1.9873 14.805-3.3077 23.705-3.8187 2.7349-0.15701-1.2073-0.23758 1.6582-0.23758l0.0765 9.2646c-3.7487 0.11199-7.3905 0.29917-9.7411 0.60179-4.7649 0.61344-9.0159 1.4835-12.472 2.5098s-6.0905 2.2331-7.5611 3.2266-1.6214 1.4742-1.6415 1.6824 0.0354 0.71198 1.3139 1.7055 3.6792 2.2003 6.9372 3.2266c6.5161 2.0526 16.331 3.4801 27.355 3.4801s21.144-1.4275 28.057-3.4801c3.4565-1.0263 6.0905-2.2331 7.5612-3.2266s1.5946-1.4972 1.6147-1.7055-9e-3 -0.68892-1.2872-1.6824-3.6792-2.2002-6.9372-3.2266-7.348-1.8963-12.002-2.5098-5.0792-0.75252-10.591-0.75252z" fill="url(#a)" filter="url(#g)" opacity=".64751"/>
<path d="m257.31 330.38c17.886 5.8187 39.891 3.5219 62.41-1.0835l0.44026 55.295c-21.953 6.8399-42.524 6.0827-62.156 0.15625z" fill="url(#o)" opacity=".49808"/>
<path d="m286.61 386.36h0.43558v3.0491h-0.43558z" fill="#241b1b" opacity=".64751"/>
<path d="m290.1 385.92h0.43558v3.4846h-0.43558z" fill="#241b1b" opacity=".64751"/>
<path d="m317.86 382.77c0 3.7423-12.687 6.776-28.336 6.776s-28.336-3.0337-28.336-6.776 12.687-6.776 28.336-6.776 28.336 3.0337 28.336 6.776z" fill="#135f9b" opacity=".68199"/>
</g>
<path transform="matrix(1.9941 0 0 2.091 -288.72 -517.12)" d="m433.86 608.91c0 25.384-64.786 45.962-144.7 45.962s-144.7-20.578-144.7-45.962 64.786-45.962 144.7-45.962 144.7 20.578 144.7 45.962z" filter="url(#l)"/>
<path d="m343.96 316.59c-36.488 11.107-76.596 11.386-113.2 0.27351 0.53792 46.603 1.0846 9.1828 1.5936 55.796 0.0109 2.2465-0.85524 4.4873-2.3904 6.1814-49.924 55.725-96.267 114.19-140.13 174.61-31.99 44.059-67.307 86.139-81.389 135.72l-0.05682 0.1094c-5.0334 16.983-0.66321 35.921 12.294 47.919 0.05755 0.0539 0.11456 0.10871 0.17066 0.16402 36.175 35.044 87.464 52.978 138.19 65.643 75.353 18.686 155.55 11.934 233.69 1.8599v-0.0546c52.783-8.3462 105.98-17.699 150.26-43.434-5e-5 -0.0182-5e-5 -0.0364 0-0.0546 8.3013-4.766 16.185-11.467 21.173-18.872s7.2202-15.113 5.5208-23.686c-0.0461-0.21741-0.084-0.43641-0.11383-0.65643-5.5192-45.016-31.045-86.344-56.289-126.69-0.0435-0.0697-0.0703-0.14914-0.11383-0.21881-48.821-73.814-105.65-142.55-163.63-210.77-1.3661-1.591-2.1605-3.627-2.2197-5.689-1.1671-47.402-2.2458-10.764-3.358-58.149z" fill="url(#m)"/>
<path transform="matrix(1.8213 0 0 1.7505 -239.14 -356.63)" d="m308.76 387.93c-15.75 1.6761-28.556 1.9621-44.482-1.3589 0.21917 26.636 0.31563 3.3544 0.52303 29.996 5e-3 1.284-0.34845 2.5647-0.97395 3.533-20.341 31.85-39.222 65.266-57.092 99.798-13.034 25.182-27.423 49.233-33.161 77.569l-0.0232 0.0625c-2.0508 9.7065-0.27021 20.53 5.0089 27.388l0.0696 0.0937c11.203 12.958 20.695 21.066 48.728 28.023s68.254 7.0598 102.79 2.5782c20.824-2.7021 47.44-9.1506 61.22-16.876-3e-5 -0.0104-3e-5 -0.0208 0-0.0312 3.3822-2.724 6.5943-6.5538 8.6265-10.786s2.9418-8.6377 2.2494-13.538c-0.0188-0.12426-0.0342-0.24943-0.0464-0.37518-2.2487-25.729-12.649-49.35-22.934-72.41-0.0178-0.0398-0.0286-0.0852-0.0464-0.12506-19.891-42.189-43.047-81.475-66.67-120.46-0.5566-0.90934-0.88028-2.073-0.90439-3.2516-0.47553-27.093 0.0951-3.1219-0.35803-30.204z" fill="url(#d)" filter="url(#j)"/>
<path transform="matrix(1.8213 0 0 1.6411 -239.14 -321.18)" d="m324.07 315.36c0 4.8113-15.991 8.7116-35.718 8.7116s-35.718-3.9003-35.718-8.7116 15.991-8.7116 35.718-8.7116 35.718 3.9003 35.718 8.7116z" fill="url(#c)"/>
<path transform="matrix(1.8213 0 0 1.9027 -239.14 -446.99)" d="m433.86 608.91c0 25.384-64.786 45.962-144.7 45.962s-144.7-20.578-144.7-45.962 64.786-45.962 144.7-45.962 144.7 20.578 144.7 45.962z" fill="url(#b)" filter="url(#i)" opacity=".7"/>
<path transform="matrix(1.3625 .8523 -.76759 1.6338 351.96 -191.6)" d="m105.06 429.6c0 15.342-4.7487 27.779-10.607 27.779s-10.607-12.437-10.607-27.779 4.7487-27.779 10.607-27.779 10.607 12.437 10.607 27.779z" fill="#fff" filter="url(#h)"/>
<path transform="matrix(1.2658 .51966 -.54607 1.2865 361.6 -178.11)" d="m105.06 429.6c0 15.342-4.7487 27.779-10.607 27.779s-10.607-12.437-10.607-27.779 4.7487-27.779 10.607-27.779 10.607 12.437 10.607 27.779z" fill="#fff" filter="url(#k)"/>
<path d="m282.86 319.68h0.79332v5.3373h-0.79332z" fill="#241b1b" opacity=".64751"/>
<path d="m289.21 318.92h0.79332v6.0998h-0.79332z" fill="#241b1b" opacity=".64751"/>
<path d="m229.49 221.69c32.576 10.186 72.653 6.165 113.67-1.8966l0.80184 96.793c-39.983 11.973-77.45 10.648-113.2 0.27351z" fill="url(#n)" opacity=".49808"/>
<path d="m314.53 88.096c11.175-7.4188 26.676-9.6276 40.922-9.6276 20.515 0 42.424 0.67751 63.119 1.3129-14.157 12.706-20.02 32.833-20.603 60.884s7.4772 46.002 19.522 56.234 26.603 12.035 36.71 12.035c9.5446 0 23.331-0.79894 35.231-9.8464s20.303-25.487 22.083-52.296c1.8812-28.327-6.4708-49.691-19.01-63.838 12.054 0.0088 22.878-0.32242 30.962 0.43762 11.434 1.0751 18.465 3.5429 26.636 14.168 6.5038 8.4571 10.278 28.096 11.099 50.764s-0.56916 48.252-0.56916 70.183h18.213c0-21.201 1.4303-46.992 0.56916-70.785s-3.2322-45.719-14.684-60.61c-10.902-14.176-25.129-19.764-39.499-21.115s-29.235 0.31775-46.898-0.71113c-4.6471-0.27069-8.9502-0.18951-13.261-0.10941-4.37-1.2458-8.7613-2.0787-13.091-2.0787-25.276 0-63.498-2.1334-96.529-2.1334-16.045 1.8e-5 -35.249 2.0482-51.281 12.691s-27.971 33.041-27.875 62.294l-0.30018 580.36c6.7459 3.5107 13.492 6.3162 20.238 0l-0.41466-580.94c0.37865-26.774 7.5356-39.862 18.711-47.281zm147.01-5.525h0.0568c15.896 5.5007 34.337 24.301 31.759 63.127-1.5853 23.871-8.3043 34.419-15.196 39.659s-15.555 6.072-23.961 6.072c-7.843 0-17.341-1.4545-24.644-7.6583s-13.892-17.899-13.375-42.723c0.53821-25.865 5.9461-40.522 14.798-48.466 6.639-5.9586 16.402-9.3 30.564-10.011z" fill="url(#r)" stroke="#000" stroke-opacity=".51587" stroke-width=".53566"/>
<path transform="matrix(1.8213 0 0 1.7505 -239.14 -356.63)" d="m293.58 299.25c4.5514 0.12881 9.3278 0.24858 13.379 0.77697 5.2851 0.68931 10.077 1.7034 14.201 3.0024s7.6027 2.8509 10.281 4.932 4.6532 4.9568 4.3302 8.2969-2.8562 6.2388-5.9368 8.3199-6.8597 3.633-11.235 4.932c-8.7499 2.598-19.953 4.0562-32.144 4.0562s-23.083-1.4582-31.33-4.0562c-4.1238-1.299-7.6317-2.8509-10.31-4.932s-4.6509-4.9799-4.328-8.3199 2.8539-6.2158 5.9346-8.2969 6.8887-3.633 11.264-4.932c6.6932-1.9873 14.805-3.3077 23.705-3.8187 2.7349-0.15701-1.2073-0.23758 1.6582-0.23758l0.0765 9.2646c-3.7487 0.11199-7.3905 0.29917-9.7411 0.60179-4.7649 0.61344-9.0159 1.4835-12.472 2.5098s-6.0905 2.2331-7.5611 3.2266-1.6214 1.4742-1.6415 1.6824 0.0354 0.71198 1.3139 1.7055 3.6792 2.2003 6.9372 3.2266c6.5161 2.0526 16.331 3.4801 27.355 3.4801s21.144-1.4275 28.057-3.4801c3.4565-1.0263 6.0905-2.2331 7.5612-3.2266s1.5946-1.4972 1.6147-1.7055-9e-3 -0.68892-1.2872-1.6824-3.6792-2.2002-6.9372-3.2266-7.348-1.8963-12.002-2.5098-5.0792-0.75252-10.591-0.75252z" fill="url(#a)" filter="url(#g)" opacity=".64751"/>
<path transform="matrix(1.8213 0 0 1.7505 -239.14 -356.63)" d="m317.86 382.77c0 3.7423-12.687 6.776-28.336 6.776s-28.336-3.0337-28.336-6.776 12.687-6.776 28.336-6.776 28.336 3.0337 28.336 6.776z" fill="#135f9b" opacity=".68199"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -0,0 +1,6 @@
Changelog
=========
.. include:: ../../CHANGES.rst

View File

@@ -0,0 +1,336 @@
# -*- coding: utf-8 -*-
#
# PyASN1 documentation build configuration file, created by
# sphinx-quickstart on Sat Jun 27 23:15:54 2015.
#
# This file is execfile()d with the current directory set to its
# containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
# sys.path.insert(0, os.path.abspath('.'))
import os, sys
# add ../.. to module lookup path
sys.path.insert(
0,
os.path.abspath(
os.path.join(os.path.dirname(__file__), "..", "..")
)
)
import pyasn1
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
# needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.napoleon',
'sphinx.ext.intersphinx',
]
# Add any paths that contain templates here, relative to this directory.
templates_path = ['.templates']
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
# source_suffix = ['.rst', '.md']
source_suffix = '.rst'
# The encoding of source files.
# source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'contents'
# General information about the project.
project = u'ASN.1 types and codecs'
copyright = u'2005-2020, Ilya Etingof <etingof@gmail.com>'
author = u'Ilya Etingof <etingof@gmail.com>'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = ".".join(pyasn1.__version__.split(".")[:2])
# The full version, including alpha/beta/rc tags.
release = pyasn1.__version__
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = "en"
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
# today = ''
# Else, today_fmt is used as the format for a strftime call.
# today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = []
# The reST default role (used for this markup: `text`) to use for all
# documents.
# default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
# add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
# add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
# show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
# modindex_common_prefix = []
# If true, keep warnings as "system message" paragraphs in the built documents.
# keep_warnings = False
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = False
# -- Options for HTML output ----------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'alabaster'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
html_theme_options = {
'logo': 'logo.svg',
'description': '<p align=left><i><b>Brewing free software for the greater good</i></b></p>',
'show_powered_by': False,
'github_user': 'etingof',
'github_repo': 'pyasn1',
'fixed_sidebar': True,
}
html_sidebars = {
'**': [
'about.html',
'navigation.html',
'relations.html',
'searchbox.html',
'donate.html',
]
}
# Add any paths that contain custom themes here, relative to this directory.
# html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
# html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
# html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
# html_logo = ""
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
html_favicon = '.static/favicon.ico'
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['.static']
# Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied
# directly to the root of the documentation.
# html_extra_path = []
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
# html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
# html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
# html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
# html_additional_pages = {}
# If false, no module index is generated.
# html_domain_indices = True
# If false, no index is generated.
# html_use_index = True
# If true, the index is split into individual pages for each letter.
# html_split_index = False
# If true, links to the reST sources are added to the pages.
html_show_sourcelink = False
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
html_show_sphinx = False
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
# html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
# html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
# html_file_suffix = None
# Language to be used for generating the HTML full-text search index.
# Sphinx supports the following languages:
# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja'
# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr'
# html_search_language = 'en'
# A dictionary with options for the search language support, empty by default.
# Now only 'ja' uses this config value
# html_search_options = {'type': 'default'}
# The name of a javascript file (relative to the configuration directory) that
# implements a search results scorer. If empty, the default will be used.
# html_search_scorer = 'scorer.js'
# Output file base name for HTML help builder.
htmlhelp_basename = 'pyasn1doc'
# html_context = {
# 'include_analytics': 'PYASN1DEV' in os.environ
# }
# -- Options for LaTeX output ---------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
# 'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
# 'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
# 'preamble': '',
# Latex figure (float) alignment
# 'figure_align': 'htbp',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(master_doc, 'PyASN1.tex', u'PyASN1 Documentation',
u'Ilya Etingof \\textless{}etingof@gmail.com\\textgreater{}', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
# latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
# latex_use_parts = False
# If true, show page references after internal links.
# latex_show_pagerefs = False
# If true, show URL addresses after external links.
# latex_show_urls = False
# Documents to append as an appendix to all manuals.
# latex_appendices = []
# If false, no module index is generated.
# latex_domain_indices = True
# -- Options for manual page output ---------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
(master_doc, 'pyasn1', u'PyASN1 Documentation',
[author], 1)
]
# If true, show URL addresses after external links.
# man_show_urls = False
# -- Options for Texinfo output -------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(master_doc, 'PyASN1', u'PyASN1 Documentation',
author, 'PyASN1', 'One line description of project.',
'Miscellaneous'),
]
# Documents to append as an appendix to all manuals.
# texinfo_appendices = []
# If false, no module index is generated.
# texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
# texinfo_show_urls = 'footnote'
# If true, do not generate a @detailmenu in the "Top" node's menu.
# texinfo_no_detailmenu = False
# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {'python': ('https://docs.python.org/3.10/', None)}
# this merges constructor docstring with class docstring
autoclass_content = 'both'
# Sort members by type
autodoc_member_order = 'bysource'
# autodoc_member_order = 'groupwise'
# Napoleon settings
napoleon_google_docstring = False
napoleon_numpy_docstring = True
napoleon_include_private_with_doc = False
napoleon_include_special_with_doc = True
napoleon_use_admonition_for_examples = False
napoleon_use_admonition_for_notes = False
napoleon_use_admonition_for_references = False
napoleon_use_ivar = False
napoleon_use_param = False
napoleon_use_rtype = False

View File

@@ -0,0 +1,168 @@
.. _Start Content:
ASN.1 library for Python
========================
.. toctree::
:maxdepth: 1
Abstract Syntax Notation One (`ASN.1
<http://en.wikipedia.org/wiki/Abstract_Syntax_Notation_1x>`_) is a
technology for exchanging structured data in a universally understood,
hardware agnostic way. Many industrial, security and telephony
applications heavily rely on ASN.1.
The `pyasn1 <https://pypi.org/project/pyasn1/>`_ library implements
ASN.1 support in pure-Python.
What is ASN.1
-------------
ASN.1 is a large, arguably over-engineered and extremely old data modelling and
serialisation tool. It is probably among the first serialisation protocols in
the history of computer science and technology.
ASN.1 started its life over 30 years ago as a serialisation mechanism for the first
electronic mail (known as X.400). Later on if was split off the e-mail application
and become a stand-alone tech still being actively supported by its designers
and widely used in industry and technology.
Since then ASN.1 is sort of haunted by its relations with the OSI model -- the
first, unsuccessful, version of the Internet. You can read many interesting
`discussions <https://news.ycombinator.com/item?id=8871453>`_ on that topic.
In the following years, generations of software engineers tackled the serialisation
problem many times. We can see that in Google's `ProtoBuffers <https://developers.google.com/protocol-buffers/>`_
or `FlatBuffers <https://google.github.io/flatbuffers/>`_, for example.
Interestingly, many new takes on binary protocol design do not depart
far from ASN.1 from technical perspective. It's more of a matter of striking
a balance between processing overhead, wire format overhead and human
readability.
Looking at what ASN.1 has to offer, it has three loosely coupled parts:
* Data types: the standard introduces a collection of basic data types
(integers, bits, strings, arrays and records) that can be used for describing
arbitrarily complex, nested data structures.
* Serialisation protocols: the above data structures could be converted into a
series of octets for storage or transmission over the wire as well as
recovered back into their structured form. The system is fully agnostic
to hardware architectures differences.
* Schema language: ASN.1 data structures could be described in terms
of a schema language for ASN.1 compiler to turn it into platform-specific
implementation.
ASN.1 applications
------------------
Being an old and generally successful standard, ASN.1 is widely
adopted for many uses. To give you an example, these technologies
use ASN.1 for their data exchange needs:
* Signaling standards for the public switched telephone network (SS7 family)
* Network management standards (SNMP, CMIP)
* Directory standards (X.500 family, LDAP)
* Public Key Infrastructure standards (X.509, etc.)
* PBX control (CSTA)
* IP-based Videoconferencing (H.323 family)
* Biometrics (BIP, CBEFF, ACBio)
* Intelligent transportation (SAE J2735)
* Cellular telephony (GSM, GPRS/EDGE, UMTS, LTE)
ASN.1 gotchas
-------------
Apparently, ASN.1 is hard to implement properly. Quality open-source
ASN.1 tools are rare, but ad-hoc implementations are numerous. Judging from the
`statistics <http://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=ASN.1>`_ on discovered
security vulnerabilities, many people have implemented ASN.1 parsers
and oftentimes fell victim to its edge cases.
On the bright side, ASN.1 has been around for a long time, it is well understood
and security reviewed.
Documentation
-------------
.. toctree::
:maxdepth: 2
/pyasn1/contents
Use case
--------
.. toctree::
:maxdepth: 2
/example-use-case
Download & Install
------------------
.. toctree::
:maxdepth: 2
/download
Changes
-------
All changes and release history is maintained in changelog. There you
could also download the latest unreleased pyasn1 tarball containing
the latest fixes and improvements.
.. toctree::
:maxdepth: 1
/changelog
License
-------
The PyASN1 software is distributed under 2-clause BSD License.
.. toctree::
:maxdepth: 2
/license
Getting help
------------
Please, file your `issues <https://github.com/pyasn1/pyasn1/issues>`_
and `PRs <https://github.com/pyasn1/pyasn1/pulls>`_ at GitHub.
Alternatively, you could ask for help at
`Stack Overflow <http://stackoverflow.com/questions/tagged/pyasn1>`_
or search
`pyasn1-users <https://lists.sourceforge.net/lists/listinfo/pyasn1-users>`_
mailing list archive.
Books on ASN.1
--------------
The pyasn1 implementation is largely based on reading up the following awesome
books:
* `ASN.1 - Communication between heterogeneous systems <http://www.oss.com/asn1/dubuisson.html>`_ by Olivier Dubuisson
* `ASN.1 Complete <http://www.oss.com/asn1/resources/books-whitepapers-pubs/larmouth-asn1-book.pdf>`_ by Prof John Larmouth
Here you can get the official standards which is hard to read:
* `ITU standards <http://www.itu.int/ITU-T/studygroups/com17/languages/X.680-X.693-0207w.zip>`_
On the other end of the readability spectrum, here is a quick and sweet write up:
* `A Layman's Guide to a Subset of ASN.1, BER, and DER <https://www.researchgate.net/publication/2820226_A_Layman's_Guide_to_a_Subset_of_ASN1_BER_and_DER>`_ by Burton S. Kaliski
If you are working with ASN.1, we'd highly recommend reading a proper
book on the subject.
.. hidden toctree to include `index.rst` for RTD
.. toctree::
:hidden:
/index

View File

@@ -0,0 +1,24 @@
Download & Install
==================
The *pyasn1* library is a pure-Python package with no external
dependencies. It works with Python 3.8+.
The best way to obtain PyASN1 is by running `pip`:
.. code-block:: bash
$ virtualenv venv
$ source venv/bin/activate
$ pip install pyasn1
You may also want to use `pyasn1-modules`:
.. code-block:: bash
$ pip install pyasn1-modules
Alternatively, you can download the latest release from
`GitHub <https://github.com/pyasn1/pyasn1/releases>`_
or `PyPI <https://pypi.org/project/pyasn1>`_.

View File

@@ -0,0 +1,193 @@
Example use case
================
.. toctree::
:maxdepth: 2
To briefly explain how to approach pyasn1, consider a quick workflow example.
Grab ASN.1 schema for SSH keys
------------------------------
ASN.1 is widely used in many Internet protocols. Frequently, whenever ASN.1 is employed,
data structures are described in ASN.1 schema language right in the RFC.
Take `RFC2437 <https://www.ietf.org/rfc/rfc2437.txt>`_ for example -- we can look into
it and weed out data structures specification into a local file:
.. code-block:: python
# pkcs-1.asn
PKCS-1 {iso(1) member(2) us(840) rsadsi(113549) pkcs(1) pkcs-1(1) modules(0) pkcs-1(1)}
DEFINITIONS EXPLICIT TAGS ::= BEGIN
RSAPrivateKey ::= SEQUENCE {
version Version,
modulus INTEGER,
publicExponent INTEGER,
privateExponent INTEGER,
prime1 INTEGER,
prime2 INTEGER,
exponent1 INTEGER,
exponent2 INTEGER,
coefficient INTEGER
}
Version ::= INTEGER
END
Compile ASN.1 schema into Python
--------------------------------
In the best case, you should be able to automatically compile ASN.1 spec into
Python classes. For that purpose we have the `asn1ate <https://github.com/kimgr/asn1ate>`_
tool:
.. code-block:: bash
$ asn1ate pkcs-1.asn > rsakey.py
Though it may not work out as, as it stands now, asn1ate does not support
all ASN.1 language constructs.
Alternatively, you could check out the `pyasn1-modules <https://github.com/pyasn1/pyasn1-modules>`_
package to see if it already has the ASN.1 spec you are looking for compiled and shipped
there. Then just install the package, import the data structure you need and use it:
.. code-block:: bash
$ pip install pyasn1-modules
As a last resort, you could express ASN.1 in Python by hand. The end result
should be a declarative Python code resembling original ASN.1 syntax like
this:
.. code-block:: python
# rsakey.py
class Version(Integer):
pass
class RSAPrivateKey(Sequence):
componentType = NamedTypes(
NamedType('version', Version()),
NamedType('modulus', Integer()),
NamedType('publicExponent', Integer()),
NamedType('privateExponent', Integer()),
NamedType('prime1', Integer()),
NamedType('prime2', Integer()),
NamedType('exponent1', Integer()),
NamedType('exponent2', Integer()),
NamedType('coefficient', Integer())
)
Read your ~/.ssh/id_rsa
-----------------------
Given we've put our Python classes into the `rsakey.py` module, we could import
the top-level object for SSH keys container and initialize it from our
`~/.ssh/id_rsa` file (for sake of simplicity here we assume no passphrase is
set on the key file):
.. code-block:: python
from base64 import b64decode
from pyasn1.codec.der.decoder import decode as der_decoder
from rsakey import RSAPrivateKey
# Read SSH key from file (assuming no passphrase)
with open('.ssh/id_rsa') as key_file:
b64_serialisation = ''.join(key_file.readlines()[1:-1])
# Undo BASE64 serialisation
der_serialisation = b64decode(b64_serialisation)
# Undo DER serialisation, reconstruct SSH key structure
private_key, rest_of_input = der_decoder(der_serialisation, asn1Spec=RSAPrivateKey())
Once we have Python ASN.1 structures initialized, we could inspect them:
.. code-block:: pycon
>>> print('%s' % private_key)
RSAPrivateKey:
version=0
modulus=280789907761334970323210643584308373...
publicExponent=65537
privateExponent=1704567874679144879123080924...
prime1=1780178536719561265324798296279384073...
prime2=1577313184995269616049017780493740138...
exponent1=1193974819720845247396384239609024...
exponent2=9240965721817961178848297404494811...
coefficient=10207364473358910343346707141115...
Play with the keys
------------------
As well as use them nearly as we do with native Python types:
.. code-block:: pycon
>>> pk = private_key
>>>
>>> pk['prime1'] * pk['prime2'] == pk['modulus']
True
>>> pk['prime1'] == pk['modulus'] // pk['prime2']
True
>>> pk['exponent1'] == pk['privateExponent'] % (pk['prime1'] - 1)
True
>>> pk['exponent2'] == pk['privateExponent'] % (pk['prime2'] - 1)
True
Technically, pyasn1 classes `emulate <https://docs.python.org/3/reference/datamodel.html#emulating-container-types>`_
Python built-in types.
Transform to built-ins
----------------------
ASN.1 data structures exhibit a way more complicated behaviour compared to
Python types. You may wish to simplify things by turning the whole tree of
pyasn1 objects into an analogous tree made of base Python types:
.. code-block:: pycon
>>> from pyasn1.codec.native.encoder import encode
>>> ...
>>> py_private_key = encode(private_key)
>>> py_private_key
{'version': 0, 'modulus': 280789907761334970323210643584308373, 'publicExponent': 65537,
'privateExponent': 1704567874679144879123080924, 'prime1': 1780178536719561265324798296279384073,
'prime2': 1577313184995269616049017780493740138, 'exponent1': 1193974819720845247396384239609024,
'exponent2': 9240965721817961178848297404494811, 'coefficient': 10207364473358910343346707141115}
You can do vice-versa: initialize ASN.1 structure from a dict:
.. code-block:: pycon
>>> from pyasn1.codec.native.decoder import decode
>>> py_private_key = {'modulus': 280789907761334970323210643584308373}
>>> private_key = decode(py_private_key, asn1Spec=RSAPrivateKey())
Write it back
-------------
Possibly not that applicable to the SSH key example, but you can of course modify
any part of the ASN.1 data structure and serialise it back into the same or other
wire representation:
.. code-block:: python
from pyasn1.codec.der.encoder import encode as der_encoder
# Serialise SSH key data structure into DER stream
der_serialisation = der_encoder(private_key)
# Serialise DER stream into BASE64 stream
b64_serialisation = '-----BEGIN RSA PRIVATE KEY-----\n'
b64_serialisation += b64encode(der_serialisation)
b64_serialisation += '-----END RSA PRIVATE KEY-----\n'
with open('.ssh/id_rsa.new', 'w') as key_file:
key_file.write(b64_serialisation)

View File

@@ -0,0 +1,7 @@
Index
=====
.. Make RTD happy. We have a redirect index.html to contents.html.
:ref:`Start Content`

View File

@@ -0,0 +1,6 @@
.. _license:
License
=======
.. include:: ../../LICENSE.rst

View File

@@ -0,0 +1,7 @@
Basic Encoding Rules
--------------------
.. autofunction:: pyasn1.codec.ber.encoder.encode(value, asn1Spec=None, defMode=True, maxChunkSize=0)
.. autofunction:: pyasn1.codec.ber.decoder.decode(substrate, asn1Spec=None)

View File

@@ -0,0 +1,7 @@
Canonical Encoding Rules
------------------------
.. autofunction:: pyasn1.codec.cer.encoder.encode(value, asn1Spec=None)
.. autofunction:: pyasn1.codec.cer.decoder.decode(substrate, asn1Spec=None)

View File

@@ -0,0 +1,7 @@
Distinguished Encoding Rules
----------------------------
.. autofunction:: pyasn1.codec.der.encoder.encode(value, asn1Spec=None)
.. autofunction:: pyasn1.codec.der.decoder.decode(substrate, asn1Spec=None)

View File

@@ -0,0 +1,7 @@
Native Python types
-------------------
.. autofunction:: pyasn1.codec.native.encoder.encode(asn1Value)
.. autofunction:: pyasn1.codec.native.decoder.decode(pyObject, asn1Spec)

View File

@@ -0,0 +1,228 @@
.. _pyasn1-library:
Library documentation
=====================
As of this moment, pyasn1 library implements all ASN.1 data
types as Python objects in accordance with X.208 standard. Later,
post-1995, revision (X.680) introduced some changes to the schema
language which may not be fully supported by pyasn1. Aside from data
types a collection of data transformation codecs comes with the
pyasn1 package.
As for ASN.1 schema language, pyasn1 package does
not ship any compiler for it. However, there's a tool called
`asn1late <https://github.com/kimgr/asn1ate>`_ which is an ASN.1
grammar parser paired to code generator capable of generating pyasn1
code. So this is an alternative (or at least a good start) to manual
implementation of pyasn1 classes from ASN.1 specification.
Both `pyasn1 <https://github.com/pyasn1/pyasn1>`_ and
`pyasn1-modules <https://github.com/pyasn1/pyasn1-modules>`_ libraries
can be used out-of-the-box with Python versions 3.8+.
No external dependencies required.
.. _pyasn1-types:
ASN.1 types
-----------
The ASN.1 data description
`language <https://www.itu.int/rec/dologin_pub.asp?lang=e&id=T-REC-X.208-198811-W!!PDF-E&type=items>`_
defines a handful of built-in data types. ASN.1 types exhibit different
semantics (e.g. number vs string) and can be distinguished from each other by
:ref:`tags <type.tag>`.
Subtypes can be created on top of base ASN.1 types by adding/overriding the
:ref:`tags <type.tag>` and/or imposing additional
:ref:`constraints <type.constraint>` on accepted values.
ASN.1 types in pyasn1 are Python objects. One or more ASN.1 types
comprise a *schema* describing data structures of unbounded complexity.
.. code-block:: python
class RSAPublicKey(Sequence):
"""
ASN.1 specification:
RSAPublicKey ::= SEQUENCE {
modulus INTEGER, -- n
publicExponent INTEGER -- e
}
"""
componentType = NamedTypes(
NamedType('modulus', Integer()),
NamedType('publicExponent', Integer())
)
ASN.1 schema can be "instantiated" by essentially putting some concrete value
into the type container. Such instantiated schema object can still be
used as a schema, but additionally it can play a role of a value in the
context of any applicable operator (e.g. arithmetic etc.).
.. code-block:: python
rsaPublicKey = RSAPublicKey()
# ASN.1 SEQUENCE type quacks like Python dict
rsaPublicKey['modulus'] = 280789907761334970323210643584308373
rsaPublicKey['publicExponent'] = 65537
Main use of ASN.1 schemas is to guide data transformation. Instantiated
ASN.1 schemas carry concrete data to/from data transformation services.
.. _isValue:
To tell instantiated schema object from just a schema, the *.isValue*
property can come in handy:
.. code-block:: python
schema = RSAPublicKey()
# non-instantiated schema
assert schema.isValue == False
rsaPublicKey['modulus'] = 280789907761334970323210643584308373
# partially instantiated schema
assert schema['modulus'].isValue == True
assert schema.isValue == False
rsaPublicKey['publicExponent'] = 65537
# fully instantiated schema
assert schema.isValue == True
Copies of existing ASN.1 types can be created with *.clone()* method.
All the existing properties of the prototype ASN.1 object get copied
over the new type unless the replacements are given. Main use-case
for *.clone()* is to instantiate a schema.
.. _clone:
.. code-block:: python
instantiated_schema_A = Integer(1)
# ASN.1 INTEGER type quacks like Python int
assert instantiated_schema_A == 1
instantiated_schema_B = instantiated_schema_A.clone(2)
assert instantiated_schema_B == 2
.. _subtype:
New ASN.1 types can be created on top of existing ASN.1 types with
the *subtype()* method. Desired properties of the new type get
merged with the corresponding properties of the old type. Main use-case
for *.subtype()* is to assemble new ASN.1 types by :ref:`tagging <type.tag>`
or applying additional :ref:`constraints <type.constraint>` to accepted
type's values.
.. code-block:: python
parent_type_schema = Integer()
child_type_schema = parent_type_schema.subtype(
explicitTag=Tag(tag.tagClassApplication, tag.tagFormatSimple, 0x06)
)
# test ASN.1 type relationships
assert child_type_schema.isSubtypeOf(parent_type_schema) == True
assert child_type_schema.isSameTypeWith(parent_type_schema) == False
.. toctree::
:maxdepth: 2
/pyasn1/type/base/contents
/pyasn1/type/univ/contents
/pyasn1/type/char/contents
/pyasn1/type/useful/contents
ASN.1 type harness
++++++++++++++++++
The identification and behaviour of ASN.1 types is determined by
:ref:`tags <type.tag>` and :ref:`constraints <type.constraint>`.
The inner structure of *constructed* ASN.1 types is defined by
its :ref:`fields <type.namedtype>` specification.
.. toctree::
:maxdepth: 2
/pyasn1/type/tag/contents
/pyasn1/type/constraint/contents
/pyasn1/type/namedtype/contents
/pyasn1/type/opentype/contents
/pyasn1/type/namedval/contents
.. _pyasn1-codecs:
Serialisation codecs
--------------------
Common use-case for pyasn1 is to instantiate ASN.1 schema with
user-supplied values and pass instantiated schema to the encoder.
The encoder will then turn the data structure into serialised form
(stream of bytes) suitable for storing into a file or sending over
the network.
.. code-block:: python
value = 1
instantiated_schema = Integer(value)
serialised = encode(instantiated_schema)
Alternatively, value and schema can be passed separately:
.. code-block:: python
value = 1
schema = Integer()
serialised = encode(value, asn1Spec=schema)
At the receiving end, a decoder would be invoked and given the
serialised data as received from the network along with the ASN.1
schema describing the layout of the data structures. The outcome
would be an instance of ASN.1 schema filled with values as supplied
by the sender.
.. code-block:: python
serialised = b'\x01\x01\x01'
schema = Integer()
value, _ = decode(serialised, asn1Spec=schema)
assert value == 1
Many distinct serialisation protocols exist for ASN.1, some are
implemented in pyasn1.
.. toctree::
:maxdepth: 2
/pyasn1/codec/ber/contents
/pyasn1/codec/cer/contents
/pyasn1/codec/der/contents
/pyasn1/codec/native/contents
Exceptions
----------
Operations on PyASN1 schema and value objects might cause errors. These
errors are manifested to the caller in form of Python exceptions.
The exception hierarchy is as follows (ordered from least specific).
.. toctree::
:maxdepth: 2
/pyasn1/error/contents

View File

@@ -0,0 +1,60 @@
.. _error.PyAsn1Error:
.. |PyAsn1Error| replace:: PyAsn1Error
|PyAsn1Error|
-------------
.. autoclass:: pyasn1.error.PyAsn1Error
:members:
.. _error.ValueConstraintError:
.. |ValueConstraintError| replace:: ValueConstraintError
|ValueConstraintError|
----------------------
.. autoclass:: pyasn1.error.ValueConstraintError
:members:
.. _error.SubstrateUnderrunError:
.. |SubstrateUnderrunError| replace:: SubstrateUnderrunError
|SubstrateUnderrunError|
------------------------
.. autoclass:: pyasn1.error.SubstrateUnderrunError
:members:
.. _error.PyAsn1UnicodeError:
.. |PyAsn1UnicodeError| replace:: PyAsn1UnicodeError
|PyAsn1UnicodeError|
--------------------
.. autoclass:: pyasn1.error.PyAsn1UnicodeError
:members:
.. _error.PyAsn1UnicodeDecodeError:
.. |PyAsn1UnicodeDecodeError| replace:: PyAsn1UnicodeDecodeError
|PyAsn1UnicodeDecodeError|
--------------------------
.. autoclass:: pyasn1.error.PyAsn1UnicodeDecodeError
:members:
.. _error.PyAsn1UnicodeEncodeError:
.. |PyAsn1UnicodeEncodeError| replace:: PyAsn1UnicodeEncodeError
|PyAsn1UnicodeEncodeError|
--------------------------
.. autoclass:: pyasn1.error.PyAsn1UnicodeEncodeError
:members:

View File

@@ -0,0 +1,10 @@
.. _base.Asn1Type:
.. |ASN.1| replace:: Asn1Type
|ASN.1| type
------------
.. autoclass:: pyasn1.type.base.Asn1Type(tagSet=TagSet(), subtypeSpec=ConstraintsIntersection())
:members: isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap, subtypeSpec

View File

@@ -0,0 +1,10 @@
.. _base.ConstructedAsn1Type:
.. |ASN.1| replace:: ConstructedAsn1Type
|ASN.1| type
------------
.. autoclass:: pyasn1.type.base.ConstructedAsn1Type(tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), componentType=None)
:members: isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap, subtypeSpec

View File

@@ -0,0 +1,20 @@
.. _type.base:
ASN.1 type system
-----------------
The ASN.1 language defines a collection of data types such as *INTEGER*
or *SET*. With pyasn1, ASN.1 types are represented by Python classes.
The base classes are described in this part of the documentation.
User code might not need to use them directly, except for figuring out
if given object belongs to ASN.1 type or not.
.. toctree::
:maxdepth: 2
/pyasn1/type/base/asn1type
/pyasn1/type/base/simpleasn1type
/pyasn1/type/base/constructedasn1type
/pyasn1/type/base/novalue

View File

@@ -0,0 +1,6 @@
.. _type.base.NoValue:
NoValue sentinel
----------------
.. autoclass:: pyasn1.type.base.NoValue()

View File

@@ -0,0 +1,10 @@
.. _base.SimpleAsn1Type:
.. |ASN.1| replace:: SimpleAsn1Type
|ASN.1| type
------------
.. autoclass:: pyasn1.type.base.SimpleAsn1Type(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection())
:members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap, subtypeSpec

View File

@@ -0,0 +1,19 @@
.. _char.BMPString:
.. |ASN.1| replace:: BMPString
.. |encoding| replace:: utf-16-be
|ASN.1| type
------------
.. autoclass:: pyasn1.type.char.BMPString(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii')
:members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap
.. note::
The |ASN.1| type models a Unicode (ISO10646-1) character string implicitly serialised into UTF-16 big endian.
.. automethod:: pyasn1.type.char.BMPString.clone(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii')
.. automethod:: pyasn1.type.char.BMPString.subtype(value=NoValue(), implicitTag=Tag(), explicitTag=Tag(),subtypeSpec=ConstraintsIntersection(), encoding='us-ascii')

View File

@@ -0,0 +1,30 @@
.. _type.char:
Character types
---------------
Besides :ref:`universal types <type.univ>` also defines a collection
of text types. Most of these types come from the past trying to capture
the fragments of long-forgotten technologies.
These *character* types are all scalars. They are similar to
:ref:`OctetString <univ.OctetString>` except that they all operate on
text, not bytes.
.. toctree::
:maxdepth: 2
/pyasn1/type/char/numericstring
/pyasn1/type/char/printablestring
/pyasn1/type/char/teletexstring
/pyasn1/type/char/t61string
/pyasn1/type/char/videotexstring
/pyasn1/type/char/ia5string
/pyasn1/type/char/graphicstring
/pyasn1/type/char/visiblestring
/pyasn1/type/char/iso646string
/pyasn1/type/char/generalstring
/pyasn1/type/char/universalstring
/pyasn1/type/char/bmpstring
/pyasn1/type/char/utf8string

View File

@@ -0,0 +1,20 @@
.. _char.GeneralString:
.. |ASN.1| replace:: GeneralString
.. |encoding| replace:: iso-8859-1
|ASN.1| type
------------
.. autoclass:: pyasn1.type.char.GeneralString(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii')
:members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap
.. note::
The |ASN.1| type models a character string similar to :py:class:`GraphicString` but additionally
including control characters.
.. automethod:: pyasn1.type.char.GeneralString.clone(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii')
.. automethod:: pyasn1.type.char.GeneralString.subtype(value=NoValue(), implicitTag=Tag(), explicitTag=Tag(),subtypeSpec=ConstraintsIntersection(), encoding='us-ascii')

View File

@@ -0,0 +1,20 @@
.. _char.GraphicString:
.. |ASN.1| replace:: GraphicString
.. |encoding| replace:: iso-8859-1
|ASN.1| type
------------
.. autoclass:: pyasn1.type.char.GraphicString(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii')
:members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap
.. note::
The |ASN.1| type models a character string that can hold any "graphical" characters
mixed with control ones to select particular alphabet.
.. automethod:: pyasn1.type.char.GraphicString.clone(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii')
.. automethod:: pyasn1.type.char.GraphicString.subtype(value=NoValue(), implicitTag=Tag(), explicitTag=Tag(),subtypeSpec=ConstraintsIntersection(), encoding='us-ascii')

View File

@@ -0,0 +1,19 @@
.. _char.IA5String:
.. |ASN.1| replace:: IA5String
.. |encoding| replace:: us-ascii
|ASN.1| type
------------
.. autoclass:: pyasn1.type.char.IA5String(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii')
:members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap
.. note::
The |ASN.1| type models a basic character string first published in 1963 as an ISO/ITU standard, then it turned into ASCII.
.. automethod:: pyasn1.type.char.IA5String.clone(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii')
.. automethod:: pyasn1.type.char.IA5String.subtype(value=NoValue(), implicitTag=Tag(), explicitTag=Tag(),subtypeSpec=ConstraintsIntersection(), encoding='us-ascii')

View File

@@ -0,0 +1,19 @@
.. _char.ISO646String:
.. |ASN.1| replace:: ISO646String
.. |encoding| replace:: us-ascii
|ASN.1| type
------------
.. autoclass:: pyasn1.type.char.ISO646String(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii')
:members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap
.. note::
The |ASN.1| type is an alias to the :py:class:`VisibleString` type
.. automethod:: pyasn1.type.char.ISO646String.clone(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii')
.. automethod:: pyasn1.type.char.ISO646String.subtype(value=NoValue(), implicitTag=Tag(), explicitTag=Tag(),subtypeSpec=ConstraintsIntersection(), encoding='us-ascii')

View File

@@ -0,0 +1,19 @@
.. _char.NumericString:
.. |ASN.1| replace:: NumericString
.. |encoding| replace:: us-ascii
|ASN.1| type
------------
.. autoclass:: pyasn1.type.char.NumericString(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii')
:members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap
.. note::
The |ASN.1| models character string that can be entered from a telephone handset.
.. automethod:: pyasn1.type.char.NumericString.clone(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii')
.. automethod:: pyasn1.type.char.NumericString.subtype(value=NoValue(), implicitTag=Tag(), explicitTag=Tag(),subtypeSpec=ConstraintsIntersection(), encoding='us-ascii')

View File

@@ -0,0 +1,20 @@
.. _char.PrintableString:
.. |ASN.1| replace:: PrintableString
.. |encoding| replace:: us-ascii
|ASN.1| type
------------
.. autoclass:: pyasn1.type.char.PrintableString(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii')
:members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap
.. note::
The |ASN.1| models character string that can be entered from a very rudimentary terminals featuring letters,
digits and punctuation marks.
.. automethod:: pyasn1.type.char.PrintableString.clone(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii')
.. automethod:: pyasn1.type.char.PrintableString.subtype(value=NoValue(), implicitTag=Tag(), explicitTag=Tag(),subtypeSpec=ConstraintsIntersection(), encoding='us-ascii')

View File

@@ -0,0 +1,19 @@
.. _char.T61String:
.. |ASN.1| replace:: T61String
.. |encoding| replace:: iso-8859-1
|ASN.1| type
------------
.. autoclass:: pyasn1.type.char.T61String(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii')
:members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap
.. note::
The |ASN.1| type is an alias to :py:class:`TeletexString` type.
.. automethod:: pyasn1.type.char.T61String.clone(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii')
.. automethod:: pyasn1.type.char.T61String.subtype(value=NoValue(), implicitTag=Tag(), explicitTag=Tag(),subtypeSpec=ConstraintsIntersection(), encoding='us-ascii')

View File

@@ -0,0 +1,21 @@
.. _char.TeletexString:
.. |ASN.1| replace:: TeletexString
.. |encoding| replace:: iso-8859-1
|ASN.1| type
------------
.. autoclass:: pyasn1.type.char.TeletexString(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii')
:members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap
.. note::
The |ASN.1| type models character string that can be entered from a sophisticated text processing machines
(by 20-th century standards) featuring letters from multiple alphabets (308 characters!), digits,
punctuation marks and escape sequences.
.. automethod:: pyasn1.type.char.TeletexString.clone(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii')
.. automethod:: pyasn1.type.char.TeletexString.subtype(value=NoValue(), implicitTag=Tag(), explicitTag=Tag(),subtypeSpec=ConstraintsIntersection(), encoding='us-ascii')

View File

@@ -0,0 +1,19 @@
.. _char.UniversalString:
.. |ASN.1| replace:: UniversalString
.. |encoding| replace:: utf-32-be
|ASN.1| type
------------
.. autoclass:: pyasn1.type.char.UniversalString(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii')
:members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap
.. note::
The |ASN.1| type models a Unicode (ISO10646-1) character string implicitly serialised into UTF-32 big endian.
.. automethod:: pyasn1.type.char.UniversalString.clone(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii')
.. automethod:: pyasn1.type.char.UniversalString.subtype(value=NoValue(), implicitTag=Tag(), explicitTag=Tag(),subtypeSpec=ConstraintsIntersection(), encoding='us-ascii')

View File

@@ -0,0 +1,19 @@
.. _char.UTF8String:
.. |ASN.1| replace:: UTF8String
.. |encoding| replace:: utf-8
|ASN.1| type
------------
.. autoclass:: pyasn1.type.char.UTF8String(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii')
:members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap
.. note::
The |ASN.1| type models a Unicode (ISO10646-1) character string implicitly serialised into UTF-8.
.. automethod:: pyasn1.type.char.UTF8String.clone(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii')
.. automethod:: pyasn1.type.char.UTF8String.subtype(value=NoValue(), implicitTag=Tag(), explicitTag=Tag(),subtypeSpec=ConstraintsIntersection(), encoding='us-ascii')

View File

@@ -0,0 +1,20 @@
.. _char.VideotexString:
.. |ASN.1| replace:: VideotexString
.. |encoding| replace:: iso-8859-1
|ASN.1| type
------------
.. autoclass:: pyasn1.type.char.VideotexString(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii')
:members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap
.. note::
The |ASN.1| type models character string that can be consumed by sophisticated video
terminals (by 20-th century standards) to render ascii-art style pictures and animations.
.. automethod:: pyasn1.type.char.VideotexString.clone(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii')
.. automethod:: pyasn1.type.char.VideotexString.subtype(value=NoValue(), implicitTag=Tag(), explicitTag=Tag(),subtypeSpec=ConstraintsIntersection(), encoding='us-ascii')

View File

@@ -0,0 +1,20 @@
.. _char.VisibleString:
.. |ASN.1| replace:: VisibleString
.. |encoding| replace:: us-ascii
|ASN.1| type
------------
.. autoclass:: pyasn1.type.char.VisibleString(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii')
:members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap
.. note::
The |ASN.1| type models a character string that can hold any "graphical" characters
mixed with control ones to select particular alphabet.
.. automethod:: pyasn1.type.char.VisibleString.clone(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii')
.. automethod:: pyasn1.type.char.VisibleString.subtype(value=NoValue(), implicitTag=Tag(), explicitTag=Tag(),subtypeSpec=ConstraintsIntersection(), encoding='us-ascii')

View File

@@ -0,0 +1,10 @@
.. _constrain.ConstraintsExclusion:
.. |Constraint| replace:: ConstraintsExclusion
Constraints exclusion
---------------------
.. autoclass:: pyasn1.type.constraint.ConstraintsExclusion(constraint)
:members:

View File

@@ -0,0 +1,10 @@
.. _constrain.ConstraintsIntersection:
.. |Constraint| replace:: ConstraintsIntersection
Constraints intersection
------------------------
.. autoclass:: pyasn1.type.constraint.ConstraintsIntersection(*constraints)
:members:

View File

@@ -0,0 +1,10 @@
.. _constrain.ConstraintsUnion:
.. |Constraint| replace:: ConstraintsUnion
Constraints union
-----------------
.. autoclass:: pyasn1.type.constraint.ConstraintsUnion(*constraints)
:members:

View File

@@ -0,0 +1,10 @@
.. _constrain.ContainedSubtypeConstraint:
.. |Constraint| replace:: ContainedSubtypeConstraint
Contained subtype constraint
----------------------------
.. autoclass:: pyasn1.type.constraint.ContainedSubtypeConstraint
:members:

View File

@@ -0,0 +1,68 @@
.. _type.constraint:
Constraints
-----------
ASN.1 standard has a built-in way of limiting the set of values
a type can possibly have. Imposing value constraints on an ASN.1
type, together with :ref:`tagging <type.tag>`, is a way of creating
a more specialized subtype of an ASN.1 type.
The pyasn1 implementation represents all flavors of constraints,
as well as their combinations, as immutable Python objects. Ultimately,
they get attached to ASN.1 type object at a *.subtypeSpec* attribute.
.. code-block:: python
class Age(Integer):
"""
ASN.1 specification:
Age ::= INTEGER (0..120)
"""
subtypeSpec = ValueRangeConstraint(0, 120)
.. toctree::
:maxdepth: 2
/pyasn1/type/constraint/singlevalue
/pyasn1/type/constraint/containedsubtype
/pyasn1/type/constraint/valuerange
/pyasn1/type/constraint/valuesize
/pyasn1/type/constraint/permittedalphabet
/pyasn1/type/constraint/withcomponents
Logic operations on constraints
+++++++++++++++++++++++++++++++
Sometimes multiple constraints are applied on an ASN.1 type. To capture
this situation, individual constraint objects can be glued together
by the logic operator objects.
The logic operators are Python objects that exhibit similar behaviour
as the constraint objects do with the only difference that logic operators
are instantiated on the constraint and logic operator objects, not on the
bare values.
.. code-block:: python
class PhoneNumber(NumericString):
"""
ASN.1 specification:
PhoneNumber ::=
NumericString (FROM ("0".."9")) (SIZE (10))
"""
subtypeSpec = ConstraintsIntersection(
ValueRangeConstraint('0', '9'), ValueSizeConstraint(10)
)
.. toctree::
:maxdepth: 2
/pyasn1/type/constraint/constraintsintersection
/pyasn1/type/constraint/constraintsunion
/pyasn1/type/constraint/constraintsexclusion

View File

@@ -0,0 +1,10 @@
.. _constrain.PermittedAlphabetConstraint:
.. |Constraint| replace:: PermittedAlphabetConstraint
Permitted alphabet constraint
-----------------------------
.. autoclass:: pyasn1.type.constraint.PermittedAlphabetConstraint(*alphabet)
:members:

View File

@@ -0,0 +1,10 @@
.. _constrain.SingleValueConstraint:
.. |Constraint| replace:: SingleValueConstraint
Single value constraint
-----------------------
.. autoclass:: pyasn1.type.constraint.SingleValueConstraint
:members:

View File

@@ -0,0 +1,10 @@
.. _constrain.ValueRangeConstraint:
.. |Constraint| replace:: ValueRangeConstraint
Value range constraint
----------------------
.. autoclass:: pyasn1.type.constraint.ValueRangeConstraint(start, end)
:members:

View File

@@ -0,0 +1,10 @@
.. _constrain.ValueSizeConstraint:
.. |Constraint| replace:: ValueSizeConstraint
Value size constraint
----------------------
.. autoclass:: pyasn1.type.constraint.ValueSizeConstraint(minimum, maximum)
:members:

View File

@@ -0,0 +1,16 @@
.. _constrain.WithComponentsConstraint:
.. |Constraint| replace:: WithComponentsConstraint
WITH COMPONENTS constraint
--------------------------
.. autoclass:: pyasn1.type.constraint.WithComponentsConstraint(*fields)
:members:
.. autoclass:: pyasn1.type.constraint.ComponentPresentConstraint()
:members:
.. autoclass:: pyasn1.type.constraint.ComponentAbsentConstraint()
:members:

View File

@@ -0,0 +1,40 @@
.. _type.namedtype:
Fields of constructed types
---------------------------
The :ref:`Sequence <univ.Sequence>`, :ref:`Set <univ.Set>` and
:ref:`Choice <univ.Choice>` ASN.1 types embed other ASN.1 types
as named fields.
Each field can be expressed via the :ref:`NamedType <namedtype.NamedType>`
object while the individual fields are brought together by the
:ref:`NamedTypes <namedtype.NamedTypes>` object.
Ultimately, the fields get attached to the ASN.1 type's *.componentType*
attributes.
.. code-block:: python
class RSAPublicKey(Sequence):
"""
ASN.1 specification:
RSAPublicKey ::= SEQUENCE {
modulus INTEGER, -- n
publicExponent INTEGER -- e
}
"""
componentType = NamedTypes(
NamedType('modulus', Integer()),
NamedType('publicExponent', Integer())
)
.. toctree::
:maxdepth: 2
/pyasn1/type/namedtype/namedtype
/pyasn1/type/namedtype/optionalnamedtype
/pyasn1/type/namedtype/defaultednamedtype
/pyasn1/type/namedtype/namedtypes

View File

@@ -0,0 +1,20 @@
.. _namedtype.DefaultedNamedType:
.. |NamedType| replace:: DefaultedNamedType
DefaultedNamedType
------------------
.. autoclass:: pyasn1.type.namedtype.DefaultedNamedType
:members:
.. note::
The *DefaultedNamedType* class models named field of a constructed
ASN.1 type which has a default value.
The *DefaultedNamedType* objects are normally utilized
by the :ref:`NamedTypes <namedtype.NamedTypes>` objects
to model individual fields of the constructed ASN.1
types.

View File

@@ -0,0 +1,20 @@
.. _namedtype.NamedType:
.. |NamedType| replace:: NamedType
NamedType
---------
.. autoclass:: pyasn1.type.namedtype.NamedType
:members:
.. note::
The *NamedType* class models a mandatory field of a constructed
ASN.1 type.
The *NamedType* objects are normally utilized by the
the :ref:`NamedTypes <namedtype.NamedTypes>` objects
to model individual fields of the constructed ASN.1
types.

View File

@@ -0,0 +1,15 @@
.. _namedtype.NamedTypes:
NamedTypes
----------
.. autoclass:: pyasn1.type.namedtype.NamedTypes
:members:
.. note::
The *NamedTypes* objects are normally utilized by the
constructed ASN.1 types (e.g. :ref:`Sequence <univ.Sequence>`,
:ref:`Set <univ.Set>` and :ref:`Choice <univ.Choice>`) to model
the set of fields of those types.

View File

@@ -0,0 +1,20 @@
.. _namedtype.OptionalNamedType:
.. |NamedType| replace:: OptionalNamedType
OptionalNamedType
-----------------
.. autoclass:: pyasn1.type.namedtype.OptionalNamedType
:members:
.. note::
The *OptionalNamedType* class models an optional field of
a constructed ASN.1 type.
The *OptionalNamedType* objects are normally utilized by
the :ref:`NamedTypes <namedtype.NamedTypes>` objects
to model individual fields of the constructed ASN.1
types.

View File

@@ -0,0 +1,43 @@
.. _type.namedval:
Enumerating numbers
-------------------
Some ASN.1 types such as :ref:`Integer <univ.Integer>`,
:ref:`Enumerated <univ.Enumerated>` and :ref:`BitString <univ.BitString>`
may enumerate their otherwise numeric values associating them with
human-friendly labels.
.. code-block:: python
class ErrorStatus(Integer):
"""
ASN.1 specification:
error-status
INTEGER {
noError(0),
tooBig(1),
noSuchName(2),
...
}
"""
namedValues = NamedValues(
('noError', 0), ('tooBig', 1), ('noSuchName', 2)
)
The enumerated types behave exactly like the non-enumerated ones but,
additionally, values can be referred by labels.
.. code-block:: python
errorStatus = ErrorStatus('tooBig')
assert errorStatus == 1
.. toctree::
:maxdepth: 2
/pyasn1/type/namedval/namedval

View File

@@ -0,0 +1,13 @@
.. _namedval.NamedValues:
.. |NamedValues| replace:: NamedValues
|NamedValues|
-------------
The |NamedValues| class associates human-friendly names to a set of numbers
or bits.
.. autoclass:: pyasn1.type.namedval.NamedValues
:members:

View File

@@ -0,0 +1,114 @@
.. _type.opentype:
Dynamic or open type
--------------------
ASN.1 allows data structure designer to leave "holes" in field type
specification of :ref:`Sequence <univ.Sequence>` or
:ref:`Set <univ.Set>` types.
The idea behind that feature is that there can be times, when the
exact field type is not known at the design time, or it is anticipated
that new field types may come up in the future.
This "hole" type is manifested in the data structure by :ref:`Any <univ.Any>`
type. Technically, the actual type is serialized into an octet stream
and then put into :ref:`Any <univ.Any>` "container", which is in fact an
(untagged, by default) specialization of ASN.1
:ref:`OctetString <univ.OctetString>` type.
.. code-block:: bash
Algorithm ::= SEQUENCE {
algorithm OBJECT IDENTIFIER,
parameters ANY DEFINED BY algorithm OPTIONAL
}
On the receiving end, to know how to interpret the open type
serialization, the receiver can rely on the supplied value in
the other field of the data structure. That other field is
semantically linked with the open type field. This link
is expressed in ASN.1 by the *DEFINE BY* clause.
From ASN.1 perspective, it is not an error if the decoder does
not know a type selector value it receives. In that case pyasn1 decoder
just leaves serialized blob in the open type field.
.. note::
By default, ASN.1 ANY type has no tag. That makes it an
"invisible" in serialization. However, like any other ASN.1 type,
ANY type can be subtyped by :ref:`tagging <type.tag>`.
Besides scalar open type fields, ASN.1 allows using *SET OF*
or *SEQUENCE OF* containers holding zero or more of *ANY*
scalars.
.. code-block:: bash
AttributeTypeAndValues ::= SEQUENCE {
type OBJECT IDENTIFIER,
values SET OF ANY DEFINED BY type
}
.. note::
A single type selector field is used to guide the decoder
of potentially many elements of a *SET OF* or *SEQUENCE OF* container
all at once. That implies that all *ANY* elements must be of the same
type in any given instance of a data structure.
When expressing ASN.1 type "holes" in pyasn1, the
:ref:`OpenType <opentype.OpenType>` object should be used to establish
a semantic link between type selector field and open type field.
.. code-block:: python
algo_map = {
ObjectIdentifier('1.2.840.113549.1.1.1'): rsaEncryption(),
ObjectIdentifier('1.2.840.113549.1.1.2'): md2WithRSAEncryption()
}
class Algorithm(Sequence):
"""
Algorithm ::= SEQUENCE {
algorithm OBJECT IDENTIFIER,
parameters ANY DEFINED BY algorithm
}
"""
componentType = NamedTypes(
NamedType('algorithm', ObjectIdentifier()),
NamedType('parameters', Any(),
openType=OpenType('algorithm', algo_map))
)
Similarly for `SET OF ANY DEFINED BY` or `SEQUENCE OF ANY DEFINED BY`
constructs:
.. code-block:: python
algo_map = {
ObjectIdentifier('1.2.840.113549.1.1.1'): rsaEncryption(),
ObjectIdentifier('1.2.840.113549.1.1.2'): md2WithRSAEncryption()
}
class Algorithm(Sequence):
"""
Algorithm ::= SEQUENCE {
algorithm OBJECT IDENTIFIER,
parameters SET OF ANY DEFINED BY algorithm
}
"""
componentType = NamedTypes(
NamedType('algorithm', ObjectIdentifier()),
NamedType('parameters', SetOf(componentType=Any()),
openType=OpenType('algorithm', algo_map))
)
.. toctree::
:maxdepth: 2
/pyasn1/type/opentype/opentype

View File

@@ -0,0 +1,12 @@
.. _opentype.OpenType:
.. |OpenType| replace:: OpenType
|OpenType|
-----------
.. autoclass:: pyasn1.type.opentype.OpenType
:members:
More information on open type use can be found :ref:`here <type.opentype>`.

View File

@@ -0,0 +1,54 @@
.. _type.tag:
Tags
----
ASN.1 types formally differ from each other by carrying distinct
tags. A tag is essentially an integer exhibiting certain inner
structure.
Individual tags are usually combined into a collection known as
*TagSet*. Tags and tag sets in pyasn1 are immutable objects assigned
to ASN.1 types as the *tagSet* attribute.
Tags can be appended to one another (in EXPLICIT tagging mode)
or overridden (IMPLICIT tagging mode) ultimately creating a new
ASN.1 subtype.
.. code-block:: python
class Counter64(Integer):
"""
ASN.1 specification:
Counter64 ::=
[APPLICATION 6]
IMPLICIT INTEGER
"""
tagSet = Integer.tagSet.tagImplicitly(
Tag(tagClassApplication, tagFormatSimple, 6)
)
# alternatively
counter64 = Integer().subtype(
implicitTag=Tag(tagClassApplication, tagFormatSimple, 6)
)
ASN.1 types can be related to each other via the *.isSameTypeWith()*,
*.isSuperTypeOf()* and *.isSubTypeOf()* methods. Internally, the *.tagSet*
of the types are compared along with the value constraints
(e.g. *.subtypeSpec*).
.. code-block:: python
assert Counter64().isSubTypeOf(Integer()) == True
assert Counter64().isSameTypeWith(Integer()) == False
.. toctree::
:maxdepth: 2
/pyasn1/type/tag/tag
/pyasn1/type/tag/tagset
/pyasn1/type/tag/tagmap

View File

@@ -0,0 +1,18 @@
.. _tag.tag:
Solitary tag
------------
.. automodule:: pyasn1.type.tag
:members: tagClassUniversal, tagClassApplication, tagClassContext,
tagClassPrivate, tagFormatSimple, tagFormatConstructed
.. autoclass:: pyasn1.type.tag.Tag
:members:
.. note::
The *Tag* objects are normally used by the
:ref:`TagSet <tag.TagSet>`, objects to model a collection
of ASN.1 tags.

View File

@@ -0,0 +1,14 @@
.. _tag.tagmap:
Tag->type map
-------------
.. autoclass:: pyasn1.type.tagmap.TagMap
:members:
.. note::
The *TagMap* objects are used by the
:ref:`TagSet <tag.TagSet>`, objects for looking up components
of constructed ASN.1 types by :ref:`Tag <tag.Tag>`.

View File

@@ -0,0 +1,14 @@
.. _tag.tagset:
Tag set
-------
.. autoclass:: pyasn1.type.tag.TagSet
:members:
.. note::
The *TagSet* objects are normally used by all ASN.1 type
objects both simple (like :ref:`Integer <univ.Integer>`)
and constructed (e.g. :ref:`Sequence <univ.Sequence>`).

View File

@@ -0,0 +1,22 @@
.. _univ.Any:
.. |ASN.1| replace:: Any
.. |encoding| replace:: iso-8859-1
|ASN.1| type
------------
.. autoclass:: pyasn1.type.univ.Any(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='iso-8859-1', binValue=NoValue(),hexValue=NoValue())
:members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap, subtypeSpec
.. note::
The |ASN.1| type models an arbitrary value of an arbitrary type. Typically,
a selection of types are defined in form of an
:ref:`open type <opentype.OpenType>` . Technically, the ANY
value is a serialised representation of some other ASN.1 object.
.. automethod:: pyasn1.type.univ.Any.clone(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='iso-8859-1')
.. automethod:: pyasn1.type.univ.Any.subtype(value=NoValue(), implicitTag=Tag(), explicitTag=Tag(),subtypeSpec=ConstraintsIntersection(),encoding='iso-8859-1')

View File

@@ -0,0 +1,17 @@
.. _univ.BitString:
.. |ASN.1| replace:: BitString
|ASN.1| type
------------
.. autoclass:: pyasn1.type.univ.BitString(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), namedValues=NamedValues(),binValue=NoValue(), hexValue=NoValue())
:members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap, subtypeSpec, asInteger, asNumbers, asOctets, asBinary, fromHexString, fromBinaryString, fromOctetString
.. note::
The |ASN.1| type models an arbitrary sequence of bits.
.. automethod:: pyasn1.type.univ.BitString.clone(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), namedValues=NamedValues(),binValue=NoValue(), hexValue=NoValue())
.. automethod:: pyasn1.type.univ.BitString.subtype(value=NoValue(), implicitTag=Tag(), explicitTag=Tag(),subtypeSpec=ConstraintsIntersection(), , namedValues=NamedValues(),binValue=NoValue(), hexValue=NoValue())

View File

@@ -0,0 +1,17 @@
.. _univ.Boolean:
.. |ASN.1| replace:: Boolean
|ASN.1| type
------------
.. autoclass:: pyasn1.type.univ.Boolean(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection())
:members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap, subtypeSpec
.. note::
The |ASN.1| type models a BOOLEAN that can be either TRUE or FALSE.
.. automethod:: pyasn1.type.univ.Boolean.clone(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection())
.. automethod:: pyasn1.type.univ.Boolean.subtype(value=NoValue(), implicitTag=Tag(), explicitTag=Tag(), subtypeSpec=ConstraintsIntersection())

View File

@@ -0,0 +1,19 @@
.. _univ.Choice:
.. |ASN.1| replace:: Choice
|ASN.1| type
------------
.. autoclass:: pyasn1.type.univ.Choice(componentType=None, tagSet=tagSet(), subtypeSpec=ConstraintsIntersection())
:members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap, componentType, subtypeSpec,
getComponentByPosition, setComponentByPosition, getComponentByName, setComponentByName, setDefaultComponents,
getComponentByType, setComponentByType, getName, getComponent, isInconsistent
.. note::
The |ASN.1| type can only hold a single component at a time belonging to the list of allowed types.
.. automethod:: pyasn1.type.univ.Choice.clone(componentType=None, tagSet=tagSet(), subtypeSpec=ConstraintsIntersection())
.. automethod:: pyasn1.type.univ.Choice.subtype(componentType=None, implicitTag=Tag(), explicitTag=Tag(),subtypeSpec=ConstraintsIntersection())

View File

@@ -0,0 +1,34 @@
.. _type.univ:
Universal types
---------------
The ASN.1 language defines a collection of core data types
also known as *universal* types.
Some of these types behave like a scalar (e.g. *simple* types) while
the rest are structured types (the standard calls them *constructed*).
Example of simple types include :ref:`Integer <univ.Integer>` or
:ref:`OctetString <univ.OctetString>`. Constructed types like
:ref:`Sequence <univ.Sequence>` embed other types, both simple
and constructed.
.. toctree::
:maxdepth: 2
/pyasn1/type/univ/integer
/pyasn1/type/univ/boolean
/pyasn1/type/univ/bitstring
/pyasn1/type/univ/octetstring
/pyasn1/type/univ/null
/pyasn1/type/univ/objectidentifier
/pyasn1/type/univ/real
/pyasn1/type/univ/enumerated
/pyasn1/type/univ/any
/pyasn1/type/univ/setof
/pyasn1/type/univ/sequenceof
/pyasn1/type/univ/set
/pyasn1/type/univ/sequence
/pyasn1/type/univ/choice

View File

@@ -0,0 +1,18 @@
.. _univ.Enumerated:
.. |ASN.1| replace:: Enumerated
|ASN.1| type
------------
.. autoclass:: pyasn1.type.univ.Enumerated(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), namedValues=NamedValues())
:members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap, subtypeSpec, namedValues
.. note::
The |ASN.1| type models bounded set of named integer values. Other than that, it is identical to
the *Integer* class.
.. automethod:: pyasn1.type.univ.Enumerated.clone(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), namedValues=NamedValues())
.. automethod:: pyasn1.type.univ.Enumerated.subtype(value=NoValue(), implicitTag=Tag(), explicitTag=Tag(),subtypeSpec=ConstraintsIntersection(), namedValues=NamedValues())

View File

@@ -0,0 +1,19 @@
.. _univ.Integer:
.. |ASN.1| replace:: Integer
|ASN.1| type
------------
.. autoclass:: pyasn1.type.univ.Integer(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), namedValues=NamedValues())
:members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap,
subtypeSpec, namedValues
.. note::
The |ASN.1| type models an arbitrary integer. INTEGER values can be positive, negative,
or zero, and can have any magnitude.
.. automethod:: pyasn1.type.univ.Integer.clone(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), namedValues=NamedValues())
.. automethod:: pyasn1.type.univ.Integer.subtype(value=NoValue(), implicitTag=Tag(), explicitTag=Tag(),subtypeSpec=ConstraintsIntersection(), namedValues=NamedValues())

View File

@@ -0,0 +1,17 @@
.. _univ.Null:
.. |ASN.1| replace:: Null
|ASN.1| type
------------
.. autoclass:: pyasn1.type.univ.Null(value=NoValue(), tagSet=TagSet())
:members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap, subtypeSpec
.. note::
The |ASN.1| type models ASN.1 NULL.
.. automethod:: pyasn1.type.univ.Null.clone(value=NoValue(), tagSet=TagSet())
.. automethod:: pyasn1.type.univ.Null.subtype(value=NoValue(), implicitTag=Tag(), explicitTag=Tag())

View File

@@ -0,0 +1,17 @@
.. _univ.ObjectIdentifier:
.. |ASN.1| replace:: ObjectIdentifier
|ASN.1| type
------------
.. autoclass:: pyasn1.type.univ.ObjectIdentifier(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection())
:members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap, subtypeSpec, isPrefixOf
.. note::
The |ASN.1| type models ASN.1 OBJECT IDENTIFIER as a sequence of integer numbers.
.. automethod:: pyasn1.type.univ.ObjectIdentifier.clone(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection())
.. automethod:: pyasn1.type.univ.ObjectIdentifier.subtype(value=NoValue(), implicitTag=Tag(), explicitTag=Tag(), subtypeSpec=ConstraintsIntersection())

View File

@@ -0,0 +1,19 @@
.. _univ.OctetString:
.. |ASN.1| replace:: OctetString
.. |encoding| replace:: iso-8859-1
|ASN.1| type
------------
.. autoclass:: pyasn1.type.univ.OctetString(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='iso-8859-1', binValue=NoValue(),hexValue=NoValue())
:members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap, subtypeSpec, fromHexString, fromBinaryString
.. note::
The |ASN.1| type models an arbitrary string of octets (eight-bit numbers), not printable text string.
.. automethod:: pyasn1.type.univ.OctetString.clone(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='iso-8859-1')
.. automethod:: pyasn1.type.univ.OctetString.subtype(value=NoValue(), implicitTag=Tag(), explicitTag=Tag(),subtypeSpec=ConstraintsIntersection(),encoding='iso-8859-1')

View File

@@ -0,0 +1,17 @@
.. _univ.Real:
.. |ASN.1| replace:: Real
|ASN.1| type
------------
.. autoclass:: pyasn1.type.univ.Real(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection())
:members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap, subtypeSpec, isInf, isPlusInf, isMinusInf
.. note::
The |ASN.1| type models a rational number of arbitrary precision.
.. automethod:: pyasn1.type.univ.Real.clone(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection())
.. automethod:: pyasn1.type.univ.Real.subtype(value=NoValue(), implicitTag=Tag(), explicitTag=Tag(), subtypeSpec=ConstraintsIntersection())

View File

@@ -0,0 +1,20 @@
.. _univ.Sequence:
.. |ASN.1| replace:: Sequence
|ASN.1| type
------------
.. autoclass:: pyasn1.type.univ.Sequence(componentType=NamedTypes(), tagSet=tagSet(), subtypeSpec=ConstraintsIntersection())
:members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap, componentType, subtypeSpec, getComponentByPosition,
setComponentByPosition, getComponentByName, setComponentByName, setDefaultComponents,
clear, reset, isInconsistent
.. note::
The |ASN.1| type models a collection of named ASN.1 components.
Ordering of the components **is** preserved upon de/serialisation.
.. automethod:: pyasn1.type.univ.Sequence.clone(componentType=NamedTypes(), tagSet=tagSet(), subtypeSpec=ConstraintsIntersection())
.. automethod:: pyasn1.type.univ.Sequence.subtype(componentType=NamedTypes(), implicitTag=Tag(), explicitTag=Tag(),subtypeSpec=ConstraintsIntersection())

View File

@@ -0,0 +1,19 @@
.. _univ.SequenceOf:
.. |ASN.1| replace:: SequenceOf
|ASN.1| type
------------
.. autoclass:: pyasn1.type.univ.SequenceOf(componentType=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection())
:members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap, componentType, subtypeSpec,
getComponentByPosition, setComponentByPosition, clear, reset, isInconsistent
.. note::
The |ASN.1| type models a collection of elements of a single ASN.1 type.
Ordering of the components **is** preserved upon de/serialisation.
.. automethod:: pyasn1.type.univ.SequenceOf.clone(componentType=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection())
.. automethod:: pyasn1.type.univ.SequenceOf.subtype(componentType=NoValue(), implicitTag=Tag(), explicitTag=Tag(),subtypeSpec=ConstraintsIntersection())

View File

@@ -0,0 +1,20 @@
.. _univ.Set:
.. |ASN.1| replace:: Set
|ASN.1| type
------------
.. autoclass:: pyasn1.type.univ.Set(componentType=NamedTypes(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection())
:members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap, componentType, subtypeSpec,
getComponentByPosition, setComponentByPosition, getComponentByName, setComponentByName, setDefaultComponents,
getComponentByType, setComponentByType, clear, reset, isInconsistent
.. note::
The |ASN.1| type models a collection of named ASN.1 components.
Ordering of the components **is not** preserved upon de/serialisation.
.. automethod:: pyasn1.type.univ.Set.clone(componentType=NamedTypes(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection())
.. automethod:: pyasn1.type.univ.Set.subtype(componentType=NamedTypes(), implicitTag=Tag(), explicitTag=Tag(),subtypeSpec=ConstraintsIntersection())

View File

@@ -0,0 +1,19 @@
.. _univ.SetOf:
.. |ASN.1| replace:: SetOf
|ASN.1| type
------------
.. autoclass:: pyasn1.type.univ.SetOf(componentType=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection())
:members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap, componentType, subtypeSpec,
 getComponentByPosition, setComponentByPosition, clear, reset, isInconsistent
.. note::
The |ASN.1| type models a collection of elements of a single ASN.1 type.
Ordering of the components **is not** preserved upon de/serialisation.
.. automethod:: pyasn1.type.univ.SetOf.clone(componentType=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection())
.. automethod:: pyasn1.type.univ.SetOf.subtype(componentType=NoValue(), implicitTag=Tag(), explicitTag=Tag(),subtypeSpec=ConstraintsIntersection())

View File

@@ -0,0 +1,15 @@
.. _type.useful:
Useful types
------------
Some assorted utility ASN.1 types belong to the *useful* group.
These types are all scalar.
.. toctree::
:maxdepth: 2
/pyasn1/type/useful/objectdescriptor
/pyasn1/type/useful/generalizedtime
/pyasn1/type/useful/utctime

View File

@@ -0,0 +1,37 @@
.. _useful.GeneralizedTime:
.. |ASN.1| replace:: GeneralizedTime
.. |encoding| replace:: iso-8859-1
|ASN.1| type
------------
.. autoclass:: pyasn1.type.useful.GeneralizedTime(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii')
:members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, asDateTime, fromDateTime
.. note::
The |ASN.1| type models a character string representing date and time
in many different formats.
Formal syntax for the *GeneralizedTime* value is:
* **YYYYMMDDhh[mm[ss[(.|,)ffff]]]** standing for a local time, four
digits for the year, two for the month, two for the day and two
for the hour, followed by two digits for the minutes and two
for the seconds if required, then a dot (or a comma), and a
number for the fractions of second or
* a string as above followed by the letter “Z” (denoting a UTC
time) or
* a string as above followed by a string **(+|-)hh[mm]** denoting
time zone offset relative to UTC
For example, *20170126120000Z* stands for YYYYMMDDHHMMSSZ.
.. automethod:: pyasn1.type.useful.GeneralizedTime.clone(self, value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii')
.. automethod:: pyasn1.type.useful.GeneralizedTime.subtype(self, value=NoValue(), implicitTag=TagSet(), explicitTag=TagSet(),subtypeSpec=ConstraintsIntersection(), encoding='us-ascii')

View File

@@ -0,0 +1,20 @@
.. _useful.ObjectDescriptor:
.. |ASN.1| replace:: ObjectDescriptor
.. |encoding| replace:: iso-8859-1
|ASN.1| type
------------
.. autoclass:: pyasn1.type.useful.ObjectDescriptor(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii')
:members: isValue, isSameTypeWith, isSuperTypeOf, tagSet
.. note::
The |ASN.1| type models a character string that can accompany the *ObjectIdentifier* type
to serve as a human-friendly annotation for an OBJECT IDENTIFIER.
.. automethod:: pyasn1.type.useful.ObjectDescriptor.clone(self, value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii')
.. automethod:: pyasn1.type.useful.ObjectDescriptor.subtype(self, value=NoValue(), implicitTag=TagSet(), explicitTag=TagSet(),subtypeSpec=ConstraintsIntersection(), encoding='us-ascii')

View File

@@ -0,0 +1,34 @@
.. _useful.UTCTime:
.. |ASN.1| replace:: UTCTime
.. |encoding| replace:: iso-8859-1
|ASN.1| type
------------
.. autoclass:: pyasn1.type.useful.UTCTime(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii')
:members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, asDateTime, fromDateTime
.. note::
The |ASN.1| type models a character string representing date and time.
Formal syntax for the *UTCTime* value is:
* **YYMMDDhhmm[ss]** standing for UTC time, two
digits for the year, two for the month, two for the day and two
for the hour, followed by two digits for the minutes and two
for the seconds if required or
* a string as above followed by the letter “Z” (denoting a UTC
time) or
* a string as above followed by a string **(+|-)hhmm** denoting
time zone offset relative to UTC
For example, *170126120000Z* which stands for YYMMDDHHMMSSZ.
.. automethod:: pyasn1.type.useful.UTCTime.clone(self, value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii')
.. automethod:: pyasn1.type.useful.UTCTime.subtype(self, value=NoValue(), implicitTag=TagSet(), explicitTag=TagSet(),subtypeSpec=ConstraintsIntersection(), encoding='us-ascii')

View File

@@ -0,0 +1,2 @@
# https://www.python.org/dev/peps/pep-0396/
__version__ = '0.6.1'

View File

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

View File

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

View File

@@ -0,0 +1,954 @@
#
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2020, Ilya Etingof <etingof@gmail.com>
# License: https://pyasn1.readthedocs.io/en/latest/license.html
#
import sys
import warnings
from pyasn1 import debug
from pyasn1 import error
from pyasn1.codec.ber import eoo
from pyasn1.compat import _MISSING
from pyasn1.compat.integer import to_bytes
from pyasn1.type import char
from pyasn1.type import tag
from pyasn1.type import univ
from pyasn1.type import useful
__all__ = ['Encoder', 'encode']
LOG = debug.registerLoggee(__name__, flags=debug.DEBUG_ENCODER)
class AbstractItemEncoder(object):
supportIndefLenMode = True
# An outcome of otherwise legit call `encodeFun(eoo.endOfOctets)`
eooIntegerSubstrate = (0, 0)
eooOctetsSubstrate = bytes(eooIntegerSubstrate)
# noinspection PyMethodMayBeStatic
def encodeTag(self, singleTag, isConstructed):
tagClass, tagFormat, tagId = singleTag
encodedTag = tagClass | tagFormat
if isConstructed:
encodedTag |= tag.tagFormatConstructed
if tagId < 31:
return encodedTag | tagId,
else:
substrate = tagId & 0x7f,
tagId >>= 7
while tagId:
substrate = (0x80 | (tagId & 0x7f),) + substrate
tagId >>= 7
return (encodedTag | 0x1F,) + substrate
def encodeLength(self, length, defMode):
if not defMode and self.supportIndefLenMode:
return (0x80,)
if length < 0x80:
return length,
else:
substrate = ()
while length:
substrate = (length & 0xff,) + substrate
length >>= 8
substrateLen = len(substrate)
if substrateLen > 126:
raise error.PyAsn1Error('Length octets overflow (%d)' % substrateLen)
return (0x80 | substrateLen,) + substrate
def encodeValue(self, value, asn1Spec, encodeFun, **options):
raise error.PyAsn1Error('Not implemented')
def encode(self, value, asn1Spec=None, encodeFun=None, **options):
if asn1Spec is None:
tagSet = value.tagSet
else:
tagSet = asn1Spec.tagSet
# untagged item?
if not tagSet:
substrate, isConstructed, isOctets = self.encodeValue(
value, asn1Spec, encodeFun, **options
)
return substrate
defMode = options.get('defMode', True)
substrate = b''
for idx, singleTag in enumerate(tagSet.superTags):
defModeOverride = defMode
# base tag?
if not idx:
try:
substrate, isConstructed, isOctets = self.encodeValue(
value, asn1Spec, encodeFun, **options
)
except error.PyAsn1Error as exc:
raise error.PyAsn1Error(
'Error encoding %r: %s' % (value, exc))
if LOG:
LOG('encoded %svalue %s into %s' % (
isConstructed and 'constructed ' or '', value, substrate
))
if not substrate and isConstructed and options.get('ifNotEmpty', False):
return substrate
if not isConstructed:
defModeOverride = True
if LOG:
LOG('overridden encoding mode into definitive for primitive type')
header = self.encodeTag(singleTag, isConstructed)
if LOG:
LOG('encoded %stag %s into %s' % (
isConstructed and 'constructed ' or '',
singleTag, debug.hexdump(bytes(header))))
header += self.encodeLength(len(substrate), defModeOverride)
if LOG:
LOG('encoded %s octets (tag + payload) into %s' % (
len(substrate), debug.hexdump(bytes(header))))
if isOctets:
substrate = bytes(header) + substrate
if not defModeOverride:
substrate += self.eooOctetsSubstrate
else:
substrate = header + substrate
if not defModeOverride:
substrate += self.eooIntegerSubstrate
if not isOctets:
substrate = bytes(substrate)
return substrate
class EndOfOctetsEncoder(AbstractItemEncoder):
def encodeValue(self, value, asn1Spec, encodeFun, **options):
return b'', False, True
class BooleanEncoder(AbstractItemEncoder):
supportIndefLenMode = False
def encodeValue(self, value, asn1Spec, encodeFun, **options):
return value and (1,) or (0,), False, False
class IntegerEncoder(AbstractItemEncoder):
supportIndefLenMode = False
supportCompactZero = False
def encodeValue(self, value, asn1Spec, encodeFun, **options):
if value == 0:
if LOG:
LOG('encoding %spayload for zero INTEGER' % (
self.supportCompactZero and 'no ' or ''
))
# de-facto way to encode zero
if self.supportCompactZero:
return (), False, False
else:
return (0,), False, False
return to_bytes(int(value), signed=True), False, True
class BitStringEncoder(AbstractItemEncoder):
def encodeValue(self, value, asn1Spec, encodeFun, **options):
if asn1Spec is not None:
# TODO: try to avoid ASN.1 schema instantiation
value = asn1Spec.clone(value)
valueLength = len(value)
if valueLength % 8:
alignedValue = value << (8 - valueLength % 8)
else:
alignedValue = value
maxChunkSize = options.get('maxChunkSize', 0)
if not maxChunkSize or len(alignedValue) <= maxChunkSize * 8:
substrate = alignedValue.asOctets()
return bytes((len(substrate) * 8 - valueLength,)) + substrate, False, True
if LOG:
LOG('encoding into up to %s-octet chunks' % maxChunkSize)
baseTag = value.tagSet.baseTag
# strip off explicit tags
if baseTag:
tagSet = tag.TagSet(baseTag, baseTag)
else:
tagSet = tag.TagSet()
alignedValue = alignedValue.clone(tagSet=tagSet)
stop = 0
substrate = b''
while stop < valueLength:
start = stop
stop = min(start + maxChunkSize * 8, valueLength)
substrate += encodeFun(alignedValue[start:stop], asn1Spec, **options)
return substrate, True, True
class OctetStringEncoder(AbstractItemEncoder):
def encodeValue(self, value, asn1Spec, encodeFun, **options):
if asn1Spec is None:
substrate = value.asOctets()
elif not isinstance(value, bytes):
substrate = asn1Spec.clone(value).asOctets()
else:
substrate = value
maxChunkSize = options.get('maxChunkSize', 0)
if not maxChunkSize or len(substrate) <= maxChunkSize:
return substrate, False, True
if LOG:
LOG('encoding into up to %s-octet chunks' % maxChunkSize)
# strip off explicit tags for inner chunks
if asn1Spec is None:
baseTag = value.tagSet.baseTag
# strip off explicit tags
if baseTag:
tagSet = tag.TagSet(baseTag, baseTag)
else:
tagSet = tag.TagSet()
asn1Spec = value.clone(tagSet=tagSet)
elif not isinstance(value, bytes):
baseTag = asn1Spec.tagSet.baseTag
# strip off explicit tags
if baseTag:
tagSet = tag.TagSet(baseTag, baseTag)
else:
tagSet = tag.TagSet()
asn1Spec = asn1Spec.clone(tagSet=tagSet)
pos = 0
substrate = b''
while True:
chunk = value[pos:pos + maxChunkSize]
if not chunk:
break
substrate += encodeFun(chunk, asn1Spec, **options)
pos += maxChunkSize
return substrate, True, True
class NullEncoder(AbstractItemEncoder):
supportIndefLenMode = False
def encodeValue(self, value, asn1Spec, encodeFun, **options):
return b'', False, True
class ObjectIdentifierEncoder(AbstractItemEncoder):
supportIndefLenMode = False
def encodeValue(self, value, asn1Spec, encodeFun, **options):
if asn1Spec is not None:
value = asn1Spec.clone(value)
oid = value.asTuple()
# Build the first pair
try:
first = oid[0]
second = oid[1]
except IndexError:
raise error.PyAsn1Error('Short OID %s' % (value,))
if 0 <= second <= 39:
if first == 1:
oid = (second + 40,) + oid[2:]
elif first == 0:
oid = (second,) + oid[2:]
elif first == 2:
oid = (second + 80,) + oid[2:]
else:
raise error.PyAsn1Error('Impossible first/second arcs at %s' % (value,))
elif first == 2:
oid = (second + 80,) + oid[2:]
else:
raise error.PyAsn1Error('Impossible first/second arcs at %s' % (value,))
octets = ()
# Cycle through subIds
for subOid in oid:
if 0 <= subOid <= 127:
# Optimize for the common case
octets += (subOid,)
elif subOid > 127:
# Pack large Sub-Object IDs
res = (subOid & 0x7f,)
subOid >>= 7
while subOid:
res = (0x80 | (subOid & 0x7f),) + res
subOid >>= 7
# Add packed Sub-Object ID to resulted Object ID
octets += res
else:
raise error.PyAsn1Error('Negative OID arc %s at %s' % (subOid, value))
return octets, False, False
class RelativeOIDEncoder(AbstractItemEncoder):
supportIndefLenMode = False
def encodeValue(self, value, asn1Spec, encodeFun, **options):
if asn1Spec is not None:
value = asn1Spec.clone(value)
octets = ()
# Cycle through subIds
for subOid in value.asTuple():
if 0 <= subOid <= 127:
# Optimize for the common case
octets += (subOid,)
elif subOid > 127:
# Pack large Sub-Object IDs
res = (subOid & 0x7f,)
subOid >>= 7
while subOid:
res = (0x80 | (subOid & 0x7f),) + res
subOid >>= 7
# Add packed Sub-Object ID to resulted RELATIVE-OID
octets += res
else:
raise error.PyAsn1Error('Negative RELATIVE-OID arc %s at %s' % (subOid, value))
return octets, False, False
class RealEncoder(AbstractItemEncoder):
supportIndefLenMode = False
binEncBase = 2 # set to None to choose encoding base automatically
@staticmethod
def _dropFloatingPoint(m, encbase, e):
ms, es = 1, 1
if m < 0:
ms = -1 # mantissa sign
if e < 0:
es = -1 # exponent sign
m *= ms
if encbase == 8:
m *= 2 ** (abs(e) % 3 * es)
e = abs(e) // 3 * es
elif encbase == 16:
m *= 2 ** (abs(e) % 4 * es)
e = abs(e) // 4 * es
while True:
if int(m) != m:
m *= encbase
e -= 1
continue
break
return ms, int(m), encbase, e
def _chooseEncBase(self, value):
m, b, e = value
encBase = [2, 8, 16]
if value.binEncBase in encBase:
return self._dropFloatingPoint(m, value.binEncBase, e)
elif self.binEncBase in encBase:
return self._dropFloatingPoint(m, self.binEncBase, e)
# auto choosing base 2/8/16
mantissa = [m, m, m]
exponent = [e, e, e]
sign = 1
encbase = 2
e = float('inf')
for i in range(3):
(sign,
mantissa[i],
encBase[i],
exponent[i]) = self._dropFloatingPoint(mantissa[i], encBase[i], exponent[i])
if abs(exponent[i]) < abs(e) or (abs(exponent[i]) == abs(e) and mantissa[i] < m):
e = exponent[i]
m = int(mantissa[i])
encbase = encBase[i]
if LOG:
LOG('automatically chosen REAL encoding base %s, sign %s, mantissa %s, '
'exponent %s' % (encbase, sign, m, e))
return sign, m, encbase, e
def encodeValue(self, value, asn1Spec, encodeFun, **options):
if asn1Spec is not None:
value = asn1Spec.clone(value)
if value.isPlusInf:
return (0x40,), False, False
if value.isMinusInf:
return (0x41,), False, False
m, b, e = value
if not m:
return b'', False, True
if b == 10:
if LOG:
LOG('encoding REAL into character form')
return b'\x03%dE%s%d' % (m, e == 0 and b'+' or b'', e), False, True
elif b == 2:
fo = 0x80 # binary encoding
ms, m, encbase, e = self._chooseEncBase(value)
if ms < 0: # mantissa sign
fo |= 0x40 # sign bit
# exponent & mantissa normalization
if encbase == 2:
while m & 0x1 == 0:
m >>= 1
e += 1
elif encbase == 8:
while m & 0x7 == 0:
m >>= 3
e += 1
fo |= 0x10
else: # encbase = 16
while m & 0xf == 0:
m >>= 4
e += 1
fo |= 0x20
sf = 0 # scale factor
while m & 0x1 == 0:
m >>= 1
sf += 1
if sf > 3:
raise error.PyAsn1Error('Scale factor overflow') # bug if raised
fo |= sf << 2
eo = b''
if e == 0 or e == -1:
eo = bytes((e & 0xff,))
else:
while e not in (0, -1):
eo = bytes((e & 0xff,)) + eo
e >>= 8
if e == 0 and eo and eo[0] & 0x80:
eo = bytes((0,)) + eo
if e == -1 and eo and not (eo[0] & 0x80):
eo = bytes((0xff,)) + eo
n = len(eo)
if n > 0xff:
raise error.PyAsn1Error('Real exponent overflow')
if n == 1:
pass
elif n == 2:
fo |= 1
elif n == 3:
fo |= 2
else:
fo |= 3
eo = bytes((n & 0xff,)) + eo
po = b''
while m:
po = bytes((m & 0xff,)) + po
m >>= 8
substrate = bytes((fo,)) + eo + po
return substrate, False, True
else:
raise error.PyAsn1Error('Prohibited Real base %s' % b)
class SequenceEncoder(AbstractItemEncoder):
omitEmptyOptionals = False
# TODO: handling three flavors of input is too much -- split over codecs
def encodeValue(self, value, asn1Spec, encodeFun, **options):
substrate = b''
omitEmptyOptionals = options.get(
'omitEmptyOptionals', self.omitEmptyOptionals)
if LOG:
LOG('%sencoding empty OPTIONAL components' % (
omitEmptyOptionals and 'not ' or ''))
if asn1Spec is None:
# instance of ASN.1 schema
inconsistency = value.isInconsistent
if inconsistency:
raise error.PyAsn1Error(
f"ASN.1 object {value.__class__.__name__} is inconsistent")
namedTypes = value.componentType
for idx, component in enumerate(value.values()):
if namedTypes:
namedType = namedTypes[idx]
if namedType.isOptional and not component.isValue:
if LOG:
LOG('not encoding OPTIONAL component %r' % (namedType,))
continue
if namedType.isDefaulted and component == namedType.asn1Object:
if LOG:
LOG('not encoding DEFAULT component %r' % (namedType,))
continue
if omitEmptyOptionals:
options.update(ifNotEmpty=namedType.isOptional)
# wrap open type blob if needed
if namedTypes and namedType.openType:
wrapType = namedType.asn1Object
if wrapType.typeId in (
univ.SetOf.typeId, univ.SequenceOf.typeId):
substrate += encodeFun(
component, asn1Spec,
**dict(options, wrapType=wrapType.componentType))
else:
chunk = encodeFun(component, asn1Spec, **options)
if wrapType.isSameTypeWith(component):
substrate += chunk
else:
substrate += encodeFun(chunk, wrapType, **options)
if LOG:
LOG('wrapped with wrap type %r' % (wrapType,))
else:
substrate += encodeFun(component, asn1Spec, **options)
else:
# bare Python value + ASN.1 schema
for idx, namedType in enumerate(asn1Spec.componentType.namedTypes):
try:
component = value[namedType.name]
except KeyError:
raise error.PyAsn1Error('Component name "%s" not found in %r' % (
namedType.name, value))
if namedType.isOptional and namedType.name not in value:
if LOG:
LOG('not encoding OPTIONAL component %r' % (namedType,))
continue
if namedType.isDefaulted and component == namedType.asn1Object:
if LOG:
LOG('not encoding DEFAULT component %r' % (namedType,))
continue
if omitEmptyOptionals:
options.update(ifNotEmpty=namedType.isOptional)
componentSpec = namedType.asn1Object
# wrap open type blob if needed
if namedType.openType:
if componentSpec.typeId in (
univ.SetOf.typeId, univ.SequenceOf.typeId):
substrate += encodeFun(
component, componentSpec,
**dict(options, wrapType=componentSpec.componentType))
else:
chunk = encodeFun(component, componentSpec, **options)
if componentSpec.isSameTypeWith(component):
substrate += chunk
else:
substrate += encodeFun(chunk, componentSpec, **options)
if LOG:
LOG('wrapped with wrap type %r' % (componentSpec,))
else:
substrate += encodeFun(component, componentSpec, **options)
return substrate, True, True
class SequenceOfEncoder(AbstractItemEncoder):
def _encodeComponents(self, value, asn1Spec, encodeFun, **options):
if asn1Spec is None:
inconsistency = value.isInconsistent
if inconsistency:
raise error.PyAsn1Error(
f"ASN.1 object {value.__class__.__name__} is inconsistent")
else:
asn1Spec = asn1Spec.componentType
chunks = []
wrapType = options.pop('wrapType', None)
for idx, component in enumerate(value):
chunk = encodeFun(component, asn1Spec, **options)
if (wrapType is not None and
not wrapType.isSameTypeWith(component)):
# wrap encoded value with wrapper container (e.g. ANY)
chunk = encodeFun(chunk, wrapType, **options)
if LOG:
LOG('wrapped with wrap type %r' % (wrapType,))
chunks.append(chunk)
return chunks
def encodeValue(self, value, asn1Spec, encodeFun, **options):
chunks = self._encodeComponents(
value, asn1Spec, encodeFun, **options)
return b''.join(chunks), True, True
class ChoiceEncoder(AbstractItemEncoder):
def encodeValue(self, value, asn1Spec, encodeFun, **options):
if asn1Spec is None:
component = value.getComponent()
else:
names = [namedType.name for namedType in asn1Spec.componentType.namedTypes
if namedType.name in value]
if len(names) != 1:
raise error.PyAsn1Error('%s components for Choice at %r' % (len(names) and 'Multiple ' or 'None ', value))
name = names[0]
component = value[name]
asn1Spec = asn1Spec[name]
return encodeFun(component, asn1Spec, **options), True, True
class AnyEncoder(OctetStringEncoder):
def encodeValue(self, value, asn1Spec, encodeFun, **options):
if asn1Spec is None:
value = value.asOctets()
elif not isinstance(value, bytes):
value = asn1Spec.clone(value).asOctets()
return value, not options.get('defMode', True), True
TAG_MAP = {
eoo.endOfOctets.tagSet: EndOfOctetsEncoder(),
univ.Boolean.tagSet: BooleanEncoder(),
univ.Integer.tagSet: IntegerEncoder(),
univ.BitString.tagSet: BitStringEncoder(),
univ.OctetString.tagSet: OctetStringEncoder(),
univ.Null.tagSet: NullEncoder(),
univ.ObjectIdentifier.tagSet: ObjectIdentifierEncoder(),
univ.RelativeOID.tagSet: RelativeOIDEncoder(),
univ.Enumerated.tagSet: IntegerEncoder(),
univ.Real.tagSet: RealEncoder(),
# Sequence & Set have same tags as SequenceOf & SetOf
univ.SequenceOf.tagSet: SequenceOfEncoder(),
univ.SetOf.tagSet: SequenceOfEncoder(),
univ.Choice.tagSet: ChoiceEncoder(),
# character string types
char.UTF8String.tagSet: OctetStringEncoder(),
char.NumericString.tagSet: OctetStringEncoder(),
char.PrintableString.tagSet: OctetStringEncoder(),
char.TeletexString.tagSet: OctetStringEncoder(),
char.VideotexString.tagSet: OctetStringEncoder(),
char.IA5String.tagSet: OctetStringEncoder(),
char.GraphicString.tagSet: OctetStringEncoder(),
char.VisibleString.tagSet: OctetStringEncoder(),
char.GeneralString.tagSet: OctetStringEncoder(),
char.UniversalString.tagSet: OctetStringEncoder(),
char.BMPString.tagSet: OctetStringEncoder(),
# useful types
useful.ObjectDescriptor.tagSet: OctetStringEncoder(),
useful.GeneralizedTime.tagSet: OctetStringEncoder(),
useful.UTCTime.tagSet: OctetStringEncoder()
}
# Put in ambiguous & non-ambiguous types for faster codec lookup
TYPE_MAP = {
univ.Boolean.typeId: BooleanEncoder(),
univ.Integer.typeId: IntegerEncoder(),
univ.BitString.typeId: BitStringEncoder(),
univ.OctetString.typeId: OctetStringEncoder(),
univ.Null.typeId: NullEncoder(),
univ.ObjectIdentifier.typeId: ObjectIdentifierEncoder(),
univ.RelativeOID.typeId: RelativeOIDEncoder(),
univ.Enumerated.typeId: IntegerEncoder(),
univ.Real.typeId: RealEncoder(),
# Sequence & Set have same tags as SequenceOf & SetOf
univ.Set.typeId: SequenceEncoder(),
univ.SetOf.typeId: SequenceOfEncoder(),
univ.Sequence.typeId: SequenceEncoder(),
univ.SequenceOf.typeId: SequenceOfEncoder(),
univ.Choice.typeId: ChoiceEncoder(),
univ.Any.typeId: AnyEncoder(),
# character string types
char.UTF8String.typeId: OctetStringEncoder(),
char.NumericString.typeId: OctetStringEncoder(),
char.PrintableString.typeId: OctetStringEncoder(),
char.TeletexString.typeId: OctetStringEncoder(),
char.VideotexString.typeId: OctetStringEncoder(),
char.IA5String.typeId: OctetStringEncoder(),
char.GraphicString.typeId: OctetStringEncoder(),
char.VisibleString.typeId: OctetStringEncoder(),
char.GeneralString.typeId: OctetStringEncoder(),
char.UniversalString.typeId: OctetStringEncoder(),
char.BMPString.typeId: OctetStringEncoder(),
# useful types
useful.ObjectDescriptor.typeId: OctetStringEncoder(),
useful.GeneralizedTime.typeId: OctetStringEncoder(),
useful.UTCTime.typeId: OctetStringEncoder()
}
class SingleItemEncoder(object):
fixedDefLengthMode = None
fixedChunkSize = None
TAG_MAP = TAG_MAP
TYPE_MAP = TYPE_MAP
def __init__(self, tagMap=_MISSING, typeMap=_MISSING, **ignored):
self._tagMap = tagMap if tagMap is not _MISSING else self.TAG_MAP
self._typeMap = typeMap if typeMap is not _MISSING else self.TYPE_MAP
def __call__(self, value, asn1Spec=None, **options):
try:
if asn1Spec is None:
typeId = value.typeId
else:
typeId = asn1Spec.typeId
except AttributeError:
raise error.PyAsn1Error('Value %r is not ASN.1 type instance '
'and "asn1Spec" not given' % (value,))
if LOG:
LOG('encoder called in %sdef mode, chunk size %s for type %s, '
'value:\n%s' % (not options.get('defMode', True) and 'in' or '',
options.get('maxChunkSize', 0),
asn1Spec is None and value.prettyPrintType() or
asn1Spec.prettyPrintType(), value))
if self.fixedDefLengthMode is not None:
options.update(defMode=self.fixedDefLengthMode)
if self.fixedChunkSize is not None:
options.update(maxChunkSize=self.fixedChunkSize)
try:
concreteEncoder = self._typeMap[typeId]
if LOG:
LOG('using value codec %s chosen by type ID '
'%s' % (concreteEncoder.__class__.__name__, typeId))
except KeyError:
if asn1Spec is None:
tagSet = value.tagSet
else:
tagSet = asn1Spec.tagSet
# use base type for codec lookup to recover untagged types
baseTagSet = tag.TagSet(tagSet.baseTag, tagSet.baseTag)
try:
concreteEncoder = self._tagMap[baseTagSet]
except KeyError:
raise error.PyAsn1Error('No encoder for %r (%s)' % (value, tagSet))
if LOG:
LOG('using value codec %s chosen by tagSet '
'%s' % (concreteEncoder.__class__.__name__, tagSet))
substrate = concreteEncoder.encode(value, asn1Spec, self, **options)
if LOG:
LOG('codec %s built %s octets of substrate: %s\nencoder '
'completed' % (concreteEncoder, len(substrate),
debug.hexdump(substrate)))
return substrate
class Encoder(object):
SINGLE_ITEM_ENCODER = SingleItemEncoder
def __init__(self, tagMap=_MISSING, typeMap=_MISSING, **options):
self._singleItemEncoder = self.SINGLE_ITEM_ENCODER(
tagMap=tagMap, typeMap=typeMap, **options
)
def __call__(self, pyObject, asn1Spec=None, **options):
return self._singleItemEncoder(
pyObject, asn1Spec=asn1Spec, **options)
#: Turns ASN.1 object into BER octet stream.
#:
#: Takes any ASN.1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative)
#: walks all its components recursively and produces a BER octet stream.
#:
#: Parameters
#: ----------
#: value: either a Python or pyasn1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative)
#: A Python or pyasn1 object to encode. If Python object is given, `asnSpec`
#: parameter is required to guide the encoding process.
#:
#: Keyword Args
#: ------------
#: asn1Spec:
#: Optional ASN.1 schema or value object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative
#:
#: defMode: :py:class:`bool`
#: If :obj:`False`, produces indefinite length encoding
#:
#: maxChunkSize: :py:class:`int`
#: Maximum chunk size in chunked encoding mode (0 denotes unlimited chunk size)
#:
#: Returns
#: -------
#: : :py:class:`bytes`
#: Given ASN.1 object encoded into BER octetstream
#:
#: Raises
#: ------
#: ~pyasn1.error.PyAsn1Error
#: On encoding errors
#:
#: Examples
#: --------
#: Encode Python value into BER with ASN.1 schema
#:
#: .. code-block:: pycon
#:
#: >>> seq = SequenceOf(componentType=Integer())
#: >>> encode([1, 2, 3], asn1Spec=seq)
#: b'0\t\x02\x01\x01\x02\x01\x02\x02\x01\x03'
#:
#: Encode ASN.1 value object into BER
#:
#: .. code-block:: pycon
#:
#: >>> seq = SequenceOf(componentType=Integer())
#: >>> seq.extend([1, 2, 3])
#: >>> encode(seq)
#: b'0\t\x02\x01\x01\x02\x01\x02\x02\x01\x03'
#:
encode = Encoder()
def __getattr__(attr: str):
if newAttr := {"tagMap": "TAG_MAP", "typeMap": "TYPE_MAP"}.get(attr):
warnings.warn(f"{attr} is deprecated. Please use {newAttr} instead.", DeprecationWarning)
return globals()[newAttr]
raise AttributeError(attr)

View File

@@ -0,0 +1,28 @@
#
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2020, Ilya Etingof <etingof@gmail.com>
# License: https://pyasn1.readthedocs.io/en/latest/license.html
#
from pyasn1.type import base
from pyasn1.type import tag
__all__ = ['endOfOctets']
class EndOfOctets(base.SimpleAsn1Type):
defaultValue = 0
tagSet = tag.initTagSet(
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x00)
)
_instance = None
def __new__(cls, *args, **kwargs):
if cls._instance is None:
cls._instance = object.__new__(cls, *args, **kwargs)
return cls._instance
endOfOctets = EndOfOctets()

View File

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

View File

@@ -0,0 +1,149 @@
#
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2020, Ilya Etingof <etingof@gmail.com>
# License: https://pyasn1.readthedocs.io/en/latest/license.html
#
import warnings
from pyasn1 import error
from pyasn1.codec.streaming import readFromStream
from pyasn1.codec.ber import decoder
from pyasn1.type import univ
__all__ = ['decode', 'StreamingDecoder']
SubstrateUnderrunError = error.SubstrateUnderrunError
class BooleanPayloadDecoder(decoder.AbstractSimplePayloadDecoder):
protoComponent = univ.Boolean(0)
def valueDecoder(self, substrate, asn1Spec,
tagSet=None, length=None, state=None,
decodeFun=None, substrateFun=None,
**options):
if length != 1:
raise error.PyAsn1Error('Not single-octet Boolean payload')
for chunk in readFromStream(substrate, length, options):
if isinstance(chunk, SubstrateUnderrunError):
yield chunk
byte = chunk[0]
# CER/DER specifies encoding of TRUE as 0xFF and FALSE as 0x0, while
# BER allows any non-zero value as TRUE; cf. sections 8.2.2. and 11.1
# in https://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf
if byte == 0xff:
value = 1
elif byte == 0x00:
value = 0
else:
raise error.PyAsn1Error('Unexpected Boolean payload: %s' % byte)
yield self._createComponent(asn1Spec, tagSet, value, **options)
# TODO: prohibit non-canonical encoding
BitStringPayloadDecoder = decoder.BitStringPayloadDecoder
OctetStringPayloadDecoder = decoder.OctetStringPayloadDecoder
RealPayloadDecoder = decoder.RealPayloadDecoder
TAG_MAP = decoder.TAG_MAP.copy()
TAG_MAP.update(
{univ.Boolean.tagSet: BooleanPayloadDecoder(),
univ.BitString.tagSet: BitStringPayloadDecoder(),
univ.OctetString.tagSet: OctetStringPayloadDecoder(),
univ.Real.tagSet: RealPayloadDecoder()}
)
TYPE_MAP = decoder.TYPE_MAP.copy()
# Put in non-ambiguous types for faster codec lookup
for typeDecoder in TAG_MAP.values():
if typeDecoder.protoComponent is not None:
typeId = typeDecoder.protoComponent.__class__.typeId
if typeId is not None and typeId not in TYPE_MAP:
TYPE_MAP[typeId] = typeDecoder
class SingleItemDecoder(decoder.SingleItemDecoder):
__doc__ = decoder.SingleItemDecoder.__doc__
TAG_MAP = TAG_MAP
TYPE_MAP = TYPE_MAP
class StreamingDecoder(decoder.StreamingDecoder):
__doc__ = decoder.StreamingDecoder.__doc__
SINGLE_ITEM_DECODER = SingleItemDecoder
class Decoder(decoder.Decoder):
__doc__ = decoder.Decoder.__doc__
STREAMING_DECODER = StreamingDecoder
#: Turns CER octet stream into an ASN.1 object.
#:
#: Takes CER octet-stream and decode it into an ASN.1 object
#: (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) which
#: may be a scalar or an arbitrary nested structure.
#:
#: Parameters
#: ----------
#: substrate: :py:class:`bytes`
#: CER octet-stream
#:
#: Keyword Args
#: ------------
#: asn1Spec: any pyasn1 type object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative
#: A pyasn1 type object to act as a template guiding the decoder. Depending on the ASN.1 structure
#: being decoded, *asn1Spec* may or may not be required. Most common reason for
#: it to require is that ASN.1 structure is encoded in *IMPLICIT* tagging mode.
#:
#: Returns
#: -------
#: : :py:class:`tuple`
#: A tuple of pyasn1 object recovered from CER substrate (:py:class:`~pyasn1.type.base.PyAsn1Item` derivative)
#: and the unprocessed trailing portion of the *substrate* (may be empty)
#:
#: Raises
#: ------
#: ~pyasn1.error.PyAsn1Error, ~pyasn1.error.SubstrateUnderrunError
#: On decoding errors
#:
#: Examples
#: --------
#: Decode CER serialisation without ASN.1 schema
#:
#: .. code-block:: pycon
#:
#: >>> s, _ = decode(b'0\x80\x02\x01\x01\x02\x01\x02\x02\x01\x03\x00\x00')
#: >>> str(s)
#: SequenceOf:
#: 1 2 3
#:
#: Decode CER serialisation with ASN.1 schema
#:
#: .. code-block:: pycon
#:
#: >>> seq = SequenceOf(componentType=Integer())
#: >>> s, _ = decode(b'0\x80\x02\x01\x01\x02\x01\x02\x02\x01\x03\x00\x00', asn1Spec=seq)
#: >>> str(s)
#: SequenceOf:
#: 1 2 3
#:
decode = Decoder()
def __getattr__(attr: str):
if newAttr := {"tagMap": "TAG_MAP", "typeMap": "TYPE_MAP"}.get(attr):
warnings.warn(f"{attr} is deprecated. Please use {newAttr} instead.", DeprecationWarning)
return globals()[newAttr]
raise AttributeError(attr)

View File

@@ -0,0 +1,331 @@
#
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2020, Ilya Etingof <etingof@gmail.com>
# License: https://pyasn1.readthedocs.io/en/latest/license.html
#
import warnings
from pyasn1 import error
from pyasn1.codec.ber import encoder
from pyasn1.type import univ
from pyasn1.type import useful
__all__ = ['Encoder', 'encode']
class BooleanEncoder(encoder.IntegerEncoder):
def encodeValue(self, value, asn1Spec, encodeFun, **options):
if value == 0:
substrate = (0,)
else:
substrate = (255,)
return substrate, False, False
class RealEncoder(encoder.RealEncoder):
def _chooseEncBase(self, value):
m, b, e = value
return self._dropFloatingPoint(m, b, e)
# specialized GeneralStringEncoder here
class TimeEncoderMixIn(object):
Z_CHAR = ord('Z')
PLUS_CHAR = ord('+')
MINUS_CHAR = ord('-')
COMMA_CHAR = ord(',')
DOT_CHAR = ord('.')
ZERO_CHAR = ord('0')
MIN_LENGTH = 12
MAX_LENGTH = 19
def encodeValue(self, value, asn1Spec, encodeFun, **options):
# CER encoding constraints:
# - minutes are mandatory, seconds are optional
# - sub-seconds must NOT be zero / no meaningless zeros
# - no hanging fraction dot
# - time in UTC (Z)
# - only dot is allowed for fractions
if asn1Spec is not None:
value = asn1Spec.clone(value)
numbers = value.asNumbers()
if self.PLUS_CHAR in numbers or self.MINUS_CHAR in numbers:
raise error.PyAsn1Error('Must be UTC time: %r' % value)
if numbers[-1] != self.Z_CHAR:
raise error.PyAsn1Error('Missing "Z" time zone specifier: %r' % value)
if self.COMMA_CHAR in numbers:
raise error.PyAsn1Error('Comma in fractions disallowed: %r' % value)
if self.DOT_CHAR in numbers:
isModified = False
numbers = list(numbers)
searchIndex = min(numbers.index(self.DOT_CHAR) + 4, len(numbers) - 1)
while numbers[searchIndex] != self.DOT_CHAR:
if numbers[searchIndex] == self.ZERO_CHAR:
del numbers[searchIndex]
isModified = True
searchIndex -= 1
searchIndex += 1
if searchIndex < len(numbers):
if numbers[searchIndex] == self.Z_CHAR:
# drop hanging comma
del numbers[searchIndex - 1]
isModified = True
if isModified:
value = value.clone(numbers)
if not self.MIN_LENGTH < len(numbers) < self.MAX_LENGTH:
raise error.PyAsn1Error('Length constraint violated: %r' % value)
options.update(maxChunkSize=1000)
return encoder.OctetStringEncoder.encodeValue(
self, value, asn1Spec, encodeFun, **options
)
class GeneralizedTimeEncoder(TimeEncoderMixIn, encoder.OctetStringEncoder):
MIN_LENGTH = 12
MAX_LENGTH = 20
class UTCTimeEncoder(TimeEncoderMixIn, encoder.OctetStringEncoder):
MIN_LENGTH = 10
MAX_LENGTH = 14
class SetOfEncoder(encoder.SequenceOfEncoder):
def encodeValue(self, value, asn1Spec, encodeFun, **options):
chunks = self._encodeComponents(
value, asn1Spec, encodeFun, **options)
# sort by serialised and padded components
if len(chunks) > 1:
zero = b'\x00'
maxLen = max(map(len, chunks))
paddedChunks = [
(x.ljust(maxLen, zero), x) for x in chunks
]
paddedChunks.sort(key=lambda x: x[0])
chunks = [x[1] for x in paddedChunks]
return b''.join(chunks), True, True
class SequenceOfEncoder(encoder.SequenceOfEncoder):
def encodeValue(self, value, asn1Spec, encodeFun, **options):
if options.get('ifNotEmpty', False) and not len(value):
return b'', True, True
chunks = self._encodeComponents(
value, asn1Spec, encodeFun, **options)
return b''.join(chunks), True, True
class SetEncoder(encoder.SequenceEncoder):
@staticmethod
def _componentSortKey(componentAndType):
"""Sort SET components by tag
Sort regardless of the Choice value (static sort)
"""
component, asn1Spec = componentAndType
if asn1Spec is None:
asn1Spec = component
if asn1Spec.typeId == univ.Choice.typeId and not asn1Spec.tagSet:
if asn1Spec.tagSet:
return asn1Spec.tagSet
else:
return asn1Spec.componentType.minTagSet
else:
return asn1Spec.tagSet
def encodeValue(self, value, asn1Spec, encodeFun, **options):
substrate = b''
comps = []
compsMap = {}
if asn1Spec is None:
# instance of ASN.1 schema
inconsistency = value.isInconsistent
if inconsistency:
raise error.PyAsn1Error(
f"ASN.1 object {value.__class__.__name__} is inconsistent")
namedTypes = value.componentType
for idx, component in enumerate(value.values()):
if namedTypes:
namedType = namedTypes[idx]
if namedType.isOptional and not component.isValue:
continue
if namedType.isDefaulted and component == namedType.asn1Object:
continue
compsMap[id(component)] = namedType
else:
compsMap[id(component)] = None
comps.append((component, asn1Spec))
else:
# bare Python value + ASN.1 schema
for idx, namedType in enumerate(asn1Spec.componentType.namedTypes):
try:
component = value[namedType.name]
except KeyError:
raise error.PyAsn1Error('Component name "%s" not found in %r' % (namedType.name, value))
if namedType.isOptional and namedType.name not in value:
continue
if namedType.isDefaulted and component == namedType.asn1Object:
continue
compsMap[id(component)] = namedType
comps.append((component, asn1Spec[idx]))
for comp, compType in sorted(comps, key=self._componentSortKey):
namedType = compsMap[id(comp)]
if namedType:
options.update(ifNotEmpty=namedType.isOptional)
chunk = encodeFun(comp, compType, **options)
# wrap open type blob if needed
if namedType and namedType.openType:
wrapType = namedType.asn1Object
if wrapType.tagSet and not wrapType.isSameTypeWith(comp):
chunk = encodeFun(chunk, wrapType, **options)
substrate += chunk
return substrate, True, True
class SequenceEncoder(encoder.SequenceEncoder):
omitEmptyOptionals = True
TAG_MAP = encoder.TAG_MAP.copy()
TAG_MAP.update({
univ.Boolean.tagSet: BooleanEncoder(),
univ.Real.tagSet: RealEncoder(),
useful.GeneralizedTime.tagSet: GeneralizedTimeEncoder(),
useful.UTCTime.tagSet: UTCTimeEncoder(),
# Sequence & Set have same tags as SequenceOf & SetOf
univ.SetOf.tagSet: SetOfEncoder(),
univ.Sequence.typeId: SequenceEncoder()
})
TYPE_MAP = encoder.TYPE_MAP.copy()
TYPE_MAP.update({
univ.Boolean.typeId: BooleanEncoder(),
univ.Real.typeId: RealEncoder(),
useful.GeneralizedTime.typeId: GeneralizedTimeEncoder(),
useful.UTCTime.typeId: UTCTimeEncoder(),
# Sequence & Set have same tags as SequenceOf & SetOf
univ.Set.typeId: SetEncoder(),
univ.SetOf.typeId: SetOfEncoder(),
univ.Sequence.typeId: SequenceEncoder(),
univ.SequenceOf.typeId: SequenceOfEncoder()
})
class SingleItemEncoder(encoder.SingleItemEncoder):
fixedDefLengthMode = False
fixedChunkSize = 1000
TAG_MAP = TAG_MAP
TYPE_MAP = TYPE_MAP
class Encoder(encoder.Encoder):
SINGLE_ITEM_ENCODER = SingleItemEncoder
#: Turns ASN.1 object into CER octet stream.
#:
#: Takes any ASN.1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative)
#: walks all its components recursively and produces a CER octet stream.
#:
#: Parameters
#: ----------
#: value: either a Python or pyasn1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative)
#: A Python or pyasn1 object to encode. If Python object is given, `asnSpec`
#: parameter is required to guide the encoding process.
#:
#: Keyword Args
#: ------------
#: asn1Spec:
#: Optional ASN.1 schema or value object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative
#:
#: Returns
#: -------
#: : :py:class:`bytes`
#: Given ASN.1 object encoded into BER octet-stream
#:
#: Raises
#: ------
#: ~pyasn1.error.PyAsn1Error
#: On encoding errors
#:
#: Examples
#: --------
#: Encode Python value into CER with ASN.1 schema
#:
#: .. code-block:: pycon
#:
#: >>> seq = SequenceOf(componentType=Integer())
#: >>> encode([1, 2, 3], asn1Spec=seq)
#: b'0\x80\x02\x01\x01\x02\x01\x02\x02\x01\x03\x00\x00'
#:
#: Encode ASN.1 value object into CER
#:
#: .. code-block:: pycon
#:
#: >>> seq = SequenceOf(componentType=Integer())
#: >>> seq.extend([1, 2, 3])
#: >>> encode(seq)
#: b'0\x80\x02\x01\x01\x02\x01\x02\x02\x01\x03\x00\x00'
#:
encode = Encoder()
# EncoderFactory queries class instance and builds a map of tags -> encoders
def __getattr__(attr: str):
if newAttr := {"tagMap": "TAG_MAP", "typeMap": "TYPE_MAP"}.get(attr):
warnings.warn(f"{attr} is deprecated. Please use {newAttr} instead.", DeprecationWarning)
return globals()[newAttr]
raise AttributeError(attr)

Some files were not shown because too many files have changed in this diff Show More